Skip to content

Commit

Permalink
feat: support editing sides in space and inset controls (#4341)
Browse files Browse the repository at this point in the history
Here made space and inset controls to remember active properties when
open side input.

Test inset and space controls with alt and shift pressed.



https://github.com/user-attachments/assets/c6718245-9426-49ed-91a5-05f83c3ccb88
  • Loading branch information
TrySound authored Oct 25, 2024
1 parent c7c9033 commit ac2e8d9
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +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";

const Cell = ({
scrubStatus,
property,
activeProperties,
onHover,
isPopoverOpen,
onPopoverClose,
Expand All @@ -21,6 +23,7 @@ const Cell = ({
onPopoverClose: () => void;
scrubStatus: ReturnType<typeof useScrub>;
property: InsetProperty;
activeProperties: InsetProperty[];
onHover: (target: HoverTarget | undefined) => void;
}) => {
const styleDecl = useComputedStyleDecl(property);
Expand All @@ -35,6 +38,7 @@ const Cell = ({
value={finalValue}
isOpen={isPopoverOpen}
property={property}
activeProperties={activeProperties}
onClose={onPopoverClose}
/>
<InsetTooltip property={property} preventOpen={scrubStatus.isActive}>
Expand Down Expand Up @@ -88,26 +92,30 @@ export const InsetControl = () => {
});

const [openProperty, setOpenProperty] = useState<InsetProperty>();
const [activePopoverProperties, setActivePopoverProperties] = useState<
undefined | readonly InsetProperty[]
>();
const modifiers = useModifierKeys();
const handleOpenProperty = (property: undefined | InsetProperty) => {
setOpenProperty(property);
setActivePopoverProperties(
property ? getInsetModifiersGroup(property, modifiers) : undefined
);
};

const layoutRef = useRef<HTMLDivElement>(null);

const keyboardNavigation = useKeyboardNavigation({
onOpen: setOpenProperty,
onOpen: handleOpenProperty,
movementMap: movementMapInset,
});

// by deafult highlight hovered or scrubbed properties
let activeProperties = scrubStatus.properties;

// if keyboard navigation is active, highlight its active property
if (keyboardNavigation.isActive) {
activeProperties = [keyboardNavigation.activeProperty];
}

// if popover is open, highlight its property and hovered properties
if (openProperty !== undefined) {
activeProperties = [openProperty, ...scrubStatus.properties];
}
const activeProperties = [
...(activePopoverProperties ?? scrubStatus.properties),
];

const handleHover = (target: HoverTarget | undefined) => {
setHoverTarget(target);
Expand Down Expand Up @@ -138,11 +146,19 @@ export const InsetControl = () => {
onMouseLeave={keyboardNavigation.handleMouseLeave}
onClick={(event) => {
const property = hoverTarget?.property;
if (event.altKey && property) {
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;
}
setOpenProperty(property);
handleOpenProperty(property);
}}
>
<InsetLayout
Expand All @@ -151,11 +167,12 @@ export const InsetControl = () => {
<Cell
scrubStatus={scrubStatus}
property={property}
activeProperties={activeProperties}
onHover={handleHover}
isPopoverOpen={openProperty === property}
onPopoverClose={() => {
if (openProperty === property) {
setOpenProperty(undefined);
handleOpenProperty(undefined);
layoutRef.current?.focus();
}
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,31 @@ import {
PopoverTrigger,
PopoverContent,
} from "@webstudio-is/design-system";
import type { StyleValue } from "@webstudio-is/css-engine";
import type { StyleProperty, StyleValue } from "@webstudio-is/css-engine";
import {
CssValueInput,
type IntermediateStyleValue,
} from "../../shared/css-value-input";
import type { StyleSource } from "../../shared/style-info";
import { createBatchUpdate } from "../../shared/use-style-data";
import { theme } from "@webstudio-is/design-system";
import { getInsetModifiersGroup, getSpaceModifiersGroup } from "./scrub";
import type { SpaceStyleProperty } from "../space/types";
import type { InsetProperty } from "../position/inset-layout";
import { $availableUnitVariables } from "../../shared/model";

const slideUpAndFade = keyframes({
"0%": { opacity: 0, transform: "scale(0.8)" },
"100%": { opacity: 1, transform: "scale(1)" },
});

// We need to differentiate between marginTop and top for example.
const isSpace = (property: string) => {
return property.startsWith("margin") || property.startsWith("padding");
};

const Input = ({
styleSource,
value,
property,
activeProperties,
onClosePopover,
}: {
styleSource: StyleSource;
property: SpaceStyleProperty | InsetProperty;
property: StyleProperty;
activeProperties: StyleProperty[];
value: StyleValue;
onClosePopover: () => void;
}) => {
Expand All @@ -55,35 +49,37 @@ const Input = ({
setIntermediateValue(styleValue);
if (styleValue === undefined) {
const batch = createBatchUpdate();
batch.deleteProperty(property);
for (const property of activeProperties) {
batch.deleteProperty(property);
}
batch.publish({ isEphemeral: true });
return;
}
if (styleValue.type !== "intermediate") {
const batch = createBatchUpdate();
batch.setProperty(property)(styleValue);
for (const property of activeProperties) {
batch.setProperty(property)(styleValue);
}
batch.publish({ isEphemeral: true });
}
}}
onHighlight={(styleValue) => {
if (styleValue === undefined) {
const batch = createBatchUpdate();
batch.deleteProperty(property);
for (const property of activeProperties) {
batch.deleteProperty(property);
}
batch.publish({ isEphemeral: true });
return;
}
const batch = createBatchUpdate();
batch.setProperty(property)(styleValue);
batch.publish({ isEphemeral: true });
}}
onChangeComplete={({ value, altKey, shiftKey }) => {
onChangeComplete={({ value }) => {
const batch = createBatchUpdate();
const modifiers = { shiftKey, altKey };
const properties = isSpace(property)
? getSpaceModifiersGroup(property as SpaceStyleProperty, modifiers)
: getInsetModifiersGroup(property as InsetProperty, modifiers);
setIntermediateValue(undefined);
for (const property of properties) {
for (const property of activeProperties) {
batch.setProperty(property)(value);
}
batch.publish();
Expand Down Expand Up @@ -118,12 +114,14 @@ const PopoverContentStyled = styled(PopoverContent, {
export const InputPopover = ({
styleSource,
property,
activeProperties,
value,
isOpen,
onClose,
}: {
styleSource: StyleSource;
property: SpaceStyleProperty | InsetProperty;
property: StyleProperty;
activeProperties: StyleProperty[];
value: StyleValue;
isOpen: boolean;
onClose: () => void;
Expand Down Expand Up @@ -151,6 +149,7 @@ export const InputPopover = ({
styleSource={styleSource}
value={value}
property={property}
activeProperties={activeProperties}
onClosePopover={onClose}
/>
</PopoverContentStyled>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ 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";

const Cell = ({
isPopoverOpen,
onPopoverClose,
onHover,
property,
activeProperties,
scrubStatus,
}: {
isPopoverOpen: boolean;
onPopoverClose: () => void;
onHover: (target: HoverTarget | undefined) => void;
property: SpaceStyleProperty;
activeProperties: SpaceStyleProperty[];
scrubStatus: ReturnType<typeof useScrub>;
}) => {
const styleDecl = useComputedStyleDecl(property);
Expand All @@ -36,6 +39,7 @@ const Cell = ({
value={finalValue}
isOpen={isPopoverOpen}
property={property}
activeProperties={activeProperties}
onClose={onPopoverClose}
/>
<SpaceTooltip property={property} preventOpen={scrubStatus.isActive}>
Expand Down Expand Up @@ -86,26 +90,30 @@ export const Section = () => {
});

const [openProperty, setOpenProperty] = useState<SpaceStyleProperty>();
const [activePopoverProperties, setActivePopoverProperties] = useState<
undefined | readonly SpaceStyleProperty[]
>();
const modifiers = useModifierKeys();
const handleOpenProperty = (property: undefined | SpaceStyleProperty) => {
setOpenProperty(property);
setActivePopoverProperties(
property ? getSpaceModifiersGroup(property, modifiers) : undefined
);
};

const layoutRef = useRef<HTMLDivElement>(null);

const keyboardNavigation = useKeyboardNavigation({
onOpen: setOpenProperty,
onOpen: handleOpenProperty,
movementMap: movementMapSpace,
});

// by deafult highlight hovered or scrubbed properties
let activeProperties = scrubStatus.properties;

// if keyboard navigation is active, highlight its active property
if (keyboardNavigation.isActive) {
activeProperties = [keyboardNavigation.activeProperty];
}

// if popover is open, highlight its property and hovered properties
if (openProperty !== undefined) {
activeProperties = [openProperty, ...scrubStatus.properties];
}
const activeProperties = [
...(activePopoverProperties ?? scrubStatus.properties),
];

const handleHover = (target: HoverTarget | undefined) => {
setHoverTarget(target);
Expand All @@ -118,11 +126,19 @@ export const Section = () => {
ref={layoutRef}
onClick={(event) => {
const property = hoverTarget?.property;
if (event.altKey && property) {
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;
}
setOpenProperty(property);
handleOpenProperty(property);
}}
onHover={handleHover}
onFocus={keyboardNavigation.handleFocus}
Expand All @@ -136,12 +152,13 @@ export const Section = () => {
isPopoverOpen={openProperty === property}
onPopoverClose={() => {
if (openProperty === property) {
setOpenProperty(undefined);
handleOpenProperty(undefined);
layoutRef.current?.focus();
}
}}
onHover={handleHover}
property={property}
activeProperties={activeProperties}
scrubStatus={scrubStatus}
/>
)}
Expand Down

0 comments on commit ac2e8d9

Please sign in to comment.