feat: new mobile layout (#9996)
* compact bottom toolbar * put menu trigger to top left * add popup to switch between grouped tool types * add a dedicated mobile toolbar * update position for mobile * fix active tool type * add mobile mode as well * mobile actions * remove refactored popups * excali logo mobile * include mobile * update mobile menu layout * move selection and deletion back to right * do not fill eraser * fix styling * fix active styling * bigger buttons, smaller gaps * fix other tools not opened * fix: Style panel persistence and restore Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * move hidden action btns to extra popover * fix dropdown overlapping with welcome screen * replace custom popup with popover * improve button styles * swapping redo and delete * always show undo & redo and improve styling * change background * toolbar styles * no any * persist perferred selection tool and align tablet as well * add a renderTopLeftUI to props * tweak border and bg * show combined properties only when using suitable tools * fix preferred tool * new stroke icon * hide color picker hot keys * init preferred tool based on device * fix main menu sizing * fix welcome screen offset * put text before image * disable call highlight on buttons * fix renderTopLeftUI --------- Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Co-authored-by: Mark Tolmacs <mark@lazycat.hu> Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -666,14 +666,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
>();
|
||||
onRemoveEventListenersEmitter = new Emitter<[]>();
|
||||
|
||||
defaultSelectionTool: "selection" | "lasso" = "selection";
|
||||
|
||||
constructor(props: AppProps) {
|
||||
super(props);
|
||||
const defaultAppState = getDefaultAppState();
|
||||
this.defaultSelectionTool = isMobileOrTablet()
|
||||
? ("lasso" as const)
|
||||
: ("selection" as const);
|
||||
const {
|
||||
excalidrawAPI,
|
||||
viewModeEnabled = false,
|
||||
@@ -1527,7 +1522,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
public render() {
|
||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||
const { renderTopRightUI, renderCustomStats } = this.props;
|
||||
const { renderTopRightUI, renderTopLeftUI, renderCustomStats } = this.props;
|
||||
|
||||
const sceneNonce = this.scene.getSceneNonce();
|
||||
const { elementsMap, visibleElements } =
|
||||
@@ -1613,6 +1608,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
onPenModeToggle={this.togglePenMode}
|
||||
onHandToolToggle={this.onHandToolToggle}
|
||||
langCode={getLanguage().code}
|
||||
renderTopLeftUI={renderTopLeftUI}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderCustomStats={renderCustomStats}
|
||||
showExitZenModeBtn={
|
||||
@@ -1625,7 +1621,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
!this.state.isLoading &&
|
||||
this.state.showWelcomeScreen &&
|
||||
this.state.activeTool.type ===
|
||||
this.defaultSelectionTool &&
|
||||
this.state.preferredSelectionTool.type &&
|
||||
!this.state.zenModeEnabled &&
|
||||
!this.scene.getElementsIncludingDeleted().length
|
||||
}
|
||||
@@ -2370,6 +2366,14 @@ class App extends React.Component<AppProps, AppState> {
|
||||
deleteInvisibleElements: true,
|
||||
});
|
||||
const activeTool = scene.appState.activeTool;
|
||||
|
||||
if (!scene.appState.preferredSelectionTool.initialized) {
|
||||
scene.appState.preferredSelectionTool = {
|
||||
type: this.device.editor.isMobile ? "lasso" : "selection",
|
||||
initialized: true,
|
||||
};
|
||||
}
|
||||
|
||||
scene.appState = {
|
||||
...scene.appState,
|
||||
theme: this.props.theme || scene.appState.theme,
|
||||
@@ -2384,12 +2388,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
activeTool.type === "selection"
|
||||
? {
|
||||
...activeTool,
|
||||
type: this.defaultSelectionTool,
|
||||
type: scene.appState.preferredSelectionTool.type,
|
||||
}
|
||||
: scene.appState.activeTool,
|
||||
isLoading: false,
|
||||
toast: this.state.toast,
|
||||
};
|
||||
|
||||
if (initialData?.scrollToContent) {
|
||||
scene.appState = {
|
||||
...scene.appState,
|
||||
@@ -2490,6 +2495,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
// but not too narrow (> MQ_MAX_WIDTH_MOBILE)
|
||||
this.isTabletBreakpoint(editorWidth, editorHeight) && isMobileOrTablet()
|
||||
? "compact"
|
||||
: this.isMobileBreakpoint(editorWidth, editorHeight)
|
||||
? "mobile"
|
||||
: "full",
|
||||
});
|
||||
|
||||
@@ -3289,7 +3296,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
await this.insertClipboardContent(data, filesList, isPlainPaste);
|
||||
|
||||
this.setActiveTool({ type: this.defaultSelectionTool }, true);
|
||||
this.setActiveTool(
|
||||
{ type: this.state.preferredSelectionTool.type },
|
||||
true,
|
||||
);
|
||||
event?.preventDefault();
|
||||
},
|
||||
);
|
||||
@@ -3435,7 +3445,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
},
|
||||
);
|
||||
this.setActiveTool({ type: this.defaultSelectionTool }, true);
|
||||
this.setActiveTool({ type: this.state.preferredSelectionTool.type }, true);
|
||||
|
||||
if (opts.fitToContent) {
|
||||
this.scrollToContent(duplicatedElements, {
|
||||
@@ -3647,7 +3657,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
...updateActiveTool(
|
||||
this.state,
|
||||
prevState.activeTool.locked
|
||||
? { type: this.defaultSelectionTool }
|
||||
? { type: this.state.preferredSelectionTool.type }
|
||||
: prevState.activeTool,
|
||||
),
|
||||
locked: !prevState.activeTool.locked,
|
||||
@@ -3989,7 +3999,12 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
|
||||
if (appState) {
|
||||
this.setState(appState);
|
||||
this.setState({
|
||||
...appState,
|
||||
// keep existing stylesPanelMode as it needs to be preserved
|
||||
// or set at startup
|
||||
stylesPanelMode: this.state.stylesPanelMode,
|
||||
} as Pick<AppState, K> | null);
|
||||
}
|
||||
|
||||
if (elements) {
|
||||
@@ -4653,7 +4668,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
if (event.key === KEYS.K && !event.altKey && !event[KEYS.CTRL_OR_CMD]) {
|
||||
if (this.state.activeTool.type === "laser") {
|
||||
this.setActiveTool({ type: this.defaultSelectionTool });
|
||||
this.setActiveTool({ type: this.state.preferredSelectionTool.type });
|
||||
} else {
|
||||
this.setActiveTool({ type: "laser" });
|
||||
}
|
||||
@@ -5498,7 +5513,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return;
|
||||
}
|
||||
// we should only be able to double click when mode is selection
|
||||
if (this.state.activeTool.type !== this.defaultSelectionTool) {
|
||||
if (this.state.activeTool.type !== this.state.preferredSelectionTool.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6491,6 +6506,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setAppState({ snapLines: [] });
|
||||
}
|
||||
|
||||
if (this.state.openPopup) {
|
||||
this.setState({ openPopup: null });
|
||||
}
|
||||
|
||||
this.updateGestureOnPointerDown(event);
|
||||
|
||||
// if dragging element is freedraw and another pointerdown event occurs
|
||||
@@ -7695,7 +7714,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
if (!this.state.activeTool.locked) {
|
||||
this.setState({
|
||||
activeTool: updateActiveTool(this.state, {
|
||||
type: this.defaultSelectionTool,
|
||||
type: this.state.preferredSelectionTool.type,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -9409,7 +9428,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.setState((prevState) => ({
|
||||
newElement: null,
|
||||
activeTool: updateActiveTool(this.state, {
|
||||
type: this.defaultSelectionTool,
|
||||
type: this.state.preferredSelectionTool.type,
|
||||
}),
|
||||
selectedElementIds: makeNextSelectedElementIds(
|
||||
{
|
||||
@@ -10026,7 +10045,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
newElement: null,
|
||||
suggestedBindings: [],
|
||||
activeTool: updateActiveTool(this.state, {
|
||||
type: this.defaultSelectionTool,
|
||||
type: this.state.preferredSelectionTool.type,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
@@ -10256,7 +10275,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
{
|
||||
newElement: null,
|
||||
activeTool: updateActiveTool(this.state, {
|
||||
type: this.defaultSelectionTool,
|
||||
type: this.state.preferredSelectionTool.type,
|
||||
}),
|
||||
},
|
||||
() => {
|
||||
@@ -10720,7 +10739,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
event.nativeEvent.pointerType === "pen" &&
|
||||
// always allow if user uses a pen secondary button
|
||||
event.button !== POINTER_BUTTON.SECONDARY)) &&
|
||||
this.state.activeTool.type !== this.defaultSelectionTool
|
||||
this.state.activeTool.type !== this.state.preferredSelectionTool.type
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user