forked from github/plane
color support added for row and columns and fixed naming conventions
This commit is contained in:
parent
020e5fe922
commit
94ce5ce332
@ -2,7 +2,7 @@
|
|||||||
// import "./styles/tailwind.css";
|
// import "./styles/tailwind.css";
|
||||||
// import "./styles/editor.css";
|
// import "./styles/editor.css";
|
||||||
|
|
||||||
export * from "./ui/extensions/table-new/Table";
|
export * from "./ui/extensions/table/table";
|
||||||
|
|
||||||
// utils
|
// utils
|
||||||
export * from "./lib/utils";
|
export * from "./lib/utils";
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Editor, EditorContent } from "@tiptap/react";
|
import { Editor, EditorContent } from "@tiptap/react";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { ImageResizer } from "../extensions/image/image-resize";
|
import { ImageResizer } from "../extensions/image/image-resize";
|
||||||
import { TableMenu } from "../menus/table-menu";
|
|
||||||
|
|
||||||
interface EditorContentProps {
|
interface EditorContentProps {
|
||||||
editor: Editor | null;
|
editor: Editor | null;
|
||||||
@ -11,9 +10,7 @@ interface EditorContentProps {
|
|||||||
|
|
||||||
export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => (
|
export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => (
|
||||||
<div className={`contentEditor ${editorContentCustomClassNames}`}>
|
<div className={`contentEditor ${editorContentCustomClassNames}`}>
|
||||||
{/* @ts-ignore */}
|
|
||||||
<EditorContent editor={editor} />
|
<EditorContent editor={editor} />
|
||||||
{/* <TableMenu editor={editor} /> */}
|
|
||||||
{editor?.isActive("image") && <ImageResizer editor={editor} />}
|
{editor?.isActive("image") && <ImageResizer editor={editor} />}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,20 +8,14 @@ import TaskList from "@tiptap/extension-task-list";
|
|||||||
import { Markdown } from "tiptap-markdown";
|
import { Markdown } from "tiptap-markdown";
|
||||||
import Gapcursor from "@tiptap/extension-gapcursor";
|
import Gapcursor from "@tiptap/extension-gapcursor";
|
||||||
|
|
||||||
// import { CustomTableCell } from "./table/table-cell";
|
|
||||||
// import { Table } from "./table";
|
|
||||||
// import { TableHeader } from "./table/table-header";
|
|
||||||
// import { TableRow } from "@tiptap/extension-table-row";
|
|
||||||
|
|
||||||
import ImageExtension from "./image";
|
import ImageExtension from "./image";
|
||||||
|
|
||||||
import { DeleteImage } from "../../types/delete-image";
|
import { DeleteImage } from "../../types/delete-image";
|
||||||
import { isValidHttpUrl } from "../../lib/utils";
|
import { isValidHttpUrl } from "../../lib/utils";
|
||||||
import Table from "./table-new/Table";
|
import TableHeader from "./table/table-header/table-header";
|
||||||
import TableHeader from "./table-new/TableHeader";
|
import Table from "./table/table";
|
||||||
import TableCell from "./table-new/TableCell";
|
import TableCell from "./table/table-cell/table-cell";
|
||||||
import TableRow from "./table-new/TableRow";
|
import TableRow from "./table/table-row/table-row";
|
||||||
|
|
||||||
|
|
||||||
export const CoreEditorExtensions = (
|
export const CoreEditorExtensions = (
|
||||||
deleteFile: DeleteImage,
|
deleteFile: DeleteImage,
|
||||||
@ -98,8 +92,4 @@ export const CoreEditorExtensions = (
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
// Table,
|
|
||||||
// TableHeader,
|
|
||||||
// CustomTableCell,
|
|
||||||
// TableRow,
|
|
||||||
];
|
];
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default as default } from "./Table"
|
|
@ -1,55 +0,0 @@
|
|||||||
import { mergeAttributes, Node } from "@tiptap/core"
|
|
||||||
|
|
||||||
export interface TableCellOptions {
|
|
||||||
HTMLAttributes: Record<string, any>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Node.create<TableCellOptions>({
|
|
||||||
name: "tableCell",
|
|
||||||
|
|
||||||
addOptions() {
|
|
||||||
return {
|
|
||||||
HTMLAttributes: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
content: "paragraph+",
|
|
||||||
|
|
||||||
addAttributes() {
|
|
||||||
return {
|
|
||||||
colspan: {
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
rowspan: {
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
colwidth: {
|
|
||||||
default: null,
|
|
||||||
parseHTML: (element) => {
|
|
||||||
const colwidth = element.getAttribute("colwidth")
|
|
||||||
const value = colwidth ? [parseInt(colwidth, 10)] : null
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tableRole: "cell",
|
|
||||||
|
|
||||||
isolating: true,
|
|
||||||
|
|
||||||
parseHTML() {
|
|
||||||
return [{ tag: "td" }]
|
|
||||||
},
|
|
||||||
|
|
||||||
renderHTML({ node, HTMLAttributes }) {
|
|
||||||
return [
|
|
||||||
"td",
|
|
||||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
||||||
style: `background-color: ${node.attrs.background}`
|
|
||||||
}),
|
|
||||||
0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
export { default as default } from "./TableCell"
|
|
@ -1,54 +0,0 @@
|
|||||||
import { mergeAttributes, Node } from "@tiptap/core"
|
|
||||||
|
|
||||||
export interface TableHeaderOptions {
|
|
||||||
HTMLAttributes: Record<string, any>
|
|
||||||
}
|
|
||||||
export default Node.create<TableHeaderOptions>({
|
|
||||||
name: "tableHeader",
|
|
||||||
|
|
||||||
addOptions() {
|
|
||||||
return {
|
|
||||||
HTMLAttributes: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
content: "paragraph+",
|
|
||||||
|
|
||||||
addAttributes() {
|
|
||||||
return {
|
|
||||||
colspan: {
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
rowspan: {
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
colwidth: {
|
|
||||||
default: null,
|
|
||||||
parseHTML: (element) => {
|
|
||||||
const colwidth = element.getAttribute("colwidth")
|
|
||||||
const value = colwidth ? [parseInt(colwidth, 10)] : null
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tableRole: "header_cell",
|
|
||||||
|
|
||||||
isolating: true,
|
|
||||||
|
|
||||||
parseHTML() {
|
|
||||||
return [{ tag: "th" }]
|
|
||||||
},
|
|
||||||
|
|
||||||
renderHTML({ node, HTMLAttributes }) {
|
|
||||||
return [
|
|
||||||
"th",
|
|
||||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
||||||
style: `background-color: ${node.attrs.background}`
|
|
||||||
}),
|
|
||||||
0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
export { default as default } from "./TableHeader"
|
|
@ -1 +0,0 @@
|
|||||||
export { default as default } from "./TableRow"
|
|
@ -0,0 +1 @@
|
|||||||
|
export { default as default } from "./table-cell"
|
@ -0,0 +1,58 @@
|
|||||||
|
import { mergeAttributes, Node } from "@tiptap/core"
|
||||||
|
|
||||||
|
export interface TableCellOptions {
|
||||||
|
HTMLAttributes: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Node.create<TableCellOptions>({
|
||||||
|
name: "tableCell",
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
HTMLAttributes: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
content: "paragraph+",
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
colspan: {
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
rowspan: {
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
colwidth: {
|
||||||
|
default: null,
|
||||||
|
parseHTML: (element) => {
|
||||||
|
const colwidth = element.getAttribute("colwidth")
|
||||||
|
const value = colwidth ? [parseInt(colwidth, 10)] : null
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tableRole: "cell",
|
||||||
|
|
||||||
|
isolating: true,
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [{ tag: "td" }]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ node, HTMLAttributes }) {
|
||||||
|
return [
|
||||||
|
"td",
|
||||||
|
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
||||||
|
style: `background-color: ${node.attrs.background}`
|
||||||
|
}),
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1 @@
|
|||||||
|
export { default as default } from "./table-header"
|
@ -0,0 +1,57 @@
|
|||||||
|
import { mergeAttributes, Node } from "@tiptap/core"
|
||||||
|
|
||||||
|
export interface TableHeaderOptions {
|
||||||
|
HTMLAttributes: Record<string, any>
|
||||||
|
}
|
||||||
|
export default Node.create<TableHeaderOptions>({
|
||||||
|
name: "tableHeader",
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
HTMLAttributes: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
content: "paragraph+",
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
colspan: {
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
rowspan: {
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
colwidth: {
|
||||||
|
default: null,
|
||||||
|
parseHTML: (element) => {
|
||||||
|
const colwidth = element.getAttribute("colwidth")
|
||||||
|
const value = colwidth ? [parseInt(colwidth, 10)] : null
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: "rgb(var(--color-primary-100))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tableRole: "header_cell",
|
||||||
|
|
||||||
|
isolating: true,
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [{ tag: "th" }]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ node, HTMLAttributes }) {
|
||||||
|
return [
|
||||||
|
"th",
|
||||||
|
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
||||||
|
style: `background-color: ${node.attrs.background}`
|
||||||
|
}),
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1 @@
|
|||||||
|
export { default as default } from "./table-row"
|
@ -0,0 +1 @@
|
|||||||
|
export { default as default } from "./table"
|
@ -1,7 +1,7 @@
|
|||||||
import { h } from "jsx-dom-cjs"
|
import { h } from "jsx-dom-cjs"
|
||||||
import { Node as ProseMirrorNode } from "@tiptap/pm/model"
|
import { Node as ProseMirrorNode } from "@tiptap/pm/model"
|
||||||
import { Decoration, NodeView } from "@tiptap/pm/view"
|
import { Decoration, NodeView } from "@tiptap/pm/view"
|
||||||
import tippy, { Instance, Props, Tippy } from "tippy.js"
|
import tippy, { Instance, Props } from "tippy.js"
|
||||||
|
|
||||||
import { Editor } from "@tiptap/core"
|
import { Editor } from "@tiptap/core"
|
||||||
import {
|
import {
|
||||||
@ -109,7 +109,7 @@ const columnsToolboxItems = [
|
|||||||
{
|
{
|
||||||
label: "Pick Column Color",
|
label: "Pick Column Color",
|
||||||
icon: icons.colorPicker,
|
icon: icons.colorPicker,
|
||||||
action: ({ editor, triggerButton, controlsContainer }) => {
|
action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLElement, controlsContainer }) => {
|
||||||
createColorPickerToolbox({
|
createColorPickerToolbox({
|
||||||
triggerButton,
|
triggerButton,
|
||||||
tippyOptions: {
|
tippyOptions: {
|
||||||
@ -140,7 +140,7 @@ const rowsToolboxItems = [
|
|||||||
{
|
{
|
||||||
label: "Pick a Color",
|
label: "Pick a Color",
|
||||||
icon: icons.colorPicker,
|
icon: icons.colorPicker,
|
||||||
action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLElement, controlsContainer: any }) => {
|
action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLButtonElement, controlsContainer: Element | "parent" | ((ref: Element) => Element) | undefined }) => {
|
||||||
createColorPickerToolbox({
|
createColorPickerToolbox({
|
||||||
triggerButton,
|
triggerButton,
|
||||||
tippyOptions: {
|
tippyOptions: {
|
||||||
@ -202,12 +202,12 @@ function createColorPickerToolbox({
|
|||||||
onSelectColor?: (color: string) => void
|
onSelectColor?: (color: string) => void
|
||||||
}) {
|
}) {
|
||||||
const items = {
|
const items = {
|
||||||
"Fond par défault": "#ffffff",
|
"Default": "rgb(var(--color-primary-100))",
|
||||||
"Fond gris clair": "#e7f3f8",
|
"Light gray": "#e7f3f8",
|
||||||
"Fond gris foncé": "#c7d2d7",
|
"Dark gray": "#c7d2d7",
|
||||||
"Fond bleu": "#e7f3f8",
|
"Light blue": "#e7f3f8",
|
||||||
"Fond rouge": "#ffc4c7",
|
"Light red": "#ffc4c7",
|
||||||
"Fond jaune": "#fbf3db"
|
"Light yellow": "#fbf3db"
|
||||||
}
|
}
|
||||||
|
|
||||||
const colorPicker = tippy(triggerButton, {
|
const colorPicker = tippy(triggerButton, {
|
||||||
@ -265,11 +265,11 @@ export class TableView implements NodeView {
|
|||||||
table: HTMLElement
|
table: HTMLElement
|
||||||
colgroup: HTMLElement
|
colgroup: HTMLElement
|
||||||
tbody: HTMLElement
|
tbody: HTMLElement
|
||||||
rowsControl: HTMLElement
|
rowsControl?: HTMLElement
|
||||||
columnsControl: HTMLElement
|
columnsControl?: HTMLElement
|
||||||
columnsToolbox: Instance<Props>
|
columnsToolbox?: Instance<Props>
|
||||||
rowsToolbox: Instance<Props>
|
rowsToolbox?: Instance<Props>
|
||||||
controls: HTMLElement
|
controls?: HTMLElement
|
||||||
|
|
||||||
get dom() {
|
get dom() {
|
||||||
return this.root
|
return this.root
|
||||||
@ -333,10 +333,10 @@ export class TableView implements NodeView {
|
|||||||
onClickItem: (item) => {
|
onClickItem: (item) => {
|
||||||
item.action({
|
item.action({
|
||||||
editor: this.editor,
|
editor: this.editor,
|
||||||
triggerButton: this.columnsControl.firstElementChild,
|
triggerButton: this.columnsControl?.firstElementChild,
|
||||||
controlsContainer: this.controls
|
controlsContainer: this.controls
|
||||||
})
|
})
|
||||||
this.columnsToolbox.hide()
|
this.columnsToolbox?.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -350,10 +350,10 @@ export class TableView implements NodeView {
|
|||||||
onClickItem: (item) => {
|
onClickItem: (item) => {
|
||||||
item.action({
|
item.action({
|
||||||
editor: this.editor,
|
editor: this.editor,
|
||||||
triggerButton: this.rowsControl.firstElementChild,
|
triggerButton: this.rowsControl?.firstElementChild,
|
||||||
controlsContainer: this.controls
|
controlsContainer: this.controls
|
||||||
})
|
})
|
||||||
this.rowsToolbox.hide()
|
this.rowsToolbox?.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -21,15 +21,10 @@ import {
|
|||||||
toggleHeaderCell
|
toggleHeaderCell
|
||||||
} from "@tiptap/prosemirror-tables"
|
} from "@tiptap/prosemirror-tables"
|
||||||
|
|
||||||
import { tableControls } from "./tableControls"
|
import { tableControls } from "./table-controls"
|
||||||
import { TableView } from "./TableView"
|
import { TableView } from "./table-view"
|
||||||
import { createTable } from "./utilities/createTable"
|
import { createTable } from "./utilities/create-table"
|
||||||
import { deleteTableWhenAllCellsSelected } from "./utilities/deleteTableWhenAllCellsSelected"
|
import { deleteTableWhenAllCellsSelected } from "./utilities/delete-table-when-all-cells-selected"
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension based on:
|
|
||||||
* - Tiptap TableExtension (https://github.com/ueberdosis/tiptap/blob/main/packages/extension-table/src/table.ts)
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface TableOptions {
|
export interface TableOptions {
|
||||||
HTMLAttributes: Record<string, any>
|
HTMLAttributes: Record<string, any>
|
||||||
@ -73,9 +68,6 @@ declare module "@tiptap/core" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface NodeConfig<Options, Storage> {
|
interface NodeConfig<Options, Storage> {
|
||||||
/**
|
|
||||||
* Table Role
|
|
||||||
*/
|
|
||||||
tableRole?:
|
tableRole?:
|
||||||
| string
|
| string
|
||||||
| ((this: {
|
| ((this: {
|
||||||
@ -149,64 +141,40 @@ export default Node.create({
|
|||||||
},
|
},
|
||||||
addColumnBefore:
|
addColumnBefore:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => addColumnBefore(state, dispatch),
|
||||||
return addColumnBefore(state, dispatch)
|
|
||||||
},
|
|
||||||
addColumnAfter:
|
addColumnAfter:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => addColumnAfter(state, dispatch),
|
||||||
return addColumnAfter(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteColumn:
|
deleteColumn:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => deleteColumn(state, dispatch),
|
||||||
return deleteColumn(state, dispatch)
|
|
||||||
},
|
|
||||||
addRowBefore:
|
addRowBefore:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => addRowBefore(state, dispatch),
|
||||||
return addRowBefore(state, dispatch)
|
|
||||||
},
|
|
||||||
addRowAfter:
|
addRowAfter:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => addRowAfter(state, dispatch),
|
||||||
return addRowAfter(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteRow:
|
deleteRow:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => deleteRow(state, dispatch),
|
||||||
return deleteRow(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteTable:
|
deleteTable:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => deleteTable(state, dispatch),
|
||||||
return deleteTable(state, dispatch)
|
|
||||||
},
|
|
||||||
mergeCells:
|
mergeCells:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => mergeCells(state, dispatch),
|
||||||
return mergeCells(state, dispatch)
|
|
||||||
},
|
|
||||||
splitCell:
|
splitCell:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => splitCell(state, dispatch),
|
||||||
return splitCell(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderColumn:
|
toggleHeaderColumn:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => toggleHeader("column")(state, dispatch),
|
||||||
return toggleHeader("column")(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderRow:
|
toggleHeaderRow:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => toggleHeader("row")(state, dispatch),
|
||||||
return toggleHeader("row")(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderCell:
|
toggleHeaderCell:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => toggleHeaderCell(state, dispatch),
|
||||||
return toggleHeaderCell(state, dispatch)
|
|
||||||
},
|
|
||||||
mergeOrSplit:
|
mergeOrSplit:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => {
|
||||||
@ -218,19 +186,13 @@ export default Node.create({
|
|||||||
},
|
},
|
||||||
setCellAttribute:
|
setCellAttribute:
|
||||||
(name, value) =>
|
(name, value) =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => setCellAttr(name, value)(state, dispatch),
|
||||||
return setCellAttr(name, value)(state, dispatch)
|
|
||||||
},
|
|
||||||
goToNextCell:
|
goToNextCell:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => goToNextCell(1)(state, dispatch),
|
||||||
return goToNextCell(1)(state, dispatch)
|
|
||||||
},
|
|
||||||
goToPreviousCell:
|
goToPreviousCell:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => goToNextCell(-1)(state, dispatch),
|
||||||
return goToNextCell(-1)(state, dispatch)
|
|
||||||
},
|
|
||||||
fixTables:
|
fixTables:
|
||||||
() =>
|
() =>
|
||||||
({ state, dispatch }) => {
|
({ state, dispatch }) => {
|
@ -1,9 +1,7 @@
|
|||||||
import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model"
|
import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model"
|
||||||
|
|
||||||
import { ReactNodeViewRenderer } from "@tiptap/react"
|
import { createCell } from "./create-cell"
|
||||||
|
import { getTableNodeTypes } from "./get-table-node-types"
|
||||||
import { createCell } from "./createCell"
|
|
||||||
import { getTableNodeTypes } from "./getTableNodeTypes"
|
|
||||||
|
|
||||||
export function createTable(
|
export function createTable(
|
||||||
schema: Schema,
|
schema: Schema,
|
@ -1,6 +1,6 @@
|
|||||||
import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core"
|
import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core"
|
||||||
|
|
||||||
import { isCellSelection } from "./isCellSelection"
|
import { isCellSelection } from "./is-cell-selection"
|
||||||
|
|
||||||
export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({
|
export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({
|
||||||
editor
|
editor
|
||||||
@ -14,9 +14,7 @@ export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({
|
|||||||
let cellCount = 0
|
let cellCount = 0
|
||||||
const table = findParentNodeClosestToPos(
|
const table = findParentNodeClosestToPos(
|
||||||
selection.ranges[0].$from,
|
selection.ranges[0].$from,
|
||||||
(node) => {
|
(node) => node.type.name === "table"
|
||||||
return node.type.name === "table"
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
table?.node.descendants((node) => {
|
table?.node.descendants((node) => {
|
@ -11,7 +11,7 @@ interface CustomReadOnlyEditorProps {
|
|||||||
editorProps?: EditorProps;
|
editorProps?: EditorProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useReadOnlyEditor = ({ value, forwardedRef, extensions, editorProps }: CustomReadOnlyEditorProps) => {
|
export const useReadOnlyEditor = ({ value, forwardedRef, extensions = [], editorProps = {} }: CustomReadOnlyEditorProps) => {
|
||||||
const editor = useCustomEditor({
|
const editor = useCustomEditor({
|
||||||
editable: false,
|
editable: false,
|
||||||
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
const InsertBottomTableIcon = (props: any) => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M212.309-152.31q-30.308 0-51.308-21t-21-51.307V-360q0-30.307 21-51.307 21-21 51.308-21h535.382q30.308 0 51.308 21t21 51.307v135.383q0 30.307-21 51.307-21 21-51.308 21H212.309Zm0-375.383q-30.308 0-51.308-21t-21-51.307v-135.383q0-30.307 21-51.307 21-21 51.308-21h535.382q30.308 0 51.308 21t21 51.307V-600q0 30.307-21 51.307-21 21-51.308 21H212.309Zm535.382-219.998H212.309q-4.616 0-8.463 3.846-3.846 3.846-3.846 8.462V-600q0 4.616 3.846 8.462 3.847 3.847 8.463 3.847h535.382q4.616 0 8.463-3.847Q760-595.384 760-600v-135.383q0-4.616-3.846-8.462-3.847-3.846-8.463-3.846ZM200-587.691v-160 160Z"
|
|
||||||
fill="rgb(var(--color-text-300))"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default InsertBottomTableIcon;
|
|
@ -1,15 +0,0 @@
|
|||||||
const InsertLeftTableIcon = (props: any) => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M224.617-140.001q-30.307 0-51.307-21-21-21-21-51.308v-535.382q0-30.308 21-51.308t51.307-21H360q30.307 0 51.307 21 21 21 21 51.308v535.382q0 30.308-21 51.308t-51.307 21H224.617Zm375.383 0q-30.307 0-51.307-21-21-21-21-51.308v-535.382q0-30.308 21-51.308t51.307-21h135.383q30.307 0 51.307 21 21 21 21 51.308v535.382q0 30.308-21 51.308t-51.307 21H600Zm147.691-607.69q0-4.616-3.846-8.463-3.846-3.846-8.462-3.846H600q-4.616 0-8.462 3.846-3.847 3.847-3.847 8.463v535.382q0 4.616 3.847 8.463Q595.384-200 600-200h135.383q4.616 0 8.462-3.846 3.846-3.847 3.846-8.463v-535.382ZM587.691-200h160-160Z"
|
|
||||||
fill="rgb(var(--color-text-300))"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
export default InsertLeftTableIcon;
|
|
@ -1,16 +0,0 @@
|
|||||||
const InsertRightTableIcon = (props: any) => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M600-140.001q-30.307 0-51.307-21-21-21-21-51.308v-535.382q0-30.308 21-51.308t51.307-21h135.383q30.307 0 51.307 21 21 21 21 51.308v535.382q0 30.308-21 51.308t-51.307 21H600Zm-375.383 0q-30.307 0-51.307-21-21-21-21-51.308v-535.382q0-30.308 21-51.308t51.307-21H360q30.307 0 51.307 21 21 21 21 51.308v535.382q0 30.308-21 51.308t-51.307 21H224.617Zm-12.308-607.69v535.382q0 4.616 3.846 8.463 3.846 3.846 8.462 3.846H360q4.616 0 8.462-3.846 3.847-3.847 3.847-8.463v-535.382q0-4.616-3.847-8.463Q364.616-760 360-760H224.617q-4.616 0-8.462 3.846-3.846 3.847-3.846 8.463Zm160 547.691h-160 160Z"
|
|
||||||
fill="rgb(var(--color-text-300))"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default InsertRightTableIcon;
|
|
@ -1,15 +0,0 @@
|
|||||||
const InsertTopTableIcon = (props: any) => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M212.309-527.693q-30.308 0-51.308-21t-21-51.307v-135.383q0-30.307 21-51.307 21-21 51.308-21h535.382q30.308 0 51.308 21t21 51.307V-600q0 30.307-21 51.307-21 21-51.308 21H212.309Zm0 375.383q-30.308 0-51.308-21t-21-51.307V-360q0-30.307 21-51.307 21-21 51.308-21h535.382q30.308 0 51.308 21t21 51.307v135.383q0 30.307-21 51.307-21 21-51.308 21H212.309Zm0-59.999h535.382q4.616 0 8.463-3.846 3.846-3.846 3.846-8.462V-360q0-4.616-3.846-8.462-3.847-3.847-8.463-3.847H212.309q-4.616 0-8.463 3.847Q200-364.616 200-360v135.383q0 4.616 3.846 8.462 3.847 3.846 8.463 3.846Zm-12.309-160v160-160Z"
|
|
||||||
fill="rgb(var(--color-text-300))"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
export default InsertTopTableIcon;
|
|
@ -1,120 +0,0 @@
|
|||||||
import { useState, useEffect } from "react";
|
|
||||||
import { Rows, Columns, ToggleRight } from "lucide-react";
|
|
||||||
import InsertLeftTableIcon from "./InsertLeftTableIcon";
|
|
||||||
import InsertRightTableIcon from "./InsertRightTableIcon";
|
|
||||||
import InsertTopTableIcon from "./InsertTopTableIcon";
|
|
||||||
import InsertBottomTableIcon from "./InsertBottomTableIcon";
|
|
||||||
import { cn, findTableAncestor } from "../../../lib/utils";
|
|
||||||
import { Tooltip } from "./tooltip";
|
|
||||||
|
|
||||||
interface TableMenuItem {
|
|
||||||
command: () => void;
|
|
||||||
icon: any;
|
|
||||||
key: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const TableMenu = ({ editor }: { editor: any }) => {
|
|
||||||
const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 });
|
|
||||||
const isOpen = editor?.isActive("table");
|
|
||||||
|
|
||||||
const items: TableMenuItem[] = [
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().addColumnBefore().run(),
|
|
||||||
icon: InsertLeftTableIcon,
|
|
||||||
key: "insert-column-left",
|
|
||||||
name: "Insert 1 column left",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().addColumnAfter().run(),
|
|
||||||
icon: InsertRightTableIcon,
|
|
||||||
key: "insert-column-right",
|
|
||||||
name: "Insert 1 column right",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().addRowBefore().run(),
|
|
||||||
icon: InsertTopTableIcon,
|
|
||||||
key: "insert-row-above",
|
|
||||||
name: "Insert 1 row above",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().addRowAfter().run(),
|
|
||||||
icon: InsertBottomTableIcon,
|
|
||||||
key: "insert-row-below",
|
|
||||||
name: "Insert 1 row below",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().deleteColumn().run(),
|
|
||||||
icon: Columns,
|
|
||||||
key: "delete-column",
|
|
||||||
name: "Delete column",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().deleteRow().run(),
|
|
||||||
icon: Rows,
|
|
||||||
key: "delete-row",
|
|
||||||
name: "Delete row",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: () => editor.chain().focus().toggleHeaderRow().run(),
|
|
||||||
icon: ToggleRight,
|
|
||||||
key: "toggle-header-row",
|
|
||||||
name: "Toggle header row",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!window) return;
|
|
||||||
|
|
||||||
const handleWindowClick = () => {
|
|
||||||
const selection: any = window?.getSelection();
|
|
||||||
|
|
||||||
if (selection.rangeCount !== 0) {
|
|
||||||
const range = selection.getRangeAt(0);
|
|
||||||
const tableNode = findTableAncestor(range.startContainer);
|
|
||||||
|
|
||||||
if (tableNode) {
|
|
||||||
const tableRect = tableNode.getBoundingClientRect();
|
|
||||||
const tableCenter = tableRect.left + tableRect.width / 2;
|
|
||||||
const menuWidth = 45;
|
|
||||||
const menuLeft = tableCenter - menuWidth / 2;
|
|
||||||
const tableBottom = tableRect.bottom;
|
|
||||||
|
|
||||||
setTableLocation({ bottom: tableBottom, left: menuLeft });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("click", handleWindowClick);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("click", handleWindowClick);
|
|
||||||
};
|
|
||||||
}, [tableLocation, editor]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
className={`absolute z-20 left-1/2 -translate-x-1/2 overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 shadow-custom-shadow-sm p-1 ${
|
|
||||||
isOpen ? "block" : "hidden"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{items.map((item, index) => (
|
|
||||||
<Tooltip key={index} tooltipContent={item.name}>
|
|
||||||
<button
|
|
||||||
onClick={item.command}
|
|
||||||
className="p-1.5 text-custom-text-200 hover:bg-text-custom-text-100 hover:bg-custom-background-80 active:bg-custom-background-80 rounded"
|
|
||||||
title={item.name}
|
|
||||||
>
|
|
||||||
<item.icon
|
|
||||||
className={cn("h-4 w-4 text-lg", {
|
|
||||||
"text-red-600": item.key.includes("delete"),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
// next-themes
|
|
||||||
import { useTheme } from "next-themes";
|
|
||||||
// tooltip2
|
|
||||||
import { Tooltip2 } from "@blueprintjs/popover2";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
tooltipHeading?: string;
|
|
||||||
tooltipContent: string | React.ReactNode;
|
|
||||||
position?:
|
|
||||||
| "top"
|
|
||||||
| "right"
|
|
||||||
| "bottom"
|
|
||||||
| "left"
|
|
||||||
| "auto"
|
|
||||||
| "auto-end"
|
|
||||||
| "auto-start"
|
|
||||||
| "bottom-left"
|
|
||||||
| "bottom-right"
|
|
||||||
| "left-bottom"
|
|
||||||
| "left-top"
|
|
||||||
| "right-bottom"
|
|
||||||
| "right-top"
|
|
||||||
| "top-left"
|
|
||||||
| "top-right";
|
|
||||||
children: JSX.Element;
|
|
||||||
disabled?: boolean;
|
|
||||||
className?: string;
|
|
||||||
openDelay?: number;
|
|
||||||
closeDelay?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Tooltip: React.FC<Props> = ({
|
|
||||||
tooltipHeading,
|
|
||||||
tooltipContent,
|
|
||||||
position = "top",
|
|
||||||
children,
|
|
||||||
disabled = false,
|
|
||||||
className = "",
|
|
||||||
openDelay = 200,
|
|
||||||
closeDelay,
|
|
||||||
}) => {
|
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip2
|
|
||||||
disabled={disabled}
|
|
||||||
hoverOpenDelay={openDelay}
|
|
||||||
hoverCloseDelay={closeDelay}
|
|
||||||
content={
|
|
||||||
<div
|
|
||||||
className={`relative z-50 max-w-xs gap-1 rounded-md p-2 text-xs shadow-md ${
|
|
||||||
theme === "custom"
|
|
||||||
? "bg-custom-background-100 text-custom-text-200"
|
|
||||||
: "bg-black text-gray-400"
|
|
||||||
} break-words overflow-hidden ${className}`}
|
|
||||||
>
|
|
||||||
{tooltipHeading && (
|
|
||||||
<h5
|
|
||||||
className={`font-medium ${
|
|
||||||
theme === "custom" ? "text-custom-text-100" : "text-white"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{tooltipHeading}
|
|
||||||
</h5>
|
|
||||||
)}
|
|
||||||
{tooltipContent}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
position={position}
|
|
||||||
renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) =>
|
|
||||||
React.cloneElement(children, { ref: eleReference, ...tooltipProps, ...children.props })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -45,9 +45,9 @@
|
|||||||
background-color: rgb(var(--color-primary-100));
|
background-color: rgb(var(--color-primary-100));
|
||||||
}
|
}
|
||||||
|
|
||||||
.tableWrapper table td:hover{
|
/* .tableWrapper table td:hover{ */
|
||||||
background-color: rgba(var(--color-primary-300), 0.1);
|
/* background-color: rgba(var(--color-primary-300), 0.1); */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
.tableWrapper table th * {
|
.tableWrapper table th * {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
Loading…
Reference in New Issue
Block a user