@atlaskit/editor-plugin-floating-toolbar 0.5.0 → 0.6.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 (135) hide show
  1. package/CHANGELOG.md +22 -10
  2. package/README.md +1 -1
  3. package/dist/cjs/index.js +8 -1
  4. package/dist/cjs/plugin.js +385 -0
  5. package/dist/cjs/pm-plugins/force-focus/index.js +73 -0
  6. package/dist/cjs/pm-plugins/toolbar-data/commands.js +26 -0
  7. package/dist/cjs/pm-plugins/toolbar-data/plugin-factory.js +16 -0
  8. package/dist/cjs/pm-plugins/toolbar-data/plugin-key.js +9 -0
  9. package/dist/cjs/pm-plugins/toolbar-data/plugin.js +16 -0
  10. package/dist/cjs/pm-plugins/toolbar-data/reducer.js +25 -0
  11. package/dist/cjs/pm-plugins/toolbar-data/types.js +5 -0
  12. package/dist/cjs/ui/CheckboxModal.js +83 -0
  13. package/dist/cjs/ui/ConfirmationModal.js +22 -0
  14. package/dist/cjs/ui/Dropdown.js +212 -0
  15. package/dist/cjs/ui/DropdownMenu.js +218 -0
  16. package/dist/cjs/ui/EditorEmojiAddIcon.js +32 -0
  17. package/dist/cjs/ui/EmojiPickerButton.js +121 -0
  18. package/dist/cjs/ui/ExtensionsPlaceholder.js +179 -0
  19. package/dist/cjs/ui/Input.js +80 -0
  20. package/dist/cjs/ui/ScrollButtons.js +155 -0
  21. package/dist/cjs/ui/Select.js +74 -0
  22. package/dist/cjs/ui/Separator.js +9 -0
  23. package/dist/cjs/ui/SimpleModal.js +42 -0
  24. package/dist/cjs/ui/Toolbar.js +436 -0
  25. package/dist/cjs/ui/ToolbarLoader.js +25 -0
  26. package/dist/cjs/ui/messages.js +55 -0
  27. package/dist/cjs/ui/styles.js +79 -0
  28. package/dist/cjs/utils.js +22 -0
  29. package/dist/es2019/index.js +1 -1
  30. package/dist/es2019/plugin.js +366 -0
  31. package/dist/es2019/pm-plugins/force-focus/index.js +63 -0
  32. package/dist/es2019/pm-plugins/toolbar-data/commands.js +10 -0
  33. package/dist/es2019/pm-plugins/toolbar-data/plugin-factory.js +8 -0
  34. package/dist/es2019/pm-plugins/toolbar-data/plugin-key.js +2 -0
  35. package/dist/es2019/pm-plugins/toolbar-data/plugin.js +9 -0
  36. package/dist/es2019/pm-plugins/toolbar-data/reducer.js +16 -0
  37. package/dist/es2019/pm-plugins/toolbar-data/types.js +1 -0
  38. package/dist/es2019/ui/CheckboxModal.js +71 -0
  39. package/dist/es2019/ui/ConfirmationModal.js +13 -0
  40. package/dist/es2019/ui/Dropdown.js +185 -0
  41. package/dist/es2019/ui/DropdownMenu.js +205 -0
  42. package/dist/es2019/ui/EditorEmojiAddIcon.js +25 -0
  43. package/dist/es2019/ui/EmojiPickerButton.js +108 -0
  44. package/dist/es2019/ui/ExtensionsPlaceholder.js +100 -0
  45. package/dist/es2019/ui/Input.js +54 -0
  46. package/dist/es2019/ui/ScrollButtons.js +141 -0
  47. package/dist/es2019/ui/Select.js +62 -0
  48. package/dist/es2019/ui/Separator.js +2 -0
  49. package/dist/es2019/ui/SimpleModal.js +35 -0
  50. package/dist/es2019/ui/Toolbar.js +428 -0
  51. package/dist/es2019/ui/ToolbarLoader.js +6 -0
  52. package/dist/es2019/ui/messages.js +48 -0
  53. package/dist/es2019/ui/styles.js +64 -0
  54. package/dist/es2019/utils.js +16 -0
  55. package/dist/esm/index.js +1 -1
  56. package/dist/esm/plugin.js +373 -0
  57. package/dist/esm/pm-plugins/force-focus/index.js +64 -0
  58. package/dist/esm/pm-plugins/toolbar-data/commands.js +18 -0
  59. package/dist/esm/pm-plugins/toolbar-data/plugin-factory.js +8 -0
  60. package/dist/esm/pm-plugins/toolbar-data/plugin-key.js +2 -0
  61. package/dist/esm/pm-plugins/toolbar-data/plugin.js +9 -0
  62. package/dist/esm/pm-plugins/toolbar-data/reducer.js +17 -0
  63. package/dist/esm/pm-plugins/toolbar-data/types.js +1 -0
  64. package/dist/esm/ui/CheckboxModal.js +72 -0
  65. package/dist/esm/ui/ConfirmationModal.js +14 -0
  66. package/dist/esm/ui/Dropdown.js +204 -0
  67. package/dist/esm/ui/DropdownMenu.js +211 -0
  68. package/dist/esm/ui/EditorEmojiAddIcon.js +25 -0
  69. package/dist/esm/ui/EmojiPickerButton.js +114 -0
  70. package/dist/esm/ui/ExtensionsPlaceholder.js +168 -0
  71. package/dist/esm/ui/Input.js +72 -0
  72. package/dist/esm/ui/ScrollButtons.js +145 -0
  73. package/dist/esm/ui/Select.js +64 -0
  74. package/dist/esm/ui/Separator.js +2 -0
  75. package/dist/esm/ui/SimpleModal.js +31 -0
  76. package/dist/esm/ui/Toolbar.js +426 -0
  77. package/dist/esm/ui/ToolbarLoader.js +12 -0
  78. package/dist/esm/ui/messages.js +48 -0
  79. package/dist/esm/ui/styles.js +68 -0
  80. package/dist/esm/utils.js +16 -0
  81. package/dist/types/index.d.ts +1 -0
  82. package/dist/types/plugin.d.ts +12 -0
  83. package/dist/types/pm-plugins/force-focus/index.d.ts +21 -0
  84. package/dist/types/pm-plugins/toolbar-data/commands.d.ts +3 -0
  85. package/dist/types/pm-plugins/toolbar-data/plugin-factory.d.ts +1 -0
  86. package/dist/types/pm-plugins/toolbar-data/plugin-key.d.ts +3 -0
  87. package/dist/types/pm-plugins/toolbar-data/plugin.d.ts +3 -0
  88. package/dist/types/pm-plugins/toolbar-data/reducer.d.ts +3 -0
  89. package/dist/types/pm-plugins/toolbar-data/types.d.ts +8 -0
  90. package/dist/types/ui/CheckboxModal.d.ts +4 -0
  91. package/dist/types/ui/ConfirmationModal.d.ts +6 -0
  92. package/dist/types/ui/Dropdown.d.ts +41 -0
  93. package/dist/types/ui/DropdownMenu.d.ts +29 -0
  94. package/dist/types/ui/EditorEmojiAddIcon.d.ts +2 -0
  95. package/dist/types/ui/EmojiPickerButton.d.ts +16 -0
  96. package/dist/types/ui/ExtensionsPlaceholder.d.ts +16 -0
  97. package/dist/types/ui/Input.d.ts +23 -0
  98. package/dist/types/ui/ScrollButtons.d.ts +13 -0
  99. package/dist/types/ui/Select.d.ts +21 -0
  100. package/dist/types/ui/Separator.d.ts +2 -0
  101. package/dist/types/ui/SimpleModal.d.ts +4 -0
  102. package/dist/types/ui/Toolbar.d.ts +44 -0
  103. package/dist/types/ui/ToolbarLoader.d.ts +4 -0
  104. package/dist/types/ui/messages.d.ts +48 -0
  105. package/dist/types/ui/styles.d.ts +20 -0
  106. package/dist/types/utils.d.ts +2 -0
  107. package/dist/types-ts4.5/index.d.ts +1 -0
  108. package/dist/types-ts4.5/plugin.d.ts +12 -0
  109. package/dist/types-ts4.5/pm-plugins/force-focus/index.d.ts +21 -0
  110. package/dist/types-ts4.5/pm-plugins/toolbar-data/commands.d.ts +3 -0
  111. package/dist/types-ts4.5/pm-plugins/toolbar-data/plugin-factory.d.ts +1 -0
  112. package/dist/types-ts4.5/pm-plugins/toolbar-data/plugin-key.d.ts +3 -0
  113. package/dist/types-ts4.5/pm-plugins/toolbar-data/plugin.d.ts +3 -0
  114. package/dist/types-ts4.5/pm-plugins/toolbar-data/reducer.d.ts +3 -0
  115. package/dist/types-ts4.5/pm-plugins/toolbar-data/types.d.ts +8 -0
  116. package/dist/types-ts4.5/ui/CheckboxModal.d.ts +4 -0
  117. package/dist/types-ts4.5/ui/ConfirmationModal.d.ts +6 -0
  118. package/dist/types-ts4.5/ui/Dropdown.d.ts +41 -0
  119. package/dist/types-ts4.5/ui/DropdownMenu.d.ts +29 -0
  120. package/dist/types-ts4.5/ui/EditorEmojiAddIcon.d.ts +2 -0
  121. package/dist/types-ts4.5/ui/EmojiPickerButton.d.ts +16 -0
  122. package/dist/types-ts4.5/ui/ExtensionsPlaceholder.d.ts +16 -0
  123. package/dist/types-ts4.5/ui/Input.d.ts +23 -0
  124. package/dist/types-ts4.5/ui/ScrollButtons.d.ts +13 -0
  125. package/dist/types-ts4.5/ui/Select.d.ts +21 -0
  126. package/dist/types-ts4.5/ui/Separator.d.ts +2 -0
  127. package/dist/types-ts4.5/ui/SimpleModal.d.ts +4 -0
  128. package/dist/types-ts4.5/ui/Toolbar.d.ts +44 -0
  129. package/dist/types-ts4.5/ui/ToolbarLoader.d.ts +4 -0
  130. package/dist/types-ts4.5/ui/messages.d.ts +48 -0
  131. package/dist/types-ts4.5/ui/styles.d.ts +20 -0
  132. package/dist/types-ts4.5/utils.d.ts +2 -0
  133. package/package.json +32 -3
  134. package/report.api.md +3 -0
  135. package/tmp/api-report-tmp.d.ts +3 -0
@@ -0,0 +1,141 @@
1
+ /** @jsx jsx */
2
+ import React, { useEffect, useRef, useState } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import rafSchedule from 'raf-schd';
5
+ import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
6
+ import ChevronLeftLargeIcon from '@atlaskit/icon/glyph/chevron-left-large';
7
+ import ChevronRightLargeIcon from '@atlaskit/icon/glyph/chevron-right-large';
8
+ import { N30 } from '@atlaskit/theme/colors';
9
+ import messages from './messages';
10
+
11
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
12
+ const toolbarScrollButtons = css`
13
+ display: grid;
14
+ grid-template-columns: 1fr 1fr;
15
+ grid-gap: ${"var(--ds-space-050, 4px)"};
16
+ padding: ${"var(--ds-space-050, 4px)"} ${"var(--ds-space-100, 8px)"};
17
+ border-left: solid ${`var(--ds-border, ${N30})`} 1px;
18
+ flex-shrink: 0;
19
+ align-items: center;
20
+ `;
21
+ const LeftIcon = ChevronLeftLargeIcon;
22
+ const RightIcon = ChevronRightLargeIcon;
23
+ export const ScrollButtons = ({
24
+ intl,
25
+ scrollContainerRef,
26
+ node,
27
+ disabled
28
+ }) => {
29
+ const buttonsContainerRef = useRef(null);
30
+ const [needScroll, setNeedScroll] = useState(false);
31
+ const [canScrollLeft, setCanScrollLeft] = useState(true);
32
+ const [canScrollRight, setCanScrollRight] = useState(true);
33
+ const setCanScrollDebounced = rafSchedule(() => {
34
+ // Refs are null before mounting and after unmount
35
+ if (!scrollContainerRef.current) {
36
+ return;
37
+ }
38
+ const {
39
+ scrollLeft,
40
+ scrollWidth,
41
+ offsetWidth
42
+ } = scrollContainerRef.current;
43
+ setCanScrollLeft(scrollLeft > 0);
44
+ setCanScrollRight(scrollLeft + offsetWidth < scrollWidth - 1); // -1 to account for half pixel
45
+ });
46
+
47
+ const onScroll = () => setCanScrollDebounced();
48
+ const scrollLeft = () => {
49
+ var _scrollContainerRef$c, _scrollContainerRef$c2, _scrollContainerRef$c3;
50
+ const {
51
+ width: scrollContainerWidth = 0
52
+ } = ((_scrollContainerRef$c = scrollContainerRef.current) === null || _scrollContainerRef$c === void 0 ? void 0 : _scrollContainerRef$c.getBoundingClientRect()) || {};
53
+ const scrollLeft = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.scrollLeft) || 0;
54
+
55
+ // scroll to current position - scroll container width
56
+ let scrollTo = scrollLeft - scrollContainerWidth;
57
+ (_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollTo({
58
+ top: 0,
59
+ left: scrollTo,
60
+ behavior: 'smooth'
61
+ });
62
+ };
63
+ const scrollRight = () => {
64
+ var _scrollContainerRef$c4, _scrollContainerRef$c5, _scrollContainerRef$c6;
65
+ const {
66
+ width: scrollContainerWidth = 0
67
+ } = ((_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 ? void 0 : _scrollContainerRef$c4.getBoundingClientRect()) || {};
68
+ const scrollLeft = ((_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.scrollLeft) || 0;
69
+
70
+ // scroll to current position + scroll container width
71
+ let scrollTo = scrollLeft + scrollContainerWidth;
72
+ (_scrollContainerRef$c6 = scrollContainerRef.current) === null || _scrollContainerRef$c6 === void 0 ? void 0 : _scrollContainerRef$c6.scrollTo({
73
+ top: 0,
74
+ left: scrollTo,
75
+ behavior: 'smooth'
76
+ });
77
+ };
78
+ const resizeObserver = new ResizeObserver(t => {
79
+ var _scrollContainerRef$c7, _scrollContainerRef$c8, _scrollContainerRef$c9;
80
+ const widthNeededToShowAllItems = ((_scrollContainerRef$c7 = scrollContainerRef.current) === null || _scrollContainerRef$c7 === void 0 ? void 0 : _scrollContainerRef$c7.scrollWidth) || 0;
81
+ const availableSpace = (_scrollContainerRef$c8 = scrollContainerRef.current) === null || _scrollContainerRef$c8 === void 0 ? void 0 : (_scrollContainerRef$c9 = _scrollContainerRef$c8.parentNode) === null || _scrollContainerRef$c9 === void 0 ? void 0 : _scrollContainerRef$c9.offsetWidth;
82
+ if (availableSpace >= widthNeededToShowAllItems) {
83
+ setNeedScroll(false);
84
+ } else {
85
+ setNeedScroll(true);
86
+ onScroll();
87
+ }
88
+ });
89
+ useEffect(() => {
90
+ onScroll();
91
+ const scrollContainerRefCurrent = scrollContainerRef.current;
92
+ if (scrollContainerRefCurrent) {
93
+ // enable/disable scroll buttons depending on scroll position
94
+ // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
95
+ scrollContainerRefCurrent.addEventListener('scroll', onScroll);
96
+
97
+ // watch for toolbar resize and show/hide scroll buttons if needed
98
+ resizeObserver.observe(scrollContainerRefCurrent);
99
+ }
100
+ return () => {
101
+ if (scrollContainerRefCurrent) {
102
+ // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
103
+ scrollContainerRefCurrent.removeEventListener('scroll', onScroll);
104
+ resizeObserver.unobserve(scrollContainerRefCurrent);
105
+ }
106
+ setCanScrollDebounced.cancel();
107
+ };
108
+ // eslint-disable-next-line react-hooks/exhaustive-deps
109
+ }, []);
110
+ useEffect(() => {
111
+ const scrollContainerRefCurrent = scrollContainerRef.current;
112
+ if (scrollContainerRefCurrent) {
113
+ var _scrollContainerRefCu;
114
+ // reset scroll position when switching from one node with toolbar to another
115
+ // scroll to made optional as it may not be rendered in testing env
116
+ (_scrollContainerRefCu = scrollContainerRefCurrent.scrollTo) === null || _scrollContainerRefCu === void 0 ? void 0 : _scrollContainerRefCu.call(scrollContainerRefCurrent, {
117
+ left: 0
118
+ });
119
+ }
120
+ // eslint-disable-next-line react-hooks/exhaustive-deps
121
+ }, [node.type]);
122
+ return needScroll ? jsx("div", {
123
+ ref: buttonsContainerRef,
124
+ css: toolbarScrollButtons,
125
+ className: "scroll-buttons"
126
+ }, jsx(Button, {
127
+ title: intl.formatMessage(messages.floatingToolbarScrollLeft),
128
+ icon: jsx(LeftIcon, {
129
+ label: intl.formatMessage(messages.floatingToolbarScrollLeft)
130
+ }),
131
+ onClick: scrollLeft,
132
+ disabled: !canScrollLeft || disabled
133
+ }), jsx(Button, {
134
+ title: intl.formatMessage(messages.floatingToolbarScrollRight),
135
+ icon: jsx(RightIcon, {
136
+ label: intl.formatMessage(messages.floatingToolbarScrollRight)
137
+ }),
138
+ onClick: scrollRight,
139
+ disabled: !canScrollRight || disabled
140
+ })) : null;
141
+ };
@@ -0,0 +1,62 @@
1
+ import React, { useRef } from 'react';
2
+ import Select from '@atlaskit/select';
3
+ export default function Search(props) {
4
+ const selectRef = useRef(null);
5
+ const {
6
+ width = 200
7
+ } = props;
8
+ const style = React.useMemo(() => ({
9
+ container: base => ({
10
+ ...base,
11
+ width
12
+ }),
13
+ menuPortal: base => {
14
+ var _selectRef$current, _selectRef$current$se, _selectRef$current$se2, _selectRef$current2, _selectRef$current2$s, _selectRef$current2$s2, _selectRef$current2$s3;
15
+ // ED:16095: We add two possible getter paths for safely reaching into the underlying
16
+ // react-select element. We first try a getter that conforms with react-select v5 APIs,
17
+ // Failing that, we try a getter consistent with react-select v4 APIs. (We
18
+ // handle both as consumers may control the time of the actual dependency version
19
+ // cutover).
20
+ const controlWrapper = (selectRef === null || selectRef === void 0 ? void 0 : (_selectRef$current = selectRef.current) === null || _selectRef$current === void 0 ? void 0 : (_selectRef$current$se = _selectRef$current.select) === null || _selectRef$current$se === void 0 ? void 0 : (_selectRef$current$se2 = _selectRef$current$se.controlRef) === null || _selectRef$current$se2 === void 0 ? void 0 : _selectRef$current$se2.parentNode) || (selectRef === null || selectRef === void 0 ? void 0 : (_selectRef$current2 = selectRef.current) === null || _selectRef$current2 === void 0 ? void 0 : (_selectRef$current2$s = _selectRef$current2.select) === null || _selectRef$current2$s === void 0 ? void 0 : (_selectRef$current2$s2 = _selectRef$current2$s.select) === null || _selectRef$current2$s2 === void 0 ? void 0 : (_selectRef$current2$s3 = _selectRef$current2$s2.controlRef) === null || _selectRef$current2$s3 === void 0 ? void 0 : _selectRef$current2$s3.parentNode);
21
+ const menuPortalStyles = controlWrapper && props.setDisableParentScroll ? {
22
+ // since the portal is now outside, we need to position it as before
23
+ top: controlWrapper.offsetTop,
24
+ left: controlWrapper.offsetLeft,
25
+ height: controlWrapper.offsetHeight,
26
+ width
27
+ } : {};
28
+ return {
29
+ ...base,
30
+ ...menuPortalStyles
31
+ };
32
+ }
33
+ }),
34
+ // eslint-disable-next-line react-hooks/exhaustive-deps
35
+ [width]);
36
+ const onMenuOpen = () => {
37
+ if (props.setDisableParentScroll) {
38
+ props.setDisableParentScroll(true);
39
+ }
40
+ };
41
+ const onMenuClose = () => {
42
+ if (props.setDisableParentScroll) {
43
+ props.setDisableParentScroll(false);
44
+ }
45
+ };
46
+ return /*#__PURE__*/React.createElement(Select, {
47
+ ref: selectRef,
48
+ options: props.options,
49
+ value: props.defaultValue,
50
+ onChange: props.onChange,
51
+ placeholder: props.placeholder,
52
+ spacing: "compact",
53
+ menuPlacement: "auto",
54
+ filterOption: props.filterOption,
55
+ styles: style,
56
+ menuPortalTarget: props.mountPoint,
57
+ onMenuOpen: onMenuOpen,
58
+ onMenuClose: onMenuClose,
59
+ "aria-label": props.ariaLabel,
60
+ classNamePrefix: props.classNamePrefix
61
+ });
62
+ }
@@ -0,0 +1,2 @@
1
+ import { FloatingToolbarSeparator } from '@atlaskit/editor-common/ui';
2
+ export default FloatingToolbarSeparator;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import Button from '@atlaskit/button/standard-button';
3
+ import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
4
+ import messages from './messages';
5
+ export const SimpleModal = props => {
6
+ const {
7
+ onConfirm,
8
+ onClose,
9
+ options,
10
+ intl: {
11
+ formatMessage
12
+ },
13
+ testId
14
+ } = props;
15
+ const heading = (options === null || options === void 0 ? void 0 : options.title) || formatMessage(messages.confirmModalDefaultHeading);
16
+ const okButtonLabel = (options === null || options === void 0 ? void 0 : options.okButtonLabel) || formatMessage(messages.confirmModalOK);
17
+ const cancelButtonLabel = (options === null || options === void 0 ? void 0 : options.cancelButtonLabel) || formatMessage(messages.confirmModalCancel);
18
+ return /*#__PURE__*/React.createElement(Modal, {
19
+ onClose: onClose,
20
+ testId: testId
21
+ }, /*#__PURE__*/React.createElement(ModalHeader, null, /*#__PURE__*/React.createElement(ModalTitle, {
22
+ appearance: "warning"
23
+ }, heading)), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement("p", null, options === null || options === void 0 ? void 0 : options.message)), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
24
+ appearance: "default",
25
+ onClick: onClose,
26
+ testId: testId ? `${testId}-cancel-button` : undefined
27
+ }, cancelButtonLabel), /*#__PURE__*/React.createElement(Button, {
28
+ appearance: "warning",
29
+ onClick: () => {
30
+ onConfirm();
31
+ onClose();
32
+ },
33
+ testId: testId ? `${testId}-confirm-button` : undefined
34
+ }, okButtonLabel)));
35
+ };
@@ -0,0 +1,428 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ /** @jsx jsx */
4
+ import React, { Component } from 'react';
5
+ import { css, jsx } from '@emotion/react';
6
+ import { injectIntl } from 'react-intl-next';
7
+ import ButtonGroup from '@atlaskit/button/button-group';
8
+ import { areSameItems } from '@atlaskit/editor-common/floating-toolbar';
9
+ import { Announcer, FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
10
+ import { backgroundPaletteTooltipMessages } from '@atlaskit/editor-common/ui-color';
11
+ import { ToolbarArrowKeyNavigationProvider } from '@atlaskit/editor-common/ui-menu';
12
+ import { ColorPickerButton } from '@atlaskit/editor-common/ui-menu';
13
+ import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
14
+ import { clearHoverSelection } from '@atlaskit/editor-plugin-table/commands';
15
+ import { DN70 } from '@atlaskit/theme/colors';
16
+ // eslint-disable-next-line @atlaskit/design-system/no-deprecated-imports
17
+ import { themed } from '@atlaskit/theme/components';
18
+ // eslint-disable-next-line @atlaskit/design-system/no-deprecated-imports
19
+ import { borderRadius } from '@atlaskit/theme/constants';
20
+ import { checkShouldForceFocusAndApply, forceFocusSelector } from '../pm-plugins/force-focus';
21
+ import { showConfirmDialog } from '../pm-plugins/toolbar-data/commands';
22
+ import Dropdown from './Dropdown';
23
+ import { EmojiPickerButton } from './EmojiPickerButton';
24
+ import { ExtensionsPlaceholder } from './ExtensionsPlaceholder';
25
+ import Input from './Input';
26
+ import messages from './messages';
27
+ import { ScrollButtons } from './ScrollButtons';
28
+ import Select from './Select';
29
+ import Separator from './Separator';
30
+ const ToolbarItems = /*#__PURE__*/React.memo(({
31
+ items,
32
+ dispatchCommand,
33
+ popupsMountPoint,
34
+ popupsBoundariesElement,
35
+ editorView,
36
+ dispatchAnalyticsEvent,
37
+ popupsScrollableElement,
38
+ scrollable,
39
+ providerFactory,
40
+ extensionsProvider,
41
+ node,
42
+ setDisableScroll,
43
+ mountRef,
44
+ featureFlags,
45
+ api
46
+ }) => {
47
+ const emojiAndColourPickerMountPoint = scrollable ? popupsMountPoint || (editorView === null || editorView === void 0 ? void 0 : editorView.dom.closest('.fabric-editor-popup-scroll-parent')) || (editorView === null || editorView === void 0 ? void 0 : editorView.dom.closest('.ak-editor-content-area')) || undefined : popupsMountPoint;
48
+ return jsx(ButtonGroup, null, items.filter(item => !item.hidden).map((item, idx) => {
49
+ var _api$contextPanel, _api$extension;
50
+ switch (item.type) {
51
+ case 'button':
52
+ const ButtonIcon = item.icon;
53
+ const onClickHandler = () => {
54
+ if (item.confirmDialog) {
55
+ dispatchCommand(showConfirmDialog(idx));
56
+ } else {
57
+ dispatchCommand(item.onClick);
58
+ if (item.focusEditoronEnter && !(editorView !== null && editorView !== void 0 && editorView.hasFocus())) {
59
+ editorView === null || editorView === void 0 ? void 0 : editorView.focus();
60
+ }
61
+ }
62
+ };
63
+ return jsx(Button, {
64
+ className: item.className,
65
+ key: idx,
66
+ title: item.title,
67
+ href: item.href,
68
+ icon: item.icon ? jsx(ButtonIcon, {
69
+ label: item.title
70
+ }) : undefined,
71
+ appearance: item.appearance,
72
+ target: item.target,
73
+ onClick: onClickHandler,
74
+ onMouseEnter: () => dispatchCommand(item.onMouseEnter),
75
+ onMouseLeave: () => dispatchCommand(item.onMouseLeave),
76
+ onFocus: () => dispatchCommand(item.onFocus),
77
+ onBlur: () => dispatchCommand(item.onBlur),
78
+ selected: item.selected,
79
+ disabled: item.disabled,
80
+ tooltipContent: item.tooltipContent,
81
+ testId: item.testId,
82
+ hideTooltipOnClick: item.hideTooltipOnClick,
83
+ ariaHasPopup: item.ariaHasPopup,
84
+ tabIndex: item.tabIndex
85
+ }, item.showTitle && item.title);
86
+ case 'input':
87
+ return jsx(Input, {
88
+ key: idx,
89
+ mountPoint: popupsMountPoint,
90
+ boundariesElement: popupsBoundariesElement,
91
+ defaultValue: item.defaultValue,
92
+ placeholder: item.placeholder,
93
+ onSubmit: value => dispatchCommand(item.onSubmit(value)),
94
+ onBlur: value => dispatchCommand(item.onBlur(value))
95
+ });
96
+ case 'custom':
97
+ {
98
+ return item.render(editorView, idx, dispatchAnalyticsEvent);
99
+ }
100
+ case 'dropdown':
101
+ const DropdownIcon = item.icon;
102
+ return jsx(Dropdown, {
103
+ key: idx,
104
+ title: item.title,
105
+ icon: DropdownIcon && jsx(DropdownIcon, {
106
+ label: item.title
107
+ }),
108
+ dispatchCommand: dispatchCommand,
109
+ options: item.options,
110
+ disabled: item.disabled,
111
+ tooltip: item.tooltip,
112
+ hideExpandIcon: item.hideExpandIcon,
113
+ mountPoint: popupsMountPoint,
114
+ boundariesElement: popupsBoundariesElement,
115
+ scrollableElement: popupsScrollableElement,
116
+ dropdownWidth: item.dropdownWidth,
117
+ showSelected: item.showSelected,
118
+ buttonTestId: item.testId,
119
+ editorView: editorView,
120
+ setDisableParentScroll: scrollable ? setDisableScroll : undefined,
121
+ dropdownListId: (item === null || item === void 0 ? void 0 : item.id) && `${item.id}-dropdownList`,
122
+ alignDropdownWithToolbar: items.length === 1
123
+ });
124
+ case 'select':
125
+ if (item.selectType === 'list') {
126
+ const ariaLabel = item.title || item.placeholder;
127
+ return jsx(Select, {
128
+ key: idx,
129
+ dispatchCommand: dispatchCommand,
130
+ options: item.options,
131
+ hideExpandIcon: item.hideExpandIcon,
132
+ mountPoint: scrollable ? mountRef.current : undefined,
133
+ boundariesElement: popupsBoundariesElement,
134
+ scrollableElement: popupsScrollableElement,
135
+ defaultValue: item.defaultValue,
136
+ placeholder: item.placeholder,
137
+ onChange: selected => dispatchCommand(item.onChange(selected)),
138
+ ariaLabel: ariaLabel,
139
+ filterOption: item.filterOption,
140
+ setDisableParentScroll: scrollable ? setDisableScroll : undefined,
141
+ classNamePrefix: 'floating-toolbar-select'
142
+ });
143
+ }
144
+ if (item.selectType === 'color') {
145
+ return jsx(ColorPickerButton, {
146
+ skipFocusButtonAfterPick: true,
147
+ key: idx,
148
+ title: item.title,
149
+ onChange: selected => {
150
+ dispatchCommand(item.onChange(selected));
151
+ },
152
+ colorPalette: item.options,
153
+ currentColor: item.defaultValue ? item.defaultValue.value : undefined,
154
+ placement: "Panels",
155
+ mountPoint: emojiAndColourPickerMountPoint,
156
+ setDisableParentScroll: scrollable ? setDisableScroll : undefined
157
+ // Currently in floating toolbar, color picker is only
158
+ // used in panel and table cell background color.
159
+ // Both uses same color palette.
160
+ // That's why hard-coding hexToEditorBackgroundPaletteColor
161
+ // and paletteColorTooltipMessages.
162
+ // When we need to support different color palette
163
+ // in floating toolbar, we need to set hexToPaletteColor
164
+ // and paletteColorTooltipMessages in item options.
165
+ ,
166
+ hexToPaletteColor: hexToEditorBackgroundPaletteColor,
167
+ paletteColorTooltipMessages: backgroundPaletteTooltipMessages
168
+ });
169
+ }
170
+ if (item.selectType === 'emoji') {
171
+ return jsx(EmojiPickerButton, {
172
+ key: idx,
173
+ editorView: editorView,
174
+ title: item.title,
175
+ providerFactory: providerFactory,
176
+ isSelected: item.selected,
177
+ onChange: selected => dispatchCommand(item.onChange(selected)),
178
+ mountPoint: emojiAndColourPickerMountPoint,
179
+ setDisableParentScroll: scrollable ? setDisableScroll : undefined
180
+ });
181
+ }
182
+ return null;
183
+ case 'extensions-placeholder':
184
+ if (!editorView || !extensionsProvider) {
185
+ return null;
186
+ }
187
+ const {
188
+ extendFloatingToolbar
189
+ } = featureFlags || {};
190
+ if (!extendFloatingToolbar) {
191
+ return null;
192
+ }
193
+ return jsx(ExtensionsPlaceholder, {
194
+ key: idx,
195
+ node: node,
196
+ editorView: editorView,
197
+ extensionProvider: extensionsProvider,
198
+ separator: item.separator,
199
+ applyChangeToContextPanel: api === null || api === void 0 ? void 0 : (_api$contextPanel = api.contextPanel) === null || _api$contextPanel === void 0 ? void 0 : _api$contextPanel.actions.applyChange,
200
+ extensionApi: api === null || api === void 0 ? void 0 : (_api$extension = api.extension) === null || _api$extension === void 0 ? void 0 : _api$extension.actions.api()
201
+ });
202
+ case 'separator':
203
+ return jsx(Separator, {
204
+ key: idx
205
+ });
206
+ }
207
+ }));
208
+ }, (prevProps, nextProps) => {
209
+ if (!nextProps.node) {
210
+ return false;
211
+ }
212
+ // only rerender toolbar items if the node is different
213
+ // otherwise it causes an issue where multiple popups stays open
214
+ return !(prevProps.node.type !== nextProps.node.type || prevProps.node.attrs.localId !== nextProps.node.attrs.localId || !areSameItems(prevProps.items, nextProps.items) || !prevProps.mounted !== !nextProps.mounted);
215
+ });
216
+
217
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
218
+ const toolbarContainer = (theme, scrollable, hasSelect, firstElementIsSelect) => css`
219
+ background-color: ${themed({
220
+ light: "var(--ds-surface-overlay, white)",
221
+ dark: `var(--ds-surface-overlay, ${DN70})`
222
+ })(theme)};
223
+ border-radius: ${borderRadius()}px;
224
+ box-shadow: ${`var(--ds-shadow-overlay, ${`0 0 1px rgba(9, 30, 66, 0.31), 0 4px 8px -2px rgba(9, 30, 66, 0.25)`})`};
225
+ display: flex;
226
+ line-height: 1;
227
+ box-sizing: border-box;
228
+
229
+ & > div > div {
230
+ align-items: center;
231
+ }
232
+ ${scrollable ? css`
233
+ ${hasSelect ? css`
234
+ height: 40px;
235
+ ` : css`
236
+ height: 32px;
237
+ `}
238
+ overflow: hidden;
239
+ ` : css`
240
+ padding: ${"var(--ds-space-050, 4px)"} ${"var(--ds-space-100, 8px)"};
241
+ ${firstElementIsSelect && css`
242
+ padding-left: ${"var(--ds-space-050, 4px)"};
243
+ `}
244
+ `}
245
+ `;
246
+
247
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
248
+ const toolbarOverflow = (scrollable, scrollDisabled, firstElementIsSelect) => css`
249
+ ${scrollable ? css`
250
+ ${scrollDisabled ? css`
251
+ overflow: hidden;
252
+ ` : css`
253
+ overflow-x: auto;
254
+ overflow-y: hidden;
255
+ `}
256
+ -webkit-overflow-scrolling: touch;
257
+ padding: ${"var(--ds-space-050, 4px)"} 0 50px;
258
+ > div {
259
+ > div:first-child {
260
+ ${firstElementIsSelect ? css`
261
+ margin-left: ${"var(--ds-space-050, 4px)"};
262
+ ` : css`
263
+ margin-left: ${"var(--ds-space-100, 8px)"};
264
+ `}
265
+ }
266
+ > div:last-child {
267
+ margin-right: ${"var(--ds-space-100, 8px)"};
268
+ }
269
+ }
270
+ ` : css`
271
+ display: flex;
272
+ `}
273
+ `;
274
+ // eslint-disable-next-line @repo/internal/react/no-class-components
275
+ class Toolbar extends Component {
276
+ constructor(props) {
277
+ super(props);
278
+ _defineProperty(this, "shouldHandleArrowKeys", () => {
279
+ var _this$props$items;
280
+ //To prevent the keydown handling of arrow keys for custom toolbar items with 'disableArrowNavigation' prop enabled,
281
+ //Usually the button which has menus or popups
282
+ return !((_this$props$items = this.props.items) !== null && _this$props$items !== void 0 && _this$props$items.find(item => item.type === 'custom' && item.disableArrowNavigation));
283
+ });
284
+ _defineProperty(this, "handleEscape", event => {
285
+ var _this$props$editorVie;
286
+ // If any menu is open inside the floating toolbar 'Esc' key should not
287
+ // focus the editorview.
288
+ // Event can't be stopped as they are not childnodes of floating toolbar
289
+
290
+ const isDropdownOpen = !!document.querySelector('[data-role="droplistContent"]');
291
+ const isSelectMenuOpen = !!document.querySelector('.floating-toolbar-select__menu');
292
+ if (isDropdownOpen || isSelectMenuOpen) {
293
+ return;
294
+ }
295
+ (_this$props$editorVie = this.props.editorView) === null || _this$props$editorVie === void 0 ? void 0 : _this$props$editorVie.focus();
296
+ event.preventDefault();
297
+ event.stopPropagation();
298
+ });
299
+ this.scrollContainerRef = /*#__PURE__*/React.createRef();
300
+ this.mountRef = /*#__PURE__*/React.createRef();
301
+ this.toolbarContainerRef = /*#__PURE__*/React.createRef();
302
+ this.state = {
303
+ scrollDisabled: false,
304
+ mounted: false
305
+ };
306
+ }
307
+ // remove any decorations added by toolbar buttons i.e danger and selected styling
308
+ // this prevents https://product-fabric.atlassian.net/browse/ED-10207
309
+ resetStyling({
310
+ table
311
+ }) {
312
+ if (this.props.editorView) {
313
+ var _this$props$api;
314
+ const {
315
+ state,
316
+ dispatch
317
+ } = this.props.editorView;
318
+ if (table) {
319
+ return clearHoverSelection()(state, dispatch);
320
+ }
321
+ (_this$props$api = this.props.api) === null || _this$props$api === void 0 ? void 0 : _this$props$api.decorations.actions.removeDecoration(state, dispatch);
322
+ }
323
+ }
324
+ setDisableScroll(disabled) {
325
+ // wait before setting disabled state incase users jumping from one popup to another
326
+ if (disabled) {
327
+ requestAnimationFrame(() => {
328
+ this.setState({
329
+ scrollDisabled: disabled
330
+ });
331
+ });
332
+ } else {
333
+ this.setState({
334
+ scrollDisabled: disabled
335
+ });
336
+ }
337
+ }
338
+ componentDidMount() {
339
+ this.setState({
340
+ mounted: true
341
+ });
342
+ }
343
+ componentDidUpdate(prevProps) {
344
+ var _this$props;
345
+ checkShouldForceFocusAndApply((_this$props = this.props) === null || _this$props === void 0 ? void 0 : _this$props.editorView);
346
+ if (this.props.node !== prevProps.node) {
347
+ this.resetStyling({
348
+ table: (prevProps === null || prevProps === void 0 ? void 0 : prevProps.node.type.name) === 'table'
349
+ });
350
+ }
351
+ }
352
+ componentWillUnmount() {
353
+ const {
354
+ editorView
355
+ } = this.props;
356
+ if (editorView) {
357
+ const {
358
+ state: {
359
+ tr
360
+ },
361
+ dispatch
362
+ } = editorView;
363
+ dispatch(forceFocusSelector(null)(tr));
364
+ }
365
+ this.resetStyling({
366
+ table: this.props.node.type.name === 'table'
367
+ });
368
+ }
369
+ render() {
370
+ const {
371
+ items,
372
+ className,
373
+ node,
374
+ intl,
375
+ scrollable
376
+ } = this.props;
377
+ if (!items || !items.length) {
378
+ return null;
379
+ }
380
+
381
+ // Select has left padding of 4px to the border, everything else 8px
382
+ const firstElementIsSelect = items[0].type === 'select';
383
+ const hasSelect = items.find(item => item.type === 'select' && item.selectType === 'list');
384
+ const isShortcutToFocusToolbar = event => {
385
+ //Alt + F10 to reach first element in this floating toolbar
386
+ return event.altKey && (event.key === 'F10' || event.keyCode === 121);
387
+ };
388
+ return jsx(React.Fragment, null, jsx(ToolbarArrowKeyNavigationProvider, {
389
+ editorView: this.props.editorView,
390
+ handleEscape: this.handleEscape,
391
+ disableArrowKeyNavigation: !this.shouldHandleArrowKeys(),
392
+ childComponentSelector: "[data-testid='editor-floating-toolbar']",
393
+ isShortcutToFocusToolbar: isShortcutToFocusToolbar,
394
+ intl: intl
395
+ }, jsx("div", {
396
+ ref: this.toolbarContainerRef,
397
+ css: theme => [toolbarContainer({
398
+ theme
399
+ }, scrollable, hasSelect !== undefined, firstElementIsSelect)],
400
+ "aria-label": intl.formatMessage(messages.floatingToolbarAriaLabel),
401
+ role: "toolbar",
402
+ "data-testid": "editor-floating-toolbar",
403
+ className: className
404
+ }, jsx(Announcer, {
405
+ text: intl.formatMessage(messages.floatingToolbarAnnouncer),
406
+ delay: 250
407
+ }), jsx("div", {
408
+ "data-testid": "floating-toolbar-items",
409
+ ref: this.scrollContainerRef
410
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
411
+ ,
412
+ css: toolbarOverflow(scrollable, this.state.scrollDisabled, firstElementIsSelect)
413
+ }, jsx(ToolbarItems, _extends({}, this.props, {
414
+ setDisableScroll: this.setDisableScroll.bind(this),
415
+ mountRef: this.mountRef,
416
+ mounted: this.state.mounted,
417
+ featureFlags: this.props.featureFlags
418
+ }))), scrollable && jsx(ScrollButtons, {
419
+ intl: intl,
420
+ scrollContainerRef: this.scrollContainerRef,
421
+ node: node,
422
+ disabled: this.state.scrollDisabled
423
+ })), jsx("div", {
424
+ ref: this.mountRef
425
+ })));
426
+ }
427
+ }
428
+ export default injectIntl(Toolbar);
@@ -0,0 +1,6 @@
1
+ import Loadable from 'react-loadable';
2
+ export const ToolbarLoader = Loadable({
3
+ loader: () => import( /* webpackChunkName: "@atlaskit-internal_editor-core-floating-toolbar" */
4
+ './Toolbar').then(mod => mod.default),
5
+ loading: () => null
6
+ });