Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toolbar/list #3918

Merged
merged 6 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
toolbar
  • Loading branch information
felixfeng33 committed Dec 25, 2024
commit b4f8182c6092bdfbbc7b13966c710e3f417195c2
12 changes: 8 additions & 4 deletions apps/www/src/registry/default/plate-ui/fixed-toolbar-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
FontColorPlugin,
} from '@udecode/plate-font/react';
import { HighlightPlugin } from '@udecode/plate-highlight/react';
import { ListStyleType } from '@udecode/plate-indent-list';
import {
AudioPlugin,
FilePlugin,
Expand Down Expand Up @@ -44,7 +43,10 @@ import { CommentToolbarButton } from './comment-toolbar-button';
import { EmojiDropdownMenu } from './emoji-dropdown-menu';
import { ExportToolbarButton } from './export-toolbar-button';
import { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';
import { IndentListToolbarButton } from './indent-list-toolbar-button';
import {
BulletedListToolbarButton,
NumberedListToolbarButton,
} from './indent-list-toolbar-button';
import { IndentTodoToolbarButton } from './indent-todo-toolbar-button';
import { IndentToolbarButton } from './indent-toolbar-button';
import { InsertDropdownMenu } from './insert-dropdown-menu';
Expand Down Expand Up @@ -136,8 +138,10 @@ export function FixedToolbarButtons() {
<ToolbarGroup>
<AlignDropdownMenu />

<IndentListToolbarButton nodeType={ListStyleType.Disc} />
<IndentListToolbarButton nodeType={ListStyleType.Decimal} />
<NumberedListToolbarButton />
<BulletedListToolbarButton />
{/* <IndentListToolbarButton nodeType={ListStyleType.Disc} /> */}
{/* <IndentListToolbarButton nodeType={ListStyleType.Decimal} /> */}
<IndentTodoToolbarButton />
<ToggleToolbarButton />
</ToolbarGroup>
Expand Down
203 changes: 179 additions & 24 deletions apps/www/src/registry/default/plate-ui/indent-list-toolbar-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,189 @@

import React from 'react';

import { withRef } from '@udecode/cn';
import { ListStyleType } from '@udecode/plate-indent-list';
import { useEditorRef, useEditorSelector } from '@udecode/plate-common/react';
import {
useIndentListToolbarButton,
useIndentListToolbarButtonState,
} from '@udecode/plate-indent-list/react';
ListStyleType,
someIndentList,
toggleIndentList,
} from '@udecode/plate-indent-list';
import { List, ListOrdered } from 'lucide-react';

import { ToolbarButton } from './toolbar';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
useOpenState,
} from './dropdown-menu';
import {
ToolbarSplitButton,
ToolbarSplitButtonPrimary,
ToolbarSplitButtonSecondary,
} from './toolbar';

export function NumberedListToolbarButton() {
const editor = useEditorRef();
const openState = useOpenState();

const pressed = useEditorSelector(
(editor) =>
someIndentList(editor, [
ListStyleType.Decimal,
ListStyleType.LowerAlpha,
ListStyleType.UpperAlpha,
ListStyleType.LowerRoman,
ListStyleType.UpperRoman,
]),
[]
);

return (
<ToolbarSplitButton pressed={openState.open} tooltip="Numbered List">
<ToolbarSplitButtonPrimary
onClick={() => {
toggleIndentList(editor, {
listStyleType: ListStyleType.Decimal,
});
}}
pressed={pressed}
>
<ListOrdered className="size-4" />
</ToolbarSplitButtonPrimary>

export const IndentListToolbarButton = withRef<
typeof ToolbarButton,
{
nodeType?: ListStyleType;
}
>(({ nodeType = ListStyleType.Disc }, ref) => {
const state = useIndentListToolbarButtonState({ nodeType });
const { props } = useIndentListToolbarButton(state);
<DropdownMenu {...openState} modal={false}>
<DropdownMenuTrigger asChild>
<ToolbarSplitButtonSecondary />
</DropdownMenuTrigger>

<DropdownMenuContent align="start" alignOffset={-32}>
<DropdownMenuGroup>
<DropdownMenuItem
onSelect={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.Decimal,
})
}
>
Decimal (1, 2, 3)
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.LowerAlpha,
})
}
>
Lower Alpha (a, b, c)
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.UpperAlpha,
})
}
>
Upper Alpha (A, B, C)
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.LowerRoman,
})
}
>
Lower Roman (i, ii, iii)
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.UpperRoman,
})
}
>
Upper Roman (I, II, III)
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ToolbarSplitButton>
);
}

export function BulletedListToolbarButton() {
const editor = useEditorRef();
const openState = useOpenState();

const pressed = useEditorSelector(
(editor) =>
someIndentList(editor, [
ListStyleType.Disc,
ListStyleType.Circle,
ListStyleType.Square,
]),
[]
);

return (
<ToolbarButton
ref={ref}
tooltip={
nodeType === ListStyleType.Disc ? 'Bulleted List' : 'Numbered List'
}
{...props}
>
{nodeType === ListStyleType.Disc ? <List /> : <ListOrdered />}
</ToolbarButton>
<ToolbarSplitButton pressed={openState.open} tooltip="Bulleted List">
<ToolbarSplitButtonPrimary
onClick={() => {
toggleIndentList(editor, {
listStyleType: ListStyleType.Disc,
});
}}
pressed={pressed}
>
<List className="size-4" />
</ToolbarSplitButtonPrimary>

<DropdownMenu {...openState} modal={false}>
<DropdownMenuTrigger asChild>
<ToolbarSplitButtonSecondary />
</DropdownMenuTrigger>

<DropdownMenuContent align="start" alignOffset={-32}>
<DropdownMenuGroup>
<DropdownMenuItem
onClick={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.Disc,
})
}
>
<div className="flex items-center gap-2">
<div className="size-2 rounded-full border border-current bg-current" />
Default
</div>
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.Circle,
})
}
>
<div className="flex items-center gap-2">
<div className="size-2 rounded-full border border-current" />
Circle
</div>
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
toggleIndentList(editor, {
listStyleType: ListStyleType.Square,
})
}
>
<div className="flex items-center gap-2">
<div className="size-2 border border-current bg-current" />
Square
</div>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ToolbarSplitButton>
);
});
}
86 changes: 66 additions & 20 deletions apps/www/src/registry/default/plate-ui/table-dropdown-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use client';

import React from 'react';
import React, { useCallback, useState } from 'react';

import type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';

import { cn } from '@udecode/cn';
import { someNode } from '@udecode/plate-common';
import {
focusEditor,
Expand Down Expand Up @@ -40,6 +41,8 @@ import {
} from './dropdown-menu';
import { ToolbarButton } from './toolbar';

const COLS = 8;

export function TableDropdownMenu(props: DropdownMenuProps) {
const tableSelected = useEditorSelector(
(editor) => someNode(editor, { match: { type: TablePlugin.key } }),
Expand All @@ -50,6 +53,32 @@ export function TableDropdownMenu(props: DropdownMenuProps) {

const openState = useOpenState();

const [table, setTable] = useState(
Array.from({ length: COLS }, () => Array.from({ length: COLS }).fill(0))
);
const [info, setInfo] = useState({ colCount: 0, rowCount: 0 });

const onCellMove = useCallback(
(rowIndex: number, colIndex: number) => {
const newTables = [...table];

for (let i = 0; i < newTables.length; i++) {
for (let j = 0; j < newTables[i].length; j++) {
newTables[i][j] =
i >= 0 && i <= rowIndex && j >= 0 && j <= colIndex ? 1 : 0;
}
}

setInfo({ colCount: colIndex + 1, rowCount: rowIndex + 1 });
setTable(newTables);
},
[table]
);

const onInsertTable = useCallback(() => {
insertTable(editor, info);
}, [editor, info]);

return (
<DropdownMenu modal={false} {...openState} {...props}>
<DropdownMenuTrigger asChild>
Expand All @@ -68,27 +97,33 @@ export function TableDropdownMenu(props: DropdownMenuProps) {
<Table />
<span>Table</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuSubContent className="m-0 p-0">
<DropdownMenuItem
className="min-w-[180px]"
onSelect={() => {
insertTable(editor, {}, { select: true });
focusEditor(editor);
}}
className="m-0 !flex flex-col p-0"
onSelect={onInsertTable}
>
<Plus />
Insert table
</DropdownMenuItem>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
onSelect={() => {
deleteTable(editor);
focusEditor(editor);
}}
>
<Trash />
Delete table
<div className="grid size-[130px] grid-cols-8 gap-0.5 p-1">
{table.map((rows, rowIndex) =>
rows.map((value, columIndex) => {
return (
<div
key={`(${rowIndex},${columIndex})`}
className={cn(
'col-span-1 size-3 border border-solid bg-secondary',
!!value && 'border-brand'
)}
onMouseMove={() => {
onCellMove(rowIndex, columIndex);
}}
/>
);
})
)}
</div>

<div className="text-center text-xs text-current">
{info.rowCount} x {info.colCount}
</div>
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
Expand Down Expand Up @@ -153,6 +188,17 @@ export function TableDropdownMenu(props: DropdownMenuProps) {
Delete row
</DropdownMenuItem>
</DropdownMenuSubContent>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
onSelect={() => {
deleteTable(editor);
focusEditor(editor);
}}
>
<Trash />
Delete table
</DropdownMenuItem>
</DropdownMenuSub>
</DropdownMenuGroup>
</DropdownMenuContent>
Expand Down
8 changes: 6 additions & 2 deletions apps/www/src/registry/default/plate-ui/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,10 @@ export const ToolbarSplitButton = React.forwardRef<

export const ToolbarSplitButtonPrimary = React.forwardRef<
React.ElementRef<typeof ToolbarToggleItem>,
Omit<React.ComponentPropsWithoutRef<typeof ToolbarToggleItem>, 'value'>
>(({ children, className, size, variant, ...props }, ref) => {
Omit<React.ComponentPropsWithoutRef<typeof ToolbarToggleItem>, 'value'> & {
pressed?: boolean;
}
>(({ children, className, pressed, size, variant, ...props }, ref) => {
return (
<span
ref={ref}
Expand All @@ -184,8 +186,10 @@ export const ToolbarSplitButtonPrimary = React.forwardRef<
}),
'rounded-r-none',
'group-data-[pressed=true]:bg-accent group-data-[pressed=true]:text-accent-foreground',
pressed && 'bg-accent text-accent-foreground',
className
)}
data-pressed={pressed}
{...props}
>
{children}
Expand Down
Loading