Merge pull request #16801 from KDSBrowne/bbb-16662
refactor: Move Pan Tool Next To The Pointer Tool
This commit is contained in:
commit
aa517df377
@ -98,6 +98,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
main {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.overrideSelect {
|
||||
background-color: #FFF !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.select {
|
||||
background-color: rgba(66, 133, 244, 1) !important;
|
||||
color: #FFF !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('gesturestart', function (e) {
|
||||
|
@ -264,9 +264,7 @@ class PresentationToolbar extends PureComponent {
|
||||
currentSlide,
|
||||
slidePosition,
|
||||
multiUserSize,
|
||||
multiUser,
|
||||
setIsPanning,
|
||||
isPanning,
|
||||
multiUser
|
||||
} = this.props;
|
||||
|
||||
const { isMobile } = deviceInfo;
|
||||
@ -400,20 +398,6 @@ class PresentationToolbar extends PureComponent {
|
||||
/>
|
||||
</TooltipContainer>
|
||||
) : null}
|
||||
<Styled.FitToWidthButton
|
||||
role="button"
|
||||
data-test="panButton"
|
||||
aria-label={intl.formatMessage(intlMessages.pan)}
|
||||
color="light"
|
||||
disabled={(zoom <= HUNDRED_PERCENT && !fitToWidth)}
|
||||
icon="hand"
|
||||
size="md"
|
||||
circle
|
||||
onClick={setIsPanning}
|
||||
label={intl.formatMessage(intlMessages.pan)}
|
||||
hideLabel
|
||||
panning={isPanning}
|
||||
/>
|
||||
<Styled.FitToWidthButton
|
||||
role="button"
|
||||
data-test="fitToWidthButton"
|
||||
|
@ -10,6 +10,8 @@ import logger from '/imports/startup/client/logger';
|
||||
import KEY_CODES from '/imports/utils/keyCodes';
|
||||
import { presentationMenuHeight, borderSize, borderSizeLarge } from '/imports/ui/stylesheets/styled-components/general';
|
||||
import { colorWhite, colorBlack } from '/imports/ui/stylesheets/styled-components/palette';
|
||||
import Styled from './styles';
|
||||
import PanToolInjector from './pan-tool-injector/component';
|
||||
|
||||
function usePrevious(value) {
|
||||
const ref = React.useRef();
|
||||
@ -49,6 +51,7 @@ const SMALLEST_WIDTH = 645;
|
||||
const TOOLBAR_SMALL = 28;
|
||||
const TOOLBAR_LARGE = 38;
|
||||
const TOOLBAR_OFFSET = 0;
|
||||
const DEFAULT_TOOL_COUNT = 9;
|
||||
|
||||
const TldrawGlobalStyle = createGlobalStyle`
|
||||
${({ hideContextMenu }) => hideContextMenu && `
|
||||
@ -149,7 +152,6 @@ export default function Whiteboard(props) {
|
||||
isRTL,
|
||||
fitToWidth,
|
||||
zoomValue,
|
||||
isPanning,
|
||||
intl,
|
||||
svgUri,
|
||||
maxStickyNoteLength,
|
||||
@ -160,8 +162,8 @@ export default function Whiteboard(props) {
|
||||
maxNumberOfAnnotations,
|
||||
notifyShapeNumberExceeded,
|
||||
darkTheme,
|
||||
isPanning: shortcutPanning,
|
||||
} = props;
|
||||
|
||||
const { pages, pageStates } = initDefaultPages(curPres?.pages.length || 1);
|
||||
const rDocument = React.useRef({
|
||||
name: "test",
|
||||
@ -186,6 +188,60 @@ export default function Whiteboard(props) {
|
||||
const language = mapLanguage(Settings?.application?.locale?.toLowerCase() || 'en');
|
||||
const [currentTool, setCurrentTool] = React.useState(null);
|
||||
const [isMoving, setIsMoving] = React.useState(false);
|
||||
const [isPanning, setIsPanning] = React.useState(shortcutPanning);
|
||||
const [panSelected, setPanSelected] = React.useState(isPanning);
|
||||
const isMountedRef = React.useRef(true);
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const setSafeTLDrawAPI = (api) => {
|
||||
if (isMountedRef.current) {
|
||||
setTLDrawAPI(api);
|
||||
}
|
||||
};
|
||||
|
||||
const setSafeCurrentTool = (tool) => {
|
||||
if (isMountedRef.current) {
|
||||
setCurrentTool(tool);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOffCheck = (evt) => {
|
||||
const clickedElement = evt.target;
|
||||
const toolbar = document.getElementById("TD-PrimaryTools");
|
||||
const panBtnClicked = clickedElement?.getAttribute('data-test') === 'panButton'
|
||||
|| clickedElement?.parentElement?.getAttribute('data-test') === 'panButton';
|
||||
const panButton = document.querySelector('[data-test="panButton"]');
|
||||
if (panBtnClicked) {
|
||||
const dataZoom = panButton.getAttribute('data-zoom');
|
||||
if ((dataZoom <= HUNDRED_PERCENT && !fitToWidth)) {
|
||||
return;
|
||||
}
|
||||
panButton.classList.add('select');
|
||||
panButton.classList.remove('selectOverride');
|
||||
return;
|
||||
} else {
|
||||
setIsPanning(false);
|
||||
setPanSelected(false);
|
||||
panButton.classList.add('selectOverride');
|
||||
panButton.classList.remove('select');
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const toolbar = document.getElementById("TD-PrimaryTools");
|
||||
const handleClick = (evt) => {
|
||||
toggleOffCheck(evt);
|
||||
};
|
||||
toolbar?.addEventListener('click', handleClick);
|
||||
return () => {
|
||||
toolbar?.removeEventListener('click', handleClick);
|
||||
};
|
||||
}, [tldrawAPI]);
|
||||
|
||||
const throttledResetCurrentPoint = React.useRef(_.throttle(() => {
|
||||
setEnable(false);
|
||||
@ -676,6 +732,8 @@ export default function Whiteboard(props) {
|
||||
|
||||
const onMount = (app) => {
|
||||
const menu = document.getElementById("TD-Styles")?.parentElement;
|
||||
setSafeCurrentTool('select');
|
||||
|
||||
if (menu) {
|
||||
const MENU_OFFSET = `48px`;
|
||||
menu.style.position = `relative`;
|
||||
@ -703,7 +761,7 @@ export default function Whiteboard(props) {
|
||||
}
|
||||
);
|
||||
|
||||
setTLDrawAPI(app);
|
||||
setSafeTLDrawAPI(app);
|
||||
props.setTldrawAPI(app);
|
||||
// disable for non presenter that doesn't have multi user access
|
||||
if (!hasWBAccess && !isPresenter) {
|
||||
@ -771,7 +829,7 @@ export default function Whiteboard(props) {
|
||||
}
|
||||
|
||||
if (reason && isPresenter && slidePosition && (reason.includes("zoomed") || reason.includes("panned"))) {
|
||||
const camera = tldrawAPI.getPageState()?.camera;
|
||||
const camera = tldrawAPI?.getPageState()?.camera;
|
||||
|
||||
// limit bounds
|
||||
if (tldrawAPI?.viewport.maxX > slidePosition.width) {
|
||||
@ -862,8 +920,9 @@ export default function Whiteboard(props) {
|
||||
|
||||
if (reason && reason.includes('selected_tool')) {
|
||||
const tool = reason.split(':')[1];
|
||||
|
||||
setCurrentTool(tool);
|
||||
setPanSelected(false);
|
||||
setIsPanning(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1021,6 +1080,21 @@ export default function Whiteboard(props) {
|
||||
}}
|
||||
/>
|
||||
</Cursors>
|
||||
{isPresenter &&
|
||||
<PanToolInjector
|
||||
{...{
|
||||
tldrawAPI,
|
||||
fitToWidth,
|
||||
isPanning,
|
||||
setIsPanning,
|
||||
zoomValue,
|
||||
panSelected,
|
||||
setPanSelected,
|
||||
currentTool,
|
||||
}}
|
||||
formatMessage={intl?.formatMessage}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
import * as React from "react";
|
||||
import ReactDOM from 'react-dom';
|
||||
import { HUNDRED_PERCENT } from '/imports/utils/slideCalcUtils';
|
||||
import Styled from '../styles';
|
||||
|
||||
const DEFAULT_TOOL_COUNT = 9;
|
||||
|
||||
class PanToolInjector extends React.Component {
|
||||
componentDidMount() {
|
||||
this.addPanTool();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
zoomValue,
|
||||
fitToWidth,
|
||||
isPanning,
|
||||
setIsPanning,
|
||||
formatMessage,
|
||||
tldrawAPI,
|
||||
panSelected,
|
||||
setPanSelected
|
||||
} = this.props;
|
||||
if (prevProps.zoomValue !== zoomValue
|
||||
|| prevProps.fitToWidth !== fitToWidth
|
||||
|| prevProps.isPanning !== isPanning
|
||||
|| prevProps.tldrawAPI !== tldrawAPI
|
||||
|| prevProps.panSelected !== panSelected
|
||||
) {
|
||||
this.addPanTool();
|
||||
if (panSelected) {
|
||||
// tldrawAPI?.selectTool('draw');
|
||||
setIsPanning(true);
|
||||
setPanSelected(true);
|
||||
} else {
|
||||
setIsPanning(false);
|
||||
setPanSelected(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPanTool() {
|
||||
const {
|
||||
zoomValue,
|
||||
fitToWidth,
|
||||
isPanning,
|
||||
setIsPanning,
|
||||
formatMessage,
|
||||
tldrawAPI,
|
||||
panSelected,
|
||||
setPanSelected
|
||||
} = this.props;
|
||||
|
||||
const tools = document.querySelectorAll('[id*="TD-PrimaryTools-"]');
|
||||
tools.forEach(tool => {
|
||||
const classList = tool.firstElementChild.classList;
|
||||
if (panSelected) {
|
||||
classList.add('overrideSelect');
|
||||
tldrawAPI?.selectTool('draw');
|
||||
} else {
|
||||
classList.remove('overrideSelect');
|
||||
}
|
||||
});
|
||||
|
||||
if (zoomValue === HUNDRED_PERCENT) {
|
||||
setPanSelected(false);
|
||||
setIsPanning(false);
|
||||
tldrawAPI?.selectTool('select');
|
||||
}
|
||||
|
||||
const parentElement = document.getElementById('TD-PrimaryTools');
|
||||
if (!parentElement) return;
|
||||
|
||||
if (parentElement.childElementCount === DEFAULT_TOOL_COUNT) {
|
||||
parentElement.removeChild(parentElement.children[1]);
|
||||
}
|
||||
|
||||
if (parentElement.childElementCount < DEFAULT_TOOL_COUNT) {
|
||||
const label = formatMessage({
|
||||
id: 'app.whiteboard.toolbar.tools.hand',
|
||||
description: 'presentation toolbar pan label',
|
||||
});
|
||||
const container = document.createElement('span');
|
||||
parentElement.appendChild(container);
|
||||
ReactDOM.render(
|
||||
<Styled.PanTool
|
||||
key={'bbb-panBtn'}
|
||||
role="button"
|
||||
data-test="panButton"
|
||||
data-zoom={zoomValue}
|
||||
className={"overrideSelect"}
|
||||
color="light"
|
||||
icon="hand"
|
||||
size="md"
|
||||
aria-label={label}
|
||||
disabled={(zoomValue <= HUNDRED_PERCENT && !fitToWidth)}
|
||||
onClick={() => {
|
||||
setPanSelected(true);
|
||||
setIsPanning(true);
|
||||
if (!(zoomValue <= HUNDRED_PERCENT && !fitToWidth)) {
|
||||
const panButton = document.querySelector('[data-test="panButton"]');
|
||||
if (panButton) {
|
||||
panButton.classList.remove('selectOverride');
|
||||
panButton.classList.add('select');
|
||||
}
|
||||
}
|
||||
}}
|
||||
label={label}
|
||||
hideLabel
|
||||
/>,
|
||||
container
|
||||
);
|
||||
const lastChild = parentElement.lastChild;
|
||||
const secondChild = parentElement.children[1];
|
||||
parentElement.insertBefore(lastChild, secondChild);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default PanToolInjector;
|
@ -0,0 +1,38 @@
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
toolbarButtonColor,
|
||||
colorWhite,
|
||||
} from '/imports/ui/stylesheets/styled-components/palette';
|
||||
import {
|
||||
fontSizeLarger,
|
||||
} from '/imports/ui/stylesheets/styled-components/typography';
|
||||
import Button from '/imports/ui/components/common/button/component';
|
||||
|
||||
const PanTool = styled(Button)`
|
||||
border: none !important;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 7px;
|
||||
background-color: ${colorWhite};
|
||||
color: ${toolbarButtonColor};
|
||||
|
||||
& > i {
|
||||
font-size: ${fontSizeLarger} !important;
|
||||
[dir="rtl"] & {
|
||||
-webkit-transform: scale(-1, 1);
|
||||
-moz-transform: scale(-1, 1);
|
||||
-ms-transform: scale(-1, 1);
|
||||
-o-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--colors-hover);
|
||||
}
|
||||
`;
|
||||
|
||||
export default {
|
||||
PanTool,
|
||||
};
|
Loading…
Reference in New Issue
Block a user