@atlaskit/editor-plugin-autocomplete 4.1.3 → 4.3.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @atlaskit/editor-plugin-autocomplete
2
2
 
3
+ ## 4.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`51c33ef5349b6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/51c33ef5349b6) -
8
+ Enable compatibility with React 19.2.0
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
14
+ ## 4.2.0
15
+
16
+ ### Minor Changes
17
+
18
+ - [`268f447fd26f4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/268f447fd26f4) -
19
+ Fix autocomplete click interactions in the editor
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies
24
+
3
25
  ## 4.1.3
4
26
 
5
27
  ### Patch Changes
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "extends": "../tsconfig",
3
3
  "compilerOptions": {
4
+ "rootDir": "../src",
4
5
  "resolveJsonModule": true
5
6
  },
6
7
  "include": ["../src/**/*.ts", "../src/**/*.tsx"],
@@ -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
- var _pluginState$ghostTex;
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
- var _pluginState$ghostTex2;
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 = 'none';
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
- var _pluginState$ghostTex;
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
- var _pluginState$ghostTex2;
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 = 'none';
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
- var _pluginState$ghostTex;
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
- var _pluginState$ghostTex2;
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 = 'none';
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
@@ -27,9 +27,9 @@ import { type CustomData } from '@atlaskit/ufo';
27
27
  * otherwise emit zero-duration events on every word boundary.
28
28
  */
29
29
  export declare const EXPERIENCE_NAME: {
30
- readonly SLOW_LANE_FETCH: "slow-lane-fetch";
31
- readonly LOAD_VOCABULARY: "load-vocabulary";
32
- readonly LOAD_VECTORS: "load-vectors";
30
+ readonly SLOW_LANE_FETCH: 'slow-lane-fetch';
31
+ readonly LOAD_VOCABULARY: 'load-vocabulary';
32
+ readonly LOAD_VECTORS: 'load-vectors';
33
33
  };
34
34
  export type AutocompleteExperienceName = (typeof EXPERIENCE_NAME)[keyof typeof EXPERIENCE_NAME];
35
35
  export declare const startExp: (name: AutocompleteExperienceName, id: string, metadata?: CustomData) => void;
@@ -51,7 +51,7 @@ export declare const getPredictorStatus: () => {
51
51
  export declare const getLastPredictionDebug: () => {
52
52
  contextWords: string[];
53
53
  currentWord: string;
54
- mode: "cold" | "warm";
54
+ mode: 'cold' | 'warm';
55
55
  suggestion: string | null;
56
56
  textBefore: string;
57
57
  topCandidates: Array<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-autocomplete",
3
- "version": "4.1.3",
3
+ "version": "4.3.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,9 +30,9 @@
30
30
  "wink-nlp": "^2.4.0"
31
31
  },
32
32
  "peerDependencies": {
33
- "@atlaskit/editor-common": "^116.30.0",
34
- "@atlaskit/editor-plugin-analytics": "^12.0.0",
35
- "react": "^18.2.0"
33
+ "@atlaskit/editor-common": "^116.45.0",
34
+ "@atlaskit/editor-plugin-analytics": "^12.1.0",
35
+ "react": "^18.2.0 || ^19.2.0"
36
36
  },
37
37
  "techstack": {
38
38
  "@atlassian/frontend": {
@@ -48,6 +48,6 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "react": "^18.2.0"
51
+ "react": "^19.2.0"
52
52
  }
53
53
  }
@@ -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
- const pluginState = autocompletePluginKey.getState(state) as
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
- const pluginState = autocompletePluginKey.getState(state) as
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 = 'none';
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