@prosekit/extensions 0.11.5 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drop-indicator-E7nCfdnR.js +58 -0
- package/dist/drop-indicator-E7nCfdnR.js.map +1 -0
- package/dist/file-DVUhe5KJ.js +134 -0
- package/dist/file-DVUhe5KJ.js.map +1 -0
- package/dist/index-DY6lIIYV.d.ts +134 -0
- package/dist/index-DY6lIIYV.d.ts.map +1 -0
- package/dist/{mark-rule-BCqIZMDu.js → mark-rule-CGmswjQ_.js} +1 -1
- package/dist/{mark-rule-BCqIZMDu.js.map → mark-rule-CGmswjQ_.js.map} +1 -1
- package/dist/{paste-rule-DIEJKIje.js → paste-rule-BIztzELg.js} +1 -1
- package/dist/{paste-rule-DIEJKIje.js.map → paste-rule-BIztzELg.js.map} +1 -1
- package/dist/prosekit-extensions-code-block.d.ts +1 -1
- package/dist/prosekit-extensions-drop-indicator.d.ts +3 -106
- package/dist/prosekit-extensions-drop-indicator.d.ts.map +1 -1
- package/dist/prosekit-extensions-drop-indicator.js +1 -1
- package/dist/prosekit-extensions-file.d.ts +2 -126
- package/dist/prosekit-extensions-file.js +2 -128
- package/dist/prosekit-extensions-hard-break.d.ts +0 -4
- package/dist/prosekit-extensions-hard-break.d.ts.map +1 -1
- package/dist/prosekit-extensions-image.d.ts +79 -3
- package/dist/prosekit-extensions-image.d.ts.map +1 -1
- package/dist/prosekit-extensions-image.js +88 -8
- package/dist/prosekit-extensions-image.js.map +1 -1
- package/dist/prosekit-extensions-link.js +2 -2
- package/dist/prosekit-extensions-list.js +2 -2
- package/dist/prosekit-extensions-mark-rule.js +1 -1
- package/dist/prosekit-extensions-paragraph.d.ts +0 -4
- package/dist/prosekit-extensions-paragraph.d.ts.map +1 -1
- package/dist/prosekit-extensions-paste-rule.js +1 -1
- package/dist/prosekit-extensions-placeholder.js +2 -2
- package/dist/prosekit-extensions-table.js +2 -2
- package/dist/prosekit-extensions.d.ts +1 -1
- package/dist/{shiki-highlighter-chunk-DSPM0T27.d.ts → shiki-highlighter-chunk-Cwu1Jr9o.d.ts} +1 -1
- package/dist/{shiki-highlighter-chunk-DSPM0T27.d.ts.map → shiki-highlighter-chunk-Cwu1Jr9o.d.ts.map} +1 -1
- package/dist/shiki-highlighter-chunk.d.ts +1 -1
- package/dist/{table-Bi7WsMI3.js → table-BNwuK7xg.js} +2 -2
- package/dist/{table-Bi7WsMI3.js.map → table-BNwuK7xg.js.map} +1 -1
- package/package.json +7 -6
- package/src/drop-indicator/drop-indicator-facet.ts +6 -28
- package/src/drop-indicator/drop-indicator.ts +3 -5
- package/src/drop-indicator/index.ts +6 -6
- package/src/file/file-upload.ts +29 -8
- package/src/image/image-commands.ts +12 -3
- package/src/image/image-upload-handler.ts +156 -0
- package/src/image/index.ts +9 -0
- package/dist/drop-indicator-D1eHOhSi.js +0 -267
- package/dist/drop-indicator-D1eHOhSi.js.map +0 -1
- package/dist/prosekit-extensions-file.d.ts.map +0 -1
- package/dist/prosekit-extensions-file.js.map +0 -1
- package/src/drop-indicator/drop-indicator-plugin.ts +0 -147
- package/src/drop-indicator/drop-target.ts +0 -168
- package/src/drop-indicator/types.ts +0 -90
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-Bi7WsMI3.js","names":["exitTable: Command","onDrag: DragEventHandler","match: boolean"],"sources":["../src/table/table-commands/exit-table.ts","../src/table/table-commands/insert-table.ts","../src/table/table-utils.ts","../src/table/table-commands/select-table.ts","../src/table/table-commands/select-table-cell.ts","../src/table/table-commands/select-table-column.ts","../src/table/table-commands/select-table-row.ts","../src/table/table-commands.ts","../src/table/table-drop-indicator.ts","../src/table/table-plugins.ts","../src/table/table-spec.ts","../src/table/table.ts"],"sourcesContent":["import { defaultBlockAt } from '@prosekit/core'\nimport { TextSelection } from '@prosekit/pm/state'\nimport type { Command } from '@prosekit/pm/state'\nimport type { TableRole } from 'prosemirror-tables'\n\n/**\n * When the selection is in a table node, create a default block after the table\n * table, and move the cursor there.\n *\n * @public\n */\nexport const exitTable: Command = (state, dispatch) => {\n const { $head, $anchor } = state.selection\n\n if (!$head.sameParent($anchor)) {\n return false\n }\n\n let tableStart = -1\n let tableDepth = -1\n for (let depth = $head.depth; depth >= 0; depth--) {\n const node = $head.node(depth)\n if ((node.type.spec.tableRole as TableRole) === 'table') {\n tableStart = $head.before(depth)\n tableDepth = depth\n }\n }\n\n if (tableStart < 0 || tableDepth <= 0) {\n return false\n }\n\n const above = $head.node(tableDepth - 1)\n const after = $head.indexAfter(tableDepth - 1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n const node = type?.createAndFill()\n\n if (!type || !node || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n if (dispatch) {\n const pos = $head.after(tableDepth)\n const tr = state.tr.replaceWith(pos, pos, node)\n tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1))\n dispatch(tr.scrollIntoView())\n }\n return true\n}\n","import {\n getNodeType,\n insertNode,\n} from '@prosekit/core'\nimport type { Schema } from '@prosekit/pm/model'\nimport type { Command } from '@prosekit/pm/state'\n\nfunction createEmptyTable(\n schema: Schema,\n row: number,\n col: number,\n header: boolean,\n) {\n const tableType = getNodeType(schema, 'table')\n const tableRowType = getNodeType(schema, 'tableRow')\n const tableCellType = getNodeType(schema, 'tableCell')\n const tableHeaderCellType = getNodeType(schema, 'tableHeaderCell')\n\n if (header) {\n const headerCell = tableHeaderCellType.createAndFill()!\n const headerCells = repeat(headerCell, col)\n const headerRow = tableRowType.createAndFill(null, headerCells)!\n\n const bodyCell = tableCellType.createAndFill()!\n const bodyCells = repeat(bodyCell, col)\n const bodyRow = tableRowType.createAndFill(null, bodyCells)!\n const bodyRows = repeat(bodyRow, row - 1)\n\n return tableType.createAndFill(null, [headerRow, ...bodyRows])!\n } else {\n const bodyCell = tableCellType.createAndFill()!\n const bodyCells = repeat(bodyCell, col)\n const bodyRow = tableRowType.createAndFill(null, bodyCells)!\n const bodyRows = repeat(bodyRow, row)\n\n return tableType.createAndFill(null, bodyRows)!\n }\n}\n\nfunction repeat<T>(node: T, length: number): T[] {\n return Array<T>(length).fill(node)\n}\n\n/**\n * @public\n */\nexport interface InsertTableOptions {\n /**\n * The number of rows in the table.\n */\n row: number\n\n /**\n * The number of columns in the table.\n */\n col: number\n\n /**\n * Whether the table has a header row.\n *\n * @default false\n */\n header?: boolean\n}\n\n/**\n * Insert a table node with the given number of rows and columns, and optionally\n * a header row.\n *\n * @param options\n *\n * @public\n */\nexport function insertTable(options: InsertTableOptions): Command {\n return (state, dispatch, view) => {\n const { row, col, header = false } = options\n const table = createEmptyTable(state.schema, row, col, header)\n return insertNode({ node: table })(state, dispatch, view)\n }\n}\n","import { CellSelection } from 'prosemirror-tables'\n\nexport {\n findCellPos,\n findCellRange,\n findTable,\n} from 'prosemirror-tables'\n\n/**\n * Checks if the given object is a `CellSelection` instance.\n *\n * @public\n */\nexport function isCellSelection(value: unknown): value is CellSelection {\n return value instanceof CellSelection\n}\n","import type { Command } from '@prosekit/pm/state'\nimport {\n CellSelection,\n TableMap,\n} from 'prosemirror-tables'\n\nimport { findTable } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableOptions {\n /**\n * A hit position of the table to select from. By default, the selection\n * anchor will be used.\n */\n pos?: number\n}\n\n/**\n * @public\n */\nexport function selectTable(options?: SelectTableOptions): Command {\n return (state, dispatch) => {\n const $pos = options?.pos\n ? state.doc.resolve(options.pos)\n : state.selection.$anchor\n const table = findTable($pos)\n if (!table) {\n return false\n }\n const map = TableMap.get(table.node)\n if (map.map.length === 0) {\n return false\n }\n if (dispatch) {\n let tr = state.tr\n const firstCellPosInTable = map.map[0]\n const lastCellPosInTable = map.map[map.map.length - 1]\n const firstCellPos = table.pos + firstCellPosInTable + 1\n const lastCellPos = table.pos + lastCellPosInTable + 1\n const $firstCellPos = tr.doc.resolve(firstCellPos)\n const $lastCellPos = tr.doc.resolve(lastCellPos)\n const selection = new CellSelection($firstCellPos, $lastCellPos)\n tr = tr.setSelection(selection)\n dispatch?.(tr)\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellPos } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableCellOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n pos?: number\n}\n\n/**\n * @public\n */\nexport function selectTableCell(options?: SelectTableCellOptions): Command {\n return (state, dispatch) => {\n const $cellPos = findCellPos(\n state.doc,\n options?.pos ?? state.selection.anchor,\n )\n if (!$cellPos) {\n return false\n }\n if (dispatch) {\n const selection = new CellSelection($cellPos)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellRange } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableColumnOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n anchor?: number\n\n /**\n * A hit position of the table cell to select to. By default, the selection\n * head will be used.\n */\n head?: number\n}\n\n/**\n * @public\n */\nexport function selectTableColumn(options?: SelectTableColumnOptions): Command {\n return (state, dispatch) => {\n const range = findCellRange(state.selection, options?.anchor, options?.head)\n if (!range) {\n return false\n }\n if (dispatch) {\n const [$anchorCell, $headCell] = range\n const selection = CellSelection.colSelection($anchorCell, $headCell)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellRange } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableRowOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n anchor?: number\n\n /**\n * A hit position of the table cell to select to. By default, the selection\n * head will be used.\n */\n head?: number\n}\n\n/**\n * @public\n */\nexport function selectTableRow(options?: SelectTableRowOptions): Command {\n return (state, dispatch) => {\n const range = findCellRange(state.selection, options?.anchor, options?.head)\n if (!range) {\n return false\n }\n if (dispatch) {\n const [$anchorCell, $headCell] = range\n const selection = CellSelection.rowSelection($anchorCell, $headCell)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import {\n defineCommands,\n type Extension,\n} from '@prosekit/core'\nimport {\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n deleteColumn,\n deleteRow,\n deleteTable,\n mergeCells,\n splitCell,\n} from 'prosemirror-tables'\n\nimport { deleteCellSelection } from './table-commands/delete-cell-selection'\nimport { exitTable } from './table-commands/exit-table'\nimport {\n insertTable,\n type InsertTableOptions,\n} from './table-commands/insert-table'\nimport {\n moveTableColumn,\n type MoveTableColumnOptions,\n} from './table-commands/move-table-column'\nimport {\n moveTableRow,\n type MoveTableRowOptions,\n} from './table-commands/move-table-row'\nimport {\n selectTable,\n type SelectTableOptions,\n} from './table-commands/select-table'\nimport {\n selectTableCell,\n type SelectTableCellOptions,\n} from './table-commands/select-table-cell'\nimport {\n selectTableColumn,\n type SelectTableColumnOptions,\n} from './table-commands/select-table-column'\nimport {\n selectTableRow,\n type SelectTableRowOptions,\n} from './table-commands/select-table-row'\n\n/**\n * @internal\n */\nexport type TableCommandsExtension = Extension<{\n Commands: {\n insertTable: [options: InsertTableOptions]\n exitTable: []\n\n selectTable: [options?: SelectTableOptions]\n selectTableCell: [options?: SelectTableCellOptions]\n selectTableColumn: [options?: SelectTableColumnOptions]\n selectTableRow: [options?: SelectTableRowOptions]\n\n addTableColumnBefore: []\n addTableColumnAfter: []\n addTableRowAbove: []\n addTableRowBelow: []\n\n deleteTable: []\n deleteTableColumn: []\n deleteTableRow: []\n deleteCellSelection: []\n\n mergeTableCells: []\n splitTableCell: []\n\n moveTableRow: [options: MoveTableRowOptions]\n moveTableColumn: [options: MoveTableColumnOptions]\n }\n}>\n\n/**\n * Adds commands for working with `table` nodes.\n *\n * @public\n */\nexport function defineTableCommands(): TableCommandsExtension {\n return defineCommands({\n insertTable,\n exitTable: () => exitTable,\n\n selectTable,\n selectTableCell,\n selectTableColumn,\n selectTableRow,\n\n addTableColumnBefore: () => addColumnBefore,\n addTableColumnAfter: () => addColumnAfter,\n addTableRowAbove: () => addRowBefore,\n addTableRowBelow: () => addRowAfter,\n\n deleteTable: () => deleteTable,\n deleteTableColumn: () => deleteColumn,\n deleteTableRow: () => deleteRow,\n deleteCellSelection: () => deleteCellSelection,\n\n mergeTableCells: () => mergeCells,\n splitTableCell: () => splitCell,\n\n moveTableRow,\n moveTableColumn,\n })\n}\n","import type { PlainExtension } from '@prosekit/core'\n\nimport type { DragEventHandler } from '../drop-indicator'\nimport { defineDropIndicator } from '../drop-indicator'\n\n/**\n * Hides the drop indicator when dragging a table column or row by using the\n * table handle.\n *\n * @internal\n */\nexport function defineTableDropIndicator(): PlainExtension {\n return defineDropIndicator({\n onDrag,\n })\n}\n\nconst matchMap = new WeakMap<DataTransfer, boolean>()\n\nconst onDrag: DragEventHandler = ({ event }): boolean => {\n const dataTransfer = event.dataTransfer\n if (!dataTransfer) return true\n\n let match: boolean\n\n if (matchMap.has(dataTransfer)) {\n match = matchMap.get(dataTransfer)!\n } else {\n // On Safari, accessing `dataTransfer.types` is more than 10x slower than in\n // Chrome. This becomes a bottleneck when `onDrag` is called frequently, so\n // we cache the result in a WeakMap.\n const types = dataTransfer.types\n match = types.includes('application/x-prosekit-table-handle-drag')\n matchMap.set(dataTransfer, match)\n }\n\n // Don't show the drop indicator when the drag event has\n // \"application/x-prosekit-table-handle-drag\" type.\n return !match\n}\n","import {\n definePlugin,\n type PlainExtension,\n} from '@prosekit/core'\nimport {\n columnResizing,\n tableEditing,\n} from 'prosemirror-tables'\n\n/**\n * @public\n */\nexport function defineTablePlugins(): PlainExtension {\n return definePlugin([tableEditing(), columnResizing()])\n}\n","import {\n defineNodeSpec,\n type Extension,\n} from '@prosekit/core'\nimport type {\n AttributeSpec,\n Attrs,\n} from '@prosekit/pm/model'\nimport { tableNodes } from 'prosemirror-tables'\n\nconst cellContent = 'block+'\n\n/**\n * @public\n */\nexport interface CellAttrs {\n colspan?: number\n rowspan?: number\n colwidth?: number[] | null\n}\n\nconst cellAttrs = {\n colspan: { default: 1 },\n rowspan: { default: 1 },\n colwidth: { default: null },\n} satisfies Record<string, AttributeSpec>\n\n/**\n * @internal\n */\nexport type TableSpecExtension = Extension<{\n Nodes: {\n table: Attrs\n }\n}>\n\nconst specs = tableNodes({\n tableGroup: 'block',\n cellContent,\n cellAttributes: {},\n})\n\n/**\n * @internal\n */\nexport function defineTableSpec(): TableSpecExtension {\n return defineNodeSpec({\n ...specs['table'],\n content: 'tableRow+',\n name: 'table',\n })\n}\n\n/**\n * @internal\n */\nexport type TableRowSpecExtension = Extension<{\n Nodes: {\n tableRow: Attrs\n }\n}>\n\n/**\n * @internal\n */\nexport function defineTableRowSpec(): TableRowSpecExtension {\n return defineNodeSpec({\n ...specs['table_row'],\n content: '(tableCell | tableHeaderCell)*',\n name: 'tableRow',\n })\n}\n\n/**\n * @internal\n */\nexport type TableCellSpecExtension = Extension<{\n Nodes: {\n tableCell: CellAttrs\n }\n}>\n\n/**\n * @internal\n */\nexport function defineTableCellSpec(): TableCellSpecExtension {\n return defineNodeSpec({\n ...specs['table_cell'],\n name: 'tableCell',\n attrs: cellAttrs,\n })\n}\n\n/**\n * @internal\n */\nexport type TableHeaderCellSpecExtension = Extension<{\n Nodes: {\n tableHeaderCell: CellAttrs\n }\n}>\n\nexport function defineTableHeaderCellSpec(): TableHeaderCellSpecExtension {\n return defineNodeSpec({\n ...specs['table_header'],\n name: 'tableHeaderCell',\n attrs: cellAttrs,\n })\n}\n","import {\n union,\n type Union,\n} from '@prosekit/core'\n\nimport {\n defineTableCommands,\n type TableCommandsExtension,\n} from './table-commands'\nimport { defineTableDropIndicator } from './table-drop-indicator'\nimport { defineTablePlugins } from './table-plugins'\nimport {\n defineTableCellSpec,\n defineTableHeaderCellSpec,\n defineTableRowSpec,\n defineTableSpec,\n type TableCellSpecExtension,\n type TableHeaderCellSpecExtension,\n type TableRowSpecExtension,\n type TableSpecExtension,\n} from './table-spec'\n\n/**\n * @internal\n */\nexport type TableExtension = Union<\n [\n TableSpecExtension,\n TableRowSpecExtension,\n TableCellSpecExtension,\n TableHeaderCellSpecExtension,\n TableCommandsExtension,\n ]\n>\n\n/**\n * @public\n */\nexport function defineTable(): TableExtension {\n return union(\n defineTableSpec(),\n defineTableRowSpec(),\n defineTableCellSpec(),\n defineTableHeaderCellSpec(),\n defineTablePlugins(),\n defineTableCommands(),\n defineTableDropIndicator(),\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-BNwuK7xg.js","names":["exitTable: Command","onDrag: DragEventHandler","match: boolean"],"sources":["../src/table/table-commands/exit-table.ts","../src/table/table-commands/insert-table.ts","../src/table/table-utils.ts","../src/table/table-commands/select-table.ts","../src/table/table-commands/select-table-cell.ts","../src/table/table-commands/select-table-column.ts","../src/table/table-commands/select-table-row.ts","../src/table/table-commands.ts","../src/table/table-drop-indicator.ts","../src/table/table-plugins.ts","../src/table/table-spec.ts","../src/table/table.ts"],"sourcesContent":["import { defaultBlockAt } from '@prosekit/core'\nimport { TextSelection } from '@prosekit/pm/state'\nimport type { Command } from '@prosekit/pm/state'\nimport type { TableRole } from 'prosemirror-tables'\n\n/**\n * When the selection is in a table node, create a default block after the table\n * table, and move the cursor there.\n *\n * @public\n */\nexport const exitTable: Command = (state, dispatch) => {\n const { $head, $anchor } = state.selection\n\n if (!$head.sameParent($anchor)) {\n return false\n }\n\n let tableStart = -1\n let tableDepth = -1\n for (let depth = $head.depth; depth >= 0; depth--) {\n const node = $head.node(depth)\n if ((node.type.spec.tableRole as TableRole) === 'table') {\n tableStart = $head.before(depth)\n tableDepth = depth\n }\n }\n\n if (tableStart < 0 || tableDepth <= 0) {\n return false\n }\n\n const above = $head.node(tableDepth - 1)\n const after = $head.indexAfter(tableDepth - 1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n const node = type?.createAndFill()\n\n if (!type || !node || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n if (dispatch) {\n const pos = $head.after(tableDepth)\n const tr = state.tr.replaceWith(pos, pos, node)\n tr.setSelection(TextSelection.near(tr.doc.resolve(pos), 1))\n dispatch(tr.scrollIntoView())\n }\n return true\n}\n","import {\n getNodeType,\n insertNode,\n} from '@prosekit/core'\nimport type { Schema } from '@prosekit/pm/model'\nimport type { Command } from '@prosekit/pm/state'\n\nfunction createEmptyTable(\n schema: Schema,\n row: number,\n col: number,\n header: boolean,\n) {\n const tableType = getNodeType(schema, 'table')\n const tableRowType = getNodeType(schema, 'tableRow')\n const tableCellType = getNodeType(schema, 'tableCell')\n const tableHeaderCellType = getNodeType(schema, 'tableHeaderCell')\n\n if (header) {\n const headerCell = tableHeaderCellType.createAndFill()!\n const headerCells = repeat(headerCell, col)\n const headerRow = tableRowType.createAndFill(null, headerCells)!\n\n const bodyCell = tableCellType.createAndFill()!\n const bodyCells = repeat(bodyCell, col)\n const bodyRow = tableRowType.createAndFill(null, bodyCells)!\n const bodyRows = repeat(bodyRow, row - 1)\n\n return tableType.createAndFill(null, [headerRow, ...bodyRows])!\n } else {\n const bodyCell = tableCellType.createAndFill()!\n const bodyCells = repeat(bodyCell, col)\n const bodyRow = tableRowType.createAndFill(null, bodyCells)!\n const bodyRows = repeat(bodyRow, row)\n\n return tableType.createAndFill(null, bodyRows)!\n }\n}\n\nfunction repeat<T>(node: T, length: number): T[] {\n return Array<T>(length).fill(node)\n}\n\n/**\n * @public\n */\nexport interface InsertTableOptions {\n /**\n * The number of rows in the table.\n */\n row: number\n\n /**\n * The number of columns in the table.\n */\n col: number\n\n /**\n * Whether the table has a header row.\n *\n * @default false\n */\n header?: boolean\n}\n\n/**\n * Insert a table node with the given number of rows and columns, and optionally\n * a header row.\n *\n * @param options\n *\n * @public\n */\nexport function insertTable(options: InsertTableOptions): Command {\n return (state, dispatch, view) => {\n const { row, col, header = false } = options\n const table = createEmptyTable(state.schema, row, col, header)\n return insertNode({ node: table })(state, dispatch, view)\n }\n}\n","import { CellSelection } from 'prosemirror-tables'\n\nexport {\n findCellPos,\n findCellRange,\n findTable,\n} from 'prosemirror-tables'\n\n/**\n * Checks if the given object is a `CellSelection` instance.\n *\n * @public\n */\nexport function isCellSelection(value: unknown): value is CellSelection {\n return value instanceof CellSelection\n}\n","import type { Command } from '@prosekit/pm/state'\nimport {\n CellSelection,\n TableMap,\n} from 'prosemirror-tables'\n\nimport { findTable } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableOptions {\n /**\n * A hit position of the table to select from. By default, the selection\n * anchor will be used.\n */\n pos?: number\n}\n\n/**\n * @public\n */\nexport function selectTable(options?: SelectTableOptions): Command {\n return (state, dispatch) => {\n const $pos = options?.pos\n ? state.doc.resolve(options.pos)\n : state.selection.$anchor\n const table = findTable($pos)\n if (!table) {\n return false\n }\n const map = TableMap.get(table.node)\n if (map.map.length === 0) {\n return false\n }\n if (dispatch) {\n let tr = state.tr\n const firstCellPosInTable = map.map[0]\n const lastCellPosInTable = map.map[map.map.length - 1]\n const firstCellPos = table.pos + firstCellPosInTable + 1\n const lastCellPos = table.pos + lastCellPosInTable + 1\n const $firstCellPos = tr.doc.resolve(firstCellPos)\n const $lastCellPos = tr.doc.resolve(lastCellPos)\n const selection = new CellSelection($firstCellPos, $lastCellPos)\n tr = tr.setSelection(selection)\n dispatch?.(tr)\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellPos } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableCellOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n pos?: number\n}\n\n/**\n * @public\n */\nexport function selectTableCell(options?: SelectTableCellOptions): Command {\n return (state, dispatch) => {\n const $cellPos = findCellPos(\n state.doc,\n options?.pos ?? state.selection.anchor,\n )\n if (!$cellPos) {\n return false\n }\n if (dispatch) {\n const selection = new CellSelection($cellPos)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellRange } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableColumnOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n anchor?: number\n\n /**\n * A hit position of the table cell to select to. By default, the selection\n * head will be used.\n */\n head?: number\n}\n\n/**\n * @public\n */\nexport function selectTableColumn(options?: SelectTableColumnOptions): Command {\n return (state, dispatch) => {\n const range = findCellRange(state.selection, options?.anchor, options?.head)\n if (!range) {\n return false\n }\n if (dispatch) {\n const [$anchorCell, $headCell] = range\n const selection = CellSelection.colSelection($anchorCell, $headCell)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import type { Command } from '@prosekit/pm/state'\nimport { CellSelection } from 'prosemirror-tables'\n\nimport { findCellRange } from '../table-utils'\n\n/**\n * @public\n */\nexport interface SelectTableRowOptions {\n /**\n * A hit position of the table cell to select from. By default, the selection\n * anchor will be used.\n */\n anchor?: number\n\n /**\n * A hit position of the table cell to select to. By default, the selection\n * head will be used.\n */\n head?: number\n}\n\n/**\n * @public\n */\nexport function selectTableRow(options?: SelectTableRowOptions): Command {\n return (state, dispatch) => {\n const range = findCellRange(state.selection, options?.anchor, options?.head)\n if (!range) {\n return false\n }\n if (dispatch) {\n const [$anchorCell, $headCell] = range\n const selection = CellSelection.rowSelection($anchorCell, $headCell)\n dispatch(state.tr.setSelection(selection))\n }\n return true\n }\n}\n","import {\n defineCommands,\n type Extension,\n} from '@prosekit/core'\nimport {\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n deleteColumn,\n deleteRow,\n deleteTable,\n mergeCells,\n splitCell,\n} from 'prosemirror-tables'\n\nimport { deleteCellSelection } from './table-commands/delete-cell-selection'\nimport { exitTable } from './table-commands/exit-table'\nimport {\n insertTable,\n type InsertTableOptions,\n} from './table-commands/insert-table'\nimport {\n moveTableColumn,\n type MoveTableColumnOptions,\n} from './table-commands/move-table-column'\nimport {\n moveTableRow,\n type MoveTableRowOptions,\n} from './table-commands/move-table-row'\nimport {\n selectTable,\n type SelectTableOptions,\n} from './table-commands/select-table'\nimport {\n selectTableCell,\n type SelectTableCellOptions,\n} from './table-commands/select-table-cell'\nimport {\n selectTableColumn,\n type SelectTableColumnOptions,\n} from './table-commands/select-table-column'\nimport {\n selectTableRow,\n type SelectTableRowOptions,\n} from './table-commands/select-table-row'\n\n/**\n * @internal\n */\nexport type TableCommandsExtension = Extension<{\n Commands: {\n insertTable: [options: InsertTableOptions]\n exitTable: []\n\n selectTable: [options?: SelectTableOptions]\n selectTableCell: [options?: SelectTableCellOptions]\n selectTableColumn: [options?: SelectTableColumnOptions]\n selectTableRow: [options?: SelectTableRowOptions]\n\n addTableColumnBefore: []\n addTableColumnAfter: []\n addTableRowAbove: []\n addTableRowBelow: []\n\n deleteTable: []\n deleteTableColumn: []\n deleteTableRow: []\n deleteCellSelection: []\n\n mergeTableCells: []\n splitTableCell: []\n\n moveTableRow: [options: MoveTableRowOptions]\n moveTableColumn: [options: MoveTableColumnOptions]\n }\n}>\n\n/**\n * Adds commands for working with `table` nodes.\n *\n * @public\n */\nexport function defineTableCommands(): TableCommandsExtension {\n return defineCommands({\n insertTable,\n exitTable: () => exitTable,\n\n selectTable,\n selectTableCell,\n selectTableColumn,\n selectTableRow,\n\n addTableColumnBefore: () => addColumnBefore,\n addTableColumnAfter: () => addColumnAfter,\n addTableRowAbove: () => addRowBefore,\n addTableRowBelow: () => addRowAfter,\n\n deleteTable: () => deleteTable,\n deleteTableColumn: () => deleteColumn,\n deleteTableRow: () => deleteRow,\n deleteCellSelection: () => deleteCellSelection,\n\n mergeTableCells: () => mergeCells,\n splitTableCell: () => splitCell,\n\n moveTableRow,\n moveTableColumn,\n })\n}\n","import type { PlainExtension } from '@prosekit/core'\n\nimport type { DragEventHandler } from '../drop-indicator'\nimport { defineDropIndicator } from '../drop-indicator'\n\n/**\n * Hides the drop indicator when dragging a table column or row by using the\n * table handle.\n *\n * @internal\n */\nexport function defineTableDropIndicator(): PlainExtension {\n return defineDropIndicator({\n onDrag,\n })\n}\n\nconst matchMap = new WeakMap<DataTransfer, boolean>()\n\nconst onDrag: DragEventHandler = ({ event }): boolean => {\n const dataTransfer = event.dataTransfer\n if (!dataTransfer) return true\n\n let match: boolean\n\n if (matchMap.has(dataTransfer)) {\n match = matchMap.get(dataTransfer)!\n } else {\n // On Safari, accessing `dataTransfer.types` is more than 10x slower than in\n // Chrome. This becomes a bottleneck when `onDrag` is called frequently, so\n // we cache the result in a WeakMap.\n const types = dataTransfer.types\n match = types.includes('application/x-prosekit-table-handle-drag')\n matchMap.set(dataTransfer, match)\n }\n\n // Don't show the drop indicator when the drag event has\n // \"application/x-prosekit-table-handle-drag\" type.\n return !match\n}\n","import {\n definePlugin,\n type PlainExtension,\n} from '@prosekit/core'\nimport {\n columnResizing,\n tableEditing,\n} from 'prosemirror-tables'\n\n/**\n * @public\n */\nexport function defineTablePlugins(): PlainExtension {\n return definePlugin([tableEditing(), columnResizing()])\n}\n","import {\n defineNodeSpec,\n type Extension,\n} from '@prosekit/core'\nimport type {\n AttributeSpec,\n Attrs,\n} from '@prosekit/pm/model'\nimport { tableNodes } from 'prosemirror-tables'\n\nconst cellContent = 'block+'\n\n/**\n * @public\n */\nexport interface CellAttrs {\n colspan?: number\n rowspan?: number\n colwidth?: number[] | null\n}\n\nconst cellAttrs = {\n colspan: { default: 1 },\n rowspan: { default: 1 },\n colwidth: { default: null },\n} satisfies Record<string, AttributeSpec>\n\n/**\n * @internal\n */\nexport type TableSpecExtension = Extension<{\n Nodes: {\n table: Attrs\n }\n}>\n\nconst specs = tableNodes({\n tableGroup: 'block',\n cellContent,\n cellAttributes: {},\n})\n\n/**\n * @internal\n */\nexport function defineTableSpec(): TableSpecExtension {\n return defineNodeSpec({\n ...specs['table'],\n content: 'tableRow+',\n name: 'table',\n })\n}\n\n/**\n * @internal\n */\nexport type TableRowSpecExtension = Extension<{\n Nodes: {\n tableRow: Attrs\n }\n}>\n\n/**\n * @internal\n */\nexport function defineTableRowSpec(): TableRowSpecExtension {\n return defineNodeSpec({\n ...specs['table_row'],\n content: '(tableCell | tableHeaderCell)*',\n name: 'tableRow',\n })\n}\n\n/**\n * @internal\n */\nexport type TableCellSpecExtension = Extension<{\n Nodes: {\n tableCell: CellAttrs\n }\n}>\n\n/**\n * @internal\n */\nexport function defineTableCellSpec(): TableCellSpecExtension {\n return defineNodeSpec({\n ...specs['table_cell'],\n name: 'tableCell',\n attrs: cellAttrs,\n })\n}\n\n/**\n * @internal\n */\nexport type TableHeaderCellSpecExtension = Extension<{\n Nodes: {\n tableHeaderCell: CellAttrs\n }\n}>\n\nexport function defineTableHeaderCellSpec(): TableHeaderCellSpecExtension {\n return defineNodeSpec({\n ...specs['table_header'],\n name: 'tableHeaderCell',\n attrs: cellAttrs,\n })\n}\n","import {\n union,\n type Union,\n} from '@prosekit/core'\n\nimport {\n defineTableCommands,\n type TableCommandsExtension,\n} from './table-commands'\nimport { defineTableDropIndicator } from './table-drop-indicator'\nimport { defineTablePlugins } from './table-plugins'\nimport {\n defineTableCellSpec,\n defineTableHeaderCellSpec,\n defineTableRowSpec,\n defineTableSpec,\n type TableCellSpecExtension,\n type TableHeaderCellSpecExtension,\n type TableRowSpecExtension,\n type TableSpecExtension,\n} from './table-spec'\n\n/**\n * @internal\n */\nexport type TableExtension = Union<\n [\n TableSpecExtension,\n TableRowSpecExtension,\n TableCellSpecExtension,\n TableHeaderCellSpecExtension,\n TableCommandsExtension,\n ]\n>\n\n/**\n * @public\n */\nexport function defineTable(): TableExtension {\n return union(\n defineTableSpec(),\n defineTableRowSpec(),\n defineTableCellSpec(),\n defineTableHeaderCellSpec(),\n defineTablePlugins(),\n defineTableCommands(),\n defineTableDropIndicator(),\n )\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosekit/extensions",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.6",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "A collection of common extensions for ProseKit",
|
|
7
7
|
"author": {
|
|
@@ -215,9 +215,10 @@
|
|
|
215
215
|
"prosemirror-highlight": "^0.13.0",
|
|
216
216
|
"prosemirror-search": "^1.1.0",
|
|
217
217
|
"prosemirror-tables": "^1.8.1",
|
|
218
|
-
"shiki": "^3.
|
|
218
|
+
"shiki": "^3.13.0",
|
|
219
219
|
"@prosekit/core": "^0.8.4",
|
|
220
|
-
"@prosekit/pm": "^0.1.12"
|
|
220
|
+
"@prosekit/pm": "^0.1.12",
|
|
221
|
+
"prosemirror-drop-indicator": "^0.1.0"
|
|
221
222
|
},
|
|
222
223
|
"peerDependencies": {
|
|
223
224
|
"loro-crdt": ">= 0.16.7",
|
|
@@ -244,15 +245,15 @@
|
|
|
244
245
|
"@vitest/browser": "^3.2.4",
|
|
245
246
|
"diffable-html": "^6.0.1",
|
|
246
247
|
"just-pick": "^4.2.0",
|
|
247
|
-
"loro-crdt": "^1.
|
|
248
|
+
"loro-crdt": "^1.8.0",
|
|
248
249
|
"loro-prosemirror": "^0.3.1",
|
|
249
250
|
"rehype-parse": "^9.0.1",
|
|
250
251
|
"rehype-remark": "^10.0.1",
|
|
251
252
|
"remark-html": "^16.0.1",
|
|
252
253
|
"remark-parse": "^11.0.0",
|
|
253
254
|
"remark-stringify": "^11.0.0",
|
|
254
|
-
"tsdown": "^0.
|
|
255
|
-
"type-fest": "^
|
|
255
|
+
"tsdown": "^0.15.4",
|
|
256
|
+
"type-fest": "^5.0.1",
|
|
256
257
|
"typescript": "~5.9.2",
|
|
257
258
|
"unified": "^11.0.5",
|
|
258
259
|
"vitest": "^3.2.4",
|
|
@@ -5,48 +5,26 @@ import {
|
|
|
5
5
|
type PlainExtension,
|
|
6
6
|
type PluginPayload,
|
|
7
7
|
} from '@prosekit/core'
|
|
8
|
-
|
|
9
|
-
import { createDropIndicatorPlugin } from './drop-indicator-plugin'
|
|
10
8
|
import type {
|
|
11
9
|
DragEventHandler,
|
|
10
|
+
DropIndicatorPluginOptions,
|
|
12
11
|
ShowHandler,
|
|
13
|
-
} from '
|
|
12
|
+
} from 'prosemirror-drop-indicator'
|
|
13
|
+
import { createDropIndicatorPlugin } from 'prosemirror-drop-indicator'
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @internal
|
|
17
17
|
*/
|
|
18
18
|
export function defineDropIndicatorPayload(
|
|
19
|
-
payload:
|
|
19
|
+
payload: DropIndicatorPluginOptions,
|
|
20
20
|
): PlainExtension {
|
|
21
21
|
return defineFacetPayload(dropIndicatorFacet, [payload]) as PlainExtension
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
export interface DropIndicatorPayload {
|
|
28
|
-
/**
|
|
29
|
-
* A callback that is called when the drop indicator should be shown.
|
|
30
|
-
*/
|
|
31
|
-
onShow?: ShowHandler
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* A callback that is called when the drop indicator should be hidden.
|
|
35
|
-
*/
|
|
36
|
-
onHide?: VoidFunction
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* A callback that is called when the `dragover` event is fired. You can
|
|
40
|
-
* return `false` to disable the current drop point and thus hide the drop
|
|
41
|
-
* indicator.
|
|
42
|
-
*/
|
|
43
|
-
onDrag?: DragEventHandler
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const dropIndicatorFacet = defineFacet<DropIndicatorPayload, PluginPayload>({
|
|
24
|
+
const dropIndicatorFacet = defineFacet<DropIndicatorPluginOptions, PluginPayload>({
|
|
47
25
|
parent: pluginFacet,
|
|
48
26
|
singleton: true,
|
|
49
|
-
reducer: (payloads:
|
|
27
|
+
reducer: (payloads: DropIndicatorPluginOptions[]): PluginPayload => {
|
|
50
28
|
let showHandlers = payloads.map(p => p.onShow).filter(x => !!x)
|
|
51
29
|
let hideHandlers = payloads.map(p => p.onHide).filter(x => !!x)
|
|
52
30
|
let dragHandlers = payloads.map(p => p.onDrag).filter(x => !!x)
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { PlainExtension } from '@prosekit/core'
|
|
2
|
+
import type { DropIndicatorPluginOptions } from 'prosemirror-drop-indicator'
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
defineDropIndicatorPayload,
|
|
5
|
-
type DropIndicatorPayload,
|
|
6
|
-
} from './drop-indicator-facet'
|
|
4
|
+
import { defineDropIndicatorPayload } from './drop-indicator-facet'
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
7
|
* @internal
|
|
@@ -34,4 +32,4 @@ export function defineDropIndicator(
|
|
|
34
32
|
*
|
|
35
33
|
* @public
|
|
36
34
|
*/
|
|
37
|
-
export interface DropIndicatorOptions extends
|
|
35
|
+
export interface DropIndicatorOptions extends DropIndicatorPluginOptions {}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
defineDropIndicator,
|
|
3
|
-
type DropIndicatorExtension,
|
|
4
|
-
type DropIndicatorOptions,
|
|
5
|
-
} from './drop-indicator'
|
|
6
1
|
export type {
|
|
7
2
|
DragEventHandler,
|
|
8
3
|
DragEventHandlerOptions,
|
|
@@ -11,4 +6,9 @@ export type {
|
|
|
11
6
|
ShowHandler,
|
|
12
7
|
ShowHandlerOptions,
|
|
13
8
|
ViewDragging,
|
|
14
|
-
} from '
|
|
9
|
+
} from 'prosemirror-drop-indicator'
|
|
10
|
+
export {
|
|
11
|
+
defineDropIndicator,
|
|
12
|
+
type DropIndicatorExtension,
|
|
13
|
+
type DropIndicatorOptions,
|
|
14
|
+
} from './drop-indicator'
|
package/src/file/file-upload.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ProseKitError } from '@prosekit/core'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* An interface representing the upload progress.
|
|
3
5
|
*/
|
|
@@ -44,6 +46,16 @@ export class UploadTask<Result> {
|
|
|
44
46
|
*/
|
|
45
47
|
protected done = false
|
|
46
48
|
|
|
49
|
+
/**
|
|
50
|
+
* If the upload is complete successfully, this will be the result of the upload.
|
|
51
|
+
*/
|
|
52
|
+
protected result: Result | undefined
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* If the upload is complete with an error, this will be the error that occurred.
|
|
56
|
+
*/
|
|
57
|
+
protected error: Error | undefined
|
|
58
|
+
|
|
47
59
|
/**
|
|
48
60
|
* A promise that fulfills once the upload is complete, or rejects if an error occurs.
|
|
49
61
|
*/
|
|
@@ -63,8 +75,16 @@ export class UploadTask<Result> {
|
|
|
63
75
|
const maybePromise = uploader({
|
|
64
76
|
file,
|
|
65
77
|
onProgress: (progress) => {
|
|
66
|
-
|
|
67
|
-
|
|
78
|
+
if (typeof progress.total !== 'number') {
|
|
79
|
+
throw new TypeError('total must be a number')
|
|
80
|
+
}
|
|
81
|
+
if (typeof progress.loaded !== 'number') {
|
|
82
|
+
throw new TypeError('loaded must be a number')
|
|
83
|
+
}
|
|
84
|
+
if (progress.loaded > 0) {
|
|
85
|
+
for (const subscriber of this.subscribers) {
|
|
86
|
+
subscriber(progress)
|
|
87
|
+
}
|
|
68
88
|
}
|
|
69
89
|
},
|
|
70
90
|
})
|
|
@@ -72,13 +92,14 @@ export class UploadTask<Result> {
|
|
|
72
92
|
(result) => {
|
|
73
93
|
this.done = true
|
|
74
94
|
URL.revokeObjectURL(this.objectURL)
|
|
95
|
+
this.result = result
|
|
75
96
|
resolve(result)
|
|
76
97
|
},
|
|
77
|
-
(
|
|
98
|
+
(err) => {
|
|
78
99
|
this.done = true
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
100
|
+
const error = new ProseKitError('[prosekit] Failed to upload file', { cause: err })
|
|
101
|
+
this.error = error
|
|
102
|
+
reject(error)
|
|
82
103
|
},
|
|
83
104
|
)
|
|
84
105
|
})
|
|
@@ -100,7 +121,7 @@ export class UploadTask<Result> {
|
|
|
100
121
|
}
|
|
101
122
|
|
|
102
123
|
/**
|
|
103
|
-
* Finds an upload task by its object URL.
|
|
124
|
+
* Finds an upload task from the global store by its object URL.
|
|
104
125
|
*/
|
|
105
126
|
static get<Result = unknown>(
|
|
106
127
|
objectURL: string,
|
|
@@ -109,7 +130,7 @@ export class UploadTask<Result> {
|
|
|
109
130
|
}
|
|
110
131
|
|
|
111
132
|
/**
|
|
112
|
-
* Deletes an upload task by its object URL.
|
|
133
|
+
* Deletes an upload task from the global store by its object URL.
|
|
113
134
|
*/
|
|
114
135
|
static delete(objectURL: string): void {
|
|
115
136
|
store.delete(objectURL)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
insertNode,
|
|
4
4
|
type Extension,
|
|
5
5
|
} from '@prosekit/core'
|
|
6
|
+
import type { Command } from '@prosekit/pm/state'
|
|
6
7
|
|
|
7
8
|
import type { ImageAttrs } from './image-spec'
|
|
8
9
|
|
|
@@ -15,13 +16,21 @@ export type ImageCommandsExtension = Extension<{
|
|
|
15
16
|
}
|
|
16
17
|
}>
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Returns a command that inserts an image node with the given attributes at the
|
|
21
|
+
* current selection position.
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export function insertImage(attrs?: ImageAttrs): Command {
|
|
26
|
+
return insertNode({ type: 'image', attrs })
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
/**
|
|
19
30
|
* @internal
|
|
20
31
|
*/
|
|
21
32
|
export function defineImageCommands(): ImageCommandsExtension {
|
|
22
33
|
return defineCommands({
|
|
23
|
-
insertImage
|
|
24
|
-
return insertNode({ type: 'image', attrs })
|
|
25
|
-
},
|
|
34
|
+
insertImage,
|
|
26
35
|
})
|
|
27
36
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
insertNode,
|
|
3
|
+
ProseKitError,
|
|
4
|
+
union,
|
|
5
|
+
type PlainExtension,
|
|
6
|
+
} from '@prosekit/core'
|
|
7
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
defineFileDropHandler,
|
|
11
|
+
defineFilePasteHandler,
|
|
12
|
+
UploadTask,
|
|
13
|
+
type FileDropHandler,
|
|
14
|
+
type FileDropHandlerOptions,
|
|
15
|
+
type FilePasteHandler,
|
|
16
|
+
type FilePasteHandlerOptions,
|
|
17
|
+
type Uploader,
|
|
18
|
+
} from '../file'
|
|
19
|
+
|
|
20
|
+
import type { ImageAttrs } from './image-spec'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A predicate to determine if the pasted file should be uploaded and inserted as an image.
|
|
24
|
+
*/
|
|
25
|
+
export type ImageCanPastePredicate = (options: FilePasteHandlerOptions) => boolean
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A predicate to determine if the dropped file should be uploaded and inserted as an image.
|
|
29
|
+
*/
|
|
30
|
+
export type ImageCanDropPredicate = (options: FileDropHandlerOptions) => boolean
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A handler to be called when an error occurs during the upload.
|
|
34
|
+
*/
|
|
35
|
+
export type ImageUploadErrorHandler = (options: ImageUploadErrorHandlerOptions) => void
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Options for the {@link ImageUploadErrorHandler} callback.
|
|
39
|
+
*/
|
|
40
|
+
export interface ImageUploadErrorHandlerOptions {
|
|
41
|
+
/**
|
|
42
|
+
* The file that was uploaded.
|
|
43
|
+
*/
|
|
44
|
+
file: File
|
|
45
|
+
/**
|
|
46
|
+
* The error that occurred during the upload.
|
|
47
|
+
*/
|
|
48
|
+
error: unknown
|
|
49
|
+
/**
|
|
50
|
+
* The upload task that was used to upload the file.
|
|
51
|
+
*/
|
|
52
|
+
uploadTask: UploadTask<string>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Options for {@link defineImageUploadHandler}.
|
|
57
|
+
*/
|
|
58
|
+
export interface ImageUploadHandlerOptions {
|
|
59
|
+
/**
|
|
60
|
+
* The uploader used to upload the file. It should return a promise that
|
|
61
|
+
* resolves to the URL of the uploaded image.
|
|
62
|
+
*/
|
|
63
|
+
uploader: Uploader<string>
|
|
64
|
+
/**
|
|
65
|
+
* A predicate to determine if the pasted file should be uploaded and inserted as an image.
|
|
66
|
+
* If not provided, it defaults to only allowing paste of files with a content type starting with `image/`.
|
|
67
|
+
*/
|
|
68
|
+
canPaste?: ImageCanPastePredicate
|
|
69
|
+
/**
|
|
70
|
+
* A predicate to determine if the dropped file should be uploaded and inserted as an image.
|
|
71
|
+
* If not provided, it defaults to only allowing drop of files with a content type starting with `image/`.
|
|
72
|
+
*/
|
|
73
|
+
canDrop?: ImageCanDropPredicate
|
|
74
|
+
/**
|
|
75
|
+
* A handler to be called when an error occurs during the upload.
|
|
76
|
+
* If not provided, it defaults to logging the error to the console.
|
|
77
|
+
*/
|
|
78
|
+
onError?: ImageUploadErrorHandler
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function defaultCanUpload({ file }: { file: File }): boolean {
|
|
82
|
+
// Only handle image files by default
|
|
83
|
+
return file.type.startsWith('image/')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const defaultOnError: ImageUploadErrorHandler = ({ error }) => {
|
|
87
|
+
console.error('[prosekit] Failed to upload image:', error)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Returns an extension that handles image file uploads when pasting or dropping
|
|
92
|
+
* images into the editor.
|
|
93
|
+
*
|
|
94
|
+
* @param options
|
|
95
|
+
*/
|
|
96
|
+
export function defineImageUploadHandler({
|
|
97
|
+
uploader,
|
|
98
|
+
canPaste = defaultCanUpload,
|
|
99
|
+
canDrop = defaultCanUpload,
|
|
100
|
+
onError = defaultOnError,
|
|
101
|
+
}: ImageUploadHandlerOptions): PlainExtension {
|
|
102
|
+
const handleInsert = (view: EditorView, file: File, pos?: number): boolean => {
|
|
103
|
+
const uploadTask = new UploadTask({ file, uploader })
|
|
104
|
+
const objectURL = uploadTask.objectURL
|
|
105
|
+
const attrs: ImageAttrs = { src: objectURL }
|
|
106
|
+
uploadTask.finished.then((resultURL) => {
|
|
107
|
+
if (view.isDestroyed) {
|
|
108
|
+
return
|
|
109
|
+
} else if (typeof resultURL !== 'string') {
|
|
110
|
+
const error = new ProseKitError(`Unexpected upload result. Expected a string but got ${typeof resultURL}`)
|
|
111
|
+
onError({ file, error, uploadTask })
|
|
112
|
+
} else {
|
|
113
|
+
replaceImageURL(view, objectURL, resultURL)
|
|
114
|
+
UploadTask.delete(objectURL)
|
|
115
|
+
}
|
|
116
|
+
}).catch((error) => {
|
|
117
|
+
onError({ file, error, uploadTask })
|
|
118
|
+
})
|
|
119
|
+
const command = insertNode({ type: 'image', attrs, pos })
|
|
120
|
+
return command(view.state, view.dispatch, view)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const handlePaste: FilePasteHandler = (options) => {
|
|
124
|
+
if (!canPaste(options)) return false
|
|
125
|
+
return handleInsert(options.view, options.file)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const handleDrop: FileDropHandler = (options) => {
|
|
129
|
+
if (!canDrop(options)) return false
|
|
130
|
+
return handleInsert(options.view, options.file, options.pos)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return union(
|
|
134
|
+
defineFilePasteHandler(handlePaste),
|
|
135
|
+
defineFileDropHandler(handleDrop),
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function replaceImageURL(view: EditorView, oldURL: string, newURL: string) {
|
|
140
|
+
const positions: number[] = []
|
|
141
|
+
view.state.doc.descendants((node, pos) => {
|
|
142
|
+
if (node.type.name === 'image') {
|
|
143
|
+
const attrs = node.attrs as ImageAttrs
|
|
144
|
+
if (attrs.src === oldURL) {
|
|
145
|
+
positions.push(pos)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
if (positions.length > 0) {
|
|
150
|
+
const tr = view.state.tr
|
|
151
|
+
for (const pos of positions) {
|
|
152
|
+
tr.setNodeAttribute(pos, 'src', newURL)
|
|
153
|
+
}
|
|
154
|
+
view.dispatch(tr)
|
|
155
|
+
}
|
|
156
|
+
}
|
package/src/image/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export {
|
|
|
4
4
|
} from './image'
|
|
5
5
|
export {
|
|
6
6
|
defineImageCommands,
|
|
7
|
+
insertImage,
|
|
7
8
|
type ImageCommandsExtension,
|
|
8
9
|
} from './image-commands'
|
|
9
10
|
export {
|
|
@@ -11,3 +12,11 @@ export {
|
|
|
11
12
|
type ImageAttrs,
|
|
12
13
|
type ImageSpecExtension,
|
|
13
14
|
} from './image-spec'
|
|
15
|
+
export {
|
|
16
|
+
defineImageUploadHandler,
|
|
17
|
+
type ImageCanDropPredicate,
|
|
18
|
+
type ImageCanPastePredicate,
|
|
19
|
+
type ImageUploadErrorHandler,
|
|
20
|
+
type ImageUploadErrorHandlerOptions,
|
|
21
|
+
type ImageUploadHandlerOptions,
|
|
22
|
+
} from './image-upload-handler'
|