Skip to content

Commit

Permalink
fix: Table operations
Browse files Browse the repository at this point in the history
  • Loading branch information
areknawo committed Jul 4, 2024
1 parent 070a68e commit 6ea0991
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 48 deletions.
2 changes: 1 addition & 1 deletion apps/web/public/sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@
h = "/transformers";
M = (t) => ({ create: (e) => t("POST", `${h}`, { body: e }), delete: (e) => t("DELETE", `${h}`, { params: e }), list: () => t("GET", `${h}/list`) });
b = "/snippets";
J = (t) => ({ get: (e) => t("GET", `${b}`, { params: e }), create: (e) => t("POST", `${b}`, { body: e }), update: (e) => t("PUT", `${b}`, { body: e }), delete: (e) => t("DELETE", `${b}`, { params: e }), list: () => t("GET", `${b}/list`) });
J = (t) => ({ get: (e) => t("GET", `${b}`, { params: e }), create: (e) => t("POST", `${b}`, { body: e }), update: (e) => t("PUT", `${b}`, { body: e }), delete: (e) => t("DELETE", `${b}`, { params: e }), list: (e) => t("GET", `${b}/list`, { params: e }) });
N = (t) => {
const { sendRequest: e, reconfigure: p2, getConfig: n, getSignal: $, useSignal: c } = L(t), s2 = { contentGroups: S(e), contentPieces: f2(e), snippets: J(e), tags: O(e), profile: R(e), userSettings: D(e), webhooks: j(e), workspace: I(e), roles: v(e), workspaceSettings: q(e), workspaceMemberships: A(e), extension: z(e), variants: B(e), transformers: M(e), search(a2) {
return e("GET", "/search", { params: a2 });
Expand Down
42 changes: 40 additions & 2 deletions apps/web/src/lib/editor/extensions/table-menu/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { ChainedCommands } from "@tiptap/core";
import { SolidEditor } from "@vrite/tiptap-solid";
import { Component, For, Show, createMemo } from "solid-js";
import clsx from "clsx";
import { Selection } from "@tiptap/pm/state";
import { Node } from "@tiptap/pm/model";
import { Card, IconButton, Tooltip } from "#components/primitives";
import { breakpoints } from "#lib/utils";

Expand All @@ -26,6 +28,18 @@ const TableMenu: Component<TableMenuProps> = (props) => {
const hasHeader = createMemo(() => {
return props.state.container?.querySelector("tr:first-child > th") !== null;
});
const getTableNode = (selection: Selection): { node: Node; pos: number } | null => {
for (let { depth } = selection.$from; depth > 0; depth--) {
const node = selection.$from.node(depth);
const pos = selection.$from.before(depth);

if (node.type.name === "table") {
return { node, pos };
}
}

return null;
};
const runCommand = (fn: (chain: ChainedCommands) => void): void => {
const chain = props.state.editor.chain();

Expand Down Expand Up @@ -82,13 +96,37 @@ const TableMenu: Component<TableMenuProps> = (props) => {
},
{
label() {
return hasHeader() ? "Remove header row" : "Add header row";
return hasHeader() ? "Remove header" : "Add header";
},
icon() {
return hasHeader() ? mdiTableHeadersEyeOff : mdiTableHeadersEye;
},
onClick() {
props.state.editor.chain().focus().toggleHeaderRow().run();
if (hasHeader()) {
const { node, pos } = getTableNode(props.state.editor.state.selection)!;

node.descendants((descendantNode, descendantPos) => {
if (descendantNode.type.name === "tableHeader") {
props.state.editor
.chain()
.command(({ tr, state }) => {
tr.setNodeMarkup(
pos + descendantPos + 1,
state.schema.nodes.tableCell,
descendantNode.attrs,
descendantNode.marks
);

return true;
})
.fixTables()
.focus()
.run();
}
});
} else {
props.state.editor.chain().toggleHeaderRow().fixTables().focus().run();
}
}
},
{
Expand Down
9 changes: 5 additions & 4 deletions apps/web/src/lib/editor/extensions/table-menu/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@ const handleUpdate = (editor: SolidEditor): void => {
bottom: childPos.bottom - parentPos.bottom,
left: childPos.left - parentPos.left
};
const alignCenter =
parentPos.width > relativePos.left + 125 &&
((tablePos?.width || 0) > 250 || relativePos.left > 125);

generalMenuContainer.style.top = `${relativePos.top + (tablePos?.height || 0)}px`;
generalMenuContainer.style.transform = `translate(${
(tablePos?.width || 0) > 250 ? "-50%" : "0"
},0.75rem)`;
generalMenuContainer.style.transform = `translate(${alignCenter ? "-50%" : "0"},0.75rem)`;

if ((tablePos?.width || 0) > 250 && breakpoints.md()) {
if (alignCenter && breakpoints.md()) {
generalMenuContainer.style.left = `${
relativePos.left + Math.min(tablePos?.width || parentPos.width, parentPos.width) / 2
}px`;
Expand Down
81 changes: 40 additions & 41 deletions apps/web/src/views/editor/menus/bubble/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import {
mdiTableSplitCell
} from "@mdi/js";
import clsx from "clsx";
import { Component, For, Show } from "solid-js";
import { Component, For, Show, createSignal, onCleanup } from "solid-js";
import { SolidEditor } from "@vrite/tiptap-solid";
import { CellSelection } from "@tiptap/pm/tables";
import { Node } from "@tiptap/pm/model";
import { TextSelection } from "@tiptap/pm/state";
import { Card, IconButton, Tooltip } from "#components/primitives";

const TableMenu: Component<{
Expand Down Expand Up @@ -54,7 +53,7 @@ const TableMenu: Component<{
const tableNode = getTableNode(selection);
const rowNode = getTableRowNode(selection);

if (!tableNode || !rowNode || tableNode.child(0) !== rowNode) {
if (!tableNode || !rowNode) {
return false;
}

Expand Down Expand Up @@ -112,55 +111,56 @@ const TableMenu: Component<{
const { selection } = props.editor.state;

if (selection instanceof CellSelection) {
if (selection.isRowSelection()) return false;

const tableNode = getTableNode(selection);

let isSingleColumn = false;
let isMergedColumn = false;

tableNode?.content.forEach((rowNode) => {
isSingleColumn = rowNode.childCount === 1;
isSingleColumn = isSingleColumn || rowNode.childCount === 1;
});

if (isSingleColumn) return false;

selection.forEachCell((node) => {
isMergedColumn = isMergedColumn || node.attrs.colspan !== 1;
});

return !isSingleColumn;
return !isMergedColumn;
}

return true;
return false;
},
onClick() {
props.editor
.chain()
.deleteColumn()
.command(({ tr }) => {
tr.setSelection(
TextSelection.near(
tr.doc.resolve(
Math.min(props.editor.state.selection.$from.pos - 2, tr.doc.nodeSize)
),
-1
)
);

return true;
})
.focus()
.run();
props.editor.chain().deleteColumn().focus().run();
}
},
{
icon: mdiTableRowRemove,
label: "Delete row(s)",

show() {
const { selection } = props.editor.state;

if (selection instanceof CellSelection) {
if (selection.isColSelection()) return false;

const tableNode = getTableNode(selection);
const isSingleRow = tableNode?.childCount === 1;

if (tableNode?.content.childCount === 1) {
return false;
}
let isMergedRow = false;

if (isSingleRow) return false;

selection.forEachCell((node) => {
isMergedRow = isMergedRow || node.attrs.rowspan !== 1;
});

return !isMergedRow;
}

return true;
return false;
},
onClick() {
props.editor.chain().deleteRow().focus().run();
Expand All @@ -169,22 +169,11 @@ const TableMenu: Component<{
{
icon: mdiTableRemove,
label: "Delete table",

show() {
const { selection } = props.editor.state;

if (selection instanceof CellSelection) {
const tableNode = getTableNode(selection);

if (tableNode?.childCount === 1) return true;

let isSingleColumn = false;

tableNode?.content.forEach((rowNode) => {
isSingleColumn = rowNode.childCount === 1;
});

return isSingleColumn;
return selection.isColSelection() && selection.isRowSelection();
}

return false;
Expand All @@ -207,8 +196,18 @@ const TableMenu: Component<{
fallback={<span class="px-1.5 py-0.5 text-base">No available options</span>}
>
{(menuItem) => {
const [show, setShow] = createSignal(!menuItem.show || menuItem.show());
const selectionUpdateHandler = (): void => {
setShow(!menuItem.show || menuItem.show());
};

props.editor.on("selectionUpdate", selectionUpdateHandler);
onCleanup(() => {
props.editor.off("selectionUpdate", selectionUpdateHandler);
});

return (
<Show when={!menuItem.show || menuItem.show()}>
<Show when={show()}>
<Tooltip text={menuItem.label} side="bottom" wrapperClass="snap-start">
<IconButton
path={menuItem.icon}
Expand Down

0 comments on commit 6ea0991

Please sign in to comment.