@atlaskit/editor-plugin-quick-insert 15.1.4 → 16.0.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/entry-points/registry-element-browser.js +12 -0
  3. package/dist/cjs/quickInsertPlugin.js +10 -3
  4. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowser.compiled.css +2 -0
  5. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowser.js +176 -0
  6. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserCategories.compiled.css +2 -0
  7. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserCategories.js +52 -0
  8. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserFooter.js +40 -0
  9. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.compiled.css +2 -0
  10. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +123 -0
  11. package/dist/cjs/ui/RegistryElementBrowser/index.js +144 -0
  12. package/dist/cjs/ui/RegistryElementBrowser/model.js +129 -0
  13. package/dist/es2019/entry-points/registry-element-browser.js +2 -0
  14. package/dist/es2019/quickInsertPlugin.js +8 -3
  15. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowser.compiled.css +2 -0
  16. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowser.js +147 -0
  17. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserCategories.compiled.css +2 -0
  18. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserCategories.js +55 -0
  19. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserFooter.js +35 -0
  20. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.compiled.css +2 -0
  21. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +112 -0
  22. package/dist/es2019/ui/RegistryElementBrowser/index.js +123 -0
  23. package/dist/es2019/ui/RegistryElementBrowser/model.js +97 -0
  24. package/dist/esm/entry-points/registry-element-browser.js +2 -0
  25. package/dist/esm/quickInsertPlugin.js +10 -3
  26. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowser.compiled.css +2 -0
  27. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowser.js +167 -0
  28. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserCategories.compiled.css +2 -0
  29. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserCategories.js +45 -0
  30. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserFooter.js +33 -0
  31. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.compiled.css +2 -0
  32. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +114 -0
  33. package/dist/esm/ui/RegistryElementBrowser/index.js +135 -0
  34. package/dist/esm/ui/RegistryElementBrowser/model.js +122 -0
  35. package/dist/types/entry-points/registry-element-browser.d.ts +1 -0
  36. package/dist/types/ui/RegistryElementBrowser/RegistryElementBrowser.d.ts +25 -0
  37. package/dist/types/ui/RegistryElementBrowser/RegistryElementBrowserCategories.d.ts +14 -0
  38. package/dist/types/ui/RegistryElementBrowser/RegistryElementBrowserFooter.d.ts +9 -0
  39. package/dist/types/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.d.ts +31 -0
  40. package/dist/types/ui/RegistryElementBrowser/index.d.ts +9 -0
  41. package/dist/types/ui/RegistryElementBrowser/model.d.ts +31 -0
  42. package/package.json +12 -7
  43. package/registry-element-browser/package.json +10 -0
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getRegistryElementBrowserItems = exports.getInitialRegistryElementBrowserSection = exports.createRegistryElementBrowserModel = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
11
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
12
+ var compareRanks = function compareRanks(left, right) {
13
+ for (var index = 0; index < Math.max(left.length, right.length); index++) {
14
+ var _left$index, _right$index;
15
+ var difference = ((_left$index = left[index]) !== null && _left$index !== void 0 ? _left$index : 0) - ((_right$index = right[index]) !== null && _right$index !== void 0 ? _right$index : 0);
16
+ if (difference !== 0) {
17
+ return difference;
18
+ }
19
+ }
20
+ return 0;
21
+ };
22
+ var isVisible = function isVisible(registration) {
23
+ var _registration$isHidde;
24
+ return ((_registration$isHidde = registration.isHidden) === null || _registration$isHidde === void 0 ? void 0 : _registration$isHidde.call(registration)) !== true;
25
+ };
26
+ var getChildren = function getChildren(components, parentKey) {
27
+ return components.filter(function (component) {
28
+ var _component$parents;
29
+ return isVisible(component) && ((_component$parents = component.parents) === null || _component$parents === void 0 ? void 0 : _component$parents.some(function (parent) {
30
+ return parent.key === parentKey;
31
+ }));
32
+ });
33
+ };
34
+ var getParentRank = function getParentRank(registration, parentKey) {
35
+ var _registration$parents, _registration$parents2;
36
+ return (_registration$parents = (_registration$parents2 = registration.parents) === null || _registration$parents2 === void 0 || (_registration$parents2 = _registration$parents2.find(function (parent) {
37
+ return parent.key === parentKey;
38
+ })) === null || _registration$parents2 === void 0 ? void 0 : _registration$parents2.rank) !== null && _registration$parents !== void 0 ? _registration$parents : Number.MAX_SAFE_INTEGER;
39
+ };
40
+ var _getDescendantItems = function getDescendantItems(components, parentKey, ancestorRanks, sectionKey) {
41
+ return getChildren(components, parentKey).flatMap(function (component) {
42
+ var ranks = [].concat((0, _toConsumableArray2.default)(ancestorRanks), [getParentRank(component, parentKey)]);
43
+ if (component.type === 'menu-item') {
44
+ return component.component ? [{
45
+ ranks: ranks,
46
+ registration: component,
47
+ sectionKeys: [sectionKey]
48
+ }] : [];
49
+ }
50
+ return _getDescendantItems(components, component.key, ranks, sectionKey);
51
+ });
52
+ };
53
+
54
+ /**
55
+ * Builds the Element Browser's immutable open-time view of the Quick Insert registry.
56
+ * The caller provides only components rooted at the Quick Insert menu surface.
57
+ */
58
+ var createRegistryElementBrowserModel = exports.createRegistryElementBrowserModel = function createRegistryElementBrowserModel(components, _ref) {
59
+ var footerKey = _ref.footerKey,
60
+ overflowKeys = _ref.overflowKeys,
61
+ recommendedSectionKey = _ref.recommendedSectionKey,
62
+ rootKey = _ref.rootKey;
63
+ var excludedKeys = new Set([footerKey, recommendedSectionKey].concat((0, _toConsumableArray2.default)(overflowKeys)));
64
+ var visibleComponents = components.filter(function (component) {
65
+ return isVisible(component) && !excludedKeys.has(component.key);
66
+ });
67
+ var sections = getChildren(visibleComponents, rootKey).filter(function (component) {
68
+ return component.type === 'menu-section';
69
+ }).map(function (section) {
70
+ return {
71
+ key: section.key,
72
+ rank: getParentRank(section, rootKey)
73
+ };
74
+ }).sort(function (left, right) {
75
+ return left.rank - right.rank;
76
+ });
77
+ var itemByKey = new Map();
78
+ sections.forEach(function (section) {
79
+ _getDescendantItems(visibleComponents, section.key, [section.rank], section.key).forEach(function (item) {
80
+ var existing = itemByKey.get(item.registration.key);
81
+ if (!existing) {
82
+ itemByKey.set(item.registration.key, item);
83
+ return;
84
+ }
85
+ var sectionKeys = (0, _toConsumableArray2.default)(new Set([].concat((0, _toConsumableArray2.default)(existing.sectionKeys), (0, _toConsumableArray2.default)(item.sectionKeys))));
86
+ itemByKey.set(item.registration.key, compareRanks(item.ranks, existing.ranks) < 0 ? _objectSpread(_objectSpread({}, item), {}, {
87
+ sectionKeys: sectionKeys
88
+ }) : _objectSpread(_objectSpread({}, existing), {}, {
89
+ sectionKeys: sectionKeys
90
+ }));
91
+ });
92
+ });
93
+ return {
94
+ items: (0, _toConsumableArray2.default)(itemByKey.values()).sort(function (left, right) {
95
+ return compareRanks(left.ranks, right.ranks);
96
+ }),
97
+ sections: sections
98
+ };
99
+ };
100
+ var getInitialRegistryElementBrowserSection = exports.getInitialRegistryElementBrowserSection = function getInitialRegistryElementBrowserSection(model, requestedSection) {
101
+ return model.sections.some(function (section) {
102
+ return section.key === requestedSection;
103
+ }) ? requestedSection : undefined;
104
+ };
105
+ var getRegistryElementBrowserItems = exports.getRegistryElementBrowserItems = function getRegistryElementBrowserItems(_ref2) {
106
+ var formatMessage = _ref2.formatMessage,
107
+ model = _ref2.model,
108
+ query = _ref2.query,
109
+ section = _ref2.section;
110
+ var normalizedQuery = query.trim();
111
+ var items = section ? model.items.filter(function (item) {
112
+ return item.sectionKeys.includes(section);
113
+ }) : model.items;
114
+ if (!normalizedQuery) {
115
+ return items;
116
+ }
117
+ return items.flatMap(function (item) {
118
+ var _item$registration$ma, _item$registration;
119
+ var result = (_item$registration$ma = (_item$registration = item.registration).match) === null || _item$registration$ma === void 0 ? void 0 : _item$registration$ma.call(_item$registration, {
120
+ formatMessage: formatMessage,
121
+ query: normalizedQuery
122
+ });
123
+ return result ? [_objectSpread(_objectSpread({}, item), {}, {
124
+ score: Math.min(1, Math.max(0, result.score))
125
+ })] : [];
126
+ }).sort(function (left, right) {
127
+ return left.score - right.score || compareRanks(left.ranks, right.ranks) || left.registration.key.localeCompare(right.registration.key);
128
+ });
129
+ };
@@ -0,0 +1,2 @@
1
+ /* eslint-disable @atlaskit/editor/no-re-export */
2
+ export { RegistryElementBrowser } from '../ui/RegistryElementBrowser/RegistryElementBrowser';
@@ -16,6 +16,7 @@ import { pluginKey } from './pm-plugins/plugin-key';
16
16
  import { getLegacyCompatibleComponents } from './ui/getLegacyCompatibleComponents';
17
17
  import { getQuickInsertComponents } from './ui/getQuickInsertComponents';
18
18
  import ModalElementBrowser from './ui/ModalElementBrowser';
19
+ import { RegistryElementBrowserContainer } from './ui/RegistryElementBrowser';
19
20
  import { getQuickInsertSuggestions, withLayoutQuickInsertPrioritySorting } from './ui/search';
20
21
  export const quickInsertPlugin = ({
21
22
  config: options,
@@ -79,7 +80,7 @@ export const quickInsertPlugin = ({
79
80
  return {
80
81
  title: formatMessage(messages.viewMore),
81
82
  ariaLabel: formatMessage(messages.viewMoreAriaLabel),
82
- onClick: openElementBrowserModal,
83
+ onClick: props => openElementBrowser()(props),
83
84
  iconBefore: /*#__PURE__*/React.createElement(ShowMoreHorizontalIcon, {
84
85
  label: ""
85
86
  })
@@ -106,7 +107,7 @@ export const quickInsertPlugin = ({
106
107
  tr
107
108
  });
108
109
  }
109
- return openElementBrowserCommand(options)({
110
+ return (isExperimentEnabled('platform_editor_slash_command') ? openElementBrowserCommand(options) : openElementBrowserModal)({
110
111
  tr
111
112
  });
112
113
  };
@@ -148,7 +149,11 @@ export const quickInsertPlugin = ({
148
149
  return null;
149
150
  }
150
151
  if (options !== null && options !== void 0 && options.enableElementBrowser) {
151
- return /*#__PURE__*/React.createElement(ModalElementBrowser, {
152
+ return isExperimentEnabled('platform_editor_slash_command') && api !== null && api !== void 0 && api.uiControlRegistry ? /*#__PURE__*/React.createElement(RegistryElementBrowserContainer, {
153
+ editorView: editorView,
154
+ helpUrl: options === null || options === void 0 ? void 0 : options.elementBrowserHelpUrl,
155
+ pluginInjectionAPI: api
156
+ }) : /*#__PURE__*/React.createElement(ModalElementBrowser, {
152
157
  editorView: editorView,
153
158
  helpUrl: options === null || options === void 0 ? void 0 : options.elementBrowserHelpUrl,
154
159
  pluginInjectionAPI: api
@@ -0,0 +1,2 @@
1
+ ._zulp1ejb{gap:var(--ds-space-300,24px)}._1e0c11p5{display:grid}
2
+ ._yv0eo9bh{grid-template-columns:minmax(0,1fr) minmax(0,3fr)}
@@ -0,0 +1,147 @@
1
+ /* RegistryElementBrowser.tsx generated by @compiled/babel-plugin v2.0.0 */
2
+ import "./RegistryElementBrowser.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { useIntl } from 'react-intl';
6
+ import Heading from '@atlaskit/heading/heading';
7
+ import { MENU, RECOMMENDED_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
8
+ import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
9
+ import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
10
+ import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTransition } from '@atlaskit/modal-dialog';
11
+ import { createRegistryElementBrowserModel, getInitialRegistryElementBrowserSection, getRegistryElementBrowserItems } from './model';
12
+ import { RegistryElementBrowserCategories } from './RegistryElementBrowserCategories';
13
+ import { RegistryElementBrowserFooter } from './RegistryElementBrowserFooter';
14
+ import { RegistryElementBrowserSearchResults } from './RegistryElementBrowserSearchResults';
15
+ const browserLayoutStyles = null;
16
+ const resultsId = 'registry-element-browser-results';
17
+ export const RegistryElementBrowser = ({
18
+ components,
19
+ emptyStateHandler,
20
+ defaultSection,
21
+ helpUrl,
22
+ editorView,
23
+ isOffline,
24
+ isOpen,
25
+ onClearSelection,
26
+ onClose,
27
+ onCloseComplete,
28
+ onConfirmInsert,
29
+ onSelect
30
+ }) => {
31
+ const {
32
+ formatMessage
33
+ } = useIntl();
34
+ const model = useMemo(() => createRegistryElementBrowserModel(components, {
35
+ footerKey: getMenuFooterSectionKey(MENU.key),
36
+ overflowKeys: new Set(components.filter(component => component.type === 'menu-section').map(component => getSectionOverflowItemKey(component.key))),
37
+ recommendedSectionKey: RECOMMENDED_SECTION.key,
38
+ rootKey: MENU.key
39
+ }), [components]);
40
+ const [query, setQuery] = useState('');
41
+ const [section, setSection] = useState(() => getInitialRegistryElementBrowserSection(model, defaultSection));
42
+ const [selectedKey, setSelectedKey] = useState();
43
+ const wasOpen = useRef(false);
44
+ const previousIsOffline = useRef(isOffline);
45
+ useEffect(() => {
46
+ if (isOpen && !wasOpen.current) {
47
+ setQuery('');
48
+ setSection(getInitialRegistryElementBrowserSection(model, defaultSection));
49
+ // This clears local visual state and the parent-held insertion handler together.
50
+ // eslint-disable-next-line @atlassian/perf-linting/no-chain-state-updates
51
+ setSelectedKey(undefined);
52
+ onClearSelection();
53
+ }
54
+ wasOpen.current = isOpen;
55
+ }, [defaultSection, isOpen, model, onClearSelection]);
56
+ const items = useMemo(() => getRegistryElementBrowserItems({
57
+ formatMessage,
58
+ model,
59
+ query,
60
+ section: query ? undefined : section
61
+ }), [formatMessage, model, query, section]);
62
+ useEffect(() => {
63
+ if (previousIsOffline.current !== isOffline) {
64
+ setSelectedKey(undefined);
65
+ onClearSelection();
66
+ }
67
+ previousIsOffline.current = isOffline;
68
+ }, [isOffline, onClearSelection]);
69
+ const onSearchChange = useCallback(event => {
70
+ setQuery(event.currentTarget.value);
71
+ setSection(undefined);
72
+ setSelectedKey(undefined);
73
+ onClearSelection();
74
+ }, [onClearSelection]);
75
+ const onSectionClick = useCallback(event => {
76
+ setQuery('');
77
+ setSection(event.currentTarget.dataset.section || undefined);
78
+ setSelectedKey(undefined);
79
+ onClearSelection();
80
+ }, [onClearSelection]);
81
+ const onRegistrySelect = useCallback((key, handler) => {
82
+ setSelectedKey(key);
83
+ onSelect(handler);
84
+ }, [onSelect]);
85
+ const onKeyDown = useCallback(event => {
86
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
87
+ var _resultCollection$que;
88
+ const resultCollection = event.currentTarget.ownerDocument.getElementById(resultsId);
89
+ const options = Array.from((_resultCollection$que = resultCollection === null || resultCollection === void 0 ? void 0 : resultCollection.querySelectorAll('[role="option"]:not([aria-disabled="true"]):not([disabled])')) !== null && _resultCollection$que !== void 0 ? _resultCollection$que : []);
90
+ const currentIndex = options.findIndex(option => option === event.currentTarget.ownerDocument.activeElement);
91
+ const nextIndex = event.key === 'ArrowDown' ? currentIndex + 1 : currentIndex - 1;
92
+ const nextOption = options.at(nextIndex);
93
+ if (nextOption) {
94
+ event.preventDefault();
95
+ nextOption.focus();
96
+ }
97
+ return;
98
+ }
99
+ if (event.key === 'Escape') {
100
+ event.preventDefault();
101
+ onClose();
102
+ return;
103
+ }
104
+ if (event.key === 'Enter' && selectedKey) {
105
+ event.preventDefault();
106
+ onConfirmInsert();
107
+ }
108
+ }, [onClose, onConfirmInsert, selectedKey]);
109
+ return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(Modal, {
110
+ label: formatMessage({
111
+ defaultMessage: 'Insert elements',
112
+ id: 'editor.quick-insert.title'
113
+ }),
114
+ onClose: onClose,
115
+ onCloseComplete: onCloseComplete,
116
+ width: "x-large"
117
+ }, /*#__PURE__*/React.createElement(ModalHeader, null, /*#__PURE__*/React.createElement(Heading, {
118
+ size: "medium"
119
+ }, formatMessage({
120
+ defaultMessage: 'Insert elements',
121
+ id: 'editor.quick-insert.title'
122
+ }))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement("div", {
123
+ className: ax(["_zulp1ejb _1e0c11p5 _yv0eo9bh"])
124
+ }, /*#__PURE__*/React.createElement(RegistryElementBrowserCategories, {
125
+ query: query,
126
+ section: section,
127
+ sections: model.sections,
128
+ onSectionClick: onSectionClick
129
+ }), /*#__PURE__*/React.createElement(RegistryElementBrowserSearchResults, {
130
+ editorView: editorView,
131
+ emptyStateHandler: emptyStateHandler,
132
+ isOffline: isOffline,
133
+ items: items,
134
+ query: query,
135
+ resultsId: resultsId,
136
+ section: section,
137
+ selectedKey: selectedKey,
138
+ onKeyDown: onKeyDown,
139
+ onSearchChange: onSearchChange,
140
+ onSelect: onRegistrySelect
141
+ }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(RegistryElementBrowserFooter, {
142
+ helpUrl: helpUrl,
143
+ isInsertEnabled: Boolean(selectedKey),
144
+ onClose: onClose,
145
+ onConfirmInsert: onConfirmInsert
146
+ }))));
147
+ };
@@ -0,0 +1,2 @@
1
+ ._zulpu2gc{gap:var(--ds-space-100,8px)}._1e0c11p5{display:grid}
2
+ ._yv0e9sye{grid-template-columns:repeat(2,minmax(0,1fr))}
@@ -0,0 +1,55 @@
1
+ /* RegistryElementBrowserCategories.tsx generated by @compiled/babel-plugin v2.0.0 */
2
+ import "./RegistryElementBrowserCategories.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React from 'react';
5
+ import { useIntl } from 'react-intl';
6
+ import Button from '@atlaskit/button/default/button';
7
+ import { BLOCK_TEMPLATES_SECTION, DATA_AND_CHARTS_SECTION, EMBED_SECTION, MEDIA_SECTION, OTHER_SECTION, ROVO_SECTION, STRUCTURE_SECTION, TEXT_FORMATTING_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
8
+ import { messages } from '@atlaskit/editor-common/quick-insert/messages';
9
+ const sectionMessages = {
10
+ [BLOCK_TEMPLATES_SECTION.key]: messages.categoryBlockTemplates,
11
+ [DATA_AND_CHARTS_SECTION.key]: messages.categoryDataAndCharts,
12
+ [EMBED_SECTION.key]: messages.categoryEmbed,
13
+ [MEDIA_SECTION.key]: messages.categoryMedia,
14
+ [OTHER_SECTION.key]: messages.categoryOther,
15
+ [ROVO_SECTION.key]: messages.categoryRovo,
16
+ [STRUCTURE_SECTION.key]: messages.categoryStructure,
17
+ [TEXT_FORMATTING_SECTION.key]: messages.categoryTextFormatting
18
+ };
19
+ const categoryGridStyles = null;
20
+ export const RegistryElementBrowserCategories = ({
21
+ query,
22
+ section,
23
+ sections,
24
+ onSectionClick
25
+ }) => {
26
+ const {
27
+ formatMessage
28
+ } = useIntl();
29
+ const isAllSelected = section === undefined && !query;
30
+ return /*#__PURE__*/React.createElement("div", {
31
+ "aria-label": formatMessage({
32
+ defaultMessage: 'Element categories',
33
+ id: 'editor.quick-insert.categories-label'
34
+ }),
35
+ "data-testid": "registry-element-browser-categories",
36
+ className: ax(["_zulpu2gc _1e0c11p5 _yv0e9sye"])
37
+ }, /*#__PURE__*/React.createElement(Button, {
38
+ appearance: isAllSelected ? 'primary' : 'subtle',
39
+ "aria-pressed": isAllSelected,
40
+ "data-section": "",
41
+ onClick: onSectionClick
42
+ }, formatMessage({
43
+ defaultMessage: 'All',
44
+ id: 'editor.quick-insert.all'
45
+ })), sections.map(entry => {
46
+ var _sectionMessages;
47
+ return /*#__PURE__*/React.createElement(Button, {
48
+ appearance: section === entry.key && !query ? 'primary' : 'subtle',
49
+ "aria-pressed": section === entry.key && !query,
50
+ "data-section": entry.key,
51
+ key: entry.key,
52
+ onClick: onSectionClick
53
+ }, formatMessage((_sectionMessages = sectionMessages[entry.key]) !== null && _sectionMessages !== void 0 ? _sectionMessages : messages.categoryOther));
54
+ }));
55
+ };
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import Button from '@atlaskit/button/default/button';
4
+ import LinkButton from '@atlaskit/button/link';
5
+ export const RegistryElementBrowserFooter = ({
6
+ helpUrl,
7
+ isInsertEnabled,
8
+ onClose,
9
+ onConfirmInsert
10
+ }) => {
11
+ const {
12
+ formatMessage
13
+ } = useIntl();
14
+ return /*#__PURE__*/React.createElement(React.Fragment, null, helpUrl && /*#__PURE__*/React.createElement(LinkButton, {
15
+ appearance: "subtle",
16
+ href: helpUrl,
17
+ target: "_blank"
18
+ }, formatMessage({
19
+ defaultMessage: 'Help',
20
+ id: 'editor.quick-insert.help'
21
+ })), /*#__PURE__*/React.createElement(Button, {
22
+ appearance: "subtle",
23
+ onClick: onClose
24
+ }, formatMessage({
25
+ defaultMessage: 'Close',
26
+ id: 'editor.quick-insert.close'
27
+ })), /*#__PURE__*/React.createElement(Button, {
28
+ appearance: "primary",
29
+ isDisabled: !isInsertEnabled,
30
+ onClick: onConfirmInsert
31
+ }, formatMessage({
32
+ defaultMessage: 'Insert',
33
+ id: 'editor.quick-insert.insert'
34
+ })));
35
+ };
@@ -0,0 +1,2 @@
1
+ ._zulpu2gc{gap:var(--ds-space-100,8px)}._1e0c11p5{display:grid}
2
+ ._yv0e13mt{grid-template-columns:repeat(3,minmax(0,1fr))}
@@ -0,0 +1,112 @@
1
+ /* RegistryElementBrowserSearchResults.tsx generated by @compiled/babel-plugin v2.0.0 */
2
+ import "./RegistryElementBrowserSearchResults.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React, { useMemo } from 'react';
5
+ import { useIntl } from 'react-intl';
6
+ import LinkButton from '@atlaskit/button/link';
7
+ import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
8
+ import { Stack, Text } from '@atlaskit/primitives/compiled';
9
+ import Textfield from '@atlaskit/textfield';
10
+ const resultsGridStyles = null;
11
+ const RegistryElementBrowserItem = ({
12
+ editorView,
13
+ isOffline,
14
+ isSelected,
15
+ item,
16
+ onSelect
17
+ }) => {
18
+ const {
19
+ component: Component,
20
+ key
21
+ } = item.registration;
22
+ const contextValue = useMemo(() => ({
23
+ editorView,
24
+ isOffline,
25
+ item: {
26
+ id: key,
27
+ isSelected
28
+ },
29
+ select: handler => onSelect(key, handler),
30
+ surface: 'element-browser'
31
+ }), [editorView, isOffline, isSelected, key, onSelect]);
32
+ if (!Component) {
33
+ return null;
34
+ }
35
+ return /*#__PURE__*/React.createElement(QuickInsertProvider, {
36
+ value: contextValue
37
+ }, /*#__PURE__*/React.createElement(Component, undefined, null));
38
+ };
39
+ export const RegistryElementBrowserSearchResults = ({
40
+ editorView,
41
+ emptyStateHandler,
42
+ isOffline,
43
+ items,
44
+ query,
45
+ resultsId,
46
+ section,
47
+ selectedKey,
48
+ onKeyDown,
49
+ onSearchChange,
50
+ onSelect
51
+ }) => {
52
+ var _emptyStateHandler;
53
+ const {
54
+ formatMessage
55
+ } = useIntl();
56
+ return /*#__PURE__*/React.createElement(Stack, {
57
+ space: "space.200"
58
+ }, /*#__PURE__*/React.createElement(Textfield, {
59
+ autoFocus: true,
60
+ "aria-controls": resultsId,
61
+ "aria-label": formatMessage({
62
+ defaultMessage: 'Search elements',
63
+ id: 'editor.quick-insert.search'
64
+ }),
65
+ name: "registry-element-browser-search",
66
+ onChange: onSearchChange,
67
+ onKeyDown: onKeyDown,
68
+ value: query
69
+ }), /*#__PURE__*/React.createElement(Text, {
70
+ "aria-live": "polite"
71
+ }, formatMessage({
72
+ defaultMessage: '{count} results',
73
+ id: 'editor.quick-insert.results'
74
+ }, {
75
+ count: items.length
76
+ })), /*#__PURE__*/React.createElement("div", {
77
+ "aria-label": formatMessage({
78
+ defaultMessage: 'Element results',
79
+ id: 'editor.quick-insert.results-label'
80
+ }),
81
+ "data-testid": "registry-element-browser-results",
82
+ id: resultsId,
83
+ onKeyDown: onKeyDown,
84
+ tabIndex: -1,
85
+ role: items.length ? 'listbox' : undefined,
86
+ className: ax(["_zulpu2gc _1e0c11p5 _yv0e13mt"])
87
+ }, items.length ? items.map(item => /*#__PURE__*/React.createElement(RegistryElementBrowserItem, {
88
+ editorView: editorView,
89
+ isOffline: isOffline,
90
+ isSelected: selectedKey === item.registration.key,
91
+ item: item,
92
+ key: item.registration.key,
93
+ onSelect: onSelect
94
+ })) : (_emptyStateHandler = emptyStateHandler === null || emptyStateHandler === void 0 ? void 0 : emptyStateHandler({
95
+ mode: 'full',
96
+ searchTerm: query,
97
+ selectedCategory: section
98
+ })) !== null && _emptyStateHandler !== void 0 ? _emptyStateHandler : /*#__PURE__*/React.createElement(Stack, {
99
+ alignInline: "center",
100
+ space: "space.100"
101
+ }, /*#__PURE__*/React.createElement(Text, null, formatMessage({
102
+ defaultMessage: 'Nothing matches your search',
103
+ id: 'editor.quick-insert.empty'
104
+ })), /*#__PURE__*/React.createElement(LinkButton, {
105
+ appearance: "primary",
106
+ href: "https://marketplace.atlassian.com/search?category=Macros&hosting=cloud&product=confluence",
107
+ target: "_blank"
108
+ }, formatMessage({
109
+ defaultMessage: 'Explore Atlassian Marketplace',
110
+ id: 'editor.quick-insert.explore-marketplace'
111
+ })))));
112
+ };
@@ -0,0 +1,123 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { isOfflineMode } from '@atlaskit/editor-common/connectivity/isOfflineMode';
4
+ import { insertSelectedItem } from '@atlaskit/editor-common/insert';
5
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
6
+ import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
7
+ import { closeElementBrowser } from '../../pm-plugins/commands';
8
+ import { pluginKey } from '../../pm-plugins/plugin-key';
9
+ import { RegistryElementBrowser } from './RegistryElementBrowser';
10
+ export const RegistryElementBrowserContainer = ({
11
+ editorView,
12
+ pluginInjectionAPI,
13
+ helpUrl
14
+ }) => {
15
+ var _pluginKey$getState;
16
+ const {
17
+ emptyStateHandler: currentEmptyStateHandler,
18
+ isElementBrowserOpen,
19
+ mode
20
+ } = useSharedPluginStateWithSelector(pluginInjectionAPI, ['quickInsert', 'connectivity'], state => {
21
+ var _state$quickInsertSta, _state$quickInsertSta2, _state$quickInsertSta3, _state$connectivitySt;
22
+ return {
23
+ isElementBrowserOpen: (_state$quickInsertSta = (_state$quickInsertSta2 = state.quickInsertState) === null || _state$quickInsertSta2 === void 0 ? void 0 : _state$quickInsertSta2.isElementBrowserOpen) !== null && _state$quickInsertSta !== void 0 ? _state$quickInsertSta : false,
24
+ emptyStateHandler: (_state$quickInsertSta3 = state.quickInsertState) === null || _state$quickInsertSta3 === void 0 ? void 0 : _state$quickInsertSta3.emptyStateHandler,
25
+ mode: (_state$connectivitySt = state.connectivityState) === null || _state$connectivitySt === void 0 ? void 0 : _state$connectivitySt.mode
26
+ };
27
+ });
28
+ const [snapshot, setSnapshot] = useState([]);
29
+ const [emptyStateHandler, setEmptyStateHandler] = useState();
30
+ const wasOpen = useRef(false);
31
+ const selectionHandler = useRef(undefined);
32
+ const isInsertConfirmed = useRef(false);
33
+ const lifecycleOpen = useRef(false);
34
+ const fireLifecycleEvent = useCallback(action => {
35
+ var _pluginInjectionAPI$a;
36
+ pluginInjectionAPI === null || pluginInjectionAPI === void 0 ? void 0 : (_pluginInjectionAPI$a = pluginInjectionAPI.analytics) === null || _pluginInjectionAPI$a === void 0 ? void 0 : _pluginInjectionAPI$a.actions.fireAnalyticsEvent({
37
+ action,
38
+ actionSubject: ACTION_SUBJECT.ELEMENT_BROWSER,
39
+ attributes: {
40
+ mode: 'full'
41
+ },
42
+ eventType: EVENT_TYPE.UI
43
+ });
44
+ }, [pluginInjectionAPI]);
45
+ useEffect(() => {
46
+ if (isElementBrowserOpen && !wasOpen.current) {
47
+ var _pluginInjectionAPI$u, _pluginInjectionAPI$u2;
48
+ setSnapshot((_pluginInjectionAPI$u = pluginInjectionAPI === null || pluginInjectionAPI === void 0 ? void 0 : (_pluginInjectionAPI$u2 = pluginInjectionAPI.uiControlRegistry) === null || _pluginInjectionAPI$u2 === void 0 ? void 0 : _pluginInjectionAPI$u2.actions.getComponents(MENU.key)) !== null && _pluginInjectionAPI$u !== void 0 ? _pluginInjectionAPI$u : []);
49
+ selectionHandler.current = undefined;
50
+ setEmptyStateHandler(() => currentEmptyStateHandler);
51
+ isInsertConfirmed.current = false;
52
+ lifecycleOpen.current = true;
53
+ fireLifecycleEvent(ACTION.OPENED);
54
+ } else if (!isElementBrowserOpen && wasOpen.current && lifecycleOpen.current) {
55
+ lifecycleOpen.current = false;
56
+ fireLifecycleEvent(ACTION.CLOSED);
57
+ }
58
+ wasOpen.current = isElementBrowserOpen;
59
+ }, [currentEmptyStateHandler, fireLifecycleEvent, isElementBrowserOpen, pluginInjectionAPI]);
60
+ useEffect(() => () => {
61
+ if (lifecycleOpen.current) {
62
+ lifecycleOpen.current = false;
63
+ fireLifecycleEvent(ACTION.CLOSED);
64
+ }
65
+ }, [fireLifecycleEvent]);
66
+ const focusInEditor = useCallback(() => {
67
+ if (!editorView.hasFocus()) {
68
+ editorView.focus();
69
+ }
70
+ }, [editorView]);
71
+ const onClose = useCallback(() => {
72
+ if (!isInsertConfirmed.current) {
73
+ selectionHandler.current = undefined;
74
+ }
75
+ closeElementBrowser()(editorView.state, editorView.dispatch);
76
+ focusInEditor();
77
+ }, [editorView, focusInEditor]);
78
+ const onCloseComplete = useCallback(() => {
79
+ const handler = isInsertConfirmed.current ? selectionHandler.current : undefined;
80
+ selectionHandler.current = undefined;
81
+ isInsertConfirmed.current = false;
82
+ focusInEditor();
83
+ if (!handler) {
84
+ return;
85
+ }
86
+ const insert = (maybeNode, options = {}) => insertSelectedItem(maybeNode, options)(editorView.state, editorView.state.tr, editorView.state.selection.head);
87
+ const transaction = handler({
88
+ insert,
89
+ source: INPUT_METHOD.ELEMENT_BROWSER
90
+ });
91
+ if (transaction) {
92
+ editorView.dispatch(transaction);
93
+ }
94
+ }, [editorView, focusInEditor]);
95
+ const onSelect = useCallback(handler => {
96
+ selectionHandler.current = handler;
97
+ }, []);
98
+ const onClearSelection = useCallback(() => {
99
+ selectionHandler.current = undefined;
100
+ isInsertConfirmed.current = false;
101
+ }, []);
102
+ const onConfirmInsert = useCallback(() => {
103
+ if (!selectionHandler.current) {
104
+ return;
105
+ }
106
+ isInsertConfirmed.current = true;
107
+ onClose();
108
+ }, [onClose]);
109
+ return /*#__PURE__*/React.createElement(RegistryElementBrowser, {
110
+ components: snapshot,
111
+ emptyStateHandler: emptyStateHandler,
112
+ helpUrl: helpUrl,
113
+ defaultSection: (_pluginKey$getState = pluginKey.getState(editorView.state)) === null || _pluginKey$getState === void 0 ? void 0 : _pluginKey$getState.elementBrowserInitialCategory,
114
+ editorView: editorView,
115
+ isOffline: isOfflineMode(mode),
116
+ isOpen: isElementBrowserOpen,
117
+ onClearSelection: onClearSelection,
118
+ onClose: onClose,
119
+ onCloseComplete: onCloseComplete,
120
+ onConfirmInsert: onConfirmInsert,
121
+ onSelect: onSelect
122
+ });
123
+ };