@atlaskit/editor-plugin-type-ahead 2.0.0 → 2.0.1

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,17 @@
1
1
  # @atlaskit/editor-plugin-type-ahead
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#118492](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/118492)
8
+ [`cf0944583828b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cf0944583828b) -
9
+ [ED-26542] Fix typeahead popup doesn't close when clicking outside
10
+ - [#119058](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/119058)
11
+ [`4f8ad7d7497be`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4f8ad7d7497be) -
12
+ [ux] [ED-26575] Add placeholder to quick insert input field
13
+ - Updated dependencies
14
+
3
15
  ## 2.0.0
4
16
 
5
17
  ### Major Changes
@@ -13,6 +13,7 @@ var _history = require("@atlaskit/editor-prosemirror/history");
13
13
  var _state = require("@atlaskit/editor-prosemirror/state");
14
14
  var _view = require("@atlaskit/editor-prosemirror/view");
15
15
  var _colors = require("@atlaskit/theme/colors");
16
+ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
16
17
  var _WrapperTypeAhead = require("../ui/WrapperTypeAhead");
17
18
  var _closeTypeAhead = require("./commands/close-type-ahead");
18
19
  var _constants = require("./constants");
@@ -62,6 +63,11 @@ var factoryDecorations = exports.factoryDecorations = function factoryDecoration
62
63
  typeaheadComponent.dataset.typeAhead = _constants.TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE;
63
64
  typeaheadComponent.style.color = "var(--ds-text-accent-blue, ".concat(_colors.B400, ")");
64
65
  typeaheadComponent.style.backgroundColor = 'transparent';
66
+ if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
67
+ // As part of controls work, we add placeholder `Search` to quick insert command
68
+ // This style is to prevent `/Search` being wrapped if it's triggered at the end of the line
69
+ typeaheadComponent.style.whiteSpace = 'nowrap';
70
+ }
65
71
  var onUndoRedo = function onUndoRedo(inputType) {
66
72
  if (!['historyUndo', 'historyRedo'].includes(inputType)) {
67
73
  return false;
@@ -14,6 +14,7 @@ var _w3cKeyname = require("w3c-keyname");
14
14
  var _browser = require("@atlaskit/editor-common/browser");
15
15
  var _typeAhead = require("@atlaskit/editor-common/type-ahead");
16
16
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
17
+ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
17
18
  var _constants = require("../pm-plugins/constants");
18
19
  var _utils = require("../pm-plugins/utils");
19
20
  var _AssistiveText = require("./AssistiveText");
@@ -26,6 +27,22 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
26
27
 
27
28
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
28
29
 
30
+ var placeholderStyles = (0, _react2.css)({
31
+ '&::after': {
32
+ content: 'attr(data-place-holder)',
33
+ color: "var(--ds-text-subtlest, #626F86)",
34
+ position: 'relative',
35
+ padding: "var(--ds-space-025, 2px)",
36
+ left: "var(--ds-space-negative-050, -4px)",
37
+ backgroundColor: "var(--ds-background-neutral, #091E420F)",
38
+ borderRadius: '3px'
39
+ }
40
+ });
41
+ var queryWithoutPlaceholderStyles = (0, _react2.css)({
42
+ '&::after': {
43
+ content: "''"
44
+ }
45
+ });
29
46
  var querySpanStyles = (0, _react2.css)({
30
47
  outline: 'none',
31
48
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
@@ -91,6 +108,11 @@ var InputQuery = exports.InputQuery = /*#__PURE__*/_react.default.memo(function
91
108
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
92
109
  query = _useState2[0],
93
110
  setQuery = _useState2[1];
111
+ var isEditorControlsEnabled = (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1');
112
+ var _useState3 = (0, _react.useState)(isEditorControlsEnabled && triggerQueryPrefix === '/'),
113
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
114
+ showPlaceholder = _useState4[0],
115
+ setShowPlaceholder = _useState4[1];
94
116
  var cleanedInputContent = (0, _react.useCallback)(function () {
95
117
  var _ref$current;
96
118
  var raw = ((_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.textContent) || '';
@@ -100,10 +122,15 @@ var InputQuery = exports.InputQuery = /*#__PURE__*/_react.default.memo(function
100
122
  var text = cleanedInputContent();
101
123
  onQueryChange(text);
102
124
  }, [onQueryChange, cleanedInputContent]);
103
- var _useState3 = (0, _react.useState)(false),
104
- _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
105
- isInFocus = _useState4[0],
106
- setInFocus = _useState4[1];
125
+ var onInput = (0, _react.useCallback)(function () {
126
+ if (cleanedInputContent()) {
127
+ setShowPlaceholder(false);
128
+ }
129
+ }, [cleanedInputContent]);
130
+ var _useState5 = (0, _react.useState)(false),
131
+ _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
132
+ isInFocus = _useState6[0],
133
+ setInFocus = _useState6[1];
107
134
  var checkKeyEvent = (0, _react.useCallback)(function (event) {
108
135
  var _ref$current2;
109
136
  var key = (0, _w3cKeyname.keyName)(event);
@@ -403,18 +430,20 @@ var InputQuery = exports.InputQuery = /*#__PURE__*/_react.default.memo(function
403
430
  Task added in https://product-fabric.atlassian.net/wiki/spaces/E/pages/3182068181/Potential+improvements#Moderate-changes.
404
431
  */
405
432
  return (0, _react2.jsx)(_react.Fragment, null, triggerQueryPrefix, (0, _react2.jsx)("span", {
406
- css: querySpanStyles,
433
+ css: [querySpanStyles, isEditorControlsEnabled && queryWithoutPlaceholderStyles, showPlaceholder && placeholderStyles],
407
434
  contentEditable: true,
408
435
  ref: ref,
409
436
  onKeyUp: onKeyUp,
410
437
  onClick: onClick,
438
+ onInput: isEditorControlsEnabled ? onInput : undefined,
411
439
  role: "combobox",
412
440
  "aria-controls": _constants.TYPE_AHEAD_DECORATION_ELEMENT_ID,
413
441
  "aria-autocomplete": "list",
414
442
  "aria-expanded": items.length !== 0,
415
443
  "aria-labelledby": assistiveHintID,
416
444
  suppressContentEditableWarning: true,
417
- "data-query-prefix": triggerQueryPrefix
445
+ "data-query-prefix": triggerQueryPrefix,
446
+ "data-place-holder": intl.formatMessage(_typeAhead.typeAheadListMessages.quickInsertInputPlaceholderLabel)
418
447
  }, query === null ? (0, _react2.jsx)("input", {
419
448
  ref: inputRef,
420
449
  type: "text",
@@ -15,6 +15,7 @@ var _hooks = require("@atlaskit/editor-common/hooks");
15
15
  var _typeAhead = require("@atlaskit/editor-common/type-ahead");
16
16
  var _ui = require("@atlaskit/editor-common/ui");
17
17
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
18
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
18
19
  var _colors = require("@atlaskit/theme/colors");
19
20
  var _constants = require("../pm-plugins/constants");
20
21
  var _TypeAheadErrorFallback = require("./TypeAheadErrorFallback");
@@ -193,15 +194,41 @@ var TypeAheadPopup = exports.TypeAheadPopup = /*#__PURE__*/_react.default.memo(f
193
194
  var focusOut = function focusOut(event) {
194
195
  var _window$getSelection;
195
196
  var relatedTarget = event.relatedTarget;
196
-
197
197
  // Given the user is changing the focus
198
198
  // When the target is inside the TypeAhead Popup
199
199
  // Then the popup should stay open
200
200
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(".".concat(_constants.TYPE_AHEAD_POPUP_CONTENT_CLASS)) || relatedTarget.closest("[data-type-ahead=\"".concat(_constants.TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, "\"]")))) {
201
201
  return;
202
202
  }
203
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
204
- return;
203
+
204
+ // Handles cases like emoji (:) and mention (@) typeaheads that open new typeaheads
205
+ var isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
206
+ if ((0, _platformFeatureFlags.fg)('platform_editor_legacy_content_macro_typeahead_fix')) {
207
+ var _window$getSelection2;
208
+ // Check if new focus point is inside the current editor. If it is not we
209
+ // want to close the typeahead popup regardless of text selection state
210
+ var focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
211
+ if (focusNode instanceof HTMLElement) {
212
+ var innerEditor = focusNode.closest('.extension-editable-area');
213
+ // When there is no related target, we default to not closing the popup
214
+ var newFocusInsideCurrentEditor = !relatedTarget;
215
+ if (relatedTarget instanceof HTMLElement) {
216
+ if (innerEditor) {
217
+ // check if the new focus is inside inner editor, keep popup opens
218
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
219
+ } else {
220
+ // if the new focus contains current focus node, the popup won't close
221
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
222
+ }
223
+ }
224
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
225
+ return;
226
+ }
227
+ }
228
+ } else {
229
+ if (!isTextSelected) {
230
+ return;
231
+ }
205
232
  }
206
233
  cancel({
207
234
  addPrefixTrigger: true,
@@ -14,6 +14,7 @@ var _analytics = require("@atlaskit/editor-common/analytics");
14
14
  var _ui = require("@atlaskit/editor-common/ui");
15
15
  var _editorElementBrowser = require("@atlaskit/editor-element-browser");
16
16
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
17
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
17
18
  var _colors = require("@atlaskit/theme/colors");
18
19
  var _constants = require("../../pm-plugins/constants");
19
20
  var _TypeAheadErrorFallback = require("../TypeAheadErrorFallback");
@@ -193,8 +194,35 @@ var TypeAheadPopup = exports.TypeAheadPopup = /*#__PURE__*/_react.default.memo(f
193
194
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(".".concat(_constants.TYPE_AHEAD_POPUP_CONTENT_CLASS)) || relatedTarget.closest("[data-type-ahead=\"".concat(_constants.TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, "\"]")))) {
194
195
  return;
195
196
  }
196
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
197
- return;
197
+
198
+ // Handles cases like emoji and @ typeaheads that open new typeaheads
199
+ var isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
200
+ if ((0, _platformFeatureFlags.fg)('platform_editor_legacy_content_macro_typeahead_fix')) {
201
+ var _window$getSelection2;
202
+ // Check if new focus point is inside the current editor. If it is not we
203
+ // want to close the typeahead popup regardless of text selection state
204
+ var focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
205
+ if (focusNode instanceof HTMLElement) {
206
+ var innerEditor = focusNode.closest('.extension-editable-area');
207
+ // When there is no related target, we default to not closing the popup
208
+ var newFocusInsideCurrentEditor = !relatedTarget;
209
+ if (relatedTarget instanceof HTMLElement) {
210
+ if (innerEditor) {
211
+ // check if the new focus is inside inner editor, keep popup opens
212
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
213
+ } else {
214
+ // if the new focus contains current focus node, the popup won't close
215
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
216
+ }
217
+ }
218
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
219
+ return;
220
+ }
221
+ }
222
+ } else {
223
+ if (!isTextSelected) {
224
+ return;
225
+ }
198
226
  }
199
227
  cancel({
200
228
  addPrefixTrigger: true,
@@ -6,6 +6,7 @@ import { redo, undo } from '@atlaskit/editor-prosemirror/history';
6
6
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
7
7
  import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
8
  import { B400 } from '@atlaskit/theme/colors';
9
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
9
10
  import { WrapperTypeAhead } from '../ui/WrapperTypeAhead';
10
11
  import { closeTypeAhead } from './commands/close-type-ahead';
11
12
  import { TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_DECORATION_KEY } from './constants';
@@ -61,6 +62,11 @@ export const factoryDecorations = ({
61
62
  typeaheadComponent.dataset.typeAhead = TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE;
62
63
  typeaheadComponent.style.color = `var(--ds-text-accent-blue, ${B400})`;
63
64
  typeaheadComponent.style.backgroundColor = 'transparent';
65
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
66
+ // As part of controls work, we add placeholder `Search` to quick insert command
67
+ // This style is to prevent `/Search` being wrapped if it's triggered at the end of the line
68
+ typeaheadComponent.style.whiteSpace = 'nowrap';
69
+ }
64
70
  const onUndoRedo = inputType => {
65
71
  if (!['historyUndo', 'historyRedo'].includes(inputType)) {
66
72
  return false;
@@ -11,9 +11,26 @@ import { keyName as keyNameNormalized } from 'w3c-keyname';
11
11
  import { browser } from '@atlaskit/editor-common/browser';
12
12
  import { SelectItemMode, typeAheadListMessages } from '@atlaskit/editor-common/type-ahead';
13
13
  import { blockNodesVerticalMargin } from '@atlaskit/editor-shared-styles';
14
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
14
15
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_ELEMENT_ID, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../pm-plugins/constants';
15
16
  import { getPluginState } from '../pm-plugins/utils';
16
17
  import { AssistiveText } from './AssistiveText';
18
+ const placeholderStyles = css({
19
+ '&::after': {
20
+ content: 'attr(data-place-holder)',
21
+ color: "var(--ds-text-subtlest, #626F86)",
22
+ position: 'relative',
23
+ padding: "var(--ds-space-025, 2px)",
24
+ left: "var(--ds-space-negative-050, -4px)",
25
+ backgroundColor: "var(--ds-background-neutral, #091E420F)",
26
+ borderRadius: '3px'
27
+ }
28
+ });
29
+ const queryWithoutPlaceholderStyles = css({
30
+ '&::after': {
31
+ content: `''`
32
+ }
33
+ });
17
34
  const querySpanStyles = css({
18
35
  outline: 'none',
19
36
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
@@ -77,6 +94,8 @@ export const InputQuery = /*#__PURE__*/React.memo(({
77
94
  const ref = useRef(document.createElement('span'));
78
95
  const inputRef = useRef(null);
79
96
  const [query, setQuery] = useState(null);
97
+ const isEditorControlsEnabled = editorExperiment('platform_editor_controls', 'variant1');
98
+ const [showPlaceholder, setShowPlaceholder] = useState(isEditorControlsEnabled && triggerQueryPrefix === '/');
80
99
  const cleanedInputContent = useCallback(() => {
81
100
  var _ref$current;
82
101
  const raw = ((_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.textContent) || '';
@@ -86,6 +105,11 @@ export const InputQuery = /*#__PURE__*/React.memo(({
86
105
  const text = cleanedInputContent();
87
106
  onQueryChange(text);
88
107
  }, [onQueryChange, cleanedInputContent]);
108
+ const onInput = useCallback(() => {
109
+ if (cleanedInputContent()) {
110
+ setShowPlaceholder(false);
111
+ }
112
+ }, [cleanedInputContent]);
89
113
  const [isInFocus, setInFocus] = useState(false);
90
114
  const checkKeyEvent = useCallback(event => {
91
115
  var _ref$current2;
@@ -395,18 +419,20 @@ export const InputQuery = /*#__PURE__*/React.memo(({
395
419
  Task added in https://product-fabric.atlassian.net/wiki/spaces/E/pages/3182068181/Potential+improvements#Moderate-changes.
396
420
  */
397
421
  return jsx(Fragment, null, triggerQueryPrefix, jsx("span", {
398
- css: querySpanStyles,
422
+ css: [querySpanStyles, isEditorControlsEnabled && queryWithoutPlaceholderStyles, showPlaceholder && placeholderStyles],
399
423
  contentEditable: true,
400
424
  ref: ref,
401
425
  onKeyUp: onKeyUp,
402
426
  onClick: onClick,
427
+ onInput: isEditorControlsEnabled ? onInput : undefined,
403
428
  role: "combobox",
404
429
  "aria-controls": TYPE_AHEAD_DECORATION_ELEMENT_ID,
405
430
  "aria-autocomplete": "list",
406
431
  "aria-expanded": items.length !== 0,
407
432
  "aria-labelledby": assistiveHintID,
408
433
  suppressContentEditableWarning: true,
409
- "data-query-prefix": triggerQueryPrefix
434
+ "data-query-prefix": triggerQueryPrefix,
435
+ "data-place-holder": intl.formatMessage(typeAheadListMessages.quickInsertInputPlaceholderLabel)
410
436
  }, query === null ? jsx("input", {
411
437
  ref: inputRef,
412
438
  type: "text",
@@ -12,6 +12,7 @@ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
12
12
  import { TypeAheadAvailableNodes } from '@atlaskit/editor-common/type-ahead';
13
13
  import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
14
14
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
15
16
  import { N0, N50A, N60A } from '@atlaskit/theme/colors';
16
17
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../pm-plugins/constants';
17
18
  import { TypeAheadErrorFallback } from './TypeAheadErrorFallback';
@@ -182,15 +183,41 @@ export const TypeAheadPopup = /*#__PURE__*/React.memo(props => {
182
183
  const {
183
184
  relatedTarget
184
185
  } = event;
185
-
186
186
  // Given the user is changing the focus
187
187
  // When the target is inside the TypeAhead Popup
188
188
  // Then the popup should stay open
189
189
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`) || relatedTarget.closest(`[data-type-ahead="${TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE}"]`))) {
190
190
  return;
191
191
  }
192
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
193
- return;
192
+
193
+ // Handles cases like emoji (:) and mention (@) typeaheads that open new typeaheads
194
+ const isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
195
+ if (fg('platform_editor_legacy_content_macro_typeahead_fix')) {
196
+ var _window$getSelection2;
197
+ // Check if new focus point is inside the current editor. If it is not we
198
+ // want to close the typeahead popup regardless of text selection state
199
+ const focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
200
+ if (focusNode instanceof HTMLElement) {
201
+ const innerEditor = focusNode.closest('.extension-editable-area');
202
+ // When there is no related target, we default to not closing the popup
203
+ let newFocusInsideCurrentEditor = !relatedTarget;
204
+ if (relatedTarget instanceof HTMLElement) {
205
+ if (innerEditor) {
206
+ // check if the new focus is inside inner editor, keep popup opens
207
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
208
+ } else {
209
+ // if the new focus contains current focus node, the popup won't close
210
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
211
+ }
212
+ }
213
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
214
+ return;
215
+ }
216
+ }
217
+ } else {
218
+ if (!isTextSelected) {
219
+ return;
220
+ }
194
221
  }
195
222
  cancel({
196
223
  addPrefixTrigger: true,
@@ -11,6 +11,7 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/anal
11
11
  import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
12
12
  import { QuickInsertPanel } from '@atlaskit/editor-element-browser';
13
13
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
14
+ import { fg } from '@atlaskit/platform-feature-flags';
14
15
  import { N0, N50A, N60A } from '@atlaskit/theme/colors';
15
16
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../../pm-plugins/constants';
16
17
  import { TypeAheadErrorFallback } from '../TypeAheadErrorFallback';
@@ -182,8 +183,35 @@ export const TypeAheadPopup = /*#__PURE__*/React.memo(props => {
182
183
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`) || relatedTarget.closest(`[data-type-ahead="${TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE}"]`))) {
183
184
  return;
184
185
  }
185
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
186
- return;
186
+
187
+ // Handles cases like emoji and @ typeaheads that open new typeaheads
188
+ const isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
189
+ if (fg('platform_editor_legacy_content_macro_typeahead_fix')) {
190
+ var _window$getSelection2;
191
+ // Check if new focus point is inside the current editor. If it is not we
192
+ // want to close the typeahead popup regardless of text selection state
193
+ const focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
194
+ if (focusNode instanceof HTMLElement) {
195
+ const innerEditor = focusNode.closest('.extension-editable-area');
196
+ // When there is no related target, we default to not closing the popup
197
+ let newFocusInsideCurrentEditor = !relatedTarget;
198
+ if (relatedTarget instanceof HTMLElement) {
199
+ if (innerEditor) {
200
+ // check if the new focus is inside inner editor, keep popup opens
201
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
202
+ } else {
203
+ // if the new focus contains current focus node, the popup won't close
204
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
205
+ }
206
+ }
207
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
208
+ return;
209
+ }
210
+ }
211
+ } else {
212
+ if (!isTextSelected) {
213
+ return;
214
+ }
187
215
  }
188
216
  cancel({
189
217
  addPrefixTrigger: true,
@@ -6,6 +6,7 @@ import { redo, undo } from '@atlaskit/editor-prosemirror/history';
6
6
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
7
7
  import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
8
  import { B400 } from '@atlaskit/theme/colors';
9
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
9
10
  import { WrapperTypeAhead } from '../ui/WrapperTypeAhead';
10
11
  import { closeTypeAhead } from './commands/close-type-ahead';
11
12
  import { TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_DECORATION_KEY } from './constants';
@@ -55,6 +56,11 @@ export var factoryDecorations = function factoryDecorations(_ref) {
55
56
  typeaheadComponent.dataset.typeAhead = TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE;
56
57
  typeaheadComponent.style.color = "var(--ds-text-accent-blue, ".concat(B400, ")");
57
58
  typeaheadComponent.style.backgroundColor = 'transparent';
59
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
60
+ // As part of controls work, we add placeholder `Search` to quick insert command
61
+ // This style is to prevent `/Search` being wrapped if it's triggered at the end of the line
62
+ typeaheadComponent.style.whiteSpace = 'nowrap';
63
+ }
58
64
  var onUndoRedo = function onUndoRedo(inputType) {
59
65
  if (!['historyUndo', 'historyRedo'].includes(inputType)) {
60
66
  return false;
@@ -12,9 +12,26 @@ import { keyName as keyNameNormalized } from 'w3c-keyname';
12
12
  import { browser } from '@atlaskit/editor-common/browser';
13
13
  import { SelectItemMode, typeAheadListMessages } from '@atlaskit/editor-common/type-ahead';
14
14
  import { blockNodesVerticalMargin } from '@atlaskit/editor-shared-styles';
15
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
16
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_ELEMENT_ID, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../pm-plugins/constants';
16
17
  import { getPluginState } from '../pm-plugins/utils';
17
18
  import { AssistiveText } from './AssistiveText';
19
+ var placeholderStyles = css({
20
+ '&::after': {
21
+ content: 'attr(data-place-holder)',
22
+ color: "var(--ds-text-subtlest, #626F86)",
23
+ position: 'relative',
24
+ padding: "var(--ds-space-025, 2px)",
25
+ left: "var(--ds-space-negative-050, -4px)",
26
+ backgroundColor: "var(--ds-background-neutral, #091E420F)",
27
+ borderRadius: '3px'
28
+ }
29
+ });
30
+ var queryWithoutPlaceholderStyles = css({
31
+ '&::after': {
32
+ content: "''"
33
+ }
34
+ });
18
35
  var querySpanStyles = css({
19
36
  outline: 'none',
20
37
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
@@ -80,6 +97,11 @@ export var InputQuery = /*#__PURE__*/React.memo(function (_ref) {
80
97
  _useState2 = _slicedToArray(_useState, 2),
81
98
  query = _useState2[0],
82
99
  setQuery = _useState2[1];
100
+ var isEditorControlsEnabled = editorExperiment('platform_editor_controls', 'variant1');
101
+ var _useState3 = useState(isEditorControlsEnabled && triggerQueryPrefix === '/'),
102
+ _useState4 = _slicedToArray(_useState3, 2),
103
+ showPlaceholder = _useState4[0],
104
+ setShowPlaceholder = _useState4[1];
83
105
  var cleanedInputContent = useCallback(function () {
84
106
  var _ref$current;
85
107
  var raw = ((_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.textContent) || '';
@@ -89,10 +111,15 @@ export var InputQuery = /*#__PURE__*/React.memo(function (_ref) {
89
111
  var text = cleanedInputContent();
90
112
  onQueryChange(text);
91
113
  }, [onQueryChange, cleanedInputContent]);
92
- var _useState3 = useState(false),
93
- _useState4 = _slicedToArray(_useState3, 2),
94
- isInFocus = _useState4[0],
95
- setInFocus = _useState4[1];
114
+ var onInput = useCallback(function () {
115
+ if (cleanedInputContent()) {
116
+ setShowPlaceholder(false);
117
+ }
118
+ }, [cleanedInputContent]);
119
+ var _useState5 = useState(false),
120
+ _useState6 = _slicedToArray(_useState5, 2),
121
+ isInFocus = _useState6[0],
122
+ setInFocus = _useState6[1];
96
123
  var checkKeyEvent = useCallback(function (event) {
97
124
  var _ref$current2;
98
125
  var key = keyNameNormalized(event);
@@ -392,18 +419,20 @@ export var InputQuery = /*#__PURE__*/React.memo(function (_ref) {
392
419
  Task added in https://product-fabric.atlassian.net/wiki/spaces/E/pages/3182068181/Potential+improvements#Moderate-changes.
393
420
  */
394
421
  return jsx(Fragment, null, triggerQueryPrefix, jsx("span", {
395
- css: querySpanStyles,
422
+ css: [querySpanStyles, isEditorControlsEnabled && queryWithoutPlaceholderStyles, showPlaceholder && placeholderStyles],
396
423
  contentEditable: true,
397
424
  ref: ref,
398
425
  onKeyUp: onKeyUp,
399
426
  onClick: onClick,
427
+ onInput: isEditorControlsEnabled ? onInput : undefined,
400
428
  role: "combobox",
401
429
  "aria-controls": TYPE_AHEAD_DECORATION_ELEMENT_ID,
402
430
  "aria-autocomplete": "list",
403
431
  "aria-expanded": items.length !== 0,
404
432
  "aria-labelledby": assistiveHintID,
405
433
  suppressContentEditableWarning: true,
406
- "data-query-prefix": triggerQueryPrefix
434
+ "data-query-prefix": triggerQueryPrefix,
435
+ "data-place-holder": intl.formatMessage(typeAheadListMessages.quickInsertInputPlaceholderLabel)
407
436
  }, query === null ? jsx("input", {
408
437
  ref: inputRef,
409
438
  type: "text",
@@ -13,6 +13,7 @@ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
13
13
  import { TypeAheadAvailableNodes } from '@atlaskit/editor-common/type-ahead';
14
14
  import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
15
15
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
16
+ import { fg } from '@atlaskit/platform-feature-flags';
16
17
  import { N0, N50A, N60A } from '@atlaskit/theme/colors';
17
18
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../pm-plugins/constants';
18
19
  import { TypeAheadErrorFallback } from './TypeAheadErrorFallback';
@@ -182,15 +183,41 @@ export var TypeAheadPopup = /*#__PURE__*/React.memo(function (props) {
182
183
  var focusOut = function focusOut(event) {
183
184
  var _window$getSelection;
184
185
  var relatedTarget = event.relatedTarget;
185
-
186
186
  // Given the user is changing the focus
187
187
  // When the target is inside the TypeAhead Popup
188
188
  // Then the popup should stay open
189
189
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(".".concat(TYPE_AHEAD_POPUP_CONTENT_CLASS)) || relatedTarget.closest("[data-type-ahead=\"".concat(TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, "\"]")))) {
190
190
  return;
191
191
  }
192
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
193
- return;
192
+
193
+ // Handles cases like emoji (:) and mention (@) typeaheads that open new typeaheads
194
+ var isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
195
+ if (fg('platform_editor_legacy_content_macro_typeahead_fix')) {
196
+ var _window$getSelection2;
197
+ // Check if new focus point is inside the current editor. If it is not we
198
+ // want to close the typeahead popup regardless of text selection state
199
+ var focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
200
+ if (focusNode instanceof HTMLElement) {
201
+ var innerEditor = focusNode.closest('.extension-editable-area');
202
+ // When there is no related target, we default to not closing the popup
203
+ var newFocusInsideCurrentEditor = !relatedTarget;
204
+ if (relatedTarget instanceof HTMLElement) {
205
+ if (innerEditor) {
206
+ // check if the new focus is inside inner editor, keep popup opens
207
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
208
+ } else {
209
+ // if the new focus contains current focus node, the popup won't close
210
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
211
+ }
212
+ }
213
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
214
+ return;
215
+ }
216
+ }
217
+ } else {
218
+ if (!isTextSelected) {
219
+ return;
220
+ }
194
221
  }
195
222
  cancel({
196
223
  addPrefixTrigger: true,
@@ -12,6 +12,7 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/anal
12
12
  import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
13
13
  import { QuickInsertPanel } from '@atlaskit/editor-element-browser';
14
14
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
15
16
  import { N0, N50A, N60A } from '@atlaskit/theme/colors';
16
17
  import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../../pm-plugins/constants';
17
18
  import { TypeAheadErrorFallback } from '../TypeAheadErrorFallback';
@@ -182,8 +183,35 @@ export var TypeAheadPopup = /*#__PURE__*/React.memo(function (props) {
182
183
  if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(".".concat(TYPE_AHEAD_POPUP_CONTENT_CLASS)) || relatedTarget.closest("[data-type-ahead=\"".concat(TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, "\"]")))) {
183
184
  return;
184
185
  }
185
- if (!(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range')) {
186
- return;
186
+
187
+ // Handles cases like emoji and @ typeaheads that open new typeaheads
188
+ var isTextSelected = ((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range';
189
+ if (fg('platform_editor_legacy_content_macro_typeahead_fix')) {
190
+ var _window$getSelection2;
191
+ // Check if new focus point is inside the current editor. If it is not we
192
+ // want to close the typeahead popup regardless of text selection state
193
+ var focusNode = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode;
194
+ if (focusNode instanceof HTMLElement) {
195
+ var innerEditor = focusNode.closest('.extension-editable-area');
196
+ // When there is no related target, we default to not closing the popup
197
+ var newFocusInsideCurrentEditor = !relatedTarget;
198
+ if (relatedTarget instanceof HTMLElement) {
199
+ if (innerEditor) {
200
+ // check if the new focus is inside inner editor, keep popup opens
201
+ newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
202
+ } else {
203
+ // if the new focus contains current focus node, the popup won't close
204
+ newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
205
+ }
206
+ }
207
+ if (!isTextSelected && newFocusInsideCurrentEditor) {
208
+ return;
209
+ }
210
+ }
211
+ } else {
212
+ if (!isTextSelected) {
213
+ return;
214
+ }
187
215
  }
188
216
  cancel({
189
217
  addPrefixTrigger: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-type-ahead",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Type-ahead plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -32,22 +32,22 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@atlaskit/adf-schema": "^47.2.1",
35
- "@atlaskit/editor-common": "^100.0.0",
35
+ "@atlaskit/editor-common": "^100.2.0",
36
36
  "@atlaskit/editor-element-browser": "^0.1.0",
37
37
  "@atlaskit/editor-plugin-analytics": "^2.0.0",
38
38
  "@atlaskit/editor-plugin-connectivity": "^2.0.0",
39
39
  "@atlaskit/editor-plugin-context-panel": "^3.0.0",
40
40
  "@atlaskit/editor-prosemirror": "7.0.0",
41
41
  "@atlaskit/editor-shared-styles": "^3.3.0",
42
- "@atlaskit/heading": "^5.0.0",
43
- "@atlaskit/icon": "^24.0.0",
44
- "@atlaskit/menu": "^3.0.0",
42
+ "@atlaskit/heading": "^5.1.0",
43
+ "@atlaskit/icon": "^24.1.0",
44
+ "@atlaskit/menu": "^3.1.0",
45
45
  "@atlaskit/platform-feature-flags": "^1.1.0",
46
- "@atlaskit/primitives": "^14.0.0",
46
+ "@atlaskit/primitives": "^14.1.0",
47
47
  "@atlaskit/prosemirror-input-rules": "^3.3.0",
48
48
  "@atlaskit/theme": "^17.0.0",
49
- "@atlaskit/tmp-editor-statsig": "^3.0.0",
50
- "@atlaskit/tokens": "^4.0.0",
49
+ "@atlaskit/tmp-editor-statsig": "^3.2.0",
50
+ "@atlaskit/tokens": "^4.2.0",
51
51
  "@babel/runtime": "^7.0.0",
52
52
  "@emotion/react": "^11.7.1",
53
53
  "lodash": "^4.17.21",
@@ -98,6 +98,9 @@
98
98
  },
99
99
  "platform_editor_offline_editing_ga": {
100
100
  "type": "boolean"
101
+ },
102
+ "platform_editor_legacy_content_macro_typeahead_fix": {
103
+ "type": "boolean"
101
104
  }
102
105
  }
103
106
  }