Skip to content

Commit 0ceaac9

Browse files
authored
refactor: improve advanced section performance (#4215)
Ref #3399 Here did a few things to improve performance of advanced panel with hundreds if css variables. - remove unused dom elements - replaced field-sizing polyfill with css property which is supported in chrome since March Here's perf stats from local test, both scripting and rendering cut 1s each ![Screenshot 2024-10-04 at 13 31 13](https://github.com/user-attachments/assets/122969f4-1ed8-4cc5-a7e9-8070c6d9bf2d) ![Screenshot 2024-10-04 at 14 20 55](https://github.com/user-attachments/assets/ceff3221-4b63-4467-a7de-cd845e2b351a) Here's the result in branch preview ![Screenshot 2024-10-04 at 14 30 19](https://github.com/user-attachments/assets/97939e31-9eba-465e-888c-ed89aa0d1205) ![Screenshot 2024-10-04 at 14 31 22](https://github.com/user-attachments/assets/dc3d116e-fef7-4e31-b054-17107e160590)
1 parent ab86c89 commit 0ceaac9

File tree

7 files changed

+98
-129
lines changed

7 files changed

+98
-129
lines changed

apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -176,41 +176,37 @@ const AdvancedPropertyLabel = ({ property }: { property: StyleProperty }) => {
176176
styleDecl.source.name === "default" ? "code" : styleDecl.source.name;
177177
const [isOpen, setIsOpen] = useState(false);
178178
return (
179-
<Flex align="center">
180-
<Tooltip
181-
open={isOpen}
182-
onOpenChange={setIsOpen}
183-
// prevent closing tooltip on content click
184-
onPointerDown={(event) => event.preventDefault()}
185-
triggerProps={{
186-
onClick: (event) => {
187-
if (event.altKey) {
188-
event.preventDefault();
189-
deleteProperty(property);
190-
return;
191-
}
192-
setIsOpen(true);
193-
},
194-
}}
195-
content={
196-
<PropertyInfo
197-
title={label}
198-
description={description}
199-
styles={[styleDecl]}
200-
onReset={() => {
201-
deleteProperty(property);
202-
setIsOpen(false);
203-
}}
204-
/>
205-
}
206-
>
207-
<Flex shrink gap={1} align="center">
208-
<Label color={color} text="mono" truncate>
209-
{label}
210-
</Label>
211-
</Flex>
212-
</Tooltip>
213-
</Flex>
179+
<Tooltip
180+
open={isOpen}
181+
onOpenChange={setIsOpen}
182+
// prevent closing tooltip on content click
183+
onPointerDown={(event) => event.preventDefault()}
184+
triggerProps={{
185+
onClick: (event) => {
186+
if (event.altKey) {
187+
event.preventDefault();
188+
deleteProperty(property);
189+
return;
190+
}
191+
setIsOpen(true);
192+
},
193+
}}
194+
content={
195+
<PropertyInfo
196+
title={label}
197+
description={description}
198+
styles={[styleDecl]}
199+
onReset={() => {
200+
deleteProperty(property);
201+
setIsOpen(false);
202+
}}
203+
/>
204+
}
205+
>
206+
<Label color={color} text="mono">
207+
{label}
208+
</Label>
209+
</Tooltip>
214210
);
215211
};
216212

@@ -374,7 +370,7 @@ export const Section = () => {
374370
)}
375371
<Box>
376372
{advancedProperties.map((property) => (
377-
<Flex key={property} wrap="wrap" align="center">
373+
<Flex key={property} wrap="wrap" align="center" justify="start">
378374
<AdvancedPropertyLabel property={property} />
379375
<Text>:</Text>
380376
<AdvancedPropertyValue

apps/builder/app/builder/features/style-panel/sections/borders/border-property.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { type ReactNode } from "react";
22
import type { StyleProperty } from "@webstudio-is/css-engine";
33
import { toValue } from "@webstudio-is/css-engine";
4-
import {
5-
Box,
6-
Grid,
7-
NestedIconLabel,
8-
ToggleButton,
9-
} from "@webstudio-is/design-system";
4+
import { Box, Grid, ToggleButton } from "@webstudio-is/design-system";
105
import { CssValueInputContainer } from "../../shared/css-value-input";
116
import { styleConfigByName } from "../../shared/configs";
127
import { rowCss } from "./utils";
@@ -124,12 +119,7 @@ export const BorderProperty = ({
124119
<CssValueInputContainer
125120
key={styleDecl.property}
126121
icon={
127-
<NestedIconLabel>
128-
{
129-
borderPropertyOptions[styleDecl.property as StyleProperty]
130-
?.icon
131-
}
132-
</NestedIconLabel>
122+
borderPropertyOptions[styleDecl.property as StyleProperty]?.icon
133123
}
134124
property={styleDecl.property as StyleProperty}
135125
styleSource={styleDecl.source.name}
Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { type ComponentProps, useState } from "react";
22
import type { StyleValue } from "@webstudio-is/css-engine";
3-
import { Box } from "@webstudio-is/design-system";
43
import { CssValueInput, type IntermediateStyleValue } from "./css-value-input";
54
import type { DeleteProperty, SetValue } from "../use-style-data";
65

@@ -28,39 +27,37 @@ export const CssValueInputContainer = ({
2827
>();
2928

3029
return (
31-
<Box>
32-
<CssValueInput
33-
{...props}
34-
property={property}
35-
intermediateValue={intermediateValue}
36-
keywords={keywords}
37-
onChange={(styleValue) => {
38-
setIntermediateValue(styleValue);
30+
<CssValueInput
31+
{...props}
32+
property={property}
33+
intermediateValue={intermediateValue}
34+
keywords={keywords}
35+
onChange={(styleValue) => {
36+
setIntermediateValue(styleValue);
3937

40-
if (styleValue === undefined) {
41-
deleteProperty(property, { isEphemeral: true });
42-
return;
43-
}
38+
if (styleValue === undefined) {
39+
deleteProperty(property, { isEphemeral: true });
40+
return;
41+
}
4442

45-
if (styleValue.type !== "intermediate") {
46-
setValue(styleValue, { isEphemeral: true });
47-
}
48-
}}
49-
onHighlight={(styleValue) => {
50-
if (styleValue !== undefined) {
51-
setValue(styleValue, { isEphemeral: true });
52-
} else {
53-
deleteProperty(property, { isEphemeral: true });
54-
}
55-
}}
56-
onChangeComplete={({ value }) => {
57-
setValue(value);
58-
setIntermediateValue(undefined);
59-
}}
60-
onAbort={() => {
43+
if (styleValue.type !== "intermediate") {
44+
setValue(styleValue, { isEphemeral: true });
45+
}
46+
}}
47+
onHighlight={(styleValue) => {
48+
if (styleValue !== undefined) {
49+
setValue(styleValue, { isEphemeral: true });
50+
} else {
6151
deleteProperty(property, { isEphemeral: true });
62-
}}
63-
/>
64-
</Box>
52+
}
53+
}}
54+
onChangeComplete={({ value }) => {
55+
setValue(value);
56+
setIntermediateValue(undefined);
57+
}}
58+
onAbort={() => {
59+
deleteProperty(property, { isEphemeral: true });
60+
}}
61+
/>
6562
);
6663
};

apps/builder/app/builder/features/style-panel/shared/css-value-input/css-value-input.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,8 @@ export const CssValueInput = ({
692692

693693
return (
694694
<ComboboxRoot open={isOpen}>
695-
<Box {...getComboboxProps()} css={{ width: "100%" }}>
696-
<ComboboxAnchor>
695+
<Box {...getComboboxProps()}>
696+
<ComboboxAnchor asChild>
697697
<InputField
698698
size={size}
699699
variant={variant}
@@ -716,7 +716,7 @@ export const CssValueInput = ({
716716
color={value.type === "invalid" ? "error" : undefined}
717717
prefix={finalPrefix}
718718
suffix={suffix}
719-
css={{ cursor: "default", minWidth: "3em" }}
719+
css={{ cursor: "default", minWidth: "2em" }}
720720
text={text}
721721
/>
722722
</ComboboxAnchor>

packages/design-system/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
"change-case": "^5.4.4",
6666
"downshift": "^6.1.7",
6767
"match-sorter": "^6.3.4",
68-
"react-field-sizing-content": "^1.0.0",
6968
"react-hot-toast": "^2.4.1",
7069
"token-transformer": "^0.0.28",
7170
"use-debounce": "^9.0.4",

packages/design-system/src/components/input-field.tsx

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ import { css, theme, type CSS } from "../stitches.config";
1717
import { ArrowFocus } from "./primitives/arrow-focus";
1818
import { mergeRefs } from "@react-aria/utils";
1919
import { useFocusWithin } from "@react-aria/interactions";
20-
import {
21-
type InputProps as InputWithFieldSizingProps,
22-
Input as InputWithFieldSizing,
23-
} from "react-field-sizing-content";
2420

2521
// we only support types that behave more or less like a regular text input
2622
export const inputFieldTypes = [
@@ -66,6 +62,14 @@ const inputStyle = css({
6662
regular: textVariants.regular,
6763
mono: textVariants.mono,
6864
},
65+
fieldSizing: {
66+
content: {
67+
fieldSizing: "content",
68+
},
69+
fixed: {
70+
fieldSizing: "fixed",
71+
},
72+
},
6973
},
7074
defaultVariants: {
7175
text: "regular",
@@ -193,42 +197,26 @@ const Container = forwardRef(
193197
);
194198
Container.displayName = "Container";
195199

196-
type InputProps = {
197-
type?: (typeof inputFieldTypes)[number];
198-
color?: (typeof inputFieldColors)[number];
199-
css?: CSS;
200-
text?: "regular" | "mono";
201-
} & Omit<InputWithFieldSizingProps, "prefix" | "onFocus" | "onBlur" | "size">;
202-
203-
const Input = forwardRef(
204-
(
205-
{ css, className, color, disabled = false, text, ...props }: InputProps,
206-
ref: Ref<HTMLInputElement>
207-
) => {
208-
return (
209-
<InputWithFieldSizing
210-
{...props}
211-
spellCheck={false}
212-
data-input-field-input // to distinguish from potential other inputs in prefix/suffix
213-
data-color={color}
214-
disabled={disabled}
215-
className={inputStyle({ className, css, text })}
216-
ref={ref}
217-
/>
218-
);
219-
}
220-
);
221-
Input.displayName = "Input";
200+
type InputProps = Omit<
201+
ComponentProps<"input">,
202+
"onFocus" | "onBlur" | "prefix" | "size"
203+
> & {
204+
onFocus?: FocusEventHandler;
205+
onBlur?: FocusEventHandler;
206+
};
222207

223208
type InputFieldProps = {
224209
prefix?: ReactNode;
225210
suffix?: ReactNode;
226211
containerRef?: Ref<HTMLDivElement>;
227212
inputRef?: Ref<HTMLInputElement>;
228-
onFocus?: FocusEventHandler;
229-
onBlur?: FocusEventHandler;
230213
variant?: "chromeless";
231214
size?: "1" | "2" | "3";
215+
type?: (typeof inputFieldTypes)[number];
216+
color?: (typeof inputFieldColors)[number];
217+
css?: CSS;
218+
text?: "regular" | "mono";
219+
fieldSizing?: "content" | "fixed";
232220
};
233221

234222
export const InputField = forwardRef(
@@ -244,6 +232,9 @@ export const InputField = forwardRef(
244232
onBlur,
245233
variant,
246234
size,
235+
color,
236+
text,
237+
fieldSizing,
247238
onKeyDown,
248239
...inputProps
249240
}: InputProps & InputFieldProps,
@@ -283,7 +274,15 @@ export const InputField = forwardRef(
283274
// When managing focus with ArrowFocus, we don't want to focus this element.
284275
data-no-arrow-focus
285276
/>
286-
<Input {...inputProps} onKeyDown={handleKeyDown} ref={inputRef} />
277+
<input
278+
{...inputProps}
279+
ref={inputRef}
280+
spellCheck={false}
281+
data-input-field-input // to distinguish from potential other inputs in prefix/suffix
282+
data-color={color}
283+
className={inputStyle({ className, css, text, fieldSizing })}
284+
onKeyDown={handleKeyDown}
285+
/>
287286
</Container>
288287
);
289288
}

pnpm-lock.yaml

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)