@atlaskit/editor-plugin-selection-extension 2.0.0 → 2.1.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/pm-plugins/main.js +39 -0
  3. package/dist/cjs/selectionExtensionPlugin.js +73 -15
  4. package/dist/cjs/types/index.js +5 -0
  5. package/dist/cjs/ui/extension/SelectionExtensionComponentWrapper.js +69 -0
  6. package/dist/cjs/ui/getBoundingBoxFromSelection.js +35 -0
  7. package/dist/cjs/ui/toolbar/SelectionExtensionDropdownMenu.js +18 -3
  8. package/dist/cjs/ui/toolbar/SelectionExtensionDropdownMenuButton.js +1 -0
  9. package/dist/cjs/ui/toolbar/SelectionExtensionItems.js +13 -1
  10. package/dist/es2019/pm-plugins/main.js +31 -0
  11. package/dist/es2019/selectionExtensionPlugin.js +63 -12
  12. package/dist/es2019/types/index.js +1 -0
  13. package/dist/es2019/ui/extension/SelectionExtensionComponentWrapper.js +62 -0
  14. package/dist/es2019/ui/getBoundingBoxFromSelection.js +29 -0
  15. package/dist/es2019/ui/toolbar/SelectionExtensionDropdownMenu.js +18 -3
  16. package/dist/es2019/ui/toolbar/SelectionExtensionDropdownMenuButton.js +1 -0
  17. package/dist/es2019/ui/toolbar/SelectionExtensionItems.js +13 -1
  18. package/dist/esm/pm-plugins/main.js +32 -0
  19. package/dist/esm/selectionExtensionPlugin.js +73 -15
  20. package/dist/esm/types/index.js +1 -0
  21. package/dist/esm/ui/extension/SelectionExtensionComponentWrapper.js +60 -0
  22. package/dist/esm/ui/getBoundingBoxFromSelection.js +29 -0
  23. package/dist/esm/ui/toolbar/SelectionExtensionDropdownMenu.js +18 -3
  24. package/dist/esm/ui/toolbar/SelectionExtensionDropdownMenuButton.js +1 -0
  25. package/dist/esm/ui/toolbar/SelectionExtensionItems.js +13 -1
  26. package/dist/types/index.d.ts +1 -0
  27. package/dist/types/pm-plugins/main.d.ts +7 -0
  28. package/dist/types/selectionExtensionPluginType.d.ts +11 -23
  29. package/dist/types/types/index.d.ts +51 -0
  30. package/dist/types/ui/extension/SelectionExtensionComponentWrapper.d.ts +12 -0
  31. package/dist/types/ui/getBoundingBoxFromSelection.d.ts +11 -0
  32. package/dist/types/ui/toolbar/SelectionExtensionDropdownMenu.d.ts +5 -1
  33. package/dist/types/ui/toolbar/SelectionExtensionItems.d.ts +3 -2
  34. package/dist/types-ts4.5/index.d.ts +1 -0
  35. package/dist/types-ts4.5/pm-plugins/main.d.ts +7 -0
  36. package/dist/types-ts4.5/selectionExtensionPluginType.d.ts +11 -23
  37. package/dist/types-ts4.5/types/index.d.ts +51 -0
  38. package/dist/types-ts4.5/ui/extension/SelectionExtensionComponentWrapper.d.ts +12 -0
  39. package/dist/types-ts4.5/ui/getBoundingBoxFromSelection.d.ts +11 -0
  40. package/dist/types-ts4.5/ui/toolbar/SelectionExtensionDropdownMenu.d.ts +5 -1
  41. package/dist/types-ts4.5/ui/toolbar/SelectionExtensionItems.d.ts +3 -2
  42. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atlaskit/editor-plugin-selection-extension
2
2
 
3
+ ## 2.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#119729](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/119729)
8
+ [`beae885f06562`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/beae885f06562) -
9
+ ED-26710 add analytics events to selection extension plugin
10
+
11
+ ## 2.1.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#115116](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/115116)
16
+ [`344eb36211daa`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/344eb36211daa) -
17
+ [ux] ED-26394 support component rendering in editor selection plugin
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies
22
+
3
23
  ## 2.0.0
4
24
 
5
25
  ### Major Changes
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.selectionExtensionPluginKey = exports.createPlugin = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
10
+ var _state = require("@atlaskit/editor-prosemirror/state");
11
+ 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; }
12
+ 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; }
13
+ var selectionExtensionPluginKey = exports.selectionExtensionPluginKey = new _state.PluginKey('selectionExtensionPlugin');
14
+ var createPlugin = exports.createPlugin = function createPlugin() {
15
+ return new _safePlugin.SafePlugin({
16
+ key: selectionExtensionPluginKey,
17
+ state: {
18
+ init: function init() {
19
+ return {
20
+ activeExtension: undefined
21
+ };
22
+ },
23
+ apply: function apply(tr, pluginState) {
24
+ var meta = tr.getMeta(selectionExtensionPluginKey);
25
+ switch (meta === null || meta === void 0 ? void 0 : meta.type) {
26
+ case 'set-active-extension':
27
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
28
+ activeExtension: meta.extension
29
+ });
30
+ case 'clear-active-extension':
31
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
32
+ activeExtension: undefined
33
+ });
34
+ }
35
+ return pluginState;
36
+ }
37
+ }
38
+ });
39
+ };
@@ -6,12 +6,49 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.selectionExtensionPlugin = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
+ var _main = require("./pm-plugins/main");
10
+ var _SelectionExtensionComponentWrapper = require("./ui/extension/SelectionExtensionComponentWrapper");
11
+ var _getBoundingBoxFromSelection = require("./ui/getBoundingBoxFromSelection");
9
12
  var _SelectionExtensionItems = require("./ui/toolbar/SelectionExtensionItems");
10
13
  var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selectionExtensionPlugin(_ref) {
11
14
  var api = _ref.api,
12
15
  config = _ref.config;
13
16
  return {
14
17
  name: 'selectionExtension',
18
+ getSharedState: function getSharedState(editorState) {
19
+ if (!editorState) {
20
+ return null;
21
+ }
22
+ return _main.selectionExtensionPluginKey.getState(editorState) || null;
23
+ },
24
+ commands: {
25
+ setActiveExtension: function setActiveExtension(extension) {
26
+ return function (_ref2) {
27
+ var tr = _ref2.tr;
28
+ return tr.setMeta(_main.selectionExtensionPluginKey, {
29
+ type: 'set-active-extension',
30
+ extension: extension
31
+ });
32
+ };
33
+ },
34
+ clearActiveExtension: function clearActiveExtension() {
35
+ return function (_ref3) {
36
+ var tr = _ref3.tr;
37
+ return tr.setMeta(_main.selectionExtensionPluginKey, {
38
+ type: 'clear-active-extension'
39
+ });
40
+ };
41
+ }
42
+ },
43
+ contentComponent: function contentComponent(_ref4) {
44
+ var _api$analytics;
45
+ var editorView = _ref4.editorView;
46
+ return /*#__PURE__*/_react.default.createElement(_SelectionExtensionComponentWrapper.SelectionExtensionComponentWrapper, {
47
+ editorView: editorView,
48
+ api: api,
49
+ editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions
50
+ });
51
+ },
15
52
  pluginsOptions: {
16
53
  selectionToolbar: function selectionToolbar(state) {
17
54
  var _api$editorViewMode;
@@ -52,20 +89,33 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
52
89
  return;
53
90
  }
54
91
  }
55
- var handleOnExtensionClick = function handleOnExtensionClick(extension) {
56
- var selection = state.selection;
57
- var from = selection.from,
58
- to = selection.to;
59
- var text = state.doc.textBetween(from, to, '\n');
92
+ var handleOnExtensionClick = function handleOnExtensionClick(view) {
93
+ return function (extension) {
94
+ var currentSelection = state.selection;
95
+ var from = currentSelection.from,
96
+ to = currentSelection.to;
97
+ var text = state.doc.textBetween(from, to, '\n');
98
+ var coords = (0, _getBoundingBoxFromSelection.getBoundingBoxFromSelection)(view, from, to);
99
+ var selection = {
100
+ text: text,
101
+ selection: {
102
+ from: from,
103
+ to: to
104
+ },
105
+ coords: coords
106
+ };
60
107
 
61
- // TODO: Probably some validator logic here
62
- extension.onClick({
63
- text: text,
64
- selection: {
65
- from: from,
66
- to: to
108
+ // Render component here
109
+ if (extension.component) {
110
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 ? void 0 : api.selectionExtension.commands.setActiveExtension({
111
+ extension: extension,
112
+ selection: selection
113
+ }));
67
114
  }
68
- });
115
+ if (extension.onClick) {
116
+ extension.onClick(selection);
117
+ }
118
+ };
69
119
  };
70
120
 
71
121
  /**
@@ -75,16 +125,16 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
75
125
  type: 'custom',
76
126
  supportsViewMode: true,
77
127
  render: function render(view) {
78
- var _api$analytics;
128
+ var _api$analytics2;
79
129
  if (!view) {
80
130
  return;
81
131
  }
82
132
  return /*#__PURE__*/_react.default.createElement(_SelectionExtensionItems.SelectionExtensionItems, {
83
133
  api: api,
84
134
  editorView: view,
85
- editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions,
135
+ editorAnalyticsAPI: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions,
86
136
  extensions: extensions,
87
- onExtensionClick: handleOnExtensionClick
137
+ onExtensionClick: handleOnExtensionClick(view)
88
138
  });
89
139
  },
90
140
  fallback: []
@@ -95,6 +145,14 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
95
145
  rank: -6
96
146
  };
97
147
  }
148
+ },
149
+ pmPlugins: function pmPlugins() {
150
+ return [{
151
+ name: 'selectionExtension',
152
+ plugin: function plugin() {
153
+ return (0, _main.createPlugin)();
154
+ }
155
+ }];
98
156
  }
99
157
  };
100
158
  };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SelectionExtensionComponentWrapper = void 0;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ var _analytics = require("@atlaskit/editor-common/analytics");
10
+ var _hooks = require("@atlaskit/editor-common/hooks");
11
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
12
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
+ var SelectionExtensionComponentWrapper = exports.SelectionExtensionComponentWrapper = function SelectionExtensionComponentWrapper(_ref) {
14
+ var _selectionExtensionSt4;
15
+ var api = _ref.api,
16
+ editorAnalyticsAPI = _ref.editorAnalyticsAPI;
17
+ var componentRef = (0, _react.useRef)();
18
+ var _useSharedPluginState = (0, _hooks.useSharedPluginState)(api, ['selectionExtension', 'editorViewMode']),
19
+ selectionExtensionState = _useSharedPluginState.selectionExtensionState,
20
+ editorViewModeState = _useSharedPluginState.editorViewModeState;
21
+
22
+ // Closed from active extension
23
+ var handleOnClose = (0, _react.useCallback)(function () {
24
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 ? void 0 : api.selectionExtension.commands.clearActiveExtension());
25
+ // Clears reference to active component
26
+ componentRef.current = undefined;
27
+ if (editorAnalyticsAPI) {
28
+ editorAnalyticsAPI.fireAnalyticsEvent({
29
+ action: _analytics.ACTION.CLOSED,
30
+ actionSubject: _analytics.ACTION_SUBJECT.EDITOR_PLUGIN_SELECTION_EXTENSION,
31
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_COMPONENT,
32
+ eventType: _analytics.EVENT_TYPE.TRACK
33
+ });
34
+ }
35
+ }, [editorAnalyticsAPI, api]);
36
+
37
+ // Closed from editor page mode change
38
+ (0, _react.useEffect)(function () {
39
+ if (componentRef.current !== undefined) {
40
+ handleOnClose();
41
+ }
42
+ }, [handleOnClose, editorViewModeState]);
43
+
44
+ // Viewed analytics event for component mount
45
+ (0, _react.useEffect)(function () {
46
+ var _selectionExtensionSt, _selectionExtensionSt2;
47
+ if (componentRef.current !== (selectionExtensionState === null || selectionExtensionState === void 0 || (_selectionExtensionSt = selectionExtensionState.activeExtension) === null || _selectionExtensionSt === void 0 ? void 0 : _selectionExtensionSt.extension.component) && (selectionExtensionState === null || selectionExtensionState === void 0 || (_selectionExtensionSt2 = selectionExtensionState.activeExtension) === null || _selectionExtensionSt2 === void 0 ? void 0 : _selectionExtensionSt2.extension.component) !== undefined) {
48
+ var _selectionExtensionSt3;
49
+ if (editorAnalyticsAPI) {
50
+ editorAnalyticsAPI.fireAnalyticsEvent({
51
+ action: _analytics.ACTION.VIEWED,
52
+ actionSubject: _analytics.ACTION_SUBJECT.EDITOR_PLUGIN_SELECTION_EXTENSION,
53
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_COMPONENT,
54
+ eventType: _analytics.EVENT_TYPE.TRACK
55
+ });
56
+ }
57
+ // Sets reference to active component
58
+ componentRef.current = selectionExtensionState === null || selectionExtensionState === void 0 || (_selectionExtensionSt3 = selectionExtensionState.activeExtension) === null || _selectionExtensionSt3 === void 0 ? void 0 : _selectionExtensionSt3.extension.component;
59
+ }
60
+ }, [selectionExtensionState, editorAnalyticsAPI]);
61
+ if (!(selectionExtensionState !== null && selectionExtensionState !== void 0 && (_selectionExtensionSt4 = selectionExtensionState.activeExtension) !== null && _selectionExtensionSt4 !== void 0 && _selectionExtensionSt4.extension.component)) {
62
+ return null;
63
+ }
64
+ var ExtensionComponent = selectionExtensionState.activeExtension.extension.component;
65
+ return /*#__PURE__*/_react.default.createElement(ExtensionComponent, {
66
+ closeExtension: handleOnClose,
67
+ selection: selectionExtensionState.activeExtension.selection
68
+ });
69
+ };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getBoundingBoxFromSelection = void 0;
7
+ /**
8
+ * Calculates the bounding box coordinates of a text selection within an editor view.
9
+ *
10
+ * @param view - The editor view instance.
11
+ * @param from - The starting position of the selection.
12
+ * @param to - The ending position of the selection.
13
+ * @returns An object containing the top, left, bottom, and right coordinates of the bounding box.
14
+ */
15
+ var getBoundingBoxFromSelection = exports.getBoundingBoxFromSelection = function getBoundingBoxFromSelection(view, from, to) {
16
+ var top = Infinity,
17
+ left = Infinity,
18
+ bottom = -Infinity,
19
+ right = -Infinity;
20
+
21
+ // initial version
22
+ for (var pos = from; pos <= to; pos++) {
23
+ var coords = view.coordsAtPos(pos);
24
+ top = Math.min(top, coords.top);
25
+ left = Math.min(left, coords.left);
26
+ bottom = Math.max(bottom, coords.bottom);
27
+ right = Math.max(right, coords.right);
28
+ }
29
+ return {
30
+ top: top,
31
+ left: left,
32
+ bottom: bottom,
33
+ right: right
34
+ };
35
+ };
@@ -9,13 +9,15 @@ exports.SelectionExtensionDropdownMenu = void 0;
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var _reactIntlNext = require("react-intl-next");
12
+ var _analytics = require("@atlaskit/editor-common/analytics");
12
13
  var _uiMenu = require("@atlaskit/editor-common/ui-menu");
13
14
  var _SelectionExtensionDropdownMenuButton = require("./SelectionExtensionDropdownMenuButton");
14
15
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
15
16
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
17
  var SelectionExtensionDropdownMenuComponent = /*#__PURE__*/_react.default.memo(function (_ref) {
17
18
  var items = _ref.items,
18
- onItemActivated = _ref.onItemActivated;
19
+ onItemActivated = _ref.onItemActivated,
20
+ editorAnalyticsAPI = _ref.editorAnalyticsAPI;
19
21
  var _useState = (0, _react.useState)(false),
20
22
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
21
23
  isMenuOpen = _useState2[0],
@@ -31,9 +33,22 @@ var SelectionExtensionDropdownMenuComponent = /*#__PURE__*/_react.default.memo(f
31
33
  onItemActivated: onItemActivated,
32
34
  "data-testid": "selection-extension-dropdown-menu"
33
35
  }, /*#__PURE__*/_react.default.createElement(_SelectionExtensionDropdownMenuButton.SelectionExtensionDropdownMenuButton, {
34
- "data-testid": "selection-extension-dropdown-button",
35
36
  onClick: function onClick() {
36
- return setIsMenuOpen(!isMenuOpen);
37
+ return setIsMenuOpen(function (prevIsMenuOpen) {
38
+ var nextIsMenuOpen = !prevIsMenuOpen;
39
+ if (editorAnalyticsAPI) {
40
+ editorAnalyticsAPI.fireAnalyticsEvent({
41
+ action: _analytics.ACTION.CLICKED,
42
+ actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
43
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_DROPDOWN,
44
+ eventType: _analytics.EVENT_TYPE.TRACK,
45
+ attributes: {
46
+ toggle: nextIsMenuOpen ? _analytics.ACTION.OPENED : _analytics.ACTION.CLOSED
47
+ }
48
+ });
49
+ }
50
+ return nextIsMenuOpen;
51
+ });
37
52
  }
38
53
  }));
39
54
  });
@@ -12,6 +12,7 @@ var _apps = _interopRequireDefault(require("@atlaskit/icon/core/apps"));
12
12
  var SelectionExtensionDropdownMenuButtonComponent = function SelectionExtensionDropdownMenuButtonComponent(_ref) {
13
13
  var onClick = _ref.onClick;
14
14
  return /*#__PURE__*/_react.default.createElement(_uiMenu.ToolbarButton, {
15
+ testId: "selection-extension-dropdown-button",
15
16
  onClick: onClick
16
17
  }, /*#__PURE__*/_react.default.createElement(_apps.default, {
17
18
  label: "selection extension dropdown"
@@ -10,6 +10,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var _reactIntlNext = require("react-intl-next");
12
12
  var _uuid = require("uuid");
13
+ var _analytics = require("@atlaskit/editor-common/analytics");
13
14
  var _SelectionExtensionDropdownMenu = require("./SelectionExtensionDropdownMenu");
14
15
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
15
16
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -21,6 +22,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
21
22
  var transformExtensionsToItems = function transformExtensionsToItems(extensions) {
22
23
  var extensionToItems = extensions.map(function (extension) {
23
24
  return {
25
+ key: extension.id,
24
26
  content: extension.name,
25
27
  value: {
26
28
  name: extension.id
@@ -33,7 +35,8 @@ var transformExtensionsToItems = function transformExtensionsToItems(extensions)
33
35
  };
34
36
  var SelectionExtensionItemsComponent = exports.SelectionExtensionItemsComponent = function SelectionExtensionItemsComponent(_ref) {
35
37
  var extensions = _ref.extensions,
36
- onExtensionClick = _ref.onExtensionClick;
38
+ onExtensionClick = _ref.onExtensionClick,
39
+ editorAnalyticsAPI = _ref.editorAnalyticsAPI;
37
40
  var extensionsWithIdentifier = (0, _react.useMemo)(function () {
38
41
  return extensions.map(function (extension) {
39
42
  return _objectSpread(_objectSpread({}, extension), {}, {
@@ -51,9 +54,18 @@ var SelectionExtensionItemsComponent = exports.SelectionExtensionItemsComponent
51
54
  });
52
55
  if (extension) {
53
56
  onExtensionClick(extension);
57
+ if (editorAnalyticsAPI) {
58
+ editorAnalyticsAPI.fireAnalyticsEvent({
59
+ action: _analytics.ACTION.CLICKED,
60
+ actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
61
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_ITEM,
62
+ eventType: _analytics.EVENT_TYPE.TRACK
63
+ });
64
+ }
54
65
  }
55
66
  };
56
67
  return /*#__PURE__*/_react.default.createElement(_SelectionExtensionDropdownMenu.SelectionExtensionDropdownMenu, {
68
+ editorAnalyticsAPI: editorAnalyticsAPI,
57
69
  items: items,
58
70
  onItemActivated: handleOnItemActivated
59
71
  });
@@ -0,0 +1,31 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ export const selectionExtensionPluginKey = new PluginKey('selectionExtensionPlugin');
4
+ export const createPlugin = () => {
5
+ return new SafePlugin({
6
+ key: selectionExtensionPluginKey,
7
+ state: {
8
+ init: () => {
9
+ return {
10
+ activeExtension: undefined
11
+ };
12
+ },
13
+ apply: (tr, pluginState) => {
14
+ const meta = tr.getMeta(selectionExtensionPluginKey);
15
+ switch (meta === null || meta === void 0 ? void 0 : meta.type) {
16
+ case 'set-active-extension':
17
+ return {
18
+ ...pluginState,
19
+ activeExtension: meta.extension
20
+ };
21
+ case 'clear-active-extension':
22
+ return {
23
+ ...pluginState,
24
+ activeExtension: undefined
25
+ };
26
+ }
27
+ return pluginState;
28
+ }
29
+ }
30
+ });
31
+ };
@@ -1,4 +1,7 @@
1
1
  import React from 'react';
2
+ import { selectionExtensionPluginKey, createPlugin } from './pm-plugins/main';
3
+ import { SelectionExtensionComponentWrapper } from './ui/extension/SelectionExtensionComponentWrapper';
4
+ import { getBoundingBoxFromSelection } from './ui/getBoundingBoxFromSelection';
2
5
  import { SelectionExtensionItems } from './ui/toolbar/SelectionExtensionItems';
3
6
  export const selectionExtensionPlugin = ({
4
7
  api,
@@ -6,6 +9,39 @@ export const selectionExtensionPlugin = ({
6
9
  }) => {
7
10
  return {
8
11
  name: 'selectionExtension',
12
+ getSharedState(editorState) {
13
+ if (!editorState) {
14
+ return null;
15
+ }
16
+ return selectionExtensionPluginKey.getState(editorState) || null;
17
+ },
18
+ commands: {
19
+ setActiveExtension: extension => ({
20
+ tr
21
+ }) => {
22
+ return tr.setMeta(selectionExtensionPluginKey, {
23
+ type: 'set-active-extension',
24
+ extension
25
+ });
26
+ },
27
+ clearActiveExtension: () => ({
28
+ tr
29
+ }) => {
30
+ return tr.setMeta(selectionExtensionPluginKey, {
31
+ type: 'clear-active-extension'
32
+ });
33
+ }
34
+ },
35
+ contentComponent: ({
36
+ editorView
37
+ }) => {
38
+ var _api$analytics;
39
+ return /*#__PURE__*/React.createElement(SelectionExtensionComponentWrapper, {
40
+ editorView: editorView,
41
+ api: api,
42
+ editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions
43
+ });
44
+ },
9
45
  pluginsOptions: {
10
46
  selectionToolbar: state => {
11
47
  var _api$editorViewMode, _api$editorViewMode$s;
@@ -48,24 +84,35 @@ export const selectionExtensionPlugin = ({
48
84
  return;
49
85
  }
50
86
  }
51
- const handleOnExtensionClick = extension => {
87
+ const handleOnExtensionClick = view => extension => {
52
88
  const {
53
- selection
89
+ selection: currentSelection
54
90
  } = state;
55
91
  const {
56
92
  from,
57
93
  to
58
- } = selection;
94
+ } = currentSelection;
59
95
  const text = state.doc.textBetween(from, to, '\n');
60
-
61
- // TODO: Probably some validator logic here
62
- extension.onClick({
96
+ const coords = getBoundingBoxFromSelection(view, from, to);
97
+ const selection = {
63
98
  text,
64
99
  selection: {
65
100
  from,
66
101
  to
67
- }
68
- });
102
+ },
103
+ coords
104
+ };
105
+
106
+ // Render component here
107
+ if (extension.component) {
108
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.selectionExtension.commands.setActiveExtension({
109
+ extension,
110
+ selection
111
+ }));
112
+ }
113
+ if (extension.onClick) {
114
+ extension.onClick(selection);
115
+ }
69
116
  };
70
117
 
71
118
  /**
@@ -75,16 +122,16 @@ export const selectionExtensionPlugin = ({
75
122
  type: 'custom',
76
123
  supportsViewMode: true,
77
124
  render: view => {
78
- var _api$analytics;
125
+ var _api$analytics2;
79
126
  if (!view) {
80
127
  return;
81
128
  }
82
129
  return /*#__PURE__*/React.createElement(SelectionExtensionItems, {
83
130
  api: api,
84
131
  editorView: view,
85
- editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions,
132
+ editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions,
86
133
  extensions: extensions,
87
- onExtensionClick: handleOnExtensionClick
134
+ onExtensionClick: handleOnExtensionClick(view)
88
135
  });
89
136
  },
90
137
  fallback: []
@@ -95,6 +142,10 @@ export const selectionExtensionPlugin = ({
95
142
  rank: -6
96
143
  };
97
144
  }
98
- }
145
+ },
146
+ pmPlugins: () => [{
147
+ name: 'selectionExtension',
148
+ plugin: () => createPlugin()
149
+ }]
99
150
  };
100
151
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import React, { useCallback, useEffect, useRef } from 'react';
2
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
3
+ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
4
+ export const SelectionExtensionComponentWrapper = ({
5
+ api,
6
+ editorAnalyticsAPI
7
+ }) => {
8
+ var _selectionExtensionSt4;
9
+ const componentRef = useRef();
10
+ const {
11
+ selectionExtensionState,
12
+ editorViewModeState
13
+ } = useSharedPluginState(api, ['selectionExtension', 'editorViewMode']);
14
+
15
+ // Closed from active extension
16
+ const handleOnClose = useCallback(() => {
17
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.selectionExtension.commands.clearActiveExtension());
18
+ // Clears reference to active component
19
+ componentRef.current = undefined;
20
+ if (editorAnalyticsAPI) {
21
+ editorAnalyticsAPI.fireAnalyticsEvent({
22
+ action: ACTION.CLOSED,
23
+ actionSubject: ACTION_SUBJECT.EDITOR_PLUGIN_SELECTION_EXTENSION,
24
+ actionSubjectId: ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_COMPONENT,
25
+ eventType: EVENT_TYPE.TRACK
26
+ });
27
+ }
28
+ }, [editorAnalyticsAPI, api]);
29
+
30
+ // Closed from editor page mode change
31
+ useEffect(() => {
32
+ if (componentRef.current !== undefined) {
33
+ handleOnClose();
34
+ }
35
+ }, [handleOnClose, editorViewModeState]);
36
+
37
+ // Viewed analytics event for component mount
38
+ useEffect(() => {
39
+ var _selectionExtensionSt, _selectionExtensionSt2;
40
+ if (componentRef.current !== (selectionExtensionState === null || selectionExtensionState === void 0 ? void 0 : (_selectionExtensionSt = selectionExtensionState.activeExtension) === null || _selectionExtensionSt === void 0 ? void 0 : _selectionExtensionSt.extension.component) && (selectionExtensionState === null || selectionExtensionState === void 0 ? void 0 : (_selectionExtensionSt2 = selectionExtensionState.activeExtension) === null || _selectionExtensionSt2 === void 0 ? void 0 : _selectionExtensionSt2.extension.component) !== undefined) {
41
+ var _selectionExtensionSt3;
42
+ if (editorAnalyticsAPI) {
43
+ editorAnalyticsAPI.fireAnalyticsEvent({
44
+ action: ACTION.VIEWED,
45
+ actionSubject: ACTION_SUBJECT.EDITOR_PLUGIN_SELECTION_EXTENSION,
46
+ actionSubjectId: ACTION_SUBJECT_ID.EDITOR_PLUGIN_SELECTION_EXTENSION_COMPONENT,
47
+ eventType: EVENT_TYPE.TRACK
48
+ });
49
+ }
50
+ // Sets reference to active component
51
+ componentRef.current = selectionExtensionState === null || selectionExtensionState === void 0 ? void 0 : (_selectionExtensionSt3 = selectionExtensionState.activeExtension) === null || _selectionExtensionSt3 === void 0 ? void 0 : _selectionExtensionSt3.extension.component;
52
+ }
53
+ }, [selectionExtensionState, editorAnalyticsAPI]);
54
+ if (!(selectionExtensionState !== null && selectionExtensionState !== void 0 && (_selectionExtensionSt4 = selectionExtensionState.activeExtension) !== null && _selectionExtensionSt4 !== void 0 && _selectionExtensionSt4.extension.component)) {
55
+ return null;
56
+ }
57
+ const ExtensionComponent = selectionExtensionState.activeExtension.extension.component;
58
+ return /*#__PURE__*/React.createElement(ExtensionComponent, {
59
+ closeExtension: handleOnClose,
60
+ selection: selectionExtensionState.activeExtension.selection
61
+ });
62
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Calculates the bounding box coordinates of a text selection within an editor view.
3
+ *
4
+ * @param view - The editor view instance.
5
+ * @param from - The starting position of the selection.
6
+ * @param to - The ending position of the selection.
7
+ * @returns An object containing the top, left, bottom, and right coordinates of the bounding box.
8
+ */
9
+ export const getBoundingBoxFromSelection = (view, from, to) => {
10
+ let top = Infinity,
11
+ left = Infinity,
12
+ bottom = -Infinity,
13
+ right = -Infinity;
14
+
15
+ // initial version
16
+ for (let pos = from; pos <= to; pos++) {
17
+ const coords = view.coordsAtPos(pos);
18
+ top = Math.min(top, coords.top);
19
+ left = Math.min(left, coords.left);
20
+ bottom = Math.max(bottom, coords.bottom);
21
+ right = Math.max(right, coords.right);
22
+ }
23
+ return {
24
+ top,
25
+ left,
26
+ bottom,
27
+ right
28
+ };
29
+ };