mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 22:14:29 +09:00
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:
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={() => {
|
||||
|
||||
+2
-12
@@ -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​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 = () => {
|
||||
|
||||
Reference in new issue
Block a user