@atlaskit/editor-plugin-insert-block 1.12.0 → 1.14.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 (30) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cjs/plugin.js +36 -5
  3. package/dist/cjs/ui/ElementBrowser/InsertMenu.js +47 -13
  4. package/dist/cjs/ui/ElementRail/index.js +186 -2
  5. package/dist/cjs/ui/ElementRail/useInsertMenuRailItems.js +63 -0
  6. package/dist/cjs/ui/templateOptions.js +128 -57
  7. package/dist/cjs/ui/templates.js +1130 -0
  8. package/dist/es2019/plugin.js +36 -5
  9. package/dist/es2019/ui/ElementBrowser/InsertMenu.js +61 -26
  10. package/dist/es2019/ui/ElementRail/index.js +189 -1
  11. package/dist/es2019/ui/ElementRail/useInsertMenuRailItems.js +54 -0
  12. package/dist/es2019/ui/templateOptions.js +78 -11
  13. package/dist/es2019/ui/templates.js +1118 -0
  14. package/dist/esm/plugin.js +36 -5
  15. package/dist/esm/ui/ElementBrowser/InsertMenu.js +47 -13
  16. package/dist/esm/ui/ElementRail/index.js +185 -2
  17. package/dist/esm/ui/ElementRail/useInsertMenuRailItems.js +56 -0
  18. package/dist/esm/ui/templateOptions.js +128 -57
  19. package/dist/esm/ui/templates.js +1124 -0
  20. package/dist/types/ui/ElementRail/index.d.ts +7 -4
  21. package/dist/types/ui/ElementRail/useInsertMenuRailItems.d.ts +4 -0
  22. package/dist/types/ui/ToolbarInsertBlock/create-items.d.ts +1 -1
  23. package/dist/types/ui/templateOptions.d.ts +3 -1
  24. package/dist/types/ui/templates.d.ts +522 -0
  25. package/dist/types-ts4.5/ui/ElementRail/index.d.ts +7 -4
  26. package/dist/types-ts4.5/ui/ElementRail/useInsertMenuRailItems.d.ts +4 -0
  27. package/dist/types-ts4.5/ui/ToolbarInsertBlock/create-items.d.ts +1 -1
  28. package/dist/types-ts4.5/ui/templateOptions.d.ts +3 -1
  29. package/dist/types-ts4.5/ui/templates.d.ts +522 -0
  30. package/package.json +14 -6
@@ -4,9 +4,11 @@ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
4
4
  import { contentAllowedInCodeBlock, shouldSplitSelectedNodeOnNodeInsertion } from '@atlaskit/editor-common/insert';
5
5
  import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { WithProviders } from '@atlaskit/editor-common/provider-factory';
7
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
7
8
  import { ToolbarSize } from '@atlaskit/editor-common/types';
8
9
  import { getWrappingOptions } from '@atlaskit/editor-common/utils';
9
10
  import { BLOCK_QUOTE, CODE_BLOCK, PANEL } from '@atlaskit/editor-plugin-block-type/consts';
11
+ import { fg } from '@atlaskit/platform-feature-flags';
10
12
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
11
13
  import SwitchIcon from './assets/switch';
12
14
  import { elementBrowserPmKey, elementBrowserPmPlugin } from './pm-plugins/elementBrowser';
@@ -53,6 +55,9 @@ export const insertBlockPlugin = ({
53
55
  const toggleDropdownMenuOptionsRef = {
54
56
  current: null
55
57
  };
58
+ const editorViewRef = {
59
+ current: null
60
+ };
56
61
  const registerToggleDropdownMenuOptions = cb => {
57
62
  toggleDropdownMenuOptionsRef.current = cb;
58
63
  return () => {
@@ -119,6 +124,17 @@ export const insertBlockPlugin = ({
119
124
  return [{
120
125
  name: 'elementBrowserPmPlugin',
121
126
  plugin: () => elementBrowserPmPlugin()
127
+ }, {
128
+ name: 'elementBrowserEditorViewRef',
129
+ plugin: () => {
130
+ return new SafePlugin({
131
+ view: editorView => {
132
+ // Workaround - need reference to editorView for contextPanel component
133
+ editorViewRef.current = editorView;
134
+ return {};
135
+ }
136
+ });
137
+ }
122
138
  }];
123
139
  },
124
140
  pluginsOptions: {
@@ -188,10 +204,13 @@ export const insertBlockPlugin = ({
188
204
  // If we decide to ship the feature, we will consider a separate plugin if needed.
189
205
  // Experiment one-pager: https://hello.atlassian.net/wiki/spaces/ETM/pages/3983684902/Experiment+Drive+element+usage+via+element+templates
190
206
  quickInsert: () => {
191
- if (editorExperiment('element-level-templates', true, {
207
+ var _options$UNSAFE_edito;
208
+ if (
209
+ // @ts-ignore
210
+ ['full-page', 'full-width'].includes((_options$UNSAFE_edito = options.UNSAFE_editorAppearance) !== null && _options$UNSAFE_edito !== void 0 ? _options$UNSAFE_edito : '') && editorExperiment('element-level-templates', true, {
192
211
  exposure: true
193
212
  })) {
194
- return templateOptions;
213
+ return templateOptions(api);
195
214
  }
196
215
  return [];
197
216
  }
@@ -210,8 +229,10 @@ export const insertBlockPlugin = ({
210
229
  // api.getSharedState() will have an outdated reference to editorState on first mount of this component
211
230
  // so instead just rely on plugin key as we don't need to be reactive to changes here
212
231
  const pluginState = elementBrowserPmKey.getState(state);
213
- if (pluginState !== null && pluginState !== void 0 && pluginState.menuBrowserOpen) {
232
+ if (pluginState !== null && pluginState !== void 0 && pluginState.menuBrowserOpen && editorViewRef.current) {
214
233
  return /*#__PURE__*/React.createElement(InsertMenuRail, {
234
+ editorView: editorViewRef.current,
235
+ options: options,
215
236
  api: api
216
237
  });
217
238
  }
@@ -249,6 +270,16 @@ function ToolbarInsertBlockWithInjectionApi({
249
270
  typeAheadState,
250
271
  placeholderTextState
251
272
  } = useSharedPluginState(pluginInjectionApi, ['hyperlink', 'date', 'imageUpload', 'mention', 'emoji', 'blockType', 'media', 'typeAhead', 'placeholderText']);
273
+ const getEmojiProvider = () => {
274
+ if (fg('platform_editor_get_emoji_provider_from_config')) {
275
+ if (emojiState !== null && emojiState !== void 0 && emojiState.emojiProvider) {
276
+ return Promise.resolve(emojiState === null || emojiState === void 0 ? void 0 : emojiState.emojiProvider);
277
+ }
278
+ } else {
279
+ return providers.emojiProvider;
280
+ }
281
+ };
282
+ const emojiProvider = getEmojiProvider();
252
283
  return /*#__PURE__*/React.createElement(ToolbarInsertBlock, {
253
284
  pluginInjectionApi: pluginInjectionApi,
254
285
  buttons: buttons,
@@ -275,8 +306,8 @@ function ToolbarInsertBlockWithInjectionApi({
275
306
  availableWrapperBlockTypes: blockTypeState && blockTypeState.availableWrapperBlockTypes,
276
307
  linkSupported: !!hyperlinkState,
277
308
  linkDisabled: !hyperlinkState || !hyperlinkState.canInsertLink || !!hyperlinkState.activeLinkMark,
278
- emojiDisabled: !emojiState || !providers.emojiProvider,
279
- emojiProvider: providers.emojiProvider,
309
+ emojiDisabled: !emojiState || !emojiProvider,
310
+ emojiProvider: emojiProvider,
280
311
  nativeStatusSupported: options.nativeStatusSupported,
281
312
  horizontalRuleEnabled: options.horizontalRuleEnabled,
282
313
  onInsertBlockType: handleInsertBlockType(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$c = pluginInjectionApi.codeBlock) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.actions.insertCodeBlock, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$p = pluginInjectionApi.panel) === null || _pluginInjectionApi$p === void 0 ? void 0 : _pluginInjectionApi$p.actions.insertPanel, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$b = pluginInjectionApi.blockType) === null || _pluginInjectionApi$b === void 0 ? void 0 : _pluginInjectionApi$b.actions.insertBlockQuote),
@@ -16,6 +16,7 @@ import { withReactEditorViewOuterListeners as withOuterListeners } from '@atlask
16
16
  // eslint-disable-next-line @atlassian/tangerine/import/entry-points
17
17
  import { borderRadius } from '@atlaskit/theme';
18
18
  import { N0, N30A, N60A } from '@atlaskit/theme/colors';
19
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
19
20
  const InsertMenu = ({
20
21
  editorView,
21
22
  dropdownItems,
@@ -24,7 +25,7 @@ const InsertMenu = ({
24
25
  toggleVisiblity,
25
26
  pluginInjectionApi
26
27
  }) => {
27
- var _pluginInjectionApi$q6, _pluginInjectionApi$q7, _pluginInjectionApi$q8;
28
+ var _pluginInjectionApi$q7, _pluginInjectionApi$q8, _pluginInjectionApi$q9;
28
29
  const [itemCount, setItemCount] = useState(0);
29
30
  const transform = useCallback(item => ({
30
31
  title: item.content,
@@ -47,12 +48,19 @@ const InsertMenu = ({
47
48
  const quickInsertDropdownItems = dropdownItems.map(transform);
48
49
  const viewMoreItem = showElementBrowserLink ? quickInsertDropdownItems.pop() : undefined;
49
50
  const onInsertItem = useCallback(item => {
50
- var _pluginInjectionApi$q;
51
51
  toggleVisiblity();
52
52
  if (!editorView.hasFocus()) {
53
53
  editorView.focus();
54
54
  }
55
- pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q === void 0 ? void 0 : _pluginInjectionApi$q.actions.insertItem(item, INPUT_METHOD.TOOLBAR)(editorView.state, editorView.dispatch);
55
+ if (editorExperiment('insert-menu-in-right-rail', true)) {
56
+ var _pluginInjectionApi$q;
57
+ pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q === void 0 ? void 0 : _pluginInjectionApi$q.actions.insertItem(item,
58
+ // @ts-expect-error
59
+ INPUT_METHOD.INSERT_MENU_RIGHT_RAIL)(editorView.state, editorView.dispatch);
60
+ } else {
61
+ var _pluginInjectionApi$q2;
62
+ pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q2 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q2 === void 0 ? void 0 : _pluginInjectionApi$q2.actions.insertItem(item, INPUT_METHOD.TOOLBAR)(editorView.state, editorView.dispatch);
63
+ }
56
64
  }, [editorView, toggleVisiblity, pluginInjectionApi]);
57
65
  const getItems = useCallback((query, category) => {
58
66
  let result;
@@ -63,23 +71,35 @@ const InsertMenu = ({
63
71
  * @see above transform function for more details.
64
72
  */
65
73
  if (query) {
66
- var _pluginInjectionApi$q2, _pluginInjectionApi$q3;
67
- result = (_pluginInjectionApi$q2 = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q3 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q3 === void 0 ? void 0 : _pluginInjectionApi$q3.actions.getSuggestions({
74
+ var _pluginInjectionApi$q3, _pluginInjectionApi$q4;
75
+ result = (_pluginInjectionApi$q3 = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q4 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q4 === void 0 ? void 0 : _pluginInjectionApi$q4.actions.getSuggestions({
68
76
  query,
69
77
  category
70
- })) !== null && _pluginInjectionApi$q2 !== void 0 ? _pluginInjectionApi$q2 : [];
78
+ })) !== null && _pluginInjectionApi$q3 !== void 0 ? _pluginInjectionApi$q3 : [];
71
79
  } else {
72
- var _pluginInjectionApi$q4, _pluginInjectionApi$q5;
73
- const featuredQuickInsertSuggestions = (_pluginInjectionApi$q4 = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q5 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q5 === void 0 ? void 0 : _pluginInjectionApi$q5.actions.getSuggestions({
80
+ var _pluginInjectionApi$q5, _pluginInjectionApi$q6;
81
+ const featuredQuickInsertSuggestions = (_pluginInjectionApi$q5 = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q6 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q6 === void 0 ? void 0 : _pluginInjectionApi$q6.actions.getSuggestions({
74
82
  category,
75
- featuredItems: true
76
- })) !== null && _pluginInjectionApi$q4 !== void 0 ? _pluginInjectionApi$q4 : [];
77
- result = quickInsertDropdownItems.concat(featuredQuickInsertSuggestions);
83
+ featuredItems: true,
84
+ // @ts-ignore
85
+ templateItems: editorExperiment('element-level-templates', true)
86
+ })) !== null && _pluginInjectionApi$q5 !== void 0 ? _pluginInjectionApi$q5 : [];
87
+ if (editorExperiment('element-level-templates', true)) {
88
+ // Make sure template options appear as top 5 items
89
+ featuredQuickInsertSuggestions.sort((a, b) => {
90
+ var _b$priority, _a$priority;
91
+ return ((_b$priority = b.priority) !== null && _b$priority !== void 0 ? _b$priority : 0) - ((_a$priority = a.priority) !== null && _a$priority !== void 0 ? _a$priority : 0);
92
+ });
93
+ const templateItems = featuredQuickInsertSuggestions.splice(0, 5);
94
+ result = [...templateItems, ...quickInsertDropdownItems, ...featuredQuickInsertSuggestions];
95
+ } else {
96
+ result = quickInsertDropdownItems.concat(featuredQuickInsertSuggestions);
97
+ }
78
98
  }
79
99
  setItemCount(result.length);
80
100
  return result;
81
- }, [pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q6 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q6 === void 0 ? void 0 : _pluginInjectionApi$q6.actions, quickInsertDropdownItems]);
82
- const emptyStateHandler = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q7 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q7 === void 0 ? void 0 : (_pluginInjectionApi$q8 = _pluginInjectionApi$q7.sharedState.currentState()) === null || _pluginInjectionApi$q8 === void 0 ? void 0 : _pluginInjectionApi$q8.emptyStateHandler;
101
+ }, [pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q7 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q7 === void 0 ? void 0 : _pluginInjectionApi$q7.actions, quickInsertDropdownItems]);
102
+ const emptyStateHandler = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$q8 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q8 === void 0 ? void 0 : (_pluginInjectionApi$q9 = _pluginInjectionApi$q8.sharedState.currentState()) === null || _pluginInjectionApi$q9 === void 0 ? void 0 : _pluginInjectionApi$q9.emptyStateHandler;
83
103
  return (
84
104
  // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
85
105
  jsx("div", {
@@ -129,21 +149,36 @@ const getInsertMenuHeight = ({
129
149
  }
130
150
  return 560; // For showing 6 Elements.
131
151
  };
132
- const insertMenuWrapper = itemCount => css({
133
- display: 'flex',
134
- flexDirection: 'column',
135
- width: '320px',
136
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
137
- height: `${getInsertMenuHeight({
138
- itemCount
139
- })}px`,
140
- backgroundColor: `${`var(--ds-surface-overlay, ${N0})`}`,
141
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
142
- borderRadius: `${borderRadius()}px`,
143
- boxShadow: `${`var(--ds-shadow-overlay, ${`0 0 0 1px ${N30A},
152
+ const insertMenuWrapper = itemCount => {
153
+ if (editorExperiment('insert-menu-in-right-rail', true)) {
154
+ return css({
155
+ display: 'flex',
156
+ flexDirection: 'column',
157
+ width: '310px',
158
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
159
+ height: 'calc(100% - 32px)',
160
+ margin: `0 -10px`,
161
+ backgroundColor: `${`var(--ds-surface-overlay, ${N0})`}`,
162
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
163
+ borderRadius: `${borderRadius()}px`
164
+ });
165
+ }
166
+ return css({
167
+ display: 'flex',
168
+ flexDirection: 'column',
169
+ width: '320px',
170
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
171
+ height: `${getInsertMenuHeight({
172
+ itemCount
173
+ })}px`,
174
+ backgroundColor: `${`var(--ds-surface-overlay, ${N0})`}`,
175
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
176
+ borderRadius: `${borderRadius()}px`,
177
+ boxShadow: `${`var(--ds-shadow-overlay, ${`0 0 0 1px ${N30A},
144
178
  0 2px 1px ${N30A},
145
179
  0 0 20px -6px ${N60A}`})`}`
146
- });
180
+ });
181
+ };
147
182
  const flexWrapperStyles = css({
148
183
  display: 'flex',
149
184
  flex: 1,
@@ -1,10 +1,198 @@
1
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
1
2
  import React from 'react';
3
+ import { useIntl } from 'react-intl-next';
4
+ import { IconButton } from '@atlaskit/button/new';
5
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
6
+ import { toolbarInsertBlockMessages } from '@atlaskit/editor-common/messages';
7
+ import Heading from '@atlaskit/heading';
8
+ import CrossIcon from '@atlaskit/icon/glyph/cross';
9
+ import { Box, xcss } from '@atlaskit/primitives';
10
+ import { toggleInsertMenuRightRail } from '../../pm-plugins/commands';
11
+ import InsertMenu from '../ElementBrowser/InsertMenu';
12
+ import { useInsertMenuRailItems } from './useInsertMenuRailItems';
13
+ const panelWrapper = xcss({
14
+ height: '100%'
15
+ });
16
+ const panelContentHeader = xcss({
17
+ height: '32px',
18
+ display: 'flex',
19
+ justifyContent: 'space-between',
20
+ alignItems: 'center'
21
+ });
22
+
2
23
  /**
3
24
  * For insert menu in right rail experiment
4
25
  * - Clean up ticket ED-24801
5
26
  */
6
27
  export const InsertMenuRail = ({
28
+ editorView,
29
+ options,
7
30
  api
8
31
  }) => {
9
- return /*#__PURE__*/React.createElement("div", null);
32
+ const dropdownItems = useInsertMenuRailItems(editorView, options, api);
33
+ const {
34
+ formatMessage
35
+ } = useIntl();
36
+ const onInsert = ({
37
+ item
38
+ }) => {
39
+ var _api$core, _api$hyperlink, _api$imageUpload, _api$media, _api$mention, _api$emoji, _api$codeBlock, _api$blockType, _api$panel, _api$taskDecision, _api$taskDecision2, _api$rule, _api$core2, _api$quickInsert, _api$core3, _api$date, _api$date$commands, _api$placeholderText, _api$layout, _api$core4, _api$status, _api$status$commands;
40
+ const {
41
+ state,
42
+ dispatch
43
+ } = editorView;
44
+ let inputMethod = INPUT_METHOD.INSERT_MENU_RIGHT_RAIL;
45
+ if (!api) {
46
+ return;
47
+ }
48
+ if (!editorView.hasFocus()) {
49
+ editorView.focus();
50
+ }
51
+
52
+ // Below is duplicated from ToolbarInsertBlock/index.tsx - this function is only called
53
+ // for BlockMenuItem items, which are rendered in the insert menu when no search has been performed.
54
+ // When a search is performed, the list will be filled by QuickInsertItems, which handle their own insertion.
55
+ switch (item.value.name) {
56
+ case 'link':
57
+ // @ts-expect-error
58
+ (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$hyperlink = api.hyperlink) === null || _api$hyperlink === void 0 ? void 0 : _api$hyperlink.commands.showLinkToolbar(inputMethod));
59
+ break;
60
+ case 'table':
61
+ // workaround to solve race condition where cursor is not placed correctly inside table
62
+ queueMicrotask(() => {
63
+ var _api$table, _api$table$actions$in, _api$table$actions;
64
+ // @ts-expect-error
65
+ (_api$table = api.table) === null || _api$table === void 0 ? void 0 : (_api$table$actions$in = (_api$table$actions = _api$table.actions).insertTable) === null || _api$table$actions$in === void 0 ? void 0 : _api$table$actions$in.call(_api$table$actions, {
66
+ action: ACTION.INSERTED,
67
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
68
+ actionSubjectId: ACTION_SUBJECT_ID.TABLE,
69
+ attributes: {
70
+ inputMethod
71
+ },
72
+ eventType: EVENT_TYPE.TRACK
73
+ })(state, dispatch);
74
+ });
75
+ break;
76
+ case 'image upload':
77
+ (_api$imageUpload = api.imageUpload) === null || _api$imageUpload === void 0 ? void 0 : _api$imageUpload.actions.startUpload()(state, dispatch);
78
+ break;
79
+ case 'media':
80
+ const mediaState = (_api$media = api.media) === null || _api$media === void 0 ? void 0 : _api$media.sharedState.currentState();
81
+ if (mediaState) {
82
+ var _api$analytics;
83
+ mediaState.showMediaPicker();
84
+ // @ts-expect-error
85
+ (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent({
86
+ action: ACTION.OPENED,
87
+ actionSubject: ACTION_SUBJECT.PICKER,
88
+ actionSubjectId: ACTION_SUBJECT_ID.PICKER_CLOUD,
89
+ attributes: {
90
+ inputMethod
91
+ },
92
+ eventType: EVENT_TYPE.UI
93
+ });
94
+ }
95
+ break;
96
+ case 'mention':
97
+ const pluginState = (_api$mention = api.mention) === null || _api$mention === void 0 ? void 0 : _api$mention.sharedState.currentState();
98
+ if (pluginState && pluginState.canInsertMention) {
99
+ var _api$mention2, _api$mention2$actions;
100
+ // @ts-expect-error
101
+ (_api$mention2 = api.mention) === null || _api$mention2 === void 0 ? void 0 : (_api$mention2$actions = _api$mention2.actions) === null || _api$mention2$actions === void 0 ? void 0 : _api$mention2$actions.openTypeAhead(inputMethod);
102
+ }
103
+ break;
104
+ case 'emoji':
105
+ // @ts-expect-error
106
+ (_api$emoji = api.emoji) === null || _api$emoji === void 0 ? void 0 : _api$emoji.actions.openTypeAhead(inputMethod);
107
+ break;
108
+ case 'codeblock':
109
+ (_api$codeBlock = api.codeBlock) === null || _api$codeBlock === void 0 ? void 0 : _api$codeBlock.actions.insertCodeBlock(inputMethod);
110
+ break;
111
+ case 'blockquote':
112
+ // @ts-expect-error
113
+ (_api$blockType = api.blockType) === null || _api$blockType === void 0 ? void 0 : _api$blockType.actions.insertBlockQuote(inputMethod);
114
+ break;
115
+ case 'panel':
116
+ (_api$panel = api.panel) === null || _api$panel === void 0 ? void 0 : _api$panel.actions.insertPanel(inputMethod);
117
+ break;
118
+ case 'action':
119
+ // @ts-expect-error
120
+ (_api$taskDecision = api.taskDecision) === null || _api$taskDecision === void 0 ? void 0 : _api$taskDecision.actions.insertTaskDecision('taskList', inputMethod)(state, dispatch);
121
+ break;
122
+ case 'decision':
123
+ // @ts-expect-error
124
+ (_api$taskDecision2 = api.taskDecision) === null || _api$taskDecision2 === void 0 ? void 0 : _api$taskDecision2.actions.insertTaskDecision('decisionList', inputMethod)(state, dispatch);
125
+ break;
126
+ case 'horizontalrule':
127
+ // @ts-expect-error
128
+ (_api$rule = api.rule) === null || _api$rule === void 0 ? void 0 : _api$rule.actions.insertHorizontalRule(inputMethod)(state, dispatch);
129
+ break;
130
+ case 'macro':
131
+ (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute((_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 ? void 0 : _api$quickInsert.commands.openElementBrowserModal);
132
+ break;
133
+ case 'date':
134
+ (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute((_api$date = api.date) === null || _api$date === void 0 ? void 0 : (_api$date$commands = _api$date.commands) === null || _api$date$commands === void 0 ? void 0 : _api$date$commands.insertDate({
135
+ // @ts-expect-error
136
+ inputMethod
137
+ }));
138
+ break;
139
+ case 'placeholder text':
140
+ (_api$placeholderText = api.placeholderText) === null || _api$placeholderText === void 0 ? void 0 : _api$placeholderText.actions.showPlaceholderFloatingToolbar(editorView.state, editorView.dispatch);
141
+ break;
142
+ case 'layout':
143
+ // @ts-expect-error
144
+ (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.actions.insertLayoutColumns(inputMethod)(editorView.state, editorView.dispatch);
145
+ break;
146
+ case 'status':
147
+ // @ts-expect-error
148
+ (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute((_api$status = api.status) === null || _api$status === void 0 ? void 0 : (_api$status$commands = _api$status.commands) === null || _api$status$commands === void 0 ? void 0 : _api$status$commands.insertStatus(inputMethod));
149
+ break;
150
+
151
+ // https://product-fabric.atlassian.net/browse/ED-8053
152
+ // @ts-ignore: OK to fallthrough to default
153
+ case 'expand':
154
+ if (options.allowExpand) {
155
+ var _api$expand;
156
+ (_api$expand = api.expand) === null || _api$expand === void 0 ? void 0 : _api$expand.actions.insertExpand(state, dispatch);
157
+ break;
158
+ }
159
+
160
+ // eslint-disable-next-line no-fallthrough
161
+ default:
162
+ // leaving this blank for now
163
+ }
164
+ };
165
+ return /*#__PURE__*/React.createElement(Box, {
166
+ xcss: panelWrapper
167
+ }, /*#__PURE__*/React.createElement(Box, {
168
+ xcss: panelContentHeader
169
+ }, /*#__PURE__*/React.createElement(Heading, {
170
+ size: "small",
171
+ as: "h2"
172
+ }, formatMessage(toolbarInsertBlockMessages.insertRightRailTitle)), /*#__PURE__*/React.createElement(IconButton, {
173
+ appearance: "subtle",
174
+ testId: "right-rail-insert-menu-close-button",
175
+ label: formatMessage(toolbarInsertBlockMessages.closeInsertRightRail),
176
+ icon: CrossIcon,
177
+ onClick: () => {
178
+ if (!api) {
179
+ return;
180
+ }
181
+ api.core.actions.execute(({
182
+ tr
183
+ }) => {
184
+ var _api$contextPanel;
185
+ toggleInsertMenuRightRail(tr);
186
+ (_api$contextPanel = api.contextPanel) === null || _api$contextPanel === void 0 ? void 0 : _api$contextPanel.actions.applyChange(tr);
187
+ return tr;
188
+ });
189
+ }
190
+ })), /*#__PURE__*/React.createElement(InsertMenu, {
191
+ editorView: editorView,
192
+ dropdownItems: dropdownItems,
193
+ onInsert: onInsert,
194
+ toggleVisiblity: () => {},
195
+ showElementBrowserLink: true,
196
+ pluginInjectionApi: api
197
+ }));
10
198
  };
@@ -0,0 +1,54 @@
1
+ import { useMemo } from 'react';
2
+ import { useIntl } from 'react-intl-next';
3
+ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
4
+ import { createItems } from '../ToolbarInsertBlock/create-items';
5
+ export const useInsertMenuRailItems = (editorView, options, api) => {
6
+ const {
7
+ formatMessage
8
+ } = useIntl();
9
+ const {
10
+ dateState,
11
+ hyperlinkState,
12
+ imageUploadState,
13
+ mentionState,
14
+ emojiState,
15
+ blockTypeState,
16
+ mediaState,
17
+ typeAheadState,
18
+ placeholderTextState
19
+ } = useSharedPluginState(api, ['hyperlink', 'date', 'imageUpload', 'mention', 'emoji', 'blockType', 'media', 'typeAhead', 'placeholderText']);
20
+ const [_, dropdownItems] = useMemo(() => {
21
+ var _ref;
22
+ return createItems({
23
+ isTypeAheadAllowed: Boolean(typeAheadState === null || typeAheadState === void 0 ? void 0 : typeAheadState.isAllowed),
24
+ tableSupported: !!editorView.state.schema.nodes.table,
25
+ tableSelectorSupported: options.tableSelectorSupported && !!editorView.state.schema.nodes.table,
26
+ mediaUploadsEnabled: (_ref = mediaState && mediaState.allowsUploads) !== null && _ref !== void 0 ? _ref : undefined,
27
+ mediaSupported: !!mediaState,
28
+ imageUploadSupported: !!(api !== null && api !== void 0 && api.imageUpload),
29
+ imageUploadEnabled: imageUploadState === null || imageUploadState === void 0 ? void 0 : imageUploadState.enabled,
30
+ mentionsSupported: !!(mentionState && mentionState.mentionProvider),
31
+ mentionsDisabled: !!(mentionState && !mentionState.canInsertMention),
32
+ actionSupported: !!editorView.state.schema.nodes.taskItem,
33
+ decisionSupported: !!editorView.state.schema.nodes.decisionItem,
34
+ linkSupported: !!hyperlinkState,
35
+ linkDisabled: !hyperlinkState || !hyperlinkState.canInsertLink || !!hyperlinkState.activeLinkMark,
36
+ emojiDisabled: !emojiState || !emojiState.emojiProvider,
37
+ nativeStatusSupported: options.nativeStatusSupported,
38
+ dateEnabled: !!dateState,
39
+ placeholderTextEnabled: placeholderTextState && placeholderTextState.allowInserting,
40
+ horizontalRuleEnabled: options.horizontalRuleEnabled,
41
+ layoutSectionEnabled: Boolean(api === null || api === void 0 ? void 0 : api.layout),
42
+ expandEnabled: !!options.allowExpand,
43
+ showElementBrowserLink: options.showElementBrowserLink,
44
+ emojiProvider: emojiState === null || emojiState === void 0 ? void 0 : emojiState.emojiProvider,
45
+ availableWrapperBlockTypes: blockTypeState && blockTypeState.availableWrapperBlockTypes,
46
+ insertMenuItems: options.insertMenuItems,
47
+ schema: editorView.state.schema,
48
+ numberOfButtons: 10,
49
+ formatMessage,
50
+ isNewMenuEnabled: true
51
+ });
52
+ }, [api === null || api === void 0 ? void 0 : api.imageUpload, api === null || api === void 0 ? void 0 : api.layout, blockTypeState, dateState, editorView.state.schema, emojiState, formatMessage, hyperlinkState, imageUploadState === null || imageUploadState === void 0 ? void 0 : imageUploadState.enabled, mediaState, mentionState, options.allowExpand, options.horizontalRuleEnabled, options.insertMenuItems, options.nativeStatusSupported, options.showElementBrowserLink, options.tableSelectorSupported, placeholderTextState, typeAheadState === null || typeAheadState === void 0 ? void 0 : typeAheadState.isAllowed]);
53
+ return dropdownItems;
54
+ };
@@ -1,53 +1,120 @@
1
1
  import React from 'react';
2
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
4
  import ActionListIcon from '../assets/action-list';
3
5
  import ApprovalsTrackerIcon from '../assets/approvals-tracker';
4
6
  import DecisionMatrixIcon from '../assets/decision-matrix';
5
7
  import DiscussionNotesIcon from '../assets/discussion-notes';
6
8
  import InstructionsOutlineIcon from '../assets/instructions-outline';
7
- export const templateOptions = [{
9
+ import { actionList, approvalsTracker, decisionMatrix, discussionNotes, instructionsOutline } from './templates';
10
+ const getTemplateInsertionPayload = (templateType, source) => ({
11
+ action: ACTION.INSERTED,
12
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
13
+ actionSubjectId: 'elementTemplate',
14
+ attributes: {
15
+ inputMethod: source !== null && source !== void 0 ? source : INPUT_METHOD.QUICK_INSERT,
16
+ templateType
17
+ },
18
+ eventType: EVENT_TYPE.TRACK
19
+ });
20
+ const getTableWidth = api => {
21
+ var _api$table, _api$table$sharedStat;
22
+ return api !== null && api !== void 0 && (_api$table = api.table) !== null && _api$table !== void 0 && (_api$table$sharedStat = _api$table.sharedState.currentState()) !== null && _api$table$sharedStat !== void 0 && _api$table$sharedStat.isFullWidthModeEnabled ? 1800 : 760;
23
+ };
24
+ export const templateOptions = api => [{
8
25
  title: 'Discussion notes',
26
+ // @ts-ignore
27
+ id: 'discussionNotes',
9
28
  description: 'Record discussion points and action items',
10
29
  keywords: ['decisions', 'summary', 'meeting', 'chat', 'debrief', 'track', 'keep track', 'tasks', 'outstanding items', 'owners'],
11
30
  // Place templates right after AI item
12
31
  priority: 99,
13
32
  icon: () => /*#__PURE__*/React.createElement(DiscussionNotesIcon, null),
14
- action: () => {
15
- return false;
33
+ action: (insert, state, source) => {
34
+ var _api$analytics;
35
+ const tr = insert(Fragment.fromJSON(state.schema, discussionNotes(getTableWidth(api))), {
36
+ // @ts-ignore
37
+ isTemplate: true
38
+ });
39
+ api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent(
40
+ // @ts-ignore
41
+ getTemplateInsertionPayload('discussionNotes', source))(tr);
42
+ return tr;
16
43
  }
17
44
  }, {
18
45
  title: 'Approvals tracker',
46
+ // @ts-ignore
47
+ id: 'approvalsTracker',
19
48
  description: 'Track reviewer approvals and dates',
20
49
  keywords: ['reviews', 'requests', 'rejected requests', 'review dates', 'timeline', 'checklist', 'sme timeline', 'sme requests', 'sme check', 'table'],
21
50
  priority: 99,
22
51
  icon: () => /*#__PURE__*/React.createElement(ApprovalsTrackerIcon, null),
23
- action: () => {
24
- return false;
52
+ action: (insert, state, source) => {
53
+ var _api$analytics2;
54
+ const tr = insert(Fragment.fromJSON(state.schema, approvalsTracker(getTableWidth(api))), {
55
+ // @ts-ignore
56
+ isTemplate: true
57
+ });
58
+ api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.attachAnalyticsEvent(
59
+ // @ts-ignore
60
+ getTemplateInsertionPayload('approvalsTracker', source))(tr);
61
+ return tr;
25
62
  }
26
63
  }, {
27
64
  title: 'Decision matrix',
65
+ // @ts-ignore
66
+ id: 'decisionMatrix',
28
67
  description: 'Compare options and make recommendations',
29
68
  keywords: ['pros', 'cons', 'recommended', 'rationale', 'evaluation', 'options', 'choice', 'table'],
30
69
  priority: 99,
31
70
  icon: () => /*#__PURE__*/React.createElement(DecisionMatrixIcon, null),
32
- action: () => {
33
- return false;
71
+ action: (insert, state, source) => {
72
+ var _api$analytics3;
73
+ const tr = insert(Fragment.fromJSON(state.schema, decisionMatrix(getTableWidth(api))), {
74
+ // @ts-ignore
75
+ isTemplate: true
76
+ });
77
+ api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.attachAnalyticsEvent(
78
+ // @ts-ignore
79
+ getTemplateInsertionPayload('decisionMatrix', source))(tr);
80
+ return tr;
34
81
  }
35
82
  }, {
36
83
  title: 'List of actions',
84
+ // @ts-ignore
85
+ id: 'actionList',
37
86
  description: 'Track tasks, assignees and deadlines',
38
87
  keywords: ['checklist', 'check', 'items', 'shopping list', 'jtbd', 'jobs to be done', 'due date', 'progress', 'task', 'tasks', 'prioritization', 'timeline', 'approvals', 'reviewers', 'review date'],
39
88
  priority: 99,
40
89
  icon: () => /*#__PURE__*/React.createElement(ActionListIcon, null),
41
- action: () => {
42
- return false;
90
+ action: (insert, state, source) => {
91
+ var _api$analytics4;
92
+ // @ts-ignore
93
+ const tr = insert(Fragment.fromJSON(state.schema, actionList), {
94
+ isTemplate: true
95
+ });
96
+ api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions.attachAnalyticsEvent(
97
+ // @ts-ignore
98
+ getTemplateInsertionPayload('actionList', source))(tr);
99
+ return tr;
43
100
  }
44
101
  }, {
45
102
  title: 'Instructions outline',
103
+ // @ts-ignore
104
+ id: 'instructionsOutline',
46
105
  description: 'Detailed steps for any process',
47
106
  keywords: ['steps', 'manual', 'tasks', 'jobs to be done', 'jtbd', 'how-to', 'guide', 'journey', 'checklist', 'tutorial', 'map', 'brochure', 'columns', 'layout', 'help'],
48
107
  priority: 99,
49
108
  icon: () => /*#__PURE__*/React.createElement(InstructionsOutlineIcon, null),
50
- action: () => {
51
- return false;
109
+ action: (insert, state, source) => {
110
+ var _api$analytics5;
111
+ // @ts-ignore
112
+ const tr = insert(Fragment.fromJSON(state.schema, instructionsOutline), {
113
+ isTemplate: true
114
+ });
115
+ api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions.attachAnalyticsEvent(
116
+ // @ts-ignore
117
+ getTemplateInsertionPayload('instructionsOutline', source))(tr);
118
+ return tr;
52
119
  }
53
120
  }];