diff --git a/packages/plotly/README.md b/packages/plotly/README.md
new file mode 100644
index 000000000..ad2515752
--- /dev/null
+++ b/packages/plotly/README.md
@@ -0,0 +1,112 @@
+# @openuidev/plotly
+
+Plotly.js component library for OpenUI's generative UI runtime. An LLM speaking openui-lang gets **47 typed chart components** — bar, line, heatmap, violin, sankey, sunburst, candlestick, scatter3d, choropleth, parallel coordinates, the rest of Plotly's catalog — plus a `` wrapper that drops onto any "use client" page.
+
+## Install
+
+```bash
+pnpm add @openuidev/plotly @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang react react-dom zod
+```
+
+## Quick start
+
+```tsx
+"use client";
+import "@openuidev/react-ui/components.css";
+import "@openuidev/react-ui/styles/index.css";
+import "@openuidev/plotly/styles.css";
+
+import { PlotlyChat } from "@openuidev/plotly";
+
+export default function Home() {
+ return (
+
+ );
+}
+```
+
+Pair with an `/api/chat` proxy that streams from your LLM provider (see `examples/` for a working OpenAI implementation).
+
+## Two-tier API
+
+Following Plotly's own dual API:
+
+**Tier 1** — Typed Plotly-Express-style components. Small zod schemas, ergonomic for the LLM:
+
+```
+Bar(rows, "month", "revenue", "product") # Express style
+Bar(null, ["Jan", "Feb", "Mar"], [1.2, 1.5, 1.8]) # Graph-Objects style
+```
+
+**Tier 2** — `Figure(data, layout)` accepts the full Plotly Graph-Objects schema. Use this for charts Tier 1 doesn't cover (multi-trace overlays, dual axes, animation frames, custom polar/ternary/carpet, advanced 3D scenes).
+
+**Tier 0** — `PlotlyJSON({ figure })` renders a fully-formed Plotly figure JSON verbatim. Bridge for backend-produced figures (Python `fig.to_json()`).
+
+## Component catalog
+
+| Family | Components |
+|---|---|
+| Layout | `Stack`, `Card`, `CardHeader`, `Heading`, `Text`, `Callout`, `KPI` |
+| Cartesian | `Bar`, `Line`, `Scatter`, `Area`, `Histogram` |
+| Distributions | `Violin`, `Box` |
+| Matrix & 2D-density | `Heatmap`, `Histogram2D`, `Histogram2DContour`, `Contour` |
+| Hierarchical | `Sunburst`, `Treemap`, `Icicle` |
+| Categorical | `Pie`, `Donut`, `Funnel`, `FunnelArea`, `Waterfall` |
+| Flow | `Sankey` |
+| Multivariate | `ScatterMatrix`, `ParCoords`, `ParCats` |
+| Financial | `Candlestick`, `OHLC` |
+| Polar | `ScatterPolar`, `BarPolar` |
+| Specialty coords | `ScatterTernary`, `ScatterSmith` |
+| Geo | `Choropleth`, `ScatterGeo` |
+| Data display | `Indicator`, `Table` |
+| Escape hatches | `Figure`, `PlotlyJSON` |
+
+The LLM sees these via the auto-generated system prompt — no manual Plotly schema authoring required.
+
+## Bidirectional reactivity
+
+Plotly events flow into OpenUI's action system:
+
+```
+Bar(rows, "month", "revenue",
+ onClick=Action([@Set($selectedMonth, event.x), @Run(monthlyDetail)]))
+```
+
+Supported events: `onClick`, `onSelected` (lasso/box select), `onRelayout` (zoom/pan).
+
+## Bundle & loading
+
+- The Plotly bundle (~3.5 MB minified, ~1 MB gzipped) is loaded **lazily via `React.lazy`** on first chart render. The chat shell first paint is unaffected.
+- Chart instances mount only after the assistant message finishes streaming — avoids token-by-token flicker as the LLM populates trace shape.
+
+## Custom chat shell
+
+If `` is too restrictive, drop down to the lower-level pieces:
+
+```tsx
+import { Renderer, useTriggerAction } from "@openuidev/react-lang";
+import { FullScreen } from "@openuidev/react-ui";
+import {
+ plotlyLibrary,
+ plotlyPromptOptions,
+ PlotlyAssistantMessage,
+} from "@openuidev/plotly";
+
+const systemPrompt = plotlyLibrary.prompt(plotlyPromptOptions);
+// …compose your own FullScreen / processMessage / assistantMessage…
+```
+
+## Theming
+
+`lightTemplate` + `darkTemplate` are exported as plain Plotly `Layout` objects matching OpenUI's design language. Apply them to your own (non-OpenUI) Plotly charts elsewhere if you want consistent visuals.
+
+## Limitations
+
+- **`image` trace** is not registered in the default bundle. Plotly's image source does `require('buffer/').Buffer` (with the trailing slash, deliberately), which Turbopack can't resolve. Use `Figure` with custom Plotly registration to enable it in non-Turbopack environments.
+- **Carpet family** (`Carpet`, `ScatterCarpet`, `ContourCarpet`) is figure-only — they only render when composed in a single figure, which separate `defineComponent` calls can't express. Use ``.
+
+## License
+
+MIT
diff --git a/packages/plotly/package.json b/packages/plotly/package.json
new file mode 100644
index 000000000..0a87cd417
--- /dev/null
+++ b/packages/plotly/package.json
@@ -0,0 +1,96 @@
+{
+ "type": "module",
+ "name": "@openuidev/plotly",
+ "license": "MIT",
+ "version": "0.1.0",
+ "description": "Plotly.js component library for OpenUI generative UI — 47 typed chart components an LLM can compose via openui-lang, plus a wrapper.",
+ "main": "dist/index.cjs",
+ "module": "dist/index.mjs",
+ "types": "dist/index.d.cts",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.mts",
+ "default": "./dist/index.mjs"
+ },
+ "require": {
+ "types": "./dist/index.d.cts",
+ "default": "./dist/index.cjs"
+ }
+ },
+ "./styles.css": {
+ "default": "./styles/plotly.css"
+ }
+ },
+ "files": [
+ "dist",
+ "styles",
+ "README.md"
+ ],
+ "sideEffects": [
+ "*.css",
+ "./dist/index.mjs",
+ "./dist/index.cjs"
+ ],
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "build": "rm -rf dist && pnpm build:tsc && pnpm build:cjs",
+ "build:tsc": "tsc -p . || true",
+ "build:cjs": "tsdown",
+ "typecheck": "tsc --noEmit",
+ "lint:check": "eslint ./src",
+ "lint:fix": "eslint ./src --fix",
+ "format:fix": "prettier --write ./src",
+ "format:check": "prettier --check ./src",
+ "check:publint": "publint",
+ "check:attw": "attw --pack . --ignore-rules no-resolution",
+ "prepare": "pnpm run build",
+ "prepublishOnly": "pnpm run check:publint && pnpm run check:attw",
+ "ci": "pnpm run lint:check && pnpm run format:check"
+ },
+ "peerDependencies": {
+ "@openuidev/react-headless": "workspace:^",
+ "@openuidev/react-lang": "workspace:^",
+ "@openuidev/react-ui": "workspace:^",
+ "react": "^18.3.1 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0",
+ "zod": "^3.25.0 || ^4.0.0"
+ },
+ "dependencies": {
+ "plotly.js-dist-min": "^3.0.0",
+ "react-plotly.js": "^2.6.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.15.32",
+ "@types/plotly.js": "^3.0.0",
+ "@types/plotly.js-dist-min": "^2.3.4",
+ "@types/react": ">=18.3.1",
+ "@types/react-dom": ">=18.3.1",
+ "@types/react-plotly.js": "^2.6.3"
+ },
+ "keywords": [
+ "openui",
+ "plotly",
+ "plotly.js",
+ "generative-ui",
+ "ai",
+ "llm",
+ "react",
+ "charts",
+ "data-visualization",
+ "scientific"
+ ],
+ "homepage": "https://openui.com",
+ "author": "engineering@openui.com",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/thesysdev/openui.git",
+ "directory": "packages/plotly"
+ },
+ "bugs": {
+ "url": "https://github.com/thesysdev/openui/issues"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/plotly/src/AssistantMessage.tsx b/packages/plotly/src/AssistantMessage.tsx
new file mode 100644
index 000000000..bc774d07a
--- /dev/null
+++ b/packages/plotly/src/AssistantMessage.tsx
@@ -0,0 +1,94 @@
+"use client";
+import type { AssistantMessage as AssistantMessageType } from "@openuidev/react-headless";
+import type { Library } from "@openuidev/react-lang";
+import { Renderer } from "@openuidev/react-lang";
+import React from "react";
+
+interface Props {
+ message: AssistantMessageType;
+ isStreaming: boolean;
+ library: Library;
+}
+
+interface ErrorBoundaryState {
+ err: Error | null;
+}
+
+class MessageErrorBoundary extends React.Component<
+ { children: React.ReactNode },
+ ErrorBoundaryState
+> {
+ override state: ErrorBoundaryState = { err: null };
+ static getDerivedStateFromError(err: Error): ErrorBoundaryState {
+ return { err };
+ }
+ override componentDidCatch(err: Error) {
+ if (typeof window !== "undefined") {
+ console.error("[plotly] message render crashed:", err);
+ }
+ }
+ override render() {
+ if (this.state.err) {
+ return (
+
+
Render error
+
+ {this.state.err.message}
+
+
+ );
+ }
+ return this.props.children;
+ }
+}
+
+export function PlotlyAssistantMessage({ message, isStreaming, library }: Props) {
+ const content = typeof message.content === "string" ? message.content : "";
+
+ React.useEffect(() => {
+ if (!isStreaming && content) {
+ // eslint-disable-next-line no-console
+ console.groupCollapsed(
+ `%c[plotly] openui-lang (${content.length} chars)`,
+ "color:#4c78a8;font-weight:600",
+ );
+ // eslint-disable-next-line no-console
+ console.log(content);
+ // eslint-disable-next-line no-console
+ console.groupEnd();
+ }
+ }, [isStreaming, content]);
+
+ return (
+
+
+ {
+ if (errors.length === 0) return;
+ console.warn(
+ `%c[plotly] ${errors.length} render error(s)`,
+ "color:#dc2626;font-weight:600",
+ errors,
+ );
+ }}
+ // onParseResult intentionally omitted — it fires on every reactive
+ // state change which spams the console with N×M log lines on multi-
+ // chart messages. Re-enable behind a debug flag if needed.
+ />
+
+
+ );
+}
diff --git a/packages/plotly/src/PlotlyChat.tsx b/packages/plotly/src/PlotlyChat.tsx
new file mode 100644
index 000000000..234704acf
--- /dev/null
+++ b/packages/plotly/src/PlotlyChat.tsx
@@ -0,0 +1,86 @@
+"use client";
+// One-line chat shell: wires up FullScreen, the plotlyLibrary,
+// the OpenAI adapter, and PlotlyAssistantMessage with sensible defaults.
+// Use the lower-level pieces (plotlyLibrary, PlotlyAssistantMessage, etc.)
+// directly if you need custom message processing.
+
+import {
+ openAIMessageFormat,
+ openAIReadableStreamAdapter,
+ type Message,
+} from "@openuidev/react-headless";
+import { FullScreen } from "@openuidev/react-ui";
+import React from "react";
+import { PlotlyAssistantMessage } from "./AssistantMessage";
+import { plotlyLibrary, plotlyPromptOptions } from "./library";
+
+export interface PlotlyChatProps {
+ /** API endpoint that proxies to your LLM. Receives `{ systemPrompt, messages }`
+ * and returns a streaming response. Defaults to `/api/chat`. */
+ apiUrl?: string;
+ /** Or supply your own message processor (overrides `apiUrl`). */
+ processMessage?: (params: {
+ threadId: string;
+ messages: Message[];
+ abortController: AbortController;
+ }) => Promise;
+ /** Override the system prompt fed to the LLM. Defaults to the catalog of
+ * all 47 components. */
+ systemPrompt?: string;
+ /** Display name shown in the chat shell header. */
+ agentName?: string;
+ /** Inline class on the wrapping div. */
+ className?: string;
+}
+
+export function PlotlyChat({
+ apiUrl = "/api/chat",
+ processMessage,
+ systemPrompt,
+ agentName = "OpenUI × Plotly",
+ className,
+}: PlotlyChatProps) {
+ const finalSystemPrompt = React.useMemo(
+ () => systemPrompt ?? plotlyLibrary.prompt(plotlyPromptOptions),
+ [systemPrompt],
+ );
+
+ const finalProcessMessage = React.useMemo(() => {
+ if (processMessage) return processMessage;
+ return async ({
+ messages,
+ abortController,
+ }: {
+ threadId: string;
+ messages: Message[];
+ abortController: AbortController;
+ }) =>
+ fetch(apiUrl, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ systemPrompt: finalSystemPrompt,
+ messages: openAIMessageFormat.toApi(messages),
+ }),
+ signal: abortController.signal,
+ });
+ }, [processMessage, apiUrl, finalSystemPrompt]);
+
+ return (
+
+ );
+}
diff --git a/packages/plotly/src/figure/Figure.ts b/packages/plotly/src/figure/Figure.ts
new file mode 100644
index 000000000..f30bd14bf
--- /dev/null
+++ b/packages/plotly/src/figure/Figure.ts
@@ -0,0 +1,27 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Config, Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const FigureSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())),
+ layout: z.record(z.string(), z.unknown()).optional(),
+ config: z.record(z.string(), z.unknown()).optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Figure = defineComponent({
+ name: "Figure",
+ props: FigureSchema,
+ description:
+ "Generic Plotly Graph-Objects figure. Pass `data` as an array of full Plotly trace objects, e.g. [{ type: 'bar', x: [...], y: [...] }, { type: 'scatter', x: [...], y: [...], mode: 'lines' }]. `layout` accepts the full Plotly layout JSON. Use this when you need a chart not covered by the typed Tier-1 components (Bar, Line, Heatmap, etc.).",
+ component: ({ props }) =>
+ React.createElement(PlotShell, {
+ data: props.data as Data[],
+ layout: props.layout as Partial | undefined,
+ config: props.config as Partial | undefined,
+ height: props.height,
+ }),
+});
diff --git a/packages/plotly/src/figure/PlotlyJSON.ts b/packages/plotly/src/figure/PlotlyJSON.ts
new file mode 100644
index 000000000..1740b47cc
--- /dev/null
+++ b/packages/plotly/src/figure/PlotlyJSON.ts
@@ -0,0 +1,32 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Config, Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const PlotlyJSONSchema = z.object({
+ figure: z.object({
+ data: z.array(z.record(z.string(), z.unknown())),
+ layout: z.record(z.string(), z.unknown()).optional(),
+ config: z.record(z.string(), z.unknown()).optional(),
+ }),
+ height: z.number().positive().optional(),
+});
+
+export const PlotlyJSON = defineComponent({
+ name: "PlotlyJSON",
+ props: PlotlyJSONSchema,
+ description:
+ "Render a fully-formed Plotly figure JSON object verbatim. Use this when a backend tool or query returns a figure produced server-side (e.g. Python `fig.to_json()`). Shape: { figure: { data: [...traces], layout?: {...}, config?: {...} } }.",
+ component: ({ props }) => {
+ const fig = props.figure;
+ if (!fig || !Array.isArray(fig.data)) return null;
+ return React.createElement(PlotShell, {
+ data: fig.data as Data[],
+ layout: fig.layout as Partial | undefined,
+ config: fig.config as Partial | undefined,
+ height: props.height,
+ });
+ },
+});
diff --git a/packages/plotly/src/helpers/buildTrace.ts b/packages/plotly/src/helpers/buildTrace.ts
new file mode 100644
index 000000000..77343882a
--- /dev/null
+++ b/packages/plotly/src/helpers/buildTrace.ts
@@ -0,0 +1,113 @@
+// Helpers shared by Tier-1 typed components. They accept either Plotly Express
+// style (`data` is an array of objects + `x`/`y` are field names) or
+// Graph-Objects style (`data` is null/undefined and `x`/`y` are raw arrays).
+
+export type Row = Record;
+export type ArrayLike = readonly (string | number | null | undefined)[];
+
+export function isStringField(v: unknown): v is string {
+ return typeof v === "string";
+}
+
+export function isArray(v: unknown): v is unknown[] {
+ return Array.isArray(v);
+}
+
+export function pluck(rows: Row[], field: string): T[] {
+ return rows.map((r) => r[field] as T);
+}
+
+export interface Resolved {
+ x: ArrayLike;
+ y: ArrayLike;
+ /** Categorical series — present when `color` resolves to a string column. */
+ group?: string[];
+ /** Continuous color values — present when `color` resolves to a numeric column. */
+ color?: number[];
+}
+
+export interface ResolveInput {
+ data?: Row[] | null;
+ x?: ArrayLike | string;
+ y?: ArrayLike | string;
+ color?: ArrayLike | string;
+}
+
+/**
+ * Normalize the (data, x, y, color) input pattern into resolved arrays.
+ *
+ * Express style: `data` is row-objects, `x`/`y`/`color` are field names.
+ * Graph-Objects style: `data` is null, `x`/`y`/`color` are arrays.
+ *
+ * `color` is treated as continuous if every value is numeric, categorical otherwise.
+ */
+export function resolve({ data, x, y, color }: ResolveInput): Resolved | null {
+ const fromRows = (rows: Row[]): Resolved | null => {
+ if (!isStringField(x) || !isStringField(y)) return null;
+ const xs = pluck(rows, x) as ArrayLike;
+ const ys = pluck(rows, y) as ArrayLike;
+ if (!color) return { x: xs, y: ys };
+ if (!isStringField(color)) return null;
+ const cs = pluck(rows, color);
+ if (cs.every((v) => typeof v === "number")) {
+ return { x: xs, y: ys, color: cs as number[] };
+ }
+ return { x: xs, y: ys, group: cs.map(String) };
+ };
+
+ if (data && Array.isArray(data) && data.length > 0) {
+ return fromRows(data);
+ }
+
+ // Graph-Objects style: x / y are raw arrays.
+ if (isArray(x) && isArray(y)) {
+ const out: Resolved = { x: x as ArrayLike, y: y as ArrayLike };
+ if (isArray(color)) {
+ const cs = color as unknown[];
+ if (cs.every((v) => typeof v === "number")) out.color = cs as number[];
+ else out.group = cs.map(String);
+ }
+ return out;
+ }
+
+ return null;
+}
+
+/**
+ * Split a resolved Resolved into per-group sub-arrays so we can produce
+ * one Plotly trace per categorical color level.
+ */
+export function splitByGroup(r: Resolved): Array<{ group: string; x: ArrayLike; y: ArrayLike }> {
+ if (!r.group) return [{ group: "", x: r.x, y: r.y }];
+ const groups = new Map();
+ const groupArr = r.group;
+ for (let i = 0; i < r.x.length; i++) {
+ const g = groupArr[i];
+ if (g === undefined) continue;
+ if (!groups.has(g)) groups.set(g, { x: [], y: [] });
+ const bucket = groups.get(g)!;
+ bucket.x.push(r.x[i]);
+ bucket.y.push(r.y[i]);
+ }
+ return Array.from(groups.entries()).map(([group, { x, y }]) => ({
+ group,
+ x: x as ArrayLike,
+ y: y as ArrayLike,
+ }));
+}
+
+/**
+ * Build a layout title from the chart's title/xLabel/yLabel props with
+ * Plotly's expected shape (string is title text).
+ */
+export function buildAxisLayout(opts: {
+ title?: string;
+ xLabel?: string;
+ yLabel?: string;
+}): Record {
+ const out: Record = {};
+ if (opts.title) out["title"] = { text: opts.title };
+ if (opts.xLabel) out["xaxis"] = { title: { text: opts.xLabel } };
+ if (opts.yLabel) out["yaxis"] = { title: { text: opts.yLabel } };
+ return out;
+}
diff --git a/packages/plotly/src/index.ts b/packages/plotly/src/index.ts
new file mode 100644
index 000000000..e15a2ef19
--- /dev/null
+++ b/packages/plotly/src/index.ts
@@ -0,0 +1,86 @@
+// Public entry point for @openuidev/plotly.
+//
+// Pairs with @openuidev/react-ui, @openuidev/react-headless, and
+// @openuidev/react-lang (peer dependencies) to provide 47 typed Plotly
+// components an LLM can address by name in openui-lang, plus a high-level
+// wrapper for one-line chat shells.
+
+// ── The high-level wrapper ──────────────────────────────────────────────────
+//
+// 99% of users only need this. Drop on a "use client" page,
+// add an /api/chat route, you have a working chat with all 47 chart types.
+export { PlotlyChat, type PlotlyChatProps } from "./PlotlyChat";
+
+// ── The library + prompt + assistantMessage ─────────────────────────────────
+//
+// Use these directly if you want to compose your own chat shell.
+export { PlotlyAssistantMessage } from "./AssistantMessage";
+export {
+ plotlyAdditionalRules,
+ plotlyComponentGroups,
+ plotlyExamples,
+ plotlyLibrary,
+ plotlyPromptOptions,
+ type PlotlyLibrary,
+} from "./library";
+
+// ── OpenUI re-exports (convenience) ─────────────────────────────────────────
+//
+// These come from peer-dependency packages — re-exporting just so consumers
+// can import everything from a single module if they want to.
+export {
+ BottomTray,
+ Copilot,
+ FullScreen,
+ ThemeProvider,
+ createTheme,
+ defaultDarkTheme,
+ defaultLightTheme,
+ type Theme,
+ type ThemeMode,
+ type ThemeProps,
+} from "@openuidev/react-ui";
+
+export {
+ identityMessageFormat,
+ openAIAdapter,
+ openAIConversationMessageFormat,
+ openAIMessageFormat,
+ openAIReadableStreamAdapter,
+ openAIResponsesAdapter,
+ type AssistantMessage,
+ type Message,
+ type SystemMessage,
+ type ToolMessage,
+ type UserMessage,
+} from "@openuidev/react-headless";
+
+export {
+ Renderer,
+ createLibrary,
+ defineComponent,
+ generatePrompt,
+ useIsStreaming,
+ useRenderNode,
+ useTriggerAction,
+ type ActionEvent,
+ type ActionPlan,
+ type ComponentGroup,
+ type Library,
+ type LibraryDefinition,
+ type OpenUIError,
+ type PromptOptions,
+} from "@openuidev/react-lang";
+
+// ── Theme / shell / advanced ────────────────────────────────────────────────
+export { isDivergingColormap, resolveColormap } from "./shell/colormap";
+export { PlotShell, type PlotShellProps } from "./shell/PlotShell";
+export { ChartSkeleton, NoDataNotice } from "./shell/skeleton";
+export { darkTemplate, defaultConfig, lightTemplate } from "./shell/template";
+
+// NOTE: do not statically re-export Plotly here. plotly.js-dist-min references
+// `self` at module load, which crashes Next.js / any SSR environment when the
+// package's index is touched on the server. PlotShell loads Plotly lazily via
+// React.lazy + dynamic import so the SSR boundary stays clean. Power users
+// who want direct access can import "plotly.js-dist-min" themselves inside
+// a "use client" boundary.
diff --git a/packages/plotly/src/layout/Layout.tsx b/packages/plotly/src/layout/Layout.tsx
new file mode 100644
index 000000000..d1a977aed
--- /dev/null
+++ b/packages/plotly/src/layout/Layout.tsx
@@ -0,0 +1,266 @@
+"use client";
+import { defineComponent, useRenderNode } from "@openuidev/react-lang";
+import React from "react";
+import { z } from "zod/v4";
+
+const FONT =
+ 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
+
+// Stack ---------------------------------------------------------------------
+
+const StackSchema = z.object({
+ children: z.array(z.unknown()),
+ direction: z.enum(["row", "column"]).optional(),
+ gap: z.number().optional(),
+ wrap: z.boolean().optional(),
+});
+
+export const Stack = defineComponent({
+ name: "Stack",
+ props: StackSchema,
+ description:
+ "Flex container. `direction='column'` (default) or 'row'. `gap` in px, `wrap=true` to wrap rows. Wrap charts and Cards as children.",
+ component: ({ props }) => {
+ const renderNode = useRenderNode();
+ const direction = props.direction ?? "column";
+ return (
+
+ {(props.children ?? []).map((c, i) => (
+
+ {renderNode(c)}
+
+ ))}
+
+ );
+ },
+});
+
+// Card ----------------------------------------------------------------------
+
+const CardSchema = z.object({ children: z.array(z.unknown()) });
+
+export const Card = defineComponent({
+ name: "Card",
+ props: CardSchema,
+ description:
+ "Surface that wraps related content (e.g. CardHeader + a chart). Pass children as an array.",
+ component: ({ props }) => {
+ const renderNode = useRenderNode();
+ return (
+
+ {(props.children ?? []).map((c, i) => (
+ {renderNode(c)}
+ ))}
+
+ );
+ },
+});
+
+// CardHeader ----------------------------------------------------------------
+
+const CardHeaderSchema = z.object({
+ title: z.string(),
+ subtitle: z.string().optional(),
+});
+
+export const CardHeader = defineComponent({
+ name: "CardHeader",
+ props: CardHeaderSchema,
+ description: "Header for a Card: title and optional subtitle.",
+ component: ({ props }) => (
+
+
+ {props.title}
+
+ {props.subtitle && (
+
+ {props.subtitle}
+
+ )}
+
+ ),
+});
+
+// Heading -------------------------------------------------------------------
+
+const HeadingSchema = z.object({
+ text: z.string(),
+ level: z.enum(["h1", "h2", "h3"]).optional(),
+});
+
+const HEADING_SIZES = {
+ h1: { fontSize: 22, fontWeight: 700, lineHeight: 1.2 },
+ h2: { fontSize: 17, fontWeight: 600, lineHeight: 1.3 },
+ h3: { fontSize: 14, fontWeight: 600, lineHeight: 1.35 },
+};
+
+export const Heading = defineComponent({
+ name: "Heading",
+ props: HeadingSchema,
+ description:
+ "Heading. `level`: 'h1' (default), 'h2', 'h3'. Use 'h1' for dashboard titles, 'h2' for section titles.",
+ component: ({ props }) => {
+ const s = HEADING_SIZES[props.level ?? "h1"];
+ return (
+
+ {props.text}
+
+ );
+ },
+});
+
+// Text ----------------------------------------------------------------------
+
+const TextSchema = z.object({
+ text: z.string(),
+ color: z.string().optional(),
+});
+
+export const Text = defineComponent({
+ name: "Text",
+ props: TextSchema,
+ description: "Paragraph of analysis prose. Use newlines for line breaks.",
+ component: ({ props }) => (
+
+ {props.text}
+
+ ),
+});
+
+// Callout -------------------------------------------------------------------
+
+const CalloutSchema = z.object({
+ variant: z.enum(["info", "success", "warning", "error"]).optional(),
+ title: z.string().optional(),
+ body: z.string(),
+});
+
+const CALLOUT_COLORS = {
+ info: { bg: "rgba(59,130,246,0.08)", border: "#3b82f6", icon: "i" },
+ success: { bg: "rgba(34,197,94,0.08)", border: "#22c55e", icon: "✓" },
+ warning: { bg: "rgba(234,179,8,0.10)", border: "#eab308", icon: "!" },
+ error: { bg: "rgba(239,68,68,0.08)", border: "#ef4444", icon: "✕" },
+};
+
+export const Callout = defineComponent({
+ name: "Callout",
+ props: CalloutSchema,
+ description:
+ "Highlight a finding next to a chart. `variant`: 'info' | 'success' | 'warning' | 'error'. Use to flag effect sizes, p-values, anomalies.",
+ component: ({ props }) => {
+ const v = props.variant ?? "info";
+ const c = CALLOUT_COLORS[v];
+ return (
+
+
{c.icon}
+
+ {props.title &&
{props.title}
}
+
{props.body}
+
+
+ );
+ },
+});
+
+// KPI -----------------------------------------------------------------------
+
+const KPISchema = z.object({
+ label: z.string(),
+ value: z.string(),
+ change: z.string().optional(),
+ changeDirection: z.enum(["up", "down", "flat"]).optional(),
+});
+
+export const KPI = defineComponent({
+ name: "KPI",
+ props: KPISchema,
+ description:
+ "Single big-number metric. `value` should already be formatted (e.g. '$1.26M'). Optional `change` (e.g. '+12.4%') with direction for up/down/flat coloring.",
+ component: ({ props }) => {
+ const dir = props.changeDirection ?? "flat";
+ const color = dir === "up" ? "#16a34a" : dir === "down" ? "#dc2626" : "rgba(15,23,42,0.55)";
+ return (
+
+
+ {props.label}
+
+
+ {props.value}
+
+ {props.change && (
+
+ {dir === "up" ? "↑" : dir === "down" ? "↓" : "→"} {props.change}
+
+ )}
+
+ );
+ },
+});
diff --git a/packages/plotly/src/library.ts b/packages/plotly/src/library.ts
new file mode 100644
index 000000000..06a7aa000
--- /dev/null
+++ b/packages/plotly/src/library.ts
@@ -0,0 +1,401 @@
+import { createLibrary } from "@openuidev/react-lang";
+
+import { Callout, Card, CardHeader, Heading, KPI, Stack, Text } from "./layout/Layout";
+
+// Tier 0/2 — escape hatches
+import { Figure } from "./figure/Figure";
+import { PlotlyJSON } from "./figure/PlotlyJSON";
+
+// Tier 1 — Cartesian
+import { Area } from "./traces/Area";
+import { Bar } from "./traces/Bar";
+import { Histogram } from "./traces/Histogram";
+import { Line } from "./traces/Line";
+import { Scatter } from "./traces/Scatter";
+
+// Tier 1 — Distributions
+import { Box } from "./traces/Box";
+import { Violin } from "./traces/Violin";
+
+// Tier 1 — Matrix & 2D-density
+import { Contour } from "./traces/Contour";
+import { Heatmap } from "./traces/Heatmap";
+import { Histogram2D } from "./traces/Histogram2D";
+import { Histogram2DContour } from "./traces/Histogram2DContour";
+
+// Tier 1 — Hierarchical
+import { Icicle } from "./traces/Icicle";
+import { Sunburst } from "./traces/Sunburst";
+import { Treemap } from "./traces/Treemap";
+
+// Tier 1 — Categorical / proportions
+import { Funnel } from "./traces/Funnel";
+import { FunnelArea } from "./traces/FunnelArea";
+import { Donut, Pie } from "./traces/Pie";
+import { Waterfall } from "./traces/Waterfall";
+
+// Tier 1 — Flow
+import { Sankey } from "./traces/Sankey";
+
+// Tier 1 — Multivariate
+import { ParCats } from "./traces/ParCats";
+import { ParCoords } from "./traces/ParCoords";
+import { ScatterMatrix } from "./traces/ScatterMatrix";
+
+// Tier 1 — Financial
+import { Candlestick } from "./traces/Candlestick";
+import { OHLC } from "./traces/OHLC";
+
+// Tier 1 — Polar
+import { BarPolar } from "./traces/BarPolar";
+import { ScatterPolar } from "./traces/ScatterPolar";
+
+// Tier 1 — Specialty coordinates
+import { ScatterSmith } from "./traces/ScatterSmith";
+import { ScatterTernary } from "./traces/ScatterTernary";
+
+// Carpet / ScatterCarpet / ContourCarpet are intentionally NOT registered as
+// Tier-1 components. They only render when a Carpet trace and a Carpet-overlay
+// trace coexist in the SAME figure — a constraint the openui-lang call site
+// can't express because each defineComponent invocation produces its own Plot.
+// Users who want carpet plots should compose them via Figure(...).
+
+// Tier 1 — WebGL
+import { ScatterGL } from "./traces/ScatterGL";
+import { ScatterPolarGL } from "./traces/ScatterPolarGL";
+
+// Tier 1 — Geo (cartesian projection only — tile-based map traces are gated
+// behind a future `@openuidev/plotly/geo` sub-entry because maplibre-gl's CSS
+// breaks Turbopack HMR.)
+import { Choropleth } from "./traces/Choropleth";
+import { ScatterGeo } from "./traces/ScatterGeo";
+// import { ChoroplethMap } from "./traces/ChoroplethMap";
+// import { ScatterMap } from "./traces/ScatterMap";
+// import { DensityMap } from "./traces/DensityMap";
+
+// Tier 1 — 3D
+import { Cone } from "./traces/Cone";
+import { Isosurface } from "./traces/Isosurface";
+import { Mesh3D } from "./traces/Mesh3D";
+import { Scatter3D } from "./traces/Scatter3D";
+import { StreamTube } from "./traces/StreamTube";
+import { Surface } from "./traces/Surface";
+import { Volume } from "./traces/Volume";
+
+// Tier 1 — Data display
+import { Indicator } from "./traces/Indicator";
+// Image trace disabled — plotly's image helpers require `buffer/` which doesn't
+// resolve under Next.js 16 + Turbopack. Re-enable when Plotly drops the polyfill
+// or when a Turbopack alias for `buffer/` becomes possible.
+import { Table } from "./traces/Table";
+
+export const plotlyComponentGroups = [
+ {
+ name: "Layout",
+ components: ["Stack", "Card", "CardHeader", "Heading", "Text", "Callout", "KPI"],
+ notes: [
+ "- Wrap each chart in a Card with a CardHeader for a titled section.",
+ '- Use Stack(direction="row", wrap=true) to lay charts side-by-side; Stack defaults to vertical.',
+ "- Use KPI for big-number metrics; Heading for dashboard titles; Callout for findings.",
+ ],
+ },
+ {
+ name: "Cartesian",
+ components: ["Bar", "Line", "Scatter", "Area", "Histogram"],
+ notes: [
+ "- Two ways to pass data:",
+ " • Express style: `data` is row objects, `x`/`y`/`color` are field names. Bar(rows, 'month', 'revenue', 'product').",
+ " • Graph-Objects style: `data` is null, `x`/`y`/`color` are parallel arrays. Bar(null, ['Jan','Feb'], [120, 150]).",
+ "- For grouped bars use barmode='group' (default); 'stack' to stack.",
+ ],
+ },
+ {
+ name: "Distributions",
+ components: ["Histogram", "Violin", "Box"],
+ notes: [
+ "- One-variable distribution: Histogram(rows, 'value', nbinsx?, color?).",
+ "- Compare across groups: Violin (shape) or Box (summary).",
+ "- Violin overlays a box plot by default — pass showBox=false to hide.",
+ ],
+ },
+ {
+ name: "Matrix & 2D-density",
+ components: ["Heatmap", "Histogram2D", "Histogram2DContour", "Contour"],
+ notes: [
+ "- Heatmap(z, x?, y?, colormap?) for a labeled matrix.",
+ "- Histogram2D / Histogram2DContour for density of a 2D scatter.",
+ "- Contour for a continuous scalar field z (rows×cols).",
+ "- colormap defaults to 'viridis'. Use a diverging map ('RdBu', 'BrBG', 'PiYG', 'spectral') only when zero is meaningful.",
+ ],
+ },
+ {
+ name: "Hierarchical",
+ components: ["Sunburst", "Treemap", "Icicle"],
+ notes: [
+ "- All three take parallel arrays: ids, parents (root parent is empty string ''), values, optional labels.",
+ "- Sunburst: radial; Treemap: rectangular; Icicle: rectangular like Treemap but stacked along an orientation.",
+ ],
+ },
+ {
+ name: "Categorical / proportions",
+ components: ["Pie", "Donut", "Funnel", "FunnelArea", "Waterfall"],
+ notes: [
+ "- Pie / Donut: parallel `values` and `labels`.",
+ "- Funnel: stages + values, with auto-computed conversion percentages.",
+ "- FunnelArea: triangular ribbon-style funnel.",
+ "- Waterfall: running totals with up/down deltas — `measure` per step ('relative'|'total'|'absolute').",
+ ],
+ },
+ {
+ name: "Flow",
+ components: ["Sankey"],
+ notes: [
+ "- Sankey takes nodes ([{id, label?, color?}]) and links ([{source, target, value}]) with ids referencing nodes.",
+ ],
+ },
+ {
+ name: "Multivariate",
+ components: ["ScatterMatrix", "ParCoords", "ParCats"],
+ notes: [
+ "- ScatterMatrix(rows, ['feature1','feature2','feature3'], color?) — pair plot.",
+ "- ParCoords for numeric multi-dimension comparison; ParCats for categorical multi-dimension flow.",
+ "- All three accept a row-objects `data` array + `dimensions` field names.",
+ ],
+ },
+ {
+ name: "Financial",
+ components: ["Candlestick", "OHLC"],
+ notes: [
+ "- Candlestick(x, open, high, low, close) — parallel arrays. OHLC has the same shape with a denser bar style.",
+ "- Pass showRangeSlider=true on Candlestick for a range slider.",
+ ],
+ },
+ {
+ name: "Polar",
+ components: ["ScatterPolar", "BarPolar"],
+ notes: [
+ "- ScatterPolar(r, theta, mode?) — also makes radar plots when fill='toself'.",
+ "- BarPolar(r, theta, width?) — wind-rose style.",
+ "- thetaUnit defaults to 'degrees'; pass 'radians' to switch.",
+ ],
+ },
+ {
+ name: "Specialty coordinates",
+ components: ["ScatterTernary", "ScatterSmith"],
+ notes: [
+ "- ScatterTernary: compositions in a triangle (chemistry, soil, mineralogy).",
+ "- ScatterSmith: complex impedance (RF/microwave engineering).",
+ "- For carpet plots (curvilinear grids with ScatterCarpet/ContourCarpet overlays), use Figure with the full Plotly trace JSON — they only render when the carpet and overlay traces coexist in one figure.",
+ ],
+ },
+ {
+ name: "WebGL accelerated",
+ components: ["ScatterGL", "ScatterPolarGL"],
+ notes: ["- Use these instead of Scatter / ScatterPolar when you have >10k points. Same API."],
+ },
+ {
+ name: "Geo",
+ components: ["Choropleth", "ScatterGeo"],
+ notes: [
+ "- Choropleth: country / state region shading using Plotly's natural-earth projection.",
+ "- ScatterGeo: points / great-circle paths on a globe.",
+ "- locationmode for Choropleth: 'ISO-3' (default), 'USA-states', 'country names', 'geojson-id'.",
+ ],
+ },
+ {
+ name: "3D",
+ components: ["Scatter3D", "Surface", "Mesh3D", "Cone", "StreamTube", "Isosurface", "Volume"],
+ notes: [
+ "- All 3D charts open with full mouse rotate/pan/zoom.",
+ "- Scatter3D for points/lines; Surface for z=f(x,y); Mesh3D for arbitrary point clouds.",
+ "- Cone / StreamTube for vector fields (x,y,z,u,v,w).",
+ "- Isosurface / Volume for 3D scalar fields (x,y,z,value).",
+ ],
+ },
+ {
+ name: "Data display",
+ components: ["Indicator", "Table"],
+ notes: [
+ "- Indicator: KPI alternative — `mode`: 'number' | 'delta' | 'gauge' | combinations. For deltas pass `reference`; for gauges pass `rangeMin`/`rangeMax`.",
+ "- Table is COLUMN-oriented — `values` is an array of columns where each column is an array of cells.",
+ ],
+ },
+ {
+ name: "Advanced (escape hatches)",
+ components: ["Figure", "PlotlyJSON"],
+ notes: [
+ "- Figure({ data: [...traces], layout: {...} }) for any composition the typed components don't cover (multi-trace overlays, subplots, dual axes, animation frames, custom polar shapes, …). Use full Plotly Graph-Objects schema.",
+ "- PlotlyJSON({ figure }) renders a Plotly figure JSON object verbatim — useful when a backend tool returns a precomputed figure (e.g. Python `fig.to_json()`).",
+ ],
+ },
+];
+
+export const plotlyExamples = [
+ `Example — Bar chart (Express style):
+
+root = Card([CardHeader("Q4 revenue"), b])
+b = Bar(rows, "month", "revenue", "product", null, "group", null, "month", "revenue ($)")
+rows = [
+ {month: "Oct", revenue: 1200, product: "A"},
+ {month: "Oct", revenue: 980, product: "B"},
+ {month: "Nov", revenue: 1500, product: "A"},
+ {month: "Nov", revenue: 1100, product: "B"},
+ {month: "Dec", revenue: 1800, product: "A"},
+ {month: "Dec", revenue: 1400, product: "B"}
+]`,
+
+ `Example — Histogram and Violin in two cards:
+
+root = Stack([h1, row])
+h1 = Heading("Latency analysis", "h1")
+row = Stack([histCard, violCard], "row", 12, true)
+histCard = Card([CardHeader("Distribution"), hist])
+violCard = Card([CardHeader("By region"), viol])
+hist = Histogram(null, latencies, null, 30, null, null, "Latency", "ms", "Count")
+viol = Violin(rows, "region", "latency_ms", null, true, "all")
+latencies = [120, 135, 142, 158, 175, 195, 220, 245, 280, 310]
+rows = [{region:"US", latency_ms: 120}, {region:"EU", latency_ms: 195}, {region:"APAC", latency_ms: 280}]`,
+
+ `Example — Correlation heatmap (diverging colormap):
+
+root = Card([CardHeader("Feature correlations"), hm])
+hm = Heatmap(matrix, features, features, "RdBu", -1, 1, true, ".2f", "Correlation (Pearson r)")
+features = ["sepal_len", "sepal_wid", "petal_len", "petal_wid"]
+matrix = [
+ [1.00, -0.12, 0.87, 0.82],
+ [-0.12, 1.00, -0.43, -0.36],
+ [0.87, -0.43, 1.00, 0.96],
+ [0.82, -0.36, 0.96, 1.00]
+]`,
+
+ `Example — Sankey funnel:
+
+root = Card([CardHeader("User funnel"), s])
+s = Sankey(nodes, links, "Q4 conversion", 360)
+nodes = [{id:"visit", label:"Visit"}, {id:"signup", label:"Sign up"}, {id:"trial", label:"Trial"}, {id:"paid", label:"Paid"}]
+links = [{source:"visit", target:"signup", value:1200}, {source:"signup", target:"trial", value:480}, {source:"trial", target:"paid", value:140}]`,
+
+ `Example — Sunburst hierarchy:
+
+root = Sunburst(ids, parents, values, labels, "remainder", null, "Engineering org")
+ids = ["eng", "eng-platform", "eng-product", "eng-platform-data", "eng-platform-infra", "eng-product-web", "eng-product-mobile"]
+parents = ["", "eng", "eng", "eng-platform", "eng-platform", "eng-product", "eng-product"]
+values = [0, 0, 0, 14, 9, 22, 11]
+labels = ["Engineering", "Platform", "Product", "Data", "Infra", "Web", "Mobile"]`,
+
+ `Example — KPI dashboard:
+
+root = Stack([head, kpiRow, chart])
+head = Heading("Q4 dashboard", "h1")
+kpiRow = Stack([k1, k2, k3], "row", 12)
+k1 = KPI("Active users", "48,120", "+8.4%", "up")
+k2 = KPI("Conversion", "3.84%", "-0.2pp", "down")
+k3 = KPI("Net revenue", "$1.26M", "+12.4%", "up")
+chart = Card([CardHeader("Revenue by month"), Bar(rows, "month", "revenue")])
+rows = [{month:"Oct", revenue:1200000}, {month:"Nov", revenue:1500000}, {month:"Dec", revenue:1800000}]`,
+
+ `Example — escape hatch via Figure (polar wind-rose with multiple traces):
+
+root = Card([CardHeader("Polar wind rose"), poly])
+poly = Figure([t1, t2], {polar: {radialaxis: {ticksuffix: " mph"}}}, null, 360)
+t1 = {type: "barpolar", r: [77, 32, 11, 5], theta: ["N", "E", "S", "W"], width: [80, 80, 80, 80], marker: {color: "#4c78a8"}, name: "Calm"}
+t2 = {type: "barpolar", r: [44, 18, 6, 3], theta: ["N", "E", "S", "W"], width: [80, 80, 80, 80], marker: {color: "#f58518"}, name: "Windy"}`,
+];
+
+export const plotlyAdditionalRules = [
+ "Hard limit: do not emit more than ~25 chart components in a single response. Comprehensive tours quickly exceed the parser's reference budget and produce broken charts. If the user asks for 'all components', give them 5–8 representative ones plus a sentence offering to render any specific type on request.",
+ "Never emit a chart whose data is purely a placeholder reference (e.g. `Bar(rows, 'x', 'y')` where `rows` is undefined). EVERY chart component in your output MUST be paired with a concrete `rows = [...]` or `arr = [...]` definition that resolves locally — otherwise the chart will render as 'No data'.",
+ "If the user asks 'what can you do?' or similar capability questions, prefer Markdown / Text describing the catalog over rendering empty cards. Render actual charts only when there's data.",
+ "Express style is preferred when the data is naturally row-oriented (each object is a row). Pass `data` as the array of objects and use field names for `x`, `y`, `color`. The LLM should NOT pre-flatten data into parallel arrays unless the user already provided data that way.",
+ "Graph-Objects style (data=null, x/y as raw arrays) is fine for small literal datasets and pasted columns.",
+ "Always wrap each chart in a Card with a CardHeader carrying a concise title. Use the chart's xLabel/yLabel for axis units (e.g. 'response (mV)').",
+ "Use diverging colormaps ('RdBu', 'BrBG', 'PiYG', 'spectral') ONLY when zero is a meaningful midpoint (correlations, log fold-change). For ordinal/quantitative data without a special zero, prefer perceptually uniform sequential maps: 'viridis' (default), 'inferno', 'plasma', 'magma', 'cividis', 'turbo'.",
+ "When the user has raw samples per group, prefer Violin or Box. When they have summary stats already (mean ± sd), prefer Bar with explicit error bars via Figure.",
+ "For any chart the typed components don't cover (multi-trace overlays, subplots, dual axes, animation frames, custom polar/ternary layouts, advanced 3D scenes, custom hovertemplates), use Figure with full Plotly trace + layout JSON.",
+ "Pair charts with a short prose interpretation in Text or a Callout when reporting a finding.",
+ "Sunburst/Treemap/Icicle parents arrays: the root node MUST have an empty string '' as its parent.",
+ "Sankey link source/target are NODE IDS, not indices. The renderer translates to indices.",
+ "For >10k points use ScatterGL / ScatterPolarGL instead of Scatter / ScatterPolar.",
+ "Choropleth with country data: `locationmode='ISO-3'` and 3-letter ISO codes (USA, FRA, JPN). For US states use 'USA-states' and two-letter codes (CA, TX, NY).",
+];
+
+export const plotlyPromptOptions = {
+ examples: plotlyExamples,
+ additionalRules: plotlyAdditionalRules,
+};
+
+export const plotlyLibrary = createLibrary({
+ root: "Stack",
+ componentGroups: plotlyComponentGroups,
+ components: [
+ // Layout
+ Stack,
+ Card,
+ CardHeader,
+ Heading,
+ Text,
+ Callout,
+ KPI,
+ // Cartesian
+ Bar,
+ Line,
+ Scatter,
+ Area,
+ Histogram,
+ // Distributions
+ Violin,
+ Box,
+ // Matrix / 2D density
+ Heatmap,
+ Histogram2D,
+ Histogram2DContour,
+ Contour,
+ // Hierarchical
+ Sunburst,
+ Treemap,
+ Icicle,
+ // Categorical / proportions
+ Pie,
+ Donut,
+ Funnel,
+ FunnelArea,
+ Waterfall,
+ // Flow
+ Sankey,
+ // Multivariate
+ ScatterMatrix,
+ ParCoords,
+ ParCats,
+ // Financial
+ Candlestick,
+ OHLC,
+ // Polar
+ ScatterPolar,
+ BarPolar,
+ // Specialty coords
+ ScatterTernary,
+ ScatterSmith,
+ // WebGL
+ ScatterGL,
+ ScatterPolarGL,
+ // Geo (cartesian projection only — tile-map traces gated behind future sub-entry)
+ Choropleth,
+ ScatterGeo,
+ // 3D
+ Scatter3D,
+ Surface,
+ Mesh3D,
+ Cone,
+ StreamTube,
+ Isosurface,
+ Volume,
+ // Data display
+ Indicator,
+ Table,
+ // Advanced
+ Figure,
+ PlotlyJSON,
+ ],
+});
+
+export type PlotlyLibrary = typeof plotlyLibrary;
diff --git a/packages/plotly/src/shell/PlotShell.tsx b/packages/plotly/src/shell/PlotShell.tsx
new file mode 100644
index 000000000..284190cc7
--- /dev/null
+++ b/packages/plotly/src/shell/PlotShell.tsx
@@ -0,0 +1,183 @@
+"use client";
+import type { ActionPlan } from "@openuidev/react-lang";
+import { useIsStreaming, useTriggerAction } from "@openuidev/react-lang";
+import type {
+ Config,
+ Data,
+ Layout,
+ PlotMouseEvent,
+ PlotRelayoutEvent,
+ PlotSelectionEvent,
+} from "plotly.js";
+import React from "react";
+import { ChartSkeleton, NoDataNotice } from "./skeleton";
+import { defaultConfig, lightTemplate } from "./template";
+
+// Single React.lazy Plot component shared by every chart in the library.
+// Dynamic imports of plotly.js-dist-min and react-plotly.js stay dynamic at
+// build time — neither module is touched at SSR / module-load time, only when
+// React actually mounts the lazy component on the client. This is essential
+// because plotly.js-dist-min references `self` at top level and would crash
+// any Node SSR pass that statically imports it.
+const Plot = React.lazy(async () => {
+ const [{ default: Plotly }, { default: createPlotlyComponent }] = await Promise.all([
+ import("plotly.js-dist-min"),
+ import("react-plotly.js/factory"),
+ ]);
+ return { default: createPlotlyComponent(Plotly) };
+});
+
+export interface PlotShellProps {
+ data: Data[];
+ layout?: Partial;
+ config?: Partial;
+ height?: number;
+ /** Optional openui-lang ActionPlan fired on plotly_click. */
+ onClick?: ActionPlan;
+ /** Optional openui-lang ActionPlan fired on plotly_selected (lasso/box select). */
+ onSelected?: ActionPlan;
+ /** Optional openui-lang ActionPlan fired on plotly_relayout (zoom/pan). */
+ onRelayout?: ActionPlan;
+ /** Bumped on each render to force Plotly's diff path; built-in default is fine. */
+ revision?: number;
+}
+
+const HASH_SAMPLE_LIMIT = 6;
+
+// Cheap content hash to bump datarevision so Plotly always diffs even if
+// the parent passes the same array reference (defensive for streaming edits).
+function quickHash(data: Data[], layout?: Partial): number {
+ let h = 0;
+ const str =
+ JSON.stringify(
+ data.map((trace) => {
+ const t = trace as Record;
+ return {
+ type: t["type"],
+ // sample the first few values of x/y/values rather than the full arrays
+ x: Array.isArray(t["x"]) ? (t["x"] as unknown[]).slice(0, HASH_SAMPLE_LIMIT) : undefined,
+ y: Array.isArray(t["y"]) ? (t["y"] as unknown[]).slice(0, HASH_SAMPLE_LIMIT) : undefined,
+ values: Array.isArray(t["values"])
+ ? (t["values"] as unknown[]).slice(0, HASH_SAMPLE_LIMIT)
+ : undefined,
+ };
+ }),
+ ) + (layout ? JSON.stringify(layout.title ?? "") : "");
+ for (let i = 0; i < str.length; i++) {
+ h = ((h << 5) - h + str.charCodeAt(i)) | 0;
+ }
+ return h;
+}
+
+// Extract the small, stable subset of Plotly's event payload that's useful in
+// an Action context. Plotly's full payload is huge and unstable across versions.
+function extractPoints(e: PlotMouseEvent | PlotSelectionEvent): Record {
+ const points = (e?.points ?? []).slice(0, 50).map((p) => {
+ const point = p as unknown as {
+ x?: unknown;
+ y?: unknown;
+ label?: unknown;
+ value?: unknown;
+ pointIndex?: number;
+ pointNumber?: number;
+ curveNumber?: number;
+ customdata?: unknown;
+ };
+ return {
+ x: point.x,
+ y: point.y,
+ label: point.label,
+ value: point.value,
+ pointIndex: point.pointIndex ?? point.pointNumber,
+ curveNumber: point.curveNumber,
+ customdata: point.customdata,
+ };
+ });
+ return { points };
+}
+
+export function PlotShell({
+ data,
+ layout,
+ config,
+ height = 320,
+ onClick,
+ onSelected,
+ onRelayout,
+ revision,
+}: PlotShellProps) {
+ const isStreaming = useIsStreaming();
+ const triggerAction = useTriggerAction();
+
+ const hasData = Array.isArray(data) && data.length > 0;
+
+ // No data + still streaming → loading skeleton (data may arrive any moment).
+ // No data + stream finished → "No data" notice (data is never coming; usually
+ // an unresolved variable in the LLM's openui-lang).
+ if (!hasData) {
+ return isStreaming ? (
+
+ ) : (
+
+ );
+ }
+
+ const merged: Partial = {
+ ...lightTemplate,
+ ...layout,
+ // Keep nested overrides composable
+ xaxis: { ...lightTemplate.xaxis, ...(layout?.xaxis ?? {}) },
+ yaxis: { ...lightTemplate.yaxis, ...(layout?.yaxis ?? {}) },
+ legend: { ...lightTemplate.legend, ...(layout?.legend ?? {}) },
+ hoverlabel: { ...lightTemplate.hoverlabel, ...(layout?.hoverlabel ?? {}) },
+ title: {
+ ...(lightTemplate.title ?? {}),
+ ...(typeof layout?.title === "string" ? { text: layout.title } : (layout?.title ?? {})),
+ },
+ datarevision: revision ?? quickHash(data, layout),
+ autosize: true,
+ };
+
+ const mergedConfig: Partial = { ...defaultConfig, ...config };
+
+ return (
+
+
}>
+
+ triggerAction("plotly_click", undefined, {
+ type: "plotly_click",
+ params: extractPoints(e),
+ })
+ : undefined
+ }
+ onSelected={
+ onSelected
+ ? (e) =>
+ triggerAction("plotly_selected", undefined, {
+ type: "plotly_selected",
+ params: e ? extractPoints(e) : { points: [] },
+ })
+ : undefined
+ }
+ onRelayout={
+ onRelayout
+ ? (e: PlotRelayoutEvent) =>
+ triggerAction("plotly_relayout", undefined, {
+ type: "plotly_relayout",
+ params: e as Record,
+ })
+ : undefined
+ }
+ />
+
+
+ );
+}
diff --git a/packages/plotly/src/shell/colormap.ts b/packages/plotly/src/shell/colormap.ts
new file mode 100644
index 000000000..9a67c4005
--- /dev/null
+++ b/packages/plotly/src/shell/colormap.ts
@@ -0,0 +1,49 @@
+// Map LLM-friendly colormap names onto Plotly colorscale arrays.
+// Plotly accepts a string ("Viridis", "RdBu", …) for built-ins; we lower-case
+// and translate so the LLM can write `colormap: "viridis"` and we hand Plotly
+// what it actually wants. We also accept arbitrary strings that Plotly knows
+// natively, falling back to the value verbatim.
+
+import type { ColorScale } from "plotly.js";
+
+// Sequential and diverging colormaps Plotly ships natively.
+const NATIVE_NAME_MAP: Record = {
+ // sequential — perceptually uniform
+ viridis: "Viridis",
+ inferno: "Inferno",
+ plasma: "Plasma",
+ magma: "Magma",
+ cividis: "Cividis",
+ turbo: "Turbo",
+
+ // sequential — branded
+ blues: "Blues",
+ greens: "Greens",
+ oranges: "Oranges",
+ purples: "Purples",
+ greys: "Greys",
+ reds: "Reds",
+ ylorrd: "YlOrRd",
+ ylgnbu: "YlGnBu",
+
+ // diverging
+ rdbu: "RdBu",
+ brbg: "BrBG",
+ piyg: "PiYG",
+ spectral: "Spectral",
+ rdylgn: "RdYlGn",
+ rdylbu: "RdYlBu",
+};
+
+const DIVERGING = new Set(["rdbu", "brbg", "piyg", "spectral", "rdylgn", "rdylbu"]);
+
+export function resolveColormap(name?: string): string | ColorScale | undefined {
+ if (!name) return undefined;
+ const key = name.toLowerCase();
+ return NATIVE_NAME_MAP[key] ?? name;
+}
+
+export function isDivergingColormap(name?: string): boolean {
+ if (!name) return false;
+ return DIVERGING.has(name.toLowerCase());
+}
diff --git a/packages/plotly/src/shell/skeleton.tsx b/packages/plotly/src/shell/skeleton.tsx
new file mode 100644
index 000000000..e529a8d4d
--- /dev/null
+++ b/packages/plotly/src/shell/skeleton.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+interface ChartSkeletonProps {
+ height?: number;
+}
+
+export function ChartSkeleton({ height = 320 }: ChartSkeletonProps) {
+ return (
+
+ );
+}
+
+interface NoDataProps {
+ height?: number;
+ reason?: string;
+}
+
+// Distinct from ChartSkeleton — used when streaming has finished and the chart
+// genuinely received no data (e.g. an unresolved reference in the openui-lang).
+export function NoDataNotice({ height = 160, reason }: NoDataProps) {
+ return (
+
+
No data
+
+ {reason ??
+ "This chart did not receive any traces. The model may have referenced an unresolved variable."}
+
+
+ );
+}
diff --git a/packages/plotly/src/shell/template.ts b/packages/plotly/src/shell/template.ts
new file mode 100644
index 000000000..245f73de2
--- /dev/null
+++ b/packages/plotly/src/shell/template.ts
@@ -0,0 +1,110 @@
+// OpenUI-flavored Plotly templates. Light and dark variants. Merged into every
+// chart's `layout` so the LLM never has to author chart styling — only data.
+
+import type { Layout } from "plotly.js";
+
+const SYSTEM_FONT_STACK =
+ 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
+
+const OPENUI_PALETTE = [
+ "#4c78a8",
+ "#f58518",
+ "#54a24b",
+ "#e45756",
+ "#72b7b2",
+ "#eeca3b",
+ "#b279a2",
+ "#ff9da6",
+ "#9d755d",
+ "#bab0ac",
+ "#5b8ff9",
+ "#a3a637",
+];
+
+export const lightTemplate: Partial = {
+ font: { family: SYSTEM_FONT_STACK, size: 12, color: "#0f172a" },
+ paper_bgcolor: "transparent",
+ plot_bgcolor: "transparent",
+ margin: { t: 16, r: 16, b: 40, l: 56, pad: 0 },
+ colorway: OPENUI_PALETTE,
+ xaxis: {
+ gridcolor: "rgba(15,23,42,0.06)",
+ linecolor: "rgba(15,23,42,0.18)",
+ tickcolor: "rgba(15,23,42,0.18)",
+ tickfont: { size: 10.5, color: "rgba(15,23,42,0.6)" },
+ title: { font: { size: 12, color: "rgba(15,23,42,0.8)" } },
+ zeroline: false,
+ automargin: true,
+ },
+ yaxis: {
+ gridcolor: "rgba(15,23,42,0.06)",
+ linecolor: "rgba(15,23,42,0.18)",
+ tickcolor: "rgba(15,23,42,0.18)",
+ tickfont: { size: 10.5, color: "rgba(15,23,42,0.6)" },
+ title: { font: { size: 12, color: "rgba(15,23,42,0.8)" } },
+ zeroline: false,
+ automargin: true,
+ },
+ legend: {
+ font: { size: 11, color: "rgba(15,23,42,0.85)" },
+ bgcolor: "transparent",
+ bordercolor: "rgba(15,23,42,0.10)",
+ borderwidth: 0,
+ },
+ hoverlabel: {
+ bgcolor: "white",
+ bordercolor: "rgba(15,23,42,0.12)",
+ font: { family: SYSTEM_FONT_STACK, size: 12, color: "#0f172a" },
+ align: "left",
+ },
+ title: {
+ font: { family: SYSTEM_FONT_STACK, size: 14, color: "#0f172a" },
+ x: 0,
+ xanchor: "left",
+ pad: { l: 0, t: 0, r: 0, b: 8 },
+ },
+ transition: { duration: 220, easing: "cubic-in-out" },
+ modebar: {
+ bgcolor: "transparent",
+ color: "rgba(15,23,42,0.45)",
+ activecolor: "rgba(15,23,42,0.85)",
+ },
+};
+
+// Dark template — same shape, swap surface and ink.
+export const darkTemplate: Partial = {
+ ...lightTemplate,
+ font: { family: SYSTEM_FONT_STACK, size: 12, color: "#e2e8f0" },
+ xaxis: {
+ ...lightTemplate.xaxis,
+ gridcolor: "rgba(226,232,240,0.07)",
+ linecolor: "rgba(226,232,240,0.22)",
+ tickcolor: "rgba(226,232,240,0.22)",
+ tickfont: { size: 10.5, color: "rgba(226,232,240,0.6)" },
+ title: { font: { size: 12, color: "rgba(226,232,240,0.8)" } },
+ },
+ yaxis: {
+ ...lightTemplate.yaxis,
+ gridcolor: "rgba(226,232,240,0.07)",
+ linecolor: "rgba(226,232,240,0.22)",
+ tickcolor: "rgba(226,232,240,0.22)",
+ tickfont: { size: 10.5, color: "rgba(226,232,240,0.6)" },
+ title: { font: { size: 12, color: "rgba(226,232,240,0.8)" } },
+ },
+ hoverlabel: {
+ bgcolor: "#0f172a",
+ bordercolor: "rgba(226,232,240,0.18)",
+ font: { family: SYSTEM_FONT_STACK, size: 12, color: "#e2e8f0" },
+ align: "left",
+ },
+};
+
+import type { Config } from "plotly.js";
+
+export const defaultConfig: Partial = {
+ displayModeBar: false,
+ displaylogo: false,
+ responsive: true,
+ doubleClick: "reset",
+ scrollZoom: false,
+};
diff --git a/packages/plotly/src/traces/Area.ts b/packages/plotly/src/traces/Area.ts
new file mode 100644
index 000000000..362e469db
--- /dev/null
+++ b/packages/plotly/src/traces/Area.ts
@@ -0,0 +1,54 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const AreaSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.union([z.string(), z.number()])), z.string()]),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ stack: z.boolean().optional(),
+ groupnorm: z.enum(["", "fraction", "percent"]).optional(),
+ smooth: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Area = defineComponent({
+ name: "Area",
+ props: AreaSchema,
+ description:
+ "Filled area chart. `stack=true` stacks multiple series into a stream. `groupnorm`: 'percent' to normalize stacks to 100%, 'fraction' for 0..1, '' for raw values. `smooth=true` uses spline interpolation.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const traces: Data[] = groups.map((g, i) => ({
+ type: "scatter",
+ mode: "lines",
+ x: g.x as Array,
+ y: g.y as number[],
+ name: g.group || undefined,
+ fill: props.stack ? "tonexty" : i === 0 ? "tozeroy" : "tonexty",
+ stackgroup: props.stack ? "one" : undefined,
+ groupnorm: props.stack ? props.groupnorm : undefined,
+ line: props.smooth ? { shape: "spline", smoothing: 1 } : undefined,
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Bar.ts b/packages/plotly/src/traces/Bar.ts
new file mode 100644
index 000000000..a30825854
--- /dev/null
+++ b/packages/plotly/src/traces/Bar.ts
@@ -0,0 +1,51 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const BarSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.union([z.string(), z.number()])), z.string()]),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ orientation: z.enum(["v", "h"]).optional(),
+ barmode: z.enum(["group", "stack", "overlay", "relative"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Bar = defineComponent({
+ name: "Bar",
+ props: BarSchema,
+ description:
+ "Bar chart (Plotly Express style). Two ways to pass data: (1) `data` as an array of objects + `x`/`y` as field names, e.g. Bar(rows, 'month', 'revenue'); (2) `x`/`y` as parallel arrays directly, e.g. Bar(null, ['Jan','Feb','Mar'], [120, 150, 180]). `color` field/array adds grouping. `barmode` controls grouping behaviour: 'group' (default), 'stack', 'overlay', 'relative'.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const orientation = props.orientation ?? "v";
+ const traces: Data[] = groups.map((g) => ({
+ type: "bar",
+ orientation,
+ x: orientation === "v" ? (g.x as Array) : (g.y as number[]),
+ y: orientation === "v" ? (g.y as number[]) : (g.x as Array),
+ name: g.group || undefined,
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ barmode: props.barmode ?? "group",
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/BarPolar.ts b/packages/plotly/src/traces/BarPolar.ts
new file mode 100644
index 000000000..513a56609
--- /dev/null
+++ b/packages/plotly/src/traces/BarPolar.ts
@@ -0,0 +1,38 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const BarPolarSchema = z.object({
+ r: z.array(z.number()),
+ theta: z.union([z.array(z.number()), z.array(z.string())]),
+ width: z.union([z.number(), z.array(z.number())]).optional(),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const BarPolar = defineComponent({
+ name: "BarPolar",
+ props: BarPolarSchema,
+ description:
+ "Polar bar chart (a.k.a. wind-rose, radial bar chart). Pass parallel `r` (bar lengths) and `theta` (bar angles, degrees). `width` controls bar widths.",
+ component: ({ props }) => {
+ const trace = {
+ type: "barpolar",
+ r: props.r,
+ theta: props.theta,
+ width: props.width as never,
+ marker: props.color ? { color: props.color } : undefined,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ polar: { angularaxis: { direction: "clockwise" } },
+ showlegend: false,
+ margin: { t: props.title ? 40 : 16, l: 16, r: 16, b: 16 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Box.ts b/packages/plotly/src/traces/Box.ts
new file mode 100644
index 000000000..81426442a
--- /dev/null
+++ b/packages/plotly/src/traces/Box.ts
@@ -0,0 +1,62 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const BoxSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.string()), z.string()]).optional(),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ showPoints: z.union([z.boolean(), z.enum(["all", "outliers", "suspectedoutliers"])]).optional(),
+ notched: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Box = defineComponent({
+ name: "Box",
+ props: BoxSchema,
+ description:
+ "Box plot (Q1/median/Q3, 1.5×IQR whiskers, outliers). Pass `y` and optionally `x` (group field/array). `showPoints`: 'all' | 'outliers' (default) | true | false. `notched=true` for confidence-interval notches around the median. Use Violin when distribution shape matters; Box when summary suffices.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x ?? props.y,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const points =
+ props.showPoints === undefined
+ ? "outliers"
+ : props.showPoints === true
+ ? "all"
+ : props.showPoints === false
+ ? false
+ : props.showPoints;
+ const traces: Data[] = groups.map((g) => ({
+ type: "box",
+ x:
+ typeof props.x === "string" || Array.isArray(props.x)
+ ? (g.x as Array)
+ : undefined,
+ y: g.y as number[],
+ name: g.group || undefined,
+ boxpoints: points as never,
+ notched: props.notched,
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ boxmode: "group",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Candlestick.ts b/packages/plotly/src/traces/Candlestick.ts
new file mode 100644
index 000000000..dd52188fe
--- /dev/null
+++ b/packages/plotly/src/traces/Candlestick.ts
@@ -0,0 +1,54 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const CandlestickSchema = z.object({
+ x: z.array(z.union([z.string(), z.number()])),
+ open: z.array(z.number()),
+ high: z.array(z.number()),
+ low: z.array(z.number()),
+ close: z.array(z.number()),
+ upColor: z.string().optional(),
+ downColor: z.string().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ showRangeSlider: z.boolean().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Candlestick = defineComponent({
+ name: "Candlestick",
+ props: CandlestickSchema,
+ description:
+ "OHLC candlestick chart. Pass parallel arrays: `x` (timestamps or labels), `open`, `high`, `low`, `close`. Up days fill green, down days red — override with `upColor`/`downColor`. `showRangeSlider=true` adds a Plotly range slider below the chart.",
+ component: ({ props }) => {
+ if (!props.x?.length) return null;
+ const trace = {
+ type: "candlestick",
+ x: props.x as Array,
+ open: props.open,
+ high: props.high,
+ low: props.low,
+ close: props.close,
+ increasing: {
+ line: { color: props.upColor ?? "#16a34a" },
+ fillcolor: props.upColor ?? "#16a34a",
+ },
+ decreasing: {
+ line: { color: props.downColor ?? "#dc2626" },
+ fillcolor: props.downColor ?? "#dc2626",
+ },
+ } as unknown as Data;
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ xaxis: { rangeslider: { visible: props.showRangeSlider ?? false } },
+ showlegend: false,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Carpet.ts b/packages/plotly/src/traces/Carpet.ts
new file mode 100644
index 000000000..e2e4f5389
--- /dev/null
+++ b/packages/plotly/src/traces/Carpet.ts
@@ -0,0 +1,37 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const CarpetSchema = z.object({
+ a: z.array(z.number()),
+ b: z.array(z.number()),
+ x: z.array(z.array(z.number())).optional(),
+ y: z.array(z.array(z.number())).optional(),
+ carpet: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Carpet = defineComponent({
+ name: "Carpet",
+ props: CarpetSchema,
+ description:
+ "Carpet grid (a,b) — the underlying coordinate system for ScatterCarpet and ContourCarpet. Pass `a`/`b` axis values; `x`/`y` are 2D arrays specifying the grid's mapping to cartesian space. `carpet` is the id used by overlaid traces.",
+ component: ({ props }) => {
+ const trace = {
+ type: "carpet",
+ carpet: props.carpet ?? "carpet1",
+ a: props.a,
+ b: props.b,
+ x: props.x,
+ y: props.y,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Choropleth.ts b/packages/plotly/src/traces/Choropleth.ts
new file mode 100644
index 000000000..5c2b5dae4
--- /dev/null
+++ b/packages/plotly/src/traces/Choropleth.ts
@@ -0,0 +1,50 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const ChoroplethSchema = z.object({
+ locations: z.array(z.string()),
+ z: z.array(z.number()),
+ locationmode: z.enum(["ISO-3", "USA-states", "country names", "geojson-id"]).optional(),
+ scope: z
+ .enum(["world", "usa", "europe", "asia", "africa", "north america", "south america"])
+ .optional(),
+ colormap: z.string().optional(),
+ zmin: z.number().optional(),
+ zmax: z.number().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Choropleth = defineComponent({
+ name: "Choropleth",
+ props: ChoroplethSchema,
+ description:
+ "Choropleth map (region color shading). Pass `locations` (e.g. ISO-3 country codes or US state codes) and parallel `z` values. `locationmode` defaults to 'ISO-3'; use 'USA-states' for two-letter US codes. `scope` zooms the map to a region.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "choropleth",
+ locations: props.locations,
+ z: props.z,
+ locationmode: (props.locationmode ?? "ISO-3") as never,
+ colorscale: resolveColormap(props.colormap ?? "viridis") as never,
+ zmin: props.zmin,
+ zmax: props.zmax,
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ geo: {
+ scope: props.scope ?? "world",
+ showframe: false,
+ projection: { type: "natural earth" },
+ } as never,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 380 });
+ },
+});
diff --git a/packages/plotly/src/traces/ChoroplethMap.ts b/packages/plotly/src/traces/ChoroplethMap.ts
new file mode 100644
index 000000000..21eb09a13
--- /dev/null
+++ b/packages/plotly/src/traces/ChoroplethMap.ts
@@ -0,0 +1,53 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const ChoroplethMapSchema = z.object({
+ geojson: z.unknown(),
+ locations: z.array(z.string()),
+ z: z.array(z.number()),
+ featureidkey: z.string().optional(),
+ colormap: z.string().optional(),
+ zmin: z.number().optional(),
+ zmax: z.number().optional(),
+ centerLat: z.number().optional(),
+ centerLon: z.number().optional(),
+ zoom: z.number().min(0).max(22).optional(),
+ style: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ChoroplethMap = defineComponent({
+ name: "ChoroplethMap",
+ props: ChoroplethMapSchema,
+ description:
+ "Choropleth on an interactive MapLibre map using a custom GeoJSON FeatureCollection. Pass `geojson` (FeatureCollection), `locations` (feature ids), parallel `z` values, optional `featureidkey` (defaults to 'id', e.g. 'properties.name'). Combine with map zoom/center for region focus.",
+ component: ({ props }) => {
+ const trace = {
+ type: "choroplethmap",
+ geojson: props.geojson,
+ locations: props.locations,
+ z: props.z,
+ featureidkey: props.featureidkey,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ zmin: props.zmin,
+ zmax: props.zmax,
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ } as unknown as Data;
+ const layout = {
+ title: props.title ? { text: props.title } : undefined,
+ map: {
+ style: props.style ?? "open-street-map",
+ center: { lat: props.centerLat ?? 0, lon: props.centerLon ?? 0 },
+ zoom: props.zoom ?? 1,
+ },
+ margin: { t: props.title ? 32 : 0, l: 0, r: 0, b: 0 },
+ } as unknown as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Cone.ts b/packages/plotly/src/traces/Cone.ts
new file mode 100644
index 000000000..c41546f43
--- /dev/null
+++ b/packages/plotly/src/traces/Cone.ts
@@ -0,0 +1,47 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const ConeSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ u: z.array(z.number()),
+ v: z.array(z.number()),
+ w: z.array(z.number()),
+ colormap: z.string().optional(),
+ sizemode: z.enum(["scaled", "absolute"]).optional(),
+ sizeref: z.number().positive().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Cone = defineComponent({
+ name: "Cone",
+ props: ConeSchema,
+ description:
+ "3D vector field as cones (arrows). At each `(x, y, z)` location, draws a cone in the direction `(u, v, w)`. Common for fluid dynamics, electromagnetics, gradient fields.",
+ component: ({ props }) => {
+ const trace = {
+ type: "cone",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ u: props.u,
+ v: props.v,
+ w: props.w,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ sizemode: props.sizemode ?? "scaled",
+ sizeref: props.sizeref ?? 1,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Contour.ts b/packages/plotly/src/traces/Contour.ts
new file mode 100644
index 000000000..13cafcfe2
--- /dev/null
+++ b/packages/plotly/src/traces/Contour.ts
@@ -0,0 +1,54 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const ContourSchema = z.object({
+ z: z.array(z.array(z.number())),
+ x: z.array(z.union([z.string(), z.number()])).optional(),
+ y: z.array(z.union([z.string(), z.number()])).optional(),
+ ncontours: z.number().int().positive().optional(),
+ start: z.number().optional(),
+ end: z.number().optional(),
+ step: z.number().optional(),
+ colormap: z.string().optional(),
+ showLines: z.boolean().optional(),
+ showLabels: z.boolean().optional(),
+ filled: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Contour = defineComponent({
+ name: "Contour",
+ props: ContourSchema,
+ description:
+ "Contour plot of a 2D scalar field `z` (rows×cols). `start`/`end`/`step` define explicit contour levels; otherwise `ncontours` controls auto-leveling. `filled=false` to draw lines only; `showLabels=true` to label contour lines with their value.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "contour",
+ z: props.z,
+ x: props.x as Array | undefined,
+ y: props.y as Array | undefined,
+ ncontours: props.ncontours,
+ contours: {
+ start: props.start,
+ end: props.end,
+ size: props.step,
+ showlines: props.showLines ?? true,
+ showlabels: props.showLabels ?? false,
+ coloring: props.filled === false ? "lines" : "fill",
+ },
+ colorscale: resolveColormap(props.colormap ?? "viridis") as never,
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ };
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ContourCarpet.ts b/packages/plotly/src/traces/ContourCarpet.ts
new file mode 100644
index 000000000..c87ea665d
--- /dev/null
+++ b/packages/plotly/src/traces/ContourCarpet.ts
@@ -0,0 +1,40 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const ContourCarpetSchema = z.object({
+ carpet: z.string(),
+ a: z.array(z.number()),
+ b: z.array(z.number()),
+ z: z.array(z.number()),
+ ncontours: z.number().int().positive().optional(),
+ colormap: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ContourCarpet = defineComponent({
+ name: "ContourCarpet",
+ props: ContourCarpetSchema,
+ description:
+ "Contour overlay on a Carpet plot. References the Carpet's `carpet` id and provides `a`/`b`/`z` triples (a flat list of carpet-space samples).",
+ component: ({ props }) => {
+ const trace = {
+ type: "contourcarpet",
+ carpet: props.carpet,
+ a: props.a,
+ b: props.b,
+ z: props.z,
+ ncontours: props.ncontours ?? 14,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/DensityMap.ts b/packages/plotly/src/traces/DensityMap.ts
new file mode 100644
index 000000000..b4bd83c5f
--- /dev/null
+++ b/packages/plotly/src/traces/DensityMap.ts
@@ -0,0 +1,49 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const DensityMapSchema = z.object({
+ lat: z.array(z.number()),
+ lon: z.array(z.number()),
+ z: z.array(z.number()).optional(),
+ radius: z.number().positive().optional(),
+ colormap: z.string().optional(),
+ centerLat: z.number().optional(),
+ centerLon: z.number().optional(),
+ zoom: z.number().min(0).max(22).optional(),
+ style: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const DensityMap = defineComponent({
+ name: "DensityMap",
+ props: DensityMapSchema,
+ description:
+ "Heatmap-style density overlay on an interactive map (MapLibre tiles). Pass `lat`/`lon` arrays. Optional `z` weights each point (e.g. magnitude); without it, density = count. `radius` controls smoothing kernel size in pixels.",
+ component: ({ props }) => {
+ const trace = {
+ type: "densitymap",
+ lat: props.lat,
+ lon: props.lon,
+ z: props.z,
+ radius: props.radius ?? 12,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ } as unknown as Data;
+ const layout = {
+ title: props.title ? { text: props.title } : undefined,
+ map: {
+ style: props.style ?? "open-street-map",
+ center: { lat: props.centerLat ?? 0, lon: props.centerLon ?? 0 },
+ zoom: props.zoom ?? 1,
+ },
+ margin: { t: props.title ? 32 : 0, l: 0, r: 0, b: 0 },
+ } as unknown as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Funnel.ts b/packages/plotly/src/traces/Funnel.ts
new file mode 100644
index 000000000..f9c41dd30
--- /dev/null
+++ b/packages/plotly/src/traces/Funnel.ts
@@ -0,0 +1,40 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const FunnelSchema = z.object({
+ stages: z.array(z.string()),
+ values: z.array(z.number()),
+ orientation: z.enum(["h", "v"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Funnel = defineComponent({
+ name: "Funnel",
+ props: FunnelSchema,
+ description:
+ "Funnel chart — horizontal bars per stage with auto-computed conversion percentages between stages. Pass parallel `stages` (labels) and `values` arrays.",
+ component: ({ props }) => {
+ const orientation = props.orientation ?? "h";
+ const trace = {
+ type: "funnel",
+ orientation,
+ x: orientation === "h" ? props.values : (props.stages as Array),
+ y: orientation === "h" ? (props.stages as Array) : props.values,
+ textposition: "inside",
+ textinfo: "value+percent initial",
+ } as unknown as Data;
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: false,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/FunnelArea.ts b/packages/plotly/src/traces/FunnelArea.ts
new file mode 100644
index 000000000..fc87ea1c1
--- /dev/null
+++ b/packages/plotly/src/traces/FunnelArea.ts
@@ -0,0 +1,34 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const FunnelAreaSchema = z.object({
+ stages: z.array(z.string()),
+ values: z.array(z.number()),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const FunnelArea = defineComponent({
+ name: "FunnelArea",
+ props: FunnelAreaSchema,
+ description:
+ "Triangular funnel-area chart (a.k.a. ribbon funnel). Like Funnel but the area of each stage is proportional to value. Good for visual conversion stories where exact widths matter less than overall shape.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "funnelarea",
+ values: props.values,
+ labels: props.stages,
+ textinfo: "label+percent",
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ showlegend: false,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Heatmap.ts b/packages/plotly/src/traces/Heatmap.ts
new file mode 100644
index 000000000..17079cabb
--- /dev/null
+++ b/packages/plotly/src/traces/Heatmap.ts
@@ -0,0 +1,60 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { isDivergingColormap, resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const HeatmapSchema = z.object({
+ z: z.array(z.array(z.number())),
+ x: z.array(z.union([z.string(), z.number()])).optional(),
+ y: z.array(z.union([z.string(), z.number()])).optional(),
+ colormap: z.string().optional(),
+ zmin: z.number().optional(),
+ zmax: z.number().optional(),
+ showText: z.boolean().optional(),
+ textFormat: z.string().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Heatmap = defineComponent({
+ name: "Heatmap",
+ props: HeatmapSchema,
+ description:
+ "2D heatmap of a numeric matrix. `z` is rows×cols. `x`/`y` are optional axis labels. `colormap`: 'viridis' (default), 'inferno', 'plasma', 'magma', 'cividis', 'turbo', 'blues', 'RdBu', 'BrBG', 'PiYG', 'spectral'. Diverging colormaps auto-center on 0 unless `zmin`/`zmax` are provided. `showText=true` overlays cell values; `textFormat` is a Plotly d3-format string (default '.2f').",
+ component: ({ props }) => {
+ if (!props.z || props.z.length === 0) return null;
+ const colorscale = resolveColormap(props.colormap ?? "viridis");
+ const div = isDivergingColormap(props.colormap);
+
+ let zmin = props.zmin;
+ let zmax = props.zmax;
+ if (div && zmin === undefined && zmax === undefined) {
+ const flat = props.z.flat().filter(Number.isFinite) as number[];
+ const absMax = Math.max(...flat.map(Math.abs));
+ zmin = -absMax;
+ zmax = absMax;
+ }
+
+ const trace: Data = {
+ type: "heatmap",
+ z: props.z,
+ x: props.x as Array | undefined,
+ y: props.y as Array | undefined,
+ colorscale: colorscale as never,
+ zmin,
+ zmax,
+ hoverongaps: false,
+ texttemplate: props.showText ? `%{z:${props.textFormat ?? ".2f"}}` : undefined,
+ textfont: props.showText ? { size: 10 } : undefined,
+ colorbar: { thickness: 12, outlinewidth: 0, tickfont: { size: 10 } },
+ };
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Histogram.ts b/packages/plotly/src/traces/Histogram.ts
new file mode 100644
index 000000000..c9dedac2a
--- /dev/null
+++ b/packages/plotly/src/traces/Histogram.ts
@@ -0,0 +1,56 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const HistogramSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ nbinsx: z.number().int().positive().optional(),
+ histnorm: z.enum(["", "percent", "probability", "density", "probability density"]).optional(),
+ barmode: z.enum(["overlay", "stack", "group"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Histogram = defineComponent({
+ name: "Histogram",
+ props: HistogramSchema,
+ description:
+ "Frequency histogram of a single numeric variable. Pass `x` as a field name (with `data`) or a raw array. `color` enables per-group histograms. `histnorm`: '' (count, default), 'probability', 'density', etc. `nbinsx` overrides Plotly's auto-binning.",
+ component: ({ props }) => {
+ // Histogram needs only x; treat y as identical to x for resolve().
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.x,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const traces: Data[] = groups.map((g) => ({
+ type: "histogram",
+ x: g.x as number[],
+ nbinsx: props.nbinsx,
+ histnorm: props.histnorm,
+ name: g.group || undefined,
+ opacity: groups.length > 1 ? 0.7 : 1,
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout({
+ title: props.title,
+ xLabel: props.xLabel,
+ yLabel: props.yLabel ?? (props.histnorm ? "Density" : "Count"),
+ }) as Partial),
+ barmode: props.barmode ?? (groups.length > 1 ? "overlay" : "group"),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Histogram2D.ts b/packages/plotly/src/traces/Histogram2D.ts
new file mode 100644
index 000000000..70d0dab5e
--- /dev/null
+++ b/packages/plotly/src/traces/Histogram2D.ts
@@ -0,0 +1,42 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const Histogram2DSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ nbinsx: z.number().int().positive().optional(),
+ nbinsy: z.number().int().positive().optional(),
+ colormap: z.string().optional(),
+ histnorm: z.enum(["", "percent", "probability", "density", "probability density"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Histogram2D = defineComponent({
+ name: "Histogram2D",
+ props: Histogram2DSchema,
+ description:
+ "Rectangular 2D-histogram heatmap (counts of points falling in each bin). Use for >500 points where a Scatter would overplot. `nbinsx`/`nbinsy` override auto-binning.",
+ component: ({ props }) => {
+ const trace = {
+ type: "histogram2d",
+ x: props.x,
+ y: props.y,
+ nbinsx: props.nbinsx,
+ nbinsy: props.nbinsy,
+ histnorm: props.histnorm,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ } as unknown as Data;
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Histogram2DContour.ts b/packages/plotly/src/traces/Histogram2DContour.ts
new file mode 100644
index 000000000..bfc90f6bc
--- /dev/null
+++ b/packages/plotly/src/traces/Histogram2DContour.ts
@@ -0,0 +1,53 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const Histogram2DContourSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ ncontours: z.number().int().positive().optional(),
+ colormap: z.string().optional(),
+ showPoints: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Histogram2DContour = defineComponent({
+ name: "Histogram2DContour",
+ props: Histogram2DContourSchema,
+ description:
+ "Smooth 2D KDE contour density of a point cloud. Use to show density structure where Histogram2D would feel chunky. `showPoints=true` overlays the raw samples on top.",
+ component: ({ props }) => {
+ const traces: Data[] = [
+ {
+ type: "histogram2dcontour",
+ x: props.x,
+ y: props.y,
+ ncontours: props.ncontours ?? 20,
+ colorscale: resolveColormap(props.colormap ?? "viridis") as never,
+ colorbar: { thickness: 12, outlinewidth: 0 },
+ showscale: true,
+ },
+ ];
+ if (props.showPoints) {
+ traces.push({
+ type: "scatter",
+ mode: "markers",
+ x: props.x,
+ y: props.y,
+ marker: { size: 2, color: "rgba(15,23,42,0.4)" },
+ showlegend: false,
+ hoverinfo: "skip",
+ });
+ }
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Icicle.ts b/packages/plotly/src/traces/Icicle.ts
new file mode 100644
index 000000000..b87f8f3ac
--- /dev/null
+++ b/packages/plotly/src/traces/Icicle.ts
@@ -0,0 +1,42 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const IcicleSchema = z.object({
+ ids: z.array(z.string()),
+ parents: z.array(z.string()),
+ values: z.array(z.number()).optional(),
+ labels: z.array(z.string()).optional(),
+ orientation: z.enum(["h", "v"]).optional(),
+ branchvalues: z.enum(["remainder", "total"]).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Icicle = defineComponent({
+ name: "Icicle",
+ props: IcicleSchema,
+ description:
+ "Icicle chart — rectangular hierarchical layout (think horizontal Sunburst). Same parallel `ids`/`parents`/`values` shape as Treemap. `orientation='h'` (default) stacks horizontally, 'v' vertically.",
+ component: ({ props }) => {
+ if (!props.ids?.length) return null;
+ const trace = {
+ type: "icicle",
+ ids: props.ids,
+ parents: props.parents,
+ values: props.values,
+ labels: props.labels ?? props.ids,
+ branchvalues: props.branchvalues ?? "remainder",
+ tiling: { orientation: props.orientation ?? "h" },
+ hovertemplate: "%{label}
value: %{value}",
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Image.ts b/packages/plotly/src/traces/Image.ts
new file mode 100644
index 000000000..2c7a3d2f7
--- /dev/null
+++ b/packages/plotly/src/traces/Image.ts
@@ -0,0 +1,36 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ImageSchema = z.object({
+ z: z.array(z.array(z.array(z.number()))),
+ source: z.string().optional(),
+ colormodel: z.enum(["rgb", "rgba", "hsl", "hsla"]).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Image = defineComponent({
+ name: "Image",
+ props: ImageSchema,
+ description:
+ "Render a 2D image / pixel matrix as a Plotly trace. Pass `z` as a height×width×channels array (RGB or RGBA). Use `colormodel` to switch color spaces. Useful for rendering ML model attention maps, tensors, or small generated images inline.",
+ component: ({ props }) => {
+ const trace = {
+ type: "image",
+ z: props.z,
+ source: props.source,
+ colormodel: props.colormodel ?? "rgb",
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ xaxis: { showticklabels: false, showgrid: false, zeroline: false },
+ yaxis: { showticklabels: false, showgrid: false, zeroline: false, scaleanchor: "x" },
+ margin: { t: props.title ? 32 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Indicator.ts b/packages/plotly/src/traces/Indicator.ts
new file mode 100644
index 000000000..8e574b80d
--- /dev/null
+++ b/packages/plotly/src/traces/Indicator.ts
@@ -0,0 +1,73 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const IndicatorSchema = z.object({
+ value: z.number(),
+ reference: z.number().optional(),
+ mode: z
+ .enum(["number", "delta", "gauge", "number+delta", "number+gauge", "gauge+number+delta"])
+ .optional(),
+ title: z.string().optional(),
+ prefix: z.string().optional(),
+ suffix: z.string().optional(),
+ decimals: z.number().int().min(0).optional(),
+ rangeMin: z.number().optional(),
+ rangeMax: z.number().optional(),
+ threshold: z.number().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Indicator = defineComponent({
+ name: "Indicator",
+ props: IndicatorSchema,
+ description:
+ "Big-number / delta / gauge indicator. `mode`: 'number' (default) | 'delta' | 'gauge' | combinations like 'number+delta'. For deltas, pass `reference` (the previous value). For gauges, pass `rangeMin`/`rangeMax` (default 0..value*2) and optional `threshold`.",
+ component: ({ props }) => {
+ const mode = props.mode ?? "number";
+ const usesGauge = mode.includes("gauge");
+ const usesDelta = mode.includes("delta");
+ const trace = {
+ type: "indicator",
+ mode,
+ value: props.value,
+ title: props.title ? { text: props.title, font: { size: 13 } } : undefined,
+ number: {
+ prefix: props.prefix,
+ suffix: props.suffix,
+ valueformat: props.decimals !== undefined ? `,.${props.decimals}f` : ",",
+ font: { size: 36 },
+ },
+ delta: usesDelta
+ ? {
+ reference: props.reference,
+ relative: false,
+ valueformat: ",.1f",
+ }
+ : undefined,
+ gauge: usesGauge
+ ? {
+ axis: {
+ range: [props.rangeMin ?? 0, props.rangeMax ?? props.value * 2],
+ },
+ bar: { color: "#4c78a8" },
+ threshold:
+ props.threshold !== undefined
+ ? { line: { color: "#dc2626", width: 3 }, value: props.threshold }
+ : undefined,
+ }
+ : undefined,
+ } as unknown as Data;
+ const layout: Partial = {
+ margin: { t: 24, b: 16, l: 24, r: 24 },
+ };
+ return React.createElement(PlotShell, {
+ data: [trace],
+ layout,
+ height: props.height ?? (usesGauge ? 240 : 160),
+ });
+ },
+});
diff --git a/packages/plotly/src/traces/Isosurface.ts b/packages/plotly/src/traces/Isosurface.ts
new file mode 100644
index 000000000..7c0a9c3ce
--- /dev/null
+++ b/packages/plotly/src/traces/Isosurface.ts
@@ -0,0 +1,47 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const IsosurfaceSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ value: z.array(z.number()),
+ isomin: z.number().optional(),
+ isomax: z.number().optional(),
+ surfaceCount: z.number().int().positive().optional(),
+ colormap: z.string().optional(),
+ opacity: z.number().min(0).max(1).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Isosurface = defineComponent({
+ name: "Isosurface",
+ props: IsosurfaceSchema,
+ description:
+ "Isosurface — 3D level-sets of a scalar field. `x`/`y`/`z` are sample point coordinates (typically a structured grid flattened); `value` is the scalar at each. `surfaceCount` controls how many iso-levels are drawn between `isomin` and `isomax`.",
+ component: ({ props }) => {
+ const trace = {
+ type: "isosurface",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ value: props.value,
+ isomin: props.isomin,
+ isomax: props.isomax,
+ surface: { count: props.surfaceCount ?? 4 },
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ opacity: props.opacity ?? 0.6,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Line.ts b/packages/plotly/src/traces/Line.ts
new file mode 100644
index 000000000..f2578d405
--- /dev/null
+++ b/packages/plotly/src/traces/Line.ts
@@ -0,0 +1,50 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const LineSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.union([z.string(), z.number()])), z.string()]),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ smooth: z.boolean().optional(),
+ showMarkers: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Line = defineComponent({
+ name: "Line",
+ props: LineSchema,
+ description:
+ "Line chart. Same `data`/`x`/`y` patterns as Bar — Express style with field names, or Graph-Objects with parallel arrays. `color` adds multiple series. `smooth=true` uses spline interpolation; `showMarkers=true` overlays point markers.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const traces: Data[] = groups.map((g) => ({
+ type: "scatter",
+ mode: props.showMarkers ? "lines+markers" : "lines",
+ x: g.x as Array,
+ y: g.y as number[],
+ name: g.group || undefined,
+ line: props.smooth ? { shape: "spline", smoothing: 1.0 } : undefined,
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Mesh3D.ts b/packages/plotly/src/traces/Mesh3D.ts
new file mode 100644
index 000000000..1afe7f5ae
--- /dev/null
+++ b/packages/plotly/src/traces/Mesh3D.ts
@@ -0,0 +1,47 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const Mesh3DSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ i: z.array(z.number()).optional(),
+ j: z.array(z.number()).optional(),
+ k: z.array(z.number()).optional(),
+ intensity: z.array(z.number()).optional(),
+ colormap: z.string().optional(),
+ opacity: z.number().min(0).max(1).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Mesh3D = defineComponent({
+ name: "Mesh3D",
+ props: Mesh3DSchema,
+ description:
+ "WebGL 3D mesh from a point cloud. Pass `x`/`y`/`z` (vertex coordinates). For an explicit triangulation pass `i`/`j`/`k` (vertex index triples per triangle); without them, Plotly computes a Delaunay/alpha-shape triangulation. Optional `intensity` for vertex coloring.",
+ component: ({ props }) => {
+ const trace = {
+ type: "mesh3d",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ i: props.i,
+ j: props.j,
+ k: props.k,
+ intensity: props.intensity,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ opacity: props.opacity ?? 1,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/OHLC.ts b/packages/plotly/src/traces/OHLC.ts
new file mode 100644
index 000000000..36f2901f5
--- /dev/null
+++ b/packages/plotly/src/traces/OHLC.ts
@@ -0,0 +1,46 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const OHLCSchema = z.object({
+ x: z.array(z.union([z.string(), z.number()])),
+ open: z.array(z.number()),
+ high: z.array(z.number()),
+ low: z.array(z.number()),
+ close: z.array(z.number()),
+ upColor: z.string().optional(),
+ downColor: z.string().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const OHLC = defineComponent({
+ name: "OHLC",
+ props: OHLCSchema,
+ description:
+ "OHLC bar chart (open-high-low-close). Same shape as Candlestick but without the body fill — preferred when you want a denser time-series view.",
+ component: ({ props }) => {
+ const trace = {
+ type: "ohlc",
+ x: props.x as Array,
+ open: props.open,
+ high: props.high,
+ low: props.low,
+ close: props.close,
+ increasing: { line: { color: props.upColor ?? "#16a34a" } },
+ decreasing: { line: { color: props.downColor ?? "#dc2626" } },
+ } as unknown as Data;
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ xaxis: { rangeslider: { visible: false } },
+ showlegend: false,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ParCats.ts b/packages/plotly/src/traces/ParCats.ts
new file mode 100644
index 000000000..d23aa19fc
--- /dev/null
+++ b/packages/plotly/src/traces/ParCats.ts
@@ -0,0 +1,45 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ParCatsSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())),
+ dimensions: z.array(z.string()),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ParCats = defineComponent({
+ name: "ParCats",
+ props: ParCatsSchema,
+ description:
+ "Parallel categories plot — multi-dimensional ribbon view of categorical fields. Pass `data` rows and `dimensions` (categorical field names). Optional `color` field gives ribbon coloring (numeric or categorical).",
+ component: ({ props }) => {
+ const rows = props.data ?? [];
+ const dims = props.dimensions ?? [];
+ if (rows.length === 0 || dims.length === 0) return null;
+ const dimensionsArr = dims.map((d) => ({
+ label: d,
+ values: rows.map((r) => r[d]),
+ }));
+ const trace = {
+ type: "parcats",
+ dimensions: dimensionsArr,
+ line: props.color
+ ? {
+ color: rows.map((r) => r[props.color as string]),
+ colorscale: "Viridis",
+ }
+ : undefined,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 60 : 32, l: 60, r: 60, b: 24 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 360 });
+ },
+});
diff --git a/packages/plotly/src/traces/ParCoords.ts b/packages/plotly/src/traces/ParCoords.ts
new file mode 100644
index 000000000..389f7eced
--- /dev/null
+++ b/packages/plotly/src/traces/ParCoords.ts
@@ -0,0 +1,48 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const ParCoordsSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())),
+ dimensions: z.array(z.string()),
+ color: z.string().optional(),
+ colormap: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ParCoords = defineComponent({
+ name: "ParCoords",
+ props: ParCoordsSchema,
+ description:
+ "Parallel coordinates plot — one polyline per row across multiple axes. Pass `data` as row objects and `dimensions` as the field names to plot. `color` is an optional numeric field name for continuous coloring (uses `colormap`, default 'viridis'). Brushing on each axis filters interactively.",
+ component: ({ props }) => {
+ const rows = props.data ?? [];
+ const dims = props.dimensions ?? [];
+ if (rows.length === 0 || dims.length === 0) return null;
+ const dimensionsArr = dims.map((d) => ({
+ label: d,
+ values: rows.map((r) => Number(r[d])),
+ }));
+ const trace = {
+ type: "parcoords",
+ dimensions: dimensionsArr,
+ line: props.color
+ ? {
+ color: rows.map((r) => Number(r[props.color as string])),
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ showscale: true,
+ }
+ : { color: "#4c78a8" },
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 60 : 32, l: 60, r: 60, b: 24 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 360 });
+ },
+});
diff --git a/packages/plotly/src/traces/Pie.ts b/packages/plotly/src/traces/Pie.ts
new file mode 100644
index 000000000..01e8616b7
--- /dev/null
+++ b/packages/plotly/src/traces/Pie.ts
@@ -0,0 +1,77 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+// IMPORTANT: Pie and Donut must NOT share a single schema instance — defineComponent
+// tags the schema with the component name via schemaIdTags, and the second call
+// overwrites the first. Effect: zod's toJSONSchema() only emits the last tag in
+// $defs and the parser catalog drops the first component as "unknown".
+// Build two structurally identical but distinct schemas instead.
+const pieFields = () =>
+ ({
+ values: z.array(z.number()),
+ labels: z.array(z.string()),
+ hole: z.number().min(0).max(0.95).optional(),
+ pull: z.union([z.number(), z.array(z.number())]).optional(),
+ sort: z.boolean().optional(),
+ rotation: z.number().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+ }) as const;
+
+const PieSchema = z.object(pieFields());
+const DonutSchema = z.object(pieFields());
+
+export const Pie = defineComponent({
+ name: "Pie",
+ props: PieSchema,
+ description:
+ "Pie chart. Pass parallel `values` and `labels` arrays. `hole` (0..1) makes a donut. `pull` (0..1) explodes one or all slices. `sort=true` orders slices by value. Use Donut as a shortcut for a 0.5 hole.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "pie",
+ values: props.values,
+ labels: props.labels,
+ hole: props.hole,
+ pull: props.pull as never,
+ sort: props.sort ?? true,
+ rotation: props.rotation,
+ textinfo: "label+percent",
+ hovertemplate: "%{label}
%{value} (%{percent})",
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ showlegend: false,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
+
+export const Donut = defineComponent({
+ name: "Donut",
+ props: DonutSchema,
+ description: "Donut chart — Pie with `hole=0.5` by default. Same props as Pie.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "pie",
+ values: props.values,
+ labels: props.labels,
+ hole: props.hole ?? 0.5,
+ pull: props.pull as never,
+ sort: props.sort ?? true,
+ rotation: props.rotation,
+ textinfo: "label+percent",
+ hovertemplate: "%{label}
%{value} (%{percent})",
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ showlegend: false,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Sankey.ts b/packages/plotly/src/traces/Sankey.ts
new file mode 100644
index 000000000..823213554
--- /dev/null
+++ b/packages/plotly/src/traces/Sankey.ts
@@ -0,0 +1,67 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const NodeSchema = z.object({
+ id: z.string(),
+ label: z.string().optional(),
+ color: z.string().optional(),
+});
+const LinkSchema = z.object({
+ source: z.string(),
+ target: z.string(),
+ value: z.number(),
+ color: z.string().optional(),
+});
+
+const SankeySchema = z.object({
+ nodes: z.array(NodeSchema),
+ links: z.array(LinkSchema),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Sankey = defineComponent({
+ name: "Sankey",
+ props: SankeySchema,
+ description:
+ "Sankey flow diagram. `nodes`: [{ id, label?, color? }, ...]; `links`: [{ source, target, value, color? }] where source/target reference node ids. Width of each link is proportional to value.",
+ component: ({ props }) => {
+ const nodes = props.nodes ?? [];
+ const links = props.links ?? [];
+ if (nodes.length === 0) return null;
+ const idToIndex = new Map(nodes.map((n, i) => [n.id, i]));
+ const validLinks = links.filter(
+ (l) => idToIndex.has(l.source) && idToIndex.has(l.target) && l.value > 0,
+ );
+ if (validLinks.length === 0) return null;
+
+ const trace: Data = {
+ type: "sankey",
+ orientation: "h",
+ arrangement: "snap",
+ node: {
+ label: nodes.map((n) => n.label ?? n.id),
+ color: nodes.map((n) => n.color ?? undefined) as never,
+ pad: 14,
+ thickness: 16,
+ line: { color: "rgba(15,23,42,0.10)", width: 0.5 },
+ },
+ link: {
+ source: validLinks.map((l) => idToIndex.get(l.source) as number),
+ target: validLinks.map((l) => idToIndex.get(l.target) as number),
+ value: validLinks.map((l) => l.value),
+ color: validLinks.map((l) => l.color ?? "rgba(76,120,168,0.45)"),
+ },
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ font: { size: 11 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Scatter.ts b/packages/plotly/src/traces/Scatter.ts
new file mode 100644
index 000000000..aa80b9716
--- /dev/null
+++ b/packages/plotly/src/traces/Scatter.ts
@@ -0,0 +1,83 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.number()), z.string()]),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.union([z.string(), z.number()])), z.string()]).optional(),
+ size: z.union([z.array(z.number()), z.string(), z.number()]).optional(),
+ colormap: z.string().optional(),
+ trendline: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Scatter = defineComponent({
+ name: "Scatter",
+ props: ScatterSchema,
+ description:
+ "Scatter plot. `color` may be a categorical column (string values → discrete colors per group) or a numeric column (continuous coloring via `colormap`, default 'viridis'). `size` accepts a constant, an array, or a field name for variable point size.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+
+ const sizeArr: number[] | number | undefined = (() => {
+ if (typeof props.size === "number") return props.size;
+ if (Array.isArray(props.size)) return props.size as number[];
+ if (typeof props.size === "string" && props.data) {
+ return (props.data as Array>).map((row) => {
+ const v = row[props.size as string];
+ return typeof v === "number" ? v : 0;
+ });
+ }
+ return undefined;
+ })();
+
+ if (r.color) {
+ // Continuous coloring — single trace with colorscale.
+ const trace: Data = {
+ type: "scatter",
+ mode: "markers",
+ x: r.x as number[],
+ y: r.y as number[],
+ marker: {
+ color: r.color,
+ colorscale: resolveColormap(props.colormap ?? "viridis") as never,
+ size: sizeArr ?? 6,
+ showscale: true,
+ },
+ };
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ }
+
+ const groups = splitByGroup(r);
+ const traces: Data[] = groups.map((g) => ({
+ type: "scatter",
+ mode: "markers",
+ x: g.x as number[],
+ y: g.y as number[],
+ name: g.group || undefined,
+ marker: { size: sizeArr ?? 6 },
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Scatter3D.ts b/packages/plotly/src/traces/Scatter3D.ts
new file mode 100644
index 000000000..c11acb584
--- /dev/null
+++ b/packages/plotly/src/traces/Scatter3D.ts
@@ -0,0 +1,60 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const Scatter3DSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ color: z.union([z.array(z.number()), z.string()]).optional(),
+ size: z.union([z.array(z.number()), z.number()]).optional(),
+ colormap: z.string().optional(),
+ text: z.array(z.string()).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ zLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Scatter3D = defineComponent({
+ name: "Scatter3D",
+ props: Scatter3DSchema,
+ description:
+ "WebGL 3D scatter / line plot. Pass `x`/`y`/`z` arrays. `color` may be a constant string or numeric array (uses `colormap`, default 'viridis'). `mode='lines'` for 3D paths.",
+ component: ({ props }) => {
+ const numericColor = Array.isArray(props.color) ? (props.color as number[]) : undefined;
+ const trace: Data = {
+ type: "scatter3d",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ mode: props.mode ?? "markers",
+ text: props.text,
+ marker: {
+ size: (props.size as never) ?? 4,
+ color: (numericColor ?? props.color) as never,
+ colorscale: numericColor
+ ? (resolveColormap(props.colormap ?? "viridis") as never)
+ : undefined,
+ showscale: !!numericColor,
+ },
+ line: { width: 2, color: numericColor ? undefined : (props.color as string) },
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ scene: {
+ xaxis: { title: { text: props.xLabel ?? "x" } },
+ yaxis: { title: { text: props.yLabel ?? "y" } },
+ zaxis: { title: { text: props.zLabel ?? "z" } },
+ },
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterCarpet.ts b/packages/plotly/src/traces/ScatterCarpet.ts
new file mode 100644
index 000000000..332628721
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterCarpet.ts
@@ -0,0 +1,37 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterCarpetSchema = z.object({
+ carpet: z.string(),
+ a: z.array(z.number()),
+ b: z.array(z.number()),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ text: z.array(z.string()).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterCarpet = defineComponent({
+ name: "ScatterCarpet",
+ props: ScatterCarpetSchema,
+ description:
+ "Scatter trace overlaid on a Carpet plot. References the Carpet's `carpet` id and provides `a`/`b` coordinates in carpet space. Compose alongside a Carpet trace in a Figure.",
+ component: ({ props }) => {
+ const trace = {
+ type: "scattercarpet",
+ carpet: props.carpet,
+ a: props.a,
+ b: props.b,
+ mode: props.mode ?? "markers",
+ text: props.text,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterGL.ts b/packages/plotly/src/traces/ScatterGL.ts
new file mode 100644
index 000000000..7bd4596e0
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterGL.ts
@@ -0,0 +1,68 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { resolveColormap } from "../shell/colormap";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterGLSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.number()), z.string()]),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.union([z.string(), z.number()])), z.string()]).optional(),
+ size: z.union([z.array(z.number()), z.number()]).optional(),
+ colormap: z.string().optional(),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterGL = defineComponent({
+ name: "ScatterGL",
+ props: ScatterGLSchema,
+ description:
+ "WebGL-accelerated scatter — same API as Scatter but renders thousands to millions of points without choking the canvas. Use for high-cardinality scatter (>10k points). Loses some text-rendering features but is dramatically faster.",
+ component: ({ props }) => {
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ if (r.color) {
+ const trace: Data = {
+ type: "scattergl",
+ mode: props.mode ?? "markers",
+ x: r.x as number[],
+ y: r.y as number[],
+ marker: {
+ color: r.color,
+ colorscale: resolveColormap(props.colormap ?? "viridis") as never,
+ size: (props.size as never) ?? 4,
+ showscale: true,
+ },
+ };
+ const layout: Partial = buildAxisLayout(props) as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ }
+ const groups = splitByGroup(r);
+ const traces: Data[] = groups.map((g) => ({
+ type: "scattergl",
+ mode: props.mode ?? "markers",
+ x: g.x as number[],
+ y: g.y as number[],
+ name: g.group || undefined,
+ marker: { size: (props.size as never) ?? 4 },
+ }));
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ };
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterGeo.ts b/packages/plotly/src/traces/ScatterGeo.ts
new file mode 100644
index 000000000..c1b8ec231
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterGeo.ts
@@ -0,0 +1,51 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterGeoSchema = z.object({
+ lat: z.array(z.number()),
+ lon: z.array(z.number()),
+ text: z.array(z.string()).optional(),
+ size: z.union([z.array(z.number()), z.number()]).optional(),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ scope: z
+ .enum(["world", "usa", "europe", "asia", "africa", "north america", "south america"])
+ .optional(),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterGeo = defineComponent({
+ name: "ScatterGeo",
+ props: ScatterGeoSchema,
+ description:
+ "Geographic scatter / lines on a globe (cartesian projection). Pass `lat` and `lon` arrays. `text` for hover labels per point. `mode='lines'` draws great-circle paths between consecutive lat/lon pairs.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "scattergeo",
+ lat: props.lat,
+ lon: props.lon,
+ text: props.text,
+ mode: props.mode ?? "markers",
+ marker: {
+ size: (props.size as never) ?? 6,
+ color: props.color as never,
+ },
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ geo: {
+ scope: props.scope ?? "world",
+ showland: true,
+ landcolor: "rgba(15,23,42,0.04)",
+ projection: { type: "natural earth" },
+ } as never,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 380 });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterMap.ts b/packages/plotly/src/traces/ScatterMap.ts
new file mode 100644
index 000000000..b533c4b74
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterMap.ts
@@ -0,0 +1,51 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterMapSchema = z.object({
+ lat: z.array(z.number()),
+ lon: z.array(z.number()),
+ text: z.array(z.string()).optional(),
+ size: z.union([z.array(z.number()), z.number()]).optional(),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ centerLat: z.number().optional(),
+ centerLon: z.number().optional(),
+ zoom: z.number().min(0).max(22).optional(),
+ style: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterMap = defineComponent({
+ name: "ScatterMap",
+ props: ScatterMapSchema,
+ description:
+ "Interactive map points using MapLibre tiles (no token required as of plotly.js 3.x). Pass `lat`/`lon` arrays. `centerLat`/`centerLon`/`zoom` set the initial viewport. `style`: 'open-street-map' (default), 'carto-positron', 'carto-darkmatter', 'white-bg', 'basic'.",
+ component: ({ props }) => {
+ const trace = {
+ type: "scattermap",
+ lat: props.lat,
+ lon: props.lon,
+ text: props.text,
+ mode: props.mode ?? "markers",
+ marker: {
+ size: props.size ?? 8,
+ color: props.color,
+ },
+ } as unknown as Data;
+ const layout = {
+ title: props.title ? { text: props.title } : undefined,
+ map: {
+ style: props.style ?? "open-street-map",
+ center: { lat: props.centerLat ?? 0, lon: props.centerLon ?? 0 },
+ zoom: props.zoom ?? 1,
+ },
+ margin: { t: props.title ? 32 : 0, l: 0, r: 0, b: 0 },
+ } as unknown as Partial;
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterMatrix.ts b/packages/plotly/src/traces/ScatterMatrix.ts
new file mode 100644
index 000000000..5f6c7a554
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterMatrix.ts
@@ -0,0 +1,61 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterMatrixSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())),
+ dimensions: z.array(z.string()),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterMatrix = defineComponent({
+ name: "ScatterMatrix",
+ props: ScatterMatrixSchema,
+ description:
+ "Pairwise scatter matrix (a.k.a. SPLOM / pair plot). Pass `data` as an array of objects and `dimensions` as the field names to plot pairwise. Optional `color` field for categorical grouping (one color per unique value).",
+ component: ({ props }) => {
+ const rows = props.data ?? [];
+ const dims = props.dimensions ?? [];
+ if (rows.length === 0 || dims.length < 2) return null;
+
+ const dimensionsArr = dims.map((d) => ({
+ label: d,
+ values: rows.map((r) => r[d] as number),
+ }));
+
+ let marker: Record = { size: 4, line: { width: 0 } };
+ if (props.color) {
+ const groups = Array.from(new Set(rows.map((r) => String(r[props.color as string]))));
+ const groupIdx = rows.map((r) => groups.indexOf(String(r[props.color as string])));
+ marker = {
+ size: 4,
+ color: groupIdx,
+ colorscale: groups.map((_, i) => [
+ i / Math.max(1, groups.length - 1),
+ `hsl(${(i * 360) / groups.length}, 60%, 50%)`,
+ ]),
+ showscale: false,
+ line: { width: 0 },
+ };
+ }
+
+ const trace = {
+ type: "splom",
+ dimensions: dimensionsArr,
+ marker,
+ diagonal: { visible: false },
+ showupperhalf: false,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ dragmode: "select",
+ hovermode: "closest",
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterPolar.ts b/packages/plotly/src/traces/ScatterPolar.ts
new file mode 100644
index 000000000..fc390a3fc
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterPolar.ts
@@ -0,0 +1,43 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterPolarSchema = z.object({
+ r: z.array(z.number()),
+ theta: z.union([z.array(z.number()), z.array(z.string())]),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ fill: z.enum(["none", "toself", "tonext"]).optional(),
+ thetaUnit: z.enum(["radians", "degrees"]).optional(),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterPolar = defineComponent({
+ name: "ScatterPolar",
+ props: ScatterPolarSchema,
+ description:
+ "Polar scatter / line / radar plot. Pass parallel `r` (radii) and `theta` (angles in degrees by default; pass `thetaUnit='radians'` to switch). `mode`: 'markers' | 'lines' | 'lines+markers'. `fill='toself'` makes a closed radar-style polygon.",
+ component: ({ props }) => {
+ const trace: Data = {
+ type: "scatterpolar",
+ r: props.r,
+ theta: props.theta as never,
+ mode: props.mode ?? "markers",
+ fill: props.fill,
+ marker: props.color ? { color: props.color } : undefined,
+ line: props.color ? { color: props.color } : undefined,
+ thetaunit: (props.thetaUnit ?? "degrees") as never,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ polar: { angularaxis: { direction: "clockwise" } },
+ showlegend: false,
+ margin: { t: props.title ? 40 : 16, l: 16, r: 16, b: 16 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterPolarGL.ts b/packages/plotly/src/traces/ScatterPolarGL.ts
new file mode 100644
index 000000000..9124709f1
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterPolarGL.ts
@@ -0,0 +1,38 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterPolarGLSchema = z.object({
+ r: z.array(z.number()),
+ theta: z.union([z.array(z.number()), z.array(z.string())]),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterPolarGL = defineComponent({
+ name: "ScatterPolarGL",
+ props: ScatterPolarGLSchema,
+ description:
+ "WebGL-accelerated polar scatter. Same API as ScatterPolar but for very-high-point-count polar data. Use when ScatterPolar feels sluggish past ~10k points.",
+ component: ({ props }) => {
+ const trace = {
+ type: "scatterpolargl",
+ r: props.r,
+ theta: props.theta,
+ mode: props.mode ?? "markers",
+ marker: props.color ? { color: props.color } : undefined,
+ line: props.color ? { color: props.color } : undefined,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ polar: { angularaxis: { direction: "clockwise" } },
+ showlegend: false,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterSmith.ts b/packages/plotly/src/traces/ScatterSmith.ts
new file mode 100644
index 000000000..62383d287
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterSmith.ts
@@ -0,0 +1,38 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterSmithSchema = z.object({
+ real: z.array(z.number()),
+ imag: z.array(z.number()),
+ text: z.array(z.string()).optional(),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ color: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterSmith = defineComponent({
+ name: "ScatterSmith",
+ props: ScatterSmithSchema,
+ description:
+ "Smith chart — complex impedance / reflection coefficient scatter. Used in RF/microwave engineering. Pass parallel `real` and `imag` arrays of normalized impedance values.",
+ component: ({ props }) => {
+ const trace = {
+ type: "scattersmith",
+ real: props.real,
+ imag: props.imag,
+ mode: props.mode ?? "markers",
+ text: props.text,
+ marker: props.color ? { color: props.color } : undefined,
+ line: props.color ? { color: props.color } : undefined,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/ScatterTernary.ts b/packages/plotly/src/traces/ScatterTernary.ts
new file mode 100644
index 000000000..1a0a8a797
--- /dev/null
+++ b/packages/plotly/src/traces/ScatterTernary.ts
@@ -0,0 +1,49 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const ScatterTernarySchema = z.object({
+ a: z.array(z.number()),
+ b: z.array(z.number()),
+ c: z.array(z.number()),
+ text: z.array(z.string()).optional(),
+ mode: z.enum(["markers", "lines", "lines+markers"]).optional(),
+ size: z.union([z.array(z.number()), z.number()]).optional(),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ aLabel: z.string().optional(),
+ bLabel: z.string().optional(),
+ cLabel: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const ScatterTernary = defineComponent({
+ name: "ScatterTernary",
+ props: ScatterTernarySchema,
+ description:
+ "Ternary scatter — points in a triangle whose three corners are constrained to sum to a constant. Pass parallel `a`/`b`/`c` arrays (compositions). Common in chemistry, soil science, mineralogy.",
+ component: ({ props }) => {
+ const trace = {
+ type: "scatterternary",
+ a: props.a,
+ b: props.b,
+ c: props.c,
+ mode: props.mode ?? "markers",
+ text: props.text,
+ marker: { size: props.size ?? 8, color: props.color },
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ ternary: {
+ sum: 100,
+ aaxis: { title: { text: props.aLabel ?? "a" } },
+ baxis: { title: { text: props.bLabel ?? "b" } },
+ caxis: { title: { text: props.cLabel ?? "c" } },
+ } as never,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/StreamTube.ts b/packages/plotly/src/traces/StreamTube.ts
new file mode 100644
index 000000000..56cb71ab0
--- /dev/null
+++ b/packages/plotly/src/traces/StreamTube.ts
@@ -0,0 +1,45 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const StreamTubeSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ u: z.array(z.number()),
+ v: z.array(z.number()),
+ w: z.array(z.number()),
+ colormap: z.string().optional(),
+ maxdisplayed: z.number().int().positive().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const StreamTube = defineComponent({
+ name: "StreamTube",
+ props: StreamTubeSchema,
+ description:
+ "3D stream tubes — integrated paths through a vector field starting from given seed points. Same input shape as Cone (`x,y,z,u,v,w`). `maxdisplayed` caps the number of tubes for performance.",
+ component: ({ props }) => {
+ const trace = {
+ type: "streamtube",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ u: props.u,
+ v: props.v,
+ w: props.w,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ maxdisplayed: props.maxdisplayed,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Sunburst.ts b/packages/plotly/src/traces/Sunburst.ts
new file mode 100644
index 000000000..283f2daa2
--- /dev/null
+++ b/packages/plotly/src/traces/Sunburst.ts
@@ -0,0 +1,42 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const SunburstSchema = z.object({
+ ids: z.array(z.string()),
+ parents: z.array(z.string()),
+ values: z.array(z.number()).optional(),
+ labels: z.array(z.string()).optional(),
+ branchvalues: z.enum(["remainder", "total"]).optional(),
+ colormap: z.string().optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Sunburst = defineComponent({
+ name: "Sunburst",
+ props: SunburstSchema,
+ description:
+ "Hierarchical sunburst. Pass parallel arrays: `ids` (unique node ids), `parents` (parent id of each node — empty string for the root), `values` (leaf-only or all-nodes; controlled by `branchvalues`). Optional `labels` (defaults to `ids`). `branchvalues='total'` if values include parent sums; 'remainder' (default) if Plotly should sum from leaves.",
+ component: ({ props }) => {
+ if (!props.ids?.length || !props.parents?.length) return null;
+ const trace: Data = {
+ type: "sunburst",
+ ids: props.ids,
+ parents: props.parents,
+ values: props.values,
+ labels: props.labels ?? props.ids,
+ branchvalues: props.branchvalues ?? "remainder",
+ hovertemplate:
+ "%{label}
value: %{value}
share: %{percentEntry:.1%} of parent",
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Surface.ts b/packages/plotly/src/traces/Surface.ts
new file mode 100644
index 000000000..aa79a0944
--- /dev/null
+++ b/packages/plotly/src/traces/Surface.ts
@@ -0,0 +1,52 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const SurfaceSchema = z.object({
+ z: z.array(z.array(z.number())),
+ x: z.array(z.number()).optional(),
+ y: z.array(z.number()).optional(),
+ colormap: z.string().optional(),
+ showContours: z.boolean().optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ zLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Surface = defineComponent({
+ name: "Surface",
+ props: SurfaceSchema,
+ description:
+ "WebGL 3D surface plot. Pass `z` as a height×width matrix; optional `x`/`y` axis values. `showContours=true` projects contour lines onto the surface for shape readability.",
+ component: ({ props }) => {
+ const trace = {
+ type: "surface",
+ z: props.z,
+ x: props.x,
+ y: props.y,
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ contours: props.showContours
+ ? {
+ z: { show: true, usecolormap: true, highlightcolor: "#ffffff", project: { z: true } },
+ }
+ : undefined,
+ showscale: true,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ scene: {
+ xaxis: { title: { text: props.xLabel ?? "x" } },
+ yaxis: { title: { text: props.yLabel ?? "y" } },
+ zaxis: { title: { text: props.zLabel ?? "z" } },
+ },
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Table.ts b/packages/plotly/src/traces/Table.ts
new file mode 100644
index 000000000..ec961dee5
--- /dev/null
+++ b/packages/plotly/src/traces/Table.ts
@@ -0,0 +1,67 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const TableSchema = z.object({
+ headers: z.array(z.string()),
+ values: z.array(z.array(z.union([z.string(), z.number()]))),
+ align: z.enum(["left", "center", "right"]).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+// Defensive normalization — the LLM frequently emits Tables where:
+// • the number of value columns < the number of headers, or
+// • columns have different lengths.
+// Rather than rendering empty space, pad to a consistent rectangle and use
+// "—" for cells the model never filled in. This makes incomplete data
+// visibly incomplete instead of looking like an empty table.
+function normalize(
+ headers: string[],
+ values: Array>,
+): Array> {
+ const numCols = headers.length;
+ const cols = Array.from({ length: numCols }, (_, i) => values[i] ?? []);
+ const rowCount = Math.max(0, ...cols.map((c) => c.length));
+ return cols.map((c) => {
+ if (c.length === rowCount) return c;
+ return [...c, ...Array(rowCount - c.length).fill("—")];
+ });
+}
+
+export const Table = defineComponent({
+ name: "Table",
+ props: TableSchema,
+ description:
+ "Plotly table — COLUMN-oriented. `headers` is the list of column titles. `values` is an array of columns, where each column is an array of cells (e.g. `Table(['Name','Age'], [['Alice','Bob'], [30, 25]])`). Pass ALL columns matching headers length — short or missing columns are padded with '—' so missing data is visible.",
+ component: ({ props }) => {
+ const headers = props.headers ?? [];
+ if (headers.length === 0) return null;
+ const cols = normalize(headers, props.values ?? []);
+ const trace = {
+ type: "table",
+ header: {
+ values: headers,
+ align: props.align ?? "left",
+ fill: { color: "rgba(15,23,42,0.04)" },
+ font: { size: 11, color: "rgba(15,23,42,0.85)" },
+ line: { color: "rgba(15,23,42,0.10)" },
+ },
+ cells: {
+ values: cols,
+ align: props.align ?? "left",
+ font: { size: 12, color: "#0f172a" },
+ line: { color: "rgba(15,23,42,0.06)" },
+ height: 28,
+ },
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 4, l: 4, r: 4, b: 4 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Treemap.ts b/packages/plotly/src/traces/Treemap.ts
new file mode 100644
index 000000000..c16c1a132
--- /dev/null
+++ b/packages/plotly/src/traces/Treemap.ts
@@ -0,0 +1,41 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+
+const TreemapSchema = z.object({
+ ids: z.array(z.string()),
+ parents: z.array(z.string()),
+ values: z.array(z.number()).optional(),
+ labels: z.array(z.string()).optional(),
+ branchvalues: z.enum(["remainder", "total"]).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Treemap = defineComponent({
+ name: "Treemap",
+ props: TreemapSchema,
+ description:
+ "Hierarchical treemap. Pass parallel arrays: `ids`, `parents` (root parent is empty string ''), `values`, optional `labels`. `branchvalues='total'` if values include parent sums; 'remainder' (default) sums from leaves.",
+ component: ({ props }) => {
+ if (!props.ids?.length || !props.parents?.length) return null;
+ const trace: Data = {
+ type: "treemap",
+ ids: props.ids,
+ parents: props.parents,
+ values: props.values,
+ labels: props.labels ?? props.ids,
+ branchvalues: props.branchvalues ?? "remainder",
+ hovertemplate:
+ "%{label}
value: %{value}
share: %{percentEntry:.1%} of parent",
+ };
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 40 : 8, l: 8, r: 8, b: 8 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Violin.ts b/packages/plotly/src/traces/Violin.ts
new file mode 100644
index 000000000..3424e8ed7
--- /dev/null
+++ b/packages/plotly/src/traces/Violin.ts
@@ -0,0 +1,60 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout, resolve, splitByGroup } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const ViolinSchema = z.object({
+ data: z.array(z.record(z.string(), z.unknown())).nullable().optional(),
+ x: z.union([z.array(z.string()), z.string()]).optional(),
+ y: z.union([z.array(z.number()), z.string()]),
+ color: z.union([z.array(z.string()), z.string()]).optional(),
+ showBox: z.boolean().optional(),
+ showPoints: z.union([z.boolean(), z.enum(["all", "outliers", "suspectedoutliers"])]).optional(),
+ side: z.enum(["both", "positive", "negative"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Violin = defineComponent({
+ name: "Violin",
+ props: ViolinSchema,
+ description:
+ "Violin plot. Pass `y` (the numeric variable) and optionally `x` (a categorical grouping field/array) to compare distributions across groups. `showBox=true` overlays the box; `showPoints` controls jittered point overlay ('all' | 'outliers' | true | false). For ridgeline-style stacking, set `side='positive'`.",
+ component: ({ props }) => {
+ // Violin always needs y; x is optional for grouping.
+ const r = resolve({
+ data: props.data ?? undefined,
+ x: props.x ?? props.y,
+ y: props.y,
+ color: props.color,
+ });
+ if (!r) return null;
+ const groups = splitByGroup(r);
+ const points =
+ props.showPoints === undefined ? false : props.showPoints === true ? "all" : props.showPoints;
+ const traces: Data[] = groups.map((g) => ({
+ type: "violin",
+ x:
+ typeof props.x === "string" || Array.isArray(props.x)
+ ? (g.x as Array)
+ : undefined,
+ y: g.y as number[],
+ name: g.group || undefined,
+ box: { visible: props.showBox ?? true },
+ meanline: { visible: true },
+ points: points as never,
+ side: props.side,
+ }));
+ const layout = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: groups.length > 1 && groups[0]!.group !== "",
+ violinmode: "group",
+ } as Partial;
+ return React.createElement(PlotShell, { data: traces, layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/src/traces/Volume.ts b/packages/plotly/src/traces/Volume.ts
new file mode 100644
index 000000000..495c005d7
--- /dev/null
+++ b/packages/plotly/src/traces/Volume.ts
@@ -0,0 +1,47 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { PlotShell } from "../shell/PlotShell";
+import { resolveColormap } from "../shell/colormap";
+
+const VolumeSchema = z.object({
+ x: z.array(z.number()),
+ y: z.array(z.number()),
+ z: z.array(z.number()),
+ value: z.array(z.number()),
+ isomin: z.number().optional(),
+ isomax: z.number().optional(),
+ surfaceCount: z.number().int().positive().optional(),
+ colormap: z.string().optional(),
+ opacity: z.number().min(0).max(1).optional(),
+ title: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Volume = defineComponent({
+ name: "Volume",
+ props: VolumeSchema,
+ description:
+ "Volume rendering of a 3D scalar field — multiple translucent isosurfaces stacked. Like Isosurface but with semi-transparent layering for the full volumetric structure. Same input shape (`x,y,z,value`).",
+ component: ({ props }) => {
+ const trace = {
+ type: "volume",
+ x: props.x,
+ y: props.y,
+ z: props.z,
+ value: props.value,
+ isomin: props.isomin,
+ isomax: props.isomax,
+ surface: { count: props.surfaceCount ?? 12 },
+ colorscale: resolveColormap(props.colormap ?? "viridis"),
+ opacity: props.opacity ?? 0.15,
+ } as unknown as Data;
+ const layout: Partial = {
+ title: props.title ? { text: props.title } : undefined,
+ margin: { t: props.title ? 32 : 8, l: 0, r: 0, b: 0 },
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height ?? 420 });
+ },
+});
diff --git a/packages/plotly/src/traces/Waterfall.ts b/packages/plotly/src/traces/Waterfall.ts
new file mode 100644
index 000000000..852694edb
--- /dev/null
+++ b/packages/plotly/src/traces/Waterfall.ts
@@ -0,0 +1,45 @@
+"use client";
+import { defineComponent } from "@openuidev/react-lang";
+import type { Data, Layout } from "plotly.js";
+import React from "react";
+import { z } from "zod/v4";
+import { buildAxisLayout } from "../helpers/buildTrace";
+import { PlotShell } from "../shell/PlotShell";
+
+const WaterfallSchema = z.object({
+ x: z.array(z.union([z.string(), z.number()])),
+ y: z.array(z.number()),
+ measure: z.array(z.enum(["relative", "total", "absolute"])).optional(),
+ orientation: z.enum(["v", "h"]).optional(),
+ title: z.string().optional(),
+ xLabel: z.string().optional(),
+ yLabel: z.string().optional(),
+ height: z.number().positive().optional(),
+});
+
+export const Waterfall = defineComponent({
+ name: "Waterfall",
+ props: WaterfallSchema,
+ description:
+ "Waterfall chart — running totals with up/down deltas. `x` is category labels, `y` is the delta value at each step. `measure` per step: 'relative' (default — adds to running total), 'total' (subtotal), 'absolute' (resets running total).",
+ component: ({ props }) => {
+ const orientation = props.orientation ?? "v";
+ const measure = props.measure ?? props.y.map(() => "relative" as const);
+ const trace = {
+ type: "waterfall",
+ orientation,
+ x: orientation === "v" ? (props.x as Array) : props.y,
+ y: orientation === "v" ? props.y : (props.x as Array),
+ measure,
+ connector: { line: { color: "rgba(15,23,42,0.18)" } },
+ increasing: { marker: { color: "#16a34a" } },
+ decreasing: { marker: { color: "#dc2626" } },
+ totals: { marker: { color: "#4c78a8" } },
+ } as unknown as Data;
+ const layout: Partial = {
+ ...(buildAxisLayout(props) as Partial),
+ showlegend: false,
+ };
+ return React.createElement(PlotShell, { data: [trace], layout, height: props.height });
+ },
+});
diff --git a/packages/plotly/styles/plotly.css b/packages/plotly/styles/plotly.css
new file mode 100644
index 000000000..7eb6320ff
--- /dev/null
+++ b/packages/plotly/styles/plotly.css
@@ -0,0 +1,38 @@
+@keyframes openui-plotly-shimmer {
+ 0% {
+ background-position: 200% 0;
+ }
+ 100% {
+ background-position: -200% 0;
+ }
+}
+
+@keyframes openui-plotly-mount {
+ from {
+ opacity: 0;
+ transform: translateY(4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.openui-plotly-mount {
+ animation: openui-plotly-mount 320ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+/* Plotly's default modebar can clash with the chat surface — ensure it sits
+ above the chart on hover but stays out of the way otherwise. */
+.openui-plotly-mount .modebar-container {
+ z-index: 2;
+}
+.openui-plotly-mount:hover .modebar-container {
+ opacity: 1;
+}
+
+/* Soften Plotly's hover label transitions to match the rest of OpenUI */
+.openui-plotly-mount .hoverlayer .hovertext {
+ filter: drop-shadow(0 1px 2px rgba(15, 23, 42, 0.06))
+ drop-shadow(0 4px 12px rgba(15, 23, 42, 0.08));
+}
diff --git a/packages/plotly/tsconfig.json b/packages/plotly/tsconfig.json
new file mode 100644
index 000000000..59b6ae42e
--- /dev/null
+++ b/packages/plotly/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": false,
+ "declarationMap": true
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
+ "exclude": ["node_modules", "dist", "tsdown.config.ts"]
+}
diff --git a/packages/plotly/tsdown.config.ts b/packages/plotly/tsdown.config.ts
new file mode 100644
index 000000000..6ee8f6fcd
--- /dev/null
+++ b/packages/plotly/tsdown.config.ts
@@ -0,0 +1,20 @@
+import { defineConfig } from "tsdown";
+
+export default defineConfig({
+ entry: ["src/index.ts"],
+ format: ["esm", "cjs"],
+ dts: false,
+ sourcemap: true,
+ clean: false,
+ treeshake: true,
+ external: [
+ "react",
+ "react-dom",
+ "react/jsx-runtime",
+ /^plotly\.js/,
+ "plotly.js-dist-min",
+ /^react-plotly\.js/,
+ /^@openuidev\//,
+ /^zod/,
+ ],
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 46f5095dc..93be238ed 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1152,6 +1152,52 @@ importers:
specifier: ^22.15.32
version: 22.15.32
+ packages/plotly:
+ dependencies:
+ '@openuidev/react-headless':
+ specifier: workspace:^
+ version: link:../react-headless
+ '@openuidev/react-lang':
+ specifier: workspace:^
+ version: link:../react-lang
+ '@openuidev/react-ui':
+ specifier: workspace:^
+ version: link:../react-ui
+ plotly.js-dist-min:
+ specifier: ^3.0.0
+ version: 3.5.1
+ react:
+ specifier: ^18.3.1 || ^19.0.0
+ version: 19.2.4
+ react-dom:
+ specifier: ^18.0.0 || ^19.0.0
+ version: 19.2.4(react@19.2.4)
+ react-plotly.js:
+ specifier: ^2.6.0
+ version: 2.6.0(plotly.js@3.5.1(mapbox-gl@1.13.3))(react@19.2.4)
+ zod:
+ specifier: ^3.25.0 || ^4.0.0
+ version: 4.3.6
+ devDependencies:
+ '@types/node':
+ specifier: ^22.15.32
+ version: 22.15.32
+ '@types/plotly.js':
+ specifier: ^3.0.0
+ version: 3.0.10
+ '@types/plotly.js-dist-min':
+ specifier: ^2.3.4
+ version: 2.3.4
+ '@types/react':
+ specifier: '>=18.3.1'
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: '>=18.3.1'
+ version: 19.2.3(@types/react@19.2.14)
+ '@types/react-plotly.js':
+ specifier: ^2.6.3
+ version: 2.6.4
+
packages/react-email:
dependencies:
'@openuidev/react-lang':
@@ -2322,6 +2368,10 @@ packages:
'@chevrotain/utils@11.1.2':
resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==}
+ '@choojs/findup@0.2.1':
+ resolution: {integrity: sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==}
+ hasBin: true
+
'@chromatic-com/storybook@3.2.6':
resolution: {integrity: sha512-FDmn5Ry2DzQdik+eq2sp/kJMMT36Ewe7ONXUXM2Izd97c7r6R/QyGli8eyh/F0iyqVvbLveNYFyF0dBOJNwLqw==}
engines: {node: '>=16.0.0', yarn: '>=1.22.18'}
@@ -3935,11 +3985,53 @@ packages:
resolution: {integrity: sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==}
engines: {node: '>=8'}
+ '@mapbox/geojson-rewind@0.5.2':
+ resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==}
+ hasBin: true
+
+ '@mapbox/geojson-types@1.0.2':
+ resolution: {integrity: sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==}
+
+ '@mapbox/jsonlint-lines-primitives@2.0.2':
+ resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==}
+ engines: {node: '>= 0.6'}
+
+ '@mapbox/mapbox-gl-supported@1.5.0':
+ resolution: {integrity: sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==}
+ peerDependencies:
+ mapbox-gl: '>=0.32.1 <2.0.0'
+
'@mapbox/node-pre-gyp@2.0.3':
resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==}
engines: {node: '>=18'}
hasBin: true
+ '@mapbox/point-geometry@0.1.0':
+ resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==}
+
+ '@mapbox/tiny-sdf@1.2.5':
+ resolution: {integrity: sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==}
+
+ '@mapbox/tiny-sdf@2.2.0':
+ resolution: {integrity: sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==}
+
+ '@mapbox/unitbezier@0.0.0':
+ resolution: {integrity: sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==}
+
+ '@mapbox/unitbezier@0.0.1':
+ resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==}
+
+ '@mapbox/vector-tile@1.3.1':
+ resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==}
+
+ '@mapbox/whoots-js@3.1.0':
+ resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==}
+ engines: {node: '>=6.0.0'}
+
+ '@maplibre/maplibre-gl-style-spec@20.4.0':
+ resolution: {integrity: sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==}
+ hasBin: true
+
'@mastra/client-js@1.11.2':
resolution: {integrity: sha512-CCjrC1TIuu1hKhnRZPumVpW3ePL3xTafxBY93hIaxPUm/8F/dS1symv4YD0hgFQv/ajiVrjeQcWK+zp2KovDCA==}
engines: {node: '>=22.13.0'}
@@ -4981,6 +5073,25 @@ packages:
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ '@plotly/d3-sankey-circular@0.33.1':
+ resolution: {integrity: sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==}
+
+ '@plotly/d3-sankey@0.7.2':
+ resolution: {integrity: sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw==}
+
+ '@plotly/d3@3.8.2':
+ resolution: {integrity: sha512-wvsNmh1GYjyJfyEBPKJLTMzgf2c2bEbSIL50lmqVUi+o1NHaLPi1Lb4v7VxXXJn043BhNyrxUrWI85Q+zmjOVA==}
+
+ '@plotly/mapbox-gl@1.13.4':
+ resolution: {integrity: sha512-sR3/Pe5LqT/fhYgp4rT4aSFf1rTsxMbGiH6Hojc7PH36ny5Bn17iVFUjpzycafETURuFbLZUfjODO8LvSI+5zQ==}
+ engines: {node: '>=6.4.0'}
+
+ '@plotly/point-cluster@3.1.9':
+ resolution: {integrity: sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw==}
+
+ '@plotly/regl@2.1.2':
+ resolution: {integrity: sha512-Mdk+vUACbQvjd0m/1JJjOOafmkp/EpmHjISsopEz5Av44CBq7rPC05HHNbYGKVyNUF2zmEoBS/TT0pd0SPFFyw==}
+
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -7983,6 +8094,21 @@ packages:
peerDependencies:
'@testing-library/dom': '>=7.21.4'
+ '@turf/area@7.3.5':
+ resolution: {integrity: sha512-sSn80wPT7XfBIDN3vurCPxhk9W4U8ozS/XImSqeLN8qveTICOxzZkhsGDMp0CuncaN+plWut4a2TdNM7mzZB6Q==}
+
+ '@turf/bbox@7.3.5':
+ resolution: {integrity: sha512-oG1ya/HtBjAIg4TimbWx+nOYPbY0bCvt82Bq8tm6sBw3qqtbOyRSfDz79Sq90TnH7DXJprJ1qnVGKNtZ6jemfw==}
+
+ '@turf/centroid@7.3.5':
+ resolution: {integrity: sha512-hkWaqwGFdOn6Tf0EWfn2yn1XZ1FWE1h2C5ZWstDMu/FxYO5DB+YjlmOFPl4K6SmSOEgdV07eK2vDCyPeTHqKGA==}
+
+ '@turf/helpers@7.3.5':
+ resolution: {integrity: sha512-E/NMGV5MwbjjP7AJXBtsanC3yY8N2MQ87IGdIgkB2ji5AtBpwnH4L3gEqpYN4RlCJJWbLbzO91BbKv2waUd0eg==}
+
+ '@turf/meta@7.3.5':
+ resolution: {integrity: sha512-r+ohqxoyqeigFB0oFrQx/YEHIkOKqcKpCjvZkvZs7Tkv+IFco5MezAd2zd4rzK+0DfFgDP3KpJc7HqrYjvEjhg==}
+
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -8142,6 +8268,9 @@ packages:
'@types/express@4.17.25':
resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==}
+ '@types/geojson-vt@3.2.5':
+ resolution: {integrity: sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==}
+
'@types/geojson@7946.0.16':
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
@@ -8184,6 +8313,12 @@ packages:
'@types/lodash@4.17.18':
resolution: {integrity: sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==}
+ '@types/mapbox__point-geometry@0.1.4':
+ resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==}
+
+ '@types/mapbox__vector-tile@1.3.4':
+ resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==}
+
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
@@ -8211,6 +8346,15 @@ packages:
'@types/node@25.3.2':
resolution: {integrity: sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==}
+ '@types/pbf@3.0.5':
+ resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==}
+
+ '@types/plotly.js-dist-min@2.3.4':
+ resolution: {integrity: sha512-ISwLFV6Zs/v3DkaRFLyk2rvYAfVdnYP2VVVy7h+fBDWw52sn7sMUzytkWiN4M75uxr1uz1uiBioePTDpAfoFIg==}
+
+ '@types/plotly.js@3.0.10':
+ resolution: {integrity: sha512-q+MgO4aajC2HrO7FllTYWzrpdfbTjboSMfjkz/aXKjg1v7HNo1zMEFfAW7quKfk6SL+bH74A5ThBEps/7hZxOA==}
+
'@types/prismjs@1.26.6':
resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==}
@@ -8225,6 +8369,9 @@ packages:
peerDependencies:
'@types/react': ^19.2.0
+ '@types/react-plotly.js@2.6.4':
+ resolution: {integrity: sha512-AU6w1u3qEGM0NmBA69PaOgNc0KPFA/+qkH6Uu9EBTJ45/WYOUoXi9AF5O15PRM2klpHSiHAAs4WnlI+OZAFmUA==}
+
'@types/react-syntax-highlighter@15.5.13':
resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==}
@@ -8255,6 +8402,9 @@ packages:
'@types/stack-utils@2.0.3':
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+ '@types/supercluster@7.1.3':
+ resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==}
+
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -8761,6 +8911,9 @@ packages:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
+ abs-svg-path@0.1.1:
+ resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==}
+
accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@@ -8779,6 +8932,11 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ acorn@7.4.1:
+ resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
acorn@8.16.0:
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
engines: {node: '>=0.4.0'}
@@ -8925,10 +9083,17 @@ packages:
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
engines: {node: '>= 0.4'}
+ array-bounds@1.0.1:
+ resolution: {integrity: sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ==}
+
array-buffer-byte-length@1.0.2:
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
engines: {node: '>= 0.4'}
+ array-find-index@1.0.2:
+ resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==}
+ engines: {node: '>=0.10.0'}
+
array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -8936,6 +9101,12 @@ packages:
resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
engines: {node: '>= 0.4'}
+ array-normalize@1.1.4:
+ resolution: {integrity: sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg==}
+
+ array-range@1.0.1:
+ resolution: {integrity: sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA==}
+
array.prototype.findlast@1.2.5:
resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
engines: {node: '>= 0.4'}
@@ -9155,6 +9326,10 @@ packages:
bare-url@2.4.0:
resolution: {integrity: sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==}
+ base64-arraybuffer@1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -9181,6 +9356,9 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
+ binary-search-bounds@2.0.5:
+ resolution: {integrity: sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==}
+
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
@@ -9190,6 +9368,15 @@ packages:
birpc@4.0.0:
resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==}
+ bit-twiddle@1.0.2:
+ resolution: {integrity: sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==}
+
+ bitmap-sdf@1.0.4:
+ resolution: {integrity: sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==}
+
+ bl@2.2.1:
+ resolution: {integrity: sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==}
+
body-parser@1.20.4:
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -9449,6 +9636,9 @@ packages:
cjs-module-lexer@1.4.3:
resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
+ clamp@1.0.1:
+ resolution: {integrity: sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==}
+
class-transformer@0.5.1:
resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==}
@@ -9512,6 +9702,9 @@ packages:
collapse-white-space@2.1.0:
resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
+ color-alpha@1.1.3:
+ resolution: {integrity: sha512-krPYBO1RSO5LH4AGb/b6z70O1Ip2o0F0+0cVFN5FN99jfQtZFT08rQyg+9oOBNJYAn3SRwJIFC8jUEOKz7PisA==}
+
color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@@ -9519,12 +9712,37 @@ packages:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
+ color-id@1.1.0:
+ resolution: {integrity: sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==}
+
color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ color-name@2.1.0:
+ resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==}
+ engines: {node: '>=12.20'}
+
+ color-normalize@1.5.0:
+ resolution: {integrity: sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw==}
+
+ color-parse@1.4.3:
+ resolution: {integrity: sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==}
+
+ color-parse@2.0.2:
+ resolution: {integrity: sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==}
+
+ color-rgba@2.4.0:
+ resolution: {integrity: sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==}
+
+ color-rgba@3.0.0:
+ resolution: {integrity: sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==}
+
+ color-space@2.3.2:
+ resolution: {integrity: sha512-BcKnbOEsOarCwyoLstcoEztwT0IJxqqQkNwDuA3a65sICvvHL2yoeV13psoDFh5IuiOMnIOKdQDwB4Mk3BypiA==}
+
colord@2.9.3:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
@@ -9599,6 +9817,10 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ concat-stream@1.6.2:
+ resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
+ engines: {'0': node >= 0.8}
+
concurrently@9.2.0:
resolution: {integrity: sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==}
engines: {node: '>=18'}
@@ -9682,6 +9904,9 @@ packages:
cose-base@2.2.0:
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
+ country-regex@1.1.0:
+ resolution: {integrity: sha512-iSPlClZP8vX7MC3/u6s3lrDuoQyhQukh5LyABJ3hvfzbQ3Yyayd4fp04zjLnfi267B/B2FkumcWWgrbban7sSA==}
+
crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
@@ -9715,12 +9940,33 @@ packages:
peerDependencies:
postcss: ^8.0.9
+ css-font-size-keywords@1.0.0:
+ resolution: {integrity: sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q==}
+
+ css-font-stretch-keywords@1.0.1:
+ resolution: {integrity: sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg==}
+
+ css-font-style-keywords@1.0.1:
+ resolution: {integrity: sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg==}
+
+ css-font-weight-keywords@1.0.0:
+ resolution: {integrity: sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA==}
+
+ css-font@1.2.0:
+ resolution: {integrity: sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA==}
+
+ css-global-keywords@1.0.1:
+ resolution: {integrity: sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ==}
+
css-in-js-utils@3.1.0:
resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==}
css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
+ css-system-font-keywords@1.0.0:
+ resolution: {integrity: sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA==}
+
css-tree@1.1.3:
resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
engines: {node: '>=8.0.0'}
@@ -9740,6 +9986,9 @@ packages:
css.escape@1.5.1:
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+ csscolorparser@1.0.3:
+ resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==}
+
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@@ -9788,6 +10037,9 @@ packages:
resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==}
engines: {node: '>=0.10'}
+ d3-array@1.2.4:
+ resolution: {integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==}
+
d3-array@2.12.1:
resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
@@ -9807,6 +10059,9 @@ packages:
resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
engines: {node: '>=12'}
+ d3-collection@1.0.7:
+ resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==}
+
d3-color@3.1.0:
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
engines: {node: '>=12'}
@@ -9819,6 +10074,9 @@ packages:
resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
engines: {node: '>=12'}
+ d3-dispatch@1.0.6:
+ resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==}
+
d3-dispatch@3.0.1:
resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
engines: {node: '>=12'}
@@ -9840,18 +10098,34 @@ packages:
resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
engines: {node: '>=12'}
+ d3-force@1.2.1:
+ resolution: {integrity: sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==}
+
d3-force@3.0.0:
resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
engines: {node: '>=12'}
+ d3-format@1.4.5:
+ resolution: {integrity: sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==}
+
d3-format@3.1.0:
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
engines: {node: '>=12'}
+ d3-geo-projection@2.9.0:
+ resolution: {integrity: sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==}
+ hasBin: true
+
+ d3-geo@1.12.1:
+ resolution: {integrity: sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==}
+
d3-geo@3.1.1:
resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==}
engines: {node: '>=12'}
+ d3-hierarchy@1.1.9:
+ resolution: {integrity: sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==}
+
d3-hierarchy@3.1.2:
resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
engines: {node: '>=12'}
@@ -9871,6 +10145,9 @@ packages:
resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==}
engines: {node: '>=12'}
+ d3-quadtree@1.0.7:
+ resolution: {integrity: sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==}
+
d3-quadtree@3.0.1:
resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
engines: {node: '>=12'}
@@ -9901,14 +10178,23 @@ packages:
resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
engines: {node: '>=12'}
+ d3-time-format@2.3.0:
+ resolution: {integrity: sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==}
+
d3-time-format@4.1.0:
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
engines: {node: '>=12'}
+ d3-time@1.1.0:
+ resolution: {integrity: sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==}
+
d3-time@3.1.0:
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
engines: {node: '>=12'}
+ d3-timer@1.0.10:
+ resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==}
+
d3-timer@3.0.1:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
@@ -9927,6 +10213,10 @@ packages:
resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==}
engines: {node: '>=12'}
+ d@1.0.2:
+ resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
+ engines: {node: '>=0.12'}
+
dagre-d3-es@7.0.14:
resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==}
@@ -10070,6 +10360,9 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
+ defined@1.0.1:
+ resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
+
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
@@ -10099,6 +10392,9 @@ packages:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ detect-kerning@2.1.2:
+ resolution: {integrity: sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==}
+
detect-libc@1.0.3:
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
engines: {node: '>=0.10'}
@@ -10176,6 +10472,9 @@ packages:
resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==}
engines: {node: '>=12'}
+ draw-svg-path@1.0.0:
+ resolution: {integrity: sha512-P8j3IHxcgRMcY6sDzr0QvJDLzBnJJqpTG33UZ2Pvp8rw0apCHhJCWqYprqrXjrgHnJ6tuhP1iTJSAodPDHxwkg==}
+
dset@3.1.4:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'}
@@ -10189,13 +10488,29 @@ packages:
oxc-resolver:
optional: true
+ dtype@2.0.0:
+ resolution: {integrity: sha512-s2YVcLKdFGS0hpFqJaTwscsyt0E8nNFdmo73Ocd81xNPj4URI4rj6D60A+vFMIw7BXWlb4yRkEwfBqcZzPGiZg==}
+ engines: {node: '>= 0.8.0'}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
+ dup@1.0.0:
+ resolution: {integrity: sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA==}
+
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+ duplexify@3.7.1:
+ resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
+
+ earcut@2.2.4:
+ resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==}
+
+ earcut@3.0.2:
+ resolution: {integrity: sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==}
+
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -10213,6 +10528,9 @@ packages:
electron-to-chromium@1.5.313:
resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==}
+ elementary-circuits-directed-graph@1.3.1:
+ resolution: {integrity: sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ==}
+
embla-carousel-react@8.6.0:
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
peerDependencies:
@@ -10327,6 +10645,20 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
+ es5-ext@0.10.64:
+ resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
+ engines: {node: '>=0.10'}
+
+ es6-iterator@2.0.3:
+ resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
+
+ es6-symbol@3.1.4:
+ resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
+ engines: {node: '>=0.12'}
+
+ es6-weak-map@2.0.3:
+ resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
+
esast-util-from-estree@2.0.0:
resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
@@ -10386,6 +10718,11 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
+ escodegen@2.1.0:
+ resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+ engines: {node: '>=6.0'}
+ hasBin: true
+
eslint-config-next@16.1.6:
resolution: {integrity: sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==}
peerDependencies:
@@ -10542,6 +10879,10 @@ packages:
esm-env@1.2.2:
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
+ esniff@2.0.1:
+ resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
+ engines: {node: '>=0.10'}
+
espree@10.4.0:
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -10605,6 +10946,9 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
+ event-emitter@0.3.5:
+ resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
+
event-target-shim@5.0.1:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
@@ -10728,6 +11072,9 @@ packages:
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
+ ext@1.7.0:
+ resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+
extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
@@ -10738,6 +11085,10 @@ packages:
externality@1.0.2:
resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==}
+ falafel@2.2.5:
+ resolution: {integrity: sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==}
+ engines: {node: '>=0.4.0'}
+
fast-content-type-parse@3.0.0:
resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
@@ -10768,6 +11119,9 @@ packages:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
+ fast-isnumeric@1.1.4:
+ resolution: {integrity: sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==}
+
fast-json-patch@3.1.1:
resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
@@ -10877,9 +11231,18 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ flatten-vertex-data@1.0.2:
+ resolution: {integrity: sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==}
+
flow-enums-runtime@0.0.6:
resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==}
+ font-atlas@2.1.0:
+ resolution: {integrity: sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==}
+
+ font-measure@1.2.2:
+ resolution: {integrity: sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA==}
+
fontfaceobserver@2.3.0:
resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==}
@@ -10939,6 +11302,9 @@ packages:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
+ from2@2.3.0:
+ resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==}
+
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
@@ -11072,10 +11438,19 @@ packages:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
+ geojson-vt@3.2.1:
+ resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==}
+
+ geojson-vt@4.0.2:
+ resolution: {integrity: sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
+ get-canvas-context@1.0.2:
+ resolution: {integrity: sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A==}
+
get-east-asian-width@1.5.0:
resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
engines: {node: '>=18'}
@@ -11099,6 +11474,10 @@ packages:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
+ get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
@@ -11132,6 +11511,18 @@ packages:
github-slugger@2.0.0:
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
+ gl-mat4@1.2.0:
+ resolution: {integrity: sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==}
+
+ gl-matrix@3.4.4:
+ resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==}
+
+ gl-text@1.4.0:
+ resolution: {integrity: sha512-o47+XBqLCj1efmuNyCHt7/UEJmB9l66ql7pnobD6p+sgmBUdzfMZXIF0zD2+KRfpd99DJN+QXdvTFAGCKCVSmQ==}
+
+ gl-util@3.1.3:
+ resolution: {integrity: sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA==}
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -11160,6 +11551,10 @@ packages:
resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
engines: {node: '>=18'}
+ global-prefix@4.0.0:
+ resolution: {integrity: sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==}
+ engines: {node: '>=16'}
+
globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -11180,6 +11575,52 @@ packages:
resolution: {integrity: sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==}
engines: {node: '>=20'}
+ glsl-inject-defines@1.0.3:
+ resolution: {integrity: sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==}
+
+ glsl-resolve@0.0.1:
+ resolution: {integrity: sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA==}
+
+ glsl-token-assignments@2.0.2:
+ resolution: {integrity: sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ==}
+
+ glsl-token-defines@1.0.0:
+ resolution: {integrity: sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ==}
+
+ glsl-token-depth@1.1.2:
+ resolution: {integrity: sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg==}
+
+ glsl-token-descope@1.0.2:
+ resolution: {integrity: sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw==}
+
+ glsl-token-inject-block@1.1.0:
+ resolution: {integrity: sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA==}
+
+ glsl-token-properties@1.0.1:
+ resolution: {integrity: sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA==}
+
+ glsl-token-scope@1.1.2:
+ resolution: {integrity: sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A==}
+
+ glsl-token-string@1.0.1:
+ resolution: {integrity: sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==}
+
+ glsl-token-whitespace-trim@1.0.0:
+ resolution: {integrity: sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ==}
+
+ glsl-tokenizer@2.1.5:
+ resolution: {integrity: sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==}
+
+ glslify-bundle@5.1.1:
+ resolution: {integrity: sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==}
+
+ glslify-deps@1.3.2:
+ resolution: {integrity: sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==}
+
+ glslify@7.1.1:
+ resolution: {integrity: sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog==}
+ hasBin: true
+
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
@@ -11215,6 +11656,9 @@ packages:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
+ grid-index@1.1.0:
+ resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==}
+
gzip-size@7.0.0:
resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -11240,6 +11684,12 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ has-hover@1.0.1:
+ resolution: {integrity: sha512-0G6w7LnlcpyDzpeGUTuT0CEw05+QlMuGVk1IHNAlHrGJITGodjZu3x8BNDUMfKJSZXNB2ZAclqc1bvrd+uUpfg==}
+
+ has-passive-events@1.0.0:
+ resolution: {integrity: sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw==}
+
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
@@ -11514,6 +11964,10 @@ packages:
resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ ini@4.1.3:
+ resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
inline-style-parser@0.2.4:
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
@@ -11594,6 +12048,9 @@ packages:
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
engines: {node: '>= 0.4'}
+ is-browser@2.1.0:
+ resolution: {integrity: sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==}
+
is-bun-module@2.0.0:
resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
@@ -11641,6 +12098,14 @@ packages:
resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
engines: {node: '>= 0.4'}
+ is-finite@1.1.0:
+ resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==}
+ engines: {node: '>=0.10.0'}
+
+ is-firefox@1.0.3:
+ resolution: {integrity: sha512-6Q9ITjvWIm0Xdqv+5U12wgOKEM2KoBw4Y926m0OFkvlCxnbG94HKAsVz8w3fWcfAS5YA2fJORXX1dLrkprCCxA==}
+ engines: {node: '>=0.10.0'}
+
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
@@ -11676,6 +12141,9 @@ packages:
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
engines: {node: '>= 0.4'}
+ is-mobile@4.0.0:
+ resolution: {integrity: sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew==}
+
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
@@ -11695,10 +12163,18 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-obj@1.0.1:
+ resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==}
+ engines: {node: '>=0.10.0'}
+
is-path-inside@4.0.0:
resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
engines: {node: '>=12'}
+ is-plain-obj@1.1.0:
+ resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
+ engines: {node: '>=0.10.0'}
+
is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
@@ -11739,10 +12215,16 @@ packages:
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
engines: {node: '>=18'}
+ is-string-blank@1.0.1:
+ resolution: {integrity: sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==}
+
is-string@1.1.1:
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
engines: {node: '>= 0.4'}
+ is-svg-path@1.0.2:
+ resolution: {integrity: sha512-Lj4vePmqpPR1ZnRctHv8ltSh1OrSxHkhUkd7wi+VQdcdP15/KvQFyk7LhNuM7ZW0EVbJz8kZLVmL9quLrfq4Kg==}
+
is-symbol@1.1.1:
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
engines: {node: '>= 0.4'}
@@ -11779,6 +12261,9 @@ packages:
resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==}
engines: {node: '>=18'}
+ isarray@0.0.1:
+ resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
+
isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
@@ -11788,6 +12273,10 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ isexe@3.1.5:
+ resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==}
+ engines: {node: '>=18'}
+
isexe@4.0.0:
resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==}
engines: {node: '>=20'}
@@ -11940,6 +12429,9 @@ packages:
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ json-stringify-pretty-compact@4.0.0:
+ resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==}
+
json-with-bigint@3.5.8:
resolution: {integrity: sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==}
@@ -11967,6 +12459,12 @@ packages:
resolution: {integrity: sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==}
hasBin: true
+ kdbush@3.0.0:
+ resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==}
+
+ kdbush@4.0.2:
+ resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==}
+
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@@ -12346,9 +12844,20 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ map-limit@0.0.1:
+ resolution: {integrity: sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==}
+
map-or-similar@1.5.0:
resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
+ mapbox-gl@1.13.3:
+ resolution: {integrity: sha512-p8lJFEiqmEQlyv+DQxFAOG/XPWN0Wp7j/Psq93Zywz7qt9CcUKFYDBOoOEKzqe6gudHVJY8/Bhqw6VDpX2lSBg==}
+ engines: {node: '>=6.4.0'}
+
+ maplibre-gl@4.7.1:
+ resolution: {integrity: sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==}
+ engines: {node: '>=16.14.0', npm: '>=8.1.0'}
+
markdown-extensions@2.0.0:
resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
engines: {node: '>=16'}
@@ -12389,6 +12898,10 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ math-log2@1.0.1:
+ resolution: {integrity: sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA==}
+ engines: {node: '>=0.10.0'}
+
md-to-react-email@5.0.5:
resolution: {integrity: sha512-OvAXqwq57uOk+WZqFFNCMZz8yDp8BD3WazW1wAKHUrPbbdr89K9DWS6JXY09vd9xNdPNeurI8DU/X4flcfaD8A==}
peerDependencies:
@@ -12825,6 +13338,9 @@ packages:
react-dom:
optional: true
+ mouse-event-offset@3.0.2:
+ resolution: {integrity: sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w==}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -12842,6 +13358,9 @@ packages:
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+ murmurhash-js@1.0.0:
+ resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==}
+
mustache@4.2.0:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
@@ -12866,9 +13385,17 @@ packages:
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
hasBin: true
+ native-promise-only@0.8.1:
+ resolution: {integrity: sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==}
+
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ needle@2.9.1:
+ resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==}
+ engines: {node: '>= 4.4.x'}
+ hasBin: true
+
negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
@@ -12893,6 +13420,9 @@ packages:
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ next-tick@1.1.0:
+ resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
+
next@15.5.12:
resolution: {integrity: sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
@@ -13028,6 +13558,12 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
+ normalize-svg-path@0.1.0:
+ resolution: {integrity: sha512-1/kmYej2iedi5+ROxkRESL/pI02pkg0OBnaR4hJkSIX6+ORzepwbuUXfrdZaPjysTsJInj0Rj5NuX027+dMBvA==}
+
+ normalize-svg-path@1.1.0:
+ resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==}
+
npm-package-arg@11.0.3:
resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -13050,6 +13586,10 @@ packages:
nullthrows@1.1.1:
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
+ number-is-integer@1.0.1:
+ resolution: {integrity: sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg==}
+ engines: {node: '>=0.10.0'}
+
numbro@2.5.0:
resolution: {integrity: sha512-xDcctDimhzko/e+y+Q2/8i3qNC9Svw1QgOkSkQoO0kIPI473tR9QRbo2KP88Ty9p8WbPy+3OpTaAIzehtuHq+A==}
@@ -13154,6 +13694,9 @@ packages:
resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==}
engines: {node: '>= 0.8'}
+ once@1.3.3:
+ resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -13309,6 +13852,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parenthesis@3.1.8:
+ resolution: {integrity: sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==}
+
parse-entities@2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
@@ -13323,6 +13869,15 @@ packages:
resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==}
engines: {node: '>=10'}
+ parse-rect@1.2.0:
+ resolution: {integrity: sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA==}
+
+ parse-svg-path@0.1.2:
+ resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==}
+
+ parse-unit@1.0.1:
+ resolution: {integrity: sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==}
+
parse5-htmlparser2-tree-adapter@6.0.1:
resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==}
@@ -13394,12 +13949,22 @@ packages:
resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
engines: {node: '>= 14.16'}
+ pbf@3.3.0:
+ resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==}
+ hasBin: true
+
peberminta@0.9.0:
resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==}
perfect-debounce@2.1.0:
resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==}
+ performance-now@2.1.0:
+ resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
+ pick-by-alias@1.2.0:
+ resolution: {integrity: sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==}
+
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -13455,10 +14020,20 @@ packages:
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
engines: {node: '>=10.4.0'}
+ plotly.js-dist-min@3.5.1:
+ resolution: {integrity: sha512-N2R4RXKFSRTapdMc/+CDIbvcgFk3HNhs3tR6cKK499tNrSo7C3X7p20Wqi7qpf03s+3oH+DC/hDINYlsE8hxxA==}
+
+ plotly.js@3.5.1:
+ resolution: {integrity: sha512-rUzQ7Q46whi1aWT2JlvKE2dnryNORPrxyy66OGSMXgejK3XgD4ysD9SapMOI1RzzUJyX0KbfVDFcB9/DqOyH9Q==}
+ engines: {node: '>=18.0.0'}
+
pngjs@3.4.0:
resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
engines: {node: '>=4.0.0'}
+ point-in-polygon@1.1.0:
+ resolution: {integrity: sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==}
+
points-on-curve@0.2.0:
resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==}
@@ -13469,6 +14044,9 @@ packages:
resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==}
engines: {node: '>=10'}
+ polybooljs@1.2.2:
+ resolution: {integrity: sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==}
+
possible-typed-array-names@1.1.0:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
@@ -13700,6 +14278,12 @@ packages:
posthog-js@1.358.1:
resolution: {integrity: sha512-teipwLZtfErKDrURiUlLMnmpjgjGlni15JxyJ7oRaSlT3sX4E/mgvNatHIbWnp+7z1zYm3Jz5BYwGqwgyesRnw==}
+ potpack@1.0.2:
+ resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
+
+ potpack@2.1.0:
+ resolution: {integrity: sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==}
+
powershell-utils@0.1.0:
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
engines: {node: '>=20'}
@@ -13766,6 +14350,9 @@ packages:
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
engines: {node: '>=6'}
+ probe-image-size@7.3.0:
+ resolution: {integrity: sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ==}
+
proc-log@4.2.0:
resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -13810,6 +14397,9 @@ packages:
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
engines: {node: '>=12.0.0'}
+ protocol-buffers-schema@3.6.1:
+ resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==}
+
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@@ -13856,6 +14446,12 @@ packages:
quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+ quickselect@2.0.0:
+ resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==}
+
+ quickselect@3.0.0:
+ resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==}
+
radash@12.1.1:
resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==}
engines: {node: '>=14.18.0'}
@@ -13876,6 +14472,9 @@ packages:
radix3@1.1.2:
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
+ raf@3.4.1:
+ resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
+
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -14009,6 +14608,12 @@ packages:
'@types/react':
optional: true
+ react-plotly.js@2.6.0:
+ resolution: {integrity: sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA==}
+ peerDependencies:
+ plotly.js: '>1.34.0'
+ react: '>0.13.0'
+
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
@@ -14093,6 +14698,9 @@ packages:
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ readable-stream@1.0.34:
+ resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==}
+
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
@@ -14210,6 +14818,21 @@ packages:
resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==}
hasBin: true
+ regl-error2d@2.0.12:
+ resolution: {integrity: sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA==}
+
+ regl-line2d@3.1.3:
+ resolution: {integrity: sha512-fkgzW+tTn4QUQLpFKsUIE0sgWdCmXAM3ctXcCgoGBZTSX5FE2A0M7aynz7nrZT5baaftLrk9te54B+MEq4QcSA==}
+
+ regl-scatter2d@3.4.0:
+ resolution: {integrity: sha512-DavKQlHsI+iHZuLgOL+yGkg+sPd94CS+7FCBWkcQ6s/TbaNfUsF9eN591fjjSWIoKrGNfb/SEGhsXR5lXjqZ2w==}
+
+ regl-splom@1.0.14:
+ resolution: {integrity: sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw==}
+
+ regl@2.1.1:
+ resolution: {integrity: sha512-+IOGrxl3FZ8ZM9ixCWQZzFRiRn7Rzn9bu3iFHwg/yz4tlOUQgbO4PHLgG+1ZT60zcIV8tief6Qrmyl8qcoJP0g==}
+
rehype-harden@1.1.8:
resolution: {integrity: sha512-Qn7vR1xrf6fZCrkm9TDWi/AB4ylrHy+jqsNm1EHOAmbARYA6gsnVJBq/sdBh6kmT4NEZxH5vgIjrscefJAOXcw==}
@@ -14279,6 +14902,9 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ resolve-protobuf-schema@2.1.0:
+ resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==}
+
resolve-workspace-root@2.0.1:
resolution: {integrity: sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==}
@@ -14286,6 +14912,9 @@ packages:
resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
engines: {node: '>=10'}
+ resolve@0.6.3:
+ resolution: {integrity: sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==}
+
resolve@1.22.10:
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
engines: {node: '>= 0.4'}
@@ -14529,6 +15158,9 @@ packages:
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ shallow-copy@0.0.1:
+ resolution: {integrity: sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==}
+
sharp@0.34.5:
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -14659,6 +15291,9 @@ packages:
stable-hash@0.0.5:
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+ stack-trace@0.0.9:
+ resolution: {integrity: sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==}
+
stack-utils@2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
@@ -14676,6 +15311,9 @@ packages:
standard-as-callback@2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
+ static-eval@2.1.1:
+ resolution: {integrity: sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==}
+
statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
@@ -14707,6 +15345,12 @@ packages:
resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==}
engines: {node: '>= 0.10.0'}
+ stream-parser@0.3.1:
+ resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==}
+
+ stream-shift@1.0.3:
+ resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==}
+
streamdown@2.5.0:
resolution: {integrity: sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA==}
peerDependencies:
@@ -14716,6 +15360,9 @@ packages:
streamx@2.25.0:
resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==}
+ string-split-by@1.0.0:
+ resolution: {integrity: sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==}
+
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -14751,6 +15398,9 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
+ string_decoder@0.10.31:
+ resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
+
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
@@ -14807,6 +15457,9 @@ packages:
strip-literal@3.1.0:
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+ strongly-connected-components@1.0.1:
+ resolution: {integrity: sha512-i0TFx4wPcO0FwX+4RkLJi1MxmcTv90jNZgxMu9XRnMXMeFUY1VJlIoXpZunPUvUUqbCT1pg5PEkFqqpcaElNaA==}
+
structured-clone-es@2.0.0:
resolution: {integrity: sha512-5UuAHmBLXYPCl22xWJrFuGmIhBKQzxISPVz6E7nmTmTcAOpUzlbjKJsRrCE4vADmMQ0dzeCnlWn9XufnAGf76Q==}
@@ -14854,6 +15507,12 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
+ supercluster@7.1.5:
+ resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==}
+
+ supercluster@8.0.1:
+ resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==}
+
supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
@@ -14900,6 +15559,15 @@ packages:
resolution: {integrity: sha512-QjvU7EFemf6mRzdMGlAFttMWtAAVXrax61SZYHdkD6yoVGQ89VeyKfZD4H1JrV1WLmJBxWhFch9H6ig/87VGjw==}
engines: {node: '>=18'}
+ svg-arc-to-cubic-bezier@3.2.0:
+ resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==}
+
+ svg-path-bounds@1.0.2:
+ resolution: {integrity: sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ==}
+
+ svg-path-sdf@1.1.3:
+ resolution: {integrity: sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg==}
+
svgo@4.0.1:
resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==}
engines: {node: '>=16'}
@@ -15020,6 +15688,12 @@ packages:
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
engines: {node: '>=18'}
+ through2@0.6.5:
+ resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==}
+
+ through2@2.0.5:
+ resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+
tiny-emitter@2.1.0:
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
@@ -15033,6 +15707,9 @@ packages:
resolution: {integrity: sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==}
engines: {node: ^16.14.0 || >= 17.3.0}
+ tinycolor2@1.6.0:
+ resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
+
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
@@ -15052,6 +15729,12 @@ packages:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
+ tinyqueue@2.0.3:
+ resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==}
+
+ tinyqueue@3.0.0:
+ resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==}
+
tinyrainbow@1.2.0:
resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
engines: {node: '>=14.0.0'}
@@ -15082,6 +15765,12 @@ packages:
tmpl@1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+ to-float32@1.1.0:
+ resolution: {integrity: sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==}
+
+ to-px@1.1.0:
+ resolution: {integrity: sha512-bfg3GLYrGoEzrGoE05TAL/Uw+H/qrf2ptr9V3W7U0lkjjyYnIfgxmVLUfhQ1hZpIQwin81uxhDjvUkDYsC0xWw==}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -15097,6 +15786,10 @@ packages:
tokenx@1.3.0:
resolution: {integrity: sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==}
+ topojson-client@3.1.0:
+ resolution: {integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==}
+ hasBin: true
+
totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
@@ -15226,6 +15919,9 @@ packages:
type-level-regexp@0.1.17:
resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==}
+ type@2.7.3:
+ resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
+
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
@@ -15242,6 +15938,12 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
+ typedarray-pool@1.2.0:
+ resolution: {integrity: sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==}
+
+ typedarray@0.0.6:
+ resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
+
typescript-eslint@8.56.1:
resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -15403,6 +16105,9 @@ packages:
resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==}
engines: {node: ^20.19.0 || >=22.12.0}
+ unquote@1.1.1:
+ resolution: {integrity: sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==}
+
unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
@@ -15504,6 +16209,9 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
+ update-diff@1.1.0:
+ resolution: {integrity: sha512-rCiBPiHxZwT4+sBhEbChzpO5hYHjm91kScWgdHf4Qeafs6Ba7MBl+d9GlGv72bcTZQO0sLmtQS1pHSWoCLtN/A==}
+
uqr@0.1.2:
resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==}
@@ -15555,6 +16263,7 @@ packages:
uuid@10.0.0:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
hasBin: true
uuid@11.1.0:
@@ -15876,6 +16585,9 @@ packages:
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
+ vt-pbf@3.1.3:
+ resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==}
+
vue-bundle-renderer@2.2.0:
resolution: {integrity: sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==}
@@ -15921,6 +16633,9 @@ packages:
wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ weak-map@1.0.8:
+ resolution: {integrity: sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==}
+
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
@@ -15931,6 +16646,9 @@ packages:
web-vitals@5.1.0:
resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==}
+ webgl-context@2.2.0:
+ resolution: {integrity: sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q==}
+
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@@ -16003,6 +16721,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
+ which@4.0.0:
+ resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
+ engines: {node: ^16.13.0 || >=18.0.0}
+ hasBin: true
+
which@6.0.1:
resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==}
engines: {node: ^20.17.0 || >=22.9.0}
@@ -16020,6 +16743,9 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
+ world-calendars@1.0.4:
+ resolution: {integrity: sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==}
+
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -16117,6 +16843,10 @@ packages:
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+ xtend@2.2.0:
+ resolution: {integrity: sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw==}
+ engines: {node: '>=0.4'}
+
xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
@@ -17246,6 +17976,10 @@ snapshots:
'@chevrotain/utils@11.1.2': {}
+ '@choojs/findup@0.2.1':
+ dependencies:
+ commander: 2.20.3
+
'@chromatic-com/storybook@3.2.6(react@19.2.4)(storybook@8.6.14(prettier@3.5.3))':
dependencies:
chromatic: 11.29.0
@@ -18846,6 +19580,19 @@ snapshots:
dependencies:
'@lukeed/csprng': 1.1.0
+ '@mapbox/geojson-rewind@0.5.2':
+ dependencies:
+ get-stream: 6.0.1
+ minimist: 1.2.8
+
+ '@mapbox/geojson-types@1.0.2': {}
+
+ '@mapbox/jsonlint-lines-primitives@2.0.2': {}
+
+ '@mapbox/mapbox-gl-supported@1.5.0(mapbox-gl@1.13.3)':
+ dependencies:
+ mapbox-gl: 1.13.3
+
'@mapbox/node-pre-gyp@2.0.3':
dependencies:
consola: 3.4.2
@@ -18859,6 +19606,32 @@ snapshots:
- encoding
- supports-color
+ '@mapbox/point-geometry@0.1.0': {}
+
+ '@mapbox/tiny-sdf@1.2.5': {}
+
+ '@mapbox/tiny-sdf@2.2.0': {}
+
+ '@mapbox/unitbezier@0.0.0': {}
+
+ '@mapbox/unitbezier@0.0.1': {}
+
+ '@mapbox/vector-tile@1.3.1':
+ dependencies:
+ '@mapbox/point-geometry': 0.1.0
+
+ '@mapbox/whoots-js@3.1.0': {}
+
+ '@maplibre/maplibre-gl-style-spec@20.4.0':
+ dependencies:
+ '@mapbox/jsonlint-lines-primitives': 2.0.2
+ '@mapbox/unitbezier': 0.0.1
+ json-stringify-pretty-compact: 4.0.0
+ minimist: 1.2.8
+ quickselect: 2.0.0
+ rw: 1.3.3
+ tinyqueue: 3.0.0
+
'@mastra/client-js@1.11.2(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@1.0.0)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@1.0.0)(zod-to-json-schema@3.25.2(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(openapi-types@12.1.3)(zod@4.3.6)':
dependencies:
'@ai-sdk/ui-utils': 1.2.11(zod@4.3.6)
@@ -20058,6 +20831,63 @@ snapshots:
'@pkgr/core@0.2.9': {}
+ '@plotly/d3-sankey-circular@0.33.1':
+ dependencies:
+ d3-array: 1.2.4
+ d3-collection: 1.0.7
+ d3-shape: 1.3.7
+ elementary-circuits-directed-graph: 1.3.1
+
+ '@plotly/d3-sankey@0.7.2':
+ dependencies:
+ d3-array: 1.2.4
+ d3-collection: 1.0.7
+ d3-shape: 1.3.7
+
+ '@plotly/d3@3.8.2': {}
+
+ '@plotly/mapbox-gl@1.13.4(mapbox-gl@1.13.3)':
+ dependencies:
+ '@mapbox/geojson-rewind': 0.5.2
+ '@mapbox/geojson-types': 1.0.2
+ '@mapbox/jsonlint-lines-primitives': 2.0.2
+ '@mapbox/mapbox-gl-supported': 1.5.0(mapbox-gl@1.13.3)
+ '@mapbox/point-geometry': 0.1.0
+ '@mapbox/tiny-sdf': 1.2.5
+ '@mapbox/unitbezier': 0.0.0
+ '@mapbox/vector-tile': 1.3.1
+ '@mapbox/whoots-js': 3.1.0
+ csscolorparser: 1.0.3
+ earcut: 2.2.4
+ geojson-vt: 3.2.1
+ gl-matrix: 3.4.4
+ grid-index: 1.1.0
+ murmurhash-js: 1.0.0
+ pbf: 3.3.0
+ potpack: 1.0.2
+ quickselect: 2.0.0
+ rw: 1.3.3
+ supercluster: 7.1.5
+ tinyqueue: 2.0.3
+ vt-pbf: 3.1.3
+ transitivePeerDependencies:
+ - mapbox-gl
+
+ '@plotly/point-cluster@3.1.9':
+ dependencies:
+ array-bounds: 1.0.1
+ binary-search-bounds: 2.0.5
+ clamp: 1.0.1
+ defined: 1.0.1
+ dtype: 2.0.0
+ flatten-vertex-data: 1.0.2
+ is-obj: 1.0.1
+ math-log2: 1.0.1
+ parse-rect: 1.2.0
+ pick-by-alias: 1.2.0
+
+ '@plotly/regl@2.1.2': {}
+
'@polka/url@1.0.0-next.29': {}
'@poppinss/colors@4.1.6':
@@ -24350,6 +25180,38 @@ snapshots:
dependencies:
'@testing-library/dom': 10.4.0
+ '@turf/area@7.3.5':
+ dependencies:
+ '@turf/helpers': 7.3.5
+ '@turf/meta': 7.3.5
+ '@types/geojson': 7946.0.16
+ tslib: 2.8.1
+
+ '@turf/bbox@7.3.5':
+ dependencies:
+ '@turf/helpers': 7.3.5
+ '@turf/meta': 7.3.5
+ '@types/geojson': 7946.0.16
+ tslib: 2.8.1
+
+ '@turf/centroid@7.3.5':
+ dependencies:
+ '@turf/helpers': 7.3.5
+ '@turf/meta': 7.3.5
+ '@types/geojson': 7946.0.16
+ tslib: 2.8.1
+
+ '@turf/helpers@7.3.5':
+ dependencies:
+ '@types/geojson': 7946.0.16
+ tslib: 2.8.1
+
+ '@turf/meta@7.3.5':
+ dependencies:
+ '@turf/helpers': 7.3.5
+ '@types/geojson': 7946.0.16
+ tslib: 2.8.1
+
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
@@ -24557,6 +25419,10 @@ snapshots:
'@types/qs': 6.15.0
'@types/serve-static': 1.15.10
+ '@types/geojson-vt@3.2.5':
+ dependencies:
+ '@types/geojson': 7946.0.16
+
'@types/geojson@7946.0.16': {}
'@types/graceful-fs@4.1.9':
@@ -24597,6 +25463,14 @@ snapshots:
'@types/lodash@4.17.18': {}
+ '@types/mapbox__point-geometry@0.1.4': {}
+
+ '@types/mapbox__vector-tile@1.3.4':
+ dependencies:
+ '@types/geojson': 7946.0.16
+ '@types/mapbox__point-geometry': 0.1.4
+ '@types/pbf': 3.0.5
+
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 3.0.3
@@ -24628,6 +25502,14 @@ snapshots:
dependencies:
undici-types: 7.18.2
+ '@types/pbf@3.0.5': {}
+
+ '@types/plotly.js-dist-min@2.3.4':
+ dependencies:
+ '@types/plotly.js': 3.0.10
+
+ '@types/plotly.js@3.0.10': {}
+
'@types/prismjs@1.26.6': {}
'@types/qs@6.15.0': {}
@@ -24638,6 +25520,11 @@ snapshots:
dependencies:
'@types/react': 19.2.14
+ '@types/react-plotly.js@2.6.4':
+ dependencies:
+ '@types/plotly.js': 3.0.10
+ '@types/react': 19.2.14
+
'@types/react-syntax-highlighter@15.5.13':
dependencies:
'@types/react': 19.2.14
@@ -24671,6 +25558,10 @@ snapshots:
'@types/stack-utils@2.0.3': {}
+ '@types/supercluster@7.1.3':
+ dependencies:
+ '@types/geojson': 7946.0.16
+
'@types/trusted-types@2.0.7': {}
'@types/unist@2.0.11': {}
@@ -25309,6 +26200,8 @@ snapshots:
dependencies:
event-target-shim: 5.0.1
+ abs-svg-path@0.1.1: {}
+
accepts@1.3.8:
dependencies:
mime-types: 2.1.35
@@ -25327,6 +26220,8 @@ snapshots:
dependencies:
acorn: 8.16.0
+ acorn@7.4.1: {}
+
acorn@8.16.0: {}
agent-base@7.1.4: {}
@@ -25479,11 +26374,15 @@ snapshots:
aria-query@5.3.2: {}
+ array-bounds@1.0.1: {}
+
array-buffer-byte-length@1.0.2:
dependencies:
call-bound: 1.0.4
is-array-buffer: 3.0.5
+ array-find-index@1.0.2: {}
+
array-flatten@1.1.1: {}
array-includes@3.1.9:
@@ -25497,6 +26396,12 @@ snapshots:
is-string: 1.1.1
math-intrinsics: 1.1.0
+ array-normalize@1.1.4:
+ dependencies:
+ array-bounds: 1.0.1
+
+ array-range@1.0.1: {}
+
array.prototype.findlast@1.2.5:
dependencies:
call-bind: 1.0.8
@@ -25776,6 +26681,8 @@ snapshots:
dependencies:
bare-path: 3.0.0
+ base64-arraybuffer@1.0.2: {}
+
base64-js@1.5.1: {}
baseline-browser-mapping@2.10.0: {}
@@ -25792,6 +26699,8 @@ snapshots:
binary-extensions@2.3.0: {}
+ binary-search-bounds@2.0.5: {}
+
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
@@ -25800,6 +26709,15 @@ snapshots:
birpc@4.0.0: {}
+ bit-twiddle@1.0.2: {}
+
+ bitmap-sdf@1.0.4: {}
+
+ bl@2.2.1:
+ dependencies:
+ readable-stream: 2.3.8
+ safe-buffer: 5.2.1
+
body-parser@1.20.4:
dependencies:
bytes: 3.1.2
@@ -26092,6 +27010,8 @@ snapshots:
cjs-module-lexer@1.4.3: {}
+ clamp@1.0.1: {}
+
class-transformer@0.5.1: {}
class-validator@0.14.4:
@@ -26161,6 +27081,10 @@ snapshots:
collapse-white-space@2.1.0: {}
+ color-alpha@1.1.3:
+ dependencies:
+ color-parse: 1.4.3
+
color-convert@1.9.3:
dependencies:
color-name: 1.1.3
@@ -26169,10 +27093,42 @@ snapshots:
dependencies:
color-name: 1.1.4
+ color-id@1.1.0:
+ dependencies:
+ clamp: 1.0.1
+
color-name@1.1.3: {}
color-name@1.1.4: {}
+ color-name@2.1.0: {}
+
+ color-normalize@1.5.0:
+ dependencies:
+ clamp: 1.0.1
+ color-rgba: 2.4.0
+ dtype: 2.0.0
+
+ color-parse@1.4.3:
+ dependencies:
+ color-name: 1.1.4
+
+ color-parse@2.0.2:
+ dependencies:
+ color-name: 2.1.0
+
+ color-rgba@2.4.0:
+ dependencies:
+ color-parse: 1.4.3
+ color-space: 2.3.2
+
+ color-rgba@3.0.0:
+ dependencies:
+ color-parse: 2.0.2
+ color-space: 2.3.2
+
+ color-space@2.3.2: {}
+
colord@2.9.3: {}
colorette@2.0.20: {}
@@ -26235,6 +27191,13 @@ snapshots:
concat-map@0.0.1: {}
+ concat-stream@1.6.2:
+ dependencies:
+ buffer-from: 1.1.2
+ inherits: 2.0.4
+ readable-stream: 2.3.8
+ typedarray: 0.0.6
+
concurrently@9.2.0:
dependencies:
chalk: 4.1.2
@@ -26314,6 +27277,8 @@ snapshots:
dependencies:
layout-base: 2.0.1
+ country-regex@1.1.0: {}
+
crc-32@1.2.2: {}
crc32-stream@6.0.0:
@@ -26347,6 +27312,28 @@ snapshots:
dependencies:
postcss: 8.5.8
+ css-font-size-keywords@1.0.0: {}
+
+ css-font-stretch-keywords@1.0.1: {}
+
+ css-font-style-keywords@1.0.1: {}
+
+ css-font-weight-keywords@1.0.0: {}
+
+ css-font@1.2.0:
+ dependencies:
+ css-font-size-keywords: 1.0.0
+ css-font-stretch-keywords: 1.0.1
+ css-font-style-keywords: 1.0.1
+ css-font-weight-keywords: 1.0.0
+ css-global-keywords: 1.0.1
+ css-system-font-keywords: 1.0.0
+ pick-by-alias: 1.2.0
+ string-split-by: 1.0.0
+ unquote: 1.1.1
+
+ css-global-keywords@1.0.1: {}
+
css-in-js-utils@3.1.0:
dependencies:
hyphenate-style-name: 1.1.0
@@ -26359,6 +27346,8 @@ snapshots:
domutils: 3.2.2
nth-check: 2.1.1
+ css-system-font-keywords@1.0.0: {}
+
css-tree@1.1.3:
dependencies:
mdn-data: 2.0.14
@@ -26378,6 +27367,8 @@ snapshots:
css.escape@1.5.1: {}
+ csscolorparser@1.0.3: {}
+
cssesc@3.0.0: {}
cssnano-preset-default@7.0.11(postcss@8.5.8):
@@ -26447,6 +27438,8 @@ snapshots:
cytoscape@3.33.1: {}
+ d3-array@1.2.4: {}
+
d3-array@2.12.1:
dependencies:
internmap: 1.0.1
@@ -26469,6 +27462,8 @@ snapshots:
dependencies:
d3-path: 3.1.0
+ d3-collection@1.0.7: {}
+
d3-color@3.1.0: {}
d3-contour@4.0.2:
@@ -26479,6 +27474,8 @@ snapshots:
dependencies:
delaunator: 5.1.0
+ d3-dispatch@1.0.6: {}
+
d3-dispatch@3.0.1: {}
d3-drag@3.0.0:
@@ -26498,18 +27495,40 @@ snapshots:
dependencies:
d3-dsv: 3.0.1
+ d3-force@1.2.1:
+ dependencies:
+ d3-collection: 1.0.7
+ d3-dispatch: 1.0.6
+ d3-quadtree: 1.0.7
+ d3-timer: 1.0.10
+
d3-force@3.0.0:
dependencies:
d3-dispatch: 3.0.1
d3-quadtree: 3.0.1
d3-timer: 3.0.1
+ d3-format@1.4.5: {}
+
d3-format@3.1.0: {}
+ d3-geo-projection@2.9.0:
+ dependencies:
+ commander: 2.20.3
+ d3-array: 1.2.4
+ d3-geo: 1.12.1
+ resolve: 1.22.11
+
+ d3-geo@1.12.1:
+ dependencies:
+ d3-array: 1.2.4
+
d3-geo@3.1.1:
dependencies:
d3-array: 3.2.4
+ d3-hierarchy@1.1.9: {}
+
d3-hierarchy@3.1.2: {}
d3-interpolate@3.0.1:
@@ -26522,6 +27541,8 @@ snapshots:
d3-polygon@3.0.1: {}
+ d3-quadtree@1.0.7: {}
+
d3-quadtree@3.0.1: {}
d3-random@3.0.1: {}
@@ -26554,14 +27575,22 @@ snapshots:
dependencies:
d3-path: 3.1.0
+ d3-time-format@2.3.0:
+ dependencies:
+ d3-time: 1.1.0
+
d3-time-format@4.1.0:
dependencies:
d3-time: 3.1.0
+ d3-time@1.1.0: {}
+
d3-time@3.1.0:
dependencies:
d3-array: 3.2.4
+ d3-timer@1.0.10: {}
+
d3-timer@3.0.1: {}
d3-transition@3.0.1(d3-selection@3.0.0):
@@ -26614,6 +27643,11 @@ snapshots:
d3-transition: 3.0.1(d3-selection@3.0.0)
d3-zoom: 3.0.0
+ d@1.0.2:
+ dependencies:
+ es5-ext: 0.10.64
+ type: 2.7.3
+
dagre-d3-es@7.0.14:
dependencies:
d3: 7.9.0
@@ -26715,6 +27749,8 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
+ defined@1.0.1: {}
+
defu@6.1.4: {}
delaunator@5.1.0:
@@ -26733,6 +27769,8 @@ snapshots:
destroy@1.2.0: {}
+ detect-kerning@2.1.2: {}
+
detect-libc@1.0.3: {}
detect-libc@2.1.2: {}
@@ -26802,18 +27840,38 @@ snapshots:
dotenv@17.3.1: {}
+ draw-svg-path@1.0.0:
+ dependencies:
+ abs-svg-path: 0.1.1
+ normalize-svg-path: 0.1.0
+
dset@3.1.4: {}
dts-resolver@2.1.3: {}
+ dtype@2.0.0: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
+ dup@1.0.0: {}
+
duplexer@0.1.2: {}
+ duplexify@3.7.1:
+ dependencies:
+ end-of-stream: 1.4.5
+ inherits: 2.0.4
+ readable-stream: 2.3.8
+ stream-shift: 1.0.3
+
+ earcut@2.2.4: {}
+
+ earcut@3.0.2: {}
+
eastasianwidth@0.2.0: {}
editorconfig@1.0.7:
@@ -26829,6 +27887,10 @@ snapshots:
electron-to-chromium@1.5.313: {}
+ elementary-circuits-directed-graph@1.3.1:
+ dependencies:
+ strongly-connected-components: 1.0.1
+
embla-carousel-react@8.6.0(react@19.2.3):
dependencies:
embla-carousel: 8.6.0
@@ -26989,6 +28051,31 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
+ es5-ext@0.10.64:
+ dependencies:
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.4
+ esniff: 2.0.1
+ next-tick: 1.1.0
+
+ es6-iterator@2.0.3:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-symbol: 3.1.4
+
+ es6-symbol@3.1.4:
+ dependencies:
+ d: 1.0.2
+ ext: 1.7.0
+
+ es6-weak-map@2.0.3:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.4
+
esast-util-from-estree@2.0.0:
dependencies:
'@types/estree-jsx': 1.0.5
@@ -27163,6 +28250,14 @@ snapshots:
escape-string-regexp@5.0.0: {}
+ escodegen@2.1.0:
+ dependencies:
+ esprima: 4.0.1
+ estraverse: 5.3.0
+ esutils: 2.0.3
+ optionalDependencies:
+ source-map: 0.6.1
+
eslint-config-next@16.1.6(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 16.1.6
@@ -27230,7 +28325,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -27252,7 +28347,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.29.0(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1))
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -27411,6 +28506,13 @@ snapshots:
esm-env@1.2.2: {}
+ esniff@2.0.1:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ event-emitter: 0.3.5
+ type: 2.7.3
+
espree@10.4.0:
dependencies:
acorn: 8.16.0
@@ -27479,6 +28581,11 @@ snapshots:
etag@1.8.1: {}
+ event-emitter@0.3.5:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+
event-target-shim@5.0.1: {}
eventemitter3@4.0.7: {}
@@ -27695,6 +28802,10 @@ snapshots:
exsolve@1.0.8: {}
+ ext@1.7.0:
+ dependencies:
+ type: 2.7.3
+
extend-shallow@2.0.1:
dependencies:
is-extendable: 0.1.1
@@ -27708,6 +28819,11 @@ snapshots:
pathe: 1.1.2
ufo: 1.6.3
+ falafel@2.2.5:
+ dependencies:
+ acorn: 7.4.1
+ isarray: 2.0.5
+
fast-content-type-parse@3.0.0: {}
fast-copy@3.0.2: {}
@@ -27738,6 +28854,10 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.8
+ fast-isnumeric@1.1.4:
+ dependencies:
+ is-string-blank: 1.0.1
+
fast-json-patch@3.1.1: {}
fast-json-stable-stringify@2.1.0: {}
@@ -27868,8 +28988,20 @@ snapshots:
flatted@3.3.3: {}
+ flatten-vertex-data@1.0.2:
+ dependencies:
+ dtype: 2.0.0
+
flow-enums-runtime@0.0.6: {}
+ font-atlas@2.1.0:
+ dependencies:
+ css-font: 1.2.0
+
+ font-measure@1.2.2:
+ dependencies:
+ css-font: 1.2.0
+
fontfaceobserver@2.3.0: {}
for-each@0.3.5:
@@ -27917,6 +29049,11 @@ snapshots:
fresh@2.0.0: {}
+ from2@2.3.0:
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 2.3.8
+
fs.realpath@1.0.0: {}
fsevents@2.3.3:
@@ -28045,8 +29182,14 @@ snapshots:
gensync@1.0.0-beta.2: {}
+ geojson-vt@3.2.1: {}
+
+ geojson-vt@4.0.2: {}
+
get-caller-file@2.0.5: {}
+ get-canvas-context@1.0.2: {}
+
get-east-asian-width@1.5.0: {}
get-intrinsic@1.3.0:
@@ -28073,6 +29216,8 @@ snapshots:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
+ get-stream@6.0.1: {}
+
get-stream@8.0.1: {}
get-stream@9.0.1:
@@ -28109,6 +29254,40 @@ snapshots:
github-slugger@2.0.0: {}
+ gl-mat4@1.2.0: {}
+
+ gl-matrix@3.4.4: {}
+
+ gl-text@1.4.0:
+ dependencies:
+ bit-twiddle: 1.0.2
+ color-normalize: 1.5.0
+ css-font: 1.2.0
+ detect-kerning: 2.1.2
+ es6-weak-map: 2.0.3
+ flatten-vertex-data: 1.0.2
+ font-atlas: 2.1.0
+ font-measure: 1.2.2
+ gl-util: 3.1.3
+ is-plain-obj: 1.1.0
+ object-assign: 4.1.1
+ parse-rect: 1.2.0
+ parse-unit: 1.0.1
+ pick-by-alias: 1.2.0
+ regl: 2.1.1
+ to-px: 1.1.0
+ typedarray-pool: 1.2.0
+
+ gl-util@3.1.3:
+ dependencies:
+ is-browser: 2.1.0
+ is-firefox: 1.0.3
+ is-plain-obj: 1.1.0
+ number-is-integer: 1.0.1
+ object-assign: 4.1.1
+ pick-by-alias: 1.2.0
+ weak-map: 1.0.8
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -28147,6 +29326,12 @@ snapshots:
dependencies:
ini: 4.1.1
+ global-prefix@4.0.0:
+ dependencies:
+ ini: 4.1.3
+ kind-of: 6.0.3
+ which: 4.0.0
+
globals@11.12.0: {}
globals@14.0.0: {}
@@ -28167,6 +29352,88 @@ snapshots:
slash: 5.1.0
unicorn-magic: 0.4.0
+ glsl-inject-defines@1.0.3:
+ dependencies:
+ glsl-token-inject-block: 1.1.0
+ glsl-token-string: 1.0.1
+ glsl-tokenizer: 2.1.5
+
+ glsl-resolve@0.0.1:
+ dependencies:
+ resolve: 0.6.3
+ xtend: 2.2.0
+
+ glsl-token-assignments@2.0.2: {}
+
+ glsl-token-defines@1.0.0:
+ dependencies:
+ glsl-tokenizer: 2.1.5
+
+ glsl-token-depth@1.1.2: {}
+
+ glsl-token-descope@1.0.2:
+ dependencies:
+ glsl-token-assignments: 2.0.2
+ glsl-token-depth: 1.1.2
+ glsl-token-properties: 1.0.1
+ glsl-token-scope: 1.1.2
+
+ glsl-token-inject-block@1.1.0: {}
+
+ glsl-token-properties@1.0.1: {}
+
+ glsl-token-scope@1.1.2: {}
+
+ glsl-token-string@1.0.1: {}
+
+ glsl-token-whitespace-trim@1.0.0: {}
+
+ glsl-tokenizer@2.1.5:
+ dependencies:
+ through2: 0.6.5
+
+ glslify-bundle@5.1.1:
+ dependencies:
+ glsl-inject-defines: 1.0.3
+ glsl-token-defines: 1.0.0
+ glsl-token-depth: 1.1.2
+ glsl-token-descope: 1.0.2
+ glsl-token-scope: 1.1.2
+ glsl-token-string: 1.0.1
+ glsl-token-whitespace-trim: 1.0.0
+ glsl-tokenizer: 2.1.5
+ murmurhash-js: 1.0.0
+ shallow-copy: 0.0.1
+
+ glslify-deps@1.3.2:
+ dependencies:
+ '@choojs/findup': 0.2.1
+ events: 3.3.0
+ glsl-resolve: 0.0.1
+ glsl-tokenizer: 2.1.5
+ graceful-fs: 4.2.11
+ inherits: 2.0.4
+ map-limit: 0.0.1
+ resolve: 1.22.11
+
+ glslify@7.1.1:
+ dependencies:
+ bl: 2.2.1
+ concat-stream: 1.6.2
+ duplexify: 3.7.1
+ falafel: 2.2.5
+ from2: 2.3.0
+ glsl-resolve: 0.0.1
+ glsl-token-whitespace-trim: 1.0.0
+ glslify-bundle: 5.1.1
+ glslify-deps: 1.3.2
+ minimist: 1.2.8
+ resolve: 1.22.11
+ stack-trace: 0.0.9
+ static-eval: 2.1.1
+ through2: 2.0.5
+ xtend: 4.0.2
+
gopd@1.2.0: {}
gpt-tokenizer@3.4.0: {}
@@ -28208,6 +29475,8 @@ snapshots:
section-matter: 1.0.0
strip-bom-string: 1.0.0
+ grid-index@1.1.0: {}
+
gzip-size@7.0.0:
dependencies:
duplexer: 0.1.2
@@ -28241,6 +29510,14 @@ snapshots:
has-flag@4.0.0: {}
+ has-hover@1.0.1:
+ dependencies:
+ is-browser: 2.1.0
+
+ has-passive-events@1.0.0:
+ dependencies:
+ is-browser: 2.1.0
+
has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.1
@@ -28599,6 +29876,8 @@ snapshots:
ini@4.1.1: {}
+ ini@4.1.3: {}
+
inline-style-parser@0.2.4: {}
inline-style-prefixer@7.0.1:
@@ -28697,6 +29976,8 @@ snapshots:
call-bound: 1.0.4
has-tostringtag: 1.0.2
+ is-browser@2.1.0: {}
+
is-bun-module@2.0.0:
dependencies:
semver: 7.7.4
@@ -28734,6 +30015,10 @@ snapshots:
dependencies:
call-bound: 1.0.4
+ is-finite@1.1.0: {}
+
+ is-firefox@1.0.3: {}
+
is-fullwidth-code-point@3.0.0: {}
is-generator-function@1.1.0:
@@ -28764,6 +30049,8 @@ snapshots:
is-map@2.0.3: {}
+ is-mobile@4.0.0: {}
+
is-module@1.0.0: {}
is-negative-zero@2.0.3: {}
@@ -28777,8 +30064,12 @@ snapshots:
is-number@7.0.0: {}
+ is-obj@1.0.1: {}
+
is-path-inside@4.0.0: {}
+ is-plain-obj@1.1.0: {}
+
is-plain-obj@4.1.0: {}
is-potential-custom-element-name@1.0.1: {}
@@ -28812,11 +30103,15 @@ snapshots:
is-stream@4.0.1: {}
+ is-string-blank@1.0.1: {}
+
is-string@1.1.1:
dependencies:
call-bound: 1.0.4
has-tostringtag: 1.0.2
+ is-svg-path@1.0.2: {}
+
is-symbol@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -28852,12 +30147,16 @@ snapshots:
dependencies:
system-architecture: 0.1.0
+ isarray@0.0.1: {}
+
isarray@1.0.0: {}
isarray@2.0.5: {}
isexe@2.0.0: {}
+ isexe@3.1.5: {}
+
isexe@4.0.0: {}
istanbul-lib-coverage@3.2.2: {}
@@ -29053,6 +30352,8 @@ snapshots:
json-stable-stringify-without-jsonify@1.0.1: {}
+ json-stringify-pretty-compact@4.0.0: {}
+
json-with-bigint@3.5.8: {}
json5@1.0.2:
@@ -29082,6 +30383,10 @@ snapshots:
dependencies:
commander: 8.3.0
+ kdbush@3.0.0: {}
+
+ kdbush@4.0.2: {}
+
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
@@ -29408,8 +30713,66 @@ snapshots:
dependencies:
tmpl: 1.0.5
+ map-limit@0.0.1:
+ dependencies:
+ once: 1.3.3
+
map-or-similar@1.5.0: {}
+ mapbox-gl@1.13.3:
+ dependencies:
+ '@mapbox/geojson-rewind': 0.5.2
+ '@mapbox/geojson-types': 1.0.2
+ '@mapbox/jsonlint-lines-primitives': 2.0.2
+ '@mapbox/mapbox-gl-supported': 1.5.0(mapbox-gl@1.13.3)
+ '@mapbox/point-geometry': 0.1.0
+ '@mapbox/tiny-sdf': 1.2.5
+ '@mapbox/unitbezier': 0.0.0
+ '@mapbox/vector-tile': 1.3.1
+ '@mapbox/whoots-js': 3.1.0
+ csscolorparser: 1.0.3
+ earcut: 2.2.4
+ geojson-vt: 3.2.1
+ gl-matrix: 3.4.4
+ grid-index: 1.1.0
+ murmurhash-js: 1.0.0
+ pbf: 3.3.0
+ potpack: 1.0.2
+ quickselect: 2.0.0
+ rw: 1.3.3
+ supercluster: 7.1.5
+ tinyqueue: 2.0.3
+ vt-pbf: 3.1.3
+
+ maplibre-gl@4.7.1:
+ dependencies:
+ '@mapbox/geojson-rewind': 0.5.2
+ '@mapbox/jsonlint-lines-primitives': 2.0.2
+ '@mapbox/point-geometry': 0.1.0
+ '@mapbox/tiny-sdf': 2.2.0
+ '@mapbox/unitbezier': 0.0.1
+ '@mapbox/vector-tile': 1.3.1
+ '@mapbox/whoots-js': 3.1.0
+ '@maplibre/maplibre-gl-style-spec': 20.4.0
+ '@types/geojson': 7946.0.16
+ '@types/geojson-vt': 3.2.5
+ '@types/mapbox__point-geometry': 0.1.4
+ '@types/mapbox__vector-tile': 1.3.4
+ '@types/pbf': 3.0.5
+ '@types/supercluster': 7.1.3
+ earcut: 3.0.2
+ geojson-vt: 4.0.2
+ gl-matrix: 3.4.4
+ global-prefix: 4.0.0
+ kdbush: 4.0.2
+ murmurhash-js: 1.0.0
+ pbf: 3.3.0
+ potpack: 2.1.0
+ quickselect: 3.0.0
+ supercluster: 8.0.1
+ tinyqueue: 3.0.0
+ vt-pbf: 3.1.3
+
markdown-extensions@2.0.0: {}
markdown-table@3.0.4: {}
@@ -29437,6 +30800,8 @@ snapshots:
math-intrinsics@1.1.0: {}
+ math-log2@1.0.1: {}
+
md-to-react-email@5.0.5(react@19.2.3):
dependencies:
marked: 7.0.4
@@ -30382,6 +31747,8 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
+ mouse-event-offset@3.0.2: {}
+
mri@1.2.0: {}
mrmime@2.0.1: {}
@@ -30392,6 +31759,8 @@ snapshots:
muggle-string@0.4.1: {}
+ murmurhash-js@1.0.0: {}
+
mustache@4.2.0: {}
mute-stream@3.0.0: {}
@@ -30408,8 +31777,18 @@ snapshots:
napi-postinstall@0.3.4: {}
+ native-promise-only@0.8.1: {}
+
natural-compare@1.4.0: {}
+ needle@2.9.1:
+ dependencies:
+ debug: 3.2.7
+ iconv-lite: 0.4.24
+ sax: 1.5.0
+ transitivePeerDependencies:
+ - supports-color
+
negotiator@0.6.3: {}
negotiator@0.6.4: {}
@@ -30425,6 +31804,8 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
+ next-tick@1.1.0: {}
+
next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.89.2):
dependencies:
'@next/env': 15.5.12
@@ -30681,6 +32062,12 @@ snapshots:
normalize-path@3.0.0: {}
+ normalize-svg-path@0.1.0: {}
+
+ normalize-svg-path@1.1.0:
+ dependencies:
+ svg-arc-to-cubic-bezier: 3.2.0
+
npm-package-arg@11.0.3:
dependencies:
hosted-git-info: 7.0.2
@@ -30705,6 +32092,10 @@ snapshots:
nullthrows@1.1.1: {}
+ number-is-integer@1.0.1:
+ dependencies:
+ is-finite: 1.1.0
+
numbro@2.5.0:
dependencies:
bignumber.js: 9.3.1
@@ -30936,6 +32327,10 @@ snapshots:
on-headers@1.1.0: {}
+ once@1.3.3:
+ dependencies:
+ wrappy: 1.0.2
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -31167,6 +32562,8 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parenthesis@3.1.8: {}
+
parse-entities@2.0.0:
dependencies:
character-entities: 1.2.4
@@ -31192,6 +32589,14 @@ snapshots:
dependencies:
pngjs: 3.4.0
+ parse-rect@1.2.0:
+ dependencies:
+ pick-by-alias: 1.2.0
+
+ parse-svg-path@0.1.2: {}
+
+ parse-unit@1.0.1: {}
+
parse5-htmlparser2-tree-adapter@6.0.1:
dependencies:
parse5: 6.0.1
@@ -31247,10 +32652,19 @@ snapshots:
pathval@2.0.0: {}
+ pbf@3.3.0:
+ dependencies:
+ ieee754: 1.2.1
+ resolve-protobuf-schema: 2.1.0
+
peberminta@0.9.0: {}
perfect-debounce@2.1.0: {}
+ performance-now@2.1.0: {}
+
+ pick-by-alias@1.2.0: {}
+
picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -31322,8 +32736,61 @@ snapshots:
base64-js: 1.5.1
xmlbuilder: 15.1.1
+ plotly.js-dist-min@3.5.1: {}
+
+ plotly.js@3.5.1(mapbox-gl@1.13.3):
+ dependencies:
+ '@plotly/d3': 3.8.2
+ '@plotly/d3-sankey': 0.7.2
+ '@plotly/d3-sankey-circular': 0.33.1
+ '@plotly/mapbox-gl': 1.13.4(mapbox-gl@1.13.3)
+ '@plotly/regl': 2.1.2
+ '@turf/area': 7.3.5
+ '@turf/bbox': 7.3.5
+ '@turf/centroid': 7.3.5
+ base64-arraybuffer: 1.0.2
+ color-normalize: 1.5.0
+ color-rgba: 3.0.0
+ country-regex: 1.1.0
+ d3-force: 1.2.1
+ d3-format: 1.4.5
+ d3-geo: 1.12.1
+ d3-geo-projection: 2.9.0
+ d3-hierarchy: 1.1.9
+ d3-interpolate: 3.0.1
+ d3-time: 1.1.0
+ d3-time-format: 2.3.0
+ fast-isnumeric: 1.1.4
+ gl-mat4: 1.2.0
+ gl-text: 1.4.0
+ has-hover: 1.0.1
+ has-passive-events: 1.0.0
+ is-mobile: 4.0.0
+ maplibre-gl: 4.7.1
+ mouse-event-offset: 3.0.2
+ native-promise-only: 0.8.1
+ parse-svg-path: 0.1.2
+ point-in-polygon: 1.1.0
+ polybooljs: 1.2.2
+ probe-image-size: 7.3.0
+ regl-error2d: 2.0.12
+ regl-line2d: 3.1.3
+ regl-scatter2d: 3.4.0
+ regl-splom: 1.0.14
+ strongly-connected-components: 1.0.1
+ svg-path-sdf: 1.1.3
+ tinycolor2: 1.6.0
+ topojson-client: 3.1.0
+ webgl-context: 2.2.0
+ world-calendars: 1.0.4
+ transitivePeerDependencies:
+ - mapbox-gl
+ - supports-color
+
pngjs@3.4.0: {}
+ point-in-polygon@1.1.0: {}
+
points-on-curve@0.2.0: {}
points-on-path@0.2.1:
@@ -31335,6 +32802,8 @@ snapshots:
dependencies:
'@babel/runtime': 7.27.6
+ polybooljs@1.2.2: {}
+
possible-typed-array-names@1.1.0: {}
postcss-calc@10.1.1(postcss@8.5.8):
@@ -31566,6 +33035,10 @@ snapshots:
query-selector-shadow-dom: 1.0.1
web-vitals: 5.1.0
+ potpack@1.0.2: {}
+
+ potpack@2.1.0: {}
+
powershell-utils@0.1.0: {}
preact@10.28.4: {}
@@ -31613,6 +33086,14 @@ snapshots:
prismjs@1.30.0: {}
+ probe-image-size@7.3.0:
+ dependencies:
+ lodash.merge: 4.6.2
+ needle: 2.9.1
+ stream-parser: 0.3.1
+ transitivePeerDependencies:
+ - supports-color
+
proc-log@4.2.0: {}
process-nextick-args@2.0.1: {}
@@ -31665,6 +33146,8 @@ snapshots:
'@types/node': 22.15.32
long: 5.3.2
+ protocol-buffers-schema@3.6.1: {}
+
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
@@ -31708,6 +33191,10 @@ snapshots:
quick-format-unescaped@4.0.4: {}
+ quickselect@2.0.0: {}
+
+ quickselect@3.0.0: {}
+
radash@12.1.1: {}
radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
@@ -31775,6 +33262,10 @@ snapshots:
radix3@1.1.2: {}
+ raf@3.4.1:
+ dependencies:
+ performance-now: 2.1.0
+
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -32091,6 +33582,12 @@ snapshots:
- supports-color
- utf-8-validate
+ react-plotly.js@2.6.0(plotly.js@3.5.1(mapbox-gl@1.13.3))(react@19.2.4):
+ dependencies:
+ plotly.js: 3.5.1(mapbox-gl@1.13.3)
+ prop-types: 15.8.1
+ react: 19.2.4
+
react-promise-suspense@0.3.4:
dependencies:
fast-deep-equal: 2.0.1
@@ -32267,6 +33764,13 @@ snapshots:
dependencies:
pify: 2.3.0
+ readable-stream@1.0.34:
+ dependencies:
+ core-util-is: 1.0.3
+ inherits: 2.0.4
+ isarray: 0.0.1
+ string_decoder: 0.10.31
+
readable-stream@2.3.8:
dependencies:
core-util-is: 1.0.3
@@ -32442,6 +33946,56 @@ snapshots:
dependencies:
jsesc: 3.1.0
+ regl-error2d@2.0.12:
+ dependencies:
+ array-bounds: 1.0.1
+ color-normalize: 1.5.0
+ flatten-vertex-data: 1.0.2
+ object-assign: 4.1.1
+ pick-by-alias: 1.2.0
+ to-float32: 1.1.0
+ update-diff: 1.1.0
+
+ regl-line2d@3.1.3:
+ dependencies:
+ array-bounds: 1.0.1
+ array-find-index: 1.0.2
+ array-normalize: 1.1.4
+ color-normalize: 1.5.0
+ earcut: 2.2.4
+ es6-weak-map: 2.0.3
+ flatten-vertex-data: 1.0.2
+ object-assign: 4.1.1
+ parse-rect: 1.2.0
+ pick-by-alias: 1.2.0
+ to-float32: 1.1.0
+
+ regl-scatter2d@3.4.0:
+ dependencies:
+ '@plotly/point-cluster': 3.1.9
+ array-bounds: 1.0.1
+ color-id: 1.1.0
+ color-normalize: 1.5.0
+ flatten-vertex-data: 1.0.2
+ glslify: 7.1.1
+ parse-rect: 1.2.0
+ pick-by-alias: 1.2.0
+ to-float32: 1.1.0
+ update-diff: 1.1.0
+
+ regl-splom@1.0.14:
+ dependencies:
+ array-bounds: 1.0.1
+ array-range: 1.0.1
+ color-alpha: 1.1.3
+ flatten-vertex-data: 1.0.2
+ parse-rect: 1.2.0
+ pick-by-alias: 1.2.0
+ raf: 3.4.1
+ regl-scatter2d: 3.4.0
+
+ regl@2.1.1: {}
+
rehype-harden@1.1.8:
dependencies:
unist-util-visit: 5.1.0
@@ -32566,10 +34120,16 @@ snapshots:
resolve-pkg-maps@1.0.0: {}
+ resolve-protobuf-schema@2.1.0:
+ dependencies:
+ protocol-buffers-schema: 3.6.1
+
resolve-workspace-root@2.0.1: {}
resolve.exports@2.0.3: {}
+ resolve@0.6.3: {}
+
resolve@1.22.10:
dependencies:
is-core-module: 2.16.1
@@ -32925,6 +34485,8 @@ snapshots:
setprototypeof@1.2.0: {}
+ shallow-copy@0.0.1: {}
+
sharp@0.34.5:
dependencies:
'@img/colour': 1.0.0
@@ -33080,6 +34642,8 @@ snapshots:
stable-hash@0.0.5: {}
+ stack-trace@0.0.9: {}
+
stack-utils@2.0.6:
dependencies:
escape-string-regexp: 2.0.0
@@ -33094,6 +34658,10 @@ snapshots:
standard-as-callback@2.1.0: {}
+ static-eval@2.1.1:
+ dependencies:
+ escodegen: 2.1.0
+
statuses@1.5.0: {}
statuses@2.0.2: {}
@@ -33119,6 +34687,14 @@ snapshots:
stream-buffers@2.2.0: {}
+ stream-parser@0.3.1:
+ dependencies:
+ debug: 2.6.9
+ transitivePeerDependencies:
+ - supports-color
+
+ stream-shift@1.0.3: {}
+
streamdown@2.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
clsx: 2.1.1
@@ -33151,6 +34727,10 @@ snapshots:
- bare-abort-controller
- react-native-b4a
+ string-split-by@1.0.0:
+ dependencies:
+ parenthesis: 3.1.8
+
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -33219,6 +34799,8 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
+ string_decoder@0.10.31: {}
+
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
@@ -33268,6 +34850,8 @@ snapshots:
dependencies:
js-tokens: 9.0.1
+ strongly-connected-components@1.0.1: {}
+
structured-clone-es@2.0.0: {}
structured-headers@0.4.1: {}
@@ -33324,6 +34908,14 @@ snapshots:
tinyglobby: 0.2.15
ts-interface-checker: 0.1.13
+ supercluster@7.1.5:
+ dependencies:
+ kdbush: 3.0.0
+
+ supercluster@8.0.1:
+ dependencies:
+ kdbush: 4.0.2
+
supports-color@10.2.2: {}
supports-color@5.5.0:
@@ -33388,6 +34980,23 @@ snapshots:
magic-string: 0.30.21
zimmerframe: 1.1.4
+ svg-arc-to-cubic-bezier@3.2.0: {}
+
+ svg-path-bounds@1.0.2:
+ dependencies:
+ abs-svg-path: 0.1.1
+ is-svg-path: 1.0.2
+ normalize-svg-path: 1.1.0
+ parse-svg-path: 0.1.2
+
+ svg-path-sdf@1.1.3:
+ dependencies:
+ bitmap-sdf: 1.0.4
+ draw-svg-path: 1.0.0
+ is-svg-path: 1.0.2
+ parse-svg-path: 0.1.2
+ svg-path-bounds: 1.0.2
+
svgo@4.0.1:
dependencies:
commander: 11.1.0
@@ -33538,6 +35147,16 @@ snapshots:
throttleit@2.1.0: {}
+ through2@0.6.5:
+ dependencies:
+ readable-stream: 1.0.34
+ xtend: 4.0.2
+
+ through2@2.0.5:
+ dependencies:
+ readable-stream: 2.3.8
+ xtend: 4.0.2
+
tiny-emitter@2.1.0: {}
tiny-invariant@1.3.3: {}
@@ -33546,6 +35165,8 @@ snapshots:
tinyclip@0.1.12: {}
+ tinycolor2@1.6.0: {}
+
tinyexec@0.3.2: {}
tinyexec@1.0.2: {}
@@ -33559,6 +35180,10 @@ snapshots:
tinypool@1.1.1: {}
+ tinyqueue@2.0.3: {}
+
+ tinyqueue@3.0.0: {}
+
tinyrainbow@1.2.0: {}
tinyrainbow@2.0.0: {}
@@ -33577,6 +35202,12 @@ snapshots:
tmpl@1.0.5: {}
+ to-float32@1.1.0: {}
+
+ to-px@1.1.0:
+ dependencies:
+ parse-unit: 1.0.1
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -33587,6 +35218,10 @@ snapshots:
tokenx@1.3.0: {}
+ topojson-client@3.1.0:
+ dependencies:
+ commander: 2.20.3
+
totalist@3.0.1: {}
tough-cookie@5.1.2:
@@ -33710,6 +35345,8 @@ snapshots:
type-level-regexp@0.1.17: {}
+ type@2.7.3: {}
+
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
@@ -33743,6 +35380,13 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
+ typedarray-pool@1.2.0:
+ dependencies:
+ bit-twiddle: 1.0.2
+ dup: 1.0.0
+
+ typedarray@0.0.6: {}
+
typescript-eslint@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3)
@@ -33944,6 +35588,8 @@ snapshots:
picomatch: 4.0.3
webpack-virtual-modules: 0.6.2
+ unquote@1.1.1: {}
+
unrs-resolver@1.11.1:
dependencies:
napi-postinstall: 0.3.4
@@ -34028,6 +35674,8 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
+ update-diff@1.1.0: {}
+
uqr@0.1.2: {}
uri-js@4.4.1:
@@ -34399,6 +36047,12 @@ snapshots:
vscode-uri@3.1.0: {}
+ vt-pbf@3.1.3:
+ dependencies:
+ '@mapbox/point-geometry': 0.1.0
+ '@mapbox/vector-tile': 1.3.1
+ pbf: 3.3.0
+
vue-bundle-renderer@2.2.0:
dependencies:
ufo: 1.6.3
@@ -34447,12 +36101,18 @@ snapshots:
dependencies:
defaults: 1.0.4
+ weak-map@1.0.8: {}
+
web-namespaces@2.0.1: {}
web-streams-polyfill@4.0.0-beta.3: {}
web-vitals@5.1.0: {}
+ webgl-context@2.2.0:
+ dependencies:
+ get-canvas-context: 1.0.2
+
webidl-conversions@3.0.1: {}
webidl-conversions@5.0.0: {}
@@ -34563,6 +36223,10 @@ snapshots:
dependencies:
isexe: 2.0.0
+ which@4.0.0:
+ dependencies:
+ isexe: 3.1.5
+
which@6.0.1:
dependencies:
isexe: 4.0.0
@@ -34576,6 +36240,10 @@ snapshots:
word-wrap@1.2.5: {}
+ world-calendars@1.0.4:
+ dependencies:
+ object-assign: 4.1.1
+
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -34638,6 +36306,8 @@ snapshots:
xmlchars@2.2.0: {}
+ xtend@2.2.0: {}
+
xtend@4.0.2: {}
xxhash-wasm@1.1.0: {}