mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-23 19:49:56 +01:00
editors: add support for write protecting a specific task list (#3285)
* editor: added readonly attr for tasklist * Update packages/editor/src/extensions/task-list/task-list.ts Signed-off-by: Abdullah Atta <thecodrr@protonmail.com> * editor: fixed tasklist title input * editor: allow write protecting nested task lists --------- Signed-off-by: Abdullah Atta <thecodrr@protonmail.com> Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
This commit is contained in:
@@ -18,14 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Box, Flex, Input, Text } from "@theme-ui/components";
|
||||
import { findChildren, getNodeType } from "@tiptap/core";
|
||||
import {
|
||||
findChildren,
|
||||
findParentNodeClosestToPos,
|
||||
getNodeType
|
||||
} from "@tiptap/core";
|
||||
import { Node } from "prosemirror-model";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ToolButton } from "../../toolbar/components/tool-button";
|
||||
import { findParentNodeOfTypeClosestToPos } from "../../utils/prosemirror";
|
||||
import { ReactNodeViewProps } from "../react";
|
||||
import { TaskItemNode } from "../task-item";
|
||||
import { TaskListAttributes } from "./task-list";
|
||||
import { TaskListAttributes, TaskListNode } from "./task-list";
|
||||
import { countCheckedItems, deleteCheckedItems, sortList } from "./utils";
|
||||
|
||||
export function TaskListComponent(
|
||||
@@ -34,7 +38,7 @@ export function TaskListComponent(
|
||||
// const isMobile = useIsMobile();
|
||||
const { editor, getPos, node, updateAttributes, forwardRef, pos } = props;
|
||||
const taskItemType = getNodeType(TaskItemNode.name, editor.schema);
|
||||
const { title, textDirection } = node.attrs;
|
||||
const { title, textDirection, readonly } = node.attrs;
|
||||
const [stats, setStats] = useState({ checked: 0, total: 0, percentage: 0 });
|
||||
|
||||
const getParent = useCallback(() => {
|
||||
@@ -49,6 +53,18 @@ export function TaskListComponent(
|
||||
return !!getParent();
|
||||
}, [getParent]);
|
||||
|
||||
const isReadonly = useMemo(() => {
|
||||
console.log("HEERE!");
|
||||
const isParentReadonly =
|
||||
!!isNested &&
|
||||
!!pos &&
|
||||
!!findParentNodeClosestToPos(
|
||||
editor.state.doc.resolve(pos),
|
||||
(node) => node.type.name === TaskListNode.name && node.attrs.readonly
|
||||
);
|
||||
return readonly || isParentReadonly;
|
||||
}, [isNested, readonly, editor.state.doc, pos]);
|
||||
|
||||
useEffect(() => {
|
||||
const parent = getParent();
|
||||
if (!parent) return;
|
||||
@@ -103,7 +119,7 @@ export function TaskListComponent(
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
readOnly={!editor.isEditable}
|
||||
readOnly={!editor.isEditable || readonly}
|
||||
value={title || ""}
|
||||
variant={"clean"}
|
||||
sx={{
|
||||
@@ -125,6 +141,24 @@ export function TaskListComponent(
|
||||
/>
|
||||
{editor.isEditable && (
|
||||
<>
|
||||
<ToolButton
|
||||
toggled={false}
|
||||
title="Make tasklist readonly"
|
||||
icon={readonly ? "readonlyOn" : "readonlyOff"}
|
||||
variant="small"
|
||||
sx={{
|
||||
zIndex: 1
|
||||
}}
|
||||
onClick={() => {
|
||||
const pos = getPos();
|
||||
const node = editor.current?.state.doc.nodeAt(pos);
|
||||
if (!node) return;
|
||||
updateAttributes(
|
||||
{ readonly: !node.attrs.readonly },
|
||||
{ addToHistory: true, preventUpdate: false }
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<ToolButton
|
||||
toggled={false}
|
||||
title="Move all checked tasks to bottom"
|
||||
@@ -184,6 +218,7 @@ export function TaskListComponent(
|
||||
<Box
|
||||
ref={forwardRef}
|
||||
dir={textDirection}
|
||||
contentEditable={editor.isEditable && !isReadonly}
|
||||
sx={{
|
||||
ul: {
|
||||
display: "block",
|
||||
|
||||
@@ -33,6 +33,7 @@ import { countCheckedItems } from "./utils";
|
||||
|
||||
export type TaskListAttributes = {
|
||||
title: string;
|
||||
readonly: boolean;
|
||||
};
|
||||
|
||||
const stateKey = new PluginKey("task-item-drop-override");
|
||||
@@ -52,6 +53,19 @@ export const TaskListNode = TaskList.extend({
|
||||
"data-title": attributes.title
|
||||
};
|
||||
}
|
||||
},
|
||||
readonly: {
|
||||
default: false,
|
||||
keepOnSplit: false,
|
||||
parseHTML: (element) => element.dataset.readonly,
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.readonly) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
"data-readonly": attributes.readonly
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -115,7 +115,9 @@ import {
|
||||
mdiTableRowRemove,
|
||||
mdiTableSplitCell,
|
||||
mdiUploadOutline,
|
||||
mdiWeb
|
||||
mdiWeb,
|
||||
mdiPencilOff,
|
||||
mdiPencil
|
||||
} from "@mdi/js";
|
||||
|
||||
export const Icons = {
|
||||
@@ -239,6 +241,8 @@ export const Icons = {
|
||||
circle: mdiCircle,
|
||||
arrowLeft: mdiArrowLeft,
|
||||
resize: mdiResizeBottomRight,
|
||||
readonlyOn: mdiPencilOff,
|
||||
readonlyOff: mdiPencil,
|
||||
none: ""
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user