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:
73 files changed
+395
-228
No files matched your search
@@ -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
|
||||
);
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+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;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+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,9 +137,8 @@ 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(
|
||||
item.action = async ({ std }) => {
|
||||
const [success, { insertedLinkType }] = std.command.exec(
|
||||
insertLinkByQuickSearchCommand
|
||||
);
|
||||
|
||||
|
||||
@@ -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