feat: reuse dropdown instead of radix select

This commit is contained in:
Arnošt Pleskot 2023-09-18 23:14:33 +02:00
parent c578e4b640
commit bb847e391c
No known key found for this signature in database
7 changed files with 86 additions and 441 deletions

View file

@ -12,10 +12,9 @@ import { register } from "./register";
import { CheckboxItem } from "../components/CheckboxItem";
import { getExportSize } from "../scene/export";
import {
DEFAULT_FANCY_BACKGROUND_IMAGE,
DEFAULT_EXPORT_PADDING,
FANCY_BACKGROUND_IMAGES,
EXPORT_SCALES,
FANCY_BACKGROUND_IMAGES,
THEME,
} from "../constants";
import { getSelectedElements, isSomeElementSelected } from "../scene";
@ -25,7 +24,7 @@ import { nativeFileSystemSupported } from "../data/filesystem";
import { Theme } from "../element/types";
import "../components/ToolIcon.scss";
import Select, { convertToSelectItems } from "../components/Select";
import { Select } from "../components/Select";
export const actionChangeProjectName = register({
name: "changeProjectName",
@ -124,19 +123,18 @@ export const actionChangeFancyBackgroundImageUrl = register({
commitToHistory: false,
};
},
PanelComponent: ({ updateData }) => {
const items = convertToSelectItems(
FANCY_BACKGROUND_IMAGES,
(item) => item.label,
);
PanelComponent: ({ updateData, appState }) => {
return (
<Select
items={items}
ariaLabel={t("imageExportDialog.label.backgroundImage")}
placeholder={t("imageExportDialog.label.backgroundImage")}
value={DEFAULT_FANCY_BACKGROUND_IMAGE}
onChange={(value) => {
updateData(value);
value={appState.fancyBackgroundImageKey}
options={Object.entries(FANCY_BACKGROUND_IMAGES).map(
([value, { label }]) => ({
value,
label,
}),
)}
onSelect={(key) => {
updateData(key);
}}
/>
);

View file

@ -43,14 +43,26 @@ import { Tooltip } from "./Tooltip";
import "./ImageExportDialog.scss";
import { useAppProps } from "./App";
import { FilledButton } from "./FilledButton";
import Select, { convertToSelectItems } from "./Select";
import { getCommonBounds } from "../element";
import { convertToExportPadding, defaultExportScale, distance } from "../utils";
import {
convertToExportPadding,
defaultExportScale,
distance,
isBackgroundImageKey,
} from "../utils";
import { getFancyBackgroundPadding } from "../scene/fancyBackground";
import { Select } from "./Select";
const supportsContextFilters =
"filter" in document.createElement("canvas").getContext("2d")!;
const fancyBackgroundImageOptions = Object.entries(FANCY_BACKGROUND_IMAGES).map(
([value, { label }]) => ({
value,
label,
}),
);
export const ErrorCanvasPreview = () => {
return (
<div>
@ -71,17 +83,6 @@ type ImageExportModalProps = {
onExportImage: AppClassProperties["onExportImage"];
};
function isBackgroundImageKey(
key: string,
): key is keyof typeof FANCY_BACKGROUND_IMAGES {
return key in FANCY_BACKGROUND_IMAGES;
}
const backgroundSelectItems = convertToSelectItems(
FANCY_BACKGROUND_IMAGES,
(item) => item.label,
);
const ImageExportModal = ({
appState,
elements,
@ -283,17 +284,15 @@ const ImageExportModal = ({
>
{exportWithBackground && (
<Select
items={backgroundSelectItems}
ariaLabel={t("imageExportDialog.label.backgroundImage")}
placeholder={t("imageExportDialog.label.backgroundImage")}
value={exportBackgroundImage}
onChange={(value) => {
if (isBackgroundImageKey(value)) {
setExportBackgroundImage(value);
options={fancyBackgroundImageOptions}
onSelect={(key) => {
if (isBackgroundImageKey(key)) {
setExportBackgroundImage(key);
actionManager.executeAction(
actionChangeFancyBackgroundImageUrl,
"ui",
value,
key,
);
}
}}

View file

@ -1,68 +1,11 @@
.Select {
&__trigger {
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 1;
gap: 5px;
background: transparent;
border: none;
font-weight: 600;
font-size: 0.8rem;
color: var(--text-primary-color);
}
&__trigger-icon {
width: 15px;
height: 15px;
}
position: relative;
&__content {
overflow: hidden;
box-shadow: var(--shadow-island);
border-radius: var(--border-radius-md);
padding: calc(var(--padding) * var(--space-factor));
background-color: var(--input-bg-color);
z-index: 1;
}
&__viewport {
padding: 0.5rem;
}
&__item {
font-size: 0.8rem;
line-height: 1;
border-radius: var(--border-radius-md);
display: flex;
align-items: center;
padding: 0.5rem 1rem;
position: relative;
user-select: none;
font-weight: 600;
color: var(--text-primary-color);
&[data-highlighted] {
outline: none;
background-color: var(--button-hover-bg);
}
&[data-state="checked"] {
background-color: var(--color-primary);
color: var(--input-bg-color);
}
&[data-highlighted][data-state="checked"] {
background-color: var(--color-primary-darker);
}
}
&__scroll-button {
display: flex;
align-items: center;
justify-content: center;
height: 25px;
background-color: white;
cursor: default;
right: 0;
}
}
.excalidraw .Modal .Select .Island {
padding: 1rem !important;
}

View file

@ -1,95 +1,49 @@
import React, { forwardRef } from "react";
import clxs from "clsx";
import * as RadixSelect from "@radix-ui/react-select";
import React, { useMemo } from "react";
import DropdownMenu from "./dropdownMenu/DropdownMenu";
import "./Select.scss";
import { tablerChevronDownIcon, tablerChevronUpIcon } from "./icons";
type SelectItems<T extends string> = Record<T, string>;
export type SelectProps<T extends string> = {
items: SelectItems<T>;
export type SelectProps<T> = {
onSelect: (value: T) => void;
options: { value: T; label: string }[];
value: T;
onChange: (value: T) => void;
placeholder?: string;
ariaLabel?: string;
};
type ConverterFunction<T> = (
items: Record<string, T>,
getLabel: (item: T) => string,
) => SelectItems<string>;
export const Select = <T,>({ onSelect, options, value }: SelectProps<T>) => {
const [isOpen, setIsOpen] = React.useState(false);
export const convertToSelectItems: ConverterFunction<any> = (
items,
getLabel,
) => {
const result: SelectItems<string> = {};
for (const key in items) {
result[key] = getLabel(items[key]);
}
return result;
const currentLabel = useMemo(() => {
return options.find((option) => option.value === value)?.label;
}, [value, options]);
return (
<div className="Select">
<DropdownMenu open={isOpen}>
<DropdownMenu.Trigger onToggle={() => setIsOpen(!isOpen)}>
{currentLabel}
</DropdownMenu.Trigger>
<DropdownMenu.Content
onClickOutside={() => {
console.log("click outside");
setIsOpen(false);
}}
onSelect={() => setIsOpen(false)}
className="Select__content"
>
{options.map(({ value, label }) => {
return (
<DropdownMenu.Item
key={label}
onSelect={() => {
onSelect(value);
setIsOpen(false);
}}
>
{label}
</DropdownMenu.Item>
);
})}
</DropdownMenu.Content>
</DropdownMenu>
</div>
);
};
const Select = <T extends string>({
items,
value,
onChange,
placeholder,
ariaLabel,
}: SelectProps<T>) => (
<RadixSelect.Root value={value} onValueChange={onChange}>
<RadixSelect.Trigger
className="Select__trigger"
aria-label={ariaLabel ?? placeholder}
>
{placeholder && <RadixSelect.Value placeholder={placeholder} />}
<RadixSelect.Icon className="Select__trigger-icon">
{tablerChevronDownIcon}
</RadixSelect.Icon>
</RadixSelect.Trigger>
<RadixSelect.Content
className="Select__content"
position="popper"
align="center"
>
<RadixSelect.ScrollUpButton className="Select__scroll-button">
{tablerChevronUpIcon}
</RadixSelect.ScrollUpButton>
<RadixSelect.Viewport className="Select__viewport">
{(Object.entries(items) as [T, string][]).map(
([itemValue, itemLabel]) => (
<SelectItem value={itemValue} key={itemValue}>
{itemLabel}
</SelectItem>
),
)}
</RadixSelect.Viewport>
<RadixSelect.ScrollDownButton className="Select__scroll-button">
{tablerChevronDownIcon}
</RadixSelect.ScrollDownButton>
</RadixSelect.Content>
</RadixSelect.Root>
);
type SelectItemProps = React.ComponentProps<typeof RadixSelect.Item>;
const SelectItem = forwardRef(
(
{ children, className, ...props }: SelectItemProps,
forwardedRef: React.ForwardedRef<HTMLDivElement>,
) => {
return (
<RadixSelect.Item
className={clxs("Select__item", className)}
{...props}
ref={forwardedRef}
>
<RadixSelect.ItemText>{children}</RadixSelect.ItemText>
</RadixSelect.Item>
);
},
);
export default Select;

View file

@ -5,6 +5,7 @@ import {
DEFAULT_VERSION,
EVENT,
EXPORT_SCALES,
FANCY_BACKGROUND_IMAGES,
FONT_FAMILY,
isDarwin,
MIME_TYPES,
@ -1081,3 +1082,9 @@ export const convertToExportPadding = (
throw new Error("Invalid padding value");
};
export function isBackgroundImageKey(
key: string,
): key is keyof typeof FANCY_BACKGROUND_IMAGES {
return key in FANCY_BACKGROUND_IMAGES;
}