mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 03:29:21 +02:00
Compare commits
5 Commits
fix-move-f
...
feat--new-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1658b6de2 | ||
|
|
fab0f6f834 | ||
|
|
8d10dd040f | ||
|
|
56078a8ef3 | ||
|
|
df4fac7005 |
600
apps/desktop/package-lock.json
generated
600
apps/desktop/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,25 +11,24 @@
|
||||
"repository": "https://github.com/streetwriters/notesnook",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "^11.2.1",
|
||||
"electron-trpc": "0.6.1",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/server": "10.38.3",
|
||||
"better-sqlite3-multiple-ciphers": "^9.5.0",
|
||||
"electron-trpc": "0.5.2",
|
||||
"electron-updater": "^6.2.1",
|
||||
"icojs": "^0.19.4",
|
||||
"icojs": "^0.17.1",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.7.2",
|
||||
"yargs": "^17.6.2",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@types/node": "20.14.8",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"@types/node": "18.16.1",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "^30.4.0",
|
||||
"electron": "^29.3.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"esbuild": "^0.23.0",
|
||||
"node-abi": "^3.67.0",
|
||||
"kysely": "^0.27.3",
|
||||
"node-gyp-build": "^4.8.0",
|
||||
"prebuildify": "^6.0.1",
|
||||
"tree-kill": "^1.2.2",
|
||||
@@ -158,8 +157,7 @@
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": true,
|
||||
"createDesktopShortcut": "always",
|
||||
"deleteAppDataOnUninstall": true
|
||||
"createDesktopShortcut": "always"
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
|
||||
@@ -94,7 +94,7 @@ async function patchBetterSQLite3() {
|
||||
);
|
||||
const json = JSON.parse(await readFile(jsonPath, "utf-8"));
|
||||
|
||||
json.version = "11.2.2";
|
||||
json.version = "9.5.1";
|
||||
json.homepage = "https://github.com/thecodrr/better-sqlite3-multiple-ciphers";
|
||||
json.repository.url =
|
||||
"git://github.com/thecodrr/better-sqlite3-multiple-ciphers.git";
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { Database, Statement } from "better-sqlite3-multiple-ciphers";
|
||||
import type { QueryResult } from "@streetwriters/kysely";
|
||||
import type { QueryResult } from "kysely";
|
||||
|
||||
type SQLiteCompatibleType =
|
||||
| number
|
||||
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { NativeImage, nativeImage } from "electron";
|
||||
import path from "path";
|
||||
import { isDevelopment } from "./index";
|
||||
import { ParsedImage, parseICO } from "icojs";
|
||||
import { parse, ParsedImage } from "icojs";
|
||||
import { getSystemTheme } from "./theme";
|
||||
import { readFile } from "fs/promises";
|
||||
|
||||
@@ -71,7 +71,7 @@ export class AssetManager {
|
||||
`${icon}${prefix}.ico`
|
||||
);
|
||||
const icoBuffer = await readFile(icoPath);
|
||||
const images = await parseICO(icoBuffer, "image/png");
|
||||
const images = await parse(icoBuffer, "image/png");
|
||||
ALL_ICONS.push({ id: icon, images, prefix });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,7 @@ import { Platform } from "react-native";
|
||||
import * as Gzip from "react-native-gzip";
|
||||
import EventSource from "../../utils/sse/even-source-ios";
|
||||
import AndroidEventSource from "../../utils/sse/event-source";
|
||||
import {
|
||||
SqliteAdapter,
|
||||
SqliteIntrospector,
|
||||
SqliteQueryCompiler
|
||||
} from "@streetwriters/kysely";
|
||||
import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely";
|
||||
import filesystem from "../filesystem";
|
||||
import Storage from "./storage";
|
||||
import { RNSqliteDriver } from "./sqlite.kysely";
|
||||
|
||||
@@ -18,11 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { initialize } from "@notesnook/core/dist/logger";
|
||||
import {
|
||||
SqliteAdapter,
|
||||
SqliteIntrospector,
|
||||
SqliteQueryCompiler
|
||||
} from "@streetwriters/kysely";
|
||||
import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely";
|
||||
import { Platform } from "react-native";
|
||||
import { setLogger } from ".";
|
||||
import { RNSqliteDriver } from "./sqlite.kysely";
|
||||
|
||||
@@ -17,12 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
DatabaseConnection,
|
||||
Driver,
|
||||
QueryResult
|
||||
} from "@streetwriters/kysely";
|
||||
import { CompiledQuery } from "@streetwriters/kysely";
|
||||
import type { DatabaseConnection, Driver, QueryResult } from "kysely";
|
||||
import { CompiledQuery } from "kysely";
|
||||
import { QuickSQLiteConnection, open } from "react-native-quick-sqlite";
|
||||
|
||||
type Config = { dbName: string; async: boolean; location: string };
|
||||
|
||||
@@ -43,7 +43,6 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
|
||||
DatabaseLogger.log(`File Exists already: ${filename}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const attachment = await db.attachments.attachment(filename);
|
||||
const size = await getUploadedFileSize(filename);
|
||||
|
||||
@@ -91,8 +90,7 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
|
||||
DatabaseLogger.log(`Download starting: ${filename}`);
|
||||
let request = RNFetchBlob.config({
|
||||
path: tempFilePath,
|
||||
IOSBackgroundTask: true,
|
||||
overwrite: true
|
||||
IOSBackgroundTask: true
|
||||
})
|
||||
.fetch("GET", downloadUrl, null)
|
||||
.progress(async (recieved, total) => {
|
||||
@@ -124,11 +122,6 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
|
||||
|
||||
let status = response.info().status;
|
||||
useAttachmentStore.getState().remove(filename);
|
||||
|
||||
if (exists(originalFilePath)) {
|
||||
await RNFetchBlob.fs.unlink(originalFilePath).catch(console.log);
|
||||
}
|
||||
|
||||
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath);
|
||||
|
||||
if (!(await exists(filename))) {
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { eHideToast, eShowToast } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
export const Toast = ({ context = "global" }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [data, setData] = useState({});
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const hideTimeout = useRef();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const toastMessages = useRef([]);
|
||||
|
||||
const show = useCallback(
|
||||
async (data) => {
|
||||
if (!data) return;
|
||||
if (data.context !== context) return;
|
||||
if (
|
||||
toastMessages.current.findIndex((m) => m.message === data.message) >= 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
toastMessages.current.push(data);
|
||||
if (toastMessages.current?.length > 1) return;
|
||||
setData(data);
|
||||
|
||||
setVisible(true);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hide();
|
||||
}, data.duration);
|
||||
},
|
||||
[context, hide]
|
||||
);
|
||||
|
||||
const next = useCallback(
|
||||
(data) => {
|
||||
if (!data) {
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
setData(data);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hide();
|
||||
}, data?.duration);
|
||||
},
|
||||
[hide]
|
||||
);
|
||||
|
||||
const hide = useCallback(() => {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
let msg =
|
||||
toastMessages.current.length > 1 ? toastMessages.current.shift() : null;
|
||||
|
||||
if (msg) {
|
||||
setVisible(false);
|
||||
next(msg);
|
||||
setTimeout(() => {
|
||||
setVisible(true);
|
||||
}, 300);
|
||||
} else {
|
||||
setVisible(false);
|
||||
toastMessages.current.shift();
|
||||
setTimeout(() => {
|
||||
setData({});
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}, [next]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eShowToast, show);
|
||||
eSubscribeEvent(eHideToast, hide);
|
||||
return () => {
|
||||
toastMessages.current = [];
|
||||
eUnSubscribeEvent(eShowToast, show);
|
||||
eUnSubscribeEvent(eHideToast, hide);
|
||||
};
|
||||
}, [hide, show]);
|
||||
|
||||
return (
|
||||
visible && (
|
||||
<TouchableOpacity
|
||||
onPress={hide}
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
width: DDS.isTab ? 400 : "100%",
|
||||
alignItems: "center",
|
||||
alignSelf: "center",
|
||||
minHeight: 30,
|
||||
top: insets.top + 10,
|
||||
position: "absolute",
|
||||
zIndex: 999,
|
||||
elevation: 15
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
...getElevationStyle(5),
|
||||
maxWidth: "95%",
|
||||
backgroundColor: colors.secondary.background,
|
||||
minWidth: data?.func ? "95%" : "50%",
|
||||
alignSelf: "center",
|
||||
borderRadius: 5,
|
||||
minHeight: 30,
|
||||
paddingVertical: 10,
|
||||
paddingLeft: 12,
|
||||
paddingRight: 5,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
width: "95%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexGrow: 1,
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
height: 30,
|
||||
borderRadius: 100,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={data?.type === "success" ? "check" : "close"}
|
||||
size={SIZE.lg}
|
||||
color={
|
||||
data?.type === "error"
|
||||
? colors.error.icon
|
||||
: colors.primary.accent
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
paddingRight: 25
|
||||
}}
|
||||
>
|
||||
{data?.heading ? (
|
||||
<Heading
|
||||
color={colors.primary.paragraph}
|
||||
size={SIZE.md}
|
||||
onPress={() => {
|
||||
hide();
|
||||
}}
|
||||
>
|
||||
{data.heading}
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
{data?.message ? (
|
||||
<Paragraph
|
||||
color={colors.primary.paragraph}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
paddingRight: 10
|
||||
}}
|
||||
onPress={() => {
|
||||
hide();
|
||||
}}
|
||||
>
|
||||
{data.message}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{data.func ? (
|
||||
<Button
|
||||
testID={notesnook.toast.button}
|
||||
fontSize={SIZE.md}
|
||||
type={data.type === "error" ? "errorShade" : "transparent"}
|
||||
onPress={data.func}
|
||||
title={data.actionText}
|
||||
height={30}
|
||||
style={{
|
||||
zIndex: 10
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
);
|
||||
};
|
||||
219
apps/mobile/app/components/toast/index.tsx
Normal file
219
apps/mobile/app/components/toast/index.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Platform,
|
||||
TouchableOpacity,
|
||||
useWindowDimensions,
|
||||
View
|
||||
} from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import useKeyboard from "../../hooks/use-keyboard";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
ToastOptions
|
||||
} from "../../services/event-manager";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { eHideToast, eShowToast } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const Toast = ({ context = "global" }) => {
|
||||
const { colors, isDark } = useThemeColors();
|
||||
const [toastOptions, setToastOptions] = useState<ToastOptions | undefined>();
|
||||
const hideTimeout = useRef<NodeJS.Timeout | undefined>();
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const toastMessages = useRef<ToastOptions[]>([]);
|
||||
const dimensions = useWindowDimensions();
|
||||
const keyboard = useKeyboard();
|
||||
|
||||
const hideToast = useCallback(() => {
|
||||
const nextToastMessage = toastMessages.current.shift();
|
||||
if (nextToastMessage) {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
setVisible(true);
|
||||
setToastOptions(nextToastMessage);
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToast();
|
||||
}, nextToastMessage?.duration);
|
||||
} else {
|
||||
setVisible(false);
|
||||
setToastOptions(undefined);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const showToast = useCallback(
|
||||
(data?: ToastOptions) => {
|
||||
if (
|
||||
!data ||
|
||||
data.context !== context ||
|
||||
toastMessages.current.findIndex((m) => m.message === data.message) != -1
|
||||
)
|
||||
return;
|
||||
|
||||
toastMessages.current.push(data);
|
||||
if (toastMessages.current?.length > 1) return;
|
||||
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
setVisible(true);
|
||||
const nextToastMessage = toastMessages.current.shift();
|
||||
setToastOptions(nextToastMessage);
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToast();
|
||||
}, nextToastMessage?.duration);
|
||||
},
|
||||
[context, hideToast]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eShowToast, showToast);
|
||||
eSubscribeEvent(eHideToast, hideToast);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eShowToast, showToast);
|
||||
eUnSubscribeEvent(eHideToast, hideToast);
|
||||
};
|
||||
}, [hideToast, showToast]);
|
||||
|
||||
const isFullToastMessage = toastOptions?.heading && toastOptions?.message;
|
||||
|
||||
return visible && toastOptions ? (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
hideToast();
|
||||
}}
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
width: DDS.isTab ? dimensions.width / 2 : "100%",
|
||||
alignItems: "center",
|
||||
alignSelf: "center",
|
||||
bottom:
|
||||
Platform.OS === "android"
|
||||
? Math.max(insets.bottom, 40)
|
||||
: Math.max(insets.bottom, 40) +
|
||||
(keyboard.keyboardShown ? keyboard.keyboardHeight : 0),
|
||||
position: "absolute",
|
||||
zIndex: 999,
|
||||
elevation: 15
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
...getElevationStyle(5),
|
||||
backgroundColor: isDark ? colors.static.black : colors.static.white,
|
||||
alignSelf: "center",
|
||||
borderRadius: 100,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 12,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
maxWidth: "95%",
|
||||
gap: 10,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={
|
||||
toastOptions.type === "success"
|
||||
? "check"
|
||||
: toastOptions.type === "info"
|
||||
? "information"
|
||||
: "close"
|
||||
}
|
||||
size={isFullToastMessage ? SIZE.xxxl : SIZE.xl}
|
||||
color={
|
||||
toastOptions?.icon
|
||||
? toastOptions?.icon
|
||||
: toastOptions.type === "error"
|
||||
? colors.error.icon
|
||||
: toastOptions.type === "info"
|
||||
? isDark
|
||||
? colors.static.white
|
||||
: colors.static.black
|
||||
: colors.success.icon
|
||||
}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingRight: toastOptions?.func ? 0 : 12,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{isFullToastMessage ? (
|
||||
<Heading
|
||||
color={!isDark ? colors.static.black : colors.static.white}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{toastOptions.heading}
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
{toastOptions.message || toastOptions.heading ? (
|
||||
<Paragraph
|
||||
color={!isDark ? colors.static.black : colors.static.white}
|
||||
size={SIZE.xs}
|
||||
>
|
||||
{toastOptions.message || toastOptions.heading}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{toastOptions.func ? (
|
||||
<Button
|
||||
testID={notesnook.toast.button}
|
||||
fontSize={SIZE.md}
|
||||
type={toastOptions.type === "error" ? "errorShade" : "transparent"}
|
||||
onPress={toastOptions.func}
|
||||
title={toastOptions.actionText}
|
||||
height={35}
|
||||
style={{
|
||||
zIndex: 10
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
) : null;
|
||||
};
|
||||
@@ -36,11 +36,11 @@
|
||||
"react-native-wheel-color-picker": "^1.3.1",
|
||||
"tinycolor2": "1.6.0",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/react-query": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@tanstack/react-query": "^4.29.19",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/react-query": "10.38.3",
|
||||
"@trpc/server": "10.38.3",
|
||||
"kysely": "^0.26.3",
|
||||
"pathe": "1.1.2"
|
||||
},
|
||||
"sideEffects": false
|
||||
|
||||
@@ -139,6 +139,7 @@ export type ToastOptions = {
|
||||
duration?: number;
|
||||
func?: () => void;
|
||||
actionText?: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
export const ToastManager = {
|
||||
|
||||
8944
apps/mobile/patches/kysely+0.26.3.patch
Normal file
8944
apps/mobile/patches/kysely+0.26.3.patch
Normal file
File diff suppressed because it is too large
Load Diff
25
apps/theme-builder/package-lock.json
generated
25
apps/theme-builder/package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"@notesnook/web": "file:../web",
|
||||
"@theme-ui/components": "^0.14.7",
|
||||
"@theme-ui/core": "^0.14.7",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/client": "^10.38.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"clipboard-polyfill": "^4.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -979,7 +979,7 @@
|
||||
},
|
||||
"../web": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.0.17",
|
||||
"version": "3.0.13",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
@@ -993,7 +993,7 @@
|
||||
"@henrygd/queue": "^1.0.6",
|
||||
"@mdi/js": "^7.2.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@notesnook-importer/core": "^2.1.1",
|
||||
"@notesnook-importer/core": "^2.0.0",
|
||||
"@notesnook/common": "file:../../packages/common",
|
||||
"@notesnook/core": "file:../../packages/core",
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
@@ -1007,14 +1007,13 @@
|
||||
"@notesnook/web-clipper": "file:../../extensions/web-clipper",
|
||||
"@react-pdf-viewer/core": "^3.12.0",
|
||||
"@react-pdf-viewer/toolbar": "^3.12.0",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"@tanstack/react-query": "^4.29.19",
|
||||
"@tanstack/react-virtual": "^3.0.1",
|
||||
"@theme-ui/color": "^0.16.1",
|
||||
"@theme-ui/components": "^0.16.1",
|
||||
"@theme-ui/core": "^0.16.1",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/react-query": "10.45.2",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/react-query": "10.38.3",
|
||||
"@zip.js/zip.js": "^2.7.32",
|
||||
"async-mutex": "^0.4.0",
|
||||
"axios": "^1.3.4",
|
||||
@@ -1032,6 +1031,8 @@
|
||||
"hash-wasm": "^4.9.0",
|
||||
"hotkeys-js": "^3.8.3",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mac-scrollbar": "^0.13.5",
|
||||
"marked": "^4.1.0",
|
||||
"mutative": "^1.0.6",
|
||||
@@ -1067,7 +1068,7 @@
|
||||
"@playwright/test": "^1.43.1",
|
||||
"@swc/core": "^1.5.24",
|
||||
"@swc/plugin-react-remove-properties": "^2.0.4",
|
||||
"@trpc/server": "10.45.2",
|
||||
"@trpc/server": "10.38.3",
|
||||
"@types/babel__core": "^7.20.1",
|
||||
"@types/event-source-polyfill": "^1.0.1",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
@@ -2018,14 +2019,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@trpc/client": {
|
||||
"version": "10.45.2",
|
||||
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.45.2.tgz",
|
||||
"integrity": "sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==",
|
||||
"version": "10.38.3",
|
||||
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
|
||||
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
|
||||
"funding": [
|
||||
"https://trpc.io/sponsor"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@trpc/server": "10.45.2"
|
||||
"@trpc/server": "10.38.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"@notesnook/web": "file:../web",
|
||||
"@theme-ui/components": "^0.14.7",
|
||||
"@theme-ui/core": "^0.14.7",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/client": "^10.38.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"clipboard-polyfill": "^4.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
1672
apps/web/package-lock.json
generated
1672
apps/web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -32,13 +32,13 @@
|
||||
"@notesnook/web-clipper": "file:../../extensions/web-clipper",
|
||||
"@react-pdf-viewer/core": "^3.12.0",
|
||||
"@react-pdf-viewer/toolbar": "^3.12.0",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"@tanstack/react-query": "^4.29.19",
|
||||
"@tanstack/react-virtual": "^3.0.1",
|
||||
"@theme-ui/color": "^0.16.1",
|
||||
"@theme-ui/components": "^0.16.1",
|
||||
"@theme-ui/core": "^0.16.1",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/react-query": "10.45.2",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/react-query": "10.38.3",
|
||||
"@zip.js/zip.js": "^2.7.32",
|
||||
"async-mutex": "^0.4.0",
|
||||
"axios": "^1.3.4",
|
||||
@@ -56,7 +56,7 @@
|
||||
"hash-wasm": "^4.9.0",
|
||||
"hotkeys-js": "^3.8.3",
|
||||
"katex": "0.16.2",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"kysely": "^0.26.3",
|
||||
"mac-scrollbar": "^0.13.5",
|
||||
"marked": "^4.1.0",
|
||||
"mutative": "^1.0.6",
|
||||
@@ -92,7 +92,7 @@
|
||||
"@playwright/test": "^1.43.1",
|
||||
"@swc/core": "^1.5.24",
|
||||
"@swc/plugin-react-remove-properties": "^2.0.4",
|
||||
"@trpc/server": "10.45.2",
|
||||
"@trpc/server": "10.38.3",
|
||||
"@types/babel__core": "^7.20.1",
|
||||
"@types/event-source-polyfill": "^1.0.1",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
|
||||
8944
apps/web/patches/kysely+0.26.3.patch
Normal file
8944
apps/web/patches/kysely+0.26.3.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,6 @@ import { store as noteStore } from "../stores/note-store";
|
||||
import { store as notebookStore } from "../stores/notebook-store";
|
||||
import { store as attachmentStore } from "../stores/attachment-store";
|
||||
import { store as reminderStore } from "../stores/reminder-store";
|
||||
import { store as tagStore } from "../stores/tag-store";
|
||||
import { store as appStore } from "../stores/app-store";
|
||||
import { db } from "./db";
|
||||
import { showToast } from "../utils/toast";
|
||||
import Vault from "./vault";
|
||||
@@ -61,8 +59,6 @@ async function moveNotesToTrash(ids: string[], confirm = true) {
|
||||
}
|
||||
|
||||
async function moveNotebooksToTrash(ids: string[]) {
|
||||
if (!ids.length) return;
|
||||
|
||||
const isMultiselect = ids.length > 1;
|
||||
if (isMultiselect) {
|
||||
if (!(await showMultiDeleteConfirmation(ids.length))) return;
|
||||
@@ -138,42 +134,9 @@ async function moveRemindersToTrash(ids: string[]) {
|
||||
showToast("success", `${pluralize(ids.length, "reminder")} deleted.`);
|
||||
}
|
||||
|
||||
async function deleteTags(ids: string[]) {
|
||||
if (
|
||||
!(await ConfirmDialog.show({
|
||||
title: "Are you sure?",
|
||||
message:
|
||||
"Are you sure you want to permanently delete these tags? This action is IRREVERSIBLE.",
|
||||
negativeButtonText: "No",
|
||||
positiveButtonText: "Yes"
|
||||
}))
|
||||
)
|
||||
return;
|
||||
|
||||
await TaskManager.startTask({
|
||||
type: "status",
|
||||
id: "deleteTags",
|
||||
title: "Deleting tags",
|
||||
action: async (report) => {
|
||||
report({
|
||||
text: `Deleting ${pluralize(ids.length, "tag")}...`
|
||||
});
|
||||
for (const id of ids) {
|
||||
await db.tags.remove(id);
|
||||
}
|
||||
await appStore.refreshNavItems();
|
||||
await tagStore.refresh();
|
||||
await noteStore.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
showToast("success", `${pluralize(ids.length, "tag")} deleted.`);
|
||||
}
|
||||
|
||||
export const Multiselect = {
|
||||
moveRemindersToTrash,
|
||||
moveNotebooksToTrash,
|
||||
moveNotesToTrash,
|
||||
deleteAttachments,
|
||||
deleteTags
|
||||
deleteAttachments
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
QueryResult,
|
||||
CompiledQuery,
|
||||
Driver
|
||||
} from "@streetwriters/kysely";
|
||||
} from "kysely";
|
||||
import { desktop } from "../desktop-bridge";
|
||||
import Worker from "./sqlite.worker.desktop.ts?worker";
|
||||
import type { SQLiteWorker } from "./sqlite.worker.desktop";
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
SqliteQueryCompiler,
|
||||
SqliteIntrospector,
|
||||
Dialect
|
||||
} from "@streetwriters/kysely";
|
||||
} from "kysely";
|
||||
import {
|
||||
WaSqliteWorkerMultipleTabDriver,
|
||||
WaSqliteWorkerSingleTabDriver
|
||||
|
||||
@@ -21,7 +21,7 @@ import type { SQLiteAPI, SQLiteCompatibleType } from "./sqlite-types";
|
||||
import { Factory, SQLITE_ROW, SQLiteError } from "./sqlite-api";
|
||||
import { expose, transfer } from "comlink";
|
||||
import type { RunMode } from "./type";
|
||||
import { QueryResult } from "@streetwriters/kysely";
|
||||
import { QueryResult } from "kysely";
|
||||
import { DatabaseSource } from "./sqlite-export";
|
||||
import { createSharedServicePort } from "./shared-service";
|
||||
import type { IDBBatchAtomicVFS } from "./IDBBatchAtomicVFS";
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { QueryResult } from "@streetwriters/kysely";
|
||||
import type { QueryResult } from "kysely";
|
||||
|
||||
export type Promisable<T> = T | Promise<T>;
|
||||
|
||||
|
||||
@@ -17,12 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
DatabaseConnection,
|
||||
Driver,
|
||||
QueryResult
|
||||
} from "@streetwriters/kysely";
|
||||
import { CompiledQuery } from "@streetwriters/kysely";
|
||||
import type { DatabaseConnection, Driver, QueryResult } from "kysely";
|
||||
import { CompiledQuery } from "kysely";
|
||||
import Worker from "./sqlite.worker.ts?worker";
|
||||
import type { SQLiteWorker } from "./sqlite.worker";
|
||||
import SQLiteSyncURI from "./wa-sqlite.wasm?url";
|
||||
|
||||
@@ -57,7 +57,6 @@ import { Attachment as AttachmentType } from "@notesnook/core";
|
||||
import { useEditorStore } from "../../stores/editor-store";
|
||||
import { PromptDialog } from "../../dialogs/prompt";
|
||||
import { DialogManager } from "../../common/dialog-manager";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
|
||||
const FILE_ICONS: Record<string, Icon> = {
|
||||
"image/": FileImage,
|
||||
@@ -136,13 +135,6 @@ export function Attachment({
|
||||
Menu.openMenu(AttachmentMenuItems(item, status));
|
||||
}}
|
||||
onClick={onSelected}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
await Multiselect.deleteAttachments(
|
||||
useSelectionStore.getState().selectedItems
|
||||
);
|
||||
}
|
||||
}}
|
||||
style={style}
|
||||
ref={rowRef}
|
||||
>
|
||||
|
||||
@@ -133,9 +133,8 @@ function Note(props: NoteProps) {
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
// @ts-expect-error write tests for this
|
||||
await Multiselect.moveNotesToTrash(
|
||||
selectionStore.get().selectedItems
|
||||
);
|
||||
const selectedItems = selectionStore.get().selectedItems;
|
||||
await Multiselect.moveNotesToTrash([item.id, ...selectedItems]);
|
||||
}
|
||||
}}
|
||||
colors={{
|
||||
|
||||
@@ -44,7 +44,6 @@ import { Notebook as NotebookType } from "@notesnook/core";
|
||||
import { handleDrop } from "../../common/drop-handler";
|
||||
import { useDragHandler } from "../../hooks/use-drag-handler";
|
||||
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
|
||||
type NotebookProps = {
|
||||
item: NotebookType;
|
||||
@@ -81,13 +80,6 @@ function Notebook(props: NotebookProps) {
|
||||
|
||||
handleDrop(e.dataTransfer, notebook);
|
||||
}}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
await Multiselect.moveNotebooksToTrash(
|
||||
useSelectionStore.getState().selectedItems
|
||||
);
|
||||
}
|
||||
}}
|
||||
title={notebook.title}
|
||||
body={notebook.description as string}
|
||||
menuItems={notebookMenuItems}
|
||||
|
||||
@@ -43,7 +43,6 @@ import { MenuItem } from "@notesnook/ui";
|
||||
import { Reminder as ReminderType } from "@notesnook/core/dist/types";
|
||||
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||
import { EditReminderDialog } from "../../dialogs/add-reminder-dialog";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
|
||||
const RECURRING_MODE_MAP = {
|
||||
week: "Weekly",
|
||||
@@ -75,13 +74,6 @@ function Reminder(props: ReminderProps) {
|
||||
isDisabled={reminder.disabled}
|
||||
isCompact={compact}
|
||||
onClick={() => EditReminderDialog.show({ reminderId: reminder.id })}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
await Multiselect.moveRemindersToTrash(
|
||||
useSelectionStore.getState().selectedItems
|
||||
);
|
||||
}
|
||||
}}
|
||||
footer={
|
||||
<Flex
|
||||
sx={{
|
||||
|
||||
@@ -29,8 +29,6 @@ import { useCallback, useRef } from "react";
|
||||
import { handleDrop } from "../../common/drop-handler";
|
||||
import { useDragHandler } from "../../hooks/use-drag-handler";
|
||||
import { AddNotebookDialog } from "../../dialogs/add-notebook-dialog";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
import { Multiselect } from "../../common/multi-select";
|
||||
|
||||
type SubNotebookProps = {
|
||||
item: Notebook;
|
||||
@@ -114,11 +112,6 @@ function SubNotebook(props: SubNotebookProps) {
|
||||
});
|
||||
navigate(`/notebooks/${rootId}/${item.id}`);
|
||||
}
|
||||
} else if (e.code === "Delete") {
|
||||
console.log("Delete", useSelectionStore.getState().selectedItems);
|
||||
await Multiselect.moveNotebooksToTrash(
|
||||
useSelectionStore.getState().selectedItems
|
||||
);
|
||||
}
|
||||
}}
|
||||
title={
|
||||
|
||||
@@ -21,14 +21,16 @@ import ListItem from "../list-item";
|
||||
import { navigate } from "../../navigation";
|
||||
import { Text } from "@theme-ui/components";
|
||||
import { store as appStore } from "../../stores/app-store";
|
||||
import { store as tagStore } from "../../stores/tag-store";
|
||||
import { store as noteStore } from "../../stores/note-store";
|
||||
import { db } from "../../common/db";
|
||||
import { Edit, Shortcut, DeleteForver } from "../icons";
|
||||
import { showToast } from "../../utils/toast";
|
||||
import { pluralize } from "@notesnook/common";
|
||||
import { MenuItem } from "@notesnook/ui";
|
||||
import { Tag as TagType } from "@notesnook/core";
|
||||
import { handleDrop } from "../../common/drop-handler";
|
||||
import { EditTagDialog } from "../../dialogs/item-dialog";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
import { Multiselect } from "../../common/multi-select";
|
||||
|
||||
type TagProps = { item: TagType; totalNotes: number };
|
||||
function Tag(props: TagProps) {
|
||||
@@ -52,13 +54,6 @@ function Tag(props: TagProps) {
|
||||
{totalNotes}
|
||||
</Text>
|
||||
}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
await Multiselect.deleteTags(
|
||||
useSelectionStore.getState().selectedItems
|
||||
);
|
||||
}
|
||||
}}
|
||||
menuItems={menuItems}
|
||||
onClick={() => {
|
||||
navigate(`/tags/${id}`);
|
||||
@@ -101,7 +96,11 @@ const menuItems: (tag: TagType, ids?: string[]) => MenuItem[] = (
|
||||
title: "Delete",
|
||||
icon: DeleteForver.path,
|
||||
onClick: async () => {
|
||||
await Multiselect.deleteTags(ids);
|
||||
await db.tags.remove(...ids);
|
||||
showToast("success", `${pluralize(ids.length, "tag")} deleted`);
|
||||
await appStore.refreshNavItems();
|
||||
await tagStore.refresh();
|
||||
await noteStore.refresh();
|
||||
},
|
||||
multiSelect: true
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import { MenuItem } from "@notesnook/ui";
|
||||
import { TrashItem as TrashItemType } from "@notesnook/core/dist/types";
|
||||
import { useEditorStore } from "../../stores/editor-store";
|
||||
import { showMultiPermanentDeleteConfirmation } from "../../dialogs/confirm";
|
||||
import { useStore as useSelectionStore } from "../../stores/selection-store";
|
||||
|
||||
type TrashItemProps = { item: TrashItemType; date: number };
|
||||
function TrashItem(props: TrashItemProps) {
|
||||
@@ -41,11 +40,6 @@ function TrashItem(props: TrashItemProps) {
|
||||
item={item}
|
||||
title={item.title}
|
||||
body={item.itemType === "note" ? item.headline : item.description}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Delete") {
|
||||
await deleteTrash(useSelectionStore.getState().selectedItems);
|
||||
}
|
||||
}}
|
||||
footer={
|
||||
<Flex
|
||||
mt={1}
|
||||
@@ -93,15 +87,14 @@ const menuItems: (item: TrashItemType, ids?: string[]) => MenuItem[] = (
|
||||
icon: DeleteForver.path,
|
||||
variant: "dangerous",
|
||||
onClick: async () => {
|
||||
await deleteTrash(ids);
|
||||
if (!(await showMultiPermanentDeleteConfirmation(ids.length))) return;
|
||||
await store.delete(...ids);
|
||||
showToast(
|
||||
"success",
|
||||
`${pluralize(ids.length, "item")} permanently deleted`
|
||||
);
|
||||
},
|
||||
multiSelect: true
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
async function deleteTrash(ids: string[]) {
|
||||
if (!(await showMultiPermanentDeleteConfirmation(ids.length))) return;
|
||||
await store.delete(...ids);
|
||||
showToast("success", `${pluralize(ids.length, "item")} permanently deleted`);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import { db } from "../common/db";
|
||||
import { getChangelog } from "../utils/version";
|
||||
import { downloadUpdate } from "../utils/updater";
|
||||
import { ErrorText } from "../components/error-text";
|
||||
import { pluralize } from "@notesnook/common";
|
||||
|
||||
type Check = { text: string; default?: boolean };
|
||||
export type ConfirmDialogProps<TCheckId extends string> = BaseDialogProps<
|
||||
@@ -144,7 +143,7 @@ export const ConfirmDialog = DialogManager.register(function ConfirmDialog<
|
||||
|
||||
export function showMultiDeleteConfirmation(length: number) {
|
||||
return ConfirmDialog.show({
|
||||
title: `Delete ${pluralize(length, "item")}?`,
|
||||
title: `Delete ${length} items?`,
|
||||
message: `These items will be **kept in your Trash for ${
|
||||
db.settings.getTrashCleanupInterval() || 7
|
||||
} days** after which they will be permanently deleted.`,
|
||||
@@ -155,7 +154,7 @@ export function showMultiDeleteConfirmation(length: number) {
|
||||
|
||||
export function showMultiPermanentDeleteConfirmation(length: number) {
|
||||
return ConfirmDialog.show({
|
||||
title: `Permanently delete ${pluralize(length, "item")}?`,
|
||||
title: `Permanently delete ${length} items?`,
|
||||
message:
|
||||
"These items will be **permanently deleted**. This is IRREVERSIBLE.",
|
||||
positiveButtonText: "Yes",
|
||||
|
||||
@@ -802,11 +802,10 @@ class EditorStore extends BaseStore<EditorStore> {
|
||||
{ type, id: currentSession.context.id },
|
||||
{ id, type: "note" }
|
||||
);
|
||||
} else {
|
||||
const defaultNotebook = db.settings.getDefaultNotebook();
|
||||
if (defaultNotebook)
|
||||
await db.notes.addToNotebook(defaultNotebook, id);
|
||||
}
|
||||
const defaultNotebook = db.settings.getDefaultNotebook();
|
||||
if (defaultNotebook)
|
||||
await db.notes.addToNotebook(defaultNotebook, id);
|
||||
}
|
||||
|
||||
const attachmentsLength = await db.attachments
|
||||
|
||||
8
packages/common/package-lock.json
generated
8
packages/common/package-lock.json
generated
@@ -35,8 +35,7 @@
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"@notesnook/logger": "file:../logger",
|
||||
"@readme/data-urls": "^3.0.0",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@streetwriters/showdown": "^3.0.8-alpha",
|
||||
"@streetwriters/showdown": "^3.0.7-alpha",
|
||||
"async-mutex": "^0.3.2",
|
||||
"dayjs": "1.11.9",
|
||||
"dom-serializer": "^2.0.0",
|
||||
@@ -47,6 +46,7 @@
|
||||
"html-to-text": "^9.0.5",
|
||||
"htmlparser2": "^8.0.1",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"linkedom": "^0.14.17",
|
||||
"liqe": "^1.13.0",
|
||||
"mime-db": "1.52.0",
|
||||
@@ -1828,8 +1828,7 @@
|
||||
"@notesnook/crypto": "file:../crypto",
|
||||
"@notesnook/logger": "file:../logger",
|
||||
"@readme/data-urls": "^3.0.0",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@streetwriters/showdown": "^3.0.8-alpha",
|
||||
"@streetwriters/showdown": "^3.0.7-alpha",
|
||||
"@types/better-sqlite3": "^7.6.5",
|
||||
"@types/event-source-polyfill": "^1.0.1",
|
||||
"@types/html-to-text": "^9.0.0",
|
||||
@@ -1859,6 +1858,7 @@
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"linkedom": "^0.14.17",
|
||||
"liqe": "^1.13.0",
|
||||
"mime-db": "1.52.0",
|
||||
|
||||
@@ -25,7 +25,7 @@ import { CHECK_IDS, EV, EVENTS } from "../src/common";
|
||||
import { EventSource } from "event-source-polyfill";
|
||||
import { test, expect, vitest } from "vitest";
|
||||
import { login } from "./utils";
|
||||
import { SqliteDialect } from "@streetwriters/kysely";
|
||||
import { SqliteDialect } from "kysely";
|
||||
import BetterSQLite3 from "better-sqlite3-multiple-ciphers";
|
||||
|
||||
const TEST_TIMEOUT = 60 * 1000;
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { initialize, logManager, logger } from "../src/logger";
|
||||
import { SqliteDialect } from "@streetwriters/kysely";
|
||||
import { SqliteDialect } from "kysely";
|
||||
import BetterSQLite3 from "better-sqlite3-multiple-ciphers";
|
||||
import { NoopLogger } from "@notesnook/logger";
|
||||
import { delay } from "./utils";
|
||||
|
||||
@@ -25,7 +25,7 @@ import { EventSourcePolyfill as EventSource } from "event-source-polyfill";
|
||||
import { randomBytes } from "../../src/utils/random";
|
||||
import { Note, Notebook } from "../../src/types";
|
||||
import { NoteContent } from "../../src/collections/session-content";
|
||||
import { SqliteDialect } from "@streetwriters/kysely";
|
||||
import { SqliteDialect } from "kysely";
|
||||
import BetterSQLite3 from "better-sqlite3-multiple-ciphers";
|
||||
import path from "path";
|
||||
import { tmpdir } from "os";
|
||||
|
||||
@@ -115,23 +115,6 @@ test("unlock a note permanently", () =>
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(false);
|
||||
}));
|
||||
|
||||
test("lock an empty note", () =>
|
||||
noteTest({ title: "I am a note" }).then(async ({ db, id }) => {
|
||||
await db.vault.create("password");
|
||||
|
||||
await db.vault.add(id);
|
||||
|
||||
const note = await db.notes.note(id);
|
||||
const content = await db.content.get(note.contentId);
|
||||
const vault = await db.vaults.default();
|
||||
expect(note.headline).toBe("");
|
||||
expect(content.locked).toBeTruthy();
|
||||
expect(content.noteId).toBeDefined();
|
||||
expect(content.data.iv).toBeDefined();
|
||||
expect(content.data.cipher).toBeDefined();
|
||||
expect(await db.relations.from(vault, "note").has(id)).toBe(true);
|
||||
}));
|
||||
|
||||
test("save a locked note", () =>
|
||||
noteTest().then(async ({ db, id }) => {
|
||||
await db.vault.create("password");
|
||||
|
||||
18
packages/core/package-lock.json
generated
18
packages/core/package-lock.json
generated
@@ -14,7 +14,6 @@
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"@notesnook/logger": "file:../logger",
|
||||
"@readme/data-urls": "^3.0.0",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@streetwriters/showdown": "^3.0.8-alpha",
|
||||
"async-mutex": "^0.3.2",
|
||||
"dayjs": "1.11.9",
|
||||
@@ -26,6 +25,7 @@
|
||||
"html-to-text": "^9.0.5",
|
||||
"htmlparser2": "^8.0.1",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"linkedom": "^0.14.17",
|
||||
"liqe": "^1.13.0",
|
||||
"mime-db": "1.52.0",
|
||||
@@ -2216,14 +2216,6 @@
|
||||
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@streetwriters/kysely": {
|
||||
"version": "0.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@streetwriters/kysely/-/kysely-0.27.4.tgz",
|
||||
"integrity": "sha512-c2p+wtX8WESSVjJAc16j4lT44w/g1DvJFEIeKj/CFy36vmi0uq9FOAzxc50VtRc7rp0UlECCfl3Sxd+BTZOHFg==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@streetwriters/showdown": {
|
||||
"version": "3.0.8-alpha",
|
||||
"resolved": "https://registry.npmjs.org/@streetwriters/showdown/-/showdown-3.0.8-alpha.tgz",
|
||||
@@ -3567,6 +3559,14 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/kysely": {
|
||||
"version": "0.26.3",
|
||||
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.26.3.tgz",
|
||||
"integrity": "sha512-yWSgGi9bY13b/W06DD2OCDDHQmq1kwTGYlQ4wpZkMOJqMGCstVCFIvxCCVG4KfY1/3G0MhDAcZsip/Lw8/vJWw==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/leac": {
|
||||
"version": "0.6.0",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
"html-to-text": "^9.0.5",
|
||||
"htmlparser2": "^8.0.1",
|
||||
"katex": "0.16.2",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"kysely": "^0.26.3",
|
||||
"linkedom": "^0.14.17",
|
||||
"liqe": "^1.13.0",
|
||||
"mime-db": "1.52.0",
|
||||
|
||||
8944
packages/core/patches/kysely+0.26.3.patch
Normal file
8944
packages/core/patches/kysely+0.26.3.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -70,7 +70,7 @@ import {
|
||||
createDatabase,
|
||||
initializeDatabase
|
||||
} from "../database";
|
||||
import { Kysely, Transaction, sql } from "@streetwriters/kysely";
|
||||
import { Kysely, Transaction, sql } from "kysely";
|
||||
import { CachedCollection } from "../database/cached-collection";
|
||||
import { Vaults } from "../collections/vaults";
|
||||
import { KVStorage } from "../database/kv";
|
||||
|
||||
@@ -21,7 +21,7 @@ import { match } from "fuzzyjs";
|
||||
import Database from ".";
|
||||
import { Item, Note, TrashItem } from "../types";
|
||||
import { DatabaseSchema, RawDatabaseSchema } from "../database";
|
||||
import { AnyColumnWithTable, Kysely, sql } from "@streetwriters/kysely";
|
||||
import { AnyColumnWithTable, Kysely, sql } from "kysely";
|
||||
import { FilteredSelector } from "../database/sql-collection";
|
||||
import { VirtualizedGrouping } from "../utils/virtualized-grouping";
|
||||
import { logger } from "../logger";
|
||||
@@ -79,12 +79,6 @@ export default class Lookup {
|
||||
.select(["results.id"])
|
||||
.groupBy("results.id")
|
||||
.$if(!!limit, (eb) => eb.limit(limit!))
|
||||
// filter out ids that have no note against them
|
||||
.where(
|
||||
"results.id",
|
||||
"in",
|
||||
(notes || this.db.notes.all).filter.select("id")
|
||||
)
|
||||
.execute()
|
||||
.catch((e) => {
|
||||
logger.error(e, `Error while searching`, { query });
|
||||
|
||||
@@ -251,7 +251,7 @@ export default class Vault {
|
||||
.storage()
|
||||
.encrypt({ password }, JSON.stringify(content.data));
|
||||
|
||||
return await this.db.content.add({
|
||||
await this.db.content.add({
|
||||
noteId,
|
||||
sessionId,
|
||||
data: encryptedContent,
|
||||
@@ -295,7 +295,7 @@ export default class Vault {
|
||||
// Case: when note is being newly locked
|
||||
if (!locked && (!data || !type)) {
|
||||
const rawContent = await this.db.content.findByNoteId(id);
|
||||
if (rawContent?.locked) {
|
||||
if (!rawContent || rawContent.locked) {
|
||||
await this.db.relations.add(vault, {
|
||||
id,
|
||||
type: "note"
|
||||
@@ -305,8 +305,8 @@ export default class Vault {
|
||||
// NOTE:
|
||||
// At this point, the note already has all the attachments extracted
|
||||
// so we should just encrypt it as normal.
|
||||
data = rawContent?.data || "<p></p>";
|
||||
type = rawContent?.type || "tiptap";
|
||||
data = rawContent.data;
|
||||
type = rawContent.type;
|
||||
} else if (data && type) {
|
||||
data = await this.db.content.postProcess({
|
||||
data,
|
||||
@@ -315,14 +315,13 @@ export default class Vault {
|
||||
});
|
||||
}
|
||||
|
||||
if (data && type)
|
||||
await this.encryptContent({ data, type }, id, password, sessionId);
|
||||
|
||||
await this.db.notes.add({
|
||||
id,
|
||||
headline: "",
|
||||
dateEdited: Date.now(),
|
||||
contentId:
|
||||
data && type
|
||||
? await this.encryptContent({ data, type }, id, password, sessionId)
|
||||
: undefined
|
||||
dateEdited: Date.now()
|
||||
});
|
||||
|
||||
await this.db.relations.add(vault, {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { Attachment } from "../types";
|
||||
import Database from "../api";
|
||||
import { FilteredSelector, SQLCollection } from "../database/sql-collection";
|
||||
import { isFalse } from "../database";
|
||||
import { sql } from "@streetwriters/kysely";
|
||||
import { sql } from "kysely";
|
||||
import { logger } from "../logger";
|
||||
|
||||
export class Attachments implements ICollection {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { Notebook, TrashOrItem, isTrashItem } from "../types";
|
||||
import { ICollection } from "./collection";
|
||||
import { SQLCollection } from "../database/sql-collection";
|
||||
import { isFalse } from "../database";
|
||||
import { sql } from "@streetwriters/kysely";
|
||||
import { sql } from "kysely";
|
||||
import { deleteItems } from "../utils/array";
|
||||
import { CHECK_IDS, checkIsUserPremium } from "../common";
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import Database from "../api";
|
||||
import { FilteredSelector, SQLCollection } from "../database/sql-collection";
|
||||
import { DatabaseSchema, UnlinkEvent, isFalse } from "../database";
|
||||
import { SelectQueryBuilder } from "@streetwriters/kysely";
|
||||
import { SelectQueryBuilder } from "kysely";
|
||||
import { EVENTS } from "../common";
|
||||
|
||||
export class Relations implements ICollection {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { Reminder } from "../types";
|
||||
import Database from "../api";
|
||||
import { SQLCollection } from "../database/sql-collection";
|
||||
import { isFalse } from "../database";
|
||||
import { sql } from "@streetwriters/kysely";
|
||||
import { sql } from "kysely";
|
||||
|
||||
dayjs.extend(isTomorrow);
|
||||
dayjs.extend(isSameOrBefore);
|
||||
|
||||
@@ -23,7 +23,7 @@ import Database from "../api";
|
||||
import { ICollection } from "./collection";
|
||||
import { SQLCollection } from "../database/sql-collection";
|
||||
import { isFalse } from "../database";
|
||||
import { sql } from "@streetwriters/kysely";
|
||||
import { sql } from "kysely";
|
||||
import { CHECK_IDS, checkIsUserPremium } from "../common";
|
||||
|
||||
export class Tags implements ICollection {
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
getSortSelectors,
|
||||
groupArray
|
||||
} from "../utils/grouping";
|
||||
import { sql } from "@streetwriters/kysely";
|
||||
import { sql } from "kysely";
|
||||
import { MAX_SQL_PARAMETERS } from "../database/sql-collection";
|
||||
|
||||
export default class Trash {
|
||||
|
||||
@@ -123,21 +123,28 @@ export const EVENTS = {
|
||||
systemTimeInvalid: "system:invalidTime"
|
||||
};
|
||||
|
||||
const separators = ["-", "/", "."];
|
||||
const separators = ["-", "/"];
|
||||
const DD = "DD";
|
||||
const MM = "MM";
|
||||
const YYYY = "YYYY";
|
||||
export const DATE_FORMATS = [
|
||||
...[
|
||||
[DD, MM, YYYY],
|
||||
[MM, DD, YYYY],
|
||||
[YYYY, MM, DD]
|
||||
]
|
||||
.map((item) => separators.map((sep) => item.join(sep)))
|
||||
...separators
|
||||
.map((sep) => [
|
||||
[DD, MM, YYYY].join(sep),
|
||||
[MM, DD, YYYY].join(sep),
|
||||
[YYYY, MM, DD].join(sep)
|
||||
])
|
||||
.flat(),
|
||||
"MMM D, YYYY"
|
||||
];
|
||||
|
||||
export const DATE_FORMATS_WITHOUT_YEAR = [
|
||||
...separators
|
||||
.map((sep) => [[DD, MM].join(sep), [MM, DD].join(sep), [MM, DD].join(sep)])
|
||||
.flat(),
|
||||
"MMM D"
|
||||
];
|
||||
|
||||
export const TIME_FORMATS = ["12-hour", "24-hour"];
|
||||
|
||||
export const CURRENT_DATABASE_VERSION = 6.1;
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Kysely, sql } from "@streetwriters/kysely";
|
||||
import { Kysely, sql } from "kysely";
|
||||
import { RawDatabaseSchema } from ".";
|
||||
|
||||
export async function rebuildSearchIndex(db: Kysely<RawDatabaseSchema>) {
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
ReferenceExpression,
|
||||
Dialect,
|
||||
MigrationProvider
|
||||
} from "@streetwriters/kysely";
|
||||
} from "kysely";
|
||||
import {
|
||||
Attachment,
|
||||
Color,
|
||||
|
||||
@@ -20,11 +20,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import {
|
||||
ColumnBuilderCallback,
|
||||
CreateTableBuilder,
|
||||
ExpressionBuilder,
|
||||
Migration,
|
||||
MigrationProvider,
|
||||
sql
|
||||
} from "@streetwriters/kysely";
|
||||
} from "kysely";
|
||||
import { rebuildSearchIndex } from "./fts";
|
||||
|
||||
const COLLATE_NOCASE: ColumnBuilderCallback = (col) =>
|
||||
@@ -295,7 +294,7 @@ export class NNMigrationProvider implements MigrationProvider {
|
||||
async up(db) {
|
||||
await db
|
||||
.updateTable("notes")
|
||||
.where("id", "in", (eb: ExpressionBuilder<any, string>) =>
|
||||
.where("id", "in", (eb) =>
|
||||
eb
|
||||
.selectFrom("content")
|
||||
.select("noteId as id")
|
||||
|
||||
@@ -21,7 +21,7 @@ import { MaybeDeletedItem, isDeleted } from "../types";
|
||||
import EventManager from "../utils/event-manager";
|
||||
import { DatabaseAccessor, DatabaseCollection, DatabaseSchema } from ".";
|
||||
import { SQLCollection } from "./sql-collection";
|
||||
import { Kysely } from "@streetwriters/kysely";
|
||||
import { Kysely } from "kysely";
|
||||
import { Sanitizer } from "./sanitizer";
|
||||
|
||||
export class SQLCachedCollection<
|
||||
|
||||
@@ -45,7 +45,7 @@ import {
|
||||
SelectQueryBuilder,
|
||||
SqlBool,
|
||||
sql
|
||||
} from "@streetwriters/kysely";
|
||||
} from "kysely";
|
||||
import { VirtualizedGrouping } from "../utils/virtualized-grouping";
|
||||
import { createKeySelector, groupArray } from "../utils/grouping";
|
||||
import { toChunks } from "../utils/array";
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Kysely, sql } from "@streetwriters/kysely";
|
||||
import { Kysely, sql } from "kysely";
|
||||
import { DatabaseSchema, RawDatabaseSchema } from ".";
|
||||
|
||||
export async function createTriggers(db: Kysely<RawDatabaseSchema>) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
format,
|
||||
ILogger
|
||||
} from "@notesnook/logger";
|
||||
import { Kysely, Migration, MigrationProvider } from "@streetwriters/kysely";
|
||||
import { Kysely, Migration, MigrationProvider } from "kysely";
|
||||
import { SQLiteOptions, createDatabase } from "./database";
|
||||
import { toChunks } from "./utils/array";
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import { DATE_FORMATS, DATE_FORMATS_WITHOUT_YEAR } from "../common";
|
||||
|
||||
export type TimeFormat = "12-hour" | "24-hour";
|
||||
|
||||
@@ -69,7 +70,7 @@ export type TimeOptions = {
|
||||
timeFormat: TimeFormat;
|
||||
};
|
||||
export type DateOptions = {
|
||||
type: "date";
|
||||
type: "date" | "date-without-year";
|
||||
dateFormat: string;
|
||||
};
|
||||
export type DateTimeOptions = {
|
||||
@@ -96,6 +97,12 @@ export function formatDate(
|
||||
return dayjs(date).format(getTimeFormat(options.timeFormat));
|
||||
case "date":
|
||||
return dayjs(date).format(options.dateFormat);
|
||||
case "date-without-year": {
|
||||
const format =
|
||||
DATE_FORMATS_WITHOUT_YEAR[DATE_FORMATS.indexOf(options.dateFormat)];
|
||||
if (!format) return dayjs(date).format("MM-DD");
|
||||
return dayjs(date).format(format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
104
packages/editor-mobile/package-lock.json
generated
104
packages/editor-mobile/package-lock.json
generated
@@ -42,76 +42,70 @@
|
||||
"@notesnook/core": "file:../core",
|
||||
"@notesnook/theme": "file:../theme",
|
||||
"@notesnook/ui": "file:../ui",
|
||||
"@social-embed/lib": "^0.1.0-next.7",
|
||||
"@tiptap/core": "2.6.6",
|
||||
"@tiptap/extension-blockquote": "^2.6.6",
|
||||
"@tiptap/extension-bullet-list": "^2.6.6",
|
||||
"@tiptap/extension-character-count": "2.6.6",
|
||||
"@tiptap/extension-code": "^2.6.6",
|
||||
"@tiptap/extension-color": "2.6.6",
|
||||
"@tiptap/extension-font-family": "2.6.6",
|
||||
"@tiptap/extension-heading": "^2.6.6",
|
||||
"@tiptap/extension-history": "2.6.6",
|
||||
"@tiptap/extension-horizontal-rule": "2.6.6",
|
||||
"@tiptap/extension-list-item": "^2.6.6",
|
||||
"@tiptap/extension-list-keymap": "2.6.6",
|
||||
"@tiptap/extension-ordered-list": "^2.6.6",
|
||||
"@tiptap/extension-placeholder": "2.6.6",
|
||||
"@tiptap/extension-subscript": "2.6.6",
|
||||
"@tiptap/extension-superscript": "2.6.6",
|
||||
"@tiptap/extension-table": "2.6.6",
|
||||
"@tiptap/extension-table-cell": "2.6.6",
|
||||
"@tiptap/extension-table-header": "2.6.6",
|
||||
"@tiptap/extension-table-row": "2.6.6",
|
||||
"@tiptap/extension-task-item": "2.6.6",
|
||||
"@tiptap/extension-task-list": "2.6.6",
|
||||
"@tiptap/extension-text-align": "2.6.6",
|
||||
"@tiptap/extension-text-style": "2.6.6",
|
||||
"@tiptap/extension-underline": "2.6.6",
|
||||
"@tiptap/pm": "2.6.6",
|
||||
"@tiptap/starter-kit": "2.6.6",
|
||||
"@social-embed/lib": "^0.0.2-next.1",
|
||||
"@tiptap/core": "2.2.4",
|
||||
"@tiptap/extension-character-count": "2.2.4",
|
||||
"@tiptap/extension-color": "2.2.4",
|
||||
"@tiptap/extension-font-family": "2.2.4",
|
||||
"@tiptap/extension-history": "2.2.4",
|
||||
"@tiptap/extension-horizontal-rule": "2.2.4",
|
||||
"@tiptap/extension-list-keymap": "2.2.4",
|
||||
"@tiptap/extension-placeholder": "2.2.4",
|
||||
"@tiptap/extension-subscript": "2.2.4",
|
||||
"@tiptap/extension-superscript": "2.2.4",
|
||||
"@tiptap/extension-table": "2.2.4",
|
||||
"@tiptap/extension-table-cell": "2.2.4",
|
||||
"@tiptap/extension-table-header": "2.2.4",
|
||||
"@tiptap/extension-table-row": "2.2.4",
|
||||
"@tiptap/extension-task-item": "2.2.4",
|
||||
"@tiptap/extension-task-list": "2.2.4",
|
||||
"@tiptap/extension-text-align": "2.2.4",
|
||||
"@tiptap/extension-text-style": "2.2.4",
|
||||
"@tiptap/extension-underline": "2.2.4",
|
||||
"@tiptap/pm": "2.2.4",
|
||||
"@tiptap/starter-kit": "2.2.4",
|
||||
"alfaaz": "^1.1.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"clipboard-polyfill": "4.1.0",
|
||||
"detect-indent": "^7.0.1",
|
||||
"entities": "^5.0.0",
|
||||
"katex": "0.16.11",
|
||||
"async-mutex": "^0.4.0",
|
||||
"clipboard-polyfill": "4.0.0",
|
||||
"detect-indent": "^7.0.0",
|
||||
"entities": "^4.5.0",
|
||||
"katex": "0.16.9",
|
||||
"linkifyjs": "^4.1.3",
|
||||
"nanoid": "^5.0.7",
|
||||
"nanoid": "^4.0.1",
|
||||
"prism-themes": "^1.9.0",
|
||||
"prosemirror-codemark": "^0.4.2",
|
||||
"prosemirror-view": "1.34.2",
|
||||
"re-resizable": "^6.9.18",
|
||||
"prosemirror-view": "1.33.1",
|
||||
"re-resizable": "^6.9.11",
|
||||
"react-colorful": "^5.6.1",
|
||||
"redent": "^4.0.0",
|
||||
"refractor": "^4.8.1",
|
||||
"strip-indent": "^4.0.0",
|
||||
"unfurl.js": "^6.4.0"
|
||||
"unfurl.js": "^6.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/react": "11.13.3",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@emotion/react": "11.11.1",
|
||||
"@mdi/js": "^7.2.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@theme-ui/components": "^0.16.2",
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/prismjs": "^1.26.4",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-color": "^3.0.12",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@theme-ui/components": "^0.16.1",
|
||||
"@theme-ui/core": "^0.16.1",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/react": "^18.2.39",
|
||||
"@types/react-color": "^3.0.6",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@types/react-modal": "^3.16.3 ",
|
||||
"@types/tinycolor2": "^1.4.6",
|
||||
"framer-motion": "^11.5.4",
|
||||
"happy-dom": "^15.7.4",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"framer-motion": "^10.16.8",
|
||||
"happy-dom": "^8.9.0",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"prosemirror-test-builder": "^1.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"prosemirror-test-builder": "^1.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-modal": "3.16.1",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"vitest": "^2.0.5",
|
||||
"web-vitals": "^4.2.3",
|
||||
"zustand": "4.5.5"
|
||||
"vitest": "^0.29.2",
|
||||
"web-vitals": "^2.1.4",
|
||||
"zustand": "4.4.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": ">=11",
|
||||
|
||||
2729
packages/editor/package-lock.json
generated
2729
packages/editor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,76 +8,70 @@
|
||||
"@notesnook/core": "file:../core",
|
||||
"@notesnook/theme": "file:../theme",
|
||||
"@notesnook/ui": "file:../ui",
|
||||
"@social-embed/lib": "^0.1.0-next.7",
|
||||
"@tiptap/core": "2.6.6",
|
||||
"@tiptap/extension-blockquote": "^2.6.6",
|
||||
"@tiptap/extension-bullet-list": "^2.6.6",
|
||||
"@tiptap/extension-character-count": "2.6.6",
|
||||
"@tiptap/extension-code": "^2.6.6",
|
||||
"@tiptap/extension-color": "2.6.6",
|
||||
"@tiptap/extension-font-family": "2.6.6",
|
||||
"@tiptap/extension-heading": "^2.6.6",
|
||||
"@tiptap/extension-history": "2.6.6",
|
||||
"@tiptap/extension-horizontal-rule": "2.6.6",
|
||||
"@tiptap/extension-list-item": "^2.6.6",
|
||||
"@tiptap/extension-list-keymap": "2.6.6",
|
||||
"@tiptap/extension-ordered-list": "^2.6.6",
|
||||
"@tiptap/extension-placeholder": "2.6.6",
|
||||
"@tiptap/extension-subscript": "2.6.6",
|
||||
"@tiptap/extension-superscript": "2.6.6",
|
||||
"@tiptap/extension-table": "2.6.6",
|
||||
"@tiptap/extension-table-cell": "2.6.6",
|
||||
"@tiptap/extension-table-header": "2.6.6",
|
||||
"@tiptap/extension-table-row": "2.6.6",
|
||||
"@tiptap/extension-task-item": "2.6.6",
|
||||
"@tiptap/extension-task-list": "2.6.6",
|
||||
"@tiptap/extension-text-align": "2.6.6",
|
||||
"@tiptap/extension-text-style": "2.6.6",
|
||||
"@tiptap/extension-underline": "2.6.6",
|
||||
"@tiptap/pm": "2.6.6",
|
||||
"@tiptap/starter-kit": "2.6.6",
|
||||
"@social-embed/lib": "^0.0.2-next.1",
|
||||
"@tiptap/core": "2.2.4",
|
||||
"@tiptap/extension-character-count": "2.2.4",
|
||||
"@tiptap/extension-color": "2.2.4",
|
||||
"@tiptap/extension-font-family": "2.2.4",
|
||||
"@tiptap/extension-history": "2.2.4",
|
||||
"@tiptap/extension-horizontal-rule": "2.2.4",
|
||||
"@tiptap/extension-list-keymap": "2.2.4",
|
||||
"@tiptap/extension-placeholder": "2.2.4",
|
||||
"@tiptap/extension-subscript": "2.2.4",
|
||||
"@tiptap/extension-superscript": "2.2.4",
|
||||
"@tiptap/extension-table": "2.2.4",
|
||||
"@tiptap/extension-table-cell": "2.2.4",
|
||||
"@tiptap/extension-table-header": "2.2.4",
|
||||
"@tiptap/extension-table-row": "2.2.4",
|
||||
"@tiptap/extension-task-item": "2.2.4",
|
||||
"@tiptap/extension-task-list": "2.2.4",
|
||||
"@tiptap/extension-text-align": "2.2.4",
|
||||
"@tiptap/extension-text-style": "2.2.4",
|
||||
"@tiptap/extension-underline": "2.2.4",
|
||||
"@tiptap/pm": "2.2.4",
|
||||
"@tiptap/starter-kit": "2.2.4",
|
||||
"alfaaz": "^1.1.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"clipboard-polyfill": "4.1.0",
|
||||
"detect-indent": "^7.0.1",
|
||||
"entities": "^5.0.0",
|
||||
"katex": "0.16.11",
|
||||
"async-mutex": "^0.4.0",
|
||||
"clipboard-polyfill": "4.0.0",
|
||||
"detect-indent": "^7.0.0",
|
||||
"entities": "^4.5.0",
|
||||
"katex": "0.16.9",
|
||||
"linkifyjs": "^4.1.3",
|
||||
"nanoid": "^5.0.7",
|
||||
"nanoid": "^4.0.1",
|
||||
"prism-themes": "^1.9.0",
|
||||
"prosemirror-codemark": "^0.4.2",
|
||||
"prosemirror-view": "1.34.2",
|
||||
"re-resizable": "^6.9.18",
|
||||
"prosemirror-view": "1.33.1",
|
||||
"re-resizable": "^6.9.11",
|
||||
"react-colorful": "^5.6.1",
|
||||
"redent": "^4.0.0",
|
||||
"refractor": "^4.8.1",
|
||||
"strip-indent": "^4.0.0",
|
||||
"unfurl.js": "^6.4.0"
|
||||
"unfurl.js": "^6.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/react": "11.13.3",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@emotion/react": "11.11.1",
|
||||
"@mdi/js": "^7.2.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@theme-ui/components": "^0.16.2",
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/prismjs": "^1.26.4",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-color": "^3.0.12",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@theme-ui/components": "^0.16.1",
|
||||
"@theme-ui/core": "^0.16.1",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/react": "^18.2.39",
|
||||
"@types/react-color": "^3.0.6",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@types/react-modal": "^3.16.3 ",
|
||||
"@types/tinycolor2": "^1.4.6",
|
||||
"framer-motion": "^11.5.4",
|
||||
"happy-dom": "^15.7.4",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"framer-motion": "^10.16.8",
|
||||
"happy-dom": "^8.9.0",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"prosemirror-test-builder": "^1.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"prosemirror-test-builder": "^1.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-modal": "3.16.1",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"vitest": "^2.0.5",
|
||||
"web-vitals": "^4.2.3",
|
||||
"zustand": "4.5.5"
|
||||
"vitest": "^0.29.2",
|
||||
"web-vitals": "^2.1.4",
|
||||
"zustand": "4.4.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": ">=11",
|
||||
|
||||
334
packages/editor/patches/@tiptap+core+2.2.4.patch
Normal file
334
packages/editor/patches/@tiptap+core+2.2.4.patch
Normal file
@@ -0,0 +1,334 @@
|
||||
diff --git a/node_modules/@tiptap/core/dist/index.cjs b/node_modules/@tiptap/core/dist/index.cjs
|
||||
index 1ea30e0..2291615 100644
|
||||
--- a/node_modules/@tiptap/core/dist/index.cjs
|
||||
+++ b/node_modules/@tiptap/core/dist/index.cjs
|
||||
@@ -383,7 +383,7 @@ function fromString(value) {
|
||||
* @param extensionAttributes List of attributes to inject
|
||||
*/
|
||||
function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
||||
- if (parseRule.style) {
|
||||
+ if (parseRule.style || (!parseRule.attrs && !parseRule.getAttrs && extensionAttributes.length === 0)) {
|
||||
return parseRule;
|
||||
}
|
||||
return {
|
||||
@@ -400,12 +400,10 @@ function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
||||
if (value === null || value === undefined) {
|
||||
return items;
|
||||
}
|
||||
- return {
|
||||
- ...items,
|
||||
- [item.name]: value,
|
||||
- };
|
||||
- }, {});
|
||||
- return { ...oldAttributes, ...newAttributes };
|
||||
+ items[item.name] = value;
|
||||
+ return items;
|
||||
+ }, oldAttributes || {});
|
||||
+ return newAttributes;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1327,7 +1325,7 @@ const cut = (originRange, targetPos) => ({ editor, tr }) => {
|
||||
tr.deleteRange(originRange.from, originRange.to);
|
||||
const newPos = tr.mapping.map(targetPos);
|
||||
tr.insert(newPos, contentSlice.content);
|
||||
- tr.setSelection(new state.TextSelection(tr.doc.resolve(newPos - 1)));
|
||||
+ tr.setSelection(new state.TextSelection(tr.doc.resolve(Math.max(0, newPos - 1))));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1587,24 +1585,11 @@ const insertContent = (value, options) => ({ tr, commands }) => {
|
||||
return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
|
||||
};
|
||||
|
||||
-const removeWhitespaces = (node) => {
|
||||
- const children = node.childNodes;
|
||||
- for (let i = children.length - 1; i >= 0; i -= 1) {
|
||||
- const child = children[i];
|
||||
- if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) {
|
||||
- node.removeChild(child);
|
||||
- }
|
||||
- else if (child.nodeType === 1) {
|
||||
- removeWhitespaces(child);
|
||||
- }
|
||||
- }
|
||||
- return node;
|
||||
-};
|
||||
function elementFromString(value) {
|
||||
// add a wrapper to preserve leading and trailing whitespace
|
||||
const wrappedValue = `<body>${value}</body>`;
|
||||
const html = new window.DOMParser().parseFromString(wrappedValue, 'text/html').body;
|
||||
- return removeWhitespaces(html);
|
||||
+ return html;
|
||||
}
|
||||
|
||||
function createNodeFromContent(content, schema, options) {
|
||||
@@ -1901,9 +1886,24 @@ const lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
||||
return commands$1.lift(state, dispatch);
|
||||
};
|
||||
|
||||
-const liftEmptyBlock = () => ({ state, dispatch }) => {
|
||||
- return commands$1.liftEmptyBlock(state, dispatch);
|
||||
-};
|
||||
+const liftEmptyBlock = () => ({ state, dispatch, editor }) => {
|
||||
+ return commands$1.liftEmptyBlock(state, (tr) => {
|
||||
+ if (!dispatch) return true;
|
||||
+
|
||||
+ const { selection, storedMarks } = state;
|
||||
+ const marks = storedMarks || (selection.$to.parentOffset && selection.$from.marks());
|
||||
+
|
||||
+ if (!marks) return dispatch(tr);
|
||||
+
|
||||
+ const { splittableMarks } = editor.extensionManager;
|
||||
+ const filteredMarks = marks.filter((mark) =>
|
||||
+ splittableMarks.includes(mark.type.name)
|
||||
+ );
|
||||
+ tr.ensureMarks(filteredMarks)
|
||||
+
|
||||
+ return dispatch(tr);
|
||||
+ });
|
||||
+}
|
||||
|
||||
const liftListItem = typeOrName => ({ state, dispatch }) => {
|
||||
const type = getNodeType(typeOrName, state.schema);
|
||||
@@ -3279,16 +3279,20 @@ const Keymap = Extension.create({
|
||||
new state.Plugin({
|
||||
key: new state.PluginKey('clearDocument'),
|
||||
appendTransaction: (transactions, oldState, newState) => {
|
||||
+ const { empty, from, to } = oldState.selection;
|
||||
+ if (empty) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
const docChanges = transactions.some(transaction => transaction.docChanged)
|
||||
- && !oldState.doc.eq(newState.doc);
|
||||
+ && oldState.doc.nodeSize !== newState.doc.nodeSize;
|
||||
if (!docChanges) {
|
||||
return;
|
||||
}
|
||||
- const { empty, from, to } = oldState.selection;
|
||||
const allFrom = state.Selection.atStart(oldState.doc).from;
|
||||
const allEnd = state.Selection.atEnd(oldState.doc).to;
|
||||
const allWasSelected = from === allFrom && to === allEnd;
|
||||
- if (empty || !allWasSelected) {
|
||||
+ if (!allWasSelected) {
|
||||
return;
|
||||
}
|
||||
const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
|
||||
@@ -3788,23 +3792,28 @@ class Editor extends EventEmitter {
|
||||
* Creates a ProseMirror view.
|
||||
*/
|
||||
createView() {
|
||||
- const doc = createDocument(this.options.content, this.schema, this.options.parseOptions);
|
||||
- const selection = resolveFocusPosition(doc, this.options.autofocus);
|
||||
- this.view = new view.EditorView(this.options.element, {
|
||||
+ this.view = new EditorView(this.options.element, {
|
||||
...this.options.editorProps,
|
||||
dispatchTransaction: this.dispatchTransaction.bind(this),
|
||||
- state: state.EditorState.create({
|
||||
- doc,
|
||||
- selection: selection || undefined,
|
||||
- }),
|
||||
+ state: EditorState.create({
|
||||
+ doc: this.schema.topNodeType.create(),
|
||||
+ })
|
||||
});
|
||||
+
|
||||
+ const doc = createDocument(this.options.content, this.schema, this.options.parseOptions);
|
||||
+ const selection = resolveFocusPosition(doc, this.options.autofocus);
|
||||
// `editor.view` is not yet available at this time.
|
||||
// Therefore we will add all plugins and node views directly afterwards.
|
||||
- const newState = this.state.reconfigure({
|
||||
+ const newState = EditorState.create({
|
||||
plugins: this.extensionManager.plugins,
|
||||
+ doc,
|
||||
+ selection
|
||||
+ });
|
||||
+
|
||||
+ this.view.setProps({
|
||||
+ state: newState,
|
||||
+ nodeViews: this.extensionManager.nodeViews
|
||||
});
|
||||
- this.view.updateState(newState);
|
||||
- this.createNodeViews();
|
||||
this.prependClass();
|
||||
// Let’s store the editor instance in the DOM element.
|
||||
// So we’ll have access to it for tests.
|
||||
diff --git a/node_modules/@tiptap/core/dist/index.js b/node_modules/@tiptap/core/dist/index.js
|
||||
index 554e919..28fc1c1 100644
|
||||
--- a/node_modules/@tiptap/core/dist/index.js
|
||||
+++ b/node_modules/@tiptap/core/dist/index.js
|
||||
@@ -379,9 +379,10 @@ function fromString(value) {
|
||||
* @param extensionAttributes List of attributes to inject
|
||||
*/
|
||||
function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
||||
- if (parseRule.style) {
|
||||
+ if (parseRule.style || (!parseRule.attrs && !parseRule.getAttrs && extensionAttributes.length === 0)) {
|
||||
return parseRule;
|
||||
}
|
||||
+
|
||||
return {
|
||||
...parseRule,
|
||||
getAttrs: node => {
|
||||
@@ -396,12 +397,10 @@ function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
||||
if (value === null || value === undefined) {
|
||||
return items;
|
||||
}
|
||||
- return {
|
||||
- ...items,
|
||||
- [item.name]: value,
|
||||
- };
|
||||
- }, {});
|
||||
- return { ...oldAttributes, ...newAttributes };
|
||||
+ items[item.name] = value;
|
||||
+ return items;
|
||||
+ }, oldAttributes || {});
|
||||
+ return newAttributes;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1323,7 +1322,7 @@ const cut = (originRange, targetPos) => ({ editor, tr }) => {
|
||||
tr.deleteRange(originRange.from, originRange.to);
|
||||
const newPos = tr.mapping.map(targetPos);
|
||||
tr.insert(newPos, contentSlice.content);
|
||||
- tr.setSelection(new TextSelection(tr.doc.resolve(newPos - 1)));
|
||||
+ tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(0, newPos - 1))));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1583,24 +1582,11 @@ const insertContent = (value, options) => ({ tr, commands }) => {
|
||||
return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
|
||||
};
|
||||
|
||||
-const removeWhitespaces = (node) => {
|
||||
- const children = node.childNodes;
|
||||
- for (let i = children.length - 1; i >= 0; i -= 1) {
|
||||
- const child = children[i];
|
||||
- if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) {
|
||||
- node.removeChild(child);
|
||||
- }
|
||||
- else if (child.nodeType === 1) {
|
||||
- removeWhitespaces(child);
|
||||
- }
|
||||
- }
|
||||
- return node;
|
||||
-};
|
||||
function elementFromString(value) {
|
||||
// add a wrapper to preserve leading and trailing whitespace
|
||||
const wrappedValue = `<body>${value}</body>`;
|
||||
const html = new window.DOMParser().parseFromString(wrappedValue, 'text/html').body;
|
||||
- return removeWhitespaces(html);
|
||||
+ return html;
|
||||
}
|
||||
|
||||
function createNodeFromContent(content, schema, options) {
|
||||
@@ -1897,9 +1883,24 @@ const lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
||||
return lift$1(state, dispatch);
|
||||
};
|
||||
|
||||
-const liftEmptyBlock = () => ({ state, dispatch }) => {
|
||||
- return liftEmptyBlock$1(state, dispatch);
|
||||
-};
|
||||
+const liftEmptyBlock = () => ({ state, dispatch, editor }) => {
|
||||
+ return liftEmptyBlock$1(state, (tr) => {
|
||||
+ if (!dispatch) return true;
|
||||
+
|
||||
+ const { selection, storedMarks } = state;
|
||||
+ const marks = storedMarks || (selection.$to.parentOffset && selection.$from.marks());
|
||||
+
|
||||
+ if (!marks) return dispatch(tr);
|
||||
+
|
||||
+ const { splittableMarks } = editor.extensionManager;
|
||||
+ const filteredMarks = marks.filter((mark) =>
|
||||
+ splittableMarks.includes(mark.type.name)
|
||||
+ );
|
||||
+ tr.ensureMarks(filteredMarks)
|
||||
+
|
||||
+ return dispatch(tr);
|
||||
+ });
|
||||
+}
|
||||
|
||||
const liftListItem = typeOrName => ({ state, dispatch }) => {
|
||||
const type = getNodeType(typeOrName, state.schema);
|
||||
@@ -3275,16 +3276,20 @@ const Keymap = Extension.create({
|
||||
new Plugin({
|
||||
key: new PluginKey('clearDocument'),
|
||||
appendTransaction: (transactions, oldState, newState) => {
|
||||
+ const { empty, from, to } = oldState.selection;
|
||||
+ if (empty) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
const docChanges = transactions.some(transaction => transaction.docChanged)
|
||||
- && !oldState.doc.eq(newState.doc);
|
||||
+ && oldState.doc.nodeSize !== newState.doc.nodeSize;
|
||||
if (!docChanges) {
|
||||
return;
|
||||
}
|
||||
- const { empty, from, to } = oldState.selection;
|
||||
const allFrom = Selection.atStart(oldState.doc).from;
|
||||
const allEnd = Selection.atEnd(oldState.doc).to;
|
||||
const allWasSelected = from === allFrom && to === allEnd;
|
||||
- if (empty || !allWasSelected) {
|
||||
+ if (!allWasSelected) {
|
||||
return;
|
||||
}
|
||||
const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
|
||||
@@ -3784,23 +3789,28 @@ class Editor extends EventEmitter {
|
||||
* Creates a ProseMirror view.
|
||||
*/
|
||||
createView() {
|
||||
- const doc = createDocument(this.options.content, this.schema, this.options.parseOptions);
|
||||
- const selection = resolveFocusPosition(doc, this.options.autofocus);
|
||||
this.view = new EditorView(this.options.element, {
|
||||
...this.options.editorProps,
|
||||
dispatchTransaction: this.dispatchTransaction.bind(this),
|
||||
state: EditorState.create({
|
||||
- doc,
|
||||
- selection: selection || undefined,
|
||||
- }),
|
||||
+ doc: this.schema.topNodeType.create(),
|
||||
+ })
|
||||
});
|
||||
+
|
||||
+ const doc = createDocument(this.options.content, this.schema, this.options.parseOptions);
|
||||
+ const selection = resolveFocusPosition(doc, this.options.autofocus);
|
||||
// `editor.view` is not yet available at this time.
|
||||
// Therefore we will add all plugins and node views directly afterwards.
|
||||
- const newState = this.state.reconfigure({
|
||||
+ const newState = EditorState.create({
|
||||
plugins: this.extensionManager.plugins,
|
||||
+ doc,
|
||||
+ selection
|
||||
+ });
|
||||
+
|
||||
+ this.view.setProps({
|
||||
+ state: newState,
|
||||
+ nodeViews: this.extensionManager.nodeViews
|
||||
});
|
||||
- this.view.updateState(newState);
|
||||
- this.createNodeViews();
|
||||
this.prependClass();
|
||||
// Let’s store the editor instance in the DOM element.
|
||||
// So we’ll have access to it for tests.
|
||||
diff --git a/node_modules/@tiptap/core/dist/packages/core/src/Editor.d.ts b/node_modules/@tiptap/core/dist/packages/core/src/Editor.d.ts
|
||||
index 55d710f..e9698f5 100644
|
||||
--- a/node_modules/@tiptap/core/dist/packages/core/src/Editor.d.ts
|
||||
+++ b/node_modules/@tiptap/core/dist/packages/core/src/Editor.d.ts
|
||||
@@ -7,6 +7,7 @@ import * as extensions from './extensions/index.js';
|
||||
import { NodePos } from './NodePos.js';
|
||||
import { CanCommands, ChainedCommands, EditorEvents, EditorOptions, JSONContent, SingleCommands, TextSerializer } from './types.js';
|
||||
export { extensions };
|
||||
+export interface EditorStorage extends Record<string, any> { }
|
||||
export interface HTMLElement {
|
||||
editor?: Editor;
|
||||
}
|
||||
@@ -23,7 +24,7 @@ export declare class Editor extends EventEmitter<EditorEvents> {
|
||||
/**
|
||||
* Returns the editor storage.
|
||||
*/
|
||||
- get storage(): Record<string, any>;
|
||||
+ get storage(): EditorStorage;
|
||||
/**
|
||||
* An object of all registered commands.
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/@tiptap/extension-list-keymap/dist/index.cjs b/node_modules/@tiptap/extension-list-keymap/dist/index.cjs
|
||||
index 0f8ae36..2f715b5 100644
|
||||
index 9cd822f..1539b13 100644
|
||||
--- a/node_modules/@tiptap/extension-list-keymap/dist/index.cjs
|
||||
+++ b/node_modules/@tiptap/extension-list-keymap/dist/index.cjs
|
||||
@@ -82,7 +82,9 @@ const handleBackspace = (editor, name, parentListTypes) => {
|
||||
@@ -14,7 +14,7 @@ index 0f8ae36..2f715b5 100644
|
||||
const listDescendants = [];
|
||||
$listPos.node().descendants((node, pos) => {
|
||||
diff --git a/node_modules/@tiptap/extension-list-keymap/dist/index.js b/node_modules/@tiptap/extension-list-keymap/dist/index.js
|
||||
index f7ab1e4..8645c44 100644
|
||||
index e759826..11a385f 100644
|
||||
--- a/node_modules/@tiptap/extension-list-keymap/dist/index.js
|
||||
+++ b/node_modules/@tiptap/extension-list-keymap/dist/index.js
|
||||
@@ -78,7 +78,9 @@ const handleBackspace = (editor, name, parentListTypes) => {
|
||||
File diff suppressed because one or more lines are too long
7
packages/editor/patches/katex+0.16.9.patch
Normal file
7
packages/editor/patches/katex+0.16.9.patch
Normal file
File diff suppressed because one or more lines are too long
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/prosemirror-model/dist/index.cjs b/node_modules/prosemirror-model/dist/index.cjs
|
||||
index aa31355..dcb4a75 100644
|
||||
index 1c45f1c..c92ec8d 100644
|
||||
--- a/node_modules/prosemirror-model/dist/index.cjs
|
||||
+++ b/node_modules/prosemirror-model/dist/index.cjs
|
||||
@@ -95,6 +95,7 @@ var Fragment = function () {
|
||||
@@ -98,6 +98,7 @@ var Fragment = function () {
|
||||
var nodeStart = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
||||
var parent = arguments.length > 4 ? arguments[4] : undefined;
|
||||
for (var i = 0, pos = 0; pos < to; i++) {
|
||||
@@ -11,7 +11,7 @@ index aa31355..dcb4a75 100644
|
||||
end = pos + child.nodeSize;
|
||||
if (end > from && f(child, nodeStart + pos, parent || null, i) !== false && child.content.size) {
|
||||
diff --git a/node_modules/prosemirror-model/dist/index.js b/node_modules/prosemirror-model/dist/index.js
|
||||
index 0097d9f..44f7d4a 100644
|
||||
index 9c37a40..a215c60 100644
|
||||
--- a/node_modules/prosemirror-model/dist/index.js
|
||||
+++ b/node_modules/prosemirror-model/dist/index.js
|
||||
@@ -84,6 +84,7 @@ class Fragment {
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/prosemirror-view/dist/index.cjs b/node_modules/prosemirror-view/dist/index.cjs
|
||||
index 8ea57c7..aeda01d 100644
|
||||
index 81a331c..6e60d39 100644
|
||||
--- a/node_modules/prosemirror-view/dist/index.cjs
|
||||
+++ b/node_modules/prosemirror-view/dist/index.cjs
|
||||
@@ -3456,7 +3456,7 @@ editHandlers.drop = function (view, _event) {
|
||||
@@ -3380,7 +3380,7 @@ editHandlers.drop = function (view, _event) {
|
||||
});
|
||||
tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
|
||||
}
|
||||
@@ -12,10 +12,10 @@ index 8ea57c7..aeda01d 100644
|
||||
};
|
||||
handlers.focus = function (view) {
|
||||
diff --git a/node_modules/prosemirror-view/dist/index.js b/node_modules/prosemirror-view/dist/index.js
|
||||
index 9583dc3..991bf0a 100644
|
||||
index e076a13..2a0fea5 100644
|
||||
--- a/node_modules/prosemirror-view/dist/index.js
|
||||
+++ b/node_modules/prosemirror-view/dist/index.js
|
||||
@@ -3731,7 +3731,7 @@ editHandlers.drop = (view, _event) => {
|
||||
@@ -3647,7 +3647,7 @@ editHandlers.drop = (view, _event) => {
|
||||
tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo);
|
||||
tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import React, {
|
||||
useEffect
|
||||
} from "react";
|
||||
import { MenuItem, Icon, MenuButton, MenuSeparator } from "@notesnook/ui";
|
||||
import { Box, Button, Flex, Text } from "@theme-ui/components";
|
||||
import { Box, Button, Flex, Text, FlexProps } from "@theme-ui/components";
|
||||
import { Icons } from "../../toolbar/icons";
|
||||
import Modal from "react-modal";
|
||||
import {
|
||||
@@ -38,7 +38,9 @@ import {
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { EmotionThemeProvider, Theme } from "@notesnook/theme";
|
||||
|
||||
const AnimatedFlex = motion(Flex);
|
||||
const AnimatedFlex = motion(
|
||||
Flex as React.FunctionComponent<Omit<FlexProps, "onDrag" | "onDragEnd">>
|
||||
);
|
||||
|
||||
type ActionSheetHistoryItem = {
|
||||
title?: string;
|
||||
|
||||
@@ -22,8 +22,8 @@ import { Node } from "@tiptap/pm/model";
|
||||
import { Plugin } from "@tiptap/pm/state";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
const NESTED_BLOCK_ID_TYPES = ["callout"];
|
||||
const BLOCK_ID_TYPES = [
|
||||
const NESTED_BLOCK_ID_TYPES = new Set(["callout"]);
|
||||
const BLOCK_ID_TYPES = new Set([
|
||||
"paragraph",
|
||||
"heading",
|
||||
"blockquote",
|
||||
@@ -39,7 +39,7 @@ const BLOCK_ID_TYPES = [
|
||||
"mathBlock",
|
||||
"webclip",
|
||||
"embed"
|
||||
];
|
||||
]);
|
||||
|
||||
export const BlockId = Extension.create<any, { seen: WeakSet<Node> }>({
|
||||
name: "blockId",
|
||||
@@ -86,11 +86,11 @@ export const BlockId = Extension.create<any, { seen: WeakSet<Node> }>({
|
||||
if (seen.has(n)) return;
|
||||
seen.add(n);
|
||||
|
||||
if (!n.isBlock || !BLOCK_ID_TYPES.includes(n.type.name)) return;
|
||||
if (!n.isBlock || !BLOCK_ID_TYPES.has(n.type.name)) return;
|
||||
if (!n.attrs.blockId)
|
||||
blocksWithoutBlockId.push({ node: n, pos: offset });
|
||||
|
||||
if (NESTED_BLOCK_ID_TYPES.includes(n.type.name))
|
||||
if (NESTED_BLOCK_ID_TYPES.has(n.type.name))
|
||||
n.forEach((n, pos) => addBlocks(n, offset + pos + 1));
|
||||
});
|
||||
if (blocksWithoutBlockId.length > 0) {
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`convert br tags to paragraphs 1`] = `"<p>line 1</p><p data-spacing="single">line 2</p>"`;
|
||||
exports[`convert br tags to paragraphs 1`] = `"<p>line 1</p><p data-spacing=\\"single\\">line 2</p>"`;
|
||||
|
||||
exports[`convert br tags to paragraphs 2`] = `"<p>line <em>1</em></p><p data-spacing="single"><em>line</em> 2</p>"`;
|
||||
exports[`convert br tags to paragraphs 2`] = `"<p>line <em>1</em></p><p data-spacing=\\"single\\"><em>line</em> 2</p>"`;
|
||||
|
||||
exports[`convert br tags to paragraphs 3`] = `"<p>line <span><em>1</em></span></p><p data-spacing="single"><span><em>line</em></span> 2</p>"`;
|
||||
exports[`convert br tags to paragraphs 3`] = `"<p>line <span><em>1</em></span></p><p data-spacing=\\"single\\"><span><em>line</em></span> 2</p>"`;
|
||||
|
||||
exports[`convert br tags to paragraphs 4`] = `"<p>line <span><em>1</em></span></p><p data-spacing="single"><span><em>line</em></span> 2</p>"`;
|
||||
exports[`convert br tags to paragraphs 4`] = `"<p>line <span><em>1</em></span></p><p data-spacing=\\"single\\"><span><em>line</em></span> 2</p>"`;
|
||||
|
||||
exports[`convert br tags to paragraphs 5`] = `"<p></p>"`;
|
||||
|
||||
exports[`convert br tags to paragraphs 6`] = `
|
||||
"<p data-spacing="single">A troll, they call me, but I have no wish<!--StartFragment-->
|
||||
</p><p data-spacing="single">
|
||||
to be associated with those dolls</p><p data-spacing="single">
|
||||
</p><p data-spacing="single">
|
||||
We lack religion, purpose, politics,</p><p data-spacing="single">
|
||||
"<p data-spacing=\\"single\\">A troll, they call me, but I have no wish<!--StartFragment-->
|
||||
</p><p data-spacing=\\"single\\">
|
||||
to be associated with those dolls</p><p data-spacing=\\"single\\">
|
||||
</p><p data-spacing=\\"single\\">
|
||||
We lack religion, purpose, politics,</p><p data-spacing=\\"single\\">
|
||||
and yet, we somehow manage to get by.</p>"
|
||||
`;
|
||||
|
||||
exports[`convert br tags to paragraphs 7`] = `
|
||||
"<!--StartFragment--><p dir="auto">When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.</p><p data-spacing="single">
|
||||
"<!--StartFragment--><p dir=\\"auto\\">When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.</p><p data-spacing=\\"single\\">
|
||||
Also when I share the selection to Notesnook via the share functionality from Android, I have the same issue.</p>
|
||||
<hr>
|
||||
<p dir="auto"><strong>Device information:</strong></p><p data-spacing="single">
|
||||
App version: 2.3.0</p><p data-spacing="single">
|
||||
Platform: android</p><p data-spacing="single">
|
||||
Model: OnePlus-CPH2409-31</p><p data-spacing="single">
|
||||
Pro: true</p><p data-spacing="single">
|
||||
<p dir=\\"auto\\"><strong>Device information:</strong></p><p data-spacing=\\"single\\">
|
||||
App version: 2.3.0</p><p data-spacing=\\"single\\">
|
||||
Platform: android</p><p data-spacing=\\"single\\">
|
||||
Model: OnePlus-CPH2409-31</p><p data-spacing=\\"single\\">
|
||||
Pro: true</p><p data-spacing=\\"single\\">
|
||||
Logged in: yes</p><!--EndFragment-->"
|
||||
`;
|
||||
|
||||
exports[`convert br tags to paragraphs 8`] = `
|
||||
"<!--StartFragment--><span class="css-901oao css-16my406 r-poiln3 r-bcqeeo r-qvutc0">Why switch from Gmail?
|
||||
"<!--StartFragment--><span class=\\"css-901oao css-16my406 r-poiln3 r-bcqeeo r-qvutc0\\">Why switch from Gmail?
|
||||
|
||||
Not sacrificing features for more privacy, prefer using one app, in many public groups and channels (Telegram)
|
||||
|
||||
@@ -43,10 +43,10 @@ exports[`convert br tags to paragraphs 8`] = `
|
||||
|
||||
exports[`convert br tags to paragraphs 9`] = `
|
||||
"<div>
|
||||
<p style="line-height: 100%; margin-bottom: 0in">
|
||||
<p style=\\"line-height: 100%; margin-bottom: 0in\\">
|
||||
I am not talk9ing to you</p>
|
||||
<p style="line-height: 100%; margin-bottom: 0in"></p>
|
||||
<p style="line-height: 100%; margin-bottom: 0in">I am not talk9ing to
|
||||
<p style=\\"line-height: 100%; margin-bottom: 0in\\"></p>
|
||||
<p style=\\"line-height: 100%; margin-bottom: 0in\\">I am not talk9ing to
|
||||
you</p>
|
||||
|
||||
</div>"
|
||||
@@ -54,8 +54,8 @@ exports[`convert br tags to paragraphs 9`] = `
|
||||
|
||||
exports[`convert br tags to paragraphs 10`] = `
|
||||
"<div>
|
||||
<p style="line-height: 100%; margin-bottom: 0in">
|
||||
I am not talking to you</p><p data-spacing="single">
|
||||
<p style=\\"line-height: 100%; margin-bottom: 0in\\">
|
||||
I am not talking to you</p><p data-spacing=\\"single\\">
|
||||
</p>
|
||||
<p>I am talking to you</p>
|
||||
</div>"
|
||||
@@ -63,32 +63,32 @@ exports[`convert br tags to paragraphs 10`] = `
|
||||
|
||||
exports[`convert br tags to paragraphs 11`] = `
|
||||
"<div>
|
||||
<!--StartFragment--><p><span>Hello</span></p><p data-spacing="single"></p><p data-spacing="single"></p><p data-spacing="single"></p><p data-spacing="single"></p><p data-spacing="single"></p><p data-spacing="single"><span>world</span></p><!--EndFragment-->
|
||||
<!--StartFragment--><p><span>Hello</span></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"><span>world</span></p><!--EndFragment-->
|
||||
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`convert br tags to paragraphs 12`] = `
|
||||
"<div>
|
||||
<!--StartFragment--><meta charset="utf-8"><h1><span>Write notes</span></h1><p data-spacing="single"></p><p dir="ltr" data-spacing="single"><span>Welcome of </span><a><span>Notesnook</span></a><span>, an syncing.</span></p><p data-spacing="single"></p><p dir="ltr" data-spacing="single"><span>Enjoy the read!</span></p><p data-spacing="single"></p><p dir="ltr" data-spacing="single"><span><span><img></span></span></p><p data-spacing="single"></p><p dir="ltr" data-spacing="single"><span>vision?</span></p><p data-spacing="single"></p><p dir="ltr" data-spacing="single"><span>everyone means</span></p><!--EndFragment-->
|
||||
<!--StartFragment--><meta charset=\\"utf-8\\"><h1><span>Write notes</span></h1><p data-spacing=\\"single\\"></p><p dir=\\"ltr\\" data-spacing=\\"single\\"><span>Welcome of </span><a><span>Notesnook</span></a><span>, an syncing.</span></p><p data-spacing=\\"single\\"></p><p dir=\\"ltr\\" data-spacing=\\"single\\"><span>Enjoy the read!</span></p><p data-spacing=\\"single\\"></p><p dir=\\"ltr\\" data-spacing=\\"single\\"><span><span><img></span></span></p><p data-spacing=\\"single\\"></p><p dir=\\"ltr\\" data-spacing=\\"single\\"><span>vision?</span></p><p data-spacing=\\"single\\"></p><p dir=\\"ltr\\" data-spacing=\\"single\\"><span>everyone means</span></p><!--EndFragment-->
|
||||
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`convert br tags to paragraphs 13`] = `"<ul xmlns="http://www.w3.org/1999/xhtml" data-block-id="A9jEKaAm" class="checklist"><li class="checklist--item"><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a>hello <a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></li><li class="checklist--item"><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></li><li class="checklist--item"><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hellohello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello hello hello</a></p><p data-spacing="single"><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></p><a target="_blank" rel="noopener noreferrer nofollow" href="https://google.com">hello</a></li><li class="checklist--item">vsvdsavdsa</li><li class="checklist--item">vadsvasdv</li></ul><p xmlns="http://www.w3.org/1999/xhtml" data-block-id="CuscJzDm" data-spacing="double"></p>"`;
|
||||
exports[`convert br tags to paragraphs 13`] = `"<ul xmlns=\\"http://www.w3.org/1999/xhtml\\" data-block-id=\\"A9jEKaAm\\" class=\\"checklist\\"><li class=\\"checklist--item\\"><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a>hello <a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></li><li class=\\"checklist--item\\"><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></li><li class=\\"checklist--item\\"><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hellohello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello hello hello</a></p><p data-spacing=\\"single\\"><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></p><a target=\\"_blank\\" rel=\\"noopener noreferrer nofollow\\" href=\\"https://google.com\\">hello</a></li><li class=\\"checklist--item\\">vsvdsavdsa</li><li class=\\"checklist--item\\">vadsvasdv</li></ul><p xmlns=\\"http://www.w3.org/1999/xhtml\\" data-block-id=\\"CuscJzDm\\" data-spacing=\\"double\\"></p>"`;
|
||||
|
||||
exports[`convert google docs checklist 1`] = `
|
||||
"<div>
|
||||
<!--StartFragment--><meta charset="utf-8"><ul id="docs-internal-guid-0d9a5db3-7fff-ab55-e7ca-b178e1031970" class="checklist"><li dir="ltr" role="checkbox" aria-checked="false" aria-level="1" class="checklist--item"><p dir="ltr" role="presentation"><span>Adsjkfhasdf</span></p></li><li dir="ltr" role="checkbox" aria-checked="false" aria-level="1" class="checklist--item"><p dir="ltr" role="presentation"><span>Asdfsadf</span></p></li><li dir="ltr" role="checkbox" aria-checked="true" aria-level="1" class="checklist--item checked"><p dir="ltr" role="presentation"><span>Asdfsda</span></p></li><li dir="ltr" role="checkbox" aria-checked="true" aria-level="1" class="checklist--item checked"><p dir="ltr" role="presentation"><span>Fasd</span></p></li><li dir="ltr" role="checkbox" aria-checked="true" aria-level="1" class="checklist--item checked"><p dir="ltr" role="presentation"><span>Fasd</span></p></li><li dir="ltr" role="checkbox" aria-checked="false" aria-level="1" class="checklist--item"><p dir="ltr" role="presentation"><span>F</span></p></li><li dir="ltr" role="checkbox" aria-checked="true" aria-level="1" class="checklist--item checked"><p dir="ltr" role="presentation"><span>akcasb</span></p></li><ul class="checklist"><li dir="ltr" role="checkbox" aria-checked="true" aria-level="2" class="checklist--item checked"><p dir="ltr" role="presentation"><span>Asdf</span></p></li><li dir="ltr" role="checkbox" aria-checked="false" aria-level="2" class="checklist--item"><p dir="ltr" role="presentation"><span>Asdcasdc</span></p></li><li dir="ltr" role="checkbox" aria-checked="false" aria-level="2" class="checklist--item"><p dir="ltr" role="presentation"><span>sdac</span></p></li></ul><li dir="ltr" role="checkbox" aria-checked="false" aria-level="1" class="checklist--item"><p dir="ltr" role="presentation"><span>Asdfsda</span></p></li></ul><!--EndFragment-->
|
||||
<!--StartFragment--><meta charset=\\"utf-8\\"><ul id=\\"docs-internal-guid-0d9a5db3-7fff-ab55-e7ca-b178e1031970\\" class=\\"checklist\\"><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"1\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Adsjkfhasdf</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"1\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Asdfsadf</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"true\\" aria-level=\\"1\\" class=\\"checklist--item checked\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Asdfsda</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"true\\" aria-level=\\"1\\" class=\\"checklist--item checked\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Fasd</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"true\\" aria-level=\\"1\\" class=\\"checklist--item checked\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Fasd</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"1\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>F</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"true\\" aria-level=\\"1\\" class=\\"checklist--item checked\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>akcasb</span></p></li><ul class=\\"checklist\\"><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"true\\" aria-level=\\"2\\" class=\\"checklist--item checked\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Asdf</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"2\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Asdcasdc</span></p></li><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"2\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>sdac</span></p></li></ul><li dir=\\"ltr\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-level=\\"1\\" class=\\"checklist--item\\"><p dir=\\"ltr\\" role=\\"presentation\\"><span>Asdfsda</span></p></li></ul><!--EndFragment-->
|
||||
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`properly format codeblocks 1`] = `
|
||||
"<div>
|
||||
<!--StartFragment--><p>Sure! Here's an implementation of a word counter for Thai that considers each syllable consisting of a consonant sound followed by a vowel sound as a word:</p><pre><code>javascript</code></pre><pre class="language-javascript"><code>function countThaiWords(text) {
|
||||
<!--StartFragment--><p>Sure! Here's an implementation of a word counter for Thai that considers each syllable consisting of a consonant sound followed by a vowel sound as a word:</p><pre><code>javascript</code></pre><pre class=\\"language-javascript\\"><code>function countThaiWords(text) {
|
||||
// define a regular expression to match Thai syllables
|
||||
const thaiSyllableRegex = /[ก-ฺเ-๛]+[-]?/g;
|
||||
const thaiSyllableRegex = /[ก-ฺเ-๛]+[฀-๿]?/g;
|
||||
|
||||
// count the number of matches of the Thai syllable regex in the text
|
||||
const matches = text.match(thaiSyllableRegex) || [];
|
||||
@@ -99,9 +99,9 @@ exports[`properly format codeblocks 1`] = `
|
||||
}
|
||||
|
||||
// example usage
|
||||
const text = "สวัสดีค่ะยินดีต้อนรับเข้าสู่โลกของฉัน";
|
||||
const text = "สวัสดีค่ะยินดีต้อนรับเข้าสู่โลกของฉัน";
|
||||
const wordCount = countThaiWords(text);
|
||||
console.log(\`Word count: \${wordCount}\`);
|
||||
console.log(\`Word count: ${wordCount}\`);
|
||||
// output: Word count: 9
|
||||
</code></pre><p>This implementation defines a regular expression to match Thai syllables, which are composed of one or more Thai characters. It then uses the <code>match</code> function of the <code>String</code> object to count the number of matches of the Thai syllable regex in the input text.</p><p>Note that this implementation assumes that each syllable consisting of a consonant sound followed by a vowel sound is considered a word in Thai. This may not always be accurate, as some words in Thai may consist of multiple syllables, and some syllables may be used as prefixes or suffixes to modify other words. However, this approach should work well for many cases where each syllable is considered a separate word.</p><!--EndFragment-->
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`convert text to html 1`] = `"<p data-spacing="single">Hello</p><p data-spacing="single">world</p>"`;
|
||||
exports[`convert text to html 1`] = `"<p data-spacing=\\"single\\">Hello</p><p data-spacing=\\"single\\">world</p>"`;
|
||||
|
||||
exports[`convert text to html 2`] = `"<p data-spacing="single">What</p><p data-spacing="single"></p><p data-spacing="single"></p><p data-spacing="single">NO!</p>"`;
|
||||
exports[`convert text to html 2`] = `"<p data-spacing=\\"single\\">What</p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\"></p><p data-spacing=\\"single\\">NO!</p>"`;
|
||||
|
||||
exports[`convert text to html 3`] = `"<p data-spacing="single">Hello</p><p data-spacing="single">World</p><p data-spacing="single">what?</p><p data-spacing="single">Nay!</p>"`;
|
||||
exports[`convert text to html 3`] = `"<p data-spacing=\\"single\\">Hello</p><p data-spacing=\\"single\\">World</p><p data-spacing=\\"single\\">what?</p><p data-spacing=\\"single\\">Nay!</p>"`;
|
||||
|
||||
@@ -43,7 +43,6 @@ exports[`copying multiple lists shouldn't copy only the first list 1`] = `
|
||||
"attrs": {
|
||||
"listType": "",
|
||||
"start": 1,
|
||||
"type": undefined,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
@@ -67,7 +66,6 @@ exports[`copying multiple lists shouldn't copy only the first list 1`] = `
|
||||
"attrs": {
|
||||
"listType": "",
|
||||
"start": 1,
|
||||
"type": undefined,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
@@ -91,7 +89,6 @@ exports[`copying multiple lists shouldn't copy only the first list 1`] = `
|
||||
"attrs": {
|
||||
"listType": "",
|
||||
"start": 1,
|
||||
"type": undefined,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
|
||||
@@ -234,20 +234,11 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
|
||||
},
|
||||
toggleCodeBlock:
|
||||
(attributes) =>
|
||||
({ commands, state, tr }) => {
|
||||
const isInsideCodeBlock = this.editor.isActive(this.type.name);
|
||||
if (!isInsideCodeBlock) {
|
||||
const { from, to } = state.selection;
|
||||
const text = state.doc.textBetween(from, to, "\n");
|
||||
tr.replaceSelectionWith(
|
||||
this.type.create(
|
||||
{ ...attributes, id: createCodeblockId() },
|
||||
state.schema.text(text)
|
||||
)
|
||||
);
|
||||
return commands.setTextSelection({ from, to: tr.mapping.map(to) });
|
||||
}
|
||||
return commands.clearNodes();
|
||||
({ commands }) => {
|
||||
return commands.toggleNode(this.name, "paragraph", {
|
||||
...attributes,
|
||||
id: createCodeblockId()
|
||||
});
|
||||
},
|
||||
changeCodeBlockIndentation:
|
||||
(options) =>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -33,17 +33,6 @@ const CODEBLOCKS_HTML = h("div", [
|
||||
})
|
||||
]).innerHTML;
|
||||
|
||||
const CODE_PARAGRAPH = `function helloWorld() {
|
||||
console.log('Hello, World!');
|
||||
}`;
|
||||
|
||||
interface DocumentNode {
|
||||
type: string;
|
||||
attrs?: { [key: string]: any };
|
||||
content?: DocumentNode[];
|
||||
text?: string;
|
||||
}
|
||||
|
||||
test("codeblocks should get highlighted on init", async () => {
|
||||
const editorElement = h("div");
|
||||
createEditor({
|
||||
@@ -254,73 +243,3 @@ test("Switching codeblock language should register the new language", async () =
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
expect(refractor.registered("java")).toBe(true);
|
||||
});
|
||||
|
||||
test("Toggling multiple paragraphs into a codeblock should make one codeblock", async () => {
|
||||
const editorElement = h("div");
|
||||
const { editor } = createEditor({
|
||||
element: editorElement,
|
||||
initialContent: CODE_PARAGRAPH,
|
||||
extensions: {
|
||||
codeblock: CodeBlock,
|
||||
codeBlock: false,
|
||||
code: false
|
||||
}
|
||||
});
|
||||
|
||||
const docLength = editor.state.doc.nodeSize - 2;
|
||||
|
||||
editor.commands.setTextSelection({ from: 0, to: docLength });
|
||||
editor.commands.toggleCodeBlock();
|
||||
editor.commands.updateAttributes(CodeBlock.name, { language: "javascript" });
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
expect(editorElement.outerHTML).toMatchSnapshot();
|
||||
|
||||
const docJSON = editor.state.doc.toJSON();
|
||||
const content = docJSON.content;
|
||||
const codeBlockNodes = content.filter(
|
||||
(node: DocumentNode) => node.type === "codeblock"
|
||||
);
|
||||
const otherNodes = content.filter(
|
||||
(node: DocumentNode) => node.type !== "codeblock"
|
||||
);
|
||||
|
||||
expect(codeBlockNodes).toHaveLength(1);
|
||||
expect(otherNodes).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("Toggling from a codeblock should make codeblock disappear", async () => {
|
||||
const editorElement = document.createElement("div");
|
||||
const { editor } = createEditor({
|
||||
element: editorElement,
|
||||
initialContent: CODEBLOCKS_HTML,
|
||||
extensions: {
|
||||
codeblock: CodeBlock,
|
||||
codeBlock: false,
|
||||
code: false
|
||||
}
|
||||
});
|
||||
|
||||
const docLength = editor.state.doc.nodeSize - 2;
|
||||
|
||||
editor.commands.setTextSelection({ from: 0, to: docLength });
|
||||
|
||||
editor.commands.toggleCodeBlock();
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
expect(editorElement.outerHTML).toMatchSnapshot();
|
||||
|
||||
const docJSON = editor.state.doc.toJSON();
|
||||
const content = docJSON.content;
|
||||
const codeBlockNodes = content.filter(
|
||||
(node: DocumentNode) => node.type === "codeblock"
|
||||
);
|
||||
const paragraphNodes = content.filter(
|
||||
(node: DocumentNode) => node.type === "paragraph"
|
||||
);
|
||||
|
||||
expect(codeBlockNodes).toHaveLength(0);
|
||||
expect(paragraphNodes).toHaveLength(2);
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ import { Extension } from "@tiptap/core";
|
||||
import { isInTable } from "@tiptap/pm/tables";
|
||||
import { isListActive } from "../../utils/prosemirror";
|
||||
import { CodeBlock } from "../code-block";
|
||||
import { showLinkPopup } from "../../toolbar/popups/link-popup";
|
||||
|
||||
export const KeyMap = Extension.create({
|
||||
name: "key-map",
|
||||
@@ -66,10 +65,6 @@ export const KeyMap = Extension.create({
|
||||
});
|
||||
});
|
||||
return true;
|
||||
},
|
||||
"Mod-k": ({ editor }) => {
|
||||
showLinkPopup(editor);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
} from "@tiptap/core";
|
||||
import { Plugin, TextSelection } from "@tiptap/pm/state";
|
||||
import { find, registerCustomProtocol, reset } from "linkifyjs";
|
||||
|
||||
import { autolink } from "./helpers/autolink";
|
||||
import { clickHandler } from "./helpers/clickHandler";
|
||||
import { pasteHandler } from "./helpers/pasteHandler";
|
||||
@@ -289,22 +290,6 @@ export const Link = Mark.create<LinkOptions>({
|
||||
}
|
||||
|
||||
return plugins;
|
||||
},
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
Space: ({ editor }) => {
|
||||
const { from, to } = editor.state.selection;
|
||||
|
||||
if (!editor.state.doc.rangeHasMark(from, to + 1, this.type)) {
|
||||
const { tr } = editor.state;
|
||||
tr.removeStoredMark(editor.schema.marks.link);
|
||||
editor.view.dispatch(tr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { createEditor, h, ul, li } from "../../../../test-utils";
|
||||
import { createEditor, h, ul, li } from "@/test-utils";
|
||||
import { test, expect } from "vitest";
|
||||
import { TaskListNode } from "../index";
|
||||
import { TaskItemNode } from "../../task-item";
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NodeWithOffset } from "../../../utils/prosemirror";
|
||||
import { NodeWithOffset } from "@/src/utils/prosemirror";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
const HoverPopupContext = createContext<{
|
||||
|
||||
@@ -21,12 +21,7 @@ import { Input } from "@theme-ui/components";
|
||||
import { Flex } from "@theme-ui/components";
|
||||
import { useRefValue } from "../../hooks/use-ref-value";
|
||||
import { Popup } from "../components/popup";
|
||||
import { isInternalLink, LinkDefinition } from "../tools/link";
|
||||
import { showPopup } from "../../components/popup-presenter";
|
||||
import Link, { LinkAttributes } from "../../extensions/link";
|
||||
import { ImageNode } from "../../extensions/image";
|
||||
import { findMark, selectionToOffset } from "../../utils/prosemirror";
|
||||
import { Editor, getMarkAttributes } from "@tiptap/core";
|
||||
import { LinkDefinition } from "../tools/link";
|
||||
|
||||
export type LinkPopupProps = {
|
||||
link?: LinkDefinition;
|
||||
@@ -51,17 +46,13 @@ export function LinkPopup(props: LinkPopupProps) {
|
||||
onClose={onClose}
|
||||
action={{
|
||||
title: isEditing ? "Save edits" : "Insert link",
|
||||
onClick: () => onDone(link.current)
|
||||
onClick: () => {
|
||||
if (!link.current) return;
|
||||
onDone(link.current);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
sx={{ p: 1, flexDirection: "column", width: ["auto", 250] }}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
onDone(link.current);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex sx={{ p: 1, flexDirection: "column", width: ["auto", 250] }}>
|
||||
{!isImageActive && (
|
||||
<Input
|
||||
type="text"
|
||||
@@ -89,60 +80,3 @@ export function LinkPopup(props: LinkPopupProps) {
|
||||
</Popup>
|
||||
);
|
||||
}
|
||||
|
||||
export async function showLinkPopup(editor: Editor) {
|
||||
const isActive = editor.isActive(Link.name);
|
||||
const isImageActive = editor.isActive(ImageNode.name);
|
||||
const selectedNode = selectionToOffset(editor.state);
|
||||
const link = selectedNode?.node
|
||||
? findMark(selectedNode.node, Link.name)
|
||||
: null;
|
||||
const attrs = link?.attrs || getMarkAttributes(editor.state, Link.name);
|
||||
const selectedText = editor.state.doc.textBetween(
|
||||
editor.state.selection.from,
|
||||
editor.state.selection.to
|
||||
);
|
||||
if (isInternalLink(attrs.href)) {
|
||||
const link = await editor.storage.createInternalLink?.(
|
||||
attrs as LinkAttributes
|
||||
);
|
||||
if (!link) return;
|
||||
if (isActive) {
|
||||
const { from, to } = editor.state.selection;
|
||||
if (selectedNode) editor.commands.setTextSelection(selectedNode);
|
||||
editor.commands.setLink(link);
|
||||
if (selectedNode) editor.commands.setTextSelection({ from, to });
|
||||
} else {
|
||||
editor.commands.setLink({ ...link, title: selectedText || link.title });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
showPopup({
|
||||
popup: (close) => (
|
||||
<LinkPopup
|
||||
link={
|
||||
selectedNode && selectedNode.node
|
||||
? {
|
||||
title: isActive ? selectedNode.node.textContent : selectedText,
|
||||
href: link?.attrs.href || ""
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onClose={close}
|
||||
onDone={(link) => {
|
||||
if (isActive) {
|
||||
if (selectedNode)
|
||||
editor.chain().focus().setTextSelection(selectedNode).run();
|
||||
editor.commands.setLink(link);
|
||||
} else editor.commands.toggleLink(link);
|
||||
close();
|
||||
}}
|
||||
isEditing={isActive}
|
||||
isImageActive={isImageActive}
|
||||
/>
|
||||
),
|
||||
mobile: "sheet",
|
||||
desktop: "popup"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { MoreTools } from "../components/more-tools";
|
||||
import { useToolbarLocation } from "../stores/toolbar-store";
|
||||
import { ImageProperties as ImagePropertiesPopup } from "../popups/image-properties";
|
||||
import { findSelectedNode } from "../../utils/prosemirror";
|
||||
import { ImageAttributes } from "../../extensions/image";
|
||||
import { ImageAttributes } from "@/src/extensions/image";
|
||||
|
||||
export function ImageSettings(props: ToolProps) {
|
||||
const { editor } = props;
|
||||
|
||||
@@ -315,6 +315,6 @@ function LinkTool(props: LinkToolProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export function isInternalLink(href?: string | null) {
|
||||
function isInternalLink(href?: string | null) {
|
||||
return typeof href === "string" ? href.startsWith("nn://") : false;
|
||||
}
|
||||
|
||||
2
packages/editor/styles/katex.min.css
vendored
2
packages/editor/styles/katex.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -4,6 +4,10 @@
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist/",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["*"]
|
||||
},
|
||||
"incremental": true
|
||||
},
|
||||
"exclude": ["src/**/*.test.ts"],
|
||||
|
||||
19
packages/editor/tsconfig.tests.json
Normal file
19
packages/editor/tsconfig.tests.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist/",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["*"]
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
"transpileOnly": true,
|
||||
"swc": true,
|
||||
"require": ["tsconfig-paths/register"]
|
||||
},
|
||||
"include": ["src/"]
|
||||
}
|
||||
Reference in New Issue
Block a user