Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Make select and combobox description height stable #3385

Merged
merged 1 commit into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ const TypeField = ({
disabled: options.get(option)?.disabled,
})}
getDescription={(option) => (
<Box css={{ width: theme.spacing[25] }}>
<Box css={{ width: theme.spacing[27] }}>
{options.get(option)?.description}
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const SelectControl = ({
if (description === undefined) {
return;
}
return <Box css={{ width: theme.spacing[25] }}>{description}</Box>;
return <Box css={{ width: theme.spacing[26] }}>{description}</Box>;
}}
getItemProps={() => ({ text: "sentence" })}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const Add = ({
item.value as keyof typeof propertyDescriptions
];
}
return <Box css={{ width: theme.spacing[25] }}>{description}</Box>;
return <Box css={{ width: theme.spacing[28] }}>{description}</Box>;
}}
defaultHighlightedIndex={0}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
handleNumericInputArrowKeys,
theme,
Flex,
styled,
} from "@webstudio-is/design-system";
import type {
KeywordValue,
Expand Down Expand Up @@ -325,6 +326,9 @@ const itemToString = (item: CssValueInputValue | null) => {
? String(item.value)
: toValue(item);
};

const Description = styled(Box, { width: theme.spacing[27] });

/**
* Common:
* - Free text editing
Expand Down Expand Up @@ -651,13 +655,27 @@ export const CssValueInput = ({
: items[0]?.type === "keyword"
? items[0]
: undefined;

if (valueForDescription) {
const key = `${property}:${toValue(
valueForDescription
)}` as keyof typeof declarationDescriptions;
description = declarationDescriptions[key];
}

const descriptions = items
.map((item) =>
item.type === "keyword"
? declarationDescriptions[
`${property}:${toValue(
item
)}` as keyof typeof declarationDescriptions
]
: undefined
)
.filter(Boolean)
.map((descr) => <Description>{descr}</Description>);

return (
<ComboboxRoot open={isOpen}>
<Box {...getComboboxProps()} css={{ width: "100%" }}>
Expand Down Expand Up @@ -701,8 +719,8 @@ export const CssValueInput = ({
))}
</ComboboxScrollArea>
{description && (
<ComboboxItemDescription>
<Box css={{ width: theme.spacing[25] }}>{description}</Box>
<ComboboxItemDescription descriptions={descriptions}>
<Description>{description}</Description>
</ComboboxItemDescription>
)}
</ComboboxListbox>
Expand Down
6 changes: 5 additions & 1 deletion packages/design-system/src/components/combobox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ export const Complex = () => {
</ComboboxListboxItem>
);
})}
<ComboboxItemDescription>Description</ComboboxItemDescription>
<ComboboxItemDescription
descriptions={["Hello", "World", "Description"]}
>
Description
</ComboboxItemDescription>
</ComboboxListbox>
</ComboboxContent>
</Flex>
Expand Down
40 changes: 33 additions & 7 deletions packages/design-system/src/components/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from "./menu";
import { ScrollArea } from "./scroll-area";
import { Flex, InputField, NestedInputButton } from "..";
import { Box } from "./box";

export const ComboboxListbox = styled(
"ul",
Expand Down Expand Up @@ -119,9 +120,11 @@ export const ComboboxListboxItem = forwardRef(ListboxItemBase);

export const ComboboxItemDescription = ({
children,
style,
...props
}: ComponentProps<typeof ListboxItem>) => {
descriptions,
}: {
children: ReactNode;
descriptions: ReactNode[];
}) => {
return (
<>
<ComboboxSeparator
Expand All @@ -131,14 +134,34 @@ export const ComboboxItemDescription = ({
}}
/>
<ListboxItem
{...props}
css={{
display: "grid",
}}
hint
style={{
...style,
order: "var(--ws-combobox-description-order)",
}}
>
{children}
{descriptions.map((descr, index) => (
<Box
css={{
gridColumn: "1",
gridRow: "1",
visibility: "hidden",
}}
key={index}
>
{descr}
</Box>
))}
<Box
css={{
gridColumn: "1",
gridRow: "1",
}}
>
{children}
</Box>
</ListboxItem>
<ComboboxSeparator
style={{
Expand Down Expand Up @@ -435,6 +458,7 @@ export const Combobox = <Item,>({
: combobox.items[combobox.highlightedIndex];

const description = getDescription?.(descriptionItem);
const descriptions = combobox.items.map((item) => getDescription?.(item));

return (
<ComboboxRoot open={combobox.isOpen}>
Expand Down Expand Up @@ -463,7 +487,9 @@ export const Combobox = <Item,>({
})}
</ComboboxScrollArea>
{description && (
<ComboboxItemDescription>{description}</ComboboxItemDescription>
<ComboboxItemDescription descriptions={descriptions}>
{description}
</ComboboxItemDescription>
)}
</ComboboxListbox>
</ComboboxContent>
Expand Down
35 changes: 21 additions & 14 deletions packages/design-system/src/components/select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,26 +86,33 @@ export const WithDescriptions: StoryFn<typeof Select> = () => {
const options = [
{ label: "Apple", description: "An apple fruit" },
{ label: "Banana", description: "A banana fruit" },
{ label: "Orange", description: "An orange fruit" },
{
label: "Orange",
description:
"An orange fruit An orange fruit An orange fruit An orange fruit",
},
{ label: "Pear", description: "A pear fruit" },
{ label: "Grape", description: "A grape fruit" },
];
const [value, setValue] = useState<(typeof options)[number]>(options[0]);

return (
<Select
name="fruit"
options={options}
value={value}
getValue={(value) => value.label}
onChange={setValue}
getLabel={(option) => {
return option.label;
}}
getDescription={(option) => {
return option.description;
}}
/>
<>
<div style={{ height: "300px" }}></div>
<Select
name="fruit"
options={options}
value={value}
getValue={(value) => value.label}
onChange={setValue}
getLabel={(option) => {
return option.label;
}}
getDescription={(option) => {
return <div style={{ width: "150px" }}>{option.description}</div>;
}}
/>
</>
);
};

Expand Down
43 changes: 36 additions & 7 deletions packages/design-system/src/components/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
MenuCheckedIcon,
} from "./menu";
import { SelectButton } from "./select-button";
import { Box } from "./box";

export const SelectContent = styled(Primitive.Content, menuCss, {
"&[data-side=top]": {
Expand Down Expand Up @@ -86,9 +87,11 @@ const Description = styled("div", menuItemCss);
// Note this only works in combination with position: popper on Content component, because only popper exposes data-side attribute
export const SelectItemDescription = ({
children,
style,
...props
}: ComponentProps<typeof Description>) => {
descriptions,
}: {
children: ReactNode;
descriptions: ReactNode[];
}) => {
return (
<>
<SelectSeparator
Expand All @@ -97,16 +100,38 @@ export const SelectItemDescription = ({
order: "var(--ws-select-description-order)",
}}
/>

<Description
{...props}
css={{
display: "grid",
}}
hint
style={{
...style,
order: "var(--ws-select-description-order)",
}}
>
{children}
{descriptions.map((descr, index) => (
<Box
css={{
gridColumn: "1",
gridRow: "1",
visibility: "hidden",
}}
key={index}
>
{descr}
</Box>
))}
<Box
css={{
gridColumn: "1",
gridRow: "1",
}}
>
{children}
</Box>
</Description>

<SelectSeparator
style={{
display: `var(--ws-select-description-display-top, none)`,
Expand Down Expand Up @@ -193,6 +218,8 @@ const SelectBase = <Option,>(
? getDescription?.(itemForDescription)
: undefined;

const descriptions = options.map((option) => getDescription?.(option));

return (
<Primitive.Root
name={name}
Expand Down Expand Up @@ -252,7 +279,9 @@ const SelectBase = <Option,>(
</SelectScrollDownButton>

{description && (
<SelectItemDescription>{description}</SelectItemDescription>
<SelectItemDescription descriptions={descriptions}>
{description}
</SelectItemDescription>
)}
</SelectContent>
</Primitive.Portal>
Expand Down
Loading