@atlaskit/editor-plugin-floating-toolbar 3.3.4 → 3.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/ui/ScrollButton.js +148 -0
- package/dist/cjs/ui/ScrollButtons.js +1 -0
- package/dist/cjs/ui/Toolbar.js +18 -3
- package/dist/es2019/ui/ScrollButton.js +133 -0
- package/dist/es2019/ui/ScrollButtons.js +1 -0
- package/dist/es2019/ui/Toolbar.js +18 -3
- package/dist/esm/ui/ScrollButton.js +138 -0
- package/dist/esm/ui/ScrollButtons.js +1 -0
- package/dist/esm/ui/Toolbar.js +18 -3
- package/dist/types/ui/ScrollButton.d.ts +12 -0
- package/dist/types-ts4.5/ui/ScrollButton.d.ts +12 -0
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-floating-toolbar
|
|
2
2
|
|
|
3
|
+
## 3.3.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#134885](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/134885)
|
|
8
|
+
[`0d61709802162`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0d61709802162) -
|
|
9
|
+
[ux] [ED-27312] Implement new scroll left/right buttons for scrollable floating toolbars
|
|
10
|
+
|
|
3
11
|
## 3.3.4
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.ScrollButton = void 0;
|
|
9
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
var _bindEventListener = require("bind-event-listener");
|
|
12
|
+
var _rafSchd = _interopRequireDefault(require("raf-schd"));
|
|
13
|
+
var _new = require("@atlaskit/button/new");
|
|
14
|
+
var _floatingToolbar = require("@atlaskit/editor-common/floating-toolbar");
|
|
15
|
+
var _chevronLeftChevronLeftLarge = _interopRequireDefault(require("@atlaskit/icon/utility/migration/chevron-left--chevron-left-large"));
|
|
16
|
+
var _chevronRightChevronRightLarge = _interopRequireDefault(require("@atlaskit/icon/utility/migration/chevron-right--chevron-right-large"));
|
|
17
|
+
var _primitives = require("@atlaskit/primitives");
|
|
18
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
19
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
20
|
+
var rightSideStyles = (0, _primitives.xcss)({
|
|
21
|
+
borderLeft: "solid ".concat("var(--ds-border, #091E4224)", " 1px"),
|
|
22
|
+
right: 'space.0',
|
|
23
|
+
borderTopRightRadius: '3px',
|
|
24
|
+
borderBottomRightRadius: '3px'
|
|
25
|
+
});
|
|
26
|
+
var leftSideStyles = (0, _primitives.xcss)({
|
|
27
|
+
borderRight: "solid ".concat("var(--ds-border, #091E4224)", " 1px"),
|
|
28
|
+
left: 'space.0',
|
|
29
|
+
borderTopLeftRadius: '3px',
|
|
30
|
+
borderBottomLeftRadius: '3px'
|
|
31
|
+
});
|
|
32
|
+
var buttonCommonStyles = (0, _primitives.xcss)({
|
|
33
|
+
backgroundColor: 'elevation.surface.overlay',
|
|
34
|
+
zIndex: '1',
|
|
35
|
+
position: 'absolute'
|
|
36
|
+
});
|
|
37
|
+
var ScrollButton = exports.ScrollButton = function ScrollButton(_ref) {
|
|
38
|
+
var intl = _ref.intl,
|
|
39
|
+
scrollContainerRef = _ref.scrollContainerRef,
|
|
40
|
+
node = _ref.node,
|
|
41
|
+
disabled = _ref.disabled,
|
|
42
|
+
side = _ref.side;
|
|
43
|
+
var _useState = (0, _react.useState)(false),
|
|
44
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
45
|
+
needScroll = _useState2[0],
|
|
46
|
+
setNeedScroll = _useState2[1];
|
|
47
|
+
var _useState3 = (0, _react.useState)(true),
|
|
48
|
+
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
|
|
49
|
+
canScrollToSide = _useState4[0],
|
|
50
|
+
setCanScrollToSide = _useState4[1];
|
|
51
|
+
var setCanScrollDebounced = (0, _rafSchd.default)(function () {
|
|
52
|
+
// Refs are null before mounting and after unmount
|
|
53
|
+
if (!scrollContainerRef.current) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
var _scrollContainerRef$c = scrollContainerRef.current,
|
|
57
|
+
scrollLeft = _scrollContainerRef$c.scrollLeft,
|
|
58
|
+
scrollWidth = _scrollContainerRef$c.scrollWidth,
|
|
59
|
+
offsetWidth = _scrollContainerRef$c.offsetWidth;
|
|
60
|
+
setCanScrollToSide(
|
|
61
|
+
// -1 to account for pixel rounding error
|
|
62
|
+
side === 'left' ? scrollLeft > 0 : scrollLeft < scrollWidth - offsetWidth - 1);
|
|
63
|
+
});
|
|
64
|
+
var onScroll = function onScroll() {
|
|
65
|
+
setCanScrollDebounced();
|
|
66
|
+
};
|
|
67
|
+
var onClick = function onClick() {
|
|
68
|
+
var _scrollContainerRef$c2, _scrollContainerRef$c3, _scrollContainerRef$c4;
|
|
69
|
+
var _ref2 = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.getBoundingClientRect()) || {},
|
|
70
|
+
_ref2$width = _ref2.width,
|
|
71
|
+
scrollContainerWidth = _ref2$width === void 0 ? 0 : _ref2$width;
|
|
72
|
+
var scrollLeft = ((_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollLeft) || 0;
|
|
73
|
+
var scrollTo = side === 'left' ? scrollLeft - scrollContainerWidth : scrollLeft + scrollContainerWidth;
|
|
74
|
+
(_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 || _scrollContainerRef$c4.scrollTo({
|
|
75
|
+
top: 0,
|
|
76
|
+
left: scrollTo,
|
|
77
|
+
behavior: 'smooth'
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
var resizeObserver = new ResizeObserver(function (t) {
|
|
81
|
+
var _scrollContainerRef$c5, _scrollContainerRef$c6;
|
|
82
|
+
var widthNeededToShowAllItems = ((_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.scrollWidth) || 0;
|
|
83
|
+
var parentNode = (_scrollContainerRef$c6 = scrollContainerRef.current) === null || _scrollContainerRef$c6 === void 0 ? void 0 : _scrollContainerRef$c6.parentNode;
|
|
84
|
+
var availableSpace = -1;
|
|
85
|
+
if (parentNode instanceof HTMLElement) {
|
|
86
|
+
availableSpace = parentNode.offsetWidth;
|
|
87
|
+
}
|
|
88
|
+
if (availableSpace === -1) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (availableSpace >= widthNeededToShowAllItems) {
|
|
92
|
+
setNeedScroll(false);
|
|
93
|
+
} else {
|
|
94
|
+
setNeedScroll(true);
|
|
95
|
+
onScroll();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
(0, _react.useEffect)(function () {
|
|
99
|
+
onScroll();
|
|
100
|
+
var scrollContainerRefCurrent = scrollContainerRef.current;
|
|
101
|
+
var unbind;
|
|
102
|
+
if (scrollContainerRefCurrent) {
|
|
103
|
+
// Adding/removing scroll button depending on scroll position
|
|
104
|
+
unbind = (0, _bindEventListener.bind)(scrollContainerRefCurrent, {
|
|
105
|
+
type: 'scroll',
|
|
106
|
+
listener: onScroll
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// watch for toolbar resize and show/hide scroll buttons if needed
|
|
110
|
+
resizeObserver.observe(scrollContainerRefCurrent);
|
|
111
|
+
}
|
|
112
|
+
return function () {
|
|
113
|
+
if (scrollContainerRefCurrent) {
|
|
114
|
+
var _unbind;
|
|
115
|
+
(_unbind = unbind) === null || _unbind === void 0 || _unbind();
|
|
116
|
+
resizeObserver.unobserve(scrollContainerRefCurrent);
|
|
117
|
+
}
|
|
118
|
+
setCanScrollDebounced.cancel();
|
|
119
|
+
};
|
|
120
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
+
}, []);
|
|
122
|
+
(0, _react.useEffect)(function () {
|
|
123
|
+
var scrollContainerRefCurrent = scrollContainerRef.current;
|
|
124
|
+
if (scrollContainerRefCurrent) {
|
|
125
|
+
var _scrollContainerRefCu;
|
|
126
|
+
// reset scroll position when switching from one node with toolbar to another
|
|
127
|
+
// scroll to made optional as it may not be rendered in testing env
|
|
128
|
+
(_scrollContainerRefCu = scrollContainerRefCurrent.scrollTo) === null || _scrollContainerRefCu === void 0 || _scrollContainerRefCu.call(scrollContainerRefCurrent, {
|
|
129
|
+
left: 0
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}, [node.type, scrollContainerRef]);
|
|
133
|
+
var Icon = side === 'left' ? _chevronLeftChevronLeftLarge.default : _chevronRightChevronRightLarge.default;
|
|
134
|
+
return needScroll && (side === 'left' && canScrollToSide || side === 'right' && canScrollToSide) && /*#__PURE__*/_react.default.createElement(_primitives.Box, {
|
|
135
|
+
padding: "space.050",
|
|
136
|
+
xcss: [side === 'left' ? leftSideStyles : rightSideStyles, buttonCommonStyles]
|
|
137
|
+
}, /*#__PURE__*/_react.default.createElement(_new.IconButton, {
|
|
138
|
+
appearance: "subtle",
|
|
139
|
+
label: intl.formatMessage(side === 'left' ? _floatingToolbar.messages.floatingToolbarScrollLeft : _floatingToolbar.messages.floatingToolbarScrollRight),
|
|
140
|
+
onClick: onClick,
|
|
141
|
+
isDisabled: disabled,
|
|
142
|
+
icon: Icon,
|
|
143
|
+
isTooltipDisabled: false,
|
|
144
|
+
tooltip: {
|
|
145
|
+
position: 'top'
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
};
|
|
@@ -36,6 +36,7 @@ var toolbarScrollButtons = (0, _react2.css)({
|
|
|
36
36
|
});
|
|
37
37
|
var LeftIcon = _chevronLeftChevronLeftLarge.default;
|
|
38
38
|
var RightIcon = _chevronRightChevronRightLarge.default;
|
|
39
|
+
// Remove this component (replaced by ScrollButton) as part of platform_editor_controls clean up
|
|
39
40
|
var ScrollButtons = exports.ScrollButtons = function ScrollButtons(_ref) {
|
|
40
41
|
var intl = _ref.intl,
|
|
41
42
|
scrollContainerRef = _ref.scrollContainerRef,
|
package/dist/cjs/ui/Toolbar.js
CHANGED
|
@@ -33,6 +33,7 @@ var _Dropdown = _interopRequireDefault(require("./Dropdown"));
|
|
|
33
33
|
var _EmojiPickerButton = require("./EmojiPickerButton");
|
|
34
34
|
var _ExtensionsPlaceholder = require("./ExtensionsPlaceholder");
|
|
35
35
|
var _Input = require("./Input");
|
|
36
|
+
var _ScrollButton = require("./ScrollButton");
|
|
36
37
|
var _ScrollButtons = require("./ScrollButtons");
|
|
37
38
|
var _Select = _interopRequireDefault(require("./Select"));
|
|
38
39
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
@@ -646,6 +647,8 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
646
647
|
intl = _this$props2.intl,
|
|
647
648
|
scrollable = _this$props2.scrollable,
|
|
648
649
|
mediaAssistiveMessage = _this$props2.mediaAssistiveMessage;
|
|
650
|
+
var isEditorControlsEnabled = (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1');
|
|
651
|
+
var isEditorControlsPatch2Enabled = isEditorControlsEnabled && (0, _platformFeatureFlags.fg)('platform_editor_controls_patch_2');
|
|
649
652
|
if (!items || !items.length) {
|
|
650
653
|
return null;
|
|
651
654
|
}
|
|
@@ -677,10 +680,16 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
677
680
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
678
681
|
,
|
|
679
682
|
className: className,
|
|
680
|
-
onMouseDown:
|
|
683
|
+
onMouseDown: isEditorControlsEnabled ? this.captureMouseEvent : undefined
|
|
681
684
|
}, (0, _react2.jsx)(_ui.Announcer, {
|
|
682
685
|
text: mediaAssistiveMessage ? "".concat(mediaAssistiveMessage, ", ").concat(intl.formatMessage(_floatingToolbar.messages.floatingToolbarAnnouncer)) : intl.formatMessage(_floatingToolbar.messages.floatingToolbarAnnouncer),
|
|
683
686
|
delay: 250
|
|
687
|
+
}), scrollable && isEditorControlsPatch2Enabled && (0, _react2.jsx)(_ScrollButton.ScrollButton, {
|
|
688
|
+
intl: intl,
|
|
689
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
690
|
+
node: node,
|
|
691
|
+
disabled: this.state.scrollDisabled,
|
|
692
|
+
side: "left"
|
|
684
693
|
}), (0, _react2.jsx)("div", {
|
|
685
694
|
"data-testid": "floating-toolbar-items",
|
|
686
695
|
ref: this.scrollContainerRef
|
|
@@ -700,12 +709,18 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
700
709
|
setDisableScroll: this.setDisableScroll.bind(this),
|
|
701
710
|
mountRef: this.mountRef,
|
|
702
711
|
mounted: this.state.mounted
|
|
703
|
-
}))), scrollable && (0, _react2.jsx)(
|
|
712
|
+
}))), scrollable && (isEditorControlsPatch2Enabled ? (0, _react2.jsx)(_ScrollButton.ScrollButton, {
|
|
713
|
+
intl: intl,
|
|
714
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
715
|
+
node: node,
|
|
716
|
+
disabled: this.state.scrollDisabled,
|
|
717
|
+
side: "right"
|
|
718
|
+
}) : (0, _react2.jsx)(_ScrollButtons.ScrollButtons, {
|
|
704
719
|
intl: intl,
|
|
705
720
|
scrollContainerRef: this.scrollContainerRef,
|
|
706
721
|
node: node,
|
|
707
722
|
disabled: this.state.scrollDisabled
|
|
708
|
-
})), (0, _react2.jsx)("div", {
|
|
723
|
+
}))), (0, _react2.jsx)("div", {
|
|
709
724
|
ref: this.mountRef
|
|
710
725
|
})));
|
|
711
726
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
import rafSchedule from 'raf-schd';
|
|
4
|
+
import { IconButton } from '@atlaskit/button/new';
|
|
5
|
+
import { messages } from '@atlaskit/editor-common/floating-toolbar';
|
|
6
|
+
import ChevronLeftLargeIcon from '@atlaskit/icon/utility/migration/chevron-left--chevron-left-large';
|
|
7
|
+
import ChevronRightLargeIcon from '@atlaskit/icon/utility/migration/chevron-right--chevron-right-large';
|
|
8
|
+
import { Box, xcss } from '@atlaskit/primitives';
|
|
9
|
+
const rightSideStyles = xcss({
|
|
10
|
+
borderLeft: `solid ${"var(--ds-border, #091E4224)"} 1px`,
|
|
11
|
+
right: 'space.0',
|
|
12
|
+
borderTopRightRadius: '3px',
|
|
13
|
+
borderBottomRightRadius: '3px'
|
|
14
|
+
});
|
|
15
|
+
const leftSideStyles = xcss({
|
|
16
|
+
borderRight: `solid ${"var(--ds-border, #091E4224)"} 1px`,
|
|
17
|
+
left: 'space.0',
|
|
18
|
+
borderTopLeftRadius: '3px',
|
|
19
|
+
borderBottomLeftRadius: '3px'
|
|
20
|
+
});
|
|
21
|
+
const buttonCommonStyles = xcss({
|
|
22
|
+
backgroundColor: 'elevation.surface.overlay',
|
|
23
|
+
zIndex: '1',
|
|
24
|
+
position: 'absolute'
|
|
25
|
+
});
|
|
26
|
+
export const ScrollButton = ({
|
|
27
|
+
intl,
|
|
28
|
+
scrollContainerRef,
|
|
29
|
+
node,
|
|
30
|
+
disabled,
|
|
31
|
+
side
|
|
32
|
+
}) => {
|
|
33
|
+
const [needScroll, setNeedScroll] = useState(false);
|
|
34
|
+
const [canScrollToSide, setCanScrollToSide] = useState(true);
|
|
35
|
+
const setCanScrollDebounced = rafSchedule(() => {
|
|
36
|
+
// Refs are null before mounting and after unmount
|
|
37
|
+
if (!scrollContainerRef.current) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const {
|
|
41
|
+
scrollLeft,
|
|
42
|
+
scrollWidth,
|
|
43
|
+
offsetWidth
|
|
44
|
+
} = scrollContainerRef.current;
|
|
45
|
+
setCanScrollToSide(
|
|
46
|
+
// -1 to account for pixel rounding error
|
|
47
|
+
side === 'left' ? scrollLeft > 0 : scrollLeft < scrollWidth - offsetWidth - 1);
|
|
48
|
+
});
|
|
49
|
+
const onScroll = () => {
|
|
50
|
+
setCanScrollDebounced();
|
|
51
|
+
};
|
|
52
|
+
const onClick = () => {
|
|
53
|
+
var _scrollContainerRef$c, _scrollContainerRef$c2, _scrollContainerRef$c3;
|
|
54
|
+
const {
|
|
55
|
+
width: scrollContainerWidth = 0
|
|
56
|
+
} = ((_scrollContainerRef$c = scrollContainerRef.current) === null || _scrollContainerRef$c === void 0 ? void 0 : _scrollContainerRef$c.getBoundingClientRect()) || {};
|
|
57
|
+
const scrollLeft = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.scrollLeft) || 0;
|
|
58
|
+
const scrollTo = side === 'left' ? scrollLeft - scrollContainerWidth : scrollLeft + scrollContainerWidth;
|
|
59
|
+
(_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollTo({
|
|
60
|
+
top: 0,
|
|
61
|
+
left: scrollTo,
|
|
62
|
+
behavior: 'smooth'
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const resizeObserver = new ResizeObserver(t => {
|
|
66
|
+
var _scrollContainerRef$c4, _scrollContainerRef$c5;
|
|
67
|
+
const widthNeededToShowAllItems = ((_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 ? void 0 : _scrollContainerRef$c4.scrollWidth) || 0;
|
|
68
|
+
const parentNode = (_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.parentNode;
|
|
69
|
+
let availableSpace = -1;
|
|
70
|
+
if (parentNode instanceof HTMLElement) {
|
|
71
|
+
availableSpace = parentNode.offsetWidth;
|
|
72
|
+
}
|
|
73
|
+
if (availableSpace === -1) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (availableSpace >= widthNeededToShowAllItems) {
|
|
77
|
+
setNeedScroll(false);
|
|
78
|
+
} else {
|
|
79
|
+
setNeedScroll(true);
|
|
80
|
+
onScroll();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
onScroll();
|
|
85
|
+
const scrollContainerRefCurrent = scrollContainerRef.current;
|
|
86
|
+
let unbind;
|
|
87
|
+
if (scrollContainerRefCurrent) {
|
|
88
|
+
// Adding/removing scroll button depending on scroll position
|
|
89
|
+
unbind = bind(scrollContainerRefCurrent, {
|
|
90
|
+
type: 'scroll',
|
|
91
|
+
listener: onScroll
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// watch for toolbar resize and show/hide scroll buttons if needed
|
|
95
|
+
resizeObserver.observe(scrollContainerRefCurrent);
|
|
96
|
+
}
|
|
97
|
+
return () => {
|
|
98
|
+
if (scrollContainerRefCurrent) {
|
|
99
|
+
var _unbind;
|
|
100
|
+
(_unbind = unbind) === null || _unbind === void 0 ? void 0 : _unbind();
|
|
101
|
+
resizeObserver.unobserve(scrollContainerRefCurrent);
|
|
102
|
+
}
|
|
103
|
+
setCanScrollDebounced.cancel();
|
|
104
|
+
};
|
|
105
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
106
|
+
}, []);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
const scrollContainerRefCurrent = scrollContainerRef.current;
|
|
109
|
+
if (scrollContainerRefCurrent) {
|
|
110
|
+
var _scrollContainerRefCu;
|
|
111
|
+
// reset scroll position when switching from one node with toolbar to another
|
|
112
|
+
// scroll to made optional as it may not be rendered in testing env
|
|
113
|
+
(_scrollContainerRefCu = scrollContainerRefCurrent.scrollTo) === null || _scrollContainerRefCu === void 0 ? void 0 : _scrollContainerRefCu.call(scrollContainerRefCurrent, {
|
|
114
|
+
left: 0
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}, [node.type, scrollContainerRef]);
|
|
118
|
+
const Icon = side === 'left' ? ChevronLeftLargeIcon : ChevronRightLargeIcon;
|
|
119
|
+
return needScroll && (side === 'left' && canScrollToSide || side === 'right' && canScrollToSide) && /*#__PURE__*/React.createElement(Box, {
|
|
120
|
+
padding: "space.050",
|
|
121
|
+
xcss: [side === 'left' ? leftSideStyles : rightSideStyles, buttonCommonStyles]
|
|
122
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
123
|
+
appearance: "subtle",
|
|
124
|
+
label: intl.formatMessage(side === 'left' ? messages.floatingToolbarScrollLeft : messages.floatingToolbarScrollRight),
|
|
125
|
+
onClick: onClick,
|
|
126
|
+
isDisabled: disabled,
|
|
127
|
+
icon: Icon,
|
|
128
|
+
isTooltipDisabled: false,
|
|
129
|
+
tooltip: {
|
|
130
|
+
position: 'top'
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
133
|
+
};
|
|
@@ -24,6 +24,7 @@ const toolbarScrollButtons = css({
|
|
|
24
24
|
});
|
|
25
25
|
const LeftIcon = ChevronLeftLargeIcon;
|
|
26
26
|
const RightIcon = ChevronRightLargeIcon;
|
|
27
|
+
// Remove this component (replaced by ScrollButton) as part of platform_editor_controls clean up
|
|
27
28
|
export const ScrollButtons = ({
|
|
28
29
|
intl,
|
|
29
30
|
scrollContainerRef,
|
|
@@ -26,6 +26,7 @@ import Dropdown from './Dropdown';
|
|
|
26
26
|
import { EmojiPickerButton } from './EmojiPickerButton';
|
|
27
27
|
import { ExtensionsPlaceholder } from './ExtensionsPlaceholder';
|
|
28
28
|
import { Input } from './Input';
|
|
29
|
+
import { ScrollButton } from './ScrollButton';
|
|
29
30
|
import { ScrollButtons } from './ScrollButtons';
|
|
30
31
|
import Select from './Select';
|
|
31
32
|
export function groupItems(items) {
|
|
@@ -600,6 +601,8 @@ class Toolbar extends Component {
|
|
|
600
601
|
scrollable,
|
|
601
602
|
mediaAssistiveMessage
|
|
602
603
|
} = this.props;
|
|
604
|
+
const isEditorControlsEnabled = editorExperiment('platform_editor_controls', 'variant1');
|
|
605
|
+
const isEditorControlsPatch2Enabled = isEditorControlsEnabled && fg('platform_editor_controls_patch_2');
|
|
603
606
|
if (!items || !items.length) {
|
|
604
607
|
return null;
|
|
605
608
|
}
|
|
@@ -627,10 +630,16 @@ class Toolbar extends Component {
|
|
|
627
630
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
628
631
|
,
|
|
629
632
|
className: className,
|
|
630
|
-
onMouseDown:
|
|
633
|
+
onMouseDown: isEditorControlsEnabled ? this.captureMouseEvent : undefined
|
|
631
634
|
}, jsx(Announcer, {
|
|
632
635
|
text: mediaAssistiveMessage ? `${mediaAssistiveMessage}, ${intl.formatMessage(messages.floatingToolbarAnnouncer)}` : intl.formatMessage(messages.floatingToolbarAnnouncer),
|
|
633
636
|
delay: 250
|
|
637
|
+
}), scrollable && isEditorControlsPatch2Enabled && jsx(ScrollButton, {
|
|
638
|
+
intl: intl,
|
|
639
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
640
|
+
node: node,
|
|
641
|
+
disabled: this.state.scrollDisabled,
|
|
642
|
+
side: "left"
|
|
634
643
|
}), jsx("div", {
|
|
635
644
|
"data-testid": "floating-toolbar-items",
|
|
636
645
|
ref: this.scrollContainerRef
|
|
@@ -650,12 +659,18 @@ class Toolbar extends Component {
|
|
|
650
659
|
setDisableScroll: this.setDisableScroll.bind(this),
|
|
651
660
|
mountRef: this.mountRef,
|
|
652
661
|
mounted: this.state.mounted
|
|
653
|
-
}))), scrollable && jsx(
|
|
662
|
+
}))), scrollable && (isEditorControlsPatch2Enabled ? jsx(ScrollButton, {
|
|
663
|
+
intl: intl,
|
|
664
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
665
|
+
node: node,
|
|
666
|
+
disabled: this.state.scrollDisabled,
|
|
667
|
+
side: "right"
|
|
668
|
+
}) : jsx(ScrollButtons, {
|
|
654
669
|
intl: intl,
|
|
655
670
|
scrollContainerRef: this.scrollContainerRef,
|
|
656
671
|
node: node,
|
|
657
672
|
disabled: this.state.scrollDisabled
|
|
658
|
-
})), jsx("div", {
|
|
673
|
+
}))), jsx("div", {
|
|
659
674
|
ref: this.mountRef
|
|
660
675
|
})));
|
|
661
676
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { bind } from 'bind-event-listener';
|
|
4
|
+
import rafSchedule from 'raf-schd';
|
|
5
|
+
import { IconButton } from '@atlaskit/button/new';
|
|
6
|
+
import { messages } from '@atlaskit/editor-common/floating-toolbar';
|
|
7
|
+
import ChevronLeftLargeIcon from '@atlaskit/icon/utility/migration/chevron-left--chevron-left-large';
|
|
8
|
+
import ChevronRightLargeIcon from '@atlaskit/icon/utility/migration/chevron-right--chevron-right-large';
|
|
9
|
+
import { Box, xcss } from '@atlaskit/primitives';
|
|
10
|
+
var rightSideStyles = xcss({
|
|
11
|
+
borderLeft: "solid ".concat("var(--ds-border, #091E4224)", " 1px"),
|
|
12
|
+
right: 'space.0',
|
|
13
|
+
borderTopRightRadius: '3px',
|
|
14
|
+
borderBottomRightRadius: '3px'
|
|
15
|
+
});
|
|
16
|
+
var leftSideStyles = xcss({
|
|
17
|
+
borderRight: "solid ".concat("var(--ds-border, #091E4224)", " 1px"),
|
|
18
|
+
left: 'space.0',
|
|
19
|
+
borderTopLeftRadius: '3px',
|
|
20
|
+
borderBottomLeftRadius: '3px'
|
|
21
|
+
});
|
|
22
|
+
var buttonCommonStyles = xcss({
|
|
23
|
+
backgroundColor: 'elevation.surface.overlay',
|
|
24
|
+
zIndex: '1',
|
|
25
|
+
position: 'absolute'
|
|
26
|
+
});
|
|
27
|
+
export var ScrollButton = function ScrollButton(_ref) {
|
|
28
|
+
var intl = _ref.intl,
|
|
29
|
+
scrollContainerRef = _ref.scrollContainerRef,
|
|
30
|
+
node = _ref.node,
|
|
31
|
+
disabled = _ref.disabled,
|
|
32
|
+
side = _ref.side;
|
|
33
|
+
var _useState = useState(false),
|
|
34
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
35
|
+
needScroll = _useState2[0],
|
|
36
|
+
setNeedScroll = _useState2[1];
|
|
37
|
+
var _useState3 = useState(true),
|
|
38
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
39
|
+
canScrollToSide = _useState4[0],
|
|
40
|
+
setCanScrollToSide = _useState4[1];
|
|
41
|
+
var setCanScrollDebounced = rafSchedule(function () {
|
|
42
|
+
// Refs are null before mounting and after unmount
|
|
43
|
+
if (!scrollContainerRef.current) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
var _scrollContainerRef$c = scrollContainerRef.current,
|
|
47
|
+
scrollLeft = _scrollContainerRef$c.scrollLeft,
|
|
48
|
+
scrollWidth = _scrollContainerRef$c.scrollWidth,
|
|
49
|
+
offsetWidth = _scrollContainerRef$c.offsetWidth;
|
|
50
|
+
setCanScrollToSide(
|
|
51
|
+
// -1 to account for pixel rounding error
|
|
52
|
+
side === 'left' ? scrollLeft > 0 : scrollLeft < scrollWidth - offsetWidth - 1);
|
|
53
|
+
});
|
|
54
|
+
var onScroll = function onScroll() {
|
|
55
|
+
setCanScrollDebounced();
|
|
56
|
+
};
|
|
57
|
+
var onClick = function onClick() {
|
|
58
|
+
var _scrollContainerRef$c2, _scrollContainerRef$c3, _scrollContainerRef$c4;
|
|
59
|
+
var _ref2 = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.getBoundingClientRect()) || {},
|
|
60
|
+
_ref2$width = _ref2.width,
|
|
61
|
+
scrollContainerWidth = _ref2$width === void 0 ? 0 : _ref2$width;
|
|
62
|
+
var scrollLeft = ((_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollLeft) || 0;
|
|
63
|
+
var scrollTo = side === 'left' ? scrollLeft - scrollContainerWidth : scrollLeft + scrollContainerWidth;
|
|
64
|
+
(_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 || _scrollContainerRef$c4.scrollTo({
|
|
65
|
+
top: 0,
|
|
66
|
+
left: scrollTo,
|
|
67
|
+
behavior: 'smooth'
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
var resizeObserver = new ResizeObserver(function (t) {
|
|
71
|
+
var _scrollContainerRef$c5, _scrollContainerRef$c6;
|
|
72
|
+
var widthNeededToShowAllItems = ((_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.scrollWidth) || 0;
|
|
73
|
+
var parentNode = (_scrollContainerRef$c6 = scrollContainerRef.current) === null || _scrollContainerRef$c6 === void 0 ? void 0 : _scrollContainerRef$c6.parentNode;
|
|
74
|
+
var availableSpace = -1;
|
|
75
|
+
if (parentNode instanceof HTMLElement) {
|
|
76
|
+
availableSpace = parentNode.offsetWidth;
|
|
77
|
+
}
|
|
78
|
+
if (availableSpace === -1) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (availableSpace >= widthNeededToShowAllItems) {
|
|
82
|
+
setNeedScroll(false);
|
|
83
|
+
} else {
|
|
84
|
+
setNeedScroll(true);
|
|
85
|
+
onScroll();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
useEffect(function () {
|
|
89
|
+
onScroll();
|
|
90
|
+
var scrollContainerRefCurrent = scrollContainerRef.current;
|
|
91
|
+
var unbind;
|
|
92
|
+
if (scrollContainerRefCurrent) {
|
|
93
|
+
// Adding/removing scroll button depending on scroll position
|
|
94
|
+
unbind = bind(scrollContainerRefCurrent, {
|
|
95
|
+
type: 'scroll',
|
|
96
|
+
listener: onScroll
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// watch for toolbar resize and show/hide scroll buttons if needed
|
|
100
|
+
resizeObserver.observe(scrollContainerRefCurrent);
|
|
101
|
+
}
|
|
102
|
+
return function () {
|
|
103
|
+
if (scrollContainerRefCurrent) {
|
|
104
|
+
var _unbind;
|
|
105
|
+
(_unbind = unbind) === null || _unbind === void 0 || _unbind();
|
|
106
|
+
resizeObserver.unobserve(scrollContainerRefCurrent);
|
|
107
|
+
}
|
|
108
|
+
setCanScrollDebounced.cancel();
|
|
109
|
+
};
|
|
110
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
111
|
+
}, []);
|
|
112
|
+
useEffect(function () {
|
|
113
|
+
var scrollContainerRefCurrent = scrollContainerRef.current;
|
|
114
|
+
if (scrollContainerRefCurrent) {
|
|
115
|
+
var _scrollContainerRefCu;
|
|
116
|
+
// reset scroll position when switching from one node with toolbar to another
|
|
117
|
+
// scroll to made optional as it may not be rendered in testing env
|
|
118
|
+
(_scrollContainerRefCu = scrollContainerRefCurrent.scrollTo) === null || _scrollContainerRefCu === void 0 || _scrollContainerRefCu.call(scrollContainerRefCurrent, {
|
|
119
|
+
left: 0
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}, [node.type, scrollContainerRef]);
|
|
123
|
+
var Icon = side === 'left' ? ChevronLeftLargeIcon : ChevronRightLargeIcon;
|
|
124
|
+
return needScroll && (side === 'left' && canScrollToSide || side === 'right' && canScrollToSide) && /*#__PURE__*/React.createElement(Box, {
|
|
125
|
+
padding: "space.050",
|
|
126
|
+
xcss: [side === 'left' ? leftSideStyles : rightSideStyles, buttonCommonStyles]
|
|
127
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
128
|
+
appearance: "subtle",
|
|
129
|
+
label: intl.formatMessage(side === 'left' ? messages.floatingToolbarScrollLeft : messages.floatingToolbarScrollRight),
|
|
130
|
+
onClick: onClick,
|
|
131
|
+
isDisabled: disabled,
|
|
132
|
+
icon: Icon,
|
|
133
|
+
isTooltipDisabled: false,
|
|
134
|
+
tooltip: {
|
|
135
|
+
position: 'top'
|
|
136
|
+
}
|
|
137
|
+
}));
|
|
138
|
+
};
|
|
@@ -25,6 +25,7 @@ var toolbarScrollButtons = css({
|
|
|
25
25
|
});
|
|
26
26
|
var LeftIcon = ChevronLeftLargeIcon;
|
|
27
27
|
var RightIcon = ChevronRightLargeIcon;
|
|
28
|
+
// Remove this component (replaced by ScrollButton) as part of platform_editor_controls clean up
|
|
28
29
|
export var ScrollButtons = function ScrollButtons(_ref) {
|
|
29
30
|
var intl = _ref.intl,
|
|
30
31
|
scrollContainerRef = _ref.scrollContainerRef,
|
package/dist/esm/ui/Toolbar.js
CHANGED
|
@@ -33,6 +33,7 @@ import Dropdown from './Dropdown';
|
|
|
33
33
|
import { EmojiPickerButton } from './EmojiPickerButton';
|
|
34
34
|
import { ExtensionsPlaceholder } from './ExtensionsPlaceholder';
|
|
35
35
|
import { Input } from './Input';
|
|
36
|
+
import { ScrollButton } from './ScrollButton';
|
|
36
37
|
import { ScrollButtons } from './ScrollButtons';
|
|
37
38
|
import Select from './Select';
|
|
38
39
|
export function groupItems(items) {
|
|
@@ -639,6 +640,8 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
639
640
|
intl = _this$props2.intl,
|
|
640
641
|
scrollable = _this$props2.scrollable,
|
|
641
642
|
mediaAssistiveMessage = _this$props2.mediaAssistiveMessage;
|
|
643
|
+
var isEditorControlsEnabled = editorExperiment('platform_editor_controls', 'variant1');
|
|
644
|
+
var isEditorControlsPatch2Enabled = isEditorControlsEnabled && fg('platform_editor_controls_patch_2');
|
|
642
645
|
if (!items || !items.length) {
|
|
643
646
|
return null;
|
|
644
647
|
}
|
|
@@ -670,10 +673,16 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
670
673
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
671
674
|
,
|
|
672
675
|
className: className,
|
|
673
|
-
onMouseDown:
|
|
676
|
+
onMouseDown: isEditorControlsEnabled ? this.captureMouseEvent : undefined
|
|
674
677
|
}, jsx(Announcer, {
|
|
675
678
|
text: mediaAssistiveMessage ? "".concat(mediaAssistiveMessage, ", ").concat(intl.formatMessage(messages.floatingToolbarAnnouncer)) : intl.formatMessage(messages.floatingToolbarAnnouncer),
|
|
676
679
|
delay: 250
|
|
680
|
+
}), scrollable && isEditorControlsPatch2Enabled && jsx(ScrollButton, {
|
|
681
|
+
intl: intl,
|
|
682
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
683
|
+
node: node,
|
|
684
|
+
disabled: this.state.scrollDisabled,
|
|
685
|
+
side: "left"
|
|
677
686
|
}), jsx("div", {
|
|
678
687
|
"data-testid": "floating-toolbar-items",
|
|
679
688
|
ref: this.scrollContainerRef
|
|
@@ -693,12 +702,18 @@ var Toolbar = /*#__PURE__*/function (_Component) {
|
|
|
693
702
|
setDisableScroll: this.setDisableScroll.bind(this),
|
|
694
703
|
mountRef: this.mountRef,
|
|
695
704
|
mounted: this.state.mounted
|
|
696
|
-
}))), scrollable && jsx(
|
|
705
|
+
}))), scrollable && (isEditorControlsPatch2Enabled ? jsx(ScrollButton, {
|
|
706
|
+
intl: intl,
|
|
707
|
+
scrollContainerRef: this.scrollContainerRef,
|
|
708
|
+
node: node,
|
|
709
|
+
disabled: this.state.scrollDisabled,
|
|
710
|
+
side: "right"
|
|
711
|
+
}) : jsx(ScrollButtons, {
|
|
697
712
|
intl: intl,
|
|
698
713
|
scrollContainerRef: this.scrollContainerRef,
|
|
699
714
|
node: node,
|
|
700
715
|
disabled: this.state.scrollDisabled
|
|
701
|
-
})), jsx("div", {
|
|
716
|
+
}))), jsx("div", {
|
|
702
717
|
ref: this.mountRef
|
|
703
718
|
})));
|
|
704
719
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { IntlShape } from 'react-intl-next';
|
|
3
|
+
import type { Node } from '@atlaskit/editor-prosemirror/model';
|
|
4
|
+
type ScrollButtonProps = {
|
|
5
|
+
intl: IntlShape;
|
|
6
|
+
scrollContainerRef: React.RefObject<HTMLDivElement>;
|
|
7
|
+
node: Node;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
side: 'left' | 'right';
|
|
10
|
+
};
|
|
11
|
+
export declare const ScrollButton: ({ intl, scrollContainerRef, node, disabled, side, }: ScrollButtonProps) => false | React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { IntlShape } from 'react-intl-next';
|
|
3
|
+
import type { Node } from '@atlaskit/editor-prosemirror/model';
|
|
4
|
+
type ScrollButtonProps = {
|
|
5
|
+
intl: IntlShape;
|
|
6
|
+
scrollContainerRef: React.RefObject<HTMLDivElement>;
|
|
7
|
+
node: Node;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
side: 'left' | 'right';
|
|
10
|
+
};
|
|
11
|
+
export declare const ScrollButton: ({ intl, scrollContainerRef, node, disabled, side, }: ScrollButtonProps) => false | React.JSX.Element;
|
|
12
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-floating-toolbar",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.5",
|
|
4
4
|
"description": "Floating toolbar plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"@atlaskit/tooltip": "^20.0.0",
|
|
54
54
|
"@babel/runtime": "^7.0.0",
|
|
55
55
|
"@emotion/react": "^11.7.1",
|
|
56
|
+
"bind-event-listener": "^3.0.0",
|
|
56
57
|
"lodash": "^4.17.21",
|
|
57
58
|
"raf-schd": "^4.0.3",
|
|
58
59
|
"react-intl-next": "npm:react-intl@^5.18.1",
|
|
@@ -130,6 +131,9 @@
|
|
|
130
131
|
},
|
|
131
132
|
"platform_editor_controls_patch_1": {
|
|
132
133
|
"type": "boolean"
|
|
134
|
+
},
|
|
135
|
+
"platform_editor_controls_patch_2": {
|
|
136
|
+
"type": "boolean"
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
}
|