feat(editor): add footnote node click handler (#11699)

Close [BS-3114](https://linear.app/affine-design/issue/BS-3114/点击-footnote-node-行为更新)
This commit is contained in:
donteatfriedrice
2025-04-15 12:22:43 +00:00
parent b5c9741f18
commit 96e58316f7
2 changed files with 46 additions and 48 deletions

View File

@@ -1,4 +1,5 @@
import { HoverController } from '@blocksuite/affine-components/hover';
import { PeekViewProvider } from '@blocksuite/affine-components/peek';
import type { FootNote } from '@blocksuite/affine-model';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
@@ -105,8 +106,47 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
return selfInlineRange;
}
get footnote() {
return this.delta.attributes?.footnote;
}
onFootnoteClick = () => {
if (!this.footnote) {
return;
}
const { type, docId, url } = this.footnote.reference;
switch (type) {
case 'doc':
if (docId) {
this._handleDocReference(docId);
}
break;
case 'url':
if (url) {
this._handleUrlReference(url);
}
break;
}
};
private readonly _handleDocReference = (docId: string) => {
this.std
.getOptional(PeekViewProvider)
?.peek({
docId,
})
.catch(console.error);
};
private readonly _handleUrlReference = (url: string) => {
window.open(url, '_blank');
};
private readonly _FootNoteDefaultContent = (footnote: FootNote) => {
return html`<span class="footnote-content-default"
return html`<span
class="footnote-content-default"
@click=${this.onFootnoteClick}
>${footnote.label}</span
>`;
};
@@ -121,14 +161,14 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
.footnote=${footnote}
.std=${this.std}
.abortController=${abortController}
.onPopupClick=${this.onPopupClick}
.onPopupClick=${this.onPopupClick ?? this.onFootnoteClick}
></footnote-popup>`;
};
private readonly _whenHover: HoverController = new HoverController(
this,
({ abortController }) => {
const footnote = this.delta.attributes?.footnote;
const { footnote } = this;
if (!footnote) return null;
if (

View File

@@ -4,7 +4,6 @@ import {
LightLoadingIcon,
WebIcon16,
} from '@blocksuite/affine-components/icons';
import { PeekViewProvider } from '@blocksuite/affine-components/peek';
import { ColorScheme, type FootNote } from '@blocksuite/affine-model';
import {
DocDisplayMetaProvider,
@@ -127,50 +126,9 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
return theme === ColorScheme.Light ? LightLoadingIcon : DarkLoadingIcon;
};
/**
* When clicking the chip, we will navigate to the reference doc or open the url
*/
private readonly _handleDocReference = (docId: string) => {
this.std
.getOptional(PeekViewProvider)
?.peek({
docId,
})
.catch(console.error);
};
private readonly _handleUrlReference = (url: string) => {
window.open(url, '_blank');
};
private readonly _handleReference = () => {
const { type, docId, url } = this.footnote.reference;
switch (type) {
case 'doc':
if (docId) {
this._handleDocReference(docId);
}
break;
case 'url':
if (url) {
this._handleUrlReference(url);
}
break;
}
this.abortController.abort();
};
private readonly _onChipClick = () => {
// If the onPopupClick is defined, use it
if (this.onPopupClick) {
this.onPopupClick(this.footnote, this.abortController);
return;
}
// Otherwise, handle the reference by default
this._handleReference();
this.onPopupClick(this.footnote, this.abortController);
this.abortController.abort();
};
override connectedCallback() {
@@ -217,5 +175,5 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
accessor abortController!: AbortController;
@property({ attribute: false })
accessor onPopupClick: FootNotePopupClickHandler | undefined = undefined;
accessor onPopupClick: FootNotePopupClickHandler | (() => void) = () => {};
}