More mobile tweaks (#790)

* Disable text selection

* Set content-editable=plaintext-only to disable Touch Bar formatting buttons

* Enlarge resize handle tap targets for pen/touch

* Make the lock button a button in mobile mode

* Use icons instead of Unicode characters; add an alternate toolbar for creating multipoint lines

* Allow buttons to hide themselves

* Fix heuristic for showing shape actions

* Refactor icons

* Fix label for edit button

* Switch edit button icon

* Remove lock button on mobile

* Add language selector on mobile

* Fix showing edit button on mobile

* Fix showing edit button on mobile, part 2

* Fix handle touch regions

* Fix scroll-back button position

* Allow using the text tool on a text object to start editing it

* Fix deletion of last point in line
This commit is contained in:
Jed Fox 2020-02-21 14:34:18 -05:00 committed by GitHub
parent 949c3841ea
commit 0fd3fb4b5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 272 additions and 222 deletions

View file

@ -109,6 +109,7 @@ import useIsMobile, { IsMobileProvider } from "./is-mobile";
import { copyToAppClipboard, getClipboardContent } from "./clipboard";
import { normalizeScroll } from "./scene/data";
import { getCenter, getDistance } from "./gesture";
import { menu, palette } from "./components/icons";
let { elements } = createScene();
const { history } = createHistory();
@ -286,9 +287,11 @@ const LayerUI = React.memo(
);
}
const showSelectedShapeActions =
(appState.editingElement || getSelectedElements(elements).length) &&
appState.elementType === "selection";
const showSelectedShapeActions = Boolean(
appState.editingElement ||
getSelectedElements(elements).length ||
appState.elementType !== "selection",
);
function renderSelectedShapeActions() {
const { elementType, editingElement } = appState;
@ -386,21 +389,6 @@ const LayerUI = React.memo(
);
}
const lockButton = (
<LockIcon
checked={appState.elementLocked}
onChange={() => {
setAppState({
elementLocked: !appState.elementLocked,
elementType: appState.elementLocked
? "selection"
: appState.elementType,
});
}}
title={t("toolBar.lock")}
/>
);
return isMobile ? (
<>
{appState.openedMenu === "canvas" ? (
@ -411,13 +399,24 @@ const LayerUI = React.memo(
<h2 className="visually-hidden" id="canvas-actions-title">
{t("headings.canvasActions")}
</h2>
<div className="App-mobile-menu-scroller">
<div className="App-mobile-menu-scroller panelColumn">
<Stack.Col gap={4}>
{actionManager.renderAction("loadScene")}
{actionManager.renderAction("saveScene")}
{renderExportDialog()}
{actionManager.renderAction("clearCanvas")}
{actionManager.renderAction("changeViewBackgroundColor")}
<fieldset>
<legend>{t("labels.language")}</legend>
<LanguageList
onChange={lng => {
setLanguage(lng);
setAppState({});
}}
languages={languages}
currentLanguage={language}
/>
</fieldset>
</Stack.Col>
</div>
</section>
@ -456,61 +455,57 @@ const LayerUI = React.memo(
</FixedSideContainer>
<footer className="App-toolbar">
<div className="App-toolbar-content">
<ToolButton
type="button"
icon={
<span style={{ fontSize: "2em", marginTop: "-0.15em" }}></span>
}
aria-label={t("buttons.menu")}
onClick={() =>
setAppState(({ openedMenu }: any) => ({
openedMenu: openedMenu === "canvas" ? null : "canvas",
}))
}
/>
<div
style={{
visibility: isSomeElementSelected(elements)
? "visible"
: "hidden",
}}
>
{" "}
{actionManager.renderAction("deleteSelectedElements")}
</div>
{lockButton}
{actionManager.renderAction("finalize")}
<div
style={{
visibility: isSomeElementSelected(elements)
? "visible"
: "hidden",
}}
>
<ToolButton
type="button"
icon={
<span style={{ fontSize: "2em", marginTop: "-0.15em" }}>
</span>
}
aria-label={t("buttons.menu")}
onClick={() =>
setAppState(({ openedMenu }: any) => ({
openedMenu: openedMenu === "shape" ? null : "shape",
}))
}
/>
</div>
{appState.scrolledOutside && (
<button
className="scroll-back-to-content"
onClick={() => {
setAppState({ ...calculateScrollCenter(elements) });
}}
>
{t("buttons.scrollBackToContent")}
</button>
{appState.multiElement ? (
<>
{actionManager.renderAction("deleteSelectedElements")}
<ToolButton
visible={showSelectedShapeActions}
type="button"
icon={palette}
aria-label={t("buttons.edit")}
onClick={() =>
setAppState(({ openedMenu }: any) => ({
openedMenu: openedMenu === "shape" ? null : "shape",
}))
}
/>
{actionManager.renderAction("finalize")}
</>
) : (
<>
<ToolButton
type="button"
icon={menu}
aria-label={t("buttons.menu")}
onClick={() =>
setAppState(({ openedMenu }: any) => ({
openedMenu: openedMenu === "canvas" ? null : "canvas",
}))
}
/>
<ToolButton
visible={showSelectedShapeActions}
type="button"
icon={palette}
aria-label={t("buttons.edit")}
onClick={() =>
setAppState(({ openedMenu }: any) => ({
openedMenu: openedMenu === "shape" ? null : "shape",
}))
}
/>
{actionManager.renderAction("deleteSelectedElements")}
{appState.scrolledOutside && (
<button
className="scroll-back-to-content"
onClick={() => {
setAppState({ ...calculateScrollCenter(elements) });
}}
>
{t("buttons.scrollBackToContent")}
</button>
)}
</>
)}
</div>
</footer>
@ -545,7 +540,7 @@ const LayerUI = React.memo(
</Stack.Col>
</Island>
</section>
{showSelectedShapeActions ? (
{showSelectedShapeActions && (
<section
className="App-right-menu"
aria-labelledby="selected-shape-title"
@ -555,7 +550,7 @@ const LayerUI = React.memo(
</h2>
<Island padding={4}>{renderSelectedShapeActions()}</Island>
</section>
) : null}
)}
</Stack.Col>
<section aria-labelledby="shapes-title">
<Stack.Col gap={4} align="start">
@ -566,7 +561,19 @@ const LayerUI = React.memo(
</h2>
<Stack.Row gap={1}>{renderShapesSwitcher()}</Stack.Row>
</Island>
{lockButton}
<LockIcon
checked={appState.elementLocked}
onChange={() => {
setAppState({
elementLocked: !appState.elementLocked,
elementType: appState.elementLocked
? "selection"
: appState.elementType,
});
}}
title={t("toolBar.lock")}
isButton={isMobile}
/>
</Stack.Row>
</Stack.Col>
</section>
@ -591,6 +598,7 @@ const LayerUI = React.memo(
}}
languages={languages}
currentLanguage={language}
floating
/>
{appState.scrolledOutside && (
<button
@ -1085,6 +1093,8 @@ export class App extends React.Component<any, AppState> {
return;
}
this.setState({ lastPointerDownWith: e.pointerType });
// pan canvas on wheel button drag or space+drag
if (
gesture.pointers.length === 0 &&
@ -1213,6 +1223,7 @@ export class App extends React.Component<any, AppState> {
elements,
{ x, y },
this.state.zoom,
e.pointerType,
);
const selectedElements = getSelectedElements(elements);
@ -1279,6 +1290,9 @@ export class App extends React.Component<any, AppState> {
if (this.state.editingElement?.type === "text") {
return;
}
if (elementIsAddedToSelection) {
element = hitElement!;
}
let textX = e.clientX;
let textY = e.clientY;
if (!e.altKey) {
@ -2152,6 +2166,7 @@ export class App extends React.Component<any, AppState> {
elements,
{ x, y },
this.state.zoom,
e.pointerType,
);
if (resizeElement && resizeElement.resizeHandle) {
document.documentElement.style.cursor = getCursorForResizingElement(