fix(core): should invoke cleanup fn when ai sub item list is removed (#10685)
Closes: [BS-2755](https://linear.app/affine-design/issue/BS-2755/ai-translate-死循环报错)
This commit is contained in:
@@ -92,7 +92,7 @@ export class AIItemList extends WithDisposable(LitElement) {
|
|||||||
.onClick=${this.onClick}
|
.onClick=${this.onClick}
|
||||||
.abortController=${this._abortController}
|
.abortController=${this._abortController}
|
||||||
></ai-sub-item-list>`,
|
></ai-sub-item-list>`,
|
||||||
positionStrategy: 'fixed',
|
positionStrategy: 'absolute',
|
||||||
computePosition: {
|
computePosition: {
|
||||||
referenceElement: aiItemContainer,
|
referenceElement: aiItemContainer,
|
||||||
placement: 'right-start',
|
placement: 'right-start',
|
||||||
@@ -104,6 +104,11 @@ export class AIItemList extends WithDisposable(LitElement) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
override disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this._closeSubMenu();
|
||||||
|
}
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
return html`${repeat(this.groups, group => {
|
return html`${repeat(this.groups, group => {
|
||||||
return html`
|
return html`
|
||||||
@@ -114,15 +119,14 @@ export class AIItemList extends WithDisposable(LitElement) {
|
|||||||
: nothing}
|
: nothing}
|
||||||
${repeat(
|
${repeat(
|
||||||
group.items,
|
group.items,
|
||||||
|
item => item.name,
|
||||||
item =>
|
item =>
|
||||||
html`<ai-item
|
html`<ai-item
|
||||||
.onClick=${this.onClick}
|
.onClick=${this.onClick}
|
||||||
.item=${item}
|
.item=${item}
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
class=${this._itemClassName(item)}
|
class=${this._itemClassName(item)}
|
||||||
@mouseover=${() => {
|
@mouseenter=${() => this._openSubMenu(item)}
|
||||||
this._openSubMenu(item);
|
|
||||||
}}
|
|
||||||
></ai-item>`
|
></ai-item>`
|
||||||
)}
|
)}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import {
|
|||||||
PropTypes,
|
PropTypes,
|
||||||
requiredProperties,
|
requiredProperties,
|
||||||
} from '@blocksuite/affine/block-std';
|
} from '@blocksuite/affine/block-std';
|
||||||
import { EnterIcon } from '@blocksuite/affine/blocks';
|
import { EnterIcon, stopPropagation } from '@blocksuite/affine/blocks';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
import { baseTheme } from '@toeverything/theme';
|
import { baseTheme } from '@toeverything/theme';
|
||||||
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
|
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
import { menuItemStyles } from './styles';
|
import { menuItemStyles } from './styles';
|
||||||
import type { AIItemConfig, AISubItemConfig } from './types';
|
import type { AIItemConfig, AISubItemConfig } from './types';
|
||||||
@@ -54,10 +55,18 @@ export class AISubItemList extends WithDisposable(LitElement) {
|
|||||||
this.abortController.abort();
|
this.abortController.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
override connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
this.disposables.addFromEvent(this, 'pointerdown', stopPropagation);
|
||||||
|
}
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
if (!this.item.subItem || this.item.subItem.length <= 0) return nothing;
|
if (!this.item.subItem || this.item.subItem.length <= 0) return nothing;
|
||||||
return html`<div class="ai-sub-menu">
|
return html`<div class="ai-sub-menu">
|
||||||
${this.item.subItem?.map(
|
${repeat(
|
||||||
|
this.item.subItem,
|
||||||
|
subItem => subItem.type,
|
||||||
subItem =>
|
subItem =>
|
||||||
html`<div
|
html`<div
|
||||||
class="menu-item"
|
class="menu-item"
|
||||||
|
|||||||
@@ -783,6 +783,44 @@ test.describe('chat with block', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test.describe('Translate to', () => {
|
||||||
|
test('should close all ai item list when clicking outside', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const item = await page.waitForSelector('.ai-item-translate-to');
|
||||||
|
await item.hover();
|
||||||
|
|
||||||
|
const subItemList = await page.waitForSelector('ai-sub-item-list');
|
||||||
|
|
||||||
|
const bounds = await subItemList.boundingBox();
|
||||||
|
expect(bounds).toBeTruthy();
|
||||||
|
|
||||||
|
await page.mouse.click(bounds!.x + bounds!.width / 2, bounds!.y - 20);
|
||||||
|
|
||||||
|
await expect(page.locator('ai-sub-item-list')).toBeHidden();
|
||||||
|
await expect(page.locator('ai-item-list')).toBeHidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should close all ai item list when clicking sub item', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const item = await page.waitForSelector(
|
||||||
|
'ask-ai-panel .ai-item-translate-to'
|
||||||
|
);
|
||||||
|
await item.hover();
|
||||||
|
|
||||||
|
const subItemList = await page.waitForSelector('ai-sub-item-list');
|
||||||
|
|
||||||
|
const bounds = await subItemList.boundingBox();
|
||||||
|
expect(bounds).toBeTruthy();
|
||||||
|
|
||||||
|
(await subItemList.waitForSelector('.menu-item:nth-child(1)')).click();
|
||||||
|
|
||||||
|
await expect(page.locator('ai-sub-item-list')).toBeHidden();
|
||||||
|
await expect(page.locator('ask-ai-panel ai-item-list')).toBeHidden();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('chat with image block', () => {
|
test.describe('chat with image block', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user