diff --git a/.gitignore b/.gitignore index 39633b2..39d49f7 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ node_modules # Build artifacts /examples/static /lib + +test/__screenshots__ diff --git a/package.json b/package.json index 567c36f..0272f9c 100644 --- a/package.json +++ b/package.json @@ -89,9 +89,10 @@ }, "dependencies": { "@babel/runtime": "^7.26.7", - "@popperjs/core": "^2.11.8", + "@floating-ui/dom": "^1.7.4", "@restart/hooks": "^0.6.2", "@types/warning": "^3.0.3", + "clsx": "^2.1.1", "dequal": "^2.0.3", "dom-helpers": "^6.0.1", "uncontrollable": "^9.0.0", @@ -113,6 +114,7 @@ "@eslint/js": "^9.20.0", "@rollup/plugin-node-resolve": "^16.0.0", "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.6.1", "@types/react": "^19.1.8", @@ -121,8 +123,8 @@ "@typescript-eslint/eslint-plugin": "^8.23.0", "@typescript-eslint/parser": "^8.23.0", "@vitejs/plugin-react": "^4.4.1", - "@vitest/browser": "^3.1.3", - "@vitest/coverage-istanbul": "3.1.3", + "@vitest/browser": "3.2.4", + "@vitest/coverage-istanbul": "3.2.4", "babel-eslint": "^10.1.0", "babel-preset-env-modules": "^1.0.1", "cross-env": "^7.0.3", @@ -134,6 +136,7 @@ "gh-pages": "^3.1.0", "globals": "^15.14.0", "hookem": "^3.0.4", + "jsdom": "^27.0.0", "lint-staged": "^15.4.3", "playwright": "^1.50.1", "prettier": "^3.4.2", @@ -144,7 +147,7 @@ "rollup": "^4.34.6", "typescript": "^5.7.3", "typescript-eslint": "^8.23.0", - "vitest": "^3.1.3" + "vitest": "3.2.4" }, "bugs": { "url": "https://github.com/react-restart/ui/issues" diff --git a/src/index.ts b/src/index.ts index b9d7dcf..1065e8f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ export { useDropdownItem } from './DropdownItem.js'; export { default as Modal, type ModalProps } from './Modal.js'; export { default as Overlay, type OverlayProps } from './Overlay.js'; export { default as Portal, type PortalProps } from './Portal.js'; +export { default as usePopper } from './usePopper.js'; export { default as useRootClose, type RootCloseOptions, diff --git a/src/popper.ts b/src/popper.ts index 758294f..b32fe30 100644 --- a/src/popper.ts +++ b/src/popper.ts @@ -1,31 +1,197 @@ -// Since tsconfig is set for nodenext, these imports are resolving with a { default: ... } object, which -// messes up the types. -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import arrow from '@popperjs/core/lib/modifiers/arrow.js'; -import computeStyles from '@popperjs/core/lib/modifiers/computeStyles.js'; -import eventListeners from '@popperjs/core/lib/modifiers/eventListeners.js'; -import flip from '@popperjs/core/lib/modifiers/flip.js'; -import hide from '@popperjs/core/lib/modifiers/hide.js'; -import offset from '@popperjs/core/lib/modifiers/offset.js'; -import popperOffsets from '@popperjs/core/lib/modifiers/popperOffsets.js'; -import preventOverflow from '@popperjs/core/lib/modifiers/preventOverflow.js'; -import { placements } from '@popperjs/core/lib/enums.js'; -import { popperGenerator } from '@popperjs/core/lib/popper-base.js'; - -// For the common JS build we will turn this file into a bundle with no imports. -// This is b/c the Popper lib is all esm files, and would break in a common js only environment -export const createPopper = popperGenerator({ - defaultModifiers: [ - hide, - popperOffsets, - computeStyles, - eventListeners, - offset, - flip, - preventOverflow, - arrow, - ], -}); - -export { placements }; +import { + computePosition, + offset, + flip, + shift, + arrow, + hide, + autoUpdate, + Placement, + Middleware, + OffsetOptions, + Strategy, + limitShift, + MiddlewareState, + AutoUpdateOptions, + autoPlacement, +} from '@floating-ui/dom'; + +// Mimic Popper’s placements enum +export const placements = { + top: 'top', + bottom: 'bottom', + right: 'right', + left: 'left', + 'top-start': 'top-start', + 'top-end': 'top-end', + 'bottom-start': 'bottom-start', + 'bottom-end': 'bottom-end', + 'right-start': 'right-start', + 'right-end': 'right-end', + 'left-start': 'left-start', + 'left-end': 'left-end', +}; + +export interface Modifier { + name: Name; + enabled?: boolean; + fn: (arg0: MiddlewareState) => ReturnType; + options?: Partial; +} + +export type PopperModifierLikeMiddleware = Middleware & { + enabled?: boolean; + options?: Modifier['options']; +}; + +export function createPopper( + reference: HTMLElement, + popper: HTMLElement, + options?: { + placement?: Placement; + modifiers?: PopperModifierLikeMiddleware[]; + strategy?: Strategy; + }, +) { + const { + placement = 'bottom', + modifiers = [], + strategy = 'absolute', + } = options || {}; + + // Detect arrow element from modifiers if present + const arrowModifier = modifiers.find((m) => m.name === 'arrow'); + + // Default Popper-like values + const defaultOffset = 0; + const defaultArrowPadding = 5; + + const offsetValue = () => { + let offsetValue: OffsetOptions = defaultOffset; + const o = modifiers.find((m) => m.name === 'offset'); + if (o?.options?.offset) { + if (Array.isArray(o?.options?.offset)) { + if (o.options.offset.length == 2) { + offsetValue = { + crossAxis: o.options.offset[0], + mainAxis: o.options.offset[1], + }; + } else { + offsetValue = { mainAxis: o.options.offset[0] }; + } + } + } + return offsetValue; + }; + + const flipMiddleware = () => { + const flipModifier = modifiers.find((m) => m.name === 'flip'); + if (flipModifier?.enabled !== false) { + return flip({ + fallbackPlacements: flipModifier?.options?.fallbackPlacements, + //Rest of the options are not supported by Floating UI + }); + } + return undefined; + }; + + const shiftMiddleware = () => { + const preventOverflowModifier = modifiers.find( + (m) => m.name === 'preventOverflow', + ); + if (preventOverflowModifier?.enabled !== false) { + const { + mainAxis = true, + altAxis = false, + boundary, + rootBoundary, + padding = 0, + tether = true, + altBoundary = false, + } = preventOverflowModifier?.options || {}; + + return shift({ + mainAxis, + crossAxis: altAxis, + boundary, + rootBoundary, + padding, + altBoundary, + limiter: tether ? limitShift() : undefined, + }); + } + return undefined; + }; + + // Map Popper modifiers to Floating UI middleware + const middleware: Middleware[] = [ + modifiers.find((m) => m.name === 'hide') ? hide() : undefined, + offset(offsetValue()), + flipMiddleware(), + shiftMiddleware(), + arrowModifier?.options?.element + ? arrow({ + element: arrowModifier?.options?.element, + padding: arrowModifier?.options?.padding ?? defaultArrowPadding, + }) + : undefined, + ...modifiers.filter( + (m) => + ![ + 'offset', + 'flip', + 'preventOverflow', + 'arrow', + 'hide', + 'eventListeners', + ].includes(m.name), + ), + (placement as Placement & 'auto') === 'auto' ? autoPlacement() : undefined, + ].filter(Boolean) as Middleware[]; + + const update = async (): Promise => { + const { x, y, middlewareData } = await computePosition(reference, popper, { + placement, + middleware, + }); + + Object.assign(popper.style, { + left: `${x}px`, + top: `${y}px`, + position: strategy, + }); + + if (arrowModifier?.options?.element && middlewareData.arrow) { + const { x: arrowX, y: arrowY } = middlewareData.arrow as { + x: number | null; + y: number | null; + }; + Object.assign(arrowModifier.options.element.style, { + left: arrowX != null ? `${arrowX}px` : '', + top: arrowY != null ? `${arrowY}px` : '', + }); + } + }; + + let autoUpdateOptions: AutoUpdateOptions = {}; + const eventListenersModifier = modifiers.find( + (m) => m.name === 'eventListeners', + ); + + if (eventListenersModifier?.enabled === false) { + autoUpdateOptions = { + ancestorScroll: false, + ancestorResize: false, + }; + } else { + autoUpdateOptions = { + ancestorScroll: eventListenersModifier?.options?.scroll ?? true, + ancestorResize: eventListenersModifier?.options?.resize ?? true, + }; + } + + const cleanup = autoUpdate(reference, popper, update, autoUpdateOptions); + update(); + + return { update, cleanup }; +} diff --git a/src/usePopper.ts b/src/usePopper.ts index 7b3e0d9..8b6da44 100644 --- a/src/usePopper.ts +++ b/src/usePopper.ts @@ -1,117 +1,79 @@ -import * as Popper from '@popperjs/core'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { dequal } from 'dequal'; +//import * as Popper from '@popperjs/core'; +import { useCallback, useEffect, useRef, useState } from 'react'; import useSafeState from '@restart/hooks/useSafeState'; -import { createPopper } from './popper.js'; +import { + createPopper, + PopperModifierLikeMiddleware, + Modifier, +} from './popper.js'; +import type { Placement } from '@floating-ui/dom'; +import type { Middleware, Strategy } from '@floating-ui/core'; -const disabledApplyStylesModifier = { - name: 'applyStyles', - enabled: false, - phase: 'afterWrite', - fn: () => undefined, -}; - -// until docjs supports type exports... -export type Modifier = Popper.Modifier< - Name, - Options ->; -export type Options = Popper.Options; -export type Instance = Popper.Instance; -export type Placement = Popper.Placement; -export type VirtualElement = Popper.VirtualElement; -export type State = Popper.State; - -export type OffsetValue = [ - number | null | undefined, - number | null | undefined, -]; -export type OffsetFunction = (details: { - popper: Popper.Rect; - reference: Popper.Rect; - placement: Placement; -}) => OffsetValue; - -export type Offset = OffsetFunction | OffsetValue; +export type { Placement, OffsetOptions as Offset } from '@floating-ui/dom'; +export type { Modifier } from './popper.js'; export type ModifierMap = Record>>; export type Modifiers = - | Popper.Options['modifiers'] + | Partial>[] | Record>>; -export type UsePopperOptions = Omit< - Options, - 'modifiers' | 'placement' | 'strategy' -> & { - enabled?: boolean; - placement?: Options['placement']; - strategy?: Options['strategy']; - modifiers?: Options['modifiers']; +// VirtualElement compatible with Floating UI +export type VirtualElement = { + getBoundingClientRect(): DOMRect; + contextElement?: Element; }; +// Options for usePopper hook +export interface UsePopperOptions { + enabled?: boolean; + placement?: Placement; + strategy?: Strategy; + modifiers?: Modifiers; +} + +// Popper state returned by the hook export interface UsePopperState { placement: Placement; update: () => void; - forceUpdate: () => void; attributes: Record>; styles: Record>; - state?: State; + state?: any; } -const ariaDescribedByModifier: Modifier< - 'ariaDescribedBy', - Record -> = { - name: 'ariaDescribedBy', - enabled: true, - phase: 'afterWrite', - effect: - ({ state }) => - () => { - const { reference, popper } = state.elements; - if ('removeAttribute' in reference) { - const ids = (reference.getAttribute('aria-describedby') || '') - .split(',') - .filter((id) => id.trim() !== popper.id); +const EMPTY_MODIFIERS: Modifier[] = []; - if (!ids.length) reference.removeAttribute('aria-describedby'); - else reference.setAttribute('aria-describedby', ids.join(',')); - } - }, - fn: ({ state }) => { - const { popper, reference } = state.elements; +function useAriaDescribedBy( + reference: HTMLElement | null, + popper: HTMLElement | null, +) { + useEffect(() => { + if (!reference || !popper) return; const role = popper.getAttribute('role')?.toLowerCase(); - if (popper.id && role === 'tooltip' && 'setAttribute' in reference) { const ids = reference.getAttribute('aria-describedby'); - if (ids && ids.split(',').indexOf(popper.id) !== -1) { - return; + if (!ids || !ids.split(',').includes(popper.id)) { + reference.setAttribute( + 'aria-describedby', + ids ? `${ids},${popper.id}` : popper.id, + ); } - - reference.setAttribute( - 'aria-describedby', - ids ? `${ids},${popper.id}` : popper.id, - ); } - }, -}; -const EMPTY_MODIFIERS = [] as any; + return () => { + if ('removeAttribute' in reference) { + const ids = (reference.getAttribute('aria-describedby') || '') + .split(',') + .filter((id) => id.trim() !== popper.id); + if (!ids.length) reference.removeAttribute('aria-describedby'); + else reference.setAttribute('aria-describedby', ids.join(',')); + } + }; + }, [reference, popper]); +} + /** - * Position an element relative some reference element using Popper.js - * - * @param referenceElement - * @param popperElement - * @param {object} options - * @param {object=} options.modifiers Popper.js modifiers - * @param {boolean=} options.enabled toggle the popper functionality on/off - * @param {string=} options.placement The popper element placement relative to the reference element - * @param {string=} options.strategy the positioning strategy - * @param {function=} options.onCreate called when the popper is created - * @param {function=} options.onUpdate called when the popper is updated - * - * @returns {UsePopperState} The popper state + * React hook for positioning a floating element relative to a reference element using Floating UI */ function usePopper( referenceElement: VirtualElement | null | undefined, @@ -119,110 +81,80 @@ function usePopper( { enabled = true, placement = 'bottom', - strategy = 'absolute', modifiers = EMPTY_MODIFIERS, - ...config + strategy = 'absolute', }: UsePopperOptions = {}, ): UsePopperState { - const prevModifiers = useRef(modifiers); - const popperInstanceRef = useRef(undefined); + const popperInstanceRef = useRef(undefined); const update = useCallback(() => { - popperInstanceRef.current?.update(); - }, []); - - const forceUpdate = useCallback(() => { - popperInstanceRef.current?.forceUpdate(); + popperInstanceRef.current?.update?.(); }, []); const [popperState, setState] = useSafeState( useState({ placement, update, - forceUpdate, attributes: {}, - styles: { - popper: {}, - arrow: {}, - }, + styles: { popper: {}, arrow: {} }, }), ); - const updateModifier = useMemo>( - () => ({ - name: 'updateStateModifier', - enabled: true, - phase: 'write', - requires: ['computeStyles'], - fn: ({ state }) => { - const styles: UsePopperState['styles'] = {}; - const attributes: UsePopperState['attributes'] = {}; - - Object.keys(state.elements).forEach((element) => { - styles[element] = state.styles[element]; - attributes[element] = state.attributes[element]; - }); - - setState({ - state, - styles, - attributes, - update, - forceUpdate, - placement: state.placement, - }); - }, - }), - [update, forceUpdate, setState], + useAriaDescribedBy( + referenceElement as HTMLElement | null, + popperElement as HTMLElement | null, ); - const nextModifiers = useMemo(() => { - if (!dequal(prevModifiers.current, modifiers)) { - prevModifiers.current = modifiers; - } - return prevModifiers.current!; - }, [modifiers]); - - useEffect(() => { - if (!popperInstanceRef.current || !enabled) return; - - popperInstanceRef.current.setOptions({ - placement, - strategy, - modifiers: [ - ...nextModifiers, - updateModifier, - disabledApplyStylesModifier, - ], - }); - }, [strategy, placement, updateModifier, enabled, nextModifiers]); + const updateModifier: Middleware = { + name: 'updateStateModifier', + fn(args) { + setState({ + ...popperState, + styles: { + popper: { + top: String(args.y ?? 0), + left: String(args.x ?? 0), + position: args.strategy, + }, + }, + state: args, + placement: args.placement, + }); + + return {}; + }, + }; + // Create the popper instance useEffect(() => { - if (!enabled || referenceElement == null || popperElement == null) { - return undefined; - } - - popperInstanceRef.current = createPopper(referenceElement, popperElement, { - ...config, - placement, - strategy, - modifiers: [...nextModifiers, ariaDescribedByModifier, updateModifier], - }); + if (!enabled || referenceElement == null || popperElement == null) return; + + popperInstanceRef.current?.cleanup?.(); + popperInstanceRef.current = createPopper( + referenceElement as any, + popperElement, + { + placement, + strategy, + modifiers: [ + ...((Array.isArray(modifiers) + ? modifiers + : Object.values(modifiers)) as PopperModifierLikeMiddleware[]), + updateModifier, + ], + }, + ); return () => { - if (popperInstanceRef.current != null) { - popperInstanceRef.current.destroy(); - popperInstanceRef.current = undefined; - - setState((s) => ({ - ...s, - attributes: {}, - styles: { popper: {} }, - })); - } + popperInstanceRef.current?.cleanup?.(); + popperInstanceRef.current = undefined; + setState((s) => ({ + ...s, + attributes: {}, + styles: { popper: {}, arrow: {} }, + })); }; - // This is only run once to _create_ the popper - }, [enabled, referenceElement, popperElement]); + }, [placement, strategy, enabled, referenceElement, popperElement]); return popperState; } diff --git a/test/DropdownSpec.tsx b/test/DropdownSpec.tsx index 9dcba60..6acc37d 100644 --- a/test/DropdownSpec.tsx +++ b/test/DropdownSpec.tsx @@ -441,7 +441,7 @@ describe('', () => { describe('popper config', () => { it('can add modifiers', async () => { - const spy = vi.fn(); + const spy = vi.fn(() => ({})); const popper = { modifiers: [ { @@ -465,7 +465,7 @@ describe('', () => { , ); - await waitFor(() => expect(spy).toHaveBeenCalledOnce()); + await waitFor(() => expect(spy).toHaveBeenCalled()); }); }); }); diff --git a/test/globals.d.ts b/test/globals.d.ts new file mode 100644 index 0000000..7b0828b --- /dev/null +++ b/test/globals.d.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/test/usePopperSpec.tsx b/test/usePopperSpec.tsx index 7b2d331..09c6f6e 100644 --- a/test/usePopperSpec.tsx +++ b/test/usePopperSpec.tsx @@ -1,6 +1,65 @@ -import { renderHook, waitFor } from '@testing-library/react'; +import { fireEvent, render, renderHook, waitFor } from '@testing-library/react'; import { expect, describe, it, beforeEach, afterEach } from 'vitest'; -import usePopper from '../src/usePopper'; +import * as matchers from '@testing-library/jest-dom/matchers'; +import { useState, useRef } from 'react'; +import useCallbackRef from '@restart/hooks/useCallbackRef'; +import clsx from 'clsx'; +import usePopper, { Modifier } from '../src/usePopper'; +expect.extend(matchers); + +const PopperComponent = ({ + modifiers, +}: { + modifiers: Partial>[]; +}) => { + const referenceRef = useRef(null); + const [popperElement, attachPopperRef] = useCallbackRef(); + const [arrowElement, attachArrowRef] = useCallbackRef(); + const [show, setShow] = useState(false); + + const { styles, placement } = usePopper(referenceRef.current, popperElement, { + enabled: show, + placement: 'right', + modifiers: [ + { name: 'arrow', options: { element: arrowElement } }, + ...modifiers, + ], + }); + + return ( +
+ + {show && ( + + ); +}; describe('usePopper', () => { const elements: Record = {}; @@ -27,7 +86,6 @@ describe('usePopper', () => { await waitFor(() => expect(result.current).toHaveProperty('update')); expect(result.current.update).toBeInstanceOf(Function); - expect(result.current.forceUpdate).toBeInstanceOf(Function); expect(result.current.styles).toHaveProperty('popper'); }); @@ -109,4 +167,73 @@ describe('usePopper', () => { elements.reference, ); }); + + it('renders floating element on hover at the right with 20px gap', async () => { + const { queryByRole, getByRole } = render( + , + ); + + // Initially tooltip is not in the DOM + expect(queryByRole('tooltip')).toBeNull(); + + const button = getByRole('button', { name: /hover me/i }); + + fireEvent.mouseEnter(button); + + // Tooltip should appear + const tooltip = getByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(tooltip).toHaveTextContent('Hi there!'); + + // Check tooltip position relative to button with 20 offset + const buttonRect = button.getBoundingClientRect(); + await waitFor(() => { + const tooltipRect = tooltip.getBoundingClientRect(); + expect(tooltipRect.left).not.toBe(0); + + // Assert that tooltip is to the right of button + expect(Math.abs(tooltipRect.left - (buttonRect.right + 20))).toBeLessThan( + 1, + ); + }); + + fireEvent.mouseLeave(button); + + // Tooltip should disappear + expect(queryByRole('tooltip')).toBeNull(); + }); + + it('can flip the floating element to fallback placement', async () => { + const { getByRole } = render( + , + ); + + const button = getByRole('button', { name: /hover me/i }); + button.style.width = '350px'; + fireEvent.mouseEnter(button); + + const tooltip = await waitFor(() => getByRole('tooltip')); + + await waitFor(() => { + const tooltipRect = tooltip.getBoundingClientRect(); + const buttonRect = button.getBoundingClientRect(); + + const tooltipCenterX = tooltipRect.left + tooltipRect.width / 2; + const buttonCenterX = buttonRect.left + buttonRect.width / 2; + + // Tooltip is horizontally aligned with the button + expect(Math.abs(tooltipCenterX - buttonCenterX)).toBeLessThan(1); + + // Tooltip is below the button + expect(tooltipRect.top).toBeGreaterThanOrEqual(buttonRect.bottom); + }); + }); + + //TODO: add test for layoutEvents and preventOverflow }); diff --git a/vitest.config.mts b/vitest.config.mts index aa3de0a..b62c9e6 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -5,16 +5,17 @@ export default defineConfig({ plugins: [react()], test: { include: ['test/**/*Spec.ts', 'test/**/*Spec.tsx'], + environment: 'jsdom', setupFiles: ['test/setup.ts'], browser: { enabled: true, - name: 'chromium', provider: 'playwright', - // https://playwright.dev - providerOptions: {}, + instances: [{ browser: 'chromium' }, { browser: 'firefox' }], }, coverage: { provider: 'istanbul', + reporter: ['text', 'lcov'], // lcov & json for VSCode + reportsDirectory: './coverage', exclude: [...coverageConfigDefaults.exclude, 'www/**', '**/*.js'], }, }, diff --git a/www/docs/usePopper.mdx b/www/docs/usePopper.mdx index e69de29..b2dc2ca 100644 --- a/www/docs/usePopper.mdx +++ b/www/docs/usePopper.mdx @@ -0,0 +1,105 @@ +# usePopper + +`usePopper` is a React hook that provides positioning logic using [Floating UI](https://floating-ui.com/). + +## Example + +```jsx live renderAsComponent +import { usePopper } from "@restart/ui"; +import useCallbackRef from "@restart/hooks/useCallbackRef"; +import clsx from "clsx"; +import Button from "../src/Button"; + +function Example() { + const referenceRef = useRef(null); + const [popperElement, attachPopperRef] = useCallbackRef(); + const [arrowElement, attachArrowRef] = useCallbackRef(); + const [show, setShow] = useState(true); + + const { styles, placement } = usePopper( + referenceRef.current, + popperElement, + { + enabled: show, + placement: "right", + modifiers: [ + { + name: "arrow", + options: { element: arrowElement }, + }, + { + name: "offset", + options: { + offset: [0, 100], + }, + }, + { + name: "preventOverflow", + options: { + padding: 8, + boundary: "viewport", + }, + }, + { + name: "eventListeners", + options: { + scroll: true, + resize: true, + }, + }, + { + name: "flip", + options: { + fallbackPlacements: ["top"], + }, + }, + ], + } + ); + + return ( +
+ + {show && ( + + ); +} + +``` diff --git a/www/src/LiveCodeblock.tsx b/www/src/LiveCodeblock.tsx index 07311ae..3e49a9c 100644 --- a/www/src/LiveCodeblock.tsx +++ b/www/src/LiveCodeblock.tsx @@ -13,6 +13,7 @@ import { import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as RestartUi from '@restart/ui'; +import useCallbackRef from '@restart/hooks/useCallbackRef'; import Button from './Button'; import Dropdown from './Dropdown'; import Tooltip from './Tooltip'; @@ -35,6 +36,7 @@ const LocalImports = { react: React, 'react-dom': ReactDOM, '@restart/ui': RestartUi, + '@restart/hooks/useCallbackRef': useCallbackRef, 'react-transition-group/Transition': Transition, 'dom-helpers/scrollParent': scrollParent, clsx, diff --git a/www/src/Tooltip.tsx b/www/src/Tooltip.tsx index f6730fb..199907f 100644 --- a/www/src/Tooltip.tsx +++ b/www/src/Tooltip.tsx @@ -3,7 +3,7 @@ import React from 'react'; const Tooltip = React.forwardRef( ({ children, arrowProps, popper, show: _, ...props }: any, ref: any) => ( -
+
=0.5.1" -fdir@^6.4.4: - version "6.4.4" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9" - integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== figures@^1.7.0: version "1.7.0" @@ -5255,6 +5556,13 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + html-entities@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" @@ -5307,6 +5615,14 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== +http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -5326,6 +5642,14 @@ http-proxy@^1.17.0: follow-redirects "^1.0.0" requires-port "^1.0.0" +https-proxy-agent@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" @@ -5343,6 +5667,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -5839,6 +6170,11 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-promise@^2.1.0: version "2.2.2" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" @@ -6071,6 +6407,11 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + js-yaml@^3.6.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" @@ -6086,6 +6427,32 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsdom@^27.0.0: + version "27.0.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-27.0.0.tgz#831fb76bcfde14b0d92aec1c2bfd8ea462f17eb9" + integrity sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A== + dependencies: + "@asamuzakjp/dom-selector" "^6.5.4" + cssstyle "^5.3.0" + data-urls "^6.0.0" + decimal.js "^10.5.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.6" + is-potential-custom-element-name "^1.0.1" + parse5 "^7.3.0" + rrweb-cssom "^0.8.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^6.0.0" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^8.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^15.0.0" + ws "^8.18.2" + xml-name-validator "^5.0.0" + jsesc@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" @@ -6448,11 +6815,16 @@ loose-envify@^1.0.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^3.1.0, loupe@^3.1.3: +loupe@^3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.3.tgz#042a8f7986d77f3d0f98ef7990a2b2fef18b0fd2" integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug== +loupe@^3.1.4: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -6470,6 +6842,11 @@ lru-cache@^11.0.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA== +lru-cache@^11.2.1: + version "11.2.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.2.tgz#40fd37edffcfae4b2940379c0722dc6eeaa75f24" + integrity sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -6559,6 +6936,11 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +mdn-data@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.2.tgz#9ae6c41a9e65adf61318b32bff7b64fbfb13f8cf" + integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -6844,10 +7226,10 @@ nanoid@^2.0.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== -nanoid@^3.3.8: - version "3.3.8" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== nanomatch@^1.2.9: version "1.2.13" @@ -7386,6 +7768,13 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse5@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" + integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== + dependencies: + entities "^6.0.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -7530,6 +7919,11 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + pidtree@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" @@ -7621,12 +8015,12 @@ possible-typed-array-names@^1.0.0: resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== -postcss@^8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.1.tgz#e2272a1f8a807fafa413218245630b5db10a3214" - integrity sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ== +postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== dependencies: - nanoid "^3.3.8" + nanoid "^3.3.11" picocolors "^1.1.1" source-map-js "^1.2.1" @@ -7719,6 +8113,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -8056,6 +8455,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -8180,7 +8584,7 @@ rimraf@^6.0.1: glob "^11.0.0" package-json-from-dist "^1.0.0" -rollup@^4.30.1, rollup@^4.34.6: +rollup@^4.34.6: version "4.34.6" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.6.tgz#a07e4d2621759e29034d909655e7a32eee9195c9" integrity sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ== @@ -8208,6 +8612,42 @@ rollup@^4.30.1, rollup@^4.34.6: "@rollup/rollup-win32-x64-msvc" "4.34.6" fsevents "~2.3.2" +rollup@^4.43.0: + version "4.52.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.52.2.tgz#43dd135805c919285376634c8520074c5eb7a91a" + integrity sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.52.2" + "@rollup/rollup-android-arm64" "4.52.2" + "@rollup/rollup-darwin-arm64" "4.52.2" + "@rollup/rollup-darwin-x64" "4.52.2" + "@rollup/rollup-freebsd-arm64" "4.52.2" + "@rollup/rollup-freebsd-x64" "4.52.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.52.2" + "@rollup/rollup-linux-arm-musleabihf" "4.52.2" + "@rollup/rollup-linux-arm64-gnu" "4.52.2" + "@rollup/rollup-linux-arm64-musl" "4.52.2" + "@rollup/rollup-linux-loong64-gnu" "4.52.2" + "@rollup/rollup-linux-ppc64-gnu" "4.52.2" + "@rollup/rollup-linux-riscv64-gnu" "4.52.2" + "@rollup/rollup-linux-riscv64-musl" "4.52.2" + "@rollup/rollup-linux-s390x-gnu" "4.52.2" + "@rollup/rollup-linux-x64-gnu" "4.52.2" + "@rollup/rollup-linux-x64-musl" "4.52.2" + "@rollup/rollup-openharmony-arm64" "4.52.2" + "@rollup/rollup-win32-arm64-msvc" "4.52.2" + "@rollup/rollup-win32-ia32-msvc" "4.52.2" + "@rollup/rollup-win32-x64-gnu" "4.52.2" + "@rollup/rollup-win32-x64-msvc" "4.52.2" + fsevents "~2.3.2" + +rrweb-cssom@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz#3021d1b4352fbf3b614aaeed0bc0d5739abe0bc2" + integrity sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw== + run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -8279,11 +8719,18 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + scheduler@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" @@ -8644,7 +9091,7 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" -source-map-js@^1.2.0, source-map-js@^1.2.1: +source-map-js@^1.0.1, source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -8783,7 +9230,7 @@ string-argv@^0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8818,6 +9265,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -8909,7 +9365,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8937,6 +9393,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -8971,6 +9434,13 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-literal@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.0.0.tgz#ce9c452a91a0af2876ed1ae4e583539a353df3fc" + integrity sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA== + dependencies: + js-tokens "^9.0.1" + strip-outer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" @@ -9050,6 +9520,11 @@ symbol-observable@^1.1.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + synckit@^0.9.1: version "0.9.2" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" @@ -9131,28 +9606,28 @@ tinyexec@^0.3.2: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== -tinyglobby@^0.2.13: - version "0.2.13" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e" - integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw== +tinyglobby@^0.2.14, tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: - fdir "^6.4.4" - picomatch "^4.0.2" + fdir "^6.5.0" + picomatch "^4.0.3" -tinypool@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" - integrity sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA== +tinypool@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== tinyrainbow@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== -tinyspy@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" - integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== +tinyspy@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-4.0.4.tgz#d77a002fb53a88aa1429b419c1c92492e0c81f78" + integrity sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q== title-case@^3.0.3: version "3.0.3" @@ -9161,6 +9636,18 @@ title-case@^3.0.3: dependencies: tslib "^2.0.3" +tldts-core@^7.0.16: + version "7.0.16" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-7.0.16.tgz#f94a42b1f571ee7e4d5c58a4a3486d557b093c14" + integrity sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA== + +tldts@^7.0.5: + version "7.0.16" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-7.0.16.tgz#8eecb4c15608a23e5b360d64d74f937fb9dbe6aa" + integrity sha512-5bdPHSwbKTeHmXrgecID4Ljff8rQjv7g8zKQPkCozRo2HWWni+p310FSn5ImI+9kWw9kK4lzOB5q/a6iv0IJsw== + dependencies: + tldts-core "^7.0.16" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -9210,6 +9697,20 @@ totalist@^3.0.0: resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== +tough-cookie@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-6.0.0.tgz#11e418b7864a2c0d874702bc8ce0f011261940e5" + integrity sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w== + dependencies: + tldts "^7.0.5" + +tr46@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-6.0.0.tgz#f5a1ae546a0adb32a277a2278d0d17fa2f9093e6" + integrity sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw== + dependencies: + punycode "^2.3.1" + trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -9558,55 +10059,67 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -vite-node@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.1.3.tgz#d021ced40b5a057305eaea9ce62c610c33b60a48" - integrity sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA== +vite-node@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" + integrity sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg== dependencies: cac "^6.7.14" - debug "^4.4.0" + debug "^4.4.1" es-module-lexer "^1.7.0" pathe "^2.0.3" - vite "^5.0.0 || ^6.0.0" - -"vite@^5.0.0 || ^6.0.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/vite/-/vite-6.1.0.tgz#00a4e99a23751af98a2e4701c65ba89ce23858a6" - integrity sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ== - dependencies: - esbuild "^0.24.2" - postcss "^8.5.1" - rollup "^4.30.1" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0": + version "7.1.7" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.7.tgz#ed3f9f06e21d6574fe1ad425f6b0912d027ffc13" + integrity sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA== + dependencies: + esbuild "^0.25.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" optionalDependencies: fsevents "~2.3.3" -vitest@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.1.3.tgz#0b0b01932408cd3af61867f4468d28bd83406ffb" - integrity sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw== - dependencies: - "@vitest/expect" "3.1.3" - "@vitest/mocker" "3.1.3" - "@vitest/pretty-format" "^3.1.3" - "@vitest/runner" "3.1.3" - "@vitest/snapshot" "3.1.3" - "@vitest/spy" "3.1.3" - "@vitest/utils" "3.1.3" +vitest@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.4.tgz#0637b903ad79d1539a25bc34c0ed54b5c67702ea" + integrity sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/expect" "3.2.4" + "@vitest/mocker" "3.2.4" + "@vitest/pretty-format" "^3.2.4" + "@vitest/runner" "3.2.4" + "@vitest/snapshot" "3.2.4" + "@vitest/spy" "3.2.4" + "@vitest/utils" "3.2.4" chai "^5.2.0" - debug "^4.4.0" + debug "^4.4.1" expect-type "^1.2.1" magic-string "^0.30.17" pathe "^2.0.3" + picomatch "^4.0.2" std-env "^3.9.0" tinybench "^2.9.0" tinyexec "^0.3.2" - tinyglobby "^0.2.13" - tinypool "^1.0.2" + tinyglobby "^0.2.14" + tinypool "^1.1.1" tinyrainbow "^2.0.0" - vite "^5.0.0 || ^6.0.0" - vite-node "3.1.3" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node "3.2.4" why-is-node-running "^2.3.0" +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" @@ -9628,6 +10141,11 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +webidl-conversions@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-8.0.0.tgz#821c92aa4f88d88a31264d887e244cb9655690c6" + integrity sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA== + webpack-dev-middleware@^3.7.2: version "3.7.3" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" @@ -9727,6 +10245,26 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^15.0.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-15.1.0.tgz#5c433439b9a5789eeb3806bbd0da89a8bd40b8d7" + integrity sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g== + dependencies: + tr46 "^6.0.0" + webidl-conversions "^8.0.0" + which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" @@ -9816,7 +10354,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -9842,6 +10380,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -9872,10 +10419,20 @@ ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^8.18.1: - version "8.18.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" - integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== +ws@^8.18.2: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xtend@~4.0.1: version "4.0.2"