@atlaskit/editor-plugin-autocomplete 4.1.3 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +38 -14
- package/dist/cjs/pm-plugins/ghost-text-decoration.js +4 -1
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +38 -14
- package/dist/es2019/pm-plugins/ghost-text-decoration.js +4 -1
- package/dist/esm/pm-plugins/autocomplete-plugin.js +38 -14
- package/dist/esm/pm-plugins/ghost-text-decoration.js +4 -1
- package/package.json +2 -2
- package/src/pm-plugins/autocomplete-plugin.ts +48 -17
- package/src/pm-plugins/ghost-text-decoration.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-autocomplete
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`268f447fd26f4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/268f447fd26f4) -
|
|
8
|
+
Fix autocomplete click interactions in the editor
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
3
14
|
## 4.1.3
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -169,6 +169,16 @@ var acceptGhostText = function acceptGhostText(state, dispatch) {
|
|
|
169
169
|
}
|
|
170
170
|
return true;
|
|
171
171
|
};
|
|
172
|
+
var acceptGhostTextWithAnalytics = function acceptGhostTextWithAnalytics(state, dispatch, onAccepted) {
|
|
173
|
+
var _pluginState$ghostTex;
|
|
174
|
+
var pluginState = autocompletePluginKey.getState(state);
|
|
175
|
+
var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
176
|
+
var accepted = acceptGhostText(state, dispatch);
|
|
177
|
+
if (accepted) {
|
|
178
|
+
onAccepted(ghostText);
|
|
179
|
+
}
|
|
180
|
+
return accepted;
|
|
181
|
+
};
|
|
172
182
|
|
|
173
183
|
/**
|
|
174
184
|
* Context provided to the autocomplete plugin on first editor focus.
|
|
@@ -609,28 +619,18 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
|
|
|
609
619
|
},
|
|
610
620
|
handleKeyDown: (0, _keymap.keydownHandler)({
|
|
611
621
|
Tab: function Tab(state, dispatch) {
|
|
612
|
-
|
|
613
|
-
var pluginState = autocompletePluginKey.getState(state);
|
|
614
|
-
var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
615
|
-
var accepted = acceptGhostText(state, dispatch);
|
|
616
|
-
if (accepted) {
|
|
622
|
+
return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
|
|
617
623
|
justAccepted = true;
|
|
618
624
|
lastShownGhostText = '';
|
|
619
625
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
620
|
-
}
|
|
621
|
-
return accepted;
|
|
626
|
+
});
|
|
622
627
|
},
|
|
623
628
|
ArrowRight: function ArrowRight(state, dispatch) {
|
|
624
|
-
|
|
625
|
-
var pluginState = autocompletePluginKey.getState(state);
|
|
626
|
-
var ghostText = (_pluginState$ghostTex2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex2 !== void 0 ? _pluginState$ghostTex2 : '';
|
|
627
|
-
var accepted = acceptGhostText(state, dispatch);
|
|
628
|
-
if (accepted) {
|
|
629
|
+
return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
|
|
629
630
|
justAccepted = true;
|
|
630
631
|
lastShownGhostText = '';
|
|
631
632
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
632
|
-
}
|
|
633
|
-
return accepted;
|
|
633
|
+
});
|
|
634
634
|
},
|
|
635
635
|
Escape: function Escape(state, dispatch) {
|
|
636
636
|
var didClear = clearGhostText(state, dispatch);
|
|
@@ -653,6 +653,30 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
|
|
|
653
653
|
}
|
|
654
654
|
return false;
|
|
655
655
|
},
|
|
656
|
+
mousedown: function mousedown(view, event) {
|
|
657
|
+
if (!isAutocompleteEnabled || !(event.target instanceof Element)) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
|
|
661
|
+
var didClear = clearGhostText(view.state, view.dispatch);
|
|
662
|
+
if (didClear) {
|
|
663
|
+
dismissedContext = getTextBeforeCursor(view.state);
|
|
664
|
+
lastShownGhostText = '';
|
|
665
|
+
fireSuggestionDismissedAnalytics('click');
|
|
666
|
+
}
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
event.preventDefault();
|
|
670
|
+
var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (ghostText) {
|
|
671
|
+
justAccepted = true;
|
|
672
|
+
lastShownGhostText = '';
|
|
673
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
674
|
+
});
|
|
675
|
+
if (accepted) {
|
|
676
|
+
view.focus();
|
|
677
|
+
}
|
|
678
|
+
return accepted;
|
|
679
|
+
},
|
|
656
680
|
focus: function focus() {
|
|
657
681
|
var _options$useLocalMode, _options$useLocalMode2;
|
|
658
682
|
if (!isAutocompleteEnabled) {
|
|
@@ -19,10 +19,13 @@ var createGhostTextDecorationSet = exports.createGhostTextDecorationSet = functi
|
|
|
19
19
|
var container = document.createElement('span');
|
|
20
20
|
container.className = GHOST_TEXT_CLASS;
|
|
21
21
|
container.setAttribute('data-autocomplete-ghost', 'true');
|
|
22
|
+
container.setAttribute('contenteditable', 'false');
|
|
23
|
+
container.setAttribute('aria-hidden', 'true');
|
|
22
24
|
container.style.color = '#999';
|
|
23
25
|
container.style.opacity = '0.6';
|
|
24
|
-
container.style.pointerEvents = '
|
|
26
|
+
container.style.pointerEvents = 'auto';
|
|
25
27
|
container.style.userSelect = 'none';
|
|
28
|
+
container.style.cursor = 'pointer';
|
|
26
29
|
container.style.fontStyle = 'italic';
|
|
27
30
|
// U+200B (Zero Width Space) gives the browser a line-break opportunity
|
|
28
31
|
// immediately before the ghost text. This ensures the typed text before
|
|
@@ -157,6 +157,16 @@ const acceptGhostText = (state, dispatch) => {
|
|
|
157
157
|
}
|
|
158
158
|
return true;
|
|
159
159
|
};
|
|
160
|
+
const acceptGhostTextWithAnalytics = (state, dispatch, onAccepted) => {
|
|
161
|
+
var _pluginState$ghostTex;
|
|
162
|
+
const pluginState = autocompletePluginKey.getState(state);
|
|
163
|
+
const ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
164
|
+
const accepted = acceptGhostText(state, dispatch);
|
|
165
|
+
if (accepted) {
|
|
166
|
+
onAccepted(ghostText);
|
|
167
|
+
}
|
|
168
|
+
return accepted;
|
|
169
|
+
};
|
|
160
170
|
|
|
161
171
|
/**
|
|
162
172
|
* Context provided to the autocomplete plugin on first editor focus.
|
|
@@ -596,28 +606,18 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
596
606
|
},
|
|
597
607
|
handleKeyDown: keydownHandler({
|
|
598
608
|
Tab: (state, dispatch) => {
|
|
599
|
-
|
|
600
|
-
const pluginState = autocompletePluginKey.getState(state);
|
|
601
|
-
const ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
602
|
-
const accepted = acceptGhostText(state, dispatch);
|
|
603
|
-
if (accepted) {
|
|
609
|
+
return acceptGhostTextWithAnalytics(state, dispatch, ghostText => {
|
|
604
610
|
justAccepted = true;
|
|
605
611
|
lastShownGhostText = '';
|
|
606
612
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
607
|
-
}
|
|
608
|
-
return accepted;
|
|
613
|
+
});
|
|
609
614
|
},
|
|
610
615
|
ArrowRight: (state, dispatch) => {
|
|
611
|
-
|
|
612
|
-
const pluginState = autocompletePluginKey.getState(state);
|
|
613
|
-
const ghostText = (_pluginState$ghostTex2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex2 !== void 0 ? _pluginState$ghostTex2 : '';
|
|
614
|
-
const accepted = acceptGhostText(state, dispatch);
|
|
615
|
-
if (accepted) {
|
|
616
|
+
return acceptGhostTextWithAnalytics(state, dispatch, ghostText => {
|
|
616
617
|
justAccepted = true;
|
|
617
618
|
lastShownGhostText = '';
|
|
618
619
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
619
|
-
}
|
|
620
|
-
return accepted;
|
|
620
|
+
});
|
|
621
621
|
},
|
|
622
622
|
Escape: (state, dispatch) => {
|
|
623
623
|
const didClear = clearGhostText(state, dispatch);
|
|
@@ -640,6 +640,30 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
640
640
|
}
|
|
641
641
|
return false;
|
|
642
642
|
},
|
|
643
|
+
mousedown: (view, event) => {
|
|
644
|
+
if (!isAutocompleteEnabled || !(event.target instanceof Element)) {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
|
|
648
|
+
const didClear = clearGhostText(view.state, view.dispatch);
|
|
649
|
+
if (didClear) {
|
|
650
|
+
dismissedContext = getTextBeforeCursor(view.state);
|
|
651
|
+
lastShownGhostText = '';
|
|
652
|
+
fireSuggestionDismissedAnalytics('click');
|
|
653
|
+
}
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
event.preventDefault();
|
|
657
|
+
const accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, ghostText => {
|
|
658
|
+
justAccepted = true;
|
|
659
|
+
lastShownGhostText = '';
|
|
660
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
661
|
+
});
|
|
662
|
+
if (accepted) {
|
|
663
|
+
view.focus();
|
|
664
|
+
}
|
|
665
|
+
return accepted;
|
|
666
|
+
},
|
|
643
667
|
focus: () => {
|
|
644
668
|
var _options$useLocalMode, _options$useLocalMode2;
|
|
645
669
|
if (!isAutocompleteEnabled) {
|
|
@@ -13,10 +13,13 @@ export const createGhostTextDecorationSet = (state, position, text) => {
|
|
|
13
13
|
const container = document.createElement('span');
|
|
14
14
|
container.className = GHOST_TEXT_CLASS;
|
|
15
15
|
container.setAttribute('data-autocomplete-ghost', 'true');
|
|
16
|
+
container.setAttribute('contenteditable', 'false');
|
|
17
|
+
container.setAttribute('aria-hidden', 'true');
|
|
16
18
|
container.style.color = '#999';
|
|
17
19
|
container.style.opacity = '0.6';
|
|
18
|
-
container.style.pointerEvents = '
|
|
20
|
+
container.style.pointerEvents = 'auto';
|
|
19
21
|
container.style.userSelect = 'none';
|
|
22
|
+
container.style.cursor = 'pointer';
|
|
20
23
|
container.style.fontStyle = 'italic';
|
|
21
24
|
// U+200B (Zero Width Space) gives the browser a line-break opportunity
|
|
22
25
|
// immediately before the ghost text. This ensures the typed text before
|
|
@@ -162,6 +162,16 @@ var acceptGhostText = function acceptGhostText(state, dispatch) {
|
|
|
162
162
|
}
|
|
163
163
|
return true;
|
|
164
164
|
};
|
|
165
|
+
var acceptGhostTextWithAnalytics = function acceptGhostTextWithAnalytics(state, dispatch, onAccepted) {
|
|
166
|
+
var _pluginState$ghostTex;
|
|
167
|
+
var pluginState = autocompletePluginKey.getState(state);
|
|
168
|
+
var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
169
|
+
var accepted = acceptGhostText(state, dispatch);
|
|
170
|
+
if (accepted) {
|
|
171
|
+
onAccepted(ghostText);
|
|
172
|
+
}
|
|
173
|
+
return accepted;
|
|
174
|
+
};
|
|
165
175
|
|
|
166
176
|
/**
|
|
167
177
|
* Context provided to the autocomplete plugin on first editor focus.
|
|
@@ -602,28 +612,18 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
602
612
|
},
|
|
603
613
|
handleKeyDown: keydownHandler({
|
|
604
614
|
Tab: function Tab(state, dispatch) {
|
|
605
|
-
|
|
606
|
-
var pluginState = autocompletePluginKey.getState(state);
|
|
607
|
-
var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
608
|
-
var accepted = acceptGhostText(state, dispatch);
|
|
609
|
-
if (accepted) {
|
|
615
|
+
return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
|
|
610
616
|
justAccepted = true;
|
|
611
617
|
lastShownGhostText = '';
|
|
612
618
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
613
|
-
}
|
|
614
|
-
return accepted;
|
|
619
|
+
});
|
|
615
620
|
},
|
|
616
621
|
ArrowRight: function ArrowRight(state, dispatch) {
|
|
617
|
-
|
|
618
|
-
var pluginState = autocompletePluginKey.getState(state);
|
|
619
|
-
var ghostText = (_pluginState$ghostTex2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex2 !== void 0 ? _pluginState$ghostTex2 : '';
|
|
620
|
-
var accepted = acceptGhostText(state, dispatch);
|
|
621
|
-
if (accepted) {
|
|
622
|
+
return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
|
|
622
623
|
justAccepted = true;
|
|
623
624
|
lastShownGhostText = '';
|
|
624
625
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
625
|
-
}
|
|
626
|
-
return accepted;
|
|
626
|
+
});
|
|
627
627
|
},
|
|
628
628
|
Escape: function Escape(state, dispatch) {
|
|
629
629
|
var didClear = clearGhostText(state, dispatch);
|
|
@@ -646,6 +646,30 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
646
646
|
}
|
|
647
647
|
return false;
|
|
648
648
|
},
|
|
649
|
+
mousedown: function mousedown(view, event) {
|
|
650
|
+
if (!isAutocompleteEnabled || !(event.target instanceof Element)) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
|
|
654
|
+
var didClear = clearGhostText(view.state, view.dispatch);
|
|
655
|
+
if (didClear) {
|
|
656
|
+
dismissedContext = getTextBeforeCursor(view.state);
|
|
657
|
+
lastShownGhostText = '';
|
|
658
|
+
fireSuggestionDismissedAnalytics('click');
|
|
659
|
+
}
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
event.preventDefault();
|
|
663
|
+
var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (ghostText) {
|
|
664
|
+
justAccepted = true;
|
|
665
|
+
lastShownGhostText = '';
|
|
666
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
667
|
+
});
|
|
668
|
+
if (accepted) {
|
|
669
|
+
view.focus();
|
|
670
|
+
}
|
|
671
|
+
return accepted;
|
|
672
|
+
},
|
|
649
673
|
focus: function focus() {
|
|
650
674
|
var _options$useLocalMode, _options$useLocalMode2;
|
|
651
675
|
if (!isAutocompleteEnabled) {
|
|
@@ -13,10 +13,13 @@ export var createGhostTextDecorationSet = function createGhostTextDecorationSet(
|
|
|
13
13
|
var container = document.createElement('span');
|
|
14
14
|
container.className = GHOST_TEXT_CLASS;
|
|
15
15
|
container.setAttribute('data-autocomplete-ghost', 'true');
|
|
16
|
+
container.setAttribute('contenteditable', 'false');
|
|
17
|
+
container.setAttribute('aria-hidden', 'true');
|
|
16
18
|
container.style.color = '#999';
|
|
17
19
|
container.style.opacity = '0.6';
|
|
18
|
-
container.style.pointerEvents = '
|
|
20
|
+
container.style.pointerEvents = 'auto';
|
|
19
21
|
container.style.userSelect = 'none';
|
|
22
|
+
container.style.cursor = 'pointer';
|
|
20
23
|
container.style.fontStyle = 'italic';
|
|
21
24
|
// U+200B (Zero Width Space) gives the browser a line-break opportunity
|
|
22
25
|
// immediately before the ghost text. This ensures the typed text before
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-autocomplete",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Client-side text autocomplete plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"wink-nlp": "^2.4.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@atlaskit/editor-common": "^116.
|
|
33
|
+
"@atlaskit/editor-common": "^116.40.0",
|
|
34
34
|
"@atlaskit/editor-plugin-analytics": "^12.0.0",
|
|
35
35
|
"react": "^18.2.0"
|
|
36
36
|
},
|
|
@@ -192,6 +192,20 @@ const acceptGhostText = (state: EditorState, dispatch?: (tr: Transaction) => voi
|
|
|
192
192
|
return true;
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
+
const acceptGhostTextWithAnalytics = (
|
|
196
|
+
state: EditorState,
|
|
197
|
+
dispatch: ((tr: Transaction) => void) | undefined,
|
|
198
|
+
onAccepted: (ghostText: string) => void,
|
|
199
|
+
): boolean => {
|
|
200
|
+
const pluginState = autocompletePluginKey.getState(state) as AutocompletePluginState | undefined;
|
|
201
|
+
const ghostText = pluginState?.ghostText ?? '';
|
|
202
|
+
const accepted = acceptGhostText(state, dispatch);
|
|
203
|
+
if (accepted) {
|
|
204
|
+
onAccepted(ghostText);
|
|
205
|
+
}
|
|
206
|
+
return accepted;
|
|
207
|
+
};
|
|
208
|
+
|
|
195
209
|
/**
|
|
196
210
|
* Context provided to the autocomplete plugin on first editor focus.
|
|
197
211
|
* Text fields are selectively ingested to boost word-frequency scoring for
|
|
@@ -378,7 +392,7 @@ export const createAutocompletePlugin = (
|
|
|
378
392
|
return options?.useLocalModel ? 'localLlm' : 'server';
|
|
379
393
|
};
|
|
380
394
|
|
|
381
|
-
const fireSuggestionDismissedAnalytics = (reason: 'escape' | 'blur'): void => {
|
|
395
|
+
const fireSuggestionDismissedAnalytics = (reason: 'escape' | 'blur' | 'click'): void => {
|
|
382
396
|
api?.analytics?.actions.fireAnalyticsEvent({
|
|
383
397
|
action: ACTION.SUGGESTION_DISMISSED,
|
|
384
398
|
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
@@ -736,30 +750,18 @@ export const createAutocompletePlugin = (
|
|
|
736
750
|
|
|
737
751
|
handleKeyDown: keydownHandler({
|
|
738
752
|
Tab: (state: EditorState, dispatch?: (tr: Transaction) => void) => {
|
|
739
|
-
|
|
740
|
-
| AutocompletePluginState
|
|
741
|
-
| undefined;
|
|
742
|
-
const ghostText = pluginState?.ghostText ?? '';
|
|
743
|
-
const accepted = acceptGhostText(state, dispatch);
|
|
744
|
-
if (accepted) {
|
|
753
|
+
return acceptGhostTextWithAnalytics(state, dispatch, (ghostText) => {
|
|
745
754
|
justAccepted = true;
|
|
746
755
|
lastShownGhostText = '';
|
|
747
756
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
748
|
-
}
|
|
749
|
-
return accepted;
|
|
757
|
+
});
|
|
750
758
|
},
|
|
751
759
|
ArrowRight: (state: EditorState, dispatch?: (tr: Transaction) => void) => {
|
|
752
|
-
|
|
753
|
-
| AutocompletePluginState
|
|
754
|
-
| undefined;
|
|
755
|
-
const ghostText = pluginState?.ghostText ?? '';
|
|
756
|
-
const accepted = acceptGhostText(state, dispatch);
|
|
757
|
-
if (accepted) {
|
|
760
|
+
return acceptGhostTextWithAnalytics(state, dispatch, (ghostText) => {
|
|
758
761
|
justAccepted = true;
|
|
759
762
|
lastShownGhostText = '';
|
|
760
763
|
fireSuggestionInsertedAnalytics(ghostText);
|
|
761
|
-
}
|
|
762
|
-
return accepted;
|
|
764
|
+
});
|
|
763
765
|
},
|
|
764
766
|
Escape: (state: EditorState, dispatch?: (tr: Transaction) => void) => {
|
|
765
767
|
const didClear = clearGhostText(state, dispatch);
|
|
@@ -786,6 +788,35 @@ export const createAutocompletePlugin = (
|
|
|
786
788
|
}
|
|
787
789
|
return false;
|
|
788
790
|
},
|
|
791
|
+
mousedown: (view: EditorView, event: MouseEvent) => {
|
|
792
|
+
if (!isAutocompleteEnabled || !(event.target instanceof Element)) {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
|
|
797
|
+
const didClear = clearGhostText(view.state, view.dispatch);
|
|
798
|
+
if (didClear) {
|
|
799
|
+
dismissedContext = getTextBeforeCursor(view.state);
|
|
800
|
+
lastShownGhostText = '';
|
|
801
|
+
fireSuggestionDismissedAnalytics('click');
|
|
802
|
+
}
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
event.preventDefault();
|
|
807
|
+
|
|
808
|
+
const accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, (ghostText) => {
|
|
809
|
+
justAccepted = true;
|
|
810
|
+
lastShownGhostText = '';
|
|
811
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
if (accepted) {
|
|
815
|
+
view.focus();
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return accepted;
|
|
819
|
+
},
|
|
789
820
|
focus: () => {
|
|
790
821
|
if (!isAutocompleteEnabled) {
|
|
791
822
|
return false;
|
|
@@ -22,10 +22,13 @@ export const createGhostTextDecorationSet = (
|
|
|
22
22
|
const container = document.createElement('span');
|
|
23
23
|
container.className = GHOST_TEXT_CLASS;
|
|
24
24
|
container.setAttribute('data-autocomplete-ghost', 'true');
|
|
25
|
+
container.setAttribute('contenteditable', 'false');
|
|
26
|
+
container.setAttribute('aria-hidden', 'true');
|
|
25
27
|
container.style.color = '#999';
|
|
26
28
|
container.style.opacity = '0.6';
|
|
27
|
-
container.style.pointerEvents = '
|
|
29
|
+
container.style.pointerEvents = 'auto';
|
|
28
30
|
container.style.userSelect = 'none';
|
|
31
|
+
container.style.cursor = 'pointer';
|
|
29
32
|
container.style.fontStyle = 'italic';
|
|
30
33
|
// U+200B (Zero Width Space) gives the browser a line-break opportunity
|
|
31
34
|
// immediately before the ghost text. This ensures the typed text before
|