From d52ffd6061575b53aa5d357ee7cf2dd2689f606e Mon Sep 17 00:00:00 2001 From: Brian Lee Date: Mon, 6 Jul 2026 06:08:23 +0800 Subject: [PATCH 1/5] feat(storybook): rebuild stories into capability groups with shared meta infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reorganize both packages' stories into capability groups (Features / Configuration / Theming / Extending / Robustness; Mantine Features + Configuration) with an Introduction.mdx guide mapping the whole tree. - Shared _shared/ bases (coreMeta / mantineMeta / colorScheme / SideBySide) enforce the CSF constraints (literal title+tags, explicit meta annotation) and live theme switching, incl. on autodocs pages via ThemedDocsContainer. - Scope the dark highlight.js theme through Sass meta.load-css (globals.scss): CSS @import cannot be nested under a selector — the old globals.css silently dropped the dark scoping at build time. - Align CrossChunkFootnote with the shared conventions; reframe the RemoveComments demo around a case with a real visible difference. - New stories: Core/Theming/Extra Styles and Core/Extending/TypeScript Generics (executable docs for the generic config/metadata surface). - Drop the react-scan decorator and the dead src story globs. --- .storybook/ThemedDocsContainer.tsx | 33 +++ .storybook/decorators/withReactScan.tsx | 15 -- .storybook/main.ts | 7 +- .storybook/preview.ts | 49 ++--- .storybook/vitest.setup.ts | 20 +- packages/core/stories/Introduction.mdx | 132 ++++++++++++ packages/core/stories/_shared/SideBySide.tsx | 27 +++ packages/core/stories/_shared/colorScheme.tsx | 20 ++ packages/core/stories/_shared/coreMeta.tsx | 91 ++++++++ .../DisplayOptimizations.stories.tsx | 85 ++++++++ .../SyntaxExtensions.stories.tsx | 64 ++++++ .../CrossChunkFootnote.stories.tsx | 204 ++++++++---------- packages/core/stories/decorators.tsx | 22 +- .../ContentPreprocessors.stories.tsx | 92 ++++++++ .../extending/CustomComponents.stories.tsx | 132 ++++++++++++ .../extending/CustomTypography.stories.tsx | 87 ++++++++ .../extending/MetadataContext.stories.tsx | 136 ++++++++++++ .../extending/TypeScriptGenerics.stories.tsx | 141 ++++++++++++ .../stories/features/CodeBlocks.stories.tsx | 69 ++++++ .../stories/features/EmojiAndCJK.stories.tsx | 57 +++++ .../core/stories/features/GFM.stories.tsx | 59 +++++ .../features/ListsAndFootnotes.stories.tsx | 63 ++++++ .../core/stories/features/Math.stories.tsx | 98 +++++++++ .../features/TextAndInline.stories.tsx | 62 ++++++ .../robustness/DocumentIsolation.stories.tsx | 67 ++++++ .../robustness/PartialMarkdown.stories.tsx | 87 ++++++++ .../robustness/UrlSanitization.stories.tsx | 71 ++++++ .../stories/theming/ColorSchemes.stories.tsx | 69 ++++++ .../stories/theming/DesignTokens.stories.tsx | 103 +++++++++ .../stories/theming/ExtraStyles.stories.tsx | 96 +++++++++ .../core/stories/theming/FontSize.stories.tsx | 58 +++++ .../mantine/stories/_shared/mantineMeta.tsx | 60 ++++++ .../configuration/CodeBlock.stories.tsx | 54 +++++ packages/mantine/stories/decorators.tsx | 14 +- .../features/CodeHighlighting.stories.tsx | 79 +++++++ .../stories/features/GFMAndText.stories.tsx | 53 +++++ .../mantine/stories/features/Math.stories.tsx | 32 +++ .../features/MermaidDiagrams.stories.tsx | 66 ++++++ .../stories/features/RichDocument.stories.tsx | 73 +++++++ packages/mantine/stories/globals.css | 5 - packages/mantine/stories/globals.scss | 12 ++ 41 files changed, 2587 insertions(+), 177 deletions(-) create mode 100644 .storybook/ThemedDocsContainer.tsx delete mode 100644 .storybook/decorators/withReactScan.tsx create mode 100644 packages/core/stories/Introduction.mdx create mode 100644 packages/core/stories/_shared/SideBySide.tsx create mode 100644 packages/core/stories/_shared/colorScheme.tsx create mode 100644 packages/core/stories/_shared/coreMeta.tsx create mode 100644 packages/core/stories/configuration/DisplayOptimizations.stories.tsx create mode 100644 packages/core/stories/configuration/SyntaxExtensions.stories.tsx create mode 100644 packages/core/stories/extending/ContentPreprocessors.stories.tsx create mode 100644 packages/core/stories/extending/CustomComponents.stories.tsx create mode 100644 packages/core/stories/extending/CustomTypography.stories.tsx create mode 100644 packages/core/stories/extending/MetadataContext.stories.tsx create mode 100644 packages/core/stories/extending/TypeScriptGenerics.stories.tsx create mode 100644 packages/core/stories/features/CodeBlocks.stories.tsx create mode 100644 packages/core/stories/features/EmojiAndCJK.stories.tsx create mode 100644 packages/core/stories/features/GFM.stories.tsx create mode 100644 packages/core/stories/features/ListsAndFootnotes.stories.tsx create mode 100644 packages/core/stories/features/Math.stories.tsx create mode 100644 packages/core/stories/features/TextAndInline.stories.tsx create mode 100644 packages/core/stories/robustness/DocumentIsolation.stories.tsx create mode 100644 packages/core/stories/robustness/PartialMarkdown.stories.tsx create mode 100644 packages/core/stories/robustness/UrlSanitization.stories.tsx create mode 100644 packages/core/stories/theming/ColorSchemes.stories.tsx create mode 100644 packages/core/stories/theming/DesignTokens.stories.tsx create mode 100644 packages/core/stories/theming/ExtraStyles.stories.tsx create mode 100644 packages/core/stories/theming/FontSize.stories.tsx create mode 100644 packages/mantine/stories/_shared/mantineMeta.tsx create mode 100644 packages/mantine/stories/configuration/CodeBlock.stories.tsx create mode 100644 packages/mantine/stories/features/CodeHighlighting.stories.tsx create mode 100644 packages/mantine/stories/features/GFMAndText.stories.tsx create mode 100644 packages/mantine/stories/features/Math.stories.tsx create mode 100644 packages/mantine/stories/features/MermaidDiagrams.stories.tsx create mode 100644 packages/mantine/stories/features/RichDocument.stories.tsx delete mode 100644 packages/mantine/stories/globals.css create mode 100644 packages/mantine/stories/globals.scss diff --git a/.storybook/ThemedDocsContainer.tsx b/.storybook/ThemedDocsContainer.tsx new file mode 100644 index 0000000..0fe4c2b --- /dev/null +++ b/.storybook/ThemedDocsContainer.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useState } from 'react'; +import { DocsContainer } from '@storybook/addon-docs/blocks'; +import { themes } from 'storybook/theming'; +import { addons } from 'storybook/preview-api'; +import { GLOBALS_UPDATED } from 'storybook/internal/core-events'; +import { getUserPreferredColorTheme } from './utils/sb-theme'; + +/** + * A Docs container that themes the autodocs / MDX **page chrome** (background, + * prose, doc blocks) to match the toolbar Theme switch. + * + * `addon-docs` themes the Docs page from `parameters.docs.theme`, which is + * static and defaults to the light theme — so the custom `theme` global drives + * the embedded story previews and the manager UI, but the Docs page itself + * stays light. This container closes that gap: it seeds from the persisted + * preference and then subscribes to `GLOBALS_UPDATED` on the preview channel so + * a live toggle re-themes the page immediately. + */ +export function ThemedDocsContainer(props: React.ComponentProps) { + const [isDark, setIsDark] = useState(() => getUserPreferredColorTheme() === 'dark'); + + useEffect(() => { + const channel = addons.getChannel(); + const handler = (event: { globals?: Record }) => { + const theme = event?.globals?.theme; + if (typeof theme === 'string') setIsDark(theme === 'dark'); + }; + channel.on(GLOBALS_UPDATED, handler); + return () => channel.off(GLOBALS_UPDATED, handler); + }, []); + + return ; +} diff --git a/.storybook/decorators/withReactScan.tsx b/.storybook/decorators/withReactScan.tsx deleted file mode 100644 index 17718ff..0000000 --- a/.storybook/decorators/withReactScan.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { Decorator } from '@storybook/react-vite'; -import { setOptions } from 'react-scan'; - -let lastEnabled: boolean | null = null; - -const sync = (enabled: boolean) => { - if (enabled === lastEnabled) return; - setOptions({ enabled, showToolbar: enabled }); - lastEnabled = enabled; -}; - -export const withReactScan: Decorator = (Story, context) => { - sync(context.globals.reactScan === 'on'); - return ; -}; diff --git a/.storybook/main.ts b/.storybook/main.ts index 2d85316..cc152a9 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,12 +1,7 @@ import type { StorybookConfig } from '@storybook/react-vite'; const config: StorybookConfig = { - stories: [ - '../packages/*/src/**/*.mdx', - '../packages/*/src/**/*.stories.@(js|jsx|mjs|ts|tsx)', - '../packages/*/stories/**/*.mdx', - '../packages/*/stories/**/*.stories.@(js|jsx|mjs|ts|tsx)', - ], + stories: ['../packages/*/stories/**/*.mdx', '../packages/*/stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ '@chromatic-com/storybook', '@storybook/addon-vitest', diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 2a31318..3caeb41 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,22 +1,29 @@ import type { Preview } from '@storybook/react-vite'; -import { setOptions, start } from 'react-scan'; import { getUserPreferredColorTheme } from './utils/sb-theme'; -import { withReactScan } from './decorators/withReactScan'; - -// `scan()` short-circuits when running inside an iframe (Storybook preview is one) -// and also bails when called with both `enabled: false` and `showToolbar: false`. -// Calling `start()` directly bypasses both guards so the renderer hook is armed -// from the very first commit, regardless of toggle state. -// -// NOTE: outlines only render in Storybook's *standalone* iframe view -// (http://localhost:6006/iframe.html?id=...). In the default canvas view the -// nested manager→preview iframe layout breaks react-scan's overlay positioning. -// See https://github.com/aidenybai/react-scan/issues/419 — open as of 2025-12. -setOptions({ enabled: false, showToolbar: false, dangerouslyForceRunInProduction: true }); -start(); +import { ThemedDocsContainer } from './ThemedDocsContainer'; const preview: Preview = { parameters: { + options: { + // Curate the sidebar: Introduction first, then the two packages (Core, + // Mantine) as top-level branches, each ordered capability-first via the + // nested arrays. Anything not listed falls through to the end, A→Z. + storySort: { + order: [ + 'Introduction', + 'Core', + ['AIMarkdown', 'Features', 'Theming', 'Configuration', 'Extending', 'Robustness', 'Coordination'], + 'Mantine', + ['MantineAIMarkdown', 'Features', 'Configuration'], + ], + }, + }, + docs: { + // Theme the Docs page chrome (MDX / autodocs) to follow the toolbar Theme + // switch — `addon-docs`'s static `docs.theme` otherwise keeps it light. + container: ThemedDocsContainer, + }, + controls: { matchers: { color: /(background|color)$/i, @@ -33,7 +40,6 @@ const preview: Preview = { }, initialGlobals: { theme: getUserPreferredColorTheme(), - reactScan: 'off', }, globalTypes: { theme: { @@ -48,20 +54,7 @@ const preview: Preview = { dynamicTitle: true, }, }, - reactScan: { - description: 'Toggle react-scan render visualisation (outlines render only in standalone iframe view)', - toolbar: { - title: 'React Scan', - icon: 'lightning', - items: [ - { value: 'off', icon: 'eyeclose', title: 'Off' }, - { value: 'on', icon: 'eye', title: 'On (use Open Canvas in New Tab)' }, - ], - dynamicTitle: true, - }, - }, }, - decorators: [withReactScan], }; export default preview; diff --git a/.storybook/vitest.setup.ts b/.storybook/vitest.setup.ts index ea170b0..c51460c 100644 --- a/.storybook/vitest.setup.ts +++ b/.storybook/vitest.setup.ts @@ -1,7 +1,13 @@ -import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview'; -import { setProjectAnnotations } from '@storybook/react-vite'; -import * as projectAnnotations from './preview'; - -// This is an important step to apply the right configuration when testing your stories. -// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations -setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]); +// Intentionally empty. Since Storybook 10.3, @storybook/addon-vitest applies +// the project's preview annotations (./preview) and every addon's preview +// annotations automatically, so the manual set-project-annotations call this +// file used to make is redundant — the test runner itself said it can be +// removed. The file stays because vitest.config.ts lists it in the storybook +// project's `setupFiles`. +// +// CAUTION: do not mention the removed API by its camelCase name anywhere in +// this file (not even in a comment) — the addon decides whether to auto-apply +// annotations by TEXT-SEARCHING this file for that identifier, and a stray +// mention silently disables the auto-application, failing every story test +// with "context.renderToCanvas is not a function". +export {}; diff --git a/packages/core/stories/Introduction.mdx b/packages/core/stories/Introduction.mdx new file mode 100644 index 0000000..13a3639 --- /dev/null +++ b/packages/core/stories/Introduction.mdx @@ -0,0 +1,132 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + + + +# ai-react-markdown + +A batteries-included React component for rendering **AI-generated markdown** — LaTeX math, +GFM, CJK text, emoji, and streaming content — with the robustness an LLM chat surface +actually needs. + +```tsx +import AIMarkdown from '@ai-react-markdown/core'; +import '@ai-react-markdown/core/typography/default.css'; +import 'katex/dist/katex.min.css'; // only if you render math + +function Message({ content }: { content: string }) { + return ; +} +``` + +That's the whole API for the common case. Everything below is opt-in. + +> **Tip — use the toolbar.** The **Theme** switch (top toolbar) drives every story's +> `colorScheme`, so you can preview light/dark on any example. Open the **Controls** and +> **Docs** tabs to edit content live and read the per-story notes. + +--- + +## What to explore + +The sidebar has two top-level branches — one per package. **Core** is the framework-agnostic +renderer; **Mantine** is the Mantine-integrated build layered on top of it. Pick your package, +then drill into the capability you care about. Each leaf isolates one facet so you can feel the +capability, the robustness, and the ergonomics on their own — instead of hunting through one +giant blob. + +## Core — `@ai-react-markdown/core` + +The zero-dependency-on-any-UI-kit renderer. Everything below lives under the **Core** branch. + +- **Core / AIMarkdown** — the interactive playground plus the streaming, profiling, and + block-memo benchmark stories. Start here to see real token-by-token rendering and the + per-frame cost savings of block-level memoization. + +### Core / Features — what it renders out of the box + +| Group | Covers | +| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| **Core / Features / Math** | KaTeX inline + display math, and the LaTeX preprocessor that survives currency `$`, `\[…\]`/`\(…\)` delimiters, table pipes, and `mhchem`. | +| **Core / Features / GFM** | Tables (with alignment), task lists, strikethrough, autolinks. | +| **Core / Features / Code Blocks** | Language-tagged, theme-able code blocks (semantic output — bring your own tokenizer or use the Mantine package for highlighting). | +| **Core / Features / Text & Inline** | Headings, blockquotes, `==highlight==`, raw inline HTML (``, ``, ``), horizontal rules. | +| **Core / Features / Lists & Footnotes** | Ordered/unordered/nested lists, definition lists, footnotes with back-references. | +| **Core / Features / Emoji & CJK** | `:shortcode:` emoji, CJK-friendly emphasis, and pangu auto-spacing between CJK and Latin. | + +### Core / Theming — make it yours without forking + +- **Core / Theming / Color Schemes** — light/dark, driven entirely by CSS token scopes. +- **Core / Theming / Font Size** — one prop proportionally scales every dimension. +- **Core / Theming / Design Tokens** — retheme spacing, color, and weight by overriding CSS + custom properties. No JavaScript required. +- **Core / Theming / Extra Styles** — a wrapper slot between typography and the markdown + content for scoped stylesheets or theme providers. + +### Core / Configuration — toggle the pipeline + +- **Core / Configuration / Syntax Extensions** — `==highlight==` and definition lists, on/off. +- **Core / Configuration / Display Optimizations** — SmartyPants, pangu CJK spacing, HTML + comment removal, each independently switchable. + +### Core / Extending — escape hatches that compose + +- **Core / Extending / Custom Components** — replace any element renderer (code blocks, links, …). +- **Core / Extending / Custom Typography** — swap the wrapper for design-system integration. +- **Core / Extending / Metadata Context** — pass callbacks to nested components without + prop-drilling or busting the streaming cache. +- **Core / Extending / Content Preprocessors** — string→string transforms before parsing. +- **Core / Extending / TypeScript Generics** — type an extended config and metadata + end-to-end with `>` and typed wrapper hooks. + +### Core / Robustness — the unglamorous part that matters for LLM output + +- **Core / Robustness / URL Sanitization** — two-gate XSS defense neutralizes `javascript:`, + `data:`, and `onerror` injection in model output. +- **Core / Robustness / Partial Markdown** — half-streamed, unclosed syntax renders gracefully + instead of throwing. +- **Core / Robustness / Document Isolation** — two messages on one page never cross-link their + footnotes or hash anchors. + +### Core / Coordination + +- **Core / Coordination / Cross-Chunk Footnotes** — `` stitches footnotes + and references across a document split into multiple streamed chunks. + +## Mantine — `@ai-react-markdown/mantine` + +The same renderer wired into the Mantine design system: tokenized syntax highlighting, +Mermaid diagrams, Mantine-native theming, and code-block ergonomics. Lives under the +**Mantine** branch. + +- **Mantine / MantineAIMarkdown** — the interactive playground for the Mantine build. + +### Mantine / Features — what the integration adds (and inherits) + +| Group | Covers | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Mantine / Features / GFM & Text** | The Core markdown surface — tables, task lists, strikethrough, the full heading scale — restyled through Mantine typography. | +| **Mantine / Features / Code Highlighting** | The headline difference from Core: fenced code blocks tokenized via `@mantine/code-highlight` (highlight.js), with language tabs and a copy button. | +| **Mantine / Features / Math** | Core's full KaTeX + LaTeX-preprocessor pipeline, inherited unchanged inside Mantine typography. | +| **Mantine / Features / Mermaid Diagrams** | ` ```mermaid ` fences render as live SVG diagrams with light/dark theming and a raw-source toggle; parse errors fall back to source. | +| **Mantine / Features / Rich Document** | A realistic assistant message exercising the whole surface at once — prose, highlighted code, math, a table, a task list, a diagram. | + +### Mantine / Configuration — Mantine-only knobs + +- **Mantine / Configuration / Code Block** — `codeBlock.defaultExpanded` (collapse long blocks + behind an expand button) and `codeBlock.autoDetectUnknownLanguage` (highlight.js language + detection for untagged fences). + +--- + +## Design goals + +1. **Correct on messy input.** LLM output is partial, malformed mid-stream, and occasionally + hostile. The renderer is built to degrade gracefully and sanitize aggressively. +2. **Cheap to re-render while streaming.** Block-level memoization keeps per-frame cost + proportional to the _changed_ fraction of the document — see **Core / AIMarkdown**. +3. **Themable without forking.** A CSS-custom-property token surface covers most theming; + component and typography overrides cover the rest. +4. **Honest about boundaries.** Core ships semantic, sanitized HTML + typography. Tokenized + syntax highlighting and Mermaid diagram rendering are deliberately left out of Core — the + Mantine subpackage ships both. Anything beyond that (admonitions, callouts, …) is custom + component territory in either package. diff --git a/packages/core/stories/_shared/SideBySide.tsx b/packages/core/stories/_shared/SideBySide.tsx new file mode 100644 index 0000000..6cae286 --- /dev/null +++ b/packages/core/stories/_shared/SideBySide.tsx @@ -0,0 +1,27 @@ +import React from 'react'; + +/** A wrapping flex row of equal-width comparison panels. */ +export function Columns({ children }: { children: React.ReactNode }) { + return
{children}
; +} + +/** A single labeled comparison panel. */ +export function Column({ label, children }: { label: string; children: React.ReactNode }) { + return ( +
+
+ {label} +
+ {children} +
+ ); +} diff --git a/packages/core/stories/_shared/colorScheme.tsx b/packages/core/stories/_shared/colorScheme.tsx new file mode 100644 index 0000000..15c4e21 --- /dev/null +++ b/packages/core/stories/_shared/colorScheme.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +/** + * The active Storybook color scheme, provided by the `withThemedBackground` + * decorator (which subscribes to the globals channel via `useGlobals`). + * + * Why a React context instead of reading `context.globals.theme` in each + * render: inside autodocs **Docs pages**, an embedded story's render is not + * re-invoked when a global changes via the toolbar — so `context.globals` + * stays frozen and the light/dark switch appears dead. The decorator DOES + * re-render (its `useGlobals` call subscribes it to the channel), so feeding + * the value down through context lets every nested component pick up live + * theme changes with a plain `useContext` — in both Canvas and Docs. + */ +export const ColorSchemeContext = React.createContext<'light' | 'dark'>('light'); + +/** Read the live color scheme. Safe in any component rendered inside a story. */ +export function useColorScheme(): 'light' | 'dark' { + return React.useContext(ColorSchemeContext); +} diff --git a/packages/core/stories/_shared/coreMeta.tsx b/packages/core/stories/_shared/coreMeta.tsx new file mode 100644 index 0000000..6bb0869 --- /dev/null +++ b/packages/core/stories/_shared/coreMeta.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import AIMarkdown, { type AIMarkdownProps } from '../../src/index'; +import { useColorScheme } from './colorScheme'; + +// Side-effect CSS every core story needs: KaTeX glyphs + the bundled +// `default` typography variant (which also defines the `light`/`dark` token +// scopes). Imported once here so individual story files don't repeat it. +import 'katex/dist/katex.min.css'; +import '../../src/components/typography/variants/all.scss'; + +import { withThemedBackground } from '../decorators'; + +export type CoreMeta = Meta; +export type CoreStory = StoryObj; + +/** + * Shared `argTypes` for the `` Controls panel. Function-typed and + * advanced props are hidden from the table so the common surface stays + * approachable; the Extending/* stories opt those back in where relevant. + */ +export const coreArgTypes: CoreMeta['argTypes'] = { + content: { control: 'text', description: 'Raw markdown content to render.' }, + streaming: { control: 'boolean', description: 'Whether content is actively being streamed.' }, + fontSize: { + control: 'text', + description: 'Base font size (e.g. `"0.9375rem"`, `"14px"`, or a number for px). Scales every token.', + }, + variant: { control: 'select', options: ['default'], description: 'Typography variant name.' }, + config: { + control: 'object', + description: 'Partial render config, deep-merged with defaults. Array values are replaced entirely.', + }, + metadata: { control: 'object', description: 'Arbitrary data passed to custom components via context.' }, + colorScheme: { table: { disable: true } }, + contentPreprocessors: { table: { disable: true } }, + customComponents: { table: { disable: true } }, + Typography: { table: { disable: true } }, + ExtraStyles: { table: { disable: true } }, + defaultConfig: { table: { disable: true } }, + sanitizeSchema: { table: { disable: true } }, + urlTransform: { table: { disable: true } }, +}; + +export { useColorScheme }; + +/** + * `` with `colorScheme` wired to the live Storybook theme (read from + * {@link useColorScheme}). Use this anywhere you'd render `` in a + * story so the light/dark toolbar switch drives it — in Canvas and Docs alike — + * without each render having to thread the scheme through manually. + */ +export function ThemedAIMarkdown(props: Omit) { + const colorScheme = useColorScheme(); + return ; +} + +/** + * Default theme-aware `render`: renders {@link ThemedAIMarkdown} so the toolbar's + * light/dark switch drives the component in both Canvas and Docs. + */ +export const themedRender: CoreMeta['render'] = (args) => ; + +/** + * Shared meta fields for a core showcase story group. Spread this into each + * story file's default export, then add the (statically required) `title` and + * `tags` literals plus any per-group `parameters`/`args`: + * + * ```ts + * const meta: CoreMeta = { + * ...coreMetaBase, + * title: 'Core/Features/Math', + * tags: ['autodocs'], + * parameters: { docs: { description: { component: '…' } } }, + * }; + * ``` + * + * Use the explicit `: CoreMeta` annotation (not `satisfies`) — with an + * inferred export type, declaration builds hit TS2742 ("cannot be named"). + * + * `title` and `tags` must be object-literal properties in the file itself — + * Storybook's static CSF indexer can't see them through a spread or a factory. + */ +export const coreMetaBase: Partial = { + component: AIMarkdown, + decorators: [withThemedBackground], + argTypes: coreArgTypes, + render: themedRender, +}; + +export { AIMarkdown }; diff --git a/packages/core/stories/configuration/DisplayOptimizations.stories.tsx b/packages/core/stories/configuration/DisplayOptimizations.stories.tsx new file mode 100644 index 0000000..d5e9524 --- /dev/null +++ b/packages/core/stories/configuration/DisplayOptimizations.stories.tsx @@ -0,0 +1,85 @@ +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import { Columns, Column } from '../_shared/SideBySide'; +import { AIMarkdownRenderDisplayOptimizeAbility as Ability } from '../../src/index'; + +const SMARTY = `"Smart quotes" and 'single quotes' become curly. An em-dash --- and an +en-dash -- get real glyphs. Ellipses... collapse to a single character.`; + +const PANGU = `在 React19 项目里使用 AIMarkdown 渲染 LLM 输出的 Markdown,2026年 上线。`; + +// The comment shares its raw-HTML block with stray same-line text — the case +// where the ability makes a VISIBLE difference. A well-formed comment standing +// alone is invisible either way: the raw-HTML pass parses it into a hast +// comment node, and comment nodes never render. +const COMMENTS = `Visible paragraph. + + stray annotation on the comment's line + +Another visible paragraph.`; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Configuration/Display Optimizations', + parameters: { + docs: { + description: { + component: + 'Three display optimizations run via `config.displayOptimizeAbilities`, all on by ' + + 'default: `SMARTYPANTS` (curly quotes, real dashes, ellipses), `PANGU` (auto-spacing ' + + 'between CJK and half-width characters), and `REMOVE_COMMENTS` (strip HTML comments). ' + + 'Each story compares the same input with the ability on vs off. Remember: `config` ' + + 'arrays replace, so list exactly the abilities you want.', + }, + }, + }, +}; + +export default meta; + +function Compare({ + content, + onLabel, + abilitiesWhenOff, +}: { + content: string; + onLabel: string; + abilitiesWhenOff: Ability[]; +}) { + return ( + + + + + + + + + ); +} + +/** Typographic punctuation: straight quotes/dashes/ellipses on the left, raw on the right. */ +export const SmartyPants: CoreStory = { + render: () => ( + + ), +}; + +/** CJK ↔ Latin spacing: notice the gaps around `React19` and `2026年` appear only on the left. */ +export const Pangu: CoreStory = { + render: () => ( + + ), +}; + +/** + * With the ability on (left), the whole raw-HTML block containing the comment is stripped at + * the markdown stage — stray text on the comment's line goes with it. Off (right), the comment + * itself still never renders (it becomes a hast comment node), but the stray text leaks into + * the output as bare text between the paragraphs. + */ +export const RemoveComments: CoreStory = { + render: () => ( + + ), +}; diff --git a/packages/core/stories/configuration/SyntaxExtensions.stories.tsx b/packages/core/stories/configuration/SyntaxExtensions.stories.tsx new file mode 100644 index 0000000..ee4f61a --- /dev/null +++ b/packages/core/stories/configuration/SyntaxExtensions.stories.tsx @@ -0,0 +1,64 @@ +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import { Columns, Column } from '../_shared/SideBySide'; +import { AIMarkdownRenderExtraSyntax } from '../../src/index'; + +const SAMPLE = `Inline ==highlighted text== uses the HIGHLIGHT extension. + +Apple +: A pomaceous fruit. + +Browser +: Software for accessing the web. +: Often ships a JavaScript engine.`; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Configuration/Syntax Extensions', + parameters: { + docs: { + description: { + component: + 'Two markdown extensions beyond GFM are controlled by `config.extraSyntaxSupported`: ' + + '`HIGHLIGHT` (`==text==` → ``) and `DEFINITION_LIST`. Both are on by default. ' + + 'Passing `config` deep-merges with the defaults, but **array values replace entirely** ' + + '— so `extraSyntaxSupported: []` turns both off and the syntax renders as literal text.', + }, + }, + }, + args: { content: SAMPLE }, +}; + +export default meta; + +/** Both extensions on (the default): the highlight renders and the definition list formats. */ +export const Enabled: CoreStory = { + render: (args) => , +}; + +/** Both off: `==text==` shows its literal equals signs and the term/`:` lines stay plain. */ +export const Disabled: CoreStory = { + render: (args) => , +}; + +/** Side by side, so the difference is unmistakable. */ +export const Comparison: CoreStory = { + parameters: { docs: { description: { story: 'Left: default (both on). Right: both extensions disabled.' } } }, + render: (args) => ( + + + + + + + + + ), +}; + +/** Enable only HIGHLIGHT, leaving definition lists off. */ +export const HighlightOnly: CoreStory = { + render: (args) => ( + + ), +}; diff --git a/packages/core/stories/coordination/CrossChunkFootnote.stories.tsx b/packages/core/stories/coordination/CrossChunkFootnote.stories.tsx index 64cc0e3..a98c2ef 100644 --- a/packages/core/stories/coordination/CrossChunkFootnote.stories.tsx +++ b/packages/core/stories/coordination/CrossChunkFootnote.stories.tsx @@ -1,49 +1,41 @@ -import type { Meta, StoryObj } from '@storybook/react-vite'; -import AIMarkdown from '../../src'; +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; import { AIMarkdownDocuments } from '../../src/components/AIMarkdownDocuments'; -import { withThemedBackground } from '../decorators'; -// Read the Storybook toolbar theme global and normalize to a colorScheme value. -// AIMarkdown defaults to 'light', so without this every story would stay light -// regardless of the toolbar toggle — `withThemedBackground` would still flip -// the page background, leaving white-on-dark text unreadable. The decorator + -// per-story colorScheme prop together mirror what AIMarkdown.stories.tsx does. -// Plain function (not a hook) — the leading verb keeps the React Compiler / -// react-hooks lint rule from flagging it inside render. -function resolveToolbarColorScheme(globals: Record): 'light' | 'dark' { - return globals.theme === 'dark' ? 'dark' : 'light'; -} +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Coordination/Cross-Chunk Footnotes', + parameters: { + docs: { + description: { + component: + 'When one logical document is split across multiple `` instances (chunked / ' + + 'streamed rendering), wrap them in `` and give every chunk the same ' + + '`documentId`. A shared registry then coordinates footnotes and reference definitions ' + + 'across chunks: refs resolve to defs that live in a *later* chunk, global footnote ' + + 'numbering stays consistent, backrefs are injected, and the aggregate footnote footer ' + + 'renders only after the last chunk. Different `documentId`s stay fully isolated — same ' + + 'labels in two documents never cross-link.', + }, + }, + }, +}; -const meta = { - title: 'coordination/Cross-chunk footnote', - component: AIMarkdownDocuments, - decorators: [withThemedBackground], -} satisfies Meta; export default meta; -export const TwoChunks: StoryObj = { - render: (_, context) => { - const colorScheme = resolveToolbarColorScheme(context.globals); - return ( - - - - - ); - }, +/** Ref in chunk 1, definition arrives in chunk 2 — the footnote still resolves. */ +export const TwoChunks: CoreStory = { + render: () => ( + + + + + ), }; -export const OrphanDef: StoryObj = { - render: (_, context) => { - const colorScheme = resolveToolbarColorScheme(context.globals); - return ( - - ); - }, +/** A definition with no ref anywhere is still rendered (Direction A: preserve orphans). */ +export const OrphanDef: CoreStory = { + render: () => , }; /** @@ -57,67 +49,59 @@ export const OrphanDef: StoryObj = { * - backref injection should fire on chunks 4 and 5 for each of their * local defs that have cross-chunk refs. */ -export const FiveChunksScattered: StoryObj = { - render: (_, context) => { - const colorScheme = resolveToolbarColorScheme(context.globals); - return ( - - - - - - - - ); - }, +export const FiveChunksScattered: CoreStory = { + render: () => ( + + + + + + + + ), }; // ─── Stress: 30 chunks, single document ────────────────────────────────────── @@ -200,9 +184,9 @@ function buildThirtyChunkSingleDoc(): string[] { ]; } -export const ThirtyChunksSingleDoc: StoryObj = { - render: (_, context) => { - const colorScheme = resolveToolbarColorScheme(context.globals); +/** Stress: one document in exactly 30 chunks — footer only after the last one. */ +export const ThirtyChunksSingleDoc: CoreStory = { + render: () => { const chunks = buildThirtyChunkSingleDoc(); // dev-only sanity assertion — keep the chunk count truthful in the title. if (chunks.length !== 30) { @@ -211,7 +195,7 @@ export const ThirtyChunksSingleDoc: StoryObj = { return ( {chunks.map((c, i) => ( - + ))} ); @@ -265,22 +249,22 @@ function buildDocChunks(tag: string): string[] { return all; } -export const SixtyChunksThreeDocs: StoryObj = { - render: (_, context) => { - const colorScheme = resolveToolbarColorScheme(context.globals); +/** Stress: three interleaved documents sharing labels — registries must not leak. */ +export const SixtyChunksThreeDocs: CoreStory = { + render: () => { const a = buildDocChunks('A'); const b = buildDocChunks('B'); const c = buildDocChunks('C'); return ( {a.map((ch, i) => ( - + ))} {b.map((ch, i) => ( - + ))} {c.map((ch, i) => ( - + ))} ); diff --git a/packages/core/stories/decorators.tsx b/packages/core/stories/decorators.tsx index b795866..c6700dd 100644 --- a/packages/core/stories/decorators.tsx +++ b/packages/core/stories/decorators.tsx @@ -1,8 +1,24 @@ import React from 'react'; import type { Decorator } from '@storybook/react-vite'; +import { useGlobals } from 'storybook/preview-api'; +import { ColorSchemeContext } from './_shared/colorScheme'; -export const withThemedBackground: Decorator = (Story, context) => { - const theme = context.globals.theme === 'dark' ? 'dark' : 'light'; +export const withThemedBackground: Decorator = (Story) => { + // `useGlobals` is a STORYBOOK preview hook — it must be called directly in the + // decorator (not a nested React component, which throws "preview hooks can only + // be called inside decorators and story functions"). The eslint rule below is a + // false positive: it sees a Storybook hook as a React hook in a non-component. + // Subscribing here re-renders the decorator on a live theme toggle — in Canvas + // AND in autodocs Docs pages, where a story's own render reading + // `context.globals` would stay frozen. The scheme is published through context + // so every nested component picks it up with `useColorScheme`. + // eslint-disable-next-line react-hooks/rules-of-hooks + const [globals] = useGlobals(); + const theme = globals.theme === 'dark' ? 'dark' : 'light'; document.body.style.backgroundColor = theme === 'dark' ? 'rgb(36, 36, 36)' : ''; - return ; + return ( + + + + ); }; diff --git a/packages/core/stories/extending/ContentPreprocessors.stories.tsx b/packages/core/stories/extending/ContentPreprocessors.stories.tsx new file mode 100644 index 0000000..1313c27 --- /dev/null +++ b/packages/core/stories/extending/ContentPreprocessors.stories.tsx @@ -0,0 +1,92 @@ +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import { Columns, Column } from '../_shared/SideBySide'; +import type { AIMDContentPreprocessor } from '../../src/index'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Extending/Content Preprocessors', + parameters: { + docs: { + description: { + component: + 'Preprocessors are `(content: string) => string` transforms applied to the raw markdown ' + + '**before** the remark/rehype pipeline. Use them for string-level fixes that are simpler ' + + 'than a remark plugin: frontmatter stripping, dialect normalization, model-quirk regexes. ' + + 'They run after the built-in LaTeX preprocessor, left-to-right (`c(b(a(x)))`). Each story ' + + 'compares raw input (no preprocessor) against the transformed output.', + }, + }, + }, +}; + +export default meta; + +function Compare({ raw, preprocessors }: { raw: string; preprocessors: AIMDContentPreprocessor[] }) { + return ( + + + + + + + + + ); +} + +/** Rewrite Obsidian-style `[[wikilinks]]` into real markdown links. */ +const wikiLinks: AIMDContentPreprocessor = (content) => + content.replace(/\[\[([^\]]+)\]\]/g, (_m, name) => `[${name}](/wiki/${encodeURIComponent(name)})`); + +export const WikiLinks: CoreStory = { + render: () => ( + + ), +}; + +/** Strip a leading YAML frontmatter block the model echoed into the message. */ +const stripFrontmatter: AIMDContentPreprocessor = (content) => { + if (!content.startsWith('---\n')) return content; + const end = content.indexOf('\n---\n', 4); + return end === -1 ? content : content.slice(end + 5); +}; + +export const StripFrontmatter: CoreStory = { + render: () => ( + + ), +}; + +/** Chain transforms: collapse excess blank lines, then drop a stream sentinel. */ +const normalizeBlankLines: AIMDContentPreprocessor = (content) => content.replace(/\n{3,}/g, '\n\n'); +const stripStreamMarker: AIMDContentPreprocessor = (content) => content.replace(/\s*\[end of stream\]\s*$/i, ''); + +export const ChainedPipeline: CoreStory = { + parameters: { + docs: { + description: { story: 'Preprocessors compose left-to-right: blank-line collapse, then sentinel removal.' }, + }, + }, + render: () => ( + + ), +}; diff --git a/packages/core/stories/extending/CustomComponents.stories.tsx b/packages/core/stories/extending/CustomComponents.stories.tsx new file mode 100644 index 0000000..8fc76cc --- /dev/null +++ b/packages/core/stories/extending/CustomComponents.stories.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import { useAIMarkdownRenderState, type AIMarkdownCustomComponents } from '../../src/index'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Extending/Custom Components', + parameters: { + docs: { + description: { + component: + 'Replace any element renderer via the `customComponents` prop (a re-exported ' + + "`react-markdown` `Components` map). Each component receives the element's props plus " + + '`node` (the hast element) — destructure `node` out before spreading onto a DOM node. ' + + 'Define the map at module scope so its identity stays stable across renders (the ' + + 'block-memo cache depends on it).', + }, + }, + }, +}; + +export default meta; + +/** Open external links in a new tab; keep relative links in-tab. */ +const linkComponents: AIMarkdownCustomComponents = { + a: ({ node, href, children, ...rest }) => { + const external = !!href && /^https?:\/\//.test(href); + return ( + + {children} + {external ? ' ↗' : null} + + ); + }, +}; + +export const ExternalLinks: CoreStory = { + args: { + content: `An [external link](https://github.com) opens in a new tab and gets a ↗ marker. + +A [relative link](/docs/intro) stays in the same tab.`, + }, + render: (args) => , +}; + +/** + * A copy button on fenced code blocks. Block code is detected by the + * `language-*` class; inline code is left untouched. The button is hidden while + * `streaming` (read from `useAIMarkdownRenderState`) so you don't copy a + * half-arrived snippet. + */ +function CodeWithCopy({ node, className, children, ...rest }: React.ComponentProps<'code'> & { node?: unknown }) { + const { streaming } = useAIMarkdownRenderState(); + const isBlock = typeof className === 'string' && className.startsWith('language-'); + if (!isBlock) { + return ( + + {children} + + ); + } + const text = String(children).replace(/\n$/, ''); + return ( + + {!streaming && ( + + )} + + {children} + + + ); +} + +const codeComponents: AIMarkdownCustomComponents = { code: CodeWithCopy }; + +export const CodeWithCopyButton: CoreStory = { + args: { + content: `Hover the block for a copy button (inline \`code\` is untouched): + +\`\`\`ts +export function greet(name: string): string { + return \`Hello, \${name}!\`; +} +\`\`\``, + }, + render: (args) => , +}; + +/** Lazy-load images and render their title as a caption. */ +const imageComponents: AIMarkdownCustomComponents = { + img: ({ node, src, alt, title, ...rest }) => ( +
+ {alt + {title ?
{title}
: null} +
+ ), +}; + +export const ImagesWithCaptions: CoreStory = { + args: { + content: `![Vue logo](https://vuejs.org/images/logo.png "Figure 1 — the title becomes a caption")`, + }, + render: (args) => , +}; diff --git a/packages/core/stories/extending/CustomTypography.stories.tsx b/packages/core/stories/extending/CustomTypography.stories.tsx new file mode 100644 index 0000000..a09360b --- /dev/null +++ b/packages/core/stories/extending/CustomTypography.stories.tsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import type { AIMarkdownTypographyComponent } from '../../src/index'; + +const SAMPLE = `## Wrapped by a custom Typography + +The wrapper below adds a card frame and an ARIA landmark **around** the markdown +— while still merging the injected \`style\` so design tokens keep working. + +- It must spread \`style\` onto its root element. +- It receives \`fontSize\`, \`variant\`, and \`colorScheme\`. + +\`\`\`ts +const ok = true; +\`\`\``; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Extending/Custom Typography', + parameters: { + docs: { + description: { + component: + 'The `Typography` prop swaps the wrapper element rendered around all markdown output. ' + + 'Reach for it when you need to change **structure** (a card, a Context provider, an ARIA ' + + 'landmark) — most pure-theming needs are better served by Design Tokens. The one ' + + 'non-negotiable rule: **merge the injected `style` onto your root element**, or ' + + 'descendant rules that read `var(--aim-font-size-root)` lose their anchor.', + }, + }, + }, + args: { content: SAMPLE }, +}; + +export default meta; + +/** A card wrapper that also exposes the message as an ARIA `article` landmark. */ +const CardTypography: AIMarkdownTypographyComponent = ({ children, fontSize, colorScheme, style }) => { + const dark = colorScheme === 'dark'; + return ( +
+ {children} +
+ ); +}; + +export const CardWrapper: CoreStory = { + render: (args) => , +}; + +/** + * The footgun, shown deliberately: this wrapper forgets to spread `style`, so + * `--aim-font-size-root` never reaches the content. The `fontSize` arg below is + * large, yet token-driven dimensions fall back to their inherited defaults. + * Compare with `CardWrapper`, which spreads `style` correctly. + */ +// Intentional anti-pattern for the docs: `style` is deliberately NOT spread. +const BrokenTypography: AIMarkdownTypographyComponent = ({ children, fontSize }) => ( +
{children}
+); + +export const MissingStyleFootgun: CoreStory = { + args: { fontSize: '1.5rem' }, + parameters: { + docs: { + description: { + story: + 'Anti-pattern: `style` is not spread. Even at `fontSize="1.5rem"`, headings and spacing ' + + 'do not scale because the token anchor is missing.', + }, + }, + }, + render: (args) => , +}; diff --git a/packages/core/stories/extending/MetadataContext.stories.tsx b/packages/core/stories/extending/MetadataContext.stories.tsx new file mode 100644 index 0000000..7472ff8 --- /dev/null +++ b/packages/core/stories/extending/MetadataContext.stories.tsx @@ -0,0 +1,136 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, AIMarkdown, useColorScheme } from '../_shared/coreMeta'; +import { useAIMarkdownMetadata, type AIMarkdownCustomComponents } from '../../src/index'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Extending/Metadata Context', + parameters: { + docs: { + description: { + component: + '`metadata` is a typed React context for passing app data — callbacks, ids, config — to ' + + 'deeply nested custom components **without prop drilling**. Crucially it lives in a ' + + 'separate context from render state, so rebuilding `metadata` every render (new callback ' + + 'refs and all) does **not** re-render the markdown body or bust the block-memo cache. ' + + 'Read it with `useAIMarkdownMetadata()`, which returns `T | undefined`.', + }, + }, + }, +}; + +export default meta; + +interface ChatMeta { + onCopyCode: (code: string) => void; + onCite: (label: string) => void; +} + +/** A code block whose Copy button calls a callback carried by `metadata`. */ +function MetaCodeBlock({ node, className, children, ...rest }: React.ComponentProps<'code'> & { node?: unknown }) { + const meta = useAIMarkdownMetadata(); + const isBlock = typeof className === 'string' && className.startsWith('language-'); + if (!isBlock) { + return ( + + {children} + + ); + } + const text = String(children).replace(/\n$/, ''); + return ( + + + + {children} + + + ); +} + +/** A citation link `[n](#cite-n)` that calls back instead of navigating. */ +function MetaCite({ node, href, children, ...rest }: React.ComponentProps<'a'> & { node?: unknown }) { + const meta = useAIMarkdownMetadata(); + if (href?.startsWith('#cite-')) { + const label = href.slice('#cite-'.length); + return ( + { + e.preventDefault(); + meta?.onCite(label); + }} + > + {children} + + ); + } + return ( + + {children} + + ); +} + +const components: AIMarkdownCustomComponents = { code: MetaCodeBlock, a: MetaCite }; + +const CONTENT = `The result follows from the lemma [1](#cite-1) and the theorem [2](#cite-2). + +\`\`\`ts +const total = items.reduce((a, b) => a + b, 0); +\`\`\` + +Click **Copy** or a citation — both fire callbacks passed via \`metadata\`.`; + +function MetadataDemo() { + const colorScheme = useColorScheme(); + const [log, setLog] = React.useState('— interact above —'); + // Rebuilt every render with fresh callback identities — and yet the markdown + // body below is NOT re-rendered, because metadata lives in its own context. + const metadata: ChatMeta = { + onCopyCode: (code) => setLog(`Copied ${code.length} chars to clipboard`), + onCite: (label) => setLog(`Citation [${label}] clicked`), + }; + return ( +
+
+ last action: {log} +
+ +
+ ); +} + +/** Copy and citation buttons drive a live log via `metadata` callbacks. */ +export const CallbacksWithoutPropDrilling: CoreStory = { + render: () => , +}; diff --git a/packages/core/stories/extending/TypeScriptGenerics.stories.tsx b/packages/core/stories/extending/TypeScriptGenerics.stories.tsx new file mode 100644 index 0000000..a2f5d73 --- /dev/null +++ b/packages/core/stories/extending/TypeScriptGenerics.stories.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, AIMarkdown, useColorScheme } from '../_shared/coreMeta'; +import { + defaultAIMarkdownRenderConfig, + useAIMarkdownRenderState, + useAIMarkdownMetadata, + type AIMarkdownRenderConfig, + type AIMarkdownMetadata, + type AIMarkdownCustomComponents, +} from '../../src/index'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Extending/TypeScript Generics', + parameters: { + docs: { + description: { + component: + '`>` takes two generic parameters: `TConfig` extends ' + + 'the render config with your own fields (pair it with a matching `defaultConfig` so ' + + '`config` can stay partial), and `TRenderData` types the `metadata` object your custom ' + + 'components read back. Consumers read both with `useAIMarkdownRenderState()` ' + + 'and `useAIMarkdownMetadata()`. **Both hook generics are caller ' + + 'assertions** — TypeScript cannot verify the provider actually supplied that shape, so ' + + 'pin each assertion once in a wrapper hook next to the config definition (the pattern ' + + 'below, and what `@ai-react-markdown/mantine` does). Full guide: ' + + '`docs/typescript-generics.md`.', + }, + }, + }, +}; + +export default meta; + +// ── 1. Shape: extend the base config with app-specific fields ─────────────── +interface DemoConfig extends AIMarkdownRenderConfig { + showLineNumbers: boolean; +} + +// ── 2. Default: required so the `config` prop can stay deeply partial ─────── +const defaultDemoConfig: DemoConfig = { + ...defaultAIMarkdownRenderConfig, + showLineNumbers: true, +}; + +// ── 3. Typed metadata carried alongside (but independent of) the config ───── +interface ChatMeta extends AIMarkdownMetadata { + messageId: string; +} + +// ── 4. Wrapper hooks: the ONE place each generic assertion lives ──────────── +// Custom components import these instead of sprinkling `` / +// `` across the codebase — if the shape changes, one file changes. +const useDemoRenderState = () => useAIMarkdownRenderState(); +const useChatMeta = () => useAIMarkdownMetadata(); + +/** + * A code renderer driven by BOTH generics: `config.showLineNumbers` (typed via `TConfig`) + * toggles the gutter, and the footer cites `metadata.messageId` (typed via `TRenderData`). + * Note the optional chain on metadata — unlike config, it has no default fallback. + */ +function LineNumberedCode({ node, className, children, ...rest }: React.ComponentProps<'code'> & { node?: unknown }) { + const { config } = useDemoRenderState(); + const chatMeta = useChatMeta(); + const isBlock = typeof className === 'string' && className.startsWith('language-'); + if (!isBlock || !config.showLineNumbers) { + return ( + + {children} + + ); + } + const lines = String(children).replace(/\n$/, '').split('\n'); + return ( + + {lines.map((line, i) => ( + + + {i + 1} + + {line} + + ))} + + {`// from message ${chatMeta?.messageId ?? '(no metadata provided)'}`} + + + ); +} + +const components: AIMarkdownCustomComponents = { code: LineNumberedCode }; + +const CONTENT = `The renderer below reads \`config.showLineNumbers\` and \`metadata.messageId\`, +both fully typed: + +\`\`\`ts +export function fibonacci(n: number): number { + if (n < 2) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} +\`\`\``; + +// Module-scope so the reference is stable across renders (metadata is +// intentionally NOT deep-stabilized by the library). +const METADATA: ChatMeta = { messageId: 'msg-42' }; + +/** Both generics wired explicitly; `config` is partial and deep-merged over `defaultDemoConfig`. */ +function TypedDemo({ showLineNumbers }: { showLineNumbers?: boolean }) { + const colorScheme = useColorScheme(); + return ( + // ── 5. Explicit generic arguments at the provider call site ── + + content={CONTENT} + colorScheme={colorScheme} + defaultConfig={defaultDemoConfig} + config={{ showLineNumbers }} + metadata={METADATA} + customComponents={components} + /> + ); +} + +/** Extended config + typed metadata flowing into a custom component, gutter on. */ +export const TypedConfigAndMetadata: CoreStory = { + render: () => , +}; + +/** Same setup, overriding the extended field through the partial `config` prop. */ +export const ExtendedFieldToggledOff: CoreStory = { + render: () => , +}; diff --git a/packages/core/stories/features/CodeBlocks.stories.tsx b/packages/core/stories/features/CodeBlocks.stories.tsx new file mode 100644 index 0000000..b025556 --- /dev/null +++ b/packages/core/stories/features/CodeBlocks.stories.tsx @@ -0,0 +1,69 @@ +import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Features/Code Blocks', + parameters: { + docs: { + description: { + component: + 'Fenced code blocks render as semantic, language-tagged `
` ' +
+          'styled by the typography tokens. **Core does not tokenize** — it deliberately ships no ' +
+          'syntax-highlighting engine, so the output stays small and you choose the tokenizer ' +
+          '(or use the `@ai-react-markdown/mantine` subpackage, which adds highlighting). ' +
+          'See **Extending / Custom Components** to wire in your own highlighter or copy button.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** Inline code and a fenced block with a language tag. */
+export const Basic: CoreStory = {
+  args: {
+    content: `Install with \`pnpm add @ai-react-markdown/core\`, then:
+
+\`\`\`tsx
+import AIMarkdown from '@ai-react-markdown/core';
+
+export function Message({ content }: { content: string }) {
+  return ;
+}
+\`\`\``,
+  },
+};
+
+/** The `language-*` class is preserved per fence, ready for any CSS theme or tokenizer. */
+export const MultipleLanguages: CoreStory = {
+  args: {
+    content: `\`\`\`python
+def fib(n: int) -> int:
+    a, b = 0, 1
+    for _ in range(n):
+        a, b = b, a + b
+    return a
+\`\`\`
+
+\`\`\`sql
+SELECT id, name FROM users WHERE active = true ORDER BY created_at DESC;
+\`\`\`
+
+\`\`\`bash
+curl -s https://api.example.com/v1/models | jq '.data[].id'
+\`\`\``,
+  },
+};
+
+/** A fence with no language info string still renders as a clean monospace block. */
+export const NoLanguage: CoreStory = {
+  args: {
+    content: `\`\`\`
+packages/
+  core/
+  mantine/
+pnpm-workspace.yaml
+\`\`\``,
+  },
+};
diff --git a/packages/core/stories/features/EmojiAndCJK.stories.tsx b/packages/core/stories/features/EmojiAndCJK.stories.tsx
new file mode 100644
index 0000000..48258df
--- /dev/null
+++ b/packages/core/stories/features/EmojiAndCJK.stories.tsx
@@ -0,0 +1,57 @@
+import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Features/Emoji & CJK',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          '`:shortcode:` emoji via `remark-emoji`, plus first-class CJK handling: ' +
+          '`remark-cjk-friendly` makes `**bold**` work even when it touches CJK punctuation ' +
+          '(stock markdown fails here), and the pangu display optimization auto-inserts spacing ' +
+          'between CJK and half-width Latin/numbers.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** Emoji shortcodes expand to Unicode emoji. */
+export const Emoji: CoreStory = {
+  args: {
+    content: `Ship it :rocket: — tests are green :white_check_mark: and the team is happy :tada:.
+
+Reactions inline: :thumbsup: :heart: :eyes: :fire:`,
+  },
+};
+
+/**
+ * The canonical CJK emphasis bug: stock markdown won't treat `**…**` as bold
+ * when an asterisk is adjacent to a full-width quote or paren. `remark-cjk-friendly`
+ * fixes it, so every line below renders the intended emphasis.
+ */
+export const CJKEmphasisFix: CoreStory = {
+  args: {
+    content:
+      '这是一个**“会引起”**渲染错误的**“已知问题”**,当加重符号遇到某些中文标点时,可能就会出现**“识别不了”**的情况。\n\n' +
+      '**このアスタリスクは強調記号として認識されます。**この文のおかげで。\n\n' +
+      '**해당 별표는 강조 표시로 인식됩니다(이 괄호에도 불구하고).**이 문장 덕분에.\n\n' +
+      '删除线同理:**~~该星号会被正确识别~~**这是因为它被识别为强调符号。',
+  },
+};
+
+/**
+ * Pangu auto-spacing (a default display optimization) inserts a thin gap between
+ * CJK characters and adjacent Latin words or numbers, matching typographic
+ * convention. Toggle it off in **Configuration / Display Optimizations**.
+ */
+export const PanguSpacing: CoreStory = {
+  args: {
+    content:
+      '使用 AIMarkdown 渲染 LLM 输出的 Markdown,支持 GFM 和 LaTeX 公式。\n\n' +
+      '当 CJK 文本紧贴 ASCII 单词或数字(如 React19 与 2026年)时,pangu 会补上正确的间距。',
+  },
+};
diff --git a/packages/core/stories/features/GFM.stories.tsx b/packages/core/stories/features/GFM.stories.tsx
new file mode 100644
index 0000000..7494e8b
--- /dev/null
+++ b/packages/core/stories/features/GFM.stories.tsx
@@ -0,0 +1,59 @@
+import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Features/GFM',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          'GitHub Flavored Markdown via `remark-gfm`: tables (with per-column alignment), ' +
+          'task lists, strikethrough, and autolinked URLs.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** Column alignment is driven by the `:` markers in the delimiter row. */
+export const Tables: CoreStory = {
+  args: {
+    content: `## Plans
+
+| Feature        | Free      |    Pro     |       Enterprise |
+| :------------- | :-------- | :--------: | ---------------: |
+| Seats          | 1         |     10     |        Unlimited |
+| Streaming      | ✓         |     ✓      |                ✓ |
+| Priority queue | —         |     ✓      |                ✓ |
+| SSO            | —         |     —      |                ✓ |
+
+Left-aligned, center-aligned, and right-aligned columns respectively.`,
+  },
+};
+
+/** Checked and unchecked items render as (disabled) checkboxes by default. */
+export const TaskLists: CoreStory = {
+  args: {
+    content: `### Release checklist
+
+- [x] Cut the release branch
+- [x] Run the full test suite
+- [ ] Update the changelog
+- [ ] Publish to npm
+  - [x] Build the package
+  - [ ] Verify the published tarball`,
+  },
+};
+
+/** Strikethrough and GFM autolinks need no explicit link syntax. */
+export const StrikethroughAndAutolinks: CoreStory = {
+  args: {
+    content: `Pricing was ~~$99/mo~~ now $79/mo for early adopters.
+
+Bare URLs autolink: visit https://github.com/AIEPhoenix/ai-react-markdown for the source.
+
+Email autolinks too: reach the maintainer at hello@example.com.`,
+  },
+};
diff --git a/packages/core/stories/features/ListsAndFootnotes.stories.tsx b/packages/core/stories/features/ListsAndFootnotes.stories.tsx
new file mode 100644
index 0000000..6baeea9
--- /dev/null
+++ b/packages/core/stories/features/ListsAndFootnotes.stories.tsx
@@ -0,0 +1,63 @@
+import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Features/Lists & Footnotes',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          'Ordered, unordered, and nested lists; definition lists (the DEFINITION_LIST extra ' +
+          'syntax, on by default); and footnotes with auto back-references. Footnote ids are ' +
+          'namespaced per document — see **Robustness / Document Isolation** for why that matters.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** Mixed ordered/unordered nesting to several levels. */
+export const NestedLists: CoreStory = {
+  args: {
+    content: `1. First step
+2. Second step
+   - Sub-point A
+   - Sub-point B
+     1. Deeply nested ordered item
+     2. Another one
+3. Third step
+
+- Top-level bullet
+  - Nested bullet
+    - Even deeper`,
+  },
+};
+
+/**
+ * Definition lists use the PHP-Markdown-Extra syntax: a term line followed by
+ * one or more `: definition` lines.
+ */
+export const DefinitionLists: CoreStory = {
+  args: {
+    content: `Token System
+: A set of CSS custom properties that define colors, spacing, and typography.
+
+Design Token
+: An individual variable (e.g. \`--aim-color-anchor\`) you can override to retheme.
+: A term may have multiple definitions, each on its own line.`,
+  },
+};
+
+/** Footnote references link down to definitions, which link back up. */
+export const Footnotes: CoreStory = {
+  args: {
+    content: `The token system[^tokens] enables full theme customization without forking[^fork].
+
+Multiple references to the same note[^tokens] resolve to one definition.
+
+[^tokens]: See the Design Tokens story for the complete token reference.
+[^fork]: You override CSS custom properties in your own stylesheet — no source changes.`,
+  },
+};
diff --git a/packages/core/stories/features/Math.stories.tsx b/packages/core/stories/features/Math.stories.tsx
new file mode 100644
index 0000000..ce9b52d
--- /dev/null
+++ b/packages/core/stories/features/Math.stories.tsx
@@ -0,0 +1,98 @@
+import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Features/Math',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          'Inline and display math via `remark-math` + KaTeX. A built-in LaTeX preprocessor ' +
+          'runs first and fixes the rough edges of model-emitted math: currency `$`, ' +
+          '`\\[…\\]` / `\\(…\\)` delimiters, table-pipe escaping, and `mhchem`. Requires ' +
+          "`import 'katex/dist/katex.min.css'`.",
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** Inline math sits in running text; display math gets its own centered block. */
+export const InlineAndDisplay: CoreStory = {
+  args: {
+    content: String.raw`Euler's identity, $e^{i\pi} + 1 = 0$, ties together five constants inline.
+
+The Gaussian integral as a display block:
+
+$$\int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$$
+
+And a matrix:
+
+$$
+\begin{bmatrix} a & b \\ c & d \end{bmatrix}
+\begin{bmatrix} x \\ y \end{bmatrix}
+=
+\begin{bmatrix} ax + by \\ cx + dy \end{bmatrix}
+$$`,
+  },
+};
+
+/**
+ * The preprocessor normalizes the alternate delimiters LLMs love to emit —
+ * `\(…\)` for inline and `\[…\]` for display — into the `$…$` / `$$…$$` form
+ * `remark-math` understands. No configuration needed.
+ */
+export const BracketDelimiters: CoreStory = {
+  args: {
+    content: String.raw`Written with TeX-style delimiters instead of dollar signs:
+
+Inline: \(a^2 + b^2 = c^2\) renders just like dollar-delimited math.
+
+Display:
+
+\[
+f(x) = \sum_{n=0}^{\infty} \frac{f^{(n)}(0)}{n!} x^n
+\]`,
+  },
+};
+
+/**
+ * The single hardest disambiguation in markdown math: a `$` that means *money*
+ * versus a `$` that opens a formula. The preprocessor recognizes currency
+ * patterns so prices render as plain text and never swallow the rest of the
+ * line into a formula.
+ */
+export const CurrencyVsMath: CoreStory = {
+  args: {
+    content: String.raw`The license costs $5.99 per seat, or $59.90 per year — these stay as prices.
+
+But $E = mc^2$ is still parsed as math, because the preprocessor only treats a
+dollar sign as currency when it looks like currency (a digit follows, and there
+is no closing dollar on the same line).
+
+A range like $10–$20 also survives without collapsing into a formula.`,
+  },
+};
+
+/**
+ * `mhchem` chemical equations and pipes inside math both work: the preprocessor
+ * escapes `|` so a formula can live inside a GFM table cell without the pipe
+ * being read as a column separator.
+ */
+export const ChemistryAndTables: CoreStory = {
+  args: {
+    content: String.raw`Chemical equation via mhchem:
+
+$$\ce{2 H2 + O2 -> 2 H2O}$$
+
+Math inside a table cell (note the pipe in the set-builder notation survives):
+
+| Concept | Definition |
+| ------- | ---------- |
+| Norm | $\lVert x \rVert = \sqrt{x_1^2 + x_2^2}$ |
+| Set | $\{\, x \mid x > 0 \,\}$ |
+| Limit | $\lim_{n \to \infty} \frac{1}{n} = 0$ |`,
+  },
+};
diff --git a/packages/core/stories/features/TextAndInline.stories.tsx b/packages/core/stories/features/TextAndInline.stories.tsx
new file mode 100644
index 0000000..0d6c121
--- /dev/null
+++ b/packages/core/stories/features/TextAndInline.stories.tsx
@@ -0,0 +1,62 @@
+import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Features/Text & Inline',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          'Block and inline text rendering: the full heading scale, nested blockquotes, ' +
+          '`==highlight==` (the HIGHLIGHT extra syntax, on by default), and raw inline HTML ' +
+          '(``, ``, ``) — allowed through because `rehype-raw` runs but ' +
+          '`rehype-sanitize` still strips anything dangerous.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+/** All six heading levels share a weight token but scale down in size. */
+export const Headings: CoreStory = {
+  args: {
+    content: `# Heading 1
+## Heading 2
+### Heading 3
+#### Heading 4
+##### Heading 5
+###### Heading 6
+
+Body text for reference, with **bold**, *italic*, and \`inline code\`.`,
+  },
+};
+
+/** Emphasis, highlight, and inline HTML composed together in running prose. */
+export const InlineFormatting: CoreStory = {
+  args: {
+    content: `Combine **bold**, *italic*, ***bold italic***, ~~strikethrough~~, and
+==highlighted text== in one sentence.
+
+Scientific notation needs inline HTML: H2O and E = mc2.
+Track edits with inserted text.
+
+Use \`npm install\` to add a dependency; the \`--save-dev\` flag marks it as a dev dependency.`,
+  },
+};
+
+/** Blockquotes nest, and a horizontal rule separates sections. */
+export const BlockquotesAndRules: CoreStory = {
+  args: {
+    content: `> A single-level blockquote with **bold** and \`code\`.
+>
+> > Nested blockquotes work too, for quoting a reply within a quote.
+
+---
+
+> Attribution-style quote.
+>
+> — someone worth quoting`,
+  },
+};
diff --git a/packages/core/stories/robustness/DocumentIsolation.stories.tsx b/packages/core/stories/robustness/DocumentIsolation.stories.tsx
new file mode 100644
index 0000000..e79d3a6
--- /dev/null
+++ b/packages/core/stories/robustness/DocumentIsolation.stories.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { coreMetaBase, type CoreMeta, type CoreStory, AIMarkdown, useColorScheme } from '../_shared/coreMeta';
+
+const meta: CoreMeta = {
+  ...coreMetaBase,
+  tags: ['autodocs'],
+  title: 'Core/Robustness/Document Isolation',
+  parameters: {
+    docs: {
+      description: {
+        component:
+          'Two assistant messages on one page will both contain a footnote `[^1]` and identical ' +
+          'heading ids. Naïvely that means clicking `[^1]` in message A could jump to message B. ' +
+          'The renderer namespaces every clobberable id (`id`, hash `href`) with a per-document ' +
+          'prefix, so footnotes and anchors **never cross-link**. The namespace is keyed by ' +
+          '`documentId` — auto-generated via `useId()` when you omit it, or pass an explicit, ' +
+          'deterministic value.',
+      },
+    },
+  },
+};
+
+export default meta;
+
+const MESSAGE_A = `**Message A.** The architecture is token-driven[^1] and streaming-aware[^2].
+
+[^1]: A's note one — clicking the ref above lands *here*, inside A.
+[^2]: A's note two.`;
+
+const MESSAGE_B = `**Message B.** This message also defines a footnote[^1] with the very same label.
+
+[^1]: B's note one — isolated from A despite the identical \`[^1]\` label.`;
+
+function Stack({ idA, idB }: { idA?: string; idB?: string }) {
+  const colorScheme = useColorScheme();
+  const frame: React.CSSProperties = {
+    padding: '12px 16px',
+    borderRadius: 10,
+    border: `1px solid ${colorScheme === 'dark' ? '#373a40' : '#e9ecef'}`,
+  };
+  return (
+    
+
+ +
+
+ +
+
+ ); +} + +/** + * No `documentId` supplied — each instance auto-generates a unique id via + * `useId()`. Click `[^1]` in either message: it scrolls within its own message. + */ +export const AutoIsolated: CoreStory = { + render: () => , +}; + +/** + * Explicit, deterministic ids (useful for SSR snapshots or cross-component deep + * links). The rendered anchor ids are stable and still fully isolated. + */ +export const ExplicitDocumentId: CoreStory = { + render: () => , +}; diff --git a/packages/core/stories/robustness/PartialMarkdown.stories.tsx b/packages/core/stories/robustness/PartialMarkdown.stories.tsx new file mode 100644 index 0000000..7c3bf93 --- /dev/null +++ b/packages/core/stories/robustness/PartialMarkdown.stories.tsx @@ -0,0 +1,87 @@ +import { coreMetaBase, type CoreMeta, type CoreStory } from '../_shared/coreMeta'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Robustness/Partial Markdown', + parameters: { + docs: { + description: { + component: + 'During streaming the renderer is constantly handed **syntactically incomplete** markdown ' + + '— an open code fence, a half-typed bold, a table with no body yet, a `$$` block that ' + + "hasn't closed. None of these should throw or corrupt the output. Each story freezes one " + + 'such mid-stream state; the component degrades gracefully every time. For the live version, ' + + 'see **Core / AIMarkdown → Streaming**.', + }, + }, + }, +}; + +export default meta; + +/** A fenced block that never closes still renders as a code block, not raw text. */ +export const UnclosedCodeFence: CoreStory = { + args: { + streaming: true, + content: `Here's the implementation so far: + +\`\`\`ts +export function partial(n: number) { + const acc = []; + for (let i = 0; i < n; i++) {`, + }, +}; + +/** Half-finished emphasis and a dangling link don't break the surrounding text. */ +export const UnclosedInline: CoreStory = { + args: { + streaming: true, + content: `This sentence has **bold that never closes and keeps going. + +An incomplete [link label](https://exa + +And an unfinished inline \`code span that runs off the edge.`, + }, +}; + +/** A table mid-construction (header + delimiter, partial row) renders what it can. */ +export const TruncatedTable: CoreStory = { + args: { + streaming: true, + content: `| Name | Role | +| ---- | ---- | +| Ada | Eng`, + }, +}; + +/** + * The LaTeX preprocessor truncates an unclosed `$$` block while streaming so a + * half-arrived formula doesn't swallow the rest of the document into math mode. + */ +export const UnclosedMath: CoreStory = { + args: { + streaming: true, + content: `The integral we're deriving: + +$$\\int_{0}^{1} x^2 \\,dx = `, + }, +}; + +/** All of the above at once — the realistic shape of a single streamed frame. */ +export const MixedMidStream: CoreStory = { + args: { + streaming: true, + content: `## Summary so far + +We computed the result and found that **the value is + +| Metric | Value | +| ------ | ----- | +| Mean | + +\`\`\`python +def estimate(xs): + return sum(xs) /`, + }, +}; diff --git a/packages/core/stories/robustness/UrlSanitization.stories.tsx b/packages/core/stories/robustness/UrlSanitization.stories.tsx new file mode 100644 index 0000000..ad431c0 --- /dev/null +++ b/packages/core/stories/robustness/UrlSanitization.stories.tsx @@ -0,0 +1,71 @@ +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; +import { defaultUrlTransform, extendSanitizeSchema } from '../../src/index'; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Robustness/URL Sanitization', + parameters: { + docs: { + description: { + component: + 'LLM output is untrusted. URLs pass through **two independent gates** (defense in depth): ' + + 'Gate 1 is the `rehype-sanitize` protocol allowlist (`http https irc ircs mailto xmpp`), ' + + 'Gate 2 is `urlTransform`. Anything else — `javascript:`, `data:`, `vbscript:`, inline ' + + "event handlers — is rewritten to `''` and rendered as a dead link. Both gates must " + + 'permit a URL for it to render.', + }, + }, + }, +}; + +export default meta; + +/** + * Hostile markdown that a compromised or jailbroken model might emit. Every + * attack below is neutralized: the links go dead, the `onerror` handler and the + * ` + +By contrast, a [safe https link](https://example.com) renders normally.`, + }, +}; + +// ── Custom-scheme opt-in: BOTH gates extended at module scope ───────────────── +// Gate 1 — allow `myapp` on href + src in the sanitize schema. +const SCHEMA = extendSanitizeSchema((s) => { + s.protocols!.href!.push('myapp'); + s.protocols!.src!.push('myapp'); +}); +// Gate 2 — let `myapp:` through, defer everything else to the safe default. +const ALLOWED = /^myapp:/i; +const URL_TRANSFORM = (url: string, key: string, node: unknown) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ALLOWED.test(url) ? url : (defaultUrlTransform as any)(url, key, node); + +/** + * Allowing a private scheme requires opting *both* gates in — the most common + * mistake is extending only one. Here `myapp://` links render live, while + * `javascript:` is still blocked because it isn't on either allowlist. + */ +export const CustomSchemeOptIn: CoreStory = { + args: { + content: `A deep link into the app: [open item 42](myapp://item/42) — this renders live. + +A still-blocked attack: [nope](javascript:alert(1)).`, + }, + render: (args) => , +}; diff --git a/packages/core/stories/theming/ColorSchemes.stories.tsx b/packages/core/stories/theming/ColorSchemes.stories.tsx new file mode 100644 index 0000000..f1fe053 --- /dev/null +++ b/packages/core/stories/theming/ColorSchemes.stories.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, AIMarkdown } from '../_shared/coreMeta'; + +const SAMPLE = `## Color scheme demo + +A paragraph with a [link](https://example.com), some \`inline code\`, and +==highlighted text== so you can compare accent colors. + +> A blockquote picks up the dimmed border and background tokens. + +| Token | Light | Dark | +| ----- | ----- | ---- | +| Anchor | blue | lighter blue | +| Border | grey | darker grey | + +\`\`\`ts +const scheme: 'light' | 'dark' = 'light'; +\`\`\``; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Theming/Color Schemes', + parameters: { + docs: { + description: { + component: + 'The `colorScheme` prop (`"light"` | `"dark"`) switches which CSS token scope is ' + + 'active — `.aim-typography-root.light` vs `.aim-typography-root.dark`. No JS theme ' + + 'context, just a class. Use the toolbar **Theme** switch on the first story, or see ' + + 'both at once below.', + }, + }, + }, + args: { content: SAMPLE }, +}; + +export default meta; + +/** Honors the toolbar Theme switch — flip it to see light ↔ dark. */ +export const FollowToolbar: CoreStory = {}; + +const panelStyle = (dark: boolean): React.CSSProperties => ({ + flex: '1 1 320px', + minWidth: 280, + padding: 20, + borderRadius: 10, + border: `1px solid ${dark ? '#373a40' : '#dee2e6'}`, + background: dark ? 'rgb(36, 36, 36)' : '#ffffff', + color: dark ? '#c1c2c5' : '#1a1b1e', +}); + +/** + * Both schemes rendered simultaneously and independently of the toolbar, so the + * accent, border, and code-surface differences are directly comparable. + */ +export const SideBySide: CoreStory = { + parameters: { docs: { description: { story: 'Two fixed instances — one `light`, one `dark`.' } } }, + render: (args) => ( +
+
+ +
+
+ +
+
+ ), +}; diff --git a/packages/core/stories/theming/DesignTokens.stories.tsx b/packages/core/stories/theming/DesignTokens.stories.tsx new file mode 100644 index 0000000..7c775bd --- /dev/null +++ b/packages/core/stories/theming/DesignTokens.stories.tsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, ThemedAIMarkdown } from '../_shared/coreMeta'; + +const SAMPLE = `# Retheme with CSS variables + +No JavaScript needed — just override the tokens you care about. + +A paragraph with a [link](https://example.com), ==a highlight==, and \`inline code\`. + +> A blockquote, to show border and spacing tokens. + +1. Ordered item one +2. Ordered item two + +\`\`\`ts +const themed = true; +\`\`\``; + +/** + * Inject a scoped stylesheet that overrides design tokens at higher specificity + * than the library's own `.aim-typography-root.default` rule. The library + * documents overriding "at that selector or a more specific one" — prefixing + * with our scope class is exactly that. + */ +function TokenScope({ + scope, + tokens, + children, +}: { + scope: string; + tokens: Record; + children: React.ReactNode; +}) { + const body = Object.entries(tokens) + .map(([k, v]) => ` ${k}: ${v};`) + .join('\n'); + const css = `.${scope} .aim-typography-root.default {\n${body}\n}`; + return ( +
+ + {children} +
+ ); +} + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Theming/Design Tokens', + parameters: { + docs: { + description: { + component: + 'The `default` variant is driven entirely by CSS custom properties scoped to ' + + '`.aim-typography-root.default`. Override the tokens you want in your own stylesheet ' + + '(at that selector or a more specific one) and the library picks them up — **full ' + + 'retheme, zero JavaScript**. Each story below injects a scoped ` + {children} + +); + +/** + * Makes the slot's position visible: a labeled frame around exactly what `ExtraStyles` + * wraps. The frame sits inside the typography wrapper (tokens, font-size, and color scheme + * still apply) and outside the markdown content. A wrapper component may use hooks — here it + * reads the story's live color scheme for the frame chrome. + */ +const VisibleSlotFrame: AIMarkdownExtraStylesComponent = ({ children }) => { + const colorScheme = useColorScheme(); + const border = colorScheme === 'dark' ? '#5c636a' : '#adb5bd'; + return ( +
+ + ExtraStyles wrapper + + {children} +
+ ); +}; + +/** Scoped CSS that auto-numbers the headings — styling a token surface can't express. */ +export const ScopedStylesheet: CoreStory = { + render: (args) => , +}; + +/** A dashed, labeled frame showing exactly what the slot wraps — and that hooks work inside it. */ +export const SlotPositionVisualized: CoreStory = { + render: (args) => , +}; diff --git a/packages/core/stories/theming/FontSize.stories.tsx b/packages/core/stories/theming/FontSize.stories.tsx new file mode 100644 index 0000000..16302b9 --- /dev/null +++ b/packages/core/stories/theming/FontSize.stories.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { coreMetaBase, type CoreMeta, type CoreStory, AIMarkdown } from '../_shared/coreMeta'; + +const SAMPLE = `# Heading scales too + +Body copy at the base size, with a nested list: + +- First item +- Second item + +\`\`\`ts +const scaled = true; +\`\`\` + +> Blockquotes, code, and headings all track the single \`fontSize\` prop.`; + +const meta: CoreMeta = { + ...coreMetaBase, + tags: ['autodocs'], + title: 'Core/Theming/Font Size', + parameters: { + docs: { + description: { + component: + 'Every spacing, font-size, and heading token is defined as ' + + '`calc(var(--aim-font-size-root) * k)`, and the core renderer injects ' + + '`--aim-font-size-root` from the `fontSize` prop. So **one prop proportionally scales ' + + 'the entire output** — text, spacing, headings, and KaTeX. Accepts a CSS length string ' + + 'or a number (treated as px).', + }, + }, + }, + args: { content: SAMPLE }, +}; + +export default meta; + +/** Edit the `fontSize` control to watch every dimension scale in lockstep. */ +export const Interactive: CoreStory = { + args: { fontSize: '0.9375rem' }, +}; + +const SIZES = ['0.8125rem', '0.9375rem', '1.125rem'] as const; + +/** Three fixed sizes side by side — small, default, large. */ +export const Scales: CoreStory = { + parameters: { docs: { description: { story: 'The same markdown at 13px, 15px, and 18px equivalents.' } } }, + render: (args) => ( +
+ {SIZES.map((size) => ( +
+
fontSize={size}
+ +
+ ))} +
+ ), +}; diff --git a/packages/mantine/stories/_shared/mantineMeta.tsx b/packages/mantine/stories/_shared/mantineMeta.tsx new file mode 100644 index 0000000..6f67b12 --- /dev/null +++ b/packages/mantine/stories/_shared/mantineMeta.tsx @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import MantineAIMarkdown from '../../src/index'; + +// KaTeX glyphs for math stories. Mantine core + code-highlight + highlight.js +// theme CSS are imported by the `withMantineProvider` decorator. +import 'katex/dist/katex.min.css'; + +import { withMantineProvider } from '../decorators'; + +export type MantineMeta = Meta; +export type MantineStory = StoryObj; + +/** + * Shared Controls config. `colorScheme` is hidden because the Mantine build + * resolves it from `MantineProvider` (the toolbar Theme switch drives + * `forceColorScheme` in the decorator); function-typed props are hidden too. + */ +export const mantineArgTypes: MantineMeta['argTypes'] = { + content: { control: 'text', description: 'Raw markdown content to render.' }, + streaming: { control: 'boolean', description: 'Whether content is actively being streamed.' }, + fontSize: { control: 'text', description: 'Base font size (e.g. `"0.9375rem"`, `"14px"`, or a number for px).' }, + config: { + control: 'object', + description: + 'Partial render config, deep-merged with defaults. Adds Mantine-only ' + + '`codeBlock.defaultExpanded` and `codeBlock.autoDetectUnknownLanguage` on top of the ' + + 'core `extraSyntaxSupported` / `displayOptimizeAbilities`.', + }, + metadata: { control: 'object', description: 'Arbitrary data passed to custom components via context.' }, + colorScheme: { table: { disable: true } }, + contentPreprocessors: { table: { disable: true } }, + customComponents: { table: { disable: true } }, + Typography: { table: { disable: true } }, + ExtraStyles: { table: { disable: true } }, + defaultConfig: { table: { disable: true } }, + sanitizeSchema: { table: { disable: true } }, + urlTransform: { table: { disable: true } }, +}; + +/** + * Shared meta fields for the Mantine showcase groups. Spread into each file's + * default export, then add the (statically required) `title` and `tags` + * literals — the CSF indexer can't read them through a spread or factory. + * + * ```ts + * const meta: MantineMeta = { + * ...mantineMetaBase, + * tags: ['autodocs'], + * title: 'Mantine/Features/Code Highlighting', + * }; + * ``` + */ +export const mantineMetaBase: Partial = { + component: MantineAIMarkdown, + decorators: [withMantineProvider], + argTypes: mantineArgTypes, + render: (args) => , +}; + +export { MantineAIMarkdown }; diff --git a/packages/mantine/stories/configuration/CodeBlock.stories.tsx b/packages/mantine/stories/configuration/CodeBlock.stories.tsx new file mode 100644 index 0000000..9e33edb --- /dev/null +++ b/packages/mantine/stories/configuration/CodeBlock.stories.tsx @@ -0,0 +1,54 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const LONG_CODE = `\`\`\`ts +// A deliberately long block to show the collapse behavior. +export function quicksort(xs: number[]): number[] { + if (xs.length <= 1) return xs; + const [pivot, ...rest] = xs; + const left = rest.filter((x) => x < pivot); + const right = rest.filter((x) => x >= pivot); + return [...quicksort(left), pivot, ...quicksort(right)]; +} + +export function mergesort(xs: number[]): number[] { + if (xs.length <= 1) return xs; + const mid = Math.floor(xs.length / 2); + const l = mergesort(xs.slice(0, mid)); + const r = mergesort(xs.slice(mid)); + const out: number[] = []; + let i = 0; + let j = 0; + while (i < l.length && j < r.length) out.push(l[i] <= r[j] ? l[i++] : r[j++]); + return [...out, ...l.slice(i), ...r.slice(j)]; +} +\`\`\``; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Configuration/Code Block', + parameters: { + docs: { + description: { + component: + 'Mantine-only `config.codeBlock` options. `defaultExpanded` (default `true`) controls ' + + 'whether long blocks start expanded or collapsed behind an expand button. ' + + '`autoDetectUnknownLanguage` (default `false`) highlights untagged fences via ' + + 'highlight.js language detection.', + }, + }, + }, + args: { content: LONG_CODE }, +}; + +export default meta; + +/** Default: code blocks start expanded. */ +export const Expanded: MantineStory = { + args: { config: { codeBlock: { defaultExpanded: true } } }, +}; + +/** Collapsed by default — long blocks show an expand control instead of the full body. */ +export const Collapsed: MantineStory = { + args: { config: { codeBlock: { defaultExpanded: false } } }, +}; diff --git a/packages/mantine/stories/decorators.tsx b/packages/mantine/stories/decorators.tsx index d71ac10..5a66784 100644 --- a/packages/mantine/stories/decorators.tsx +++ b/packages/mantine/stories/decorators.tsx @@ -1,17 +1,25 @@ import React from 'react'; import type { Decorator } from '@storybook/react-vite'; +import { useGlobals } from 'storybook/preview-api'; import { MantineProvider, createTheme } from '@mantine/core'; import { CodeHighlightAdapterProvider, createHighlightJsAdapter } from '@mantine/code-highlight'; import hljs from 'highlight.js'; import '@mantine/core/styles.css'; import '@mantine/code-highlight/styles.css'; -import './globals.css'; +import './globals.scss'; const theme = createTheme({}); const highlightJsAdapter = createHighlightJsAdapter(hljs); -export const withMantineProvider: Decorator = (Story, context) => { - const colorScheme = context.globals.theme === 'dark' ? 'dark' : 'light'; +export const withMantineProvider: Decorator = (Story) => { + // `useGlobals` is a STORYBOOK preview hook — it must be called directly in the + // decorator, not a nested component. Subscribing here re-renders on a live theme + // toggle (so `forceColorScheme` updates) — including inside autodocs Docs pages, + // where `context.globals` would otherwise stay frozen. The eslint rule below is a + // false positive (Storybook hook seen as a React hook in a non-component). + // eslint-disable-next-line react-hooks/rules-of-hooks + const [globals] = useGlobals(); + const colorScheme = globals.theme === 'dark' ? 'dark' : 'light'; return ( diff --git a/packages/mantine/stories/features/CodeHighlighting.stories.tsx b/packages/mantine/stories/features/CodeHighlighting.stories.tsx new file mode 100644 index 0000000..56441e0 --- /dev/null +++ b/packages/mantine/stories/features/CodeHighlighting.stories.tsx @@ -0,0 +1,79 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Features/Code Highlighting', + parameters: { + docs: { + description: { + component: + 'The headline difference from Core: fenced code blocks are **tokenized and ' + + 'syntax-highlighted** via `@mantine/code-highlight` (highlight.js), wrapped in ' + + "Mantine's `CodeHighlightTabs` with a language label and copy button. Core ships no " + + 'tokenizer — it emits semantic `language-*` classes only. The highlight.js theme ' + + 'follows the Mantine color scheme (atom-one-light / agate).', + }, + }, + }, +}; + +export default meta; + +/** Several languages, each tokenized with a language label and copy button. */ +export const ManyLanguages: MantineStory = { + args: { + content: `\`\`\`tsx +import MantineAIMarkdown from '@ai-react-markdown/mantine'; + +export function Message({ content }: { content: string }) { + return ; +} +\`\`\` + +\`\`\`python +def fib(n: int) -> int: + a, b = 0, 1 + for _ in range(n): + a, b = b, a + b + return a +\`\`\` + +\`\`\`sql +SELECT id, name FROM users WHERE active = true ORDER BY created_at DESC; +\`\`\` + +\`\`\`bash +curl -s https://api.example.com/v1/models | jq '.data[].id' +\`\`\``, + }, +}; + +/** A unified diff highlights additions and deletions. */ +export const Diff: MantineStory = { + args: { + content: `\`\`\`diff + function greet(name) { +- return 'Hello ' + name; ++ return \`Hello, \${name}!\`; + } +\`\`\``, + }, +}; + +/** + * With `autoDetectUnknownLanguage: true`, a fence that lacks a language tag is + * still highlighted — highlight.js guesses the language. Default is `false` + * (untagged blocks render as plain monospace). + */ +export const AutoDetectLanguage: MantineStory = { + args: { + config: { codeBlock: { autoDetectUnknownLanguage: true } }, + content: `No language tag on this fence, yet it gets highlighted: + +\`\`\` +const compiled = template.replace(/\\{(\\w+)\\}/g, (_, k) => vars[k]); +export default compiled; +\`\`\``, + }, +}; diff --git a/packages/mantine/stories/features/GFMAndText.stories.tsx b/packages/mantine/stories/features/GFMAndText.stories.tsx new file mode 100644 index 0000000..db5ebad --- /dev/null +++ b/packages/mantine/stories/features/GFMAndText.stories.tsx @@ -0,0 +1,53 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Features/GFM & Text', + parameters: { + docs: { + description: { + component: + 'GFM (tables, task lists, strikethrough) and the full text/heading scale, rendered ' + + 'through Mantine typography so spacing, headings, and table styling match the Mantine ' + + 'design system. Same markdown surface as **Core / Features**, Mantine-themed.', + }, + }, + }, +}; + +export default meta; + +/** Tables with alignment and a task list, Mantine-styled. */ +export const TablesAndTaskLists: MantineStory = { + args: { + content: `## Plans + +| Feature | Free | Pro | Enterprise | +| :-------- | :--: | :-: | ----------: | +| Seats | 1 | 10 | Unlimited | +| Streaming | ✓ | ✓ | ✓ | +| SSO | — | — | ✓ | + +### Checklist + +- [x] Install \`@ai-react-markdown/mantine\` +- [x] Wrap the app in \`MantineProvider\` +- [ ] Ship to production`, + }, +}; + +/** Headings, emphasis, blockquotes, and highlight through Mantine typography. */ +export const TextScale: MantineStory = { + args: { + content: `# Heading 1 +## Heading 2 +### Heading 3 + +Body text with **bold**, *italic*, ~~strikethrough~~, ==highlight==, and \`inline code\`. + +> A blockquote, styled by Mantine. +> +> > Nested for good measure.`, + }, +}; diff --git a/packages/mantine/stories/features/Math.stories.tsx b/packages/mantine/stories/features/Math.stories.tsx new file mode 100644 index 0000000..3c35ca5 --- /dev/null +++ b/packages/mantine/stories/features/Math.stories.tsx @@ -0,0 +1,32 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Features/Math', + parameters: { + docs: { + description: { + component: + 'The Mantine build inherits Core’s full math pipeline (KaTeX + the LaTeX ' + + 'preprocessor), rendered inside Mantine typography. Inline and display math, currency ' + + 'disambiguation, and `mhchem` all work exactly as in **Core / Features / Math**.', + }, + }, + }, +}; + +export default meta; + +/** Inline and display math, themed by Mantine. */ +export const InlineAndDisplay: MantineStory = { + args: { + content: String.raw`Euler's identity inline: $e^{i\pi} + 1 = 0$. + +A display block: + +$$\int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$$ + +Currency stays text — the plan costs $9.99/mo — while $a^2 + b^2 = c^2$ is math.`, + }, +}; diff --git a/packages/mantine/stories/features/MermaidDiagrams.stories.tsx b/packages/mantine/stories/features/MermaidDiagrams.stories.tsx new file mode 100644 index 0000000..3451c0c --- /dev/null +++ b/packages/mantine/stories/features/MermaidDiagrams.stories.tsx @@ -0,0 +1,66 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Features/Mermaid Diagrams', + parameters: { + docs: { + description: { + component: + 'A ```` ```mermaid ```` fence renders as a **live SVG diagram** (via the `mermaid` ' + + 'engine), with a toggle to view the raw source and automatic light/dark theming. On a ' + + 'parse error it falls back to showing the source instead of throwing. Core renders the ' + + 'same fence as a plain code block — diagram rendering is a Mantine-package feature.', + }, + }, + }, +}; + +export default meta; + +/** A flowchart. Use the control to switch between the diagram and its source. */ +export const Flowchart: MantineStory = { + args: { + content: `\`\`\`mermaid +graph TD + A[User message] --> B{Streaming?} + B -->|yes| C[Render partial chunks] + B -->|no| D[Render full document] + C --> E[Block-memo skips unchanged blocks] + D --> E + E --> F[Sanitized HTML output] +\`\`\``, + }, +}; + +/** A sequence diagram. */ +export const SequenceDiagram: MantineStory = { + args: { + content: `\`\`\`mermaid +sequenceDiagram + participant U as User + participant LLM + participant R as MantineAIMarkdown + U->>LLM: prompt + loop token stream + LLM-->>R: markdown chunk + R-->>U: rendered update + end +\`\`\``, + }, +}; + +/** + * Graceful degradation: invalid mermaid source does not crash the renderer — it + * falls back to displaying the raw source so the user still sees the content. + */ +export const InvalidSourceFallback: MantineStory = { + args: { + content: `\`\`\`mermaid +graph TD + A --> + this is not valid mermaid syntax {{{ +\`\`\``, + }, +}; diff --git a/packages/mantine/stories/features/RichDocument.stories.tsx b/packages/mantine/stories/features/RichDocument.stories.tsx new file mode 100644 index 0000000..b690c97 --- /dev/null +++ b/packages/mantine/stories/features/RichDocument.stories.tsx @@ -0,0 +1,73 @@ +import { mantineMetaBase, type MantineMeta, type MantineStory } from '../_shared/mantineMeta'; + +const meta: MantineMeta = { + ...mantineMetaBase, + tags: ['autodocs'], + title: 'Mantine/Features/Rich Document', + parameters: { + docs: { + description: { + component: + 'A realistic assistant message exercising the whole Mantine surface at once: prose, a ' + + 'highlighted code block, display math, a GFM table, a task list, and a live Mermaid ' + + 'diagram — the kind of mixed output an LLM actually streams into a chat UI.', + }, + }, + }, +}; + +export default meta; + +/** Everything composed together, the way a real answer arrives. */ +export const KitchenSink: MantineStory = { + args: { + content: String.raw`# Implementing debounce + +A **debounce** delays invoking a function until input settles. Here's a typed implementation: + +\`\`\`ts +export function debounce(fn: (...args: A) => void, ms: number) { + let t: ReturnType | undefined; + return (...args: A) => { + clearTimeout(t); + t = setTimeout(() => fn(...args), ms); + }; +} +\`\`\` + +## Cost model + +If events arrive at rate $\lambda$ and the wait is $w$, the expected number of +deferred calls before one fires is: + +$$E[N] = \frac{1}{1 - e^{-\lambda w}}$$ + +## When to reach for it + +| Scenario | Debounce | Throttle | +| :---------------- | :------: | :------: | +| Search-as-you-type | ✓ | — | +| Scroll handler | — | ✓ | +| Window resize | ✓ | — | + +### Follow-ups + +- [x] Implement the helper +- [ ] Add a leading-edge option +- [ ] Write tests + +## Control flow + +\`\`\`mermaid +graph LR + E[event] --> C{timer running?} + C -->|yes| R[reset timer] + C -->|no| S[start timer] + R --> W[wait w ms] + S --> W + W --> F[fire fn] +\`\`\` + +That's the complete picture. :rocket:`, + }, +}; diff --git a/packages/mantine/stories/globals.css b/packages/mantine/stories/globals.css deleted file mode 100644 index 25870ed..0000000 --- a/packages/mantine/stories/globals.css +++ /dev/null @@ -1,5 +0,0 @@ -@import 'highlight.js/styles/atom-one-light.min.css' layer(highlight-js); - -[data-mantine-color-scheme='dark'] { - @import 'highlight.js/styles/agate.min.css' layer(highlight-js); -} diff --git a/packages/mantine/stories/globals.scss b/packages/mantine/stories/globals.scss new file mode 100644 index 0000000..15cdb9f --- /dev/null +++ b/packages/mantine/stories/globals.scss @@ -0,0 +1,12 @@ +@use 'sass:meta'; + +@import 'highlight.js/styles/atom-one-light.min.css' layer(highlight-js); + +// CSS `@import` is only valid at the top of a stylesheet — nesting it under a +// selector silently drops the scoping at build time. Inline the dark theme via +// Sass instead so every rule actually nests under the Mantine dark attribute. +@layer highlight-js { + [data-mantine-color-scheme='dark'] { + @include meta.load-css('highlight.js/styles/agate.min.css'); + } +} From 9f7407fb2d29737abac65ff9e02f2efdfba6a3a1 Mon Sep 17 00:00:00 2001 From: Brian Lee Date: Mon, 6 Jul 2026 06:47:51 +0800 Subject: [PATCH 2/5] fix(core): harden block-memo internals and hot streaming paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - renderHastSubtree now clones by default (structural cloneHastForRender, shares position/data): memoized hast is never mutated in place, so a non-idempotent urlTransform can no longer compound across re-renders without a re-parse (registry bump / G3 flush / transform swap). The legacy single-use path opts out; non-element inline items skip the per-frame clone; aggregateFootnotesIfLast drops its manual JSON clone. - documentRegistry selectors read from version-keyed tables built in one pass — fingerprint computation drops from O(blocks x refs) per frame to O(1) lookups per version. - ownLabels is ref-stabilized (shared setsEqual) so streaming tokens no longer re-register the chunk and wake every renderer per token. - computeBlockFingerprint uses JSON tuple encoding (delimiter-injection proof); buildBlocks degrades offset-less nodes to inline items instead of dropping them; phantom labels are injected raw (micromark keeps escapes inside identifiers, so verbatim round-trips by construction). - useReferenceFlipWarning: recency-window burst detection plus a sustained consecutive-flip trigger that survives StrictMode's double-invoke; nested-wrapper prod warning is once-per-instance; new dev warning (via the shared useWouldCoordinate gate) when the legacy path renders under with an explicit documentId. - Remove the dead per-element documentId attribute plumbing (handlers, sanitize allowlist, placeholder props); context remains the source. --- .../components/AIMarkdownDocuments.test.tsx | 41 +++++ .../src/components/AIMarkdownDocuments.tsx | 45 ++++-- .../core/src/components/MarkdownContent.tsx | 84 +++++++--- .../components/aggregateFootnotesIfLast.tsx | 18 ++- .../core/src/components/blockMemo.test.ts | 148 +++++++++++++++++- packages/core/src/components/blockMemo.ts | 36 +++-- .../core/src/components/cloneHastForRender.ts | 30 ++++ .../src/components/crossChunkPlaceholders.tsx | 2 - .../components/customMdastHandlers.test.ts | 10 +- .../src/components/customMdastHandlers.ts | 7 - .../core/src/components/documentRegistry.ts | 127 ++++++++------- .../components/extendSanitizeSchema.test.ts | 3 +- .../extractDefBodiesFromHast.test.ts | 3 +- .../legacyCoordinationWarning.client.test.tsx | 88 +++++++++++ .../core/src/components/markdown/Markdown.tsx | 30 +++- .../core/src/components/markdown/types.ts | 3 +- .../remarkInjectPhantomDefs.test.ts | 31 ++++ .../src/components/remarkInjectPhantomDefs.ts | 12 ++ .../src/components/sanitizeSchema.test.ts | 9 +- .../core/src/components/sanitizeSchema.ts | 6 +- .../src/hooks/useReferenceFlipWarning.test.ts | 77 ++++++++- .../core/src/hooks/useReferenceFlipWarning.ts | 68 ++++++-- packages/core/src/typings/partial-deep.d.ts | 13 +- 23 files changed, 724 insertions(+), 167 deletions(-) create mode 100644 packages/core/src/components/cloneHastForRender.ts create mode 100644 packages/core/src/components/legacyCoordinationWarning.client.test.tsx diff --git a/packages/core/src/components/AIMarkdownDocuments.test.tsx b/packages/core/src/components/AIMarkdownDocuments.test.tsx index 1af2e25..83ae292 100644 --- a/packages/core/src/components/AIMarkdownDocuments.test.tsx +++ b/packages/core/src/components/AIMarkdownDocuments.test.tsx @@ -90,6 +90,29 @@ describe('', () => { } }); + test('nested-wrapper prod warning is once-per-instance, not once-per-module', () => { + // The guard lives in a ref: re-renders of one mounted misuse (every + // streaming token) log once, while a second, separately mounted misuse + // still gets its own report. Two independent trees → two logs. + const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + vi.stubEnv('NODE_ENV', 'production'); + try { + for (let i = 0; i < 2; i++) { + renderToString( + + +
+ + + ); + } + expect(errSpy).toHaveBeenCalledTimes(2); + } finally { + vi.unstubAllEnvs(); + errSpy.mockRestore(); + } + }); + test('useDocumentRegistry returns null if documentId is undefined', () => { let captured: Registry | null | undefined; function Probe() { @@ -105,6 +128,24 @@ describe('', () => { expect(captured).toBeNull(); }); + test('useDocumentRegistry returns null for an empty-string documentId', () => { + // Locks the falsy-string semantics of the shared `useWouldCoordinate` + // gate: `''` must behave like "no id" (a `documentId != null` refactor + // would silently regress this). + let captured: Registry | null | undefined; + function Probe() { + // eslint-disable-next-line react-hooks/globals -- test-probe pattern; see above. + captured = useDocumentRegistry(''); + return null; + } + renderToString( + + + + ); + expect(captured).toBeNull(); + }); + test('useDocumentRegistry returns null for a non-explicit (auto-generated) id inside wrapper', () => { // The crux of the standalone-vs-coordinated split: a chunk that did NOT // receive a documentId gets an auto-generated useId fallback. Even though diff --git a/packages/core/src/components/AIMarkdownDocuments.tsx b/packages/core/src/components/AIMarkdownDocuments.tsx index 0b22c6d..7ef5ece 100644 --- a/packages/core/src/components/AIMarkdownDocuments.tsx +++ b/packages/core/src/components/AIMarkdownDocuments.tsx @@ -109,6 +109,16 @@ const AIMarkdownDocumentsRoot: FC< export const AIMarkdownDocuments: FC = ({ preserveOrphanReferences = true, children }) => { const parent = useContext(AIMarkdownDocumentsContext); + // Once-per-instance guard for the prod nested-wrapper warning below. A + // nested wrapper inside a streaming chat re-renders on every token; + // without the guard the `console.error` would flood the console (and any + // wired-up error reporter) per token. Per-instance (ref) rather than + // module-level so a second, separately mounted misuse still gets reported. + // Warning must fire during render (not an effect) so SSR-only apps — + // where effects never run — still surface the misuse; the `== null` + // init-once shape is the ref-during-render pattern react-hooks/refs + // sanctions. + const warnedNestedRef = useRef(null); if (parent !== null) { // Dev: fail fast. The error makes the misuse obvious in any non- // production environment and prevents subtle bugs (the inner wrapper's @@ -125,10 +135,10 @@ export const AIMarkdownDocuments: FC = ({ preserveOrph // and render `children` as-is so the existing outer Provider continues // to apply. // - // Hooks-rules note: the outer component only calls `useContext` before - // the early return; the hooks that allocate state (`useRef`, `useMemo`) - // live in `AIMarkdownDocumentsRoot`, which is only mounted on the - // non-nested branch. Whichever branch this instance takes, it takes + // Hooks-rules note: the outer component only calls `useContext` and the + // warn-guard `useRef` before the early return; the hooks that allocate + // registry state (`useRef`, `useMemo`) live in `AIMarkdownDocumentsRoot`, + // which is only mounted on the non-nested branch. Whichever branch this instance takes, it takes // for its entire lifetime — React's per-instance hook order stays // stable and ESLint's `react-hooks/rules-of-hooks` is happy. // @@ -136,9 +146,12 @@ export const AIMarkdownDocuments: FC = ({ preserveOrph if (process.env.NODE_ENV !== 'production') { throw new Error(NESTED_WRAPPER_MESSAGE); } - console.error( - `[ai-react-markdown] ${NESTED_WRAPPER_MESSAGE} Falling back to the outer wrapper; the inner wrapper is a no-op.` - ); + if (warnedNestedRef.current == null) { + warnedNestedRef.current = true; + console.error( + `[ai-react-markdown] ${NESTED_WRAPPER_MESSAGE} Falling back to the outer wrapper; the inner wrapper is a no-op.` + ); + } return <>{children}; } return ( @@ -167,8 +180,22 @@ export const AIMarkdownDocuments: FC = ({ preserveOrph */ export function useDocumentRegistry(documentId: string | undefined, documentIdExplicit = true): Registry | null { const ctx = useContext(AIMarkdownDocumentsContext); - if (!ctx || !documentId || !documentIdExplicit) return null; - return ctx.getRegistry(documentId); + if (!useWouldCoordinate(documentId, documentIdExplicit)) return null; + return ctx!.getRegistry(documentId!); +} + +/** The coordination gate itself, WITHOUT registry allocation: true iff this + * position would coordinate — inside an `` wrapper AND + * carrying an explicitly-supplied documentId. Single source of truth for + * the gate: `useDocumentRegistry` delegates here, and diagnostics (the + * legacy-path warning in `MarkdownContent`) read the same predicate instead + * of hand-copying the conditions. Safe for pure diagnostics — an allocated + * registry with no registering chunk would never fire `onEmpty` and leak + * its shell, which is why diagnostics must NOT call `useDocumentRegistry`. + * Internal: not re-exported from the package barrel. */ +export function useWouldCoordinate(documentId: string | undefined, documentIdExplicit = true): boolean { + const ctx = useContext(AIMarkdownDocumentsContext); + return !!ctx && !!documentId && documentIdExplicit; } /** Returns the effective preserveOrphanReferences for this position in the tree: diff --git a/packages/core/src/components/MarkdownContent.tsx b/packages/core/src/components/MarkdownContent.tsx index f556a56..e7c6456 100644 --- a/packages/core/src/components/MarkdownContent.tsx +++ b/packages/core/src/components/MarkdownContent.tsx @@ -72,7 +72,7 @@ import { AIMarkdownRenderExtraSyntax, } from '../defs'; import { collectDefLabels } from './collectDefLabels'; -import { useDocumentRegistry, usePreserveOrphanReferences } from './AIMarkdownDocuments'; +import { useDocumentRegistry, usePreserveOrphanReferences, useWouldCoordinate } from './AIMarkdownDocuments'; import type { RegistryInternal } from './documentRegistry'; import type { SanitizeSchema } from './extendSanitizeSchema'; import { augmentSourceWithPhantoms } from './remarkInjectPhantomDefs'; @@ -108,6 +108,16 @@ const ExtraSyntaxRemarkPluginMap = { /** Stable empty object to avoid unnecessary re-renders when no custom components are given. */ const DefaultCustomComponents: AIMarkdownCustomComponents = {}; +/** Zero-allocation Set equality (same size, same members). Shared by the + * ref-stabilized memo pattern used for `ownLabels` and `targetPhantoms`. */ +function setsEqual(a: ReadonlySet, b: ReadonlySet): boolean { + if (a.size !== b.size) return false; + for (const v of a) { + if (!b.has(v)) return false; + } + return true; +} + interface AIMarkdownContentProps { /** Preprocessed markdown string to render. */ content: string; @@ -223,11 +233,36 @@ const BlockMemoizedRenderer = memo( useSyncExternalStore(subscribeRegistry, getRegistryVersion, REGISTRY_SSR_SNAPSHOT); // PASS 0: lightweight def-label scan, then publish to registry.labelSet. - const ownLabels = useMemo(() => collectDefLabels(content ?? ''), [content]); + // + // Stable reference (same pattern as targetPhantoms below): during + // streaming, `content` changes on every token, so an unstabilized useMemo + // would mint fresh Set identities per token → the register effect below + // re-fires per token → releaseSymbol + registerChunk + full labelSet + // rebuild + `_notify`, waking EVERY chunk in the document once per token. + // Compare the fresh scan against the previous result and keep the old + // reference while the label contents are unchanged (the common case — + // definitions appear rarely relative to token count). + const ownLabelsRef = useRef>({ + footnoteLabels: new Set(), + linkLabels: new Set(), + }); + const ownLabels = useMemo(() => { + const next = collectDefLabels(content ?? ''); + const prev = ownLabelsRef.current; + if (setsEqual(next.footnoteLabels, prev.footnoteLabels) && setsEqual(next.linkLabels, prev.linkLabels)) { + return prev; + } + ownLabelsRef.current = next; + return next; + }, [content]); useEffect(() => { if (!registry) return; const s = registry.registerChunk(reactId, ownLabels.footnoteLabels, ownLabels.linkLabels); + // No bail needed: the cleanup below always resets to null before a + // re-run, so an updater's `prev` could never match anyway. The churn + // protection lives upstream — `ownLabels` is ref-stabilized, so this + // effect only re-fires when the label CONTENTS actually changed. setAllocation({ registry, sym: s }); return () => { registry.releaseSymbol(reactId); @@ -348,12 +383,7 @@ const BlockMemoizedRenderer = memo( } } const prev = targetPhantomsRef.current; - if ( - nextFootnotes.size === prev.missingFootnotes.size && - nextLinks.size === prev.missingLinks.size && - [...nextFootnotes].every((l) => prev.missingFootnotes.has(l)) && - [...nextLinks].every((l) => prev.missingLinks.has(l)) - ) { + if (setsEqual(nextFootnotes, prev.missingFootnotes) && setsEqual(nextLinks, prev.missingLinks)) { return prev; } const next = { missingFootnotes: nextFootnotes, missingLinks: nextLinks }; @@ -413,7 +443,6 @@ const BlockMemoizedRenderer = memo( phantomFootnoteLabels: targetPhantoms.missingFootnotes, phantomLinkLabels: targetPhantoms.missingLinks, preserveOrphan: preserveForBodyHarvest, - documentId, } : { ...remarkRehypeOptions, @@ -424,16 +453,7 @@ const BlockMemoizedRenderer = memo( rehypePlugins, remarkRehypeOptions: mergedRemarkRehypeOptions as RemarkRehypeOptions, }); - }, [ - content, - targetPhantoms, - remarkPlugins, - rehypePlugins, - remarkRehypeOptions, - handlers, - preserveForBodyHarvest, - documentId, - ]); + }, [content, targetPhantoms, remarkPlugins, rehypePlugins, remarkRehypeOptions, handlers, preserveForBodyHarvest]); const hast = useMemo(() => transformStage(parsed), [parsed]); // Cut hast into per-block units indexed back to mdast for cache identity, @@ -690,7 +710,10 @@ LegacyRenderer.displayName = 'LegacyRenderer'; */ const AIMarkdownContent = memo( ({ content, customComponents, urlTransform, sanitizeSchema: customSanitizeSchema }: AIMarkdownContentProps) => { - const { config, clobberPrefix } = useAIMarkdownRenderState(); + const { config, clobberPrefix, documentId, documentIdExplicit } = useAIMarkdownRenderState(); + // Same predicate (and same arguments) as BlockMemoizedRenderer's + // `useDocumentRegistry` gate — shared implementation, cannot drift. + const wouldCoordinate = useWouldCoordinate(documentId, documentIdExplicit ?? false); // Dev-mode flip warnings live in the parent `` (`./../index.tsx`) // — they MUST run BEFORE `useStableValue` collapses identity churn, otherwise // an inline-but-deep-equal `sanitizeSchema` would be silently stabilized and @@ -792,6 +815,27 @@ const AIMarkdownContent = memo( [enableDefinitionList] ); + // The legacy path silently skips cross-chunk coordination (see + // LegacyRenderer docs). Surface the misconfiguration in dev instead of + // relying on users reading the JSDoc. Runs in an effect (render must stay + // pure) with a per-instance once-guard so a streaming chat re-rendering + // per token logs a single line. Gated on `useWouldCoordinate` — NOT on + // `documentId` alone, which the provider always fills with a `useId()` + // fallback and is therefore never undefined even for standalone usage. + const warnedLegacyRef = useRef(false); + const legacyUnderDocuments = !config.blockMemoEnabled && wouldCoordinate; + useEffect(() => { + if (process.env.NODE_ENV === 'production') return; + if (!legacyUnderDocuments || warnedLegacyRef.current) return; + warnedLegacyRef.current = true; + console.warn( + '[ai-react-markdown] blockMemoEnabled is false while rendering inside . ' + + 'The legacy render path does not participate in cross-chunk coordination — footnote/link ' + + 'references across chunks will not resolve. Keep blockMemoEnabled: true (the default) for ' + + 'coordinated documents.' + ); + }, [legacyUnderDocuments]); + const Renderer = config.blockMemoEnabled ? BlockMemoizedRenderer : LegacyRenderer; return ( ` builder below pushes backref anchors into + * the cloned def bodies, which must never mutate the registry-held + * `bodyHast`. Delegates to the shared structural clone (render-time cloning + * is handled separately by `renderHastSubtree`'s default). */ function cloneHast(node: T): T { - return JSON.parse(JSON.stringify(node)) as T; + return cloneHastForRender(node); } /** Whitespace-only text node — produced by mdast-util-to-hast's @@ -281,14 +286,11 @@ const AggregateFootnotesIfLastImpl: FC = ({ if (order.length === 0) return null; if (order[order.length - 1] !== thisChunkSym) return null; if (!tree) return null; - // `renderHastSubtree` mutates its input tree in place (see comment on - // that function: it assumes the tree is freshly produced per render). // Our `tree` is memoised by registry.version, so a non-version-bumping - // parent re-render would re-enter the same cached tree. Any non- - // idempotent transform (a user-supplied non-idempotent `urlTransform` - // is the realistic case) would then compound on every re-render. Clone - // before rendering so the cached `tree` stays pristine. - return <>{renderHastSubtree(cloneHast(tree), postOptions)}; + // parent re-render re-enters the same cached tree. `renderHastSubtree`'s + // default (`preserveInput: true`) runs the mutating visit on a private + // clone, keeping the cached `tree` pristine — no manual clone needed here. + return <>{renderHastSubtree(tree, postOptions)}; }; export const AggregateFootnotesIfLast = memo(AggregateFootnotesIfLastImpl); diff --git a/packages/core/src/components/blockMemo.test.ts b/packages/core/src/components/blockMemo.test.ts index 6ddfcdb..86c7239 100644 --- a/packages/core/src/components/blockMemo.test.ts +++ b/packages/core/src/components/blockMemo.test.ts @@ -22,7 +22,8 @@ import type { Element as HastElement, Root as HastRoot } from 'hast'; import type { Root as MdastRoot } from 'mdast'; import { sanitizeSchema } from './sanitizeSchema'; import rehypeRebaseHashLinks from './rehypeRebaseHashLinks'; -import type { ReactNode } from 'react'; +import { createElement, Fragment, type ReactNode } from 'react'; +import { renderToStaticMarkup } from 'react-dom/server'; import { buildBlocks, computeBlockFingerprint, @@ -515,6 +516,42 @@ describe('buildBlocks — synthesized hast nodes', () => { // The orphan div is in the plan as inline (preserves it in render output). expect(built.plan.some((p) => p.kind === 'inline' && p.el === hast.children[hast.children.length - 1])).toBe(true); }); + + test('mdast counterpart with partial position degrades to inline instead of dropping the element', () => { + // A remark plugin that rewrites `position` but drops `end.offset` — + // the exact-offset map still hits (start.offset is present), but a + // BlockInfo cannot be built. The hast element must survive as an inline + // plan item, never be silently dropped (drive buildBlocks directly: + // remark-parse itself always emits complete positions). + const source = 'Hi'; + const mdast: MdastRoot = { + type: 'root', + children: [ + { + type: 'paragraph', + children: [{ type: 'text', value: 'Hi' }], + position: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 3 } }, + }, + ], + }; + const hast: HastRoot = { + type: 'root', + children: [ + { + type: 'element', + tagName: 'p', + properties: {}, + children: [{ type: 'text', value: 'Hi' }], + position: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 3, offset: 2 } }, + }, + ], + }; + const built = buildBlocks(mdast, hast, source); + expect(built.blocks).toHaveLength(0); + const item = built.plan.find((p) => p.kind === 'inline' && p.el === hast.children[0]); + expect(item).toBeDefined(); + expect(item?.reactKey).toBe('inline-0'); + }); }); // ─── G3 flush contract (cacheRef external reset) ────────────────────────── @@ -875,7 +912,7 @@ describe('computeBlockFingerprint (v6)', () => { sym, 'doc-user-content-' ); - expect(fp).toBe('doc-user-content-'); + expect(fp).toBe(JSON.stringify(['doc-user-content-'])); }); test('footnote ref label encoded with globalNumber', () => { @@ -894,7 +931,7 @@ describe('computeBlockFingerprint (v6)', () => { sym, 'doc-user-content-' ); - expect(fp).toBe('doc-user-content-|fn:X=1'); + expect(fp).toBe(JSON.stringify(['doc-user-content-', ['fn', 'X', 1]])); }); test('canonical change in registry → different fingerprint', () => { @@ -911,10 +948,10 @@ describe('computeBlockFingerprint (v6)', () => { const taint = { footnoteRefLabels: [], linkRefLabels: [], imageRefLabels: [], footnoteDefLabels: ['X'] }; const fpAFirst = computeBlockFingerprint(taint, reg, a, 'doc-'); // A is canonical, fingerprint encodes 1 - expect(fpAFirst).toContain('fd:X=1'); + expect(fpAFirst).toContain('["fd","X",1'); const fpBFirst = computeBlockFingerprint(taint, reg, b, 'doc-'); // B is non-canonical, fingerprint encodes 0 - expect(fpBFirst).toContain('fd:X=0'); + expect(fpBFirst).toContain('["fd","X",0'); expect(fpAFirst).not.toBe(fpBFirst); }); @@ -937,7 +974,7 @@ describe('computeBlockFingerprint (v6)', () => { a, 'doc-' ); - expect(fp).toContain('/2'); + expect(fp).toContain('["fd","X",0,2]'); }); test('image title change invalidates fingerprint (v6.1 blocker 2 fix)', () => { @@ -978,7 +1015,7 @@ describe('computeBlockFingerprint (v6)', () => { // Initial fingerprint for A's def block: refCount 0 const taint = { footnoteRefLabels: [], linkRefLabels: [], imageRefLabels: [], footnoteDefLabels: ['X'] }; const fpBefore = computeBlockFingerprint(taint, reg, a, 'doc-'); - expect(fpBefore).toContain('fd:X=1/0'); + expect(fpBefore).toContain('["fd","X",1,0]'); // B contributes a ref to X (cross-chunk). registry.getRefsForLabel('X') should rise to 1. reg.contributeChunkData(b, { refs: [{ label: 'X', kind: 'footnote' }], @@ -988,9 +1025,39 @@ describe('computeBlockFingerprint (v6)', () => { ownLinkLabels: new Set(), }); const fpAfter = computeBlockFingerprint(taint, reg, a, 'doc-'); - expect(fpAfter).toContain('fd:X=1/1'); + expect(fpAfter).toContain('["fd","X",1,1]'); expect(fpBefore).not.toBe(fpAfter); // A's def block must invalidate }); + + test('collision regression: delimiter bytes in url/title cannot alias two registry states', () => { + // Under the old join('|') encoding both states below encoded the link + // part as the SAME byte sequence `lr:X=u|t|` — url `u|t` with empty + // title vs url `u` with title `t|` — producing identical fingerprints + // for distinct registry states: a false cache hit serving a stale + // block. JSON encoding keeps the value boundaries explicit. + const taint = { footnoteRefLabels: [], linkRefLabels: ['X'], imageRefLabels: [], footnoteDefLabels: [] }; + const reg1 = createRegistry(); + const a1 = reg1.allocateSymbol('A'); + reg1.contributeChunkData(a1, { + refs: [], + defs: new Map(), + linkDefs: new Map([['X', { identifier: 'X', url: 'u|t', title: '' }]]), + ownFootnoteLabels: new Set(), + ownLinkLabels: new Set(['X']), + }); + const reg2 = createRegistry(); + const a2 = reg2.allocateSymbol('A'); + reg2.contributeChunkData(a2, { + refs: [], + defs: new Map(), + linkDefs: new Map([['X', { identifier: 'X', url: 'u', title: 't|' }]]), + ownFootnoteLabels: new Set(), + ownLinkLabels: new Set(['X']), + }); + const fp1 = computeBlockFingerprint(taint, reg1, a1, 'doc-'); + const fp2 = computeBlockFingerprint(taint, reg2, a2, 'doc-'); + expect(fp1).not.toBe(fp2); + }); }); describe('renderBlocksWithCache fingerprint cache (v6)', () => { @@ -1081,3 +1148,68 @@ describe('renderBlocksWithCache fingerprint cache (v6)', () => { expect(e1?.node).toBe(e2?.node); // globalCtx unchanged → cache hit }); }); + +// ─── renderHastSubtree input preservation (urlTransform re-entry) ────────── + +describe('renderBlocksWithCache — hast input preservation', () => { + // Renders without a re-parse (registry version bump, G3 cache flush, + // urlTransform prop swap) re-enter the SAME memoized hast elements. The + // visit transform must therefore never mutate the plan's hast in place: + // a non-idempotent urlTransform would otherwise be applied on top of its + // own previous output. + test('cache-miss re-render on the same hast applies urlTransform exactly once', () => { + const content = '[link](https://example.com/a)'; + const { mdast, hast } = runPipeline(content); + const built = buildBlocks(mdast, hast, content); + const opts: PostOptions = { urlTransform: (u: string) => `https://proxy.test/?u=${encodeURIComponent(u)}` }; + + const cacheRef = { current: createCache() }; + renderBlocksWithCache(cacheRef, built.plan, built.globalCtx, opts); + // Simulate a G3 flush: fresh cache, same plan/hast, same options. + cacheRef.current = createCache(); + const r2 = renderBlocksWithCache(cacheRef, built.plan, built.globalCtx, opts); + + const html = renderToStaticMarkup( + createElement( + Fragment, + null, + r2.map((r) => r.node) + ) + ); + expect(html).toContain('https://proxy.test/?u=https%3A%2F%2Fexample.com%2Fa'); + expect(html).not.toContain('u%3Dhttps'); // double-wrapped proxy URL + + // The plan's hast must stay pristine: the original href survives untouched. + const blockItem = built.plan.find((p) => p.kind === 'block'); + const para = blockItem && 'el' in blockItem ? (blockItem.el as HastElement) : undefined; + const anchor = para?.children.find((c): c is HastElement => c.type === 'element' && c.tagName === 'a'); + expect(anchor?.properties.href).toBe('https://example.com/a'); + }); + + test('swapping urlTransform between renders applies only the new transform', () => { + const content = '[link](https://example.com/a)'; + const { mdast, hast } = runPipeline(content); + const built = buildBlocks(mdast, hast, content); + + const cacheRef = { current: createCache() }; + renderBlocksWithCache(cacheRef, built.plan, built.globalCtx, { + urlTransform: (u: string) => `${u}?v=old`, + }); + // urlTransform is a G3 dep: swapping it flushes the cache, then the same + // hast re-renders. Only the NEW transform may appear in the output. + cacheRef.current = createCache(); + const r2 = renderBlocksWithCache(cacheRef, built.plan, built.globalCtx, { + urlTransform: (u: string) => `${u}?v=new`, + }); + + const html = renderToStaticMarkup( + createElement( + Fragment, + null, + r2.map((r) => r.node) + ) + ); + expect(html).toContain('https://example.com/a?v=new'); + expect(html).not.toContain('v=old'); + }); +}); diff --git a/packages/core/src/components/blockMemo.ts b/packages/core/src/components/blockMemo.ts index 9a790bc..2a8a190 100644 --- a/packages/core/src/components/blockMemo.ts +++ b/packages/core/src/components/blockMemo.ts @@ -82,8 +82,8 @@ export interface BlockInfo { startColumn: number; /** True if the block contains any TAINT_TYPES node — invalidate on globalCtx change. */ hasReference: boolean; - /** TAINT-block 专属:按节点类型分桶的 label set。Normalized 形态(uppercase)。 - * Undefined when hasReference === false. */ + /** TAINT-block only: label sets bucketed by node type, in normalized + * (uppercase) form. Undefined when hasReference === false. */ taintLabels?: { footnoteRefLabels: string[]; linkRefLabels: string[]; @@ -390,6 +390,11 @@ export function buildBlocks(mdast: MdastRoot, hast: HastRoot, source: string): B const mdastPos = mdastNode.position; if (!mdastPos || mdastPos.start.offset === undefined || mdastPos.end.offset === undefined) { + // Counterpart found but its position lacks the offsets BlockInfo needs + // (a remark plugin partially rewrote `position`). Degrade to `inline` + // like the other no-counterpart fallbacks — user content is never + // silently lost. + plan.push({ kind: 'inline', el, reactKey: `inline-${hastOffset}` }); continue; } @@ -425,8 +430,12 @@ export function buildBlocks(mdast: MdastRoot, hast: HastRoot, source: string): B * with the same fingerprint render byte-equal output; if any encoded value * differs, the block must re-render. * - * Encoding format (deterministic, stable across versions): - * `|fn:=|lr:=||ir:<L>=<url>|fd:<L>=<canonical>/<refCount>` + * Encoding: the collected parts are JSON-stringified (same approach as + * `globalCtx`), so content-controlled values (labels/urls/titles) cannot + * forge part boundaries the way a plain `join('|')` allowed — two distinct + * registry states always produce distinct fingerprints: + * `[<clobberPrefix>, ["fn",<L>,<globalNumber>], ["lr",<L>,<url>,<title>], + * ["ir",<L>,<url>,<title>], ["fd",<L>,<isCanonical>,<refCount>]]` * * @param taintLabels - Per-block label dependency footprint (from BlockInfo.taintLabels). * @param registry - Shared cross-chunk registry. @@ -439,23 +448,23 @@ export function computeBlockFingerprint( thisChunkSym: symbol, clobberPrefix: string ): string { - const parts: string[] = [clobberPrefix]; + const parts: unknown[] = [clobberPrefix]; for (const label of taintLabels.footnoteRefLabels) { - parts.push(`fn:${label}=${registry.globalNumber(label) ?? 'null'}`); + parts.push(['fn', label, registry.globalNumber(label) ?? null]); } for (const label of taintLabels.linkRefLabels) { const def = registry.resolveLinkDef(label); - parts.push(`lr:${label}=${def?.url ?? 'null'}|${def?.title ?? ''}`); + parts.push(['lr', label, def?.url ?? null, def?.title ?? null]); } for (const label of taintLabels.imageRefLabels) { const def = registry.resolveLinkDef(label); - parts.push(`ir:${label}=${def?.url ?? 'null'}|${def?.title ?? ''}`); + parts.push(['ir', label, def?.url ?? null, def?.title ?? null]); } for (const label of taintLabels.footnoteDefLabels) { const isCanonical = registry.canonicalFootnoteFor(label) === thisChunkSym ? 1 : 0; - parts.push(`fd:${label}=${isCanonical}/${registry.getRefsForLabel(label)}`); + parts.push(['fd', label, isCanonical, registry.getRefsForLabel(label)]); } - return parts.join('|'); + return JSON.stringify(parts); } /** @@ -499,7 +508,12 @@ export function renderBlocksWithCache( for (const item of plan) { if (item.kind === 'inline') { rendered.push({ - node: renderHastSubtree(item.el, postOptions), + // Inline items render fresh EVERY frame on the same memoized hast. + // Element inlines (raw-HTML fallbacks) take the default clone — the + // visit transform mutates elements in place. Non-element inlines + // (the common case: whitespace text between blocks) cannot be + // mutated by the transform, so skip the per-frame clone for them. + node: renderHastSubtree(item.el, postOptions, item.el.type === 'element'), reactKey: item.reactKey, }); continue; diff --git a/packages/core/src/components/cloneHastForRender.ts b/packages/core/src/components/cloneHastForRender.ts new file mode 100644 index 0000000..78da7b2 --- /dev/null +++ b/packages/core/src/components/cloneHastForRender.ts @@ -0,0 +1,30 @@ +/** + * Structural clone of a hast subtree for render-time use. + * + * Copies exactly what the render-time mutators touch — every node object, + * its `children` array (the allow/disallow filters splice it), and its + * `properties` object (`urlTransform` overwrites `href`/`src`) — while + * SHARING `position`, `data`, string values, and individual property values + * by reference. This is both cheaper than a JSON round-trip (no string + * intermediate; `position` objects, typically over half of a serialized + * hast, are never materialized) and exact for any tree the pipeline + * produces (no lossy JSON semantics to reason about). + * + * @module components/cloneHastForRender + */ + +import type { Nodes as HastNodes } from 'hast'; + +/** See module docs. Safe for any hast node union member. */ +export function cloneHastForRender<T extends HastNodes>(node: T): T { + const copy = { ...node } as T; + const withChildren = copy as { children?: HastNodes[] }; + if (Array.isArray(withChildren.children)) { + withChildren.children = withChildren.children.map((child) => cloneHastForRender(child)); + } + const withProperties = copy as { properties?: Record<string, unknown> }; + if (withProperties.properties) { + withProperties.properties = { ...withProperties.properties }; + } + return copy; +} diff --git a/packages/core/src/components/crossChunkPlaceholders.tsx b/packages/core/src/components/crossChunkPlaceholders.tsx index b355b74..66b6012 100644 --- a/packages/core/src/components/crossChunkPlaceholders.tsx +++ b/packages/core/src/components/crossChunkPlaceholders.tsx @@ -41,8 +41,6 @@ interface FootnoteSupProps { * `customMdastHandlers.test.ts`). The component accepts either form * and coerces internally so the contract is robust to the pipeline. */ localOccurrence?: number | string; - /** Optional — but normally the hast tag carries it. */ - documentId?: string; } /** Coerce the on-the-wire `localOccurrence` (which may be a JS number from diff --git a/packages/core/src/components/customMdastHandlers.test.ts b/packages/core/src/components/customMdastHandlers.test.ts index c3f52bd..9387827 100644 --- a/packages/core/src/components/customMdastHandlers.test.ts +++ b/packages/core/src/components/customMdastHandlers.test.ts @@ -18,7 +18,6 @@ function pipe( phantomFootnoteLabels?: Set<string>; phantomLinkLabels?: Set<string>; preserveOrphan?: boolean; - documentId?: string; } ): HastRoot { const handlers = buildCrossChunkHandlers(); @@ -26,7 +25,6 @@ function pipe( phantomFootnoteLabels: opts.phantomFootnoteLabels ?? new Set(), phantomLinkLabels: opts.phantomLinkLabels ?? new Set(), preserveOrphan: opts.preserveOrphan ?? true, - documentId: opts.documentId ?? 'doc', }; const processor = unified() .use(remarkParse) @@ -74,12 +72,14 @@ describe('customMdastHandlers — Direction B linkReference', () => { missingFootnotes: new Set(), missingLinks: new Set(['X']), }); - const hast = pipe(augmented, { phantomLinkLabels: new Set(['X']), documentId: 'msg-1' }); + const hast = pipe(augmented, { phantomLinkLabels: new Set(['X']) }); const link = findTag(hast, 'cross-chunk-link'); expect(link).toBeTruthy(); expect(link?.properties?.label).toBe('X'); expect(link?.properties?.referenceType).toBe('full'); - expect(link?.properties?.documentId).toBe('msg-1'); + // Placeholders read documentId from context, not from a per-element + // attribute — the handler must not emit one. + expect(link?.properties?.documentId).toBeUndefined(); }); test('linkReference with no source def emits no placeholder (mdast drops the node)', () => { @@ -135,7 +135,6 @@ describe('customMdastHandlers — footnoteReference with phantom def', () => { phantomFootnoteLabels: new Set<string>(), phantomLinkLabels: new Set<string>(), preserveOrphan: true, - documentId: 'doc', }; const processor = unified() .use(remarkParse) @@ -170,7 +169,6 @@ describe('customMdastHandlers — footnoteReference with phantom def', () => { phantomFootnoteLabels: new Set<string>(), phantomLinkLabels: new Set<string>(['MISSING']), preserveOrphan: true, - documentId: 'doc', }; const processor = unified() .use(remarkParse) diff --git a/packages/core/src/components/customMdastHandlers.ts b/packages/core/src/components/customMdastHandlers.ts index d6158d8..14d1087 100644 --- a/packages/core/src/components/customMdastHandlers.ts +++ b/packages/core/src/components/customMdastHandlers.ts @@ -33,9 +33,6 @@ export interface CrossChunkHandlerOptions { /** When true, footnoteDefinitionHandler proactively registers orphan defs * to state.footnoteOrder (Direction A). */ preserveOrphan: boolean; - /** Passed through to placeholder hast properties so React components can - * partition by document. */ - documentId: string; } // Type assertion helper for state shape (mdast-util-to-hast doesn't export it). @@ -92,7 +89,6 @@ export function buildCrossChunkHandlers(): Handlers { // internally, so cross-chunk case-insensitive matching still works. label: node.label ?? node.identifier, referenceType: node.referenceType, - documentId: s.options.documentId, }, children: s.all(node) as HastElement['children'], }; @@ -110,7 +106,6 @@ export function buildCrossChunkHandlers(): Handlers { label: node.label ?? node.identifier, referenceType: node.referenceType, alt: node.alt ?? '', - documentId: s.options.documentId, }, children: [], }; @@ -134,7 +129,6 @@ export function buildCrossChunkHandlers(): Handlers { properties: { label: node.identifier, localOccurrence, - documentId: s.options.documentId, }, children: [], }; @@ -148,7 +142,6 @@ export function buildCrossChunkHandlers(): Handlers { properties: { label: node.identifier, localOccurrence, - documentId: s.options.documentId, }, children: [], }; diff --git a/packages/core/src/components/documentRegistry.ts b/packages/core/src/components/documentRegistry.ts index 3c2cca9..45a95b3 100644 --- a/packages/core/src/components/documentRegistry.ts +++ b/packages/core/src/components/documentRegistry.ts @@ -176,6 +176,66 @@ export interface RegistryInternal extends Registry { * caller's eviction logic. */ export function createRegistry(onEmpty?: () => void): RegistryInternal { + // Version-keyed selector tables. Fingerprint computation calls the + // selectors once per taint-label per tainted block per render; walking + // chunkOrder × refs on every call is O(blocks × refs) per frame. Every + // mutation bumps `version` synchronously (all mutators funnel through + // `_notify`), so a single O(chunks × refs + defs) pass per version serves + // all subsequent selector calls as map lookups. Closure-held so the cache + // never leaks onto the (public or internal) registry surface. + let selectorCacheVersion = -1; + let selectorCache: { + canonicalFootnote: Map<string, symbol>; + canonicalLink: Map<string, symbol>; + /** label → first-occurrence ordinal (footnote numbering). */ + footnoteNumbers: Map<string, number>; + /** label → total footnote-ref count across all chunks. */ + refCounts: Map<string, number>; + /** chunkSym → label → localOccurrence-1-indexed list of global indices. */ + occurrences: Map<symbol, Map<string, number[]>>; + } | null = null; + const selectorTables = () => { + if (selectorCache && selectorCacheVersion === reg.version) return selectorCache; + const canonicalFootnote = new Map<string, symbol>(); + const canonicalLink = new Map<string, symbol>(); + const footnoteNumbers = new Map<string, number>(); + const refCounts = new Map<string, number>(); + const occurrences = new Map<symbol, Map<string, number[]>>(); + let nextNumber = 0; + for (const sym of reg.chunkOrder) { + const data = reg.chunkData.get(sym); + if (!data) continue; + for (const id of data.defs.keys()) { + if (!canonicalFootnote.has(id)) canonicalFootnote.set(id, sym); + } + for (const id of data.linkDefs.keys()) { + if (!canonicalLink.has(id)) canonicalLink.set(id, sym); + } + for (const ref of data.refs) { + // Footnote numbering is a per-space ordinal; link/image refs share + // the `refs` array but occupy a disjoint namespace, so they must + // NOT advance the footnote counter. + if (ref.kind !== 'footnote') continue; + if (!footnoteNumbers.has(ref.label)) footnoteNumbers.set(ref.label, ++nextNumber); + const globalIndex = (refCounts.get(ref.label) ?? 0) + 1; + refCounts.set(ref.label, globalIndex); + let perChunk = occurrences.get(sym); + if (!perChunk) { + perChunk = new Map(); + occurrences.set(sym, perChunk); + } + let list = perChunk.get(ref.label); + if (!list) { + list = []; + perChunk.set(ref.label, list); + } + list.push(globalIndex); + } + } + selectorCache = { canonicalFootnote, canonicalLink, footnoteNumbers, refCounts, occurrences }; + selectorCacheVersion = reg.version; + return selectorCache; + }; const reg = { chunkOrder: [] as symbol[], chunkData: new Map<symbol, ChunkData>(), @@ -316,43 +376,15 @@ export function createRegistry(onEmpty?: () => void): RegistryInternal { }, canonicalFootnoteFor(label: string): symbol | null { - const id = normalizeId(label); - for (const sym of this.chunkOrder) { - const data = this.chunkData.get(sym); - if (data?.defs.has(id)) return sym; - } - return null; + return selectorTables().canonicalFootnote.get(normalizeId(label)) ?? null; }, canonicalLinkFor(label: string): symbol | null { - const id = normalizeId(label); - for (const sym of this.chunkOrder) { - const data = this.chunkData.get(sym); - if (data?.linkDefs.has(id)) return sym; - } - return null; + return selectorTables().canonicalLink.get(normalizeId(label)) ?? null; }, globalNumber(label: string): number | null { - const id = normalizeId(label); - let n = 0; - const seen = new Set<string>(); - for (const sym of this.chunkOrder) { - const data = this.chunkData.get(sym); - if (!data) continue; - for (const ref of data.refs) { - // Footnote numbering is a per-space ordinal; link/image refs share - // the `refs` array but occupy a disjoint namespace, so they must - // NOT advance the footnote counter. - if (ref.kind !== 'footnote') continue; - if (!seen.has(ref.label)) { - seen.add(ref.label); - n++; - if (ref.label === id) return n; - } - } - } - return null; + return selectorTables().footnoteNumbers.get(normalizeId(label)) ?? null; }, resolveLinkDef(label: string): LinkDef | null { @@ -362,37 +394,14 @@ export function createRegistry(onEmpty?: () => void): RegistryInternal { }, getRefsForLabel(label: string): number { - const id = normalizeId(label); - let n = 0; - for (const sym of this.chunkOrder) { - const data = this.chunkData.get(sym); - if (!data) continue; - // Only count footnote refs: the consumers (backref-strip and - // backref-inject) decide based on whether a footnote `<li>` should - // exist, which depends on footnote refs alone. - for (const ref of data.refs) { - if (ref.kind === 'footnote' && ref.label === id) n++; - } - } - return n; + // Only counts footnote refs: the consumers (backref-strip and + // backref-inject) decide based on whether a footnote `<li>` should + // exist, which depends on footnote refs alone. + return selectorTables().refCounts.get(normalizeId(label)) ?? 0; }, globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null { - const id = normalizeId(label); - let global = 0; - for (const sym of this.chunkOrder) { - const data = this.chunkData.get(sym); - if (!data) continue; - let localCount = 0; - for (const ref of data.refs) { - if (ref.kind !== 'footnote') continue; - if (ref.label !== id) continue; - localCount++; - global++; - if (sym === chunkSym && localCount === localOccurrence) return global; - } - } - return null; + return selectorTables().occurrences.get(chunkSym)?.get(normalizeId(label))?.[localOccurrence - 1] ?? null; }, _notify(): void { diff --git a/packages/core/src/components/extendSanitizeSchema.test.ts b/packages/core/src/components/extendSanitizeSchema.test.ts index 7fabc2e..5ed7e99 100644 --- a/packages/core/src/components/extendSanitizeSchema.test.ts +++ b/packages/core/src/components/extendSanitizeSchema.test.ts @@ -71,8 +71,7 @@ describe('extendSanitizeSchema — mutate-and-return form', () => { const schema = extendSanitizeSchema(() => {}); const codeAttrs = schema.attributes?.code ?? []; const classNameEntry = codeAttrs.find((entry) => Array.isArray(entry) && entry[0] === 'className') as - | readonly unknown[] - | undefined; + readonly unknown[] | undefined; expect(classNameEntry).toBeDefined(); // The RegExp from defaultSchema should still BE a RegExp (not a plain object). expect(classNameEntry!.some((v) => v instanceof RegExp)).toBe(true); diff --git a/packages/core/src/components/extractDefBodiesFromHast.test.ts b/packages/core/src/components/extractDefBodiesFromHast.test.ts index c25d44b..54a844b 100644 --- a/packages/core/src/components/extractDefBodiesFromHast.test.ts +++ b/packages/core/src/components/extractDefBodiesFromHast.test.ts @@ -460,7 +460,7 @@ describe('extractDefBodiesFromHast', () => { { type: 'element', tagName: 'footnote-sup', - properties: { label: 'y', localOccurrence: 1, documentId: 'd' }, + properties: { label: 'y', localOccurrence: 1 }, children: [], }, ], @@ -483,7 +483,6 @@ describe('extractDefBodiesFromHast', () => { expect(sup.properties).not.toHaveProperty('localOccurrence'); // Other props survive. expect(sup.properties?.label).toBe('y'); - expect(sup.properties?.documentId).toBe('d'); }); test('returns empty map when there is no <section data-footnotes>', () => { diff --git a/packages/core/src/components/legacyCoordinationWarning.client.test.tsx b/packages/core/src/components/legacyCoordinationWarning.client.test.tsx new file mode 100644 index 0000000..f6ea9ef --- /dev/null +++ b/packages/core/src/components/legacyCoordinationWarning.client.test.tsx @@ -0,0 +1,88 @@ +// @vitest-environment jsdom + +// Client-side (effects run) coverage for the dev-only warning emitted when +// `blockMemoEnabled: false` renders with real coordination intent — inside +// `<AIMarkdownDocuments>` with an explicit documentId. The gate must NOT fire +// for standalone legacy usage: `state.documentId` is always filled with a +// `useId()` fallback, so a naive `documentId !== undefined` check would warn +// for every legacy user (regression this file locks out). + +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import { act } from 'react'; +import { createRoot, type Root } from 'react-dom/client'; +import type { ReactNode } from 'react'; +import AIMarkdown from '../index'; +import { AIMarkdownDocuments } from './AIMarkdownDocuments'; + +(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +let container: HTMLDivElement; +let root: Root; +let warnSpy: ReturnType<typeof vi.spyOn>; + +beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + root = createRoot(container); + warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); +}); + +afterEach(async () => { + await act(async () => { + root.unmount(); + }); + container.remove(); + warnSpy.mockRestore(); +}); + +async function renderClient(ui: ReactNode) { + await act(async () => { + root.render(ui); + }); + await act(async () => {}); +} + +const coordinationWarnings = () => + warnSpy.mock.calls.filter( + (args: unknown[]) => typeof args[0] === 'string' && args[0].includes('cross-chunk coordination') + ); + +describe('legacy-path coordination warning (client)', () => { + test('fires once for blockMemoEnabled:false inside <AIMarkdownDocuments> with explicit documentId', async () => { + await renderClient( + <AIMarkdownDocuments> + <AIMarkdown content="hello" documentId="doc-1" config={{ blockMemoEnabled: false }} /> + </AIMarkdownDocuments> + ); + // Re-render the same tree (streaming-style) — still one warning. + await renderClient( + <AIMarkdownDocuments> + <AIMarkdown content="hello world" documentId="doc-1" config={{ blockMemoEnabled: false }} /> + </AIMarkdownDocuments> + ); + expect(coordinationWarnings()).toHaveLength(1); + }); + + test('does NOT fire for standalone blockMemoEnabled:false (no wrapper, no documentId)', async () => { + await renderClient(<AIMarkdown content="hello" config={{ blockMemoEnabled: false }} />); + expect(coordinationWarnings()).toHaveLength(0); + }); + + test('does NOT fire inside the wrapper without an explicit documentId', async () => { + await renderClient( + <AIMarkdownDocuments> + <AIMarkdown content="hello" config={{ blockMemoEnabled: false }} /> + </AIMarkdownDocuments> + ); + expect(coordinationWarnings()).toHaveLength(0); + }); + + test('does NOT fire when blockMemoEnabled stays default (coordinated path)', async () => { + await renderClient( + <AIMarkdownDocuments> + <AIMarkdown content="hello" documentId="doc-1" /> + </AIMarkdownDocuments> + ); + expect(coordinationWarnings()).toHaveLength(0); + }); +}); diff --git a/packages/core/src/components/markdown/Markdown.tsx b/packages/core/src/components/markdown/Markdown.tsx index beab608..5fa2f98 100644 --- a/packages/core/src/components/markdown/Markdown.tsx +++ b/packages/core/src/components/markdown/Markdown.tsx @@ -24,6 +24,7 @@ import { jsx, jsxs } from 'react/jsx-runtime'; import type { Processor } from 'unified'; import { visit } from 'unist-util-visit'; import type { VFile } from 'vfile'; +import { cloneHastForRender } from '../cloneHastForRender'; import { createFile, createProcessor } from './processor'; import { buildTransform } from './transform'; import type { Deprecation, Options } from './types'; @@ -135,13 +136,25 @@ export function transformStage(parsed: ParsedMarkdown): HastRoot { * splice-based filters (`unwrapDisallowed`) have a parent context to work * against. * - * Note: the visit transform mutates the input tree in place. For the legacy - * `<Markdown>` flow this is harmless (the tree is freshly produced). For the - * block-memo flow, hast is also fresh per render, so callers do not need to - * defensively clone. + * Note: the visit transform mutates the tree it walks in place (urlTransform + * results overwrite `properties.href/src`). The SAFE default is therefore to + * run the visit on a private structural clone (`preserveInput = true`): a + * caller rendering from a tree that outlives the call — the block-memo flow + * re-enters the same memoized hast whenever a render happens without a + * re-parse (registry version bump, G3 cache flush, urlTransform prop swap) — + * would otherwise apply a non-idempotent urlTransform on top of its own + * output. Only callers whose tree is single-use and consumed within the same + * call (the legacy `<Markdown>` flow, non-element inline plan items that the + * transform cannot mutate) should opt OUT with `preserveInput: false` to + * skip the clone cost. */ -export function renderHastSubtree(tree: HastRoot | RootContent, options: Readonly<Options>): ReactNode { - const root: HastRoot = tree.type === 'root' ? tree : { type: 'root', children: [tree] }; +export function renderHastSubtree( + tree: HastRoot | RootContent, + options: Readonly<Options>, + preserveInput = true +): ReactNode { + const input: HastRoot | RootContent = preserveInput ? cloneHastForRender(tree) : tree; + const root: HastRoot = input.type === 'root' ? input : { type: 'root', children: [input] }; visit( root, @@ -177,7 +190,10 @@ export function renderHastSubtree(tree: HastRoot | RootContent, options: Readonl export function Markdown(options: Readonly<Options>): ReactElement { const parsed = parseStage(options); const tree = transformStage(parsed); - return renderHastSubtree(tree, options) as ReactElement; + // preserveInput: false — the tree is freshly produced above and consumed + // by this one call; in-place mutation is harmless and this is the hot + // full-document path, so skip the clone. + return renderHastSubtree(tree, options, false) as ReactElement; } export default Markdown; diff --git a/packages/core/src/components/markdown/types.ts b/packages/core/src/components/markdown/types.ts index 698ab19..e4cc047 100644 --- a/packages/core/src/components/markdown/types.ts +++ b/packages/core/src/components/markdown/types.ts @@ -18,8 +18,7 @@ export interface ExtraProps { /** Map tag names to user components or other tag names. */ export type Components = { [Key in keyof JSX.IntrinsicElements]?: - | ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> - | keyof JSX.IntrinsicElements; + ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements; }; /** Filter callback for elements. Return falsy to drop. */ diff --git a/packages/core/src/components/remarkInjectPhantomDefs.test.ts b/packages/core/src/components/remarkInjectPhantomDefs.test.ts index f52d5e9..c289b13 100644 --- a/packages/core/src/components/remarkInjectPhantomDefs.test.ts +++ b/packages/core/src/components/remarkInjectPhantomDefs.test.ts @@ -62,6 +62,37 @@ describe('augmentSourceWithPhantoms integration with remark-parse', () => { expect(found).toBe(true); }); + test('escape-bearing label (the only real bracket form) round-trips identically', () => { + // micromark keeps source backslash escapes inside identifiers: a real + // definition `[foo\]bar]: /url` yields the identifier `foo\]bar`. Labels + // with a BARE `]` therefore cannot come out of a real parse — the only + // bracket-bearing labels the registry can ever hold carry the backslash. + // Injecting the identifier verbatim must reparse to the SAME identifier, + // so the phantom def actually matches the reference (escaping here would + // double the backslash and break the match). + const sourceLabel = String.raw`FOO\]BAR`; + const tree = parseAugmented(String.raw`[click][foo\]bar]`, new Set(), new Set([sourceLabel])); + const defIdentifiers: string[] = []; + visit(tree, 'definition', (n) => { + defIdentifiers.push(n.identifier); + }); + let refIdentifier: string | undefined; + visit(tree, 'linkReference', (n) => { + refIdentifier = n.identifier; + }); + // Phantom def parsed as a definition (not a leaked paragraph) … + expect(defIdentifiers).toHaveLength(1); + // … and its identifier matches the in-content reference case-insensitively + // (identifiers are case-folded; normalizeId uppercases the registry side). + expect(defIdentifiers[0].toUpperCase()).toBe(refIdentifier!.toUpperCase()); + // Nothing from the injected suffix may surface as visible text. + let leaked = false; + visit(tree, 'text', (n) => { + if (n.value.includes(SENTINEL_LINK_URL) || n.value.includes(SENTINEL_FN_CONTENT)) leaked = true; + }); + expect(leaked).toBe(false); + }); + test('without augmentation, orphan ref is dropped to literal text', () => { const tree = parseAugmented('See [^X].', new Set(), new Set()); let found = false; diff --git a/packages/core/src/components/remarkInjectPhantomDefs.ts b/packages/core/src/components/remarkInjectPhantomDefs.ts index bb361b5..7b8e8d0 100644 --- a/packages/core/src/components/remarkInjectPhantomDefs.ts +++ b/packages/core/src/components/remarkInjectPhantomDefs.ts @@ -18,6 +18,18 @@ export interface PhantomLabels { * * Labels are expected to already be normalized via normalizeId (uppercase). * The output is suitable as input to remark-parse with the standard pipeline. + * + * Labels are injected RAW — do not "escape" them. micromark's identifier + * normalization retains source backslash escapes (a definition `[foo\]bar]:` + * yields the identifier `foo\]bar`, backslash included), so writing the + * identifier back verbatim round-trips to the same identifier by + * construction, and the phantom matches the reference. Escaping would + * double the backslash and break the match. A label containing a BARE `]` + * would fail to parse as a definition, but such a label cannot come out of + * a real parse (brackets must be escaped in source, and the escape survives + * into the identifier) — and today backslash-bearing labels never reach + * injection anyway (PASS 0.5's substring gate treats them as its documented + * false-negative). */ export function augmentSourceWithPhantoms(source: string, phantoms: PhantomLabels): string { if (phantoms.missingFootnotes.size === 0 && phantoms.missingLinks.size === 0) { diff --git a/packages/core/src/components/sanitizeSchema.test.ts b/packages/core/src/components/sanitizeSchema.test.ts index eeb35a2..5a7eb90 100644 --- a/packages/core/src/components/sanitizeSchema.test.ts +++ b/packages/core/src/components/sanitizeSchema.test.ts @@ -138,7 +138,7 @@ describe('sanitizeSchema integration', () => { }); describe('sanitizeSchema cross-chunk extension', () => { - test('allows <cross-chunk-link> with label/referenceType/documentId', () => { + test('allows <cross-chunk-link> with label/referenceType; strips documentId', () => { const tree: Root = { type: 'root', children: [ @@ -154,6 +154,9 @@ describe('sanitizeSchema cross-chunk extension', () => { const node = firstChildElement(out); expect(node.tagName).toBe('cross-chunk-link'); expect(node.properties?.label).toBe('X'); + // documentId is no longer part of the placeholder wire format (the + // components read it from context) — the allowlist must not keep it. + expect(node.properties).not.toHaveProperty('documentId'); }); test('allows <cross-chunk-image> + <footnote-sup>', () => { @@ -161,7 +164,7 @@ describe('sanitizeSchema cross-chunk extension', () => { type: 'root', children: [ { type: 'element', tagName: 'cross-chunk-image', properties: { label: 'X', alt: 'a' }, children: [] }, - { type: 'element', tagName: 'footnote-sup', properties: { label: 'Y', documentId: 'd' }, children: [] }, + { type: 'element', tagName: 'footnote-sup', properties: { label: 'Y' }, children: [] }, ], }; const out = sanitize(tree, sanitizeSchema) as Root; @@ -187,7 +190,7 @@ describe('sanitizeSchema cross-chunk extension', () => { { type: 'element', tagName: 'footnote-sup', - properties: { label: 'Y', localOccurrence: 2, documentId: 'd' }, + properties: { label: 'Y', localOccurrence: 2 }, children: [], }, ], diff --git a/packages/core/src/components/sanitizeSchema.ts b/packages/core/src/components/sanitizeSchema.ts index 3d6f575..3f29495 100644 --- a/packages/core/src/components/sanitizeSchema.ts +++ b/packages/core/src/components/sanitizeSchema.ts @@ -74,8 +74,8 @@ export const sanitizeSchema: Schema = cloneDeep({ attributes: { ...defaultSchema.attributes, code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ['math-inline', 'math-display']), - 'cross-chunk-link': ['label', 'referenceType', 'documentId'], - 'cross-chunk-image': ['label', 'referenceType', 'documentId', 'alt'], - 'footnote-sup': ['label', 'localOccurrence', 'documentId'], + 'cross-chunk-link': ['label', 'referenceType'], + 'cross-chunk-image': ['label', 'referenceType', 'alt'], + 'footnote-sup': ['label', 'localOccurrence'], }, }); diff --git a/packages/core/src/hooks/useReferenceFlipWarning.test.ts b/packages/core/src/hooks/useReferenceFlipWarning.test.ts index 2a6568b..315a49d 100644 --- a/packages/core/src/hooks/useReferenceFlipWarning.test.ts +++ b/packages/core/src/hooks/useReferenceFlipWarning.test.ts @@ -13,7 +13,7 @@ describe('trackFlip — pure flip-and-rate-limit logic', () => { function fresh(initial: unknown): FlipState { // Mirror the production seed: -Infinity ensures the first warn-eligible // event is never blocked by the cooldown comparison. - return { prev: initial, flips: 0, lastWarnAt: -Infinity }; + return { prev: initial, flipTimes: [], consecutiveFlips: 0, lastFlipAt: -Infinity, lastWarnAt: -Infinity }; } test('does not warn when the value is unchanged', () => { @@ -23,14 +23,14 @@ describe('trackFlip — pure flip-and-rate-limit logic', () => { trackFlip(s, stable, 'urlTransform', 2000); trackFlip(s, stable, 'urlTransform', 3000); expect(warnSpy).not.toHaveBeenCalled(); - expect(s.flips).toBe(0); + expect(s.flipTimes).toHaveLength(0); }); test('does not warn for a single identity flip', () => { const s = fresh({ k: 0 }); trackFlip(s, { k: 1 }, 'urlTransform', 1000); expect(warnSpy).not.toHaveBeenCalled(); - expect(s.flips).toBe(1); + expect(s.flipTimes).toHaveLength(1); }); test('warns once after exactly 3 identity flips', () => { @@ -97,4 +97,75 @@ describe('trackFlip — pure flip-and-rate-limit logic', () => { trackFlip(s, { k: 3 }, 'urlTransform', 600); expect(warnSpy).toHaveBeenCalledTimes(1); }); + + test('decay: flips spread across a long session never warn', () => { + // Regression: the old cumulative counter warned as soon as the 3rd flip + // EVER happened — three legitimate identity changes minutes apart + // (feature flags, route transitions) tripped the "changing on every + // render" warning. Flips outside the recency window must not count. + const s = fresh({ k: 0 }); + trackFlip(s, { k: 1 }, 'urlTransform', 0); + trackFlip(s, { k: 2 }, 'urlTransform', 60_000); + trackFlip(s, { k: 3 }, 'urlTransform', 120_000); + trackFlip(s, { k: 4 }, 'urlTransform', 180_000); + expect(warnSpy).not.toHaveBeenCalled(); + }); + + test('decay: a rapid burst after a quiet period still warns', () => { + const s = fresh({ k: 0 }); + trackFlip(s, { k: 1 }, 'urlTransform', 0); // lone legitimate change + trackFlip(s, { k: 2 }, 'urlTransform', 60_000); // another, much later + trackFlip(s, { k: 3 }, 'urlTransform', 60_100); + // Oldest tracked flip (0ms) is outside the window — no warn yet. + expect(warnSpy).not.toHaveBeenCalled(); + trackFlip(s, { k: 4 }, 'urlTransform', 60_200); + // Now the last 3 flips (60_000 / 60_100 / 60_200) fit the window. + expect(warnSpy).toHaveBeenCalledTimes(1); + }); + + test('sustained: every-render churn slower than the window still warns', () => { + // Regression: a 6s polling dashboard passing an inline prop flips on + // 100% of renders (the exact pathology this hook diagnoses) but never + // fits 3 flips into the 10s recency window — the consecutive-run + // trigger must catch it regardless of wall-clock spacing. + const s = fresh({ k: 0 }); + for (let i = 1; i <= 5; i++) { + trackFlip(s, { k: i }, 'urlTransform', i * 6000); + } + expect(warnSpy).not.toHaveBeenCalled(); // 5 consecutive — below sustained threshold + trackFlip(s, { k: 6 }, 'urlTransform', 36_000); + expect(warnSpy).toHaveBeenCalledTimes(1); // 6th consecutive flipping render + }); + + test('sustained: StrictMode double-invoke does not reset the run', () => { + // StrictMode calls the render function twice per committed render with + // the SAME value — the second call of the (flip, same-value) pair lands + // in the same millisecond and must not count as a stable render, or the + // sustained trigger would be permanently disarmed exactly where it + // matters most (dev with StrictMode on). + const s = fresh({ k: 0 }); + for (let i = 1; i <= 6; i++) { + const v = { k: i }; + const t = i * 6000; + trackFlip(s, v, 'urlTransform', t); // first invoke: flip + trackFlip(s, v, 'urlTransform', t); // double-invoke mirror: same value, same ms + } + expect(warnSpy).toHaveBeenCalledTimes(1); + }); + + test('sustained: a stable render resets the consecutive-flip run', () => { + const s = fresh({ k: 0 }); + let last: unknown; + for (let i = 1; i <= 5; i++) { + last = { k: i }; + trackFlip(s, last, 'urlTransform', i * 6000); + } + // One render with a stable identity — the run ends. + trackFlip(s, last, 'urlTransform', 36_000); + // Five more slow flips: run restarts at 1, never reaches the threshold. + for (let i = 10; i <= 14; i++) { + trackFlip(s, { k: i }, 'urlTransform', i * 6000); + } + expect(warnSpy).not.toHaveBeenCalled(); + }); }); diff --git a/packages/core/src/hooks/useReferenceFlipWarning.ts b/packages/core/src/hooks/useReferenceFlipWarning.ts index 252809b..00aadaa 100644 --- a/packages/core/src/hooks/useReferenceFlipWarning.ts +++ b/packages/core/src/hooks/useReferenceFlipWarning.ts @@ -21,31 +21,75 @@ import { useRef } from 'react'; /** Module-scope dev flag. Bundlers fold this to a constant in production. */ const __DEV__ = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'; -/** How many identity flips before the first warning fires. */ +/** How many identity flips within {@link FLIP_WINDOW_MS} before a warning fires. */ const FLIP_THRESHOLD = 3; /** Minimum delay between successive warnings, milliseconds. */ const WARN_COOLDOWN_MS = 5000; +/** Recency window for counting flips towards {@link FLIP_THRESHOLD}, + * milliseconds. Occasional legitimate identity changes (feature flags, + * route transitions) spread across a long session must not accumulate + * into a false "changing on every render" warning — only a burst of + * FLIP_THRESHOLD flips inside this window trips it. */ +const FLIP_WINDOW_MS = 2 * WARN_COOLDOWN_MS; + +/** How many CONSECUTIVE flipping renders — with no stable-identity render in + * between — before warning regardless of wall-clock spacing. The recency + * window alone is blind to every-render churn in slow-cadence apps (a 6s + * polling dashboard passing an inline prop busts the block-memo cache on + * 100% of renders yet never fits 3 flips into the window). Deliberately + * higher than {@link FLIP_THRESHOLD}: a handful of legitimate changes that + * each happen to arrive on consecutive renders (every render caused BY the + * change) must not false-positive, while sustained churn crosses this + * quickly. */ +const SUSTAINED_FLIP_THRESHOLD = 6; + /** Internal state mutated by {@link trackFlip} across renders. */ export interface FlipState { prev: unknown; - flips: number; + /** Timestamps of the most recent flips, oldest first. Trimmed to the last + * FLIP_THRESHOLD entries — enough to decide the windowed threshold. */ + flipTimes: number[]; + /** Length of the current run of consecutive renders that each flipped. + * Reset by any render with a stable identity. */ + consecutiveFlips: number; + /** Timestamp of the most recent flip. Used to recognize StrictMode's + * double-invoke: the second call of its (flip, same-value) pair arrives + * within the same millisecond and must not count as a stable render. */ + lastFlipAt: number; lastWarnAt: number; } /** * Pure flip-counting + rate-limiting logic, exported for unit testing. * - * Mutates `state` in place and emits at most one `console.warn` per call. - * Caller supplies `now` so tests can control the clock without mocking - * `Date.now()`. + * Warns when either trigger fires: the last {@link FLIP_THRESHOLD} flips all + * happened within {@link FLIP_WINDOW_MS} (fast burst — streaming), or + * {@link SUSTAINED_FLIP_THRESHOLD} consecutive renders each flipped (slow + * every-render churn the window can't see). Mutates `state` in place and + * emits at most one `console.warn` per call. Caller supplies `now` so tests + * can control the clock without mocking `Date.now()`. */ export function trackFlip(state: FlipState, value: unknown, propName: string, now: number): void { - if (state.prev === value) return; - state.flips++; + if (state.prev === value) { + // A render with a stable identity ends any "flips on every render" run — + // EXCEPT StrictMode's double-invoke: it re-runs the render function + // immediately with the same value, so every committed flip arrives as a + // (flip, same-value) pair within the same millisecond. Treating that + // mirror call as a stable render would reset the run on every frame and + // permanently disarm the sustained trigger in dev's most common setup. + if (now > state.lastFlipAt) state.consecutiveFlips = 0; + return; + } state.prev = value; - if (state.flips < FLIP_THRESHOLD) return; + state.lastFlipAt = now; + state.consecutiveFlips++; + state.flipTimes.push(now); + if (state.flipTimes.length > FLIP_THRESHOLD) state.flipTimes.shift(); + const burst = state.flipTimes.length >= FLIP_THRESHOLD && now - state.flipTimes[0] <= FLIP_WINDOW_MS; + const sustained = state.consecutiveFlips >= SUSTAINED_FLIP_THRESHOLD; + if (!burst && !sustained) return; if (now - state.lastWarnAt < WARN_COOLDOWN_MS) return; state.lastWarnAt = now; console.warn( @@ -68,7 +112,13 @@ export default function useReferenceFlipWarning<T>(value: T, propName: string): // matches `value` so the first render does not count as a flip. Sentinel // `-Infinity` for `lastWarnAt` ensures the first warn-eligible event is // never blocked by the cooldown comparison. - const stateRef = useRef<FlipState>({ prev: value, flips: 0, lastWarnAt: -Infinity }); + const stateRef = useRef<FlipState>({ + prev: value, + flipTimes: [], + consecutiveFlips: 0, + lastFlipAt: -Infinity, + lastWarnAt: -Infinity, + }); if (!__DEV__) return; // Intentional render-time `Date.now()`: this hook's whole purpose is to // observe wall-clock cooldowns between flip events. Routing the timestamp diff --git a/packages/core/src/typings/partial-deep.d.ts b/packages/core/src/typings/partial-deep.d.ts index 80bb813..b075819 100755 --- a/packages/core/src/typings/partial-deep.d.ts +++ b/packages/core/src/typings/partial-deep.d.ts @@ -83,11 +83,13 @@ export type ApplyDefaultOptions< Merge< Defaults, { - [Key in keyof SpecifiedOptions as Key extends OptionalKeysOf<Options> - ? undefined extends SpecifiedOptions[Key] - ? never + [ + Key in keyof SpecifiedOptions as Key extends OptionalKeysOf<Options> + ? undefined extends SpecifiedOptions[Key] + ? never + : Key : Key - : Key]: SpecifiedOptions[Key]; + ]: SpecifiedOptions[Key]; } > & Required<Options> @@ -218,8 +220,7 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = _PartialDe >; type _PartialDeep<T, Options extends Required<PartialDeepOptions>> = T extends - | BuiltIns - | (new (...arguments_: any[]) => unknown) + BuiltIns | (new (...arguments_: any[]) => unknown) ? T : T extends Map<infer KeyType, infer ValueType> ? PartialMapDeep<KeyType, ValueType, Options> From 3b4bb4b5101ff950569fd1520faa48d62fd81244 Mon Sep 17 00:00:00 2001 From: Brian Lee <aiephoenixbl@gmail.com> Date: Mon, 6 Jul 2026 07:12:16 +0800 Subject: [PATCH 3/5] fix(mantine): correct Mermaid failure UX and ship real client-side coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restore the 'use client' directive in the built entry (tsup keeps only the entry file's directive; internal ones were silently dropped, which crashed Server Component imports in Next.js App Router). - Mermaid: split parse-stage failures (streaming-incomplete code — keep the last good diagram silently) from draw-stage failures (real errors for the CURRENT code — show the error view instead of letting a stale diagram masquerade as new content). suppressErrorRendering replaces the error-bomb graphic; the temp-element sweep only runs for the attempt that still owns the host. - Replace dead Tailwind/Iconify class names with inline SVGs via a shared TablerIcon wrapper; revoke the view-in-new-window blob URL unconditionally. - Extract code text with a recursive toCodeText (br -> newline) instead of fabricating blank lines; thread AIMarkdown generics through as <TConfig, TRenderData>; export MantineAIMPreCode / MantineAIMMermaidCode for composition from custom pre overrides. - Document the footguns (JSON deep-parse re-serialization, global mermaid.initialize, autoDetectUnknownLanguage streaming cost) in the README; light chart-type tag uses Mantine color variables. - New jsdom client suite (mocked mermaid lifecycle with real clear-host-first geometry, PreCode language matrix) plus extended SSR tests: 7 -> 21 cases. --- packages/mantine/README.md | 23 +- .../src/MantineAIMarkdown.client.test.tsx | 230 ++++++++++++++++++ .../mantine/src/MantineAIMarkdown.test.tsx | 53 ++++ packages/mantine/src/MantineAIMarkdown.tsx | 41 +++- .../customized/MermaidCode/index.tsx | 104 ++++++-- .../customized/MermaidCode/styles.scss | 4 +- .../src/components/customized/PreCode.tsx | 5 +- packages/mantine/src/defs.tsx | 5 + packages/mantine/src/index.tsx | 12 + 9 files changed, 436 insertions(+), 41 deletions(-) create mode 100644 packages/mantine/src/MantineAIMarkdown.client.test.tsx diff --git a/packages/mantine/README.md b/packages/mantine/README.md index c864177..45cf25e 100644 --- a/packages/mantine/README.md +++ b/packages/mantine/README.md @@ -228,7 +228,7 @@ By default, code blocks without an explicit language annotation render as plaint <MantineAIMarkdown content={markdown} config={{ codeBlock: { autoDetectUnknownLanguage: true } }} /> ``` -This uses `highlight.js`'s `highlightAuto` to guess the language. Results may vary for short or ambiguous snippets. +This uses `highlight.js`'s `highlightAuto` to guess the language. Results may vary for short or ambiguous snippets. During streaming, detection re-runs over the full code text on every token append -- enable only when unlabelled code blocks are actually expected (see [Footguns](#footguns)). ## Mermaid Diagrams @@ -295,7 +295,18 @@ const customComponents: AIMarkdownCustomComponents = { <MantineAIMarkdown content={markdown} customComponents={customComponents} />; ``` -To override the default `<pre>` handler (and lose built-in code highlighting, Mermaid, and JSON pretty-print support), include `pre` in your custom components. +To override the default `<pre>` handler, include `pre` in your custom components. You don't have to give up the built-in abilities: the building blocks are exported, so a custom `pre` can delegate back to `MantineAIMPreCode` (code highlighting + Mermaid + JSON pretty-print) or render `MantineAIMMermaidCode` directly. + +```tsx +import { MantineAIMPreCode } from '@ai-react-markdown/mantine'; + +const customComponents: AIMarkdownCustomComponents = { + pre: ({ node, ...props }) => { + // ... your own handling for selected blocks ... + return <MantineAIMPreCode codeText={extractedText} existLanguage={detectedLanguage} />; + }, +}; +``` ## Cross-Chunk Coordination @@ -337,6 +348,8 @@ Caller-provided `Typography`, `ExtraStyles`, and `customComponents` props overri - `MantineAIMarkdownTypography` -- Mantine-themed typography wrapper - `MantineAIMDefaultExtraStyles` -- default extra styles wrapper with Mantine CSS scoping +- `MantineAIMPreCode` -- built-in code block renderer (highlighting + Mermaid + JSON pretty-print), for composing inside a custom `pre` override +- `MantineAIMMermaidCode` -- built-in interactive Mermaid diagram renderer ### Types @@ -353,6 +366,12 @@ Caller-provided `Typography`, `ExtraStyles`, and `customComponents` props overri - `useMantineAIMarkdownRenderState<TConfig>()` -- typed render-state access - `useMantineAIMarkdownMetadata<TMetadata>()` -- typed metadata access +## Footguns + +- **JSON blocks may not display the author's original text.** ` ```json ` blocks are run through `deep-parse-json` and re-serialized. That expands nested stringified JSON (usually what you want), but it also parses string _scalars_: `{"flag": "true"}` displays as `{"flag": true}`, and `"null"` becomes `null`. Numbers are protected from precision loss, but if byte-for-byte fidelity of JSON payloads matters, override `pre` for JSON blocks. +- **`mermaid.initialize` is global.** Mermaid keeps a single global config; every Mermaid diagram render re-initializes it (theme tracks the active color scheme, `securityLevel: 'strict'`, `suppressErrorRendering: true`). If your app also uses the `mermaid` library directly, its own `mermaid.initialize` settings will be overwritten whenever a `<MantineAIMarkdown>` diagram renders (and vice versa). +- **`codeBlock.autoDetectUnknownLanguage` is expensive during streaming.** `hljs.highlightAuto` re-runs over the full text of every unlabelled code block on each token append -- cost grows with block size × stream length. Keep it off (the default) unless unlabelled blocks are actually expected. + ## Core Package For base features, configuration options, content preprocessors, TypeScript generics, and architecture details, see the [`@ai-react-markdown/core` README](../core/README.md). diff --git a/packages/mantine/src/MantineAIMarkdown.client.test.tsx b/packages/mantine/src/MantineAIMarkdown.client.test.tsx new file mode 100644 index 0000000..949f054 --- /dev/null +++ b/packages/mantine/src/MantineAIMarkdown.client.test.tsx @@ -0,0 +1,230 @@ +// @vitest-environment jsdom + +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import { act } from 'react'; +import { createRoot, type Root } from 'react-dom/client'; +import type { ReactNode } from 'react'; +import { MantineProvider } from '@mantine/core'; +import { CodeHighlightAdapterProvider, createHighlightJsAdapter } from '@mantine/code-highlight'; +import hljs from 'highlight.js'; +import MantineAIMarkdown from './MantineAIMarkdown'; + +// Mock the mermaid module so lifecycle tests can script success/failure per +// render attempt without pulling the real (heavy, DOM-mutating) renderer in. +vi.mock('mermaid', () => ({ + default: { + initialize: vi.fn(), + parse: vi.fn(), + render: vi.fn(), + }, +})); +import mermaid from 'mermaid'; + +const mockedParse = vi.mocked(mermaid.parse); +const mockedRender = vi.mocked(mermaid.render); + +(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +// jsdom implements neither matchMedia (Mantine color-scheme detection) nor +// ResizeObserver (Mantine ScrollArea) — provide inert stubs. +if (!window.matchMedia) { + window.matchMedia = (query: string) => + ({ + matches: false, + media: query, + onchange: null, + addListener: () => {}, + removeListener: () => {}, + addEventListener: () => {}, + removeEventListener: () => {}, + dispatchEvent: () => false, + }) as MediaQueryList; +} +if (!window.ResizeObserver) { + window.ResizeObserver = class { + observe() {} + unobserve() {} + disconnect() {} + } as unknown as typeof ResizeObserver; +} + +// The error-state CodeHighlightTabs highlights with language 'mermaid', which +// the stock hljs build doesn't know — register a no-op grammar so the adapter +// doesn't throw "Unknown language". +if (!hljs.getLanguage('mermaid')) { + hljs.registerLanguage('mermaid', () => ({ contains: [] })); +} + +const adapter = createHighlightJsAdapter(hljs); + +let container: HTMLDivElement; +let root: Root; + +beforeEach(() => { + vi.clearAllMocks(); + container = document.createElement('div'); + document.body.appendChild(container); + root = createRoot(container); +}); + +afterEach(async () => { + await act(async () => { + root.unmount(); + }); + container.remove(); +}); + +/** Client-side render harness mirroring the README consumer setup. */ +async function renderMarkdown(ui: ReactNode) { + await act(async () => { + root.render( + <MantineProvider> + <CodeHighlightAdapterProvider adapter={adapter}>{ui}</CodeHighlightAdapterProvider> + </MantineProvider> + ); + }); + // Second flush: the mermaid effect awaits parse/render promises whose + // continuations land after the first act pass. + await act(async () => {}); +} + +const MERMAID_FENCE_A = '```mermaid\ngraph TD;\nA-->B;\n```'; +const MERMAID_FENCE_B = '```mermaid\ngraph TD;\nA-->B;\nB-->C;\n```'; + +/** + * Script one successful mermaid render pass returning the given svg markup. + * Mirrors real mermaid 11 geometry: render() clears the host container + * (`innerHTML = ''`) before drawing into it. + */ +function mockMermaidSuccess(svg: string) { + mockedParse.mockResolvedValue({ diagramType: 'flowchart-v2', config: {} }); + mockedRender.mockImplementation(async (_id: string, _code: string, hostElement?: Element) => { + if (hostElement) hostElement.innerHTML = ''; + return { svg, diagramType: 'flowchart-v2' } as Awaited<ReturnType<typeof mermaid.render>>; + }); +} + +/** + * Script a mermaid draw-stage failure with real mermaid 11 geometry: render() + * clears the host container FIRST (`innerHTML = ''`), and in the worst case + * (a throw point outside mermaid's cleanup wrappers) strands a temp `#d{id}` + * element in the container. + */ +function mockMermaidRenderFailure() { + mockedParse.mockResolvedValue({ diagramType: 'flowchart-v2', config: {} }); + mockedRender.mockImplementation(async (id: string, _code: string, hostElement?: Element) => { + if (hostElement) hostElement.innerHTML = ''; + const temp = document.createElement('div'); + temp.id = `d${id}`; + hostElement?.appendChild(temp); + throw new Error('mermaid render failed'); + }); +} + +describe('MermaidCode lifecycle (client)', () => { + test('successful render injects the svg and shows the chart type', async () => { + mockMermaidSuccess('<svg data-diagram="a"></svg>'); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + + expect(container.querySelector('svg[data-diagram="a"]')).not.toBeNull(); + expect(container.querySelector('.chart-type-tag')?.textContent).toBe('flowchart-v2'); + expect(mermaid.initialize).toHaveBeenCalledWith(expect.objectContaining({ suppressErrorRendering: true })); + }); + + test('first-render failure shows the error state', async () => { + mockedParse.mockRejectedValue(new Error('parse failed')); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + + expect(container.textContent).toContain('Mermaid Render Error'); + expect(container.querySelector('svg[data-diagram]')).toBeNull(); + }); + + test('success-then-PARSE-failure keeps the previous diagram silently (streaming semantics)', async () => { + mockMermaidSuccess('<svg data-diagram="a"></svg>'); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + expect(container.querySelector('svg[data-diagram="a"]')).not.toBeNull(); + + // Parse failure = streaming-incomplete code: mermaid.render is never + // called, the host is untouched — keep the last good diagram, no error. + mockedParse.mockRejectedValue(new Error('parse failed')); + mockedRender.mockClear(); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_B} />); + + expect(mockedRender).not.toHaveBeenCalled(); + expect(container.querySelector('svg[data-diagram="a"]')).not.toBeNull(); + expect(container.textContent).not.toContain('Mermaid Render Error'); + }); + + test('success-then-DRAW-failure shows the error view for the CURRENT code, not a stale diagram', async () => { + mockMermaidSuccess('<svg data-diagram="a"></svg>'); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + expect(container.querySelector('svg[data-diagram="a"]')).not.toBeNull(); + + // Draw failure = parse passed but render rejected the CURRENT code + // (often deterministic, e.g. an unregistered layout in an init + // directive). Showing diagram A for content B would be silently wrong + // content — the error view with B's source must appear instead. + mockMermaidRenderFailure(); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_B} />); + + expect(container.textContent).toContain('Mermaid Render Error'); + // The diagram panel is hidden in the error state. + expect(container.querySelector('.aim-mantine-mermaid-code')?.getAttribute('style')).toContain('display: none'); + }); + + test('draw-failure error state recovers on the next successful render, with no temp leftovers', async () => { + mockMermaidSuccess('<svg data-diagram="a"></svg>'); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + + mockMermaidRenderFailure(); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_B} />); + // Assert the sweep BEFORE the recovery render — the next successful + // mermaid.render clears the host anyway, which would make a post-recovery + // assertion vacuous. + expect(container.querySelectorAll('[id^="dmermaid-"]')).toHaveLength(0); + + mockMermaidSuccess('<svg data-diagram="a"></svg>'); + await renderMarkdown(<MantineAIMarkdown content={MERMAID_FENCE_A} />); + + expect(mockedRender).toHaveBeenCalled(); + expect(container.querySelectorAll('[id^="dmermaid-"]')).toHaveLength(0); + expect(container.querySelector('svg[data-diagram="a"]')).not.toBeNull(); + expect(container.textContent).not.toContain('Mermaid Render Error'); + }); +}); + +describe('PreCode language matrix (client)', () => { + test('unregistered language falls back to plaintext but keeps it as the file name', async () => { + await renderMarkdown(<MantineAIMarkdown content={'```foobar\nsome code here\n```'} />); + + // CodeHighlightTabs shows the unknown identifier as the tab label... + expect(container.textContent).toContain('foobar'); + expect(container.textContent).toContain('some code here'); + // ...but highlights as plaintext (no hljs token spans inside the code). + expect(container.querySelector('code .hljs-keyword')).toBeNull(); + }); + + test('autoDetectUnknownLanguage consults hljs.highlightAuto and uses its result', async () => { + const highlightAutoSpy = vi + .spyOn(hljs, 'highlightAuto') + .mockReturnValue({ language: 'python' } as ReturnType<typeof hljs.highlightAuto>); + + await renderMarkdown( + <MantineAIMarkdown content={'```\nimport os\n```'} config={{ codeBlock: { autoDetectUnknownLanguage: true } }} /> + ); + + expect(highlightAutoSpy).toHaveBeenCalledWith('import os\n'); + expect(container.textContent).toContain('python'); + highlightAutoSpy.mockRestore(); + }); + + test('auto-detection stays off by default', async () => { + const highlightAutoSpy = vi.spyOn(hljs, 'highlightAuto'); + + await renderMarkdown(<MantineAIMarkdown content={'```\nimport os\n```'} />); + + expect(highlightAutoSpy).not.toHaveBeenCalled(); + expect(container.textContent).toContain('import os'); + highlightAutoSpy.mockRestore(); + }); +}); diff --git a/packages/mantine/src/MantineAIMarkdown.test.tsx b/packages/mantine/src/MantineAIMarkdown.test.tsx index 07fbd8f..6bab1ec 100644 --- a/packages/mantine/src/MantineAIMarkdown.test.tsx +++ b/packages/mantine/src/MantineAIMarkdown.test.tsx @@ -90,4 +90,57 @@ describe('MantineAIMarkdown smoke', () => { const html = renderMarkdown(<MantineAIMarkdown content={'```mermaid\ngraph TD;\nA-->B;\n```'} />); expect(html.length).toBeGreaterThan(0); }); + + test('raw HTML <pre> without a code child falls back to a plain <pre>', () => { + const html = renderMarkdown(<MantineAIMarkdown content={'<pre>just preformatted text</pre>'} />); + expect(html).toContain('just preformatted text'); + // The Mantine code-block path always renders the expand control — a plain + // <pre> fallback must not. + expect(html).not.toContain('Expand code'); + expect(html).not.toContain('Collapse code'); + }); + + test('raw HTML <br> inside a code block maps to a single newline', () => { + const html = renderMarkdown(<MantineAIMarkdown content={'<pre><code>a<br>b</code></pre>'} />); + // join('\n') over [text, br-element, text] used to fabricate a blank line + // ("a\n\nb"); hast-util-to-string semantics + explicit br yield "a\nb". + expect(stripTags(html)).toContain('a\nb'); + expect(stripTags(html)).not.toContain('a\n\nb'); + }); + + test('invalid json code fence renders the original text without crashing', () => { + const html = renderMarkdown(<MantineAIMarkdown content={'```json\n{"a": \n```'} />); + expect(stripTags(html)).toContain('{"a":'); + }); + + test('truncated streaming json renders without crashing', () => { + const html = renderMarkdown(<MantineAIMarkdown content={'```json\n{"items": [{"id": 1}, {"id'} streaming />); + expect(html.length).toBeGreaterThan(0); + expect(stripTags(html)).toContain('{"items":'); + }); + + test('nested stringified json is expanded by the deep parse', () => { + const html = renderMarkdown(<MantineAIMarkdown content={'```json\n{"a":"{\\"b\\":1}"}\n```'} />); + // Only the deep parse turns the escaped inner string into a real object + // that pretty-prints as an indented `"b": 1` line. + expect(stripTags(html)).toContain('"b": 1'); + }); + + test('extended config deep-merges down to the CodeHighlight expand state', () => { + const collapsed = renderMarkdown( + <MantineAIMarkdown + content={'```typescript\nconst answer = 42;\n```'} + config={{ codeBlock: { defaultExpanded: false } }} + /> + ); + const expanded = renderMarkdown(<MantineAIMarkdown content={'```typescript\nconst answer = 42;\n```'} />); + // The "Expand code" button is hidden (data-hidden) while expanded and + // visible while collapsed — defaultExpanded flipping that state proves the + // partial Mantine config survived core's deep merge and reached the + // CodeHighlight component. + const showCodeButton = (html: string) => html.match(/<button[^>]*showCodeButton[^>]*>/)?.[0] ?? ''; + expect(showCodeButton(expanded)).toContain('data-hidden="true"'); + expect(showCodeButton(collapsed)).not.toContain('data-hidden="true"'); + expect(showCodeButton(collapsed)).not.toBe(''); + }); }); diff --git a/packages/mantine/src/MantineAIMarkdown.tsx b/packages/mantine/src/MantineAIMarkdown.tsx index 77ef4c5..9648f74 100644 --- a/packages/mantine/src/MantineAIMarkdown.tsx +++ b/packages/mantine/src/MantineAIMarkdown.tsx @@ -34,6 +34,28 @@ export interface MantineAIMarkdownProps< TRenderData extends MantineAIMarkdownMetadata = MantineAIMarkdownMetadata, > extends AIMarkdownProps<TConfig, TRenderData> {} +/** Minimal hast node shape needed for code-text extraction. */ +interface CodeHastNode { + type: string; + tagName?: string; + position?: { start?: { offset?: number } }; + properties?: Record<string, unknown>; + value?: string; + children?: CodeHastNode[]; +} + +/** + * Extract the plain text of a code element following `hast-util-to-string` + * semantics (concatenate text-node values), plus explicit `<br>` handling so + * raw-HTML blocks like `<pre><code>a<br>b</code></pre>` yield `"a\nb"` + * instead of gaining fabricated blank lines. + */ +const toCodeText = (node: CodeHastNode): string => { + if (node.type === 'text') return node.value ?? ''; + if (node.type === 'element' && node.tagName === 'br') return '\n'; + return (node.children ?? []).map(toCodeText).join(''); +}; + /** * Default custom component overrides applied by the Mantine integration. * @@ -44,15 +66,7 @@ export interface MantineAIMarkdownProps< */ const DefaultCustomComponents: AIMarkdownCustomComponents = { pre: ({ node, ...usefulProps }) => { - const code = node?.children[0] as - | { - type: string; - tagName?: string; - position?: { start?: { offset?: number } }; - properties?: Record<string, unknown>; - children: { value?: string }[]; - } - | undefined; + const code = node?.children[0] as CodeHastNode | undefined; if (!code || code.type !== 'element' || code.tagName !== 'code' || !code.position) { return <pre {...usefulProps} />; } @@ -60,7 +74,7 @@ const DefaultCustomComponents: AIMarkdownCustomComponents = { const detectedLanguage = (code.properties?.className as string[]) ?.find((className: string) => className.startsWith('language-')) ?.substring('language-'.length); - const codeText = code.children.map((child: { value?: string }) => child.value ?? '').join('\n'); + const codeText = (code.children ?? []).map(toCodeText).join(''); return <MantineAIMPreCode key={key} codeText={codeText} existLanguage={detectedLanguage} />; }, }; @@ -72,6 +86,11 @@ const DefaultCustomComponents: AIMarkdownCustomComponents = { * overrides take precedence). Automatically resolves the color scheme from Mantine's * `useComputedColorScheme` when no explicit `colorScheme` prop is provided. * + * Note: the `defaultConfig` fallback casts {@link defaultMantineAIMarkdownRenderConfig} + * to `TConfig`. When your `TConfig` extends the Mantine config with additional + * REQUIRED fields, that cast cannot supply them — pass an explicit `defaultConfig` + * so every field is populated at runtime. + * * @typeParam TConfig - Render configuration type. * @typeParam TRenderData - Metadata type. */ @@ -95,7 +114,7 @@ const MantineAIMarkdownComponent = < const computedColorScheme = useComputedColorScheme('light'); return ( - <AIMarkdown<MantineAIMarkdownRenderConfig, MantineAIMarkdownMetadata> + <AIMarkdown<TConfig, TRenderData> Typography={Typography} ExtraStyles={ExtraStyles} defaultConfig={defaultConfig} diff --git a/packages/mantine/src/components/customized/MermaidCode/index.tsx b/packages/mantine/src/components/customized/MermaidCode/index.tsx index 4613343..af79661 100644 --- a/packages/mantine/src/components/customized/MermaidCode/index.tsx +++ b/packages/mantine/src/components/customized/MermaidCode/index.tsx @@ -38,12 +38,32 @@ const handleViewSVGInNewWindow = (svgElement: SVGElement | null | undefined, isD const text = new XMLSerializer().serializeToString(targetSvg); const blob = new Blob([text], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); - const win = window.open(url); - if (win) { - setTimeout(() => URL.revokeObjectURL(url), 5000); - } + window.open(url); + // Revoke unconditionally: the delay covers the navigation race when the + // window opened, and prevents a blob URL leak when the popup was blocked. + setTimeout(() => URL.revokeObjectURL(url), 5000); }; +/** Shared wrapper for the inline Tabler-style stroke icons in the header + * controls. One place owns the 9 presentation attributes; call sites supply + * only their `<path>` data (and optionally a size). */ +const TablerIcon = ({ size = 16, children }: { size?: number; children: React.ReactNode }) => ( + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + strokeWidth="2" + stroke="currentColor" + fill="none" + strokeLinecap="round" + strokeLinejoin="round" + width={`${size}px`} + height={`${size}px`} + > + <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> + {children} + </svg> +); + /** * Interactive mermaid diagram renderer. * @@ -58,7 +78,15 @@ const handleViewSVGInNewWindow = (svgElement: SVGElement | null | undefined, isD * - Click on the rendered diagram to open the SVG in a new browser window * - Copy button for the raw mermaid source code * - Chart type label extracted from mermaid's parse result - * - Preserves the last successful render across transient parse failures + * - Preserves the last successful render across transient PARSE failures + * (the streaming common case: incomplete code). A DRAW-stage failure — + * parse passed but `mermaid.render` threw — is a real error for the + * current code and switches to the error view instead of silently showing + * a stale diagram. + * + * Note: mermaid keeps a single GLOBAL config — the `mermaid.initialize` call + * here overwrites any configuration the host application set on the same + * mermaid instance (and vice versa). * * @param props.code - Raw mermaid diagram source code to render. */ @@ -82,12 +110,22 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { let cancelled = false; const renderMermaid = async () => { + // Which stage failed decides the failure UX below: a parse failure on + // streaming-incomplete code is transient noise (keep the last good + // diagram — mermaid never touched the host), while a draw failure is a + // real error for the CURRENT code (parse passed; `mermaid.render` + // rejected it, often deterministically) and must not leave a stale + // diagram masquerading as the new content. + let drawStageReached = false; try { mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: isDark ? 'dark' : 'base', darkMode: isDark, + // Mermaid draws an "error bomb" graphic into the container before + // throwing — suppress it; the catch below owns failure rendering. + suppressErrorRendering: true, }); const parseResult = await mermaid.parse(props.code); if (!parseResult) { @@ -99,6 +137,7 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { return; } + drawStageReached = true; const { svg, bindFunctions, diagramType } = await mermaid.render( generateMermaidUUID(), props.code, @@ -114,10 +153,24 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { setChartType(diagramType); setRenderError(false); } catch { - if (!cancelled && renderVersion === renderVersionRef.current && !hasRenderedRef.current) { - setChartType('unknown'); - setRenderError(true); + if (cancelled || renderVersion !== renderVersionRef.current) { + // A newer attempt owns the host (mermaid serializes render calls + // on a global queue, so it runs strictly after this one and + // clears/redraws the host itself). + return; + } + if (!drawStageReached && hasRenderedRef.current) { + // Transient parse failure mid-stream: mermaid.render was never + // called, the host still shows the last good diagram — keep it. + return; } + // First-render failure, or a draw-stage failure (mermaid cleared the + // host before throwing): show the error view with the CURRENT code. + // Sweep any temp `#d{id}` element a mid-render throw point outside + // mermaid's cleanup wrappers may have stranded. + ref.current?.querySelectorAll(':scope > [id^="dmermaid-"]').forEach((element) => element.remove()); + setChartType('unknown'); + setRenderError(true); } }; @@ -159,13 +212,19 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { : [ <CodeHighlightControl tooltipLabel="Render Mermaid" - key="gpt" + key="render-mermaid" onClick={() => { setShowOriginalCode(false); }} > <Flex align="center" justify="center" w={18} h={18}> - <span className="icon-[gravity-ui--logo-mermaid] relative bottom-[1px] text-[16px]"></span> + <TablerIcon> + <path d="M12 5m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path> + <path d="M5 19m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path> + <path d="M19 19m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path> + <path d="M6.5 17.5l5.5 -4.5l5.5 4.5"></path> + <path d="M12 7l0 6"></path> + </TablerIcon> </Flex> </CodeHighlightControl>, ] @@ -197,7 +256,11 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { }} > <Flex align="center" justify="center" w={18} h={18}> - <span className="icon-[entypo--code] relative bottom-[0.25px] text-[16px]"></span> + <TablerIcon> + <path d="M7 8l-4 4l4 4"></path> + <path d="M17 8l4 4l-4 4"></path> + <path d="M14 4l-4 16"></path> + </TablerIcon> </Flex> </ActionIcon> </Tooltip> @@ -206,23 +269,14 @@ const MantineAIMMermaidCode = memo((props: { code: string }) => { <Tooltip label={copied ? 'Copied' : 'Copy'} withArrow position="right"> <ActionIcon variant="transparent" size={28} className="action-icon" onClick={copy}> {copied ? ( - <span className="icon-origin-[lucide--check] text-[18px]"></span> + <TablerIcon size={18}> + <path d="M5 12l5 5l10 -10"></path> + </TablerIcon> ) : ( - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 24 24" - strokeWidth="2" - stroke="currentColor" - fill="none" - strokeLinecap="round" - strokeLinejoin="round" - width="18px" - height="18px" - > - <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> + <TablerIcon size={18}> <path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path> <path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path> - </svg> + </TablerIcon> )} </ActionIcon> </Tooltip> diff --git a/packages/mantine/src/components/customized/MermaidCode/styles.scss b/packages/mantine/src/components/customized/MermaidCode/styles.scss index ee68080..3ce02c2 100644 --- a/packages/mantine/src/components/customized/MermaidCode/styles.scss +++ b/packages/mantine/src/components/customized/MermaidCode/styles.scss @@ -20,9 +20,9 @@ .chart-type-tag { padding: calc(0.2125rem * var(--mantine-scale)) calc(0.5625rem * var(--mantine-scale)); - color: black; + color: var(--mantine-color-black); border: 1px solid var(--mantine-color-gray-3); - background: white; + background: var(--mantine-color-white); border-radius: var(--mantine-radius-default); font-size: var(--mantine-font-size-xs); font-weight: 700; diff --git a/packages/mantine/src/components/customized/PreCode.tsx b/packages/mantine/src/components/customized/PreCode.tsx index 7076e65..be0e4fe 100644 --- a/packages/mantine/src/components/customized/PreCode.tsx +++ b/packages/mantine/src/components/customized/PreCode.tsx @@ -34,7 +34,10 @@ const SPECIAL_LANGUAGES = new Set<string>(Object.values(SpecialCodeLanguage)); * enabled, uses `highlight.js` auto-detection. * - Mermaid code blocks (`language-mermaid`) are rendered as interactive diagrams * via {@link MantineAIMMermaidCode}. - * - JSON code blocks are deep-parsed and pretty-printed before display. + * - JSON code blocks are deep-parsed and pretty-printed before display. Because + * `deep-parse-json` also parses string scalars ("true"/"null" become booleans/null, + * nested stringified JSON is expanded; numbers are protected), the displayed + * content can differ from the author's original text. * - Unrecognized languages render as plaintext with an "unknown" label using * {@link CodeHighlight} (no tabs). * - Recognized languages render with {@link CodeHighlightTabs} showing the diff --git a/packages/mantine/src/defs.tsx b/packages/mantine/src/defs.tsx index 724b4e0..971ec14 100644 --- a/packages/mantine/src/defs.tsx +++ b/packages/mantine/src/defs.tsx @@ -30,6 +30,11 @@ export interface MantineAIMarkdownRenderConfig extends AIMarkdownRenderConfig { * When `true`, uses `highlight.js` auto-detection to determine the language * of code blocks that lack an explicit language annotation. * + * Performance note: during streaming, `hljs.highlightAuto` re-runs over the + * FULL code text on every token append — cost grows with block size times + * stream length. Enable only when unlabelled code blocks are actually + * expected in your content. + * * @default false */ autoDetectUnknownLanguage: boolean; diff --git a/packages/mantine/src/index.tsx b/packages/mantine/src/index.tsx index cfe422d..53b983d 100644 --- a/packages/mantine/src/index.tsx +++ b/packages/mantine/src/index.tsx @@ -7,6 +7,8 @@ * @packageDocumentation */ +'use client'; + // --- Components --- /** Props for the main {@link MantineAIMarkdown} component. */ @@ -21,6 +23,16 @@ export { default as MantineAIMarkdownTypography } from './components/typography/ /** Default extra styles wrapper providing Mantine-compatible CSS scoping and overrides. */ export { default as MantineAIMDefaultExtraStyles } from './components/extra-styles/DefaultExtraStyles'; +/** + * Built-in code block renderer (syntax highlighting, Mermaid, JSON pretty-print). + * Exported so a custom `pre` override can delegate back to the built-in + * abilities instead of reimplementing them. + */ +export { default as MantineAIMPreCode } from './components/customized/PreCode'; + +/** Built-in interactive Mermaid diagram renderer used by {@link MantineAIMPreCode}. */ +export { default as MantineAIMMermaidCode } from './components/customized/MermaidCode'; + // --- Types, config, and hooks --- /** Extended render configuration and metadata types for the Mantine integration. */ From b629cf6559337ffd69a84b297ce474e273de0e0d Mon Sep 17 00:00:00 2001 From: Brian Lee <aiephoenixbl@gmail.com> Date: Mon, 6 Jul 2026 07:41:37 +0800 Subject: [PATCH 4/5] chore(repo): harden the release pipeline and close static-analysis blind spots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Release safety (release.yml): - Tag check now verifies EVERY published manifest, not just the root — pnpm publish -r silently skips existing versions, so a drifted package could previously ship nothing while the run stayed green. - Republish idempotency guard: an existing version is only allowed on a re-run of the same workflow run (GITHUB_RUN_ATTEMPT > 1); pnpm's OIDC publish records no gitHead, so commit identity can't come from the registry. - Post-publish registry existence assertion (with retry), tag-on-main ancestry check, storybook browser suite in the gates, idempotent gh release create, multi-section + era-boundary-aware notes extraction. - version-packages.mjs refuses only FULL no-op bumps (partial runs stay re-runnable) and skips non-package dirs. CI (ci.yml): storybook-test task (headless Chromium smoke of all stories), attw + publint packaging checks, PR-only cancel-in-progress, workflow_dispatch. Static analysis: stories and .storybook are now typechecked (per-package tsconfig.stories.json as the single-pass superset config, root tsconfig.storybook.json) and linted (.storybook un-ignored; scripts get node globals). Packaging & deps: engines >=18 and LICENSE in both tarballs; dompurify floor ^3.4.11 (prod audit clean); katex aligned to rehype-katex's 0.16 line; eslint-plugin-react-hooks pinned ~7.0.1 (7.1 conflicts with the block-memo ref patterns); policy-scoped minor updates (mermaid, remark-cjk-friendly, storybook, vitest, playwright, prettier, sass); jsdom for the client test suites; dependabot dev-deps groups. release:dry replaces the legacy local publish script — same gates as the tag workflow, publish is dry-run only (trusted publishing stays the sole real path); CONTRIBUTING updated accordingly. --- .github/dependabot.yml | 10 + .github/workflows/ci.yml | 45 +- .github/workflows/release.yml | 111 +- CONTRIBUTING.md | 2 +- eslint.config.js | 15 +- package.json | 41 +- packages/core/LICENSE | 21 + packages/core/package.json | 14 +- packages/core/tsconfig.json | 3 - packages/core/tsconfig.stories.json | 7 + packages/mantine/LICENSE | 21 + packages/mantine/package.json | 12 +- packages/mantine/tsconfig.stories.json | 7 + pnpm-lock.yaml | 3091 +++++++----------------- pnpm-workspace.yaml | 4 +- scripts/version-packages.mjs | 31 +- tsconfig.storybook.json | 4 + types/style-shims.d.ts | 5 + 18 files changed, 1205 insertions(+), 2239 deletions(-) create mode 100644 packages/core/LICENSE create mode 100644 packages/core/tsconfig.stories.json create mode 100644 packages/mantine/LICENSE create mode 100644 packages/mantine/tsconfig.stories.json create mode 100644 tsconfig.storybook.json create mode 100644 types/style-shims.d.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1b11a52..673ec67 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -101,6 +101,11 @@ updates: update-types: - minor - patch + dev-deps: + dependency-type: development + update-types: + - minor + - patch # @ai-react-markdown/mantine - package-ecosystem: npm @@ -143,6 +148,11 @@ updates: update-types: - minor - patch + dev-deps: + dependency-type: development + update-types: + - minor + - patch # GitHub Actions used in workflows — major-block only; no lint-plugin lock needed. - package-ecosystem: github-actions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 490a220..0914a8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,11 +5,14 @@ on: branches: [main] pull_request: branches: [main] + # Manual re-runs on any branch (runner debugging, flake triage). + workflow_dispatch: -# Cancel any in-progress run on the same ref when a new commit arrives. +# Cancel superseded runs on PRs only: every main commit keeps its full CI +# conclusion (bisect / branch-protection readability). concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: ci: @@ -27,6 +30,7 @@ jobs: - format-check - typecheck - test + - storybook-test - build steps: @@ -55,22 +59,45 @@ jobs: if: matrix.task == 'format-check' run: pnpm format:check - # mantine's typecheck/tests resolve @ai-react-markdown/core through its - # exports map, which points at dist/ — absent on a fresh checkout since - # matrix tasks run in isolated jobs. Build core first so dependents - # check against the real built artifact (what npm consumers get). - - name: Build core (dependents resolve its dist) + # Dependents (mantine src, stories importing package names) resolve + # through the exports maps, which point at dist/ — absent on a fresh + # checkout since matrix tasks run in isolated jobs. Building first means + # they check against the real built artifact (what npm consumers get). + - name: Build packages (dependents resolve dist) if: matrix.task == 'typecheck' || matrix.task == 'test' - run: pnpm --filter @ai-react-markdown/core build + run: pnpm build + # --include-workspace-root also runs the root typecheck script, which + # covers .storybook/ and the root config files (no package tsconfig does). - name: Typecheck (all packages) if: matrix.task == 'typecheck' - run: pnpm -r typecheck + run: pnpm -r --include-workspace-root typecheck - name: Test (all packages) if: matrix.task == 'test' run: pnpm -r test + # Smoke-renders every story in headless Chromium via the addon-vitest + # project — the only automated coverage the stories/decorators have. + - name: Storybook browser tests + if: matrix.task == 'storybook-test' + run: | + pnpm build + pnpm exec playwright install chromium --with-deps + pnpm vitest run --project storybook + - name: Build (all packages) if: matrix.task == 'build' run: pnpm build + + # Machine-guard the packaging invariants (exports map resolution across + # node10/node16/bundler, tarball contents) instead of relying on memory. + # ./styles.css is excluded from attw: it is a CSS entrypoint, which attw + # can only ever see as an unresolvable JS module. + - name: Package checks (attw + publint) + if: matrix.task == 'build' + run: | + pnpm exec attw --pack packages/core + pnpm exec attw --pack packages/mantine --exclude-entrypoints ./styles.css + pnpm exec publint packages/core + pnpm exec publint packages/mantine diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 653fa60..a8fd4e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,6 +35,19 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + # Full history: the ancestry check below needs main's commit graph. + fetch-depth: 0 + + # Any `v*` tag triggers this workflow, wherever it points. Refuse tags + # on commits that never landed on main (unreviewed / orphan commits). + - name: Verify tag commit is on main + run: | + git fetch origin main + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "::error::Tag ${GITHUB_REF_NAME} points at a commit that is not on main" + exit 1 + fi - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -51,14 +64,21 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Verify tag matches package version + # Checks every published package, not just the root: if versions drift + # (bad merge, partial bump), `pnpm publish -r` silently skips versions + # that already exist on the registry and the release would ship nothing. + - name: Verify tag matches all package versions run: | TAG_VERSION="${GITHUB_REF_NAME#v}" - PKG_VERSION="$(node -p "require('./package.json').version")" - if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then - echo "::error::Tag v${TAG_VERSION} does not match package.json version ${PKG_VERSION}" - exit 1 - fi + FAIL=0 + for PKG in package.json packages/*/package.json; do + PKG_VERSION="$(node -p "require('./${PKG}').version")" + if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then + echo "::error::Tag v${TAG_VERSION} does not match ${PKG} version ${PKG_VERSION}" + FAIL=1 + fi + done + exit "$FAIL" # Full quality gate — mirrors CI so a tag can't ship anything main # wouldn't accept. Build runs first: mantine's typecheck/tests resolve @@ -73,14 +93,45 @@ jobs: run: pnpm build - name: Typecheck - run: pnpm -r typecheck + run: pnpm -r --include-workspace-root typecheck - # Per-package unit suites, matching the CI gate. The root `vitest run` - # additionally spins up the storybook browser project, which needs - # playwright browsers the runner doesn't have. + # Per-package unit suites, matching the CI gate. - name: Test run: pnpm -r test + # Full story smoke suite in headless Chromium — same coverage as CI's + # storybook-test task, so a tag pushed before that commit's CI run + # completes (or after a red one) still can't ship a story/decorator + # regression. + - name: Storybook browser tests + run: | + pnpm exec playwright install chromium --with-deps + pnpm vitest run --project storybook + + # Idempotency guard: `pnpm publish -r` silently SKIPS versions that + # already exist on the registry, so without this check a tag pointing + # at new content while the version number already exists would go + # green with the OLD tarball staying live (shipping nothing). An + # existing version is acceptable only on a RE-RUN of this same + # workflow run (GITHUB_RUN_ATTEMPT > 1) — the recovery path for a + # partially failed release; a re-run always reuses the original + # commit, so identity is guaranteed. (Commit identity cannot be + # checked on the registry itself: pnpm's OIDC publish records no + # gitHead — verified empirically against our published versions.) + - name: Guard against republishing an existing version + run: | + VERSION="${GITHUB_REF_NAME#v}" + for PKG in @ai-react-markdown/core @ai-react-markdown/mantine; do + if npm view "${PKG}@${VERSION}" version >/dev/null 2>&1; then + if [ "${GITHUB_RUN_ATTEMPT:-1}" -gt 1 ]; then + echo "${PKG}@${VERSION} already on the registry — re-run recovery; publish will skip it harmlessly" + else + echo "::error::${PKG}@${VERSION} already exists on the registry — a fresh run must publish a NEW version (reusing one ships nothing). Recovering a partially failed release? Re-run the failed workflow run instead of pushing a new tag." + exit 1 + fi + fi + done + # pnpm delegates the actual upload to the npm CLI, and the OIDC token # exchange happens there — npm 10.x (bundled with Node 22) predates # trusted publishing and dies with ENEEDAUTH. @@ -90,17 +141,53 @@ jobs: - name: Publish to npm (OIDC trusted publishing + provenance) run: npx -y pnpm@^11.1.3 publish -r --access public --no-git-checks + # `pnpm publish -r` skips already-published versions without failing, so + # assert the tarballs actually landed before declaring the release done. + - name: Verify packages exist on the registry + run: | + VERSION="${GITHUB_REF_NAME#v}" + for PKG in @ai-react-markdown/core @ai-react-markdown/mantine; do + for i in 1 2 3 4 5; do + if npm view "${PKG}@${VERSION}" version >/dev/null 2>&1; then + echo "${PKG}@${VERSION} is live" + continue 2 + fi + if [ "$i" -lt 5 ]; then + echo "waiting for ${PKG}@${VERSION} to appear (attempt ${i}/5)…" + sleep 15 + fi + done + echo "::error::${PKG}@${VERSION} not found on the registry after publish" + exit 1 + done + # Notes come from the version's section in docs/release-highlights.md — # the hand-written changelog — falling back to GitHub's auto-generated # notes if no section exists for this version. + # + # Format contract: headings must be `### x.y.z <anything>` (version + # followed by a space). A version may span MULTIPLE `### x.y.z …` + # sections (e.g. 1.3.0 has two); extraction keeps every same-version + # section (printing the follow-up headings as separators) and stops at + # the first heading for a different version. - name: Create GitHub release env: GH_TOKEN: ${{ github.token }} run: | + # Idempotent for re-run recovery: `gh release create` 422s on an + # existing release, which would re-redden a re-run whose first + # attempt already created it. + if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then + echo "Release $GITHUB_REF_NAME already exists — re-run recovery; skipping creation" + exit 0 + fi VERSION="${GITHUB_REF_NAME#v}" awk -v ver="$VERSION" ' - index($0, "### " ver " ") == 1 { found = 1; next } - found && /^### / { exit } + index($0, "### " ver " ") == 1 { + if (!found) { found = 1; next } + print; next + } + found && (/^### / || /^## /) { exit } found { print } ' docs/release-highlights.md > /tmp/release-notes.md if [ -s /tmp/release-notes.md ]; then diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 404e8a4..fdda531 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,7 @@ git tag vX.Y.Z git push origin main vX.Y.Z ``` -The legacy local path (`pnpm release`) still runs the same gates but relies on your local `npm login` session and cannot attach provenance — prefer the tag flow. +There is no local publish path: `pnpm release:dry` runs the same quality gates plus a `pnpm publish --dry-run` as a no-publish preflight, and actual publishing only happens through the tag-triggered workflow (npm trusted publishing / OIDC, with provenance). The workflow also creates the GitHub release, with notes taken from the version's section in `docs/release-highlights.md` — write that section before tagging (it falls back to auto-generated notes otherwise). diff --git a/eslint.config.js b/eslint.config.js index 7ac309f..16808c7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -9,11 +9,11 @@ export default defineConfig( ignores: [ '**/dist/**', '**/node_modules/**', - '**/.storybook/**', // Build output — companion to `3a1b045 chore: gitignore storybook-static/`, // which added the artifact dir to .gitignore but missed the eslint // config. Linting bundled JS produces tens of thousands of false- - // positive errors against minified code. + // positive errors against minified code. (.storybook/ itself is real + // source — config, decorators, docs container — and IS linted.) '**/storybook-static/**', ], }, @@ -39,5 +39,16 @@ export default defineConfig( ], }, }, + { + // Node-run scripts (release tooling). Keeps `process`/`console` from + // tripping no-undef without inline /* global */ comments. + files: ['scripts/**'], + languageOptions: { + globals: { + process: 'readonly', + console: 'readonly', + }, + }, + }, eslintConfigPrettier ); diff --git a/package.json b/package.json index a81fec7..c555ef7 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,11 @@ "build": "pnpm --filter './packages/*' run build", "lint": "eslint .", "lint:fix": "eslint . --fix", + "typecheck": "tsc --noEmit -p tsconfig.storybook.json", "format": "prettier --write .", "format:check": "prettier --check .", "version-packages": "node scripts/version-packages.mjs", - "release": "pnpm lint && pnpm format:check && pnpm build && pnpm -r typecheck && pnpm vitest run && pnpm publish -r --access public", + "release:dry": "pnpm lint && pnpm format:check && pnpm build && pnpm -r --include-workspace-root typecheck && pnpm -r test && pnpm vitest run --project storybook && pnpm publish -r --dry-run --access public --no-git-checks", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" }, @@ -38,33 +39,35 @@ }, "packageManager": "pnpm@10.28.1", "devDependencies": { + "@arethetypeswrong/cli": "^0.18.4", "@chromatic-com/storybook": "^5.2.1", "@eslint/js": "^10.0.1", - "@storybook/addon-a11y": "^10.4.2", - "@storybook/addon-docs": "^10.4.2", - "@storybook/addon-onboarding": "^10.4.2", - "@storybook/addon-themes": "^10.4.2", - "@storybook/addon-vitest": "^10.4.2", - "@storybook/react-vite": "^10.4.2", + "@storybook/addon-a11y": "^10.4.6", + "@storybook/addon-docs": "^10.4.6", + "@storybook/addon-onboarding": "^10.4.6", + "@storybook/addon-themes": "^10.4.6", + "@storybook/addon-vitest": "^10.4.6", + "@storybook/react-vite": "^10.4.6", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@vitest/browser-playwright": "^4.1.8", - "@vitest/coverage-v8": "^4.1.8", - "autoprefixer": "^10.5.0", + "@vitest/browser-playwright": "^4.1.10", + "@vitest/coverage-v8": "^4.1.10", + "autoprefixer": "^10.5.2", "eslint": "^10.1.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-react-hooks": "^7.0.1", - "katex": "^0.17.0", - "playwright": "^1.60.0", - "postcss": "^8.5.10", + "eslint-plugin-react-hooks": "~7.0.1", + "jsdom": "^29.1.1", + "katex": "^0.16.0", + "playwright": "^1.61.1", + "postcss": "^8.5.16", "postcss-cli": "^11.0.1", - "prettier": "^3.8.3", - "react-scan": "^0.5.7", - "sass": "^1.100.0", - "storybook": "^10.4.2", + "prettier": "^3.9.4", + "publint": "^0.3.21", + "sass": "^1.101.0", + "storybook": "^10.4.6", "tsup": "^8.5.1", "typescript": "^5.9.3", "typescript-eslint": "^8.58.2", - "vitest": "^4.1.8" + "vitest": "^4.1.10" } } diff --git a/packages/core/LICENSE b/packages/core/LICENSE new file mode 100644 index 0000000..036967c --- /dev/null +++ b/packages/core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Brian Lee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/core/package.json b/packages/core/package.json index 7f769d8..ac7f4c4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -52,12 +52,15 @@ "build:css": "sass src/components/typography/variants/:dist/typography/ && postcss dist/typography/*.css --replace", "build": "pnpm run build:js && pnpm run build:css", "test": "vitest --run", - "typecheck": "tsc --noEmit -p tsconfig.json" + "typecheck": "tsc --noEmit -p tsconfig.stories.json" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { + "katex": "^0.16.0", "react": ">=19.0.0", - "react-dom": ">=19.0.0", - "katex": "^0.16.0" + "react-dom": ">=19.0.0" }, "peerDependenciesMeta": { "katex": { @@ -74,8 +77,8 @@ "rehype-sanitize": "^6.0.0", "rehype-unwrap-images": "^1.0.0", "remark-breaks": "^4.0.0", - "remark-cjk-friendly": "^2.0.1", - "remark-cjk-friendly-gfm-strikethrough": "^2.0.1", + "remark-cjk-friendly": "^2.3.1", + "remark-cjk-friendly-gfm-strikethrough": "^2.3.1", "remark-definition-list": "^2.0.0", "remark-emoji": "^5.0.2", "remark-gfm": "^4.0.1", @@ -93,6 +96,7 @@ }, "devDependencies": { "@types/hast": "^3.0.4", + "jsdom": "^29.1.1", "@types/lodash-es": "^4.17.12", "@types/mdast": "^4.0.4", "@types/react": "^19.2.17", diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 1ce6cca..564a599 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "types": ["vitest/globals"] - }, "include": ["src"] } diff --git a/packages/core/tsconfig.stories.json b/packages/core/tsconfig.stories.json new file mode 100644 index 0000000..2b6178c --- /dev/null +++ b/packages/core/tsconfig.stories.json @@ -0,0 +1,7 @@ +{ + // The single `pnpm typecheck` entry: a strict superset of tsconfig.json + // (src + stories + build configs), so src is checked exactly once. + // tsconfig.json itself stays src-only for tsup's dts build. + "extends": "../../tsconfig.base.json", + "include": ["src", "stories", "tsup.config.ts", "vitest.config.ts", "../../types/style-shims.d.ts"] +} diff --git a/packages/mantine/LICENSE b/packages/mantine/LICENSE new file mode 100644 index 0000000..036967c --- /dev/null +++ b/packages/mantine/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Brian Lee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/mantine/package.json b/packages/mantine/package.json index a9e5e22..89d7eb8 100644 --- a/packages/mantine/package.json +++ b/packages/mantine/package.json @@ -53,7 +53,10 @@ "scripts": { "build": "tsup", "test": "vitest --run", - "typecheck": "tsc --noEmit -p tsconfig.json" + "typecheck": "tsc --noEmit -p tsconfig.stories.json" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { "@ai-react-markdown/core": "^1.4.8", @@ -65,7 +68,7 @@ }, "dependencies": { "deep-parse-json": "^2.0.0", - "mermaid": "^11.15.0" + "mermaid": "^11.16.0" }, "devDependencies": { "@ai-react-markdown/core": "workspace:*", @@ -73,11 +76,12 @@ "@mantine/core": "^8.3.18", "@types/lodash-es": "^4.17.12", "@types/node": "^25.9.1", - "autoprefixer": "^10.5.0", + "autoprefixer": "^10.5.2", "esbuild-sass-plugin": "^3.7.0", "highlight.js": "^11.11.1", + "jsdom": "^29.1.1", "lodash-es": "^4.18.0", - "postcss": "^8.5.10", + "postcss": "^8.5.16", "tsup": "^8.5.1" } } diff --git a/packages/mantine/tsconfig.stories.json b/packages/mantine/tsconfig.stories.json new file mode 100644 index 0000000..2b6178c --- /dev/null +++ b/packages/mantine/tsconfig.stories.json @@ -0,0 +1,7 @@ +{ + // The single `pnpm typecheck` entry: a strict superset of tsconfig.json + // (src + stories + build configs), so src is checked exactly once. + // tsconfig.json itself stays src-only for tsup's dts build. + "extends": "../../tsconfig.base.json", + "include": ["src", "stories", "tsup.config.ts", "vitest.config.ts", "../../types/style-shims.d.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad57f55..aea9ed3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - dompurify: ^3.4.0 + dompurify: ^3.4.11 uuid: ^11.1.1 picomatch: ^4.0.4 typescript: ^5.9.3 @@ -14,30 +14,33 @@ importers: .: devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.18.4 + version: 0.18.4 '@chromatic-com/storybook': specifier: ^5.2.1 - version: 5.2.1(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + version: 5.2.1(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@eslint/js': specifier: ^10.0.1 version: 10.0.1(eslint@10.1.0(jiti@2.7.0)) '@storybook/addon-a11y': - specifier: ^10.4.2 - version: 10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + specifier: ^10.4.6 + version: 10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@storybook/addon-docs': - specifier: ^10.4.2 - version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + specifier: ^10.4.6 + version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@storybook/addon-onboarding': - specifier: ^10.4.2 - version: 10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + specifier: ^10.4.6 + version: 10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@storybook/addon-themes': - specifier: ^10.4.2 - version: 10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + specifier: ^10.4.6 + version: 10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@storybook/addon-vitest': - specifier: ^10.4.2 - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8) + specifier: ^10.4.6 + version: 10.4.6(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10)(@vitest/runner@4.1.10)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.10) '@storybook/react-vite': - specifier: ^10.4.2 - version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + specifier: ^10.4.6 + version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@types/react': specifier: ^19.2.17 version: 19.2.17 @@ -45,14 +48,14 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.17) '@vitest/browser-playwright': - specifier: ^4.1.8 - version: 4.1.8(playwright@1.60.0)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) + specifier: ^4.1.10 + version: 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/coverage-v8': - specifier: ^4.1.8 - version: 4.1.8(@vitest/browser@4.1.8)(vitest@4.1.8) + specifier: ^4.1.10 + version: 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) autoprefixer: - specifier: ^10.5.0 - version: 10.5.0(postcss@8.5.15) + specifier: ^10.5.2 + version: 10.5.2(postcss@8.5.16) eslint: specifier: ^10.1.0 version: 10.1.0(jiti@2.7.0) @@ -60,35 +63,38 @@ importers: specifier: ^10.1.8 version: 10.1.8(eslint@10.1.0(jiti@2.7.0)) eslint-plugin-react-hooks: - specifier: ^7.0.1 + specifier: ~7.0.1 version: 7.0.1(eslint@10.1.0(jiti@2.7.0)) + jsdom: + specifier: ^29.1.1 + version: 29.1.1 katex: - specifier: ^0.17.0 - version: 0.17.0 + specifier: ^0.16.0 + version: 0.16.47 playwright: - specifier: ^1.60.0 - version: 1.60.0 + specifier: ^1.61.1 + version: 1.61.1 postcss: - specifier: ^8.5.10 - version: 8.5.15 + specifier: ^8.5.16 + version: 8.5.16 postcss-cli: specifier: ^11.0.1 - version: 11.0.1(jiti@2.7.0)(postcss@8.5.15) + version: 11.0.1(jiti@2.7.0)(postcss@8.5.16) prettier: - specifier: ^3.8.3 - version: 3.8.3 - react-scan: - specifier: ^0.5.7 - version: 0.5.7(esbuild@0.27.7)(eslint@10.1.0(jiti@2.7.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0) + specifier: ^3.9.4 + version: 3.9.4 + publint: + specifier: ^0.3.21 + version: 0.3.21 sass: - specifier: ^1.100.0 - version: 1.100.0 + specifier: ^1.101.0 + version: 1.101.0 storybook: - specifier: ^10.4.2 - version: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^10.4.6 + version: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@5.9.3)(yaml@2.9.0) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.16)(typescript@5.9.3)(yaml@2.9.0) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -96,8 +102,8 @@ importers: specifier: ^8.58.2 version: 8.58.2(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3) vitest: - specifier: ^4.1.8 - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + specifier: ^4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) packages/core: dependencies: @@ -112,7 +118,7 @@ importers: version: 3.0.1 katex: specifier: ^0.16.0 - version: 0.16.44 + version: 0.16.47 mdast-util-to-hast: specifier: ^13.2.1 version: 13.2.1 @@ -132,11 +138,11 @@ importers: specifier: ^4.0.0 version: 4.0.0 remark-cjk-friendly: - specifier: ^2.0.1 - version: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5) + specifier: ^2.3.1 + version: 2.3.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5) remark-cjk-friendly-gfm-strikethrough: - specifier: ^2.0.1 - version: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5) + specifier: ^2.3.1 + version: 2.3.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5) remark-definition-list: specifier: ^2.0.0 version: 2.0.0 @@ -201,6 +207,9 @@ importers: hastscript: specifier: ^9.0.1 version: 9.0.1 + jsdom: + specifier: ^29.1.1 + version: 29.1.1 lodash-es: specifier: ^4.18.0 version: 4.18.1 @@ -220,8 +229,8 @@ importers: specifier: ^2.0.0 version: 2.0.0 mermaid: - specifier: ^11.15.0 - version: 11.15.0 + specifier: ^11.16.0 + version: 11.16.0 react: specifier: '>=19' version: 19.2.7 @@ -245,94 +254,90 @@ importers: specifier: ^25.9.1 version: 25.9.3 autoprefixer: - specifier: ^10.5.0 - version: 10.5.0(postcss@8.5.15) + specifier: ^10.5.2 + version: 10.5.2(postcss@8.5.16) esbuild-sass-plugin: specifier: ^3.7.0 version: 3.7.0(esbuild@0.27.7)(sass-embedded@1.98.0) highlight.js: specifier: ^11.11.1 version: 11.11.1 + jsdom: + specifier: ^29.1.1 + version: 29.1.1 lodash-es: specifier: ^4.18.0 version: 4.18.1 postcss: - specifier: ^8.5.10 - version: 8.5.15 + specifier: ^8.5.16 + version: 8.5.16 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@5.9.3)(yaml@2.9.0) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.16)(typescript@5.9.3)(yaml@2.9.0) packages: '@adobe/css-tools@4.5.0': resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} + '@andrewbranch/untar.js@1.0.3': + resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} + '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} + '@arethetypeswrong/cli@0.18.4': + resolution: {integrity: sha512-kNWo6LTzGAuLYPpJ7Sgo63whSUeeSuKMlYx6IBgzs4ONEG807gW4hSSENvpeCHzO2H2wIzG5EFl0OKBbqGBAyA==} + engines: {node: '>=20'} + hasBin: true + + '@arethetypeswrong/core@0.18.4': + resolution: {integrity: sha512-M5F0ePyN6h2Z6XxRiyIPqjGbltotXLjR0CKA0uKspsDu0QmgTNYvRb4RSQPMUs2ZXZHCCYpbaZbFbYOXLxCjUA==} + engines: {node: '>=20'} + + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.7': resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - '@babel/core@7.29.7': resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.29.7': resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.29.7': resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.29.7': resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.29.7': resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} @@ -347,52 +352,27 @@ packages: resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.29.7': resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.7': resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.29.7': resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - '@babel/template@7.29.7': resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.7': resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} @@ -408,11 +388,18 @@ packages: '@blazediff/core@1.9.1': resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} + '@braidai/lang@1.1.2': + resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} + '@braintree/sanitize-url@7.1.2': resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} - '@bufbuild/protobuf@2.12.0': - resolution: {integrity: sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@bufbuild/protobuf@2.12.1': + resolution: {integrity: sha512-BvAMfS6LrgZiryOAZ4pBYucu4wG/Ei/9o9DZ9akbREnMLbPJiom2i8b9C8IsKErQoiKqVhrerzt3kOT/RrzLHg==} '@chevrotain/types@11.1.2': resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} @@ -423,11 +410,45 @@ packages: peerDependencies: storybook: ^0.0.0-0 || ^10.1.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 || ^10.5.0-0 || ^10.6.0-0 - '@effect/platform-node-shared@4.0.0-beta.70': - resolution: {integrity: sha512-3VXuL63IDmq13We+ApRKn2JW3Rb9g5gj1YEmfb8u2b73norur1VsIJ/pRE4qjShevg19dQYi2JsLawSZ6gApug==} - engines: {node: '>=18.0.0'} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@csstools/color-helpers@6.1.0': + resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} peerDependencies: - effect: ^4.0.0-beta.70 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.9': + resolution: {integrity: sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.6': + resolution: {integrity: sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -444,312 +465,156 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.7': resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.7': resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.7': resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.7': resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.7': resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.7': resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.7': resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.7': resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.7': resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.7': resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.7': resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.7': resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.7': resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} @@ -795,6 +660,15 @@ packages: resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -832,9 +706,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@iarna/toml@2.2.5': - resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} - '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -866,6 +737,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@loaderkit/resolve@1.0.6': + resolution: {integrity: sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==} + '@mantine/code-highlight@8.3.18': resolution: {integrity: sha512-/KAxx+H9YfzKK8jv10XB/tJNV8IWCY3axbTmyij4VnLp1ivAInU7GLv9NzdXPHTx4JazIGxMwrrVANQD4QaQjA==} peerDependencies: @@ -892,41 +766,11 @@ packages: '@types/react': '>=16' react: '>=16' - '@mermaid-js/parser@1.1.1': - resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': - resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==} - cpu: [arm64] - os: [darwin] - - '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': - resolution: {integrity: sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==} - cpu: [x64] - os: [darwin] - - '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': - resolution: {integrity: sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==} - cpu: [arm64] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': - resolution: {integrity: sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==} - cpu: [arm] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': - resolution: {integrity: sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==} - cpu: [x64] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': - resolution: {integrity: sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==} - cpu: [x64] - os: [win32] - - '@napi-rs/wasm-runtime@1.1.5': - resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 @@ -934,292 +778,129 @@ packages: '@neoconfetti/react@1.0.0': resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@opentelemetry/api-logs@0.214.0': - resolution: {integrity: sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==} - engines: {node: '>=8.0.0'} - '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.8.0': - resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/instrumentation@0.214.0': - resolution: {integrity: sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/resources@2.8.0': - resolution: {integrity: sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/sdk-trace-base@2.8.0': - resolution: {integrity: sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/semantic-conventions@1.41.1': - resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} - engines: {node: '>=14'} - '@oxc-parser/binding-android-arm-eabi@0.127.0': resolution: {integrity: sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm-eabi@0.132.0': - resolution: {integrity: sha512-KrLaPWa5c9Y7LkW+rKkaUE3y7DBDrQtaf7rlsSDfv6KAHUjgzAIRA761Lrrp6//Yd/Rlie/yEOt9YENCoJnOcw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - '@oxc-parser/binding-android-arm64@0.127.0': resolution: {integrity: sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-android-arm64@0.132.0': - resolution: {integrity: sha512-SThDrSeamB/kG2+NxcJ5/wSLcV6dUqDknrPLqFYQ0ST/55mtBP4M7Q/f3QbubH6aAd11wpzZn/nwbVRSdobOpg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@oxc-parser/binding-darwin-arm64@0.127.0': resolution: {integrity: sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-arm64@0.132.0': - resolution: {integrity: sha512-Lc0f/TYoKBghE5/2Gsv7bLXk+TJZunx2Tf61X8hG4ARXdc8UYI26dCGccFSd1AyFbK3jfaNXtMnupggDbjPXdQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@oxc-parser/binding-darwin-x64@0.127.0': resolution: {integrity: sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.132.0': - resolution: {integrity: sha512-RG2eJIpf7C21z9HSSXFw1bTArdpKe7Y4fwcJTwRq1yCSe1vSavaN9GA1sm9KqzemTLAGVktQ+7qBTGp0vQeUZg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.127.0': resolution: {integrity: sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-freebsd-x64@0.132.0': - resolution: {integrity: sha512-wQIPntPLtJ8NcBpvKPbEv3NqzV6k8eP8tP/jE9Rg8HTg/j7urZGFSsTCPCW5k77Qfw2DM4vRvc9p3I4yq/Shvw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': resolution: {integrity: sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-gnueabihf@0.132.0': - resolution: {integrity: sha512-PixKEpeSe3yxQWqNyOCBALRYc72+Tj7ILDofUl3iXo25cVOzLA6jHUhmOINRtWIPh7dbUie3QNeabwaQpZTw6w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': resolution: {integrity: sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.132.0': - resolution: {integrity: sha512-sCR+DzGHlyHKnbA2z9zWjTUhIo8Sy0enJl4RDsBwPmkxYynPatpwOAWe8W5127SlW0boqUWHGtr1NWn5UwIhXQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.127.0': resolution: {integrity: sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.132.0': - resolution: {integrity: sha512-sQBix5P2cW+IpzTcCwYxnh9yALrKSIkKJThspBvMGcygSMnbzkSvhN7SfuX1hvBk8y1XEChsdkU3ET0V5DmzUw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - '@oxc-parser/binding-linux-arm64-musl@0.127.0': resolution: {integrity: sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxc-parser/binding-linux-arm64-musl@0.132.0': - resolution: {integrity: sha512-WozHg3Kc//8Sk756HXXgMbEAvqtG+Lzb9JOojwQzIGDtN78Az2dLttkb71akWYUF/8IgYfDSlfKh4Uot8is5Vw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': resolution: {integrity: sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - '@oxc-parser/binding-linux-ppc64-gnu@0.132.0': - resolution: {integrity: sha512-CmX/ulNBOEwWTyVRmcpYKAcAizW6+OjtLJgo7fXoL9OqQvjF4VER8tPomv44vwzfSCy1BHbsB0ZlZYzYJNj4cA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': resolution: {integrity: sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxc-parser/binding-linux-riscv64-gnu@0.132.0': - resolution: {integrity: sha512-j9oQS+hM90SdhviNGWbPgT4+Rlq+ac++q/zjgwPD1mVHgxHzATvoRGtDx0sXGmFOQ9J9YkwAhYGb5MAHL6TAsA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - '@oxc-parser/binding-linux-riscv64-musl@0.127.0': resolution: {integrity: sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxc-parser/binding-linux-riscv64-musl@0.132.0': - resolution: {integrity: sha512-bLz+Xi+Agnfmd7kWPEsSVwCn2k4EyIalZkNBcQ0OGIv9rqn8VgCPLNd03tM9mKX/5TdlvDXalz0q71BIrOPNqg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - '@oxc-parser/binding-linux-s390x-gnu@0.127.0': resolution: {integrity: sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - '@oxc-parser/binding-linux-s390x-gnu@0.132.0': - resolution: {integrity: sha512-U6t2qbJU0ypTfyj9QV3W1Y6mITDTL8ai/OR6NUn85vyHthOvobKWgXzU4tu0EskSzlpuVFz1g0jFGulDIUKHxQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - '@oxc-parser/binding-linux-x64-gnu@0.127.0': resolution: {integrity: sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxc-parser/binding-linux-x64-gnu@0.132.0': - resolution: {integrity: sha512-WcEaSNHFk8yz5YFlQQAlhq6jOFmZBB/RKE7uzhyCIf+pF1Lmv9gUH4221mle2Gd9iHyWT3ySNph8yZgb1xYdWg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - '@oxc-parser/binding-linux-x64-musl@0.127.0': resolution: {integrity: sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxc-parser/binding-linux-x64-musl@0.132.0': - resolution: {integrity: sha512-iQrV4iJzQgRwK3BWRmQl1C3C6g3wYpXN2WLdQdyR+efoUnncdShZAVp9OgcojtlD3MDRbuOMGG3SjxF4fL4nlQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - '@oxc-parser/binding-openharmony-arm64@0.127.0': resolution: {integrity: sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-openharmony-arm64@0.132.0': - resolution: {integrity: sha512-FWzmUGrZ6GUby4U7WIwcCtab6tdmlTO3xTRRKyb5kjIJVEiaUAT8animUG/nK8ZCA8gkRkPOTId4rl6uTqUmJQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@oxc-parser/binding-wasm32-wasi@0.127.0': resolution: {integrity: sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@oxc-parser/binding-wasm32-wasi@0.132.0': - resolution: {integrity: sha512-TlbMppxJI5CjWDes0QaP6G3aneVg1yikBu5QYI+DUShF9WDL66ccgKFNNGmi/Wybtszw6hxwAvv76T4DaPKnHw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - '@oxc-parser/binding-win32-arm64-msvc@0.127.0': resolution: {integrity: sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-arm64-msvc@0.132.0': - resolution: {integrity: sha512-RH/NbFjGKqdUAUi7Oh3LQPxUk2hsWFEEQ38HSnbRQT8QjBZFKqL1fMbmsB3N4jy/KPh9iX94+9dmkEMBBbambw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.127.0': resolution: {integrity: sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.132.0': - resolution: {integrity: sha512-JUr4jQY9jxoIB/YTLXr6XofSi5xikj6p5/Ns1h0VOBDT0j1jKU+kMsv2xxv51RwnETcXpA1Yw/9oUAfcqfaqEA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.127.0': resolution: {integrity: sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.132.0': - resolution: {integrity: sha512-2dapgHpA5X8DSXF4AU36hJWYf6zP0tKjMXFRAZFBD62pkevW/uhFDXoFH9Y/3Fd2EtDrw5ByNnR1wVE9X9y0SQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxc-project/runtime@0.115.0': resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1230,9 +911,6 @@ packages: '@oxc-project/types@0.127.0': resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} - '@oxc-project/types@0.132.0': - resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} - '@oxc-resolver/binding-android-arm-eabi@11.20.0': resolution: {integrity: sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg==} cpu: [arm] @@ -1328,120 +1006,6 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.69.0': - resolution: {integrity: sha512-DKQQbD5cZ/MYfDgDI7YGyGD9FSxABlsBsYFo5p26lloob543tP9+4N3guwdXIYJN+7HSZxLe8YJuwcOWw5qnHg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxlint/binding-android-arm64@1.69.0': - resolution: {integrity: sha512-lEhb+I5pr4inux+JFwfCa1HRq3Os7NirEFQ0H1I35SVEHPm6byX0Ah47xmRha3qi6LAkxUcxViL8o/9PivjzBg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxlint/binding-darwin-arm64@1.69.0': - resolution: {integrity: sha512-GY2YE8lOZW59BW1Ia1y+1gR0XyjrZRvVWHAr8LGeGhYHE0OQJ/7cRKXTkx1P+E9/6awEc3SX8a68SFTjh/E//A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxlint/binding-darwin-x64@1.69.0': - resolution: {integrity: sha512-ax1oZnOjHX3LB7myQyHEaQkDwfLb6str3/nSP6O7EVUviQGNkEGzGV0EqcBJWK+Ufwx0l4xPgyYayurvhAdl2Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxlint/binding-freebsd-x64@1.69.0': - resolution: {integrity: sha512-kHWeHv4g2h8NY+mpCxzCtY4uerMJWTN/TSnNj1CPbakFpHEJ6cTya2wWV0pDSYWOJ2+0UiEbhn3AtXxHtsnKjg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': - resolution: {integrity: sha512-gq84vM1a1oEehXo27YCDzGVcxPsZDI1yswZwz2Da1/cbnWtrL16XZZnz0G/+gIU8edtHpfjxq5c+vWEHqJfWoQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxlint/binding-linux-arm-musleabihf@1.69.0': - resolution: {integrity: sha512-kIqEa98JQ0VRyrcncxA417m2AzasqTlD+FyVT1AksjvjkqQcvm7pBWYvoW3/mpyOP2XYvi5nSCCTIe6De1yu5g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxlint/binding-linux-arm64-gnu@1.69.0': - resolution: {integrity: sha512-j+xYiXozxGWx2cpjCrwwGR4awTxPFsRv3JZrv23RCogEPMc4R7UqjHW47p/RG0aRlbWiROCJ8coUfCwy0dvzHA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxlint/binding-linux-arm64-musl@1.69.0': - resolution: {integrity: sha512-xEPpNppTfN1l/nM7gYSf9iocscu/as+p/7vxkLeLEKnYU+09Dm+5V6IhDYDh+Uz6FajEupWwCLt5SOG0y1PCKg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxlint/binding-linux-ppc64-gnu@1.69.0': - resolution: {integrity: sha512-Ug0+eU7HJBlek+SjklYH62IlOMirEJsdxpihH0kSqX0XdrDD4NdHpQc10fK1JC35yn6KrrcN+uYzlHD38XAf8Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - - '@oxlint/binding-linux-riscv64-gnu@1.69.0': - resolution: {integrity: sha512-iEyI3GIg0l/s3G4qy2TlaaWKdzj4PJJStwtlocpDTC00PY9hZueotf6OKUj9+yfQh0lrpBW/pLMgTztbAHKJEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxlint/binding-linux-riscv64-musl@1.69.0': - resolution: {integrity: sha512-NjHjpiI4WIKSMwuoJSZi5VToPeoYOS1FR52HLIDG6lidMdqquusgtODb4iLk0+lb1q3Z0nv2/aPRcC/olmpQGg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxlint/binding-linux-s390x-gnu@1.69.0': - resolution: {integrity: sha512-Ai/prDewoItkDXbp38gwGZi41DycZbUTZJ3UidwoHgQC0/DaqC2TGdtBTQLJ6hSD+SAxASzh8+/eSBPmxfOacA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - - '@oxlint/binding-linux-x64-gnu@1.69.0': - resolution: {integrity: sha512-Gt3KHgp46mRKz4sJeaASmKvD8ayXookRw07RMf+NowhEztGGDZ7VrXpoW96XuKJLjFukWizOFVNjmYb/u7caNQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxlint/binding-linux-x64-musl@1.69.0': - resolution: {integrity: sha512-7tQhJ2+p/oHv1zcfnjYI7YVzC/7iBaVOfIvFYtxdJ5F45mWgEdrCyXZXZGfiLey5t/5JhOhsaMnnv1kAzckd7g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxlint/binding-openharmony-arm64@1.69.0': - resolution: {integrity: sha512-vmWz6TKp/3hfA4lksR0zHBv/6xuX1jhym6eqOjdH2DXsDDHZWcp2f0KG0VCAnlVbIrjk29G4wAWMXb/Hn1YobA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxlint/binding-win32-arm64-msvc@1.69.0': - resolution: {integrity: sha512-9RExaLgmaw6IoIkU9cTpT71mLfI0xZ86iZH8x518LVsOkjquJMYqb9P7KpC8lgd1t0Dxs41p2pxynq4XR3Ttzw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxlint/binding-win32-ia32-msvc@1.69.0': - resolution: {integrity: sha512-1907kRPF8/PrcIw1E7LMs9JbVrpgnt/MvFdss3an8oDkYNAACXzTntV3t3869ZZhMZxb2AzRGbz1pA/jdFatXA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxlint/binding-win32-x64-msvc@1.69.0': - resolution: {integrity: sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@parcel/watcher-android-arm64@2.5.6': resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} @@ -1527,17 +1091,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@preact/signals-core@1.14.2': - resolution: {integrity: sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A==} - - '@preact/signals@2.9.1': - resolution: {integrity: sha512-xVqN8mJjbSN5IB/8Ubmd9NN+Ew6zJswoRxrjZbH3YsgkMshFeO6d8zxEFpHRTq9GJZx7cnPs2CnCpFqtGXGNsw==} - peerDependencies: - preact: '>= 10.25.0 || >=11.0.0-0' - - '@react-grab/cli@0.1.44': - resolution: {integrity: sha512-gMDYY2rw6OWajCcDlXSIgs2LC432YJXSb3Lm5yM187uhRgBYddoEVULi36h+IolX3r7jSb3ew7vn9FfI8NSo0A==} - hasBin: true + '@publint/pack@0.1.5': + resolution: {integrity: sha512-edgyN2pP07uXiP4tJs0s8KVmU8M8i60YPbbI0/WDeok1mIJHRXz+CgD8I0nelwDkoCh3EWL/G5kGfbuHjsdbvw==} + engines: {node: '>=18'} '@rolldown/binding-android-arm64@1.0.0-rc.8': resolution: {integrity: sha512-5bcmMQDWEfWUq3m79Mcf/kbO6e5Jr6YjKSsA1RnpXR6k73hQ9z1B17+4h93jXpzHvS18p7bQHM1HN/fSd+9zog==} @@ -1765,51 +1321,6 @@ packages: cpu: [x64] os: [win32] - '@sentry-internal/server-utils@10.57.0': - resolution: {integrity: sha512-Qu8ETmX/ITzteG7Im46b9HOxKKzeaIeqNvftaIlFURu1RUQdHbtGerS7QOmXzwnhuqNGNeiCQYkduB798IfRqA==} - engines: {node: '>=18'} - - '@sentry/core@10.57.0': - resolution: {integrity: sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg==} - engines: {node: '>=18'} - - '@sentry/node-core@10.57.0': - resolution: {integrity: sha512-2v2IF6MfTiu7pimWEq2rYhZsmlwyNbs3bHUsrYFPeP/Rpa6ObDuUWPdVEzJjfyK+AqqYZYxZdV0l3+B13kTEmQ==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' - '@opentelemetry/instrumentation': '>=0.57.1 <1' - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@opentelemetry/core': - optional: true - '@opentelemetry/exporter-trace-otlp-http': - optional: true - '@opentelemetry/instrumentation': - optional: true - '@opentelemetry/sdk-trace-base': - optional: true - '@opentelemetry/semantic-conventions': - optional: true - - '@sentry/node@10.57.0': - resolution: {integrity: sha512-7KEStrJ97wPf1fA5nU5ONeTTcIIlh7oT8OMffEVA1PXmlhFoXhcQZVzr4rM+zj9tfMWT01og5Ng/Grgh3dN+FA==} - engines: {node: '>=18'} - - '@sentry/opentelemetry@10.57.0': - resolution: {integrity: sha512-iwRz8cEK0GOISG34aJRO8GdYOk3nfpuT6dT2GDQrxw8f7JjkJKx9LPU8MaenOFa4MhY+Z02hI6NNcrbsoI3cXg==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1817,37 +1328,37 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-a11y@10.4.2': - resolution: {integrity: sha512-9Bm41peswHVPXm8iDBEA/sCXx+MUQV8Q10yFgNC2zTbtxKamMDb8HZCPIRDxvjBQ5v13eaXA2yZGTwQ+D8S6+g==} + '@storybook/addon-a11y@10.4.6': + resolution: {integrity: sha512-XCJy+f0DFOiCgUU9knRDlLDxVFI+AAQ3/wE/NF85zB9iDPPS2DwkSN+mas3zDgHt66zhN8Cq3/UiyCDUweV9Zw==} peerDependencies: - storybook: ^10.4.2 + storybook: ^10.4.6 - '@storybook/addon-docs@10.4.2': - resolution: {integrity: sha512-CtW1O4xSKZPNtpWgpfp4yB/x4pj/of+3MvlEDfErSlr3Hp3QmEa2pCLaecR08H5LJqJFlt1PtG0UrIynTvgW9w==} + '@storybook/addon-docs@10.4.6': + resolution: {integrity: sha512-aWAfP5JMiT5a3zBJizwroCRzOCqZwDTJmvsYvwMD3ilIEa/kT1vhf6Xrbk4XIPhDwbh8Hpb/Gfnka1xBYEISWg==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.2 + storybook: ^10.4.6 peerDependenciesMeta: '@types/react': optional: true - '@storybook/addon-onboarding@10.4.2': - resolution: {integrity: sha512-nDfdmstd+G3yScv/HBHkk1QCi19pCBZn+htPuPsVqJasaYQbszZqN+ikbkiwC3+bcDWh0eb8a0zHnaB2JPyq4w==} + '@storybook/addon-onboarding@10.4.6': + resolution: {integrity: sha512-BzTu5LW5Ygwv0BbmQM0QohGS5Uoa8GjSxPcZFCQ1iQfizUukKnd72UIsPDZBKjVytO0DbZ3YoM1Ww5+KL6ZXEg==} peerDependencies: - storybook: ^10.4.2 + storybook: ^10.4.6 - '@storybook/addon-themes@10.4.2': - resolution: {integrity: sha512-e5rP/RLujp06wmO75njxnfi3ndOBbgHIXceAsuN870BVh7D7iGx+8bwslIWy+FwRBYsCMCnWk+d25Zp4ai3p4w==} + '@storybook/addon-themes@10.4.6': + resolution: {integrity: sha512-80d622oB9xWZs3VH4uywkLOA5L2DAx04lVouvCM4XH+pLnJElidoylOLm3i3ByvlGkRjCbB27OUVsW94IgyDrw==} peerDependencies: - storybook: ^10.4.2 + storybook: ^10.4.6 - '@storybook/addon-vitest@10.4.2': - resolution: {integrity: sha512-gq1ZVr0IOLgiS2PzaJqHxKLczwrXvA5g3W2k/FVJA19fJNFNUut1IyQCQRSJTXLLXbnNaa8I0wjGGc2BoLarJg==} + '@storybook/addon-vitest@10.4.6': + resolution: {integrity: sha512-VvskHge0GZy86LG6kcY5Ww34z8rDV8JBxqSdUpcJVsWfIvyX6MfAbqI76LlereSyBIJGZJZsqaLwRXsQoVY+0Q==} peerDependencies: '@vitest/browser': ^3.0.0 || ^4.0.0 '@vitest/browser-playwright': ^4.0.0 '@vitest/runner': ^3.0.0 || ^4.0.0 - storybook: ^10.4.2 + storybook: ^10.4.6 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: '@vitest/browser': @@ -1859,18 +1370,18 @@ packages: vitest: optional: true - '@storybook/builder-vite@10.4.2': - resolution: {integrity: sha512-d3+i9vbbUfV6hvT90qabmy1WmC4bEJ7iAYDm0217doeA+S6awF25GF0qOy9gN9waU4NMntHoVpdB1YQO2wUj/w==} + '@storybook/builder-vite@10.4.6': + resolution: {integrity: sha512-BHBtD81HiXUiDQz/CaFynLtWmm7AFUQn8VnXuHipZ8KlnUANopa4yqdVuy/Gwz8ub254uFI5NMZsW/KlgWNgNg==} peerDependencies: - storybook: ^10.4.2 + storybook: ^10.4.6 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.4.2': - resolution: {integrity: sha512-GqX/2DeF3/jKs5D7gpDiuT9gd0c/f2TKcnQ5av4/s3YqeN+0nhm7btkCrDfgF16uzE1Zj3OrkxvB3AOkfxWgDg==} + '@storybook/csf-plugin@10.4.6': + resolution: {integrity: sha512-NILLxDqpA/JR/AazGWpsz+4fadJwRU4uhHephGtYpVOWnQA/DkJfKT6zpcJVq8+QA8A2zKMLX3GVKsXIrxjuDA==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.4.2 + storybook: ^10.4.6 vite: '*' webpack: '*' peerDependenciesMeta: @@ -1892,36 +1403,36 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@storybook/react-dom-shim@10.4.2': - resolution: {integrity: sha512-Eng3Yt2NCjPX94QcfyLeUFhrMj0hec2yU9J/qafBVbfj9XrFI8o+0ZwYJ7uXb9ECbvPN4y06dgt/2W/LiR417w==} + '@storybook/react-dom-shim@10.4.6': + resolution: {integrity: sha512-iGNmKzrq9vgl2PDrYAnZKI+yvac3Ym+lJXXuQaqlFRS23zA5MNm4EBX+rAG7WulqchoK6NaZ0KQOs2mAgEpTMg==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.2 + storybook: ^10.4.6 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true - '@storybook/react-vite@10.4.2': - resolution: {integrity: sha512-nGrS74p0ujPSQ7qD5jKLLlao2igfTTb6Kf/uRhVV8XM0uM7WvxR9K20ddCM8jFmx1jY9fRm0UBGaeaXHDIh5SA==} + '@storybook/react-vite@10.4.6': + resolution: {integrity: sha512-0arEQtybqGYXHbXpTot+Wv9YtG+V5Vp43QayXavPKQ20M8mpEzhyCPKd0EhqMGSC1Z1UEt0hm365WUBhI9LfKA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.2 + storybook: ^10.4.6 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.4.2': - resolution: {integrity: sha512-NfEH3CrdCAgUV4Z7SPN3Iw6nofcueqtRj8iHuo77GNjz0qSfuVi9iS7a8o7x7QFSeIBZwS0Jv3CgmhN8qvoLjg==} + '@storybook/react@10.4.6': + resolution: {integrity: sha512-9Y7YecrVFe1/01KYjfOLxVqTg2Aq+IO6TEv6sC2U0PfD0AWCSCmQ91QqgBpN/XW4aFFWoiZNinyXMUlU8zxy2w==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.2 + storybook: ^10.4.6 typescript: ^5.9.3 peerDependenciesMeta: '@types/react': @@ -1945,8 +1456,8 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -2136,9 +1647,6 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.58.2': resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2181,10 +1689,6 @@ packages: resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.61.0': - resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.2': resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2209,22 +1713,22 @@ packages: '@upsetjs/venn.js@2.0.0': resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} - '@vitest/browser-playwright@4.1.8': - resolution: {integrity: sha512-SR7FqgegaexEg73xvf3ArtygXegagMdXnL0EZMpxrWvvhQxvicD/E8p0ib0J91riPRtQUViyh67Xjw3NqvyhVg==} + '@vitest/browser-playwright@4.1.10': + resolution: {integrity: sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==} peerDependencies: playwright: '*' - vitest: 4.1.8 + vitest: 4.1.10 - '@vitest/browser@4.1.8': - resolution: {integrity: sha512-u21VzX07HzlJYpFgkxmjEXar/tG2UqWGgyGG/46SrrPc7rSdCTPw5vuowopO9CIqF8UCUQzDFdbVnNpw6N0BfQ==} + '@vitest/browser@4.1.10': + resolution: {integrity: sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==} peerDependencies: - vitest: 4.1.8 + vitest: 4.1.10 - '@vitest/coverage-v8@4.1.8': - resolution: {integrity: sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==} + '@vitest/coverage-v8@4.1.10': + resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} peerDependencies: - '@vitest/browser': 4.1.8 - vitest: 4.1.8 + '@vitest/browser': 4.1.10 + vitest: 4.1.10 peerDependenciesMeta: '@vitest/browser': optional: true @@ -2232,11 +1736,11 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.1.8': - resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.1.8': - resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2249,67 +1753,46 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.8': - resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.1.8': - resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.1.8': - resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.1.8': - resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.8': - resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@webcontainer/env@1.1.1': resolution: {integrity: sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==} - acorn-import-attributes@1.9.5: - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} - peerDependencies: - acorn: ^8 - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.17.0: resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true - agent-install@0.0.5: - resolution: {integrity: sha512-nHlms9BkP8ZiY79HrwCGiA2DcNaXrAaJrCM/BEqQ7MEsSKyCk+2A76xPGylIfASZSZE0SaU3T0bNSg4rBPIJAQ==} - hasBin: true - - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -2355,11 +1838,8 @@ packages: ast-v8-to-istanbul@1.0.4: resolution: {integrity: sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==} - atomically@2.1.1: - resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} - - autoprefixer@10.5.0: - resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} + autoprefixer@10.5.2: + resolution: {integrity: sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -2376,30 +1856,28 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.36: - resolution: {integrity: sha512-lVq/Df7LXlO79MVaaUHztSwWiG9oXoWHlgvNS51v8Dpd4+G4/VIy6qYePTw31nAVls33nUtnfezYeLkYAak9dg==} + baseline-browser-mapping@2.10.42: + resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==} engines: {node: '>=6.0.0'} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bippy@0.5.41: - resolution: {integrity: sha512-jCP2pXXLhXqPrAN+iSEFZmLI4uUM4fjSqajh0K+TmM062VehfDT3ZJNkrTGyN701Z5XMejs9qAudSqkMGhSMKg==} - peerDependencies: - react: '>=17.0.1' - - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + browserslist@4.28.4: + resolution: {integrity: sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2431,6 +1909,10 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -2482,16 +1964,20 @@ packages: '@chromatic-com/vitest': optional: true - cjs-module-lexer@2.2.0: - resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - cli-cursor@5.0.0: - resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} - engines: {node: '>=18'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true - cli-spinners@3.4.0: - resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} - engines: {node: '>=18.20'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -2514,9 +2000,9 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -2530,16 +2016,9 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - conf@15.1.0: - resolution: {integrity: sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==} - engines: {node: '>=20'} - confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.4: - resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -2557,6 +2036,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} @@ -2573,8 +2056,8 @@ packages: peerDependencies: cytoscape: ^3.2.0 - cytoscape@3.33.1: - resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + cytoscape@3.34.0: + resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==} engines: {node: '>=0.10'} d3-array@2.12.1: @@ -2719,13 +2202,13 @@ packages: dagre-d3-es@7.0.14: resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} - debounce-fn@6.0.0: - resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==} - engines: {node: '>=18'} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2735,6 +2218,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} @@ -2771,9 +2257,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - deslop-js@0.0.21: - resolution: {integrity: sha512-1fYusMl4tDaQ/xdHFtLfDe8kFrEeU0Vu0Pfiy2k/Gd4HSqYlQj1Z7iRqldNneRyuCzNMhwNBvhaL07Urbh5VOA==} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2794,18 +2277,11 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dompurify@3.4.5: - resolution: {integrity: sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==} - - dot-prop@10.1.0: - resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} - engines: {node: '>=20'} - - effect@4.0.0-beta.70: - resolution: {integrity: sha512-8AwGTRiNriirHGEYHrOS0E9fzdhIqCdZjiHP1YXmNo2UyPGS43ILsymsSHT7V0DJS+8dvlKq2RxnrDBUhDNZHg==} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} - electron-to-chromium@1.5.372: - resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} + electron-to-chromium@1.5.387: + resolution: {integrity: sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2824,9 +2300,13 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} @@ -2844,11 +2324,6 @@ packages: esbuild: '>=0.27.3' sass-embedded: ^1.97.3 - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -2878,12 +2353,6 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-hooks@7.1.1: - resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - eslint-scope@9.1.2: resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -2947,29 +2416,15 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - fast-check@4.8.0: - resolution: {integrity: sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==} - engines: {node: '>=12.17.0'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2979,6 +2434,9 @@ packages: picomatch: optional: true + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2987,9 +2445,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-my-way-ts@0.1.6: - resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3032,10 +2487,6 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} - engines: {node: '>=18'} - get-east-asian-width@1.6.0: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} @@ -3145,6 +2596,9 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} @@ -3152,6 +2606,10 @@ packages: html-comment-regex@1.1.2: resolution: {integrity: sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3173,12 +2631,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immutable@5.1.6: - resolution: {integrity: sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==} - - import-in-the-middle@3.0.2: - resolution: {integrity: sha512-LGLYRl0A2gtyUJb2WDliBHmk6TtlHwdDjxonacZ8QrEs/ZW+YDgNv2QAfjRQWpS8HqvNcq6GGnN6jrOa5FysDQ==} - engines: {node: '>=18'} + immutable@5.1.9: + resolution: {integrity: sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -3188,10 +2642,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - ini@7.0.0: - resolution: {integrity: sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==} - engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -3244,10 +2694,6 @@ packages: engines: {node: '>=14.16'} hasBin: true - is-interactive@2.0.0: - resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} - engines: {node: '>=12'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3256,9 +2702,8 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} - engines: {node: '>=18'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} @@ -3293,6 +2738,15 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3304,12 +2758,6 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -3318,37 +2766,19 @@ packages: engines: {node: '>=6'} hasBin: true - jsonc-parser@3.3.1: - resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} - jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - katex@0.16.44: - resolution: {integrity: sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==} - hasBin: true - katex@0.16.47: resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} hasBin: true - katex@0.17.0: - resolution: {integrity: sha512-Vdw0ATsQ9V+LuegM/BTwQqV/6cTl5lbGcIrU+BCgLxyf6bo38ybOr372tuSIxir3CN720flu1meYR6XzNMwQnw==} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - kubernetes-types@1.30.0: - resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} - layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} @@ -3447,10 +2877,6 @@ packages: lodash-es@4.18.1: resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} - log-symbols@7.0.1: - resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} - engines: {node: '>=18'} - longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -3481,11 +2907,22 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked-terminal@7.3.0: + resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <16' + marked@16.4.2: resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} engines: {node: '>= 20'} hasBin: true + marked@9.1.6: + resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} + engines: {node: '>= 16'} + hasBin: true + mdast-squeeze-paragraphs@6.0.0: resolution: {integrity: sha512-6NDbJPTg0M0Ye+TlYwX1KJ1LFbp515P2immRJyJQhc9Na9cetHzSoHNYIQcXpANEAP1sm9yd/CTZU2uHqR5A+w==} @@ -3537,6 +2974,24 @@ packages: mdast-util-to-hast@13.2.1: resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + mdast-util-to-markdown-cjk-friendly-gfm-strikethrough@1.0.0: + resolution: {integrity: sha512-1ePVfB4P/vz3xSsm6H3D32r6VYGErxclnuLLFK02/2ReF+UdEKm7caulK6Vm0LBIp5gPRtB2Z1OYDznCkX3k2w==} + engines: {node: '>=18'} + peerDependencies: + '@types/mdast': '*' + peerDependenciesMeta: + '@types/mdast': + optional: true + + mdast-util-to-markdown-cjk-friendly@1.0.0: + resolution: {integrity: sha512-BoaAm8mlJ+LAYz0Qs532Y3ciTuQYgBUPZcSFbvC/ZKmEMAKgulw84YvQK1gI34t/vL2euSfuaWlqczkTBgamkw==} + engines: {node: '>=18'} + peerDependencies: + '@types/mdast': '*' + peerDependenciesMeta: + '@types/mdast': + optional: true + mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} @@ -3546,12 +3001,11 @@ packages: mdast-util-toc@7.1.0: resolution: {integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - mermaid@11.15.0: - resolution: {integrity: sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==} + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -3672,14 +3126,6 @@ packages: micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mimic-function@5.0.1: - resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} - engines: {node: '>=18'} - min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -3695,14 +3141,12 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - mlly@1.8.1: - resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} - mlly@1.8.2: resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} - module-details-from-path@1.0.4: - resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} @@ -3711,16 +3155,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msgpackr-extract@3.0.4: - resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==} - hasBin: true - - msgpackr@2.0.4: - resolution: {integrity: sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA==} - - multipasta@0.2.7: - resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} - mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -3742,12 +3176,8 @@ packages: resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} engines: {node: '>=18'} - node-gyp-build-optional-packages@5.2.2: - resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} - hasBin: true - - node-releases@2.0.47: - resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + node-releases@2.0.50: + resolution: {integrity: sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==} engines: {node: '>=18'} normalize-path@3.0.0: @@ -3762,10 +3192,6 @@ packages: resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} engines: {node: '>=12.20.0'} - onetime@7.0.0: - resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} - engines: {node: '>=18'} - open@10.2.0: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} @@ -3774,38 +3200,13 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - ora@9.4.0: - resolution: {integrity: sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==} - engines: {node: '>=20'} - oxc-parser@0.127.0: resolution: {integrity: sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==} engines: {node: ^20.19.0 || >=22.12.0} - oxc-parser@0.132.0: - resolution: {integrity: sha512-+0LAPHaqtfQlvWdpaAa09SmOaZZgP8C552xosEkGJ4+ruEwP1Vgx+sqBgcBCNfR6KDCmagGOZTde8wmAvcI/Hg==} - engines: {node: ^20.19.0 || >=22.12.0} - oxc-resolver@11.20.0: resolution: {integrity: sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g==} - oxlint-plugin-react-doctor@0.5.1: - resolution: {integrity: sha512-gGx0NCPA7s8z8UYCulfhX4CiXwBI4QdQve7zaVXglakWzzdgcXMZv6pedmbKUtefegzlfzkKDcYO4lOg8vqnJw==} - engines: {node: ^20.19.0 || >=22.12.0} - - oxlint@1.69.0: - resolution: {integrity: sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - oxlint-tsgolint: '>=0.22.1' - vite-plus: '*' - peerDependenciesMeta: - oxlint-tsgolint: - optional: true - vite-plus: - optional: true - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -3827,9 +3228,21 @@ packages: parse-latin@7.0.0: resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + path-data-parser@0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} @@ -3858,8 +3271,8 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} pify@2.3.0: @@ -3873,13 +3286,13 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - playwright-core@1.60.0: - resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + playwright-core@1.61.1: + resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==} engines: {node: '>=18'} hasBin: true - playwright@1.60.0: - resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + playwright@1.61.1: + resolution: {integrity: sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==} engines: {node: '>=18'} hasBin: true @@ -3942,19 +3355,16 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} engines: {node: ^10 || ^12 || >=14} - preact@10.29.2: - resolution: {integrity: sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==} - prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + prettier@3.9.4: + resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} engines: {node: '>=14'} hasBin: true @@ -3966,23 +3376,18 @@ packages: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + publint@0.3.21: + resolution: {integrity: sha512-OqejcnMV6E9zel2oCrUOJEiiFkGiAAni0A6ibfQNh1k9Gu5z4F+Yso8lllam7AzmV6Do0vp7u3UpZNRBwuXaHQ==} + engines: {node: '>=18'} + hasBin: true + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@8.4.0: - resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - react-docgen-typescript@2.4.0: resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} peerDependencies: @@ -3992,25 +3397,11 @@ packages: resolution: {integrity: sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==} engines: {node: ^20.9.0 || >=22} - react-doctor@0.5.1: - resolution: {integrity: sha512-2LSJ/iYtUugr9xj01XTyU2tRtfjmGjiwyDotrnxL0raP+q4Uhp10VaiY7BqfDhBpj4HtCsC+//G1xVupTTBDoA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - react-dom@19.2.7: resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: react: ^19.2.7 - react-grab@0.1.44: - resolution: {integrity: sha512-bDEwBdI90ljq2lhUtPqmWis/HwYB/CvfT0m5i+P9F83Pt0Ot8o9XL8v00s9jcWzdQUlsFDzmq2FO2CHUe8JY8A==} - hasBin: true - peerDependencies: - react: '>=17.0.0' - peerDependenciesMeta: - react: - optional: true - react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -4040,17 +3431,6 @@ packages: '@types/react': optional: true - react-scan@0.5.7: - resolution: {integrity: sha512-KRlq734yN6q/f2CZmZi9CWHuiqSzoLhPFLtcJOL6XM4lR54myyFcY81pG9QOwj+eBC1hIHm5n+Ntbtqiilu8Rg==} - hasBin: true - peerDependencies: - esbuild: '>=0.18.0' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - esbuild: - optional: true - react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -4112,8 +3492,8 @@ packages: remark-breaks@4.0.0: resolution: {integrity: sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==} - remark-cjk-friendly-gfm-strikethrough@2.0.1: - resolution: {integrity: sha512-pWKj25O2eLXIL1aBupayl1fKhco+Brw8qWUWJPVB9EBzbQNd7nGLj0nLmJpggWsGLR5j5y40PIdjxby9IEYTuA==} + remark-cjk-friendly-gfm-strikethrough@2.3.1: + resolution: {integrity: sha512-JE3TGgouk/sy92SemNMEUhO5mNP4on04cmzOV3s3R5Dbk160ewmpM4tgPiinKKvoJ5UW2fTu7FOYsjVbusSA9w==} engines: {node: '>=18'} peerDependencies: '@types/mdast': ^4.0.0 @@ -4122,8 +3502,8 @@ packages: '@types/mdast': optional: true - remark-cjk-friendly@2.0.1: - resolution: {integrity: sha512-6WwkoQyZf/4j5k53zdFYrR8Ca+UVn992jXdLUSBDZR4eBpFhKyVxmA4gUHra/5fesjGIxrDhHesNr/sVoiiysA==} + remark-cjk-friendly@2.3.1: + resolution: {integrity: sha512-f+pKZRxCRwNEGFBKNRAZAqU91GIK1SAo3ZyFHWRUgC9zcxRR0BXKd6YwqgSsxtW0rNpUDtONj7H5nje2WL3fcA==} engines: {node: '>=18'} peerDependencies: '@types/mdast': ^4.0.0 @@ -4182,28 +3562,15 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-in-the-middle@8.0.1: - resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} - engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - resolve@1.22.12: resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true - restore-cursor@5.1.0: - resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} - engines: {node: '>=18'} - retext-latin@4.0.0: resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} @@ -4216,10 +3583,6 @@ packages: retext@9.0.0: resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} @@ -4240,15 +3603,16 @@ packages: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -4361,11 +3725,6 @@ packages: engines: {node: '>=16.0.0'} hasBin: true - sass@1.100.0: - resolution: {integrity: sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==} - engines: {node: '>=20.19.0'} - hasBin: true - sass@1.101.0: resolution: {integrity: sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==} engines: {node: '>=20.19.0'} @@ -4376,6 +3735,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -4399,17 +3762,10 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - skin-tone@2.0.0: resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} engines: {node: '>=8'} @@ -4439,12 +3795,8 @@ packages: std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - stdin-discarder@0.3.2: - resolution: {integrity: sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==} - engines: {node: '>=18'} - - storybook@10.4.2: - resolution: {integrity: sha512-5Ax5vbHxFgMBGGhQDm75Rrumm/HZC4ICFhMcJaM0UlqnC/4FKj/IaZtImZFupknyiiyUEcWHPQFA2kX3/VSv1A==} + storybook@10.4.6: + resolution: {integrity: sha512-6wkA6LxfDSSilloITsrFOJfsnw0mDUP2h8Ls+lRt8oRsudtz2RWFhLv+Toiwg6NW7hUpdTDc2hzR7DztJid6+A==} hasBin: true peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4462,10 +3814,6 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@8.2.1: - resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} - engines: {node: '>=20'} - stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} @@ -4489,12 +3837,6 @@ packages: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} - stubborn-fs@2.0.0: - resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} - - stubborn-utils@1.0.2: - resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} - style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -4517,10 +3859,17 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + sync-child-process@1.0.2: resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} engines: {node: '>=16.0.0'} @@ -4532,10 +3881,6 @@ packages: tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} - thenby@1.3.4: resolution: {integrity: sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==} @@ -4559,10 +3904,6 @@ packages: resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -4579,18 +3920,29 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tldts-core@7.4.6: + resolution: {integrity: sha512-TkQNGJIhlEphpHCjKodMTSe23egUZr/g+flI2qkLgiJ/maAzSgXypSLRTNH3nCmqgayEmtcJBiLcfODSAr1xoA==} + + tldts@7.4.6: + resolution: {integrity: sha512-rbP0Gyx8b3Ae9yO//CU2wbSnQNoQ66m1nJdSbSHmnwKwzkkz/u8mERYU8T2rmlmy+bJvRNn84yNCW8gYqox44Q==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toml@4.1.1: - resolution: {integrity: sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==} - engines: {node: '>=20'} - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4610,10 +3962,6 @@ packages: peerDependencies: typescript: ^5.9.3 - ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - ts-dedent@2.3.0: resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} engines: {node: '>=6.10'} @@ -4655,10 +4003,6 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - type-fest@5.7.0: - resolution: {integrity: sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==} - engines: {node: '>=20'} - typescript-eslint@8.58.2: resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4674,13 +4018,13 @@ packages: ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - uint8array-extras@1.5.0: - resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} - engines: {node: '>=18'} - undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} + engines: {node: '>=20.18.1'} + unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} engines: {node: '>=4'} @@ -4735,10 +4079,6 @@ packages: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} - unplugin@3.0.0: - resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} - engines: {node: ^20.19.0 || >=22.12.0} - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -4804,6 +4144,10 @@ packages: resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + varint@6.0.0: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} @@ -4859,20 +4203,20 @@ packages: yaml: optional: true - vitest@4.1.8: - resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.8 - '@vitest/browser-preview': 4.1.8 - '@vitest/browser-webdriverio': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 - '@vitest/coverage-v8': 4.1.8 - '@vitest/ui': 4.1.8 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -4900,34 +4244,27 @@ packages: jsdom: optional: true - vscode-jsonrpc@8.2.0: - resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} - engines: {node: '>=14.0.0'} - - vscode-languageserver-protocol@3.17.5: - resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} - - vscode-languageserver-textdocument@1.0.12: - resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} - - vscode-languageserver-types@3.17.5: - resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - - vscode-languageserver@9.0.1: - resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} - hasBin: true - - vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - when-exit@2.1.5: - resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -4963,6 +4300,13 @@ packages: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -4970,20 +4314,23 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} - engines: {node: '>= 14.6'} - hasBin: true - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@16.2.2: + resolution: {integrity: sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -4992,10 +4339,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoctocolors@2.1.2: - resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} - engines: {node: '>=18'} - zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -5005,9 +4348,6 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5015,16 +4355,53 @@ snapshots: '@adobe/css-tools@4.5.0': {} + '@andrewbranch/untar.js@1.0.3': {} + '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 tinyexec: 1.2.4 - '@babel/code-frame@7.29.0': + '@arethetypeswrong/cli@0.18.4': dependencies: - '@babel/helper-validator-identifier': 7.29.7 - js-tokens: 4.0.0 - picocolors: 1.1.1 + '@arethetypeswrong/core': 0.18.4 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.3.0(marked@9.1.6) + semver: 7.8.4 + + '@arethetypeswrong/core@0.18.4': + dependencies: + '@andrewbranch/untar.js': 1.0.3 + '@loaderkit/resolve': 1.0.6 + cjs-module-lexer: 1.4.3 + fflate: 0.8.3 + lru-cache: 11.5.1 + semver: 7.8.4 + typescript: 5.9.3 + validate-npm-package-name: 5.0.1 + + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} '@babel/code-frame@7.29.7': dependencies: @@ -5032,30 +4409,8 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} - '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.7 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/core@7.29.7': dependencies: '@babel/code-frame': 7.29.7 @@ -5076,14 +4431,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.7 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - '@babel/generator@7.29.7': dependencies: '@babel/parser': 7.29.7 @@ -5092,33 +4439,16 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - '@babel/helper-compilation-targets@7.29.7': dependencies: '@babel/compat-data': 7.29.7 '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.2 + browserslist: 4.28.4 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} - '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-imports@7.29.7': dependencies: '@babel/traverse': 7.29.7 @@ -5126,15 +4456,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 @@ -5148,56 +4469,25 @@ snapshots: '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} - '@babel/helper-validator-option@7.29.7': {} - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.7 - '@babel/helpers@7.29.7': dependencies: '@babel/template': 7.29.7 '@babel/types': 7.29.7 - '@babel/parser@7.29.2': - dependencies: - '@babel/types': 7.29.7 - '@babel/parser@7.29.7': dependencies: '@babel/types': 7.29.7 - '@babel/runtime@7.29.2': {} - '@babel/runtime@7.29.7': {} - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.7 - '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.7 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - '@babel/traverse@7.29.7': dependencies: '@babel/code-frame': 7.29.7 @@ -5219,32 +4509,56 @@ snapshots: '@blazediff/core@1.9.1': {} + '@braidai/lang@1.1.2': {} + '@braintree/sanitize-url@7.1.2': {} - '@bufbuild/protobuf@2.12.0': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + + '@bufbuild/protobuf@2.12.1': {} '@chevrotain/types@11.1.2': {} - '@chromatic-com/storybook@5.2.1(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@chromatic-com/storybook@5.2.1(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': dependencies: '@neoconfetti/react': 1.0.0 chromatic: 16.10.0 jsonfile: 6.2.1 - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) strip-ansi: 7.2.0 transitivePeerDependencies: - '@chromatic-com/cypress' - '@chromatic-com/playwright' - '@chromatic-com/vitest' - '@effect/platform-node-shared@4.0.0-beta.70(effect@4.0.0-beta.70)': + '@colors/colors@1.5.0': + optional: true + + '@csstools/color-helpers@6.1.0': {} + + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@types/ws': 8.18.1 - effect: 4.0.0-beta.70 - ws: 8.21.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.1.0 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.6(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} '@emnapi/core@1.10.0': dependencies: @@ -5273,159 +4587,81 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.3': - optional: true - '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/android-arm64@0.27.3': - optional: true - '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm@0.27.3': - optional: true - '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-x64@0.27.3': - optional: true - '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.27.3': - optional: true - '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-x64@0.27.3': - optional: true - '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.27.3': - optional: true - '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.27.3': - optional: true - - '@esbuild/freebsd-x64@0.27.7': - optional: true - - '@esbuild/linux-arm64@0.27.3': - optional: true - - '@esbuild/linux-arm64@0.27.7': - optional: true - - '@esbuild/linux-arm@0.27.3': + '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/linux-arm@0.27.7': + '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-loong64@0.27.3': - optional: true - '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-mips64el@0.27.3': - optional: true - '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-ppc64@0.27.3': - optional: true - '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.27.3': - optional: true - '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-s390x@0.27.3': - optional: true - '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-x64@0.27.3': - optional: true - '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.27.3': - optional: true - '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.27.3': - optional: true - '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.27.3': - optional: true - '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.27.3': - optional: true - '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.27.3': - optional: true - '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/sunos-x64@0.27.3': - optional: true - '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/win32-arm64@0.27.3': - optional: true - '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-ia32@0.27.3': - optional: true - '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-x64@0.27.3': - optional: true - '@esbuild/win32-x64@0.27.7': optional: true @@ -5463,6 +4699,8 @@ snapshots: '@eslint/core': 1.1.1 levn: 0.4.1 + '@exodus/bytes@1.15.1': {} + '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -5499,8 +4737,6 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@iarna/toml@2.2.5': {} - '@iconify/types@2.0.0': {} '@iconify/utils@3.1.0': @@ -5509,11 +4745,11 @@ snapshots: '@iconify/types': 2.0.0 mlly: 1.8.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) optionalDependencies: typescript: 5.9.3 @@ -5536,6 +4772,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@loaderkit/resolve@1.0.6': + dependencies: + '@braidai/lang': 1.1.2 + '@mantine/code-highlight@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.17(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@8.3.17(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@mantine/core': 8.3.18(@mantine/hooks@8.3.17(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -5568,227 +4808,99 @@ snapshots: '@types/react': 19.2.17 react: 19.2.7 - '@mermaid-js/parser@1.1.1': + '@mermaid-js/parser@1.2.0': dependencies: '@chevrotain/types': 11.1.2 - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': - optional: true - - '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': - optional: true - - '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': - optional: true - - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 + '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.2 + '@tybys/wasm-util': 0.10.3 optional: true '@neoconfetti/react@1.0.0': {} - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@opentelemetry/api-logs@0.214.0': - dependencies: - '@opentelemetry/api': 1.9.1 - - '@opentelemetry/api@1.9.1': {} - - '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.41.1 - - '@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - import-in-the-middle: 3.0.2 - require-in-the-middle: 8.0.1 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 - - '@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 - - '@opentelemetry/semantic-conventions@1.41.1': {} - - '@oxc-parser/binding-android-arm-eabi@0.127.0': + '@opentelemetry/api@1.9.1': optional: true - '@oxc-parser/binding-android-arm-eabi@0.132.0': + '@oxc-parser/binding-android-arm-eabi@0.127.0': optional: true '@oxc-parser/binding-android-arm64@0.127.0': optional: true - '@oxc-parser/binding-android-arm64@0.132.0': - optional: true - '@oxc-parser/binding-darwin-arm64@0.127.0': optional: true - '@oxc-parser/binding-darwin-arm64@0.132.0': - optional: true - '@oxc-parser/binding-darwin-x64@0.127.0': optional: true - '@oxc-parser/binding-darwin-x64@0.132.0': - optional: true - '@oxc-parser/binding-freebsd-x64@0.127.0': optional: true - '@oxc-parser/binding-freebsd-x64@0.132.0': - optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.132.0': - optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.132.0': - optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.127.0': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.132.0': - optional: true - '@oxc-parser/binding-linux-arm64-musl@0.127.0': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.132.0': - optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.132.0': - optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.132.0': - optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.127.0': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.132.0': - optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.127.0': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.132.0': - optional: true - '@oxc-parser/binding-linux-x64-gnu@0.127.0': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.132.0': - optional: true - '@oxc-parser/binding-linux-x64-musl@0.127.0': optional: true - '@oxc-parser/binding-linux-x64-musl@0.132.0': - optional: true - '@oxc-parser/binding-openharmony-arm64@0.127.0': optional: true - '@oxc-parser/binding-openharmony-arm64@0.132.0': - optional: true - '@oxc-parser/binding-wasm32-wasi@0.127.0': dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) - optional: true - - '@oxc-parser/binding-wasm32-wasi@0.132.0': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) optional: true '@oxc-parser/binding-win32-arm64-msvc@0.127.0': optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.132.0': - optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.127.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.132.0': - optional: true - '@oxc-parser/binding-win32-x64-msvc@0.127.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.132.0': - optional: true - '@oxc-project/runtime@0.115.0': {} '@oxc-project/types@0.115.0': {} '@oxc-project/types@0.127.0': {} - '@oxc-project/types@0.132.0': {} - '@oxc-resolver/binding-android-arm-eabi@11.20.0': optional: true @@ -5841,7 +4953,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@oxc-resolver/binding-win32-arm64-msvc@11.20.0': @@ -5850,63 +4962,6 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.20.0': optional: true - '@oxlint/binding-android-arm-eabi@1.69.0': - optional: true - - '@oxlint/binding-android-arm64@1.69.0': - optional: true - - '@oxlint/binding-darwin-arm64@1.69.0': - optional: true - - '@oxlint/binding-darwin-x64@1.69.0': - optional: true - - '@oxlint/binding-freebsd-x64@1.69.0': - optional: true - - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': - optional: true - - '@oxlint/binding-linux-arm-musleabihf@1.69.0': - optional: true - - '@oxlint/binding-linux-arm64-gnu@1.69.0': - optional: true - - '@oxlint/binding-linux-arm64-musl@1.69.0': - optional: true - - '@oxlint/binding-linux-ppc64-gnu@1.69.0': - optional: true - - '@oxlint/binding-linux-riscv64-gnu@1.69.0': - optional: true - - '@oxlint/binding-linux-riscv64-musl@1.69.0': - optional: true - - '@oxlint/binding-linux-s390x-gnu@1.69.0': - optional: true - - '@oxlint/binding-linux-x64-gnu@1.69.0': - optional: true - - '@oxlint/binding-linux-x64-musl@1.69.0': - optional: true - - '@oxlint/binding-openharmony-arm64@1.69.0': - optional: true - - '@oxlint/binding-win32-arm64-msvc@1.69.0': - optional: true - - '@oxlint/binding-win32-ia32-msvc@1.69.0': - optional: true - - '@oxlint/binding-win32-x64-msvc@1.69.0': - optional: true - '@parcel/watcher-android-arm64@2.5.6': optional: true @@ -5951,7 +5006,7 @@ snapshots: detect-libc: 2.1.2 is-glob: 4.0.3 node-addon-api: 7.1.1 - picomatch: 4.0.4 + picomatch: 4.0.5 optionalDependencies: '@parcel/watcher-android-arm64': 2.5.6 '@parcel/watcher-darwin-arm64': 2.5.6 @@ -5970,22 +5025,8 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@preact/signals-core@1.14.2': {} - - '@preact/signals@2.9.1(preact@10.29.2)': - dependencies: - '@preact/signals-core': 1.14.2 - preact: 10.29.2 - - '@react-grab/cli@0.1.44': + '@publint/pack@0.1.5': dependencies: - agent-install: 0.0.5 - commander: 14.0.3 - ignore: 7.0.5 - ora: 9.4.0 - package-manager-detector: 1.6.0 - picocolors: 1.1.1 - prompts: 2.4.2 tinyexec: 1.2.4 '@rolldown/binding-android-arm64@1.0.0-rc.8': @@ -6026,7 +5067,7 @@ snapshots: '@rolldown/binding-wasm32-wasi@1.0.0-rc.8(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -6044,7 +5085,7 @@ snapshots: dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.4 + picomatch: 4.0.5 optionalDependencies: rollup: 4.59.0 @@ -6123,67 +5164,25 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true - '@sentry-internal/server-utils@10.57.0': - dependencies: - '@sentry/core': 10.57.0 - - '@sentry/core@10.57.0': {} - - '@sentry/node-core@10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1)': - dependencies: - '@sentry/core': 10.57.0 - '@sentry/opentelemetry': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) - import-in-the-middle: 3.0.2 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 - - '@sentry/node@10.57.0': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 - '@sentry-internal/server-utils': 10.57.0 - '@sentry/core': 10.57.0 - '@sentry/node-core': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) - '@sentry/opentelemetry': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) - import-in-the-middle: 3.0.2 - transitivePeerDependencies: - - '@opentelemetry/exporter-trace-otlp-http' - - supports-color - - '@sentry/opentelemetry@10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 - '@sentry/core': 10.57.0 - '@sindresorhus/is@4.6.0': {} '@standard-schema/spec@1.1.0': {} - '@storybook/addon-a11y@10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@storybook/addon-a11y@10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.12.1 - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@storybook/addon-docs@10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@storybook/addon-docs@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) - '@storybook/csf-plugin': 10.4.2(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@storybook/react-dom-shim': 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + '@storybook/react-dom-shim': 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ts-dedent: 2.3.0 optionalDependencies: '@types/react': 19.2.17 @@ -6194,48 +5193,48 @@ snapshots: - vite - webpack - '@storybook/addon-onboarding@10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@storybook/addon-onboarding@10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': dependencies: - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@storybook/addon-themes@10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@storybook/addon-themes@10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': dependencies: - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ts-dedent: 2.3.0 - '@storybook/addon-vitest@10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8)(@vitest/runner@4.1.8)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.8)': + '@storybook/addon-vitest@10.4.6(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10)(@vitest/runner@4.1.10)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.10)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) optionalDependencies: - '@vitest/browser': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) - '@vitest/browser-playwright': 4.1.8(playwright@1.60.0)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) - '@vitest/runner': 4.1.8 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/runner': 4.1.10 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) transitivePeerDependencies: - react - react-dom - '@storybook/builder-vite@10.4.2(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@storybook/builder-vite@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - '@storybook/csf-plugin': 10.4.2(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ts-dedent: 2.3.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.4.2(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@storybook/csf-plugin@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.7 rollup: 4.59.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) '@storybook/global@5.0.0': {} @@ -6244,30 +5243,30 @@ snapshots: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@storybook/react-dom-shim@10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': + '@storybook/react-dom-shim@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))': dependencies: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@storybook/react-vite@10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@storybook/react-vite@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@rollup/pluginutils': 5.4.0(rollup@4.59.0) - '@storybook/builder-vite': 10.4.2(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) - '@storybook/react': 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3) + '@storybook/builder-vite': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@storybook/react': 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3) empathic: 2.0.1 magic-string: 0.30.21 react: 19.2.7 react-docgen: 8.0.3 react-dom: 19.2.7(react@19.2.7) resolve: 1.22.12 - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tsconfig-paths: 4.2.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -6277,15 +5276,15 @@ snapshots: - typescript - webpack - '@storybook/react@10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)': + '@storybook/react@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + '@storybook/react-dom-shim': 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) react: 19.2.7 react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@5.9.3) react-dom: 19.2.7(react@19.2.7) - storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) @@ -6317,7 +5316,7 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 - '@tybys/wasm-util@0.10.2': + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true @@ -6479,7 +5478,7 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree@1.0.8': {} @@ -6536,10 +5535,6 @@ snapshots: '@types/unist@3.0.3': {} - '@types/ws@8.18.1': - dependencies: - '@types/node': 25.9.3 - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -6600,8 +5595,6 @@ snapshots: '@typescript-eslint/types@8.58.2': {} - '@typescript-eslint/types@8.61.0': {} - '@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.58.2(typescript@5.9.3) @@ -6640,29 +5633,29 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - '@vitest/browser-playwright@4.1.8(playwright@1.60.0)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8)': + '@vitest/browser-playwright@4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) - '@vitest/mocker': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) - playwright: 1.60.0 + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + playwright: 1.61.1 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8)': + '@vitest/browser@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) - '@vitest/utils': 4.1.8 + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) ws: 8.21.0 transitivePeerDependencies: - bufferutil @@ -6670,10 +5663,10 @@ snapshots: - utf-8-validate - vite - '@vitest/coverage-v8@4.1.8(@vitest/browser@4.1.8)(vitest@4.1.8)': + '@vitest/coverage-v8@4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.10 ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -6682,9 +5675,9 @@ snapshots: obug: 2.1.2 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/expect@3.2.4': dependencies: @@ -6694,40 +5687,40 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.1.8': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.8 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.8': + '@vitest/pretty-format@4.1.10': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.8': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.1.8': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 @@ -6735,7 +5728,7 @@ snapshots: dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.1.8': {} + '@vitest/spy@4.1.10': {} '@vitest/utils@3.2.4': dependencies: @@ -6743,39 +5736,20 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.8': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.8 + '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 '@webcontainer/env@1.1.1': {} - acorn-import-attributes@1.9.5(acorn@8.17.0): + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: acorn: 8.17.0 - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - acorn@8.17.0: {} - agent-install@0.0.5: - dependencies: - '@iarna/toml': 2.2.5 - commander: 14.0.3 - jsonc-parser: 3.3.1 - picocolors: 1.1.1 - prompts: 2.4.2 - yaml: 2.9.0 - - ajv-formats@3.0.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -6783,12 +5757,9 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.20.0: + ansi-escapes@7.3.0: dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 + environment: 1.1.0 ansi-regex@5.0.1: {} @@ -6805,7 +5776,7 @@ snapshots: anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 4.0.4 + picomatch: 4.0.5 aria-query@5.3.0: dependencies: @@ -6827,18 +5798,13 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 - atomically@2.1.1: - dependencies: - stubborn-fs: 2.0.0 - when-exit: 2.1.5 - - autoprefixer@10.5.0(postcss@8.5.15): + autoprefixer@10.5.2(postcss@8.5.16): dependencies: - browserslist: 4.28.2 + browserslist: 4.28.4 caniuse-lite: 1.0.30001799 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.15 + postcss: 8.5.16 postcss-value-parser: 4.2.0 axe-core@4.12.1: {} @@ -6847,15 +5813,15 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.36: {} - - binary-extensions@2.3.0: {} + baseline-browser-mapping@2.10.42: {} - bippy@0.5.41(react@19.2.7): + bidi-js@1.0.3: dependencies: - react: 19.2.7 + require-from-string: 2.0.2 + + binary-extensions@2.3.0: {} - brace-expansion@5.0.5: + brace-expansion@5.0.7: dependencies: balanced-match: 4.0.4 @@ -6863,21 +5829,21 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.2: + browserslist@4.28.4: dependencies: - baseline-browser-mapping: 2.10.36 + baseline-browser-mapping: 2.10.42 caniuse-lite: 1.0.30001799 - electron-to-chromium: 1.5.372 - node-releases: 2.0.47 - update-browserslist-db: 1.2.3(browserslist@4.28.2) + electron-to-chromium: 1.5.387 + node-releases: 2.0.50 + update-browserslist-db: 1.2.3(browserslist@4.28.4) bundle-name@4.1.0: dependencies: run-applescript: 7.1.0 - bundle-require@5.1.0(esbuild@0.27.3): + bundle-require@5.1.0(esbuild@0.27.7): dependencies: - esbuild: 0.27.3 + esbuild: 0.27.7 load-tsconfig: 0.2.5 cac@6.7.14: {} @@ -6896,6 +5862,11 @@ snapshots: chai@6.2.2: {} + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@5.6.2: {} char-regex@1.0.2: {} @@ -6934,13 +5905,28 @@ snapshots: dependencies: semver: 7.8.4 - cjs-module-lexer@2.2.0: {} + cjs-module-lexer@1.4.3: {} - cli-cursor@5.0.0: + cli-highlight@2.1.11: dependencies: - restore-cursor: 5.1.0 + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.2 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 - cli-spinners@3.4.0: {} + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 cliui@8.0.1: dependencies: @@ -6960,7 +5946,7 @@ snapshots: comma-separated-tokens@2.0.3: {} - commander@14.0.3: {} + commander@10.0.1: {} commander@4.1.1: {} @@ -6968,22 +5954,8 @@ snapshots: commander@8.3.0: {} - conf@15.1.0: - dependencies: - ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - atomically: 2.1.1 - debounce-fn: 6.0.0 - dot-prop: 10.1.0 - env-paths: 3.0.0 - json-schema-typed: 8.0.2 - semver: 7.8.4 - uint8array-extras: 1.5.0 - confbox@0.1.8: {} - confbox@0.2.4: {} - consola@3.4.2: {} convert-source-map@2.0.0: {} @@ -7002,21 +5974,26 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + css.escape@1.5.1: {} csstype@3.2.3: {} - cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0): dependencies: cose-base: 1.0.3 - cytoscape: 3.33.1 + cytoscape: 3.34.0 - cytoscape-fcose@2.2.0(cytoscape@3.33.1): + cytoscape-fcose@2.2.0(cytoscape@3.34.0): dependencies: cose-base: 2.2.0 - cytoscape: 3.33.1 + cytoscape: 3.34.0 - cytoscape@3.33.1: {} + cytoscape@3.34.0: {} d3-array@2.12.1: dependencies: @@ -7190,16 +6167,21 @@ snapshots: d3: 7.9.0 lodash-es: 4.18.1 - dayjs@1.11.20: {} - - debounce-fn@6.0.0: + data-urls@7.0.0: dependencies: - mimic-function: 5.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + dayjs@1.11.20: {} debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -7227,15 +6209,6 @@ snapshots: dequal@2.0.3: {} - deslop-js@0.0.21: - dependencies: - '@oxc-project/types': 0.132.0 - fast-glob: 3.3.3 - minimatch: 10.2.5 - oxc-parser: 0.132.0 - oxc-resolver: 11.20.0 - typescript: 5.9.3 - detect-libc@2.1.2: {} detect-node-es@1.1.0: {} @@ -7252,28 +6225,11 @@ snapshots: dom-accessibility-api@0.6.3: {} - dompurify@3.4.5: + dompurify@3.4.11: optionalDependencies: '@types/trusted-types': 2.0.7 - dot-prop@10.1.0: - dependencies: - type-fest: 5.7.0 - - effect@4.0.0-beta.70: - dependencies: - '@standard-schema/spec': 1.1.0 - fast-check: 4.8.0 - find-my-way-ts: 0.1.6 - ini: 7.0.0 - kubernetes-types: 1.30.0 - msgpackr: 2.0.4 - multipasta: 0.2.7 - toml: 4.1.1 - uuid: 11.1.1 - yaml: 2.9.0 - - electron-to-chromium@1.5.372: {} + electron-to-chromium@1.5.387: {} emoji-regex@8.0.0: {} @@ -7285,7 +6241,9 @@ snapshots: entities@6.0.1: {} - env-paths@3.0.0: {} + entities@8.0.0: {} + + environment@1.1.0: {} es-errors@1.3.0: {} @@ -7296,39 +6254,10 @@ snapshots: esbuild-sass-plugin@3.7.0(esbuild@0.27.7)(sass-embedded@1.98.0): dependencies: esbuild: 0.27.7 - resolve: 1.22.11 + resolve: 1.22.12 sass: 1.101.0 sass-embedded: 1.98.0 - esbuild@0.27.3: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -7366,34 +6295,23 @@ snapshots: eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.7.0)): dependencies: - eslint: 10.1.0(jiti@2.7.0) - - eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@2.7.0)): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 - eslint: 10.1.0(jiti@2.7.0) - hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) - transitivePeerDependencies: - - supports-color + eslint: 10.1.0(jiti@2.7.0) - eslint-plugin-react-hooks@7.1.1(eslint@10.1.0(jiti@2.7.0)): + eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@2.7.0)): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.7 eslint: 10.1.0(jiti@2.7.0) hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) + zod: 4.3.6 + zod-validation-error: 4.0.2(zod@4.3.6) transitivePeerDependencies: - supports-color eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -7412,7 +6330,7 @@ snapshots: '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 ajv: 6.14.0 cross-spawn: 7.0.6 debug: 4.4.3 @@ -7440,8 +6358,8 @@ snapshots: espree@11.2.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) eslint-visitor-keys: 5.0.1 esprima@4.0.1: {} @@ -7470,33 +6388,17 @@ snapshots: extend@3.0.2: {} - fast-check@4.8.0: - dependencies: - pure-rand: 8.4.0 - fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-uri@3.1.2: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 + + fflate@0.8.3: {} file-entry-cache@8.0.0: dependencies: @@ -7506,8 +6408,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-my-way-ts@0.1.6: {} - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -7516,7 +6416,7 @@ snapshots: fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 - mlly: 1.8.1 + mlly: 1.8.2 rollup: 4.59.0 flat-cache@4.0.1: @@ -7546,8 +6446,6 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.5.0: {} - get-east-asian-width@1.6.0: {} get-nonce@1.0.1: {} @@ -7702,7 +6600,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.6: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 @@ -7772,10 +6670,18 @@ snapshots: dependencies: hermes-estree: 0.25.1 + highlight.js@10.7.3: {} + highlight.js@11.11.1: {} html-comment-regex@1.1.2: {} + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + html-escaper@2.0.2: {} html-url-attributes@3.0.1: {} @@ -7790,21 +6696,12 @@ snapshots: ignore@7.0.5: {} - immutable@5.1.6: {} - - import-in-the-middle@3.0.2: - dependencies: - acorn: 8.17.0 - acorn-import-attributes: 1.9.5(acorn@8.17.0) - cjs-module-lexer: 2.2.0 - module-details-from-path: 1.0.4 + immutable@5.1.9: {} imurmurhash@0.1.4: {} indent-string@4.0.0: {} - ini@7.0.0: {} - inline-style-parser@0.2.7: {} internmap@1.0.1: {} @@ -7844,13 +6741,11 @@ snapshots: dependencies: is-docker: 3.0.0 - is-interactive@2.0.0: {} - is-number@7.0.0: {} is-plain-obj@4.1.0: {} - is-unicode-supported@2.1.0: {} + is-potential-custom-element-name@1.0.1: {} is-wsl@3.1.1: dependencies: @@ -7871,7 +6766,8 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jiti@2.7.0: {} + jiti@2.7.0: + optional: true joycon@3.1.1: {} @@ -7879,50 +6775,58 @@ snapshots: js-tokens@4.0.0: {} + jsdom@29.1.1: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.6(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.1 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.28.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + jsesc@3.1.0: {} json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - - json-schema-typed@8.0.2: {} - json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} - jsonc-parser@3.3.1: {} - jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - katex@0.16.44: - dependencies: - commander: 8.3.0 - katex@0.16.47: dependencies: commander: 8.3.0 - katex@0.17.0: - dependencies: - commander: 8.3.0 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 khroma@2.1.0: {} - kleur@3.0.3: {} - - kubernetes-types@1.30.0: {} - layout-base@1.0.2: {} layout-base@2.0.1: {} @@ -7993,11 +6897,6 @@ snapshots: lodash-es@4.18.1: {} - log-symbols@7.0.1: - dependencies: - is-unicode-supported: 2.1.0 - yoctocolors: 2.1.2 - longest-streak@3.1.0: {} loupe@3.2.1: {} @@ -8026,8 +6925,21 @@ snapshots: markdown-table@3.0.4: {} + marked-terminal@7.3.0(marked@9.1.6): + dependencies: + ansi-escapes: 7.3.0 + ansi-regex: 6.2.2 + chalk: 5.6.2 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + marked@16.4.2: {} + marked@9.1.6: {} + mdast-squeeze-paragraphs@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -8199,6 +7111,28 @@ snapshots: unist-util-visit: 5.1.0 vfile: 6.0.3 + mdast-util-to-markdown-cjk-friendly-gfm-strikethrough@1.0.0(@types/mdast@4.0.4)(micromark-util-types@2.0.2): + dependencies: + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-to-markdown: 2.1.2 + micromark-extension-cjk-friendly-util: 3.0.1(micromark-util-types@2.0.2) + micromark-util-symbol: 2.0.1 + optionalDependencies: + '@types/mdast': 4.0.4 + transitivePeerDependencies: + - micromark-util-types + - supports-color + + mdast-util-to-markdown-cjk-friendly@1.0.0(@types/mdast@4.0.4)(micromark-util-types@2.0.2): + dependencies: + mdast-util-to-markdown: 2.1.2 + micromark-extension-cjk-friendly-util: 3.0.1(micromark-util-types@2.0.2) + micromark-util-symbol: 2.0.1 + optionalDependencies: + '@types/mdast': 4.0.4 + transitivePeerDependencies: + - micromark-util-types + mdast-util-to-markdown@2.1.2: dependencies: '@types/mdast': 4.0.4 @@ -8225,30 +7159,30 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit: 5.1.0 - merge2@1.4.1: {} + mdn-data@2.27.1: {} - mermaid@11.15.0: + mermaid@11.16.0: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.0 - '@mermaid-js/parser': 1.1.1 + '@mermaid-js/parser': 1.2.0 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 - cytoscape: 3.33.1 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) - cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + cytoscape: 3.34.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0) + cytoscape-fcose: 2.2.0(cytoscape@3.34.0) d3: 7.9.0 d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.20 - dompurify: 3.4.5 + dompurify: 3.4.11 es-toolkit: 1.46.1 katex: 0.16.47 khroma: 2.1.0 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.3.6 - ts-dedent: 2.2.0 + ts-dedent: 2.3.0 uuid: 11.1.1 micromark-core-commonmark@2.0.3: @@ -8273,7 +7207,7 @@ snapshots: micromark-extension-cjk-friendly-gfm-strikethrough@2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2): dependencies: devlop: 1.1.0 - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 micromark: 4.0.2 micromark-extension-cjk-friendly-util: 3.0.1(micromark-util-types@2.0.2) micromark-util-character: 2.1.1 @@ -8374,7 +7308,7 @@ snapshots: dependencies: '@types/katex': 0.16.8 devlop: 1.1.0 - katex: 0.16.44 + katex: 0.16.47 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 @@ -8494,30 +7428,16 @@ snapshots: transitivePeerDependencies: - supports-color - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 4.0.4 - - mimic-function@5.0.1: {} - min-indent@1.0.1: {} minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.7 minimist@1.2.8: {} minipass@7.1.3: {} - mlly@1.8.1: - dependencies: - acorn: 8.17.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - mlly@1.8.2: dependencies: acorn: 8.17.0 @@ -8525,30 +7445,12 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.3 - module-details-from-path@1.0.4: {} + mri@1.2.0: {} mrmime@2.0.1: {} ms@2.1.3: {} - msgpackr-extract@3.0.4: - dependencies: - node-gyp-build-optional-packages: 5.2.2 - optionalDependencies: - '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.4 - '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.4 - '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.4 - '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4 - '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4 - '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 - optional: true - - msgpackr@2.0.4: - optionalDependencies: - msgpackr-extract: 3.0.4 - - multipasta@0.2.7: {} - mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -8573,12 +7475,7 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 - node-gyp-build-optional-packages@5.2.2: - dependencies: - detect-libc: 2.1.2 - optional: true - - node-releases@2.0.47: {} + node-releases@2.0.50: {} normalize-path@3.0.0: {} @@ -8586,10 +7483,6 @@ snapshots: obug@2.1.2: {} - onetime@7.0.0: - dependencies: - mimic-function: 5.0.1 - open@10.2.0: dependencies: default-browser: 5.5.0 @@ -8606,17 +7499,6 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ora@9.4.0: - dependencies: - chalk: 5.6.2 - cli-cursor: 5.0.0 - cli-spinners: 3.4.0 - is-interactive: 2.0.0 - is-unicode-supported: 2.1.0 - log-symbols: 7.0.1 - stdin-discarder: 0.3.2 - string-width: 8.2.1 - oxc-parser@0.127.0: dependencies: '@oxc-project/types': 0.127.0 @@ -8642,31 +7524,6 @@ snapshots: '@oxc-parser/binding-win32-ia32-msvc': 0.127.0 '@oxc-parser/binding-win32-x64-msvc': 0.127.0 - oxc-parser@0.132.0: - dependencies: - '@oxc-project/types': 0.132.0 - optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.132.0 - '@oxc-parser/binding-android-arm64': 0.132.0 - '@oxc-parser/binding-darwin-arm64': 0.132.0 - '@oxc-parser/binding-darwin-x64': 0.132.0 - '@oxc-parser/binding-freebsd-x64': 0.132.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.132.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.132.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.132.0 - '@oxc-parser/binding-linux-arm64-musl': 0.132.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.132.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.132.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.132.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.132.0 - '@oxc-parser/binding-linux-x64-gnu': 0.132.0 - '@oxc-parser/binding-linux-x64-musl': 0.132.0 - '@oxc-parser/binding-openharmony-arm64': 0.132.0 - '@oxc-parser/binding-wasm32-wasi': 0.132.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.132.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.132.0 - '@oxc-parser/binding-win32-x64-msvc': 0.132.0 - oxc-resolver@11.20.0: optionalDependencies: '@oxc-resolver/binding-android-arm-eabi': 11.20.0 @@ -8689,35 +7546,6 @@ snapshots: '@oxc-resolver/binding-win32-arm64-msvc': 11.20.0 '@oxc-resolver/binding-win32-x64-msvc': 11.20.0 - oxlint-plugin-react-doctor@0.5.1: - dependencies: - '@typescript-eslint/types': 8.61.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - oxc-parser: 0.132.0 - - oxlint@1.69.0: - optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.69.0 - '@oxlint/binding-android-arm64': 1.69.0 - '@oxlint/binding-darwin-arm64': 1.69.0 - '@oxlint/binding-darwin-x64': 1.69.0 - '@oxlint/binding-freebsd-x64': 1.69.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.69.0 - '@oxlint/binding-linux-arm-musleabihf': 1.69.0 - '@oxlint/binding-linux-arm64-gnu': 1.69.0 - '@oxlint/binding-linux-arm64-musl': 1.69.0 - '@oxlint/binding-linux-ppc64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-musl': 1.69.0 - '@oxlint/binding-linux-s390x-gnu': 1.69.0 - '@oxlint/binding-linux-x64-gnu': 1.69.0 - '@oxlint/binding-linux-x64-musl': 1.69.0 - '@oxlint/binding-openharmony-arm64': 1.69.0 - '@oxlint/binding-win32-arm64-msvc': 1.69.0 - '@oxlint/binding-win32-ia32-msvc': 1.69.0 - '@oxlint/binding-win32-x64-msvc': 1.69.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -8749,10 +7577,22 @@ snapshots: unist-util-visit-children: 3.0.0 vfile: 6.0.3 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parse5@7.3.0: dependencies: entities: 6.0.1 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + path-data-parser@0.1.0: {} path-exists@4.0.0: {} @@ -8772,7 +7612,7 @@ snapshots: picocolors@1.1.1: {} - picomatch@4.0.4: {} + picomatch@4.0.5: {} pify@2.3.0: {} @@ -8781,14 +7621,14 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.1 + mlly: 1.8.2 pathe: 2.0.3 - playwright-core@1.60.0: {} + playwright-core@1.61.1: {} - playwright@1.60.0: + playwright@1.61.1: dependencies: - playwright-core: 1.60.0 + playwright-core: 1.61.1 optionalDependencies: fsevents: 2.3.2 @@ -8801,59 +7641,57 @@ snapshots: path-data-parser: 0.1.0 points-on-curve: 0.2.0 - postcss-cli@11.0.1(jiti@2.7.0)(postcss@8.5.15): + postcss-cli@11.0.1(jiti@2.7.0)(postcss@8.5.16): dependencies: chokidar: 3.6.0 dependency-graph: 1.0.0 fs-extra: 11.3.4 picocolors: 1.1.1 - postcss: 8.5.15 - postcss-load-config: 5.1.0(jiti@2.7.0)(postcss@8.5.15) - postcss-reporter: 7.1.0(postcss@8.5.15) + postcss: 8.5.16 + postcss-load-config: 5.1.0(jiti@2.7.0)(postcss@8.5.16) + postcss-reporter: 7.1.0(postcss@8.5.16) pretty-hrtime: 1.0.3 read-cache: 1.0.0 slash: 5.1.0 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 yargs: 17.7.2 transitivePeerDependencies: - jiti - tsx - postcss-load-config@5.1.0(jiti@2.7.0)(postcss@8.5.15): + postcss-load-config@5.1.0(jiti@2.7.0)(postcss@8.5.16): dependencies: lilconfig: 3.1.3 - yaml: 2.8.3 + yaml: 2.9.0 optionalDependencies: jiti: 2.7.0 - postcss: 8.5.15 + postcss: 8.5.16 - postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0): + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.16)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.7.0 - postcss: 8.5.15 + postcss: 8.5.16 yaml: 2.9.0 - postcss-reporter@7.1.0(postcss@8.5.15): + postcss-reporter@7.1.0(postcss@8.5.16): dependencies: picocolors: 1.1.1 - postcss: 8.5.15 + postcss: 8.5.16 thenby: 1.3.4 postcss-value-parser@4.2.0: {} - postcss@8.5.15: + postcss@8.5.16: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - preact@10.29.2: {} - prelude-ls@1.2.1: {} - prettier@3.8.3: {} + prettier@3.9.4: {} pretty-format@27.5.1: dependencies: @@ -8863,18 +7701,16 @@ snapshots: pretty-hrtime@1.0.3: {} - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - property-information@7.1.0: {} - punycode@2.3.1: {} - - pure-rand@8.4.0: {} + publint@0.3.21: + dependencies: + '@publint/pack': 0.1.5 + package-manager-detector: 1.6.0 + picocolors: 1.1.1 + sade: 1.8.1 - queue-microtask@1.2.3: {} + punycode@2.3.1: {} react-docgen-typescript@2.4.0(typescript@5.9.3): dependencies: @@ -8895,47 +7731,11 @@ snapshots: transitivePeerDependencies: - supports-color - react-doctor@0.5.1(eslint@10.1.0(jiti@2.7.0)): - dependencies: - '@babel/code-frame': 7.29.7 - '@effect/platform-node-shared': 4.0.0-beta.70(effect@4.0.0-beta.70) - '@sentry/node': 10.57.0 - agent-install: 0.0.5 - conf: 15.1.0 - confbox: 0.2.4 - deslop-js: 0.0.21 - effect: 4.0.0-beta.70 - eslint-plugin-react-hooks: 7.1.1(eslint@10.1.0(jiti@2.7.0)) - jiti: 2.7.0 - magicast: 0.5.3 - oxlint: 1.69.0 - oxlint-plugin-react-doctor: 0.5.1 - prompts: 2.4.2 - typescript: 5.9.3 - vscode-languageserver: 9.0.1 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.1.0 - transitivePeerDependencies: - - '@opentelemetry/exporter-trace-otlp-http' - - bufferutil - - eslint - - oxlint-tsgolint - - supports-color - - utf-8-validate - - vite-plus - react-dom@19.2.7(react@19.2.7): dependencies: react: 19.2.7 scheduler: 0.27.0 - react-grab@0.1.44(react@19.2.7): - dependencies: - '@react-grab/cli': 0.1.44 - bippy: 0.5.41(react@19.2.7) - optionalDependencies: - react: 19.2.7 - react-is@17.0.2: {} react-number-format@5.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7): @@ -8962,34 +7762,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - react-scan@0.5.7(esbuild@0.27.7)(eslint@10.1.0(jiti@2.7.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0): - dependencies: - '@babel/core': 7.29.7 - '@babel/types': 7.29.7 - '@preact/signals': 2.9.1(preact@10.29.2) - '@rollup/pluginutils': 5.4.0(rollup@4.59.0) - bippy: 0.5.41(react@19.2.7) - commander: 14.0.3 - picocolors: 1.1.1 - preact: 10.29.2 - prompts: 2.4.2 - react: 19.2.7 - react-doctor: 0.5.1(eslint@10.1.0(jiti@2.7.0)) - react-dom: 19.2.7(react@19.2.7) - react-grab: 0.1.44(react@19.2.7) - optionalDependencies: - esbuild: 0.27.7 - unplugin: 3.0.0 - transitivePeerDependencies: - - '@opentelemetry/exporter-trace-otlp-http' - - bufferutil - - eslint - - oxlint-tsgolint - - rollup - - supports-color - - utf-8-validate - - vite-plus - react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7): dependencies: get-nonce: 1.0.1 @@ -9000,7 +7772,7 @@ snapshots: react-textarea-autosize@8.5.9(@types/react@19.2.17)(react@19.2.7): dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 react: 19.2.7 use-composed-ref: 1.4.0(@types/react@19.2.17)(react@19.2.7) use-latest: 1.3.0(@types/react@19.2.17)(react@19.2.7) @@ -9015,7 +7787,7 @@ snapshots: readdirp@3.6.0: dependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 readdirp@4.1.2: {} @@ -9040,7 +7812,7 @@ snapshots: '@types/katex': 0.16.8 hast-util-from-html-isomorphic: 2.0.0 hast-util-to-text: 4.0.2 - katex: 0.16.44 + katex: 0.16.47 unist-util-visit-parents: 6.0.2 vfile: 6.0.3 @@ -9073,8 +7845,9 @@ snapshots: mdast-util-newline-to-break: 2.0.0 unified: 11.0.5 - remark-cjk-friendly-gfm-strikethrough@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5): + remark-cjk-friendly-gfm-strikethrough@2.3.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5): dependencies: + mdast-util-to-markdown-cjk-friendly-gfm-strikethrough: 1.0.0(@types/mdast@4.0.4)(micromark-util-types@2.0.2) micromark-extension-cjk-friendly-gfm-strikethrough: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2) unified: 11.0.5 optionalDependencies: @@ -9082,9 +7855,11 @@ snapshots: transitivePeerDependencies: - micromark - micromark-util-types + - supports-color - remark-cjk-friendly@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5): + remark-cjk-friendly@2.3.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5): dependencies: + mdast-util-to-markdown-cjk-friendly: 1.0.0(@types/mdast@4.0.4)(micromark-util-types@2.0.2) micromark-extension-cjk-friendly: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2) unified: 11.0.5 optionalDependencies: @@ -9187,21 +7962,8 @@ snapshots: require-from-string@2.0.2: {} - require-in-the-middle@8.0.1: - dependencies: - debug: 4.4.3 - module-details-from-path: 1.0.4 - transitivePeerDependencies: - - supports-color - resolve-from@5.0.0: {} - resolve@1.22.11: - dependencies: - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.12: dependencies: es-errors: 1.3.0 @@ -9209,11 +7971,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - restore-cursor@5.1.0: - dependencies: - onetime: 7.0.0 - signal-exit: 4.1.0 - retext-latin@4.0.0: dependencies: '@types/nlcst': 2.0.3 @@ -9239,8 +7996,6 @@ snapshots: retext-stringify: 4.0.0 unified: 11.0.5 - reusify@1.1.0: {} - robust-predicates@3.0.3: {} rolldown@1.0.0-rc.8(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): @@ -9307,16 +8062,16 @@ snapshots: run-applescript@7.1.0: {} - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - rw@1.3.3: {} rxjs@7.8.2: dependencies: tslib: 2.8.1 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safer-buffer@2.1.2: {} sass-embedded-all-unknown@1.98.0: @@ -9379,9 +8134,9 @@ snapshots: sass-embedded@1.98.0: dependencies: - '@bufbuild/protobuf': 2.12.0 + '@bufbuild/protobuf': 2.12.1 colorjs.io: 0.5.2 - immutable: 5.1.6 + immutable: 5.1.9 rxjs: 7.8.2 supports-color: 8.1.1 sync-child-process: 1.0.2 @@ -9406,18 +8161,10 @@ snapshots: sass-embedded-win32-arm64: 1.98.0 sass-embedded-win32-x64: 1.98.0 - sass@1.100.0: - dependencies: - chokidar: 5.0.0 - immutable: 5.1.6 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.6 - sass@1.101.0: dependencies: chokidar: 5.0.0 - immutable: 5.1.6 + immutable: 5.1.9 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.6 @@ -9425,12 +8172,16 @@ snapshots: sass@1.98.0: dependencies: chokidar: 4.0.3 - immutable: 5.1.6 + immutable: 5.1.9 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.6 optional: true + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.27.0: {} semver@6.3.1: {} @@ -9445,16 +8196,12 @@ snapshots: siginfo@2.0.0: {} - signal-exit@4.1.0: {} - sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 mrmime: 2.0.1 totalist: 3.0.1 - sisteransi@1.0.5: {} - skin-tone@2.0.0: dependencies: unicode-emoji-modifier-base: 1.0.0 @@ -9473,9 +8220,7 @@ snapshots: std-env@4.1.0: {} - stdin-discarder@0.3.2: {} - - storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.8.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -9494,7 +8239,7 @@ snapshots: ws: 8.21.0 optionalDependencies: '@types/react': 19.2.17 - prettier: 3.8.3 + prettier: 3.9.4 transitivePeerDependencies: - '@testing-library/dom' - bufferutil @@ -9508,11 +8253,6 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@8.2.1: - dependencies: - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - stringify-entities@4.0.4: dependencies: character-entities-html4: 2.1.0 @@ -9534,12 +8274,6 @@ snapshots: strip-indent@4.1.1: {} - stubborn-fs@2.0.0: - dependencies: - stubborn-utils: 1.0.2 - - stubborn-utils@1.0.2: {} - style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -9557,7 +8291,7 @@ snapshots: lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 supports-color@7.2.0: @@ -9568,8 +8302,15 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + sync-child-process@1.0.2: dependencies: sync-message-port: 1.2.0 @@ -9578,8 +8319,6 @@ snapshots: tabbable@6.4.0: {} - tagged-tag@1.0.0: {} - thenby@1.3.4: {} thenify-all@1.6.0: @@ -9598,15 +8337,10 @@ snapshots: tinyexec@1.2.4: {} - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tinyrainbow@2.0.0: {} @@ -9614,14 +8348,26 @@ snapshots: tinyspy@4.0.4: {} + tldts-core@7.4.6: {} + + tldts@7.4.6: + dependencies: + tldts-core: 7.4.6 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toml@4.1.1: {} - totalist@3.0.1: {} + tough-cookie@6.0.1: + dependencies: + tldts: 7.4.6 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -9634,8 +8380,6 @@ snapshots: dependencies: typescript: 5.9.3 - ts-dedent@2.2.0: {} - ts-dedent@2.3.0: {} ts-interface-checker@0.1.13: {} @@ -9648,27 +8392,27 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@5.9.3)(yaml@2.9.0): + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.16)(typescript@5.9.3)(yaml@2.9.0): dependencies: - bundle-require: 5.1.0(esbuild@0.27.3) + bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.3 - esbuild: 0.27.3 + esbuild: 0.27.7 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.16)(yaml@2.9.0) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 sucrase: 3.35.1 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.15 + postcss: 8.5.16 typescript: 5.9.3 transitivePeerDependencies: - jiti @@ -9682,10 +8426,6 @@ snapshots: type-fest@4.41.0: {} - type-fest@5.7.0: - dependencies: - tagged-tag: 1.0.0 - typescript-eslint@8.58.2(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3) @@ -9701,10 +8441,10 @@ snapshots: ufo@1.6.3: {} - uint8array-extras@1.5.0: {} - undici-types@7.24.6: {} + undici@7.28.0: {} + unicode-emoji-modifier-base@1.0.0: {} unified@11.0.5: @@ -9782,19 +8522,12 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 acorn: 8.17.0 - picomatch: 4.0.4 + picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 - unplugin@3.0.0: + update-browserslist-db@1.2.3(browserslist@4.28.4): dependencies: - '@jridgewell/remapping': 2.3.5 - picomatch: 4.0.4 - webpack-virtual-modules: 0.6.2 - optional: true - - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 + browserslist: 4.28.4 escalade: 3.2.0 picocolors: 1.1.1 @@ -9842,6 +8575,8 @@ snapshots: uuid@11.1.1: {} + validate-npm-package-name@5.0.1: {} + varint@6.0.0: {} vfile-location@5.0.3: @@ -9859,12 +8594,12 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0): + vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0): dependencies: '@oxc-project/runtime': 0.115.0 lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 + picomatch: 4.0.5 + postcss: 8.5.16 rolldown: 1.0.0-rc.8(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) tinyglobby: 0.2.17 optionalDependencies: @@ -9872,65 +8607,63 @@ snapshots: esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.7.0 - sass: 1.100.0 + sass: 1.101.0 sass-embedded: 1.98.0 yaml: 2.9.0 transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' - vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-v8@4.1.8)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.2 pathe: 2.0.3 - picomatch: 4.0.4 + picomatch: 4.0.5 std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.9.3 - '@vitest/browser-playwright': 4.1.8(playwright@1.60.0)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.100.0)(yaml@2.9.0))(vitest@4.1.8) - '@vitest/coverage-v8': 4.1.8(@vitest/browser@4.1.8)(vitest@4.1.8) + '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) + jsdom: 29.1.1 transitivePeerDependencies: - msw - vscode-jsonrpc@8.2.0: {} - - vscode-languageserver-protocol@3.17.5: + w3c-xmlserializer@5.0.0: dependencies: - vscode-jsonrpc: 8.2.0 - vscode-languageserver-types: 3.17.5 - - vscode-languageserver-textdocument@1.0.12: {} - - vscode-languageserver-types@3.17.5: {} - - vscode-languageserver@9.0.1: - dependencies: - vscode-languageserver-protocol: 3.17.5 - - vscode-uri@3.1.0: {} + xml-name-validator: 5.0.0 web-namespaces@2.0.1: {} + webidl-conversions@8.0.1: {} + webpack-virtual-modules@0.6.2: {} - when-exit@2.1.5: {} + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' which@2.0.2: dependencies: @@ -9955,16 +8688,30 @@ snapshots: dependencies: is-wsl: 3.1.1 + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} - yaml@2.8.3: {} - yaml@2.9.0: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.2: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -9977,18 +8724,10 @@ snapshots: yocto-queue@0.1.0: {} - yoctocolors@2.1.2: {} - zod-validation-error@4.0.2(zod@4.3.6): dependencies: zod: 4.3.6 - zod-validation-error@4.0.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - zod@4.3.6: {} - zod@4.4.3: {} - zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a65e282..844da7b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,7 +4,9 @@ packages: # Security floors for transitive deps (formerly package.json `pnpm.overrides`, # which pnpm 10 no longer reads — see https://pnpm.io/settings). overrides: - dompurify: ^3.4.0 + # >=3.4.11 clears all current advisories (GHSA-cmwh-pvxp-8882 et al.) — + # keep this floor on the latest advisory's fix version, or it's decorative. + dompurify: ^3.4.11 uuid: ^11.1.1 picomatch: ^4.0.4 # Pin the TS major: workspace packages don't declare typescript themselves, diff --git a/scripts/version-packages.mjs b/scripts/version-packages.mjs index c77400c..53fb569 100755 --- a/scripts/version-packages.mjs +++ b/scripts/version-packages.mjs @@ -1,5 +1,4 @@ #!/usr/bin/env node -/* global process, console */ // Sync all versions across the monorepo. // @@ -27,21 +26,39 @@ const ROOT = resolve(import.meta.dirname, '..'); const PACKAGES_DIR = join(ROOT, 'packages'); const CORE_PKG_NAME = '@ai-react-markdown/core'; -// Update root package.json const rootPkgPath = join(ROOT, 'package.json'); +const packageDirs = readdirSync(PACKAGES_DIR, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name); + +// Refuse only a FULL no-op: root and every workspace package already at the +// target (tagging it would make `pnpm publish -r` silently skip the +// already-published version). A partial match — e.g. a previous run that +// wrote the root manifest and crashed mid-loop — must stay re-runnable so +// this script can repair itself. +// Non-package directories under packages/ (editor leftovers, temp checkouts) +// have no manifest — skip them here and in the update loop below. +const manifestPaths = [rootPkgPath, ...packageDirs.map((dir) => join(PACKAGES_DIR, dir, 'package.json'))].filter((p) => + existsSync(p) +); +if (manifestPaths.every((p) => JSON.parse(readFileSync(p, 'utf-8')).version === newVersion)) { + console.error(`All manifests are already at ${newVersion} — refusing a no-op bump.`); + process.exit(1); +} + +// Update root package.json const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8')); const rootOldVersion = rootPkg.version; rootPkg.version = newVersion; writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n'); console.log(`${rootPkg.name} (root): ${rootOldVersion} → ${newVersion}`); -// Update each package -const packageDirs = readdirSync(PACKAGES_DIR, { withFileTypes: true }) - .filter((d) => d.isDirectory()) - .map((d) => d.name); - for (const dir of packageDirs) { const pkgPath = join(PACKAGES_DIR, dir, 'package.json'); + if (!existsSync(pkgPath)) { + console.warn(`skipping packages/${dir}: no package.json`); + continue; + } const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')); const oldVersion = pkg.version; diff --git a/tsconfig.storybook.json b/tsconfig.storybook.json new file mode 100644 index 0000000..9da8d2a --- /dev/null +++ b/tsconfig.storybook.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.base.json", + "include": [".storybook", "vitest.config.ts", "vitest.shims.d.ts", "types"] +} diff --git a/types/style-shims.d.ts b/types/style-shims.d.ts new file mode 100644 index 0000000..241cf0a --- /dev/null +++ b/types/style-shims.d.ts @@ -0,0 +1,5 @@ +// Ambient module declarations for style imports in stories / Storybook config. +// tsc has no CSS pipeline; Vite handles these at build time. Referenced by the +// tsconfig.stories.json of each package and the root tsconfig.storybook.json. +declare module '*.css'; +declare module '*.scss'; From ffee8da80cd558d93c447c912b639ea3e6feb144 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 09:42:04 +0000 Subject: [PATCH 5/5] chore(deps-dev): bump the dev-deps group across 1 directory with 2 updates Bumps the dev-deps group with 2 updates in the / directory: [katex](https://github.com/KaTeX/KaTeX) and [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node). Updates `katex` from 0.16.47 to 0.17.0 - [Release notes](https://github.com/KaTeX/KaTeX/releases) - [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md) - [Commits](https://github.com/KaTeX/KaTeX/compare/v0.16.47...v0.17.0) Updates `@types/node` from 25.9.3 to 25.9.4 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: katex dependency-version: 0.17.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-deps - dependency-name: "@types/node" dependency-version: 25.9.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-deps ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- packages/mantine/package.json | 2 +- pnpm-lock.yaml | 98 +++++++++++++++++++---------------- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index c555ef7..d8a790e 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "eslint-config-prettier": "^10.1.8", "eslint-plugin-react-hooks": "~7.0.1", "jsdom": "^29.1.1", - "katex": "^0.16.0", + "katex": "^0.17.0", "playwright": "^1.61.1", "postcss": "^8.5.16", "postcss-cli": "^11.0.1", diff --git a/packages/mantine/package.json b/packages/mantine/package.json index 89d7eb8..e7c9b4e 100644 --- a/packages/mantine/package.json +++ b/packages/mantine/package.json @@ -75,7 +75,7 @@ "@mantine/code-highlight": "^8.3.18", "@mantine/core": "^8.3.18", "@types/lodash-es": "^4.17.12", - "@types/node": "^25.9.1", + "@types/node": "^25.9.4", "autoprefixer": "^10.5.2", "esbuild-sass-plugin": "^3.7.0", "highlight.js": "^11.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aea9ed3..d3c2cdb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,7 +28,7 @@ importers: version: 10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) '@storybook/addon-docs': specifier: ^10.4.6 - version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@storybook/addon-onboarding': specifier: ^10.4.6 version: 10.4.6(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) @@ -40,7 +40,7 @@ importers: version: 10.4.6(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10)(@vitest/runner@4.1.10)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vitest@4.1.10) '@storybook/react-vite': specifier: ^10.4.6 - version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + version: 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@types/react': specifier: ^19.2.17 version: 19.2.17 @@ -49,7 +49,7 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitest/browser-playwright': specifier: ^4.1.10 - version: 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + version: 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/coverage-v8': specifier: ^4.1.10 version: 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) @@ -69,8 +69,8 @@ importers: specifier: ^29.1.1 version: 29.1.1 katex: - specifier: ^0.16.0 - version: 0.16.47 + specifier: ^0.17.0 + version: 0.17.0 playwright: specifier: ^1.61.1 version: 1.61.1 @@ -103,7 +103,7 @@ importers: version: 8.58.2(eslint@10.1.0(jiti@2.7.0))(typescript@5.9.3) vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) packages/core: dependencies: @@ -251,8 +251,8 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^25.9.1 - version: 25.9.3 + specifier: ^25.9.4 + version: 25.9.4 autoprefixer: specifier: ^10.5.2 version: 10.5.2(postcss@8.5.16) @@ -1621,8 +1621,8 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} - '@types/node@25.9.3': - resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==} + '@types/node@25.9.4': + resolution: {integrity: sha512-dszCsrKb5U7ZsVZBWiHFklTloVl0mSEnWH/iZXfZUlI4rzCUnsvGmgqfuVRHL54ugE7/wRuxEIXRa2iMZ+BG6g==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -2773,6 +2773,10 @@ packages: resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} hasBin: true + katex@0.17.0: + resolution: {integrity: sha512-Vdw0ATsQ9V+LuegM/BTwQqV/6cTl5lbGcIrU+BCgLxyf6bo38ybOr372tuSIxir3CN720flu1meYR6XzNMwQnw==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -4745,11 +4749,11 @@ snapshots: '@iconify/types': 2.0.0 mlly: 1.8.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) optionalDependencies: typescript: 5.9.3 @@ -5174,10 +5178,10 @@ snapshots: axe-core: 4.12.1 storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@storybook/addon-docs@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@storybook/addon-docs@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) - '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@storybook/react-dom-shim': 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) react: 19.2.7 @@ -5208,33 +5212,33 @@ snapshots: '@storybook/icons': 2.0.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) optionalDependencies: - '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) - '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/runner': 4.1.10 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) transitivePeerDependencies: - react - react-dom - '@storybook/builder-vite@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@storybook/builder-vite@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@storybook/csf-plugin': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) ts-dedent: 2.3.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@storybook/csf-plugin@10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.7 rollup: 4.59.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) '@storybook/global@5.0.0': {} @@ -5252,11 +5256,11 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@storybook/react-vite@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@storybook/react-vite@10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.27.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@rollup/pluginutils': 5.4.0(rollup@4.59.0) - '@storybook/builder-vite': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@storybook/builder-vite': 10.4.6(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@storybook/react': 10.4.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@5.9.3) empathic: 2.0.1 magic-string: 0.30.21 @@ -5266,7 +5270,7 @@ snapshots: resolve: 1.22.12 storybook: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@3.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tsconfig-paths: 4.2.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -5512,7 +5516,7 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/node@25.9.3': + '@types/node@25.9.4': dependencies: undici-types: 7.24.6 @@ -5633,29 +5637,29 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - '@vitest/browser-playwright@4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': + '@vitest/browser-playwright@4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) - '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) playwright: 1.61.1 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': + '@vitest/browser@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) ws: 8.21.0 transitivePeerDependencies: - bufferutil @@ -5675,9 +5679,9 @@ snapshots: obug: 2.1.2 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/expect@3.2.4': dependencies: @@ -5696,13 +5700,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -6821,6 +6825,10 @@ snapshots: dependencies: commander: 8.3.0 + katex@0.17.0: + dependencies: + commander: 8.3.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -8594,7 +8602,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0): + vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0): dependencies: '@oxc-project/runtime': 0.115.0 lightningcss: 1.32.0 @@ -8603,7 +8611,7 @@ snapshots: rolldown: 1.0.0-rc.8(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.9.3 + '@types/node': 25.9.4 esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.7.0 @@ -8614,10 +8622,10 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -8634,12 +8642,12 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) + vite: 8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.9.3 - '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) + '@types/node': 25.9.4 + '@vitest/browser-playwright': 4.1.10(playwright@1.61.1)(vite@8.0.0-beta.18(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.9.4)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.98.0)(sass@1.101.0)(yaml@2.9.0))(vitest@4.1.10) '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) jsdom: 29.1.1 transitivePeerDependencies: