Merge branch 'main' into new_canvas_route
No files matched your search
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
@@ -1,16 +1,15 @@
|
||||
import { LinksFunction, MetaFunction } from "@remix-run/node";
|
||||
import { Form, useLoaderData } from "@remix-run/react";
|
||||
import { useState } from "react";
|
||||
|
||||
import {
|
||||
Card,
|
||||
Flex,
|
||||
Heading,
|
||||
Button,
|
||||
__DEPRECATED__Text,
|
||||
TextField,
|
||||
} from "@webstudio-is/design-system";
|
||||
import interStyles from "~/shared/font-faces/inter.css";
|
||||
|
||||
import { GithubIcon, CommitIcon, GoogleIcon } from "@webstudio-is/icons";
|
||||
import { LoginButton } from "./components/login-button";
|
||||
import loginStyles from "./login.css";
|
||||
@@ -44,59 +43,72 @@ export const Login = ({ errorMessage }: { errorMessage: string }) => {
|
||||
justify="center"
|
||||
>
|
||||
<Card size={2}>
|
||||
<Flex direction="column" gap="4" align="center">
|
||||
<Flex direction="column" align="center" gap="3">
|
||||
<Heading size="2">Login</Heading>
|
||||
{errorMessage.length ? (
|
||||
<__DEPRECATED__Text css={{ textAlign: "center" }} variant="red">
|
||||
{errorMessage}
|
||||
</__DEPRECATED__Text>
|
||||
) : null}
|
||||
<Flex gap="2" direction="column" align="center">
|
||||
<Form action="/auth/github" method="post">
|
||||
<LoginButton enabled={data.isGithubEnabled}>
|
||||
<Flex gap="1">
|
||||
<GithubIcon width="20" />
|
||||
Login with GitHub
|
||||
</Flex>
|
||||
</LoginButton>
|
||||
</Form>
|
||||
<Form action="/auth/google" method="post">
|
||||
<LoginButton enabled={data.isGoogleEnabled}>
|
||||
<Flex gap="1">
|
||||
<GoogleIcon width="20" />
|
||||
Login with Google
|
||||
</Flex>
|
||||
</LoginButton>
|
||||
</Form>
|
||||
{data.isDevLogin && (
|
||||
<>
|
||||
{isDevLoginOpen ? (
|
||||
<Form action="/auth/dev" method="post">
|
||||
<Flex direction="column" gap="4" css={{ width: 300 }}>
|
||||
{errorMessage.length ? (
|
||||
<__DEPRECATED__Text css={{ textAlign: "center" }} variant="red">
|
||||
{errorMessage}
|
||||
</__DEPRECATED__Text>
|
||||
) : null}
|
||||
<Flex gap="2" direction="column">
|
||||
<Form action="/auth/github" method="post">
|
||||
<LoginButton enabled={data.isGithubEnabled}>
|
||||
<Flex gap="2" align="center">
|
||||
<Flex css={{ width: 20, height: 20 }}>
|
||||
<GithubIcon />
|
||||
</Flex>
|
||||
Login with GitHub
|
||||
</Flex>
|
||||
</LoginButton>
|
||||
</Form>
|
||||
<Form action="/auth/google" method="post">
|
||||
<LoginButton enabled={data.isGoogleEnabled}>
|
||||
<Flex gap="2" align="center">
|
||||
<Flex css={{ width: 20, height: 20 }}>
|
||||
<GoogleIcon />
|
||||
</Flex>
|
||||
Login with Google
|
||||
</Flex>
|
||||
</LoginButton>
|
||||
</Form>
|
||||
{data.isDevLogin &&
|
||||
(isDevLoginOpen ? (
|
||||
<Flex
|
||||
as="form"
|
||||
action="/auth/dev"
|
||||
method="post"
|
||||
css={{
|
||||
flexDirection: "row",
|
||||
gap: "$2",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size={2}
|
||||
css={{ width: "100%", flexGrow: 1 }}
|
||||
name="secret"
|
||||
type="text"
|
||||
minLength={2}
|
||||
required
|
||||
autoFocus
|
||||
placeholder="Place your auth secret here"
|
||||
placeholder="Auth secret"
|
||||
css={{ flexGrow: 1 }}
|
||||
/>
|
||||
</Form>
|
||||
<Button size={2}>Login</Button>
|
||||
</Flex>
|
||||
) : (
|
||||
<LoginButton
|
||||
enabled={data.isDevLogin}
|
||||
isDevLogin
|
||||
onClick={() => openDevLogin(true)}
|
||||
>
|
||||
<Flex gap="1" align="center">
|
||||
<CommitIcon width="20" />
|
||||
<Flex gap="2" align="center">
|
||||
<Flex css={{ width: 20, height: 20 }}>
|
||||
<CommitIcon />
|
||||
</Flex>
|
||||
Dev Login
|
||||
</Flex>
|
||||
</LoginButton>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
@@ -55,7 +55,6 @@ export const SelectProjectCard = ({
|
||||
<Form method="post">
|
||||
<Flex gap="1">
|
||||
<TextField
|
||||
size={2}
|
||||
state={errors ? "invalid" : undefined}
|
||||
name="project"
|
||||
defaultValue={newProject}
|
||||
|
||||
@@ -31,7 +31,6 @@ const TextControl = ({
|
||||
}: TextControlProps) => (
|
||||
<TextField
|
||||
type={type}
|
||||
variant="ghost"
|
||||
placeholder="Value"
|
||||
name="value"
|
||||
value={String(value || defaultValue || "")}
|
||||
|
||||
@@ -10,19 +10,100 @@ import type { SelectedInstanceData } from "~/shared/canvas-components";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Combobox,
|
||||
ComboboxTextField,
|
||||
ComboboxPopperContent,
|
||||
Grid,
|
||||
TextField,
|
||||
Tooltip,
|
||||
useCombobox,
|
||||
ComboboxPopper,
|
||||
ComboboxPopperContent,
|
||||
ComboboxPopperAnchor,
|
||||
ComboboxListbox,
|
||||
ComboboxListboxItem,
|
||||
IconButton,
|
||||
} from "@webstudio-is/design-system";
|
||||
import {
|
||||
PlusIcon,
|
||||
TrashIcon,
|
||||
ExclamationTriangleIcon,
|
||||
ChevronDownIcon,
|
||||
} from "@webstudio-is/icons";
|
||||
import { handleChangePropType, usePropsLogic } from "./use-props-logic";
|
||||
|
||||
type ComboboxProps = {
|
||||
isReadonly: boolean;
|
||||
isInvalid: boolean;
|
||||
items: Array<string>;
|
||||
value: string;
|
||||
onItemSelect: (value: string | null) => void;
|
||||
onSubmit: (value: string) => void;
|
||||
};
|
||||
|
||||
const Combobox = ({
|
||||
isReadonly,
|
||||
isInvalid,
|
||||
items: itemsProp,
|
||||
value,
|
||||
onItemSelect,
|
||||
onSubmit,
|
||||
}: ComboboxProps) => {
|
||||
const {
|
||||
items,
|
||||
getInputProps,
|
||||
getComboboxProps,
|
||||
getToggleButtonProps,
|
||||
getMenuProps,
|
||||
getItemProps,
|
||||
isOpen,
|
||||
} = useCombobox({
|
||||
items: itemsProp,
|
||||
value,
|
||||
itemToString: (item) => item ?? "",
|
||||
onItemSelect,
|
||||
});
|
||||
|
||||
return (
|
||||
<ComboboxPopper>
|
||||
<Box {...getComboboxProps()}>
|
||||
<ComboboxPopperAnchor>
|
||||
<TextField
|
||||
{...getInputProps({
|
||||
onKeyPress: (event) => {
|
||||
if (event.key === "Enter") {
|
||||
onSubmit(event.currentTarget.value);
|
||||
}
|
||||
},
|
||||
})}
|
||||
name="prop"
|
||||
placeholder="Property"
|
||||
readOnly={isReadonly}
|
||||
state={isInvalid ? "invalid" : undefined}
|
||||
suffix={
|
||||
<IconButton {...getToggleButtonProps()}>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</ComboboxPopperAnchor>
|
||||
<ComboboxPopperContent align="start" sideOffset={5}>
|
||||
<ComboboxListbox {...getMenuProps()}>
|
||||
{isOpen &&
|
||||
items.map((item, index) => {
|
||||
return (
|
||||
<ComboboxListboxItem
|
||||
{...getItemProps({ item, index })}
|
||||
key={index}
|
||||
>
|
||||
{item}
|
||||
</ComboboxListboxItem>
|
||||
);
|
||||
})}
|
||||
</ComboboxListbox>
|
||||
</ComboboxPopperContent>
|
||||
</Box>
|
||||
</ComboboxPopper>
|
||||
);
|
||||
};
|
||||
|
||||
type PropertyProps = UserProp & {
|
||||
component: Instance["component"];
|
||||
onChange: handleChangePropType;
|
||||
@@ -33,14 +114,15 @@ const Property = ({
|
||||
id,
|
||||
prop,
|
||||
value,
|
||||
required,
|
||||
required = false,
|
||||
component,
|
||||
onChange,
|
||||
onDelete,
|
||||
}: PropertyProps) => {
|
||||
const meta = componentsMeta[component];
|
||||
const argType = meta.argTypes?.[prop as keyof typeof meta.argTypes];
|
||||
const isInvalidProp =
|
||||
const isInvalid =
|
||||
prop != null &&
|
||||
prop.length > 0 &&
|
||||
typeof argType === "undefined" &&
|
||||
!prop.match(/^data-(.)+/);
|
||||
@@ -51,32 +133,24 @@ const Property = ({
|
||||
|
||||
return (
|
||||
<Grid
|
||||
gap="1"
|
||||
gap={1}
|
||||
css={{ gridTemplateColumns: "1fr 1fr auto", alignItems: "center" }}
|
||||
>
|
||||
<Combobox
|
||||
name="prop"
|
||||
items={allProps}
|
||||
value={prop}
|
||||
itemToString={(item) => item ?? ""}
|
||||
onItemSelect={(value) => {
|
||||
onItemSelect={(value: PropertyProps["value"] | null) => {
|
||||
if (value !== null) {
|
||||
onChange(id, "prop", value);
|
||||
}
|
||||
}}
|
||||
onSubmit={(value) => {
|
||||
onChange(id, "prop", value);
|
||||
}}
|
||||
renderTextField={({ inputProps, toggleProps }) => (
|
||||
<ComboboxTextField
|
||||
toggleProps={toggleProps}
|
||||
inputProps={{
|
||||
...inputProps,
|
||||
readOnly: required,
|
||||
placeholder: "Property",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
renderPopperContent={(props) => (
|
||||
<ComboboxPopperContent {...props} align="start" sideOffset={5} />
|
||||
)}
|
||||
isInvalid={isInvalid}
|
||||
isReadonly={required}
|
||||
/>
|
||||
{isInvalidProp ? (
|
||||
{isInvalid ? (
|
||||
<Tooltip content={`Invalid property name: ${prop}`}>
|
||||
<ExclamationTriangleIcon width={12} height={12} />
|
||||
</Tooltip>
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
PopoverContent,
|
||||
PopoverPortal,
|
||||
TextField,
|
||||
Tooltip,
|
||||
css,
|
||||
} from "@webstudio-is/design-system";
|
||||
import { PropertyName } from "../../shared/property-name";
|
||||
@@ -54,73 +53,56 @@ const ColorPicker = ({
|
||||
onChange,
|
||||
onChangeComplete,
|
||||
id,
|
||||
styleConfig,
|
||||
}: ColorPickerProps) => {
|
||||
const [displayColorPicker, setDisplayColorPicker] = useState(false);
|
||||
// Color picker will use 0 as alpha value, which will force user to set alpha every time they have to change from transparent
|
||||
if (value === "transparent") value = "";
|
||||
|
||||
return (
|
||||
<Popover
|
||||
modal
|
||||
open={displayColorPicker}
|
||||
onOpenChange={setDisplayColorPicker}
|
||||
>
|
||||
<PopoverTrigger asChild aria-label="Open color picker">
|
||||
<Grid
|
||||
css={{
|
||||
gridTemplateColumns: "$sizes$6 auto",
|
||||
gridTemplateRows: "repeat(1, 1fr)",
|
||||
}}
|
||||
<TextField
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
value={value}
|
||||
id={id}
|
||||
prefix={
|
||||
<Popover
|
||||
modal
|
||||
open={displayColorPicker}
|
||||
onOpenChange={setDisplayColorPicker}
|
||||
>
|
||||
<Tooltip
|
||||
content={styleConfig.label}
|
||||
delayDuration={700 / 4}
|
||||
disableHoverableContent={true}
|
||||
<PopoverTrigger
|
||||
asChild
|
||||
aria-label="Open color picker"
|
||||
onClick={() => setDisplayColorPicker((shown) => !shown)}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
gridArea: "1 / 1 / 2 / 2",
|
||||
width: "calc($sizes$6 - 6px)",
|
||||
height: "calc($sizes$6 - 6px)",
|
||||
margin: 3,
|
||||
width: "$sizes$3",
|
||||
height: "$sizes$3",
|
||||
borderRadius: 2,
|
||||
background: value,
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<TextField
|
||||
css={{
|
||||
height: "$6",
|
||||
gridArea: "1 / 1 / -1 / -1",
|
||||
paddingLeft: "calc($sizes$6 + 6px)",
|
||||
}}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
onClick={() => setDisplayColorPicker((shown) => !shown)}
|
||||
value={value}
|
||||
id={id}
|
||||
/>
|
||||
</Grid>
|
||||
</PopoverTrigger>
|
||||
<PopoverPortal>
|
||||
<PopoverContent>
|
||||
<SketchPicker
|
||||
color={value}
|
||||
onChange={(color: ColorResult) =>
|
||||
onChange(stringifyRGBA(color.rgb))
|
||||
}
|
||||
onChangeComplete={(color: ColorResult) => {
|
||||
onChangeComplete(stringifyRGBA(color.rgb));
|
||||
}}
|
||||
// @todo to remove both when we have preset colors
|
||||
presetColors={[]}
|
||||
className={pickerStyle()}
|
||||
styles={defaultPickerStyles}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</PopoverPortal>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
<PopoverPortal>
|
||||
<PopoverContent>
|
||||
<SketchPicker
|
||||
color={value}
|
||||
onChange={(color: ColorResult) =>
|
||||
onChange(stringifyRGBA(color.rgb))
|
||||
}
|
||||
onChangeComplete={(color: ColorResult) => {
|
||||
onChangeComplete(stringifyRGBA(color.rgb));
|
||||
}}
|
||||
// @todo to remove both when we have preset colors
|
||||
presetColors={[]}
|
||||
className={pickerStyle()}
|
||||
styles={defaultPickerStyles}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</PopoverPortal>
|
||||
</Popover>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ChangeEvent, FocusEvent, KeyboardEvent, useRef } from "react";
|
||||
import {
|
||||
Box,
|
||||
Text,
|
||||
Grid,
|
||||
IconButton,
|
||||
@@ -25,35 +24,6 @@ const commonUnitsSubset = units
|
||||
: 1
|
||||
);
|
||||
|
||||
const gridTemplateStyle = {
|
||||
gridTemplateColumns: "$sizes$6 auto $sizes$6",
|
||||
gridTemplateRows: "repeat(1, 1fr)",
|
||||
};
|
||||
|
||||
const gridLeftStyle = {
|
||||
"& ~ input": {
|
||||
paddingLeft: "calc($sizes$6 + $nudge$3)",
|
||||
},
|
||||
gridArea: "1 / 1 / 2 / 2",
|
||||
};
|
||||
|
||||
const gridRightStyle = {
|
||||
gridArea: "-1 / -1 / -2 / -2",
|
||||
"& ~ input": {
|
||||
paddingRight: "calc($sizes$5 + $nudge$3)",
|
||||
},
|
||||
};
|
||||
|
||||
const iconButtonStyle = {
|
||||
borderRadius: 2,
|
||||
height: "calc($sizes$6 - $nudge$3)",
|
||||
width: "calc($sizes$6 - $nudge$3)",
|
||||
transform: "translate(3px, 3px)",
|
||||
"&:focus": {
|
||||
boxShadow: "none",
|
||||
},
|
||||
};
|
||||
|
||||
const iconButtonActiveStyle = {
|
||||
bc: "$colors$blue4",
|
||||
"&:not(:hover)": {
|
||||
@@ -61,24 +31,6 @@ const iconButtonActiveStyle = {
|
||||
},
|
||||
};
|
||||
|
||||
const iconButtonGridLeftStyle = {
|
||||
...gridLeftStyle,
|
||||
...iconButtonStyle,
|
||||
};
|
||||
|
||||
const iconButtonGridRightStyle = {
|
||||
...gridRightStyle,
|
||||
"& button": { ...iconButtonStyle },
|
||||
};
|
||||
|
||||
const textFieldStyle = {
|
||||
height: "$6",
|
||||
fontWeight: "500",
|
||||
paddingLeft: "calc($sizes$1 + $nudge$3)",
|
||||
gridArea: "1 / 1 / -1 / -1",
|
||||
cursor: "default",
|
||||
};
|
||||
|
||||
export const TextControl = ({
|
||||
currentStyle,
|
||||
inheritedStyle,
|
||||
@@ -102,107 +54,106 @@ export const TextControl = ({
|
||||
const Icon = iconConfigs[styleConfig.property]?.normal;
|
||||
|
||||
return (
|
||||
<Grid columns={2}>
|
||||
<Grid gap={2} css={{ gridTemplateColumns: "$sizes$8 1fr" }}>
|
||||
<PropertyName property={styleConfig.property} label={styleConfig.label} />
|
||||
<Grid css={gridTemplateStyle}>
|
||||
{Icon && (
|
||||
<Tooltip
|
||||
content={styleConfig.label}
|
||||
delayDuration={200}
|
||||
disableHoverableContent={true}
|
||||
>
|
||||
<IconButton
|
||||
onPointerEnter={(event) => {
|
||||
if (value.type !== "unit" || !textFieldRef.current) return;
|
||||
const textFieldNode = textFieldRef.current;
|
||||
numericScrubRef.current =
|
||||
numericScrubRef.current ||
|
||||
numericScrubControl(event.target as HTMLInputElement, {
|
||||
minValue: 0,
|
||||
initialValue: value.value as number,
|
||||
onValueChange: ({ value }) => {
|
||||
textFieldNode.value = String(value);
|
||||
setValue(String(value), { isEphemeral: true });
|
||||
},
|
||||
});
|
||||
}}
|
||||
onPointerLeave={() => {
|
||||
if (value.type !== "unit") return;
|
||||
numericScrubRef.current?.disconnectedCallback();
|
||||
numericScrubRef.current = undefined;
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
setValue((event.target as HTMLInputElement).value);
|
||||
}}
|
||||
css={{
|
||||
...iconButtonGridLeftStyle,
|
||||
...(isCurrentBreakpoint && iconButtonActiveStyle),
|
||||
}}
|
||||
|
||||
<TextField
|
||||
ref={textFieldRef}
|
||||
spellCheck={false}
|
||||
defaultValue={value.value}
|
||||
prefix={
|
||||
Icon && (
|
||||
<Tooltip
|
||||
content={styleConfig.label}
|
||||
delayDuration={200}
|
||||
disableHoverableContent={true}
|
||||
>
|
||||
{Icon && <Icon />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{value.type === "unit" ? (
|
||||
<Units
|
||||
value={value.unit}
|
||||
items={commonUnitsSubset.map((unit) => ({
|
||||
name: unit,
|
||||
label: unit,
|
||||
}))}
|
||||
onChange={(unit) => setValue(value.value + unit)}
|
||||
onHover={(unit) =>
|
||||
setValue(value.value + unit, { isEphemeral: true })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Items
|
||||
value={value.value}
|
||||
items={styleConfig.items}
|
||||
onChange={(item) => setValue(item)}
|
||||
onHover={(item) => setValue(item, { isEphemeral: true })}
|
||||
/>
|
||||
)}
|
||||
<TextField
|
||||
ref={textFieldRef}
|
||||
css={textFieldStyle}
|
||||
spellCheck={false}
|
||||
defaultValue={value.value}
|
||||
onFocus={(event: FocusEvent<HTMLInputElement>) =>
|
||||
event.target.select()
|
||||
<IconButton
|
||||
onPointerEnter={(event) => {
|
||||
if (value.type !== "unit" || !textFieldRef.current) return;
|
||||
const textFieldNode = textFieldRef.current;
|
||||
numericScrubRef.current =
|
||||
numericScrubRef.current ||
|
||||
numericScrubControl(event.target as HTMLInputElement, {
|
||||
minValue: 0,
|
||||
initialValue: value.value as number,
|
||||
onValueChange: ({ value }) => {
|
||||
textFieldNode.value = String(value);
|
||||
setValue(String(value), { isEphemeral: true });
|
||||
},
|
||||
});
|
||||
}}
|
||||
onPointerLeave={() => {
|
||||
if (value.type !== "unit") return;
|
||||
numericScrubRef.current?.disconnectedCallback();
|
||||
numericScrubRef.current = undefined;
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
setValue((event.target as HTMLInputElement).value);
|
||||
}}
|
||||
css={{
|
||||
...(isCurrentBreakpoint && iconButtonActiveStyle),
|
||||
}}
|
||||
>
|
||||
{Icon && <Icon />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
suffix={
|
||||
value.type === "unit" ? (
|
||||
<Units
|
||||
value={value.unit}
|
||||
items={commonUnitsSubset.map((unit) => ({
|
||||
name: unit,
|
||||
label: unit,
|
||||
}))}
|
||||
onChange={(unit) => setValue(value.value + unit)}
|
||||
onHover={(unit) =>
|
||||
setValue(value.value + unit, { isEphemeral: true })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Items
|
||||
value={value.value}
|
||||
items={styleConfig.items}
|
||||
onChange={(item) => setValue(item)}
|
||||
onHover={(item) => setValue(item, { isEphemeral: true })}
|
||||
/>
|
||||
)
|
||||
}
|
||||
onFocus={(event: FocusEvent<HTMLInputElement>) => event.target.select()}
|
||||
onBlur={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
setValue(event.target.value)
|
||||
}
|
||||
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (event.code === "Enter") {
|
||||
setValue(target.value);
|
||||
const number = parseFloat(target.value);
|
||||
if (!isNaN(number)) target.value = String(number);
|
||||
}
|
||||
onBlur={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
setValue(event.target.value)
|
||||
}
|
||||
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (event.code === "Enter") {
|
||||
setValue(target.value);
|
||||
const number = parseFloat(target.value);
|
||||
if (!isNaN(number)) target.value = String(number);
|
||||
}
|
||||
if (value.type !== "unit") return;
|
||||
if (!["ArrowUp", "ArrowDown"].includes(event.code)) return;
|
||||
event.preventDefault();
|
||||
let currentValue = parseFloat(target.value);
|
||||
let currentDelta = 1;
|
||||
if (event.shiftKey) currentDelta = 10;
|
||||
if (event.altKey) currentDelta = 0.1;
|
||||
if (event.code === "ArrowUp")
|
||||
currentValue = currentValue + currentDelta;
|
||||
if (event.code === "ArrowDown")
|
||||
currentValue = currentValue - currentDelta;
|
||||
const currentValueAsString =
|
||||
currentValue % 1
|
||||
? currentValue.toPrecision(
|
||||
Math.abs(currentValue).toString().indexOf(".") + 2
|
||||
)
|
||||
: String(currentValue);
|
||||
target.value = currentValueAsString;
|
||||
setValue(currentValueAsString, { isEphemeral: true });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
if (value.type !== "unit") return;
|
||||
if (!["ArrowUp", "ArrowDown"].includes(event.code)) return;
|
||||
event.preventDefault();
|
||||
let currentValue = parseFloat(target.value);
|
||||
let currentDelta = 1;
|
||||
if (event.shiftKey) currentDelta = 10;
|
||||
if (event.altKey) currentDelta = 0.1;
|
||||
if (event.code === "ArrowUp")
|
||||
currentValue = currentValue + currentDelta;
|
||||
if (event.code === "ArrowDown")
|
||||
currentValue = currentValue - currentDelta;
|
||||
const currentValueAsString =
|
||||
currentValue % 1
|
||||
? currentValue.toPrecision(
|
||||
Math.abs(currentValue).toString().indexOf(".") + 2
|
||||
)
|
||||
: String(currentValue);
|
||||
target.value = currentValueAsString;
|
||||
setValue(currentValueAsString, { isEphemeral: true });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -219,19 +170,17 @@ const Units = ({
|
||||
onHover?: (value: string) => void;
|
||||
}) => {
|
||||
return (
|
||||
<Box css={iconButtonGridRightStyle}>
|
||||
<IconButtonWithMenu
|
||||
icon={
|
||||
<Text css={{ cursor: "default" }}>
|
||||
{value === "number" ? "—" : value}
|
||||
</Text>
|
||||
}
|
||||
items={items}
|
||||
value={String(value)}
|
||||
onChange={onChange}
|
||||
onHover={onHover}
|
||||
/>
|
||||
</Box>
|
||||
<IconButtonWithMenu
|
||||
icon={
|
||||
<Text css={{ cursor: "default" }}>
|
||||
{value === "number" ? "—" : value}
|
||||
</Text>
|
||||
}
|
||||
items={items}
|
||||
value={String(value)}
|
||||
onChange={onChange}
|
||||
onHover={onHover}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -248,14 +197,12 @@ const Items = ({
|
||||
}) => {
|
||||
if (!items?.length) return null;
|
||||
return (
|
||||
<Box css={iconButtonGridRightStyle}>
|
||||
<IconButtonWithMenu
|
||||
icon={<ChevronDownIcon />}
|
||||
items={items}
|
||||
value={String(value)}
|
||||
onChange={onChange}
|
||||
onHover={onHover}
|
||||
/>
|
||||
</Box>
|
||||
<IconButtonWithMenu
|
||||
icon={<ChevronDownIcon />}
|
||||
items={items}
|
||||
value={String(value)}
|
||||
onChange={onChange}
|
||||
onHover={onHover}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,8 @@
|
||||
import { KeyboardEvent, useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { IconButton, TextField } from "@webstudio-is/design-system";
|
||||
import { Cross2Icon, MagnifyingGlassIcon } from "@webstudio-is/icons";
|
||||
import { components } from "@webstudio-is/react-sdk";
|
||||
import type { SelectedInstanceData } from "~/shared/canvas-components";
|
||||
import { Box } from "@webstudio-is/design-system";
|
||||
|
||||
type OnSearch = (search: string) => void;
|
||||
|
||||
@@ -25,55 +24,35 @@ type SearchProps = {
|
||||
|
||||
export const Search = ({ onSearch, selectedInstanceData }: SearchProps) => {
|
||||
const [search, setSearch] = useSearch(onSearch);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
return (
|
||||
<Box
|
||||
as="form"
|
||||
css={{ position: "relative" }}
|
||||
onReset={() => {
|
||||
setSearch("");
|
||||
<TextField
|
||||
type="search"
|
||||
value={search}
|
||||
inputRef={inputRef}
|
||||
prefix={
|
||||
<IconButton aria-label="Search">
|
||||
<MagnifyingGlassIcon />
|
||||
</IconButton>
|
||||
}
|
||||
suffix={
|
||||
search.length > 0 && (
|
||||
<IconButton
|
||||
aria-label="Reset search"
|
||||
onClick={() => {
|
||||
setSearch("");
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
>
|
||||
<Cross2Icon />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
placeholder={components[selectedInstanceData.component].label}
|
||||
onChange={(event) => {
|
||||
const { value } = event.target;
|
||||
setSearch(value.toLowerCase());
|
||||
}}
|
||||
onKeyDown={(event: KeyboardEvent<HTMLFormElement>) => {
|
||||
if (event.key === "Escape") {
|
||||
event.currentTarget.reset();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
value={search}
|
||||
css={{
|
||||
fontSize: "$2",
|
||||
height: "$sizes$6",
|
||||
padding: "$3 calc($2 + $1)",
|
||||
border: "2px solid $colors$slate7",
|
||||
bc: "$colors$slate3",
|
||||
borderRadius: "$2",
|
||||
boxShadow: "none",
|
||||
"&:focus": {
|
||||
bc: "$colors$slate1",
|
||||
borderWidth: 2,
|
||||
borderColor: "$colors$blue10",
|
||||
boxShadow: "none",
|
||||
},
|
||||
}}
|
||||
placeholder={components[selectedInstanceData.component].label}
|
||||
onChange={(event) => {
|
||||
const { value } = event.target;
|
||||
setSearch(value.toLowerCase());
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
type="reset"
|
||||
aria-label="Reset search"
|
||||
css={{
|
||||
color: "$slate9",
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
right: 0,
|
||||
transform: "translate(-25%,-50%)",
|
||||
}}
|
||||
>
|
||||
{search.length === 0 ? <MagnifyingGlassIcon /> : <Cross2Icon />}
|
||||
</IconButton>
|
||||
</Box>
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -55,13 +55,13 @@ export const StylePanel = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box css={{ px: "$3", py: "$1" }}>
|
||||
<Search
|
||||
onSearch={setSearch}
|
||||
selectedInstanceData={selectedInstanceData}
|
||||
/>
|
||||
</Box>
|
||||
<Box css={{ overflow: "auto" }}>
|
||||
<Box css={{ px: "$3", paddingBottom: "$1" }}>
|
||||
<Search
|
||||
onSearch={setSearch}
|
||||
selectedInstanceData={selectedInstanceData}
|
||||
/>
|
||||
</Box>
|
||||
<StyleSettings
|
||||
search={search}
|
||||
selectedInstanceData={selectedInstanceData}
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "^6.5.6",
|
||||
"@storybook/addon-essentials": "^6.5.6",
|
||||
"@storybook/addon-interactions": "^6.5.6",
|
||||
"@storybook/addon-interactions": "^6.5.12",
|
||||
"@storybook/addon-links": "^6.5.6",
|
||||
"@storybook/builder-webpack4": "^6.5.6",
|
||||
"@storybook/jest": "^0.0.10",
|
||||
"@storybook/manager-webpack4": "^6.5.6",
|
||||
"@storybook/react": "^6.5.6",
|
||||
"@storybook/testing-library": "^0.0.11",
|
||||
"@storybook/testing-library": "^0.0.13",
|
||||
"@webstudio-is/jest-config": "*",
|
||||
"lost-pixel": "^2.20.0",
|
||||
"tsup": "^6.1.3",
|
||||
@@ -61,6 +62,8 @@
|
||||
"@radix-ui/react-toggle-group": "^1.0.0",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"@radix-ui/react-use-layout-effect": "^1.0.0",
|
||||
"@react-aria/interactions": "^3.11.0",
|
||||
"@react-aria/utils": "^3.13.3",
|
||||
"@stitches/react": "^1.2.8",
|
||||
"@webstudio-is/icons": "*",
|
||||
"react-hot-toast": "^2.3.0"
|
||||
|
||||
@@ -25,7 +25,7 @@ export const Button = styled("button", {
|
||||
// Custom
|
||||
height: "$5",
|
||||
px: "$2",
|
||||
fontFamily: "$untitled",
|
||||
fontFamily: "$sans",
|
||||
fontSize: "$2",
|
||||
fontWeight: 500,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import { ComponentStory } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Combobox, ComboboxTextField } from "./combobox";
|
||||
import { MagnifyingGlassIcon } from "@webstudio-is/icons";
|
||||
import { useCombobox as useDownshiftCombobox } from "downshift";
|
||||
import React, { useCallback } from "react";
|
||||
import { TextField } from "./text-field";
|
||||
import { Combobox, ComboboxListboxItem, useCombobox } from "./combobox";
|
||||
import { Flex } from "./flex";
|
||||
|
||||
export default {
|
||||
component: Combobox,
|
||||
@@ -9,55 +12,90 @@ export default {
|
||||
|
||||
export const Simple: ComponentStory<typeof Combobox> = () => {
|
||||
const items = [{ label: "Apple" }, { label: "Banana" }, { label: "Orange" }];
|
||||
const [value, setValue] = React.useState(items[0]);
|
||||
const [value, setValue] = React.useState<typeof items[number] | null>(null);
|
||||
return (
|
||||
<Combobox
|
||||
name="fruit"
|
||||
placeholder="Select a fruit"
|
||||
items={items}
|
||||
value={value}
|
||||
onItemSelect={setValue}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomInput: ComponentStory<typeof Combobox> = () => {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple", disabled: true },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Orange", value: "orange" },
|
||||
];
|
||||
const [value, setValue] = React.useState(items[0]);
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
name="fruit"
|
||||
items={items}
|
||||
value={value}
|
||||
onItemSelect={setValue}
|
||||
onItemHighlight={(item) => {
|
||||
action("Highlight")(item);
|
||||
onItemSelect={(value) => {
|
||||
// If the value is cleared, we revert to previous state
|
||||
if (value !== null) {
|
||||
setValue(value);
|
||||
}
|
||||
}}
|
||||
renderTextField={({ inputProps, toggleProps }) => (
|
||||
<ComboboxTextField
|
||||
toggleProps={toggleProps}
|
||||
inputProps={{
|
||||
...inputProps,
|
||||
onKeyDown: (event) => {
|
||||
inputProps.onKeyDown?.(event);
|
||||
switch (event.key) {
|
||||
case "Enter": {
|
||||
action("Enter")(inputProps.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onBlur: (event) => {
|
||||
inputProps.onBlur?.(event);
|
||||
action("Blur")(inputProps.value);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
itemToString={(item) => item?.label ?? ""}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Complex: ComponentStory<typeof Combobox> = () => {
|
||||
const [value, setValue] = React.useState<string | null>(null);
|
||||
|
||||
const stateReducer = useCallback((state, actionAndChanges) => {
|
||||
const { type, changes } = actionAndChanges;
|
||||
switch (type) {
|
||||
// on item selection.
|
||||
case useDownshiftCombobox.stateChangeTypes.ItemClick:
|
||||
case useDownshiftCombobox.stateChangeTypes.InputKeyDownEnter:
|
||||
case useDownshiftCombobox.stateChangeTypes.InputBlur:
|
||||
case useDownshiftCombobox.stateChangeTypes
|
||||
.ControlledPropUpdatedSelectedItem:
|
||||
return {
|
||||
...changes,
|
||||
// if we have a selected item.
|
||||
...(changes.selectedItem && {
|
||||
// we will set the input value to "" (empty string).
|
||||
inputValue: "",
|
||||
}),
|
||||
};
|
||||
|
||||
// Remove "reset" action
|
||||
case useDownshiftCombobox.stateChangeTypes.InputKeyDownEscape: {
|
||||
return {
|
||||
...state,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return changes; // otherwise business as usual.
|
||||
}
|
||||
}, []);
|
||||
|
||||
const { items, getComboboxProps, getMenuProps, getItemProps, getInputProps } =
|
||||
useCombobox({
|
||||
items: ["Apple", "Banana", "Orange"],
|
||||
value,
|
||||
itemToString: (item) => item ?? "",
|
||||
stateReducer,
|
||||
onItemSelect: (value) => {
|
||||
setValue(value);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Flex {...getComboboxProps()} css={{ flexDirection: "column", gap: "$3" }}>
|
||||
<TextField
|
||||
type="search"
|
||||
prefix={<MagnifyingGlassIcon />}
|
||||
{...getInputProps({})}
|
||||
/>
|
||||
<fieldset>
|
||||
<legend>Choose an item</legend>
|
||||
<Flex {...getMenuProps()} css={{ flexDirection: "column" }}>
|
||||
{items.map((item, index) => {
|
||||
return (
|
||||
<ComboboxListboxItem
|
||||
key={index}
|
||||
{...getItemProps({ item, index })}
|
||||
>
|
||||
{item}
|
||||
</ComboboxListboxItem>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
</fieldset>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
@@ -1,13 +1,19 @@
|
||||
import {
|
||||
useState,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useCallback,
|
||||
type ComponentProps,
|
||||
type ForwardRefRenderFunction,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { CheckIcon, ChevronDownIcon } from "@webstudio-is/icons";
|
||||
import { Popper, PopperContent, PopperAnchor } from "@radix-ui/react-popper";
|
||||
import { useCombobox, type UseComboboxGetItemPropsOptions } from "downshift";
|
||||
import {
|
||||
DownshiftState,
|
||||
UseComboboxStateChangeOptions,
|
||||
useCombobox as useDownshiftCombobox,
|
||||
} from "downshift";
|
||||
import { matchSorter } from "match-sorter";
|
||||
import { styled } from "../stitches.config";
|
||||
import { IconButton } from "./icon-button";
|
||||
@@ -17,41 +23,6 @@ import { TextField } from "./text-field";
|
||||
import { Box } from "./box";
|
||||
import { Grid } from "./grid";
|
||||
|
||||
type Label = string;
|
||||
|
||||
type BaseItem = { label: Label; disabled?: boolean } | Label;
|
||||
|
||||
type ComboboxTextFieldProps<Item> = {
|
||||
inputProps: ComponentProps<typeof TextField>;
|
||||
toggleProps: ComponentProps<typeof IconButton>;
|
||||
highlightedItem?: Item;
|
||||
};
|
||||
|
||||
const ComboboxTextFieldBase: ForwardRefRenderFunction<
|
||||
HTMLDivElement,
|
||||
ComboboxTextFieldProps<BaseItem>
|
||||
> = ({ inputProps, toggleProps }, ref) => {
|
||||
return (
|
||||
<Box ref={ref} css={{ position: "relative" }}>
|
||||
<TextField css={{ paddingRight: "$4" }} {...inputProps} />
|
||||
<IconButton
|
||||
{...toggleProps}
|
||||
css={{
|
||||
position: "absolute",
|
||||
transform: "translateX(-100%)",
|
||||
width: "$4",
|
||||
}}
|
||||
>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const ComboboxTextField = forwardRef(ComboboxTextFieldBase);
|
||||
|
||||
ComboboxTextField.displayName = "ComboboxTextField";
|
||||
|
||||
const Listbox = styled("ul", panelStyles, {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
@@ -66,115 +37,110 @@ const ListboxItem = styled("li", itemCss, {
|
||||
margin: 0,
|
||||
});
|
||||
|
||||
type ListProps<Item> = {
|
||||
containerProps: ComponentProps<typeof Listbox>;
|
||||
items: Array<Item>;
|
||||
getItemProps: (
|
||||
options: UseComboboxGetItemPropsOptions<Item>
|
||||
) => ComponentProps<typeof ListboxItem>;
|
||||
highlightedIndex: number;
|
||||
selectedItem: Item | null;
|
||||
itemToString: (item: Item | null) => string;
|
||||
};
|
||||
|
||||
export const List = <Item extends BaseItem>({
|
||||
containerProps,
|
||||
items,
|
||||
getItemProps,
|
||||
highlightedIndex,
|
||||
selectedItem,
|
||||
itemToString,
|
||||
}: ListProps<Item>) => {
|
||||
export const ListboxItemBase: ForwardRefRenderFunction<
|
||||
HTMLLIElement,
|
||||
ComponentProps<typeof ListboxItem> & {
|
||||
disabled?: boolean;
|
||||
selected?: boolean;
|
||||
highlighted?: boolean;
|
||||
}
|
||||
> = (props, ref) => {
|
||||
const { disabled, selected, highlighted, children, ...rest } = props;
|
||||
return (
|
||||
<Listbox {...containerProps}>
|
||||
{items.map((item, index) => {
|
||||
const itemProps: Record<string, unknown> = getItemProps({
|
||||
item,
|
||||
index,
|
||||
key: index,
|
||||
...(typeof item === "object" && item.disabled
|
||||
? { "data-disabled": true, disabled: true }
|
||||
: {}),
|
||||
...(highlightedIndex === index ? { "data-found": true } : {}),
|
||||
});
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<ListboxItem {...itemProps}>
|
||||
<Grid align="center" css={{ gridTemplateColumns: "$4 1fr" }}>
|
||||
{selectedItem === item && <CheckIcon />}
|
||||
<Box css={{ gridColumn: 2 }}>{itemToString(item)}</Box>
|
||||
</Grid>
|
||||
</ListboxItem>
|
||||
);
|
||||
})}
|
||||
</Listbox>
|
||||
<ListboxItem
|
||||
ref={ref}
|
||||
{...(disabled ? { "aria-disabled": true, disabled: true } : {})}
|
||||
{...(selected ? { "aria-current": true } : {})}
|
||||
{...rest}
|
||||
>
|
||||
<Grid align="center" css={{ gridTemplateColumns: "$4 1fr" }}>
|
||||
{selected && <CheckIcon />}
|
||||
<Box css={{ gridColumn: 2 }}>{children}</Box>
|
||||
</Grid>
|
||||
</ListboxItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const ComboboxListbox = Listbox;
|
||||
|
||||
export const ComboboxListboxItem = forwardRef(ListboxItemBase);
|
||||
|
||||
export const ComboboxPopper = Popper;
|
||||
|
||||
export const ComboboxPopperContent = PopperContent;
|
||||
|
||||
type ComboboxProps<Item> = {
|
||||
name: string;
|
||||
label?: string;
|
||||
export const ComboboxPopperAnchor = PopperAnchor;
|
||||
|
||||
const useFilter = <Item,>({
|
||||
items,
|
||||
itemToString,
|
||||
}: {
|
||||
items: Array<Item>;
|
||||
value?: Item;
|
||||
onItemSelect?: (value: Item) => void;
|
||||
onItemHighlight?: (value?: Item) => void;
|
||||
itemToString?: (item: Item | null) => string;
|
||||
renderTextField?: (
|
||||
props: ComponentProps<typeof ComboboxTextField>
|
||||
) => JSX.Element;
|
||||
renderList?: (props: ListProps<Item>) => JSX.Element;
|
||||
renderPopperContent?: (
|
||||
props: ComponentProps<typeof ComboboxPopperContent>
|
||||
) => JSX.Element;
|
||||
itemToString: (item: Item | null) => string;
|
||||
}) => {
|
||||
const [filteredItems, setFilteredItems] = useState<Array<Item>>(items);
|
||||
const cachedItems = useRef(items);
|
||||
|
||||
useEffect(() => {
|
||||
cachedItems.current = items;
|
||||
}, [items]);
|
||||
|
||||
const filter = useCallback(
|
||||
(search?: string) => {
|
||||
const foundItems: Array<Item> = matchSorter(items, search ?? "", {
|
||||
keys: [(item) => itemToString(item)],
|
||||
});
|
||||
setFilteredItems(foundItems);
|
||||
},
|
||||
[itemToString, items]
|
||||
);
|
||||
|
||||
const resetFilter = useCallback(() => {
|
||||
setFilteredItems(cachedItems.current);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
filteredItems,
|
||||
filter,
|
||||
resetFilter,
|
||||
};
|
||||
};
|
||||
|
||||
export const Combobox = <Item extends BaseItem>({
|
||||
type useComboboxProps<Item> = {
|
||||
items: Array<Item>;
|
||||
itemToString: (item: Item | null) => string;
|
||||
value: Item | null; // This is to prevent: "downshift: A component has changed the uncontrolled prop "selectedItem" to be controlled."
|
||||
onItemSelect?: (value: Item | null) => void;
|
||||
onItemHighlight?: (value: Item | null) => void;
|
||||
stateReducer?: (
|
||||
state: DownshiftState<Item>,
|
||||
changes: UseComboboxStateChangeOptions<Item>
|
||||
) => Partial<UseComboboxStateChangeOptions<Item>>;
|
||||
};
|
||||
|
||||
export const useCombobox = <Item,>({
|
||||
items,
|
||||
value,
|
||||
name,
|
||||
itemToString = (item) =>
|
||||
typeof item === "object" && item !== null && "label" in item
|
||||
? item.label
|
||||
: item ?? "",
|
||||
itemToString,
|
||||
onItemSelect,
|
||||
onItemHighlight,
|
||||
renderTextField = (props) => <ComboboxTextField {...props} />,
|
||||
// IMPORTANT! Without Item passed to list <List<Item> typescript is 10x slower!
|
||||
renderList = (props) => <List<Item> {...props} />,
|
||||
renderPopperContent = (props) => <ComboboxPopperContent {...props} />,
|
||||
}: ComboboxProps<Item>) => {
|
||||
const [foundItems, setFoundItems] = useState(items);
|
||||
const {
|
||||
isOpen,
|
||||
getToggleButtonProps,
|
||||
// getLabelProps,
|
||||
getMenuProps,
|
||||
getInputProps,
|
||||
getComboboxProps,
|
||||
highlightedIndex,
|
||||
getItemProps,
|
||||
selectedItem,
|
||||
} = useCombobox({
|
||||
onInputValueChange({ inputValue }) {
|
||||
if (inputValue) {
|
||||
const options =
|
||||
typeof items[0] === "object" && "label" in items[0]
|
||||
? { keys: ["label"] }
|
||||
: undefined;
|
||||
const foundItems = matchSorter(items, inputValue, options);
|
||||
setFoundItems(foundItems);
|
||||
}
|
||||
},
|
||||
items: foundItems,
|
||||
selectedItem: value,
|
||||
stateReducer = (state, { changes }) => changes,
|
||||
}: useComboboxProps<Item>) => {
|
||||
const { filteredItems, filter, resetFilter } = useFilter<Item>({
|
||||
items,
|
||||
itemToString,
|
||||
});
|
||||
|
||||
const downshiftProps = useDownshiftCombobox({
|
||||
items: filteredItems,
|
||||
selectedItem: value, // Prevent downshift warning about switching controlled mode
|
||||
stateReducer,
|
||||
itemToString,
|
||||
onInputValueChange({ inputValue }) {
|
||||
filter(inputValue);
|
||||
},
|
||||
onSelectedItemChange({ selectedItem }) {
|
||||
if (selectedItem) {
|
||||
onItemSelect?.(selectedItem);
|
||||
}
|
||||
onItemSelect?.(selectedItem ?? null);
|
||||
},
|
||||
onHighlightedIndexChange({ highlightedIndex }) {
|
||||
if (highlightedIndex !== undefined) {
|
||||
@@ -183,35 +149,97 @@ export const Combobox = <Item extends BaseItem>({
|
||||
},
|
||||
});
|
||||
|
||||
const { isOpen, getItemProps, highlightedIndex, selectedItem } =
|
||||
downshiftProps;
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen === false) {
|
||||
setFoundItems(items);
|
||||
resetFilter();
|
||||
}
|
||||
}, [isOpen, items]);
|
||||
}, [isOpen, resetFilter]);
|
||||
|
||||
const inputProps: Record<string, unknown> = getInputProps({ name });
|
||||
const toggleProps: Record<string, unknown> = getToggleButtonProps();
|
||||
const comboboxProps: Record<string, unknown> = getComboboxProps();
|
||||
const menuProps: Record<string, unknown> = getMenuProps();
|
||||
const highlightedItem = foundItems[highlightedIndex];
|
||||
const enhancedGetItemProps = useCallback(
|
||||
(options) => {
|
||||
return getItemProps({
|
||||
highlighted: highlightedIndex === options.index,
|
||||
// We need to either deep compare objects here or use itemToString to get primitive types
|
||||
selected: itemToString(selectedItem) === itemToString(options.item),
|
||||
key: options.id,
|
||||
...options,
|
||||
});
|
||||
},
|
||||
[getItemProps, highlightedIndex, itemToString, selectedItem]
|
||||
);
|
||||
|
||||
return {
|
||||
...downshiftProps,
|
||||
items: filteredItems,
|
||||
getItemProps: enhancedGetItemProps,
|
||||
};
|
||||
};
|
||||
|
||||
type ComboboxProps<Item> = useComboboxProps<Item> & {
|
||||
name: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
export const Combobox = <Item,>({
|
||||
items,
|
||||
value = null,
|
||||
name,
|
||||
placeholder,
|
||||
itemToString,
|
||||
onItemSelect,
|
||||
onItemHighlight,
|
||||
}: ComboboxProps<Item>) => {
|
||||
const {
|
||||
items: foundItems,
|
||||
getInputProps,
|
||||
getComboboxProps,
|
||||
getToggleButtonProps,
|
||||
getMenuProps,
|
||||
getItemProps,
|
||||
isOpen,
|
||||
} = useCombobox({
|
||||
items,
|
||||
value,
|
||||
itemToString,
|
||||
onItemSelect,
|
||||
onItemHighlight,
|
||||
});
|
||||
return (
|
||||
<Popper>
|
||||
<Box {...comboboxProps}>
|
||||
<PopperAnchor asChild>
|
||||
{renderTextField({ inputProps, toggleProps, highlightedItem })}
|
||||
<Box {...getComboboxProps()}>
|
||||
<PopperAnchor>
|
||||
<TextField
|
||||
{...getInputProps({
|
||||
name,
|
||||
placeholder,
|
||||
})}
|
||||
suffix={
|
||||
<IconButton {...getToggleButtonProps()}>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</PopperAnchor>
|
||||
{renderPopperContent({
|
||||
style: { zIndex: 1 },
|
||||
children: renderList({
|
||||
containerProps: menuProps,
|
||||
items: isOpen ? foundItems : [],
|
||||
getItemProps,
|
||||
highlightedIndex,
|
||||
selectedItem,
|
||||
itemToString,
|
||||
}),
|
||||
})}
|
||||
<PopperContent>
|
||||
<Listbox {...getMenuProps()}>
|
||||
{isOpen &&
|
||||
foundItems.map((item, index) => {
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<ComboboxListboxItem
|
||||
key={index}
|
||||
{...getItemProps({ item, index })}
|
||||
>
|
||||
{itemToString(item)}
|
||||
</ComboboxListboxItem>
|
||||
);
|
||||
})}
|
||||
</Listbox>
|
||||
</PopperContent>
|
||||
</Box>
|
||||
</Popper>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ export const baseItemCss = css({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
fontFamily: "$untitled",
|
||||
fontFamily: "$sans",
|
||||
fontSize: "$1",
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
lineHeight: "1",
|
||||
@@ -24,12 +24,12 @@ export const baseItemCss = css({
|
||||
export const itemCss = css(baseItemCss, {
|
||||
position: "relative",
|
||||
color: "$hiContrast",
|
||||
"&:focus, &[data-found]": {
|
||||
"&:focus, &[data-found], &[aria-selected=true]": {
|
||||
outline: "none",
|
||||
backgroundColor: "$blue9",
|
||||
color: "white",
|
||||
},
|
||||
"&[data-disabled]": {
|
||||
"&[data-disabled], &[aria-disabled]": {
|
||||
color: "$slate9",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
import { expect } from "@storybook/jest";
|
||||
import { userEvent, waitFor, within } from "@storybook/testing-library";
|
||||
import React from "react";
|
||||
import { ComponentStory } from "@storybook/react";
|
||||
import { RowGapIcon, ChevronDownIcon } from "@webstudio-is/icons";
|
||||
import { Button } from "./button";
|
||||
import { Flex } from "./flex";
|
||||
import { IconButton } from "./icon-button";
|
||||
import { TextField } from "./text-field";
|
||||
import { Box } from "./box";
|
||||
import { Grid } from "./grid";
|
||||
import { Text } from "./text";
|
||||
|
||||
export default {
|
||||
component: TextField,
|
||||
argTypes: {
|
||||
onFocus: { action: true },
|
||||
onBlur: { action: true },
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: ComponentStory<typeof TextField> = () => {
|
||||
return <TextField />;
|
||||
};
|
||||
|
||||
export const NativeProps: ComponentStory<typeof TextField> = () => {
|
||||
return (
|
||||
<Flex direction="column" gap={3}>
|
||||
<TextField placeholder="This is a placeholder" />
|
||||
<TextField disabled placeholder="This is a disabled placeholder" />
|
||||
<TextField type="number" defaultValue={25} />
|
||||
<TextField type="search" placeholder="This is a search input" />
|
||||
<TextField readOnly value="Read-only" />
|
||||
<TextField disabled value="Disabled" />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const Variants: ComponentStory<typeof TextField> = () => {
|
||||
return (
|
||||
<Flex direction="column" gap={3}>
|
||||
<TextField />
|
||||
<TextField variant="ghost" />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const State: ComponentStory<typeof TextField> = () => {
|
||||
return (
|
||||
<Flex direction="column" gap={3}>
|
||||
<TextField />
|
||||
<TextField state="invalid" />
|
||||
<TextField state="valid" />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const PrefixSuffix: ComponentStory<typeof TextField> = () => {
|
||||
return (
|
||||
<Flex direction="column" gap={3}>
|
||||
<TextField
|
||||
prefix={<RowGapIcon />}
|
||||
suffix={
|
||||
<IconButton>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
state="invalid"
|
||||
prefix={<RowGapIcon />}
|
||||
suffix={
|
||||
<IconButton>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
disabled
|
||||
prefix={<RowGapIcon />}
|
||||
suffix={
|
||||
<IconButton>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const Layout: ComponentStory<typeof TextField> = () => {
|
||||
return (
|
||||
<>
|
||||
<Flex direction="row" gap={2} css={{ justifyContent: "space-between" }}>
|
||||
<TextField
|
||||
value="Long content comes here and it doesn't wrap"
|
||||
prefix={<RowGapIcon />}
|
||||
suffix={
|
||||
<IconButton>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
css={{
|
||||
flexGrow: 1,
|
||||
maxWidth: "25%",
|
||||
}}
|
||||
/>
|
||||
<Box css={{ background: "$muted" }}>Content</Box>
|
||||
<TextField
|
||||
state="invalid"
|
||||
value="Long content comes here and it doesn't wrap"
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Grid
|
||||
gap={2}
|
||||
css={{
|
||||
gridTemplateColumns: "100px 1fr",
|
||||
width: 250,
|
||||
border: "1px solid",
|
||||
}}
|
||||
>
|
||||
<Box css={{ background: "$muted" }}>
|
||||
<Text as="label" htmlFor="field">
|
||||
This is a label
|
||||
</Text>
|
||||
</Box>
|
||||
<Box css={{ background: "$muted" }}>
|
||||
<TextField
|
||||
id="field"
|
||||
value="Long content comes here and it doesn't wrap"
|
||||
prefix={<RowGapIcon />}
|
||||
/>
|
||||
</Box>
|
||||
<Box css={{ background: "$muted" }}>
|
||||
<Text as="label" htmlFor="field2">
|
||||
This is a label
|
||||
</Text>
|
||||
</Box>
|
||||
<TextField
|
||||
id="field2"
|
||||
value="Long content comes here and it doesn't wrap"
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Interactive: ComponentStory<typeof TextField> = () => {
|
||||
const [value, setValue] = React.useState("");
|
||||
const wrapperRef = React.useRef<HTMLDivElement>(null);
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap={3}>
|
||||
<TextField ref={wrapperRef} inputRef={inputRef} value={value} readOnly />
|
||||
<Button
|
||||
onClick={() => {
|
||||
// eslint-disable-next-line no-console
|
||||
setValue(JSON.stringify(wrapperRef.current?.getBoundingClientRect()));
|
||||
}}
|
||||
>
|
||||
Measure TextField
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
>
|
||||
Focus TextField
|
||||
</Button>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const FocusEvents: ComponentStory<typeof TextField> = (args) => {
|
||||
return (
|
||||
<label>
|
||||
Focus and blur:
|
||||
<TextField name="focus" suffix={<Button>test</Button>} {...args} />
|
||||
</label>
|
||||
);
|
||||
};
|
||||
FocusEvents.play = async ({ args, canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const el = canvas.getByLabelText("Focus and blur:");
|
||||
|
||||
await userEvent.tab();
|
||||
await waitFor(() => expect(el).toHaveFocus());
|
||||
await userEvent.tab();
|
||||
await waitFor(() => expect(args.onBlur).not.toHaveBeenCalled());
|
||||
await userEvent.tab();
|
||||
await waitFor(() => expect(args.onBlur).toHaveBeenCalled());
|
||||
|
||||
await waitFor(() => expect(args.onFocus).toHaveBeenCalledTimes(1));
|
||||
await waitFor(() => expect(args.onBlur).toHaveBeenCalledTimes(1));
|
||||
};
|
||||
|
||||
export const ClickCapture: ComponentStory<typeof TextField> = (args) => {
|
||||
return (
|
||||
<TextField
|
||||
name="click"
|
||||
placeholder="Click on the icon to focus input"
|
||||
prefix={
|
||||
<Flex title="icon">
|
||||
<RowGapIcon />
|
||||
</Flex>
|
||||
}
|
||||
suffix={
|
||||
<IconButton>
|
||||
<ChevronDownIcon />
|
||||
</IconButton>
|
||||
}
|
||||
{...args}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ClickCapture.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const input = canvas.getByPlaceholderText("Click on the icon to focus input");
|
||||
await userEvent.click(canvas.getByTitle("icon"));
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
await userEvent.click(canvas.getByRole("button"));
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
};
|
||||
@@ -1,64 +1,39 @@
|
||||
import { mergeRefs } from "@react-aria/utils";
|
||||
import React from "react";
|
||||
import { useFocusWithin } from "@react-aria/interactions";
|
||||
import { styled } from "../stitches.config";
|
||||
import { Flex } from "./flex";
|
||||
|
||||
export const TextField = styled("input", {
|
||||
const InputBase = styled("input", {
|
||||
// Reset
|
||||
appearance: "none",
|
||||
borderWidth: "0",
|
||||
backgroundColor: "transparent",
|
||||
boxSizing: "border-box",
|
||||
fontFamily: "inherit",
|
||||
fontSize: "inherit",
|
||||
color: "inherit",
|
||||
margin: "0",
|
||||
outline: "none",
|
||||
padding: "0",
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
minWidth: 0,
|
||||
width: "100%",
|
||||
textOverflow: "ellipsis",
|
||||
outline: "none",
|
||||
WebkitTapHighlightColor: "rgba(0,0,0,0)",
|
||||
"&::before": {
|
||||
boxSizing: "border-box",
|
||||
},
|
||||
"&::after": {
|
||||
boxSizing: "border-box",
|
||||
|
||||
// Focus should start on the input element then move to prefix and suffix elements.
|
||||
// DOM order reflects focus path and visually we use order to put them into the correct visual order.
|
||||
order: 1,
|
||||
|
||||
'&[type="search"]': {
|
||||
"&::-webkit-search-decoration, &::-webkit-search-cancel-button, &::-webkit-search-results-button, &::-webkit-search-results-decoration":
|
||||
{
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
|
||||
// Custom
|
||||
backgroundColor: "$loContrast",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate7",
|
||||
color: "$hiContrast",
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
"&:-webkit-autofill": {
|
||||
boxShadow: "inset 0 0 0 1px $colors$blue6, inset 0 0 0 100px $colors$blue3",
|
||||
},
|
||||
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontFamily: "$untitled",
|
||||
color: "$hiContrast",
|
||||
},
|
||||
|
||||
"&:focus": {
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue8",
|
||||
"&:-webkit-autofill": {
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue8, inset 0 0 0 100px $colors$blue3",
|
||||
},
|
||||
},
|
||||
"&::placeholder": {
|
||||
color: "$slate9",
|
||||
},
|
||||
"&:disabled": {
|
||||
pointerEvents: "none",
|
||||
backgroundColor: "$slate2",
|
||||
color: "$slate8",
|
||||
cursor: "not-allowed",
|
||||
"&::placeholder": {
|
||||
color: "$slate7",
|
||||
},
|
||||
},
|
||||
"&:read-only": {
|
||||
backgroundColor: "$slate2",
|
||||
"&:focus": {
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$slate7",
|
||||
},
|
||||
},
|
||||
'&[type="number"]': {
|
||||
"&::-webkit-outer-spin-button, &::-webkit-inner-spin-button": {
|
||||
WebkitAppearance: "none",
|
||||
@@ -68,29 +43,64 @@ export const TextField = styled("input", {
|
||||
},
|
||||
},
|
||||
|
||||
variants: {
|
||||
size: {
|
||||
"1": {
|
||||
borderRadius: "$1",
|
||||
height: "$5",
|
||||
fontSize: "$1",
|
||||
px: "$1",
|
||||
lineHeight: "$sizes$5",
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontSize: "$1",
|
||||
},
|
||||
},
|
||||
"2": {
|
||||
borderRadius: "$2",
|
||||
height: "$6",
|
||||
fontSize: "$3",
|
||||
px: "$2",
|
||||
lineHeight: "$sizes$6",
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontSize: "$3",
|
||||
},
|
||||
},
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontFamily: "$sans",
|
||||
color: "$hiContrast",
|
||||
},
|
||||
|
||||
"&::placeholder": {
|
||||
color: "$slate9",
|
||||
},
|
||||
|
||||
"&:disabled": {
|
||||
color: "$slate8",
|
||||
cursor: "not-allowed",
|
||||
"&::placeholder": {
|
||||
color: "$slate7",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const TextFieldBase = styled("div", {
|
||||
// Custom
|
||||
display: "flex",
|
||||
gap: "$1",
|
||||
backgroundColor: "$loContrast",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate7",
|
||||
color: "$hiContrast",
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
px: "$2",
|
||||
borderRadius: "$1",
|
||||
fontFamily: "$sans",
|
||||
fontSize: "$1",
|
||||
height: 28, // @todo waiting for the sizing scale
|
||||
lineHeight: 1,
|
||||
"&[data-has-prefix]": {
|
||||
paddingLeft: 2,
|
||||
},
|
||||
|
||||
"&[data-has-suffix]": {
|
||||
paddingRight: 2,
|
||||
},
|
||||
|
||||
"&:focus-within": {
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$blue10, 0px 0px 0px 1px $colors$blue10",
|
||||
},
|
||||
|
||||
"&[aria-disabled=true]": {
|
||||
pointerEvents: "none",
|
||||
backgroundColor: "$slate2",
|
||||
},
|
||||
"&:has(input:read-only)": {
|
||||
backgroundColor: "$slate2",
|
||||
"&:focus": {
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$slate7",
|
||||
},
|
||||
},
|
||||
|
||||
variants: {
|
||||
variant: {
|
||||
ghost: {
|
||||
boxShadow: "none",
|
||||
@@ -103,7 +113,7 @@ export const TextField = styled("input", {
|
||||
"&:focus": {
|
||||
backgroundColor: "$loContrast",
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue8",
|
||||
"inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue10",
|
||||
},
|
||||
"&:disabled": {
|
||||
backgroundColor: "transparent",
|
||||
@@ -129,19 +139,97 @@ export const TextField = styled("input", {
|
||||
},
|
||||
},
|
||||
},
|
||||
cursor: {
|
||||
default: {
|
||||
cursor: "default",
|
||||
"&:focus": {
|
||||
cursor: "text",
|
||||
},
|
||||
},
|
||||
text: {
|
||||
cursor: "text",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "1",
|
||||
},
|
||||
});
|
||||
|
||||
type TextFieldProps = Pick<
|
||||
React.ComponentProps<typeof TextFieldBase>,
|
||||
"variant" | "state" | "css"
|
||||
> &
|
||||
Omit<React.ComponentProps<"input">, "prefix" | "children"> & {
|
||||
inputRef?: React.Ref<HTMLInputElement>;
|
||||
prefix?: React.ReactNode;
|
||||
suffix?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const TextField = React.forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
(props, forwardedRef) => {
|
||||
const {
|
||||
prefix,
|
||||
suffix,
|
||||
css,
|
||||
disabled,
|
||||
inputRef,
|
||||
state,
|
||||
variant,
|
||||
onFocus,
|
||||
onBlur,
|
||||
...textFieldProps
|
||||
} = props;
|
||||
|
||||
const internalInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const focusInnerInput = React.useCallback(() => {
|
||||
internalInputRef.current?.focus();
|
||||
}, [internalInputRef]);
|
||||
|
||||
const { focusWithinProps } = useFocusWithin({
|
||||
isDisabled: disabled,
|
||||
onFocusWithin: (event) => {
|
||||
// @ts-expect-error Type mismatch from react-aria
|
||||
onFocus?.(event);
|
||||
},
|
||||
onBlurWithin: (event) => {
|
||||
// @ts-expect-error Type mismatch from react-aria
|
||||
onBlur?.(event);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<TextFieldBase
|
||||
aria-disabled={disabled}
|
||||
ref={forwardedRef}
|
||||
state={state}
|
||||
variant={variant}
|
||||
css={css}
|
||||
{...focusWithinProps}
|
||||
{...(prefix && { "data-has-prefix": true })}
|
||||
{...(suffix && { "data-has-suffix": true })}
|
||||
onClickCapture={focusInnerInput}
|
||||
>
|
||||
{/* We want input to be the first element in DOM so it receives the focus first */}
|
||||
<InputBase
|
||||
disabled={disabled}
|
||||
{...textFieldProps}
|
||||
ref={mergeRefs(internalInputRef, inputRef ?? null)}
|
||||
/>
|
||||
|
||||
{prefix && (
|
||||
<Flex
|
||||
css={{
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
order: 0,
|
||||
}}
|
||||
>
|
||||
{prefix}
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{suffix && (
|
||||
<Flex
|
||||
css={{
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
order: 2,
|
||||
}}
|
||||
>
|
||||
{suffix}
|
||||
</Flex>
|
||||
)}
|
||||
</TextFieldBase>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
TextField.displayName = "TextField";
|
||||
@@ -2,6 +2,11 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@adobe/css-tools@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd"
|
||||
integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==
|
||||
|
||||
"@ampproject/remapping@^2.1.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
|
||||
@@ -1979,7 +1984,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
|
||||
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
|
||||
@@ -2336,6 +2341,13 @@
|
||||
"@types/node" "*"
|
||||
jest-mock "^27.5.1"
|
||||
|
||||
"@jest/expect-utils@^29.1.2":
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.1.2.tgz#66dbb514d38f7d21456bc774419c9ae5cca3f88d"
|
||||
integrity sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==
|
||||
dependencies:
|
||||
jest-get-type "^29.0.0"
|
||||
|
||||
"@jest/fake-timers@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74"
|
||||
@@ -2388,6 +2400,13 @@
|
||||
terminal-link "^2.0.0"
|
||||
v8-to-istanbul "^8.1.0"
|
||||
|
||||
"@jest/schemas@^29.0.0":
|
||||
version "29.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a"
|
||||
integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==
|
||||
dependencies:
|
||||
"@sinclair/typebox" "^0.24.1"
|
||||
|
||||
"@jest/source-map@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf"
|
||||
@@ -2481,6 +2500,18 @@
|
||||
"@types/yargs" "^16.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@jest/types@^29.1.2":
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.1.2.tgz#7442d32b16bcd7592d9614173078b8c334ec730a"
|
||||
integrity sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==
|
||||
dependencies:
|
||||
"@jest/schemas" "^29.0.0"
|
||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||
"@types/istanbul-reports" "^3.0.0"
|
||||
"@types/node" "*"
|
||||
"@types/yargs" "^17.0.8"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@jridgewell/gen-mapping@^0.1.0":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
|
||||
@@ -3401,6 +3432,45 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@react-aria/interactions@^3.11.0":
|
||||
version "3.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.11.0.tgz#aa6118af58ff443670152393edab97e403d6d359"
|
||||
integrity sha512-ZjK4m8u6FlV7Q9/1h9P2Ii6j/NwKR3BmTeGeBQssS2i4dV2pJeOPePnGzVQQGG8FzGQ+TcNRvZPXKaU4AlnBjw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.6.2"
|
||||
"@react-aria/utils" "^3.13.3"
|
||||
"@react-types/shared" "^3.14.1"
|
||||
|
||||
"@react-aria/ssr@^3.3.0":
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.3.0.tgz#25e81daf0c7a270a4a891159d8d984578e4512d8"
|
||||
integrity sha512-yNqUDuOVZIUGP81R87BJVi/ZUZp/nYOBXbPsRe7oltJOfErQZD+UezMpw4vM2KRz18cURffvmC8tJ6JTeyDtaQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.6.2"
|
||||
|
||||
"@react-aria/utils@^3.13.3":
|
||||
version "3.13.3"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.13.3.tgz#1b27912e4630f0db6a7b39eb1013f6c4f710075c"
|
||||
integrity sha512-wqjGNFX4TrXriUU1gvCaoqRhuckdoYogUWN0iyQRkTmzvb7H/NNzQzHou5ggWAdts/NzJUInwKarBWM9hCZZbg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.6.2"
|
||||
"@react-aria/ssr" "^3.3.0"
|
||||
"@react-stately/utils" "^3.5.1"
|
||||
"@react-types/shared" "^3.14.1"
|
||||
clsx "^1.1.1"
|
||||
|
||||
"@react-stately/utils@^3.5.1":
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.5.1.tgz#502de762e5d33e892347c5f58053674e06d3bc92"
|
||||
integrity sha512-INeQ5Er2Jm+db8Py4upKBtgfzp3UYgwXYmbU/XJn49Xw27ktuimH9e37qP3bgHaReb5L3g8IrGs38tJUpnGPHA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.6.2"
|
||||
|
||||
"@react-types/shared@^3.14.1":
|
||||
version "3.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.14.1.tgz#8fe25f729426e8043054e442eb5392364200e028"
|
||||
integrity sha512-yPPgVRWWanXqbdxFTgJmVwx0JlcnEK3dqkKDIbVk6mxAHvEESI9+oDnHvO8IMHqF+GbrTCzVtAs0zwhYI/uHJA==
|
||||
|
||||
"@remix-run/dev@^1.6.4":
|
||||
version "1.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/dev/-/dev-1.6.4.tgz#7a2a7fc24e66434c5cf64d6e79a62d35d09b73de"
|
||||
@@ -3701,6 +3771,11 @@
|
||||
dependencies:
|
||||
"@sentry/cli" "^1.74.4"
|
||||
|
||||
"@sinclair/typebox@^0.24.1":
|
||||
version "0.24.44"
|
||||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.44.tgz#0a0aa3bf4a155a678418527342a3ee84bd8caa5c"
|
||||
integrity sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==
|
||||
|
||||
"@sindresorhus/is@^4.0.0":
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
|
||||
@@ -3847,6 +3922,27 @@
|
||||
regenerator-runtime "^0.13.7"
|
||||
ts-dedent "^2.0.0"
|
||||
|
||||
"@storybook/addon-interactions@^6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-6.5.12.tgz#b9b7ae50de4c41ea2c9023dcaacf3f318a072ea4"
|
||||
integrity sha512-wAkKqUX57qZMzgykMIltjDrFfA0II+pKz2SchK4hXHK3/2rtOe+Ah0Sj5nTQo++Ee5oC1PVZWIq/Y1kufCTBJQ==
|
||||
dependencies:
|
||||
"@devtools-ds/object-inspector" "^1.1.2"
|
||||
"@storybook/addons" "6.5.12"
|
||||
"@storybook/api" "6.5.12"
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
"@storybook/components" "6.5.12"
|
||||
"@storybook/core-common" "6.5.12"
|
||||
"@storybook/core-events" "6.5.12"
|
||||
"@storybook/csf" "0.0.2--canary.4566f4d.1"
|
||||
"@storybook/instrumenter" "6.5.12"
|
||||
"@storybook/theming" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
jest-mock "^27.0.6"
|
||||
polished "^4.2.2"
|
||||
ts-dedent "^2.2.0"
|
||||
|
||||
"@storybook/addon-interactions@^6.5.6", "@storybook/addon-interactions@^6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-6.5.9.tgz#4356e96beae8f44000955d8870c3acc6c8d1fb3a"
|
||||
@@ -3946,6 +4042,23 @@
|
||||
prop-types "^15.7.2"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/addons@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.5.12.tgz#891767b5f88ea99b956cf19e9e2893594068adc7"
|
||||
integrity sha512-y3cgxZq41YGnuIlBJEuJjSFdMsm8wnvlNOGUP9Q+Er2dgfx8rJz4Q22o4hPjpvpaj4XdBtxCJXI2NeFpN59+Cw==
|
||||
dependencies:
|
||||
"@storybook/api" "6.5.12"
|
||||
"@storybook/channels" "6.5.12"
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
"@storybook/core-events" "6.5.12"
|
||||
"@storybook/csf" "0.0.2--canary.4566f4d.1"
|
||||
"@storybook/router" "6.5.12"
|
||||
"@storybook/theming" "6.5.12"
|
||||
"@types/webpack-env" "^1.16.0"
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/addons@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.5.9.tgz#5a9d7395c579a9cbc44dfc122362fb3c95dfb9d5"
|
||||
@@ -3963,6 +4076,29 @@
|
||||
global "^4.4.0"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/api@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.5.12.tgz#7cc82087fc9298be03f15bf4ab9c4aab294b3bac"
|
||||
integrity sha512-DuUZmMlQxkFNU9Vgkp9aNfCkAongU76VVmygvCuSpMVDI9HQ2lG0ydL+ppL4XKoSMCCoXTY6+rg4hJANnH+1AQ==
|
||||
dependencies:
|
||||
"@storybook/channels" "6.5.12"
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
"@storybook/core-events" "6.5.12"
|
||||
"@storybook/csf" "0.0.2--canary.4566f4d.1"
|
||||
"@storybook/router" "6.5.12"
|
||||
"@storybook/semver" "^7.3.2"
|
||||
"@storybook/theming" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
global "^4.4.0"
|
||||
lodash "^4.17.21"
|
||||
memoizerific "^1.11.3"
|
||||
regenerator-runtime "^0.13.7"
|
||||
store2 "^2.12.0"
|
||||
telejson "^6.0.8"
|
||||
ts-dedent "^2.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
"@storybook/api@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.5.9.tgz#303733214c9de0422d162f7c54ae05d088b89bf9"
|
||||
@@ -4107,6 +4243,15 @@
|
||||
global "^4.4.0"
|
||||
telejson "^6.0.8"
|
||||
|
||||
"@storybook/channels@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.5.12.tgz#98baf01691d263e2ac341853361ec69c1a6621bc"
|
||||
integrity sha512-X5XaKbe4b7LXJ4sUakBo00x6pXnW78JkOonHoaKoWsccHLlEzwfBZpVVekhVZnqtCoLT23dB8wjKgA71RYWoiw==
|
||||
dependencies:
|
||||
core-js "^3.8.2"
|
||||
ts-dedent "^2.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
"@storybook/channels@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.5.9.tgz#abfab89a6587a2688e9926d4aafeb11c9d8b2e79"
|
||||
@@ -4142,6 +4287,14 @@
|
||||
ts-dedent "^2.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
"@storybook/client-logger@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.5.12.tgz#d9809e13dc7939eb61452a5e94b1ccb61c4a022c"
|
||||
integrity sha512-IrkMr5KZcudX935/C2balFbxLHhkvQnJ78rbVThHDVckQ7l3oIXTh66IMzldeOabVFDZEMiW8AWuGEYof+JtLw==
|
||||
dependencies:
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
|
||||
"@storybook/client-logger@6.5.9", "@storybook/client-logger@^6.4.0", "@storybook/client-logger@^6.4.0 || >=6.5.0-0":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.5.9.tgz#dc1669abe8c45af1cc38f74c6f4b15ff33e63014"
|
||||
@@ -4150,6 +4303,20 @@
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
|
||||
"@storybook/components@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.5.12.tgz#e137f0683ea92e22de116bfa62cfd65ce4efe01d"
|
||||
integrity sha512-NAAGl5PDXaHdVLd6hA+ttmLwH3zAVGXeUmEubzKZ9bJzb+duhFKxDa9blM4YEkI+palumvgAMm0UgS7ou680Ig==
|
||||
dependencies:
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
"@storybook/csf" "0.0.2--canary.4566f4d.1"
|
||||
"@storybook/theming" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
memoizerific "^1.11.3"
|
||||
qs "^6.10.0"
|
||||
regenerator-runtime "^0.13.7"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
"@storybook/components@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.5.9.tgz#97e07ffe11ab76c01ccee380888991bd161f75b2"
|
||||
@@ -4192,6 +4359,62 @@
|
||||
unfetch "^4.2.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
"@storybook/core-common@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-6.5.12.tgz#9f8d5cb3812382c49c84dcfb4279a39e228a1b83"
|
||||
integrity sha512-gG20+eYdIhwQNu6Xs805FLrOCWtkoc8Rt8gJiRt8yXzZh9EZkU4xgCRoCxrrJ03ys/gTiCFbBOfRi749uM3z4w==
|
||||
dependencies:
|
||||
"@babel/core" "^7.12.10"
|
||||
"@babel/plugin-proposal-class-properties" "^7.12.1"
|
||||
"@babel/plugin-proposal-decorators" "^7.12.12"
|
||||
"@babel/plugin-proposal-export-default-from" "^7.12.1"
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.12.1"
|
||||
"@babel/plugin-proposal-optional-chaining" "^7.12.7"
|
||||
"@babel/plugin-proposal-private-methods" "^7.12.1"
|
||||
"@babel/plugin-proposal-private-property-in-object" "^7.12.1"
|
||||
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
|
||||
"@babel/plugin-transform-arrow-functions" "^7.12.1"
|
||||
"@babel/plugin-transform-block-scoping" "^7.12.12"
|
||||
"@babel/plugin-transform-classes" "^7.12.1"
|
||||
"@babel/plugin-transform-destructuring" "^7.12.1"
|
||||
"@babel/plugin-transform-for-of" "^7.12.1"
|
||||
"@babel/plugin-transform-parameters" "^7.12.1"
|
||||
"@babel/plugin-transform-shorthand-properties" "^7.12.1"
|
||||
"@babel/plugin-transform-spread" "^7.12.1"
|
||||
"@babel/preset-env" "^7.12.11"
|
||||
"@babel/preset-react" "^7.12.10"
|
||||
"@babel/preset-typescript" "^7.12.7"
|
||||
"@babel/register" "^7.12.1"
|
||||
"@storybook/node-logger" "6.5.12"
|
||||
"@storybook/semver" "^7.3.2"
|
||||
"@types/node" "^14.0.10 || ^16.0.0"
|
||||
"@types/pretty-hrtime" "^1.0.0"
|
||||
babel-loader "^8.0.0"
|
||||
babel-plugin-macros "^3.0.1"
|
||||
babel-plugin-polyfill-corejs3 "^0.1.0"
|
||||
chalk "^4.1.0"
|
||||
core-js "^3.8.2"
|
||||
express "^4.17.1"
|
||||
file-system-cache "^1.0.5"
|
||||
find-up "^5.0.0"
|
||||
fork-ts-checker-webpack-plugin "^6.0.4"
|
||||
fs-extra "^9.0.1"
|
||||
glob "^7.1.6"
|
||||
handlebars "^4.7.7"
|
||||
interpret "^2.2.0"
|
||||
json5 "^2.1.3"
|
||||
lazy-universal-dotenv "^3.0.1"
|
||||
picomatch "^2.3.0"
|
||||
pkg-dir "^5.0.0"
|
||||
pretty-hrtime "^1.0.3"
|
||||
resolve-from "^5.0.0"
|
||||
slash "^3.0.0"
|
||||
telejson "^6.0.8"
|
||||
ts-dedent "^2.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
webpack "4"
|
||||
|
||||
"@storybook/core-common@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-6.5.9.tgz#7ca8258ea2634b1d64695c1e4262f71cc7457989"
|
||||
@@ -4248,6 +4471,13 @@
|
||||
util-deprecate "^1.0.2"
|
||||
webpack "4"
|
||||
|
||||
"@storybook/core-events@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.5.12.tgz#28bd727cc4216012409bfac412fcb708346c56bc"
|
||||
integrity sha512-0AMyMM19R/lHsYRfWqM8zZTXthasTAK2ExkSRzYi2GkIaVMxRKtM33YRwxKIpJ6KmIKIs8Ru3QCXu1mfCmGzNg==
|
||||
dependencies:
|
||||
core-js "^3.8.2"
|
||||
|
||||
"@storybook/core-events@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.5.9.tgz#5b0783c7d22a586c0f5e927a61fe1b1223e19637"
|
||||
@@ -4361,6 +4591,24 @@
|
||||
lodash "^4.17.21"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/expect@storybook-jest":
|
||||
version "27.5.2-0"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/expect/-/expect-27.5.2-0.tgz#131fc4336106805ccd100809a3c2852d31f1da68"
|
||||
integrity sha512-cP99mhWN/JeCp7VSIiymvj5tmuMY050iFohvp8Zq+kewKsBSZ6/qpTJAGCCZk6pneTcp4S0Fm5BSqyxzbyJ3gw==
|
||||
dependencies:
|
||||
"@types/jest" ">=26.0.0"
|
||||
|
||||
"@storybook/instrumenter@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-6.5.12.tgz#acd721c50b65183a53fb5913fe7cdb35b06e2433"
|
||||
integrity sha512-VMl+Yg6ab79A1VqlhC69sBFI6ySw4Lganqdf9JJf6Y7uNRcZwsjfGpGfYiL4WGH1q72tGiq/25XKGIJV0jgi1Q==
|
||||
dependencies:
|
||||
"@storybook/addons" "6.5.12"
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
"@storybook/core-events" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
|
||||
"@storybook/instrumenter@6.5.9", "@storybook/instrumenter@^6.4.0", "@storybook/instrumenter@^6.4.0 || >=6.5.0-0":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-6.5.9.tgz#885d9dec31b7b7fa6ea29b446105480450e527b8"
|
||||
@@ -4372,6 +4620,16 @@
|
||||
core-js "^3.8.2"
|
||||
global "^4.4.0"
|
||||
|
||||
"@storybook/jest@^0.0.10":
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/jest/-/jest-0.0.10.tgz#4fbc43ebc3ae6cce8232d6bd9b56ef710f481e52"
|
||||
integrity sha512-qeYLIplpcOUQXboJde5pRCjTvkGmF80jEszRUoNYCNcEPfC2sMK68Wq6Ct8EQj3CoEdJqsK54O2YYh+7D9S+ag==
|
||||
dependencies:
|
||||
"@storybook/expect" storybook-jest
|
||||
"@storybook/instrumenter" "^6.4.0"
|
||||
"@testing-library/jest-dom" "^5.16.2"
|
||||
jest-mock "^27.3.0"
|
||||
|
||||
"@storybook/manager-webpack4@6.5.9", "@storybook/manager-webpack4@^6.5.6", "@storybook/manager-webpack4@^6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/manager-webpack4/-/manager-webpack4-6.5.9.tgz#c75d2cced4550c8a786f00b0e57b203d613e706c"
|
||||
@@ -4468,6 +4726,17 @@
|
||||
prettier ">=2.2.1 <=2.3.0"
|
||||
ts-dedent "^2.0.0"
|
||||
|
||||
"@storybook/node-logger@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.5.12.tgz#0f9efcd1a37c7aae493b22fe33cacca87c135b9b"
|
||||
integrity sha512-jdLtT3mX5GQKa+0LuX0q0sprKxtCGf6HdXlKZGD5FEuz4MgJUGaaiN0Hgi+U7Z4tVNOtSoIbYBYXHqfUgJrVZw==
|
||||
dependencies:
|
||||
"@types/npmlog" "^4.1.2"
|
||||
chalk "^4.1.0"
|
||||
core-js "^3.8.2"
|
||||
npmlog "^5.0.1"
|
||||
pretty-hrtime "^1.0.3"
|
||||
|
||||
"@storybook/node-logger@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.5.9.tgz#129cfe0d0f79cab4f6a2ba194d39516680b1626f"
|
||||
@@ -4562,6 +4831,17 @@
|
||||
util-deprecate "^1.0.2"
|
||||
webpack ">=4.43.0 <6.0.0"
|
||||
|
||||
"@storybook/router@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.5.12.tgz#58efbc1f2f301c8584802af1c710b2f6f03f948c"
|
||||
integrity sha512-xHubde9YnBbpkDY5+zGO4Pr6VPxP8H9J2v4OTF3H82uaxCIKR0PKG0utS9pFKIsEiP3aM62Hb9qB8nU+v1nj3w==
|
||||
dependencies:
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
memoizerific "^1.11.3"
|
||||
qs "^6.10.0"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/router@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.5.9.tgz#4740248f8517425b2056273fb366ace8a17c65e8"
|
||||
@@ -4658,6 +4938,16 @@
|
||||
"@testing-library/user-event" "^13.2.1"
|
||||
ts-dedent "^2.2.0"
|
||||
|
||||
"@storybook/theming@6.5.12":
|
||||
version "6.5.12"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.5.12.tgz#7df1b52913d49c5e84fc1f2e837c02d9fa8cc639"
|
||||
integrity sha512-uWOo84qMQ2R6c1C0faZ4Q0nY01uNaX7nXoJKieoiJ6ZqY9PSYxJl1kZLi3uPYnrxLZjzjVyXX8MgdxzbppYItA==
|
||||
dependencies:
|
||||
"@storybook/client-logger" "6.5.12"
|
||||
core-js "^3.8.2"
|
||||
memoizerific "^1.11.3"
|
||||
regenerator-runtime "^0.13.7"
|
||||
|
||||
"@storybook/theming@6.5.9":
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.5.9.tgz#13f60a3a3cd73ceb5caf9f188e1627e79f1891aa"
|
||||
@@ -4716,6 +5006,21 @@
|
||||
lz-string "^1.4.4"
|
||||
pretty-format "^27.0.2"
|
||||
|
||||
"@testing-library/jest-dom@^5.16.2":
|
||||
version "5.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e"
|
||||
integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==
|
||||
dependencies:
|
||||
"@adobe/css-tools" "^4.0.1"
|
||||
"@babel/runtime" "^7.9.2"
|
||||
"@types/testing-library__jest-dom" "^5.9.1"
|
||||
aria-query "^5.0.0"
|
||||
chalk "^3.0.0"
|
||||
css.escape "^1.5.1"
|
||||
dom-accessibility-api "^0.5.6"
|
||||
lodash "^4.17.15"
|
||||
redent "^3.0.0"
|
||||
|
||||
"@testing-library/react-hooks@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12"
|
||||
@@ -4983,6 +5288,14 @@
|
||||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/jest@*", "@types/jest@>=26.0.0":
|
||||
version "29.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.1.1.tgz#cf21a0835a1ba9a30ea1966019f1261c6a114c92"
|
||||
integrity sha512-U9Ey07dGWl6fUFaIaUQUKWG5NoKi/zizeVQCGV8s4nSU0jPgqphVZvS64+8BtWYvrc3ZGw6wo943NSYPxkrp/g==
|
||||
dependencies:
|
||||
expect "^29.0.0"
|
||||
pretty-format "^29.0.0"
|
||||
|
||||
"@types/jest@^27.4.0", "@types/jest@^27.4.1":
|
||||
version "27.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c"
|
||||
@@ -5236,6 +5549,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310"
|
||||
integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==
|
||||
|
||||
"@types/testing-library__jest-dom@^5.9.1":
|
||||
version "5.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f"
|
||||
integrity sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==
|
||||
dependencies:
|
||||
"@types/jest" "*"
|
||||
|
||||
"@types/uglify-js@*":
|
||||
version "3.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.16.0.tgz#2cf74a0e6ebb6cd54c0d48e509d5bd91160a9602"
|
||||
@@ -5303,6 +5623,13 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@types/yargs@^17.0.8":
|
||||
version "17.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.13.tgz#34cced675ca1b1d51fcf4d34c3c6f0fa142a5c76"
|
||||
integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.36.2":
|
||||
version "5.36.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz#6df092a20e0f9ec748b27f293a12cb39d0c1fe4d"
|
||||
@@ -7051,6 +7378,14 @@ chalk@^2.0.0, chalk@^2.4.1:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
|
||||
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
@@ -7330,7 +7665,7 @@ clsx@1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702"
|
||||
integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==
|
||||
|
||||
clsx@^1.0.4:
|
||||
clsx@^1.0.4, clsx@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
@@ -7839,6 +8174,11 @@ css-what@^6.0.1:
|
||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
||||
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
||||
|
||||
css.escape@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
||||
integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
|
||||
|
||||
cssesc@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
@@ -8121,6 +8461,11 @@ diff-sequences@^27.5.1:
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
|
||||
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
|
||||
|
||||
diff-sequences@^29.0.0:
|
||||
version "29.0.0"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.0.0.tgz#bae49972ef3933556bcb0800b72e8579d19d9e4f"
|
||||
integrity sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
@@ -8168,7 +8513,7 @@ doctrine@^3.0.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-accessibility-api@^0.5.9:
|
||||
dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9:
|
||||
version "0.5.14"
|
||||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56"
|
||||
integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==
|
||||
@@ -9397,6 +9742,17 @@ expect@^27.5.1:
|
||||
jest-matcher-utils "^27.5.1"
|
||||
jest-message-util "^27.5.1"
|
||||
|
||||
expect@^29.0.0:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/expect/-/expect-29.1.2.tgz#82f8f28d7d408c7c68da3a386a490ee683e1eced"
|
||||
integrity sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==
|
||||
dependencies:
|
||||
"@jest/expect-utils" "^29.1.2"
|
||||
jest-get-type "^29.0.0"
|
||||
jest-matcher-utils "^29.1.2"
|
||||
jest-message-util "^29.1.2"
|
||||
jest-util "^29.1.2"
|
||||
|
||||
express@4.17.3:
|
||||
version "4.17.3"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
|
||||
@@ -11615,6 +11971,16 @@ jest-diff@^27.5.1:
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
|
||||
jest-diff@^29.1.2:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.1.2.tgz#bb7aaf5353227d6f4f96c5e7e8713ce576a607dc"
|
||||
integrity sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
diff-sequences "^29.0.0"
|
||||
jest-get-type "^29.0.0"
|
||||
pretty-format "^29.1.2"
|
||||
|
||||
jest-docblock@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0"
|
||||
@@ -11663,6 +12029,11 @@ jest-get-type@^27.5.1:
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
|
||||
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
|
||||
|
||||
jest-get-type@^29.0.0:
|
||||
version "29.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.0.0.tgz#843f6c50a1b778f7325df1129a0fd7aa713aef80"
|
||||
integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==
|
||||
|
||||
jest-haste-map@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa"
|
||||
@@ -11745,6 +12116,16 @@ jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1:
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
|
||||
jest-matcher-utils@^29.1.2:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz#e68c4bcc0266e70aa1a5c13fb7b8cd4695e318a1"
|
||||
integrity sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
jest-diff "^29.1.2"
|
||||
jest-get-type "^29.0.0"
|
||||
pretty-format "^29.1.2"
|
||||
|
||||
jest-message-util@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf"
|
||||
@@ -11760,7 +12141,22 @@ jest-message-util@^27.5.1:
|
||||
slash "^3.0.0"
|
||||
stack-utils "^2.0.3"
|
||||
|
||||
jest-mock@^27.0.6, jest-mock@^27.5.1:
|
||||
jest-message-util@^29.1.2:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.1.2.tgz#c21a33c25f9dc1ebfcd0f921d89438847a09a501"
|
||||
integrity sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.12.13"
|
||||
"@jest/types" "^29.1.2"
|
||||
"@types/stack-utils" "^2.0.0"
|
||||
chalk "^4.0.0"
|
||||
graceful-fs "^4.2.9"
|
||||
micromatch "^4.0.4"
|
||||
pretty-format "^29.1.2"
|
||||
slash "^3.0.0"
|
||||
stack-utils "^2.0.3"
|
||||
|
||||
jest-mock@^27.0.6, jest-mock@^27.3.0, jest-mock@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6"
|
||||
integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==
|
||||
@@ -11931,6 +12327,18 @@ jest-util@^27.5.1:
|
||||
graceful-fs "^4.2.9"
|
||||
picomatch "^2.2.3"
|
||||
|
||||
jest-util@^29.1.2:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.1.2.tgz#ac5798e93cb6a6703084e194cfa0898d66126df1"
|
||||
integrity sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==
|
||||
dependencies:
|
||||
"@jest/types" "^29.1.2"
|
||||
"@types/node" "*"
|
||||
chalk "^4.0.0"
|
||||
ci-info "^3.2.0"
|
||||
graceful-fs "^4.2.9"
|
||||
picomatch "^2.2.3"
|
||||
|
||||
jest-validate@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067"
|
||||
@@ -14642,6 +15050,15 @@ pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^29.0.0, pretty-format@^29.1.2:
|
||||
version "29.1.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.1.2.tgz#b1f6b75be7d699be1a051f5da36e8ae9e76a8e6a"
|
||||
integrity sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==
|
||||
dependencies:
|
||||
"@jest/schemas" "^29.0.0"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
pretty-hrtime@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
@@ -15033,7 +15450,7 @@ react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0":
|
||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
@@ -15271,6 +15688,14 @@ redent@^1.0.0:
|
||||
indent-string "^2.1.0"
|
||||
strip-indent "^1.0.1"
|
||||
|
||||
redent@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
|
||||
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
|
||||
dependencies:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
refractor@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a"
|
||||
|
||||