feat: Change spacing alt-click behavior to reset only one value (#4540)

## Description

- When using alt modifier, on a spacing value, currently you can't reset
one value only, you would reset the opposite value too.
- When alt-click happens outside of label-button, no reset should happen
- when using input in spacing, hodling alt/shift and then pressing enter
allows to set opposite and all sides

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
This commit is contained in:
Oleg Isonen authored and GitHub committed 2024-12-10 01:03:30 +01:00
1 parent 7f09077b7d
commit a3d9ac449f
7 files changed
+74 -53

No files matched your search

@@ -9,12 +9,12 @@ import { InputPopover } from "../shared/input-popover";
import { InsetLayout, type InsetProperty } from "./inset-layout";
import { InsetTooltip } from "./inset-tooltip";
import { useComputedStyleDecl, useComputedStyles } from "../../shared/model";
import { useModifierKeys } from "../../shared/modifier-keys";
import { useModifierKeys, type Modifiers } from "../../shared/modifier-keys";
const Cell = ({
scrubStatus,
property,
activeProperties,
getActiveProperties,
onHover,
isPopoverOpen,
onPopoverClose,
@@ -23,7 +23,7 @@ const Cell = ({
onPopoverClose: () => void;
scrubStatus: ReturnType<typeof useScrub>;
property: InsetProperty;
activeProperties: InsetProperty[];
getActiveProperties: (modifiers?: Modifiers) => readonly InsetProperty[];
onHover: (target: HoverTarget | undefined) => void;
}) => {
const styleDecl = useComputedStyleDecl(property);
@@ -38,7 +38,7 @@ const Cell = ({
value={finalValue}
isOpen={isPopoverOpen}
property={property}
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
onClose={onPopoverClose}
/>
<InsetTooltip property={property} preventOpen={scrubStatus.isActive}>
@@ -116,6 +116,11 @@ export const InsetControl = () => {
const activeProperties = [
...(activePopoverProperties ?? scrubStatus.properties),
];
const getActiveProperties = (modifiers?: Modifiers) => {
return modifiers && openProperty
? getInsetModifiersGroup(openProperty, modifiers)
: activeProperties;
};
const handleHover = (target: HoverTarget | undefined) => {
setHoverTarget(target);
@@ -162,12 +167,12 @@ export const InsetControl = () => {
}}
>
<InsetLayout
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
renderCell={(property) => (
<Cell
scrubStatus={scrubStatus}
property={property}
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
onHover={handleHover}
isPopoverOpen={openProperty === property}
onPopoverClose={() => {
@@ -1,5 +1,4 @@
import type { Meta } from "@storybook/react";
import type * as React from "react";
import { InsetLayout } from "./inset-layout";
import { Grid, theme, Text } from "@webstudio-is/design-system";
@@ -7,13 +6,11 @@ const Cell = () => (
<Text variant={"spaceSectionValueText"}>auto{/*1.275&#8203;rem*/}</Text>
);
export const InsetLayoutComponent = (
args: Omit<React.ComponentProps<typeof InsetLayout>, "renderCell">
) => (
export const InsetLayoutComponent = () => (
<Grid css={{ width: theme.spacing[22], height: theme.spacing[18] }}>
<InsetLayout
renderCell={() => <Cell />}
activeProperties={args.activeProperties}
getActiveProperties={() => []}
onHover={(hoverProps) => {
console.info(hoverProps);
}}
@@ -24,11 +21,4 @@ export const InsetLayoutComponent = (
export default {
title: "Style Panel/Inset",
component: InsetLayoutComponent,
argTypes: {
activeProperties: {
options: ["left", "right", "top", "bottom"],
control: { type: "check" },
},
},
} as Meta<typeof InsetLayoutComponent>;
@@ -1,5 +1,6 @@
import { Grid, Box, theme, styled } from "@webstudio-is/design-system";
import type { MouseEvent } from "react";
import type { Modifiers } from "../../shared/modifier-keys";
const RECT_HEIGHT = 6;
const RECT_WIDTH = 42;
@@ -41,7 +42,7 @@ type InsetLayoutProps = {
onHover: (
args: { element: HTMLElement; property: InsetProperty } | undefined
) => void;
activeProperties: readonly InsetProperty[];
getActiveProperties: (modifiers?: Modifiers) => readonly InsetProperty[];
};
/**
* Grid schema for graphical layout
@@ -59,7 +60,7 @@ type InsetLayoutProps = {
export const InsetLayout = ({
renderCell,
onHover,
activeProperties,
getActiveProperties,
}: InsetLayoutProps) => {
const createHandleHover = (property: InsetProperty) => ({
onMouseEnter: (e: MouseEvent<HTMLDivElement>) => {
@@ -72,6 +73,7 @@ export const InsetLayout = ({
onHover(undefined);
},
});
const activeProperties = getActiveProperties();
return (
<Grid
@@ -15,6 +15,7 @@ import { createBatchUpdate } from "../../shared/use-style-data";
import { theme } from "@webstudio-is/design-system";
import type { StyleValueSourceColor } from "~/shared/style-object-model";
import { $availableUnitVariables } from "../../shared/model";
import type { Modifiers } from "../../shared/modifier-keys";
const slideUpAndFade = keyframes({
"0%": { opacity: 0, transform: "scale(0.8)" },
@@ -25,12 +26,12 @@ const Input = ({
styleSource,
value,
property,
activeProperties,
getActiveProperties,
onClosePopover,
}: {
styleSource: StyleValueSourceColor;
property: StyleProperty;
activeProperties: StyleProperty[];
getActiveProperties: (modifiers?: Modifiers) => readonly StyleProperty[];
value: StyleValue;
onClosePopover: () => void;
}) => {
@@ -47,6 +48,7 @@ const Input = ({
getOptions={() => $availableUnitVariables.get()}
onChange={(styleValue) => {
setIntermediateValue(styleValue);
const activeProperties = getActiveProperties();
if (styleValue === undefined) {
const batch = createBatchUpdate();
for (const property of activeProperties) {
@@ -66,6 +68,7 @@ const Input = ({
onHighlight={(styleValue) => {
if (styleValue === undefined) {
const batch = createBatchUpdate();
const activeProperties = getActiveProperties();
for (const property of activeProperties) {
batch.deleteProperty(property);
}
@@ -76,7 +79,14 @@ const Input = ({
batch.setProperty(property)(styleValue);
batch.publish({ isEphemeral: true });
}}
onChangeComplete={({ value }) => {
onChangeComplete={({ value, altKey, shiftKey }) => {
const activeProperties = getActiveProperties({
altKey,
shiftKey,
ctrlKey: false,
metaKey: false,
});
setIntermediateValue(undefined);
const batch = createBatchUpdate();
for (const property of activeProperties) {
@@ -93,6 +103,7 @@ const Input = ({
onReset={() => {
setIntermediateValue(undefined);
const batch = createBatchUpdate();
const activeProperties = getActiveProperties();
for (const property of activeProperties) {
batch.deleteProperty(property);
}
@@ -123,14 +134,14 @@ const PopoverContentStyled = styled(PopoverContent, {
export const InputPopover = ({
styleSource,
property,
activeProperties,
getActiveProperties,
value,
isOpen,
onClose,
}: {
styleSource: StyleValueSourceColor;
property: StyleProperty;
activeProperties: StyleProperty[];
getActiveProperties: (modifiers?: Modifiers) => readonly StyleProperty[];
value: StyleValue;
isOpen: boolean;
onClose: () => void;
@@ -157,7 +168,7 @@ export const InputPopover = ({
styleSource={styleSource}
value={value}
property={property}
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
onClosePopover={onClose}
/>
</PopoverContentStyled>
@@ -9,8 +9,8 @@ import { SpaceTooltip } from "./tooltip";
import { StyleSection } from "../../shared/style-section";
import { movementMapSpace, useKeyboardNavigation } from "../shared/keyboard";
import { useComputedStyleDecl, useComputedStyles } from "../../shared/model";
import { createBatchUpdate, deleteProperty } from "../../shared/use-style-data";
import { useModifierKeys } from "../../shared/modifier-keys";
import { createBatchUpdate } from "../../shared/use-style-data";
import { useModifierKeys, type Modifiers } from "../../shared/modifier-keys";
import { theme } from "@webstudio-is/design-system";
const Cell = ({
@@ -18,14 +18,14 @@ const Cell = ({
onPopoverClose,
onHover,
property,
activeProperties,
getActiveProperties,
scrubStatus,
}: {
isPopoverOpen: boolean;
onPopoverClose: () => void;
onHover: (target: HoverTarget | undefined) => void;
property: SpaceStyleProperty;
activeProperties: SpaceStyleProperty[];
getActiveProperties: (modifiers?: Modifiers) => readonly SpaceStyleProperty[];
scrubStatus: ReturnType<typeof useScrub>;
}) => {
const styleDecl = useComputedStyleDecl(property);
@@ -40,7 +40,7 @@ const Cell = ({
value={finalValue}
isOpen={isPopoverOpen}
property={property}
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
onClose={onPopoverClose}
/>
<SpaceTooltip property={property} preventOpen={scrubStatus.isActive}>
@@ -114,10 +114,16 @@ export const Section = () => {
// by deafult highlight hovered or scrubbed properties
// if keyboard navigation is active, highlight its active property
// if popover is open, highlight its property and hovered properties
const activeProperties = [
const activeProperties: readonly SpaceStyleProperty[] = [
...(activePopoverProperties ?? scrubStatus.properties),
];
const getActiveProperties = (modifiers?: Modifiers) => {
return modifiers && openProperty
? getSpaceModifiersGroup(openProperty, modifiers)
: activeProperties;
};
const handleHover = (target: HoverTarget | undefined) => {
setHoverTarget(target);
keyboardNavigation.handleHover(target?.property);
@@ -132,14 +138,27 @@ export const Section = () => {
const styleValueSource = styles.find(
(styleDecl) => styleDecl.property === property
)?.source.name;
if (
event.altKey &&
property &&
// reset when the value is set and after try to edit two sides
(styleValueSource === "local" || styleValueSource === "overwritten")
) {
deleteProperty(property);
return;
if (event.shiftKey && event.altKey) {
const properties = getSpaceModifiersGroup(property, {
shiftKey: true,
altKey: false,
});
const batch = createBatchUpdate();
for (const property of properties) {
batch.deleteProperty(property);
}
batch.publish();
return;
}
if (event.altKey) {
return;
}
}
handleOpenProperty(property);
}}
@@ -161,7 +180,7 @@ export const Section = () => {
}}
onHover={handleHover}
property={property}
activeProperties={activeProperties}
getActiveProperties={getActiveProperties}
scrubStatus={scrubStatus}
/>
)}
@@ -1,7 +1,5 @@
import { useState, type ReactElement } from "react";
import { useModifierKeys } from "../../shared/modifier-keys";
import { getSpaceModifiersGroup } from "../shared/scrub";
import { createBatchUpdate } from "../../shared/use-style-data";
import { deleteProperty } from "../../shared/use-style-data";
import { Tooltip } from "@webstudio-is/design-system";
import { PropertyInfo } from "../../property-label";
import { useComputedStyles } from "../../shared/model";
@@ -86,10 +84,7 @@ export const SpaceTooltip = ({
preventOpen: boolean;
}) => {
const [isOpen, setIsOpen] = useState(false);
const modifiers = useModifierKeys();
const properties = [...getSpaceModifiersGroup(property, modifiers)];
const properties = [property];
const styles = useComputedStyles(properties);
const propertyContent = propertyContents.find((propertyContent) =>
@@ -103,14 +98,6 @@ export const SpaceTooltip = ({
setIsOpen(value);
};
const resetProperties = () => {
const batch = createBatchUpdate();
for (const property of properties) {
batch.deleteProperty(property);
}
batch.publish();
};
return (
<Tooltip
open={isOpen}
@@ -122,7 +109,7 @@ export const SpaceTooltip = ({
onClick: (event) => {
if (event.altKey) {
event.preventDefault();
resetProperties();
deleteProperty(property);
return;
}
},
@@ -133,7 +120,7 @@ export const SpaceTooltip = ({
description={propertyContent?.description}
styles={styles}
onReset={() => {
resetProperties();
deleteProperty(property);
handleOpenChange(false);
}}
/>
@@ -1,6 +1,13 @@
import { useState, useEffect } from "react";
import { shallowEqual } from "shallow-equal";
export type Modifiers = {
altKey: boolean;
shiftKey: boolean;
ctrlKey: boolean;
metaKey: boolean;
};
// Used for combined mouse and keyboard interactions, like scrubbing while holding ALT.
// If it's just a keyboard interaction, you should already have a keyboard event at hand.
export const useModifierKeys = () => {