[WEB-5104] chore: base-ui package upgrade and combobox migration (#7931)
* chore: base ui package upgrade * feat: migrate combobox to use base-ui primitives * chore: code refactor * fix: format fixes --------- Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
1895cfe728
commit
75cd2017a0
3 changed files with 152 additions and 238 deletions
|
|
@ -165,7 +165,7 @@
|
|||
"./styles/react-day-picker": "./dist/styles/react-day-picker.css"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui-components/react": "^1.0.0-beta.2",
|
||||
"@base-ui-components/react": "1.0.0-beta.3",
|
||||
"@plane/constants": "workspace:*",
|
||||
"@plane/hooks": "workspace:*",
|
||||
"@plane/types": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
import * as React from "react";
|
||||
import { Command } from "../command/command";
|
||||
import { Popover } from "../popover/root";
|
||||
import { Combobox as BaseCombobox } from "@base-ui-components/react/combobox";
|
||||
import { Search } from "lucide-react";
|
||||
import { cn } from "../utils/classname";
|
||||
|
||||
export interface ComboboxOption {
|
||||
value: unknown;
|
||||
query: string;
|
||||
content: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
tooltip?: string | React.ReactNode;
|
||||
}
|
||||
// Type definitions
|
||||
type TMaxHeight = "lg" | "md" | "rg" | "sm";
|
||||
|
||||
export interface ComboboxProps {
|
||||
value?: string | string[];
|
||||
|
|
@ -27,19 +22,21 @@ export interface ComboboxButtonProps {
|
|||
disabled?: boolean;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
ref?: React.Ref<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
export interface ComboboxOptionsProps {
|
||||
searchPlaceholder?: string;
|
||||
emptyMessage?: string;
|
||||
showSearch?: boolean;
|
||||
showCheckIcon?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
maxHeight?: "lg" | "md" | "rg" | "sm";
|
||||
maxHeight?: TMaxHeight;
|
||||
inputClassName?: string;
|
||||
optionsContainerClassName?: string;
|
||||
positionerClassName?: string;
|
||||
searchQuery?: string;
|
||||
onSearchQueryChange?: (query: string) => void;
|
||||
}
|
||||
|
||||
export interface ComboboxOptionProps {
|
||||
|
|
@ -49,249 +46,166 @@ export interface ComboboxOptionProps {
|
|||
className?: string;
|
||||
}
|
||||
|
||||
// Context for sharing state between components
|
||||
interface ComboboxContextType {
|
||||
value: string | string[];
|
||||
onValueChange?: (value: string | string[]) => void;
|
||||
multiSelect: boolean;
|
||||
maxSelections?: number;
|
||||
disabled: boolean;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
handleValueChange: (newValue: string) => void;
|
||||
handleRemoveSelection: (valueToRemove: string) => void;
|
||||
}
|
||||
// Constants
|
||||
const MAX_HEIGHT_CLASSES: Record<TMaxHeight, string> = {
|
||||
lg: "max-h-60",
|
||||
md: "max-h-48",
|
||||
rg: "max-h-36",
|
||||
sm: "max-h-28",
|
||||
} as const;
|
||||
|
||||
const ComboboxContext = React.createContext<ComboboxContextType | null>(null);
|
||||
|
||||
function useComboboxContext() {
|
||||
const context = React.useContext(ComboboxContext);
|
||||
if (!context) {
|
||||
throw new Error("Combobox components must be used within a Combobox");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
function ComboboxComponent({
|
||||
// Root component
|
||||
function ComboboxRoot({
|
||||
value,
|
||||
defaultValue,
|
||||
onValueChange,
|
||||
multiSelect = false,
|
||||
maxSelections,
|
||||
disabled = false,
|
||||
open: openProp,
|
||||
open,
|
||||
onOpenChange,
|
||||
children,
|
||||
}: ComboboxProps) {
|
||||
// Controlled/uncontrolled value
|
||||
const isControlledValue = value !== undefined;
|
||||
const [internalValue, setInternalValue] = React.useState<string | string[]>(
|
||||
(isControlledValue ? (value as string | string[]) : defaultValue) ?? (multiSelect ? [] : "")
|
||||
);
|
||||
|
||||
// Controlled/uncontrolled open state
|
||||
const isControlledOpen = openProp !== undefined;
|
||||
const [internalOpen, setInternalOpen] = React.useState(false);
|
||||
const open = isControlledOpen ? (openProp as boolean) : internalOpen;
|
||||
|
||||
const setOpen = React.useCallback(
|
||||
(nextOpen: boolean) => {
|
||||
if (!isControlledOpen) {
|
||||
setInternalOpen(nextOpen);
|
||||
}
|
||||
onOpenChange?.(nextOpen);
|
||||
},
|
||||
[isControlledOpen, onOpenChange]
|
||||
);
|
||||
|
||||
// Update internal value when prop changes
|
||||
React.useEffect(() => {
|
||||
if (isControlledValue) {
|
||||
setInternalValue(value as string | string[]);
|
||||
}
|
||||
}, [isControlledValue, value]);
|
||||
|
||||
const handleValueChange = React.useCallback(
|
||||
(newValue: string) => {
|
||||
if (multiSelect) {
|
||||
// Functional update to avoid stale closures
|
||||
if (!isControlledValue) {
|
||||
setInternalValue((prev) => {
|
||||
const currentValues = Array.isArray(prev) ? (prev as string[]) : [];
|
||||
const isSelected = currentValues.includes(newValue);
|
||||
|
||||
if (!isSelected) {
|
||||
if (maxSelections && currentValues.length >= maxSelections) {
|
||||
return currentValues; // limit reached
|
||||
}
|
||||
const updated = [...currentValues, newValue];
|
||||
onValueChange?.(updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
const updated = currentValues.filter((v) => v !== newValue);
|
||||
onValueChange?.(updated);
|
||||
return updated;
|
||||
});
|
||||
} else {
|
||||
// Controlled value: compute next and notify only
|
||||
const currentValues = Array.isArray(internalValue) ? (internalValue as string[]) : [];
|
||||
const isSelected = currentValues.includes(newValue);
|
||||
let updated: string[];
|
||||
if (isSelected) {
|
||||
updated = currentValues.filter((v) => v !== newValue);
|
||||
} else {
|
||||
if (maxSelections && currentValues.length >= maxSelections) {
|
||||
return;
|
||||
}
|
||||
updated = [...currentValues, newValue];
|
||||
}
|
||||
onValueChange?.(updated);
|
||||
}
|
||||
} else {
|
||||
if (!isControlledValue) {
|
||||
setInternalValue(newValue);
|
||||
}
|
||||
(newValue: string | string[]) => {
|
||||
onValueChange?.(newValue);
|
||||
setOpen(false);
|
||||
}
|
||||
},
|
||||
[multiSelect, isControlledValue, internalValue, maxSelections, onValueChange, setOpen]
|
||||
);
|
||||
|
||||
const handleRemoveSelection = React.useCallback(
|
||||
(valueToRemove: string) => {
|
||||
if (!multiSelect) return;
|
||||
|
||||
if (!isControlledValue) {
|
||||
setInternalValue((prev) => {
|
||||
const currentValues = Array.isArray(prev) ? (prev as string[]) : [];
|
||||
const updated = currentValues.filter((v) => v !== valueToRemove);
|
||||
onValueChange?.(updated);
|
||||
return updated;
|
||||
});
|
||||
} else {
|
||||
const currentValues = Array.isArray(internalValue) ? (internalValue as string[]) : [];
|
||||
const updated = currentValues.filter((v) => v !== valueToRemove);
|
||||
onValueChange?.(updated);
|
||||
}
|
||||
},
|
||||
[multiSelect, isControlledValue, internalValue, onValueChange]
|
||||
);
|
||||
|
||||
const contextValue = React.useMemo<ComboboxContextType>(
|
||||
() => ({
|
||||
value: internalValue,
|
||||
onValueChange,
|
||||
multiSelect,
|
||||
maxSelections,
|
||||
disabled,
|
||||
open,
|
||||
setOpen,
|
||||
handleValueChange,
|
||||
handleRemoveSelection,
|
||||
}),
|
||||
[
|
||||
internalValue,
|
||||
onValueChange,
|
||||
multiSelect,
|
||||
maxSelections,
|
||||
disabled,
|
||||
open,
|
||||
setOpen,
|
||||
handleValueChange,
|
||||
handleRemoveSelection,
|
||||
]
|
||||
[onValueChange]
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboboxContext.Provider value={contextValue}>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
{children}
|
||||
</Popover>
|
||||
</ComboboxContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxButton({ className, children, disabled = false }: ComboboxButtonProps) {
|
||||
const { disabled: ctxDisabled, open } = useComboboxContext();
|
||||
const isDisabled = disabled || ctxDisabled;
|
||||
return (
|
||||
<Popover.Button
|
||||
disabled={isDisabled}
|
||||
aria-disabled={isDisabled || undefined}
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={open}
|
||||
className={className}
|
||||
<BaseCombobox.Root
|
||||
value={value}
|
||||
defaultValue={defaultValue}
|
||||
onValueChange={handleValueChange}
|
||||
multiple={multiSelect}
|
||||
disabled={disabled}
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
{children}
|
||||
</Popover.Button>
|
||||
</BaseCombobox.Root>
|
||||
);
|
||||
}
|
||||
|
||||
// Trigger button component
|
||||
const ComboboxButton = React.forwardRef<HTMLButtonElement, ComboboxButtonProps>(
|
||||
({ className, children, disabled = false }, ref) => (
|
||||
<BaseCombobox.Trigger ref={ref} disabled={disabled} className={className}>
|
||||
{children}
|
||||
</BaseCombobox.Trigger>
|
||||
)
|
||||
);
|
||||
|
||||
// Options popup component
|
||||
function ComboboxOptions({
|
||||
children,
|
||||
showSearch = false,
|
||||
searchPlaceholder,
|
||||
maxHeight,
|
||||
maxHeight = "lg",
|
||||
className,
|
||||
inputClassName,
|
||||
optionsContainerClassName,
|
||||
emptyMessage,
|
||||
positionerClassName,
|
||||
searchQuery: controlledSearchQuery,
|
||||
onSearchQueryChange,
|
||||
}: ComboboxOptionsProps) {
|
||||
const { multiSelect } = useComboboxContext();
|
||||
return (
|
||||
<Popover.Panel sideOffset={8} className={cn(className)} positionerClassName={positionerClassName}>
|
||||
<Command>
|
||||
{showSearch && <Command.Input placeholder={searchPlaceholder} className={cn(inputClassName)} />}
|
||||
<Command.List
|
||||
className={cn(
|
||||
{
|
||||
"max-h-60": maxHeight === "lg",
|
||||
"max-h-48": maxHeight === "md",
|
||||
"max-h-36": maxHeight === "rg",
|
||||
"max-h-28": maxHeight === "sm",
|
||||
// const [searchQuery, setSearchQuery] = React.useState("");
|
||||
const [internalSearchQuery, setInternalSearchQuery] = React.useState("");
|
||||
|
||||
const searchQuery = controlledSearchQuery !== undefined ? controlledSearchQuery : internalSearchQuery;
|
||||
|
||||
const setSearchQuery = React.useCallback(
|
||||
(query: string) => {
|
||||
if (onSearchQueryChange) {
|
||||
onSearchQueryChange(query);
|
||||
} else {
|
||||
setInternalSearchQuery(query);
|
||||
}
|
||||
},
|
||||
optionsContainerClassName
|
||||
[onSearchQueryChange]
|
||||
);
|
||||
|
||||
// Filter children based on search query
|
||||
const filteredChildren = React.useMemo(() => {
|
||||
if (!showSearch || !searchQuery) return children;
|
||||
|
||||
return React.Children.toArray(children).filter((child) => {
|
||||
if (!React.isValidElement(child)) return true;
|
||||
|
||||
// Extract text content from child to search against
|
||||
const getTextContent = (node: React.ReactNode): string => {
|
||||
if (typeof node === "string") return node;
|
||||
if (typeof node === "number") return String(node);
|
||||
if (React.isValidElement(node) && node.props.children) {
|
||||
return getTextContent(node.props.children);
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
return node.map(getTextContent).join(" ");
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const textContent = getTextContent(child.props.children);
|
||||
const value = child.props.value || "";
|
||||
|
||||
const searchLower = searchQuery.toLowerCase();
|
||||
return textContent.toLowerCase().includes(searchLower) || String(value).toLowerCase().includes(searchLower);
|
||||
});
|
||||
}, [children, searchQuery, showSearch]);
|
||||
|
||||
return (
|
||||
<BaseCombobox.Portal>
|
||||
<BaseCombobox.Positioner sideOffset={8} className={positionerClassName}>
|
||||
<BaseCombobox.Popup
|
||||
className={cn("rounded-md border border-custom-border-200 bg-custom-background-100 p-1 shadow-lg", className)}
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
{showSearch && (
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-custom-text-400" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder={searchPlaceholder}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className={cn(
|
||||
"w-full rounded border border-custom-border-100 bg-custom-background-90 py-1.5 pl-8 pr-2 text-sm outline-none placeholder:text-custom-text-400",
|
||||
inputClassName
|
||||
)}
|
||||
role="listbox"
|
||||
aria-multiselectable={multiSelect || undefined}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<BaseCombobox.List
|
||||
className={cn("overflow-auto outline-none", MAX_HEIGHT_CLASSES[maxHeight], optionsContainerClassName)}
|
||||
>
|
||||
{filteredChildren}
|
||||
{showSearch && React.Children.count(filteredChildren) === 0 && (
|
||||
<div className="px-2 py-1.5 text-sm text-custom-text-400">{emptyMessage || "No results found"}</div>
|
||||
)}
|
||||
</BaseCombobox.List>
|
||||
</div>
|
||||
</BaseCombobox.Popup>
|
||||
</BaseCombobox.Positioner>
|
||||
</BaseCombobox.Portal>
|
||||
);
|
||||
}
|
||||
|
||||
// Individual option component
|
||||
function ComboboxOption({ value, children, disabled, className }: ComboboxOptionProps) {
|
||||
return (
|
||||
<BaseCombobox.Item
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
className={cn("cursor-pointer rounded px-2 py-1.5 text-sm outline-none transition-colors", className)}
|
||||
>
|
||||
{children}
|
||||
</Command.List>
|
||||
<Command.Empty>{emptyMessage ?? "No options found."}</Command.Empty>
|
||||
</Command>
|
||||
</Popover.Panel>
|
||||
</BaseCombobox.Item>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxOption({ value, children, disabled, className }: ComboboxOptionProps) {
|
||||
const { handleValueChange, multiSelect, maxSelections, value: selectedValue } = useComboboxContext();
|
||||
|
||||
const stringValue = value;
|
||||
const isSelected = React.useMemo(() => {
|
||||
if (!multiSelect) return false;
|
||||
return Array.isArray(selectedValue) ? (selectedValue as string[]).includes(stringValue) : false;
|
||||
}, [multiSelect, selectedValue, stringValue]);
|
||||
|
||||
const reachedMax = React.useMemo(() => {
|
||||
if (!multiSelect || !maxSelections) return false;
|
||||
const currentLength = Array.isArray(selectedValue) ? (selectedValue as string[]).length : 0;
|
||||
return currentLength >= maxSelections && !isSelected;
|
||||
}, [multiSelect, maxSelections, selectedValue, isSelected]);
|
||||
|
||||
const isDisabled = disabled || reachedMax;
|
||||
|
||||
return (
|
||||
<Command.Item value={stringValue} disabled={isDisabled} onSelect={handleValueChange} className={className}>
|
||||
{children}
|
||||
</Command.Item>
|
||||
);
|
||||
}
|
||||
|
||||
// compound component
|
||||
const Combobox = Object.assign(ComboboxComponent, {
|
||||
// Compound component export
|
||||
const Combobox = Object.assign(ComboboxRoot, {
|
||||
Button: ComboboxButton,
|
||||
Options: ComboboxOptions,
|
||||
Option: ComboboxOption,
|
||||
|
|
|
|||
46
pnpm-lock.yaml
generated
46
pnpm-lock.yaml
generated
|
|
@ -995,8 +995,8 @@ importers:
|
|||
packages/propel:
|
||||
dependencies:
|
||||
'@base-ui-components/react':
|
||||
specifier: ^1.0.0-beta.2
|
||||
version: 1.0.0-beta.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: 1.0.0-beta.3
|
||||
version: 1.0.0-beta.3(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@plane/constants':
|
||||
specifier: workspace:*
|
||||
version: link:../constants
|
||||
|
|
@ -1504,8 +1504,8 @@ packages:
|
|||
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@base-ui-components/react@1.0.0-beta.2':
|
||||
resolution: {integrity: sha512-jfAUfSgXvsfr8mQi7r/6gLG8U1Ybr77NN8WK5IXXM0c/hBvFDBtvUfwDJACV0gXiYbSKpA+dRzZz01V1tULobA==}
|
||||
'@base-ui-components/react@1.0.0-beta.3':
|
||||
resolution: {integrity: sha512-4sAq6zmDA9ixV2HRjjeM1+tSEw5R6nvGjXUQmFoQnC3DZLEUdwO94gWDmUDdpoDuChn27jdbaJs9F0Ih4w2UAA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
|
|
@ -1515,8 +1515,8 @@ packages:
|
|||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@base-ui-components/utils@0.1.0':
|
||||
resolution: {integrity: sha512-9+uaWyF1o/PgXqHLJnC81IIG0HlV3o9eFCQ5hWZDMx5NHrFk0rrwqEFGQOB8lti/rnbxNPi+kYYw1D4e8xSn/Q==}
|
||||
'@base-ui-components/utils@0.1.1':
|
||||
resolution: {integrity: sha512-HWXZA8upEKgrdL1rQqxWu1H+2tB2cXzY2jCxvgnpUv3eoWN2jldhXxMZnXIjZF7jahGxSWXfSIM/qskiTWFFxA==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
react: ^17 || ^18 || ^19
|
||||
|
|
@ -1627,14 +1627,14 @@ packages:
|
|||
peerDependencies:
|
||||
'@noble/ciphers': ^1.0.0
|
||||
|
||||
'@emnapi/core@1.5.0':
|
||||
resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==}
|
||||
'@emnapi/core@1.4.5':
|
||||
resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==}
|
||||
|
||||
'@emnapi/runtime@1.5.0':
|
||||
resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
|
||||
|
||||
'@emnapi/wasi-threads@1.1.0':
|
||||
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
|
||||
'@emnapi/wasi-threads@1.0.4':
|
||||
resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==}
|
||||
|
||||
'@emotion/babel-plugin@11.13.5':
|
||||
resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
|
||||
|
|
@ -3634,8 +3634,8 @@ packages:
|
|||
'@tsconfig/node16@1.0.4':
|
||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||
|
||||
'@tybys/wasm-util@0.10.1':
|
||||
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
||||
'@tybys/wasm-util@0.10.0':
|
||||
resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==}
|
||||
|
||||
'@types/aria-query@5.0.4':
|
||||
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
||||
|
|
@ -8582,10 +8582,10 @@ snapshots:
|
|||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.27.1
|
||||
|
||||
'@base-ui-components/react@1.0.0-beta.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@base-ui-components/react@1.0.0-beta.3(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.10
|
||||
'@base-ui-components/utils': 0.1.0(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@base-ui-components/utils': 0.1.1(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@floating-ui/utils': 0.2.10
|
||||
react: 18.3.1
|
||||
|
|
@ -8596,7 +8596,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/react': 18.3.11
|
||||
|
||||
'@base-ui-components/utils@0.1.0(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@base-ui-components/utils@0.1.1(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.10
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
|
@ -8730,9 +8730,9 @@ snapshots:
|
|||
dependencies:
|
||||
'@noble/ciphers': 1.3.0
|
||||
|
||||
'@emnapi/core@1.5.0':
|
||||
'@emnapi/core@1.4.5':
|
||||
dependencies:
|
||||
'@emnapi/wasi-threads': 1.1.0
|
||||
'@emnapi/wasi-threads': 1.0.4
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
|
|
@ -8741,7 +8741,7 @@ snapshots:
|
|||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/wasi-threads@1.1.0':
|
||||
'@emnapi/wasi-threads@1.0.4':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
|
@ -9311,16 +9311,16 @@ snapshots:
|
|||
|
||||
'@napi-rs/wasm-runtime@0.2.12':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.5.0
|
||||
'@emnapi/core': 1.4.5
|
||||
'@emnapi/runtime': 1.5.0
|
||||
'@tybys/wasm-util': 0.10.1
|
||||
'@tybys/wasm-util': 0.10.0
|
||||
optional: true
|
||||
|
||||
'@napi-rs/wasm-runtime@1.0.5':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.5.0
|
||||
'@emnapi/core': 1.4.5
|
||||
'@emnapi/runtime': 1.5.0
|
||||
'@tybys/wasm-util': 0.10.1
|
||||
'@tybys/wasm-util': 0.10.0
|
||||
optional: true
|
||||
|
||||
'@next/env@14.2.32': {}
|
||||
|
|
@ -10782,7 +10782,7 @@ snapshots:
|
|||
'@tsconfig/node16@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@tybys/wasm-util@0.10.1':
|
||||
'@tybys/wasm-util@0.10.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue