diff --git a/.changeset/huge-paws-burn.md b/.changeset/huge-paws-burn.md new file mode 100644 index 00000000..6baf2b0e --- /dev/null +++ b/.changeset/huge-paws-burn.md @@ -0,0 +1,5 @@ +--- +'tiptap-docs': patch +--- + +docs: add table-node documentation diff --git a/src/content/ui-components/node-components/table-node.mdx b/src/content/ui-components/node-components/table-node.mdx new file mode 100644 index 00000000..f46c5111 --- /dev/null +++ b/src/content/ui-components/node-components/table-node.mdx @@ -0,0 +1,636 @@ +--- +title: Table Node +meta: + title: Table node | Tiptap UI Components + description: Add a table node UI component to your Tiptap editor. More in the documentation! + category: UI Components +component: + name: Table node + description: Add a table UI node component + type: node-component + isFree: false + isCloud: false + isOpen: false + isNew: true + icon: Table +tags: + - type: start +--- + +import { CodeDemo } from '@/components/CodeDemo' + +An enhanced table node component for Tiptap editors with table handles for row/column manipulation, cell alignment controls, add/delete/move/duplicate functionality, and advanced table management capabilities with responsive styling and accessibility features. + + + +## Installation + +Add the component via the Tiptap CLI: + +```bash +npx @tiptap/cli@latest add table-node +``` + +## Creating Tables + +### `` + +**The primary component for inserting tables into your editor.** This button opens an interactive grid selector that allows users to visually choose the dimensions of their table before inserting it. + +#### Key Features + +- **Visual Grid Selector**: Interactive grid interface for selecting table dimensions +- **Quick Insertion**: Click to instantly create tables up to 8×8 (customizable) +- **Accessible**: Full keyboard navigation and ARIA labels + +#### Usage + +```tsx +import { TableTriggerButton } from '@/registry/tiptap-node/table-node/ui/table-trigger-button' + +function MyToolbar() { + return ( + console.log(`Inserted ${rows}×${cols} table`)} + /> + ) +} +``` + +#### Props + +- `editor?: Editor | null` - Editor instance +- `hideWhenUnavailable?: boolean` - Hide when table insertion is not available (default: false) +- `maxRows?: number` - Maximum number of rows in the grid selector (default: 8) +- `maxCols?: number` - Maximum number of columns in the grid selector (default: 8) +- `onInserted?: (rows: number, cols: number) => void` - Callback after successful insertion +- `text?: string` - Optional text to display alongside the icon +- All standard button props (className, disabled, etc.) + +#### Custom Implementation with Hook + +For custom button implementations, use the `useTableTriggerButton` hook: + +```tsx +import { useTableTriggerButton } from '@/registry/tiptap-node/table-node/ui/table-trigger-button' + +function CustomTableButton() { + const { + isVisible, + canInsert, + isOpen, + setIsOpen, + hoveredCell, + handleCellHover, + handleCellClick, + resetHoveredCell, + label, + Icon, + } = useTableTriggerButton({ + editor, + hideWhenUnavailable: true, + maxRows: 10, + maxCols: 10, + onInserted: (rows, cols) => { + console.log(`Created ${rows}×${cols} table`) + }, + }) + + if (!isVisible) return null + + return ( + + ) +} +``` + +--- + +## Components + +### `` + +An enhanced table node component with table handles, row/column manipulation, and advanced management features. + +#### Usage + +```tsx +import { useEditor, EditorContent, EditorContext } from '@tiptap/react' +import { StarterKit } from '@tiptap/starter-kit' +import { TextStyle } from '@tiptap/extension-text-style' +import { Highlight } from '@tiptap/extension-highlight' + +import { NodeBackground } from '@/registry/tiptap-extension/node-background-extension' +import { NodeAlignment } from '@/registry/tiptap-extension/node-alignment-extension' + +import { ButtonGroup } from '@/registry/tiptap-ui-primitive/button' + +import { TableTriggerButton } from '@/registry/tiptap-node/table-node/ui/table-trigger-button' +import { TableKit } from '@/registry/tiptap-node/table-node/extensions/table-node-extension' +import { TableHandleExtension } from '@/registry/tiptap-node/table-node/extensions/table-handle-extension' +import { TableHandle } from '@/registry/tiptap-node/table-node/ui/table-handle/table-handle' +import { TableSelectionOverlay } from '@/registry/tiptap-node/table-node/ui/table-selection-overlay' +import { TableCellHandleMenu } from '@/registry/tiptap-node/table-node/ui/table-cell-handle-menu' +import { TableExtendRowColumnButtons } from '@/registry/tiptap-node/table-node/ui/table-extend-row-column-button' +import '@/registry/tiptap-node/table-node/styles/prosemirror-table.scss' +import '@/registry/tiptap-node/table-node/styles/table-node.scss' + +// --- Tiptap Node Styles --- +import '@/registry/tiptap-node/heading-node/heading-node.scss' +import '@/registry/tiptap-node/paragraph-node/paragraph-node.scss' + +export default function BasicEditor() { + const editor = useEditor({ + immediatelyRender: false, + extensions: [ + StarterKit, + TableKit.configure({ + table: { + resizable: true, + }, + }), + TableHandleExtension, + NodeBackground, + NodeAlignment, + TextStyle, + Highlight.configure({ multicolor: true }), + ], + content: ` +

Table Node Demo

+

+ This demo shows the table functionality with all features enabled. +

+ + + + + + + + + + + + + + + + + + + + + + + + +
+

Name

+
+

Role

+
+

Department

+
+

Alice Johnson

+
+

Senior Developer

+
+

Engineering

+
+

Bob Smith

+
+

Product Manager

+
+

Product

+
+

Carol White

+
+

UX Designer

+
+

Design

+
+ +

+ You can click inside the table to see the selection overlay and resize handles. Use the extend buttons to add more rows or columns. +

+ `, + }) + + return ( + +
+
+ + + +
+
+ + + + + ( + props.onResizeStart?.('br')(e)} + /> + )} + /> + +
+ ) +} +``` + +## Extensions + +### `TableKit` + +A comprehensive table extension kit that bundles multiple table-related extensions together. + +## Table Manipulation Components + +Each component is available as both a React component and a composable hook: + +### Row/Column Manipulation Components + +#### `` / `useTableAddRowColumn()` + +Add rows or columns to the table at specific positions. + +**Props:** + +- `editor?: Editor | null` - Editor instance +- `index?: number` - Row/column index +- `orientation?: Orientation` - "row" or "column" +- `direction?: "before" | "after"` - Add before or after the index +- `tablePos?: number` - Position of the table in the document +- `hideWhenUnavailable?: boolean` - Hide when action unavailable +- `onAdded?: () => void` - Callback after successful addition + +**Usage:** + +```tsx +import { TableAddRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-add-row-column-button' + +function MyToolbar() { + return +} +``` + +#### `` / `useTableDeleteRowColumn()` + +Delete rows or columns from the table. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` +- `orientation?: Orientation` +- `tablePos?: number` +- `hideWhenUnavailable?: boolean` +- `onDeleted?: () => void` + +**Usage:** + +```tsx +import { TableDeleteRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-delete-row-column-button' + +function MyToolbar() { + return +} +``` + +#### `` / `useTableMoveRowColumn()` + +Move rows or columns up/down or left/right within the table. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` +- `orientation?: Orientation` +- `direction?: "up" | "down" | "left" | "right"` +- `tablePos?: number` +- `hideWhenUnavailable?: boolean` +- `onMoved?: () => void` + +**Usage:** + +```tsx +import { TableMoveRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-move-row-column-button' + +function MyToolbar() { + return +} +``` + +#### `` / `useTableDuplicateRowColumn()` + +Duplicate rows or columns, preserving content and formatting. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` +- `orientation?: Orientation` +- `tablePos?: number` +- `hideWhenUnavailable?: boolean` +- `onDuplicated?: () => void` + +**Usage:** + +```tsx +import { TableDuplicateRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-duplicate-row-column-button' + +function MyToolbar() { + return +} +``` + +#### `` / `useTableSortRowColumn()` + +Sort rows or columns alphabetically (A-Z or Z-A). Headers are automatically excluded from sorting and remain in their original positions. Empty cells are always sorted to the end. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` +- `orientation?: Orientation` +- `direction: "asc" | "desc"` - Sort direction +- `tablePos?: number` +- `hideWhenUnavailable?: boolean` +- `onSorted?: () => void` + +**Usage:** + +```tsx +import { TableSortRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-sort-row-column-button' + +function MyToolbar() { + return +} +``` + +### Cell Manipulation Components + +#### `` / `useTableMergeSplitCell()` + +Merge multiple selected cells or split a merged cell. + +**Props:** + +- `editor?: Editor | null` +- `action: "merge" | "split"` - Action to perform +- `hideWhenUnavailable?: boolean` +- `onExecuted?: (action: "merge" | "split") => void` + +**Usage:** + +```tsx +import { TableMergeSplitCellButton } from '@/registry/tiptap-node/table-node/ui/table-merge-split-cell-button' + +function MyToolbar() { + return ( + <> + + + + ) +} +``` + +#### `` / `useTableAlignCell()` + +Align cell content (text alignment and vertical alignment). + +**Props:** + +- `editor?: Editor | null` +- `alignment: string` - Alignment value (e.g., "left", "center", "right", "top", "middle", "bottom") +- `type: "textAlign" | "verticalAlign"` - Alignment type +- `hideWhenUnavailable?: boolean` +- `onAligned?: () => void` + +**Usage:** + +```tsx +import { TableAlignCellButton } from '@/registry/tiptap-node/table-node/ui/table-align-cell-button' + +function MyToolbar() { + return ( + <> + + + + ) +} +``` + +#### `` / `useTableClearRowColumnContent()` + +Clear content from cells in a row, column, or selection. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` +- `orientation?: Orientation` +- `tablePos?: number` +- `resetAttrs?: boolean` - Also reset cell attributes (colors, alignment, etc.) +- `hideWhenUnavailable?: boolean` +- `onCleared?: () => void` + +**Usage:** + +```tsx +import { TableClearRowColumnContentButton } from '@/registry/tiptap-node/table-node/ui/table-clear-row-column-content-button' + +function MyToolbar() { + return +} +``` + +### Header and Layout Components + +#### `` / `useTableHeaderRowColumn()` + +Toggle the first row or column as a header. + +**Props:** + +- `editor?: Editor | null` +- `index?: number` - Should be 0 for first row/column +- `orientation?: Orientation` +- `tablePos?: number` +- `hideWhenUnavailable?: boolean` +- `onToggled?: () => void` + +**Usage:** + +```tsx +import { TableHeaderRowColumnButton } from '@/registry/tiptap-node/table-node/ui/table-header-row-column-button' + +function MyToolbar() { + return +} +``` + +#### `` / `useTableFitToWidth()` + +Automatically adjust table column widths to fit the editor's container width. + +**Props:** + +- `editor?: Editor | null` +- `hideWhenUnavailable?: boolean` +- `onWidthAdjusted?: () => void` + +**Usage:** + +```tsx +import { TableFitToWidthButton } from '@/registry/tiptap-node/table-node/ui/table-fit-to-width-button' + +function MyToolbar() { + return +} +``` + +### Menu Components + +#### `` + +Menu component providing alignment options for table cells. + +**Props:** + +- `index?: number` +- `orientation?: Orientation` + +**Usage:** + +```tsx +import { TableAlignmentMenu } from '@/registry/tiptap-node/table-node/ui/table-alignment-menu' + +function MyToolbar() { + return +} +``` + +### Using Hooks Directly + +All button components have corresponding hooks that can be used to build custom UI: + +```tsx +import { useTableDeleteRowColumn } from '@/registry/tiptap-node/table-node/ui/table-delete-row-column-button' + +function CustomDeleteButton() { + const { isVisible, canDeleteRowColumn, handleDelete, label, Icon } = useTableDeleteRowColumn({ + orientation: 'row', + hideWhenUnavailable: true, + }) + + if (!isVisible) return null + + return ( + + ) +} +``` + +Each hook returns: + +- `isVisible: boolean` - Whether the action should be shown +- `can[Action]: boolean` - Whether the action can be performed +- `handle[Action]: () => boolean` - Execute the action +- `label: string` - UI label for the action +- `Icon: ComponentType` - Icon component for the action + +## Styling + +The table node requires two stylesheets: + +```tsx +import '@/registry/tiptap-node/table-node/styles/prosemirror-table.scss' +import '@/registry/tiptap-node/table-node/styles/table-node.scss' +``` + +### CSS Variables + +The table node uses CSS variables for theming: + +```css +:root { + --tt-table-border-color: var(--tt-gray-light-a-300); + --tt-table-selected-bg: rgba(195, 189, 255, 0.4); + --tt-table-selected-stroke: var(--tt-brand-color-400); + --tt-table-column-resize-handle-bg: var(--tt-brand-color-400); + --tt-table-cell-padding: 0.5rem; + --tt-table-margin-block: 1.25rem; + --tt-table-pad-block-start: 1rem; + --tt-table-pad-block-end: 1.5rem; + --tt-table-pad-inline-start: 1rem; + --tt-table-pad-inline-end: 1.5rem; + --tt-table-handle-bg-color: var(--tt-gray-light-a-100); + --tt-table-extend-icon-color: var(--tt-gray-light-a-400); +} +``` + +Dark mode variants are automatically applied when using the `.dark` class. + +## Dependencies + +### Required Packages + +- `@tiptap/extension-table` - Core table extensions (Table, TableRow, TableCell, TableHeader) +- `@tiptap/pm/tables` - ProseMirror table utilities +- `@tiptap/pm/state` - ProseMirror state management +- `@tiptap/pm/view` - ProseMirror view utilities +- `@tiptap/react` - React integration +- `@floating-ui/react` - Floating UI for positioning +- `sass` / `sass-embedded` - For SCSS compilation + +### Required Extensions + +- `table-handle-extension` - Table handle extension for row/column manipulation context + +### Referenced Components + +The table-node component internally uses: + +- `use-tiptap-editor` (hook) +- `tiptap-utils` (lib) +- `tiptap-table-utils` (lib) +- Various table manipulation components and utilities + +## Features + +- ✅ **Table Creation**: Visual grid selector for quick table insertion +- ✅ **Row/Column Manipulation**: Add, delete, move, and duplicate rows/columns +- ✅ **Drag-and-Drop**: Reorder rows and columns by dragging handles +- ✅ **Cell Operations**: Merge, split, and clear cell content +- ✅ **Alignment Controls**: Text and vertical alignment for cells +- ✅ **Column Resizing**: Interactive column width adjustment +- ✅ **Selection Overlay**: Visual feedback for selected cells +- ✅ **Keyboard Shortcuts**: Efficient keyboard navigation +- ✅ **Responsive Design**: Works on desktop and mobile devices +- ✅ **Dark Mode Support**: Built-in dark mode theming +- ✅ **Accessibility**: ARIA labels and keyboard navigation + +## Related Extensions + +- **Node Alignment Extension** - Required for cell alignment support +- **UniqueID Extension** - Optional, used in the example template for giving tables unique IDs (also used for other block-level nodes) +- **Color Extension** - For cell background colors +- **TextStyle Extension** - For text styling within cells diff --git a/src/content/ui-components/sidebar.ts b/src/content/ui-components/sidebar.ts index c8cf2b4b..9b00dfed 100644 --- a/src/content/ui-components/sidebar.ts +++ b/src/content/ui-components/sidebar.ts @@ -281,6 +281,10 @@ export const sidebarConfig: SidebarConfig = { title: 'Paragraph node', href: '/ui-components/node-components/paragraph-node', }, + { + title: 'Table node', + href: '/ui-components/node-components/table-node', + }, ], }, {