diff --git a/apps/builder/app/builder/features/style-panel/sections/position/inset-control.tsx b/apps/builder/app/builder/features/style-panel/sections/position/inset-control.tsx index 5f411cfcea..1d0f569c47 100644 --- a/apps/builder/app/builder/features/style-panel/sections/position/inset-control.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/position/inset-control.tsx @@ -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; 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} /> @@ -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 = () => { }} > ( { diff --git a/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.stories.tsx b/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.stories.tsx index cb5407d78a..84da7ea76a 100644 --- a/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.stories.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.stories.tsx @@ -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 = () => ( auto{/*1.275​rem*/} ); -export const InsetLayoutComponent = ( - args: Omit, "renderCell"> -) => ( +export const InsetLayoutComponent = () => ( } - 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; diff --git a/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.tsx b/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.tsx index 83b1494abb..701e1fa443 100644 --- a/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/position/inset-layout.tsx @@ -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) => { @@ -72,6 +73,7 @@ export const InsetLayout = ({ onHover(undefined); }, }); + const activeProperties = getActiveProperties(); return ( 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} /> diff --git a/apps/builder/app/builder/features/style-panel/sections/space/space.tsx b/apps/builder/app/builder/features/style-panel/sections/space/space.tsx index 7589bb2fb8..6585e7d6e4 100644 --- a/apps/builder/app/builder/features/style-panel/sections/space/space.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/space/space.tsx @@ -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; }) => { const styleDecl = useComputedStyleDecl(property); @@ -40,7 +40,7 @@ const Cell = ({ value={finalValue} isOpen={isPopoverOpen} property={property} - activeProperties={activeProperties} + getActiveProperties={getActiveProperties} onClose={onPopoverClose} /> @@ -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} /> )} diff --git a/apps/builder/app/builder/features/style-panel/sections/space/tooltip.tsx b/apps/builder/app/builder/features/style-panel/sections/space/tooltip.tsx index 3cea1a4118..fb79394ae5 100644 --- a/apps/builder/app/builder/features/style-panel/sections/space/tooltip.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/space/tooltip.tsx @@ -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 ( { 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); }} /> diff --git a/apps/builder/app/builder/features/style-panel/shared/modifier-keys.ts b/apps/builder/app/builder/features/style-panel/shared/modifier-keys.ts index cd1026cbae..aa1a5ff3b6 100644 --- a/apps/builder/app/builder/features/style-panel/shared/modifier-keys.ts +++ b/apps/builder/app/builder/features/style-panel/shared/modifier-keys.ts @@ -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 = () => {