chore: bump blocksuite (#8230)

## 0.17.11

### Patch Changes

- [3c61be5](https://github.com/toeverything/blocksuite/commit/3c61be5dedcc1fc37d6f09ed2541b391584c0ded): - Refactor drag handle widget
  - Split embed blocks to `@blocksuite/affine-block-embed`
  - Fix latex selected state in edgeless mode
  - Fix unclear naming
  - Fix prototype pollution
  - Fix portal interaction in affine modal
  - Fix paste linked block on edgeless
  - Add scroll anchoring widget
  - Add highlight selection
This commit is contained in:
fundon
2024-09-18 12:11:14 +00:00
parent b73d3b3d55
commit f397815ad1
21 changed files with 424 additions and 300 deletions
@@ -1,10 +1,15 @@
import type { DocMode, EdgelessRootService } from '@blocksuite/blocks';
import type {
DocMode,
EdgelessRootService,
ReferenceParams,
} from '@blocksuite/blocks';
import type { InlineEditor } from '@blocksuite/inline';
import type { AffineEditorContainer, DocTitle } from '@blocksuite/presets';
import type { DocService, WorkspaceService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import { isEqual } from 'lodash-es';
import { paramsParseOptions, preprocessParams } from '../../navigation/utils';
import type { WorkbenchView } from '../../workbench';
import { EditorScope } from '../scopes/editor';
import type { EditorSelector } from '../types';
@@ -58,22 +63,11 @@ export class Editor extends Entity {
*/
bindWorkbenchView(view: WorkbenchView) {
// eslint-disable-next-line rxjs/finnish
const viewParams$ = view.queryString$<{
mode?: DocMode;
blockIds?: string[];
elementIds?: string[];
refreshKey?: string;
}>({
// Cannot handle single id situation correctly: `blockIds=xxx`
arrayFormat: 'none',
types: {
mode: value =>
value === 'page' || value === 'edgeless' ? value : undefined,
blockIds: value => (value.length ? value.split(',') : []),
elementIds: value => (value.length ? value.split(',') : []),
refreshKey: 'string',
},
});
const viewParams$ = view
.queryString$<
ReferenceParams & { refreshKey?: string }
>(paramsParseOptions)
.map(preprocessParams);
const stablePrimaryMode = this.doc.getPrimaryMode();
@@ -6,7 +6,6 @@ import type {
EdgelessRootService,
PageRootService,
} from '@blocksuite/blocks';
import { ZOOM_MAX } from '@blocksuite/blocks';
import { Bound, deserializeXYWH } from '@blocksuite/global/utils';
function scrollAnchoringInEdgelessMode(
@@ -47,8 +46,7 @@ function scrollAnchoringInEdgelessMode(
const { zoom, centerX, centerY } = service.getFitToScreenData(
[20, 20, 100, 20],
[bounds],
ZOOM_MAX
[bounds]
);
service.viewport.setCenter(centerX, centerY);
@@ -53,13 +53,37 @@ const testCases: [string, ReturnType<typeof resolveLinkToDoc>][] = [
},
],
[
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx',
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?mode=page&blockIds=xxxx',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
mode: 'page',
blockIds: ['xxxx'],
},
],
[
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?mode=&blockIds=',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
},
],
[
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?mode=edgeless&elementIds=yyyy',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
mode: 'edgeless',
elementIds: ['yyyy'],
},
],
[
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?mode=edgeles&elementId=yyyy',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
},
],
];
for (const [input, expected] of testCases) {
@@ -1,4 +1,6 @@
import type { DocMode } from '@blocksuite/blocks';
import type { ReferenceParams } from '@blocksuite/blocks';
import { isNil, pick, pickBy } from 'lodash-es';
import type { ParsedQuery, ParseOptions } from 'query-string';
import queryString from 'query-string';
function maybeAffineOrigin(origin: string) {
@@ -61,6 +63,23 @@ export const resolveRouteLinkMeta = (href: string) => {
}
};
export const isLink = (href: string) => {
try {
const hasScheme = href.match(/^https?:\/\//);
if (!hasScheme) {
const dotIdx = href.indexOf('.');
if (dotIdx > 0 && dotIdx < href.length - 1) {
href = `https://${href}`;
}
}
return Boolean(URL.canParse?.(href) ?? new URL(href));
} catch {
return null;
}
};
/**
* @see /packages/frontend/core/src/router.tsx
*/
@@ -76,22 +95,49 @@ export const resolveLinkToDoc = (href: string) => {
const meta = resolveRouteLinkMeta(href);
if (!meta || meta.moduleName !== 'doc') return null;
const params: {
mode?: DocMode;
blockIds?: string[];
elementIds?: string[];
} = queryString.parse(meta.location.search, {
arrayFormat: 'none',
types: {
mode: value => (value === 'edgeless' ? 'edgeless' : 'page') as DocMode,
blockIds: value => value.split(','),
elementIds: value => value.split(','),
},
});
const params = preprocessParams(
queryString.parse(meta.location.search, paramsParseOptions)
);
return {
workspaceId: meta.workspaceId,
docId: meta.docId,
...pick(meta, ['workspaceId', 'docId']),
...params,
};
};
export const preprocessParams = (
params: ParsedQuery<string>
): ReferenceParams & { refreshKey?: string } => {
const result: ReferenceParams & { refreshKey?: string } = pickBy(
params,
value => {
if (isNil(value)) return false;
if (typeof value === 'string' && value.length === 0) return false;
if (Array.isArray(value) && value.length === 0) return false;
return true;
}
);
if (result.blockIds?.length) {
result.blockIds = result.blockIds.filter(v => v.length);
}
if (result.elementIds?.length) {
result.elementIds = result.elementIds.filter(v => v.length);
}
return pick(result, ['mode', 'blockIds', 'elementIds', 'refreshKey']);
};
export const paramsParseOptions: ParseOptions = {
// Cannot handle single id situation correctly: `blockIds=xxx`
arrayFormat: 'none',
types: {
mode: value =>
value === 'page' || value === 'edgeless' ? value : undefined,
blockIds: value =>
value.length ? value.split(',').filter(v => v.length) : [],
elementIds: value =>
value.length ? value.split(',').filter(v => v.length) : [],
refreshKey: 'string',
},
};
@@ -3,6 +3,7 @@ import type { WorkspaceService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import { resolveLinkToDoc } from '../../navigation';
import { isLink } from '../../navigation/utils';
import type { QuickSearchSession } from '../providers/quick-search-provider';
import type { QuickSearchItem } from '../types/item';
@@ -21,11 +22,10 @@ export class ExternalLinksQuickSearchSession
query$ = new LiveData('');
items$ = LiveData.computed(get => {
const query = get(this.query$);
const query = get(this.query$).trim();
if (!query) return [];
const isLink = query.startsWith('http://') || query.startsWith('https://');
if (!isLink) return [];
if (!isLink(query)) return [];
const resolvedDoc = resolveLinkToDoc(query);
if (
@@ -1,20 +1,16 @@
import type { DocMode } from '@blocksuite/blocks';
import type { ReferenceParams } from '@blocksuite/blocks';
import { BlockLinkIcon, EdgelessIcon, PageIcon } from '@blocksuite/icons/rc';
import type { DocsService, WorkspaceService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import { truncate } from 'lodash-es';
import { omit, truncate } from 'lodash-es';
import { resolveLinkToDoc } from '../../navigation';
import { isLink } from '../../navigation/utils';
import type { QuickSearchSession } from '../providers/quick-search-provider';
import type { DocDisplayMetaService } from '../services/doc-display-meta';
import type { QuickSearchItem } from '../types/item';
type LinkPayload = {
docId: string;
blockIds?: string[];
elementIds?: string[];
mode?: DocMode;
};
type LinkPayload = { docId: string } & ReferenceParams;
export class LinksQuickSearchSession
extends Entity
@@ -31,11 +27,10 @@ export class LinksQuickSearchSession
query$ = new LiveData('');
items$ = LiveData.computed(get => {
const query = get(this.query$);
const query = get(this.query$).trim();
if (!query) return [];
const isLink = query.startsWith('http://') || query.startsWith('https://');
if (!isLink) return [];
if (!isLink(query)) return [];
const resolvedDoc = resolveLinkToDoc(query);
if (
@@ -53,6 +48,13 @@ export class LinksQuickSearchSession
this.docDisplayMetaService.getDocDisplayMeta(doc);
const linkToNode = resolvedDoc.blockIds || resolvedDoc.elementIds;
const score = 100;
const payload = omit(resolvedDoc, ['workspaceId']);
const icons = {
page: PageIcon,
edgeless: EdgelessIcon,
node: BlockLinkIcon,
other: icon,
};
return [
{
@@ -67,23 +69,12 @@ export class LinksQuickSearchSession
score: 5,
},
label: {
title: title,
title,
},
score,
icon: linkToNode
? BlockLinkIcon
: resolvedDoc.mode === 'page'
? PageIcon
: resolvedDoc.mode === 'edgeless'
? EdgelessIcon
: icon,
icon: icons[linkToNode ? 'node' : (resolvedDoc.mode ?? 'other')],
timestamp: updatedDate,
payload: {
docId,
blockIds: resolvedDoc.blockIds,
elementIds: resolvedDoc.elementIds,
mode: resolvedDoc.mode,
},
payload,
} as QuickSearchItem<'link', LinkPayload>,
];
});