Merge branch 'master' into mtolmacs/feat/precise-hitboxes

This commit is contained in:
Márk Tolmács 2025-05-17 15:09:35 +02:00 committed by GitHub
commit 49613ad0c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 393 additions and 404 deletions

View File

@ -52,7 +52,7 @@
transform: none;
}
.excalidraw .panelColumn {
.excalidraw .selected-shape-actions {
text-align: left;
}

View File

@ -73,7 +73,7 @@ import type { Scene } from "@excalidraw/element";
import type { CaptureUpdateActionType } from "@excalidraw/element";
import { trackEvent } from "../analytics";
import { ButtonIconSelect } from "../components/ButtonIconSelect";
import { RadioSelection } from "../components/RadioSelection";
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
import { FontPicker } from "../components/FontPicker/FontPicker";
import { IconPicker } from "../components/IconPicker";
@ -418,7 +418,8 @@ export const actionChangeFillStyle = register({
return (
<fieldset>
<legend>{t("labels.fill")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
type="button"
options={[
{
@ -462,6 +463,7 @@ export const actionChangeFillStyle = register({
updateData(nextValue);
}}
/>
</div>
</fieldset>
);
},
@ -485,7 +487,8 @@ export const actionChangeStrokeWidth = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.strokeWidth")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="stroke-width"
options={[
{
@ -517,6 +520,7 @@ export const actionChangeStrokeWidth = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -540,7 +544,8 @@ export const actionChangeSloppiness = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.sloppiness")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="sloppiness"
options={[
{
@ -569,6 +574,7 @@ export const actionChangeSloppiness = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -591,7 +597,8 @@ export const actionChangeStrokeStyle = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.strokeStyle")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="strokeStyle"
options={[
{
@ -620,6 +627,7 @@ export const actionChangeStrokeStyle = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -658,7 +666,8 @@ export const actionChangeFontSize = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.fontSize")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="font-size"
options={[
{
@ -715,6 +724,7 @@ export const actionChangeFontSize = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -1186,7 +1196,8 @@ export const actionChangeTextAlign = register({
return (
<fieldset>
<legend>{t("labels.textAlign")}</legend>
<ButtonIconSelect<TextAlign | false>
<div className="buttonList">
<RadioSelection<TextAlign | false>
group="text-align"
options={[
{
@ -1232,6 +1243,7 @@ export const actionChangeTextAlign = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},
@ -1274,7 +1286,8 @@ export const actionChangeVerticalAlign = register({
PanelComponent: ({ elements, appState, updateData, app }) => {
return (
<fieldset>
<ButtonIconSelect<VerticalAlign | false>
<div className="buttonList">
<RadioSelection<VerticalAlign | false>
group="text-align"
options={[
{
@ -1322,6 +1335,7 @@ export const actionChangeVerticalAlign = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},
@ -1369,7 +1383,8 @@ export const actionChangeRoundness = register({
return (
<fieldset>
<legend>{t("labels.edges")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="edges"
options={[
{
@ -1387,7 +1402,11 @@ export const actionChangeRoundness = register({
elements,
app,
(element) =>
hasLegacyRoundness ? null : element.roundness ? "round" : "sharp",
hasLegacyRoundness
? null
: element.roundness
? "round"
: "sharp",
(element) =>
!isArrowElement(element) && element.hasOwnProperty("roundness"),
(hasSelection) =>
@ -1395,6 +1414,7 @@ export const actionChangeRoundness = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},
@ -1710,7 +1730,8 @@ export const actionChangeArrowType = register({
return (
<fieldset>
<legend>{t("labels.arrowtypes")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="arrowtypes"
options={[
{
@ -1752,6 +1773,7 @@ export const actionChangeArrowType = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},

View File

@ -154,7 +154,7 @@ export const SelectedShapeActions = ({
!isSingleElementBoundContainer && alignActionsPredicate(appState, app);
return (
<div className="panelColumn">
<div className="selected-shape-actions">
<div>
{canChangeStrokeColor(appState, targetElements) &&
renderAction("changeStrokeColor")}

View File

@ -1,30 +0,0 @@
import clsx from "clsx";
export const ButtonSelect = <T extends Object>({
options,
value,
onChange,
group,
}: {
options: { value: T; text: string }[];
value: T | null;
onChange: (value: T) => void;
group: string;
}) => (
<div className="buttonList">
{options.map((option) => (
<label
key={option.text}
className={clsx({ active: value === option.value })}
>
<input
type="radio"
name={group}
onChange={() => onChange(option.value)}
checked={value === option.value}
/>
{option.text}
</label>
))}
</div>
);

View File

@ -6,7 +6,7 @@ import { FONT_FAMILY } from "@excalidraw/common";
import type { FontFamilyValues } from "@excalidraw/element/types";
import { t } from "../../i18n";
import { ButtonIconSelect } from "../ButtonIconSelect";
import { RadioSelection } from "../RadioSelection";
import { ButtonSeparator } from "../ButtonSeparator";
import {
FontFamilyCodeIcon,
@ -82,12 +82,14 @@ export const FontPicker = React.memo(
return (
<div role="dialog" aria-modal="true" className="FontPicker__container">
<ButtonIconSelect<FontFamilyValues | false>
<div className="buttonList">
<RadioSelection<FontFamilyValues | false>
type="button"
options={defaultFonts}
value={selectedFontFamily}
onClick={onSelectCallback}
/>
</div>
<ButtonSeparator />
<Popover.Root open={isOpened} onOpenChange={onPopupChange}>
<FontPickerTrigger selectedFontFamily={selectedFontFamily} />

View File

@ -4,8 +4,7 @@ import { ButtonIcon } from "./ButtonIcon";
import type { JSX } from "react";
// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
export const ButtonIconSelect = <T extends Object>(
export const RadioSelection = <T extends Object>(
props: {
options: {
value: T;
@ -28,7 +27,7 @@ export const ButtonIconSelect = <T extends Object>(
}
),
) => (
<div className="buttonList">
<>
{props.options.map((option) =>
props.type === "button" ? (
<ButtonIcon
@ -56,5 +55,5 @@ export const ButtonIconSelect = <T extends Object>(
</label>
),
)}
</div>
</>
);

View File

@ -140,7 +140,7 @@ body.excalidraw-cursor-resize * {
justify-content: space-between;
}
.panelColumn {
.selected-shape-actions {
display: flex;
flex-direction: column;
row-gap: 0.75rem;
@ -245,10 +245,6 @@ body.excalidraw-cursor-resize * {
left: 0;
right: 0;
--bar-padding: calc(4 * var(--space-factor));
padding-top: #{"max(var(--bar-padding), var(--sat,0))"};
padding-right: var(--sar, 0);
padding-bottom: var(--sab, 0);
padding-left: var(--sal, 0);
z-index: 4;
display: flex;
align-items: flex-end;
@ -263,10 +259,6 @@ body.excalidraw-cursor-resize * {
display: flex;
flex-direction: column;
pointer-events: var(--ui-pointerEvents);
.panelColumn {
padding: 8px 8px 0 8px;
}
}
}
@ -302,6 +294,10 @@ body.excalidraw-cursor-resize * {
overflow-y: auto;
box-sizing: border-box;
margin-bottom: var(--bar-padding);
.selected-shape-actions {
padding: 8px 8px 0 8px;
}
}
.App-menu {