fix(dashboard,ui): Fixes to Combobox and CategoryCombobox (#9537)

**What**
- Fixes the Combobox to keep the width of the content constant.
- Brings CategoryCombobox inline with the other Combobox component
- Adds keyboard navigation to the CategoryCombobox: You can now navigate options using ArrowUp and ArrowDown, and if an option has children you can use ArrowRight to see the children options.
- Add "outline-none" to the Drawer component to stop it from flashing whenever focus is dropped.
- Removes a dependency that was added to the UI package by mistake

Resolves CC-155
This commit is contained in:
Kasper Fabricius Kristensen
2024-10-12 16:46:32 +02:00
committed by GitHub
parent 93b38bf47b
commit 1f682daf5c
8 changed files with 1323 additions and 1765 deletions

View File

@@ -18,6 +18,7 @@ import { clx, Text } from "@medusajs/ui"
import { matchSorter } from "match-sorter"
import {
ComponentPropsWithoutRef,
CSSProperties,
ForwardedRef,
Fragment,
ReactNode,
@@ -41,6 +42,9 @@ type ComboboxOption = {
type Value = string[] | string
const TABLUAR_NUM_WIDTH = 8
const TAG_BASE_WIDTH = 28
interface ComboboxProps<T extends Value = Value>
extends Omit<ComponentPropsWithoutRef<"input">, "onChange" | "value"> {
value?: T
@@ -195,6 +199,17 @@ const ComboboxImpl = <T extends Value = string>(
const hidePlaceholder = showSelected || open
const tagWidth = useMemo(() => {
if (!Array.isArray(selectedValues)) {
return TAG_BASE_WIDTH + TABLUAR_NUM_WIDTH // There can only be a single digit
}
const count = selectedValues.length
const digits = count.toString().length
return TAG_BASE_WIDTH + digits * TABLUAR_NUM_WIDTH
}, [selectedValues])
const results = useMemo(() => {
return isSearchControlled ? options : matches
}, [matches, options, isSearchControlled])
@@ -213,41 +228,42 @@ const ComboboxImpl = <T extends Value = string>(
<div
className={clx(
"relative flex cursor-pointer items-center gap-x-2 overflow-hidden",
"h-8 w-full rounded-md px-2 py-0.5",
"h-8 w-full rounded-md",
"bg-ui-bg-field transition-fg shadow-borders-base",
"hover:bg-ui-bg-field-hover",
"has-[input:focus]:shadow-borders-interactive-with-active",
"has-[:invalid]:shadow-borders-error has-[[aria-invalid=true]]:shadow-borders-error",
"has-[:disabled]:bg-ui-bg-disabled has-[:disabled]:text-ui-fg-disabled has-[:disabled]:cursor-not-allowed",
{
"pl-0.5": hasValue && isArrayValue,
},
className
)}
style={
{
"--tag-width": `${tagWidth}px`,
} as CSSProperties
}
>
{showTag && (
<div className="bg-ui-bg-base txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive relative flex h-[28px] items-center rounded-[4px] border py-[3px] pl-1.5 pr-1">
<span>{selectedValues.length}</span>
<button
type="button"
className="size-fit outline-none"
onClick={(e) => {
e.preventDefault()
handleValueChange(undefined)
}}
>
<XMarkMini className="text-ui-fg-muted" />
</button>
</div>
<button
type="button"
onClick={(e) => {
e.preventDefault()
handleValueChange(undefined)
}}
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute left-0.5 top-0.5 z-[1] flex h-[28px] items-center rounded-[4px] border py-[3px] pl-1.5 pr-1 outline-none"
>
<span className="tabular-nums">{selectedValues.length}</span>
<XMarkMini className="text-ui-fg-muted" />
</button>
)}
<div className="relative flex size-full items-center">
{showSelected && (
<Text size="small" leading="compact">
{t("general.selected")}
</Text>
<div className="pointer-events-none absolute inset-y-0 left-[calc(var(--tag-width)+8px)] flex size-full items-center">
<Text size="small" leading="compact">
{t("general.selected")}
</Text>
</div>
)}
{hideInput && (
<div className="absolute inset-y-0 left-0 flex size-full items-center overflow-hidden">
<div className="pointer-events-none absolute inset-y-0 left-[calc(var(--tag-width)+8px)] flex size-full items-center overflow-hidden">
<Text size="small" leading="compact" className="truncate">
{selectedLabel}
</Text>
@@ -256,10 +272,14 @@ const ComboboxImpl = <T extends Value = string>(
<PrimitiveCombobox
autoSelect
ref={comboboxRef}
onFocus={() => setOpen(true)}
className={clx(
"txt-compact-small text-ui-fg-base placeholder:text-ui-fg-subtle size-full cursor-pointer bg-transparent pr-7 outline-none focus:cursor-text",
"txt-compact-small text-ui-fg-base placeholder:text-ui-fg-subtle transition-fg size-full cursor-pointer bg-transparent pl-2 pr-8 outline-none focus:cursor-text",
"hover:bg-ui-bg-field-hover",
{
"opacity-0": hideInput,
"pl-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag,
}
)}
placeholder={hidePlaceholder ? undefined : placeholder}
@@ -267,11 +287,12 @@ const ComboboxImpl = <T extends Value = string>(
/>
</div>
<PrimitiveComboboxDisclosure
render={() => {
render={(props) => {
return (
<button
{...props}
type="button"
className="text-ui-fg-muted pointer-events-none absolute right-2 size-fit outline-none"
className="text-ui-fg-muted transition-fg hover:bg-ui-bg-field-hover absolute right-0 flex size-8 items-center justify-center rounded-r outline-none"
>
<TrianglesMini />
</button>
@@ -281,10 +302,11 @@ const ComboboxImpl = <T extends Value = string>(
</div>
<PrimitiveComboboxPopover
gutter={4}
sameWidth
ref={listboxRef}
role="listbox"
className={clx(
"shadow-elevation-flyout bg-ui-bg-base -left-2 z-50 w-[calc(var(--popover-anchor-width)+16px)] rounded-[8px] p-1",
"shadow-elevation-flyout bg-ui-bg-base z-50 rounded-[8px] p-1",
"max-h-[200px] overflow-y-auto",
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
@@ -303,7 +325,7 @@ const ComboboxImpl = <T extends Value = string>(
setValueOnClick={false}
disabled={disabled}
className={clx(
"transition-fg bg-ui-bg-base data-[active-item=true]:bg-ui-bg-base-hover group flex cursor-pointer items-center gap-x-2 rounded-[4px] px-2 py-1.5",
"transition-fg bg-ui-bg-base data-[active-item=true]:bg-ui-bg-base-hover group flex cursor-pointer items-center gap-x-2 rounded-[4px] px-2 py-1",
{
"text-ui-fg-disabled": disabled,
"bg-ui-bg-component": disabled,

View File

@@ -76,13 +76,13 @@ export const useComboboxData = <
*/
const disabled = !rest.isPending && !options.length && !searchValue
// // make sure that the default value is included in the option, if its not in options already
if (
defaultValue &&
defaultOptions.length &&
!options.find((o) => o.value === defaultValue)
) {
options.unshift(defaultOptions[0])
// make sure that the default value is included in the options
if (defaultValue && defaultOptions.length && !searchValue) {
defaultOptions.forEach((option) => {
if (!options.find((o) => o.value === option.value)) {
options.unshift(option)
}
})
}
return {

View File

@@ -1,6 +1,6 @@
import {
ArrowUturnLeft,
CheckMini,
EllipseMiniSolid,
TriangleRightMini,
TrianglesMini,
XMarkMini,
@@ -9,12 +9,15 @@ import { AdminProductCategoryResponse } from "@medusajs/types"
import { Text, clx } from "@medusajs/ui"
import * as Popover from "@radix-ui/react-popover"
import {
CSSProperties,
ComponentPropsWithoutRef,
Fragment,
MouseEvent,
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
} from "react"
@@ -38,6 +41,9 @@ type Level = {
label: string
}
const TABLUAR_NUM_WIDTH = 8
const TAG_BASE_WIDTH = 28
export const CategoryCombobox = forwardRef<
HTMLInputElement,
CategoryComboboxProps
@@ -118,20 +124,23 @@ export const CategoryCombobox = forwardRef<
}
}
function handleSelect(option: ProductCategoryOption) {
return (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
const handleSelect = useCallback(
(option: ProductCategoryOption) => {
return (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
if (isSelected(value, option.value)) {
onChange(value.filter((v) => v !== option.value))
} else {
onChange([...value, option.value])
if (isSelected(value, option.value)) {
onChange(value.filter((v) => v !== option.value))
} else {
onChange([...value, option.value])
}
innerRef.current?.focus()
}
innerRef.current?.focus()
}
}
},
[value, onChange]
)
function handleOpenChange(open: boolean) {
if (!open) {
@@ -150,21 +159,101 @@ export const CategoryCombobox = forwardRef<
const options = getOptions(product_categories || [])
const showTag = value.length > 0 && !open
const showTag = value.length > 0
const showSelected = !open && value.length > 0
const tagWidth = useMemo(() => {
const count = value.length
const digits = count.toString().length
return TAG_BASE_WIDTH + digits * TABLUAR_NUM_WIDTH
}, [value])
const showLevelUp = !searchValue && level.length > 0
const [focusedIndex, setFocusedIndex] = useState<number>(-1)
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (!open) {
return
}
const optionsLength = showLevelUp ? options.length + 1 : options.length
if (e.key === "ArrowDown") {
e.preventDefault()
setFocusedIndex((prev) => {
const nextIndex = prev < optionsLength - 1 ? prev + 1 : prev
return nextIndex
})
} else if (e.key === "ArrowUp") {
e.preventDefault()
setFocusedIndex((prev) => {
return prev > 0 ? prev - 1 : prev
})
} else if (e.key === "ArrowRight") {
const index = showLevelUp ? focusedIndex - 1 : focusedIndex
const hasChildren = options[index]?.has_children
if (!hasChildren || !!searchValue) {
return
}
e.preventDefault()
setLevel([
...level,
{
id: options[index].value,
label: options[index].label,
},
])
setFocusedIndex(0)
} else if (e.key === "Enter" && focusedIndex !== -1) {
e.preventDefault()
if (showLevelUp && focusedIndex === 0) {
setLevel(level.slice(0, level.length - 1))
setFocusedIndex(0)
return
}
const index = showLevelUp ? focusedIndex - 1 : focusedIndex
handleSelect(options[index])(e as any)
}
},
[open, focusedIndex, options, level, handleSelect, searchValue, showLevelUp]
)
useEffect(() => {
window.addEventListener("keydown", handleKeyDown)
return () => {
window.removeEventListener("keydown", handleKeyDown)
}
}, [handleKeyDown])
if (isError) {
throw error
}
return (
<Popover.Root modal open={open} onOpenChange={handleOpenChange}>
<Popover.Trigger asChild>
<Popover.Root open={open} onOpenChange={handleOpenChange}>
<Popover.Anchor
asChild
onClick={() => {
if (!open) {
handleOpenChange(true)
}
}}
>
<div
data-anchor
className={clx(
"relative flex cursor-pointer items-center gap-x-2 overflow-hidden",
"h-8 w-full rounded-md px-2 py-0.5",
"h-8 w-full rounded-md",
"bg-ui-bg-field transition-fg shadow-borders-base",
"hover:bg-ui-bg-field-hover",
"has-[input:focus]:shadow-borders-interactive-with-active",
"has-[:invalid]:shadow-borders-error has-[[aria-invalid=true]]:shadow-borders-error",
"has-[:disabled]:bg-ui-bg-disabled has-[:disabled]:text-ui-fg-disabled has-[:disabled]:cursor-not-allowed",
@@ -173,169 +262,199 @@ export const CategoryCombobox = forwardRef<
// this prevents the styling from flickering when navigating
// between levels.
"shadow-borders-interactive-with-active": open,
"pl-0.5": showTag,
},
className
)}
style={
{
"--tag-width": `${tagWidth}px`,
} as CSSProperties
}
>
{open ? (
<input
ref={innerRef}
value={searchValue}
onChange={(e) => onSearchValueChange(e.target.value)}
className={clx(
"txt-compact-small w-full appearance-none bg-transparent outline-none",
"placeholder:text-ui-fg-muted"
)}
{...props}
/>
) : showTag ? (
<div className="flex w-full items-center gap-x-2">
<div className="flex w-fit items-center gap-x-1">
<div className="bg-ui-bg-base txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive relative flex h-[28px] items-center rounded-[4px] border py-[3px] pl-1.5 pr-1">
<span>{value.length}</span>
<button
type="button"
className="size-fit outline-none"
onClick={(e) => {
e.preventDefault()
onChange([])
}}
>
<XMarkMini className="text-ui-fg-muted" />
</button>
</div>
</div>
{showTag && (
<button
type="button"
onClick={(e) => {
e.preventDefault()
onChange([])
}}
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute left-0.5 top-0.5 flex h-[28px] items-center rounded-[4px] border py-[3px] pl-1.5 pr-1 outline-none"
>
<span className="tabular-nums">{value.length}</span>
<XMarkMini className="text-ui-fg-muted" />
</button>
)}
{showSelected && (
<div className="pointer-events-none absolute inset-y-0 left-[calc(var(--tag-width)+8px)] flex size-full items-center">
<Text size="small" leading="compact">
{t("general.selected")}
</Text>
</div>
) : (
<div className="w-full"></div>
)}
<div className="flex size-5 items-center justify-center">
<input
ref={innerRef}
value={searchValue}
onChange={(e) => {
onSearchValueChange(e.target.value)
}}
className={clx(
"txt-compact-small size-full cursor-pointer appearance-none bg-transparent pr-8 outline-none",
"hover:bg-ui-bg-field-hover",
"focus:cursor-text",
"placeholder:text-ui-fg-muted",
{
"pl-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag,
}
)}
{...props}
/>
<button
type="button"
onClick={() => handleOpenChange(true)}
className="text-ui-fg-muted transition-fg hover:bg-ui-bg-field-hover absolute right-0 flex size-8 items-center justify-center rounded-r outline-none"
>
<TrianglesMini className="text-ui-fg-muted" />
</div>
</button>
</div>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
sideOffset={8}
role="listbox"
className={clx(
"shadow-elevation-flyout bg-ui-bg-base -left-2 z-50 w-[var(--radix-popper-anchor-width)] rounded-[8px]",
"max-h-[200px] overflow-y-auto",
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
)}
onOpenAutoFocus={(e) => {
e.preventDefault()
}}
>
{!searchValue && level.length > 0 && (
<Fragment>
<div className="p-1">
</Popover.Anchor>
<Popover.Content
sideOffset={4}
role="listbox"
className={clx(
"shadow-elevation-flyout bg-ui-bg-base -left-2 z-50 w-[var(--radix-popper-anchor-width)] rounded-[8px]",
"max-h-[200px] overflow-y-auto",
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
)}
onInteractOutside={(e) => {
e.preventDefault()
const target = e.target as HTMLElement
if (target.closest("[data-anchor]")) {
return
}
handleOpenChange(false)
}}
>
{showLevelUp && (
<Fragment>
<div className="p-1">
<button
data-active={focusedIndex === 0}
role="button"
className={clx(
"transition-fg grid w-full appearance-none grid-cols-[20px_1fr] items-center justify-center gap-2 rounded-md px-2 py-1.5 text-left outline-none",
"data-[active=true]:bg-ui-bg-field-hover"
)}
type="button"
onClick={handleLevelUp}
onMouseEnter={() => setFocusedIndex(0)}
onMouseLeave={() => setFocusedIndex(-1)}
tabIndex={-1}
>
<ArrowUturnLeft className="text-ui-fg-muted" />
<Text size="small" leading="compact">
{getParentLabel(level)}
</Text>
</button>
</div>
<Divider />
</Fragment>
)}
<div className="p-1">
{options.length > 0 &&
!showLoading &&
options.map((option, index) => (
<div
key={option.value}
className={clx(
"transition-fg bg-ui-bg-base grid cursor-pointer grid-cols-1 items-center gap-2 overflow-hidden",
{
"grid-cols-[1fr_32px]": option.has_children && !searchValue,
}
)}
>
<button
className={clx(
"transition-fg grid w-full appearance-none grid-cols-[20px_1fr] items-center justify-center gap-2 rounded-md px-2 py-1.5 text-left outline-none",
"hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed"
)}
data-active={
showLevelUp
? focusedIndex === index + 1
: focusedIndex === index
}
type="button"
onClick={handleLevelUp}
role="option"
className={clx(
"grid h-full w-full appearance-none grid-cols-[20px_1fr] items-center gap-2 overflow-hidden rounded-md px-2 py-1.5 text-left outline-none",
"data-[active=true]:bg-ui-bg-field-hover"
)}
onClick={handleSelect(option)}
onMouseEnter={() =>
setFocusedIndex(showLevelUp ? index + 1 : index)
}
onMouseLeave={() => setFocusedIndex(-1)}
tabIndex={-1}
>
<ArrowUturnLeft className="text-ui-fg-muted" />
<Text size="small" leading="compact">
{getParentLabel(level)}
<div className="flex size-5 items-center justify-center">
{isSelected(value, option.value) && <EllipseMiniSolid />}
</div>
<Text
as="span"
size="small"
leading="compact"
className="w-full truncate"
>
{option.label}
</Text>
</button>
</div>
<Divider />
</Fragment>
)}
<div className="p-1">
{options.length > 0 &&
!showLoading &&
options.map((option) => (
<div
key={option.value}
className={clx(
"transition-fg bg-ui-bg-base grid cursor-pointer grid-cols-1 items-center gap-2 overflow-hidden",
{
"grid-cols-[1fr_32px]":
option.has_children && !searchValue,
}
)}
>
{option.has_children && !searchValue && (
<button
type="button"
role="option"
className={clx(
"grid h-full w-full appearance-none grid-cols-[20px_1fr] items-center gap-2 overflow-hidden rounded-md px-2 py-1.5 text-left",
"hover:bg-ui-bg-base-hover"
"text-ui-fg-muted flex size-8 appearance-none items-center justify-center rounded-md outline-none",
"hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed"
)}
onClick={handleSelect(option)}
type="button"
onClick={handleLevelDown(option)}
tabIndex={-1}
>
<div className="flex size-5 items-center justify-center">
{isSelected(value, option.value) && <CheckMini />}
</div>
<Text
as="span"
size="small"
leading="compact"
className="w-full truncate"
>
{option.label}
</Text>
<TriangleRightMini />
</button>
{option.has_children && !searchValue && (
<button
className={clx(
"text-ui-fg-muted flex size-8 appearance-none items-center justify-center rounded-md outline-none",
"hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed"
)}
type="button"
onClick={handleLevelDown(option)}
>
<TriangleRightMini />
</button>
)}
</div>
))}
{showLoading &&
Array.from({ length: 5 }).map((_, index) => (
<div
key={index}
className="grid grid-cols-[20px_1fr_20px] gap-2 px-2 py-1.5"
>
<div />
<TextSkeleton size="small" leading="compact" />
<div />
</div>
))}
{options.length === 0 && !showLoading && (
<div className="px-2 py-1.5">
<Text size="small" leading="compact">
{query ? (
<Trans
i18n={i18n}
i18nKey={"general.noResultsTitle"}
tOptions={{
query: query,
}}
components={[
<span className="font-medium" key="query" />,
]}
/>
) : (
t("general.noResultsTitle")
)}
</Text>
)}
</div>
)}
</div>
</Popover.Content>
</Popover.Portal>
))}
{showLoading &&
Array.from({ length: 5 }).map((_, index) => (
<div
key={index}
className="grid grid-cols-[20px_1fr_20px] gap-2 px-2 py-1.5"
>
<div />
<TextSkeleton size="small" leading="compact" />
<div />
</div>
))}
{options.length === 0 && !showLoading && (
<div className="px-2 py-1.5">
<Text size="small" leading="compact">
{query ? (
<Trans
i18n={i18n}
i18nKey={"general.noResultsTitle"}
tOptions={{
query: query,
}}
components={[<span className="font-medium" key="query" />]}
/>
) : (
t("general.noResultsTitle")
)}
</Text>
</div>
)}
</div>
</Popover.Content>
</Popover.Root>
)
})

View File

@@ -21,8 +21,8 @@ type ProductOrganizationFormProps = {
}
const ProductOrganizationSchema = zod.object({
type_id: zod.string().optional(),
collection_id: zod.string().optional(),
type_id: zod.string().nullable(),
collection_id: zod.string().nullable(),
category_ids: zod.array(zod.string()),
tag_ids: zod.array(zod.string()),
})
@@ -69,8 +69,8 @@ export const ProductOrganizationForm = ({
const form = useExtendableForm({
defaultValues: {
type_id: product.type_id || "",
collection_id: product.collection_id || "",
type_id: product.type_id ?? "",
collection_id: product.collection_id ?? "",
category_ids: product.categories?.map((c) => c.id) || [],
tag_ids: product.tags?.map((t) => t.id) || [],
},
@@ -84,13 +84,10 @@ export const ProductOrganizationForm = ({
const handleSubmit = form.handleSubmit(async (data) => {
await mutateAsync(
{
type_id: data.type_id || undefined,
collection_id: data.collection_id || undefined,
categories: data.category_ids.map((id) => ({ id })) || undefined,
tags:
data.tag_ids?.map((t) => ({
id: t,
})) || undefined,
type_id: data.type_id || null,
collection_id: data.collection_id || null,
categories: data.category_ids.map((c) => ({ id: c })),
tags: data.tag_ids?.map((t) => ({ id: t })),
},
{
onSuccess: ({ product }) => {
@@ -148,10 +145,10 @@ export const ProductOrganizationForm = ({
<Form.Control>
<Combobox
{...field}
multiple={false}
options={collections.options}
searchValue={collections.searchValue}
onSearchValueChange={collections.onSearchValueChange}
fetchNextPage={collections.fetchNextPage}
searchValue={collections.searchValue}
/>
</Form.Control>
<Form.ErrorMessage />
@@ -190,9 +187,8 @@ export const ProductOrganizationForm = ({
{...field}
multiple
options={tags.options}
searchValue={tags.searchValue}
onSearchValueChange={tags.onSearchValueChange}
fetchNextPage={tags.fetchNextPage}
searchValue={tags.searchValue}
/>
</Form.Control>
<Form.ErrorMessage />

View File

@@ -43,14 +43,14 @@
},
"devDependencies": {
"@medusajs/ui-preset": "^1.1.3",
"@storybook/addon-essentials": "^7.0.23",
"@storybook/addon-interactions": "^7.0.23",
"@storybook/addon-links": "^7.0.23",
"@storybook/addon-styling": "^1.3.6",
"@storybook/blocks": "^7.0.23",
"@storybook/react": "^7.0.23",
"@storybook/react-vite": "^7.0.23",
"@storybook/testing-library": "^0.0.14-next.2",
"@storybook/addon-essentials": "^8.3.5",
"@storybook/addon-interactions": "^8.3.5",
"@storybook/addon-links": "^8.3.5",
"@storybook/addon-styling": "^1.3.7",
"@storybook/blocks": "^8.3.5",
"@storybook/react": "^8.3.5",
"@storybook/react-vite": "^8.3.5",
"@storybook/testing-library": "^0.2.2",
"@testing-library/dom": "^9.3.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
@@ -71,7 +71,7 @@
"react-dom": "^18.2.0",
"resize-observer-polyfill": "^1.5.1",
"rimraf": "^5.0.1",
"storybook": "^7.0.23",
"storybook": "^8.3.5",
"tailwindcss": "^3.4.3",
"tsc-alias": "^1.8.7",
"typescript": "^5.1.6",
@@ -105,8 +105,7 @@
"react-currency-input-field": "^3.6.11",
"react-stately": "^3.31.1",
"sonner": "^1.5.0",
"tailwind-merge": "^2.2.1",
"upgrade": "^1.1.0"
"tailwind-merge": "^2.2.1"
},
"peerDependencies": {
"react": "^18.0.0",

View File

@@ -75,7 +75,7 @@ const DrawerContent = React.forwardRef<
<DrawerPrimitives.Content
ref={ref}
className={clx(
"bg-ui-bg-base shadow-elevation-modal border-ui-border-base fixed inset-y-2 flex w-full flex-1 flex-col rounded-lg border focus:outline-none max-sm:inset-x-2 max-sm:w-[calc(100%-16px)] sm:right-2 sm:max-w-[560px]",
"bg-ui-bg-base shadow-elevation-modal border-ui-border-base fixed inset-y-2 flex w-full flex-1 flex-col rounded-lg border outline-none max-sm:inset-x-2 max-sm:w-[calc(100%-16px)] sm:right-2 sm:max-w-[560px]",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-right-1/2 data-[state=open]:slide-in-from-right-1/2 duration-200",
className
)}

View File

@@ -86,7 +86,7 @@ const textVariants = cva({
],
})
interface TextProps
export interface TextProps
extends React.ComponentPropsWithoutRef<"p">,
VariantProps<typeof textVariants> {
asChild?: boolean

2510
yarn.lock

File diff suppressed because it is too large Load Diff