From c0b8da9b8e93fdf1e6b7f10a39a4e3de97702512 Mon Sep 17 00:00:00 2001 From: Jenny Zhu Date: Thu, 17 Sep 2026 14:06:43 -0400 Subject: [PATCH 1/2] [FEATURE] UI customization. Add Box primitive component Signed-off-by: Jenny Zhu --- .../src/next/contexts/ComponentsContext.ts | 2 + .../src/next/primitives/Box/Box.stories.tsx | 255 ++++++++++++++++++ .../src/next/primitives/Box/Box.test.tsx | 120 +++++++++ components/src/next/primitives/Box/Box.tsx | 107 ++++++++ components/src/next/primitives/Box/box.css | 20 ++ components/src/next/primitives/Box/index.ts | 14 + components/src/next/primitives/defaults.ts | 3 +- .../src/next/primitives/exports.test.tsx | 9 +- components/src/next/primitives/index.ts | 1 + design-tokens/tsconfig.build.json | 1 + 10 files changed, 530 insertions(+), 2 deletions(-) create mode 100644 components/src/next/primitives/Box/Box.stories.tsx create mode 100644 components/src/next/primitives/Box/Box.test.tsx create mode 100644 components/src/next/primitives/Box/Box.tsx create mode 100644 components/src/next/primitives/Box/box.css create mode 100644 components/src/next/primitives/Box/index.ts diff --git a/components/src/next/contexts/ComponentsContext.ts b/components/src/next/contexts/ComponentsContext.ts index 0a397d38..709d94ab 100644 --- a/components/src/next/contexts/ComponentsContext.ts +++ b/components/src/next/contexts/ComponentsContext.ts @@ -15,6 +15,7 @@ import { createContext } from 'react'; import type { ComponentType, ReactNode, SVGProps } from 'react'; import type { AlertProps } from '../primitives/Alert'; +import type { BoxProps } from '../primitives/Box'; import type { ButtonProps } from '../primitives/Button'; import type { SpinnerProps } from '../primitives/Spinner'; @@ -22,6 +23,7 @@ export interface PersesComponents { Button: ComponentType; Alert: ComponentType; Spinner: ComponentType; + Box: ComponentType; } export interface PersesIcons { diff --git a/components/src/next/primitives/Box/Box.stories.tsx b/components/src/next/primitives/Box/Box.stories.tsx new file mode 100644 index 00000000..dbf300c7 --- /dev/null +++ b/components/src/next/primitives/Box/Box.stories.tsx @@ -0,0 +1,255 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Story } from '@ladle/react'; + +import { Box } from './Box'; +import type { SpacingToken } from './Box'; + +export const BasicBox: Story = () => ( + + This is a basic box with padding. + +); +BasicBox.storyName = 'Basic Box'; + +export const DisplayVariations: Story = () => ( +
+
+

Display: block

+ + Block box + +
+
+

Display: flex

+ + + Item 1 + + + Item 2 + + +
+
+

Display: inline-block

+ + Inline 1 + + + Inline 2 + +
+
+); +DisplayVariations.storyName = 'Display Variations'; + +export const SpacingTokens: Story = () => { + const tokens: SpacingToken[] = ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl']; + + return ( +
+
+

Padding Tokens

+
+ {tokens.map((token) => ( + + p={'{token}'}: {token} + + ))} +
+
+ +
+

Margin Tokens

+
+ {tokens.map((token) => ( + + m={'{token}'}: {token} + + ))} +
+
+
+ ); +}; +SpacingTokens.storyName = 'Spacing Tokens'; + +export const DirectionalSpacing: Story = () => ( +
+
+

Horizontal Padding (px)

+ + Large horizontal, small vertical padding + +
+ +
+

Vertical Padding (py)

+ + Small horizontal, large vertical padding + +
+ +
+

Directional Margins (mx, my)

+
+ + Large horizontal, medium vertical margin + +
+
+
+); +DirectionalSpacing.storyName = 'Directional Spacing'; + +export const FlexLayout: Story = () => ( +
+
+

Flex Direction: row (default)

+ + + Item 1 + + + Item 2 + + + Item 3 + + +
+ +
+

Flex Direction: column

+ + + Item 1 + + + Item 2 + + + Item 3 + + +
+ +
+

Align Items: center

+ + Short + + This is taller +
+ content +
+
+
+ +
+

Justify Content: space-between

+ + + Left + + + Center + + + Right + + +
+
+); +FlexLayout.storyName = 'Flex Layout'; + +export const Responsive: Story = () => ( +
+

Combining Multiple Props

+ + + + Header + + + Badge + + + + +

This is the main content of the box component.

+

It demonstrates how multiple props work together.

+
+ + + + Cancel + + + Submit + + +
+
+); +Responsive.storyName = 'Combined Props'; + +export const ZeroSpacing: Story = () => ( + + This box has zero padding (no space inside border). + +); +ZeroSpacing.storyName = 'Zero Spacing'; + +export const Sizing: Story = () => ( +
+
+

Fixed Width and Height

+ + 200px x 100px + +
+ +
+

Percentage Width

+
+ + 50% width + +
+
+ +
+

Width Only (height determined by content)

+ + This box has a fixed width of 300px, but its height grows to fit the content inside it. + +
+
+); +Sizing.storyName = 'Sizing'; diff --git a/components/src/next/primitives/Box/Box.test.tsx b/components/src/next/primitives/Box/Box.test.tsx new file mode 100644 index 00000000..90b5971d --- /dev/null +++ b/components/src/next/primitives/Box/Box.test.tsx @@ -0,0 +1,120 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render, screen } from '@testing-library/react'; + +import { Box } from './Box'; + +describe('Box', () => { + it('renders children', () => { + render(Content); + expect(screen.getByText('Content')).toBeInTheDocument(); + }); + + it('applies the ps-Box class', () => { + render(Content); + expect(screen.getByTestId('box')).toHaveClass('ps-Box'); + }); + + it('merges additional className', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveClass('ps-Box'); + expect(screen.getByTestId('box')).toHaveClass('custom'); + }); + + it('renders as a div by default', () => { + render(Content); + expect(screen.getByTestId('box').tagName).toBe('DIV'); + }); + + it('applies display style', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveStyle({ display: 'flex' }); + }); + + it('resolves spacing tokens to CSS variables for padding', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveStyle({ padding: 'var(--perses-spacing-md)' }); + }); + + it('resolves directional spacing shorthands', () => { + render( + + Content + , + ); + const box = screen.getByTestId('box'); + expect(box).toHaveStyle({ paddingLeft: 'var(--perses-spacing-lg)', paddingRight: 'var(--perses-spacing-lg)' }); + expect(box).toHaveStyle({ paddingTop: 'var(--perses-spacing-sm)', paddingBottom: 'var(--perses-spacing-sm)' }); + }); + + it('resolves margin tokens', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveStyle({ margin: 'var(--perses-spacing-xl)' }); + }); + + it('resolves the 0 spacing token to a literal 0', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveStyle({ padding: '0' }); + }); + + it('merges style prop with computed spacing styles', () => { + render( + + Content + , + ); + const box = screen.getByTestId('box'); + expect(box).toHaveStyle({ padding: 'var(--perses-spacing-sm)', color: 'rgb(255, 0, 0)' }); + }); + + it('lets the style prop override a computed spacing prop', () => { + render( + + Content + , + ); + expect(screen.getByTestId('box')).toHaveStyle({ padding: '99px' }); + }); + + it('does not render a style attribute when no style-affecting props are given', () => { + render(Content); + expect(screen.getByTestId('box')).not.toHaveAttribute('style'); + }); + + it('forwards a ref to the underlying div', () => { + const ref = { current: null as HTMLDivElement | null }; + render(Content); + expect(ref.current).toBeInstanceOf(HTMLDivElement); + }); +}); diff --git a/components/src/next/primitives/Box/Box.tsx b/components/src/next/primitives/Box/Box.tsx new file mode 100644 index 00000000..09f9af18 --- /dev/null +++ b/components/src/next/primitives/Box/Box.tsx @@ -0,0 +1,107 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { tokens } from '@perses-dev/design-tokens'; +import type { SpacingScale } from '@perses-dev/design-tokens'; +import clsx from 'clsx'; +import { forwardRef } from 'react'; +import type { CSSProperties, HTMLAttributes } from 'react'; + +import './box.css'; + +export type SpacingToken = Exclude | 0; + +function resolveSpacing(token?: SpacingToken): string | undefined { + if (token === undefined) return undefined; + if (token === 0) return '0'; + return tokens.spacing[token]; +} + +function axisSpacing( + token: SpacingToken | undefined, + [start, end]: readonly [keyof CSSProperties, keyof CSSProperties], +): CSSProperties { + if (token === undefined) return {}; + return { [start]: resolveSpacing(token), [end]: resolveSpacing(token) }; +} + +export interface BoxProps extends HTMLAttributes { + display?: CSSProperties['display']; + p?: SpacingToken; + px?: SpacingToken; + py?: SpacingToken; + m?: SpacingToken; + mx?: SpacingToken; + my?: SpacingToken; + gap?: SpacingToken; + flexDirection?: CSSProperties['flexDirection']; + alignItems?: CSSProperties['alignItems']; + justifyContent?: CSSProperties['justifyContent']; + flexWrap?: CSSProperties['flexWrap']; + flex?: CSSProperties['flex']; + width?: CSSProperties['width']; + height?: CSSProperties['height']; + overflow?: CSSProperties['overflow']; +} + +export const Box = forwardRef(function Box( + { + display, + p, + px, + py, + m, + mx, + my, + gap, + flexDirection, + alignItems, + justifyContent, + flexWrap, + flex, + width, + height, + overflow, + className, + style, + children, + ...rest + }, + ref, +) { + const computedStyle: CSSProperties = { + display, + flexDirection, + alignItems, + justifyContent, + flexWrap, + flex, + width, + height, + overflow, + padding: resolveSpacing(p), + margin: resolveSpacing(m), + gap: resolveSpacing(gap), + ...axisSpacing(px, ['paddingLeft', 'paddingRight']), + ...axisSpacing(py, ['paddingTop', 'paddingBottom']), + ...axisSpacing(mx, ['marginLeft', 'marginRight']), + ...axisSpacing(my, ['marginTop', 'marginBottom']), + ...style, + }; + + return ( +
+ {children} +
+ ); +}); diff --git a/components/src/next/primitives/Box/box.css b/components/src/next/primitives/Box/box.css new file mode 100644 index 00000000..6e7d457d --- /dev/null +++ b/components/src/next/primitives/Box/box.css @@ -0,0 +1,20 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.components { + .ps-Box { + box-sizing: border-box; + } +} diff --git a/components/src/next/primitives/Box/index.ts b/components/src/next/primitives/Box/index.ts new file mode 100644 index 00000000..24f1d8c4 --- /dev/null +++ b/components/src/next/primitives/Box/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Box'; diff --git a/components/src/next/primitives/defaults.ts b/components/src/next/primitives/defaults.ts index ecfbc081..abcfa099 100644 --- a/components/src/next/primitives/defaults.ts +++ b/components/src/next/primitives/defaults.ts @@ -13,11 +13,12 @@ import type { PersesComponents, PersesIcons } from '../contexts/ComponentsContext'; import { Alert } from './Alert'; +import { Box } from './Box'; import { Button } from './Button'; import { ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from './Icon'; import { Spinner } from './Spinner'; -export const defaultComponents: PersesComponents = { Button, Alert, Spinner }; +export const defaultComponents: PersesComponents = { Button, Alert, Spinner, Box }; export const defaultIcons: PersesIcons = { Error: ErrorIcon, diff --git a/components/src/next/primitives/exports.test.tsx b/components/src/next/primitives/exports.test.tsx index cbb686d8..a2f87c22 100644 --- a/components/src/next/primitives/exports.test.tsx +++ b/components/src/next/primitives/exports.test.tsx @@ -11,21 +11,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Alert, Button, Icon, Spinner } from './index'; +import { Alert, Box, Button, Icon, Spinner } from './index'; import type { AlertProps, AlertSeverity, + BoxProps, ButtonColor, ButtonProps, ButtonSize, ButtonVariant, IconProps, + SpacingToken, SpinnerProps, } from './index'; describe('primitives barrel exports', () => { it('exports the concrete component implementations', () => { expect(Alert).toBeDefined(); + expect(Box).toBeDefined(); expect(Button).toBeDefined(); expect(Icon).toBeDefined(); expect(Spinner).toBeDefined(); @@ -34,6 +37,8 @@ describe('primitives barrel exports', () => { it('exports their prop types', () => { const alertProps: AlertProps = {}; const severity: AlertSeverity = 'info'; + const boxProps: BoxProps = {}; + const spacingToken: SpacingToken = 'md'; const buttonProps: ButtonProps = {}; const variant: ButtonVariant = 'solid'; const color: ButtonColor = 'primary'; @@ -43,6 +48,8 @@ describe('primitives barrel exports', () => { expect(alertProps).toBeDefined(); expect(severity).toBe('info'); + expect(boxProps).toBeDefined(); + expect(spacingToken).toBe('md'); expect(buttonProps).toBeDefined(); expect(variant).toBe('solid'); expect(color).toBe('primary'); diff --git a/components/src/next/primitives/index.ts b/components/src/next/primitives/index.ts index 27680cde..92ff631b 100644 --- a/components/src/next/primitives/index.ts +++ b/components/src/next/primitives/index.ts @@ -12,6 +12,7 @@ // limitations under the License. export * from './Alert'; +export * from './Box'; export * from './Button'; export * from './Icon'; export * from './Spinner'; diff --git a/design-tokens/tsconfig.build.json b/design-tokens/tsconfig.build.json index e477966e..ffb23dde 100644 --- a/design-tokens/tsconfig.build.json +++ b/design-tokens/tsconfig.build.json @@ -2,6 +2,7 @@ "extends": "./tsconfig.json", "exclude": ["**/*.stories.*", "**/*.test.*", "**/stories/*", "**/test/*"], "compilerOptions": { + "noEmit": false, "emitDeclarationOnly": true, "declaration": true, "preserveWatchOutput": true From 8db66d2924dc92416b4776d034b32c572b364ee0 Mon Sep 17 00:00:00 2001 From: Jenny Zhu Date: Thu, 17 Sep 2026 14:56:45 -0400 Subject: [PATCH 2/2] [IGNORE] Update package.json so design-tokens are a dependency Signed-off-by: Jenny Zhu --- components/package.json | 1 + package-lock.json | 533 +--------------------------------------- 2 files changed, 2 insertions(+), 532 deletions(-) diff --git a/components/package.json b/components/package.json index c0dad420..03a3874e 100644 --- a/components/package.json +++ b/components/package.json @@ -63,6 +63,7 @@ "@mui/x-date-pickers": "^7.23.1", "@perses-dev/spec": "0.3.0-beta.8", "@perses-dev/client": "0.55.0-beta.8", + "@perses-dev/design-tokens": "0.54.0", "numbro": "^2.3.6", "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.20.5", diff --git a/package-lock.json b/package-lock.json index 260e322f..1f455d82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,6 +73,7 @@ "@fontsource/inter": "^5.0.0", "@mui/x-date-pickers": "^7.23.1", "@perses-dev/client": "0.55.0-beta.8", + "@perses-dev/design-tokens": "0.54.0", "@perses-dev/spec": "0.3.0-beta.8", "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.20.5", @@ -1352,22 +1353,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -1385,22 +1370,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -1418,22 +1387,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -2098,20 +2051,6 @@ } } }, - "node_modules/@ladle/react/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "extraneous": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@ladle/react/node_modules/vite-tsconfig-paths": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz", @@ -7998,22 +7937,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -14351,20 +14274,6 @@ "string_decoder": "~0.10.x" } }, - "node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/recma-build-jsx": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", @@ -16481,20 +16390,6 @@ } } }, - "node_modules/vite-tsconfig-paths/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "extraneous": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/vitest": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", @@ -16585,374 +16480,6 @@ } } }, - "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", - "cpu": [ - "ppc64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", - "cpu": [ - "arm" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", - "cpu": [ - "arm" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", - "cpu": [ - "ia32" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", - "cpu": [ - "loong64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", - "cpu": [ - "mips64el" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", - "cpu": [ - "ppc64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", - "cpu": [ - "riscv64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", - "cpu": [ - "s390x" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", - "cpu": [ - "arm64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", - "cpu": [ - "ia32" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", - "cpu": [ - "x64" - ], - "extraneous": true, - "license": "MIT", - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/vitest/node_modules/@vitest/mocker": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", @@ -16980,48 +16507,6 @@ } } }, - "node_modules/vitest/node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", - "extraneous": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" - } - }, "node_modules/vitest/node_modules/vite": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", @@ -17100,22 +16585,6 @@ } } }, - "node_modules/vitest/node_modules/yaml": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", - "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", - "extraneous": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",