mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-02 02:00:49 +08:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bee2cb0fa | |||
| 1addd17d64 | |||
| 842c39c3be | |||
| 26674b0cb8 | |||
| cafff4e0eb | |||
| abc3f9f23f | |||
| 5dbffba08d | |||
| 2ec7de7e32 | |||
| e5e5c0a8ba | |||
| c644a46b8d | |||
| 7e892b3a7e | |||
| 848145150d | |||
| dee6be11fb | |||
| abda70d2c8 | |||
| 40104f2f87 | |||
| 162b7adc1b | |||
| 6289981fd1 | |||
| 0e581c915c | |||
| 59a791fe1f | |||
| 378bb3795d | |||
| 60b994f38b | |||
| 1b2a4377fd | |||
| 8b4175c44d | |||
| da7ab51e2d | |||
| a59e640423 | |||
| 9bb74bce6b | |||
| a0a97d0751 | |||
| b9e3fc54fd | |||
| b71fe291d1 | |||
| f02b57d58b | |||
| 2e0f0c624a | |||
| 9435118ef1 | |||
| 67889d9364 | |||
| 5fe4b2b3e4 | |||
| 2d41c2ff8d |
@@ -1 +1,2 @@
|
||||
/blocksuite/ @toeverything/blocksuite-core
|
||||
/packages/frontend/core/src/blocksuite @toeverything/blocksuite-core
|
||||
|
||||
@@ -3,4 +3,4 @@ name: affine
|
||||
description: AFFiNE cloud chart
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.19.0"
|
||||
appVersion: "0.20.0"
|
||||
|
||||
@@ -3,7 +3,7 @@ name: graphql
|
||||
description: AFFiNE GraphQL server
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.19.0"
|
||||
appVersion: "0.20.0"
|
||||
dependencies:
|
||||
- name: gcloud-sql-proxy
|
||||
version: 0.0.0
|
||||
|
||||
@@ -3,7 +3,7 @@ name: sync
|
||||
description: AFFiNE Sync Server
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.19.0"
|
||||
appVersion: "0.20.0"
|
||||
dependencies:
|
||||
- name: gcloud-sql-proxy
|
||||
version: 0.0.0
|
||||
|
||||
Generated
+1285
-42
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,12 @@ affine_common = { path = "./packages/common/native" }
|
||||
affine_nbstore = { path = "./packages/frontend/native/nbstore" }
|
||||
anyhow = "1"
|
||||
base64-simd = "0.8"
|
||||
block2 = "0.6"
|
||||
chrono = "0.4"
|
||||
core-foundation = "0.10"
|
||||
coreaudio-rs = "0.12"
|
||||
criterion2 = { version = "2", default-features = false }
|
||||
dispatch2 = "0.2"
|
||||
dotenvy = "0.15"
|
||||
file-format = { version = "0.26", features = ["reader"] }
|
||||
homedir = "0.3"
|
||||
@@ -31,6 +35,8 @@ once_cell = "1"
|
||||
parking_lot = "0.12"
|
||||
rand = "0.9"
|
||||
rayon = "1.10"
|
||||
rubato = "0.16"
|
||||
screencapturekit = "0.3"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
sha3 = "0.10"
|
||||
|
||||
@@ -98,5 +98,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"file-type": "^20.0.0",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -42,5 +42,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"zod": "^3.23.8"
|
||||
@@ -40,5 +40,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
"@blocksuite/icons": "^2.2.3",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -41,5 +41,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.3",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -42,5 +42,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"date-fns": "^4.0.0",
|
||||
"lit": "^3.2.0",
|
||||
@@ -44,5 +44,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -39,5 +39,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"zod": "^3.23.8"
|
||||
@@ -40,5 +40,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"yjs": "^13.6.21",
|
||||
@@ -44,5 +44,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -41,5 +41,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"file-type": "^20.0.0",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -42,5 +42,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"katex": "^0.16.11",
|
||||
@@ -43,5 +43,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -42,5 +42,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@vanilla-extract/css": "^1.17.0",
|
||||
"lit": "^3.2.0",
|
||||
@@ -43,5 +43,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -39,5 +39,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@vanilla-extract/css": "^1.17.0",
|
||||
@@ -69,5 +69,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -6,19 +6,19 @@ import {
|
||||
PageViewportServiceExtension,
|
||||
ThemeService,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { dragHandleWidget } from '@blocksuite/affine-widget-drag-handle';
|
||||
import { docRemoteSelectionWidget } from '@blocksuite/affine-widget-remote-selection';
|
||||
import { scrollAnchoringWidget } from '@blocksuite/affine-widget-scroll-anchoring';
|
||||
import { FlavourExtension } from '@blocksuite/block-std';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { RootBlockAdapterExtensions } from '../adapters/extension';
|
||||
import {
|
||||
docRemoteSelectionWidget,
|
||||
dragHandleWidget,
|
||||
embedCardToolbarWidget,
|
||||
formatBarWidget,
|
||||
innerModalWidget,
|
||||
linkedDocWidget,
|
||||
modalWidget,
|
||||
scrollAnchoringWidget,
|
||||
slashMenuWidget,
|
||||
viewportOverlayWidget,
|
||||
} from './widgets';
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { AFFINE_DRAG_HANDLE_WIDGET } from '@blocksuite/affine-widget-drag-handle';
|
||||
import { AFFINE_DOC_REMOTE_SELECTION_WIDGET } from '@blocksuite/affine-widget-remote-selection';
|
||||
import { AFFINE_SCROLL_ANCHORING_WIDGET } from '@blocksuite/affine-widget-scroll-anchoring';
|
||||
import { WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
@@ -32,11 +29,6 @@ export const linkedDocWidget = WidgetViewExtension(
|
||||
AFFINE_LINKED_DOC_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_LINKED_DOC_WIDGET)}`
|
||||
);
|
||||
export const dragHandleWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_DRAG_HANDLE_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_DRAG_HANDLE_WIDGET)}`
|
||||
);
|
||||
export const embedCardToolbarWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EMBED_CARD_TOOLBAR_WIDGET,
|
||||
@@ -47,18 +39,8 @@ export const formatBarWidget = WidgetViewExtension(
|
||||
AFFINE_FORMAT_BAR_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_FORMAT_BAR_WIDGET)}`
|
||||
);
|
||||
export const docRemoteSelectionWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_DOC_REMOTE_SELECTION_WIDGET)}`
|
||||
);
|
||||
export const viewportOverlayWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_VIEWPORT_OVERLAY_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_VIEWPORT_OVERLAY_WIDGET)}`
|
||||
);
|
||||
export const scrollAnchoringWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_SCROLL_ANCHORING_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_SCROLL_ANCHORING_WIDGET)}`
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AFFINE_EDGELESS_AUTO_CONNECT_WIDGET } from '@blocksuite/affine-widget-edgeless-auto-connect';
|
||||
import { AFFINE_FRAME_TITLE_WIDGET } from '@blocksuite/affine-widget-frame-title';
|
||||
import { AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET } from '@blocksuite/affine-widget-remote-selection';
|
||||
import { autoConnectWidget } from '@blocksuite/affine-widget-edgeless-auto-connect';
|
||||
import { frameTitleWidget } from '@blocksuite/affine-widget-frame-title';
|
||||
import { edgelessRemoteSelectionWidget } from '@blocksuite/affine-widget-remote-selection';
|
||||
import {
|
||||
BlockServiceWatcher,
|
||||
BlockViewExtension,
|
||||
@@ -20,31 +20,16 @@ import { EDGELESS_SELECTED_RECT_WIDGET } from './components/rects/edgeless-selec
|
||||
import { EDGELESS_TOOLBAR_WIDGET } from './components/toolbar/edgeless-toolbar.js';
|
||||
import { EdgelessRootService } from './edgeless-root-service.js';
|
||||
|
||||
export const edgelessRemoteSelectionWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET)}`
|
||||
);
|
||||
export const edgelessZoomToolbarWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET)}`
|
||||
);
|
||||
export const frameTitleWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_FRAME_TITLE_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_FRAME_TITLE_WIDGET)}`
|
||||
);
|
||||
export const elementToolbarWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
EDGELESS_ELEMENT_TOOLBAR_WIDGET,
|
||||
literal`${unsafeStatic(EDGELESS_ELEMENT_TOOLBAR_WIDGET)}`
|
||||
);
|
||||
export const autoConnectWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EDGELESS_AUTO_CONNECT_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_EDGELESS_AUTO_CONNECT_WIDGET)}`
|
||||
);
|
||||
export const edgelessDraggingAreaWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
EDGELESS_DRAGGING_AREA_WIDGET,
|
||||
|
||||
@@ -29,7 +29,10 @@ async function exportDocs(collection: Workspace, docs: Store[]) {
|
||||
snapshots
|
||||
.filter((snapshot): snapshot is DocSnapshot => !!snapshot)
|
||||
.map(async snapshot => {
|
||||
const snapshotName = `${snapshot.meta.title || 'untitled'}.snapshot.json`;
|
||||
// Use the title and id as the snapshot file name
|
||||
const title = snapshot.meta.title || 'untitled';
|
||||
const id = snapshot.meta.id;
|
||||
const snapshotName = `${title}-${id}.snapshot.json`;
|
||||
await zip.file(snapshotName, JSON.stringify(snapshot, null, 2));
|
||||
})
|
||||
);
|
||||
@@ -63,6 +66,7 @@ async function exportDocs(collection: Workspace, docs: Store[]) {
|
||||
}
|
||||
|
||||
const downloadBlob = await zip.generate();
|
||||
// Use the collection id as the zip file name
|
||||
return download(downloadBlob, `${collection.id}.bs.zip`);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"fractional-indexing": "^3.2.0",
|
||||
"lit": "^3.2.0",
|
||||
"lodash.chunk": "^4.2.0",
|
||||
@@ -44,5 +44,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"fractional-indexing": "^3.2.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"lit": "^3.2.0",
|
||||
@@ -46,5 +46,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { SurfaceBlockProps } from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
SURFACE_TEXT_UNIQ_IDENTIFIER,
|
||||
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import type {
|
||||
FromSnapshotPayload,
|
||||
SnapshotNode,
|
||||
@@ -7,10 +11,6 @@ import type {
|
||||
import { BaseBlockTransformer } from '@blocksuite/store';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
const SURFACE_TEXT_UNIQ_IDENTIFIER = 'affine:surface:text';
|
||||
// Used for group children field
|
||||
const SURFACE_YMAP_UNIQ_IDENTIFIER = 'affine:surface:ymap';
|
||||
|
||||
export class SurfaceBlockTransformer extends BaseBlockTransformer<SurfaceBlockProps> {
|
||||
private _elementToJSON(element: Y.Map<unknown>) {
|
||||
const value: Record<string, unknown> = {};
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@vanilla-extract/css": "^1.17.0",
|
||||
"lit": "^3.2.0",
|
||||
@@ -39,5 +39,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ export const tableBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
||||
}
|
||||
const { walkerContext } = context;
|
||||
if (o.node.tagName === 'table') {
|
||||
const tableProps = parseTableFromHtml(o.node);
|
||||
const astToDelta = context.deltaConverter.astToDelta.bind(
|
||||
context.deltaConverter
|
||||
);
|
||||
const tableProps = parseTableFromHtml(o.node, astToDelta);
|
||||
walkerContext.openNode(
|
||||
{
|
||||
type: 'block',
|
||||
|
||||
@@ -25,12 +25,15 @@ export const tableBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
||||
enter: (o, context) => {
|
||||
const { walkerContext } = context;
|
||||
if (o.node.type === 'table') {
|
||||
const astToDelta = context.deltaConverter.astToDelta.bind(
|
||||
context.deltaConverter
|
||||
);
|
||||
walkerContext.openNode(
|
||||
{
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: TableModelFlavour,
|
||||
props: parseTableFromMarkdown(o.node),
|
||||
props: parseTableFromMarkdown(o.node, astToDelta),
|
||||
children: [],
|
||||
},
|
||||
'children'
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
BlockPlainTextAdapterExtension,
|
||||
type BlockPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
|
||||
import { createTableProps, formatTable, processTable } from './utils.js';
|
||||
@@ -21,10 +22,14 @@ export const tableBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = {
|
||||
const text = o.node.content;
|
||||
const rowTexts = text.split('\n');
|
||||
if (rowTexts.length <= 1) return;
|
||||
const rowTextLists: string[][] = [];
|
||||
const rowTextLists: DeltaInsert[][][] = [];
|
||||
let columnCount: number | null = null;
|
||||
for (const row of rowTexts) {
|
||||
const cells = row.split('\t');
|
||||
const cells = row.split('\t').map<DeltaInsert[]>(text => [
|
||||
{
|
||||
insert: text,
|
||||
},
|
||||
]);
|
||||
if (cells.length <= 1) return;
|
||||
if (columnCount == null) {
|
||||
columnCount = cells.length;
|
||||
|
||||
@@ -5,14 +5,23 @@ import type {
|
||||
TableRow,
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
HastUtils,
|
||||
type HtmlAST,
|
||||
type MarkdownAST,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { HastUtils } from '@blocksuite/affine-shared/adapters';
|
||||
import { generateFractionalIndexingKeyBetween } from '@blocksuite/affine-shared/utils';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import type { Element, ElementContent } from 'hast';
|
||||
import type { PhrasingContent, Table as MarkdownTable, TableCell } from 'mdast';
|
||||
import type { Element } from 'hast';
|
||||
import type { Table as MarkdownTable } from 'mdast';
|
||||
|
||||
type RichTextType = DeltaInsert[];
|
||||
const createRichText = (text: RichTextType) => {
|
||||
return {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: text,
|
||||
};
|
||||
};
|
||||
function calculateColumnWidths(rows: string[][]): number[] {
|
||||
return (
|
||||
rows[0]?.map((_, colIndex) =>
|
||||
@@ -92,15 +101,6 @@ export const processTable = (
|
||||
});
|
||||
return table;
|
||||
};
|
||||
const getTextFromElement = (element: ElementContent): string => {
|
||||
if (element.type === 'text') {
|
||||
return element.value.trim();
|
||||
}
|
||||
if (element.type === 'element') {
|
||||
return element.children.map(child => getTextFromElement(child)).join('');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const getAllTag = (node: Element | undefined, tagName: string): Element[] => {
|
||||
if (!node) {
|
||||
@@ -120,7 +120,7 @@ const getAllTag = (node: Element | undefined, tagName: string): Element[] => {
|
||||
return [];
|
||||
};
|
||||
|
||||
export const createTableProps = (rowTextLists: string[][]) => {
|
||||
export const createTableProps = (deltasLists: RichTextType[][]) => {
|
||||
const createIdAndOrder = (count: number) => {
|
||||
const result: { id: string; order: string }[] = Array.from({
|
||||
length: count,
|
||||
@@ -135,8 +135,8 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const columnCount = Math.max(...rowTextLists.map(row => row.length));
|
||||
const rowCount = rowTextLists.length;
|
||||
const columnCount = Math.max(...deltasLists.map(row => row.length));
|
||||
const rowCount = deltasLists.length;
|
||||
|
||||
const columns: TableColumn[] = createIdAndOrder(columnCount).map(v => ({
|
||||
columnId: v.id,
|
||||
@@ -156,9 +156,9 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
||||
continue;
|
||||
}
|
||||
const cellId = `${row.rowId}:${column.columnId}`;
|
||||
const text = rowTextLists[i]?.[j];
|
||||
const text = deltasLists[i]?.[j];
|
||||
cells[cellId] = {
|
||||
text: AdapterTextUtils.createText(text ?? ''),
|
||||
text: createRichText(text ?? []),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,8 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
||||
};
|
||||
|
||||
export const parseTableFromHtml = (
|
||||
element: Element
|
||||
element: Element,
|
||||
astToDelta: (ast: HtmlAST) => RichTextType
|
||||
): TableBlockPropsSerialized => {
|
||||
const headerRows = getAllTag(element, 'thead').flatMap(node =>
|
||||
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'th'))
|
||||
@@ -184,33 +185,26 @@ export const parseTableFromHtml = (
|
||||
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'td'))
|
||||
);
|
||||
const allRows = [...headerRows, ...bodyRows, ...footerRows];
|
||||
const rowTextLists: string[][] = [];
|
||||
const rowTextLists: RichTextType[][] = [];
|
||||
allRows.forEach(cells => {
|
||||
const row: string[] = [];
|
||||
const row: RichTextType[] = [];
|
||||
cells.forEach(cell => {
|
||||
row.push(getTextFromElement(cell));
|
||||
row.push(astToDelta(cell));
|
||||
});
|
||||
rowTextLists.push(row);
|
||||
});
|
||||
return createTableProps(rowTextLists);
|
||||
};
|
||||
|
||||
const getTextFromTableCell = (node: TableCell) => {
|
||||
const getTextFromPhrasingContent = (node: PhrasingContent) => {
|
||||
if (node.type === 'text') {
|
||||
return node.value;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
return node.children.map(child => getTextFromPhrasingContent(child)).join('');
|
||||
};
|
||||
|
||||
export const parseTableFromMarkdown = (node: MarkdownTable) => {
|
||||
const rowTextLists: string[][] = [];
|
||||
export const parseTableFromMarkdown = (
|
||||
node: MarkdownTable,
|
||||
astToDelta: (ast: MarkdownAST) => RichTextType
|
||||
) => {
|
||||
const rowTextLists: RichTextType[][] = [];
|
||||
node.children.forEach(row => {
|
||||
const rowText: string[] = [];
|
||||
const rowText: RichTextType[] = [];
|
||||
row.children.forEach(cell => {
|
||||
rowText.push(getTextFromTableCell(cell));
|
||||
rowText.push(astToDelta(cell));
|
||||
});
|
||||
rowTextLists.push(rowText);
|
||||
});
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@lottiefiles/dotlottie-wc": "^0.4.0",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"collapse-white-space": "^2.1.0",
|
||||
@@ -74,5 +74,5 @@
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/lodash.clonedeep": "^4.5.9"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import { type EditorHost, TextSelection } from '@blocksuite/block-std';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import {
|
||||
@@ -26,6 +26,7 @@ export interface TextFormatConfig {
|
||||
hotkey?: string;
|
||||
activeWhen: (host: EditorHost) => boolean;
|
||||
action: (host: EditorHost) => void;
|
||||
textChecker?: (host: EditorHost) => boolean;
|
||||
}
|
||||
|
||||
export const textFormatConfigs: TextFormatConfig[] = [
|
||||
@@ -124,5 +125,14 @@ export const textFormatConfigs: TextFormatConfig[] = [
|
||||
action: host => {
|
||||
host.std.command.chain().pipe(toggleLink).run();
|
||||
},
|
||||
// should check text length
|
||||
textChecker: host => {
|
||||
const textSelection = host.std.selection.find(TextSelection);
|
||||
if (!textSelection || textSelection.isCollapsed()) return false;
|
||||
|
||||
return Boolean(
|
||||
textSelection.from.length + (textSelection.to?.length ?? 0)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
+12
@@ -25,6 +25,7 @@ export interface FootNoteNodeConfig {
|
||||
customPopupRenderer?: FootNotePopupRenderer;
|
||||
interactive?: boolean;
|
||||
hidePopup?: boolean;
|
||||
disableHoverEffect?: boolean;
|
||||
onPopupClick?: FootNotePopupClickHandler;
|
||||
}
|
||||
|
||||
@@ -33,7 +34,9 @@ export class FootNoteNodeConfigProvider {
|
||||
private _customPopupRenderer?: FootNotePopupRenderer;
|
||||
private _hidePopup: boolean;
|
||||
private _interactive: boolean;
|
||||
private _disableHoverEffect: boolean;
|
||||
private _onPopupClick?: FootNotePopupClickHandler;
|
||||
|
||||
get customNodeRenderer() {
|
||||
return this._customNodeRenderer;
|
||||
}
|
||||
@@ -58,6 +61,10 @@ export class FootNoteNodeConfigProvider {
|
||||
return this._interactive;
|
||||
}
|
||||
|
||||
get disableHoverEffect() {
|
||||
return this._disableHoverEffect;
|
||||
}
|
||||
|
||||
constructor(
|
||||
config: FootNoteNodeConfig,
|
||||
readonly std: BlockStdScope
|
||||
@@ -66,6 +73,7 @@ export class FootNoteNodeConfigProvider {
|
||||
this._customPopupRenderer = config.customPopupRenderer;
|
||||
this._hidePopup = config.hidePopup ?? false;
|
||||
this._interactive = config.interactive ?? true;
|
||||
this._disableHoverEffect = config.disableHoverEffect ?? false;
|
||||
this._onPopupClick = config.onPopupClick;
|
||||
}
|
||||
|
||||
@@ -85,6 +93,10 @@ export class FootNoteNodeConfigProvider {
|
||||
this._interactive = interactive;
|
||||
}
|
||||
|
||||
setDisableHoverEffect(disableHoverEffect: boolean) {
|
||||
this._disableHoverEffect = disableHoverEffect;
|
||||
}
|
||||
|
||||
setPopupClick(onPopupClick: FootNotePopupClickHandler) {
|
||||
this._onPopupClick = onPopupClick;
|
||||
}
|
||||
|
||||
+28
-3
@@ -19,6 +19,7 @@ import { shift } from '@floating-ui/dom';
|
||||
import { baseTheme } from '@toeverything/theme';
|
||||
import { css, html, nothing, unsafeCSS } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map.js';
|
||||
import { ref } from 'lit-html/directives/ref.js';
|
||||
|
||||
import { HoverController } from '../../../../../hover/controller';
|
||||
@@ -37,7 +38,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
||||
|
||||
.footnote-content-default {
|
||||
display: inline-block;
|
||||
background: ${unsafeCSSVarV2('button/primary')};
|
||||
background: ${unsafeCSSVarV2('block/footnote/numberBgHover')};
|
||||
color: ${unsafeCSSVarV2('button/pureWhiteText')};
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
@@ -48,6 +49,21 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
font-family: ${unsafeCSS(baseTheme.fontSansFamily)};
|
||||
transition: background 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.footnote-node.hover-effect {
|
||||
.footnote-content-default {
|
||||
color: var(--affine-text-primary-color);
|
||||
background: ${unsafeCSSVarV2('block/footnote/numberBg')};
|
||||
}
|
||||
}
|
||||
|
||||
.footnote-node.hover-effect:hover {
|
||||
.footnote-content-default {
|
||||
color: ${unsafeCSSVarV2('button/pureWhiteText')};
|
||||
background: ${unsafeCSSVarV2('block/footnote/numberBgHover')};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -67,6 +83,10 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
||||
return this.config?.hidePopup;
|
||||
}
|
||||
|
||||
get disableHoverEffect() {
|
||||
return this.config?.disableHoverEffect;
|
||||
}
|
||||
|
||||
get onPopupClick() {
|
||||
return this.config?.onPopupClick;
|
||||
}
|
||||
@@ -142,7 +162,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
||||
},
|
||||
};
|
||||
},
|
||||
{ enterDelay: 500 }
|
||||
{ enterDelay: 300 }
|
||||
);
|
||||
|
||||
override render() {
|
||||
@@ -156,9 +176,14 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
||||
? this.customNodeRenderer(footnote, this.std)
|
||||
: this._FootNoteDefaultContent(footnote);
|
||||
|
||||
const nodeClasses = classMap({
|
||||
'footnote-node': true,
|
||||
'hover-effect': !this.disableHoverEffect,
|
||||
});
|
||||
|
||||
return html`<span
|
||||
${this.hidePopup ? '' : ref(this._whenHover.setReference)}
|
||||
class="footnote-node"
|
||||
class=${nodeClasses}
|
||||
>${node}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
||||
></span>`;
|
||||
}
|
||||
|
||||
+1
@@ -14,6 +14,7 @@ export class FootNotePopupChip extends LitElement {
|
||||
gap: 4px;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
transition: width 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.prefix-icon,
|
||||
|
||||
-1
@@ -26,7 +26,6 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
|
||||
.footnote-popup-container {
|
||||
border-radius: 4px;
|
||||
box-shadow: ${unsafeCSSVar('overlayPanelShadow')};
|
||||
border-radius: 4px;
|
||||
background-color: ${unsafeCSSVarV2('layer/background/primary')};
|
||||
border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/border')};
|
||||
}
|
||||
|
||||
@@ -20,8 +20,14 @@ export const textFormatKeymap = (std: BlockStdScope) =>
|
||||
const textSelection = selection.find(TextSelection);
|
||||
if (!textSelection) return;
|
||||
|
||||
const allowed = config.textChecker?.(std.host) ?? true;
|
||||
if (!allowed) return;
|
||||
|
||||
const event = ctx.get('keyboardState').raw;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
config.action(std.host);
|
||||
ctx.get('keyboardState').raw.preventDefault();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"date-fns": "^4.0.0",
|
||||
"lit": "^3.2.0",
|
||||
"yjs": "^13.6.21",
|
||||
@@ -43,5 +43,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -3,17 +3,30 @@ import { propertyType } from '../../core/property/property-config.js';
|
||||
|
||||
export const checkboxPropertyType = propertyType('checkbox');
|
||||
|
||||
const FALSE_VALUES = new Set([
|
||||
'false',
|
||||
'no',
|
||||
'0',
|
||||
'',
|
||||
'undefined',
|
||||
'null',
|
||||
'否',
|
||||
'不',
|
||||
'错',
|
||||
'错误',
|
||||
'取消',
|
||||
'关闭',
|
||||
]);
|
||||
|
||||
export const checkboxPropertyModelConfig =
|
||||
checkboxPropertyType.modelConfig<boolean>({
|
||||
name: 'Checkbox',
|
||||
type: () => t.boolean.instance(),
|
||||
defaultData: () => ({}),
|
||||
cellToString: ({ value }) => (value ? 'True' : 'False'),
|
||||
cellFromString: ({ value }) => {
|
||||
return {
|
||||
value: value !== 'False',
|
||||
};
|
||||
},
|
||||
cellFromString: ({ value }) => ({
|
||||
value: !FALSE_VALUES.has((value?.trim() ?? '').toLowerCase()),
|
||||
}),
|
||||
cellToJson: ({ value }) => value ?? null,
|
||||
cellFromJson: ({ value }) =>
|
||||
typeof value !== 'boolean' ? undefined : value,
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"zod": "^3.23.8"
|
||||
@@ -41,5 +41,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@vanilla-extract/css": "^1.17.0",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
@@ -41,5 +41,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"fractional-indexing": "^3.2.0",
|
||||
"yjs": "^13.6.21",
|
||||
"zod": "^3.23.8"
|
||||
@@ -31,5 +31,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -63,10 +63,6 @@ export class BrushElementModel extends GfxPrimitiveElementModel<BrushProps> {
|
||||
return 'brush';
|
||||
}
|
||||
|
||||
static override propsToY(props: BrushProps) {
|
||||
return props;
|
||||
}
|
||||
|
||||
override containsBound(bounds: Bound) {
|
||||
const points = getPointsFromBoundWithRotation(this);
|
||||
return points.some(point => bounds.containsPoint(point));
|
||||
|
||||
@@ -125,8 +125,8 @@ export class ConnectorElementModel extends GfxPrimitiveElementModel<ConnectorEle
|
||||
return 'connector';
|
||||
}
|
||||
|
||||
static override propsToY(props: ConnectorElementProps) {
|
||||
if (props.text && !(props.text instanceof Y.Text)) {
|
||||
static propsToY(props: ConnectorElementProps) {
|
||||
if (typeof props.text === 'string') {
|
||||
props.text = new Y.Text(props.text);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ export class GroupElementModel extends GfxGroupLikeElementModel<GroupElementProp
|
||||
return 'group';
|
||||
}
|
||||
|
||||
static override propsToY(props: Record<string, unknown>) {
|
||||
if ('title' in props && !(props.title instanceof Y.Text)) {
|
||||
static propsToY(props: Record<string, unknown>) {
|
||||
if (typeof props.title === 'string') {
|
||||
props.title = new Y.Text(props.title as string);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
|
||||
return 'mindmap';
|
||||
}
|
||||
|
||||
static override propsToY(props: Record<string, unknown>) {
|
||||
static propsToY(props: Record<string, unknown>) {
|
||||
if (
|
||||
props.children &&
|
||||
!isNodeType(props.children as Record<string, unknown>) &&
|
||||
|
||||
@@ -67,8 +67,8 @@ export class ShapeElementModel extends GfxPrimitiveElementModel<ShapeProps> {
|
||||
return 'shape';
|
||||
}
|
||||
|
||||
static override propsToY(props: ShapeProps) {
|
||||
if (props.text && !(props.text instanceof Y.Text)) {
|
||||
static propsToY(props: ShapeProps) {
|
||||
if (typeof props.text === 'string') {
|
||||
props.text = new Y.Text(props.text);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ export class TextElementModel extends GfxPrimitiveElementModel<TextElementProps>
|
||||
return 'text';
|
||||
}
|
||||
|
||||
static override propsToY(props: Record<string, unknown>) {
|
||||
if (props.text && !(props.text instanceof Y.Text)) {
|
||||
props.text = new Y.Text(props.text as string);
|
||||
static propsToY(props: Record<string, unknown>) {
|
||||
if (typeof props.text === 'string') {
|
||||
props.text = new Y.Text(props.text);
|
||||
}
|
||||
|
||||
return props;
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"dompurify": "^3.2.4",
|
||||
@@ -77,5 +77,5 @@
|
||||
"@types/lodash.mergewith": "^4",
|
||||
"vitest": "3.0.6"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -13,10 +13,20 @@ export class SpecBuilder {
|
||||
|
||||
extend(extensions: ExtensionType[]) {
|
||||
this._value = [...this._value, ...extensions];
|
||||
return this;
|
||||
}
|
||||
|
||||
omit(target: ExtensionType) {
|
||||
this._value = this._value.filter(extension => extension !== target);
|
||||
return this;
|
||||
}
|
||||
|
||||
hasAll(target: ExtensionType[]) {
|
||||
return target.every(t => this._value.includes(t));
|
||||
}
|
||||
|
||||
hasOneOf(target: ExtensionType[]) {
|
||||
return target.some(t => this._value.includes(t));
|
||||
}
|
||||
|
||||
replace(target: ExtensionType[], newExtension: ExtensionType[]) {
|
||||
@@ -24,5 +34,6 @@ export class SpecBuilder {
|
||||
...this._value.filter(extension => !target.includes(extension)),
|
||||
...newExtension,
|
||||
];
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,12 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
);
|
||||
});
|
||||
|
||||
const debounceOptions = { leading: false, trailing: true };
|
||||
const debouncedRefresh = debounce(
|
||||
() => {
|
||||
this.refresh().catch(console.error);
|
||||
},
|
||||
1000, // During this period, fallback to DOM
|
||||
debounceOptions
|
||||
{ leading: false, trailing: true }
|
||||
);
|
||||
this.disposables.add(
|
||||
this.std.store.slots.blockUpdated.on(() => {
|
||||
@@ -97,11 +96,12 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
return this.std.get(GfxControllerIdentifier).viewport;
|
||||
}
|
||||
|
||||
async refresh(force = false) {
|
||||
if (this.state === 'paused' && !force) return;
|
||||
async refresh() {
|
||||
if (this.state === 'paused') return;
|
||||
|
||||
this.clearCanvas();
|
||||
if (this.viewport.zoom > zoomThreshold) {
|
||||
this.clearCanvas();
|
||||
return;
|
||||
} else if (this.canUseBitmapCache()) {
|
||||
this.drawCachedBitmap(this.layoutCache!);
|
||||
} else {
|
||||
@@ -115,8 +115,9 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
}
|
||||
|
||||
invalidate() {
|
||||
this.clearCache();
|
||||
this.clearCanvas();
|
||||
this.layoutCache = null;
|
||||
this.clearTile();
|
||||
this.clearCanvas(); // Should clear immediately after content updates
|
||||
}
|
||||
|
||||
private updateLayoutCache() {
|
||||
@@ -124,11 +125,6 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
this.layoutCache = layout;
|
||||
}
|
||||
|
||||
private clearCache() {
|
||||
this.layoutCache = null;
|
||||
this.clearTile();
|
||||
}
|
||||
|
||||
private clearTile() {
|
||||
if (this.tile) {
|
||||
this.tile.bitmap.close();
|
||||
@@ -154,17 +150,13 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
|
||||
this.worker.onmessage = (e: MessageEvent) => {
|
||||
if (e.data.type === 'bitmapPainted') {
|
||||
this.handlePaintedBitmap(e.data.bitmap, layout, resolve);
|
||||
this.handlePaintedBitmap(e.data.bitmap, resolve);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private handlePaintedBitmap(
|
||||
bitmap: ImageBitmap,
|
||||
layout: ViewportLayout,
|
||||
resolve: () => void
|
||||
) {
|
||||
private handlePaintedBitmap(bitmap: ImageBitmap, resolve: () => void) {
|
||||
if (this.tile) {
|
||||
this.tile.bitmap.close();
|
||||
}
|
||||
@@ -172,7 +164,6 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
|
||||
bitmap,
|
||||
zoom: this.viewport.zoom,
|
||||
};
|
||||
this.drawCachedBitmap(layout);
|
||||
resolve();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
"@blocksuite/icons": "^2.2.1",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"zod": "^3.23.8"
|
||||
@@ -43,5 +43,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import { WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
import { AFFINE_DRAG_HANDLE_WIDGET } from './consts';
|
||||
|
||||
export * from './consts';
|
||||
export * from './drag-handle';
|
||||
export * from './utils';
|
||||
export type { DragBlockPayload } from './watchers/drag-event-watcher';
|
||||
|
||||
export const dragHandleWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_DRAG_HANDLE_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_DRAG_HANDLE_WIDGET)}`
|
||||
);
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||
import type { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
||||
import { isGfxGroupCompatibleModel } from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
GfxController,
|
||||
type GfxModel,
|
||||
isGfxGroupCompatibleModel,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
assertType,
|
||||
type IVec,
|
||||
type SerializedXYWH,
|
||||
} from '@blocksuite/global/utils';
|
||||
import type { TransformerMiddleware } from '@blocksuite/store';
|
||||
|
||||
/**
|
||||
@@ -18,6 +28,7 @@ export const gfxBlocksFilter = (
|
||||
const surface = store.getBlocksByFlavour('affine:surface')[0]
|
||||
.model as SurfaceBlockModel;
|
||||
const idsToCheck = ids.slice();
|
||||
const gfx = std.get(GfxController);
|
||||
|
||||
for (const id of idsToCheck) {
|
||||
const blockOrElem = store.getBlock(id)?.model ?? surface.getElementById(id);
|
||||
@@ -45,5 +56,62 @@ export const gfxBlocksFilter = (
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
slots.afterExport.on(payload => {
|
||||
if (payload.type !== 'block') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.model.flavour === 'affine:surface') {
|
||||
const { snapshot } = payload;
|
||||
const elementsMap = snapshot.props.elements as Record<
|
||||
string,
|
||||
{ type: string }
|
||||
>;
|
||||
|
||||
Object.entries(elementsMap).forEach(([elementId, val]) => {
|
||||
if (val.type === 'connector') {
|
||||
assertType<{
|
||||
type: 'connector';
|
||||
source: { position: IVec; id?: string };
|
||||
target: { position: IVec; id?: string };
|
||||
xywh: SerializedXYWH;
|
||||
}>(val);
|
||||
|
||||
const connectorElem = gfx.getElementById(
|
||||
elementId
|
||||
) as ConnectorElementModel;
|
||||
|
||||
if (!connectorElem) {
|
||||
delete elementsMap[elementId];
|
||||
return;
|
||||
}
|
||||
|
||||
// should be deleted during the import process
|
||||
val.xywh = connectorElem.xywh;
|
||||
|
||||
['source', 'target'].forEach(key => {
|
||||
const endpoint = val[key as 'source' | 'target'];
|
||||
if (endpoint.id && !selectedIds.has(endpoint.id)) {
|
||||
const endElem = gfx.getElementById(endpoint.id);
|
||||
|
||||
if (!endElem) {
|
||||
delete elementsMap[elementId];
|
||||
return;
|
||||
}
|
||||
|
||||
const endElemBound = (endElem as GfxModel).elementBound;
|
||||
|
||||
val[key as 'source' | 'target'] = {
|
||||
position: endElemBound.getRelativePoint(
|
||||
endpoint.position ?? [0.5, 0.5]
|
||||
),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -290,13 +290,28 @@ export function getSnapshotRect(snapshot: SliceSnapshot): Bound | null {
|
||||
if (block.flavour === 'affine:surface') {
|
||||
if (block.props.elements) {
|
||||
Object.values(
|
||||
block.props.elements as Record<string, { xywh: SerializedXYWH }>
|
||||
block.props.elements as Record<
|
||||
string,
|
||||
{ type: string; xywh: SerializedXYWH }
|
||||
>
|
||||
).forEach(elem => {
|
||||
if (elem.xywh) {
|
||||
bound = bound
|
||||
? bound.unite(Bound.deserialize(elem.xywh))
|
||||
: Bound.deserialize(elem.xywh);
|
||||
}
|
||||
|
||||
if (elem.type === 'connector') {
|
||||
let connectorBound: Bound | undefined;
|
||||
|
||||
if (elem.xywh) {
|
||||
connectorBound = Bound.deserialize(elem.xywh);
|
||||
}
|
||||
|
||||
if (connectorBound) {
|
||||
bound = bound ? bound.unite(connectorBound) : connectorBound;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
|
||||
import { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||
import { DropIndicator } from '@blocksuite/affine-components/drop-indicator';
|
||||
import {
|
||||
AttachmentBlockModel,
|
||||
@@ -45,11 +44,14 @@ import {
|
||||
type GfxModel,
|
||||
GfxPrimitiveElementModel,
|
||||
isGfxGroupCompatibleModel,
|
||||
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||
SurfaceBlockModel,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
assertType,
|
||||
Bound,
|
||||
groupBy,
|
||||
type IVec,
|
||||
last,
|
||||
Point,
|
||||
Rect,
|
||||
@@ -752,7 +754,11 @@ export class DragEventWatcher {
|
||||
const idRemap = new Map<string, string>();
|
||||
let elemMap: Record<
|
||||
string,
|
||||
{ type: string; children?: { json: Record<string, unknown> } }
|
||||
{
|
||||
type: string;
|
||||
xywh?: SerializedXYWH;
|
||||
children?: { json: Record<string, unknown> };
|
||||
}
|
||||
> = {};
|
||||
const blockMap: Record<
|
||||
string,
|
||||
@@ -766,7 +772,7 @@ export class DragEventWatcher {
|
||||
const constructor = surface.getConstructor(elem.type);
|
||||
const isGroup = Object.isPrototypeOf.call(
|
||||
GfxGroupLikeElementModel.prototype,
|
||||
constructor
|
||||
constructor.prototype
|
||||
);
|
||||
|
||||
return isGroup;
|
||||
@@ -782,24 +788,40 @@ export class DragEventWatcher {
|
||||
if (block.flavour === 'affine:surface') {
|
||||
elemMap = (block.props.elements as typeof elemMap) ?? {};
|
||||
Object.entries(elemMap).forEach(([elemId, elem]) => {
|
||||
if (isGroupLikeElem(elem)) {
|
||||
// only add the group to the root if it's not a child of any other element
|
||||
if (
|
||||
Object.values(containerTree).every(
|
||||
childSet => !childSet.has(elemId)
|
||||
)
|
||||
) {
|
||||
containerTree['root'].add(elem.type);
|
||||
}
|
||||
if (
|
||||
Object.values(containerTree).every(
|
||||
childSet => !childSet.has(elemId)
|
||||
)
|
||||
) {
|
||||
containerTree['root'].add(elemId);
|
||||
}
|
||||
|
||||
if (isGroupLikeElem(elem)) {
|
||||
Object.keys(elem.children?.json ?? {}).forEach(childId => {
|
||||
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||
containerTree[elemId].add(childId);
|
||||
// if the child was already added to the root, remove it
|
||||
containerTree['root'].delete(childId);
|
||||
});
|
||||
} else {
|
||||
containerTree['root'].add(elemId);
|
||||
return;
|
||||
} else if (elem.type === 'connector') {
|
||||
assertType<{
|
||||
type: 'connector';
|
||||
source: { position: IVec; id?: string };
|
||||
target: { position: IVec; id?: string };
|
||||
}>(elem);
|
||||
|
||||
if (elem.source.id) {
|
||||
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||
containerTree[elemId].add(elem.source.id);
|
||||
containerTree['root'].delete(elem.source.id);
|
||||
}
|
||||
|
||||
if (elem.target.id) {
|
||||
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||
containerTree[elemId].add(elem.target.id);
|
||||
containerTree['root'].delete(elem.target.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -876,19 +898,58 @@ export class DragEventWatcher {
|
||||
idRemap.set(id, slices.content[0].id);
|
||||
}
|
||||
} else if (elemMap[id]) {
|
||||
if (elemMap[id].children) {
|
||||
const childJson = elemMap[id].children.json;
|
||||
Object.keys(childJson).forEach(childId => {
|
||||
if (idRemap.has(childId)) {
|
||||
const remappedId = idRemap.get(childId)!;
|
||||
childJson[remappedId] = childJson[childId];
|
||||
delete childJson[childId];
|
||||
} else {
|
||||
delete childJson[childId];
|
||||
const elem = elemMap[id];
|
||||
|
||||
Object.entries(elem).forEach(([_, val]) => {
|
||||
if (
|
||||
val instanceof Object &&
|
||||
Reflect.has(val, SURFACE_YMAP_UNIQ_IDENTIFIER)
|
||||
) {
|
||||
const childJson = Reflect.get(val, 'json') as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
|
||||
Object.keys(childJson).forEach(oldChildId => {
|
||||
if (idRemap.has(oldChildId)) {
|
||||
const remappedId = idRemap.get(oldChildId)!;
|
||||
const val = structuredClone(childJson[oldChildId]);
|
||||
|
||||
if (elem.type === 'mindmap') {
|
||||
assertType<{ parent?: string }>(val);
|
||||
if (val.parent) {
|
||||
val.parent = idRemap.get(val.parent);
|
||||
}
|
||||
}
|
||||
childJson[remappedId] = val;
|
||||
delete childJson[oldChildId];
|
||||
} else {
|
||||
delete childJson[oldChildId];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (elem.type === 'connector') {
|
||||
assertType<{
|
||||
type: 'connector';
|
||||
source: { position: IVec; id?: string };
|
||||
target: { position: IVec; id?: string };
|
||||
}>(elem);
|
||||
|
||||
(['source', 'target'] as const).forEach(key => {
|
||||
const endpoint = elem[key];
|
||||
if (endpoint.id) {
|
||||
if (idRemap.get(endpoint.id)) {
|
||||
endpoint.id = idRemap.get(endpoint.id);
|
||||
} else {
|
||||
delete endpoint.id;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const newId = surface.addElement(elemMap[id]);
|
||||
|
||||
const newId = surface.addElement(elem);
|
||||
idRemap.set(id, newId);
|
||||
}
|
||||
};
|
||||
@@ -918,8 +979,45 @@ export class DragEventWatcher {
|
||||
if (block.flavour === 'affine:surface') {
|
||||
if (block.props.elements) {
|
||||
Object.values(
|
||||
block.props.elements as Record<string, { xywh: SerializedXYWH }>
|
||||
block.props.elements as Record<
|
||||
string,
|
||||
{ type: string; xywh?: SerializedXYWH }
|
||||
>
|
||||
).forEach(elem => {
|
||||
if (elem.type === 'connector') {
|
||||
assertType<{
|
||||
type: 'connector';
|
||||
xywh?: SerializedXYWH;
|
||||
source: { position: IVec; id?: string };
|
||||
target: { position: IVec; id?: string };
|
||||
}>(elem);
|
||||
|
||||
const connectorBound = elem.xywh
|
||||
? Bound.deserialize(elem.xywh)
|
||||
: new Bound(0, 0, 0, 0);
|
||||
|
||||
delete elem.xywh;
|
||||
|
||||
(['source', 'target'] as const).forEach(key => {
|
||||
const endpoint = elem[key];
|
||||
if (!endpoint.id) {
|
||||
const originalPos = endpoint.position;
|
||||
|
||||
elem[key] = {
|
||||
position: ignoreOriginalPos
|
||||
? [
|
||||
originalPos[0] - connectorBound.x + modelX,
|
||||
originalPos[1] - connectorBound.y + modelY,
|
||||
]
|
||||
: [
|
||||
originalPos[0] - rect.x + modelX,
|
||||
originalPos[1] - rect.y + modelY,
|
||||
],
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (elem.xywh) {
|
||||
const elemBound = Bound.deserialize(elem.xywh);
|
||||
|
||||
@@ -956,6 +1054,7 @@ export class DragEventWatcher {
|
||||
|
||||
if (
|
||||
block.flavour === 'affine:attachment' ||
|
||||
block.flavour === 'affine:bookmark' ||
|
||||
block.flavour.startsWith('affine:embed-')
|
||||
) {
|
||||
const style = 'vertical' as EmbedCardStyle;
|
||||
@@ -1037,6 +1136,7 @@ export class DragEventWatcher {
|
||||
block.id === content[idx].id &&
|
||||
(block.flavour === 'affine:image' ||
|
||||
block.flavour === 'affine:attachment' ||
|
||||
block.flavour === 'affine:bookmark' ||
|
||||
block.flavour.startsWith('affine:embed-'))
|
||||
) {
|
||||
store.updateBlock(block as BlockModel, {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/icons": "^2.2.3",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0"
|
||||
},
|
||||
"exports": {
|
||||
@@ -35,5 +35,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from '@blocksuite/affine-model';
|
||||
import { FeatureFlagService } from '@blocksuite/affine-shared/services';
|
||||
import { matchModels, stopPropagation } from '@blocksuite/affine-shared/utils';
|
||||
import { WidgetComponent } from '@blocksuite/block-std';
|
||||
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import {
|
||||
type GfxController,
|
||||
GfxControllerIdentifier,
|
||||
@@ -28,6 +28,7 @@ import { css, html, nothing, type TemplateResult } from 'lit';
|
||||
import { state } from 'lit/decorators.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
const PAGE_VISIBLE_INDEX_LABEL_WIDTH = 44;
|
||||
const PAGE_VISIBLE_INDEX_LABEL_HEIGHT = 24;
|
||||
@@ -613,6 +614,12 @@ export class EdgelessAutoConnectWidget extends WidgetComponent<RootBlockModel> {
|
||||
private accessor _show = false;
|
||||
}
|
||||
|
||||
export const autoConnectWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EDGELESS_AUTO_CONNECT_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_EDGELESS_AUTO_CONNECT_WIDGET)}`
|
||||
);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'affine-edgeless-auto-connect-widget': EdgelessAutoConnectWidget;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0"
|
||||
},
|
||||
"exports": {
|
||||
@@ -33,5 +33,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { FrameBlockModel, type RootBlockModel } from '@blocksuite/affine-model';
|
||||
import { WidgetComponent } from '@blocksuite/block-std';
|
||||
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { html } from 'lit';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
import type { AffineFrameTitle } from './frame-title.js';
|
||||
|
||||
@@ -36,3 +37,9 @@ export class AffineFrameTitleWidget extends WidgetComponent<RootBlockModel> {
|
||||
}
|
||||
|
||||
export * from './styles.js';
|
||||
|
||||
export const frameTitleWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_FRAME_TITLE_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_FRAME_TITLE_WIDGET)}`
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/icons": "^2.2.3",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0"
|
||||
},
|
||||
"exports": {
|
||||
@@ -34,5 +34,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import type * as CommandsType from '@blocksuite/affine-shared/commands';
|
||||
import { WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
declare type _GLOBAL_ = typeof CommandsType;
|
||||
import { AFFINE_DOC_REMOTE_SELECTION_WIDGET } from './doc';
|
||||
import { AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET } from './edgeless';
|
||||
|
||||
export * from './doc';
|
||||
export * from './edgeless';
|
||||
|
||||
export const docRemoteSelectionWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_DOC_REMOTE_SELECTION_WIDGET)}`
|
||||
);
|
||||
|
||||
export const edgelessRemoteSelectionWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET)}`
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"@blocksuite/block-std": "workspace:*",
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"lit": "^3.2.0"
|
||||
},
|
||||
"exports": {
|
||||
@@ -31,5 +31,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
import { WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
import { AFFINE_SCROLL_ANCHORING_WIDGET } from './scroll-anchoring.js';
|
||||
|
||||
export * from './scroll-anchoring.js';
|
||||
|
||||
export const scrollAnchoringWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_SCROLL_ANCHORING_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_SCROLL_ANCHORING_WIDGET)}`
|
||||
);
|
||||
|
||||
@@ -63,5 +63,6 @@
|
||||
"devDependencies": {
|
||||
"@vanilla-extract/vite-plugin": "^5.0.0",
|
||||
"vitest": "3.0.6"
|
||||
}
|
||||
},
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -48,5 +48,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ export {
|
||||
prop,
|
||||
} from './model/surface/local-element-model.js';
|
||||
export {
|
||||
SURFACE_TEXT_UNIQ_IDENTIFIER,
|
||||
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||
SurfaceBlockModel,
|
||||
type SurfaceBlockProps,
|
||||
type SurfaceMiddleware,
|
||||
|
||||
@@ -199,10 +199,6 @@ export abstract class GfxPrimitiveElementModel<
|
||||
this.seed = randomSeed();
|
||||
}
|
||||
|
||||
static propsToY(props: Record<string, unknown>) {
|
||||
return props;
|
||||
}
|
||||
|
||||
containsBound(bounds: Bound): boolean {
|
||||
return getPointsFromBoundWithRotation(this).some(point =>
|
||||
bounds.containsPoint(point)
|
||||
|
||||
@@ -12,11 +12,20 @@ import { createDecoratorState } from './decorators/common.js';
|
||||
import { initializeObservers, initializeWatchers } from './decorators/index.js';
|
||||
import {
|
||||
GfxGroupLikeElementModel,
|
||||
GfxPrimitiveElementModel,
|
||||
type GfxPrimitiveElementModel,
|
||||
syncElementFromY,
|
||||
} from './element-model.js';
|
||||
import type { GfxLocalElementModel } from './local-element-model.js';
|
||||
|
||||
/**
|
||||
* Used for text field
|
||||
*/
|
||||
export const SURFACE_TEXT_UNIQ_IDENTIFIER = 'affine:surface:text';
|
||||
/**
|
||||
* Used for field that use Y.Map. E.g. group children field
|
||||
*/
|
||||
export const SURFACE_YMAP_UNIQ_IDENTIFIER = 'affine:surface:ymap';
|
||||
|
||||
export type SurfaceBlockProps = {
|
||||
elements: Boxed<Y.Map<Y.Map<unknown>>>;
|
||||
};
|
||||
@@ -390,8 +399,28 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
|
||||
throw new Error(`Invalid element type: ${type}`);
|
||||
}
|
||||
|
||||
Object.entries(props).forEach(([key, val]) => {
|
||||
if (val instanceof Object) {
|
||||
if (Reflect.has(val, SURFACE_TEXT_UNIQ_IDENTIFIER)) {
|
||||
const yText = new Y.Text();
|
||||
yText.applyDelta(Reflect.get(val, 'delta'));
|
||||
Reflect.set(props, key, yText);
|
||||
}
|
||||
|
||||
if (Reflect.has(val, SURFACE_YMAP_UNIQ_IDENTIFIER)) {
|
||||
const childJson = Reflect.get(val, 'json') as Record<string, unknown>;
|
||||
const childrenYMap = new Y.Map<unknown>();
|
||||
|
||||
Object.keys(childJson).forEach(childId => {
|
||||
childrenYMap.set(childId, childJson[childId]);
|
||||
});
|
||||
Reflect.set(props, key, childrenYMap);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-expect-error ignore
|
||||
return (ctor.propsToY ?? GfxPrimitiveElementModel.propsToY)(props);
|
||||
return ctor.propsToY ? ctor.propsToY(props) : props;
|
||||
}
|
||||
|
||||
private _watchGroupRelationChange() {
|
||||
|
||||
@@ -51,5 +51,5 @@
|
||||
"devDependencies": {
|
||||
"vitest": "3.0.6"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -34,5 +34,5 @@
|
||||
"devDependencies": {
|
||||
"vitest": "3.0.6"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
"!dist/__tests__",
|
||||
"shim.d.ts"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
"@blocksuite/icons": "^2.2.2",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.10",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@lit/context": "^1.1.3",
|
||||
"@lottiefiles/dotlottie-wc": "^0.4.0",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.11",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@vanilla-extract/css": "^1.17.0",
|
||||
"lit": "^3.2.0",
|
||||
"yjs": "^13.6.21",
|
||||
@@ -52,5 +52,5 @@
|
||||
"vite-plugin-wasm": "^3.4.1",
|
||||
"vitest": "^3.0.0"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@
|
||||
"vite-plugin-wasm": "^3.3.0",
|
||||
"vite-plugin-web-components-hmr": "^0.1.3"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -29,5 +29,5 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/toeverything/blocksuite.git"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
],
|
||||
"ext": "ts,md,json"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/monorepo",
|
||||
"version": "0.19.0",
|
||||
"version": "0.20.0",
|
||||
"private": true,
|
||||
"author": "toeverything",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/server-native",
|
||||
"version": "0.19.0",
|
||||
"version": "0.20.0",
|
||||
"engines": {
|
||||
"node": ">= 10.16.0 < 11 || >= 11.8.0"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/server",
|
||||
"private": true,
|
||||
"version": "0.19.0",
|
||||
"version": "0.20.0",
|
||||
"description": "Affine Node.js server",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -146,3 +146,26 @@ test('should tell downgrade if client version is higher than allowed', async t =
|
||||
'Unsupported client with version [0.23.0], required version is [>=0.20.0 <=0.22.0].'
|
||||
);
|
||||
});
|
||||
|
||||
test('should test prerelease version', async t => {
|
||||
runtime.fetch
|
||||
.withArgs('client/versionControl.requiredVersion')
|
||||
.resolves('>=0.19.0');
|
||||
|
||||
let res = await app
|
||||
.GET('/guarded/test')
|
||||
.set('x-affine-version', '0.19.0-canary.1');
|
||||
|
||||
// 0.19.0-canary.1 is lower than 0.19.0 obviously
|
||||
t.is(res.status, 403);
|
||||
|
||||
res = await app
|
||||
.GET('/guarded/test')
|
||||
.set('x-affine-version', '0.20.0-canary.1');
|
||||
|
||||
t.is(res.status, 200);
|
||||
|
||||
res = await app.GET('/guarded/test').set('x-affine-version', '0.20.0-beta.2');
|
||||
|
||||
t.is(res.status, 200);
|
||||
});
|
||||
|
||||
@@ -299,6 +299,7 @@ export class AuthController {
|
||||
res.send({ id: user.id });
|
||||
}
|
||||
|
||||
@UseNamedGuard('version')
|
||||
@Throttle('default', { limit: 1200 })
|
||||
@Public()
|
||||
@Get('/session')
|
||||
|
||||
@@ -45,7 +45,9 @@ type EventResponse<Data = any> = Data extends never
|
||||
data: Data;
|
||||
};
|
||||
|
||||
type RoomType = 'sync' | `${string}:awareness`;
|
||||
// 019 only receives space:broadcast-doc-updates and send space:push-doc-updates
|
||||
// 020 only receives space:broadcast-doc-update and send space:push-doc-update
|
||||
type RoomType = 'sync' | `${string}:awareness` | 'sync-019';
|
||||
|
||||
function Room(
|
||||
spaceId: string,
|
||||
@@ -214,7 +216,16 @@ export class SpaceSyncGateway
|
||||
): Promise<EventResponse<{ clientId: string; success: true }>> {
|
||||
await this.assertVersion(client, clientVersion);
|
||||
|
||||
await this.selectAdapter(client, spaceType).join(user.id, spaceId);
|
||||
// TODO(@forehalo): remove this after 0.19 goes out of life
|
||||
// simple match 0.19.x
|
||||
if (/^0.19.[\d]$/.test(clientVersion)) {
|
||||
const room = Room(spaceId, 'sync-019');
|
||||
if (!client.rooms.has(room)) {
|
||||
await client.join(room);
|
||||
}
|
||||
} else {
|
||||
await this.selectAdapter(client, spaceType).join(user.id, spaceId);
|
||||
}
|
||||
|
||||
return { data: { clientId: client.id, success: true } };
|
||||
}
|
||||
@@ -270,6 +281,8 @@ export class SpaceSyncGateway
|
||||
|
||||
/**
|
||||
* @deprecated use [space:push-doc-update] instead, client should always merge updates on their own
|
||||
*
|
||||
* only 0.19.x client will send this event
|
||||
*/
|
||||
@SubscribeMessage('space:push-doc-updates')
|
||||
async onReceiveDocUpdates(
|
||||
@@ -289,23 +302,19 @@ export class SpaceSyncGateway
|
||||
user.id
|
||||
);
|
||||
|
||||
// could be put in [adapter.push]
|
||||
// but the event should be kept away from adapter
|
||||
// so
|
||||
// broadcast to 0.19.x clients
|
||||
client
|
||||
.to(adapter.room(spaceId))
|
||||
.to(Room(spaceId, 'sync-019'))
|
||||
.emit('space:broadcast-doc-updates', { ...message, timestamp });
|
||||
|
||||
// TODO(@forehalo): remove backward compatibility
|
||||
if (spaceType === SpaceType.Workspace) {
|
||||
const id = new DocID(docId, spaceId);
|
||||
client.to(adapter.room(spaceId)).emit('server-updates', {
|
||||
workspaceId: spaceId,
|
||||
guid: id.guid,
|
||||
updates,
|
||||
// broadcast to new clients
|
||||
updates.forEach(update => {
|
||||
client.to(adapter.room(spaceId)).emit('space:broadcast-doc-update', {
|
||||
...message,
|
||||
update,
|
||||
timestamp,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
data: {
|
||||
@@ -333,9 +342,8 @@ export class SpaceSyncGateway
|
||||
user.id
|
||||
);
|
||||
|
||||
// TODO(@forehalo): separate different version of clients into different rooms,
|
||||
// so the clients won't receive useless updates events
|
||||
client.to(adapter.room(spaceId)).emit('space:broadcast-doc-updates', {
|
||||
// broadcast to 0.19.x clients
|
||||
client.to(Room(spaceId, 'sync-019')).emit('space:broadcast-doc-updates', {
|
||||
spaceType,
|
||||
spaceId,
|
||||
docId,
|
||||
@@ -445,163 +453,8 @@ export class SpaceSyncGateway
|
||||
.to(adapter.room(spaceId, roomType))
|
||||
.emit('space:broadcast-awareness-update', message);
|
||||
|
||||
// TODO(@forehalo): remove backward compatibility
|
||||
if (spaceType === SpaceType.Workspace) {
|
||||
client
|
||||
.to(adapter.room(spaceId, roomType))
|
||||
.emit('server-awareness-broadcast', {
|
||||
workspaceId: spaceId,
|
||||
awarenessUpdate: message.awarenessUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO(@forehalo): remove
|
||||
// deprecated section
|
||||
@SubscribeMessage('client-handshake-sync')
|
||||
async handleClientHandshakeSync(
|
||||
@CurrentUser() user: CurrentUser,
|
||||
@MessageBody('workspaceId') workspaceId: string,
|
||||
@MessageBody('version') version: string,
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse<{ clientId: string }>> {
|
||||
await this.assertVersion(client, version);
|
||||
|
||||
return this.onJoinSpace(user, client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
clientVersion: version,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('client-leave-sync')
|
||||
async handleLeaveSync(
|
||||
@MessageBody() workspaceId: string,
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse> {
|
||||
return this.onLeaveSpace(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('client-pre-sync')
|
||||
async loadDocStats(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody()
|
||||
{ workspaceId, timestamp }: { workspaceId: string; timestamp?: number }
|
||||
): Promise<EventResponse<Record<string, number>>> {
|
||||
return this.onLoadDocTimestamps(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('client-update-v2')
|
||||
async handleClientUpdateV2(
|
||||
@CurrentUser() user: CurrentUser,
|
||||
@MessageBody()
|
||||
{
|
||||
workspaceId,
|
||||
guid,
|
||||
updates,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
guid: string;
|
||||
updates: string[];
|
||||
},
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse<{ accepted: true; timestamp?: number }>> {
|
||||
return this.onReceiveDocUpdates(client, user, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: guid,
|
||||
updates,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('doc-load-v2')
|
||||
async loadDocV2(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody()
|
||||
{
|
||||
workspaceId,
|
||||
guid,
|
||||
stateVector,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
guid: string;
|
||||
stateVector?: string;
|
||||
}
|
||||
): Promise<
|
||||
EventResponse<{ missing: string; state?: string; timestamp: number }>
|
||||
> {
|
||||
return this.onLoadSpaceDoc(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: guid,
|
||||
stateVector,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('client-handshake-awareness')
|
||||
async handleClientHandshakeAwareness(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@CurrentUser() user: CurrentUser,
|
||||
@MessageBody('workspaceId') workspaceId: string,
|
||||
@MessageBody('version') version: string
|
||||
): Promise<EventResponse<{ clientId: string }>> {
|
||||
return this.onJoinAwareness(client, user, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: workspaceId,
|
||||
clientVersion: version,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('client-leave-awareness')
|
||||
async handleLeaveAwareness(
|
||||
@MessageBody() workspaceId: string,
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse> {
|
||||
return this.onLeaveAwareness(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('awareness-init')
|
||||
async handleInitAwareness(
|
||||
@MessageBody() workspaceId: string,
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse<{ clientId: string }>> {
|
||||
return this.onLoadAwareness(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage('awareness-update')
|
||||
async handleHelpGatheringAwareness(
|
||||
@MessageBody()
|
||||
{
|
||||
workspaceId,
|
||||
awarenessUpdate,
|
||||
}: { workspaceId: string; awarenessUpdate: string },
|
||||
@ConnectedSocket() client: Socket
|
||||
): Promise<EventResponse> {
|
||||
return this.onUpdateAwareness(client, {
|
||||
spaceType: SpaceType.Workspace,
|
||||
spaceId: workspaceId,
|
||||
docId: workspaceId,
|
||||
awarenessUpdate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SyncSocketAdapter {
|
||||
@@ -647,7 +500,8 @@ abstract class SyncSocketAdapter {
|
||||
): Promise<void>;
|
||||
|
||||
push(spaceId: string, docId: string, updates: Buffer[], editorId: string) {
|
||||
this.assertIn(spaceId);
|
||||
// TODO(@forehalo): enable this after 0.19 goes out of life
|
||||
// this.assertIn(spaceId);
|
||||
return this.storage.pushDocUpdates(spaceId, docId, updates, editorId);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,12 @@ export class VersionService {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!clientVersion || !semver.satisfies(clientVersion, range)) {
|
||||
if (
|
||||
!clientVersion ||
|
||||
!semver.satisfies(clientVersion, range, {
|
||||
includePrerelease: true,
|
||||
})
|
||||
) {
|
||||
throw new UnsupportedClientVersion({
|
||||
clientVersion: clientVersion ?? 'unset_or_invalid',
|
||||
requiredVersion,
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"@types/debug": "^4.1.12",
|
||||
"vitest": "3.0.6"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -21,5 +21,5 @@
|
||||
"dependencies": {
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -44,5 +44,5 @@
|
||||
"electron": "*",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"version": "0.19.0"
|
||||
"version": "0.20.0"
|
||||
}
|
||||
|
||||
@@ -3,15 +3,63 @@ edition = "2021"
|
||||
name = "affine_common"
|
||||
version = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
doc-loader = ["docx-parser", "infer", "path-ext", "pdf-extract", "readability", "serde_json", "strum_macros", "text-splitter", "thiserror", "tree-sitter", "url"]
|
||||
tree-sitter = [
|
||||
"cc",
|
||||
"dep:tree-sitter",
|
||||
"dep:tree-sitter-c",
|
||||
"dep:tree-sitter-c-sharp",
|
||||
"dep:tree-sitter-cpp",
|
||||
"dep:tree-sitter-go",
|
||||
"dep:tree-sitter-java",
|
||||
"dep:tree-sitter-javascript",
|
||||
"dep:tree-sitter-kotlin-ng",
|
||||
"dep:tree-sitter-python",
|
||||
"dep:tree-sitter-rust",
|
||||
"dep:tree-sitter-scala",
|
||||
"dep:tree-sitter-typescript",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
sha3 = { workspace = true }
|
||||
|
||||
docx-parser = { git = "https://github.com/toeverything/docx-parser", optional = true }
|
||||
infer = { version = "0.19.0", optional = true }
|
||||
path-ext = { version = "0.1.1", optional = true }
|
||||
pdf-extract = { version = "0.8.2", optional = true }
|
||||
readability = { version = "0.3.0", optional = true, default-features = false }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
strum_macros = { version = "0.26.2", optional = true }
|
||||
text-splitter = { version = "0.22", features = ["markdown", "tiktoken-rs"], optional = true }
|
||||
thiserror = { version = "1", optional = true }
|
||||
tree-sitter = { version = "0.25", optional = true }
|
||||
tree-sitter-c = { version = "0.23", optional = true }
|
||||
tree-sitter-c-sharp = { version = "0.23", optional = true }
|
||||
tree-sitter-cpp = { version = "0.23", optional = true }
|
||||
tree-sitter-go = { version = "0.23", optional = true }
|
||||
tree-sitter-java = { version = "0.23", optional = true }
|
||||
tree-sitter-javascript = { version = "0.23", optional = true }
|
||||
tree-sitter-kotlin-ng = { version = "1.1", optional = true }
|
||||
tree-sitter-python = { version = "0.23", optional = true }
|
||||
tree-sitter-rust = { version = "0.23", optional = true }
|
||||
tree-sitter-scala = { version = "0.23", optional = true }
|
||||
tree-sitter-typescript = { version = "0.23", optional = true }
|
||||
url = { version = "2.5", optional = true }
|
||||
|
||||
|
||||
tiktoken-rs = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion2 = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1", optional = true }
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "hashcash"
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
# DOCX Demo
|
||||
|
||||
# <a name="OLE_LINK1"></a><a name="OLE_LINK2"></a><a name="_Toc359077851"></a>Demonstration of DOCX support in calibre
|
||||
|
||||
This document demonstrates the ability of the calibre DOCX Input plugin to convert the various typographic features in a Microsoft Word (2007 and newer) document. Convert this document to a modern ebook format, such as AZW3 for Kindles or EPUB for other ebook readers, to see it in action.
|
||||
|
||||
There is support for images, tables, lists, footnotes, endnotes, links, dropcaps and various types of text and paragraph level formatting.
|
||||
|
||||
To see the DOCX conversion in action, simply add this file to calibre using the **“Add Books” **button and then click “**Convert”. ** Set the output format in the top right corner of the conversion dialog to EPUB or AZW3 and click **“OK”**.
|
||||
|
||||
# <a name="_Toc359077852"></a>Text Formatting
|
||||
|
||||
## <a name="_Toc359077853"></a>Inline formatting
|
||||
|
||||
Here, we demonstrate various types of inline text formatting and the use of embedded fonts.
|
||||
|
||||
Here is some **bold, ***italic, ****bold-italic, ***__underlined __and ~~struck out ~~ text. Then, we have a superscript and a subscript. Now we see some red, green and blue text. Some text with a yellow highlight. Some text in a box. Some text in inverse video.
|
||||
|
||||
A paragraph with styled text: subtle emphasis followed by strong text and intense emphasis. This paragraph uses document wide styles for styling rather than inline text properties as demonstrated in the previous paragraph — calibre can handle both with equal ease.
|
||||
|
||||
## <a name="_Toc359077854"></a>Fun with fonts
|
||||
|
||||
This document has embedded the Ubuntu font family. The body text is in the Ubuntu typeface, here is some text in the Ubuntu Mono typeface, notice how every letter has the same width, even i and m. Every embedded font will automatically be embedded in the output ebook during conversion.
|
||||
|
||||
## ***<a name="_Paragraph_level_formatting"></a>******<a name="_Toc359077855"></a>******Paragraph level formatting***
|
||||
|
||||
You can do crazy things with paragraphs, if the urge strikes you. For instance this paragraph is right aligned and has a right border. It has also been given a light gray background.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
For the lovers of poetry amongst you, paragraphs with hanging indents, like this often come in handy. You can use hanging indents to ensure that a line of poetry retains its individual identity as a line even when the screen is too narrow to display it as a single line. Not only does this paragraph have a hanging indent, it is also has an extra top margin, setting it apart from the preceding paragraph.
|
||||
|
||||
# <a name="_Toc359077856"></a>Tables
|
||||
|
||||
| | |
|
||||
| ----------- | -------- |
|
||||
| ITEM | NEEDED |
|
||||
| Books | 1 |
|
||||
| Pens | 3 |
|
||||
| Pencils | 2 |
|
||||
| Highlighter | 2 colors |
|
||||
| Scissors | 1 pair |
|
||||
|
||||
Tables in Word can vary from the extremely simple to the extremely complex. calibre tries to do its best when converting tables. While you may run into trouble with the occasional table, the vast majority of common cases should be converted very well, as demonstrated in this section. Note that for optimum results, when creating tables in Word, you should set their widths using percentages, rather than absolute units. To the left of this paragraph is a floating two column table with a nice green border and header row.
|
||||
|
||||
Now let’s look at a fancier table—one with alternating row colors and partial borders. This table is stretched out to take 100% of the available width.
|
||||
|
||||
| | | | | | |
|
||||
| ------------ | ------- | ------- | ------- | ------- | ------- |
|
||||
| City or Town | Point A | Point B | Point C | Point D | Point E |
|
||||
| Point A | — | | | | |
|
||||
| Point B | 87 | — | | | |
|
||||
| Point C | 64 | 56 | — | | |
|
||||
| Point D | 37 | 32 | 91 | — | |
|
||||
| Point E | 93 | 35 | 54 | 43 | — |
|
||||
|
||||
Next, we see a table with special formatting in various locations. Notice how the formatting for the header row and sub header rows is preserved.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
| | | | |
|
||||
| ---------------- | ------------- | ------------------- | ------ |
|
||||
| College | New students | Graduating students | Change |
|
||||
| | Undergraduate | | |
|
||||
| Cedar University | 110 | 103 | +7 |
|
||||
| Oak Institute | 202 | 210 | -8 |
|
||||
| | Graduate | | |
|
||||
| Cedar University | 24 | 20 | +4 |
|
||||
| Elm College | 43 | 53 | -10 |
|
||||
| Total | 998 | 908 | 90 |
|
||||
|
||||
Source: Fictitious data, for illustration purposes only
|
||||
|
||||
Next, we have something a little more complex, a nested table, i.e. a table inside another table. Additionally, the inner table has some of its cells merged. The table is displayed horizontally centered.
|
||||
|
||||
| | |
|
||||
| --- | -------------------------------------------------------------- |
|
||||
| | To the left is a table inside a table, with some cells merged. |
|
||||
|
||||
We end with a fancy calendar, note how much of the original formatting is preserved. Note that this table will only display correctly on relatively wide screens. In general, very wide tables or tables whose cells have fixed width requirements don’t fare well in ebooks.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
| | | | | | | | | | | | | |
|
||||
| ------------- | | --- | | --- | | --- | | --- | | --- | | --- |
|
||||
| December 2007 | | | | | | | | | | | | |
|
||||
| Sun | | Mon | | Tue | | Wed | | Thu | | Fri | | Sat |
|
||||
| | | | | | | | | | | | | 1 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 9 | | 10 | | 11 | | 12 | | 13 | | 14 | | 15 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 16 | | 17 | | 18 | | 19 | | 20 | | 21 | | 22 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 23 | | 24 | | 25 | | 26 | | 27 | | 28 | | 29 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 30 | | 31 | | | | | | | | | | |
|
||||
|
||||
# <a name="_Toc359077857"></a>Structural Elements
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
Miscellaneous structural elements you can add to your document, like footnotes, endnotes, dropcaps and the like.
|
||||
|
||||
## <a name="_Toc359077858"></a>Footnotes & Endnotes
|
||||
|
||||
Footnotes and endnotes are automatically recognized and both are converted to endnotes, with backlinks for maximum ease of use in ebook devices.
|
||||
|
||||
## <a name="_Toc359077859"></a>Dropcaps
|
||||
|
||||
D
|
||||
|
||||
rop caps are used to emphasize the leading paragraph at the start of a section. In Word it is possible to specify how many lines of text a drop-cap should use. Because of limitations in ebook technology, this is not possible when converting. Instead, the converted drop cap will use font size and line height to simulate the effect as well as possible. While not as good as the original, the result is usually tolerable. This paragraph has a “D” dropcap set to occupy three lines of text with a font size of 58.5 pts. Depending on the screen width and capabilities of the device you view the book on, this dropcap can look anything from perfect to ugly.
|
||||
|
||||
## <a name="_Toc359077860"></a>Links
|
||||
|
||||
Two kinds of links are possible, those that refer to an external website and those that refer to locations inside the document itself. Both are supported by calibre. For example, here is a link pointing to the [calibre download page](http://calibre-ebook.com/download). Then we have a link that points back to the section on [paragraph level formatting](#_Paragraph_level_formatting) in this document.
|
||||
|
||||
## <a name="_Toc359077861"></a>Table of Contents
|
||||
|
||||
There are two approaches that calibre takes when generating a Table of Contents. The first is if the Word document has a Table of Contents itself. Provided that the Table of Contents uses hyperlinks, calibre will automatically use it. The levels of the Table of Contents are identified by their left indent, so if you want the ebook to have a multi-level Table of Contents, make sure you create a properly indented Table of Contents in Word.
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
If no Table of Contents is found in the document, then a table of contents is automatically generated from the headings in the document. A heading is identified as something that has the Heading 1 or Heading 2, etc. style applied to it. These headings are turned into a Table of Contents with Heading 1 being the topmost level, Heading 2 the second level and so on.
|
||||
|
||||
You can see the Table of Contents created by calibre by clicking the Table of Contents button in whatever viewer you are using to view the converted ebook.
|
||||
|
||||
# <a name="_Toc359077862"></a>Images
|
||||
|
||||
Images can be of three main types. Inline images are images that are part of the normal text flow, like this image of a green dot . Inline images do not cause breaks in the text and are usually small in size. The next category of image is a floating image, one that “floats “ on the page and is surrounded by text. Word supports more types of floating images than are possible with current ebook technology, so the conversion maps floating images to simple left and right floats, as you can see with the left and right arrow images on the sides of this paragraph.
|
||||
|
||||
The final type of image is a “block” image, one that becomes a paragraph on its own and has no text on either side. Below is a centered green dot.
|
||||
|
||||
Centered images like this are useful for large pictures that should be a focus of attention.
|
||||
|
||||
Generally, it is not possible to translate the exact positioning of images from a Word document to an ebook. That is because in Word, image positioning is specified in absolute units from the page boundaries. There is no analogous technology in ebooks, so the conversion will usually end up placing the image either centered or floating close to the point in the text where it was inserted, not necessarily where it appears on the page in Word.
|
||||
|
||||
# <a name="_Toc359077863"></a>Lists
|
||||
|
||||
All types of lists are supported by the conversion, with the exception of lists that use fancy bullets, these get converted to regular bullets.
|
||||
|
||||
## <a name="_Toc359077864"></a>Bulleted List
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
## <a name="_Toc359077865"></a>Numbered List
|
||||
|
||||
1. One, with a very long line to demonstrate that the hanging indent for the list is working correctly
|
||||
|
||||
2. Two
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
## <a name="_Toc359077866"></a>Multi-level Lists
|
||||
|
||||
1. One
|
||||
|
||||
2. Two
|
||||
|
||||
3. Three
|
||||
|
||||
4. Four with a very long line to demonstrate that the hanging indent for the list is working correctly.
|
||||
|
||||
5. Five
|
||||
|
||||
6. Six
|
||||
|
||||
A Multi-level list with bullets:
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
- This bullet uses an image as the bullet item
|
||||
|
||||
- Four
|
||||
|
||||
- Five
|
||||
|
||||
## <a name="_Toc359077867"></a>Continued Lists
|
||||
|
||||
i. One
|
||||
|
||||
j. Two
|
||||
|
||||
An interruption in our regularly scheduled listing, for this essential and very relevant public service announcement.
|
||||
|
||||
k. We now resume our normal programming
|
||||
|
||||
l. Four
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user