fix(core): improve EdgelessCopilotPanel position (#11814)

Closes: [AF-2101](https://linear.app/affine-design/issue/AF-2101/ai-panel-的输入框menu定位错误,menu-应该出现在输入框下方)

[Screen Recording 2025-04-18 at 20.51.01.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/8ypiIKZXudF5a0tIgIzf/67410349-b056-40a7-b1e6-6de5a5137789.mov" />](https://app.graphite.dev/media/video/8ypiIKZXudF5a0tIgIzf/67410349-b056-40a7-b1e6-6de5a5137789.mov)
This commit is contained in:
fundon
2025-04-21 14:08:24 +00:00
parent fd67bdf88b
commit 824e66df58
2 changed files with 31 additions and 27 deletions

View File

@@ -15,14 +15,15 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) {
:host { :host {
display: flex; display: flex;
position: absolute; position: absolute;
max-height: 374px;
} }
.edgeless-copilot-panel { .edgeless-copilot-panel {
box-sizing: border-box; box-sizing: border-box;
padding: 8px 4px 8px 8px; padding: 8px 4px 8px 8px;
min-width: 330px; min-width: 330px;
max-height: 374px;
overflow-y: auto; overflow-y: auto;
overscroll-behavior: contain;
background: ${unsafeCSSVar('--affine-background-overlay-panel-color')}; background: ${unsafeCSSVar('--affine-background-overlay-panel-color')};
box-shadow: ${unsafeCSSVar('--affine-overlay-shadow')}; box-shadow: ${unsafeCSSVar('--affine-overlay-shadow')};
border-radius: 8px; border-radius: 8px;

View File

@@ -11,9 +11,10 @@ import {
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std'; import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std';
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx'; import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
import { import {
autoPlacement,
autoUpdate, autoUpdate,
computePosition, computePosition,
flip, limitShift,
offset, offset,
shift, shift,
size, size,
@@ -112,41 +113,43 @@ export class EdgelessCopilotWidget extends WidgetComponent<RootBlockModel> {
} }
private _updateCopilotPanel(referenceElement: HTMLElement) { private _updateCopilotPanel(referenceElement: HTMLElement) {
// @TODO: optimize
const viewport = this.gfx.viewport;
const panel = this._copilotPanel; const panel = this._copilotPanel;
if (!panel) return; if (!panel) return;
const originMaxHeight = window.getComputedStyle(panel).maxHeight;
autoUpdate(referenceElement, panel, () => { autoUpdate(referenceElement, panel, () => {
computePosition(referenceElement, panel, { computePosition(referenceElement, panel, {
placement: 'bottom-start', placement: 'bottom-start',
middleware: [ middleware: [
offset({ offset(4),
mainAxis: 4, autoPlacement({
}), padding: 10,
flip({ allowedPlacements: [
mainAxis: true, 'top-start',
crossAxis: true, 'top-end',
flipAlignment: true, 'bottom-start',
}), 'bottom-end',
shift(() => { ],
const { left, top, width, height } = viewport;
return {
padding: 20,
crossAxis: true,
rootBoundary: {
x: left,
y: top,
width,
height: height - 100,
},
};
}), }),
size({ size({
apply: ({ elements }) => { apply: ({ availableHeight }) => {
const { height } = viewport; availableHeight -= 10;
elements.floating.style.maxHeight = `${height - 140}px`; panel.style.maxHeight =
originMaxHeight && originMaxHeight !== 'none'
? `min(${originMaxHeight}, ${availableHeight}px)`
: `${availableHeight}px`;
}, },
}), }),
shift({
padding: {
top: 10,
right: 10,
bottom: 150,
left: 10,
},
limiter: limitShift(),
}),
], ],
}) })
.then(({ x, y }) => { .then(({ x, y }) => {