@atlaskit/editor-plugin-toolbar 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/editor-plugin-toolbar
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`e73faa5a52300`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e73faa5a52300) -
8
+ [ux] ED-28735 Fix selection toolbar opening and closing state
9
+
10
+ ### Patch Changes
11
+
12
+ - [`b27824f2875be`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b27824f2875be) -
13
+ [ux] [ED-28821] Add pin button to full page primary toolbar
14
+ - Updated dependencies
15
+
3
16
  ## 0.3.1
4
17
 
5
18
  ### Patch Changes
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.editorToolbarPluginKey = void 0;
7
+ var _state = require("@atlaskit/editor-prosemirror/state");
8
+ var editorToolbarPluginKey = exports.editorToolbarPluginKey = new _state.PluginKey('editorToolbarPluginKey');
@@ -5,10 +5,18 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.toolbarPlugin = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
8
9
  var _react = _interopRequireDefault(require("react"));
10
+ var _bindEventListener = require("bind-event-listener");
11
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
9
12
  var _editorToolbarModel = require("@atlaskit/editor-toolbar-model");
13
+ var _pluginKey = require("./pm-plugins/plugin-key");
14
+ var _consts = require("./ui/consts");
10
15
  var _SelectionToolbar = require("./ui/SelectionToolbar");
11
16
  var _toolbarComponents = require("./ui/toolbar-components");
17
+ var _toolbar = require("./ui/utils/toolbar");
18
+ 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; }
19
+ 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
20
  var toolbarPlugin = exports.toolbarPlugin = function toolbarPlugin(_ref) {
13
21
  var api = _ref.api,
14
22
  _ref$config = _ref.config,
@@ -28,6 +36,81 @@ var toolbarPlugin = exports.toolbarPlugin = function toolbarPlugin(_ref) {
28
36
  return registry.components;
29
37
  }
30
38
  },
39
+ getSharedState: function getSharedState(editorState) {
40
+ if (!editorState) {
41
+ return undefined;
42
+ }
43
+ return _pluginKey.editorToolbarPluginKey.getState(editorState);
44
+ },
45
+ pmPlugins: function pmPlugins() {
46
+ return [{
47
+ name: 'editor-toolbar-selection',
48
+ plugin: function plugin() {
49
+ return new _safePlugin.SafePlugin({
50
+ key: _pluginKey.editorToolbarPluginKey,
51
+ state: {
52
+ init: function init() {
53
+ return {
54
+ shouldShowToolbar: false
55
+ };
56
+ },
57
+ apply: function apply(tr, pluginState) {
58
+ var meta = tr.getMeta(_pluginKey.editorToolbarPluginKey);
59
+ var newPluginState = pluginState;
60
+ if (meta) {
61
+ return _objectSpread(_objectSpread({}, newPluginState), meta);
62
+ }
63
+ return newPluginState;
64
+ }
65
+ },
66
+ view: function view(_view) {
67
+ var unbind = (0, _bindEventListener.bind)(_view.root, {
68
+ type: 'mouseup',
69
+ listener: function listener(ev) {
70
+ var _api$editorViewMode;
71
+ var event = ev;
72
+ var isInToolbar = (0, _toolbar.isEventInContainer)(event, _consts.DEFAULT_POPUP_SELECTORS.toolbarContainer);
73
+ var isInPortal = (0, _toolbar.isEventInContainer)(event, _consts.DEFAULT_POPUP_SELECTORS.portal);
74
+
75
+ // We only want to set selectionStable to true if the editor has focus
76
+ // to prevent the toolbar from showing when the editor is blurred
77
+ // due to a click outside the editor.
78
+ var editorViewModePlugin = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.sharedState.currentState();
79
+ var isViewModeEnabled = (editorViewModePlugin === null || editorViewModePlugin === void 0 ? void 0 : editorViewModePlugin.mode) === 'view';
80
+ _view.dispatch(_view.state.tr.setMeta(_pluginKey.editorToolbarPluginKey, {
81
+ shouldShowToolbar: !isViewModeEnabled ? _view.hasFocus() || isInToolbar || isInPortal : true
82
+ }));
83
+ }
84
+ });
85
+ var unbindEditorViewFocus = (0, _bindEventListener.bind)(_view.dom, {
86
+ type: 'focus',
87
+ listener: function listener() {
88
+ _view.dispatch(_view.state.tr.setMeta(_pluginKey.editorToolbarPluginKey, {
89
+ shouldShowToolbar: true
90
+ }));
91
+ }
92
+ });
93
+ return {
94
+ destroy: function destroy() {
95
+ unbind();
96
+ unbindEditorViewFocus();
97
+ }
98
+ };
99
+ },
100
+ props: {
101
+ handleDOMEvents: {
102
+ mousedown: function mousedown(view) {
103
+ view.dispatch(view.state.tr.setMeta(_pluginKey.editorToolbarPluginKey, {
104
+ shouldShowToolbar: false
105
+ }));
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+ });
111
+ }
112
+ }];
113
+ },
31
114
  contentComponent: !disableSelectionToolbar ? function (_ref2) {
32
115
  var editorView = _ref2.editorView,
33
116
  popupsMountPoint = _ref2.popupsMountPoint;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.SelectionToolbar = void 0;
8
- var _react = _interopRequireDefault(require("react"));
8
+ var _react = _interopRequireWildcard(require("react"));
9
9
  var _coreUtils = require("@atlaskit/editor-common/core-utils");
10
+ var _hooks = require("@atlaskit/editor-common/hooks");
10
11
  var _toolbar = require("@atlaskit/editor-common/toolbar");
11
12
  var _ui = require("@atlaskit/editor-common/ui");
12
13
  var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
@@ -15,16 +16,26 @@ var _state = require("@atlaskit/editor-prosemirror/state");
15
16
  var _utils2 = require("@atlaskit/editor-prosemirror/utils");
16
17
  var _editorToolbar = require("@atlaskit/editor-toolbar");
17
18
  var _editorToolbarModel = require("@atlaskit/editor-toolbar-model");
19
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
18
20
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
19
21
  var _consts = require("../consts");
22
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
20
23
  var isToolbarComponent = function isToolbarComponent(component) {
21
24
  return component.type === 'toolbar' && component.key === 'inline-text-toolbar';
22
25
  };
23
26
  var SelectionToolbar = exports.SelectionToolbar = function SelectionToolbar(_ref) {
27
+ var _api$toolbar, _api$toolbar$getCompo;
24
28
  var api = _ref.api,
25
29
  editorView = _ref.editorView,
26
30
  mountPoint = _ref.mountPoint;
27
- var components = api === null || api === void 0 ? void 0 : api.toolbar.actions.getComponents();
31
+ var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['toolbar'], function (state) {
32
+ var _state$toolbarState;
33
+ return {
34
+ shouldShowToolbar: (_state$toolbarState = state.toolbarState) === null || _state$toolbarState === void 0 ? void 0 : _state$toolbarState.shouldShowToolbar
35
+ };
36
+ }),
37
+ shouldShowToolbar = _useSharedPluginState.shouldShowToolbar;
38
+ var components = api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 || (_api$toolbar = _api$toolbar.actions) === null || _api$toolbar === void 0 || (_api$toolbar$getCompo = _api$toolbar.getComponents) === null || _api$toolbar$getCompo === void 0 ? void 0 : _api$toolbar$getCompo.call(_api$toolbar);
28
39
  var toolbar = components === null || components === void 0 ? void 0 : components.find(function (component) {
29
40
  return isToolbarComponent(component);
30
41
  });
@@ -36,18 +47,28 @@ var SelectionToolbar = exports.SelectionToolbar = function SelectionToolbar(_ref
36
47
  var selection = (0, _useSharedPluginStateSelector.useSharedPluginStateSelector)(api, 'selection.selection');
37
48
  var isTextSelection = !editorView.state.selection.empty && editorView.state.selection instanceof _state.TextSelection;
38
49
  var isCellSelection = !editorView.state.selection.empty && '$anchorCell' in editorView.state.selection;
50
+ var onPositionCalculated = (0, _react.useCallback)(function (position) {
51
+ var toolbarTitle = _consts.SELECTION_TOOLBAR_LABEL;
52
+
53
+ // Show special position on cell selection only when editor controls experiment is enabled
54
+ var isEditorControlsEnabled = (0, _expValEquals.expValEquals)('platform_editor_controls', 'cohort', 'variant1');
55
+ var isCellSelection = ('$anchorCell' in editorView.state.selection);
56
+ if (isCellSelection && isEditorControlsEnabled) {
57
+ return (0, _utils.calculateToolbarPositionOnCellSelection)(toolbarTitle)(editorView, position);
58
+ }
59
+ var calc = _utils.calculateToolbarPositionTrackHead;
60
+ return calc(toolbarTitle)(editorView, position);
61
+ }, [editorView]);
39
62
  if (!components || !toolbar) {
40
63
  return null;
41
64
  }
42
- if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || currentUserIntent === 'blockMenuOpen' && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) || (0, _coreUtils.isSSR)()) {
65
+ if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) || (0, _coreUtils.isSSR)()) {
43
66
  return null;
44
67
  }
45
68
  return /*#__PURE__*/_react.default.createElement(_ui.Popup, {
46
69
  offset: [0, 10],
47
70
  target: getDomRefFromSelection(editorView),
48
- onPositionCalculated: function onPositionCalculated(position) {
49
- return (0, _utils.calculateToolbarPositionTrackHead)(_consts.SELECTION_TOOLBAR_LABEL)(editorView, position);
50
- },
71
+ onPositionCalculated: onPositionCalculated,
51
72
  mountTo: mountPoint
52
73
  }, /*#__PURE__*/_react.default.createElement(_toolbar.EditorToolbarProvider, {
53
74
  editorView: editorView
@@ -3,5 +3,9 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SELECTION_TOOLBAR_LABEL = void 0;
7
- var SELECTION_TOOLBAR_LABEL = exports.SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
6
+ exports.SELECTION_TOOLBAR_LABEL = exports.DEFAULT_POPUP_SELECTORS = void 0;
7
+ var SELECTION_TOOLBAR_LABEL = exports.SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
8
+ var DEFAULT_POPUP_SELECTORS = exports.DEFAULT_POPUP_SELECTORS = {
9
+ toolbarContainer: '[role="toolbar"]',
10
+ portal: '.atlaskit-portal'
11
+ };
@@ -120,5 +120,13 @@ var getToolbarComponents = exports.getToolbarComponents = function getToolbarCom
120
120
  var children = _ref6.children;
121
121
  return /*#__PURE__*/_react.default.createElement(_OverflowMenu.OverflowMenu, null, children);
122
122
  }
123
+ }, {
124
+ type: _toolbar.PIN_SECTION.type,
125
+ key: _toolbar.PIN_SECTION.key,
126
+ parents: [{
127
+ type: 'toolbar',
128
+ key: _toolbar.TOOLBARS.PRIMARY_TOOLBAR,
129
+ rank: _toolbar.TOOLBAR_RANK[_toolbar.PIN_SECTION.key]
130
+ }]
123
131
  }];
124
132
  };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isEventInContainer = void 0;
7
+ var isEventInContainer = exports.isEventInContainer = function isEventInContainer(event, containerSelector) {
8
+ var target = event.target instanceof Element ? event.target : null;
9
+ if (!target) {
10
+ return false;
11
+ }
12
+ return !!target.closest(containerSelector);
13
+ };
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export const editorToolbarPluginKey = new PluginKey('editorToolbarPluginKey');
@@ -1,7 +1,12 @@
1
1
  import React from 'react';
2
+ import { bind } from 'bind-event-listener';
3
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
4
  import { createComponentRegistry } from '@atlaskit/editor-toolbar-model';
5
+ import { editorToolbarPluginKey } from './pm-plugins/plugin-key';
6
+ import { DEFAULT_POPUP_SELECTORS } from './ui/consts';
3
7
  import { SelectionToolbar } from './ui/SelectionToolbar';
4
8
  import { getToolbarComponents } from './ui/toolbar-components';
9
+ import { isEventInContainer } from './ui/utils/toolbar';
5
10
  export const toolbarPlugin = ({
6
11
  api,
7
12
  config = {
@@ -23,6 +28,84 @@ export const toolbarPlugin = ({
23
28
  return registry.components;
24
29
  }
25
30
  },
31
+ getSharedState(editorState) {
32
+ if (!editorState) {
33
+ return undefined;
34
+ }
35
+ return editorToolbarPluginKey.getState(editorState);
36
+ },
37
+ pmPlugins() {
38
+ return [{
39
+ name: 'editor-toolbar-selection',
40
+ plugin: () => {
41
+ return new SafePlugin({
42
+ key: editorToolbarPluginKey,
43
+ state: {
44
+ init() {
45
+ return {
46
+ shouldShowToolbar: false
47
+ };
48
+ },
49
+ apply(tr, pluginState) {
50
+ const meta = tr.getMeta(editorToolbarPluginKey);
51
+ const newPluginState = pluginState;
52
+ if (meta) {
53
+ return {
54
+ ...newPluginState,
55
+ ...meta
56
+ };
57
+ }
58
+ return newPluginState;
59
+ }
60
+ },
61
+ view(view) {
62
+ const unbind = bind(view.root, {
63
+ type: 'mouseup',
64
+ listener: function (ev) {
65
+ var _api$editorViewMode;
66
+ const event = ev;
67
+ const isInToolbar = isEventInContainer(event, DEFAULT_POPUP_SELECTORS.toolbarContainer);
68
+ const isInPortal = isEventInContainer(event, DEFAULT_POPUP_SELECTORS.portal);
69
+
70
+ // We only want to set selectionStable to true if the editor has focus
71
+ // to prevent the toolbar from showing when the editor is blurred
72
+ // due to a click outside the editor.
73
+ const editorViewModePlugin = api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.sharedState.currentState();
74
+ const isViewModeEnabled = (editorViewModePlugin === null || editorViewModePlugin === void 0 ? void 0 : editorViewModePlugin.mode) === 'view';
75
+ view.dispatch(view.state.tr.setMeta(editorToolbarPluginKey, {
76
+ shouldShowToolbar: !isViewModeEnabled ? view.hasFocus() || isInToolbar || isInPortal : true
77
+ }));
78
+ }
79
+ });
80
+ const unbindEditorViewFocus = bind(view.dom, {
81
+ type: 'focus',
82
+ listener: () => {
83
+ view.dispatch(view.state.tr.setMeta(editorToolbarPluginKey, {
84
+ shouldShowToolbar: true
85
+ }));
86
+ }
87
+ });
88
+ return {
89
+ destroy() {
90
+ unbind();
91
+ unbindEditorViewFocus();
92
+ }
93
+ };
94
+ },
95
+ props: {
96
+ handleDOMEvents: {
97
+ mousedown: view => {
98
+ view.dispatch(view.state.tr.setMeta(editorToolbarPluginKey, {
99
+ shouldShowToolbar: false
100
+ }));
101
+ return false;
102
+ }
103
+ }
104
+ }
105
+ });
106
+ }
107
+ }];
108
+ },
26
109
  contentComponent: !disableSelectionToolbar ? ({
27
110
  editorView,
28
111
  popupsMountPoint
@@ -1,13 +1,15 @@
1
- import React from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import { isSSR } from '@atlaskit/editor-common/core-utils';
3
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
3
4
  import { EditorToolbarProvider, EditorToolbarUIProvider } from '@atlaskit/editor-common/toolbar';
4
5
  import { Popup } from '@atlaskit/editor-common/ui';
5
6
  import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
6
- import { calculateToolbarPositionTrackHead } from '@atlaskit/editor-common/utils';
7
+ import { calculateToolbarPositionTrackHead, calculateToolbarPositionOnCellSelection } from '@atlaskit/editor-common/utils';
7
8
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
9
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
9
10
  import { ToolbarSection, ToolbarButtonGroup, ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
10
11
  import { ToolbarModelRenderer } from '@atlaskit/editor-toolbar-model';
12
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
13
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
12
14
  import { SELECTION_TOOLBAR_LABEL } from '../consts';
13
15
  const isToolbarComponent = component => {
@@ -18,7 +20,16 @@ export const SelectionToolbar = ({
18
20
  editorView,
19
21
  mountPoint
20
22
  }) => {
21
- const components = api === null || api === void 0 ? void 0 : api.toolbar.actions.getComponents();
23
+ var _api$toolbar, _api$toolbar$actions, _api$toolbar$actions$;
24
+ const {
25
+ shouldShowToolbar
26
+ } = useSharedPluginStateWithSelector(api, ['toolbar'], state => {
27
+ var _state$toolbarState;
28
+ return {
29
+ shouldShowToolbar: (_state$toolbarState = state.toolbarState) === null || _state$toolbarState === void 0 ? void 0 : _state$toolbarState.shouldShowToolbar
30
+ };
31
+ });
32
+ const components = api === null || api === void 0 ? void 0 : (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 ? void 0 : (_api$toolbar$actions = _api$toolbar.actions) === null || _api$toolbar$actions === void 0 ? void 0 : (_api$toolbar$actions$ = _api$toolbar$actions.getComponents) === null || _api$toolbar$actions$ === void 0 ? void 0 : _api$toolbar$actions$.call(_api$toolbar$actions);
22
33
  const toolbar = components === null || components === void 0 ? void 0 : components.find(component => isToolbarComponent(component));
23
34
  const currentUserIntent = useSharedPluginStateSelector(api, 'userIntent.currentUserIntent');
24
35
  const connectivityStateMode = useSharedPluginStateSelector(api, 'connectivity.mode');
@@ -28,16 +39,28 @@ export const SelectionToolbar = ({
28
39
  const selection = useSharedPluginStateSelector(api, 'selection.selection');
29
40
  const isTextSelection = !editorView.state.selection.empty && editorView.state.selection instanceof TextSelection;
30
41
  const isCellSelection = !editorView.state.selection.empty && '$anchorCell' in editorView.state.selection;
42
+ const onPositionCalculated = useCallback(position => {
43
+ const toolbarTitle = SELECTION_TOOLBAR_LABEL;
44
+
45
+ // Show special position on cell selection only when editor controls experiment is enabled
46
+ const isEditorControlsEnabled = expValEquals('platform_editor_controls', 'cohort', 'variant1');
47
+ const isCellSelection = ('$anchorCell' in editorView.state.selection);
48
+ if (isCellSelection && isEditorControlsEnabled) {
49
+ return calculateToolbarPositionOnCellSelection(toolbarTitle)(editorView, position);
50
+ }
51
+ const calc = calculateToolbarPositionTrackHead;
52
+ return calc(toolbarTitle)(editorView, position);
53
+ }, [editorView]);
31
54
  if (!components || !toolbar) {
32
55
  return null;
33
56
  }
34
- if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || currentUserIntent === 'blockMenuOpen' && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) || isSSR()) {
57
+ if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) || isSSR()) {
35
58
  return null;
36
59
  }
37
60
  return /*#__PURE__*/React.createElement(Popup, {
38
61
  offset: [0, 10],
39
62
  target: getDomRefFromSelection(editorView),
40
- onPositionCalculated: position => calculateToolbarPositionTrackHead(SELECTION_TOOLBAR_LABEL)(editorView, position),
63
+ onPositionCalculated: onPositionCalculated,
41
64
  mountTo: mountPoint
42
65
  }, /*#__PURE__*/React.createElement(EditorToolbarProvider, {
43
66
  editorView: editorView
@@ -1 +1,5 @@
1
- export const SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
1
+ export const SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
2
+ export const DEFAULT_POPUP_SELECTORS = {
3
+ toolbarContainer: '[role="toolbar"]',
4
+ portal: '.atlaskit-portal'
5
+ };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { INSERT_BLOCK_SECTION, LINKING_SECTION, OVERFLOW_GROUP, OVERFLOW_GROUP_RANK, OVERFLOW_MENU, OVERFLOW_SECTION, OVERFLOW_SECTION_RANK, TEXT_SECTION, TOOLBAR_RANK, TOOLBARS } from '@atlaskit/editor-common/toolbar';
2
+ import { INSERT_BLOCK_SECTION, LINKING_SECTION, OVERFLOW_GROUP, OVERFLOW_GROUP_RANK, OVERFLOW_MENU, OVERFLOW_SECTION, OVERFLOW_SECTION_RANK, PIN_SECTION, TEXT_SECTION, TOOLBAR_RANK, TOOLBARS } from '@atlaskit/editor-common/toolbar';
3
3
  import { PrimaryToolbar, Toolbar } from '@atlaskit/editor-toolbar';
4
4
  import { SELECTION_TOOLBAR_LABEL } from './consts';
5
5
  import { OverflowMenu } from './OverflowMenu';
@@ -113,5 +113,13 @@ export const getToolbarComponents = api => {
113
113
  }) => {
114
114
  return /*#__PURE__*/React.createElement(OverflowMenu, null, children);
115
115
  }
116
+ }, {
117
+ type: PIN_SECTION.type,
118
+ key: PIN_SECTION.key,
119
+ parents: [{
120
+ type: 'toolbar',
121
+ key: TOOLBARS.PRIMARY_TOOLBAR,
122
+ rank: TOOLBAR_RANK[PIN_SECTION.key]
123
+ }]
116
124
  }];
117
125
  };
@@ -0,0 +1,7 @@
1
+ export const isEventInContainer = (event, containerSelector) => {
2
+ const target = event.target instanceof Element ? event.target : null;
3
+ if (!target) {
4
+ return false;
5
+ }
6
+ return !!target.closest(containerSelector);
7
+ };
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export var editorToolbarPluginKey = new PluginKey('editorToolbarPluginKey');
@@ -1,7 +1,15 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ 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; }
3
+ 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) { _defineProperty(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; }
1
4
  import React from 'react';
5
+ import { bind } from 'bind-event-listener';
6
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
7
  import { createComponentRegistry } from '@atlaskit/editor-toolbar-model';
8
+ import { editorToolbarPluginKey } from './pm-plugins/plugin-key';
9
+ import { DEFAULT_POPUP_SELECTORS } from './ui/consts';
3
10
  import { SelectionToolbar } from './ui/SelectionToolbar';
4
11
  import { getToolbarComponents } from './ui/toolbar-components';
12
+ import { isEventInContainer } from './ui/utils/toolbar';
5
13
  export var toolbarPlugin = function toolbarPlugin(_ref) {
6
14
  var api = _ref.api,
7
15
  _ref$config = _ref.config,
@@ -21,6 +29,81 @@ export var toolbarPlugin = function toolbarPlugin(_ref) {
21
29
  return registry.components;
22
30
  }
23
31
  },
32
+ getSharedState: function getSharedState(editorState) {
33
+ if (!editorState) {
34
+ return undefined;
35
+ }
36
+ return editorToolbarPluginKey.getState(editorState);
37
+ },
38
+ pmPlugins: function pmPlugins() {
39
+ return [{
40
+ name: 'editor-toolbar-selection',
41
+ plugin: function plugin() {
42
+ return new SafePlugin({
43
+ key: editorToolbarPluginKey,
44
+ state: {
45
+ init: function init() {
46
+ return {
47
+ shouldShowToolbar: false
48
+ };
49
+ },
50
+ apply: function apply(tr, pluginState) {
51
+ var meta = tr.getMeta(editorToolbarPluginKey);
52
+ var newPluginState = pluginState;
53
+ if (meta) {
54
+ return _objectSpread(_objectSpread({}, newPluginState), meta);
55
+ }
56
+ return newPluginState;
57
+ }
58
+ },
59
+ view: function view(_view) {
60
+ var unbind = bind(_view.root, {
61
+ type: 'mouseup',
62
+ listener: function listener(ev) {
63
+ var _api$editorViewMode;
64
+ var event = ev;
65
+ var isInToolbar = isEventInContainer(event, DEFAULT_POPUP_SELECTORS.toolbarContainer);
66
+ var isInPortal = isEventInContainer(event, DEFAULT_POPUP_SELECTORS.portal);
67
+
68
+ // We only want to set selectionStable to true if the editor has focus
69
+ // to prevent the toolbar from showing when the editor is blurred
70
+ // due to a click outside the editor.
71
+ var editorViewModePlugin = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.sharedState.currentState();
72
+ var isViewModeEnabled = (editorViewModePlugin === null || editorViewModePlugin === void 0 ? void 0 : editorViewModePlugin.mode) === 'view';
73
+ _view.dispatch(_view.state.tr.setMeta(editorToolbarPluginKey, {
74
+ shouldShowToolbar: !isViewModeEnabled ? _view.hasFocus() || isInToolbar || isInPortal : true
75
+ }));
76
+ }
77
+ });
78
+ var unbindEditorViewFocus = bind(_view.dom, {
79
+ type: 'focus',
80
+ listener: function listener() {
81
+ _view.dispatch(_view.state.tr.setMeta(editorToolbarPluginKey, {
82
+ shouldShowToolbar: true
83
+ }));
84
+ }
85
+ });
86
+ return {
87
+ destroy: function destroy() {
88
+ unbind();
89
+ unbindEditorViewFocus();
90
+ }
91
+ };
92
+ },
93
+ props: {
94
+ handleDOMEvents: {
95
+ mousedown: function mousedown(view) {
96
+ view.dispatch(view.state.tr.setMeta(editorToolbarPluginKey, {
97
+ shouldShowToolbar: false
98
+ }));
99
+ return false;
100
+ }
101
+ }
102
+ }
103
+ });
104
+ }
105
+ }];
106
+ },
24
107
  contentComponent: !disableSelectionToolbar ? function (_ref2) {
25
108
  var editorView = _ref2.editorView,
26
109
  popupsMountPoint = _ref2.popupsMountPoint;
@@ -1,23 +1,33 @@
1
- import React from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import { isSSR } from '@atlaskit/editor-common/core-utils';
3
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
3
4
  import { EditorToolbarProvider, EditorToolbarUIProvider } from '@atlaskit/editor-common/toolbar';
4
5
  import { Popup } from '@atlaskit/editor-common/ui';
5
6
  import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
6
- import { calculateToolbarPositionTrackHead } from '@atlaskit/editor-common/utils';
7
+ import { calculateToolbarPositionTrackHead, calculateToolbarPositionOnCellSelection } from '@atlaskit/editor-common/utils';
7
8
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
9
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
9
10
  import { ToolbarSection, ToolbarButtonGroup, ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
10
11
  import { ToolbarModelRenderer } from '@atlaskit/editor-toolbar-model';
12
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
13
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
12
14
  import { SELECTION_TOOLBAR_LABEL } from '../consts';
13
15
  var isToolbarComponent = function isToolbarComponent(component) {
14
16
  return component.type === 'toolbar' && component.key === 'inline-text-toolbar';
15
17
  };
16
18
  export var SelectionToolbar = function SelectionToolbar(_ref) {
19
+ var _api$toolbar, _api$toolbar$getCompo;
17
20
  var api = _ref.api,
18
21
  editorView = _ref.editorView,
19
22
  mountPoint = _ref.mountPoint;
20
- var components = api === null || api === void 0 ? void 0 : api.toolbar.actions.getComponents();
23
+ var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['toolbar'], function (state) {
24
+ var _state$toolbarState;
25
+ return {
26
+ shouldShowToolbar: (_state$toolbarState = state.toolbarState) === null || _state$toolbarState === void 0 ? void 0 : _state$toolbarState.shouldShowToolbar
27
+ };
28
+ }),
29
+ shouldShowToolbar = _useSharedPluginState.shouldShowToolbar;
30
+ var components = api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 || (_api$toolbar = _api$toolbar.actions) === null || _api$toolbar === void 0 || (_api$toolbar$getCompo = _api$toolbar.getComponents) === null || _api$toolbar$getCompo === void 0 ? void 0 : _api$toolbar$getCompo.call(_api$toolbar);
21
31
  var toolbar = components === null || components === void 0 ? void 0 : components.find(function (component) {
22
32
  return isToolbarComponent(component);
23
33
  });
@@ -29,18 +39,28 @@ export var SelectionToolbar = function SelectionToolbar(_ref) {
29
39
  var selection = useSharedPluginStateSelector(api, 'selection.selection');
30
40
  var isTextSelection = !editorView.state.selection.empty && editorView.state.selection instanceof TextSelection;
31
41
  var isCellSelection = !editorView.state.selection.empty && '$anchorCell' in editorView.state.selection;
42
+ var onPositionCalculated = useCallback(function (position) {
43
+ var toolbarTitle = SELECTION_TOOLBAR_LABEL;
44
+
45
+ // Show special position on cell selection only when editor controls experiment is enabled
46
+ var isEditorControlsEnabled = expValEquals('platform_editor_controls', 'cohort', 'variant1');
47
+ var isCellSelection = ('$anchorCell' in editorView.state.selection);
48
+ if (isCellSelection && isEditorControlsEnabled) {
49
+ return calculateToolbarPositionOnCellSelection(toolbarTitle)(editorView, position);
50
+ }
51
+ var calc = calculateToolbarPositionTrackHead;
52
+ return calc(toolbarTitle)(editorView, position);
53
+ }, [editorView]);
32
54
  if (!components || !toolbar) {
33
55
  return null;
34
56
  }
35
- if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || currentUserIntent === 'blockMenuOpen' && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) || isSSR()) {
57
+ if (!(isTextSelection || isCellSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) || isSSR()) {
36
58
  return null;
37
59
  }
38
60
  return /*#__PURE__*/React.createElement(Popup, {
39
61
  offset: [0, 10],
40
62
  target: getDomRefFromSelection(editorView),
41
- onPositionCalculated: function onPositionCalculated(position) {
42
- return calculateToolbarPositionTrackHead(SELECTION_TOOLBAR_LABEL)(editorView, position);
43
- },
63
+ onPositionCalculated: onPositionCalculated,
44
64
  mountTo: mountPoint
45
65
  }, /*#__PURE__*/React.createElement(EditorToolbarProvider, {
46
66
  editorView: editorView
@@ -1 +1,5 @@
1
- export var SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
1
+ export var SELECTION_TOOLBAR_LABEL = 'Selection toolbar';
2
+ export var DEFAULT_POPUP_SELECTORS = {
3
+ toolbarContainer: '[role="toolbar"]',
4
+ portal: '.atlaskit-portal'
5
+ };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { INSERT_BLOCK_SECTION, LINKING_SECTION, OVERFLOW_GROUP, OVERFLOW_GROUP_RANK, OVERFLOW_MENU, OVERFLOW_SECTION, OVERFLOW_SECTION_RANK, TEXT_SECTION, TOOLBAR_RANK, TOOLBARS } from '@atlaskit/editor-common/toolbar';
2
+ import { INSERT_BLOCK_SECTION, LINKING_SECTION, OVERFLOW_GROUP, OVERFLOW_GROUP_RANK, OVERFLOW_MENU, OVERFLOW_SECTION, OVERFLOW_SECTION_RANK, PIN_SECTION, TEXT_SECTION, TOOLBAR_RANK, TOOLBARS } from '@atlaskit/editor-common/toolbar';
3
3
  import { PrimaryToolbar, Toolbar } from '@atlaskit/editor-toolbar';
4
4
  import { SELECTION_TOOLBAR_LABEL } from './consts';
5
5
  import { OverflowMenu } from './OverflowMenu';
@@ -113,5 +113,13 @@ export var getToolbarComponents = function getToolbarComponents(api) {
113
113
  var children = _ref6.children;
114
114
  return /*#__PURE__*/React.createElement(OverflowMenu, null, children);
115
115
  }
116
+ }, {
117
+ type: PIN_SECTION.type,
118
+ key: PIN_SECTION.key,
119
+ parents: [{
120
+ type: 'toolbar',
121
+ key: TOOLBARS.PRIMARY_TOOLBAR,
122
+ rank: TOOLBAR_RANK[PIN_SECTION.key]
123
+ }]
116
124
  }];
117
125
  };
@@ -0,0 +1,7 @@
1
+ export var isEventInContainer = function isEventInContainer(event, containerSelector) {
2
+ var target = event.target instanceof Element ? event.target : null;
3
+ if (!target) {
4
+ return false;
5
+ }
6
+ return !!target.closest(containerSelector);
7
+ };
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const editorToolbarPluginKey: PluginKey<any>;
@@ -1,2 +1,5 @@
1
1
  import type { ToolbarPlugin } from './toolbarPluginType';
2
+ export type EditorToolbarPluginState = {
3
+ shouldShowToolbar: boolean;
4
+ };
2
5
  export declare const toolbarPlugin: ToolbarPlugin;
@@ -8,6 +8,9 @@ import type { RegisterComponent } from '@atlaskit/editor-toolbar-model';
8
8
  import type { ToolbarPluginOptions } from './types';
9
9
  export type ToolbarPlugin = NextEditorPlugin<'toolbar', {
10
10
  pluginConfiguration?: ToolbarPluginOptions;
11
+ sharedState: {
12
+ shouldShowToolbar: boolean;
13
+ };
11
14
  dependencies: [
12
15
  OptionalPlugin<UserIntentPlugin>,
13
16
  OptionalPlugin<SelectionPlugin>,
@@ -1 +1,5 @@
1
1
  export declare const SELECTION_TOOLBAR_LABEL = "Selection toolbar";
2
+ export declare const DEFAULT_POPUP_SELECTORS: {
3
+ readonly toolbarContainer: "[role=\"toolbar\"]";
4
+ readonly portal: ".atlaskit-portal";
5
+ };
@@ -0,0 +1 @@
1
+ export declare const isEventInContainer: (event: Event, containerSelector: string) => boolean;
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const editorToolbarPluginKey: PluginKey<any>;
@@ -1,2 +1,5 @@
1
1
  import type { ToolbarPlugin } from './toolbarPluginType';
2
+ export type EditorToolbarPluginState = {
3
+ shouldShowToolbar: boolean;
4
+ };
2
5
  export declare const toolbarPlugin: ToolbarPlugin;
@@ -8,6 +8,9 @@ import type { RegisterComponent } from '@atlaskit/editor-toolbar-model';
8
8
  import type { ToolbarPluginOptions } from './types';
9
9
  export type ToolbarPlugin = NextEditorPlugin<'toolbar', {
10
10
  pluginConfiguration?: ToolbarPluginOptions;
11
+ sharedState: {
12
+ shouldShowToolbar: boolean;
13
+ };
11
14
  dependencies: [
12
15
  OptionalPlugin<UserIntentPlugin>,
13
16
  OptionalPlugin<SelectionPlugin>,
@@ -1 +1,5 @@
1
1
  export declare const SELECTION_TOOLBAR_LABEL = "Selection toolbar";
2
+ export declare const DEFAULT_POPUP_SELECTORS: {
3
+ readonly toolbarContainer: "[role=\"toolbar\"]";
4
+ readonly portal: ".atlaskit-portal";
5
+ };
@@ -0,0 +1 @@
1
+ export declare const isEventInContainer: (event: Event, containerSelector: string) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-toolbar",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Toolbar plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -33,14 +33,15 @@
33
33
  "dependencies": {
34
34
  "@atlaskit/editor-plugin-connectivity": "^3.1.0",
35
35
  "@atlaskit/editor-plugin-editor-viewmode": "^5.0.0",
36
- "@atlaskit/editor-plugin-selection": "^3.1.0",
36
+ "@atlaskit/editor-plugin-selection": "^3.2.0",
37
37
  "@atlaskit/editor-plugin-user-intent": "^1.1.0",
38
38
  "@atlaskit/editor-plugin-user-preferences": "^1.2.0",
39
39
  "@atlaskit/editor-prosemirror": "7.0.0",
40
40
  "@atlaskit/editor-toolbar": "^0.3.0",
41
41
  "@atlaskit/editor-toolbar-model": "^0.1.0",
42
- "@atlaskit/tmp-editor-statsig": "^11.4.0",
42
+ "@atlaskit/tmp-editor-statsig": "^11.5.0",
43
43
  "@babel/runtime": "^7.0.0",
44
+ "bind-event-listener": "^3.0.0",
44
45
  "react-intl-next": "npm:react-intl@^5.18.1"
45
46
  },
46
47
  "peerDependencies": {