@atlaskit/editor-plugin-block-type 12.1.1 → 12.1.3

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 (29) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cjs/blockTypePlugin.js +1 -1
  3. package/dist/cjs/pm-plugins/commands/block-type.js +125 -18
  4. package/dist/cjs/pm-plugins/main.js +3 -3
  5. package/dist/cjs/pm-plugins/ui/ToolbarBlockType/HeadingButton.compiled.css +1 -0
  6. package/dist/cjs/pm-plugins/ui/ToolbarBlockType/HeadingButton.js +23 -0
  7. package/dist/cjs/pm-plugins/ui/ToolbarBlockType/QuoteButton.js +16 -0
  8. package/dist/cjs/pm-plugins/utils.js +85 -11
  9. package/dist/es2019/blockTypePlugin.js +1 -1
  10. package/dist/es2019/pm-plugins/commands/block-type.js +105 -2
  11. package/dist/es2019/pm-plugins/main.js +3 -3
  12. package/dist/es2019/pm-plugins/ui/ToolbarBlockType/HeadingButton.compiled.css +1 -0
  13. package/dist/es2019/pm-plugins/ui/ToolbarBlockType/HeadingButton.js +24 -0
  14. package/dist/es2019/pm-plugins/ui/ToolbarBlockType/QuoteButton.js +17 -0
  15. package/dist/es2019/pm-plugins/utils.js +80 -5
  16. package/dist/esm/blockTypePlugin.js +1 -1
  17. package/dist/esm/pm-plugins/commands/block-type.js +123 -18
  18. package/dist/esm/pm-plugins/main.js +3 -3
  19. package/dist/esm/pm-plugins/ui/ToolbarBlockType/HeadingButton.compiled.css +1 -0
  20. package/dist/esm/pm-plugins/ui/ToolbarBlockType/HeadingButton.js +23 -0
  21. package/dist/esm/pm-plugins/ui/ToolbarBlockType/QuoteButton.js +16 -0
  22. package/dist/esm/pm-plugins/utils.js +81 -10
  23. package/dist/types/pm-plugins/commands/block-type.d.ts +2 -0
  24. package/dist/types/pm-plugins/main.d.ts +1 -1
  25. package/dist/types/pm-plugins/utils.d.ts +18 -2
  26. package/dist/types-ts4.5/pm-plugins/commands/block-type.d.ts +2 -0
  27. package/dist/types-ts4.5/pm-plugins/main.d.ts +1 -1
  28. package/dist/types-ts4.5/pm-plugins/utils.d.ts +18 -2
  29. package/package.json +4 -4
@@ -1,9 +1,12 @@
1
1
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { createToggleBlockMarkOnRangeNext } from '@atlaskit/editor-common/commands';
2
3
  import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
3
4
  import { filterChildrenBetween, wrapSelectionIn } from '@atlaskit/editor-common/utils';
4
5
  import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
5
6
  import { CellSelection } from '@atlaskit/editor-tables';
7
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
6
8
  import { HEADINGS_BY_NAME, NORMAL_TEXT } from '../block-types';
9
+ import { getSelectionRangeExpandedToLists } from '../utils';
7
10
  import { FORMATTING_NODE_TYPES, FORMATTING_MARK_TYPES, cellSelectionNodesBetween, formatTypes, clearNodeFormattingOnSelection } from './clear-formatting';
8
11
  import { wrapSelectionInBlockType } from './wrapSelectionIn';
9
12
  export function setBlockType(name) {
@@ -18,6 +21,11 @@ export function setBlockType(name) {
18
21
  tr
19
22
  });
20
23
  }
24
+ if (name === 'smallText' && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
25
+ return setSmallText()({
26
+ tr
27
+ });
28
+ }
21
29
  const headingBlockType = HEADINGS_BY_NAME[name];
22
30
  if (headingBlockType && nodes.heading && headingBlockType.level) {
23
31
  return setHeading(headingBlockType.level)({
@@ -69,6 +77,24 @@ export function setHeading(level, fromBlockQuote) {
69
77
  });
70
78
  }
71
79
  });
80
+
81
+ // Remove fontSize mark from transformed content in range
82
+ // List content stays as paragraphs (headings aren't allowed in list items),
83
+ // but non-list content has been converted to headings by setBlockType above.
84
+ const {
85
+ fontSize
86
+ } = schema.marks;
87
+ if (fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
88
+ const allowedBlocks = [schema.nodes.paragraph, schema.nodes.heading];
89
+ if (selection instanceof CellSelection) {
90
+ selection.forEachCell((cell, pos) => {
91
+ createToggleBlockMarkOnRangeNext(fontSize, () => false, allowedBlocks)(pos, pos + cell.nodeSize, tr);
92
+ });
93
+ } else {
94
+ const expandedRange = getSelectionRangeExpandedToLists(tr);
95
+ createToggleBlockMarkOnRangeNext(fontSize, () => false, allowedBlocks)(expandedRange.from, expandedRange.to, tr);
96
+ }
97
+ }
72
98
  return tr;
73
99
  };
74
100
  }
@@ -77,13 +103,19 @@ export function setBlockTypeWithAnalytics(name, inputMethod, editorAnalyticsApi,
77
103
  tr
78
104
  }) => {
79
105
  const {
80
- nodes
106
+ nodes,
107
+ marks
81
108
  } = tr.doc.type.schema;
82
109
  if (name === 'normal' && nodes.paragraph) {
83
110
  return setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi, fromBlockQuote)({
84
111
  tr
85
112
  });
86
113
  }
114
+ if (name === 'smallText' && marks.fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
115
+ return setSmallTextWithAnalytics(inputMethod, editorAnalyticsApi)({
116
+ tr
117
+ });
118
+ }
87
119
  const headingBlockType = HEADINGS_BY_NAME[name];
88
120
  if (headingBlockType && nodes.heading && headingBlockType.level) {
89
121
  return setHeadingWithAnalytics(headingBlockType.level, inputMethod, editorAnalyticsApi, fromBlockQuote)({
@@ -93,6 +125,60 @@ export function setBlockTypeWithAnalytics(name, inputMethod, editorAnalyticsApi,
93
125
  return null;
94
126
  };
95
127
  }
128
+ export function setSmallText() {
129
+ return function ({
130
+ tr
131
+ }) {
132
+ const {
133
+ marks: {
134
+ fontSize
135
+ },
136
+ nodes: {
137
+ paragraph
138
+ }
139
+ } = tr.doc.type.schema;
140
+ if (!fontSize) {
141
+ return null;
142
+ }
143
+ const {
144
+ selection
145
+ } = tr;
146
+ if (selection instanceof CellSelection) {
147
+ selection.forEachCell((cell, pos) => {
148
+ tr.setBlockType(pos, pos + cell.nodeSize, paragraph);
149
+ createToggleBlockMarkOnRangeNext(fontSize, () => ({
150
+ fontSize: 'small'
151
+ }), [paragraph])(pos, pos + cell.nodeSize, tr);
152
+ });
153
+ } else {
154
+ tr.setBlockType(selection.from, selection.to, paragraph);
155
+ const expandedRange = getSelectionRangeExpandedToLists(tr);
156
+ createToggleBlockMarkOnRangeNext(fontSize, () => ({
157
+ fontSize: 'small'
158
+ }), [paragraph])(expandedRange.from, expandedRange.to, tr);
159
+ }
160
+ return tr;
161
+ };
162
+ }
163
+ export function setSmallTextWithAnalytics(inputMethod, editorAnalyticsApi) {
164
+ return withCurrentHeadingLevel(previousHeadingLevel => ({
165
+ tr
166
+ }) => {
167
+ editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
168
+ action: ACTION.FORMATTED,
169
+ actionSubject: ACTION_SUBJECT.TEXT,
170
+ eventType: EVENT_TYPE.TRACK,
171
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_SMALL_TEXT,
172
+ attributes: {
173
+ inputMethod,
174
+ previousBlockType: previousHeadingLevel !== undefined ? String(previousHeadingLevel) : undefined
175
+ }
176
+ })(tr);
177
+ return setSmallText()({
178
+ tr
179
+ });
180
+ });
181
+ }
96
182
  export function setNormalText(fromBlockQuote) {
97
183
  return function ({
98
184
  tr
@@ -105,6 +191,8 @@ export function setNormalText(fromBlockQuote) {
105
191
  }
106
192
  }
107
193
  } = tr;
194
+
195
+ // Apply normal text to the selection range (handles non-list content)
108
196
  const ranges = selection instanceof CellSelection ? selection.ranges : [selection];
109
197
  ranges.forEach(({
110
198
  $from,
@@ -128,6 +216,21 @@ export function setNormalText(fromBlockQuote) {
128
216
  tr.setBlockType($from.pos, $to.pos, schema.nodes.paragraph);
129
217
  }
130
218
  });
219
+
220
+ // Remove fontSize mark from any lists the selection touches
221
+ const {
222
+ fontSize
223
+ } = schema.marks;
224
+ if (fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
225
+ if (selection instanceof CellSelection) {
226
+ selection.forEachCell((cell, pos) => {
227
+ createToggleBlockMarkOnRangeNext(fontSize, () => false, [schema.nodes.paragraph])(pos, pos + cell.nodeSize, tr);
228
+ });
229
+ } else {
230
+ const expandedRange = getSelectionRangeExpandedToLists(tr);
231
+ createToggleBlockMarkOnRangeNext(fontSize, () => false, [schema.nodes.paragraph])(expandedRange.from, expandedRange.to, tr);
232
+ }
233
+ }
131
234
  return tr;
132
235
  };
133
236
  }
@@ -294,7 +397,7 @@ export const insertBlockQuoteWithAnalytics = (inputMethod, editorAnalyticsApi) =
294
397
  })(insertBlockQuote());
295
398
  };
296
399
  export function insertBlockQuoteWithAnalyticsCommand(inputMethod, editorAnalyticsApi) {
297
- return withCurrentHeadingLevel(previousHeadingLevel => ({
400
+ return withCurrentHeadingLevel(() => ({
298
401
  tr
299
402
  }) => {
300
403
  const {
@@ -75,7 +75,7 @@ const autoformatHeading = (headingLevel, editorAnalyticsApi) => {
75
75
  return setHeadingWithAnalytics(headingLevel, INPUT_METHOD.FORMATTING, editorAnalyticsApi);
76
76
  };
77
77
  export const pluginKey = new PluginKey('blockTypePlugin');
78
- export const createPlugin = (editorAPI, dispatch, lastNodeMustBeParagraph, includeBlockQuoteAsTextstyleOption) => {
78
+ export const createPlugin = (editorAPI, dispatch, lastNodeMustBeParagraph, includeBlockQuoteAsTextstyleOption, allowFontSize) => {
79
79
  var _editorAPI$analytics;
80
80
  const editorAnalyticsApi = editorAPI === null || editorAPI === void 0 ? void 0 : (_editorAPI$analytics = editorAPI.analytics) === null || _editorAPI$analytics === void 0 ? void 0 : _editorAPI$analytics.actions;
81
81
  let altKeyLocation = 0;
@@ -105,7 +105,7 @@ export const createPlugin = (editorAPI, dispatch, lastNodeMustBeParagraph, inclu
105
105
  const formattingIsPresent = hasBlockQuoteInOptions(availableBlockTypesInDropdown) ? checkFormattingIsPresent(state) : undefined;
106
106
  return {
107
107
  currentBlockType: detectBlockType(availableBlockTypesInDropdown, state),
108
- blockTypesDisabled: areBlockTypesDisabled(state),
108
+ blockTypesDisabled: areBlockTypesDisabled(state, allowFontSize),
109
109
  availableBlockTypes,
110
110
  availableWrapperBlockTypes,
111
111
  availableBlockTypesInDropdown,
@@ -116,7 +116,7 @@ export const createPlugin = (editorAPI, dispatch, lastNodeMustBeParagraph, inclu
116
116
  const newPluginState = {
117
117
  ...oldPluginState,
118
118
  currentBlockType: detectBlockType(oldPluginState.availableBlockTypesInDropdown, newState),
119
- blockTypesDisabled: areBlockTypesDisabled(newState),
119
+ blockTypesDisabled: areBlockTypesDisabled(newState, allowFontSize),
120
120
  formattingIsPresent: hasBlockQuoteInOptions(oldPluginState.availableBlockTypesInDropdown) ? checkFormattingIsPresent(newState) : undefined
121
121
  };
122
122
  if (newPluginState.currentBlockType !== oldPluginState.currentBlockType || newPluginState.blockTypesDisabled !== oldPluginState.blockTypesDisabled || newPluginState.formattingIsPresent !== oldPluginState.formattingIsPresent) {
@@ -1,6 +1,7 @@
1
1
  ._11c810sd{font:var(--ds-font-heading-large,normal 653 24px/28px "Atlassian Sans",ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Ubuntu,"Helvetica Neue",sans-serif)}
2
2
  ._11c812ln{font:var(--ds-font-heading-xlarge,normal 653 28px/2pc "Atlassian Sans",ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Ubuntu,"Helvetica Neue",sans-serif)}
3
3
  ._11c812rg{font:var(--_1h4o6ch)}
4
+ ._11c8130a{font:var(--_1b6nbh6)}
4
5
  ._11c81af2{font:var(--ds-font-heading-medium,normal 653 20px/24px "Atlassian Sans",ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Ubuntu,"Helvetica Neue",sans-serif)}
5
6
  ._11c81e3o{font:var(--ds-font-heading-small,normal 653 1pc/20px "Atlassian Sans",ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Ubuntu,"Helvetica Neue",sans-serif)}
6
7
  ._11c81fq3{font:var(--_1d0ko3v)}
@@ -7,11 +7,14 @@ import { ax, ix } from "@compiled/react/runtime";
7
7
  import { useIntl } from 'react-intl-next';
8
8
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
9
9
  import { formatShortcut, setNormalText, toggleHeading1, toggleHeading2, toggleHeading3, toggleHeading4, toggleHeading5, toggleHeading6 } from '@atlaskit/editor-common/keymaps';
10
+ import { useEditorToolbar } from '@atlaskit/editor-common/toolbar';
10
11
  import { editorUGCToken } from '@atlaskit/editor-common/ugc-tokens';
11
12
  import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
12
13
  import { ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
13
14
  import { Box } from '@atlaskit/primitives/compiled';
14
15
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
16
+ import { isSelectionInsideListNode } from '../../utils';
17
+ const smallTextStyle = null;
15
18
  const normalStyle = null;
16
19
  const heading1Style = null;
17
20
  const heading2Style = null;
@@ -66,6 +69,13 @@ const HeadingText = ({
66
69
  "--_1c98jvx": ix(editorUGCToken('editor.font.heading.h6'))
67
70
  }
68
71
  }, children);
72
+ case 'smallText':
73
+ return /*#__PURE__*/React.createElement("div", {
74
+ className: ax(["_11c8130a"]),
75
+ style: {
76
+ "--_1b6nbh6": ix(editorUGCToken('editor.font.body.small'))
77
+ }
78
+ }, children);
69
79
  case 'normal':
70
80
  default:
71
81
  return /*#__PURE__*/React.createElement("div", {
@@ -100,6 +110,12 @@ const shortcuts = {
100
110
  heading5: toggleHeading5,
101
111
  heading6: toggleHeading6
102
112
  };
113
+ const shouldDisableHeadingButton = (state, blockType) => {
114
+ if (!state) {
115
+ return false;
116
+ }
117
+ return isSelectionInsideListNode(state) && blockType.name !== 'normal' && blockType.name !== 'smallText';
118
+ };
103
119
  export const HeadingButton = ({
104
120
  blockType,
105
121
  api
@@ -109,12 +125,19 @@ export const HeadingButton = ({
109
125
  } = useIntl();
110
126
  const currentBlockType = useSharedPluginStateSelector(api, 'blockType.currentBlockType');
111
127
  const availableBlockTypesInDropdown = useSharedPluginStateSelector(api, 'blockType.availableBlockTypesInDropdown');
128
+ const {
129
+ editorView
130
+ } = useEditorToolbar();
112
131
  if (!(availableBlockTypesInDropdown !== null && availableBlockTypesInDropdown !== void 0 && availableBlockTypesInDropdown.some(availableBlockType => availableBlockType.name === blockType.name))) {
113
132
  return null;
114
133
  }
134
+ const isDisabled = expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? shouldDisableHeadingButton(editorView === null || editorView === void 0 ? void 0 : editorView.state, blockType) : false;
115
135
  const fromBlockQuote = (currentBlockType === null || currentBlockType === void 0 ? void 0 : currentBlockType.name) === 'blockquote';
116
136
  const onClick = () => {
117
137
  var _api$core, _api$blockType, _api$blockType$comman;
138
+ if (isDisabled) {
139
+ return;
140
+ }
118
141
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockType = api.blockType) === null || _api$blockType === void 0 ? void 0 : (_api$blockType$comman = _api$blockType.commands) === null || _api$blockType$comman === void 0 ? void 0 : _api$blockType$comman.setTextLevel(blockType.name, INPUT_METHOD.TOOLBAR, fromBlockQuote));
119
142
  };
120
143
  const shortcut = formatShortcut(shortcuts[blockType.name]);
@@ -126,6 +149,7 @@ export const HeadingButton = ({
126
149
  }) : undefined,
127
150
  onClick: onClick,
128
151
  isSelected: isSelected,
152
+ isDisabled: isDisabled,
129
153
  ariaKeyshortcuts: shortcut
130
154
  }, expValEquals('platform_editor_toolbar_aifc_use_editor_typography', 'isEnabled', true) ? /*#__PURE__*/React.createElement(HeadingText, {
131
155
  headingType: blockType.name
@@ -2,8 +2,17 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl-next';
3
3
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
4
4
  import { formatShortcut, toggleBlockQuote } from '@atlaskit/editor-common/keymaps';
5
+ import { useEditorToolbar } from '@atlaskit/editor-common/toolbar';
5
6
  import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
6
7
  import { ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
8
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
+ import { isSelectionInsideListNode } from '../../utils';
10
+ const shouldDisableQuoteButton = state => {
11
+ if (!state) {
12
+ return false;
13
+ }
14
+ return isSelectionInsideListNode(state);
15
+ };
7
16
  export const QuoteButton = ({
8
17
  blockType,
9
18
  api
@@ -13,11 +22,18 @@ export const QuoteButton = ({
13
22
  } = useIntl();
14
23
  const availableBlockTypesInDropdown = useSharedPluginStateSelector(api, 'blockType.availableBlockTypesInDropdown');
15
24
  const currentBlockType = useSharedPluginStateSelector(api, 'blockType.currentBlockType');
25
+ const {
26
+ editorView
27
+ } = useEditorToolbar();
16
28
  if (!(availableBlockTypesInDropdown !== null && availableBlockTypesInDropdown !== void 0 && availableBlockTypesInDropdown.some(availableBlockType => availableBlockType.name === blockType.name))) {
17
29
  return null;
18
30
  }
31
+ const isDisabled = expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? shouldDisableQuoteButton(editorView === null || editorView === void 0 ? void 0 : editorView.state) : false;
19
32
  const onClick = () => {
20
33
  var _api$core, _api$blockType, _api$blockType$comman;
34
+ if (isDisabled) {
35
+ return;
36
+ }
21
37
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockType = api.blockType) === null || _api$blockType === void 0 ? void 0 : (_api$blockType$comman = _api$blockType.commands) === null || _api$blockType$comman === void 0 ? void 0 : _api$blockType$comman.insertBlockQuote(INPUT_METHOD.TOOLBAR));
22
38
  };
23
39
  const shortcut = formatShortcut(toggleBlockQuote);
@@ -28,6 +44,7 @@ export const QuoteButton = ({
28
44
  }) : undefined,
29
45
  onClick: onClick,
30
46
  isSelected: currentBlockType === blockType,
47
+ isDisabled: isDisabled,
31
48
  ariaKeyshortcuts: shortcut
32
49
  }, formatMessage(blockType.title));
33
50
  };
@@ -1,5 +1,6 @@
1
1
  import { anyMarkActive } from '@atlaskit/editor-common/mark';
2
2
  import { createRule, createWrappingJoinRule } from '@atlaskit/editor-common/utils';
3
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
4
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
5
  import { WRAPPER_BLOCK_TYPES, FORMATTING_NODE_TYPES, FORMATTING_MARK_TYPES } from './block-types';
5
6
  export const isNodeAWrappingBlockNode = node => {
@@ -71,14 +72,20 @@ function getSelectedWrapperNodes(state) {
71
72
  /**
72
73
  * Function will check if changing block types: Paragraph, Heading is enabled.
73
74
  */
74
- export function areBlockTypesDisabled(state) {
75
+ export function areBlockTypesDisabled(state, allowFontSize = false) {
75
76
  const nodesTypes = getSelectedWrapperNodes(state);
76
77
  const {
77
78
  panel,
78
79
  blockquote,
79
80
  bulletList,
80
- orderedList
81
+ orderedList,
82
+ listItem
81
83
  } = state.schema.nodes;
84
+
85
+ // When the small font size experiment is enabled, allow block type changes inside lists
86
+ // so that users can toggle between Normal text and Small text within list contexts.
87
+ // Note: taskList/taskItem are not excluded here until blockTaskItem conversion is implemented (WI 4).
88
+ const excludedTypes = allowFontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? [panel, bulletList, orderedList, listItem] : [panel];
82
89
  if (editorExperiment('platform_editor_blockquote_in_text_formatting_menu', true)) {
83
90
  let hasQuote = false;
84
91
  let hasNestedListInQuote = false;
@@ -99,9 +106,38 @@ export function areBlockTypesDisabled(state) {
99
106
  }
100
107
  return !hasNestedListInQuote;
101
108
  });
102
- return nodesTypes.filter(type => type !== panel).length > 0 && (!hasQuote || hasNestedListInQuote);
109
+ return nodesTypes.filter(type => !excludedTypes.includes(type)).length > 0 && (!hasQuote || hasNestedListInQuote);
110
+ }
111
+ return nodesTypes.filter(type => !excludedTypes.includes(type)).length > 0;
112
+ }
113
+
114
+ /**
115
+ * Checks if the current selection is inside a list node (bulletList, orderedList, or taskList).
116
+ * Used to determine which text styles should be enabled when the small font size experiment is active.
117
+ */
118
+ export function isSelectionInsideListNode(state) {
119
+ if (!state.selection) {
120
+ return false;
103
121
  }
104
- return nodesTypes.filter(type => type !== panel).length > 0;
122
+ const {
123
+ $from,
124
+ $to
125
+ } = state.selection;
126
+ const {
127
+ bulletList,
128
+ orderedList,
129
+ taskList
130
+ } = state.schema.nodes;
131
+ const listNodeTypes = [bulletList, orderedList, taskList];
132
+ let insideList = false;
133
+ state.doc.nodesBetween($from.pos, $to.pos, node => {
134
+ if (node.isBlock && listNodeTypes.indexOf(node.type) >= 0) {
135
+ insideList = true;
136
+ return false;
137
+ }
138
+ return true;
139
+ });
140
+ return insideList;
105
141
  }
106
142
  const blockStylingIsPresent = state => {
107
143
  const {
@@ -142,4 +178,43 @@ export const checkFormattingIsPresent = state => {
142
178
  };
143
179
  export const hasBlockQuoteInOptions = dropdownOptions => {
144
180
  return !!dropdownOptions.find(blockType => blockType.name === 'blockquote');
145
- };
181
+ };
182
+
183
+ /**
184
+ * Returns a { from, to } range that extends the selection boundaries outward
185
+ * to include the entirety of any list nodes at either end. If the selection
186
+ * start is inside a list, `from` is pulled back to the list's start; if the
187
+ * selection end is inside a list, `to` is pushed forward to the list's end.
188
+ * Non-list content in the middle is included as-is.
189
+ */
190
+ export function getSelectionRangeExpandedToLists(tr) {
191
+ const {
192
+ selection
193
+ } = tr;
194
+ const {
195
+ bulletList,
196
+ orderedList,
197
+ taskList
198
+ } = tr.doc.type.schema.nodes;
199
+ const listNodeTypes = [bulletList, orderedList, taskList];
200
+ let from = selection.from;
201
+ let to = selection.to;
202
+ for (let depth = selection.$from.depth; depth > 0; depth--) {
203
+ const node = selection.$from.node(depth);
204
+ if (listNodeTypes.indexOf(node.type) >= 0) {
205
+ from = selection.$from.before(depth);
206
+ break;
207
+ }
208
+ }
209
+ for (let depth = selection.$to.depth; depth > 0; depth--) {
210
+ const node = selection.$to.node(depth);
211
+ if (listNodeTypes.indexOf(node.type) >= 0) {
212
+ to = selection.$to.after(depth);
213
+ break;
214
+ }
215
+ }
216
+ return {
217
+ from,
218
+ to
219
+ };
220
+ }
@@ -171,7 +171,7 @@ var blockTypePlugin = function blockTypePlugin(_ref3) {
171
171
  name: 'blockType',
172
172
  plugin: function plugin(_ref5) {
173
173
  var dispatch = _ref5.dispatch;
174
- return createPlugin(api, dispatch, options && options.lastNodeMustBeParagraph, options === null || options === void 0 ? void 0 : options.includeBlockQuoteAsTextstyleOption);
174
+ return createPlugin(api, dispatch, options && options.lastNodeMustBeParagraph, options === null || options === void 0 ? void 0 : options.includeBlockQuoteAsTextstyleOption, options === null || options === void 0 ? void 0 : options.allowFontSize);
175
175
  }
176
176
  }, {
177
177
  name: 'blockTypeInputRule',
@@ -2,11 +2,14 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
2
2
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
3
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
4
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
5
+ import { createToggleBlockMarkOnRangeNext } from '@atlaskit/editor-common/commands';
5
6
  import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
6
7
  import { filterChildrenBetween, wrapSelectionIn } from '@atlaskit/editor-common/utils';
7
8
  import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
8
9
  import { CellSelection } from '@atlaskit/editor-tables';
10
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
11
  import { HEADINGS_BY_NAME, NORMAL_TEXT } from '../block-types';
12
+ import { getSelectionRangeExpandedToLists } from '../utils';
10
13
  import { FORMATTING_NODE_TYPES, FORMATTING_MARK_TYPES, cellSelectionNodesBetween, formatTypes, clearNodeFormattingOnSelection } from './clear-formatting';
11
14
  import { wrapSelectionInBlockType } from './wrapSelectionIn';
12
15
  export function setBlockType(name) {
@@ -18,6 +21,11 @@ export function setBlockType(name) {
18
21
  tr: tr
19
22
  });
20
23
  }
24
+ if (name === 'smallText' && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
25
+ return setSmallText()({
26
+ tr: tr
27
+ });
28
+ }
21
29
  var headingBlockType = HEADINGS_BY_NAME[name];
22
30
  if (headingBlockType && nodes.heading && headingBlockType.level) {
23
31
  return setHeading(headingBlockType.level)({
@@ -61,18 +69,45 @@ export function setHeading(level, fromBlockQuote) {
61
69
  });
62
70
  }
63
71
  });
72
+
73
+ // Remove fontSize mark from transformed content in range
74
+ // List content stays as paragraphs (headings aren't allowed in list items),
75
+ // but non-list content has been converted to headings by setBlockType above.
76
+ var fontSize = schema.marks.fontSize;
77
+ if (fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
78
+ var allowedBlocks = [schema.nodes.paragraph, schema.nodes.heading];
79
+ if (selection instanceof CellSelection) {
80
+ selection.forEachCell(function (cell, pos) {
81
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
82
+ return false;
83
+ }, allowedBlocks)(pos, pos + cell.nodeSize, tr);
84
+ });
85
+ } else {
86
+ var expandedRange = getSelectionRangeExpandedToLists(tr);
87
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
88
+ return false;
89
+ }, allowedBlocks)(expandedRange.from, expandedRange.to, tr);
90
+ }
91
+ }
64
92
  return tr;
65
93
  };
66
94
  }
67
95
  export function setBlockTypeWithAnalytics(name, inputMethod, editorAnalyticsApi, fromBlockQuote) {
68
96
  return function (_ref4) {
69
97
  var tr = _ref4.tr;
70
- var nodes = tr.doc.type.schema.nodes;
98
+ var _tr$doc$type$schema = tr.doc.type.schema,
99
+ nodes = _tr$doc$type$schema.nodes,
100
+ marks = _tr$doc$type$schema.marks;
71
101
  if (name === 'normal' && nodes.paragraph) {
72
102
  return setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi, fromBlockQuote)({
73
103
  tr: tr
74
104
  });
75
105
  }
106
+ if (name === 'smallText' && marks.fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
107
+ return setSmallTextWithAnalytics(inputMethod, editorAnalyticsApi)({
108
+ tr: tr
109
+ });
110
+ }
76
111
  var headingBlockType = HEADINGS_BY_NAME[name];
77
112
  if (headingBlockType && nodes.heading && headingBlockType.level) {
78
113
  return setHeadingWithAnalytics(headingBlockType.level, inputMethod, editorAnalyticsApi, fromBlockQuote)({
@@ -82,15 +117,68 @@ export function setBlockTypeWithAnalytics(name, inputMethod, editorAnalyticsApi,
82
117
  return null;
83
118
  };
84
119
  }
85
- export function setNormalText(fromBlockQuote) {
120
+ export function setSmallText() {
86
121
  return function (_ref5) {
87
122
  var tr = _ref5.tr;
123
+ var _tr$doc$type$schema2 = tr.doc.type.schema,
124
+ fontSize = _tr$doc$type$schema2.marks.fontSize,
125
+ paragraph = _tr$doc$type$schema2.nodes.paragraph;
126
+ if (!fontSize) {
127
+ return null;
128
+ }
129
+ var selection = tr.selection;
130
+ if (selection instanceof CellSelection) {
131
+ selection.forEachCell(function (cell, pos) {
132
+ tr.setBlockType(pos, pos + cell.nodeSize, paragraph);
133
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
134
+ return {
135
+ fontSize: 'small'
136
+ };
137
+ }, [paragraph])(pos, pos + cell.nodeSize, tr);
138
+ });
139
+ } else {
140
+ tr.setBlockType(selection.from, selection.to, paragraph);
141
+ var expandedRange = getSelectionRangeExpandedToLists(tr);
142
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
143
+ return {
144
+ fontSize: 'small'
145
+ };
146
+ }, [paragraph])(expandedRange.from, expandedRange.to, tr);
147
+ }
148
+ return tr;
149
+ };
150
+ }
151
+ export function setSmallTextWithAnalytics(inputMethod, editorAnalyticsApi) {
152
+ return withCurrentHeadingLevel(function (previousHeadingLevel) {
153
+ return function (_ref6) {
154
+ var tr = _ref6.tr;
155
+ editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent({
156
+ action: ACTION.FORMATTED,
157
+ actionSubject: ACTION_SUBJECT.TEXT,
158
+ eventType: EVENT_TYPE.TRACK,
159
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_SMALL_TEXT,
160
+ attributes: {
161
+ inputMethod: inputMethod,
162
+ previousBlockType: previousHeadingLevel !== undefined ? String(previousHeadingLevel) : undefined
163
+ }
164
+ })(tr);
165
+ return setSmallText()({
166
+ tr: tr
167
+ });
168
+ };
169
+ });
170
+ }
171
+ export function setNormalText(fromBlockQuote) {
172
+ return function (_ref7) {
173
+ var tr = _ref7.tr;
88
174
  var selection = tr.selection,
89
175
  schema = tr.doc.type.schema;
176
+
177
+ // Apply normal text to the selection range (handles non-list content)
90
178
  var ranges = selection instanceof CellSelection ? selection.ranges : [selection];
91
- ranges.forEach(function (_ref6) {
92
- var $from = _ref6.$from,
93
- $to = _ref6.$to;
179
+ ranges.forEach(function (_ref8) {
180
+ var $from = _ref8.$from,
181
+ $to = _ref8.$to;
94
182
  if (fromBlockQuote) {
95
183
  var range = $from.blockRange($to);
96
184
  if (!range) {
@@ -109,12 +197,29 @@ export function setNormalText(fromBlockQuote) {
109
197
  tr.setBlockType($from.pos, $to.pos, schema.nodes.paragraph);
110
198
  }
111
199
  });
200
+
201
+ // Remove fontSize mark from any lists the selection touches
202
+ var fontSize = schema.marks.fontSize;
203
+ if (fontSize && expValEquals('platform_editor_small_font_size', 'isEnabled', true)) {
204
+ if (selection instanceof CellSelection) {
205
+ selection.forEachCell(function (cell, pos) {
206
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
207
+ return false;
208
+ }, [schema.nodes.paragraph])(pos, pos + cell.nodeSize, tr);
209
+ });
210
+ } else {
211
+ var expandedRange = getSelectionRangeExpandedToLists(tr);
212
+ createToggleBlockMarkOnRangeNext(fontSize, function () {
213
+ return false;
214
+ }, [schema.nodes.paragraph])(expandedRange.from, expandedRange.to, tr);
215
+ }
216
+ }
112
217
  return tr;
113
218
  };
114
219
  }
115
220
  export function clearFormatting(inputMethod, editorAnalyticsApi) {
116
- return function (_ref7) {
117
- var tr = _ref7.tr;
221
+ return function (_ref9) {
222
+ var tr = _ref9.tr;
118
223
  var formattingCleared = [];
119
224
  var schema = tr.doc.type.schema;
120
225
  FORMATTING_MARK_TYPES.forEach(function (mark) {
@@ -171,8 +276,8 @@ export function clearFormatting(inputMethod, editorAnalyticsApi) {
171
276
  };
172
277
  }
173
278
  function withCurrentHeadingLevel(fn) {
174
- return function (_ref8) {
175
- var tr = _ref8.tr;
279
+ return function (_ref0) {
280
+ var tr = _ref0.tr;
176
281
  // Find all headings and paragraphs of text
177
282
  var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
178
283
  heading = _tr$doc$type$schema$n.heading,
@@ -209,8 +314,8 @@ function withCurrentHeadingLevel(fn) {
209
314
  }
210
315
  export function setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi, fromBlockQuote) {
211
316
  return withCurrentHeadingLevel(function (previousHeadingLevel) {
212
- return function (_ref9) {
213
- var tr = _ref9.tr;
317
+ return function (_ref1) {
318
+ var tr = _ref1.tr;
214
319
  editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent({
215
320
  action: ACTION.FORMATTED,
216
321
  actionSubject: ACTION_SUBJECT.TEXT,
@@ -230,8 +335,8 @@ export function setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi, from
230
335
  }
231
336
  export var setHeadingWithAnalytics = function setHeadingWithAnalytics(newHeadingLevel, inputMethod, editorAnalyticsApi, fromBlockQuote) {
232
337
  return withCurrentHeadingLevel(function (previousHeadingLevel) {
233
- return function (_ref0) {
234
- var tr = _ref0.tr;
338
+ return function (_ref10) {
339
+ var tr = _ref10.tr;
235
340
  editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent({
236
341
  action: ACTION.FORMATTED,
237
342
  actionSubject: ACTION_SUBJECT.TEXT,
@@ -279,9 +384,9 @@ export var insertBlockQuoteWithAnalytics = function insertBlockQuoteWithAnalytic
279
384
  })(insertBlockQuote());
280
385
  };
281
386
  export function insertBlockQuoteWithAnalyticsCommand(inputMethod, editorAnalyticsApi) {
282
- return withCurrentHeadingLevel(function (previousHeadingLevel) {
283
- return function (_ref1) {
284
- var tr = _ref1.tr;
387
+ return withCurrentHeadingLevel(function () {
388
+ return function (_ref11) {
389
+ var tr = _ref11.tr;
285
390
  var nodes = tr.doc.type.schema.nodes;
286
391
  editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent({
287
392
  action: ACTION.FORMATTED,
@@ -299,8 +404,8 @@ export function insertBlockQuoteWithAnalyticsCommand(inputMethod, editorAnalytic
299
404
  });
300
405
  }
301
406
  export var cleanUpAtTheStartOfDocument = function cleanUpAtTheStartOfDocument(state, dispatch) {
302
- var _ref10 = state.selection,
303
- $cursor = _ref10.$cursor;
407
+ var _ref12 = state.selection,
408
+ $cursor = _ref12.$cursor;
304
409
  if ($cursor && !$cursor.nodeBefore && !$cursor.nodeAfter && $cursor.pos === 1) {
305
410
  var tr = state.tr,
306
411
  schema = state.schema;