mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-23 17:30:44 +02:00
fix styling
This commit is contained in:
@@ -536,3 +536,10 @@ export enum UserIdleState {
|
||||
export const LINE_POLYGON_POINT_MERGE_DISTANCE = 20;
|
||||
|
||||
export const DOUBLE_TAP_POSITION_THRESHOLD = 35;
|
||||
|
||||
// glass background for mobile action buttons
|
||||
export const MOBILE_ACTION_BUTTON_BG = {
|
||||
background: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(20px)",
|
||||
WebkitBackdropFilter: "blur(20px)",
|
||||
} as const;
|
||||
|
@@ -1,4 +1,8 @@
|
||||
import { KEYS, updateActiveTool } from "@excalidraw/common";
|
||||
import {
|
||||
KEYS,
|
||||
MOBILE_ACTION_BUTTON_BG,
|
||||
updateActiveTool,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import { getNonDeletedElements } from "@excalidraw/element";
|
||||
import { fixBindingsAfterDeletion } from "@excalidraw/element";
|
||||
@@ -326,6 +330,11 @@ export const actionDeleteSelected = register({
|
||||
disabled={
|
||||
!isSomeElementSelected(getNonDeletedElements(elements), appState)
|
||||
}
|
||||
style={{
|
||||
...(appState.stylesPanelMode === "mobile"
|
||||
? MOBILE_ACTION_BUTTON_BG
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
DEFAULT_GRID_SIZE,
|
||||
KEYS,
|
||||
MOBILE_ACTION_BUTTON_BG,
|
||||
arrayToMap,
|
||||
getShortcutKey,
|
||||
} from "@excalidraw/common";
|
||||
@@ -118,6 +119,11 @@ export const actionDuplicateSelection = register({
|
||||
disabled={
|
||||
!isSomeElementSelected(getNonDeletedElements(elements), appState)
|
||||
}
|
||||
style={{
|
||||
...(appState.stylesPanelMode === "mobile"
|
||||
? MOBILE_ACTION_BUTTON_BG
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
@@ -1,4 +1,10 @@
|
||||
import { isWindows, KEYS, matchKey, arrayToMap } from "@excalidraw/common";
|
||||
import {
|
||||
isWindows,
|
||||
KEYS,
|
||||
matchKey,
|
||||
arrayToMap,
|
||||
MOBILE_ACTION_BUTTON_BG,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||
|
||||
@@ -67,7 +73,7 @@ export const createUndoAction: ActionCreator = (history) => ({
|
||||
),
|
||||
keyTest: (event) =>
|
||||
event[KEYS.CTRL_OR_CMD] && matchKey(event, KEYS.Z) && !event.shiftKey,
|
||||
PanelComponent: ({ updateData, data }) => {
|
||||
PanelComponent: ({ appState, updateData, data }) => {
|
||||
const { isUndoStackEmpty } = useEmitter<HistoryChangedEvent>(
|
||||
history.onHistoryChangedEmitter,
|
||||
new HistoryChangedEvent(
|
||||
@@ -85,6 +91,11 @@ export const createUndoAction: ActionCreator = (history) => ({
|
||||
size={data?.size || "medium"}
|
||||
disabled={isUndoStackEmpty}
|
||||
data-testid="button-undo"
|
||||
style={{
|
||||
...(appState.stylesPanelMode === "mobile"
|
||||
? MOBILE_ACTION_BUTTON_BG
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@@ -103,7 +114,7 @@ export const createRedoAction: ActionCreator = (history) => ({
|
||||
keyTest: (event) =>
|
||||
(event[KEYS.CTRL_OR_CMD] && event.shiftKey && matchKey(event, KEYS.Z)) ||
|
||||
(isWindows && event.ctrlKey && !event.shiftKey && matchKey(event, KEYS.Y)),
|
||||
PanelComponent: ({ updateData, data }) => {
|
||||
PanelComponent: ({ appState, updateData, data }) => {
|
||||
const { isRedoStackEmpty } = useEmitter(
|
||||
history.onHistoryChangedEmitter,
|
||||
new HistoryChangedEvent(
|
||||
@@ -121,6 +132,11 @@ export const createRedoAction: ActionCreator = (history) => ({
|
||||
size={data?.size || "medium"}
|
||||
disabled={isRedoStackEmpty}
|
||||
data-testid="button-redo"
|
||||
style={{
|
||||
...(appState.stylesPanelMode === "mobile"
|
||||
? MOBILE_ACTION_BUTTON_BG
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
@@ -106,6 +106,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 2.5rem;
|
||||
pointer-events: auto;
|
||||
|
||||
--default-button-size: 2rem;
|
||||
|
||||
@@ -114,7 +115,6 @@
|
||||
height: 1.625rem;
|
||||
border: none;
|
||||
border-radius: var(--border-radius-lg);
|
||||
background: transparent;
|
||||
color: var(--color-on-surface);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -122,21 +122,17 @@
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
|
||||
svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--button-hover-bg, var(--island-bg-color));
|
||||
border-color: var(
|
||||
--button-hover-border,
|
||||
var(--button-border, var(--default-border-color))
|
||||
);
|
||||
}
|
||||
|
||||
&:active {
|
||||
&.active {
|
||||
background: var(--button-active-bg, var(--island-bg-color));
|
||||
border-color: var(--button-active-border, var(--color-primary-darkest));
|
||||
}
|
||||
@@ -168,9 +164,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ToolIcon {
|
||||
.ToolIcon__icon {
|
||||
width: 1.625rem;
|
||||
height: 1.625rem;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -328,7 +328,7 @@ const CombinedShapeProperties = ({
|
||||
hasBackground(element.type) && !isTransparent(element.backgroundColor),
|
||||
);
|
||||
|
||||
const showShowCombinedProperties =
|
||||
const shouldShowCombinedProperties =
|
||||
showFillIcons ||
|
||||
hasStrokeWidth(appState.activeTool.type) ||
|
||||
targetElements.some((element) => hasStrokeWidth(element.type)) ||
|
||||
@@ -337,14 +337,16 @@ const CombinedShapeProperties = ({
|
||||
canChangeRoundness(appState.activeTool.type) ||
|
||||
targetElements.some((element) => canChangeRoundness(element.type));
|
||||
|
||||
if (!showShowCombinedProperties) {
|
||||
const isOpen = appState.openPopup === "compactStrokeStyles";
|
||||
|
||||
if (!shouldShowCombinedProperties) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="compact-action-item">
|
||||
<Popover.Root
|
||||
open={appState.openPopup === "compactStrokeStyles"}
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (open) {
|
||||
setAppState({ openPopup: "compactStrokeStyles" });
|
||||
@@ -356,24 +358,23 @@ const CombinedShapeProperties = ({
|
||||
<Popover.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="compact-action-button properties-trigger"
|
||||
className={clsx("compact-action-button properties-trigger", {
|
||||
active: isOpen,
|
||||
})}
|
||||
title={t("labels.stroke")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
setAppState({
|
||||
openPopup:
|
||||
appState.openPopup === "compactStrokeStyles"
|
||||
? null
|
||||
: "compactStrokeStyles",
|
||||
openPopup: isOpen ? null : "compactStrokeStyles",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{adjustmentsIcon}
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
{appState.openPopup === "compactStrokeStyles" && (
|
||||
{isOpen && (
|
||||
<PropertiesPopover
|
||||
className={PROPERTIES_CLASSES}
|
||||
container={container}
|
||||
@@ -428,6 +429,7 @@ const CombinedArrowProperties = ({
|
||||
const showShowArrowProperties =
|
||||
toolIsArrow(appState.activeTool.type) ||
|
||||
targetElements.some((element) => toolIsArrow(element.type));
|
||||
const isOpen = appState.openPopup === "compactArrowProperties";
|
||||
|
||||
if (!showShowArrowProperties) {
|
||||
return null;
|
||||
@@ -436,7 +438,7 @@ const CombinedArrowProperties = ({
|
||||
return (
|
||||
<div className="compact-action-item">
|
||||
<Popover.Root
|
||||
open={appState.openPopup === "compactArrowProperties"}
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (open) {
|
||||
setAppState({ openPopup: "compactArrowProperties" });
|
||||
@@ -448,17 +450,16 @@ const CombinedArrowProperties = ({
|
||||
<Popover.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="compact-action-button properties-trigger"
|
||||
className={clsx("compact-action-button properties-trigger", {
|
||||
active: isOpen,
|
||||
})}
|
||||
title={t("labels.arrowtypes")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
setAppState({
|
||||
openPopup:
|
||||
appState.openPopup === "compactArrowProperties"
|
||||
? null
|
||||
: "compactArrowProperties",
|
||||
openPopup: isOpen ? null : "compactArrowProperties",
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -492,7 +493,7 @@ const CombinedArrowProperties = ({
|
||||
})()}
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
{appState.openPopup === "compactArrowProperties" && (
|
||||
{isOpen && (
|
||||
<PropertiesPopover
|
||||
container={container}
|
||||
className="properties-content"
|
||||
@@ -523,11 +524,12 @@ const CombinedTextProperties = ({
|
||||
elementsMap: NonDeletedElementsMap | NonDeletedSceneElementsMap;
|
||||
}) => {
|
||||
const { saveCaretPosition, restoreCaretPosition } = useTextEditorFocus();
|
||||
const isOpen = appState.openPopup === "compactTextProperties";
|
||||
|
||||
return (
|
||||
<div className="compact-action-item">
|
||||
<Popover.Root
|
||||
open={appState.openPopup === "compactTextProperties"}
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (open) {
|
||||
if (appState.editingTextElement) {
|
||||
@@ -545,13 +547,15 @@ const CombinedTextProperties = ({
|
||||
<Popover.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="compact-action-button properties-trigger"
|
||||
className={clsx("compact-action-button properties-trigger", {
|
||||
active: isOpen,
|
||||
})}
|
||||
title={t("labels.textAlign")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (appState.openPopup === "compactTextProperties") {
|
||||
if (isOpen) {
|
||||
setAppState({ openPopup: null });
|
||||
} else {
|
||||
if (appState.editingTextElement) {
|
||||
@@ -629,6 +633,7 @@ const CombinedExtraActions = ({
|
||||
}
|
||||
|
||||
const isRTL = document.documentElement.getAttribute("dir") === "rtl";
|
||||
const isOpen = appState.openPopup === "compactOtherProperties";
|
||||
|
||||
if (isEditingTextOrNewElement || targetElements.length === 0) {
|
||||
return null;
|
||||
@@ -637,7 +642,7 @@ const CombinedExtraActions = ({
|
||||
return (
|
||||
<div className="compact-action-item">
|
||||
<Popover.Root
|
||||
open={appState.openPopup === "compactOtherProperties"}
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (open) {
|
||||
setAppState({ openPopup: "compactOtherProperties" });
|
||||
@@ -649,23 +654,22 @@ const CombinedExtraActions = ({
|
||||
<Popover.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="compact-action-button properties-trigger"
|
||||
className={clsx("compact-action-button properties-trigger", {
|
||||
active: isOpen,
|
||||
})}
|
||||
title={t("labels.actions")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setAppState({
|
||||
openPopup:
|
||||
appState.openPopup === "compactOtherProperties"
|
||||
? null
|
||||
: "compactOtherProperties",
|
||||
openPopup: isOpen ? null : "compactOtherProperties",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{DotsHorizontalIcon}
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
{appState.openPopup === "compactOtherProperties" && (
|
||||
{isOpen && (
|
||||
<PropertiesPopover
|
||||
className={PROPERTIES_CLASSES}
|
||||
container={container}
|
||||
@@ -798,12 +802,7 @@ export const CompactShapeActions = ({
|
||||
<div className="compact-shape-actions">
|
||||
{/* Stroke Color */}
|
||||
{canChangeStrokeColor(appState, targetElements) && (
|
||||
<div
|
||||
className={clsx("compact-action-item")}
|
||||
style={{
|
||||
marginRight: 4,
|
||||
}}
|
||||
>
|
||||
<div className={clsx("compact-action-item")}>
|
||||
{renderAction("changeStrokeColor")}
|
||||
</div>
|
||||
)}
|
||||
@@ -925,6 +924,7 @@ export const MobileShapeActions = ({
|
||||
height: WIDTH * 1.75,
|
||||
alignItems: "center",
|
||||
gap: GAP,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
ref={mobileActionsRef}
|
||||
>
|
||||
|
@@ -7,6 +7,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker__title {
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.color-picker__heading {
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
|
@@ -18,7 +18,7 @@ import { useExcalidrawContainer } from "../App";
|
||||
import { ButtonSeparator } from "../ButtonSeparator";
|
||||
import { activeEyeDropperAtom } from "../EyeDropper";
|
||||
import { PropertiesPopover } from "../PropertiesPopover";
|
||||
import { backgroundIcon, slashIcon, strokeIcon } from "../icons";
|
||||
import { slashIcon, strokeIcon } from "../icons";
|
||||
import {
|
||||
saveCaretPosition,
|
||||
restoreCaretPosition,
|
||||
@@ -213,6 +213,10 @@ const ColorPickerPopupContent = ({
|
||||
type={type}
|
||||
elements={elements}
|
||||
updateData={updateData}
|
||||
showTitle={
|
||||
appState.stylesPanelMode === "compact" ||
|
||||
appState.stylesPanelMode === "mobile"
|
||||
}
|
||||
>
|
||||
{colorInputJSX}
|
||||
</Picker>
|
||||
@@ -272,20 +276,8 @@ const ColorPickerTrigger = ({
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="color-picker__button-outline">{!color && slashIcon}</div>
|
||||
{compactMode && color && (
|
||||
{compactMode && color && mode === "stroke" && (
|
||||
<div className="color-picker__button-background">
|
||||
{mode === "background" ? (
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
color && isColorDark(color, COLOR_OUTLINE_CONTRAST_THRESHOLD)
|
||||
? "#fff"
|
||||
: "#111",
|
||||
}}
|
||||
>
|
||||
{backgroundIcon}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
@@ -296,7 +288,6 @@ const ColorPickerTrigger = ({
|
||||
>
|
||||
{strokeIcon}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Popover.Trigger>
|
||||
|
@@ -37,6 +37,7 @@ interface PickerProps {
|
||||
palette: ColorPaletteCustom;
|
||||
updateData: (formData?: any) => void;
|
||||
children?: React.ReactNode;
|
||||
showTitle?: boolean;
|
||||
onEyeDropperToggle: (force?: boolean) => void;
|
||||
onEscape: (event: React.KeyboardEvent | KeyboardEvent) => void;
|
||||
}
|
||||
@@ -51,11 +52,20 @@ export const Picker = React.forwardRef(
|
||||
palette,
|
||||
updateData,
|
||||
children,
|
||||
showTitle,
|
||||
onEyeDropperToggle,
|
||||
onEscape,
|
||||
}: PickerProps,
|
||||
ref,
|
||||
) => {
|
||||
const title = showTitle
|
||||
? type === "elementStroke"
|
||||
? t("labels.stroke")
|
||||
: type === "elementBackground"
|
||||
? t("labels.background")
|
||||
: null
|
||||
: null;
|
||||
|
||||
const [customColors] = React.useState(() => {
|
||||
if (type === "canvasBackground") {
|
||||
return [];
|
||||
@@ -154,6 +164,8 @@ export const Picker = React.forwardRef(
|
||||
// to allow focusing by clicking but not by tabbing
|
||||
tabIndex={-1}
|
||||
>
|
||||
{title && <div className="color-picker__title">{title}</div>}
|
||||
|
||||
{!!customColors.length && (
|
||||
<div>
|
||||
<PickerHeading>
|
||||
|
@@ -21,6 +21,16 @@ export const FontPickerTrigger = ({
|
||||
}: FontPickerTriggerProps) => {
|
||||
const setAppState = useExcalidrawSetAppState();
|
||||
|
||||
const compactStyle = compactMode
|
||||
? {
|
||||
background: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(20px)",
|
||||
WebkitBackdropFilter: "blur(20px)",
|
||||
width: "1.625rem",
|
||||
height: "1.625rem",
|
||||
}
|
||||
: {};
|
||||
|
||||
return (
|
||||
<Popover.Trigger asChild>
|
||||
<div data-openpopup="fontFamily" className="properties-trigger">
|
||||
@@ -39,8 +49,7 @@ export const FontPickerTrigger = ({
|
||||
}}
|
||||
style={{
|
||||
border: "none",
|
||||
width: compactMode ? "1.625rem" : undefined,
|
||||
height: compactMode ? "1.625rem" : undefined,
|
||||
...compactStyle,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@@ -18,7 +18,7 @@ type LockIconProps = {
|
||||
export const HandButton = (props: LockIconProps) => {
|
||||
return (
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx("Shape", { fillable: false, active: props.checked })}
|
||||
type="radio"
|
||||
icon={handIcon}
|
||||
name="editor-current-shape"
|
||||
|
@@ -92,17 +92,8 @@ export const MobileMenu = ({
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<MainMenuTunnel.Out />
|
||||
</div>
|
||||
{topRightUI ? topRightUI : <DefaultSidebarTriggerTunnel.Out />}
|
||||
</div>
|
||||
);
|
||||
|
@@ -39,6 +39,15 @@
|
||||
.ToolIcon__icon {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--button-active-bg, var(--island-bg-color));
|
||||
border-color: var(--button-active-border, var(--color-primary-darkest));
|
||||
}
|
||||
|
||||
svg {
|
||||
|
@@ -190,7 +190,6 @@ export const MobileToolBar = ({
|
||||
options={SELECTION_TOOLS}
|
||||
activeTool={activeTool}
|
||||
defaultOption={app.defaultSelectionTool}
|
||||
className="Selection"
|
||||
namePrefix="selectionType"
|
||||
title={capitalizeString(t("toolBar.selection"))}
|
||||
data-testid="toolbar-selection"
|
||||
@@ -210,7 +209,9 @@ export const MobileToolBar = ({
|
||||
|
||||
{/* Free Draw */}
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx({
|
||||
active: activeTool.type === "freedraw",
|
||||
})}
|
||||
type="radio"
|
||||
icon={FreedrawIcon}
|
||||
checked={activeTool.type === "freedraw"}
|
||||
@@ -223,7 +224,9 @@ export const MobileToolBar = ({
|
||||
|
||||
{/* Eraser */}
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx({
|
||||
active: activeTool.type === "eraser",
|
||||
})}
|
||||
type="radio"
|
||||
icon={EraserIcon}
|
||||
checked={activeTool.type === "eraser"}
|
||||
@@ -296,7 +299,9 @@ export const MobileToolBar = ({
|
||||
|
||||
{/* Image */}
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx({
|
||||
active: activeTool.type === "image",
|
||||
})}
|
||||
type="radio"
|
||||
icon={ImageIcon}
|
||||
checked={activeTool.type === "image"}
|
||||
@@ -310,7 +315,9 @@ export const MobileToolBar = ({
|
||||
{/* Text Tool */}
|
||||
{showTextToolOutside && (
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx({
|
||||
active: activeTool.type === "text",
|
||||
})}
|
||||
type="radio"
|
||||
icon={TextIcon}
|
||||
checked={activeTool.type === "text"}
|
||||
@@ -325,7 +332,7 @@ export const MobileToolBar = ({
|
||||
{/* Frame Tool */}
|
||||
{showFrameToolOutside && (
|
||||
<ToolButton
|
||||
className={clsx("Shape", { fillable: false })}
|
||||
className={clsx({ active: frameToolSelected })}
|
||||
type="radio"
|
||||
icon={frameToolIcon}
|
||||
checked={frameToolSelected}
|
||||
|
@@ -48,11 +48,12 @@ export const ToolTypePopup = ({
|
||||
|
||||
const updatePosition = () => {
|
||||
const triggerRect = triggerElement.getBoundingClientRect();
|
||||
|
||||
const panelRect = panelRef.current?.getBoundingClientRect();
|
||||
const panelWidth = panelRect?.width ?? 0;
|
||||
const panelHeight = panelRect?.height ?? 0;
|
||||
setPanelPosition({
|
||||
x: triggerRect.x - panelWidth / 2,
|
||||
x: triggerRect.left - panelWidth / 2,
|
||||
y: panelHeight + 8,
|
||||
});
|
||||
};
|
||||
@@ -92,9 +93,9 @@ export const ToolTypePopup = ({
|
||||
tabIndex={-1}
|
||||
style={{
|
||||
position: "fixed",
|
||||
bottom: `${panelPosition.y}px`,
|
||||
top: `${-10}px`,
|
||||
left: `${panelPosition.x}px`,
|
||||
zIndex: 2,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
className={CLASSES.CONVERT_ELEMENT_TYPE_POPUP}
|
||||
>
|
||||
@@ -161,7 +162,13 @@ export const ToolWithPopup = ({
|
||||
<div style={{ position: "relative" }}>
|
||||
<div ref={setTriggerRef}>
|
||||
<ToolButton
|
||||
className={clsx(className, { fillable })}
|
||||
className={clsx(className, {
|
||||
fillable,
|
||||
active:
|
||||
isActive ||
|
||||
isPopupOpen ||
|
||||
options.some((o) => o.type === activeTool.type),
|
||||
})}
|
||||
type="radio"
|
||||
icon={displayedOption.icon}
|
||||
checked={isActive}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
.excalidraw {
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
top: 2.5rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
&--placement-top {
|
||||
@@ -14,32 +14,35 @@
|
||||
}
|
||||
|
||||
&--mobile {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
row-gap: 0.75rem;
|
||||
|
||||
// When main menu is in the top toolbar, position relative to trigger
|
||||
&.main-menu-dropdown {
|
||||
position: fixed;
|
||||
left: 1rem;
|
||||
top: 3.5rem;
|
||||
min-width: 280px;
|
||||
max-width: calc(100vw - 2rem);
|
||||
min-width: 232px;
|
||||
max-width: calc(100vw - var(--editor-container-padding) * 2);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
z-index: var(--zIndex-layerUI);
|
||||
|
||||
@media screen and (orientation: landscape) {
|
||||
max-width: 232px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu-container {
|
||||
padding: 8px 8px;
|
||||
box-sizing: border-box;
|
||||
// background-color: var(--island-bg-color);
|
||||
max-height: calc(
|
||||
100svh - var(--editor-container-padding) * 2 - 2.25rem
|
||||
);
|
||||
box-shadow: var(--shadow-island);
|
||||
border-radius: var(--border-radius-lg);
|
||||
position: relative;
|
||||
transition: box-shadow 0.5s ease-in-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
|
||||
&.zen-mode {
|
||||
box-shadow: none;
|
||||
@@ -49,7 +52,7 @@
|
||||
|
||||
.dropdown-menu-container {
|
||||
background-color: var(--island-bg-color);
|
||||
max-height: calc(100vh - 150px);
|
||||
|
||||
overflow-y: auto;
|
||||
--gap: 2;
|
||||
}
|
||||
|
@@ -246,7 +246,7 @@ body.excalidraw-cursor-resize * {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
--bar-padding: calc(4 * var(--space-factor));
|
||||
z-index: 4;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
Reference in New Issue
Block a user