Skip to content

Commit 0b19930

Browse files
authored
fix(Link): fix popup position when anchor DOM changes (#815)
1 parent 2d1e1fb commit 0b19930

File tree

1 file changed

+34
-41
lines changed
  • src/extensions/markdown/Link/plugins/LinkTooltipPlugin

1 file changed

+34
-41
lines changed

src/extensions/markdown/Link/plugins/LinkTooltipPlugin/index.tsx

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -82,72 +82,59 @@ class SelectionTooltip implements PluginView {
8282
private normalizeUrl;
8383

8484
private view: EditorView;
85+
private show: boolean;
8586

8687
private textNode?: ReturnType<typeof getTextNode>;
8788
private textNodeRef: HTMLElement | undefined;
8889

89-
private isTooltipOpen = false;
9090
private manualHidden = false;
9191

9292
private renderItem?: RendererItem;
93-
private selectionTooltipProps: SelectionTooltipViewBaseProps = {show: false};
9493

9594
constructor(view: EditorView, deps: ExtensionDeps) {
9695
this.normalizeUrl = normalizeUrlFactory(deps);
9796

9897
this.view = view;
98+
this.show = false;
9999

100-
this.update(view, null);
100+
this.update(view);
101101
}
102102

103-
update(view: EditorView, prevState?: EditorState | null) {
103+
update(view: EditorView) {
104104
if (!view.dom.parentNode) {
105105
this.hideTooltip();
106106
return;
107107
}
108108

109109
const {state} = view;
110110

111-
if (prevState && prevState.doc.eq(state.doc) && prevState.selection.eq(state.selection))
112-
return;
113-
114-
this.textNode = getTextNode(view.state);
111+
this.textNode = getTextNode(state);
115112

116113
const prevRef = this.textNodeRef;
117-
this.updateTextNodeRef();
118-
119-
if (!this.textNode || !this.textNodeRef) {
120-
this.hideTooltip();
121-
return;
122-
}
114+
this.textNodeRef = this.view.dom.getElementsByClassName(className)[0] as
115+
| HTMLElement
116+
| undefined;
123117

124118
if (prevRef !== this.textNodeRef) {
125119
this.manualHidden = false;
126120
}
127121

128-
if (this.manualHidden) {
122+
if (this.manualHidden || !this.textNode || !this.textNodeRef) {
129123
this.hideTooltip();
130-
} else {
131-
this.renderTooltip({
132-
show: true,
133-
domElem: this.textNodeRef,
134-
onCancel: () => this.cancelPopup(),
135-
attrs: this.getMarkAttrs(),
136-
onChange: this.changeAttrs.bind(this),
137-
onOpenChange: this.onOpenChange,
138-
});
124+
return;
139125
}
126+
127+
this.showTooltip();
140128
}
141129

142130
destroy() {
143-
this.isTooltipOpen = false;
144-
this.selectionTooltipProps = {show: false};
131+
this.show = false;
145132
this.renderItem?.remove();
146133
this.renderItem = undefined;
147134
}
148135

149136
onEscapeDown(): boolean {
150-
if (this.isTooltipOpen) {
137+
if (this.show) {
151138
this.removePlaceholderLink(this.textNode);
152139
this.manualHidden = true;
153140
this.hideTooltip();
@@ -157,38 +144,37 @@ class SelectionTooltip implements PluginView {
157144
return false;
158145
}
159146

160-
private updateTextNodeRef() {
161-
const decoElem = this.view.dom.getElementsByClassName(className)[0];
162-
this.textNodeRef = decoElem as HTMLElement | undefined;
163-
}
164-
165147
private getMarkAttrs() {
166148
const {textNode} = this;
167149
const linkMark = textNode && findMark(textNode.node, linkType(this.view.state.schema));
168150
return linkMark?.attrs;
169151
}
170152

153+
private renderTooltip() {
154+
this.renderItem = this.renderItem ?? this.createRenderItem();
155+
this.renderItem.rerender();
156+
}
157+
171158
private hideTooltip() {
172-
this.renderTooltip({show: false});
159+
this.show = false;
160+
this.renderTooltip();
173161
}
174162

175-
private renderTooltip(props: SelectionTooltipViewBaseProps) {
176-
this.isTooltipOpen = props.show;
177-
this.selectionTooltipProps = props;
178-
this.renderItem = this.renderItem ?? this.createRenderItem();
179-
this.renderItem.rerender();
163+
private showTooltip() {
164+
this.show = true;
165+
this.renderTooltip();
180166
}
181167

182168
private onOpenChange: NonNullable<PopupProps['onOpenChange']> = (open, _e, reason) => {
183169
if (open) return;
184170
if (reason === 'escape-key') {
185171
this.cancelPopup();
186172
} else {
187-
this.onOutisdeClick();
173+
this.onOutsideClick();
188174
}
189175
};
190176

191-
private onOutisdeClick = () => {
177+
private onOutsideClick = () => {
192178
this.removePlaceholderLink(this.textNode);
193179
this.hideTooltip();
194180
this.manualHidden = true;
@@ -239,7 +225,14 @@ class SelectionTooltip implements PluginView {
239225
private createRenderItem() {
240226
return getReactRendererFromState(this.view.state).createItem('link-tooltip', () => (
241227
<ErrorLoggerBoundary>
242-
<SelectionTooltipView {...this.selectionTooltipProps} />
228+
<SelectionTooltipView
229+
show={this.show}
230+
domElem={this.textNodeRef as HTMLElement}
231+
onCancel={this.cancelPopup.bind(this)}
232+
attrs={this.getMarkAttrs()}
233+
onChange={this.changeAttrs.bind(this)}
234+
onOpenChange={this.onOpenChange}
235+
/>
243236
</ErrorLoggerBoundary>
244237
));
245238
}

0 commit comments

Comments
 (0)