mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 23:07:02 +08:00
refactor(editor): remove components in blocks/_common (#9401)
This commit is contained in:
@@ -1,101 +0,0 @@
|
||||
import { type BlockComponent, ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { WithDisposable } from '@blocksuite/global/utils';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
import { html } from 'lit';
|
||||
import { property, query } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import { embedCardModalStyles } from './styles.js';
|
||||
|
||||
export class EmbedCardEditCaptionEditModal extends WithDisposable(
|
||||
ShadowlessElement
|
||||
) {
|
||||
static override styles = embedCardModalStyles;
|
||||
|
||||
private get _doc() {
|
||||
return this.block.doc;
|
||||
}
|
||||
|
||||
private get _model() {
|
||||
return this.block.model as BlockModel<{ caption: string }>;
|
||||
}
|
||||
|
||||
private _onKeydown(e: KeyboardEvent) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter' && !e.isComposing) {
|
||||
this._onSave();
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private _onSave() {
|
||||
const caption = this.captionInput.value;
|
||||
this._doc.updateBlock(this._model, {
|
||||
caption,
|
||||
});
|
||||
this.remove();
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this.updateComplete
|
||||
.then(() => {
|
||||
this.captionInput.focus();
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
this.disposables.addFromEvent(this, 'keydown', this._onKeydown);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="embed-card-modal">
|
||||
<div class="embed-card-modal-mask" @click=${() => this.remove()}></div>
|
||||
<div class="embed-card-modal-wrapper">
|
||||
<div class="embed-card-modal-row">
|
||||
<label for="card-title">Caption</label>
|
||||
<textarea
|
||||
class="embed-card-modal-input caption"
|
||||
placeholder="Write a caption..."
|
||||
.value=${this._model.caption ?? ''}
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="embed-card-modal-row">
|
||||
<button
|
||||
class=${classMap({
|
||||
'embed-card-modal-button': true,
|
||||
save: true,
|
||||
})}
|
||||
@click=${() => this._onSave()}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor block!: BlockComponent;
|
||||
|
||||
@query('.embed-card-modal-input.caption')
|
||||
accessor captionInput!: HTMLTextAreaElement;
|
||||
}
|
||||
|
||||
export function toggleEmbedCardCaptionEditModal(block: BlockComponent) {
|
||||
const host = block.host;
|
||||
host.selection.clear();
|
||||
const embedCardEditCaptionEditModal = new EmbedCardEditCaptionEditModal();
|
||||
embedCardEditCaptionEditModal.block = block;
|
||||
document.body.append(embedCardEditCaptionEditModal);
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'embed-card-caption-edit-modal': EmbedCardEditCaptionEditModal;
|
||||
}
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { toast } from '@blocksuite/affine-components/toast';
|
||||
import type { EmbedCardStyle } from '@blocksuite/affine-model';
|
||||
import {
|
||||
EMBED_CARD_HEIGHT,
|
||||
EMBED_CARD_WIDTH,
|
||||
} from '@blocksuite/affine-shared/consts';
|
||||
import { EmbedOptionProvider } from '@blocksuite/affine-shared/services';
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
import { Bound, Vec, WithDisposable } from '@blocksuite/global/utils';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
import { html } from 'lit';
|
||||
import { property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import type { EdgelessRootBlockComponent } from '../../../../root-block/edgeless/edgeless-root-block.js';
|
||||
import { getRootByEditorHost, isValidUrl } from '../../../utils/index.js';
|
||||
import { embedCardModalStyles } from './styles.js';
|
||||
|
||||
export class EmbedCardCreateModal extends WithDisposable(ShadowlessElement) {
|
||||
static override styles = embedCardModalStyles;
|
||||
|
||||
private readonly _onCancel = () => {
|
||||
this.remove();
|
||||
};
|
||||
|
||||
private readonly _onConfirm = () => {
|
||||
const url = this.input.value;
|
||||
|
||||
if (!isValidUrl(url)) {
|
||||
toast(this.host, 'Invalid link');
|
||||
return;
|
||||
}
|
||||
|
||||
const embedOptions = this.host.std
|
||||
.get(EmbedOptionProvider)
|
||||
.getEmbedBlockOptions(url);
|
||||
|
||||
const { mode } = this.createOptions;
|
||||
if (mode === 'page') {
|
||||
const { parentModel, index } = this.createOptions;
|
||||
let flavour = 'affine:bookmark';
|
||||
|
||||
if (embedOptions) {
|
||||
flavour = embedOptions.flavour;
|
||||
}
|
||||
|
||||
this.host.doc.addBlock(
|
||||
flavour as never,
|
||||
{
|
||||
url,
|
||||
},
|
||||
parentModel,
|
||||
index
|
||||
);
|
||||
} else if (mode === 'edgeless') {
|
||||
let flavour = 'affine:bookmark',
|
||||
targetStyle: EmbedCardStyle = 'vertical';
|
||||
|
||||
if (embedOptions) {
|
||||
flavour = embedOptions.flavour;
|
||||
targetStyle = embedOptions.styles[0];
|
||||
}
|
||||
|
||||
const edgelessRoot = getRootByEditorHost(
|
||||
this.host
|
||||
) as EdgelessRootBlockComponent | null;
|
||||
if (!edgelessRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gfx = this.host.std.get(GfxControllerIdentifier);
|
||||
const crud = this.host.std.get(EdgelessCRUDIdentifier);
|
||||
|
||||
const viewport = gfx.viewport;
|
||||
const surfaceModel = gfx.surface;
|
||||
if (!surfaceModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const center = Vec.toVec(viewport.center);
|
||||
crud.addBlock(
|
||||
flavour,
|
||||
{
|
||||
url,
|
||||
xywh: Bound.fromCenter(
|
||||
center,
|
||||
EMBED_CARD_WIDTH[targetStyle],
|
||||
EMBED_CARD_HEIGHT[targetStyle]
|
||||
).serialize(),
|
||||
style: targetStyle,
|
||||
},
|
||||
surfaceModel
|
||||
);
|
||||
|
||||
gfx.tool.setTool('default');
|
||||
}
|
||||
this.onConfirm();
|
||||
this.remove();
|
||||
};
|
||||
|
||||
private readonly _onDocumentKeydown = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter' && !e.isComposing) {
|
||||
this._onConfirm();
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
this.remove();
|
||||
}
|
||||
};
|
||||
|
||||
private _handleInput(e: InputEvent) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
this._linkInputValue = target.value;
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this.updateComplete
|
||||
.then(() => {
|
||||
requestAnimationFrame(() => {
|
||||
this.input.focus();
|
||||
});
|
||||
})
|
||||
.catch(console.error);
|
||||
this.disposables.addFromEvent(this, 'keydown', this._onDocumentKeydown);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`<div class="embed-card-modal">
|
||||
<div class="embed-card-modal-mask" @click=${this._onCancel}></div>
|
||||
<div class="embed-card-modal-wrapper">
|
||||
<div class="embed-card-modal-row">
|
||||
<div class="embed-card-modal-title">${this.titleText}</div>
|
||||
</div>
|
||||
|
||||
<div class="embed-card-modal-row">
|
||||
<div class="embed-card-modal-description">
|
||||
${this.descriptionText}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="embed-card-modal-row">
|
||||
<input
|
||||
class="embed-card-modal-input link"
|
||||
id="card-description"
|
||||
type="text"
|
||||
placeholder="Input in https://..."
|
||||
value=${this._linkInputValue}
|
||||
@input=${this._handleInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="embed-card-modal-row">
|
||||
<button
|
||||
class=${classMap({
|
||||
'embed-card-modal-button': true,
|
||||
save: true,
|
||||
})}
|
||||
?disabled=${!isValidUrl(this._linkInputValue)}
|
||||
@click=${this._onConfirm}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@state()
|
||||
private accessor _linkInputValue = '';
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor createOptions!:
|
||||
| {
|
||||
mode: 'page';
|
||||
parentModel: BlockModel | string;
|
||||
index?: number;
|
||||
}
|
||||
| {
|
||||
mode: 'edgeless';
|
||||
};
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor descriptionText!: string;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor host!: EditorHost;
|
||||
|
||||
@query('input')
|
||||
accessor input!: HTMLInputElement;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onConfirm!: () => void;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor titleText!: string;
|
||||
}
|
||||
|
||||
export async function toggleEmbedCardCreateModal(
|
||||
host: EditorHost,
|
||||
titleText: string,
|
||||
descriptionText: string,
|
||||
createOptions:
|
||||
| {
|
||||
mode: 'page';
|
||||
parentModel: BlockModel | string;
|
||||
index?: number;
|
||||
}
|
||||
| {
|
||||
mode: 'edgeless';
|
||||
}
|
||||
): Promise<void> {
|
||||
host.selection.clear();
|
||||
|
||||
const embedCardCreateModal = new EmbedCardCreateModal();
|
||||
embedCardCreateModal.host = host;
|
||||
embedCardCreateModal.titleText = titleText;
|
||||
embedCardCreateModal.descriptionText = descriptionText;
|
||||
embedCardCreateModal.createOptions = createOptions;
|
||||
|
||||
document.body.append(embedCardCreateModal);
|
||||
|
||||
return new Promise(resolve => {
|
||||
embedCardCreateModal.onConfirm = () => resolve();
|
||||
});
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'embed-card-create-modal': EmbedCardCreateModal;
|
||||
}
|
||||
}
|
||||
@@ -1,450 +0,0 @@
|
||||
import {
|
||||
EmbedLinkedDocBlockComponent,
|
||||
EmbedSyncedDocBlockComponent,
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import {
|
||||
notifyLinkedDocClearedAliases,
|
||||
notifyLinkedDocSwitchedToCard,
|
||||
} from '@blocksuite/affine-components/notification';
|
||||
import { toast } from '@blocksuite/affine-components/toast';
|
||||
import type { AliasInfo } from '@blocksuite/affine-model';
|
||||
import {
|
||||
EmbedLinkedDocModel,
|
||||
EmbedSyncedDocModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
type LinkEventType,
|
||||
type TelemetryEvent,
|
||||
TelemetryProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { FONT_SM, FONT_XS } from '@blocksuite/affine-shared/styles';
|
||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||
import {
|
||||
listenClickAway,
|
||||
stopPropagation,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import type {
|
||||
BlockComponent,
|
||||
BlockStdScope,
|
||||
EditorHost,
|
||||
} from '@blocksuite/block-std';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
||||
import { autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
|
||||
import { computed, signal } from '@preact/signals-core';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { property, query } from 'lit/decorators.js';
|
||||
import { choose } from 'lit/directives/choose.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
|
||||
import type { LinkableEmbedModel } from '../type.js';
|
||||
import { isInternalEmbedModel } from '../type.js';
|
||||
|
||||
export class EmbedCardEditModal extends SignalWatcher(
|
||||
WithDisposable(LitElement)
|
||||
) {
|
||||
static override styles = css`
|
||||
:host {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: var(--affine-z-index-popover);
|
||||
animation: affine-popover-fade-in 0.2s ease;
|
||||
}
|
||||
|
||||
@keyframes affine-popover-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.embed-card-modal-wrapper {
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
width: 421px;
|
||||
|
||||
color: var(--affine-icon-color);
|
||||
box-shadow: var(--affine-overlay-shadow);
|
||||
background: ${unsafeCSSVarV2('layer/background/overlayPanel')};
|
||||
border-radius: 4px;
|
||||
border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/border')};
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.row .input {
|
||||
display: flex;
|
||||
padding: 4px 10px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
user-select: none;
|
||||
background: transparent;
|
||||
border: 1px solid ${unsafeCSSVarV2('input/border/default')};
|
||||
color: var(--affine-text-primary-color);
|
||||
${FONT_SM};
|
||||
}
|
||||
.input::placeholder {
|
||||
color: var(--affine-placeholder-color);
|
||||
}
|
||||
.input:focus {
|
||||
border-color: ${unsafeCSSVarV2('input/border/active')};
|
||||
outline: none;
|
||||
}
|
||||
|
||||
textarea.input {
|
||||
min-height: 80px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.row.actions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.row.actions .button {
|
||||
display: flex;
|
||||
padding: 4px 12px;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid ${unsafeCSSVarV2('button/innerBlackBorder')};
|
||||
background: ${unsafeCSSVarV2('button/secondary')};
|
||||
${FONT_XS};
|
||||
color: ${unsafeCSSVarV2('text/primary')};
|
||||
}
|
||||
.row.actions .button[disabled],
|
||||
.row.actions .button:disabled {
|
||||
pointer-events: none;
|
||||
color: ${unsafeCSSVarV2('text/disable')};
|
||||
}
|
||||
.row.actions .button.save {
|
||||
color: ${unsafeCSSVarV2('button/pureWhiteText')};
|
||||
background: ${unsafeCSSVarV2('button/primary')};
|
||||
}
|
||||
.row.actions .button[disabled].save,
|
||||
.row.actions .button:disabled.save {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`;
|
||||
|
||||
private _blockComponent: BlockComponent | null = null;
|
||||
|
||||
private readonly _hide = () => {
|
||||
this.remove();
|
||||
};
|
||||
|
||||
private readonly _onKeydown = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter' && !(e.isComposing || e.shiftKey)) {
|
||||
this._onSave();
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
this.remove();
|
||||
}
|
||||
};
|
||||
|
||||
private readonly _onReset = () => {
|
||||
const blockComponent = this._blockComponent;
|
||||
|
||||
if (!blockComponent) {
|
||||
this.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
const std = blockComponent.std;
|
||||
|
||||
this.model.doc.updateBlock(this.model, { title: null, description: null });
|
||||
|
||||
if (
|
||||
this.isEmbedLinkedDocModel &&
|
||||
blockComponent instanceof EmbedLinkedDocBlockComponent
|
||||
) {
|
||||
blockComponent.refreshData();
|
||||
|
||||
notifyLinkedDocClearedAliases(std);
|
||||
}
|
||||
blockComponent.requestUpdate();
|
||||
|
||||
track(std, this.model, this.viewType, 'ResetedAlias', { control: 'reset' });
|
||||
|
||||
this.remove();
|
||||
};
|
||||
|
||||
private readonly _onSave = () => {
|
||||
const blockComponent = this._blockComponent;
|
||||
|
||||
if (!blockComponent) {
|
||||
this.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
const title = this.title$.value.trim();
|
||||
if (title.length === 0) {
|
||||
toast(this.host, 'Title can not be empty');
|
||||
return;
|
||||
}
|
||||
|
||||
const std = blockComponent.std;
|
||||
|
||||
const description = this.description$.value.trim();
|
||||
|
||||
const props: AliasInfo = { title };
|
||||
if (description) props.description = description;
|
||||
|
||||
if (
|
||||
this.isEmbedSyncedDocModel &&
|
||||
blockComponent instanceof EmbedSyncedDocBlockComponent
|
||||
) {
|
||||
blockComponent.convertToCard(props);
|
||||
|
||||
notifyLinkedDocSwitchedToCard(std);
|
||||
} else {
|
||||
this.model.doc.updateBlock(this.model, props);
|
||||
blockComponent.requestUpdate();
|
||||
}
|
||||
|
||||
track(std, this.model, this.viewType, 'SavedAlias', { control: 'save' });
|
||||
|
||||
this.remove();
|
||||
};
|
||||
|
||||
private readonly _updateDescription = (e: InputEvent) => {
|
||||
const target = e.target as HTMLTextAreaElement;
|
||||
this.description$.value = target.value;
|
||||
};
|
||||
|
||||
private readonly _updateTitle = (e: InputEvent) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
this.title$.value = target.value;
|
||||
};
|
||||
|
||||
get isEmbedLinkedDocModel() {
|
||||
return this.model instanceof EmbedLinkedDocModel;
|
||||
}
|
||||
|
||||
get isEmbedSyncedDocModel() {
|
||||
return this.model instanceof EmbedSyncedDocModel;
|
||||
}
|
||||
|
||||
get isInternalEmbedModel() {
|
||||
return isInternalEmbedModel(this.model);
|
||||
}
|
||||
|
||||
get modelType(): 'linked' | 'synced' | null {
|
||||
if (this.isEmbedLinkedDocModel) return 'linked';
|
||||
if (this.isEmbedSyncedDocModel) return 'synced';
|
||||
return null;
|
||||
}
|
||||
|
||||
get placeholders() {
|
||||
if (this.isInternalEmbedModel) {
|
||||
return {
|
||||
title: 'Add title alias',
|
||||
description:
|
||||
'Add description alias (empty to inherit document content)',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: 'Write a title',
|
||||
description: 'Write a description...',
|
||||
};
|
||||
}
|
||||
|
||||
private _updateInfo() {
|
||||
const title = this.model.title || this.originalDocInfo?.title || '';
|
||||
const description =
|
||||
this.model.description || this.originalDocInfo?.description || '';
|
||||
|
||||
this.title$.value = title;
|
||||
this.description$.value = description;
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this._updateInfo();
|
||||
}
|
||||
|
||||
override firstUpdated() {
|
||||
const blockComponent = this.host.std.view.getBlock(this.model.id);
|
||||
if (!blockComponent) return;
|
||||
|
||||
this._blockComponent = blockComponent;
|
||||
|
||||
this.disposables.add(
|
||||
autoUpdate(blockComponent, this, () => {
|
||||
computePosition(blockComponent, this, {
|
||||
placement: 'top-start',
|
||||
middleware: [flip(), offset(8)],
|
||||
})
|
||||
.then(({ x, y }) => {
|
||||
this.style.left = `${x}px`;
|
||||
this.style.top = `${y}px`;
|
||||
})
|
||||
.catch(console.error);
|
||||
})
|
||||
);
|
||||
|
||||
this.disposables.add(listenClickAway(this, this._hide));
|
||||
this.disposables.addFromEvent(this, 'keydown', this._onKeydown);
|
||||
this.disposables.addFromEvent(this, 'pointerdown', stopPropagation);
|
||||
|
||||
this.titleInput.focus();
|
||||
this.titleInput.select();
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="embed-card-modal-wrapper">
|
||||
<div class="row">
|
||||
<input
|
||||
class="input title"
|
||||
type="text"
|
||||
placeholder=${this.placeholders.title}
|
||||
.value=${live(this.title$.value)}
|
||||
@input=${this._updateTitle}
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<textarea
|
||||
class="input description"
|
||||
maxlength="500"
|
||||
placeholder=${this.placeholders.description}
|
||||
.value=${live(this.description$.value)}
|
||||
@input=${this._updateDescription}
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="row actions">
|
||||
${choose(this.modelType, [
|
||||
[
|
||||
'linked',
|
||||
() => html`
|
||||
<button
|
||||
class=${classMap({
|
||||
button: true,
|
||||
reset: true,
|
||||
})}
|
||||
.disabled=${this.resetButtonDisabled$.value}
|
||||
@click=${this._onReset}
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
`,
|
||||
],
|
||||
[
|
||||
'synced',
|
||||
() => html`
|
||||
<button
|
||||
class=${classMap({
|
||||
button: true,
|
||||
cancel: true,
|
||||
})}
|
||||
@click=${this._hide}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
`,
|
||||
],
|
||||
])}
|
||||
<button
|
||||
class=${classMap({
|
||||
button: true,
|
||||
save: true,
|
||||
})}
|
||||
.disabled=${this.saveButtonDisabled$.value}
|
||||
@click=${this._onSave}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
accessor description$ = signal<string>('');
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor host!: EditorHost;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor model!: LinkableEmbedModel;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor originalDocInfo: AliasInfo | undefined = undefined;
|
||||
|
||||
accessor resetButtonDisabled$ = computed<boolean>(
|
||||
() =>
|
||||
!(
|
||||
Boolean(this.model.title$.value?.length) ||
|
||||
Boolean(this.model.description$.value?.length)
|
||||
)
|
||||
);
|
||||
|
||||
accessor saveButtonDisabled$ = computed<boolean>(
|
||||
() => this.title$.value.trim().length === 0
|
||||
);
|
||||
|
||||
accessor title$ = signal<string>('');
|
||||
|
||||
@query('.input.title')
|
||||
accessor titleInput!: HTMLInputElement;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor viewType!: string;
|
||||
}
|
||||
|
||||
export function toggleEmbedCardEditModal(
|
||||
host: EditorHost,
|
||||
embedCardModel: LinkableEmbedModel,
|
||||
viewType: string,
|
||||
originalDocInfo?: AliasInfo
|
||||
) {
|
||||
document.body.querySelector('embed-card-edit-modal')?.remove();
|
||||
|
||||
const embedCardEditModal = new EmbedCardEditModal();
|
||||
embedCardEditModal.model = embedCardModel;
|
||||
embedCardEditModal.host = host;
|
||||
embedCardEditModal.viewType = viewType;
|
||||
embedCardEditModal.originalDocInfo = originalDocInfo;
|
||||
document.body.append(embedCardEditModal);
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'embed-card-edit-modal': EmbedCardEditModal;
|
||||
}
|
||||
}
|
||||
|
||||
function track(
|
||||
std: BlockStdScope,
|
||||
model: LinkableEmbedModel,
|
||||
viewType: string,
|
||||
event: LinkEventType,
|
||||
props: Partial<TelemetryEvent>
|
||||
) {
|
||||
std.getOptional(TelemetryProvider)?.track(event, {
|
||||
segment: 'toolbar',
|
||||
page: 'doc editor',
|
||||
module: 'embed card edit popup',
|
||||
type: `${viewType} view`,
|
||||
category: isInternalEmbedModel(model) ? 'linked doc' : 'link',
|
||||
...props,
|
||||
});
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './embed-card-create-modal.js';
|
||||
export * from './embed-card-edit-modal.js';
|
||||
@@ -1,120 +0,0 @@
|
||||
import { FONT_XS, PANEL_BASE } from '@blocksuite/affine-shared/styles';
|
||||
import { css } from 'lit';
|
||||
|
||||
export const embedCardModalStyles = css`
|
||||
.embed-card-modal-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.embed-card-modal-wrapper {
|
||||
${PANEL_BASE};
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 2;
|
||||
width: 305px;
|
||||
height: max-content;
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: var(--affine-font-xs);
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.embed-card-modal-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.embed-card-modal-row label {
|
||||
padding: 0px 2px;
|
||||
color: var(--affine-text-secondary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
.embed-card-modal-input {
|
||||
display: flex;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--affine-border-color);
|
||||
background: var(--affine-white-10);
|
||||
color: var(--affine-text-primary-color);
|
||||
${FONT_XS};
|
||||
}
|
||||
input.embed-card-modal-input {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
textarea.embed-card-modal-input {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
.embed-card-modal-input:focus {
|
||||
border-color: var(--affine-blue-700);
|
||||
box-shadow: var(--affine-active-shadow);
|
||||
outline: none;
|
||||
}
|
||||
.embed-card-modal-input::placeholder {
|
||||
color: var(--affine-placeholder-color);
|
||||
}
|
||||
|
||||
.embed-card-modal-row:has(.embed-card-modal-button) {
|
||||
flex-direction: row;
|
||||
gap: 4px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.embed-card-modal-row:has(.embed-card-modal-button.reset) {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.embed-card-modal-button {
|
||||
padding: 4px 18px;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.embed-card-modal-button.save {
|
||||
border: 1px solid var(--affine-black-10);
|
||||
background: var(--affine-primary-color);
|
||||
color: var(--affine-pure-white);
|
||||
}
|
||||
.embed-card-modal-button[disabled] {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
color: var(--affine-text-disable-color);
|
||||
background: transparent;
|
||||
}
|
||||
.embed-card-modal-button.reset {
|
||||
padding: 4px 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
text-decoration: underline;
|
||||
color: var(--affine-secondary-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.embed-card-modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 26px;
|
||||
user-select: none;
|
||||
}
|
||||
.embed-card-modal-description {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
user-select: none;
|
||||
}
|
||||
`;
|
||||
@@ -1,78 +0,0 @@
|
||||
import { BookmarkBlockComponent } from '@blocksuite/affine-block-bookmark';
|
||||
import {
|
||||
EmbedFigmaBlockComponent,
|
||||
EmbedGithubBlockComponent,
|
||||
EmbedHtmlBlockComponent,
|
||||
EmbedLinkedDocBlockComponent,
|
||||
EmbedLoomBlockComponent,
|
||||
EmbedSyncedDocBlockComponent,
|
||||
EmbedYoutubeBlockComponent,
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import type {
|
||||
BookmarkBlockModel,
|
||||
EmbedFigmaModel,
|
||||
EmbedGithubModel,
|
||||
EmbedHtmlModel,
|
||||
EmbedLoomModel,
|
||||
EmbedYoutubeModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
EmbedLinkedDocModel,
|
||||
EmbedSyncedDocModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import type { BlockComponent } from '@blocksuite/block-std';
|
||||
|
||||
export type ExternalEmbedBlockComponent =
|
||||
| BookmarkBlockComponent
|
||||
| EmbedFigmaBlockComponent
|
||||
| EmbedGithubBlockComponent
|
||||
| EmbedLoomBlockComponent
|
||||
| EmbedYoutubeBlockComponent;
|
||||
|
||||
export type InternalEmbedBlockComponent =
|
||||
| EmbedLinkedDocBlockComponent
|
||||
| EmbedSyncedDocBlockComponent;
|
||||
|
||||
export type LinkableEmbedBlockComponent =
|
||||
| ExternalEmbedBlockComponent
|
||||
| InternalEmbedBlockComponent;
|
||||
|
||||
export type EmbedBlockComponent =
|
||||
| LinkableEmbedBlockComponent
|
||||
| EmbedHtmlBlockComponent;
|
||||
|
||||
export type ExternalEmbedModel =
|
||||
| BookmarkBlockModel
|
||||
| EmbedFigmaModel
|
||||
| EmbedGithubModel
|
||||
| EmbedLoomModel
|
||||
| EmbedYoutubeModel;
|
||||
|
||||
export type InternalEmbedModel = EmbedLinkedDocModel | EmbedSyncedDocModel;
|
||||
|
||||
export type LinkableEmbedModel = ExternalEmbedModel | InternalEmbedModel;
|
||||
|
||||
export type EmbedModel = LinkableEmbedModel | EmbedHtmlModel;
|
||||
|
||||
export function isEmbedCardBlockComponent(
|
||||
block: BlockComponent
|
||||
): block is EmbedBlockComponent {
|
||||
return (
|
||||
block instanceof BookmarkBlockComponent ||
|
||||
block instanceof EmbedFigmaBlockComponent ||
|
||||
block instanceof EmbedGithubBlockComponent ||
|
||||
block instanceof EmbedHtmlBlockComponent ||
|
||||
block instanceof EmbedLoomBlockComponent ||
|
||||
block instanceof EmbedYoutubeBlockComponent ||
|
||||
block instanceof EmbedLinkedDocBlockComponent ||
|
||||
block instanceof EmbedSyncedDocBlockComponent
|
||||
);
|
||||
}
|
||||
|
||||
export function isInternalEmbedModel(
|
||||
model: EmbedModel
|
||||
): model is InternalEmbedModel {
|
||||
return (
|
||||
model instanceof EmbedLinkedDocModel || model instanceof EmbedSyncedDocModel
|
||||
);
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
import type { AffineInlineEditor } from '@blocksuite/affine-components/rich-text';
|
||||
import { getInlineEditorByModel } from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
getCurrentNativeRange,
|
||||
isControlledKeyboardEvent,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import type { InlineEditor, InlineRange } from '@blocksuite/inline';
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
export function getQuery(
|
||||
inlineEditor: InlineEditor,
|
||||
startRange: InlineRange | null
|
||||
) {
|
||||
const nativeRange = getCurrentNativeRange();
|
||||
if (!nativeRange) {
|
||||
return null;
|
||||
}
|
||||
if (nativeRange.startContainer !== nativeRange.endContainer) {
|
||||
return null;
|
||||
}
|
||||
const curRange = inlineEditor.getInlineRange();
|
||||
if (!startRange || !curRange) {
|
||||
return null;
|
||||
}
|
||||
if (curRange.index < startRange.index) {
|
||||
return null;
|
||||
}
|
||||
const text = inlineEditor.yText.toString();
|
||||
return text.slice(startRange.index, curRange.index);
|
||||
}
|
||||
|
||||
interface ObserverParams {
|
||||
target: HTMLElement;
|
||||
signal: AbortSignal;
|
||||
onInput?: (isComposition: boolean) => void;
|
||||
onDelete?: () => void;
|
||||
onMove?: (step: 1 | -1) => void;
|
||||
onConfirm?: () => void;
|
||||
onAbort?: () => void;
|
||||
onPaste?: () => void;
|
||||
interceptor?: (e: KeyboardEvent, next: () => void) => void;
|
||||
}
|
||||
|
||||
export const createKeydownObserver = ({
|
||||
target,
|
||||
signal,
|
||||
onInput,
|
||||
onDelete,
|
||||
onMove,
|
||||
onConfirm,
|
||||
onAbort,
|
||||
onPaste,
|
||||
interceptor = (_, next) => next(),
|
||||
}: ObserverParams) => {
|
||||
const keyDownListener = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Process' || e.isComposing) return;
|
||||
|
||||
if (e.defaultPrevented) return;
|
||||
|
||||
if (isControlledKeyboardEvent(e)) {
|
||||
const isOnlyCmd = (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey;
|
||||
// Ctrl/Cmd + alphabet key
|
||||
if (isOnlyCmd && e.key.length === 1) {
|
||||
switch (e.key) {
|
||||
// Previous command
|
||||
case 'p': {
|
||||
onMove?.(-1);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
// Next command
|
||||
case 'n': {
|
||||
onMove?.(1);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
// Paste command
|
||||
case 'v': {
|
||||
onPaste?.();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pressing **only** modifier key is allowed and will be ignored
|
||||
// Because we don't know the user's intention
|
||||
// Aborting here will cause the above hotkeys to not work
|
||||
if (e.key === 'Control' || e.key === 'Meta' || e.key === 'Alt') {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// Abort when press modifier key + any other key to avoid weird behavior
|
||||
// e.g. press ctrl + a to select all
|
||||
onAbort?.();
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
if (
|
||||
// input abc, 123, etc.
|
||||
!isControlledKeyboardEvent(e) &&
|
||||
e.key.length === 1
|
||||
) {
|
||||
onInput?.(false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'Backspace': {
|
||||
onDelete?.();
|
||||
return;
|
||||
}
|
||||
case 'Enter': {
|
||||
if (e.shiftKey) {
|
||||
onAbort?.();
|
||||
return;
|
||||
}
|
||||
onConfirm?.();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
case 'Tab': {
|
||||
if (e.shiftKey) {
|
||||
onMove?.(-1);
|
||||
} else {
|
||||
onMove?.(1);
|
||||
}
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
case 'ArrowUp': {
|
||||
if (e.shiftKey) {
|
||||
onAbort?.();
|
||||
return;
|
||||
}
|
||||
onMove?.(-1);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
case 'ArrowDown': {
|
||||
if (e.shiftKey) {
|
||||
onAbort?.();
|
||||
return;
|
||||
}
|
||||
onMove?.(1);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
case 'Escape':
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowRight': {
|
||||
onAbort?.();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
// Other control keys
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
target.addEventListener(
|
||||
'keydown',
|
||||
(e: KeyboardEvent) => interceptor(e, () => keyDownListener(e)),
|
||||
{
|
||||
// Workaround: Use capture to prevent the event from triggering the keyboard bindings action
|
||||
capture: true,
|
||||
signal,
|
||||
}
|
||||
);
|
||||
|
||||
// Fix paste input
|
||||
target.addEventListener('paste', () => onDelete?.(), { signal });
|
||||
|
||||
// Fix composition input
|
||||
target.addEventListener('compositionend', () => onInput?.(true), { signal });
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove specified text from the current range.
|
||||
*/
|
||||
export function cleanSpecifiedTail(
|
||||
editorHost: EditorHost,
|
||||
inlineEditorOrModel: AffineInlineEditor | BlockModel,
|
||||
str: string
|
||||
) {
|
||||
if (!str) {
|
||||
console.warn('Failed to clean text! Unexpected empty string');
|
||||
return;
|
||||
}
|
||||
const inlineEditor =
|
||||
inlineEditorOrModel instanceof BlockModel
|
||||
? getInlineEditorByModel(editorHost, inlineEditorOrModel)
|
||||
: inlineEditorOrModel;
|
||||
if (!inlineEditor) {
|
||||
return;
|
||||
}
|
||||
const inlineRange = inlineEditor.getInlineRange();
|
||||
if (!inlineRange) {
|
||||
return;
|
||||
}
|
||||
const idx = inlineRange.index - str.length;
|
||||
const textStr = inlineEditor.yText.toString().slice(idx, idx + str.length);
|
||||
if (textStr !== str) {
|
||||
console.warn(
|
||||
`Failed to clean text! Text mismatch expected: ${str} but actual: ${textStr}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
inlineEditor.deleteText({ index: idx, length: str.length });
|
||||
inlineEditor.setInlineRange({
|
||||
index: idx,
|
||||
length: 0,
|
||||
});
|
||||
}
|
||||
@@ -33,9 +33,6 @@ import { effects as dataViewEffects } from '@blocksuite/data-view/effects';
|
||||
import { effects as inlineEffects } from '@blocksuite/inline/effects';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import { EmbedCardEditCaptionEditModal } from './_common/components/embed-card/modal/embed-card-caption-edit-modal.js';
|
||||
import { EmbedCardCreateModal } from './_common/components/embed-card/modal/embed-card-create-modal.js';
|
||||
import { EmbedCardEditModal } from './_common/components/embed-card/modal/embed-card-edit-modal.js';
|
||||
import { registerSpecs } from './_specs/register-specs.js';
|
||||
import { DataViewBlockComponent } from './data-view-block/index.js';
|
||||
import { CenterPeek } from './database-block/components/layout.js';
|
||||
@@ -372,15 +369,9 @@ export function effects() {
|
||||
);
|
||||
customElements.define('edgeless-align-panel', EdgelessAlignPanel);
|
||||
customElements.define('card-style-panel', CardStylePanel);
|
||||
customElements.define(
|
||||
'embed-card-caption-edit-modal',
|
||||
EmbedCardEditCaptionEditModal
|
||||
);
|
||||
customElements.define('edgeless-color-button', EdgelessColorButton);
|
||||
customElements.define('edgeless-color-panel', EdgelessColorPanel);
|
||||
customElements.define('edgeless-text-color-icon', EdgelessTextColorIcon);
|
||||
customElements.define('embed-card-create-modal', EmbedCardCreateModal);
|
||||
customElements.define('embed-card-edit-modal', EmbedCardEditModal);
|
||||
customElements.define(
|
||||
'edgeless-mindmap-tool-button',
|
||||
EdgelessMindmapToolButton
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import type {
|
||||
BuiltInEmbedBlockComponent,
|
||||
BuiltInEmbedModel,
|
||||
} from '@blocksuite/affine-block-bookmark';
|
||||
import {
|
||||
isInternalEmbedModel,
|
||||
toggleEmbedCardEditModal,
|
||||
} from '@blocksuite/affine-block-bookmark';
|
||||
import {
|
||||
getDocContentWithMaxLength,
|
||||
getEmbedCardIcons,
|
||||
@@ -44,12 +52,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { join } from 'lit/directives/join.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
|
||||
import { toggleEmbedCardEditModal } from '../../../_common/components/embed-card/modal/embed-card-edit-modal.js';
|
||||
import type {
|
||||
EmbedBlockComponent,
|
||||
EmbedModel,
|
||||
} from '../../../_common/components/embed-card/type.js';
|
||||
import { isInternalEmbedModel } from '../../../_common/components/embed-card/type.js';
|
||||
import type { EmbedCardStyle } from '../../../_common/types.js';
|
||||
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
|
||||
import {
|
||||
@@ -373,7 +375,7 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
|
||||
const blockComponent = this.std.view.getBlock(
|
||||
blockSelection[0].blockId
|
||||
) as EmbedBlockComponent | null;
|
||||
) as BuiltInEmbedBlockComponent | null;
|
||||
|
||||
if (!blockComponent) return;
|
||||
|
||||
@@ -837,7 +839,7 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
accessor edgeless!: EdgelessRootBlockComponent;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor model!: EmbedModel;
|
||||
accessor model!: BuiltInEmbedModel;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor quickConnectButton!: TemplateResult<1> | typeof nothing;
|
||||
@@ -861,7 +863,7 @@ export function renderEmbedButton(
|
||||
|
||||
function track(
|
||||
std: BlockStdScope,
|
||||
model: EmbedModel,
|
||||
model: BuiltInEmbedModel,
|
||||
viewType: string,
|
||||
event: LinkEventType,
|
||||
props: Partial<TelemetryEvent>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { BuiltInEmbedModel } from '@blocksuite/affine-block-bookmark';
|
||||
import { CommonUtils } from '@blocksuite/affine-block-surface';
|
||||
import { ConnectorCWithArrowIcon } from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
@@ -38,7 +39,6 @@ import { css, html, nothing, type TemplateResult, unsafeCSS } from 'lit';
|
||||
import { property, state } from 'lit/decorators.js';
|
||||
import { join } from 'lit/directives/join.js';
|
||||
|
||||
import type { EmbedModel } from '../../../_common/components/embed-card/type.js';
|
||||
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
|
||||
import {
|
||||
isAttachmentBlock,
|
||||
@@ -79,7 +79,7 @@ type CategorizedElements = {
|
||||
image?: ImageBlockModel[];
|
||||
attachment?: AttachmentBlockModel[];
|
||||
mindmap?: MindmapElementModel[];
|
||||
embedCard?: EmbedModel[];
|
||||
embedCard?: BuiltInEmbedModel[];
|
||||
edgelessText?: EdgelessTextBlockModel[];
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { BuiltInEmbedBlockComponent } from '@blocksuite/affine-block-bookmark';
|
||||
import { MenuContext } from '@blocksuite/affine-components/toolbar';
|
||||
|
||||
import type { EmbedBlockComponent } from '../../../_common/components/embed-card/type.js';
|
||||
|
||||
export class EmbedCardToolbarContext extends MenuContext {
|
||||
override close = () => {
|
||||
this.abortController.abort();
|
||||
@@ -25,7 +24,7 @@ export class EmbedCardToolbarContext extends MenuContext {
|
||||
}
|
||||
|
||||
constructor(
|
||||
public blockComponent: EmbedBlockComponent,
|
||||
public blockComponent: BuiltInEmbedBlockComponent,
|
||||
public abortController: AbortController
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import {
|
||||
type BuiltInEmbedBlockComponent,
|
||||
type BuiltInEmbedModel,
|
||||
isEmbedCardBlockComponent,
|
||||
isInternalEmbedModel,
|
||||
toggleEmbedCardCaptionEditModal,
|
||||
toggleEmbedCardEditModal,
|
||||
} from '@blocksuite/affine-block-bookmark';
|
||||
import {
|
||||
getDocContentWithMaxLength,
|
||||
getEmbedCardIcons,
|
||||
@@ -54,14 +62,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { join } from 'lit/directives/join.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
|
||||
import { toggleEmbedCardCaptionEditModal } from '../../../_common/components/embed-card/modal/embed-card-caption-edit-modal.js';
|
||||
import { toggleEmbedCardEditModal } from '../../../_common/components/embed-card/modal/embed-card-edit-modal.js';
|
||||
import {
|
||||
type EmbedBlockComponent,
|
||||
type EmbedModel,
|
||||
isEmbedCardBlockComponent,
|
||||
isInternalEmbedModel,
|
||||
} from '../../../_common/components/embed-card/type.js';
|
||||
import {
|
||||
isBookmarkBlock,
|
||||
isEmbedGithubBlock,
|
||||
@@ -303,7 +303,7 @@ export class EmbedCardToolbar extends WidgetComponent<
|
||||
return 'inline';
|
||||
}
|
||||
|
||||
get focusModel(): EmbedModel | undefined {
|
||||
get focusModel(): BuiltInEmbedModel | undefined {
|
||||
return this.focusBlock?.model;
|
||||
}
|
||||
|
||||
@@ -726,7 +726,7 @@ export class EmbedCardToolbar extends WidgetComponent<
|
||||
return;
|
||||
}
|
||||
|
||||
this.focusBlock = block as EmbedBlockComponent;
|
||||
this.focusBlock = block as BuiltInEmbedBlockComponent;
|
||||
this._show();
|
||||
})
|
||||
);
|
||||
@@ -848,7 +848,7 @@ export class EmbedCardToolbar extends WidgetComponent<
|
||||
accessor embedCardToolbarElement!: HTMLElement;
|
||||
|
||||
@state()
|
||||
accessor focusBlock: EmbedBlockComponent | null = null;
|
||||
accessor focusBlock: BuiltInEmbedBlockComponent | null = null;
|
||||
|
||||
@state()
|
||||
accessor hide: boolean = true;
|
||||
@@ -865,7 +865,7 @@ declare global {
|
||||
|
||||
function track(
|
||||
std: BlockStdScope,
|
||||
model: EmbedModel,
|
||||
model: BuiltInEmbedModel,
|
||||
viewType: string,
|
||||
event: LinkEventType,
|
||||
props: Partial<TelemetryEvent>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { addSiblingAttachmentBlocks } from '@blocksuite/affine-block-attachment';
|
||||
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-block-bookmark';
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
getInlineEditorByModel,
|
||||
@@ -61,7 +62,6 @@ import { computed } from '@preact/signals-core';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import { toggleEmbedCardCreateModal } from '../../../_common/components/embed-card/modal/embed-card-create-modal.js';
|
||||
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
||||
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||
|
||||
@@ -2,6 +2,11 @@ import { LoadingIcon } from '@blocksuite/affine-block-image';
|
||||
import type { IconButton } from '@blocksuite/affine-components/icon-button';
|
||||
import { MoreHorizontalIcon } from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
getTextContentFromInlineRange,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
createKeydownObserver,
|
||||
getCurrentNativeRange,
|
||||
getViewportElement,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
@@ -15,11 +20,6 @@ import { html, LitElement, nothing } from 'lit';
|
||||
import { property, query, queryAll, state } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
createKeydownObserver,
|
||||
getQuery,
|
||||
} from '../../../_common/components/utils.js';
|
||||
import { getPopperPosition } from '../../utils/position.js';
|
||||
import type { LinkedDocContext, LinkedMenuGroup } from './config.js';
|
||||
import { linkedDocPopoverStyles } from './styles.js';
|
||||
@@ -86,7 +86,10 @@ export class LinkedDocPopover extends SignalWatcher(
|
||||
}
|
||||
|
||||
private get _query() {
|
||||
return getQuery(this.context.inlineEditor, this.context.startRange);
|
||||
return getTextContentFromInlineRange(
|
||||
this.context.inlineEditor,
|
||||
this.context.startRange
|
||||
);
|
||||
}
|
||||
|
||||
private _getActionItems(group: LinkedMenuGroup) {
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
getTextContentFromInlineRange,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
VirtualKeyboardController,
|
||||
type VirtualKeyboardControllerConfig,
|
||||
} from '@blocksuite/affine-components/virtual-keyboard';
|
||||
import { getViewportElement } from '@blocksuite/affine-shared/utils';
|
||||
import {
|
||||
createKeydownObserver,
|
||||
getViewportElement,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { PropTypes, requiredProperties } from '@blocksuite/block-std';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
||||
import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
|
||||
@@ -12,11 +19,6 @@ import { property } from 'lit/decorators.js';
|
||||
import { join } from 'lit/directives/join.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
createKeydownObserver,
|
||||
getQuery,
|
||||
} from '../../../_common/components/utils.js';
|
||||
import { PageRootBlockComponent } from '../../index.js';
|
||||
import type {
|
||||
LinkedDocContext,
|
||||
@@ -151,7 +153,10 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
||||
private _updateLinkedDocGroupAbortController: AbortController | null = null;
|
||||
|
||||
private get _query() {
|
||||
return getQuery(this.context.inlineEditor, this.context.startRange);
|
||||
return getTextContentFromInlineRange(
|
||||
this.context.inlineEditor,
|
||||
this.context.startRange
|
||||
);
|
||||
}
|
||||
|
||||
get virtualKeyboardControllerConfig(): VirtualKeyboardControllerConfig {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { addSiblingAttachmentBlocks } from '@blocksuite/affine-block-attachment';
|
||||
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-block-bookmark';
|
||||
import {
|
||||
FigmaIcon,
|
||||
GithubIcon,
|
||||
@@ -50,7 +51,6 @@ import type { BlockModel } from '@blocksuite/store';
|
||||
import { Slice, Text } from '@blocksuite/store';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import { toggleEmbedCardCreateModal } from '../../../_common/components/embed-card/modal/embed-card-create-modal.js';
|
||||
import type { DataViewBlockComponent } from '../../../data-view-block/index.js';
|
||||
import type { RootBlockComponent } from '../../types.js';
|
||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { ArrowDownIcon } from '@blocksuite/affine-components/icons';
|
||||
import { createLitPortal } from '@blocksuite/affine-components/portal';
|
||||
import type { AffineInlineEditor } from '@blocksuite/affine-components/rich-text';
|
||||
import { getInlineEditorByModel } from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
getInlineEditorByModel,
|
||||
getTextContentFromInlineRange,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
createKeydownObserver,
|
||||
isControlledKeyboardEvent,
|
||||
isFuzzyMatch,
|
||||
substringMatchScore,
|
||||
@@ -14,11 +19,6 @@ import { property, query, state } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import {
|
||||
cleanSpecifiedTail,
|
||||
createKeydownObserver,
|
||||
getQuery,
|
||||
} from '../../../_common/components/utils.js';
|
||||
import type {
|
||||
SlashMenuActionItem,
|
||||
SlashMenuContext,
|
||||
@@ -144,7 +144,7 @@ export class SlashMenu extends WithDisposable(LitElement) {
|
||||
};
|
||||
|
||||
private get _query() {
|
||||
return getQuery(this.inlineEditor, this._startRange);
|
||||
return getTextContentFromInlineRange(this.inlineEditor, this._startRange);
|
||||
}
|
||||
|
||||
get host() {
|
||||
|
||||
Reference in New Issue
Block a user