mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-17 18:16:15 +08:00
refactor(editor): adjust folder structure for slash menu extension (#10588)
Close [BS-2743](https://linear.app/affine-design/issue/BS-2743/slash-menu插件化:调整文件夹结构) This PR move slash menu from `affine-root-block` to `widget-affine-slash-menu`, and make it as a `WidgetViewExtension`
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
||||
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
||||
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||
"@blocksuite/affine-widget-toolbar": "workspace:*",
|
||||
"@blocksuite/block-std": "workspace:*",
|
||||
"@blocksuite/data-view": "workspace:*",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
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 { SlashMenuExtension } from '@blocksuite/affine-widget-slash-menu';
|
||||
import { toolbarWidget } from '@blocksuite/affine-widget-toolbar';
|
||||
import {
|
||||
BlockFlavourIdentifier,
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
innerModalWidget,
|
||||
linkedDocWidget,
|
||||
modalWidget,
|
||||
slashMenuWidget,
|
||||
viewportOverlayWidget,
|
||||
} from './widgets';
|
||||
|
||||
@@ -42,7 +42,7 @@ export const CommonSpecs: ExtensionType[] = [
|
||||
|
||||
modalWidget,
|
||||
innerModalWidget,
|
||||
slashMenuWidget,
|
||||
SlashMenuExtension,
|
||||
linkedDocWidget,
|
||||
dragHandleWidget,
|
||||
docRemoteSelectionWidget,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
import { AFFINE_INNER_MODAL_WIDGET } from '../widgets/inner-modal/inner-modal.js';
|
||||
import { AFFINE_LINKED_DOC_WIDGET } from '../widgets/linked-doc/config.js';
|
||||
import { AFFINE_MODAL_WIDGET } from '../widgets/modal/modal.js';
|
||||
import { AFFINE_SLASH_MENU_WIDGET } from '../widgets/slash-menu/index.js';
|
||||
import { AFFINE_VIEWPORT_OVERLAY_WIDGET } from '../widgets/viewport-overlay/viewport-overlay.js';
|
||||
|
||||
export const modalWidget = WidgetViewExtension(
|
||||
@@ -17,11 +16,6 @@ export const innerModalWidget = WidgetViewExtension(
|
||||
AFFINE_INNER_MODAL_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_INNER_MODAL_WIDGET)}`
|
||||
);
|
||||
export const slashMenuWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_SLASH_MENU_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_SLASH_MENU_WIDGET)}`
|
||||
);
|
||||
export const linkedDocWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_LINKED_DOC_WIDGET,
|
||||
|
||||
@@ -106,14 +106,6 @@ import {
|
||||
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
||||
AffinePageDraggingAreaWidget,
|
||||
} from './widgets/page-dragging-area/page-dragging-area.js';
|
||||
import {
|
||||
AFFINE_SLASH_MENU_WIDGET,
|
||||
AffineSlashMenuWidget,
|
||||
} from './widgets/slash-menu/index.js';
|
||||
import {
|
||||
InnerSlashMenu,
|
||||
SlashMenu,
|
||||
} from './widgets/slash-menu/slash-menu-popover.js';
|
||||
import {
|
||||
AFFINE_SURFACE_REF_TOOLBAR,
|
||||
AffineSurfaceRefToolbar,
|
||||
@@ -156,7 +148,6 @@ function registerWidgets() {
|
||||
AffinePageDraggingAreaWidget
|
||||
);
|
||||
customElements.define(AFFINE_IMAGE_TOOLBAR_WIDGET, AffineImageToolbarWidget);
|
||||
customElements.define(AFFINE_SLASH_MENU_WIDGET, AffineSlashMenuWidget);
|
||||
customElements.define(
|
||||
AFFINE_VIEWPORT_OVERLAY_WIDGET,
|
||||
AffineViewportOverlayWidget
|
||||
@@ -274,8 +265,6 @@ function registerEdgelessEditorComponents() {
|
||||
function registerMiscComponents() {
|
||||
// Modal and menu components
|
||||
customElements.define('affine-custom-modal', AffineCustomModal);
|
||||
customElements.define('affine-slash-menu', SlashMenu);
|
||||
customElements.define('inner-slash-menu', InnerSlashMenu);
|
||||
|
||||
// Loading and preview components
|
||||
customElements.define('loader-element', Loader);
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
|
||||
AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET,
|
||||
} from '@blocksuite/affine-widget-remote-selection';
|
||||
import type { AFFINE_SLASH_MENU_WIDGET } from '@blocksuite/affine-widget-slash-menu';
|
||||
|
||||
import type { EdgelessRootBlockComponent } from './edgeless/edgeless-root-block.js';
|
||||
import type { PageRootBlockComponent } from './page/page-root-block.js';
|
||||
@@ -14,7 +15,6 @@ import type { AFFINE_INNER_MODAL_WIDGET } from './widgets/inner-modal/inner-moda
|
||||
import type { AFFINE_LINKED_DOC_WIDGET } from './widgets/linked-doc/config.js';
|
||||
import type { AFFINE_MODAL_WIDGET } from './widgets/modal/modal.js';
|
||||
import type { AFFINE_PAGE_DRAGGING_AREA_WIDGET } from './widgets/page-dragging-area/page-dragging-area.js';
|
||||
import type { AFFINE_SLASH_MENU_WIDGET } from './widgets/slash-menu/index.js';
|
||||
import type { AFFINE_VIEWPORT_OVERLAY_WIDGET } from './widgets/viewport-overlay/viewport-overlay.js';
|
||||
|
||||
export type PageRootBlockWidgetName =
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO(@L-Sun): remove these utils
|
||||
export function formatDate(date: Date) {
|
||||
// yyyy-mm-dd
|
||||
const year = date.getFullYear();
|
||||
|
||||
@@ -21,15 +21,6 @@ export {
|
||||
export { AffineLinkedDocWidget } from './linked-doc/index.js';
|
||||
export { AffineModalWidget } from './modal/modal.js';
|
||||
export { AffinePageDraggingAreaWidget } from './page-dragging-area/page-dragging-area.js';
|
||||
export {
|
||||
type AffineSlashMenuActionItem,
|
||||
type AffineSlashMenuContext,
|
||||
type AffineSlashMenuGroupDivider,
|
||||
type AffineSlashMenuItem,
|
||||
type AffineSlashMenuItemGenerator,
|
||||
AffineSlashMenuWidget,
|
||||
type AffineSlashSubMenu,
|
||||
} from './slash-menu/index.js';
|
||||
export { AffineSurfaceRefToolbar } from './surface-ref-toolbar/surface-ref-toolbar.js';
|
||||
export * from './viewport-overlay/viewport-overlay.js';
|
||||
export { AffineFrameTitleWidget } from '@blocksuite/affine-widget-frame-title';
|
||||
|
||||
@@ -8,6 +8,7 @@ import { unsafeCSSVar } from '@blocksuite/affine-shared/theme';
|
||||
import {
|
||||
createKeydownObserver,
|
||||
getCurrentNativeRange,
|
||||
getPopperPosition,
|
||||
getViewportElement,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { PropTypes, requiredProperties } from '@blocksuite/block-std';
|
||||
@@ -20,7 +21,6 @@ import { property, query, queryAll, state } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import throttle from 'lodash-es/throttle';
|
||||
|
||||
import { getPopperPosition } from '../../utils/position.js';
|
||||
import type { LinkedDocContext, LinkedMenuGroup } from './config.js';
|
||||
import { linkedDocPopoverStyles } from './styles.js';
|
||||
import { resolveSignal } from './utils.js';
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
{ "path": "../widget-frame-title" },
|
||||
{ "path": "../widget-remote-selection" },
|
||||
{ "path": "../widget-scroll-anchoring" },
|
||||
{ "path": "../widget-slash-menu" },
|
||||
{ "path": "../widget-toolbar" },
|
||||
{ "path": "../../framework/block-std" },
|
||||
{ "path": "../data-view" },
|
||||
|
||||
@@ -14,6 +14,7 @@ export * from './insert';
|
||||
export * from './is-abort-error';
|
||||
export * from './math';
|
||||
export * from './model';
|
||||
export * from './popper-position';
|
||||
export * from './print-to-pdf';
|
||||
export * from './reference';
|
||||
export * from './reordering';
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ type CollisionBox = {
|
||||
edgeGap?: number;
|
||||
};
|
||||
|
||||
export function calcSafeCoordinate({
|
||||
function calcSafeCoordinate({
|
||||
positioningPoint,
|
||||
objRect = { width: 0, height: 0 },
|
||||
boundaryRect = document.body.getBoundingClientRect(),
|
||||
@@ -50,7 +50,7 @@ export function calcSafeCoordinate({
|
||||
*
|
||||
* Please give preference to {@link getPopperPosition}
|
||||
*/
|
||||
export function compareTopAndBottomSpace(
|
||||
function compareTopAndBottomSpace(
|
||||
obj: { getBoundingClientRect: () => DOMRect },
|
||||
container = document.body,
|
||||
gap = 20
|
||||
@@ -0,0 +1 @@
|
||||
# widget-slash-menu
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "@blocksuite/affine-widget-slash-menu",
|
||||
"description": "Affine slash menu widget.",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test:unit": "nx vite:test --run --passWithNoTests",
|
||||
"test:unit:coverage": "nx vite:test --run --coverage",
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"keywords": [],
|
||||
"author": "toeverything",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@blocksuite/affine-block-attachment": "workspace:*",
|
||||
"@blocksuite/affine-block-database": "workspace:*",
|
||||
"@blocksuite/affine-block-embed": "workspace:*",
|
||||
"@blocksuite/affine-block-image": "workspace:*",
|
||||
"@blocksuite/affine-block-latex": "workspace:*",
|
||||
"@blocksuite/affine-block-note": "workspace:*",
|
||||
"@blocksuite/affine-block-surface": "workspace:*",
|
||||
"@blocksuite/affine-block-surface-ref": "workspace:*",
|
||||
"@blocksuite/affine-block-table": "workspace:*",
|
||||
"@blocksuite/affine-components": "workspace:*",
|
||||
"@blocksuite/affine-shared": "workspace:*",
|
||||
"@blocksuite/block-std": "workspace:*",
|
||||
"@blocksuite/data-view": "workspace:*",
|
||||
"@blocksuite/global": "workspace:*",
|
||||
"@blocksuite/icons": "^2.2.4",
|
||||
"@blocksuite/inline": "workspace:*",
|
||||
"@blocksuite/store": "workspace:*",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@preact/signals-core": "^1.8.0",
|
||||
"@toeverything/theme": "^1.1.12",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"lit": "^3.2.0",
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./effects": "./src/effects.ts"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"dist",
|
||||
"!src/__tests__",
|
||||
"!dist/__tests__"
|
||||
],
|
||||
"version": "0.20.0"
|
||||
}
|
||||
+112
-113
@@ -57,8 +57,8 @@ import {
|
||||
createDefaultDoc,
|
||||
openFileOrFiles,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
||||
import { viewPresets } from '@blocksuite/data-view/view-presets';
|
||||
import { assertType } from '@blocksuite/global/utils';
|
||||
import {
|
||||
DualLinkIcon,
|
||||
ExportToPdfIcon,
|
||||
@@ -74,16 +74,15 @@ import type { BlockModel } from '@blocksuite/store';
|
||||
import { Slice, Text } from '@blocksuite/store';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import type { RootBlockComponent } from '../../types.js';
|
||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
||||
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||
import { type SlashMenuTooltip, slashMenuToolTips } from './tooltips/index.js';
|
||||
import { type SlashMenuTooltip, slashMenuToolTips } from './tooltips';
|
||||
import {
|
||||
createConversionItem,
|
||||
createTextFormatItem,
|
||||
formatDate,
|
||||
formatTime,
|
||||
insideEdgelessText,
|
||||
tryRemoveEmptyLine,
|
||||
} from './utils.js';
|
||||
} from './utils';
|
||||
|
||||
export type SlashMenuConfig = {
|
||||
triggerKeys: string[];
|
||||
@@ -136,7 +135,7 @@ export type SlashMenuItemGenerator = (
|
||||
) => (SlashMenuGroupDivider | SlashMenuActionItem | SlashSubMenu)[];
|
||||
|
||||
export type SlashMenuContext = {
|
||||
rootComponent: RootBlockComponent;
|
||||
std: BlockStdScope;
|
||||
model: BlockModel;
|
||||
};
|
||||
|
||||
@@ -183,7 +182,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
showWhen: ({ model }) => {
|
||||
return model.doc.get(FeatureFlagService).getFlag('enable_callout');
|
||||
},
|
||||
action: ({ model, rootComponent }) => {
|
||||
action: ({ model, std }) => {
|
||||
const { doc } = model;
|
||||
const parent = doc.getParent(model);
|
||||
if (!parent) return;
|
||||
@@ -194,11 +193,11 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
if (!calloutId) return;
|
||||
const paragraphId = doc.addBlock('affine:paragraph', {}, calloutId);
|
||||
if (!paragraphId) return;
|
||||
rootComponent.updateComplete
|
||||
std.host.updateComplete
|
||||
.then(() => {
|
||||
const paragraph = rootComponent.std.view.getBlock(paragraphId);
|
||||
const paragraph = std.view.getBlock(paragraphId);
|
||||
if (!paragraph) return;
|
||||
rootComponent.std.command.exec(focusBlockEnd, {
|
||||
std.command.exec(focusBlockEnd, {
|
||||
focusBlock: paragraph,
|
||||
});
|
||||
})
|
||||
@@ -211,8 +210,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Create a equation block.',
|
||||
icon: TeXIcon(),
|
||||
alias: ['inlineMath, inlineEquation', 'inlineLatex'],
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getTextSelectionCommand)
|
||||
.pipe(insertInlineLatex)
|
||||
@@ -245,9 +244,9 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['New Doc'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc'),
|
||||
action: ({ rootComponent, model }) => {
|
||||
const newDoc = createDefaultDoc(rootComponent.doc.workspace);
|
||||
insertContent(rootComponent.host, model, REFERENCE_NODE, {
|
||||
action: ({ std, model }) => {
|
||||
const newDoc = createDefaultDoc(std.host.doc.workspace);
|
||||
insertContent(std.host, model, REFERENCE_NODE, {
|
||||
reference: {
|
||||
type: 'LinkedPage',
|
||||
pageId: newDoc.id,
|
||||
@@ -261,33 +260,36 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: LinkedDocIcon,
|
||||
tooltip: slashMenuToolTips['Linked Doc'],
|
||||
alias: ['dual link'],
|
||||
showWhen: ({ rootComponent, model }) => {
|
||||
const { std } = rootComponent;
|
||||
showWhen: ({ std, model }) => {
|
||||
const root = model.doc.root;
|
||||
if (!root) return false;
|
||||
const linkedDocWidget = std.view.getWidget(
|
||||
'affine-linked-doc-widget',
|
||||
rootComponent.model.id
|
||||
root.id
|
||||
);
|
||||
if (!linkedDocWidget) return false;
|
||||
|
||||
return model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc');
|
||||
},
|
||||
action: ({ model, rootComponent }) => {
|
||||
const { std } = rootComponent;
|
||||
|
||||
action: ({ model, std }) => {
|
||||
const root = model.doc.root;
|
||||
if (!root) return;
|
||||
const linkedDocWidget = std.view.getWidget(
|
||||
'affine-linked-doc-widget',
|
||||
rootComponent.model.id
|
||||
root.id
|
||||
);
|
||||
if (!linkedDocWidget) return;
|
||||
assertType<AffineLinkedDocWidget>(linkedDocWidget);
|
||||
|
||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||
// @ts-expect-error same as above
|
||||
const triggerKey = linkedDocWidget.config.triggerKeys[0];
|
||||
|
||||
insertContent(rootComponent.host, model, triggerKey);
|
||||
insertContent(std.host, model, triggerKey);
|
||||
|
||||
const inlineEditor = getInlineEditorByModel(rootComponent.host, model);
|
||||
const inlineEditor = getInlineEditorByModel(std.host, model);
|
||||
// Wait for range to be updated
|
||||
inlineEditor?.slots.inlineRangeSync.once(() => {
|
||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||
// @ts-expect-error same as above
|
||||
linkedDocWidget.show({ addTriggerKey: true });
|
||||
});
|
||||
},
|
||||
@@ -301,8 +303,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: TableIcon(),
|
||||
tooltip: slashMenuToolTips['Table View'],
|
||||
showWhen: ({ model }) => !insideEdgelessText(model),
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertTableBlockCommand, {
|
||||
@@ -311,8 +313,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
})
|
||||
.pipe(({ insertedTableBlockId }) => {
|
||||
if (insertedTableBlockId) {
|
||||
const telemetry =
|
||||
rootComponent.std.getOptional(TelemetryProvider);
|
||||
const telemetry = std.getOptional(TelemetryProvider);
|
||||
telemetry?.track('BlockCreated', {
|
||||
blockType: 'affine:table',
|
||||
});
|
||||
@@ -328,8 +329,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['Image'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:image'),
|
||||
action: async ({ rootComponent }) => {
|
||||
const [success, ctx] = rootComponent.std.command
|
||||
action: async ({ std }) => {
|
||||
const [success, ctx] = std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertImagesCommand, { removeEmptyLine: true })
|
||||
@@ -345,14 +346,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['Link'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:bookmark'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
const parentModel = rootComponent.doc.getParent(model);
|
||||
action: async ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
rootComponent.host,
|
||||
host,
|
||||
'Links',
|
||||
'The added link will be displayed as a card view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
@@ -368,19 +370,13 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
alias: ['file'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:attachment'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
action: async ({ std, model }) => {
|
||||
const file = await openFileOrFiles();
|
||||
if (!file) return;
|
||||
|
||||
const maxFileSize =
|
||||
rootComponent.std.store.get(FileSizeLimitService).maxFileSize;
|
||||
const maxFileSize = std.store.get(FileSizeLimitService).maxFileSize;
|
||||
|
||||
await addSiblingAttachmentBlocks(
|
||||
rootComponent.host,
|
||||
[file],
|
||||
maxFileSize,
|
||||
model
|
||||
);
|
||||
await addSiblingAttachmentBlocks(std.host, [file], maxFileSize, model);
|
||||
tryRemoveEmptyLine(model);
|
||||
},
|
||||
},
|
||||
@@ -391,15 +387,14 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['PDF'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:attachment'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
action: async ({ std, model }) => {
|
||||
const file = await openFileOrFiles();
|
||||
if (!file) return;
|
||||
|
||||
const maxFileSize =
|
||||
rootComponent.std.store.get(FileSizeLimitService).maxFileSize;
|
||||
const maxFileSize = std.store.get(FileSizeLimitService).maxFileSize;
|
||||
|
||||
await addSiblingAttachmentBlocks(
|
||||
rootComponent.host,
|
||||
std.host,
|
||||
[file],
|
||||
maxFileSize,
|
||||
model,
|
||||
@@ -416,14 +411,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['YouTube'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-youtube'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
const parentModel = rootComponent.doc.getParent(model);
|
||||
action: async ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
rootComponent.host,
|
||||
host,
|
||||
'YouTube',
|
||||
'The added YouTube video link will be displayed as an embed view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
@@ -438,14 +434,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['Github'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-github'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
const parentModel = rootComponent.doc.getParent(model);
|
||||
action: async ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
rootComponent.host,
|
||||
host,
|
||||
'GitHub',
|
||||
'The added GitHub issue or pull request link will be displayed as a card view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
@@ -462,14 +459,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
tooltip: slashMenuToolTips['Figma'],
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-figma'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
const parentModel = rootComponent.doc.getParent(model);
|
||||
action: async ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
rootComponent.host,
|
||||
host,
|
||||
'Figma',
|
||||
'The added Figma link will be displayed as an embed view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
@@ -483,14 +481,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: LoomIcon,
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:embed-loom'),
|
||||
action: async ({ rootComponent, model }) => {
|
||||
const parentModel = rootComponent.doc.getParent(model);
|
||||
action: async ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const parentModel = host.doc.getParent(model);
|
||||
if (!parentModel) {
|
||||
return;
|
||||
}
|
||||
const index = parentModel.children.indexOf(model) + 1;
|
||||
await toggleEmbedCardCreateModal(
|
||||
rootComponent.host,
|
||||
host,
|
||||
'Loom',
|
||||
'The added Loom video link will be displayed as an embed view.',
|
||||
{ mode: 'page', parentModel, index }
|
||||
@@ -504,8 +503,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Create a equation block.',
|
||||
icon: TeXIcon(),
|
||||
alias: ['mathBlock, equationBlock', 'latexBlock'],
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertLatexBlockCommand, {
|
||||
@@ -519,24 +518,24 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
// TODO(@L-Sun): Linear
|
||||
|
||||
// ---------------------------------------------------------
|
||||
({ model, rootComponent }) => {
|
||||
const { doc } = rootComponent;
|
||||
({ model, std }) => {
|
||||
const { host } = std;
|
||||
|
||||
const surfaceModel = getSurfaceBlock(doc);
|
||||
const surfaceModel = getSurfaceBlock(host.doc);
|
||||
if (!surfaceModel) return [];
|
||||
|
||||
const parent = doc.getParent(model);
|
||||
const parent = host.doc.getParent(model);
|
||||
if (!parent) return [];
|
||||
|
||||
const frameModels = doc
|
||||
const frameModels = host.doc
|
||||
.getBlocksByFlavour('affine:frame')
|
||||
.map(block => block.model as FrameBlockModel);
|
||||
|
||||
const frameItems = frameModels.map<SlashMenuActionItem>(frameModel => ({
|
||||
name: 'Frame: ' + frameModel.title,
|
||||
icon: FrameIcon(),
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertSurfaceRefBlockCommand, {
|
||||
@@ -553,7 +552,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
name: 'Group: ' + group.title.toString(),
|
||||
icon: GroupingIcon(),
|
||||
action: () => {
|
||||
rootComponent.std.command
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertSurfaceRefBlockCommand, {
|
||||
@@ -594,8 +593,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: TodayIcon,
|
||||
tooltip: slashMenuToolTips['Today'],
|
||||
description: formatDate(now),
|
||||
action: ({ rootComponent, model }) => {
|
||||
insertContent(rootComponent.host, model, formatDate(now));
|
||||
action: ({ std, model }) => {
|
||||
insertContent(std.host, model, formatDate(now));
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -603,10 +602,10 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: TomorrowIcon,
|
||||
tooltip: slashMenuToolTips['Tomorrow'],
|
||||
description: formatDate(tomorrow),
|
||||
action: ({ rootComponent, model }) => {
|
||||
action: ({ std, model }) => {
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
insertContent(rootComponent.host, model, formatDate(tomorrow));
|
||||
insertContent(std.host, model, formatDate(tomorrow));
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -614,10 +613,10 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: YesterdayIcon,
|
||||
tooltip: slashMenuToolTips['Yesterday'],
|
||||
description: formatDate(yesterday),
|
||||
action: ({ rootComponent, model }) => {
|
||||
action: ({ std, model }) => {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
insertContent(rootComponent.host, model, formatDate(yesterday));
|
||||
insertContent(std.host, model, formatDate(yesterday));
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -625,8 +624,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
icon: NowIcon,
|
||||
tooltip: slashMenuToolTips['Now'],
|
||||
description: formatTime(now),
|
||||
action: ({ rootComponent, model }) => {
|
||||
insertContent(rootComponent.host, model, formatTime(now));
|
||||
action: ({ std, model }) => {
|
||||
insertContent(std.host, model, formatTime(now));
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -643,8 +642,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:database') &&
|
||||
!insideEdgelessText(model),
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertDatabaseBlockCommand, {
|
||||
@@ -654,8 +653,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
})
|
||||
.pipe(({ insertedDatabaseBlockId }) => {
|
||||
if (insertedDatabaseBlockId) {
|
||||
const telemetry =
|
||||
rootComponent.std.getOptional(TelemetryProvider);
|
||||
const telemetry = std.getOptional(TelemetryProvider);
|
||||
telemetry?.track('BlockCreated', {
|
||||
blockType: 'affine:database',
|
||||
});
|
||||
@@ -674,21 +672,22 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
!insideEdgelessText(model) &&
|
||||
!!model.doc.get(FeatureFlagService).getFlag('enable_block_query'),
|
||||
|
||||
action: ({ model, rootComponent }) => {
|
||||
const parent = rootComponent.doc.getParent(model);
|
||||
action: ({ model, std }) => {
|
||||
const { host } = std;
|
||||
const parent = host.doc.getParent(model);
|
||||
if (!parent) return;
|
||||
const index = parent.children.indexOf(model);
|
||||
const id = rootComponent.doc.addBlock(
|
||||
const id = host.doc.addBlock(
|
||||
'affine:data-view',
|
||||
{},
|
||||
rootComponent.doc.getParent(model),
|
||||
host.doc.getParent(model),
|
||||
index + 1
|
||||
);
|
||||
const dataViewModel = rootComponent.doc.getBlock(id)!;
|
||||
const dataViewModel = host.doc.getBlock(id)!;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
const dataView = rootComponent.std.view.getBlock(
|
||||
const dataView = std.view.getBlock(
|
||||
dataViewModel.id
|
||||
) as DataViewBlockComponent | null;
|
||||
dataView?.dataSource.viewManager.viewAdd('table');
|
||||
@@ -706,8 +705,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
showWhen: ({ model }) =>
|
||||
model.doc.schema.flavourSchemaMap.has('affine:database') &&
|
||||
!insideEdgelessText(model),
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getSelectedModelsCommand)
|
||||
.pipe(insertDatabaseBlockCommand, {
|
||||
@@ -717,8 +716,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
})
|
||||
.pipe(({ insertedDatabaseBlockId }) => {
|
||||
if (insertedDatabaseBlockId) {
|
||||
const telemetry =
|
||||
rootComponent.std.getOptional(TelemetryProvider);
|
||||
const telemetry = std.getOptional(TelemetryProvider);
|
||||
telemetry?.track('BlockCreated', {
|
||||
blockType: 'affine:database',
|
||||
});
|
||||
@@ -735,15 +733,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Shift this line up.',
|
||||
icon: ArrowUpBigIcon,
|
||||
tooltip: slashMenuToolTips['Move Up'],
|
||||
action: ({ rootComponent, model }) => {
|
||||
const doc = rootComponent.doc;
|
||||
const previousSiblingModel = doc.getPrev(model);
|
||||
action: ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const previousSiblingModel = host.doc.getPrev(model);
|
||||
if (!previousSiblingModel) return;
|
||||
|
||||
const parentModel = doc.getParent(previousSiblingModel);
|
||||
const parentModel = host.doc.getParent(previousSiblingModel);
|
||||
if (!parentModel) return;
|
||||
|
||||
doc.moveBlocks([model], parentModel, previousSiblingModel, true);
|
||||
host.doc.moveBlocks([model], parentModel, previousSiblingModel, true);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -751,15 +749,15 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Shift this line down.',
|
||||
icon: ArrowDownBigIcon,
|
||||
tooltip: slashMenuToolTips['Move Down'],
|
||||
action: ({ rootComponent, model }) => {
|
||||
const doc = rootComponent.doc;
|
||||
const nextSiblingModel = doc.getNext(model);
|
||||
action: ({ std, model }) => {
|
||||
const { host } = std;
|
||||
const nextSiblingModel = host.doc.getNext(model);
|
||||
if (!nextSiblingModel) return;
|
||||
|
||||
const parentModel = doc.getParent(nextSiblingModel);
|
||||
const parentModel = host.doc.getParent(nextSiblingModel);
|
||||
if (!parentModel) return;
|
||||
|
||||
doc.moveBlocks([model], parentModel, nextSiblingModel, false);
|
||||
host.doc.moveBlocks([model], parentModel, nextSiblingModel, false);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -767,13 +765,13 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Copy this line to clipboard.',
|
||||
icon: CopyIcon,
|
||||
tooltip: slashMenuToolTips['Copy'],
|
||||
action: ({ rootComponent, model }) => {
|
||||
const slice = Slice.fromModels(rootComponent.std.store, [model]);
|
||||
action: ({ std, model }) => {
|
||||
const slice = Slice.fromModels(std.store, [model]);
|
||||
|
||||
rootComponent.std.clipboard
|
||||
std.clipboard
|
||||
.copy(slice)
|
||||
.then(() => {
|
||||
toast(rootComponent.host, 'Copied to clipboard');
|
||||
toast(std.host, 'Copied to clipboard');
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
@@ -785,12 +783,13 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
description: 'Create a duplicate of this line.',
|
||||
icon: DualLinkIcon(),
|
||||
tooltip: slashMenuToolTips['Copy'],
|
||||
action: ({ rootComponent, model }) => {
|
||||
action: ({ std, model }) => {
|
||||
if (!model.text || !(model.text instanceof Text)) {
|
||||
console.error("Can't duplicate a block without text");
|
||||
return;
|
||||
}
|
||||
const parent = rootComponent.doc.getParent(model);
|
||||
const { host } = std;
|
||||
const parent = host.doc.getParent(model);
|
||||
if (!parent) {
|
||||
console.error(
|
||||
'Failed to duplicate block! Parent not found: ' +
|
||||
@@ -803,7 +802,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
const index = parent.children.indexOf(model);
|
||||
|
||||
// TODO add clone model util
|
||||
rootComponent.doc.addBlock(
|
||||
host.doc.addBlock(
|
||||
model.flavour as never,
|
||||
{
|
||||
type: (model as ParagraphBlockModel).type,
|
||||
@@ -811,7 +810,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
// @ts-expect-error FIXME: ts error
|
||||
checked: model.checked,
|
||||
},
|
||||
rootComponent.doc.getParent(model),
|
||||
host.doc.getParent(model),
|
||||
index
|
||||
);
|
||||
},
|
||||
@@ -822,8 +821,8 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||
alias: ['remove'],
|
||||
icon: DeleteIcon,
|
||||
tooltip: slashMenuToolTips['Delete'],
|
||||
action: ({ rootComponent, model }) => {
|
||||
rootComponent.doc.deleteBlock(model);
|
||||
action: ({ std, model }) => {
|
||||
std.host.doc.deleteBlock(model);
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -0,0 +1,14 @@
|
||||
import { InnerSlashMenu, SlashMenu } from './slash-menu-popover';
|
||||
import { AFFINE_SLASH_MENU_WIDGET, AffineSlashMenuWidget } from './widget';
|
||||
|
||||
export function effects() {
|
||||
customElements.define(AFFINE_SLASH_MENU_WIDGET, AffineSlashMenuWidget);
|
||||
customElements.define('affine-slash-menu', SlashMenu);
|
||||
customElements.define('inner-slash-menu', InnerSlashMenu);
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
[AFFINE_SLASH_MENU_WIDGET]: AffineSlashMenuWidget;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { WidgetViewExtension } from '@blocksuite/block-std';
|
||||
import { type Container } from '@blocksuite/global/di';
|
||||
import { Extension } from '@blocksuite/store';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
import { AFFINE_SLASH_MENU_WIDGET } from './widget';
|
||||
|
||||
export class SlashMenuExtension extends Extension {
|
||||
static override setup(di: Container) {
|
||||
WidgetViewExtension(
|
||||
'affine:page',
|
||||
AFFINE_SLASH_MENU_WIDGET,
|
||||
literal`${unsafeStatic(AFFINE_SLASH_MENU_WIDGET)}`
|
||||
).setup(di);
|
||||
|
||||
di.add(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// TODO(@L-Sun): narrow the scope of the exported symbols
|
||||
export * from './extensions';
|
||||
export * from './widget';
|
||||
+3
-3
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
createKeydownObserver,
|
||||
getCurrentNativeRange,
|
||||
getPopperPosition,
|
||||
isControlledKeyboardEvent,
|
||||
isFuzzyMatch,
|
||||
substringMatchScore,
|
||||
@@ -21,7 +22,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import throttle from 'lodash-es/throttle';
|
||||
|
||||
import { getPopperPosition } from '../../utils/position.js';
|
||||
import type {
|
||||
SlashMenuActionItem,
|
||||
SlashMenuContext,
|
||||
@@ -147,7 +147,7 @@ export class SlashMenu extends WithDisposable(LitElement) {
|
||||
}
|
||||
|
||||
get host() {
|
||||
return this.context.rootComponent.host;
|
||||
return this.context.std.host;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -480,7 +480,7 @@ export class InnerSlashMenu extends WithDisposable(LitElement) {
|
||||
});
|
||||
|
||||
const inlineEditor = getInlineEditorByModel(
|
||||
this.context.rootComponent.host,
|
||||
this.context.std.host,
|
||||
this.context.model
|
||||
);
|
||||
|
||||
+39
-39
@@ -1,44 +1,44 @@
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import { AttachmentTooltip } from './attachment.js';
|
||||
import { BoldTextTooltip } from './bold-text.js';
|
||||
import { BulletedListTooltip } from './bulleted-list.js';
|
||||
import { CodeBlockTooltip } from './code-block.js';
|
||||
import { CopyTooltip } from './copy.js';
|
||||
import { DeleteTooltip } from './delete.js';
|
||||
import { DividerTooltip } from './divider.js';
|
||||
import { EdgelessTooltip } from './edgeless.js';
|
||||
import { FigmaTooltip } from './figma.js';
|
||||
import { GithubRepoTooltip } from './github-repo.js';
|
||||
import { Heading1Tooltip } from './heading-1.js';
|
||||
import { Heading2Tooltip } from './heading-2.js';
|
||||
import { Heading3Tooltip } from './heading-3.js';
|
||||
import { Heading4Tooltip } from './heading-4.js';
|
||||
import { Heading5Tooltip } from './heading-5.js';
|
||||
import { Heading6Tooltip } from './heading-6.js';
|
||||
import { ItalicTooltip } from './italic.js';
|
||||
import { KanbanViewTooltip } from './kanban-view.js';
|
||||
import { LinearTooltip } from './linear.js';
|
||||
import { LinkTooltip } from './link.js';
|
||||
import { LinkDocTooltip } from './link-doc.js';
|
||||
import { MoveDownTooltip } from './move-down.js';
|
||||
import { MoveUpTooltip } from './move-up.js';
|
||||
import { NewDocTooltip } from './new-doc.js';
|
||||
import { NowTooltip } from './now.js';
|
||||
import { NumberedListTooltip } from './numbered-list.js';
|
||||
import { PDFTooltip } from './pdf.js';
|
||||
import { PhotoTooltip } from './photo.js';
|
||||
import { QuoteTooltip } from './quote.js';
|
||||
import { StrikethroughTooltip } from './strikethrough.js';
|
||||
import { TableViewTooltip } from './table-view.js';
|
||||
import { TextTooltip } from './text.js';
|
||||
import { ToDoListTooltip } from './to-do-list.js';
|
||||
import { TodayTooltip } from './today.js';
|
||||
import { TomorrowTooltip } from './tomorrow.js';
|
||||
import { TweetTooltip } from './tweet.js';
|
||||
import { UnderlineTooltip } from './underline.js';
|
||||
import { YesterdayTooltip } from './yesterday.js';
|
||||
import { YoutubeVideoTooltip } from './youtube-video.js';
|
||||
import { AttachmentTooltip } from './attachment';
|
||||
import { BoldTextTooltip } from './bold-text';
|
||||
import { BulletedListTooltip } from './bulleted-list';
|
||||
import { CodeBlockTooltip } from './code-block';
|
||||
import { CopyTooltip } from './copy';
|
||||
import { DeleteTooltip } from './delete';
|
||||
import { DividerTooltip } from './divider';
|
||||
import { EdgelessTooltip } from './edgeless';
|
||||
import { FigmaTooltip } from './figma';
|
||||
import { GithubRepoTooltip } from './github-repo';
|
||||
import { Heading1Tooltip } from './heading-1';
|
||||
import { Heading2Tooltip } from './heading-2';
|
||||
import { Heading3Tooltip } from './heading-3';
|
||||
import { Heading4Tooltip } from './heading-4';
|
||||
import { Heading5Tooltip } from './heading-5';
|
||||
import { Heading6Tooltip } from './heading-6';
|
||||
import { ItalicTooltip } from './italic';
|
||||
import { KanbanViewTooltip } from './kanban-view';
|
||||
import { LinearTooltip } from './linear';
|
||||
import { LinkTooltip } from './link';
|
||||
import { LinkDocTooltip } from './link-doc';
|
||||
import { MoveDownTooltip } from './move-down';
|
||||
import { MoveUpTooltip } from './move-up';
|
||||
import { NewDocTooltip } from './new-doc';
|
||||
import { NowTooltip } from './now';
|
||||
import { NumberedListTooltip } from './numbered-list';
|
||||
import { PDFTooltip } from './pdf';
|
||||
import { PhotoTooltip } from './photo';
|
||||
import { QuoteTooltip } from './quote';
|
||||
import { StrikethroughTooltip } from './strikethrough';
|
||||
import { TableViewTooltip } from './table-view';
|
||||
import { TextTooltip } from './text';
|
||||
import { ToDoListTooltip } from './to-do-list';
|
||||
import { TodayTooltip } from './today';
|
||||
import { TomorrowTooltip } from './tomorrow';
|
||||
import { TweetTooltip } from './tweet';
|
||||
import { UnderlineTooltip } from './underline';
|
||||
import { YesterdayTooltip } from './yesterday';
|
||||
import { YoutubeVideoTooltip } from './youtube-video';
|
||||
|
||||
export type SlashMenuTooltip = {
|
||||
figure: TemplateResult;
|
||||
+23
-4
@@ -103,8 +103,8 @@ export function createConversionItem(
|
||||
icon,
|
||||
tooltip: slashMenuToolTips[name],
|
||||
showWhen: ({ model }) => model.doc.schema.flavourSchemaMap.has(flavour),
|
||||
action: ({ rootComponent }) => {
|
||||
rootComponent.std.command.exec(updateBlockType, {
|
||||
action: ({ std }) => {
|
||||
std.command.exec(updateBlockType, {
|
||||
flavour,
|
||||
props: { type },
|
||||
});
|
||||
@@ -120,8 +120,8 @@ export function createTextFormatItem(
|
||||
name,
|
||||
icon,
|
||||
tooltip: slashMenuToolTips[name],
|
||||
action: ({ rootComponent, model }) => {
|
||||
const { std, host } = rootComponent;
|
||||
action: ({ std, model }) => {
|
||||
const { host } = std;
|
||||
|
||||
if (model.text?.length !== 0) {
|
||||
std.command.exec(formatBlockCommand, {
|
||||
@@ -139,3 +139,22 @@ export function createTextFormatItem(
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function formatDate(date: Date) {
|
||||
// yyyy-mm-dd
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const strTime = `${year}-${month}-${day}`;
|
||||
return strTime;
|
||||
}
|
||||
|
||||
export function formatTime(date: Date) {
|
||||
// mm-dd hh:mm
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
const strTime = `${month}-${day} ${hours}:${minutes}`;
|
||||
return strTime;
|
||||
}
|
||||
+7
-17
@@ -5,11 +5,9 @@ import {
|
||||
import type { UIEventStateContext } from '@blocksuite/block-std';
|
||||
import { TextSelection, WidgetComponent } from '@blocksuite/block-std';
|
||||
import { DisposableGroup } from '@blocksuite/global/slot';
|
||||
import { assertType } from '@blocksuite/global/utils';
|
||||
import { InlineEditor } from '@blocksuite/inline';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
import type { RootBlockComponent } from '../../types.js';
|
||||
import {
|
||||
defaultSlashMenuConfig,
|
||||
type SlashMenuActionItem,
|
||||
@@ -19,9 +17,9 @@ import {
|
||||
type SlashMenuItemGenerator,
|
||||
type SlashMenuStaticConfig,
|
||||
type SlashSubMenu,
|
||||
} from './config.js';
|
||||
import { SlashMenu } from './slash-menu-popover.js';
|
||||
import { filterEnabledSlashMenuItems } from './utils.js';
|
||||
} from './config';
|
||||
import { SlashMenu } from './slash-menu-popover';
|
||||
import { filterEnabledSlashMenuItems } from './utils';
|
||||
|
||||
export type AffineSlashMenuContext = SlashMenuContext;
|
||||
export type AffineSlashMenuItem = SlashMenuItem;
|
||||
@@ -57,7 +55,7 @@ const showSlashMenu = debounce(
|
||||
);
|
||||
|
||||
const inlineEditor = getInlineEditorByModel(
|
||||
context.rootComponent.host,
|
||||
context.std.host,
|
||||
context.model
|
||||
);
|
||||
if (!inlineEditor) return;
|
||||
@@ -115,12 +113,10 @@ export class AffineSlashMenuWidget extends WidgetComponent {
|
||||
else inlineEditor.slots.inlineRangeSync.once(callback);
|
||||
};
|
||||
|
||||
const rootComponent = this.block;
|
||||
if (rootComponent.model.flavour !== 'affine:page') {
|
||||
if (this.block.model.flavour !== 'affine:page') {
|
||||
console.error('SlashMenuWidget should be used in RootBlock');
|
||||
return;
|
||||
}
|
||||
assertType<RootBlockComponent>(rootComponent);
|
||||
|
||||
inlineRangeApplyCallback(() => {
|
||||
const textSelection = this.host.selection.find(TextSelection);
|
||||
@@ -155,7 +151,7 @@ export class AffineSlashMenuWidget extends WidgetComponent {
|
||||
...this.config,
|
||||
items: filterEnabledSlashMenuItems(this.config.items, {
|
||||
model,
|
||||
rootComponent,
|
||||
std: this.std,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -163,7 +159,7 @@ export class AffineSlashMenuWidget extends WidgetComponent {
|
||||
showSlashMenu({
|
||||
context: {
|
||||
model,
|
||||
rootComponent,
|
||||
std: this.std,
|
||||
},
|
||||
triggerKey: matchedKey,
|
||||
config,
|
||||
@@ -224,9 +220,3 @@ export class AffineSlashMenuWidget extends WidgetComponent {
|
||||
this.handleEvent('compositionEnd', this._onCompositionEnd);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
[AFFINE_SLASH_MENU_WIDGET]: AffineSlashMenuWidget;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
|
||||
},
|
||||
"include": ["./src"],
|
||||
"references": [
|
||||
{ "path": "../block-attachment" },
|
||||
{ "path": "../block-database" },
|
||||
{ "path": "../block-embed" },
|
||||
{ "path": "../block-image" },
|
||||
{ "path": "../block-latex" },
|
||||
{ "path": "../block-note" },
|
||||
{ "path": "../block-surface" },
|
||||
{ "path": "../block-surface-ref" },
|
||||
{ "path": "../block-table" },
|
||||
{ "path": "../components" },
|
||||
{ "path": "../shared" },
|
||||
{ "path": "../../framework/block-std" },
|
||||
{ "path": "../data-view" },
|
||||
{ "path": "../../framework/global" },
|
||||
{ "path": "../../framework/inline" },
|
||||
{ "path": "../../framework/store" }
|
||||
]
|
||||
}
|
||||
@@ -43,6 +43,7 @@
|
||||
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
||||
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
||||
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||
"@blocksuite/affine-widget-toolbar": "workspace:*",
|
||||
"@blocksuite/block-std": "workspace:*",
|
||||
"@blocksuite/data-view": "workspace:*",
|
||||
|
||||
@@ -46,6 +46,7 @@ import { effects as widgetEdgelessAutoConnectEffects } from '@blocksuite/affine-
|
||||
import { effects as widgetFrameTitleEffects } from '@blocksuite/affine-widget-frame-title/effects';
|
||||
import { effects as widgetRemoteSelectionEffects } from '@blocksuite/affine-widget-remote-selection/effects';
|
||||
import { effects as widgetScrollAnchoringEffects } from '@blocksuite/affine-widget-scroll-anchoring/effects';
|
||||
import { effects as widgetSlashMenuEffects } from '@blocksuite/affine-widget-slash-menu/effects';
|
||||
import { effects as widgetToolbarEffects } from '@blocksuite/affine-widget-toolbar/effects';
|
||||
import { effects as stdEffects } from '@blocksuite/block-std/effects';
|
||||
import { effects as dataViewEffects } from '@blocksuite/data-view/effects';
|
||||
@@ -103,6 +104,7 @@ export function effects() {
|
||||
widgetRemoteSelectionEffects();
|
||||
widgetDragHandleEffects();
|
||||
widgetEdgelessAutoConnectEffects();
|
||||
widgetSlashMenuEffects();
|
||||
widgetToolbarEffects();
|
||||
|
||||
fragmentFramePanelEffects();
|
||||
|
||||
@@ -114,6 +114,9 @@ export {
|
||||
export type { DragBlockPayload } from '@blocksuite/affine-widget-drag-handle';
|
||||
export { toolbarWidget } from '@blocksuite/affine-widget-toolbar';
|
||||
|
||||
// TODO(@L-Sun): Narrow the export scope
|
||||
export * from '@blocksuite/affine-widget-slash-menu';
|
||||
|
||||
const env: Record<string, unknown> =
|
||||
typeof globalThis !== 'undefined'
|
||||
? globalThis
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
{ "path": "../affine/widget-frame-title" },
|
||||
{ "path": "../affine/widget-remote-selection" },
|
||||
{ "path": "../affine/widget-scroll-anchoring" },
|
||||
{ "path": "../affine/widget-slash-menu" },
|
||||
{ "path": "../affine/widget-toolbar" },
|
||||
{ "path": "../framework/block-std" },
|
||||
{ "path": "../affine/data-view" },
|
||||
|
||||
@@ -29,26 +29,28 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
|
||||
|
||||
const showWhenWrapper =
|
||||
(item?: AIItemConfig) =>
|
||||
({ rootComponent }: AffineSlashMenuContext) => {
|
||||
const affineAIPanelWidget = rootComponent.host.view.getWidget(
|
||||
({ std }: AffineSlashMenuContext) => {
|
||||
const root = std.host.doc.root;
|
||||
if (!root) return false;
|
||||
const affineAIPanelWidget = std.view.getWidget(
|
||||
AFFINE_AI_PANEL_WIDGET,
|
||||
rootComponent.model.id
|
||||
root.id
|
||||
);
|
||||
if (affineAIPanelWidget === null) return false;
|
||||
|
||||
const chain = rootComponent.host.command.chain();
|
||||
const docModeService = rootComponent.std.get(DocModeProvider);
|
||||
const editorMode = docModeService.getPrimaryMode(rootComponent.doc.id);
|
||||
const chain = std.host.command.chain();
|
||||
const docModeService = std.get(DocModeProvider);
|
||||
const editorMode = docModeService.getPrimaryMode(std.host.doc.id);
|
||||
|
||||
return item?.showWhen?.(chain, editorMode, rootComponent.host) ?? true;
|
||||
return item?.showWhen?.(chain, editorMode, std.host) ?? true;
|
||||
};
|
||||
|
||||
const actionItemWrapper = (
|
||||
item: AIItemConfig
|
||||
): AffineSlashMenuActionItem => ({
|
||||
...basicItemConfig(item),
|
||||
action: ({ rootComponent }: AffineSlashMenuContext) => {
|
||||
item?.handler?.(rootComponent.host);
|
||||
action: ({ std }: AffineSlashMenuContext) => {
|
||||
item?.handler?.(std.host);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -58,7 +60,7 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
|
||||
subMenu: (item.subItem ?? []).map<AffineSlashMenuActionItem>(
|
||||
({ type, handler }) => ({
|
||||
name: type,
|
||||
action: ({ rootComponent }) => handler?.(rootComponent.host),
|
||||
action: ({ std }) => handler?.(std.host),
|
||||
})
|
||||
),
|
||||
};
|
||||
@@ -78,11 +80,12 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
|
||||
name: 'Ask AI',
|
||||
icon: AIStarIcon,
|
||||
showWhen: showWhenWrapper(),
|
||||
action: ({ rootComponent }) => {
|
||||
const view = rootComponent.host.view;
|
||||
const affineAIPanelWidget = view.getWidget(
|
||||
action: ({ std }) => {
|
||||
const root = std.host.doc.root;
|
||||
if (!root) return;
|
||||
const affineAIPanelWidget = std.view.getWidget(
|
||||
AFFINE_AI_PANEL_WIDGET,
|
||||
rootComponent.model.id
|
||||
root.id
|
||||
) as AffineAIPanelWidget;
|
||||
handleInlineAskAIAction(affineAIPanelWidget.host);
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
imageToolbarWidget,
|
||||
ParagraphBlockService,
|
||||
ReferenceNodeConfigIdentifier,
|
||||
slashMenuWidget,
|
||||
SlashMenuExtension,
|
||||
surfaceRefToolbarWidget,
|
||||
toolbarWidget,
|
||||
VirtualKeyboardProvider as BSVirtualKeyboardProvider,
|
||||
@@ -166,10 +166,10 @@ export function enableMobileExtension(
|
||||
specBuilder: SpecBuilder,
|
||||
framework: FrameworkProvider
|
||||
): void {
|
||||
specBuilder.omit(slashMenuWidget);
|
||||
specBuilder.omit(codeToolbarWidget);
|
||||
specBuilder.omit(imageToolbarWidget);
|
||||
specBuilder.omit(surfaceRefToolbarWidget);
|
||||
specBuilder.omit(toolbarWidget);
|
||||
specBuilder.omit(SlashMenuExtension);
|
||||
specBuilder.extend([MobileSpecsPatches, KeyboardToolbarExtension(framework)]);
|
||||
}
|
||||
|
||||
@@ -137,11 +137,10 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
|
||||
'action' in item &&
|
||||
(item.name === 'Linked Doc' || item.name === 'Link')
|
||||
) {
|
||||
item.action = async ({ rootComponent }) => {
|
||||
const [success, { insertedLinkType }] =
|
||||
rootComponent.std.command.exec(
|
||||
insertLinkByQuickSearchCommand
|
||||
);
|
||||
item.action = async ({ std }) => {
|
||||
const [success, { insertedLinkType }] = std.command.exec(
|
||||
insertLinkByQuickSearchCommand
|
||||
);
|
||||
|
||||
if (!success) return;
|
||||
|
||||
|
||||
@@ -250,6 +250,7 @@ export const PackageList = [
|
||||
'blocksuite/affine/widget-frame-title',
|
||||
'blocksuite/affine/widget-remote-selection',
|
||||
'blocksuite/affine/widget-scroll-anchoring',
|
||||
'blocksuite/affine/widget-slash-menu',
|
||||
'blocksuite/affine/widget-toolbar',
|
||||
'blocksuite/framework/block-std',
|
||||
'blocksuite/affine/data-view',
|
||||
@@ -435,6 +436,28 @@ export const PackageList = [
|
||||
'blocksuite/framework/global',
|
||||
],
|
||||
},
|
||||
{
|
||||
location: 'blocksuite/affine/widget-slash-menu',
|
||||
name: '@blocksuite/affine-widget-slash-menu',
|
||||
workspaceDependencies: [
|
||||
'blocksuite/affine/block-attachment',
|
||||
'blocksuite/affine/block-database',
|
||||
'blocksuite/affine/block-embed',
|
||||
'blocksuite/affine/block-image',
|
||||
'blocksuite/affine/block-latex',
|
||||
'blocksuite/affine/block-note',
|
||||
'blocksuite/affine/block-surface',
|
||||
'blocksuite/affine/block-surface-ref',
|
||||
'blocksuite/affine/block-table',
|
||||
'blocksuite/affine/components',
|
||||
'blocksuite/affine/shared',
|
||||
'blocksuite/framework/block-std',
|
||||
'blocksuite/affine/data-view',
|
||||
'blocksuite/framework/global',
|
||||
'blocksuite/framework/inline',
|
||||
'blocksuite/framework/store',
|
||||
],
|
||||
},
|
||||
{
|
||||
location: 'blocksuite/affine/widget-toolbar',
|
||||
name: '@blocksuite/affine-widget-toolbar',
|
||||
@@ -481,6 +504,7 @@ export const PackageList = [
|
||||
'blocksuite/affine/widget-frame-title',
|
||||
'blocksuite/affine/widget-remote-selection',
|
||||
'blocksuite/affine/widget-scroll-anchoring',
|
||||
'blocksuite/affine/widget-slash-menu',
|
||||
'blocksuite/affine/widget-toolbar',
|
||||
'blocksuite/framework/block-std',
|
||||
'blocksuite/affine/data-view',
|
||||
@@ -887,6 +911,7 @@ export type PackageName =
|
||||
| '@blocksuite/affine-widget-frame-title'
|
||||
| '@blocksuite/affine-widget-remote-selection'
|
||||
| '@blocksuite/affine-widget-scroll-anchoring'
|
||||
| '@blocksuite/affine-widget-slash-menu'
|
||||
| '@blocksuite/affine-widget-toolbar'
|
||||
| '@blocksuite/blocks'
|
||||
| '@blocksuite/block-std'
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
{ "path": "./blocksuite/affine/widget-frame-title" },
|
||||
{ "path": "./blocksuite/affine/widget-remote-selection" },
|
||||
{ "path": "./blocksuite/affine/widget-scroll-anchoring" },
|
||||
{ "path": "./blocksuite/affine/widget-slash-menu" },
|
||||
{ "path": "./blocksuite/affine/widget-toolbar" },
|
||||
{ "path": "./blocksuite/blocks" },
|
||||
{ "path": "./blocksuite/framework/block-std" },
|
||||
|
||||
@@ -2608,6 +2608,7 @@ __metadata:
|
||||
"@blocksuite/affine-widget-frame-title": "workspace:*"
|
||||
"@blocksuite/affine-widget-remote-selection": "workspace:*"
|
||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*"
|
||||
"@blocksuite/affine-widget-slash-menu": "workspace:*"
|
||||
"@blocksuite/affine-widget-toolbar": "workspace:*"
|
||||
"@blocksuite/block-std": "workspace:*"
|
||||
"@blocksuite/data-view": "workspace:*"
|
||||
@@ -2948,6 +2949,36 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@blocksuite/affine-widget-slash-menu@workspace:*, @blocksuite/affine-widget-slash-menu@workspace:blocksuite/affine/widget-slash-menu":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@blocksuite/affine-widget-slash-menu@workspace:blocksuite/affine/widget-slash-menu"
|
||||
dependencies:
|
||||
"@blocksuite/affine-block-attachment": "workspace:*"
|
||||
"@blocksuite/affine-block-database": "workspace:*"
|
||||
"@blocksuite/affine-block-embed": "workspace:*"
|
||||
"@blocksuite/affine-block-image": "workspace:*"
|
||||
"@blocksuite/affine-block-latex": "workspace:*"
|
||||
"@blocksuite/affine-block-note": "workspace:*"
|
||||
"@blocksuite/affine-block-surface": "workspace:*"
|
||||
"@blocksuite/affine-block-surface-ref": "workspace:*"
|
||||
"@blocksuite/affine-block-table": "workspace:*"
|
||||
"@blocksuite/affine-components": "workspace:*"
|
||||
"@blocksuite/affine-shared": "workspace:*"
|
||||
"@blocksuite/block-std": "workspace:*"
|
||||
"@blocksuite/data-view": "workspace:*"
|
||||
"@blocksuite/global": "workspace:*"
|
||||
"@blocksuite/icons": "npm:^2.2.4"
|
||||
"@blocksuite/inline": "workspace:*"
|
||||
"@blocksuite/store": "workspace:*"
|
||||
"@floating-ui/dom": "npm:^1.6.13"
|
||||
"@preact/signals-core": "npm:^1.8.0"
|
||||
"@toeverything/theme": "npm:^1.1.12"
|
||||
"@types/lodash-es": "npm:^4.17.12"
|
||||
lit: "npm:^3.2.0"
|
||||
lodash-es: "npm:^4.17.21"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@blocksuite/affine-widget-toolbar@workspace:*, @blocksuite/affine-widget-toolbar@workspace:blocksuite/affine/widget-toolbar":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@blocksuite/affine-widget-toolbar@workspace:blocksuite/affine/widget-toolbar"
|
||||
@@ -3049,6 +3080,7 @@ __metadata:
|
||||
"@blocksuite/affine-widget-frame-title": "workspace:*"
|
||||
"@blocksuite/affine-widget-remote-selection": "workspace:*"
|
||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*"
|
||||
"@blocksuite/affine-widget-slash-menu": "workspace:*"
|
||||
"@blocksuite/affine-widget-toolbar": "workspace:*"
|
||||
"@blocksuite/block-std": "workspace:*"
|
||||
"@blocksuite/data-view": "workspace:*"
|
||||
@@ -3097,7 +3129,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@blocksuite/icons@npm:2.2.4, @blocksuite/icons@npm:^2.2.1, @blocksuite/icons@npm:^2.2.2, @blocksuite/icons@npm:^2.2.3":
|
||||
"@blocksuite/icons@npm:2.2.4, @blocksuite/icons@npm:^2.2.1, @blocksuite/icons@npm:^2.2.2, @blocksuite/icons@npm:^2.2.3, @blocksuite/icons@npm:^2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "@blocksuite/icons@npm:2.2.4"
|
||||
peerDependencies:
|
||||
|
||||
Reference in New Issue
Block a user