From 1a8b888822bb94be75b6416979d671a04218fe02 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Thu, 30 Jul 2026 23:09:24 -0600 Subject: [PATCH 1/5] Add React Native host proof --- .../workflows/chart-library-benchmarks.yml | 3 + API-FRICTION.md | 145 +- NATIVE-PLATFORM-SUPPORT-SPIKE.md | 874 ++++ REACT-NATIVE-HOST-POC.md | 388 ++ .../entries/charts-react-native-line.ts | 11 + .../entries/charts-react-native-tooltip.ts | 2 + benchmarks/entries/charts-react-native.ts | 1 + examples/charts-react-native/App.tsx | 67 + examples/charts-react-native/app.json | 4 + examples/charts-react-native/babel.config.cjs | 3 + examples/charts-react-native/index.blank.js | 9 + examples/charts-react-native/index.core.js | 23 + examples/charts-react-native/index.js | 5 + examples/charts-react-native/index.svg.js | 23 + examples/charts-react-native/metro.config.cjs | 14 + examples/charts-react-native/package.json | 30 + examples/charts-react-native/tsconfig.json | 9 + .../charts-react-native/tsconfig.strict.json | 6 + package.json | 3 + packages/charts-core/src/reconcile.test.ts | 2 +- packages/react-native-charts/LICENSE | 21 + packages/react-native-charts/README.md | 6 + packages/react-native-charts/package.json | 20 + .../react-native-charts/src/Chart.test.tsx | 166 + packages/react-native-charts/src/Chart.tsx | 435 ++ .../react-native-charts/src/FocusOverlay.tsx | 64 + .../react-native-charts/src/SvgScene.test.tsx | 165 + packages/react-native-charts/src/SvgScene.tsx | 287 ++ .../react-native-charts/src/Tooltip.test.ts | 82 + packages/react-native-charts/src/Tooltip.tsx | 507 ++ packages/react-native-charts/src/index.ts | 5 + .../src/interaction.test.ts | 125 + .../react-native-charts/src/interaction.ts | 205 + .../react-native-charts/src/paint.test.ts | 43 + packages/react-native-charts/src/paint.ts | 48 + .../react-native-charts/src/tooltip-entry.ts | 7 + packages/react-native-charts/tsconfig.json | 9 + pnpm-lock.yaml | 4400 ++++++++++++++++- scripts/check-react-native-types.mjs | 60 + scripts/measure-bundles.mjs | 94 +- scripts/measure-react-native-poc.mjs | 163 + 41 files changed, 8274 insertions(+), 260 deletions(-) create mode 100644 NATIVE-PLATFORM-SUPPORT-SPIKE.md create mode 100644 REACT-NATIVE-HOST-POC.md create mode 100644 benchmarks/entries/charts-react-native-line.ts create mode 100644 benchmarks/entries/charts-react-native-tooltip.ts create mode 100644 benchmarks/entries/charts-react-native.ts create mode 100644 examples/charts-react-native/App.tsx create mode 100644 examples/charts-react-native/app.json create mode 100644 examples/charts-react-native/babel.config.cjs create mode 100644 examples/charts-react-native/index.blank.js create mode 100644 examples/charts-react-native/index.core.js create mode 100644 examples/charts-react-native/index.js create mode 100644 examples/charts-react-native/index.svg.js create mode 100644 examples/charts-react-native/metro.config.cjs create mode 100644 examples/charts-react-native/package.json create mode 100644 examples/charts-react-native/tsconfig.json create mode 100644 examples/charts-react-native/tsconfig.strict.json create mode 100644 packages/react-native-charts/LICENSE create mode 100644 packages/react-native-charts/README.md create mode 100644 packages/react-native-charts/package.json create mode 100644 packages/react-native-charts/src/Chart.test.tsx create mode 100644 packages/react-native-charts/src/Chart.tsx create mode 100644 packages/react-native-charts/src/FocusOverlay.tsx create mode 100644 packages/react-native-charts/src/SvgScene.test.tsx create mode 100644 packages/react-native-charts/src/SvgScene.tsx create mode 100644 packages/react-native-charts/src/Tooltip.test.ts create mode 100644 packages/react-native-charts/src/Tooltip.tsx create mode 100644 packages/react-native-charts/src/index.ts create mode 100644 packages/react-native-charts/src/interaction.test.ts create mode 100644 packages/react-native-charts/src/interaction.ts create mode 100644 packages/react-native-charts/src/paint.test.ts create mode 100644 packages/react-native-charts/src/paint.ts create mode 100644 packages/react-native-charts/src/tooltip-entry.ts create mode 100644 packages/react-native-charts/tsconfig.json create mode 100644 scripts/check-react-native-types.mjs create mode 100644 scripts/measure-react-native-poc.mjs diff --git a/.github/workflows/chart-library-benchmarks.yml b/.github/workflows/chart-library-benchmarks.yml index a6ca01db..8ba83a4e 100644 --- a/.github/workflows/chart-library-benchmarks.yml +++ b/.github/workflows/chart-library-benchmarks.yml @@ -41,6 +41,9 @@ jobs: - name: Run cached validation graph run: pnpm run validate + - name: Check React Native POC types + run: pnpm react-native:poc:types + - name: Upload production catalog if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 diff --git a/API-FRICTION.md b/API-FRICTION.md index f942b5a4..f4a3f71f 100644 --- a/API-FRICTION.md +++ b/API-FRICTION.md @@ -202,6 +202,12 @@ Each entry records: | F-164 | Sankey widths required a custom scene renderer | API | resolved | | F-165 | Incidental D3 utilities leaked into core paths | API/Tooling | resolved | | F-166 | Grouped tooltip order diverged from mark position | API | resolved | +| F-166 | D3 declarations require a browser image global | Tooling | monitoring | +| F-167 | Native interaction copied DOM-renderer policy | API | monitoring | +| F-168 | CSS theme defaults reach the native scene compiler | API | monitoring | +| F-169 | Text measurement omits native typography | API | monitoring | +| F-170 | Packed declarations assume one platform global set | Tooling | monitoring | +| F-171 | Metro skipped the fixture-owned Babel runtime | Tooling | resolved | ## Findings @@ -3735,7 +3741,7 @@ Each entry records: - Severity: high - Owner: API - Observed in: reducing the representative React line consumer from 25.11 KiB - to 13.89 KiB gzip + to 13.89 KiB gzip and restacking the React Native host proof - Friction: the renderer statically owned native tooltip DOM, formatting, placement, pinning, portal transport, and observers. React's base entries also statically owned `react-dom` portal composition and the default rich @@ -3747,13 +3753,20 @@ Each entry records: portal extension. Move React rich-body composition to drop-in Chart, CanvasChart, and RendererChart exports from `@tanstack/react-charts/tooltip`. Base entries export only erased extension - types and never import those runtime modules. + types and never import those runtime modules. Apply the same boundary to the + native host: its branded renderer token and implementation live at + `@tanstack/react-native-charts/tooltip`, while the base package imports only + the erased native extension contract. A string host brand accepts duplicate + package copies and custom native renderers without accepting the DOM token. - Verification: the representative compact React line is 14,227 gzip bytes. Native tooltip adds 3,381 bytes; portal adds 806 more. Retained-output graph checks prove base renderer and React entries contain none of the tooltip, - portal, or React rich-body modules. Core, Lit, React, export, declaration, - packed-package, and lifecycle tests cover creation, update, disable, - transport switching, custom bodies, and cleanup. + portal, or React rich-body modules. The React Native base host is 9,141 gzip + bytes and adding its tooltip subpath costs 1,685 bytes; retained-input checks + prove both the base host and line consumer omit `Tooltip.tsx`. Core, Lit, + React, native, export, declaration, packed-package, and lifecycle tests cover + creation, update, disable, host ownership, transport switching, custom + bodies, and cleanup. ### F-156 — Releases stranded manual Unreleased migration notes @@ -4001,3 +4014,125 @@ Each entry records: `color-domain`, `focus`, and custom comparators as explicit policies. - Verification: runtime tests cover both axes with input and color-domain order opposed to the rendered mark order. + +### F-166 — D3 declarations require a browser image global + +- Status: monitoring +- Severity: medium +- Owner: Tooling +- Observed in: strict DOM-free React Native consumer typecheck +- Friction: after Charts' DOM types were removed from the selected declaration + graph, `skipLibCheck: false` with native libraries still failed in + `@types/d3-array`. Its `blurImage` signature references the browser global + `ImageData`, even though the chart consumer does not import or call that API. +- Current decision: keep the strict configuration as a sentinel. Do not add a + fake `ImageData` declaration, enable DOM libraries, or weaken the package's + runtime boundary to conceal an upstream declaration issue. The normal + React Native configuration passes. +- Verification: the native type gate accepts only the two known + `@types/d3-array` diagnostics or a clean result after the upstream + declaration is fixed. It rejects every other diagnostic. + +### F-167 — Native interaction copied DOM-renderer policy + +- Status: monitoring +- Severity: high +- Owner: API +- Observed in: restacking the React Native focus, selection, and tooltip proof + after tooltip rendering moved behind an extension token +- Friction: focus preset resolution, stable-point restoration, navigation + order, tooltip content construction, anchor resolution, and placement math + are pure behavior but live as private functions inside `renderer.ts`. The + native proof reproduced them to exercise realistic interaction. The + extension split also made configured tooltip options require a host-owned + token; importing the web token would pull DOM implementation into Metro. +- Current decision: keep the duplication confined to the private proof. The + native adapter exports a branded extension from its optional `/tooltip` + subpath, accepts duplicate package copies and custom native implementations, + and rejects tokens owned by another host. The environment-neutral `/types` + entry exposes the generic token contract so an adapter does not need a hidden + core import. That generic contract means the wrong host token is rejected at + native render time rather than by the shared definition type; production + typing may need a host-refined definition. A definition becomes host-specific + when decorated with a tooltip token, while applications can still share the + chart spec and options before that platform step. A supported native package + still requires extracting renderer-neutral interaction and tooltip state, + with the DOM and native hosts consuming the same implementation. +- Verification: focused native tests cover strategy selection, grouping, + restoration, navigation, supported default content, placement, and extension + ownership. The native type and Metro gates use the native token without web + tooltip modules, and retained-input gates prove the base native entry does + not include the optional tooltip implementation. Browser portal tokens fail + explicitly instead of being ignored. The default native tooltip still lacks + the complete `items` formatting contract. + +### F-168 — CSS theme defaults reach the native scene compiler + +- Status: monitoring +- Severity: high +- Owner: API +- Observed in: React Native paint resolution +- Friction: the shared default theme contains `currentColor`, system CSS names, + and CSS custom properties. The native proof can resolve final paint strings + and their fallbacks, but a dynamic chart builder still receives the web + default theme before the host sees the scene. +- Current decision: the private host resolves final paints explicitly and + never evaluates application CSS. Before release, runtime construction needs + an additive platform-default-theme option used both by dynamic build context + and final theme merging. Structured paint references may be warranted if + more host semantics appear. +- Verification: native paint and full-scene tests contain no unresolved CSS + variable or `currentColor` output. Device themes and dynamic native-theme + builders remain unverified. + +### F-169 — Text measurement omits native typography + +- Status: monitoring +- Severity: high +- Owner: API +- Observed in: React Native SVG labels and automatic guide layout +- Friction: `ChartTextMeasureOptions` carries size and weight but not font + family, style, stretch, letter spacing, direction, locale, or font-scale + policy. The native painter accepts a `fontFamily`, while the shared layout + cannot ask a native measurer for the same font. +- Current decision: expose the existing injected measurer in the proof and do + not claim text parity. Production work must complete the typography contract + and decide how native asynchronous measurement feeds deterministic scene + layout without hidden mounted views. +- Verification: injected-measurer core tests pass. No iOS or Android font-scale + and clipping matrix has been run. + +### F-170 — Packed declarations assume one platform global set + +- Status: monitoring +- Severity: medium +- Owner: Tooling +- Observed in: evaluating a release gate for the private React Native package +- Friction: the existing packed fixture compiles web packages under DOM + libraries. Loading React Native declarations in that same TypeScript program + introduces incompatible duplicate globals. Removing DOM libraries makes the + web contracts invalid and also exposes F-166. +- Current decision: keep the private proof out of the publishable-package + matrix. Its source package, native consumer, isolated bundle, Metro bundles, + and no-browser source-map boundary are checked separately. +- Follow-up: add a native-specific build, pack, install, declaration, Metro, + and platform-condition fixture before making the package publishable. + +### F-171 — Metro skipped the fixture-owned Babel runtime + +- Status: resolved +- Severity: medium +- Owner: Tooling +- Observed in: rebuilding the React Native POC after removing redundant root + dependencies +- Friction: the example correctly declared `@babel/runtime`, but Metro resolved + React Native from pnpm's physical store path and searched that path's + ancestors instead of the example's `node_modules`. Production bundling + failed on `@babel/runtime/helpers/interopRequireDefault` unless the dependency + was duplicated at the workspace root. +- Decision: configure Metro's `resolver.nodeModulesPaths` with the example and + workspace module roots. Keep Babel ownership in the example rather than + masking the monorepo resolution boundary with a root dependency. +- Verification: all eight blank, RNSVG, core, and full-chart production bundles + complete for iOS and Android. The full-chart source-map checks also exclude + every guarded browser implementation module. diff --git a/NATIVE-PLATFORM-SUPPORT-SPIKE.md b/NATIVE-PLATFORM-SUPPORT-SPIKE.md new file mode 100644 index 00000000..1aebcf9b --- /dev/null +++ b/NATIVE-PLATFORM-SUPPORT-SPIKE.md @@ -0,0 +1,874 @@ +# Native platform support spike + +Research date: 2026-07-30 + +## Decision + +Full React Native support is feasible without replacing the chart grammar or +the D3-based compiler. It is not an adapter-only project. The reusable unit is +the keyed `ChartScene`; sizing, text, paint resolution, rendering, gestures, +tooltips, animation, accessibility, and raster export need native +implementations. + +Build in this order: + +1. Keep the compiler and existing focus algorithms DOM-free, extract the + browser-owned interaction state, and introduce a renderer-neutral + transition plan. +2. Ship `react-native-svg` as the default React Native renderer. +3. Add React Native Skia as an optional renderer for dense or frequently + updated charts, after measuring the crossover. +4. Use the same core refactor to test a NativeScript Core view backed by + `@nativescript/canvas`. +5. Treat Compose, SwiftUI, and Flutter as separate native products consuming a + portable definition or scene schema. They cannot share the live TypeScript + API. + +React Native is the highest-confidence target because its JavaScript runtime +can execute the existing definitions, accessors, imported D3 modules, scales, +and scene compiler. NativeScript is expected to reuse those layers, subject to +a bundler and runtime proof. Kotlin, Swift, and Dart cannot preserve arbitrary +JavaScript callbacks without embedding a JavaScript runtime. + +## What “everything” should mean + +Parity should be measured by outcome, not by reproducing browser mechanics. + +| Contract | Native parity | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Data-to-scene behavior | The same definition and data produce equal normalized domains, mark keys, topology, and focus order; numeric geometry and runtime-formatted labels meet explicit tolerances. | +| Visual behavior | Every current scene primitive, mark family, coordinate system, guide, legend, gradient, and clip renders within documented tolerances. | +| Interaction behavior | Library-owned focus, grouped focus, activation, and pinning match. App-owned brush, zoom, scrub, range selection, and editing use documented native integration patterns. | +| Motion behavior | Stable-key enter/update/exit, interruption, reduced motion, and incompatible-path fallback retain the same semantics. | +| Accessibility behavior | A user can discover the chart, traverse or adjust the current datum, hear values, activate selections, and reach an application-provided complete data representation. | +| Export behavior | JavaScript targets retain deterministic resource-aware SVG. Native renderers add platform bitmap snapshots and file/share integration. | +| Web-only behavior | SSR, hydration, DOM callbacks, CSS selectors, and mouse-specific input remain supported by the web renderer; they are not native device requirements. | + +Pixel-identical text across browser engines, Core Text, Android text, and Skia +is not a useful acceptance criterion. Geometry can be exact when renderers +consume the same scene; independently ported compilers need numeric tolerances +for geometry too. + +## Current repository boundary + +The repository already has most of the right compiler boundary: + +- `createChartRuntime` and `createChartScene` take definitions and logical + dimensions and produce a scene. +- Marks emit seven portable node types: group, rule, polyline, area, dot, + rectangle, and label. +- Cartesian, facet, polar, and geographic marks all end at those primitives. + Polar and geographic shapes carry path strings instead of requiring a DOM. +- Focusable `ChartPoint` records are separate from painted nodes. This permits + renderer batching without losing datum identity or hit testing. +- Resource-aware static SVG serialization through + `renderChartSvgWithResources` is already independent of a mounted browser + surface. The lower-level `renderChartSvg` does not emit gradient and clip + resources by itself. +- The conformance corpus contains 100 cases, including 16 executable + interaction cases and 51 interaction scenarios. It supplies coverage, but + many cases combine definition, DOM mount, controls, selectors, and + DOM-specific gesture code. Native conformance first requires extracting + platform-neutral data and definition factories, then replacing mounts, + application controllers, and drivers. + +The public renderer and host boundary is browser-shaped: + +| Evidence | Native consequence | +| ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `ChartSurface.element` is `Element`; `ChartRenderer.mount` accepts `HTMLElement`; render callbacks expose `HTMLElement` and `SVGSVGElement`. | A native renderer cannot implement the current public contract honestly. | +| `renderer.ts` owns `ResizeObserver`, pointer and keyboard events, animation frames, DOM tooltips, focus, and reduced-motion queries. | Reusable interaction state is mixed with browser services. | +| `canvas.ts` creates HTML canvases and reads `devicePixelRatio` and media queries. | Its painter can be extracted, but the current Canvas renderer cannot run in NativeScript or React Native. | +| `dom-text.ts` reads computed CSS and measures through browser Canvas 2D. | Native layout needs a different font-resolution and measurement service. | +| `RendererChart.tsx` imports `react-dom`, mounts `
` elements, injects HTML, and portals tooltips into DOM elements. | The React adapter is a web adapter, not a portable React component. | +| Default theme colors use `currentColor` and CSS custom properties. | Native renderers need concrete colors or platform-resolved semantic tokens. | +| Gradient references are emitted as SVG/CSS `url(#id)` strings; scene nodes also carry `className` and `ariaHidden`. | Structured paint references and semantic metadata should be separated from web serialization. | +| `SceneLabel` and `ChartTextMeasureOptions` expose size and weight, but not family, style, stretch, direction, letter spacing, or locale. | Native guide layout cannot reproduce the font that will paint the label. | +| `ResolvedScale.map` is a function and `ChartPoint.datum` can contain any live value. | The in-process scene is portable between JavaScript renderers, but is not a language-neutral serialized schema. | +| The root remains browser-inclusive; `@tanstack/charts/universal` and `@tanstack/charts/types` select the DOM-free value and declaration graph. | Native code has a supported boundary, while strict dependency checking still exposes the upstream `ImageData` declaration issue. | + +Directional code inventory: + +- The browser-heavy renderer, Canvas host, DOM export, DOM text measurement, + and reconciliation files remain a substantial but isolated implementation + layer. +- Most mark, scale, layout, polar, geographic, and scene construction code is + renderer-independent. + +Source counts change too quickly to serve as a credible reuse guarantee. +`types.ts` is now DOM-free, while `renderer.ts` and `canvas.ts` still mix +portable behavior with browser services. The React web adapter remains a +rewrite target because its UI is HTML plus `react-dom`. + +## Required architecture + +```mermaid +flowchart TD + Definition["Live TypeScript chart definition"] --> Runtime["Shared runtime
marks · D3 · scales · guides · layout"] + CompileInputs["Compiler inputs
logical size · text metrics · theme input"] --> Runtime + Runtime --> Scene["In-process ChartScene
geometry · keys · points · scale metadata"] + Scene --> State["Shared controller
focus restoration · activation · pinning · transition plan · semantics"] + Host["Host capabilities
frame clock · input · overlays · accessibility · snapshots"] --> State + State --> Web["Web
SVG · Canvas · DOM overlays"] + State --> RNSVG["React Native
react-native-svg · RN overlays"] + State --> Skia["React Native
Skia · RN semantic overlays"] + State --> NS["NativeScript
Canvas · native overlays"] + Portable["Portable definition / scene DTO"] --> Compose["Compose"] + Portable --> Flutter["Flutter"] + Portable --> Apple["SwiftUI / Core Graphics"] +``` + +Use narrow capabilities, not DOM-shaped polyfills. + +Compiler inputs: + +- `measureText(request)`: resolved font properties in; advance width and line + metrics out, with optional ink bounds. +- `resolvePaint(token)`: semantic or CSS-like theme input to renderer-usable + paint. +- `layoutSize`: logical dimensions supplied by the host. + +Host, controller, and surface capabilities: + +- `requestFrame`, `cancelFrame`, and reduced-motion state. +- Platform coordinates to logical scene coordinates. +- Tooltip and application-owned overlay presentation. +- Focus-indicator geometry, style, visibility, and paint. +- Accessible summary, active-datum controls, actions, and announcements. +- Optional renderer-specific bitmap snapshots. + +The compiler must remain a normal JavaScript operation. React Native worklets +should only own frame-critical numeric state, such as gesture coordinates, +crosshair position, preview transforms, paint interpolation, and a +worklet-safe nearest-point index. Arbitrary accessors, D3 modules, tooltip +formatters, and custom marks should not be serialized into the UI runtime. +[Reanimated worklets](https://docs.swmansion.com/react-native-reanimated/docs/guides/worklets/) +are a separate JavaScript context with serialization constraints. + +### Two scene contracts + +Do not freeze the current `ChartScene` as a cross-language wire format. + +1. **In-process scene:** retains live data references, scale mapping functions, + extension objects, and efficient indexes. React Native and NativeScript can + consume this directly. +2. **Portable scene DTO:** versioned JSON-compatible geometry, resolved paints, + scale metadata, datum IDs, semantic descriptions, and interaction policies. + Compose, SwiftUI, and Flutter can consume this, but live callbacks stay in + their host language. + +The proposed [`PORTABLE-CHART-SPEC.md`](./PORTABLE-CHART-SPEC.md) registry +model is the right definition-level companion. `$call` and `$data` can describe +a supported portable subset. It should never claim to serialize arbitrary +JavaScript accessors, custom tooltip components, or renderer plugins. + +### Core refactor + +1. Keep the completed universal/DOM declaration split. Further separate shared + renderer, focus, semantic, and transition contracts from browser host + implementations. +2. Keep the existing focus strategies, grouping, and spatial contracts. Move + focus restoration/order, pinned state, host input orchestration, default + tooltip content, and render-reason policy out of `renderer.ts` into a + renderer-neutral controller. +3. Introduce keyed scene diffing, interpolation instructions, and interruption + state as a transition planner. Current SVG motion is DOM attribute + reconciliation; current Canvas motion is a whole-frame crossfade. +4. Extract the Canvas 2D painter behind a structural drawing-context + interface. Keep HTML canvas creation, pixel ratio, media queries, and export + in the web host. +5. Resolve theme colors before painting. Keep CSS variables and + `currentColor` as web-adapter inputs, not scene paints. +6. Expand typography to include family, size, weight, style, stretch, letter + spacing, direction, locale, and font-scale policy. Measurement cache keys + must include all of them. +7. Preserve the resolved F-106 ownership rule: dynamic builders receive the + default theme; application and platform overrides enter through typed + inputs or the returned definition and merge during scene creation. Do not + pass a builder the theme that it is itself responsible for returning. +8. Keep deterministic, resource-aware SVG serialization in the shared + JavaScript package. +9. Define capability fallbacks for unsupported paint, path, filter, snapshot, + and semantic features. +10. Give gradients and other resources structured scene references; serialize + `url(#id)` only in the SVG renderer. +11. Treat typography and structured paints as public API migrations. Add + backward-compatible unions and normalization first, or version the change; + update migration docs and conformance before removing string paints or + existing text-measure options. + +This can remain additive for web consumers: add new internal contracts and +make the DOM host implement them. The browser-oriented root remains compatible; +cross-runtime consumers opt into `@tanstack/charts/universal` and +`@tanstack/charts/types`. + +## React Native + +As of this research, React Native 0.86 is current stable. React Native 0.82 +made the New Architecture mandatory. Set the initial support floor to React +Native 0.85 and test Expo SDK 56 / React Native 0.85 plus bare React Native +0.86. Supporting 0.82–0.84 later requires adding those CI lanes; a nominal +floor without tests is not support. Version-one product scope is iOS and +Android. Renderer dependencies may also run on macOS, Windows, web, or TV, but +those platforms need their own input, accessibility, packaging, and +conformance gates. +[React Native versions](https://reactnative.dev/versions.html) · +[React Native 0.82](https://reactnative.dev/blog/2025/10/08/react-native-0.82) · +[Expo SDK 56](https://docs.expo.dev/versions/v56.0.0/) + +The two supported dependency lanes differ: + +| Dependency | Expo SDK 56 / RN 0.85 | Bare RN 0.86 | +| ------------------ | -------------------------------------------- | ----------------------------------------------------- | +| `react-native-svg` | Expo-pinned 15.15.4 | current compatible 15.15.x | +| Skia | Expo-pinned 2.6.2 | current compatible 2.x | +| Reanimated | Expo-pinned 4.3.1 | 4.4+ line that declares RN 0.86 support | +| Worklets | managed with the Expo/Reanimated combination | matching line from the Reanimated compatibility table | +| Gesture Handler | Expo-pinned ~2.31.1 | current RN 0.86-compatible line | + +Reanimated 4 is New-Architecture-only. Expo configures its supported plugin +combination; bare apps must install the matching Worklets package and plugin. +Gesture Handler also requires `GestureHandlerRootView`. +[Expo Reanimated](https://docs.expo.dev/versions/v56.0.0/sdk/reanimated/) · +[Expo Gesture Handler](https://docs.expo.dev/versions/v56.0.0/sdk/gesture-handler/) · +[Expo SVG](https://docs.expo.dev/versions/v56.0.0/sdk/svg/) · +[Expo Skia](https://docs.expo.dev/versions/v56.0.0/sdk/skia/) · +[Reanimated compatibility](https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/) + +D3 is not expected to be the blocker. The imported `d3-array`, `d3-scale`, +`d3-shape`, and `d3-geo` code paths should be audited and executed under +Hermes rather than relying on a blanket package-family claim. `d3-shape` +explicitly supports path-string or Canvas-context output. +[d3-shape](https://d3js.org/d3-shape) + +### Default renderer: `react-native-svg` + +The scene maps directly: + +| Scene primitive | React Native SVG | +| ---------------------- | -------------------------------- | +| group, translate, clip | `G`, `ClipPath`, `Rect` | +| rule | `Line` or `Path` | +| polyline and area | `Path` | +| dot | `Circle` | +| rectangle | `Rect` | +| label | `Text` | +| linear gradient | `Defs`, `LinearGradient`, `Stop` | + +`react-native-svg` supports Fabric and the relevant primitives on iOS, +Android, macOS, Windows, and web. Its 15.13+ compatibility line requires React +Native 0.78+, below the proposed floor. This is dependency support, not a +promise that the chart package supports every one of those platforms. +[react-native-svg repository](https://github.com/software-mansion/react-native-svg) · +[usage reference](https://github.com/software-mansion/react-native-svg/blob/main/USAGE.md) + +Why it should ship first: + +- The current scene is already SVG-shaped. +- D3-generated polar and geographic path strings transfer directly. +- A retained node tree makes initial keyed updates and visual inspection + straightforward. +- It avoids a required Skia binary for ordinary charts. +- It keeps the public renderer replaceable. + +Known limits: + +- The package Codegen configuration creates native component types for SVG + primitives. A large tree may make React construction and Fabric commits + expensive, but that is a benchmark hypothesis rather than a pre-measured + limit. +- Native text metrics and baseline behavior differ from DOM SVG. +- The documented filter set is incomplete, and Android cannot apply a radial + gradient focal point. +- `getBBox`, `isPointInFill`, and related synchronous shape methods are marked + experimental; core layout and hit testing must not depend on them. + [Shape implementation](https://github.com/software-mansion/react-native-svg/blob/main/src/elements/Shape.tsx) +- RNSVG can parse stylesheet classes through `SvgCss`, but the typed production + renderer should resolve styles to props instead of depending on reparsed CSS. +- `strokeDasharray` and uncommon line joins need normalization and + compatibility tests. + +Parsing the existing SVG string through `SvgXml` is useful as a one-day visual +probe, not a production architecture. `SvgXml` and `SvgCss` reparse markup, +lose scene identities and transition keys, and cannot preserve the current DOM +interaction and accessibility model. +[RNSVG package Codegen configuration](https://github.com/software-mansion/react-native-svg/blob/main/package.json) · +[RNSVG filter support](https://github.com/software-mansion/react-native-svg/blob/main/USAGE.md#filters) · +[RNSVG CSS support](https://github.com/software-mansion/react-native-svg/blob/main/USAGE.md#css-support) + +### Optional renderer: React Native Skia + +Skia should consume the same scene and host controller. It is the likely +choice for dense scatterplots, heatmaps, streaming data, gesture-heavy charts, +and animation, but the renderer crossover must be measured. + +React Native Skia 2.x currently requires React Native 0.79+, React 19+, iOS +14+, and Android API 21+. Its documented binary contribution is roughly 6 MB +on iOS and 4 MB on Android, so it should remain an isolated optional entry. +[Skia installation](https://shopify.github.io/react-native-skia/docs/getting-started/installation/) + +Skia provides paths, clipping, gradients, synchronous font metrics, snapshots, +and direct Reanimated shared-value integration. +[Canvas](https://shopify.github.io/react-native-skia/docs/canvas/overview/) · +[text](https://shopify.github.io/react-native-skia/docs/text/text/) · +[gradients](https://shopify.github.io/react-native-skia/docs/shaders/gradients/) · +[animation](https://shopify.github.io/react-native-skia/docs/animations/animations/) + +Do not replace the current web renderer with Skia. Its web target loads +CanvasKit, adds roughly 2.9 MB compressed, and has different WebGL and API +constraints. +[Skia web support](https://shopify.github.io/react-native-skia/docs/getting-started/web/) + +Do not begin with a custom Fabric surface. If profiling proves that SVG and +Skia both fail a required workload, a single Codegen-backed native chart +surface could accept a compact scene buffer. That decision would add iOS, +Android, Codegen, serialization, and React Native version maintenance. +[React Native Codegen](https://reactnative.dev/docs/the-new-architecture/what-is-codegen) + +### Layout and text + +Text is the largest visual-parity risk. + +The current synchronous `ChartTextMeasurer` is a useful compiler seam, but a +React Native `Text` measurement may arrive after layout. The native host should +use this protocol: + +1. Resolve the complete font descriptor and issue keyed measurement requests. +2. Return cached metrics synchronously when present. +3. Use deterministic estimates for cache misses. +4. Batch native measurement of misses. +5. Rebuild the scene once when real measurements materially change guide + bounds. + +For the SVG renderer, test an offscreen native `Text` measurement surface and +`onTextLayout`; do not depend on experimental SVG bounding-box calls. For +Skia, `Font` can synchronously measure a resolved font, while complex scripts, +fallback, wrapping, and bidirectional text require Paragraph shaping. An +offscreen React Native `Text` result may not match RNSVG `Text`; measured and +painted output must agree closely enough to keep guide layout stable. +[Skia font interface](https://github.com/Shopify/react-native-skia/blob/main/packages/skia/src/skia/types/Font/Font.ts) · +[Skia Paragraph](https://shopify.github.io/react-native-skia/docs/text/paragraph/) + +The test matrix must include: + +- system and bundled fonts; +- unavailable weight fallback; +- emoji and mixed scripts; +- RTL; +- locale-specific shaping and number formatting; +- timezone, daylight-saving transitions, and non-Gregorian calendar settings; +- letter spacing and rotated labels; +- dynamic font scale; +- font loading after first render. + +The public API needs an explicit choice for chart text scaling. Blindly +applying unbounded system font scale can make a chart unreadable, while +ignoring it harms accessibility. The likely contract is a host-level +font-scaling policy plus an accessible nonvisual data representation. + +### Sizing and paint + +- The React Native root `View` supplies logical width and height through + `onLayout`. +- Scene coordinates should use density-independent logical units. Each + renderer handles physical pixel density at paint or snapshot time. +- Orientation and container changes schedule a new scene build; they do not + require a `ResizeObserver`. +- `PlatformColor` and `DynamicColorIOS` are opaque platform values, not + portable strings. Each renderer resolves them, subscribes to appearance and + accessibility changes, and uses `processColor` where native or animated + props require it. Deterministic SVG export requires an explicit color + scheme. +- High-contrast capabilities differ across iOS and Android; the adapter maps + the available accessibility state to semantic theme input rather than + promising one cross-platform flag. +- `currentColor`, CSS variables, inherited `font-family`, and CSS class styles + remain web-only resolution mechanisms. + +[React Native Appearance](https://reactnative.dev/docs/appearance) · +[React Native AccessibilityInfo](https://reactnative.dev/docs/accessibilityinfo) + +### Gestures, focus, and application interactions + +Use one chart-level gesture detector, not one responder per mark: + +1. Convert touch, pointer, or hover coordinates to logical scene coordinates. +2. Query the shared focus strategy and spatial index. +3. Update the visual focus overlay at frame cadence. +4. Commit semantic focus and pinned state at a coalesced cadence or gesture + end, and emit application activation or domain-change events through typed + integration points. + +Simple tap and activation can use React Native responders. Scrubbing, pinch, +pan, long press, and composed gestures should use Gesture Handler where +available. For app-owned brush, zoom, scrubber, and editor behavior, the +package supplies coordinates, focus primitives, integration contracts, and +examples; it does not take ownership of application domain or range state. +Gesture Handler recognizes gestures using native platform facilities and +integrates with Reanimated. +[Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/) + +Input parity is capability-based: + +| Web input | Native behavior | +| -------------------- | -------------------------------------------------------------------- | +| hover / pointer move | touch scrub, stylus/trackpad hover where available | +| click | tap | +| pinned click tooltip | tap or long press, with explicit dismiss | +| wheel zoom | pinch; trackpad/wheel where the platform reports it | +| drag brush | pan gesture with visible handles and minimum touch targets | +| arrow-key focus | adjustable screen-reader actions; hardware keys on supported targets | +| Escape | dismiss action, back action, or hardware key | + +The 16 interaction conformance cases should call semantic drivers such as +`focusAt`, `activate`, `pan`, `zoom`, `setBrush`, and `adjustDatum`. Each +platform harness translates those operations to real input separately. Cases +whose controller is application-owned must extract and port that controller; +they are integration conformance, not new core behavior. + +Launch gates include: + +- arbitration with nested `ScrollView`, navigation, and parent gestures; +- axis locking, cancellation, and responder loss; +- coordinate conversion under view and chart transforms; +- Android back behavior for pinned state; +- the copy and memory cost of moving any spatial index into a worklet; +- minimum touch targets and handles near safe areas. + +### Accessibility + +Painted geometry and accessibility must be separate outputs of the controller. +Skia explicitly requires overlaid React Native views to make inner canvas +elements accessible, and an SVG node per datum is not a scalable semantic +tree. +[Skia canvas accessibility](https://shopify.github.io/react-native-skia/docs/canvas/overview/) · +[React Native accessibility](https://reactnative.dev/docs/accessibility) + +Recommended native model: + +- A non-accessible layout container with sibling semantic elements. React + Native warns that VoiceOver can suppress nested accessible elements. +- One accessible summary element with label, description, and concise chart + summary. +- One sibling adjustable active-datum controller with increment, decrement, + and activate actions. +- `accessibilityValue.text` containing series, category or time, value, and + relevant interval. +- Platform-appropriate announcement or live status when the active value + changes; live-region behavior differs between iOS and Android. +- A visible focus marker and tooltip rendered through ordinary React Native + views. +- Semantics and data hooks that let the application supply a virtualized list + or table for complete inspection. Shipping that table is a new feature, not + current package parity. +- Reduced-motion behavior driven by `AccessibilityInfo`. +- Visual renderer descendants hidden with the platform-appropriate + `importantForAccessibility`, `accessibilityElementsHidden`, or equivalent + props to prevent duplicate or unusably large traversal. + +VoiceOver and TalkBack testing on physical devices is an exit criterion. +Thousands of transparent focusable views are not an acceptable implementation. + +The shared semantic model can supply series and datum descriptions for +Apple’s `AXChartDescriptor` and audio graphs. React Native core, RNSVG, and +Skia do not expose that API; using it would require a custom iOS native +accessibility component and is not part of the first renderer. +[Apple chart accessibility](https://developer.apple.com/documentation/swiftui/view/accessibilitychartdescriptor%28_%3A%29) + +### Motion + +The shared transition planner should produce stable-key enter, update, and +exit operations from the currently painted state, not only previous and next +scenes. Renderers then execute: + +- numeric geometry and opacity interpolation; +- color interpolation; +- path interpolation when topology is compatible; +- a documented resampling or crossfade fallback when it is not; +- cancellation and restart from the current visual value; +- zero-duration output under reduced motion. + +Skia’s path interpolation requires compatible path commands, so arbitrary +path morphing cannot be delegated without normalization. +[Skia path interpolation](https://shopify.github.io/react-native-skia/docs/animations/hooks/) + +Per-frame React/RNSVG prop commits are safe only as a small-scene proof, not +the assumed production default. The motion spike must compare animated props +and UI-thread execution early, including path normalization, color processing, +and interruption from the value actually painted on the UI thread. +[Reanimated `useAnimatedProps`](https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedProps/) + +Transition state must live outside React render side effects. It must discard +stale concurrent scene builds, rebase after font/theme/size invalidation, and +pause or rebase when `AppState` moves between background and foreground. + +### Export and web + +- Keep resource-aware SVG string export in the shared JavaScript core. It does + not require a mounted native surface. +- Define whether a PNG captures only chart paint or also React Native tooltip, + legend, and focus overlays. Add explicit scale, background, color-scheme, + and font-readiness options. +- Skia’s asynchronous snapshot runs on the UI thread and is required when + textures are present. Generic view capture has separate native-surface and + view-collapsing constraints; both paths need device proof. +- Add file and share helpers only in platform integration packages. +- Keep browser consumers on the existing root and DOM/SVG React adapter. React + Native Web can render native components, but the current web implementation + already has better SSR, hydration, CSS, text measurement, and semantic SVG + behavior. +- Keep native callbacks typed to native surface and layout data; do not expose + fake `HTMLElement` or `SVGSVGElement` values. + +[Skia canvas snapshots](https://shopify.github.io/react-native-skia/docs/canvas/overview/) · +[Skia view snapshots](https://shopify.github.io/react-native-skia/docs/snapshotviews/) + +A WebView can demonstrate visual reuse, but it is not native support. Expo DOM +components use a separate JavaScript engine, JSON-serialized asynchronous +props, whole-tree rerenders, and no SSR/SSG or native children. +[Expo DOM components](https://docs.expo.dev/guides/dom-components/) + +### Package shape + +```text +@tanstack/charts + browser-compatible root + ./universal + DOM-free definitions, marks, D3 integration, scene, focus, semantics + ./types + DOM-free public contracts + +@tanstack/react-charts + existing web React adapter + +@tanstack/react-native-charts + native React adapter and react-native-svg renderer + ./skia + optional Skia renderer subpath +``` + +The base native entry should peer-depend on React, React Native, and +`react-native-svg`. Skia, Reanimated, Worklets, and Gesture Handler should be +optional peers, declared through `peerDependenciesMeta.optional`, so a static +SVG chart does not acquire or autolink unrelated native modules. Do not use +`optionalDependencies`. The base implementation and declaration graph must +have no static reference to optional peers. + +Package exports need explicit `browser`, `react-native`, and `default` +conditions, with `browser` before `react-native`, plus matching type +declarations. Once an export matches, Metro does not append `.native` or `.web` +to that target. Test resolution through Metro/Expo, Vite or Webpack, Jest, and +TypeScript. An export target cannot point into another package, so a browser +re-export needs a local shim and declared dependency or peer. +[Metro package exports](https://metrobundler.dev/docs/package-exports/) + +## NativeScript + +NativeScript is the second-best reuse target because its runtime can execute +the JavaScript built from the TypeScript core and expose native platform APIs +directly. NativeScript Core supports custom native views, gestures, animation, +and accessibility. Its Canvas project provides native-backed Canvas 2D, WebGL, +and WebGPU packages. Ordinary JavaScript runs on the UI thread; Workers are +isolated and communicate through JSON-serializable messages. Large scene +compilation plus Canvas painting is therefore a first-order benchmark, not +assumed reuse. +[NativeScript documentation](https://docs.nativescript.org/) · +[native APIs](https://docs.nativescript.org/guide/adding-native-code) · +[custom native views](https://docs.nativescript.org/guide/create-custom-native-elements) · +[gestures](https://docs.nativescript.org/guide/gestures) · +[accessibility](https://docs.nativescript.org/guide/accessibility) · +[multithreading](https://docs.nativescript.org/guide/multithreading) · +[NativeScript Canvas](https://github.com/NativeScript/canvas) + +Recommended implementation: + +1. Extract the current Canvas painter from HTML canvas creation and DOM host + behavior. +2. Implement a NativeScript Core chart view that supplies size, pixel ratio, + a Canvas context, frame scheduling, and gestures. +3. Prove that the same definition and in-process scene compiler run unchanged + through NativeScript’s bundler and runtime. +4. Add Angular, Vue, Solid, Svelte, or React wrappers only after the Core view + is stable. + +React NativeScript is a React renderer over NativeScript views, not React +Native compatibility. React Native components and ecosystem packages do not +transfer. It should be a thin wrapper around a NativeScript Core chart view +rather than the foundation. +[NativeScript React tutorial](https://docs.nativescript.org/tutorials/build-a-master-detail-app-with-react) · +[React NativeScript repository](https://github.com/shirakaba/react-nativescript) + +NativeScript proof requirements: + +- correct text metrics, baselines, font fallback, and pixel ratio; +- `Path2D`, clipping, gradients, dash arrays, joins, and transforms; +- image snapshot/export; +- touch coordinate conversion and gesture composition; +- an accessible root and active-datum control implemented either with a small + number of real NativeScript views or custom iOS/Android accessibility + containers; NativeScript documents accessibility for `View` objects but no + Canvas virtual-child semantic tree; +- long-running animation and streaming stability; +- scene build and paint time at 1k, 10k, and 50k primitives; +- memory and UI-thread responsiveness on low-end Android. + +If its Canvas implementation cannot meet these gates without platform-specific +patches, stop rather than maintain a browser API imitation with divergent +behavior. + +## Other native UI stacks + +| Target | Source reuse | Technical fit | Recommendation | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Compose Multiplatform | No executable TypeScript reuse; definitions, scene DTOs, fixtures, and semantics can transfer. | Shared Kotlin API; Android uses Jetpack Compose and iOS Compose is canvas-rendered through Skiko. Custom Canvas semantics must be authored. | Best candidate for a shared Kotlin/Compose product after the portable contract is proven. | +| Flutter | No TypeScript reuse on native; requires a Dart port of the compiler/runtime or a Dart scene consumer. | `CustomPainter` maps cleanly to the scene and supports hit testing and virtual semantics; Flutter paints through its own engine/Impeller. | Build only as a first-class Flutter product with dedicated ownership and add-to-app cost. | +| SwiftUI `Canvas` | Schema and fixtures only. | Uses `GraphicsContext`; Apple excludes per-element interaction and accessibility, so synthetic children/representations are required. | Apple-only product or accessibility reference, not the cross-platform starting point. | +| UIKit / Core Graphics | Schema and fixtures only. | Separate lower-level custom-view path with maximum Apple control and no Android implementation. | Use only if SwiftUI Canvas cannot meet required fidelity or integration. | +| Swift Charts | Semantic mapping, not scene parity. | Supplies native marks, axes, legends, and chart accessibility, but owns layout and styling. | Optional native-style backend, not feature-for-feature TanStack rendering. | +| Lynx / ReactLynx | Pure TypeScript compiler may transfer after DOM removal. React Native components do not. | Lynx 4 exposes static-oriented SVG as one native view and no public Canvas element; per-mark input and semantics need overlays or custom native elements. | Watchlist until its graphics layer can support interactive dynamic scenes. | +| Separate UIKit and Android View renderers | Schema and fixtures only unless a JavaScript runtime is embedded. | Maximum control and maximum duplicated implementation. | Avoid unless profiling and commercial demand justify two permanent native engines. | + +Primary references: + +- [Compose Multiplatform](https://kotlinlang.org/docs/multiplatform/compose-multiplatform-and-jetpack-compose.html), + [iOS renderer explanation](https://blog.jetbrains.com/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/), + [iOS stable announcement](https://blog.jetbrains.com/kotlin/2025/05/compose-multiplatform-1-8-0-released-compose-multiplatform-for-ios-is-stable-and-production-ready/), + [Compose custom graphics](https://developer.android.com/develop/ui/compose/graphics/draw/overview), + [Compose semantics](https://developer.android.com/develop/ui/compose/accessibility/semantics), + and [Compose iOS accessibility](https://kotlinlang.org/docs/multiplatform/compose-ios-accessibility.html) +- [Flutter `CustomPainter`](https://api.flutter.dev/flutter/rendering/CustomPainter-class.html), + [Flutter architecture](https://docs.flutter.dev/resources/architectural-overview), + [add-to-app](https://docs.flutter.dev/add-to-app), and + [Flutter semantics](https://api.flutter.dev/flutter/widgets/Semantics-class.html) +- [SwiftUI `Canvas`](https://developer.apple.com/documentation/swiftui/canvas), + [accessibility representations](https://developer.apple.com/documentation/swiftui/view/accessibilityrepresentation%28representation%3A%29), + [AXChart](https://developer.apple.com/documentation/accessibility/axchart), + and [Swift Charts](https://developer.apple.com/documentation/charts) +- [Lynx 4 elements](https://lynxjs.org/4.0/api/), + [SVG element](https://lynxjs.org/4.0/api/elements/built-in/svg.html), and + [custom native components](https://lynxjs.org/4.0/guide/custom-native-component) + +For non-JavaScript targets, “same API” can mean equivalent chart concepts and +conformance, not source compatibility. Accessors, formatters, custom scales, +tooltip bodies, callbacks, and plugins must be declared as one of: + +- portable declarative input; +- a named registry function; +- a host-language callback; +- JavaScript-only. + +Sending a complete scene across a JavaScript-to-native or host-language +boundary on every frame is not a durable dynamic-chart design. A portable +scene DTO is appropriate for static charts, fixtures, export, and an initial +renderer proof. A production native-language library eventually needs local +layout, interaction, and animation logic. + +## Feature parity matrix + +| Capability | Shared work | React Native | NativeScript | Non-JS native | +| --------------------------------------------- | --------------------------------------------- | ------------------------------- | ------------------------------------------------- | -------------------------------------------- | +| Definitions, accessors, transforms, D3 scales | Existing compiler through universal entries | Direct reuse after Hermes proof | Expected reuse after runtime proof | Declarative subset or reimplementation | +| Cartesian marks and guides | Existing scene | Render primitives | Canvas painter | Render DTO or reimplement | +| Facets and layered charts | Existing layout and groups | Direct reuse | Expected after runtime proof | Scene-compatible | +| Polar, pie, radar, gauge | Existing path-producing marks | SVG/Skia paths | Canvas paths | Scene-compatible | +| Geography and projections | Existing D3-generated paths | SVG/Skia paths | Canvas paths | Scene-compatible | +| Gradients and clipping | Existing scene data plus capability rules | New mapping, platform tests | New mapping, platform tests | New mapping | +| Text, axes, legend margins | Shared request/cache protocol | New native measurement | New native measurement | New native measurement | +| Theme and color | Shared semantic theme | New RN resolution | New NativeScript resolution | New platform resolution | +| Focus and grouped tooltip logic | Extract from web renderer | Reuse controller; new overlay | Reuse controller; new overlay | Port controller | +| Activation / `onSelect` | Shared callback contract | Tap and accessibility actions | Tap and accessibility actions | Platform input | +| Brush, zoom, scrubber, editor | Application-owned state plus semantic drivers | Native integration examples | Native integration examples | Platform implementations | +| Keyed animation | New shared transition planner | SVG and Skia execution | Canvas execution | Port planner | +| Focus indicator | New shared overlay contract | RN overlay or renderer layer | Canvas/native overlay | Platform overlay | +| Accessibility | New shared semantic model | RN sibling semantic controls | Feasibility gate: real views or native containers | Native semantics | +| Custom marks using scene primitives | Existing extension model | Reuse | Reuse | Equivalent host-language API | +| Renderer-specific custom output | None | Native renderer callback | Canvas/native callback | Platform-specific | +| Pure SVG export | Resource-aware JavaScript serializer | Reuse | Reuse if runtime proof passes | Native serializer or externally supplied SVG | +| Mounted PNG export | Platform capability | Snapshot/view capture | Canvas or platform capture, pending proof | Platform snapshot | +| SSR and hydration | Existing browser root and React host | Not applicable on device | Web target only | Not applicable on device | + +## Validation program + +### Stage 1: portability proof + +Run the compiler under Hermes and NativeScript without DOM globals. + +Pass conditions: + +- Representative definitions import through Metro and NativeScript bundling. +- With locale, calendar, and timezone fixed, web, Hermes, and NativeScript + produce exact normalized domains, keys, topology, and explicitly formatted + labels. Compare numeric coordinates and normalized path data with a defined + epsilon. +- DOM types are absent from the Charts declaration graph; strict dependency + checking reaches only the known upstream `ImageData` declaration. +- Theme and text services are injected. +- No browser polyfill is required. +- Conditional exports and optional-peer isolation resolve through Expo/Metro, + bare Metro, TypeScript, Jest, and a browser bundler. + +### Stage 2: renderer sentinels + +Render a deliberately small set before porting all 100 cases: + +1. multi-line chart with gaps, rotated ticks, and a legend; +2. stacked area with stable-key update; +3. grouped and stacked bars; +4. 10k-point scatter; +5. labeled heatmap with clipping and gradients; +6. faceted chart; +7. pie/donut plus radar or gauge; +8. geographic projection; +9. grouped tooltip with touch scrub and pinning; +10. zoom/pan or brush interaction; +11. streaming update with interruption; +12. custom scene mark. + +Pass conditions: + +- iOS and Android screenshots meet geometry and visual tolerances. +- Every sentinel has a usable VoiceOver and TalkBack path. +- Visible focus-indicator geometry, style, and visibility match the semantic + focus state. +- Custom fonts, RTL, dark mode, high contrast, reduced motion, and orientation + changes work. +- SVG and Skia consume the same scene and interaction controller. + +### Stage 3: performance crossover + +Use release or `debugOptimized` builds on a low-end Android device and a +representative iPhone. Standard Android debug builds are not valid evidence. + +Test 100, 1k, 10k, and 50k painted primitives, with an optional 100k stress +case. Record: + +- scene preparation and layout time; +- first paint; +- single-datum update; +- full data replacement; +- streaming update cadence; +- orientation and resize; +- touch scrub, pan, and zoom latency; +- nested-scroll arbitration, cancellation, and transformed hit coordinates; +- JS and UI frame time; +- memory; +- Fabric node count; +- native binary and application bundle delta; +- snapshot time and size. + +The measured SVG/Skia crossover becomes documentation. Do not choose a point +count from intuition. + +### Stage 4: conformance + +- Run all 100 visual cases on iOS and Android for the default renderer. +- Run the performance and renderer-sensitive subset on Skia and NativeScript. +- Extract platform-neutral definition/data factories from all 100 cases. +- Translate all 16 interaction cases to semantic platform drivers, with + application controllers remaining application-owned integration fixtures. +- Compare normalized domains, keys, and topology exactly; compare numeric + geometry and normalized paths with the agreed tolerance before screenshot + tolerances. +- Keep the DOM-free TypeScript compile and Metro import smoke alongside the + current jsdom-oriented unit suite; add Hermes execution coverage. +- Test current web SSR, hydration, SVG, Canvas, and export to catch refactor + regressions. +- Test stale-scene cancellation, concurrent updates, mid-flight interruption, + font/theme/size invalidation, and app background/foreground rebasing. +- Use React Native Testing Library for adapter state and semantics, but require + device tests for native drawing, gestures, and accessibility. Its own + guidance notes that native behavior needs simulator or device validation. + [React Native Testing Library boundary](https://callstack.github.io/react-native-testing-library/12.x/docs/guides/faq) + +### Stop conditions + +Pause a public native package if any of these remain unresolved after the +proof: + +- text measurement causes repeated layout oscillation or materially wrong + guides, or the measuring and painting stacks disagree on shaped text; +- the default renderer misses interaction frame budgets on ordinary charts; +- the semantic model cannot provide useful VoiceOver and TalkBack navigation; +- Metro requires DOM declarations or browser polyfills; +- SVG and Skia require divergent public chart definitions; +- native output depends on reparsing SVG strings; +- NativeScript requires project-local patches to its graphics runtime. + +## Estimated effort + +An engineer-week means one experienced library engineer working full time. +Ranges include implementation, tests, examples, and documentation, but not +unrelated chart features or store release work. + +| Deliverable | Estimate | Confidence | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -----------------------------------------: | ----------------------- | +| Shared controller extraction, transition design, platform theme/typography contracts, and device harness | 2–4 engineer-weeks | Medium | +| React Native SVG proof productionization: gestures, complete tooltips, packaging, and release gates | 3–5 engineer-weeks | Medium | +| React Native full applicable parity: text, themes, keyed motion, gestures, tooltips, accessibility, export, API migration, 100-case hardening, Expo/bare CI | 5–8 engineer-weeks | Low–medium | +| Production React Native SVG package total | 10–16 engineer-weeks | Low–medium | +| Optional Skia execution/optimization of the shared motion contract, snapshots, and crossover benchmarks | +4–7 engineer-weeks | Low–medium | +| NativeScript Core Canvas package after shared refactor | +6–10 engineer-weeks | Low | +| Portable scene DTO plus one Compose or Flutter rendering proof | +3–6 engineer-weeks | Low | +| Production Compose, Flutter, or Swift implementation | Separate multi-month product per ecosystem | Low until the DTO proof | + +Directional implementation size is 5–8k production lines plus 3–6k lines of +tests and fixtures for first-class React Native parity. A NativeScript +framework/view wrapper could remain near 1k lines only after a portable painter +and backend exist. The renderer/backend itself is likely another 2–4k lines; +device testing, accessibility feasibility, performance work, and hardening +explain the 6–10 week estimate. + +Two experienced engineers could overlap core/controller work, React Native +rendering, and device harness work. A realistic calendar range for a +production React Native package with both SVG and Skia is roughly 8–12 weeks, +assuming the text and accessibility proofs pass early. NativeScript should not +be scheduled as a committed package until its Canvas proof passes. + +Ongoing maintenance is material: + +- React Native, Expo, Metro, `react-native-svg`, Skia, Reanimated, and Gesture + Handler compatibility; +- physical-device screenshot, performance, VoiceOver, and TalkBack coverage; +- renderer-specific bug triage; +- font and graphics differences across iOS and Android; +- conformance updates whenever the scene grammar grows. + +## Recommended first commitment + +Fund a two-week, two-engineer device and shared-behavior proof rather than +announce the private package. + +Engineer A: + +- extract the shared interaction and tooltip controller; +- define platform theme and typography ownership; +- replace the responder proof with scroll-safe gesture arbitration; +- exercise representative definitions under Hermes and on devices. + +Engineer B: + +- build the iOS/Android visual, performance, and binary-size harness; +- define semantic output and VoiceOver/TalkBack flows; +- test the existing SVG host across density and gesture sentinels; +- scope the later Canvas/NativeScript proof from measured bottlenecks. + +At the end of the proof, decide from evidence: + +1. whether `react-native-svg` is a viable default; +2. whether Skia is required for the first release or can follow; +3. whether the typography contract is stable enough for public API; +4. whether NativeScript meets the bar without runtime patches; +5. whether to stabilize a portable scene DTO for non-JavaScript targets. + +## Explicit non-goals + +- No DOM emulation layer on native. +- No WebView marketed as native support. +- No D3 or arbitrary user callbacks in UI-thread worklets. +- No Skia dependency in the base package. +- No point-count threshold before device benchmarks. +- No thousands of invisible accessible views. +- No pixel-perfect cross-engine promise. +- No claim that a JSON subset preserves the complete live TypeScript API. +- No custom Fabric, UIKit, or Android renderer before the shared renderers are + measured. diff --git a/REACT-NATIVE-HOST-POC.md b/REACT-NATIVE-HOST-POC.md new file mode 100644 index 00000000..1683c8e8 --- /dev/null +++ b/REACT-NATIVE-HOST-POC.md @@ -0,0 +1,388 @@ +# React Native host proof of concept + +Research and implementation date: 2026-07-30 + +## Decision + +A React Native SVG host is viable. The chart grammar, D3 scales, marks, +responsive scene compiler, gradients, clips, polar and geographic paths, point +identity, and most focus algorithms can run unchanged. The current web +`ChartRenderer` cannot be the native abstraction: its public contract requires +DOM elements, string prerendering, client coordinates, and browser-owned +surface lifecycle. + +The proof should advance only as a separate package and host: + +```text +definition + D3 scales + marks + │ + ▼ + shared @tanstack/charts runtime + │ + ▼ + ChartScene + │ + ▼ + React Native interaction + react-native-svg +``` + +This can remain additive for current consumers. Do not generalize +`ChartRenderer` or remove DOM types from the root API to make native fit. + +The POC establishes technical feasibility, package isolation, approximate +JavaScript cost, and the main API boundaries. It does not establish device +visual parity, application binary cost, Hermes runtime performance, or +production support. + +## Implemented proof + +The private `@tanstack/react-native-charts` package includes: + +- a generic React Native `Chart` component that owns `createChartRuntime`; +- responsive sizing from explicit dimensions, aspect ratio, or `onLayout`; +- a direct keyed `ChartScene` visitor using `react-native-svg`; +- groups, rules, polylines, areas, dots, rectangles, labels, linear gradients, + nested translation, and rectangular clips; +- current-color and CSS-variable-fallback paint resolution; +- nearest, axis-nearest, and grouped focus; +- tap selection, sticky pinning, focus restoration, and accessibility actions; +- a separate SVG focus overlay; +- an optional native tooltip subpath with point, pointer, group-center, and + custom anchors, collision-aware placement, custom content, and a custom + React body; +- an optional injected text measurer; +- a Metro fixture using React Native 0.86.0 and `react-native-svg` 15.15.5; +- source-map checks that reject browser renderer code in iOS and Android + bundles. + +The host imports runtime values from narrow core subpaths. It does not import +the root barrel, `react-dom`, a browser adapter, the DOM renderer, the Canvas +host, or the SVG string/reconciliation pipeline. The narrow imports keep this +measurement bundle-sensitive; application definitions can instead use the +environment-safe `@tanstack/charts/universal` barrel. + +That distinction matters to shared application source. A Metro probe using +`defineChart` and `lineY` from the browser-oriented root +`@tanstack/charts` barrel traversed the DOM renderer, DOM text, reconciliation, +SVG surface, and adapters. The prerequisite universal-barrel PR adds +`@tanstack/charts/universal` for normal environment-neutral authoring while +retaining granular entries for tighter bundles. + +That prerequisite also adds `@tanstack/charts/types`, exports the generic +tooltip and portal token interfaces for host-adapter authors, and moves DOM +host types to an internal `dom-types.ts` module while preserving their root +re-exports. This POC adds no further core public API. + +Minimum usage keeps the browser-oriented root unchanged and selects the native +host and tooltip explicitly: + +```tsx +import { scaleLinear } from 'd3-scale' +import { defineChart, lineY } from '@tanstack/charts/universal' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' + +const definition = defineChart( + { + marks: [lineY([4, 9, 7])], + x: { scale: scaleLinear().domain([0, 2]) }, + y: { scale: scaleLinear().domain([0, 10]) }, + }, + { tooltip: { use: tooltip, sticky: true } }, +) + +export function RevenueChart() { + return ( + + ) +} +``` + +The tooltip token makes that configured definition native-specific. A shared +application can keep the chart spec and tooltip options universal, then attach +the web or native token in its platform entry. + +## Bundle measurements + +### Isolated esbuild entries + +Production, minified ESM; React, React Native, and `react-native-svg` are +external in the native entries. + +| Entry | Minified | Gzip | +| ---------------------------------- | -------: | -------: | +| React Native SVG host | 23.26 kB | 8.93 kB | +| React Native SVG host with tooltip | 28.04 kB | 10.57 kB | +| React Native line consumer | 45.30 kB | 17.68 kB | +| Shared line scene | 34.29 kB | 13.44 kB | +| Existing React web adapter | 32.66 kB | 12.03 kB | +| Existing React web line consumer | 54.50 kB | 20.78 kB | + +The native host entry includes the host plus every shared runtime and D3 module +reachable from exporting `Chart`; it is not isolated adapter-only overhead. +The base host and line consumer omit `Tooltip.tsx`. Importing the tooltip +subpath adds 4.78 kB minified and 1.65 kB gzip. The native line consumer +additionally includes the line mark and D3 scale code while leaving platform +peers external. It is the closest comparison to the existing React line entry, +but the two platforms do not have identical runtime baselines. The native +entries are informational measurements, not locked budgets. + +### Metro application deltas + +React Native production bundles were minified for both platforms. Each row is +measured against a blank React Native application built with the same Metro +configuration. + +| Platform | Full chart minified JS delta | `react-native-svg` gzip delta | Core line gzip delta | Full chart gzip delta | Full chart module delta | +| -------- | ---------------------------: | ----------------------------: | -------------------: | --------------------: | ----------------------: | +| iOS | 309.42 KiB | 27.75 KiB | 37.78 KiB | 72.53 KiB | 281 | +| Android | 309.56 KiB | 27.69 KiB | 37.81 KiB | 72.62 KiB | 281 | + +The full iOS bundle was 1,200,921 bytes and 288,655 bytes gzip, versus 884,080 +and 214,381 for blank. Android was 1,206,437 and 289,754, versus 889,448 and +215,395 for blank. + +These are JavaScript bundle measurements, not Hermes bytecode or installed +application sizes. They exclude the native iOS and Android code linked by +`react-native-svg`. A clean release-binary before/after comparison is still +required. + +The full-chart source maps include the native host and exclude every guarded +browser module: adapters, DOM host, DOM text measurement, renderer, Canvas, +reconciliation, SVG serialization/surface code, `react-dom`, React web charts, +and Octane charts. + +## Parity and boundaries + +| Capability | POC result | Production boundary | +| -------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------ | +| Definitions, D3 scales, marks, layout | Shared unchanged | High confidence | +| Cartesian, facet, polar, geo geometry | Shared scene paths | Needs device conformance | +| All seven scene node kinds | Implemented | Needs iOS/Android visual tests | +| Linear gradients and rectangular clips | Implemented | Device and nested-clip tests remain | +| Responsive sizing | `onLayout`, explicit size, aspect ratio | Scroll/layout integration remains | +| Paint | `currentColor` and CSS fallback resolution | Dynamic definitions still see the web default theme | +| Text | SVG text plus injected core measurer | Exact native typography and async measurement are unresolved | +| Nearest and grouped focus | Implemented | Logic is duplicated from the DOM renderer | +| Tap, selection, sticky tooltip | Implemented | Responder ownership may conflict with scrolling and gestures | +| Tooltip | Native in-tree overlay | Web `className`, portal semantics, and full item formatting are not equivalent | +| Accessibility | Labeled adjustable root and actions | No per-point native accessibility tree or data-table escape | +| Motion | Not implemented | Requires a renderer-neutral transition model | +| SVG/PNG export | Not implemented | Needs native snapshot/share APIs | +| Large-data renderer | Not measured | SVG node pressure may require an optional Skia host | +| SSR and hydration | Intentionally absent | Web-only behavior | + +### Rendering details that are not exact + +- SVG `arcs` and `miter-clip` joins are explicitly normalized to `round` and + `miter`, respectively, because the React Native SVG type surface does not + expose them. +- The native paint resolver can consume CSS variable fallbacks, but it cannot + evaluate application CSS. A production host needs concrete native theme + values before scene compilation. +- The current text-measure contract does not carry font family, font style, + letter spacing, direction, or locale. Passing `fontFamily` to the painter + cannot make guide layout measure the same font. +- `react-native-svg` supports the required primitive family and Fabric, but + SVG compatibility must be verified on real iOS and Android renderers rather + than inferred from server-rendered component markup. + +### Interaction details that are not exact + +- Focus preset resolution, point restoration, navigation order, tooltip + content, anchor, and placement are private functions inside the DOM renderer. + The POC had to reproduce those policies. A supported package must extract + the pure behavior and make both hosts consume it. +- The POC does not implement the complete `tooltip.items` channel, datum, and + derived-row contract. Custom `content`, `format`, `formatGroup`, and a custom + React body work, but default structured content is only partial. +- The shared definition type accepts environment-neutral extension tokens, so + a web tooltip token typechecks in native application code and fails when the + native `Chart` resolves it. Compile-time host rejection would require a + refined native definition type before release. +- The root `View` currently claims touch responder ownership on press. + `ScrollView`, pan, brush, zoom, and application gestures require an explicit + arbitration model, likely through Pressability or Gesture Handler rather + than more responder callbacks. +- Native accessibility cannot reuse DOM focus and ARIA. The adjustable-root + behavior proves a useful minimum, not parity with keyboard traversal or a + complete accessible data representation. +- The chart is one accessible root. Nested controls in a custom pinned tooltip + may be hidden by platform accessibility grouping, and + `accessibilityLiveRegion` is Android-specific. This needs VoiceOver and + TalkBack design rather than prop translation. +- A local absolute tooltip cannot escape clipped native ancestors. Native + portal/modal behavior needs a separate definition from the browser top-layer + implementation. + +## API and compatibility impact + +No existing public call needs to break for an SVG-native release. + +Prerequisite changes delivered by the universal-barrel PR: + +- additive `@tanstack/charts/universal` export; +- additive `@tanstack/charts/types` export, including generic tooltip and portal + token contracts; +- mechanical split between universal and DOM host types, with root re-exports + preserved. + +This proof adds a separate private React Native package, base component +contract, and optional tooltip subpath. + +Additive changes likely required before release: + +- a shared, renderer-neutral interaction state module; +- a shared tooltip content/anchor/placement model; +- a runtime option for platform default themes; +- a complete typography and text-measurement contract; +- structured paint references or a host paint-resolution contract; +- native-specific tooltip overlay and gesture integration points. + +Changes to avoid: + +- making the current `ChartRenderer` union over DOM and native surfaces; +- making string prerendering optional inside that renderer contract; +- importing React Native from the core package; +- shipping CSS tokens to native and silently substituting arbitrary colors; +- claiming compatibility outside the tested React Native 0.86.0 and + `react-native-svg` 15.15.5 pair; +- adding Skia before an on-device density/performance crossover is measured. + +The root type API remains compatible. Consumers that want a DOM-free +declaration graph can opt into `@tanstack/charts/types`. Shared definitions can +replace browser-root imports with `@tanstack/charts/universal`; granular entries +remain the bundle-sensitive option. Neither path changes existing published +web behavior. + +The private package is not publishable as it stands. Metro resolves its +workspace source, and the package has no production build or published export +map. A native-specific build, declaration, tarball, install, +conditional-export, and Metro-consumer gate is part of productionization. + +## Pros and cons + +### Advantages + +- Most data-to-geometry behavior remains one implementation. +- Existing definitions, accessors, D3 scales, custom marks, polar charts, and + geographic paths remain usable. +- The direct scene visitor is small and avoids an SVG XML parse/reconcile step. +- `react-native-svg` provides one renderer across iOS and Android and supports + the current React Native architecture. +- Native callbacks receive the original datum objects because the scene and + interaction model stay in one JavaScript runtime. +- The separate package keeps native dependencies and platform assumptions out + of web bundles. + +### Costs + +- Rendering parity is only the easy half; text, input, tooltips, animation, + accessibility, and export are host products. +- `react-native-svg` adds both JavaScript and native binary code. +- Many SVG nodes can become expensive before the shared scene compiler does. +- Native support needs devices, release builds, TalkBack/VoiceOver testing, + and two platform-specific failure surfaces. +- Current interaction and tooltip ownership must be refactored out of a mature + DOM renderer without regressing web behavior. +- A publishable native package needs a separate packed-declaration gate because + React Native and DOM global declarations conflict in the current web fixture. + +## Verification performed + +- 16 focused POC tests cover every scene primitive, gradients, clips, paint + resolution, focus modes, point restoration, placement, chart compilation, + extension ownership, and no-speculative-size behavior. Component mapping + tests use React DOM server rendering with native modules mocked; they are + structural tests, not native renderer tests. +- The native package and the normal React Native application configuration + typecheck. +- The repository-wide typecheck passes with the native dependency graph. +- The prerequisite PR's packed gate validates both environment-safe entries without + changing the browser root. +- Existing locked web bundle baselines remain unchanged. +- Production Metro bundles complete for iOS and Android. +- Source-map gates prove the full native entries do not include guarded browser + implementation files, including the web tooltip and portal runtimes. +- Retained-input gates prove the base native host and line consumer omit the + optional native tooltip implementation. + +A strict native consumer with `skipLibCheck: false` now gets past the Charts +DOM boundary and stops in `@types/d3-array`, whose `blurImage` declaration +references the browser global `ImageData`. An automated diagnostic accepts +only those two known errors, or a clean result after the upstream declaration +is fixed. The POC does not add a fake global or pull DOM libraries into native +to hide the upstream declaration problem. + +The native declaration check and isolated esbuild boundary run in the normal +validation workflow. The eight-build iOS/Android Metro measurement remains a +local spike command rather than a mandatory CI gate. + +Not performed: + +- simulator or physical-device rendering; +- native component interaction tests; +- visual comparison against the conformance corpus; +- Hermes execution or profiling; +- 1k/10k-point interaction and memory tests; +- release application binary comparison; +- VoiceOver and TalkBack validation; +- Expo managed-workflow validation; +- motion, export, or Skia implementation. + +## Production path + +### Phase 1: shared behavior and a releasable SVG host + +Extract interaction and tooltip policy, add native theme ownership, complete +the typography contract, replace the proof's responder policy, and add a +native-specific package gate. Keep the package scoped to the tested RN/RNSVG +pair. + +Estimated effort: 3–5 engineering weeks. + +### Phase 2: device confidence + +Add bare and Expo fixtures, iOS and Android release builds, a platform-neutral +definition corpus, screenshot/geometry comparison, VoiceOver/TalkBack flows, +binary-size measurement, and sustained interaction benchmarks. + +Estimated effort: 3–5 engineering weeks. + +### Phase 3: broader parity + +Add renderer-neutral motion, native export/share, advanced gesture recipes, +and a Skia renderer only if measured SVG node pressure justifies it. Expand the +supported version matrix from evidence. + +Estimated effort: 4–10 engineering weeks, strongly dependent on motion, +accessibility, and dense-data requirements. + +An honest SVG-native MVP is therefore roughly 6–10 weeks. Broad parity with +the current web product is closer to 10–20 weeks. These are engineering ranges, +not schedule commitments. + +## Recommendation + +Proceed to Phase 1 if a real React Native product is planned. The architecture +is sound and the JavaScript cost is reasonable for a charting package. Keep the +package private if the immediate goal is only optional ecosystem coverage. + +Do not start a NativeScript adapter in parallel. The earlier +[native platform support spike](./NATIVE-PLATFORM-SUPPORT-SPIKE.md) remains the +architecture comparison; this proof increases confidence specifically for +React Native because its runtime, Metro pipeline, SVG implementation, and +interaction surface were exercised. + +## Primary platform references + +- [React Native 0.86 release](https://reactnative.dev/blog/2026/06/11/react-native-0.86) +- [React Native version support status](https://reactnative.dev/versions.html) +- [React Native layout events](https://reactnative.dev/docs/layoutevent) +- [React Native accessibility](https://reactnative.dev/docs/accessibility) +- [`react-native-svg` support and compatibility](https://github.com/software-mansion/react-native-svg) +- [Metro package exports and the `react-native` condition](https://metrobundler.dev/docs/package-exports/) diff --git a/benchmarks/entries/charts-react-native-line.ts b/benchmarks/entries/charts-react-native-line.ts new file mode 100644 index 00000000..88ab0a3d --- /dev/null +++ b/benchmarks/entries/charts-react-native-line.ts @@ -0,0 +1,11 @@ +import { scaleLinear } from 'd3-scale' +import { lineY } from '@tanstack/charts/line' +import { defineChart } from '@tanstack/charts/scene' + +export { Chart } from '@tanstack/react-native-charts' + +export const definition = defineChart({ + marks: [lineY([4, 9, 7])], + x: { scale: scaleLinear().domain([0, 2]) }, + y: { scale: scaleLinear().domain([0, 10]) }, +}) diff --git a/benchmarks/entries/charts-react-native-tooltip.ts b/benchmarks/entries/charts-react-native-tooltip.ts new file mode 100644 index 00000000..bc8b2df9 --- /dev/null +++ b/benchmarks/entries/charts-react-native-tooltip.ts @@ -0,0 +1,2 @@ +export { Chart } from '@tanstack/react-native-charts' +export { tooltip } from '@tanstack/react-native-charts/tooltip' diff --git a/benchmarks/entries/charts-react-native.ts b/benchmarks/entries/charts-react-native.ts new file mode 100644 index 00000000..c7629ddd --- /dev/null +++ b/benchmarks/entries/charts-react-native.ts @@ -0,0 +1 @@ +export { Chart } from '@tanstack/react-native-charts' diff --git a/examples/charts-react-native/App.tsx b/examples/charts-react-native/App.tsx new file mode 100644 index 00000000..b4ce407e --- /dev/null +++ b/examples/charts-react-native/App.tsx @@ -0,0 +1,67 @@ +import * as React from 'react' +import { SafeAreaView, Text, View } from 'react-native' +import { scaleLinear } from 'd3-scale' +import { lineY } from '@tanstack/charts/line' +import { defineChart } from '@tanstack/charts/scene' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' + +const data = [ + { month: 1, revenue: 12 }, + { month: 2, revenue: 18 }, + { month: 3, revenue: 15 }, + { month: 4, revenue: 26 }, + { month: 5, revenue: 31 }, +] + +const definition = defineChart( + { + marks: [ + lineY(data, { + x: 'month', + y: 'revenue', + stroke: 'var(--revenue, #2563eb)', + strokeWidth: 3, + points: true, + }), + ], + x: { + label: 'Month', + scale: scaleLinear().domain([1, 5]), + }, + y: { + label: 'Revenue', + grid: true, + scale: scaleLinear().domain([0, 35]), + }, + }, + { + focus: 'nearest-x', + tooltip: { use: tooltip, sticky: true }, + }, +) + +export default function App() { + return ( + + + ( + + {defaultBody} + {pinned ? ( + + Pinned + + ) : null} + + )} + /> + + + ) +} diff --git a/examples/charts-react-native/app.json b/examples/charts-react-native/app.json new file mode 100644 index 00000000..af4d3ea3 --- /dev/null +++ b/examples/charts-react-native/app.json @@ -0,0 +1,4 @@ +{ + "name": "ChartsNativePoc", + "displayName": "Charts Native POC" +} diff --git a/examples/charts-react-native/babel.config.cjs b/examples/charts-react-native/babel.config.cjs new file mode 100644 index 00000000..3e0218e6 --- /dev/null +++ b/examples/charts-react-native/babel.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:@react-native/babel-preset'], +} diff --git a/examples/charts-react-native/index.blank.js b/examples/charts-react-native/index.blank.js new file mode 100644 index 00000000..d5f656f5 --- /dev/null +++ b/examples/charts-react-native/index.blank.js @@ -0,0 +1,9 @@ +import * as React from 'react' +import { AppRegistry, View } from 'react-native' +import { name as appName } from './app.json' + +function BlankApp() { + return React.createElement(View) +} + +AppRegistry.registerComponent(appName, () => BlankApp) diff --git a/examples/charts-react-native/index.core.js b/examples/charts-react-native/index.core.js new file mode 100644 index 00000000..98759e74 --- /dev/null +++ b/examples/charts-react-native/index.core.js @@ -0,0 +1,23 @@ +import * as React from 'react' +import { AppRegistry, View } from 'react-native' +import { scaleLinear } from 'd3-scale' +import { lineY } from '@tanstack/charts/line' +import { createChartRuntime } from '@tanstack/charts/runtime' +import { defineChart } from '@tanstack/charts/scene' +import { name as appName } from './app.json' + +const definition = defineChart({ + marks: [lineY([4, 9, 7])], + x: { scale: scaleLinear().domain([0, 2]) }, + y: { scale: scaleLinear().domain([0, 10]) }, +}) +const runtime = createChartRuntime() +const scene = runtime.render(definition, { width: 320, height: 240 }) + +function CoreApp() { + return React.createElement(View, { + accessibilityLabel: `${scene.points.length} chart points`, + }) +} + +AppRegistry.registerComponent(appName, () => CoreApp) diff --git a/examples/charts-react-native/index.js b/examples/charts-react-native/index.js new file mode 100644 index 00000000..33fbb360 --- /dev/null +++ b/examples/charts-react-native/index.js @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native' +import App from './App' +import { name as appName } from './app.json' + +AppRegistry.registerComponent(appName, () => App) diff --git a/examples/charts-react-native/index.svg.js b/examples/charts-react-native/index.svg.js new file mode 100644 index 00000000..0e7e94f3 --- /dev/null +++ b/examples/charts-react-native/index.svg.js @@ -0,0 +1,23 @@ +import * as React from 'react' +import { AppRegistry, View } from 'react-native' +import { Circle, Svg } from 'react-native-svg' +import { name as appName } from './app.json' + +function SvgApp() { + return React.createElement( + View, + null, + React.createElement( + Svg, + { width: 100, height: 100 }, + React.createElement(Circle, { + cx: 50, + cy: 50, + r: 20, + fill: '#2563eb', + }), + ), + ) +} + +AppRegistry.registerComponent(appName, () => SvgApp) diff --git a/examples/charts-react-native/metro.config.cjs b/examples/charts-react-native/metro.config.cjs new file mode 100644 index 00000000..51160f83 --- /dev/null +++ b/examples/charts-react-native/metro.config.cjs @@ -0,0 +1,14 @@ +const path = require('node:path') +const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config') + +const workspaceRoot = path.resolve(__dirname, '../..') + +module.exports = mergeConfig(getDefaultConfig(__dirname), { + watchFolders: [workspaceRoot], + resolver: { + nodeModulesPaths: [ + path.resolve(__dirname, 'node_modules'), + path.resolve(workspaceRoot, 'node_modules'), + ], + }, +}) diff --git a/examples/charts-react-native/package.json b/examples/charts-react-native/package.json new file mode 100644 index 00000000..e2ad3e6d --- /dev/null +++ b/examples/charts-react-native/package.json @@ -0,0 +1,30 @@ +{ + "name": "@charts-poc/react-native-example", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "bundle:android": "react-native bundle --entry-file index.js --platform android --dev false --minify true --bundle-output ../../.bundle-output/react-native-chart.android.js --sourcemap-output ../../.bundle-output/react-native-chart.android.map", + "bundle:ios": "react-native bundle --entry-file index.js --platform ios --dev false --minify true --bundle-output ../../.bundle-output/react-native-chart.ios.js --sourcemap-output ../../.bundle-output/react-native-chart.ios.map", + "start": "react-native start" + }, + "dependencies": { + "@tanstack/charts": "workspace:*", + "@tanstack/react-native-charts": "workspace:*", + "d3-scale": "4.0.2", + "react": "19.2.3", + "react-native": "0.86.0", + "react-native-svg": "15.15.5" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/runtime": "^7.25.0", + "@react-native-community/cli": "20.1.0", + "@react-native/babel-preset": "0.86.0", + "@react-native/metro-config": "0.86.0", + "@react-native/typescript-config": "0.86.0" + }, + "engines": { + "node": ">=22.11.0" + } +} diff --git a/examples/charts-react-native/tsconfig.json b/examples/charts-react-native/tsconfig.json new file mode 100644 index 00000000..e4414983 --- /dev/null +++ b/examples/charts-react-native/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@react-native/typescript-config", + "compilerOptions": { + "lib": ["es2022"], + "types": ["react", "react-native"] + }, + "include": ["App.tsx"], + "exclude": ["node_modules"] +} diff --git a/examples/charts-react-native/tsconfig.strict.json b/examples/charts-react-native/tsconfig.strict.json new file mode 100644 index 00000000..8c174d9c --- /dev/null +++ b/examples/charts-react-native/tsconfig.strict.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "skipLibCheck": false + } +} diff --git a/package.json b/package.json index d2f1c8f8..ce317adf 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "conformance:quick": "node scripts/compare-plot-catalog.mjs --profile=quick", "conformance:size": "node scripts/compare-plot-catalog.mjs --size-only", "performance": "node scripts/measure-rendering.mjs", + "react-native:poc:bundle": "node scripts/measure-react-native-poc.mjs", + "react-native:poc:types": "node scripts/check-react-native-types.mjs", "package:check": "nx run charts-workspace:package-check", "release:artifacts": "nx run charts-workspace:release-artifacts", "release:check": "node scripts/publish-release.mjs --check", @@ -72,6 +74,7 @@ "@tanstack/charts-d3": "workspace:*", "@tanstack/charts-scales": "workspace:*", "@tanstack/octane-charts": "workspace:*", + "@tanstack/react-native-charts": "workspace:*", "@tanstack/react-charts": "workspace:*", "@types/d3-array": "^3.2.2", "@types/d3-brush": "^3.0.6", diff --git a/packages/charts-core/src/reconcile.test.ts b/packages/charts-core/src/reconcile.test.ts index 9fe0fc2e..a17e1cea 100644 --- a/packages/charts-core/src/reconcile.test.ts +++ b/packages/charts-core/src/reconcile.test.ts @@ -142,7 +142,7 @@ describe('keyed SVG reconciliation', () => { const cancelFrame = vi .spyOn(window, 'cancelAnimationFrame') .mockImplementation((handle) => { - callbacks.delete(handle) + if (typeof handle === 'number') callbacks.delete(handle) }) reconcileChartSvg( container, diff --git a/packages/react-native-charts/LICENSE b/packages/react-native-charts/LICENSE new file mode 100644 index 00000000..cce7e258 --- /dev/null +++ b/packages/react-native-charts/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 TanStack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/react-native-charts/README.md b/packages/react-native-charts/README.md new file mode 100644 index 00000000..fbbb30e8 --- /dev/null +++ b/packages/react-native-charts/README.md @@ -0,0 +1,6 @@ +# React Native Charts host spike + +Experimental React Native host for the shared `@tanstack/charts` definition, +runtime, and scene graph. It renders with `react-native-svg`. + +This package is a proof of concept, not a supported release. diff --git a/packages/react-native-charts/package.json b/packages/react-native-charts/package.json new file mode 100644 index 00000000..aa59b78b --- /dev/null +++ b/packages/react-native-charts/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tanstack/react-native-charts", + "version": "0.0.0", + "private": true, + "license": "MIT", + "type": "module", + "sideEffects": false, + "exports": { + ".": "./src/index.ts", + "./tooltip": "./src/tooltip-entry.ts" + }, + "dependencies": { + "@tanstack/charts": "workspace:*" + }, + "peerDependencies": { + "react": "^19.2.3", + "react-native": "^0.86.0", + "react-native-svg": "^15.15.5" + } +} diff --git a/packages/react-native-charts/src/Chart.test.tsx b/packages/react-native-charts/src/Chart.test.tsx new file mode 100644 index 00000000..64395a26 --- /dev/null +++ b/packages/react-native-charts/src/Chart.test.tsx @@ -0,0 +1,166 @@ +import * as React from 'react' +import { renderToStaticMarkup } from 'react-dom/server' +import { scaleLinear } from 'd3-scale' +import { describe, expect, it, vi } from 'vitest' +import { lineY } from '@tanstack/charts/line' +import { defineChart } from '@tanstack/charts/scene' +import { Chart } from './Chart' +import { + tooltip, + type NativeChartTooltipComponent, + type NativeChartTooltipExtension, +} from './tooltip-entry' + +vi.mock('react-native', () => ({ + Text: 'span', + View: 'div', +})) + +vi.mock('react-native-svg', () => ({ + Circle: 'circle', + ClipPath: 'clipPath', + Defs: 'defs', + G: 'g', + Line: 'line', + LinearGradient: 'linearGradient', + Path: 'path', + Rect: 'rect', + Stop: 'stop', + Svg: 'svg', + Text: 'text', +})) + +const data = [ + { month: 1, value: 8 }, + { month: 2, value: 12 }, +] +const definition = defineChart( + { + marks: [ + lineY(data, { + x: 'month', + y: 'value', + stroke: 'var(--series, #2563eb)', + points: true, + }), + ], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + }, + { tooltip: { use: tooltip, sticky: true } }, +) + +describe('React Native Chart', () => { + it('compiles a shared definition directly into native SVG components', () => { + const markup = renderToStaticMarkup( + , + ) + + expect(markup).toContain(' { + const markup = renderToStaticMarkup( + , + ) + + expect(markup).not.toContain(' { + const foreignDefinition = defineChart( + { + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + }, + { + tooltip: { + id: 'foreign-tooltip', + create: () => undefined, + }, + }, + ) + + expect(() => + renderToStaticMarkup( + , + ), + ).toThrow('tooltip extension from @tanstack/react-native-charts/tooltip') + }) + + it('creates branded native tooltip extensions without singleton identity', () => { + const CustomTooltip: NativeChartTooltipComponent = () => null + const create = vi.fn(() => CustomTooltip) + const customTooltip: NativeChartTooltipExtension = { + id: 'custom-native-tooltip', + __chartExtensionType: 'tooltip', + __nativeChartHost: 'react-native', + create, + } + const customDefinition = defineChart( + { + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + }, + { tooltip: { use: customTooltip, sticky: true } }, + ) + + renderToStaticMarkup( + , + ) + + expect(create).toHaveBeenCalledOnce() + }) + + it('rejects browser tooltip portal extensions', () => { + const portalDefinition = defineChart( + { + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + }, + { + tooltip: { + use: tooltip, + portal: { + id: 'browser-portal', + create: () => undefined, + }, + }, + }, + ) + + expect(() => + renderToStaticMarkup( + , + ), + ).toThrow('do not support browser tooltip portal extensions') + }) +}) diff --git a/packages/react-native-charts/src/Chart.tsx b/packages/react-native-charts/src/Chart.tsx new file mode 100644 index 00000000..f45057cd --- /dev/null +++ b/packages/react-native-charts/src/Chart.tsx @@ -0,0 +1,435 @@ +import * as React from 'react' +import type { + AccessibilityActionEvent, + ColorValue, + GestureResponderEvent, + LayoutChangeEvent, + StyleProp, + ViewStyle, +} from 'react-native' +import { View } from 'react-native' +import { createChartRuntime } from '@tanstack/charts/runtime' +import type { + ChartDefinition, + ChartPoint, + ChartScene, + ChartTextMeasurer, + ChartTooltipExtensionToken, + ChartTooltipInput, + ChartTooltipOptions, + ChartTooltipPosition, + ChartValue, +} from '@tanstack/charts/types' +import { NativeChartFocusOverlay } from './FocusOverlay' +import { + adjacentFocusPoint, + createNativeChartFocusModel, + samePointList, +} from './interaction' +import { resolveNativePaint, type NativePaintResolver } from './paint' +import { NativeChartScene } from './SvgScene' +import type { + NativeChartTooltipComponent, + NativeChartTooltipExtension, + NativeChartTooltipRenderContext, +} from './Tooltip' + +export interface NativeChartRenderContext< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +> { + scene: ChartScene +} + +export interface ChartProps< + TDatum = unknown, + TXValue extends ChartValue = ChartValue, + TYValue extends ChartValue = ChartValue, +> { + definition: ChartDefinition + accessibilityLabel: string + accessibilityHint?: string + width?: number + height?: number + aspectRatio?: number + style?: StyleProp + color?: ColorValue + focusFill?: ColorValue + fontFamily?: string + idPrefix?: string + testID?: string + measureText?: ChartTextMeasurer + resolvePaint?: NativePaintResolver + onFocusChange?: (point: ChartPoint | null) => void + onFocusGroupChange?: ( + points: readonly ChartPoint[], + ) => void + onSelect?: (point: ChartPoint | null) => void + onRender?: ( + context: NativeChartRenderContext, + ) => void + renderTooltip?: ( + context: NativeChartTooltipRenderContext, + ) => React.ReactNode +} + +export function Chart< + TDatum, + TXValue extends ChartValue = ChartValue, + TYValue extends ChartValue = ChartValue, +>({ + definition, + accessibilityLabel, + accessibilityHint, + width, + height, + aspectRatio, + style, + color = '#111827', + focusFill = '#ffffff', + fontFamily, + idPrefix: idPrefixOption, + testID, + measureText, + resolvePaint = resolveNativePaint, + onFocusChange, + onFocusGroupChange, + onSelect, + onRender, + renderTooltip, +}: ChartProps) { + const generatedId = React.useId() + const idPrefix = + idPrefixOption ?? + `ts-chart-${generatedId.replaceAll(/[^a-zA-Z0-9_-]/g, '')}` + const runtime = React.useMemo( + () => createChartRuntime(), + [], + ) + const [layout, setLayout] = React.useState<{ + width: number + height: number + } | null>(null) + const resolvedAspectRatio = positiveFinite(aspectRatio) + const explicitWidth = positiveFinite(width) + const explicitHeight = positiveFinite(height) + const sceneSize = resolveSceneSize( + explicitWidth, + explicitHeight, + resolvedAspectRatio, + layout, + ) + const scene = React.useMemo( + () => + sceneSize ? runtime.render(definition, sceneSize, { measureText }) : null, + [definition, measureText, runtime, sceneSize?.height, sceneSize?.width], + ) + const focusModel = React.useMemo( + () => (scene ? createNativeChartFocusModel(scene, definition) : null), + [definition, scene], + ) + const [focusedPoints, setFocusedPoints] = React.useState< + readonly ChartPoint[] + >([]) + const focusedPointsRef = React.useRef(focusedPoints) + const [pinnedKey, setPinnedKey] = React.useState(null) + const [pointer, setPointer] = React.useState( + null, + ) + const tooltipInput = React.useMemo( + () => resolveNativeTooltipInput(definition.tooltip), + [definition.tooltip], + ) + const TooltipComponent = tooltipInput?.component + const tooltipOptions = tooltipInput?.options + const sticky = Boolean(tooltipInput) && tooltipOptions?.sticky !== false + const interactive = Boolean(scene?.points.length) + + const commitFocus = React.useCallback( + (points: readonly ChartPoint[]) => { + if (samePointList(points, focusedPointsRef.current)) return + focusedPointsRef.current = points + setFocusedPoints(points) + onFocusChange?.(points[0] ?? null) + onFocusGroupChange?.(points) + }, + [onFocusChange, onFocusGroupChange], + ) + + React.useEffect(() => () => runtime.destroy(), [runtime]) + React.useEffect(() => { + if (scene) onRender?.({ scene }) + }, [onRender, scene]) + React.useEffect(() => { + const previous = focusedPointsRef.current[0] + if (!focusModel || !previous) return + const restored = focusModel.restore(previous) + if (restored) { + commitFocus(focusModel.group(restored)) + } else { + setPinnedKey(null) + commitFocus([]) + } + }, [commitFocus, focusModel]) + React.useEffect(() => { + if (!sticky) setPinnedKey(null) + }, [sticky]) + + const dismiss = React.useCallback(() => { + setPinnedKey(null) + setPointer(null) + commitFocus([]) + }, [commitFocus]) + + const pointAtEvent = React.useCallback( + (event: GestureResponderEvent) => { + if (!scene || !focusModel) return [] + const measuredWidth = layout?.width ?? scene.width + const measuredHeight = layout?.height ?? scene.height + if (measuredWidth <= 0 || measuredHeight <= 0) return [] + const position = { + x: (event.nativeEvent.locationX / measuredWidth) * scene.width, + y: (event.nativeEvent.locationY / measuredHeight) * scene.height, + } + setPointer(position) + return focusModel.resolve(position.x, position.y) + }, + [focusModel, layout?.height, layout?.width, scene], + ) + + const handleResponderGrant = (event: GestureResponderEvent) => { + if (pinnedKey) return + commitFocus(pointAtEvent(event)) + } + const handleResponderMove = (event: GestureResponderEvent) => { + if (pinnedKey) return + commitFocus(pointAtEvent(event)) + } + const handleResponderRelease = (event: GestureResponderEvent) => { + const points = pointAtEvent(event) + const point = points[0] ?? null + if (sticky) setPinnedKey(pinnedKey ? null : (point?.key ?? null)) + commitFocus(points) + onSelect?.(point) + } + const handleResponderTerminate = () => { + if (pinnedKey) return + setPointer(null) + commitFocus([]) + } + const handleLayout = (event: LayoutChangeEvent) => { + const next = event.nativeEvent.layout + if (!positiveFinite(next.width) || !positiveFinite(next.height)) return + setLayout((current) => + current?.width === next.width && current.height === next.height + ? current + : { width: next.width, height: next.height }, + ) + } + + const navigate = (direction: -1 | 1) => { + if (!focusModel) return + const point = adjacentFocusPoint( + focusModel, + focusedPointsRef.current[0] ?? null, + direction, + ) + setPointer(null) + commitFocus(point ? focusModel.group(point) : []) + } + const activate = () => { + const point = focusedPointsRef.current[0] ?? null + if (!point) return + if (sticky) setPinnedKey((current) => (current ? null : point.key)) + onSelect?.(point) + } + const handleAccessibilityAction = (event: AccessibilityActionEvent) => { + switch (event.nativeEvent.actionName) { + case 'increment': + navigate(1) + break + case 'decrement': + navigate(-1) + break + case 'activate': + activate() + break + case 'escape': + dismiss() + break + } + } + const handleFocus = () => { + if (definition.keyboard === false || focusedPointsRef.current.length) return + navigate(1) + } + const focusedPoint = focusedPoints[0] ?? null + + return ( + false} + onResponderGrant={handleResponderGrant} + onResponderMove={handleResponderMove} + onResponderRelease={handleResponderRelease} + onResponderTerminate={handleResponderTerminate} + onResponderTerminationRequest={() => true} + onStartShouldSetResponder={() => interactive} + style={[ + { + position: 'relative', + overflow: 'visible', + width: explicitWidth ?? '100%', + height: + explicitHeight ?? + (resolvedAspectRatio === undefined ? 320 : undefined), + aspectRatio: + explicitHeight === undefined ? resolvedAspectRatio : undefined, + }, + style, + ]} + testID={testID} + > + {scene ? ( + <> + + + {TooltipComponent && focusedPoints.length ? ( + + ) : null} + + ) : null} + + ) +} + +function resolveNativeTooltipInput< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + input: false | ChartTooltipInput | undefined, +): { + component: NativeChartTooltipComponent + options?: ChartTooltipOptions +} | null { + if (!input) return null + const extension = 'create' in input ? input : input.use + if (!isNativeTooltipExtension(extension)) { + throw new Error( + 'React Native charts require a tooltip extension from @tanstack/react-native-charts/tooltip.', + ) + } + if (!('create' in input) && input.portal) { + throw new Error( + 'React Native charts do not support browser tooltip portal extensions.', + ) + } + return { + component: extension.create(), + options: 'create' in input ? undefined : input, + } +} + +function isNativeTooltipExtension( + extension: ChartTooltipExtensionToken, +): extension is NativeChartTooltipExtension { + const candidate = extension as Partial + return ( + candidate.__chartExtensionType === 'tooltip' && + candidate.__nativeChartHost === 'react-native' + ) +} + +function resolveSceneSize( + width: number | undefined, + height: number | undefined, + aspectRatio: number | undefined, + layout: { width: number; height: number } | null, +) { + const resolvedWidth = width ?? layout?.width + if (!resolvedWidth) return null + const resolvedHeight = + height ?? + (aspectRatio === undefined + ? (layout?.height ?? (width === undefined ? undefined : 320)) + : resolvedWidth / aspectRatio) + return resolvedHeight + ? { width: resolvedWidth, height: resolvedHeight } + : null +} + +function positiveFinite(value: number | undefined) { + return value !== undefined && Number.isFinite(value) && value > 0 + ? value + : undefined +} + +function describePoint(point: ChartPoint) { + return [ + point.groupLabel, + formatValue(point.xValue), + formatValue(point.yValue), + ] + .filter(Boolean) + .join(', ') +} + +function formatValue(value: ChartValue) { + return value instanceof Date + ? Number.isNaN(+value) + ? 'Invalid Date' + : value.toISOString().replace('T00:00:00.000Z', '') + : typeof value === 'number' + ? value.toLocaleString() + : String(value) +} diff --git a/packages/react-native-charts/src/FocusOverlay.tsx b/packages/react-native-charts/src/FocusOverlay.tsx new file mode 100644 index 00000000..1e2e3869 --- /dev/null +++ b/packages/react-native-charts/src/FocusOverlay.tsx @@ -0,0 +1,64 @@ +import * as React from 'react' +import type { ColorValue } from 'react-native' +import { Circle, Svg } from 'react-native-svg' +import type { ChartPoint, ChartValue } from '@tanstack/charts/types' +import { resolveNativeSolidPaint, type NativePaintResolver } from './paint' + +export interface NativeChartFocusOverlayProps< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +> { + width: number + height: number + points: readonly ChartPoint[] + color: ColorValue + fill: ColorValue + resolvePaint: NativePaintResolver +} + +export function NativeChartFocusOverlay< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>({ + width, + height, + points, + color, + fill, + resolvePaint, +}: NativeChartFocusOverlayProps) { + if (!points.length) return null + return ( + + {points.map((point, index) => ( + + ))} + + ) +} + +const absoluteFill = { + position: 'absolute', + left: 0, + top: 0, + right: 0, + bottom: 0, +} as const diff --git a/packages/react-native-charts/src/SvgScene.test.tsx b/packages/react-native-charts/src/SvgScene.test.tsx new file mode 100644 index 00000000..fbed133c --- /dev/null +++ b/packages/react-native-charts/src/SvgScene.test.tsx @@ -0,0 +1,165 @@ +import * as React from 'react' +import { renderToStaticMarkup } from 'react-dom/server' +import { describe, expect, it, vi } from 'vitest' +import type { ChartScene, SceneNode } from '@tanstack/charts/types' +import { resolveNativePaint } from './paint' +import { NativeChartScene, resolveNativeLineJoin } from './SvgScene' + +vi.mock('react-native-svg', () => ({ + Circle: 'circle', + ClipPath: 'clipPath', + Defs: 'defs', + G: 'g', + Line: 'line', + LinearGradient: 'linearGradient', + Path: 'path', + Rect: 'rect', + Stop: 'stop', + Svg: 'svg', + Text: 'text', +})) + +describe('React Native SVG scene renderer', () => { + it('maps every scene primitive, gradients, clipping, and authored paths', () => { + const markup = renderToStaticMarkup( + , + ) + + expect(markup).toContain(' { + expect(resolveNativeLineJoin('arcs')).toBe('round') + expect(resolveNativeLineJoin('miter-clip')).toBe('miter') + expect(resolveNativeLineJoin('round')).toBe('round') + }) +}) + +function scene(): ChartScene { + const nodes: SceneNode[] = [ + { + kind: 'group', + key: 'translated-grid', + translateX: 10, + translateY: 12, + clip: { x: 0, y: 0, width: 80, height: 60 }, + style: { + stroke: 'currentColor', + strokeOpacity: 0.4, + strokeWidth: 3, + strokeDasharray: '2 4', + }, + children: [{ kind: 'rule', key: 'rule', x1: 0, y1: 0, x2: 30, y2: 30 }], + }, + { + kind: 'polyline', + key: 'line', + points: [ + [2, 4], + [20, 30], + ], + style: { fill: 'none', stroke: '#abcdef', lineJoin: 'arcs' }, + }, + { + kind: 'polyline', + key: 'curved-line', + points: [], + path: 'M0,0C10,20,20,20,30,0', + style: { + fill: 'none', + stroke: '#334455', + lineJoin: 'miter-clip', + }, + }, + { + kind: 'area', + key: 'area', + points: [ + [0, 20], + [20, 0], + [40, 20], + ], + style: { fill: 'url(#fill)' }, + }, + { + kind: 'dot', + key: 'dot', + x: 50, + y: 30, + radius: 5, + style: { fill: 'var(--dot, #ff0000)' }, + }, + { + kind: 'rect', + key: 'rect', + x: 60, + y: 10, + width: 20, + height: 30, + radius: 4, + style: { fill: '#00ff00' }, + }, + { + kind: 'label', + key: 'label', + x: 40, + y: 50, + text: 'Native', + anchor: 'middle', + baseline: 'middle', + rotate: -30, + fontSize: 12, + fontWeight: 600, + style: { fill: '#111111' }, + }, + ] + return { + width: 100, + height: 60, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + chart: { x: 0, y: 0, width: 100, height: 60 }, + nodes, + points: [], + scales: {}, + colors: { + type: 'ordinal', + domain: [], + range: [], + map: () => '#2563eb', + }, + gradients: [ + { + id: 'fill', + stops: [ + { offset: 0, color: '#2563eb', opacity: 0.2 }, + { offset: 1, color: '#2563eb' }, + ], + }, + ], + theme: { + foreground: '#111111', + muted: '#666666', + grid: '#999999', + background: '#f8fafc', + palette: ['#2563eb'], + }, + } +} diff --git a/packages/react-native-charts/src/SvgScene.tsx b/packages/react-native-charts/src/SvgScene.tsx new file mode 100644 index 00000000..e0a4f348 --- /dev/null +++ b/packages/react-native-charts/src/SvgScene.tsx @@ -0,0 +1,287 @@ +import * as React from 'react' +import type { ColorValue } from 'react-native' +import { + Circle, + ClipPath, + Defs, + G, + Line, + LinearGradient, + Path, + Rect, + Stop, + Svg, + Text, +} from 'react-native-svg' +import type { CommonPathProps, Linejoin } from 'react-native-svg' +import type { + ChartScene, + SceneGroup, + SceneNode, + SceneStyle, +} from '@tanstack/charts/types' +import type { NativePaintResolver } from './paint' + +export interface NativeChartSceneProps { + scene: ChartScene + color: ColorValue + fontFamily?: string + idPrefix: string + resolvePaint: NativePaintResolver +} + +export const NativeChartScene = React.memo(function NativeChartScene({ + scene, + color, + fontFamily, + idPrefix, + resolvePaint, +}: NativeChartSceneProps) { + const gradientIds = React.useMemo( + () => new Set(scene.gradients.map((gradient) => gradient.id)), + [scene.gradients], + ) + const paint = React.useCallback( + (value: string) => + resolveScenePaint(value, gradientIds, idPrefix, resolvePaint, color), + [color, gradientIds, idPrefix, resolvePaint], + ) + + return ( + + {scene.gradients.length ? ( + + {scene.gradients.map((gradient) => ( + + {gradient.stops.map((stop, index) => ( + + ))} + + ))} + + ) : null} + {scene.theme.background === 'transparent' ? null : ( + + )} + {scene.nodes.map((node) => renderSceneNode(node, idPrefix, paint))} + + ) +}) + +function renderSceneNode( + node: SceneNode, + idPrefix: string, + paint: (value: string) => ColorValue, +): React.ReactNode { + const style = nativeSceneStyle(node.style, paint) + + switch (node.kind) { + case 'group': + return renderGroup(node, idPrefix, paint, style) + case 'rule': + return ( + + ) + case 'polyline': + return ( + + ) + case 'area': + return ( + + ) + case 'dot': + return ( + + ) + case 'rect': + return ( + + ) + case 'label': + return ( + + {node.text} + + ) + } +} + +function renderGroup( + node: SceneGroup, + idPrefix: string, + paint: (value: string) => ColorValue, + style: ReturnType, +) { + const clipId = node.clip + ? scopedId(idPrefix, `clip-${stableId(node.key)}`) + : undefined + const transform = + node.translateX === undefined && node.translateY === undefined + ? undefined + : `translate(${node.translateX ?? 0} ${node.translateY ?? 0})` + + return ( + + {node.clip && clipId ? ( + + + + + + ) : null} + {node.children.map((child) => renderSceneNode(child, idPrefix, paint))} + + ) +} + +function nativeSceneStyle( + style: SceneStyle | undefined, + paint: (value: string) => ColorValue, +): CommonPathProps & { opacity?: number } { + if (!style) return {} + return { + fill: style.fill === undefined ? undefined : paint(style.fill), + fillOpacity: style.fillOpacity, + stroke: style.stroke === undefined ? undefined : paint(style.stroke), + strokeOpacity: style.strokeOpacity, + strokeWidth: style.strokeWidth, + opacity: style.opacity, + strokeLinecap: style.lineCap, + strokeLinejoin: resolveNativeLineJoin(style.lineJoin), + strokeDasharray: style.strokeDasharray, + } +} + +export function resolveNativeLineJoin( + lineJoin: SceneStyle['lineJoin'], +): Linejoin | undefined { + if (lineJoin === 'arcs') return 'round' + if (lineJoin === 'miter-clip') return 'miter' + return lineJoin +} + +function resolveScenePaint( + value: string, + gradientIds: ReadonlySet, + idPrefix: string, + resolvePaint: NativePaintResolver, + color: ColorValue, +) { + const match = /^url\(#([^)]+)\)$/.exec(value) + const id = match?.[1] + if (id && gradientIds.has(id)) return `url(#${scopedId(idPrefix, id)})` + return resolvePaint(value, { color }) +} + +function pointsPath( + points: readonly (readonly [number, number])[], + close: boolean, +) { + return `${points + .map(([x, y], index) => `${index === 0 ? 'M' : 'L'}${x},${y}`) + .join('')}${close ? 'Z' : ''}` +} + +function scopedId(prefix: string, id: string) { + return prefix ? `${prefix}-${sanitizeId(id)}` : sanitizeId(id) +} + +function sanitizeId(value: string) { + return value.replaceAll(/[^a-zA-Z0-9_-]/g, '') +} + +function stableId(value: string) { + let hash = 2166136261 + for (let index = 0; index < value.length; index += 1) { + hash = Math.imul(hash ^ value.charCodeAt(index), 16777619) + } + return (hash >>> 0).toString(36) +} + +function percent(value: number) { + return `${Math.max(0, Math.min(1, value)) * 100}%` +} diff --git a/packages/react-native-charts/src/Tooltip.test.ts b/packages/react-native-charts/src/Tooltip.test.ts new file mode 100644 index 00000000..a3f53166 --- /dev/null +++ b/packages/react-native-charts/src/Tooltip.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, it, vi } from 'vitest' +import type { ChartPoint, ChartScene } from '@tanstack/charts/types' +import { createNativeTooltipContent, placeNativeTooltip } from './Tooltip' + +vi.mock('react-native', () => ({ + Text: 'span', + View: 'div', +})) + +describe('native tooltip model', () => { + it('builds the supported shared-axis default content', () => { + const points = [point('alpha', 'Alpha', 3), point('beta', 'Beta', 7)] + + expect(createNativeTooltipContent(points, scene(points))).toEqual({ + title: 'x: 1', + rows: [ + { label: 'Alpha', value: '3', color: '#2563eb' }, + { label: 'Beta', value: '7', color: '#f97316' }, + ], + }) + }) + + it('chooses and clamps a placement inside the native layout boundary', () => { + expect( + placeNativeTooltip( + { x: 4, y: 4 }, + { width: 20, height: 10 }, + { width: 100, height: 60 }, + 'top', + 10, + ), + ).toEqual({ left: 8, top: 8, placement: 'top' }) + }) +}) + +function point( + key: string, + groupLabel: string, + yValue: number, +): ChartPoint { + return { + key, + markId: 'series', + group: key, + groupLabel, + datum: null, + datumIndex: 0, + xValue: 1, + yValue, + x: 20, + y: yValue * 4, + color: key === 'alpha' ? '#2563eb' : '#f97316', + } +} + +function scene( + points: readonly ChartPoint[], +): ChartScene { + return { + width: 100, + height: 60, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + chart: { x: 0, y: 0, width: 100, height: 60 }, + nodes: [], + points, + scales: {}, + colors: { + type: 'ordinal', + domain: ['alpha', 'beta'], + range: ['#2563eb', '#f97316'], + map: (value) => (value === 'beta' ? '#f97316' : '#2563eb'), + }, + gradients: [], + theme: { + foreground: '#111827', + muted: '#6b7280', + grid: '#d1d5db', + background: 'transparent', + palette: ['#2563eb', '#f97316'], + }, + } +} diff --git a/packages/react-native-charts/src/Tooltip.tsx b/packages/react-native-charts/src/Tooltip.tsx new file mode 100644 index 00000000..e08920fa --- /dev/null +++ b/packages/react-native-charts/src/Tooltip.tsx @@ -0,0 +1,507 @@ +import * as React from 'react' +import type { + ColorValue, + LayoutChangeEvent, + TextStyle, + ViewStyle, +} from 'react-native' +import { Text, View } from 'react-native' +import type { + ChartPoint, + ChartScene, + ChartTooltipContent, + ChartTooltipContentContext, + ChartTooltipExtensionToken, + ChartTooltipOptions, + ChartTooltipPlacement, + ChartTooltipPosition, + ChartValue, +} from '@tanstack/charts/types' +import { resolveNativeSolidPaint, type NativePaintResolver } from './paint' + +export interface NativeChartTooltipRenderContext< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +> { + points: readonly ChartPoint[] + content: ChartTooltipContent | string + pinned: boolean + dismiss: () => void + defaultBody: React.ReactNode +} + +export interface NativeChartTooltipProps< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +> { + scene: ChartScene + width: number + height: number + points: readonly ChartPoint[] + pointer: ChartTooltipPosition | null + options?: ChartTooltipOptions + pinned: boolean + color: ColorValue + resolvePaint: NativePaintResolver + dismiss: () => void + render?: ( + context: NativeChartTooltipRenderContext, + ) => React.ReactNode +} + +export function NativeChartTooltip< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>({ + scene, + width, + height, + points: unorderedPoints, + pointer, + options, + pinned, + color, + resolvePaint, + dismiss, + render, +}: NativeChartTooltipProps) { + const [size, setSize] = React.useState({ width: 0, height: 0 }) + const points = React.useMemo( + () => orderTooltipPoints(unorderedPoints, scene, options?.sort), + [options?.sort, scene, unorderedPoints], + ) + const point = points[0] + if (!point) return null + const content = createNativeTooltipContent(points, scene, options) + const sceneAnchor = resolveTooltipAnchor( + point, + points, + scene, + pointer, + options, + ) + const anchor = { + x: (sceneAnchor.x / scene.width) * width, + y: (sceneAnchor.y / scene.height) * height, + } + const position = placeNativeTooltip( + anchor, + size, + { width, height }, + options?.placement, + options?.offset, + ) + const defaultBody = ( + + ) + const body = + render?.({ points, content, pinned, dismiss, defaultBody }) ?? defaultBody + const accessibilityLabel = tooltipAccessibilityLabel(content) + const handleLayout = (event: LayoutChangeEvent) => { + const next = event.nativeEvent.layout + if (next.width !== size.width || next.height !== size.height) { + setSize({ width: next.width, height: next.height }) + } + } + + return ( + pinned} + pointerEvents={pinned ? 'auto' : 'none'} + style={[tooltipStyle, { left: position.left, top: position.top }]} + > + {body} + + ) +} + +export type NativeChartTooltipComponent = typeof NativeChartTooltip + +export interface NativeChartTooltipExtension extends ChartTooltipExtensionToken { + readonly __chartExtensionType: 'tooltip' + readonly __nativeChartHost: 'react-native' + create: () => NativeChartTooltipComponent +} + +export const tooltip: NativeChartTooltipExtension = { + id: 'react-native-tooltip', + __chartExtensionType: 'tooltip', + __nativeChartHost: 'react-native', + create: () => NativeChartTooltip, +} + +function DefaultNativeTooltipBody({ + content, + color, + resolvePaint, +}: { + content: ChartTooltipContent | string + color: ColorValue + resolvePaint: NativePaintResolver +}) { + if (typeof content === 'string') { + return {content} + } + return ( + + {content.title ? ( + + {content.color ? ( + + ) : null} + {content.title} + + ) : null} + {content.rows.map((row, index) => ( + + + + {row.label} + + + {row.value} + + + ))} + + ) +} + +export function createNativeTooltipContent< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + points: readonly ChartPoint[], + scene: ChartScene, + options?: ChartTooltipOptions, +): ChartTooltipContent | string { + const point = points[0] + if (!point) return { rows: [] } + const context = createTooltipContentContext(scene) + const content = options?.content?.(points, context) + if (content !== undefined) return content + const formatted = options?.formatGroup?.(points) ?? options?.format?.(point) + if (formatted !== undefined) return formatted + + const sharedX = + points.length > 1 && + points.every((candidate) => chartValueEqual(candidate.xValue, point.xValue)) + if (sharedX) { + return { + title: `${context.xLabel}: ${context.formatX(point.xValue)}`, + rows: points.map((candidate) => ({ + label: candidate.groupLabel, + value: context.formatY(candidate.yValue), + color: candidate.color, + })), + } + } + + return { + title: point.group == null ? undefined : point.groupLabel, + color: point.group == null ? undefined : point.color, + rows: [ + { label: context.xLabel, value: context.formatX(point.xValue) }, + { label: context.yLabel, value: context.formatY(point.yValue) }, + ], + } +} + +function createTooltipContentContext( + scene: ChartScene, +): ChartTooltipContentContext { + return { + xLabel: findSceneLabel(scene, 'x-label') ?? 'x', + yLabel: findSceneLabel(scene, 'y-label') ?? 'y', + formatX: formatValue, + formatY: formatValue, + } +} + +function orderTooltipPoints< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + points: readonly ChartPoint[], + scene: ChartScene, + sort: ChartTooltipOptions['sort'], +) { + if (sort === 'focus') return [...points] + if (typeof sort === 'function') return [...points].sort(sort) + return [...points].sort( + (left, right) => + colorOrder(scene, left.group) - colorOrder(scene, right.group), + ) +} + +function colorOrder(scene: ChartScene, group: ChartPoint['group']) { + const index = group == null ? -1 : scene.colors.domain.indexOf(group) + return index < 0 ? Number.MAX_SAFE_INTEGER : index +} + +function findSceneLabel(scene: ChartScene, key: string) { + const axes = scene.nodes.find( + (node) => node.kind === 'group' && node.key === 'axes', + ) + if (axes?.kind !== 'group') return undefined + const label = axes.children.find((node) => node.key === key) + return label?.kind === 'label' ? label.text : undefined +} + +function resolveTooltipAnchor< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + point: ChartPoint, + points: readonly ChartPoint[], + scene: ChartScene, + pointer: ChartTooltipPosition | null, + options?: ChartTooltipOptions, +): ChartTooltipPosition { + const fallback = { x: point.x, y: point.y } + const anchor = options?.anchor ?? 'point' + if (anchor === 'point') return fallback + if (anchor === 'pointer') return pointer ?? fallback + if (anchor === 'group-center') { + const x = points.map((candidate) => candidate.x) + const y = points.map((candidate) => candidate.y) + return { + x: (Math.min(...x) + Math.max(...x)) / 2, + y: (Math.min(...y) + Math.max(...y)) / 2, + } + } + const resolved = anchor(points, { + pointer, + chart: scene.chart, + width: scene.width, + height: scene.height, + }) + return resolved && Number.isFinite(resolved.x) && Number.isFinite(resolved.y) + ? resolved + : fallback +} + +export function placeNativeTooltip( + anchor: ChartTooltipPosition, + tooltip: { width: number; height: number }, + boundary: { width: number; height: number }, + placement: + | 'auto' + | ChartTooltipPlacement + | readonly ChartTooltipPlacement[] + | undefined, + offset: number | undefined, +) { + const edge = 8 + const gap = + offset !== undefined && Number.isFinite(offset) ? Math.max(0, offset) : 10 + const placements = + placement === undefined || placement === 'auto' + ? defaultTooltipPlacements + : Array.isArray(placement) + ? placement.length + ? placement + : defaultTooltipPlacements + : [placement as ChartTooltipPlacement] + const candidates = placements.map((candidate) => + tooltipPlacement(candidate, anchor, tooltip, gap), + ) + let selected = candidates[0]! + let selectedOverflow = overflow(selected, tooltip, boundary, edge) + for (const candidate of candidates) { + const candidateOverflow = overflow(candidate, tooltip, boundary, edge) + if (candidateOverflow === 0) { + selected = candidate + break + } + if (candidateOverflow < selectedOverflow) { + selected = candidate + selectedOverflow = candidateOverflow + } + } + return { + left: clamp( + selected.left, + edge, + Math.max(edge, boundary.width - edge - tooltip.width), + ), + top: clamp( + selected.top, + edge, + Math.max(edge, boundary.height - edge - tooltip.height), + ), + placement: selected.placement, + } +} + +const defaultTooltipPlacements: readonly ChartTooltipPlacement[] = [ + 'top', + 'bottom', + 'right', + 'left', +] + +function tooltipPlacement( + placement: ChartTooltipPlacement, + anchor: ChartTooltipPosition, + tooltip: { width: number; height: number }, + gap: number, +) { + const xDirection = + placement.endsWith('right') || placement === 'right' + ? 1 + : placement.endsWith('left') || placement === 'left' + ? -1 + : 0 + const yDirection = + placement.startsWith('bottom') || placement === 'bottom' + ? 1 + : placement.startsWith('top') || placement === 'top' + ? -1 + : 0 + return { + placement, + left: anchor.x + ((xDirection - 1) * tooltip.width) / 2 + xDirection * gap, + top: anchor.y + ((yDirection - 1) * tooltip.height) / 2 + yDirection * gap, + } +} + +function overflow( + position: { left: number; top: number }, + tooltip: { width: number; height: number }, + boundary: { width: number; height: number }, + edge: number, +) { + return ( + Math.max(0, edge - position.left) + + Math.max(0, position.left + tooltip.width + edge - boundary.width) + + Math.max(0, edge - position.top) + + Math.max(0, position.top + tooltip.height + edge - boundary.height) + ) +} + +function tooltipAccessibilityLabel(content: ChartTooltipContent | string) { + return typeof content === 'string' + ? content + : [ + content.title, + ...content.rows.map((row) => `${row.label}: ${row.value}`), + ] + .filter(Boolean) + .join('\n') +} + +function formatValue(value: ChartValue) { + return value instanceof Date + ? Number.isNaN(+value) + ? 'Invalid Date' + : value.toISOString().replace('T00:00:00.000Z', '') + : typeof value === 'number' + ? value.toLocaleString() + : String(value) +} + +function chartValueEqual(left: ChartValue, right: ChartValue) { + return left instanceof Date && right instanceof Date + ? left.getTime() === right.getTime() + : Object.is(left, right) +} + +function clamp(value: number, minimum: number, maximum: number) { + return Math.max(minimum, Math.min(maximum, value)) +} + +const tooltipStyle: ViewStyle = { + position: 'absolute', + zIndex: 1, + maxWidth: '80%', + paddingHorizontal: 9, + paddingVertical: 7, + borderWidth: 1, + borderColor: 'rgba(17, 24, 39, 0.16)', + borderRadius: 7, + backgroundColor: '#ffffff', + shadowColor: '#000000', + shadowOffset: { width: 0, height: 6 }, + shadowOpacity: 0.14, + shadowRadius: 12, + elevation: 4, +} + +const tooltipTextStyle = { + color: '#111827', + fontSize: 12, + fontWeight: '500', +} as const + +const titleStyle = { + flexDirection: 'row', + alignItems: 'center', + gap: 6, + marginBottom: 4, +} as const + +const titleTextStyle = { + color: '#111827', + fontSize: 12, + fontWeight: '700', +} as const + +const rowStyle = { + flexDirection: 'row', + alignItems: 'center', + gap: 6, +} as const + +const swatchStyle = { + width: 9, + height: 9, + borderRadius: 2, +} as const + +const rowLabelStyle = { + flexGrow: 1, + flexShrink: 1, + color: '#374151', + fontSize: 12, +} as const + +const rowValueStyle: TextStyle = { + color: '#111827', + fontSize: 12, + fontVariant: ['tabular-nums'], +} diff --git a/packages/react-native-charts/src/index.ts b/packages/react-native-charts/src/index.ts new file mode 100644 index 00000000..0d15583a --- /dev/null +++ b/packages/react-native-charts/src/index.ts @@ -0,0 +1,5 @@ +export { Chart } from './Chart' +export type { ChartProps, NativeChartRenderContext } from './Chart' +export type { NativeChartTooltipRenderContext } from './Tooltip' +export type { NativePaintContext, NativePaintResolver } from './paint' +export { resolveNativePaint } from './paint' diff --git a/packages/react-native-charts/src/interaction.test.ts b/packages/react-native-charts/src/interaction.test.ts new file mode 100644 index 00000000..0710d8a0 --- /dev/null +++ b/packages/react-native-charts/src/interaction.test.ts @@ -0,0 +1,125 @@ +import { describe, expect, it } from 'vitest' +import type { + ChartDefinition, + ChartPoint, + ChartScene, +} from '@tanstack/charts/types' +import { adjacentFocusPoint, createNativeChartFocusModel } from './interaction' + +interface Datum { + id: string +} + +describe('native focus model', () => { + it('reuses grouped focus semantics and native accessibility order', () => { + const points = [ + point('alpha-1', 'alpha', 0, 10, 10, 1, 2), + point('beta-1', 'beta', 1, 10, 30, 1, 3), + point('alpha-2', 'alpha', 2, 40, 20, 2, 4), + ] + const model = createNativeChartFocusModel( + chartScene(points), + definition({ focus: 'group-x', maxFocusDistance: 20 }), + ) + + expect(model.resolve(11, 29).map((candidate) => candidate.key)).toEqual([ + 'beta-1', + 'alpha-1', + ]) + expect(adjacentFocusPoint(model, null, 1)?.key).toBe('alpha-1') + expect(adjacentFocusPoint(model, model.navigation[0] ?? null, 1)?.key).toBe( + 'alpha-2', + ) + }) + + it('honors a supplied spatial index for nearest focus', () => { + const points = [point('alpha', 'alpha', 0, 10, 10, 1, 2)] + let calls = 0 + const model = createNativeChartFocusModel( + chartScene(points), + definition({ + spatialIndex: (indexedPoints) => ({ + findNearest() { + calls += 1 + return indexedPoints[0] ?? null + }, + }), + }), + ) + + expect(model.resolve(500, 500)[0]?.key).toBe('alpha') + expect(calls).toBe(1) + }) + + it('restores duplicate keys by datum identity after a scene update', () => { + const datum = { id: 'same' } + const previous = point('duplicate', 'alpha', 0, 10, 10, 1, 2, datum) + const other = point('duplicate', 'alpha', 0, 20, 20, 2, 3, { id: 'same' }) + const restored = point('duplicate', 'alpha', 1, 30, 30, 3, 4, datum) + const model = createNativeChartFocusModel( + chartScene([other, restored]), + definition({}), + ) + + expect(model.restore(previous)).toBe(restored) + }) +}) + +function definition( + options: Partial>, +): ChartDefinition { + return { marks: [], ...options } +} + +function point( + key: string, + group: string, + datumIndex: number, + x: number, + y: number, + xValue: number, + yValue: number, + datum: Datum = { id: key }, +): ChartPoint { + return { + key, + markId: 'series', + group, + groupLabel: group, + datum, + datumIndex, + xValue, + yValue, + x, + y, + color: '#2563eb', + } +} + +function chartScene( + points: readonly ChartPoint[], +): ChartScene { + return { + width: 100, + height: 60, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + chart: { x: 0, y: 0, width: 100, height: 60 }, + nodes: [], + points, + scales: {}, + colors: { + type: 'ordinal', + domain: ['alpha', 'beta'], + range: ['#2563eb', '#f97316'], + map: (value) => (value === 'beta' ? '#f97316' : '#2563eb'), + }, + gradients: [], + theme: { + foreground: '#111827', + muted: '#6b7280', + grid: '#d1d5db', + background: 'transparent', + palette: ['#2563eb', '#f97316'], + }, + } +} diff --git a/packages/react-native-charts/src/interaction.ts b/packages/react-native-charts/src/interaction.ts new file mode 100644 index 00000000..d432ef7a --- /dev/null +++ b/packages/react-native-charts/src/interaction.ts @@ -0,0 +1,205 @@ +import { + focusNearestX, + focusNearestY, + focusX, + focusY, +} from '@tanstack/charts/focus' +import { findNearestPoint } from '@tanstack/charts/scene' +import type { + ChartDefinition, + ChartFocusMode, + ChartFocusStrategy, + ChartPoint, + ChartScene, + ChartValue, +} from '@tanstack/charts/types' + +export interface NativeChartFocusModel< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +> { + resolve: ( + x: number, + y: number, + ) => readonly ChartPoint[] + group: ( + point: ChartPoint, + ) => readonly ChartPoint[] + navigation: readonly ChartPoint[] + restore: ( + point: ChartPoint, + ) => ChartPoint | null +} + +export function createNativeChartFocusModel< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + scene: ChartScene, + definition: ChartDefinition, +): NativeChartFocusModel { + const strategy = resolveFocusStrategy(definition.focus) + const spatialIndex = definition.spatialIndex?.(scene.points) + const maxDistance = definition.maxFocusDistance ?? 48 + const navigation = + strategy?.navigation(scene.points) ?? sceneOrder(scene.points) + + return { + resolve(x, y) { + if (strategy) { + return strategy.resolve(scene.points, x, y, maxDistance) + } + const point = spatialIndex + ? spatialIndex.findNearest(x, y, maxDistance) + : findNearestPoint(scene, x, y, maxDistance) + return point ? [point] : [] + }, + group(point) { + return strategy?.group(scene.points, point) ?? [point] + }, + navigation, + restore(point) { + return restoreFocusedPoint(scene.points, point) + }, + } +} + +export function adjacentFocusPoint< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + model: NativeChartFocusModel, + current: ChartPoint | null, + direction: -1 | 1, +) { + const currentIndex = current + ? model.navigation.findIndex((point) => samePointIdentity(point, current)) + : -1 + const nextIndex = + currentIndex < 0 + ? direction > 0 + ? 0 + : model.navigation.length - 1 + : Math.max( + 0, + Math.min(model.navigation.length - 1, currentIndex + direction), + ) + return model.navigation[nextIndex] ?? null +} + +export function samePointIdentity< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + left: ChartPoint | null, + right: ChartPoint | null, +) { + return ( + left === right || + (left !== null && + right !== null && + left.key === right.key && + left.markId === right.markId && + left.datumIndex === right.datumIndex) + ) +} + +export function samePointList< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + left: readonly ChartPoint[], + right: readonly ChartPoint[], +) { + return ( + left.length === right.length && + left.every((point, index) => samePointIdentity(point, right[index] ?? null)) + ) +} + +function resolveFocusStrategy< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + focus: ChartFocusMode | undefined, +): ChartFocusStrategy | undefined { + if (typeof focus !== 'string') return focus + switch (focus) { + case 'nearest-x': + return focusNearestX + case 'nearest-y': + return focusNearestY + case 'group-x': + return focusX + case 'group-y': + return focusY + case 'nearest': + return undefined + } +} + +function sceneOrder< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>(points: readonly ChartPoint[]) { + return points + .map((point, index) => ({ point, index })) + .sort( + (left, right) => + left.point.x - right.point.x || + left.point.y - right.point.y || + left.index - right.index, + ) + .map(({ point }) => point) +} + +function restoreFocusedPoint< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + points: readonly ChartPoint[], + previous: ChartPoint, +) { + const matches = points.filter((point) => point.key === previous.key) + if (matches.length < 2) return matches[0] ?? null + + const datumType = typeof previous.datum + const hasReferenceIdentity = + previous.datum !== null && + (datumType === 'object' || datumType === 'function') + if (hasReferenceIdentity) { + const sameDatum = matches.find((point) => point.datum === previous.datum) + if (sameDatum) return sameDatum + } + + return ( + matches.find( + (point) => + point.markId === previous.markId && + Object.is(point.group, previous.group) && + chartValueEqual(point.xValue, previous.xValue) && + chartValueEqual(point.yValue, previous.yValue), + ) ?? + matches.find( + (point) => + point.markId === previous.markId && + point.datumIndex === previous.datumIndex, + ) ?? + matches[0] ?? + null + ) +} + +function chartValueEqual(left: ChartValue, right: ChartValue) { + return left instanceof Date && right instanceof Date + ? left.getTime() === right.getTime() + : Object.is(left, right) +} diff --git a/packages/react-native-charts/src/paint.test.ts b/packages/react-native-charts/src/paint.test.ts new file mode 100644 index 00000000..6cce3707 --- /dev/null +++ b/packages/react-native-charts/src/paint.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from 'vitest' +import { resolveNativePaint, resolveNativeSolidPaint } from './paint' + +describe('native paint resolution', () => { + it('resolves the browser-backed default theme tokens', () => { + const context = { color: '#102030' } + + expect(resolveNativePaint('currentColor', context)).toBe('#102030') + expect(resolveNativePaint('CanvasText', context)).toBe('#102030') + expect(resolveNativePaint('var(--ts-chart-1, #2563eb)', context)).toBe( + '#2563eb', + ) + expect( + resolveNativePaint( + 'var(--app-chart, var(--ts-chart-2, rgb(10, 20, 30)))', + context, + ), + ).toBe('rgb(10, 20, 30)') + }) + + it('uses the host color when an authored CSS variable has no fallback', () => { + expect(resolveNativePaint('var(--app-chart)', { color: '#abcdef' })).toBe( + '#abcdef', + ) + }) + + it('preserves concrete native paints and resource references', () => { + const context = { color: '#102030' } + + expect(resolveNativePaint('transparent', context)).toBe('transparent') + expect(resolveNativePaint('#fff', context)).toBe('#fff') + expect(resolveNativePaint('url(#gradient)', context)).toBe('url(#gradient)') + }) + + it('falls back to the host color where native views cannot use SVG resources', () => { + expect( + resolveNativeSolidPaint('url(#gradient)', { color: '#102030' }), + ).toBe('#102030') + expect(resolveNativeSolidPaint('#abcdef', { color: '#102030' })).toBe( + '#abcdef', + ) + }) +}) diff --git a/packages/react-native-charts/src/paint.ts b/packages/react-native-charts/src/paint.ts new file mode 100644 index 00000000..e382df8b --- /dev/null +++ b/packages/react-native-charts/src/paint.ts @@ -0,0 +1,48 @@ +import type { ColorValue } from 'react-native' + +export interface NativePaintContext { + color: ColorValue +} + +export type NativePaintResolver = ( + paint: string, + context: NativePaintContext, +) => ColorValue + +export function resolveNativePaint( + paint: string, + { color }: NativePaintContext, +): ColorValue { + const value = paint.trim() + if (value === 'currentColor' || value === 'CanvasText') return color + if (!value.startsWith('var(') || !value.endsWith(')')) return value + + const fallback = cssVariableFallback(value) + return fallback ? resolveNativePaint(fallback, { color }) : color +} + +export function resolveNativeSolidPaint( + paint: string, + context: NativePaintContext, + resolvePaint: NativePaintResolver = resolveNativePaint, +): ColorValue { + const resolved = resolvePaint(paint, context) + return typeof resolved === 'string' && + resolved.trim().startsWith('url(') && + resolved.trim().endsWith(')') + ? context.color + : resolved +} + +function cssVariableFallback(value: string) { + let depth = 0 + for (let index = 4; index < value.length - 1; index += 1) { + const character = value[index] + if (character === '(') depth += 1 + if (character === ')') depth -= 1 + if (character === ',' && depth === 0) { + return value.slice(index + 1, -1).trim() + } + } + return undefined +} diff --git a/packages/react-native-charts/src/tooltip-entry.ts b/packages/react-native-charts/src/tooltip-entry.ts new file mode 100644 index 00000000..432e11b5 --- /dev/null +++ b/packages/react-native-charts/src/tooltip-entry.ts @@ -0,0 +1,7 @@ +export { tooltip } from './Tooltip' +export type { + NativeChartTooltipComponent, + NativeChartTooltipExtension, + NativeChartTooltipProps, + NativeChartTooltipRenderContext, +} from './Tooltip' diff --git a/packages/react-native-charts/tsconfig.json b/packages/react-native-charts/tsconfig.json new file mode 100644 index 00000000..136f244f --- /dev/null +++ b/packages/react-native-charts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "lib": ["ES2022"], + "types": ["react", "react-native"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b46f0e9..4c94dec9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,7 +36,7 @@ importers: version: link:packages/react '@sveltejs/vite-plugin-svelte': specifier: ^7.1.2 - version: 7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) '@tanstack/charts': specifier: workspace:* version: link:packages/charts-core @@ -52,6 +52,9 @@ importers: '@tanstack/react-charts': specifier: workspace:* version: link:packages/react-charts + '@tanstack/react-native-charts': + specifier: workspace:* + version: link:packages/react-native-charts '@types/d3-array': specifier: ^3.2.2 version: 3.2.2 @@ -129,7 +132,7 @@ importers: version: 1.0.5 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) chart.js: specifier: 4.5.1 version: 4.5.1 @@ -207,7 +210,7 @@ importers: version: 22.7.5(debug@4.4.3(supports-color@10.2.2)) octane: specifier: 0.1.13 - version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) playwright: specifier: 1.62.0 version: 1.62.0 @@ -243,13 +246,13 @@ importers: version: 3.0.1 vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.12 - version: 2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vitest: specifier: ^4.1.9 - version: 4.1.10(@types/node@25.9.5)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 4.1.10(@types/node@25.9.5)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) world-atlas: specifier: 2.0.2 version: 2.0.2 @@ -279,7 +282,7 @@ importers: version: 3.2.0 octane: specifier: 0.1.13 - version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) devDependencies: '@types/d3-array': specifier: ^3.2.2 @@ -292,7 +295,7 @@ importers: version: 3.1.8 vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) examples/charts-react: dependencies: @@ -332,10 +335,50 @@ importers: version: 3.1.8 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + + examples/charts-react-native: + dependencies: + '@tanstack/charts': + specifier: workspace:* + version: link:../../packages/charts-core + '@tanstack/react-native-charts': + specifier: workspace:* + version: link:../../packages/react-native-charts + d3-scale: + specifier: 4.0.2 + version: 4.0.2 + react: + specifier: 19.2.3 + version: 19.2.3 + react-native: + specifier: 0.86.0 + version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-native-svg: + specifier: 15.15.5 + version: 15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + devDependencies: + '@babel/core': + specifier: ^7.25.2 + version: 7.29.7(supports-color@10.2.2) + '@babel/runtime': + specifier: ^7.25.0 + version: 7.29.7 + '@react-native-community/cli': + specifier: 20.1.0 + version: 20.1.0(supports-color@10.2.2)(typescript@6.0.3) + '@react-native/babel-preset': + specifier: 0.86.0 + version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/metro-config': + specifier: 0.86.0 + version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/typescript-config': + specifier: 0.86.0 + version: 0.86.0 examples/conformance: dependencies: @@ -375,7 +418,7 @@ importers: version: 3.1.8 vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) examples/octane: dependencies: @@ -390,11 +433,11 @@ importers: version: link:../../packages/octane octane: specifier: 0.1.13 - version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) devDependencies: vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) examples/react: dependencies: @@ -416,10 +459,10 @@ importers: devDependencies: '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) examples/sandbox: dependencies: @@ -459,10 +502,10 @@ importers: version: 3.1.8 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 - version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) packages/alpine-charts: dependencies: @@ -638,7 +681,7 @@ importers: version: link:../plot octane: specifier: ^0.1.13 - version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) packages/octane-charts: dependencies: @@ -647,7 +690,7 @@ importers: version: link:../charts-core octane: specifier: ^0.1.13 - version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) devDependencies: '@types/d3-scale': specifier: ^4.0.9 @@ -709,6 +752,21 @@ importers: specifier: 4.0.2 version: 4.0.2 + packages/react-native-charts: + dependencies: + '@tanstack/charts': + specifier: workspace:* + version: link:../charts-core + react: + specifier: ^19.2.3 + version: 19.2.3 + react-native: + specifier: ^0.86.0 + version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-native-svg: + specifier: ^15.15.5 + version: 15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + packages/solid-charts: dependencies: '@tanstack/charts': @@ -720,7 +778,7 @@ importers: version: 1.9.14 vite-plugin-solid: specifier: ^2.11.12 - version: 2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) packages/svelte-charts: dependencies: @@ -733,7 +791,7 @@ importers: version: 2.5.8(svelte@5.56.8)(typescript@6.0.3) '@sveltejs/vite-plugin-svelte': specifier: ^7.1.2 - version: 7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + version: 7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) svelte: specifier: ^5.56.2 version: 5.56.8 @@ -891,6 +949,13 @@ packages: } engines: { node: '>=6.9.0' } + '@babel/helper-annotate-as-pure@7.29.7': + resolution: + { + integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==, + } + engines: { node: '>=6.9.0' } + '@babel/helper-compilation-targets@7.29.7': resolution: { @@ -898,6 +963,32 @@ packages: } engines: { node: '>=6.9.0' } + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: + { + integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.29.7': + resolution: + { + integrity: sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.8': + resolution: + { + integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==, + } + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-globals@7.29.7': resolution: { @@ -905,6 +996,13 @@ packages: } engines: { node: '>=6.9.0' } + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: + { + integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==, + } + engines: { node: '>=6.9.0' } + '@babel/helper-module-imports@7.18.6': resolution: { @@ -928,6 +1026,13 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.29.7': + resolution: + { + integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==, + } + engines: { node: '>=6.9.0' } + '@babel/helper-plugin-utils@7.29.7': resolution: { @@ -935,6 +1040,31 @@ packages: } engines: { node: '>=6.9.0' } + '@babel/helper-remap-async-to-generator@7.29.7': + resolution: + { + integrity: sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.29.7': + resolution: + { + integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: + { + integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==, + } + engines: { node: '>=6.9.0' } + '@babel/helper-string-parser@7.29.7': resolution: { @@ -956,6 +1086,13 @@ packages: } engines: { node: '>=6.9.0' } + '@babel/helper-wrap-function@7.29.7': + resolution: + { + integrity: sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==, + } + engines: { node: '>=6.9.0' } + '@babel/helpers@7.29.7': resolution: { @@ -971,230 +1108,497 @@ packages: engines: { node: '>=6.0.0' } hasBin: true - '@babel/plugin-syntax-jsx@7.29.7': + '@babel/plugin-proposal-export-default-from@7.29.7': resolution: { - integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==, + integrity: sha512-p+G5BNXDcy3bOXplhY4HybQ1GxH3i2Tppmdm/3epyRu2VgJJZuUlZ61MqRTg582Q7ZLBdP7fePYvsumSEkMxcQ==, } engines: { node: '>=6.9.0' } peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.29.7': + '@babel/plugin-syntax-dynamic-import@7.8.3': resolution: { - integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==, + integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==, } - engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@babel/template@7.29.7': + '@babel/plugin-syntax-export-default-from@7.29.7': resolution: { - integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==, + integrity: sha512-foag0BB37ROhdeIX9O8G0jX7hw0UekJc04cHMrYLOnrErsnBKqJGHJ8eDRpoCFZBvEPPygmmtw4qyU97qa4oOw==, } engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@babel/traverse@7.29.7': + '@babel/plugin-syntax-flow@7.29.7': resolution: { - integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==, + integrity: sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==, } engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@babel/types@7.29.7': + '@babel/plugin-syntax-jsx@7.29.7': resolution: { - integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==, + integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==, } engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@bramus/specificity@2.4.2': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': resolution: { - integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==, + integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==, } - hasBin: true + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/apply-release-plan@7.1.1': + '@babel/plugin-syntax-optional-chaining@7.8.3': resolution: { - integrity: sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==, + integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==, } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/assemble-release-plan@6.0.10': + '@babel/plugin-syntax-typescript@7.29.7': resolution: { - integrity: sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==, + integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/changelog-git@0.2.1': + '@babel/plugin-transform-async-generator-functions@7.29.7': resolution: { - integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==, + integrity: sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/changelog-github@0.7.0': + '@babel/plugin-transform-async-to-generator@7.29.7': resolution: { - integrity: sha512-rBsbRvc4TVn+FvFnOVM3LxlFJfTXXCp8gfVJ+0BubxWNSVnLuAzowi5j+IEraLLP52w8AAs9QfKbPS3MMiXQJA==, + integrity: sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/cli@2.31.1': + '@babel/plugin-transform-block-scoping@7.29.7': resolution: { - integrity: sha512-uO05WTcRBwuVOJVSW8Cmpqw6q0WDL53ajGCMyszutvOe5toOnunbpM4jZzf+qxBOz7i0AzopZ8diBuewjmF40w==, + integrity: sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==, } - hasBin: true + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/config@3.1.4': + '@babel/plugin-transform-class-properties@7.29.7': resolution: { - integrity: sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==, + integrity: sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/errors@0.2.0': + '@babel/plugin-transform-classes@7.29.7': resolution: { - integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==, + integrity: sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/get-dependents-graph@2.1.4': + '@babel/plugin-transform-destructuring@7.29.7': resolution: { - integrity: sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==, + integrity: sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/get-github-info@0.8.0': + '@babel/plugin-transform-flow-strip-types@7.29.7': resolution: { - integrity: sha512-cRnC+xdF0JIik7coko3iUP9qbnfi1iJQ3sAa6dE+Tx3+ET8bjFEm63PA4WEohgjYcmsOikPHWzPsMWWiZmntOQ==, + integrity: sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/get-release-plan@4.0.16': + '@babel/plugin-transform-for-of@7.29.7': resolution: { - integrity: sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==, + integrity: sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/get-version-range-type@0.4.0': + '@babel/plugin-transform-modules-commonjs@7.29.7': resolution: { - integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==, + integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/git@3.0.4': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7': resolution: { - integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==, + integrity: sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 - '@changesets/logger@0.1.1': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7': resolution: { - integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==, + integrity: sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/parse@0.4.3': + '@babel/plugin-transform-optional-catch-binding@7.29.7': resolution: { - integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==, + integrity: sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/pre@2.0.2': + '@babel/plugin-transform-optional-chaining@7.29.7': resolution: { - integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==, + integrity: sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/read@0.6.7': + '@babel/plugin-transform-private-methods@7.29.7': resolution: { - integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==, + integrity: sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/should-skip-package@0.1.2': + '@babel/plugin-transform-private-property-in-object@7.29.7': resolution: { - integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==, + integrity: sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/types@4.1.0': + '@babel/plugin-transform-react-display-name@7.29.7': resolution: { - integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==, + integrity: sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/types@6.1.0': + '@babel/plugin-transform-react-jsx-self@7.29.7': resolution: { - integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==, + integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@changesets/write@0.4.0': + '@babel/plugin-transform-react-jsx-source@7.29.7': resolution: { - integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==, + integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==, } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@cloudflare/kv-asset-handler@0.5.0': + '@babel/plugin-transform-react-jsx@7.29.7': resolution: { - integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==, + integrity: sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==, } - engines: { node: '>=22.0.0' } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@cloudflare/unenv-preset@2.16.1': + '@babel/plugin-transform-regenerator@7.29.7': resolution: { - integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==, + integrity: sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==, } + engines: { node: '>=6.9.0' } peerDependencies: - unenv: 2.0.0-rc.24 - workerd: '>1.20260305.0 <2.0.0-0' - peerDependenciesMeta: - workerd: - optional: true + '@babel/core': ^7.0.0-0 - '@cloudflare/workerd-darwin-64@1.20260617.1': + '@babel/plugin-transform-runtime@7.29.7': resolution: { - integrity: sha512-jWwmgEVVWbsHNrLSNXzwjJaH90VzRxq1cWkQFUidxyeUPnMxemeNE8I9qFAfrpzGgE11e9sKDcE3ettJW08swQ==, + integrity: sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==, } - engines: { node: '>=16' } - cpu: [x64] - os: [darwin] + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@cloudflare/workerd-darwin-arm64@1.20260617.1': + '@babel/plugin-transform-typescript@7.29.7': resolution: { - integrity: sha512-LHH7b565g9znfCUOkwbec6FG2rmRbsgCy6aJiU9KN662mNheWl5sw/iKleiFSiljPKQQP3HkjnC/NSkdgi/aSA==, + integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==, } - engines: { node: '>=16' } - cpu: [arm64] - os: [darwin] + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@cloudflare/workerd-linux-64@1.20260617.1': + '@babel/plugin-transform-unicode-regex@7.29.7': resolution: { - integrity: sha512-FMnaAKXe4Cfd8TQurCVd9fs2XQVBFRCsP+Id/SRdUv89MlwYu9zXfoyx6BxM+brPTIUK38SHbo8iaxiwzLi9JQ==, + integrity: sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==, } - engines: { node: '>=16' } - cpu: [x64] - os: [linux] + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 - '@cloudflare/workerd-linux-arm64@1.20260617.1': + '@babel/runtime@7.29.7': resolution: { - integrity: sha512-MRoifFYcqbxxIIQy7PqO5tFY/qPFSnjXzakWl0sO93l+HLyG35jRAgOi6jfqa4kBxc7gKKtH861DcewjxUfkjA==, + integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==, } - engines: { node: '>=16' } - cpu: [arm64] - os: [linux] + engines: { node: '>=6.9.0' } - '@cloudflare/workerd-windows-64@1.20260617.1': + '@babel/template@7.29.7': resolution: { - integrity: sha512-rgBV9wQrv0OSKgCTTbhFUFY3sLGNANZ88aqaLvtmEn2gmbFVb1J4PDGochVUdB7NSEp4D/ghHva6/8SZmbONpw==, + integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==, + } + engines: { node: '>=6.9.0' } + + '@babel/traverse@7.29.7': + resolution: + { + integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==, + } + engines: { node: '>=6.9.0' } + + '@babel/types@7.29.7': + resolution: + { + integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==, + } + engines: { node: '>=6.9.0' } + + '@bramus/specificity@2.4.2': + resolution: + { + integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==, + } + hasBin: true + + '@changesets/apply-release-plan@7.1.1': + resolution: + { + integrity: sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==, + } + + '@changesets/assemble-release-plan@6.0.10': + resolution: + { + integrity: sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==, + } + + '@changesets/changelog-git@0.2.1': + resolution: + { + integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==, + } + + '@changesets/changelog-github@0.7.0': + resolution: + { + integrity: sha512-rBsbRvc4TVn+FvFnOVM3LxlFJfTXXCp8gfVJ+0BubxWNSVnLuAzowi5j+IEraLLP52w8AAs9QfKbPS3MMiXQJA==, + } + + '@changesets/cli@2.31.1': + resolution: + { + integrity: sha512-uO05WTcRBwuVOJVSW8Cmpqw6q0WDL53ajGCMyszutvOe5toOnunbpM4jZzf+qxBOz7i0AzopZ8diBuewjmF40w==, + } + hasBin: true + + '@changesets/config@3.1.4': + resolution: + { + integrity: sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==, + } + + '@changesets/errors@0.2.0': + resolution: + { + integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==, + } + + '@changesets/get-dependents-graph@2.1.4': + resolution: + { + integrity: sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==, + } + + '@changesets/get-github-info@0.8.0': + resolution: + { + integrity: sha512-cRnC+xdF0JIik7coko3iUP9qbnfi1iJQ3sAa6dE+Tx3+ET8bjFEm63PA4WEohgjYcmsOikPHWzPsMWWiZmntOQ==, + } + + '@changesets/get-release-plan@4.0.16': + resolution: + { + integrity: sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==, + } + + '@changesets/get-version-range-type@0.4.0': + resolution: + { + integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==, + } + + '@changesets/git@3.0.4': + resolution: + { + integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==, + } + + '@changesets/logger@0.1.1': + resolution: + { + integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==, + } + + '@changesets/parse@0.4.3': + resolution: + { + integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==, + } + + '@changesets/pre@2.0.2': + resolution: + { + integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==, + } + + '@changesets/read@0.6.7': + resolution: + { + integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==, + } + + '@changesets/should-skip-package@0.1.2': + resolution: + { + integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==, + } + + '@changesets/types@4.1.0': + resolution: + { + integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==, + } + + '@changesets/types@6.1.0': + resolution: + { + integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==, + } + + '@changesets/write@0.4.0': + resolution: + { + integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==, + } + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: + { + integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==, + } + engines: { node: '>=22.0.0' } + + '@cloudflare/unenv-preset@2.16.1': + resolution: + { + integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==, + } + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20260617.1': + resolution: + { + integrity: sha512-jWwmgEVVWbsHNrLSNXzwjJaH90VzRxq1cWkQFUidxyeUPnMxemeNE8I9qFAfrpzGgE11e9sKDcE3ettJW08swQ==, + } + engines: { node: '>=16' } + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260617.1': + resolution: + { + integrity: sha512-LHH7b565g9znfCUOkwbec6FG2rmRbsgCy6aJiU9KN662mNheWl5sw/iKleiFSiljPKQQP3HkjnC/NSkdgi/aSA==, + } + engines: { node: '>=16' } + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20260617.1': + resolution: + { + integrity: sha512-FMnaAKXe4Cfd8TQurCVd9fs2XQVBFRCsP+Id/SRdUv89MlwYu9zXfoyx6BxM+brPTIUK38SHbo8iaxiwzLi9JQ==, + } + engines: { node: '>=16' } + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260617.1': + resolution: + { + integrity: sha512-MRoifFYcqbxxIIQy7PqO5tFY/qPFSnjXzakWl0sO93l+HLyG35jRAgOi6jfqa4kBxc7gKKtH861DcewjxUfkjA==, + } + engines: { node: '>=16' } + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20260617.1': + resolution: + { + integrity: sha512-rgBV9wQrv0OSKgCTTbhFUFY3sLGNANZ88aqaLvtmEn2gmbFVb1J4PDGochVUdB7NSEp4D/ghHva6/8SZmbONpw==, } engines: { node: '>=16' } cpu: [x64] @@ -1777,6 +2181,18 @@ packages: '@noble/hashes': optional: true + '@hapi/hoek@9.3.0': + resolution: + { + integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==, + } + + '@hapi/topo@5.1.0': + resolution: + { + integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==, + } + '@img/colour@1.1.0': resolution: { @@ -2017,6 +2433,13 @@ packages: '@types/node': optional: true + '@isaacs/ttlcache@1.4.1': + resolution: + { + integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==, + } + engines: { node: '>=12' } + '@jest/diff-sequences@30.0.1': resolution: { @@ -2024,6 +2447,20 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + '@jest/schemas@29.6.3': + resolution: + { + integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + '@jest/types@29.6.3': + resolution: + { + integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + '@jridgewell/gen-mapping@0.3.13': resolution: { @@ -2043,6 +2480,12 @@ packages: } engines: { node: '>=6.0.0' } + '@jridgewell/source-map@0.3.11': + resolution: + { + integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==, + } + '@jridgewell/sourcemap-codec@1.5.5': resolution: { @@ -2543,51 +2986,249 @@ packages: integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==, } - '@reduxjs/toolkit@2.12.0': + '@react-native-community/cli-clean@20.1.0': resolution: { - integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==, + integrity: sha512-77L4DifWfxAT8ByHnkypge7GBMYpbJAjBGV+toowt5FQSGaTBDcBHCX+FFqFRukD5fH6i8sZ41Gtw+nbfCTTIA==, } - peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 || ^19 - react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true - '@rolldown/binding-android-arm64@1.1.5': + '@react-native-community/cli-config-android@20.1.0': resolution: { - integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==, + integrity: sha512-3A01ZDyFeCALzzPcwP/fleHoP3sGNq1UX7FzxkTrOFX8RRL9ntXNXQd27E56VU4BBxGAjAJT4Utw8pcOjJceIA==, } - engines: { node: ^20.19.0 || >=22.12.0 } - cpu: [arm64] - os: [android] - '@rolldown/binding-darwin-arm64@1.1.5': + '@react-native-community/cli-config-apple@20.1.0': resolution: { - integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==, + integrity: sha512-n6JVs8Q3yxRbtZQOy05ofeb1kGtspGN3SgwPmuaqvURF9fsuS7c4/9up2Kp9C+1D2J1remPJXiZLNGOcJvfpOA==, } - engines: { node: ^20.19.0 || >=22.12.0 } - cpu: [arm64] - os: [darwin] - '@rolldown/binding-darwin-x64@1.1.5': + '@react-native-community/cli-config@20.1.0': resolution: { - integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==, + integrity: sha512-1x9rhLLR/dKKb92Lb5O0l0EmUG08FHf+ZVyVEf9M+tX+p5QIm52MRiy43R0UAZ2jJnFApxRk+N3sxoYK4Dtnag==, } - engines: { node: ^20.19.0 || >=22.12.0 } - cpu: [x64] - os: [darwin] - '@rolldown/binding-freebsd-x64@1.1.5': + '@react-native-community/cli-doctor@20.1.0': resolution: { - integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==, + integrity: sha512-QfJF1GVjA4PBrIT3SJ0vFFIu0km1vwOmLDlOYVqfojajZJ+Dnvl0f94GN1il/jT7fITAxom///XH3/URvi7YTQ==, + } + + '@react-native-community/cli-platform-android@20.1.0': + resolution: + { + integrity: sha512-TeHPDThOwDppQRpndm9kCdRCBI8AMy3HSIQ+iy7VYQXL5BtZ5LfmGdusoj7nVN/ZGn0Lc6Gwts5qowyupXdeKg==, + } + + '@react-native-community/cli-platform-apple@20.1.0': + resolution: + { + integrity: sha512-0ih1hrYezSM2cuOlVnwBEFtMwtd8YgpTLmZauDJCv50rIumtkI1cQoOgLoS4tbPCj9U/Vn2a9BFH0DLFOOIacg==, + } + + '@react-native-community/cli-platform-ios@20.1.0': + resolution: + { + integrity: sha512-XN7Da9z4WsJxtqVtEzY8q2bv22OsvzaFP5zy5+phMWNoJlU4lf7IvBSxqGYMpQ9XhYP7arDw5vmW4W34s06rnA==, + } + + '@react-native-community/cli-server-api@20.1.0': + resolution: + { + integrity: sha512-Tb415Oh8syXNT2zOzLzFkBXznzGaqKCiaichxKzGCDKg6JGHp3jSuCmcTcaPeYC7oc32n/S3Psw7798r4Q/7lA==, + } + + '@react-native-community/cli-tools@20.1.0': + resolution: + { + integrity: sha512-/YmzHGOkY6Bgrv4OaA1L8rFqsBlQd1EB2/ipAoKPiieV0EcB5PUamUSuNeFU3sBZZTYQCUENwX4wgOHgFUlDnQ==, + } + + '@react-native-community/cli-types@20.1.0': + resolution: + { + integrity: sha512-D0kDspcwgbVXyNjwicT7Bb1JgXjijTw1JJd+qxyF/a9+sHv7TU4IchV+gN38QegeXqVyM4Ym7YZIvXMFBmyJqA==, + } + + '@react-native-community/cli@20.1.0': + resolution: + { + integrity: sha512-441WsVtRe4nGJ9OzA+QMU1+22lA6Q2hRWqqIMKD0wjEMLqcSfOZyu2UL9a/yRpL/dRpyUsU4n7AxqKfTKO/Csg==, + } + engines: { node: '>=20.19.4' } + hasBin: true + + '@react-native/assets-registry@0.86.0': + resolution: + { + integrity: sha512-nIaXbm2jX1OTYp0qbviJ3O6KZivoE8z3BnhUQ2LsqfZSWRoOK/n1qsiAr6oALiNKWnXY3j2KPwtYORnZzp8xew==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/babel-plugin-codegen@0.86.0': + resolution: + { + integrity: sha512-qdsABWNW7uTll90l4Vh03gjeyu3WVDi2CyiiyvYGMRDcoYbjbQi6df3BMAm9lQI2yslZ1T14LlDDAsgTwNxplA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/babel-preset@0.86.0': + resolution: + { + integrity: sha512-bYQcWiPySNvF4dns9Ls9gMmwgq66ohvM9Fwc/Kn8r85t66UNHxch3p1QwPiSorDelFauZwJbgo9+ReibTgvpbA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + '@babel/core': '*' + + '@react-native/codegen@0.86.0': + resolution: + { + integrity: sha512-uTs9DBo3+/lUqinsGZK0FKJRBVClrwMXoZToaDxE1Q2SL2e55vs2GwyZfIKzPl5uJnbu4PfFMIp0/mLXLWUMuA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.86.0': + resolution: + { + integrity: sha512-Jv8p1ebEPfTzs8gmrjsdT2XMXFfeAg45Pman+XPLFGaSeGAZkutRFRyX9Cs9aGTSOyIA9YPJ6vDNb1ayTf1FKQ==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.86.0 + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.86.0': + resolution: + { + integrity: sha512-7Mb3nDfyJeys+ELF75Ageu7VKERlnIMoO+aNPoXqTXvz+b41L6l2CqMyLpDHxkBSlenij6gEepPNgaIyWHbJZw==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/debugger-shell@0.86.0': + resolution: + { + integrity: sha512-Y0zEkZzLz8ou6o/VLml1A31X/rMgc6DRjwxwzPMa94qRTMY070WeBCNTITQo4kKTBAUgbxh07oXPQqp0Tpja8w==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/dev-middleware@0.86.0': + resolution: + { + integrity: sha512-20pTO6yTybmvXvro520H6C7jydIQnLKOl5qFtVEcHSdFrY63r3OGei+Rx9bILgSRmH6jgnfEcijcMx7pwWuQtw==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/gradle-plugin@0.86.0': + resolution: + { + integrity: sha512-a1RcfaEDqWExCGfCwadIxt4l8FvKYgFqeMf2uzeKyAOnb+vTGNIeCvifFL2MqvgaeYxlER437HbMIajGcuJ1pQ==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/js-polyfills@0.86.0': + resolution: + { + integrity: sha512-zYy/Cjd1VTnZ2iCNaG9bDF9C3l2ntESiPRscjIlI5FKugu6aeTwsDSv1aI8Bc4Kp3vEdoVg+UQhLAhE4svREaQ==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/metro-babel-transformer@0.86.0': + resolution: + { + integrity: sha512-SjKej3E5qIahqo/G+rSOrmJUQM44RyKtWtO+VfmKAAMoJWkBFomM22hTLKCIS5cdbIAJ9COAmU+KAi2wVSO0wQ==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + '@babel/core': '*' + + '@react-native/metro-config@0.86.0': + resolution: + { + integrity: sha512-7v+xbTeEci9ZcQ/Z1OqI4RXcqN69wSMDYL5BAMvOReZ7U04+aDQ0/SQhClYPn6x2/RxM4WzMKSAuNyLKqvYVtw==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + '@react-native/normalize-colors@0.86.0': + resolution: + { + integrity: sha512-kG0wfCGghUKlfxkJyyHCDVutWVYWK7/DG58ojA/4v9EfulgF+osuSQmlbNb3rcKX58qutm7JcldSeVLgGFha9g==, + } + + '@react-native/typescript-config@0.86.0': + resolution: + { + integrity: sha512-oSuFIEMVAVEXdIvDnrdXsWmIF4fYdgtvAEr2ofn8OY534m7XWm9QAqHHpGUzoK0iwDPlPZ5n2Rb25gqF1SZ0rg==, + } + + '@react-native/virtualized-lists@0.86.0': + resolution: + { + integrity: sha512-4/ZLXdf/OSpPDVO0AsQ1SJdRIzt5t9BNQ46QwGgxvX7/cirYR5k8KXctNGGgW8lQo2gZChEfY2zFCZg9nM/jiw==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.86.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@reduxjs/toolkit@2.12.0': + resolution: + { + integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==, + } + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + + '@rolldown/binding-android-arm64@1.1.5': + resolution: + { + integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: + { + integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.5': + resolution: + { + integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: + { + integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==, } engines: { node: ^20.19.0 || >=22.12.0 } cpu: [x64] @@ -2948,6 +3589,30 @@ packages: engines: { node: '>=18.0.0', npm: '>=8.0.0' } hasBin: true + '@sideway/address@4.1.5': + resolution: + { + integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==, + } + + '@sideway/formula@3.0.1': + resolution: + { + integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==, + } + + '@sideway/pinpoint@2.0.0': + resolution: + { + integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==, + } + + '@sinclair/typebox@0.27.12': + resolution: + { + integrity: sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==, + } + '@sindresorhus/is@7.2.0': resolution: { @@ -3224,6 +3889,24 @@ packages: integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==, } + '@types/istanbul-lib-coverage@2.0.6': + resolution: + { + integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==, + } + + '@types/istanbul-lib-report@3.0.3': + resolution: + { + integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==, + } + + '@types/istanbul-reports@3.0.4': + resolution: + { + integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==, + } + '@types/jsdom@27.0.0': resolution: { @@ -3286,6 +3969,18 @@ packages: integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==, } + '@types/yargs-parser@21.0.3': + resolution: + { + integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==, + } + + '@types/yargs@17.0.35': + resolution: + { + integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==, + } + '@vitejs/plugin-react@6.0.4': resolution: { @@ -3352,6 +4047,12 @@ packages: integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==, } + '@vscode/sudo-prompt@9.3.2': + resolution: + { + integrity: sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==, + } + '@vue/compiler-core@3.5.40': resolution: { @@ -3431,6 +4132,27 @@ packages: } hasBin: true + abort-controller@3.0.0: + resolution: + { + integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==, + } + engines: { node: '>=6.5' } + + accepts@1.3.8: + resolution: + { + integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==, + } + engines: { node: '>= 0.6' } + + accepts@2.0.0: + resolution: + { + integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==, + } + engines: { node: '>= 0.6' } + acorn@8.17.0: resolution: { @@ -3439,6 +4161,13 @@ packages: engines: { node: '>=0.4.0' } hasBin: true + agent-base@7.1.4: + resolution: + { + integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==, + } + engines: { node: '>= 14' } + ajv@8.20.0: resolution: { @@ -3451,6 +4180,12 @@ packages: integrity: sha512-nJvPAQVNPdZZ0NrExJ/kzQco3ijR8LwvCOadQecllESiqT4NyZ/57sN9V2XyvhlBGAbmlKYgeWZvYdKq99ij/Q==, } + anser@1.4.10: + resolution: + { + integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==, + } + ansi-colors@4.1.3: resolution: { @@ -3458,6 +4193,19 @@ packages: } engines: { node: '>=6' } + ansi-fragments@0.2.1: + resolution: + { + integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==, + } + + ansi-regex@4.1.1: + resolution: + { + integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==, + } + engines: { node: '>=6' } + ansi-regex@5.0.1: resolution: { @@ -3472,6 +4220,13 @@ packages: } engines: { node: '>=12' } + ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: '>=4' } + ansi-styles@4.3.0: resolution: { @@ -3479,6 +4234,13 @@ packages: } engines: { node: '>=8' } + ansi-styles@5.2.0: + resolution: + { + integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==, + } + engines: { node: '>=10' } + ansi-styles@6.2.3: resolution: { @@ -3486,6 +4248,12 @@ packages: } engines: { node: '>=12' } + appdirsjs@1.2.8: + resolution: + { + integrity: sha512-8zl1xlxeS4a0/36CT6LOaVioPOL8TeLT1b9OHk0j9xSbzmPBuM7lUgWMSTh6SbuF8fbwjcP1rr30OCLpd1fl+A==, + } + argparse@1.0.10: resolution: { @@ -3512,6 +4280,12 @@ packages: } engines: { node: '>=8' } + asap@2.0.6: + resolution: + { + integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==, + } + assertion-error@2.0.1: resolution: { @@ -3519,6 +4293,19 @@ packages: } engines: { node: '>=12' } + astral-regex@1.0.0: + resolution: + { + integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==, + } + engines: { node: '>=4' } + + async-limiter@1.0.1: + resolution: + { + integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==, + } + asynckit@0.4.0: resolution: { @@ -3546,24 +4333,60 @@ packages: peerDependencies: '@babel/core': ^7.20.12 - babel-preset-solid@1.9.12: + babel-plugin-polyfill-corejs2@0.4.17: resolution: { - integrity: sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==, + integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==, } peerDependencies: - '@babel/core': ^7.0.0 - solid-js: ^1.9.12 - peerDependenciesMeta: - solid-js: - optional: true + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - balanced-match@4.0.3: + babel-plugin-polyfill-corejs3@0.13.0: resolution: { - integrity: sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==, + integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==, } - engines: { node: 20 || >=22 } + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.8: + resolution: + { + integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==, + } + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-syntax-hermes-parser@0.36.0: + resolution: + { + integrity: sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==, + } + + babel-plugin-transform-flow-enums@0.0.2: + resolution: + { + integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==, + } + + babel-preset-solid@1.9.12: + resolution: + { + integrity: sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==, + } + peerDependencies: + '@babel/core': ^7.0.0 + solid-js: ^1.9.12 + peerDependenciesMeta: + solid-js: + optional: true + + balanced-match@4.0.3: + resolution: + { + integrity: sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==, + } + engines: { node: 20 || >=22 } base64-js@1.5.1: resolution: @@ -3610,6 +4433,19 @@ packages: integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==, } + body-parser@1.20.6: + resolution: + { + integrity: sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==, + } + engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } + + boolbase@1.0.0: + resolution: + { + integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, + } + brace-expansion@5.0.6: resolution: { @@ -3639,12 +4475,31 @@ packages: engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true + bser@2.1.1: + resolution: + { + integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==, + } + + buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + buffer@5.7.1: resolution: { integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, } + bytes@3.1.2: + resolution: + { + integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, + } + engines: { node: '>= 0.8' } + call-bind-apply-helpers@1.0.2: resolution: { @@ -3652,6 +4507,34 @@ packages: } engines: { node: '>= 0.4' } + call-bound@1.0.4: + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: '>= 0.4' } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: '>=6' } + + camelcase@5.3.1: + resolution: + { + integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==, + } + engines: { node: '>=6' } + + camelcase@6.3.0: + resolution: + { + integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, + } + engines: { node: '>=10' } + caniuse-lite@1.0.30001806: resolution: { @@ -3706,6 +4589,33 @@ packages: } engines: { node: '>= 20.19.0' } + chrome-launcher@0.15.2: + resolution: + { + integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==, + } + engines: { node: '>=12.13.0' } + hasBin: true + + chromium-edge-launcher@0.3.0: + resolution: + { + integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==, + } + + ci-info@2.0.0: + resolution: + { + integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==, + } + + ci-info@3.9.0: + resolution: + { + integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, + } + engines: { node: '>=8' } + cli-cursor@3.1.0: resolution: { @@ -3734,6 +4644,12 @@ packages: } engines: { node: '>=18.20' } + cliui@6.0.0: + resolution: + { + integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==, + } + cliui@8.0.1: resolution: { @@ -3762,6 +4678,12 @@ packages: } engines: { node: '>=6' } + color-convert@1.9.3: + resolution: + { + integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, + } + color-convert@2.0.1: resolution: { @@ -3769,12 +4691,24 @@ packages: } engines: { node: '>=7.0.0' } + color-name@1.1.3: + resolution: + { + integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, + } + color-name@1.1.4: resolution: { integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, } + colorette@1.4.0: + resolution: + { + integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==, + } + combined-stream@1.0.8: resolution: { @@ -3782,6 +4716,19 @@ packages: } engines: { node: '>= 0.8' } + command-exists@1.2.9: + resolution: + { + integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==, + } + + commander@12.1.0: + resolution: + { + integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==, + } + engines: { node: '>=18' } + commander@14.0.3: resolution: { @@ -3802,12 +4749,47 @@ packages: } engines: { node: '>= 10' } + commander@9.5.0: + resolution: + { + integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==, + } + engines: { node: ^12.20.0 || >=14 } + common-path-prefix@3.0.0: resolution: { integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==, } + compressible@2.0.18: + resolution: + { + integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==, + } + engines: { node: '>= 0.6' } + + compression@1.8.1: + resolution: + { + integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==, + } + engines: { node: '>= 0.8.0' } + + connect@3.7.0: + resolution: + { + integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==, + } + engines: { node: '>= 0.10.0' } + + content-type@1.0.5: + resolution: + { + integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, + } + engines: { node: '>= 0.6' } + convert-source-map@1.9.0: resolution: { @@ -3834,6 +4816,24 @@ packages: } engines: { node: '>=12.13' } + core-js-compat@3.49.0: + resolution: + { + integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==, + } + + cosmiconfig@9.0.2: + resolution: + { + integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==, + } + engines: { node: '>=14' } + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-spawn@7.0.6: resolution: { @@ -3841,6 +4841,19 @@ packages: } engines: { node: '>= 8' } + css-select@5.2.2: + resolution: + { + integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==, + } + + css-tree@1.1.3: + resolution: + { + integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==, + } + engines: { node: '>=8.0.0' } + css-tree@3.2.1: resolution: { @@ -3848,6 +4861,13 @@ packages: } engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 } + css-what@6.2.2: + resolution: + { + integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==, + } + engines: { node: '>= 6' } + csstype@3.2.3: resolution: { @@ -4117,6 +5137,12 @@ packages: integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==, } + dayjs@1.11.21: + resolution: + { + integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==, + } + debug@2.6.9: resolution: { @@ -4151,6 +5177,13 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: + { + integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==, + } + engines: { node: '>=0.10.0' } + decimal.js-light@2.5.1: resolution: { @@ -4202,6 +5235,13 @@ packages: } engines: { node: '>=0.4.0' } + depd@2.0.0: + resolution: + { + integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, + } + engines: { node: '>= 0.8' } + dependency-graph@1.0.0: resolution: { @@ -4209,6 +5249,13 @@ packages: } engines: { node: '>=4' } + destroy@1.2.0: + resolution: + { + integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, + } + engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } + detect-indent@6.1.0: resolution: { @@ -4236,6 +5283,31 @@ packages: } engines: { node: '>=8' } + dom-serializer@2.0.0: + resolution: + { + integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, + } + + domelementtype@2.3.0: + resolution: + { + integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, + } + + domhandler@5.0.3: + resolution: + { + integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, + } + engines: { node: '>= 4' } + + domutils@3.2.2: + resolution: + { + integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==, + } + dotenv-expand@12.0.3: resolution: { @@ -4270,6 +5342,12 @@ packages: integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==, } + ee-first@1.1.1: + resolution: + { + integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, + } + ejs@5.0.1: resolution: { @@ -4296,6 +5374,20 @@ packages: integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, } + encodeurl@1.0.2: + resolution: + { + integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==, + } + engines: { node: '>= 0.8' } + + encodeurl@2.0.0: + resolution: + { + integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==, + } + engines: { node: '>= 0.8' } + end-of-stream@1.4.5: resolution: { @@ -4316,6 +5408,13 @@ packages: } engines: { node: '>=8.6' } + entities@4.5.0: + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: '>=0.12' } + entities@6.0.1: resolution: { @@ -4337,6 +5436,21 @@ packages: } engines: { node: '>=20.19.0' } + env-paths@2.2.1: + resolution: + { + integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, + } + engines: { node: '>=6' } + + envinfo@7.21.0: + resolution: + { + integrity: sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==, + } + engines: { node: '>=4' } + hasBin: true + errno@0.1.8: resolution: { @@ -4344,12 +5458,31 @@ packages: } hasBin: true + error-ex@1.3.4: + resolution: + { + integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==, + } + error-stack-parser-es@1.0.5: resolution: { integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==, } + error-stack-parser@2.1.4: + resolution: + { + integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==, + } + + errorhandler@1.5.2: + resolution: + { + integrity: sha512-kNAL7hESndBCrWwS72QyV3IVOTrVmj9D062FV5BQswNL5zEdeRmz/WJFyh6Aj/plvvSOrzddkxW57HgkZcR9Fw==, + } + engines: { node: '>= 0.8' } + es-define-property@1.0.1: resolution: { @@ -4413,6 +5546,12 @@ packages: } engines: { node: '>=6' } + escape-html@1.0.3: + resolution: + { + integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, + } + escape-string-regexp@1.0.5: resolution: { @@ -4420,6 +5559,13 @@ packages: } engines: { node: '>=0.8.0' } + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: '>=10' } + esm-env@1.2.2: resolution: { @@ -4457,19 +5603,46 @@ packages: integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, } - eventemitter3@5.0.4: + etag@1.8.1: resolution: { - integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, + integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, } + engines: { node: '>= 0.6' } - expect-type@1.4.0: + event-target-shim@5.0.1: + resolution: + { + integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==, + } + engines: { node: '>=6' } + + eventemitter3@5.0.4: + resolution: + { + integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, + } + + execa@5.1.1: + resolution: + { + integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, + } + engines: { node: '>=10' } + + expect-type@1.4.0: resolution: { integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==, } engines: { node: '>=12.0.0' } + exponential-backoff@3.1.3: + resolution: + { + integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==, + } + extendable-error@0.1.7: resolution: { @@ -4495,12 +5668,33 @@ packages: integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==, } + fast-xml-parser@4.5.7: + resolution: + { + integrity: sha512-a6Qh1RMCNbSrU1+sAyAAZH3rTe+OaWJbNZIq0S+ifZciUUOQtlVxBJwoTUE2bYhysmG/RYyI5WJFIKdBahJdrQ==, + } + hasBin: true + fastq@1.20.1: resolution: { integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==, } + fb-dotslash@0.5.8: + resolution: + { + integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==, + } + engines: { node: '>=20' } + hasBin: true + + fb-watchman@2.0.2: + resolution: + { + integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==, + } + fdir@6.5.0: resolution: { @@ -4527,6 +5721,13 @@ packages: } engines: { node: '>=8' } + finalhandler@1.1.2: + resolution: + { + integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==, + } + engines: { node: '>= 0.8' } + find-cache-directory@6.0.0: resolution: { @@ -4548,6 +5749,13 @@ packages: } engines: { node: '>=8' } + find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: '>=10' } + flat@5.0.2: resolution: { @@ -4555,6 +5763,12 @@ packages: } hasBin: true + flow-enums-runtime@0.0.6: + resolution: + { + integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==, + } + follow-redirects@1.16.0: resolution: { @@ -4581,6 +5795,13 @@ packages: } engines: { node: '>= 6' } + fresh@0.5.2: + resolution: + { + integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==, + } + engines: { node: '>= 0.6' } + fs-constants@1.0.0: resolution: { @@ -4658,6 +5879,13 @@ packages: } engines: { node: '>= 0.4' } + get-stream@6.0.1: + resolution: + { + integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, + } + engines: { node: '>=10' } + glob-parent@5.1.2: resolution: { @@ -4720,6 +5948,36 @@ packages: } engines: { node: '>= 0.4' } + hermes-compiler@250829098.0.14: + resolution: + { + integrity: sha512-5meXwsZxgiqFaJjNzwjzI9IyUkuGGBisu+z9BvQWmGVpjH6nz11hgqkyxe4dl8UAdyIV4lTbz91+Dlnjz0VxqA==, + } + + hermes-estree@0.35.0: + resolution: + { + integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==, + } + + hermes-estree@0.36.0: + resolution: + { + integrity: sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==, + } + + hermes-parser@0.35.0: + resolution: + { + integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==, + } + + hermes-parser@0.36.0: + resolution: + { + integrity: sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==, + } + html-encoding-sniffer@6.0.0: resolution: { @@ -4733,6 +5991,20 @@ packages: integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==, } + http-errors@2.0.1: + resolution: + { + integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==, + } + engines: { node: '>= 0.8' } + + https-proxy-agent@7.0.6: + resolution: + { + integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, + } + engines: { node: '>= 14' } + human-id@4.2.0: resolution: { @@ -4740,6 +6012,13 @@ packages: } hasBin: true + human-signals@2.1.0: + resolution: + { + integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, + } + engines: { node: '>=10.17.0' } + iconv-lite@0.4.24: resolution: { @@ -4781,6 +6060,14 @@ packages: } engines: { node: '>= 4' } + image-size@1.2.1: + resolution: + { + integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==, + } + engines: { node: '>=16.x' } + hasBin: true + immer@11.1.15: resolution: { @@ -4793,6 +6080,13 @@ packages: integrity: sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==, } + import-fresh@3.3.1: + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: '>=6' } + inherits@2.0.4: resolution: { @@ -4824,6 +6118,25 @@ packages: integrity: sha512-wY8QJH+6wNI0uh4pDQzMvl+478Qh7Rl4qLmqiluxALlNvl+I+o5x38Pw3/z7mDPTPS1dQalZJXsmbvxx5gclhQ==, } + invariant@2.2.4: + resolution: + { + integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==, + } + + is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + + is-core-module@2.16.2: + resolution: + { + integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==, + } + engines: { node: '>= 0.4' } + is-docker@2.2.1: resolution: { @@ -4839,6 +6152,13 @@ packages: } engines: { node: '>=0.10.0' } + is-fullwidth-code-point@2.0.0: + resolution: + { + integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==, + } + engines: { node: '>=4' } + is-fullwidth-code-point@3.0.0: resolution: { @@ -4886,6 +6206,13 @@ packages: integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==, } + is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: '>=8' } + is-subdir@1.2.0: resolution: { @@ -4921,6 +6248,13 @@ packages: } engines: { node: '>=0.10.0' } + is-wsl@1.1.0: + resolution: + { + integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==, + } + engines: { node: '>=4' } + is-wsl@2.2.0: resolution: { @@ -4940,6 +6274,40 @@ packages: integrity: sha512-tFLRAygk9NqrRPhJSnNGh7g7oaVWDwR0wKh/GM2LgmPa50Eg4UfyaCO4I8k6EqJHl1/uh2RAD6g06n5ygEnrjQ==, } + jest-get-type@29.6.3: + resolution: + { + integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-util@29.7.0: + resolution: + { + integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-validate@29.7.0: + resolution: + { + integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-worker@29.7.0: + resolution: + { + integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + joi@17.13.4: + resolution: + { + integrity: sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==, + } + js-tokens@4.0.0: resolution: { @@ -4960,6 +6328,12 @@ packages: } hasBin: true + jsc-safe-url@0.2.4: + resolution: + { + integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==, + } + jsdom@29.1.1: resolution: { @@ -4980,6 +6354,12 @@ packages: engines: { node: '>=6' } hasBin: true + json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + json-schema-traverse@1.0.0: resolution: { @@ -5012,6 +6392,13 @@ packages: integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, } + kleur@3.0.3: + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: '>=6' } + kleur@4.1.5: resolution: { @@ -5019,6 +6406,12 @@ packages: } engines: { node: '>=6' } + launch-editor@2.14.1: + resolution: + { + integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==, + } + less@4.8.1: resolution: { @@ -5027,6 +6420,19 @@ packages: engines: { node: '>=18' } hasBin: true + leven@3.1.0: + resolution: + { + integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, + } + engines: { node: '>=6' } + + lighthouse-logger@1.4.2: + resolution: + { + integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==, + } + lightningcss-android-arm64@1.33.0: resolution: { @@ -5137,6 +6543,12 @@ packages: } engines: { node: '>= 12.0.0' } + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + lines-and-columns@2.0.3: resolution: { @@ -5175,6 +6587,19 @@ packages: } engines: { node: '>=8' } + locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: '>=10' } + + lodash.debounce@4.0.8: + resolution: + { + integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==, + } + lodash.merge@4.6.2: resolution: { @@ -5187,6 +6612,12 @@ packages: integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==, } + lodash.throttle@4.1.1: + resolution: + { + integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==, + } + log-symbols@4.1.0: resolution: { @@ -5201,6 +6632,20 @@ packages: } engines: { node: '>=18' } + logkitty@0.7.1: + resolution: + { + integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==, + } + hasBin: true + + loose-envify@1.4.0: + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } + hasBin: true + lru-cache@11.5.2: resolution: { @@ -5227,6 +6672,18 @@ packages: } engines: { node: '>=18' } + makeerror@1.0.12: + resolution: + { + integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==, + } + + marky@1.3.0: + resolution: + { + integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==, + } + math-intrinsics@1.1.0: resolution: { @@ -5234,12 +6691,31 @@ packages: } engines: { node: '>= 0.4' } + mdn-data@2.0.14: + resolution: + { + integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==, + } + mdn-data@2.27.1: resolution: { integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==, } + media-typer@0.3.0: + resolution: + { + integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==, + } + engines: { node: '>= 0.6' } + + memoize-one@5.2.1: + resolution: + { + integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==, + } + merge-anything@5.1.7: resolution: { @@ -5247,6 +6723,12 @@ packages: } engines: { node: '>=12.13' } + merge-stream@2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } + merge2@1.4.1: resolution: { @@ -5254,70 +6736,200 @@ packages: } engines: { node: '>= 8' } - micromatch@4.0.8: + metro-babel-transformer@0.84.4: resolution: { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + integrity: sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==, } - engines: { node: '>=8.6' } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - mime-db@1.52.0: + metro-cache-key@0.84.4: resolution: { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + integrity: sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==, } - engines: { node: '>= 0.6' } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - mime-types@2.1.35: + metro-cache@0.84.4: resolution: { - integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + integrity: sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==, } - engines: { node: '>= 0.6' } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - mime@1.6.0: + metro-config@0.84.4: resolution: { - integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, + integrity: sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==, } - engines: { node: '>=4' } - hasBin: true + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - mimic-fn@2.1.0: + metro-core@0.84.4: resolution: { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + integrity: sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==, } - engines: { node: '>=6' } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - mimic-function@5.0.1: + metro-file-map@0.84.4: resolution: { - integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==, + integrity: sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==, } - engines: { node: '>=18' } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - miniflare@4.20260617.1: + metro-minify-terser@0.84.4: resolution: { - integrity: sha512-Go3/gzStm99QHptsSgU+q1S+xDfLoRgwjJNY80kaTVi0ENhTyqKq+sc4xZiWBSbM7uUcJwmzm8+QFKtcYLJ9nw==, + integrity: sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==, } - engines: { node: '>=22.0.0' } - hasBin: true + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - minimatch@10.2.5: + metro-resolver@0.84.4: resolution: { - integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==, + integrity: sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==, } - engines: { node: 18 || 20 || >=22 } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - minimist@1.2.8: + metro-runtime@0.84.4: + resolution: + { + integrity: sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + metro-source-map@0.84.4: + resolution: + { + integrity: sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + metro-symbolicate@0.84.4: + resolution: + { + integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + hasBin: true + + metro-transform-plugins@0.84.4: + resolution: + { + integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + metro-transform-worker@0.84.4: + resolution: + { + integrity: sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + metro@0.84.4: + resolution: + { + integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + hasBin: true + + micromatch@4.0.8: + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: '>=8.6' } + + mime-db@1.52.0: + resolution: + { + integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + } + engines: { node: '>= 0.6' } + + mime-db@1.54.0: + resolution: + { + integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==, + } + engines: { node: '>= 0.6' } + + mime-types@2.1.35: + resolution: + { + integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + } + engines: { node: '>= 0.6' } + + mime-types@3.0.2: + resolution: + { + integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==, + } + engines: { node: '>=18' } + + mime@1.6.0: + resolution: + { + integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, + } + engines: { node: '>=4' } + hasBin: true + + mime@2.6.0: + resolution: + { + integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==, + } + engines: { node: '>=4.0.0' } + hasBin: true + + mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: '>=6' } + + mimic-function@5.0.1: + resolution: + { + integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==, + } + engines: { node: '>=18' } + + miniflare@4.20260617.1: + resolution: + { + integrity: sha512-Go3/gzStm99QHptsSgU+q1S+xDfLoRgwjJNY80kaTVi0ENhTyqKq+sc4xZiWBSbM7uUcJwmzm8+QFKtcYLJ9nw==, + } + engines: { node: '>=22.0.0' } + hasBin: true + + minimatch@10.2.5: + resolution: + { + integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==, + } + engines: { node: 18 || 20 || >=22 } + + minimist@1.2.8: resolution: { integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, } + mkdirp@1.0.4: + resolution: + { + integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, + } + engines: { node: '>=10' } + hasBin: true + mri@1.2.0: resolution: { @@ -5361,6 +6973,27 @@ packages: engines: { node: '>= 4.4.x' } hasBin: true + negotiator@0.6.3: + resolution: + { + integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==, + } + engines: { node: '>= 0.6' } + + negotiator@0.6.4: + resolution: + { + integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==, + } + engines: { node: '>= 0.6' } + + negotiator@1.0.0: + resolution: + { + integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==, + } + engines: { node: '>= 0.6' } + ng-packagr@22.0.2: resolution: { @@ -5377,6 +7010,13 @@ packages: tailwindcss: optional: true + nocache@3.0.4: + resolution: + { + integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==, + } + engines: { node: '>=12.0.0' } + node-addon-api@7.1.1: resolution: { @@ -5395,6 +7035,12 @@ packages: encoding: optional: true + node-int64@0.4.0: + resolution: + { + integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, + } + node-releases@2.0.51: resolution: { @@ -5402,6 +7048,13 @@ packages: } engines: { node: '>=18' } + node-stream-zip@1.16.0: + resolution: + { + integrity: sha512-ObaRrRoR8T68wF6suxHd7R4XQNamij6ZQHrwG7Dx1D2zeHcDNLsIOBcWrIwtDm7AsCXBguaPHgXhcjxDa2szrg==, + } + engines: { node: '>=0.12.0' } + npm-run-path@4.0.1: resolution: { @@ -5409,6 +7062,18 @@ packages: } engines: { node: '>=8' } + nth-check@2.1.1: + resolution: + { + integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, + } + + nullthrows@1.1.1: + resolution: + { + integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==, + } + nx@22.7.5: resolution: { @@ -5424,6 +7089,20 @@ packages: '@swc/core': optional: true + ob1@0.84.4: + resolution: + { + integrity: sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + + object-inspect@1.13.4: + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: '>= 0.4' } + obug@2.1.4: resolution: { @@ -5449,6 +7128,27 @@ packages: vite: optional: true + on-finished@2.3.0: + resolution: + { + integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==, + } + engines: { node: '>= 0.8' } + + on-finished@2.4.1: + resolution: + { + integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==, + } + engines: { node: '>= 0.8' } + + on-headers@1.1.0: + resolution: + { + integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==, + } + engines: { node: '>= 0.8' } + once@1.4.0: resolution: { @@ -5469,6 +7169,20 @@ packages: } engines: { node: '>=18' } + open@6.4.0: + resolution: + { + integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==, + } + engines: { node: '>=8' } + + open@7.4.2: + resolution: + { + integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==, + } + engines: { node: '>=8' } + open@8.4.2: resolution: { @@ -5483,6 +7197,13 @@ packages: } engines: { node: '>=10' } + ora@5.4.1: + resolution: + { + integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==, + } + engines: { node: '>=10' } + ora@9.4.1: resolution: { @@ -5510,6 +7231,13 @@ packages: } engines: { node: '>=6' } + p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: '>=10' } + p-locate@4.1.0: resolution: { @@ -5517,6 +7245,13 @@ packages: } engines: { node: '>=8' } + p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: '>=10' } + p-map@2.1.0: resolution: { @@ -5537,6 +7272,20 @@ packages: integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==, } + parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: '>=6' } + + parse-json@5.2.0: + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: '>=8' } + parse-node-version@1.0.1: resolution: { @@ -5556,6 +7305,13 @@ packages: integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==, } + parseurl@1.3.3: + resolution: + { + integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, + } + engines: { node: '>= 0.8' } + path-exists@4.0.0: resolution: { @@ -5570,6 +7326,12 @@ packages: } engines: { node: '>=8' } + path-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + path-to-regexp@6.3.0: resolution: { @@ -5688,12 +7450,32 @@ packages: engines: { node: '>=14' } hasBin: true + pretty-format@29.7.0: + resolution: + { + integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + probe-image-size@7.3.0: resolution: { integrity: sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ==, } + promise@8.3.0: + resolution: + { + integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==, + } + + prompts@2.4.2: + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: '>= 6' } + proxy-from-env@2.1.0: resolution: { @@ -5714,6 +7496,13 @@ packages: } engines: { node: '>=6' } + qs@6.15.3: + resolution: + { + integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==, + } + engines: { node: '>=0.6' } + quansync@0.2.11: resolution: { @@ -5726,6 +7515,32 @@ packages: integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, } + queue@6.0.2: + resolution: + { + integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, + } + + range-parser@1.2.1: + resolution: + { + integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==, + } + engines: { node: '>= 0.6' } + + raw-body@2.5.3: + resolution: + { + integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==, + } + engines: { node: '>= 0.8' } + + react-devtools-core@6.1.5: + resolution: + { + integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==, + } + react-dom@19.2.3: resolution: { @@ -5734,12 +7549,44 @@ packages: peerDependencies: react: ^19.2.3 + react-is@18.3.1: + resolution: + { + integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, + } + react-is@19.2.8: resolution: { integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==, } + react-native-svg@15.15.5: + resolution: + { + integrity: sha512-L4go5jA+GWutdJ/JucuN20cjAbMg1HmMtAP+wZ+3JLCf6Jd0bhXQHxciRP/AQm/FlrIEZwkMcHNZP+FXAiic0w==, + } + peerDependencies: + react: '*' + react-native: '*' + + react-native@0.86.0: + resolution: + { + integrity: sha512-17ALh/dd6AO4pgOVmOO5Axll5PbErEo3XFyLokyzW6usyi+OShIEPwUW26wLPlhVifgSOIfECCH0WN+0IqtJ1w==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + hasBin: true + peerDependencies: + '@react-native/jest-preset': 0.86.0 + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@react-native/jest-preset': + optional: true + '@types/react': + optional: true + react-redux@9.3.0: resolution: { @@ -5755,6 +7602,13 @@ packages: redux: optional: true + react-refresh@0.14.2: + resolution: + { + integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==, + } + engines: { node: '>=0.10.0' } + react@19.2.3: resolution: { @@ -5821,6 +7675,45 @@ packages: integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==, } + regenerate-unicode-properties@10.2.2: + resolution: + { + integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==, + } + engines: { node: '>=4' } + + regenerate@1.4.2: + resolution: + { + integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==, + } + + regenerator-runtime@0.13.11: + resolution: + { + integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==, + } + + regexpu-core@6.4.0: + resolution: + { + integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==, + } + engines: { node: '>=4' } + + regjsgen@0.8.0: + resolution: + { + integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==, + } + + regjsparser@0.13.2: + resolution: + { + integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==, + } + hasBin: true + require-directory@2.1.1: resolution: { @@ -5835,12 +7728,25 @@ packages: } engines: { node: '>=0.10.0' } + require-main-filename@2.0.0: + resolution: + { + integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==, + } + reselect@5.2.0: resolution: { integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==, } + resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: '>=4' } + resolve-from@5.0.0: resolution: { @@ -5855,6 +7761,14 @@ packages: } engines: { node: '>=10' } + resolve@1.22.12: + resolution: + { + integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==, + } + engines: { node: '>= 0.4' } + hasBin: true + restore-cursor@3.1.0: resolution: { @@ -6002,6 +7916,20 @@ packages: engines: { node: '>=10' } hasBin: true + send@0.19.2: + resolution: + { + integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==, + } + engines: { node: '>= 0.8.0' } + + serialize-error@2.1.0: + resolution: + { + integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==, + } + engines: { node: '>=0.10.0' } + seroval-plugins@1.5.6: resolution: { @@ -6018,6 +7946,25 @@ packages: } engines: { node: '>=10' } + serve-static@1.16.3: + resolution: + { + integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==, + } + engines: { node: '>= 0.8.0' } + + set-blocking@2.0.0: + resolution: + { + integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, + } + + setprototypeof@1.2.0: + resolution: + { + integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, + } + sharp@0.34.5: resolution: { @@ -6039,6 +7986,41 @@ packages: } engines: { node: '>=8' } + shell-quote@1.10.0: + resolution: + { + integrity: sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==, + } + engines: { node: '>= 0.4' } + + side-channel-list@1.0.1: + resolution: + { + integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==, + } + engines: { node: '>= 0.4' } + + side-channel-map@1.0.1: + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: '>= 0.4' } + + side-channel-weakmap@1.0.2: + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: '>= 0.4' } + + side-channel@1.1.1: + resolution: + { + integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==, + } + engines: { node: '>= 0.4' } + siginfo@2.0.0: resolution: { @@ -6058,6 +8040,12 @@ packages: } engines: { node: '>=14' } + sisteransi@1.0.5: + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } + slash@3.0.0: resolution: { @@ -6065,6 +8053,13 @@ packages: } engines: { node: '>=8' } + slice-ansi@2.1.0: + resolution: + { + integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==, + } + engines: { node: '>=6' } + smol-toml@1.6.1: resolution: { @@ -6093,6 +8088,19 @@ packages: } engines: { node: '>=0.10.0' } + source-map-support@0.5.21: + resolution: + { + integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, + } + + source-map@0.5.7: + resolution: + { + integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, + } + engines: { node: '>=0.10.0' } + source-map@0.6.1: resolution: { @@ -6118,6 +8126,33 @@ packages: integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, } + stackframe@1.3.4: + resolution: + { + integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==, + } + + stacktrace-parser@0.1.11: + resolution: + { + integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==, + } + engines: { node: '>=6' } + + statuses@1.5.0: + resolution: + { + integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==, + } + engines: { node: '>= 0.6' } + + statuses@2.0.2: + resolution: + { + integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, + } + engines: { node: '>= 0.8' } + std-env@4.2.0: resolution: { @@ -6164,6 +8199,13 @@ packages: integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, } + strip-ansi@5.2.0: + resolution: + { + integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==, + } + engines: { node: '>=6' } + strip-ansi@6.0.1: resolution: { @@ -6185,6 +8227,19 @@ packages: } engines: { node: '>=4' } + strip-final-newline@2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: '>=6' } + + strnum@1.1.2: + resolution: + { + integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==, + } + supports-color@10.2.2: resolution: { @@ -6199,6 +8254,20 @@ packages: } engines: { node: '>=8' } + supports-color@8.1.1: + resolution: + { + integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, + } + engines: { node: '>=10' } + + supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: '>= 0.4' } + svelte-check@4.7.4: resolution: { @@ -6246,6 +8315,20 @@ packages: } engines: { node: '>=8' } + terser@5.49.0: + resolution: + { + integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==, + } + engines: { node: '>=10' } + hasBin: true + + throat@5.0.0: + resolution: + { + integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==, + } + tiny-invariant@1.3.3: resolution: { @@ -6299,6 +8382,12 @@ packages: } engines: { node: '>=14.14' } + tmpl@1.0.5: + resolution: + { + integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, + } + to-regex-range@5.0.1: resolution: { @@ -6306,6 +8395,13 @@ packages: } engines: { node: '>=8.0' } + toidentifier@1.0.1: + resolution: + { + integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, + } + engines: { node: '>=0.6' } + topojson-client@3.1.0: resolution: { @@ -6359,6 +8455,20 @@ packages: integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, } + type-fest@0.7.1: + resolution: + { + integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==, + } + engines: { node: '>=8' } + + type-is@1.6.18: + resolution: + { + integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, + } + engines: { node: '>= 0.6' } + typescript@6.0.3: resolution: { @@ -6393,6 +8503,34 @@ packages: integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==, } + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: + { + integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==, + } + engines: { node: '>=4' } + + unicode-match-property-ecmascript@2.0.0: + resolution: + { + integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==, + } + engines: { node: '>=4' } + + unicode-match-property-value-ecmascript@2.2.1: + resolution: + { + integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==, + } + engines: { node: '>=4' } + + unicode-property-aliases-ecmascript@2.2.0: + resolution: + { + integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==, + } + engines: { node: '>=4' } + universalify@0.1.2: resolution: { @@ -6400,6 +8538,13 @@ packages: } engines: { node: '>= 4.0.0' } + unpipe@1.0.0: + resolution: + { + integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, + } + engines: { node: '>= 0.8' } + update-browserslist-db@1.2.3: resolution: { @@ -6429,6 +8574,20 @@ packages: integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, } + utils-merge@1.0.1: + resolution: + { + integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==, + } + engines: { node: '>= 0.4.0' } + + vary@1.1.2: + resolution: + { + integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, + } + engines: { node: '>= 0.8' } + victory-vendor@37.3.6: resolution: { @@ -6549,6 +8708,12 @@ packages: jsdom: optional: true + vlq@1.0.1: + resolution: + { + integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==, + } + vue@3.5.40: resolution: { @@ -6567,6 +8732,12 @@ packages: } engines: { node: '>=18' } + walker@1.0.8: + resolution: + { + integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, + } + wcwidth@1.0.1: resolution: { @@ -6586,6 +8757,12 @@ packages: } engines: { node: '>=20' } + whatwg-fetch@3.6.20: + resolution: + { + integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==, + } + whatwg-mimetype@5.0.0: resolution: { @@ -6606,6 +8783,12 @@ packages: integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, } + which-module@2.0.1: + resolution: + { + integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==, + } + which@2.0.2: resolution: { @@ -6649,6 +8832,13 @@ packages: '@cloudflare/workers-types': optional: true + wrap-ansi@6.2.0: + resolution: + { + integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, + } + engines: { node: '>=8' } + wrap-ansi@7.0.0: resolution: { @@ -6669,6 +8859,35 @@ packages: integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, } + ws@6.2.6: + resolution: + { + integrity: sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==, + } + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@7.5.13: + resolution: + { + integrity: sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==, + } + engines: { node: '>=8.3.0' } + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.21.0: resolution: { @@ -6697,6 +8916,12 @@ packages: integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==, } + y18n@4.0.3: + resolution: + { + integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==, + } + y18n@5.0.8: resolution: { @@ -6718,6 +8943,13 @@ packages: engines: { node: '>= 14.6' } hasBin: true + yargs-parser@18.1.3: + resolution: + { + integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==, + } + engines: { node: '>=6' } + yargs-parser@21.1.1: resolution: { @@ -6732,6 +8964,13 @@ packages: } engines: { node: ^20.19.0 || ^22.12.0 || >=23 } + yargs@15.4.1: + resolution: + { + integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==, + } + engines: { node: '>=8' } + yargs@17.7.2: resolution: { @@ -6746,6 +8985,13 @@ packages: } engines: { node: ^20.19.0 || ^22.12.0 || >=23 } + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: '>=10' } + yoctocolors@2.2.0: resolution: { @@ -6886,56 +9132,344 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.29.7': + '@babel/helper-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.7 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + debug: 4.4.3(supports-color@10.2.2) + lodash.debounce: 4.0.8 + resolve: 1.22.12 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@10.2.2)': + dependencies: + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-module-imports@7.29.7(supports-color@10.2.2)': + dependencies: + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-wrap-function': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@10.2.2)': + dependencies: + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helper-wrap-function@7.29.7(supports-color@10.2.2)': + dependencies: + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-proposal-export-default-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-export-default-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-flow-strip-types@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/compat-data': 7.29.7 - '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.7 - lru-cache: 5.1.1 - semver: 6.3.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-globals@7.29.7': {} + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-module-imports@7.18.6': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/types': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-module-imports@7.29.7(supports-color@10.2.2)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.7(supports-color@10.2.2) - '@babel/types': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.29.7': {} + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color - '@babel/helper-string-parser@7.29.7': {} + '@babel/plugin-transform-react-display-name@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-validator-identifier@7.29.7': {} + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-validator-option@7.29.7': {} + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/helpers@7.29.7': + '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/template': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color - '@babel/parser@7.29.7': + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/types': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + '@babel/plugin-transform-runtime@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 '@babel/runtime@7.29.7': {} @@ -7362,6 +9896,12 @@ snapshots: optionalDependencies: '@noble/hashes': 2.2.0 + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -7465,8 +10005,23 @@ snapshots: optionalDependencies: '@types/node': 25.9.5 + '@isaacs/ttlcache@1.4.1': {} + '@jest/diff-sequences@30.0.1': {} + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.12 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.9.5 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7479,6 +10034,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -7723,6 +10283,277 @@ snapshots: '@poppinss/exception@1.2.3': {} + '@react-native-community/cli-clean@20.1.0': + dependencies: + '@react-native-community/cli-tools': 20.1.0 + execa: 5.1.1 + fast-glob: 3.3.3 + picocolors: 1.1.1 + + '@react-native-community/cli-config-android@20.1.0': + dependencies: + '@react-native-community/cli-tools': 20.1.0 + fast-glob: 3.3.3 + fast-xml-parser: 4.5.7 + picocolors: 1.1.1 + + '@react-native-community/cli-config-apple@20.1.0': + dependencies: + '@react-native-community/cli-tools': 20.1.0 + execa: 5.1.1 + fast-glob: 3.3.3 + picocolors: 1.1.1 + + '@react-native-community/cli-config@20.1.0(typescript@6.0.3)': + dependencies: + '@react-native-community/cli-tools': 20.1.0 + cosmiconfig: 9.0.2(typescript@6.0.3) + deepmerge: 4.3.1 + fast-glob: 3.3.3 + joi: 17.13.4 + picocolors: 1.1.1 + transitivePeerDependencies: + - typescript + + '@react-native-community/cli-doctor@20.1.0(typescript@6.0.3)': + dependencies: + '@react-native-community/cli-config': 20.1.0(typescript@6.0.3) + '@react-native-community/cli-platform-android': 20.1.0 + '@react-native-community/cli-platform-apple': 20.1.0 + '@react-native-community/cli-platform-ios': 20.1.0 + '@react-native-community/cli-tools': 20.1.0 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.21.0 + execa: 5.1.1 + node-stream-zip: 1.16.0 + ora: 5.4.1 + picocolors: 1.1.1 + semver: 7.8.5 + wcwidth: 1.0.1 + yaml: 2.9.0 + transitivePeerDependencies: + - typescript + + '@react-native-community/cli-platform-android@20.1.0': + dependencies: + '@react-native-community/cli-config-android': 20.1.0 + '@react-native-community/cli-tools': 20.1.0 + execa: 5.1.1 + logkitty: 0.7.1 + picocolors: 1.1.1 + + '@react-native-community/cli-platform-apple@20.1.0': + dependencies: + '@react-native-community/cli-config-apple': 20.1.0 + '@react-native-community/cli-tools': 20.1.0 + execa: 5.1.1 + fast-xml-parser: 4.5.7 + picocolors: 1.1.1 + + '@react-native-community/cli-platform-ios@20.1.0': + dependencies: + '@react-native-community/cli-platform-apple': 20.1.0 + + '@react-native-community/cli-server-api@20.1.0(supports-color@10.2.2)': + dependencies: + '@react-native-community/cli-tools': 20.1.0 + body-parser: 1.20.6(supports-color@10.2.2) + compression: 1.8.1(supports-color@10.2.2) + connect: 3.7.0(supports-color@10.2.2) + errorhandler: 1.5.2 + nocache: 3.0.4 + open: 6.4.0 + pretty-format: 29.7.0 + serve-static: 1.16.3(supports-color@10.2.2) + ws: 6.2.6 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native-community/cli-tools@20.1.0': + dependencies: + '@vscode/sudo-prompt': 9.3.2 + appdirsjs: 1.2.8 + execa: 5.1.1 + find-up: 5.0.0 + launch-editor: 2.14.1 + mime: 2.6.0 + ora: 5.4.1 + picocolors: 1.1.1 + prompts: 2.4.2 + semver: 7.8.5 + + '@react-native-community/cli-types@20.1.0': + dependencies: + joi: 17.13.4 + + '@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@react-native-community/cli-clean': 20.1.0 + '@react-native-community/cli-config': 20.1.0(typescript@6.0.3) + '@react-native-community/cli-doctor': 20.1.0(typescript@6.0.3) + '@react-native-community/cli-server-api': 20.1.0(supports-color@10.2.2) + '@react-native-community/cli-tools': 20.1.0 + '@react-native-community/cli-types': 20.1.0 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 5.0.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + picocolors: 1.1.1 + prompts: 2.4.2 + semver: 7.8.5 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + + '@react-native/assets-registry@0.86.0': {} + + '@react-native/babel-plugin-codegen@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@react-native/codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2)) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@react-native/babel-preset@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-export-default-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-flow-strip-types': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@react-native/babel-plugin-codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-syntax-hermes-parser: 0.36.0 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.7(supports-color@10.2.2)) + react-refresh: 0.14.2 + transitivePeerDependencies: + - supports-color + + '@react-native/codegen@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/parser': 7.29.7 + hermes-parser: 0.36.0 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.17 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.86.0(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@react-native/dev-middleware': 0.86.0(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + invariant: 2.2.4 + metro: 0.84.4(supports-color@10.2.2) + metro-config: 0.84.4(supports-color@10.2.2) + metro-core: 0.84.4 + semver: 7.8.5 + optionalDependencies: + '@react-native-community/cli': 20.1.0(supports-color@10.2.2)(typescript@6.0.3) + '@react-native/metro-config': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.86.0': {} + + '@react-native/debugger-shell@0.86.0(supports-color@10.2.2)': + dependencies: + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@10.2.2) + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color + + '@react-native/dev-middleware@0.86.0(supports-color@10.2.2)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.86.0 + '@react-native/debugger-shell': 0.86.0(supports-color@10.2.2) + chrome-launcher: 0.15.2(supports-color@10.2.2) + chromium-edge-launcher: 0.3.0(supports-color@10.2.2) + connect: 3.7.0(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.3(supports-color@10.2.2) + ws: 7.5.13 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.86.0': {} + + '@react-native/js-polyfills@0.86.0': {} + + '@react-native/metro-babel-transformer@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@react-native/babel-preset': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + hermes-parser: 0.36.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@react-native/js-polyfills': 0.86.0 + '@react-native/metro-babel-transformer': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + metro-config: 0.84.4(supports-color@10.2.2) + metro-runtime: 0.84.4 + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/normalize-colors@0.86.0': {} + + '@react-native/typescript-config@0.86.0': {} + + '@react-native/virtualized-lists@0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.3 + react-native: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + optionalDependencies: + '@types/react': 19.2.17 + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.3)(redux@5.0.1))(react@19.2.3)': dependencies: '@standard-schema/spec': 1.1.0 @@ -7881,6 +10712,16 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.27.12': {} + '@sindresorhus/is@7.2.0': {} '@speed-highlight/core@1.2.17': {} @@ -7906,23 +10747,23 @@ snapshots: transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0))': + '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.4 svelte: 5.56.8 - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) - '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0))': + '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.4 svelte: 5.56.8 - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) '@tsrx/core@0.1.48': dependencies: @@ -8052,6 +10893,16 @@ snapshots: '@types/geojson@7946.0.16': {} + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/jsdom@27.0.0': dependencies: '@types/node': 25.9.5 @@ -8087,10 +10938,16 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@vitejs/plugin-react@6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0))': + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@vitejs/plugin-react@6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) '@vitest/expect@4.1.10': dependencies: @@ -8101,13 +10958,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -8133,6 +10990,8 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 + '@vscode/sudo-prompt@9.3.2': {} + '@vue/compiler-core@3.5.40': dependencies: '@babel/parser': 7.29.7 @@ -8199,8 +11058,24 @@ snapshots: dependencies: argparse: 2.0.1 + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn@8.17.0: {} + agent-base@7.1.4: {} + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -8212,18 +11087,36 @@ snapshots: dependencies: '@vue/reactivity': 3.1.5 + anser@1.4.10: {} + ansi-colors@4.1.3: {} + ansi-fragments@0.2.1: + dependencies: + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 + + ansi-regex@4.1.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + appdirsjs@1.2.8: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -8234,8 +11127,14 @@ snapshots: array-union@2.1.0: {} + asap@2.0.6: {} + assertion-error@2.0.1: {} + astral-regex@1.0.0: {} + + async-limiter@1.0.1: {} + asynckit@0.4.0: {} axios@1.16.0(debug@4.4.3(supports-color@10.2.2)): @@ -8257,6 +11156,40 @@ snapshots: html-entities: 2.3.3 parse5: 7.3.0 + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + core-js-compat: 3.49.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + babel-plugin-syntax-hermes-parser@0.36.0: + dependencies: + hermes-parser: 0.36.0 + + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.29.7(supports-color@10.2.2)): + dependencies: + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + transitivePeerDependencies: + - '@babel/core' + babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@10.2.2))(solid-js@1.9.14): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -8288,6 +11221,25 @@ snapshots: blake3-wasm@2.1.5: {} + body-parser@1.20.6(supports-color@10.2.2): + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9(supports-color@10.2.2) + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + boolbase@1.0.0: {} + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.3 @@ -8308,16 +11260,35 @@ snapshots: node-releases: 2.0.51 update-browserslist-db: 1.2.3(browserslist@4.28.7) + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + bytes@3.1.2: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + caniuse-lite@1.0.30001806: {} chai@6.2.2: {} @@ -8343,6 +11314,29 @@ snapshots: dependencies: readdirp: 5.0.0 + chrome-launcher@0.15.2(supports-color@10.2.2): + dependencies: + '@types/node': 25.9.5 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.3.0(supports-color@10.2.2): + dependencies: + '@types/node': 25.9.5 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2(supports-color@10.2.2) + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -8355,6 +11349,12 @@ snapshots: cli-spinners@3.4.0: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -8371,24 +11371,65 @@ snapshots: clsx@2.1.1: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} + colorette@1.4.0: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 + command-exists@1.2.9: {} + + commander@12.1.0: {} + commander@14.0.3: {} commander@2.20.3: {} commander@7.2.0: {} + commander@9.5.0: {} + common-path-prefix@3.0.0: {} + compressible@2.0.18: + dependencies: + mime-db: 1.52.0 + + compression@1.8.1(supports-color@10.2.2): + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9(supports-color@10.2.2) + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + connect@3.7.0(supports-color@10.2.2): + dependencies: + debug: 2.6.9(supports-color@10.2.2) + finalhandler: 1.1.2(supports-color@10.2.2) + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + + content-type@1.0.5: {} + convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} @@ -8399,17 +11440,45 @@ snapshots: dependencies: is-what: 4.1.16 + core-js-compat@3.49.0: + dependencies: + browserslist: 4.28.7 + + cosmiconfig@9.0.2(typescript@6.0.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.3.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 6.0.3 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + css-tree@3.2.1: dependencies: mdn-data: 2.27.1 source-map-js: 1.2.1 + css-what@6.2.2: {} + csstype@3.2.3: {} d3-array@2.12.1: @@ -8590,12 +11659,13 @@ snapshots: dataloader@1.4.0: {} + dayjs@1.11.21: {} + debug@2.6.9(supports-color@10.2.2): dependencies: ms: 2.0.0 optionalDependencies: supports-color: 10.2.2 - optional: true debug@3.2.7(supports-color@10.2.2): dependencies: @@ -8610,6 +11680,8 @@ snapshots: optionalDependencies: supports-color: 10.2.2 + decamelize@1.2.0: {} + decimal.js-light@2.5.1: {} decimal.js@10.6.0: {} @@ -8630,8 +11702,12 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + dependency-graph@1.0.0: {} + destroy@1.2.0: {} + detect-indent@6.1.0: {} detect-libc@2.1.2: {} @@ -8642,6 +11718,24 @@ snapshots: dependencies: path-type: 4.0.0 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dotenv-expand@12.0.3: dependencies: dotenv: 16.4.7 @@ -8661,6 +11755,8 @@ snapshots: tslib: 2.3.0 zrender: 6.1.0 + ee-first@1.1.1: {} + ejs@5.0.1: {} electron-to-chromium@1.5.397: {} @@ -8669,6 +11765,10 @@ snapshots: emoji-regex@8.0.0: {} + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -8682,19 +11782,38 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@4.5.0: {} + entities@6.0.1: {} entities@7.0.1: {} entities@8.0.0: {} + env-paths@2.2.1: {} + + envinfo@7.21.0: {} + errno@0.1.8: dependencies: prr: 1.0.1 optional: true + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + error-stack-parser-es@1.0.5: {} + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + errorhandler@1.5.2: + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -8774,8 +11893,12 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@4.0.0: {} + esm-env@1.2.2: {} esprima@4.0.1: {} @@ -8790,10 +11913,28 @@ snapshots: dependencies: '@types/estree': 1.0.9 + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + eventemitter3@5.0.4: {} + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + expect-type@1.4.0: {} + exponential-backoff@3.1.3: {} + extendable-error@0.1.7: {} fast-deep-equal@3.1.3: {} @@ -8808,10 +11949,20 @@ snapshots: fast-uri@3.1.4: {} + fast-xml-parser@4.5.7: + dependencies: + strnum: 1.1.2 + fastq@1.20.1: dependencies: reusify: 1.1.0 + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 @@ -8824,6 +11975,18 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@1.1.2(supports-color@10.2.2): + dependencies: + debug: 2.6.9(supports-color@10.2.2) + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-cache-directory@6.0.0: dependencies: common-path-prefix: 3.0.0 @@ -8836,8 +11999,15 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + flat@5.0.2: {} + flow-enums-runtime@0.0.6: {} + follow-redirects@1.16.0(debug@4.4.3(supports-color@10.2.2)): optionalDependencies: debug: 4.4.3(supports-color@10.2.2) @@ -8858,6 +12028,8 @@ snapshots: hasown: 2.0.4 mime-types: 2.1.35 + fresh@0.5.2: {} + fs-constants@1.0.0: {} fs-extra@7.0.1: @@ -8904,6 +12076,8 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@6.0.1: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8937,6 +12111,20 @@ snapshots: dependencies: function-bind: 1.1.2 + hermes-compiler@250829098.0.14: {} + + hermes-estree@0.35.0: {} + + hermes-estree@0.36.0: {} + + hermes-parser@0.35.0: + dependencies: + hermes-estree: 0.35.0 + + hermes-parser@0.36.0: + dependencies: + hermes-estree: 0.36.0 + html-encoding-sniffer@6.0.0(@noble/hashes@2.2.0): dependencies: '@exodus/bytes': 1.15.1(@noble/hashes@2.2.0) @@ -8945,12 +12133,28 @@ snapshots: html-entities@2.3.3: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6(supports-color@10.2.2): + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + human-id@4.2.0: {} + human-signals@2.1.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - optional: true iconv-lite@0.6.3: dependencies: @@ -8966,10 +12170,19 @@ snapshots: ignore@7.0.5: {} + image-size@1.2.1: + dependencies: + queue: 6.0.2 + immer@11.1.15: {} immutable@5.1.9: {} + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + inherits@2.0.4: {} injection-js@2.6.1: @@ -8984,10 +12197,22 @@ snapshots: dependencies: binary-search-bounds: 2.0.5 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + + is-arrayish@0.2.1: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + is-docker@2.2.1: {} is-extglob@2.1.1: {} + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-glob@4.0.3: @@ -9006,6 +12231,8 @@ snapshots: dependencies: '@types/estree': 1.0.9 + is-stream@2.0.1: {} + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 @@ -9018,6 +12245,8 @@ snapshots: is-windows@1.0.2: {} + is-wsl@1.1.0: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -9026,6 +12255,41 @@ snapshots: isoformat@0.2.1: {} + jest-get-type@29.6.3: {} + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.9.5 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-worker@29.7.0: + dependencies: + '@types/node': 25.9.5 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + joi@17.13.4: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + js-tokens@4.0.0: {} js-yaml@3.15.0: @@ -9037,6 +12301,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsc-safe-url@0.2.4: {} + jsdom@29.1.1(@noble/hashes@2.2.0): dependencies: '@asamuzakjp/css-color': 5.1.11 @@ -9065,6 +12331,8 @@ snapshots: jsesc@3.1.0: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@1.0.0: {} json5@2.2.3: {} @@ -9077,8 +12345,15 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + kleur@3.0.3: {} + kleur@4.1.5: {} + launch-editor@2.14.1: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.10.0 + less@4.8.1(supports-color@10.2.2): dependencies: copy-anything: 3.0.5 @@ -9094,6 +12369,15 @@ snapshots: transitivePeerDependencies: - supports-color + leven@3.1.0: {} + + lighthouse-logger@1.4.2(supports-color@10.2.2): + dependencies: + debug: 2.6.9(supports-color@10.2.2) + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lightningcss-android-arm64@1.33.0: optional: true @@ -9143,6 +12427,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 + lines-and-columns@1.2.4: {} + lines-and-columns@2.0.3: {} lit-element@4.2.2: @@ -9167,43 +12453,249 @@ snapshots: dependencies: p-locate: 4.1.0 + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.debounce@4.0.8: {} + lodash.merge@4.6.2: optional: true lodash.startcase@4.4.0: {} + lodash.throttle@4.1.1: {} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - log-symbols@7.0.1: + log-symbols@7.0.1: + dependencies: + is-unicode-supported: 2.1.0 + yoctocolors: 2.2.0 + + logkitty@0.7.1: + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.21 + yargs: 15.4.1 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@11.5.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-dir@5.1.0: + optional: true + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + + math-intrinsics@1.1.0: {} + + mdn-data@2.0.14: {} + + mdn-data@2.27.1: {} + + media-typer@0.3.0: {} + + memoize-one@5.2.1: {} + + merge-anything@5.1.7: + dependencies: + is-what: 4.1.16 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + metro-babel-transformer@0.84.4(supports-color@10.2.2): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.84.4 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.84.4(supports-color@10.2.2): + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + metro-core: 0.84.4 + transitivePeerDependencies: + - supports-color + + metro-config@0.84.4(supports-color@10.2.2): + dependencies: + connect: 3.7.0(supports-color@10.2.2) + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.4(supports-color@10.2.2) + metro-cache: 0.84.4(supports-color@10.2.2) + metro-core: 0.84.4 + metro-runtime: 0.84.4 + yaml: 2.9.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.4 + + metro-file-map@0.84.4(supports-color@10.2.2): + dependencies: + debug: 4.4.3(supports-color@10.2.2) + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.84.4: dependencies: - is-unicode-supported: 2.1.0 - yoctocolors: 2.2.0 - - lru-cache@11.5.2: {} + flow-enums-runtime: 0.0.6 + terser: 5.49.0 - lru-cache@5.1.1: + metro-resolver@0.84.4: dependencies: - yallist: 3.1.1 + flow-enums-runtime: 0.0.6 - magic-string@0.30.21: + metro-runtime@0.84.4: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@babel/runtime': 7.29.7 + flow-enums-runtime: 0.0.6 - make-dir@5.1.0: - optional: true + metro-source-map@0.84.4(supports-color@10.2.2): + dependencies: + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.4(supports-color@10.2.2) + nullthrows: 1.1.1 + ob1: 0.84.4 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color - math-intrinsics@1.1.0: {} + metro-symbolicate@0.84.4(supports-color@10.2.2): + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.4(supports-color@10.2.2) + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color - mdn-data@2.27.1: {} + metro-transform-plugins@0.84.4(supports-color@10.2.2): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/generator': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color - merge-anything@5.1.7: + metro-transform-worker@0.84.4(supports-color@10.2.2): dependencies: - is-what: 4.1.16 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + flow-enums-runtime: 0.0.6 + metro: 0.84.4(supports-color@10.2.2) + metro-babel-transformer: 0.84.4(supports-color@10.2.2) + metro-cache: 0.84.4(supports-color@10.2.2) + metro-cache-key: 0.84.4 + metro-minify-terser: 0.84.4 + metro-source-map: 0.84.4(supports-color@10.2.2) + metro-transform-plugins: 0.84.4(supports-color@10.2.2) + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - merge2@1.4.1: {} + metro@0.84.4(supports-color@10.2.2): + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@10.2.2) + '@babel/types': 7.29.7 + accepts: 2.0.0 + ci-info: 2.0.0 + connect: 3.7.0(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.4(supports-color@10.2.2) + metro-cache: 0.84.4(supports-color@10.2.2) + metro-cache-key: 0.84.4 + metro-config: 0.84.4(supports-color@10.2.2) + metro-core: 0.84.4 + metro-file-map: 0.84.4(supports-color@10.2.2) + metro-resolver: 0.84.4 + metro-runtime: 0.84.4 + metro-source-map: 0.84.4(supports-color@10.2.2) + metro-symbolicate: 0.84.4(supports-color@10.2.2) + metro-transform-plugins: 0.84.4(supports-color@10.2.2) + metro-transform-worker: 0.84.4(supports-color@10.2.2) + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.13 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate micromatch@4.0.8: dependencies: @@ -9212,12 +12704,19 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - mime@1.6.0: - optional: true + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@1.6.0: {} + + mime@2.6.0: {} mimic-fn@2.1.0: {} @@ -9241,10 +12740,11 @@ snapshots: minimist@1.2.8: {} + mkdirp@1.0.4: {} + mri@1.2.0: {} - ms@2.0.0: - optional: true + ms@2.0.0: {} ms@2.1.3: {} @@ -9265,6 +12765,12 @@ snapshots: sax: 1.6.1 optional: true + negotiator@0.6.3: {} + + negotiator@0.6.4: {} + + negotiator@1.0.0: {} + ng-packagr@22.0.2(@angular/compiler-cli@22.0.8(@angular/compiler@22.0.8)(supports-color@10.2.2)(typescript@6.0.3))(supports-color@10.2.2)(tslib@2.8.1)(typescript@6.0.3): dependencies: '@ampproject/remapping': 2.3.0 @@ -9295,6 +12801,8 @@ snapshots: transitivePeerDependencies: - supports-color + nocache@3.0.4: {} + node-addon-api@7.1.1: optional: true @@ -9302,12 +12810,22 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-int64@0.4.0: {} + node-releases@2.0.51: {} + node-stream-zip@1.16.0: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nullthrows@1.1.1: {} + nx@22.7.5(debug@4.4.3(supports-color@10.2.2)): dependencies: '@emnapi/core': 1.4.5 @@ -9434,9 +12952,15 @@ snapshots: transitivePeerDependencies: - debug + ob1@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + + object-inspect@1.13.4: {} + obug@2.1.4: {} - octane@0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + octane@0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@tsrx/core': 0.1.48 '@types/react': 19.2.17 @@ -9445,11 +12969,11 @@ snapshots: optionalDependencies: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@typescript-eslint/types' - octane@0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + octane@0.1.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@tsrx/core': 0.1.48 '@types/react': 19.2.17 @@ -9458,10 +12982,20 @@ snapshots: optionalDependencies: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@typescript-eslint/types' + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + on-headers@1.1.0: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -9474,6 +13008,15 @@ snapshots: dependencies: mimic-function: 5.0.1 + open@6.4.0: + dependencies: + is-wsl: 1.1.0 + + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -9491,6 +13034,18 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + ora@9.4.1: dependencies: chalk: 5.6.2 @@ -9512,10 +13067,18 @@ snapshots: dependencies: p-try: 2.2.0 + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + p-map@2.1.0: {} p-try@2.2.0: {} @@ -9524,6 +13087,17 @@ snapshots: dependencies: quansync: 0.2.11 + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse-node-version@1.0.1: {} parse5@7.3.0: @@ -9534,10 +13108,14 @@ snapshots: dependencies: entities: 8.0.0 + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-key@3.1.1: {} + path-parse@1.0.7: {} + path-to-regexp@6.3.0: {} path-type@4.0.0: {} @@ -9586,6 +13164,12 @@ snapshots: prettier@3.9.6: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + probe-image-size@7.3.0(supports-color@10.2.2): dependencies: lodash.merge: 4.6.2 @@ -9595,6 +13179,15 @@ snapshots: - supports-color optional: true + promise@8.3.0: + dependencies: + asap: 2.0.6 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + proxy-from-env@2.1.0: {} prr@1.0.1: @@ -9602,17 +13195,97 @@ snapshots: punycode@2.3.1: {} + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + quansync@0.2.11: {} queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + react-devtools-core@6.1.5: + dependencies: + shell-quote: 1.10.0 + ws: 7.5.13 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + react-dom@19.2.3(react@19.2.3): dependencies: react: 19.2.3 scheduler: 0.27.0 + react-is@18.3.1: {} + react-is@19.2.8: {} + react-native-svg@15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + dependencies: + css-select: 5.2.2 + css-tree: 1.1.3 + react: 19.2.3 + react-native: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2): + dependencies: + '@react-native/assets-registry': 0.86.0 + '@react-native/codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2)) + '@react-native/community-cli-plugin': 0.86.0(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/gradle-plugin': 0.86.0 + '@react-native/js-polyfills': 0.86.0 + '@react-native/normalize-colors': 0.86.0 + '@react-native/virtualized-lists': 0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.36.0 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.14 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.4 + metro-source-map: 0.84.4(supports-color@10.2.2) + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.3 + react-devtools-core: 6.1.5 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.8.5 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.17 + whatwg-fetch: 3.6.20 + ws: 7.5.13 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.2.17 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + react-redux@9.3.0(@types/react@19.2.17)(react@19.2.3)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 @@ -9622,6 +13295,8 @@ snapshots: '@types/react': 19.2.17 redux: 5.0.1 + react-refresh@0.14.2: {} + react@19.2.3: {} read-yaml-file@1.1.0: @@ -9669,16 +13344,50 @@ snapshots: reflect-metadata@0.2.2: {} + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regenerator-runtime@0.13.11: {} + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.2 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.13.2: + dependencies: + jsesc: 3.1.0 + require-directory@2.1.1: {} require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + reselect@5.2.0: {} + resolve-from@4.0.0: {} + resolve-from@5.0.0: {} resolve.exports@2.0.3: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -9799,12 +13508,45 @@ snapshots: semver@7.8.5: {} + send@0.19.2(supports-color@10.2.2): + dependencies: + debug: 2.6.9(supports-color@10.2.2) + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-error@2.1.0: {} + seroval-plugins@1.5.6(seroval@1.5.6): dependencies: seroval: 1.5.6 seroval@1.5.6: {} + serve-static@1.16.3(supports-color@10.2.2): + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + setprototypeof@1.2.0: {} + sharp@0.34.5: dependencies: '@img/colour': 1.1.0 @@ -9842,14 +13584,52 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.10.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@3.0.7: {} signal-exit@4.1.0: {} + sisteransi@1.0.5: {} + slash@3.0.0: {} + slice-ansi@2.1.0: + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + smol-toml@1.6.1: {} solid-js@1.9.14: @@ -9869,8 +13649,14 @@ snapshots: source-map-js@1.2.1: {} - source-map@0.6.1: - optional: true + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} spawndamnit@3.0.1: dependencies: @@ -9881,6 +13667,16 @@ snapshots: stackback@0.0.2: {} + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + + statuses@2.0.2: {} + std-env@4.2.0: {} stdin-discarder@0.3.2: {} @@ -9913,6 +13709,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -9923,12 +13723,22 @@ snapshots: strip-bom@3.0.0: {} + strip-final-newline@2.0.0: {} + + strnum@1.1.2: {} + supports-color@10.2.2: {} supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + svelte-check@4.7.4(picomatch@4.0.5)(svelte@5.56.8)(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -9982,6 +13792,15 @@ snapshots: term-size@2.2.1: {} + terser@5.49.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.17.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + throat@5.0.0: {} + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -10003,10 +13822,14 @@ snapshots: tmp@0.2.6: {} + tmpl@1.0.5: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + topojson-client@3.1.0: dependencies: commander: 2.20.3 @@ -10033,6 +13856,13 @@ snapshots: tslib@2.8.1: {} + type-fest@0.7.1: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + typescript@6.0.3: {} undici-types@7.24.6: {} @@ -10045,8 +13875,21 @@ snapshots: dependencies: pathe: 2.0.3 + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + universalify@0.1.2: {} + unpipe@1.0.0: {} + update-browserslist-db@1.2.3(browserslist@4.28.7): dependencies: browserslist: 4.28.7 @@ -10061,6 +13904,10 @@ snapshots: util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} + + vary@1.1.2: {} + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.2 @@ -10078,7 +13925,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-solid@2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + vite-plugin-solid@2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@types/babel__core': 7.20.5 @@ -10086,12 +13933,12 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.9.14 solid-refresh: 0.6.3(solid-js@1.9.14)(supports-color@10.2.2) - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) transitivePeerDependencies: - supports-color - vite-plugin-solid@2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + vite-plugin-solid@2.11.14(solid-js@1.9.14)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@types/babel__core': 7.20.5 @@ -10099,12 +13946,12 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.9.14 solid-refresh: 0.6.3(solid-js@1.9.14)(supports-color@10.2.2) - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) transitivePeerDependencies: - supports-color - vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0): + vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -10117,9 +13964,10 @@ snapshots: fsevents: 2.3.3 less: 4.8.1(supports-color@10.2.2) sass: 1.102.0 + terser: 5.49.0 yaml: 2.9.0 - vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0): + vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -10132,20 +13980,21 @@ snapshots: fsevents: 2.3.3 less: 4.8.1(supports-color@10.2.2) sass: 1.102.0 + terser: 5.49.0 yaml: 2.9.0 - vitefu@1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + vitefu@1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): optionalDependencies: - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) - vitefu@1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + vitefu@1.1.3(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): optionalDependencies: - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) - vitest@4.1.10(@types/node@25.9.5)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)): + vitest@4.1.10(@types/node@25.9.5)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -10162,7 +14011,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.5 @@ -10170,6 +14019,8 @@ snapshots: transitivePeerDependencies: - msw + vlq@1.0.1: {} + vue@3.5.40(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.40 @@ -10184,6 +14035,10 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -10192,6 +14047,8 @@ snapshots: webidl-conversions@8.0.1: {} + whatwg-fetch@3.6.20: {} + whatwg-mimetype@5.0.0: {} whatwg-url@16.0.1(@noble/hashes@2.2.0): @@ -10207,6 +14064,8 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + which-module@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -10242,6 +14101,12 @@ snapshots: - bufferutil - utf-8-validate + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -10256,22 +14121,49 @@ snapshots: wrappy@1.0.2: {} + ws@6.2.6: + dependencies: + async-limiter: 1.0.1 + + ws@7.5.13: {} + ws@8.21.0: {} xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} yaml@2.9.0: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} yargs-parser@22.0.0: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -10291,6 +14183,8 @@ snapshots: y18n: 5.0.8 yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} + yoctocolors@2.2.0: {} youch-core@0.3.3: diff --git a/scripts/check-react-native-types.mjs b/scripts/check-react-native-types.mjs new file mode 100644 index 00000000..a524b052 --- /dev/null +++ b/scripts/check-react-native-types.mjs @@ -0,0 +1,60 @@ +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +const root = resolve(import.meta.dirname, '..') +const tsc = resolve(root, 'node_modules/typescript/bin/tsc') +const passingConfigs = [ + 'packages/react-native-charts/tsconfig.json', + 'examples/charts-react-native/tsconfig.json', +] + +for (const config of passingConfigs) { + const result = runTypeScript(config) + if (result.status !== 0) { + process.stderr.write(result.output) + throw new Error(`TypeScript failed for ${config}`) + } +} + +const strictConfig = 'examples/charts-react-native/tsconfig.strict.json' +const strict = runTypeScript(strictConfig) +if (strict.status === 0) { + console.log('React Native source and strict consumer typechecks passed.') + process.exit(0) +} + +const diagnostics = strict.output + .split(/\r?\n/) + .map((line) => line.trim()) + .filter(Boolean) +const expected = diagnostics.every( + (line) => + line.includes('/@types/d3-array/') && + line.includes("Cannot find name 'ImageData'."), +) + +if (!expected || diagnostics.length !== 2) { + process.stderr.write(strict.output) + throw new Error( + 'The strict React Native consumer has diagnostics beyond the known @types/d3-array ImageData boundary.', + ) +} + +console.log( + 'React Native source and consumer typechecks passed; strict dependency checking reached only the two known @types/d3-array ImageData diagnostics.', +) + +function runTypeScript(config) { + const result = spawnSync( + process.execPath, + [tsc, '--noEmit', '-p', config, '--pretty', 'false'], + { + cwd: root, + encoding: 'utf8', + }, + ) + return { + status: result.status, + output: `${result.stdout ?? ''}${result.stderr ?? ''}`, + } +} diff --git a/scripts/measure-bundles.mjs b/scripts/measure-bundles.mjs index aa042d31..bc1795a4 100644 --- a/scripts/measure-bundles.mjs +++ b/scripts/measure-bundles.mjs @@ -27,6 +27,29 @@ const rendererBoundaryModules = { 'packages/charts-core/src/svg.ts', 'packages/react-charts/src/Chart.tsx', ], + native: [ + 'packages/react-native-charts/src/Chart.tsx', + 'packages/react-native-charts/src/FocusOverlay.tsx', + 'packages/react-native-charts/src/SvgScene.tsx', + 'packages/react-native-charts/src/Tooltip.tsx', + ], + browser: [ + 'packages/charts-core/src/adapter.ts', + 'packages/charts-core/src/adapter-renderer.ts', + 'packages/charts-core/src/canvas.ts', + 'packages/charts-core/src/dom.ts', + 'packages/charts-core/src/dom-text.ts', + 'packages/charts-core/src/export.ts', + 'packages/charts-core/src/reconcile.ts', + 'packages/charts-core/src/renderer.ts', + 'packages/charts-core/src/svg-renderer.ts', + 'packages/charts-core/src/svg-resources.ts', + 'packages/charts-core/src/svg-surface.ts', + 'packages/charts-core/src/svg.ts', + 'packages/react-charts/src/CanvasChart.tsx', + 'packages/react-charts/src/Chart.tsx', + 'packages/react-charts/src/RendererChart.tsx', + ], } const retainedInputGroups = { compactLinear: [/(?:^|\/)packages\/charts-scales\/src\/linear\.ts$/u], @@ -76,6 +99,10 @@ const retainedInputGroups = { transformReduce: [ /(?:^|\/)packages\/charts-core\/src\/transform-reduce\.ts$/u, ], + nativeTooltip: [ + /(?:^|\/)packages\/react-native-charts\/src\/Tooltip\.tsx$/u, + /(?:^|\/)packages\/react-native-charts\/src\/tooltip-entry\.ts$/u, + ], d3Array: [/(?:^|\/)node_modules\/d3-array\//u], d3Shape: [/(?:^|\/)node_modules\/d3-shape\//u], d3ScaleRuntime: [ @@ -101,6 +128,14 @@ const granularTransformInputGroups = [ 'transformStack', 'transformReduce', ] +const nativeExternals = [ + 'react', + 'react/jsx-runtime', + 'react-native', + 'react-native/*', + 'react-native-svg', + 'react-native-svg/*', +] const entries = [ measured('Core host', 'benchmarks/entries/core.ts', { inputBoundary: { forbid: ['d3GeometryRuntime'] }, @@ -330,6 +365,47 @@ const entries = [ external: ['react', 'react/jsx-runtime', 'react-dom'], inputBoundary: { forbid: ['d3GeometryRuntime'] }, }), + measured( + 'React Native SVG host', + 'benchmarks/entries/charts-react-native.ts', + { + external: nativeExternals, + rendererBoundary: 'native', + inputBoundary: { + forbid: ['nativeTooltip'], + }, + platform: 'neutral', + conditions: ['react-native', 'import'], + }, + ), + measured( + 'React Native SVG host + tooltip', + 'benchmarks/entries/charts-react-native-tooltip.ts', + { + external: nativeExternals, + rendererBoundary: 'native', + inputBoundary: { + require: ['nativeTooltip'], + addedFrom: 'React Native SVG host', + allowAdded: ['nativeTooltip'], + }, + platform: 'neutral', + conditions: ['react-native', 'import'], + }, + ), + measured( + 'React Native line consumer', + 'benchmarks/entries/charts-react-native-line.ts', + { + external: nativeExternals, + rendererBoundary: 'native', + inputBoundary: { + forbid: ['nativeTooltip'], + }, + platform: 'neutral', + conditions: ['react-native', 'import'], + }, + ), lockedBudgeted( 'Compact-scale line scene', 'benchmarks/entries/charts-compact-linear-scene.ts', @@ -703,6 +779,8 @@ for (const { policy, rendererBoundary, inputBoundary, + platform, + conditions, } of entries) { const outfile = resolve( outputDirectory, @@ -714,13 +792,14 @@ for (const { bundle: true, minify: true, treeShaking: true, - platform: 'browser', + platform: platform ?? 'browser', format: 'esm', target: 'es2022', legalComments: 'none', logLevel: 'silent', external, alias, + conditions, metafile: true, }) const retainedInputs = collectRetainedInputs(result.metafile) @@ -871,6 +950,8 @@ function createEntry(label, entry, policy, options) { alias: options.alias, rendererBoundary: options.rendererBoundary, inputBoundary: options.inputBoundary, + platform: options.platform, + conditions: options.conditions, } } @@ -879,6 +960,9 @@ function assertRendererBoundary(label, inputs, boundary) { const paths = inputs.map((input) => input.replaceAll('\\', '/')) const canvas = matchingModules(paths, rendererBoundaryModules.canvas) const svg = matchingModules(paths, rendererBoundaryModules.svg) + const native = matchingModules(paths, rendererBoundaryModules.native) + const browser = matchingModules(paths, rendererBoundaryModules.browser) + const reactDom = paths.filter((input) => input.includes('/react-dom/')) const failures = [] if (boundary === 'neutral') { @@ -890,6 +974,14 @@ function assertRendererBoundary(label, inputs, boundary) { } else if (boundary === 'svg') { if (!svg.length) failures.push('did not include the SVG renderer') if (canvas.length) failures.push(`included Canvas: ${canvas.join(', ')}`) + } else if (boundary === 'native') { + if (!native.length) failures.push('did not include the native SVG host') + if (browser.length) { + failures.push(`included browser modules: ${browser.join(', ')}`) + } + if (reactDom.length) { + failures.push(`included react-dom: ${reactDom.join(', ')}`) + } } else { failures.push(`uses unknown renderer boundary ${boundary}`) } diff --git a/scripts/measure-react-native-poc.mjs b/scripts/measure-react-native-poc.mjs new file mode 100644 index 00000000..d07cafc1 --- /dev/null +++ b/scripts/measure-react-native-poc.mjs @@ -0,0 +1,163 @@ +import { spawn } from 'node:child_process' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { gzipSync } from 'node:zlib' +import { resolve } from 'node:path' + +const root = resolve(import.meta.dirname, '..') +const example = resolve(root, 'examples/charts-react-native') +const output = resolve(root, '.bundle-output') +const cli = resolve(example, 'node_modules/.bin/react-native') +const skipBuild = process.argv.includes('--skip-build') +const forbiddenSources = [ + 'packages/charts-core/src/adapter.ts', + 'packages/charts-core/src/adapter-renderer.ts', + 'packages/charts-core/src/canvas.ts', + 'packages/charts-core/src/dom.ts', + 'packages/charts-core/src/dom-text.ts', + 'packages/charts-core/src/export.ts', + 'packages/charts-core/src/reconcile.ts', + 'packages/charts-core/src/renderer.ts', + 'packages/charts-core/src/svg-renderer.ts', + 'packages/charts-core/src/svg-resources.ts', + 'packages/charts-core/src/svg-surface.ts', + 'packages/charts-core/src/svg.ts', + 'packages/charts-core/src/tooltip-portal.ts', + 'packages/charts-core/src/tooltip-position.ts', + 'packages/charts-core/src/tooltip.ts', + 'packages/react-charts/', + 'react-dom/', +] +const variants = { + blank: 'index.blank.js', + svg: 'index.svg.js', + core: 'index.core.js', + chart: 'index.js', +} + +await mkdir(output, { recursive: true }) + +const bundles = [] +for (const platform of ['ios', 'android']) { + for (const [variant, entry] of Object.entries(variants)) { + const bundle = resolve( + output, + `react-native-${variant}.${platform}.jsbundle`, + ) + const sourceMap = resolve(output, `react-native-${variant}.${platform}.map`) + if (!skipBuild) { + await run(cli, [ + 'bundle', + '--entry-file', + entry, + '--platform', + platform, + '--dev', + 'false', + '--minify', + 'true', + '--bundle-output', + bundle, + '--sourcemap-output', + sourceMap, + '--config', + resolve(example, 'metro.config.cjs'), + ]) + } + const contents = await readFile(bundle) + const map = JSON.parse(await readFile(sourceMap, 'utf8')) + const sources = map.sources.map(normalize) + if (variant === 'chart') assertNativeBoundary(platform, sources) + bundles.push({ + platform, + variant, + bytes: contents.byteLength, + gzip: gzipSync(contents).byteLength, + modules: sources.length, + }) + } +} + +const rows = [ + '| Platform | Full chart JS delta | RNSVG-only gzip delta | Core line gzip delta | Full chart gzip delta |', +] +rows.push('| --- | ---: | ---: | ---: | ---: |') +for (const platform of ['ios', 'android']) { + const blank = bundles.find( + (bundle) => bundle.platform === platform && bundle.variant === 'blank', + ) + const chart = bundles.find( + (bundle) => bundle.platform === platform && bundle.variant === 'chart', + ) + const svg = bundles.find( + (bundle) => bundle.platform === platform && bundle.variant === 'svg', + ) + const core = bundles.find( + (bundle) => bundle.platform === platform && bundle.variant === 'core', + ) + if (!blank || !chart || !svg || !core) { + throw new Error(`Missing ${platform} bundle result`) + } + rows.push( + `| ${platform} | ${format(chart.bytes - blank.bytes)} | ${format(svg.gzip - blank.gzip)} | ${format(core.gzip - blank.gzip)} | ${format(chart.gzip - blank.gzip)} |`, + ) +} + +console.log(rows.join('\n')) +await writeFile( + resolve(output, 'react-native-poc.json'), + `${JSON.stringify( + { + schemaVersion: 1, + note: 'Metro production JS only. This excludes react-native-svg native binary code.', + bundles, + }, + null, + 2, + )}\n`, +) + +function assertNativeBoundary(platform, sources) { + const nativeSources = sources.filter((source) => + source.includes('packages/react-native-charts/src/'), + ) + if (!nativeSources.length) { + throw new Error(`${platform} bundle did not include the native host`) + } + const forbidden = sources.filter((source) => + forbiddenSources.some((candidate) => source.includes(candidate)), + ) + if (forbidden.length) { + throw new Error( + `${platform} bundle crossed the browser boundary:\n${forbidden.join('\n')}`, + ) + } +} + +function run(command, args) { + return new Promise((resolvePromise, reject) => { + const child = spawn(command, args, { + cwd: example, + stdio: 'inherit', + }) + child.on('error', reject) + child.on('exit', (code, signal) => { + if (code === 0) resolvePromise() + else { + reject( + new Error( + `${command} exited with ${signal ? `signal ${signal}` : `code ${code}`}`, + ), + ) + } + }) + }) +} + +function normalize(value) { + return value.replaceAll('\\', '/') +} + +function format(bytes) { + const sign = bytes < 0 ? '-' : '' + return `${sign}${(Math.abs(bytes) / 1024).toFixed(2)} kB` +} From 14417a064a5c1de811ab4587e9fcd3e2d870dfb4 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Fri, 31 Jul 2026 15:13:53 -0600 Subject: [PATCH 2/5] Verify universal React Native usage --- API-FRICTION.md | 103 +++++--- REACT-NATIVE-HOST-POC.md | 111 +++++---- examples/charts-react-native/App.granular.tsx | 10 + examples/charts-react-native/App.tsx | 66 +----- examples/charts-react-native/RevenueChart.tsx | 75 ++++++ .../charts-react-native/index.granular.js | 5 + examples/charts-react-native/tsconfig.json | 2 +- .../react-native-charts/src/Chart.test.tsx | 219 +++++++++++++----- packages/react-native-charts/src/Chart.tsx | 22 +- .../react-native-charts/src/SvgScene.test.tsx | 16 ++ packages/react-native-charts/src/SvgScene.tsx | 1 + .../react-native-charts/src/Tooltip.test.ts | 136 ++++++++++- packages/react-native-charts/src/Tooltip.tsx | 107 ++++++++- .../react-native-charts/src/interaction.ts | 4 +- scripts/measure-bundles.mjs | 15 +- scripts/measure-react-native-poc.mjs | 51 +++- 16 files changed, 724 insertions(+), 219 deletions(-) create mode 100644 examples/charts-react-native/App.granular.tsx create mode 100644 examples/charts-react-native/RevenueChart.tsx create mode 100644 examples/charts-react-native/index.granular.js diff --git a/API-FRICTION.md b/API-FRICTION.md index f4a3f71f..f3f26f4b 100644 --- a/API-FRICTION.md +++ b/API-FRICTION.md @@ -208,6 +208,7 @@ Each entry records: | F-169 | Text measurement omits native typography | API | monitoring | | F-170 | Packed declarations assume one platform global set | Tooling | monitoring | | F-171 | Metro skipped the fixture-owned Babel runtime | Tooling | resolved | +| F-172 | Metro retained the complete universal barrel | API/Tooling | monitoring | ## Findings @@ -3184,7 +3185,9 @@ Each entry records: widths. The cross-library fixtures now configure tooltip, keyboard, focus, and animation on each definition through the typed `defineChart` overload; a typed host-options boundary prevents behavior from drifting back to - adapter props. + adapter props. The React Native `/universal` fixture keeps behavior on its + directly authored one-argument definition; the two-argument form remains + reserved for decorating an existing definition. ### F-131 — Stable identity repeated inferable key channels @@ -3718,21 +3721,22 @@ Each entry records: `@tanstack/charts/universal` for common authoring/runtime values plus `@tanstack/charts/types` for universal contracts. The name describes the supported cross-runtime surface while the browser-first root remains the - normal web entry. DOM surface, renderer, host, and render-context types now - live behind an internal module while retaining their existing root - re-exports. Definition inputs retain DOM-free extension token contracts while - the generic tooltip and portal token interfaces are exported for host-adapter - authors. Typed DOM tooltip and portal lifecycles remain in the DOM module. Do - not conditionally change the root until a native host can test one coherent - platform contract. -- Verification: root typechecking and 61 focused core tests pass. The packed - package gate resolves both new entries from `dist`, compiles their + normal web entry. `/portable` was an early pre-1.0 name and is intentionally + not restored; `/universal` is the sole cross-runtime barrel. DOM surface, + renderer, host, and render-context types now live behind an internal module + while retaining their existing root re-exports. Definition inputs retain + DOM-free extension token contracts while the generic tooltip and portal token + interfaces are exported for host-adapter authors. Typed DOM tooltip and + portal lifecycles remain in the DOM module. Do not conditionally change the + root until a native host can test one coherent platform contract. +- Verification: root typechecking and focused core tests pass. The packed + package gate resolves `/universal` and `/types` from `dist` and compiles their declarations, including tooltip definition inputs and direct generic-token imports, with Web Worker rather than DOM globals. Type regressions reject swapping tooltip and portal tokens. The packed bundle proof excludes the root, adapters, Canvas, DOM host/text, browser export, reconciliation, renderer, and SVG surface modules. That full - universal barrel measures 53.95 kB minified and 16.60 kB gzip; granular + universal barrel measures 84.30 kB minified and 26.55 kB gzip; granular subpaths remain the bundle-sensitive option. ### F-155 — Optional tooltip code burdened every chart consumer @@ -3761,9 +3765,11 @@ Each entry records: - Verification: the representative compact React line is 14,227 gzip bytes. Native tooltip adds 3,381 bytes; portal adds 806 more. Retained-output graph checks prove base renderer and React entries contain none of the tooltip, - portal, or React rich-body modules. The React Native base host is 9,141 gzip - bytes and adding its tooltip subpath costs 1,685 bytes; retained-input checks - prove both the base host and line consumer omit `Tooltip.tsx`. Core, Lit, + portal, or React rich-body modules. The React Native base host is 10,468 gzip + bytes and adding its tooltip subpath costs 1,923 bytes; retained-input checks + prove both the base host and line consumer omit `Tooltip.tsx`, all native + entries omit web tooltip and portal code, and the base host retains no D3 + runtime. Core, Lit, React, native, export, declaration, packed-package, and lifecycle tests cover creation, update, disable, host ownership, transport switching, custom bodies, and cleanup. @@ -4042,10 +4048,22 @@ Each entry records: after tooltip rendering moved behind an extension token - Friction: focus preset resolution, stable-point restoration, navigation order, tooltip content construction, anchor resolution, and placement math - are pure behavior but live as private functions inside `renderer.ts`. The - native proof reproduced them to exercise realistic interaction. The + are pure behavior but remain private across the DOM renderer and tooltip + implementation. The native proof reproduced them to exercise realistic + interaction. The extension split also made configured tooltip options require a host-owned token; importing the web token would pull DOM implementation into Metro. + Restacking onto 0.3.0 also required the duplicate native resolver to learn + the new per-axis anchors and focus-aware custom-anchor context before its + strict type gate passed again. The scene compiler now also emits authored or + default focus layers and inline mark-state metadata. Rendering those groups + directly made inactive focus marks permanently visible in the native scene. + The duplicate tooltip path also sorted display rows before choosing its + primary point, so a non-first focused series changed formatter and anchor + context. Scene restoration compared only semantic point identity, leaving + overlays, tooltips, and external callbacks attached to old point objects + after responsive geometry changed. Callback prop identity could also + retrigger restoration and incorrectly change the focus source. - Current decision: keep the duplication confined to the private proof. The native adapter exports a branded extension from its optional `/tooltip` subpath, accepts duplicate package copies and custom native implementations, @@ -4057,14 +4075,24 @@ Each entry records: when decorated with a tooltip token, while applications can still share the chart spec and options before that platform step. A supported native package still requires extracting renderer-neutral interaction and tooltip state, - with the DOM and native hosts consuming the same implementation. + with the DOM and native hosts consuming the same implementation. The proof + omits shared focus-layer groups from its base scene and uses a generic native + overlay; authored focus marks and inline mark states remain unsupported until + scene-state resolution is shared. It now preserves the original primary and + focus group independently from sorted tooltip rows, refreshes restored point + objects and callbacks, and keeps callback refs out of restoration effect + dependencies. - Verification: focused native tests cover strategy selection, grouping, - restoration, navigation, supported default content, placement, and extension - ownership. The native type and Metro gates use the native token without web - tooltip modules, and retained-input gates prove the base native entry does - not include the optional tooltip implementation. Browser portal tokens fail - explicitly instead of being ignored. The default native tooltip still lacks - the complete `items` formatting contract. + restoration, navigation, axis and custom anchors, supported default content, + placement, and extension ownership. The native type and Metro gates use the + native token without web tooltip modules, and retained-input gates prove the + base native entry does not include the optional tooltip implementation. + Browser portal tokens fail explicitly instead of being ignored. The default + native tooltip still lacks the complete `items` formatting contract. A + regression verifies inactive focus-layer paint is absent from the native + scene. Component regressions cover a primary point that sorts after another + series, restored coordinates and callbacks after resize, and stable focus + source when only callback props change. ### F-168 — CSS theme defaults reach the native scene compiler @@ -4133,6 +4161,29 @@ Each entry records: - Decision: configure Metro's `resolver.nodeModulesPaths` with the example and workspace module roots. Keep Babel ownership in the example rather than masking the monorepo resolution boundary with a root dependency. -- Verification: all eight blank, RNSVG, core, and full-chart production bundles - complete for iOS and Android. The full-chart source-map checks also exclude - every guarded browser implementation module. +- Verification: all ten blank, RNSVG, core, granular full-chart, and universal + full-chart production bundles complete for iOS and Android. The universal + variants require `/universal`, and source-map checks exclude every guarded + browser implementation module. + +### F-172 — Metro retained the complete universal barrel + +- Status: monitoring +- Severity: medium +- Owner: API/Tooling +- Observed in: measuring the documented React Native minimum usage through + `@tanstack/charts/universal` +- Friction: Metro 0.84 retained every runtime module re-exported by the broad + barrel, even though the fixture imported only `defineChart` and `lineY`. The + result included unused marks, data-transform families, and the + environment-neutral static SVG string serializer. Against the same granular + full-chart fixture, `/universal` added 119.06 KiB minified and 28.91 KiB gzip + on both iOS and Android, plus 102 modules per platform. +- Current decision: keep `/universal` as the ergonomic cross-runtime authoring + entry and make the full-chart Metro proof exercise it. Keep the native host's + own imports granular, publish granular entries as the bundle-sensitive path, + and do not describe the broad barrel as cost-equivalent under Metro. +- Verification: the iOS and Android full-chart bundles require + `packages/charts-core/src/universal.ts`, measure 102.94 and 102.99 KiB gzip over + blank respectively, and exclude DOM hosts, browser adapters, Canvas, + reconciliation, SVG resources/surface, web tooltip code, and `react-dom`. diff --git a/REACT-NATIVE-HOST-POC.md b/REACT-NATIVE-HOST-POC.md index 1683c8e8..61285f5e 100644 --- a/REACT-NATIVE-HOST-POC.md +++ b/REACT-NATIVE-HOST-POC.md @@ -47,6 +47,7 @@ The private `@tanstack/react-native-charts` package includes: - nearest, axis-nearest, and grouped focus; - tap selection, sticky pinning, focus restoration, and accessibility actions; - a separate SVG focus overlay; +- inactive shared focus-layer groups are omitted from the base scene; - an optional native tooltip subpath with point, pointer, group-center, and custom anchors, collision-aware placement, custom content, and a custom React body; @@ -57,9 +58,9 @@ The private `@tanstack/react-native-charts` package includes: The host imports runtime values from narrow core subpaths. It does not import the root barrel, `react-dom`, a browser adapter, the DOM renderer, the Canvas -host, or the SVG string/reconciliation pipeline. The narrow imports keep this -measurement bundle-sensitive; application definitions can instead use the -environment-safe `@tanstack/charts/universal` barrel. +host, or the SVG string/reconciliation pipeline. The full-chart Metro fixture +imports its application definition from `@tanstack/charts/universal`; the core +line control keeps granular imports for a tighter comparison. That distinction matters to shared application source. A Metro probe using `defineChart` and `lineY` from the browser-oriented root @@ -68,6 +69,13 @@ SVG surface, and adapters. The prerequisite universal-barrel PR adds `@tanstack/charts/universal` for normal environment-neutral authoring while retaining granular entries for tighter bundles. +Metro 0.84 retains every runtime module re-exported by `/universal`, including +unused marks and the environment-neutral static SVG string serializer. It does +not retain the guarded DOM or browser host modules. The broad entry is the +simplest supported authoring path; bundle-sensitive native applications can +use granular mark, runtime, and scene entries until Metro can eliminate those +unused re-exports. + That prerequisite also adds `@tanstack/charts/types`, exports the generic tooltip and portal token interfaces for host-adapter authors, and moves DOM host types to an internal `dom-types.ts` module while preserving their root @@ -82,14 +90,12 @@ import { defineChart, lineY } from '@tanstack/charts/universal' import { Chart } from '@tanstack/react-native-charts' import { tooltip } from '@tanstack/react-native-charts/tooltip' -const definition = defineChart( - { - marks: [lineY([4, 9, 7])], - x: { scale: scaleLinear().domain([0, 2]) }, - y: { scale: scaleLinear().domain([0, 10]) }, - }, - { tooltip: { use: tooltip, sticky: true } }, -) +const definition = defineChart({ + marks: [lineY([4, 9, 7])], + x: { scale: scaleLinear().domain([0, 2]) }, + y: { scale: scaleLinear().domain([0, 10]) }, + tooltip: { use: tooltip, sticky: true }, +}) export function RevenueChart() { return ( @@ -115,17 +121,17 @@ external in the native entries. | Entry | Minified | Gzip | | ---------------------------------- | -------: | -------: | -| React Native SVG host | 23.26 kB | 8.93 kB | -| React Native SVG host with tooltip | 28.04 kB | 10.57 kB | -| React Native line consumer | 45.30 kB | 17.68 kB | -| Shared line scene | 34.29 kB | 13.44 kB | -| Existing React web adapter | 32.66 kB | 12.03 kB | -| Existing React web line consumer | 54.50 kB | 20.78 kB | +| React Native SVG host | 26.95 kB | 10.22 kB | +| React Native SVG host with tooltip | 32.50 kB | 12.10 kB | +| React Native line consumer | 49.18 kB | 19.03 kB | +| Shared line scene | 38.17 kB | 14.82 kB | +| Existing React web adapter | 39.98 kB | 14.57 kB | +| Existing React web line consumer | 62.03 kB | 23.41 kB | The native host entry includes the host plus every shared runtime and D3 module reachable from exporting `Chart`; it is not isolated adapter-only overhead. The base host and line consumer omit `Tooltip.tsx`. Importing the tooltip -subpath adds 4.78 kB minified and 1.65 kB gzip. The native line consumer +subpath adds 5.55 kB minified and 1.88 kB gzip. The native line consumer additionally includes the line mark and D3 scale code while leaving platform peers external. It is the closest comparison to the existing React line entry, but the two platforms do not have identical runtime baselines. The native @@ -135,26 +141,29 @@ entries are informational measurements, not locked budgets. React Native production bundles were minified for both platforms. Each row is measured against a blank React Native application built with the same Metro -configuration. +configuration. The full chart uses `/universal`; the core line control uses +granular entries. -| Platform | Full chart minified JS delta | `react-native-svg` gzip delta | Core line gzip delta | Full chart gzip delta | Full chart module delta | -| -------- | ---------------------------: | ----------------------------: | -------------------: | --------------------: | ----------------------: | -| iOS | 309.42 KiB | 27.75 KiB | 37.78 KiB | 72.53 KiB | 281 | -| Android | 309.56 KiB | 27.69 KiB | 37.81 KiB | 72.62 KiB | 281 | +| Platform | Full `/universal` chart minified JS delta | `react-native-svg` gzip delta | Core line gzip delta | Full `/universal` chart gzip delta | Full chart module delta | +| -------- | ----------------------------------------: | ----------------------------: | -------------------: | ---------------------------------: | ----------------------: | +| iOS | 434.28 KiB | 27.75 KiB | 38.95 KiB | 102.94 KiB | 384 | +| Android | 434.42 KiB | 27.69 KiB | 38.94 KiB | 102.99 KiB | 384 | -The full iOS bundle was 1,200,921 bytes and 288,655 bytes gzip, versus 884,080 -and 214,381 for blank. Android was 1,206,437 and 289,754, versus 889,448 and -215,395 for blank. +The full iOS bundle was 1,328,782 bytes and 319,792 bytes gzip, versus 884,080 +and 214,381 for blank. Android was 1,334,298 and 320,860, versus 889,448 and +215,395 for blank. Compared with the otherwise identical granular fixture, +`/universal` retains another 119.06 KiB minified and 28.91 KiB gzip on both iOS +and Android, plus 102 modules per platform under this Metro version. These are JavaScript bundle measurements, not Hermes bytecode or installed application sizes. They exclude the native iOS and Android code linked by `react-native-svg`. A clean release-binary before/after comparison is still required. -The full-chart source maps include the native host and exclude every guarded -browser module: adapters, DOM host, DOM text measurement, renderer, Canvas, -reconciliation, SVG serialization/surface code, `react-dom`, React web charts, -and Octane charts. +The full-chart source maps require `/universal` and include its static SVG +serializer. They exclude every guarded browser module: adapters, DOM host, DOM +text measurement, DOM renderer, Canvas, reconciliation, SVG resources/surface, +`react-dom`, React web charts, and Octane charts. ## Parity and boundaries @@ -168,6 +177,7 @@ and Octane charts. | Paint | `currentColor` and CSS fallback resolution | Dynamic definitions still see the web default theme | | Text | SVG text plus injected core measurer | Exact native typography and async measurement are unresolved | | Nearest and grouped focus | Implemented | Logic is duplicated from the DOM renderer | +| Focus presentation | Generic native overlay | Authored focus marks and mark states are not applied | | Tap, selection, sticky tooltip | Implemented | Responder ownership may conflict with scrolling and gestures | | Tooltip | Native in-tree overlay | Web `className`, portal semantics, and full item formatting are not equivalent | | Accessibility | Labeled adjustable root and actions | No per-point native accessibility tree or data-table escape | @@ -194,9 +204,13 @@ and Octane charts. ### Interaction details that are not exact - Focus preset resolution, point restoration, navigation order, tooltip - content, anchor, and placement are private functions inside the DOM renderer. - The POC had to reproduce those policies. A supported package must extract - the pure behavior and make both hosts consume it. + content, anchor, and placement remain private across the DOM renderer and + tooltip implementation. The POC had to reproduce those policies. A supported + package must extract the pure behavior and make both hosts consume it. +- Shared focus-layer groups are hidden from the base native scene so they are + not painted permanently. The proof uses its generic native overlay instead; + authored focus marks and inline mark states need a shared scene-state + resolver before they can be supported accurately. - The POC does not implement the complete `tooltip.items` channel, datum, and derived-row contract. Custom `content`, `format`, `formatGroup`, and a custom React body work, but default structured content is only partial. @@ -287,29 +301,32 @@ conditional-export, and Metro-consumer gate is part of productionization. - Many SVG nodes can become expensive before the shared scene compiler does. - Native support needs devices, release builds, TalkBack/VoiceOver testing, and two platform-specific failure surfaces. -- Current interaction and tooltip ownership must be refactored out of a mature - DOM renderer without regressing web behavior. +- Current interaction and tooltip ownership must be refactored out of mature + DOM host implementations without regressing web behavior. - A publishable native package needs a separate packed-declaration gate because React Native and DOM global declarations conflict in the current web fixture. ## Verification performed -- 16 focused POC tests cover every scene primitive, gradients, clips, paint - resolution, focus modes, point restoration, placement, chart compilation, - extension ownership, and no-speculative-size behavior. Component mapping - tests use React DOM server rendering with native modules mocked; they are - structural tests, not native renderer tests. +- 21 focused POC tests cover every scene primitive, gradients, clips, paint + resolution, focus modes, point and callback restoration, tooltip ordering, + placement, chart compilation, extension ownership, inactive focus layers, + and no-speculative-size behavior. Component mapping tests use React DOM with + native modules mocked; they are structural tests, not native renderer tests. - The native package and the normal React Native application configuration typecheck. - The repository-wide typecheck passes with the native dependency graph. -- The prerequisite PR's packed gate validates both environment-safe entries without - changing the browser root. +- The prerequisite PR's packed gate validates the supported environment-safe + entries without changing the browser root. - Existing locked web bundle baselines remain unchanged. -- Production Metro bundles complete for iOS and Android. +- Production Metro bundles complete for iOS and Android, and the full-chart + variants must resolve `/universal`. - Source-map gates prove the full native entries do not include guarded browser implementation files, including the web tooltip and portal runtimes. - Retained-input gates prove the base native host and line consumer omit the - optional native tooltip implementation. + optional native tooltip implementation, all native entries omit web tooltip + and portal code, the base host retains no D3 runtime, and the line consumer + retains no D3 geometry runtime. A strict native consumer with `skipLibCheck: false` now gets past the Charts DOM boundary and stops in `@types/d3-array`, whose `blurImage` declaration @@ -318,9 +335,9 @@ only those two known errors, or a clean result after the upstream declaration is fixed. The POC does not add a fake global or pull DOM libraries into native to hide the upstream declaration problem. -The native declaration check and isolated esbuild boundary run in the normal -validation workflow. The eight-build iOS/Android Metro measurement remains a -local spike command rather than a mandatory CI gate. +The isolated esbuild boundary runs in `pnpm validate`. GitHub runs the native +declaration check as a separate workflow step. The ten-build iOS/Android Metro +measurement remains a local spike command rather than a mandatory CI gate. Not performed: diff --git a/examples/charts-react-native/App.granular.tsx b/examples/charts-react-native/App.granular.tsx new file mode 100644 index 00000000..8d572a44 --- /dev/null +++ b/examples/charts-react-native/App.granular.tsx @@ -0,0 +1,10 @@ +import * as React from 'react' +import { lineY } from '@tanstack/charts/line' +import { defineChart } from '@tanstack/charts/scene' +import { createRevenueDefinition, RevenueChart } from './RevenueChart' + +const definition = createRevenueDefinition(defineChart, lineY) + +export default function GranularApp() { + return +} diff --git a/examples/charts-react-native/App.tsx b/examples/charts-react-native/App.tsx index b4ce407e..46109d9e 100644 --- a/examples/charts-react-native/App.tsx +++ b/examples/charts-react-native/App.tsx @@ -1,67 +1,9 @@ import * as React from 'react' -import { SafeAreaView, Text, View } from 'react-native' -import { scaleLinear } from 'd3-scale' -import { lineY } from '@tanstack/charts/line' -import { defineChart } from '@tanstack/charts/scene' -import { Chart } from '@tanstack/react-native-charts' -import { tooltip } from '@tanstack/react-native-charts/tooltip' +import { defineChart, lineY } from '@tanstack/charts/universal' +import { createRevenueDefinition, RevenueChart } from './RevenueChart' -const data = [ - { month: 1, revenue: 12 }, - { month: 2, revenue: 18 }, - { month: 3, revenue: 15 }, - { month: 4, revenue: 26 }, - { month: 5, revenue: 31 }, -] - -const definition = defineChart( - { - marks: [ - lineY(data, { - x: 'month', - y: 'revenue', - stroke: 'var(--revenue, #2563eb)', - strokeWidth: 3, - points: true, - }), - ], - x: { - label: 'Month', - scale: scaleLinear().domain([1, 5]), - }, - y: { - label: 'Revenue', - grid: true, - scale: scaleLinear().domain([0, 35]), - }, - }, - { - focus: 'nearest-x', - tooltip: { use: tooltip, sticky: true }, - }, -) +const definition = createRevenueDefinition(defineChart, lineY) export default function App() { - return ( - - - ( - - {defaultBody} - {pinned ? ( - - Pinned - - ) : null} - - )} - /> - - - ) + return } diff --git a/examples/charts-react-native/RevenueChart.tsx b/examples/charts-react-native/RevenueChart.tsx new file mode 100644 index 00000000..607a2bb5 --- /dev/null +++ b/examples/charts-react-native/RevenueChart.tsx @@ -0,0 +1,75 @@ +import * as React from 'react' +import { SafeAreaView, Text, View } from 'react-native' +import { scaleLinear } from 'd3-scale' +import type { ChartDefinition } from '@tanstack/charts/types' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' + +const data = [ + { month: 1, revenue: 12 }, + { month: 2, revenue: 18 }, + { month: 3, revenue: 15 }, + { month: 4, revenue: 26 }, + { month: 5, revenue: 31 }, +] + +type RevenueDefinition = ChartDefinition<(typeof data)[number], number, number> +type DefineChart = typeof import('@tanstack/charts/scene').defineChart +type LineY = typeof import('@tanstack/charts/line').lineY + +export function createRevenueDefinition( + define: DefineChart, + line: LineY, +): RevenueDefinition { + return define({ + marks: [ + line(data, { + x: 'month', + y: 'revenue', + stroke: 'var(--revenue, #2563eb)', + strokeWidth: 3, + points: true, + }), + ], + x: { + label: 'Month', + scale: scaleLinear().domain([1, 5]), + }, + y: { + label: 'Revenue', + grid: true, + scale: scaleLinear().domain([0, 35]), + }, + focus: 'nearest-x', + tooltip: { use: tooltip, sticky: true }, + }) +} + +export function RevenueChart({ + definition, +}: { + definition: RevenueDefinition +}) { + return ( + + + ( + + {defaultBody} + {pinned ? ( + + Pinned + + ) : null} + + )} + /> + + + ) +} diff --git a/examples/charts-react-native/index.granular.js b/examples/charts-react-native/index.granular.js new file mode 100644 index 00000000..08a296ba --- /dev/null +++ b/examples/charts-react-native/index.granular.js @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native' +import App from './App.granular' +import { name as appName } from './app.json' + +AppRegistry.registerComponent(appName, () => App) diff --git a/examples/charts-react-native/tsconfig.json b/examples/charts-react-native/tsconfig.json index e4414983..203e9655 100644 --- a/examples/charts-react-native/tsconfig.json +++ b/examples/charts-react-native/tsconfig.json @@ -4,6 +4,6 @@ "lib": ["es2022"], "types": ["react", "react-native"] }, - "include": ["App.tsx"], + "include": ["App.tsx", "App.granular.tsx", "RevenueChart.tsx"], "exclude": ["node_modules"] } diff --git a/packages/react-native-charts/src/Chart.test.tsx b/packages/react-native-charts/src/Chart.test.tsx index 64395a26..7900d967 100644 --- a/packages/react-native-charts/src/Chart.test.tsx +++ b/packages/react-native-charts/src/Chart.test.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import { createRoot } from 'react-dom/client' import { renderToStaticMarkup } from 'react-dom/server' import { scaleLinear } from 'd3-scale' import { describe, expect, it, vi } from 'vitest' @@ -11,10 +12,30 @@ import { type NativeChartTooltipExtension, } from './tooltip-entry' -vi.mock('react-native', () => ({ - Text: 'span', - View: 'div', -})) +vi.mock('react-native', async () => { + const ReactModule = await import('react') + return { + Text: 'span', + View: ReactModule.forwardRef< + HTMLDivElement, + React.HTMLAttributes & { style?: unknown } + >(function MockView({ children, onBlur, onFocus, style }, ref) { + const resolvedStyle = Array.isArray(style) + ? Object.assign({}, ...style.filter(Boolean)) + : style + return ReactModule.createElement( + 'div', + { + ref, + onBlur, + onFocus, + style: resolvedStyle as React.CSSProperties, + }, + children, + ) + }), + } +}) vi.mock('react-native-svg', () => ({ Circle: 'circle', @@ -34,21 +55,19 @@ const data = [ { month: 1, value: 8 }, { month: 2, value: 12 }, ] -const definition = defineChart( - { - marks: [ - lineY(data, { - x: 'month', - y: 'value', - stroke: 'var(--series, #2563eb)', - points: true, - }), - ], - x: { scale: scaleLinear().domain([1, 2]) }, - y: { scale: scaleLinear().domain([8, 12]) }, - }, - { tooltip: { use: tooltip, sticky: true } }, -) +const definition = defineChart({ + marks: [ + lineY(data, { + x: 'month', + y: 'value', + stroke: 'var(--series, #2563eb)', + points: true, + }), + ], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + tooltip: { use: tooltip, sticky: true }, +}) describe('React Native Chart', () => { it('compiles a shared definition directly into native SVG components', () => { @@ -78,19 +97,15 @@ describe('React Native Chart', () => { }) it('rejects tooltip extensions owned by another host', () => { - const foreignDefinition = defineChart( - { - marks: [lineY(data, { x: 'month', y: 'value' })], - x: { scale: scaleLinear().domain([1, 2]) }, - y: { scale: scaleLinear().domain([8, 12]) }, + const foreignDefinition = defineChart({ + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + tooltip: { + id: 'foreign-tooltip', + create: (): undefined => undefined, }, - { - tooltip: { - id: 'foreign-tooltip', - create: () => undefined, - }, - }, - ) + }) expect(() => renderToStaticMarkup( @@ -113,14 +128,12 @@ describe('React Native Chart', () => { __nativeChartHost: 'react-native', create, } - const customDefinition = defineChart( - { - marks: [lineY(data, { x: 'month', y: 'value' })], - x: { scale: scaleLinear().domain([1, 2]) }, - y: { scale: scaleLinear().domain([8, 12]) }, - }, - { tooltip: { use: customTooltip, sticky: true } }, - ) + const customDefinition = defineChart({ + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + tooltip: { use: customTooltip, sticky: true }, + }) renderToStaticMarkup( { expect(create).toHaveBeenCalledOnce() }) + it('refreshes focused callbacks with points from a resized scene', async () => { + const container = document.createElement('div') + const root = createRoot(container) + const onFocusChange = vi.fn() + + try { + await React.act(() => { + root.render( + , + ) + }) + const chart = container.firstElementChild + if (!chart) throw new Error('Expected the native chart root to render.') + + await React.act(() => { + chart.dispatchEvent(new FocusEvent('focusin', { bubbles: true })) + }) + const initial = onFocusChange.mock.lastCall?.[0] + + await React.act(() => { + root.render( + , + ) + }) + const restored = onFocusChange.mock.lastCall?.[0] + + expect(onFocusChange).toHaveBeenCalledTimes(2) + expect(restored).not.toBe(initial) + expect(restored?.y).not.toBe(initial?.y) + } finally { + await React.act(() => root.unmount()) + } + }) + + it('keeps the focus source when only callback props change', async () => { + const focusSources: string[] = [] + const TrackingTooltip: NativeChartTooltipComponent = ({ focusSource }) => { + focusSources.push(focusSource) + return null + } + const trackingTooltip: NativeChartTooltipExtension = { + id: 'tracking-native-tooltip', + __chartExtensionType: 'tooltip', + __nativeChartHost: 'react-native', + create: () => TrackingTooltip, + } + const trackingDefinition = defineChart({ + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + tooltip: { use: trackingTooltip }, + }) + const container = document.createElement('div') + const root = createRoot(container) + + try { + await React.act(() => { + root.render( + , + ) + }) + const chart = container.firstElementChild + if (!chart) throw new Error('Expected the native chart root to render.') + + await React.act(() => { + chart.dispatchEvent(new FocusEvent('focusin', { bubbles: true })) + }) + expect(focusSources.at(-1)).toBe('keyboard') + + await React.act(() => { + root.render( + , + ) + }) + expect(focusSources.at(-1)).toBe('keyboard') + } finally { + await React.act(() => root.unmount()) + } + }) + it('rejects browser tooltip portal extensions', () => { - const portalDefinition = defineChart( - { - marks: [lineY(data, { x: 'month', y: 'value' })], - x: { scale: scaleLinear().domain([1, 2]) }, - y: { scale: scaleLinear().domain([8, 12]) }, - }, - { - tooltip: { - use: tooltip, - portal: { - id: 'browser-portal', - create: () => undefined, - }, + const portalDefinition = defineChart({ + marks: [lineY(data, { x: 'month', y: 'value' })], + x: { scale: scaleLinear().domain([1, 2]) }, + y: { scale: scaleLinear().domain([8, 12]) }, + tooltip: { + use: tooltip, + portal: { + id: 'browser-portal', + create: (): undefined => undefined, }, }, - ) + }) expect(() => renderToStaticMarkup( diff --git a/packages/react-native-charts/src/Chart.tsx b/packages/react-native-charts/src/Chart.tsx index f45057cd..02bd7e8d 100644 --- a/packages/react-native-charts/src/Chart.tsx +++ b/packages/react-native-charts/src/Chart.tsx @@ -11,6 +11,7 @@ import { View } from 'react-native' import { createChartRuntime } from '@tanstack/charts/runtime' import type { ChartDefinition, + ChartFocusSource, ChartPoint, ChartScene, ChartTextMeasurer, @@ -24,7 +25,7 @@ import { NativeChartFocusOverlay } from './FocusOverlay' import { adjacentFocusPoint, createNativeChartFocusModel, - samePointList, + samePointReferences, } from './interaction' import { resolveNativePaint, type NativePaintResolver } from './paint' import { NativeChartScene } from './SvgScene' @@ -133,10 +134,16 @@ export function Chart< readonly ChartPoint[] >([]) const focusedPointsRef = React.useRef(focusedPoints) + const onFocusChangeRef = React.useRef(onFocusChange) + const onFocusGroupChangeRef = React.useRef(onFocusGroupChange) + onFocusChangeRef.current = onFocusChange + onFocusGroupChangeRef.current = onFocusGroupChange const [pinnedKey, setPinnedKey] = React.useState(null) const [pointer, setPointer] = React.useState( null, ) + const [focusSource, setFocusSource] = + React.useState('programmatic') const tooltipInput = React.useMemo( () => resolveNativeTooltipInput(definition.tooltip), [definition.tooltip], @@ -148,13 +155,14 @@ export function Chart< const commitFocus = React.useCallback( (points: readonly ChartPoint[]) => { - if (samePointList(points, focusedPointsRef.current)) return + const current = focusedPointsRef.current + if (samePointReferences(points, current)) return focusedPointsRef.current = points setFocusedPoints(points) - onFocusChange?.(points[0] ?? null) - onFocusGroupChange?.(points) + onFocusChangeRef.current?.(points[0] ?? null) + onFocusGroupChangeRef.current?.(points) }, - [onFocusChange, onFocusGroupChange], + [], ) React.useEffect(() => () => runtime.destroy(), [runtime]) @@ -166,6 +174,7 @@ export function Chart< if (!focusModel || !previous) return const restored = focusModel.restore(previous) if (restored) { + setFocusSource('restored') commitFocus(focusModel.group(restored)) } else { setPinnedKey(null) @@ -192,6 +201,7 @@ export function Chart< x: (event.nativeEvent.locationX / measuredWidth) * scene.width, y: (event.nativeEvent.locationY / measuredHeight) * scene.height, } + setFocusSource('pointer') setPointer(position) return focusModel.resolve(position.x, position.y) }, @@ -230,6 +240,7 @@ export function Chart< const navigate = (direction: -1 | 1) => { if (!focusModel) return + setFocusSource('keyboard') const point = adjacentFocusPoint( focusModel, focusedPointsRef.current[0] ?? null, @@ -338,6 +349,7 @@ export function Chart< height={layout?.height ?? scene.height} points={focusedPoints} pointer={pointer} + focusSource={focusSource} options={tooltipOptions} pinned={pinnedKey !== null} color={color} diff --git a/packages/react-native-charts/src/SvgScene.test.tsx b/packages/react-native-charts/src/SvgScene.test.tsx index fbed133c..0ecc1569 100644 --- a/packages/react-native-charts/src/SvgScene.test.tsx +++ b/packages/react-native-charts/src/SvgScene.test.tsx @@ -42,6 +42,7 @@ describe('React Native SVG scene renderer', () => { expect(markup).toContain(' ColorValue, ): React.ReactNode { + if (node.kind === 'group' && node.focus) return null const style = nativeSceneStyle(node.style, paint) switch (node.kind) { diff --git a/packages/react-native-charts/src/Tooltip.test.ts b/packages/react-native-charts/src/Tooltip.test.ts index a3f53166..3789b715 100644 --- a/packages/react-native-charts/src/Tooltip.test.ts +++ b/packages/react-native-charts/src/Tooltip.test.ts @@ -1,6 +1,17 @@ +import * as React from 'react' +import { renderToStaticMarkup } from 'react-dom/server' import { describe, expect, it, vi } from 'vitest' -import type { ChartPoint, ChartScene } from '@tanstack/charts/types' -import { createNativeTooltipContent, placeNativeTooltip } from './Tooltip' +import type { + ChartPoint, + ChartScene, + ChartTooltipAnchorContext, +} from '@tanstack/charts/types' +import { + createNativeTooltipContent, + NativeChartTooltip, + placeNativeTooltip, + resolveNativeTooltipAnchor, +} from './Tooltip' vi.mock('react-native', () => ({ Text: 'span', @@ -31,6 +42,127 @@ describe('native tooltip model', () => { ), ).toEqual({ left: 8, top: 8, placement: 'top' }) }) + + it('preserves an intentional null custom body', () => { + const points = [point('alpha', 'Alpha', 3)] + const markup = renderToStaticMarkup( + React.createElement(NativeChartTooltip, { + scene: scene(points), + width: 100, + height: 60, + points, + pointer: null, + focusSource: 'programmatic', + pinned: false, + color: '#111827', + resolvePaint: (value) => value, + dismiss: vi.fn(), + render: () => null, + }), + ) + + expect(markup).not.toContain(' { + const points = [point('alpha', 'Alpha', 3), point('beta', 'Beta', 7)] + const currentScene = scene(points) + + expect( + resolveNativeTooltipAnchor( + points[0]!, + points, + currentScene, + null, + 'keyboard', + true, + { anchor: { x: 'plot-center', y: 'plot-top' } }, + ), + ).toEqual({ x: 50, y: 0 }) + + let context: ChartTooltipAnchorContext | undefined + expect( + resolveNativeTooltipAnchor( + points[0]!, + points, + currentScene, + null, + 'keyboard', + true, + { + anchor: (_focusedPoints, nextContext) => { + context = nextContext + return { x: 75, y: 25 } + }, + }, + ), + ).toEqual({ x: 75, y: 25 }) + expect(context).toEqual({ + focus: { + primary: points[0], + group: points, + source: 'keyboard', + pinned: true, + }, + pointer: null, + plot: currentScene.chart, + surface: { width: 100, height: 60 }, + scales: currentScene.scales, + }) + }) + + it('keeps the focused point stable when display rows are sorted', () => { + const beta = point('beta', 'Beta', 7) + const alpha = point('alpha', 'Alpha', 3) + const focusedPoints = [beta, alpha] + const currentScene = scene(focusedPoints) + const format = vi.fn( + (focused: ChartPoint) => focused.key, + ) + const anchor = vi.fn( + ( + _points: readonly ChartPoint[], + _context: ChartTooltipAnchorContext, + ) => ({ x: 75, y: 25 }), + ) + let renderedPoints: + readonly ChartPoint[] | undefined + + renderToStaticMarkup( + React.createElement(NativeChartTooltip, { + scene: currentScene, + width: 100, + height: 60, + points: focusedPoints, + pointer: null, + focusSource: 'keyboard', + options: { anchor, format }, + pinned: true, + color: '#111827', + resolvePaint: (value) => value, + dismiss: vi.fn(), + render: (context) => { + renderedPoints = context.points + return null + }, + }), + ) + + expect(renderedPoints).toEqual([alpha, beta]) + expect(format).toHaveBeenCalledWith(beta) + expect(anchor).toHaveBeenCalledWith([alpha, beta], { + focus: { + primary: beta, + group: focusedPoints, + source: 'keyboard', + pinned: true, + }, + pointer: null, + plot: currentScene.chart, + surface: { width: 100, height: 60 }, + scales: currentScene.scales, + }) + }) }) function point( diff --git a/packages/react-native-charts/src/Tooltip.tsx b/packages/react-native-charts/src/Tooltip.tsx index e08920fa..0e369a4e 100644 --- a/packages/react-native-charts/src/Tooltip.tsx +++ b/packages/react-native-charts/src/Tooltip.tsx @@ -8,6 +8,7 @@ import type { import { Text, View } from 'react-native' import type { ChartPoint, + ChartFocusSource, ChartScene, ChartTooltipContent, ChartTooltipContentContext, @@ -15,6 +16,8 @@ import type { ChartTooltipOptions, ChartTooltipPlacement, ChartTooltipPosition, + ChartTooltipXAnchor, + ChartTooltipYAnchor, ChartValue, } from '@tanstack/charts/types' import { resolveNativeSolidPaint, type NativePaintResolver } from './paint' @@ -41,6 +44,7 @@ export interface NativeChartTooltipProps< height: number points: readonly ChartPoint[] pointer: ChartTooltipPosition | null + focusSource: ChartFocusSource options?: ChartTooltipOptions pinned: boolean color: ColorValue @@ -61,6 +65,7 @@ export function NativeChartTooltip< height, points: unorderedPoints, pointer, + focusSource, options, pinned, color, @@ -73,15 +78,18 @@ export function NativeChartTooltip< () => orderTooltipPoints(unorderedPoints, scene, options?.sort), [options?.sort, scene, unorderedPoints], ) - const point = points[0] + const point = unorderedPoints[0] if (!point) return null - const content = createNativeTooltipContent(points, scene, options) - const sceneAnchor = resolveTooltipAnchor( + const content = createNativeTooltipContent(points, scene, options, point) + const sceneAnchor = resolveNativeTooltipAnchor( point, points, scene, pointer, + focusSource, + pinned, options, + unorderedPoints, ) const anchor = { x: (sceneAnchor.x / scene.width) * width, @@ -101,8 +109,9 @@ export function NativeChartTooltip< resolvePaint={resolvePaint} /> ) - const body = - render?.({ points, content, pinned, dismiss, defaultBody }) ?? defaultBody + const body = render + ? render({ points, content, pinned, dismiss, defaultBody }) + : defaultBody const accessibilityLabel = tooltipAccessibilityLabel(content) const handleLayout = (event: LayoutChangeEvent) => { const next = event.nativeEvent.layout @@ -206,13 +215,15 @@ export function createNativeTooltipContent< points: readonly ChartPoint[], scene: ChartScene, options?: ChartTooltipOptions, + primaryPoint?: ChartPoint, ): ChartTooltipContent | string { const point = points[0] if (!point) return { rows: [] } const context = createTooltipContentContext(scene) const content = options?.content?.(points, context) if (content !== undefined) return content - const formatted = options?.formatGroup?.(points) ?? options?.format?.(point) + const formatted = + options?.formatGroup?.(points) ?? options?.format?.(primaryPoint ?? point) if (formatted !== undefined) return formatted const sharedX = @@ -281,7 +292,7 @@ function findSceneLabel(scene: ChartScene, key: string) { return label?.kind === 'label' ? label.text : undefined } -function resolveTooltipAnchor< +export function resolveNativeTooltipAnchor< TDatum, TXValue extends ChartValue, TYValue extends ChartValue, @@ -290,7 +301,10 @@ function resolveTooltipAnchor< points: readonly ChartPoint[], scene: ChartScene, pointer: ChartTooltipPosition | null, + focusSource: ChartFocusSource, + pinned: boolean, options?: ChartTooltipOptions, + focusPoints: readonly ChartPoint[] = points, ): ChartTooltipPosition { const fallback = { x: point.x, y: point.y } const anchor = options?.anchor ?? 'point' @@ -304,17 +318,90 @@ function resolveTooltipAnchor< y: (Math.min(...y) + Math.max(...y)) / 2, } } + if (typeof anchor === 'object') { + return { + x: resolveTooltipCoordinate( + 'x', + anchor.x, + point, + points, + scene, + pointer, + fallback.x, + ), + y: resolveTooltipCoordinate( + 'y', + anchor.y, + point, + points, + scene, + pointer, + fallback.y, + ), + } + } const resolved = anchor(points, { + focus: { + primary: point, + group: focusPoints, + source: focusSource, + pinned, + }, pointer, - chart: scene.chart, - width: scene.width, - height: scene.height, + plot: scene.chart, + surface: { width: scene.width, height: scene.height }, + scales: scene.scales, }) return resolved && Number.isFinite(resolved.x) && Number.isFinite(resolved.y) ? resolved : fallback } +function resolveTooltipCoordinate< + TDatum, + TXValue extends ChartValue, + TYValue extends ChartValue, +>( + axis: 'x' | 'y', + source: ChartTooltipXAnchor | ChartTooltipYAnchor, + point: ChartPoint, + points: readonly ChartPoint[], + scene: ChartScene, + pointer: ChartTooltipPosition | null, + fallback: number, +): number { + if (source === 'point') return axis === 'x' ? point.x : point.y + if (source === 'pointer') return pointer?.[axis] ?? fallback + if (source === 'value') { + const value = axis === 'x' ? point.xValue : point.yValue + const position = scene.scales[axis]?.map(value) + return position !== undefined && Number.isFinite(position) + ? position + : fallback + } + if (source === 'group-center') { + let minimum = axis === 'x' ? point.x : point.y + let maximum = minimum + for (const candidate of points) { + const position = axis === 'x' ? candidate.x : candidate.y + minimum = Math.min(minimum, position) + maximum = Math.max(maximum, position) + } + return (minimum + maximum) / 2 + } + const plot = scene.chart + if (axis === 'x') { + if (source === 'plot-left') return plot.x + if (source === 'plot-center') return plot.x + plot.width / 2 + if (source === 'plot-right') return plot.x + plot.width + } else { + if (source === 'plot-top') return plot.y + if (source === 'plot-center') return plot.y + plot.height / 2 + if (source === 'plot-bottom') return plot.y + plot.height + } + return fallback +} + export function placeNativeTooltip( anchor: ChartTooltipPosition, tooltip: { width: number; height: number }, diff --git a/packages/react-native-charts/src/interaction.ts b/packages/react-native-charts/src/interaction.ts index d432ef7a..180d5e9c 100644 --- a/packages/react-native-charts/src/interaction.ts +++ b/packages/react-native-charts/src/interaction.ts @@ -108,7 +108,7 @@ export function samePointIdentity< ) } -export function samePointList< +export function samePointReferences< TDatum, TXValue extends ChartValue, TYValue extends ChartValue, @@ -118,7 +118,7 @@ export function samePointList< ) { return ( left.length === right.length && - left.every((point, index) => samePointIdentity(point, right[index] ?? null)) + left.every((point, index) => point === right[index]) ) } diff --git a/scripts/measure-bundles.mjs b/scripts/measure-bundles.mjs index bc1795a4..8c9202be 100644 --- a/scripts/measure-bundles.mjs +++ b/scripts/measure-bundles.mjs @@ -372,7 +372,12 @@ const entries = [ external: nativeExternals, rendererBoundary: 'native', inputBoundary: { - forbid: ['nativeTooltip'], + forbid: [ + 'nativeTooltip', + 'tooltipRuntime', + 'tooltipPortal', + 'd3Runtime', + ], }, platform: 'neutral', conditions: ['react-native', 'import'], @@ -386,6 +391,7 @@ const entries = [ rendererBoundary: 'native', inputBoundary: { require: ['nativeTooltip'], + forbid: ['tooltipRuntime', 'tooltipPortal', 'd3Runtime'], addedFrom: 'React Native SVG host', allowAdded: ['nativeTooltip'], }, @@ -400,7 +406,12 @@ const entries = [ external: nativeExternals, rendererBoundary: 'native', inputBoundary: { - forbid: ['nativeTooltip'], + forbid: [ + 'nativeTooltip', + 'tooltipRuntime', + 'tooltipPortal', + 'd3GeometryRuntime', + ], }, platform: 'neutral', conditions: ['react-native', 'import'], diff --git a/scripts/measure-react-native-poc.mjs b/scripts/measure-react-native-poc.mjs index d07cafc1..9e7bd71a 100644 --- a/scripts/measure-react-native-poc.mjs +++ b/scripts/measure-react-native-poc.mjs @@ -17,20 +17,24 @@ const forbiddenSources = [ 'packages/charts-core/src/export.ts', 'packages/charts-core/src/reconcile.ts', 'packages/charts-core/src/renderer.ts', - 'packages/charts-core/src/svg-renderer.ts', 'packages/charts-core/src/svg-resources.ts', 'packages/charts-core/src/svg-surface.ts', - 'packages/charts-core/src/svg.ts', 'packages/charts-core/src/tooltip-portal.ts', 'packages/charts-core/src/tooltip-position.ts', 'packages/charts-core/src/tooltip.ts', + 'packages/octane-charts/', 'packages/react-charts/', 'react-dom/', ] +const universalRetainedSources = [ + 'packages/charts-core/src/svg-renderer.ts', + 'packages/charts-core/src/svg.ts', +] const variants = { blank: 'index.blank.js', svg: 'index.svg.js', core: 'index.core.js', + granular: 'index.granular.js', chart: 'index.js', } @@ -66,7 +70,8 @@ for (const platform of ['ios', 'android']) { const contents = await readFile(bundle) const map = JSON.parse(await readFile(sourceMap, 'utf8')) const sources = map.sources.map(normalize) - if (variant === 'chart') assertNativeBoundary(platform, sources) + if (variant === 'chart') assertNativeBoundary(platform, sources, true) + if (variant === 'granular') assertNativeBoundary(platform, sources, false) bundles.push({ platform, variant, @@ -78,9 +83,9 @@ for (const platform of ['ios', 'android']) { } const rows = [ - '| Platform | Full chart JS delta | RNSVG-only gzip delta | Core line gzip delta | Full chart gzip delta |', + '| Platform | Full chart `/universal` JS delta | RNSVG-only gzip delta | Core line gzip delta | Full chart `/universal` gzip delta | `/universal` over granular gzip |', ] -rows.push('| --- | ---: | ---: | ---: | ---: |') +rows.push('| --- | ---: | ---: | ---: | ---: | ---: |') for (const platform of ['ios', 'android']) { const blank = bundles.find( (bundle) => bundle.platform === platform && bundle.variant === 'blank', @@ -88,17 +93,20 @@ for (const platform of ['ios', 'android']) { const chart = bundles.find( (bundle) => bundle.platform === platform && bundle.variant === 'chart', ) + const granular = bundles.find( + (bundle) => bundle.platform === platform && bundle.variant === 'granular', + ) const svg = bundles.find( (bundle) => bundle.platform === platform && bundle.variant === 'svg', ) const core = bundles.find( (bundle) => bundle.platform === platform && bundle.variant === 'core', ) - if (!blank || !chart || !svg || !core) { + if (!blank || !chart || !granular || !svg || !core) { throw new Error(`Missing ${platform} bundle result`) } rows.push( - `| ${platform} | ${format(chart.bytes - blank.bytes)} | ${format(svg.gzip - blank.gzip)} | ${format(core.gzip - blank.gzip)} | ${format(chart.gzip - blank.gzip)} |`, + `| ${platform} | ${format(chart.bytes - blank.bytes)} | ${format(svg.gzip - blank.gzip)} | ${format(core.gzip - blank.gzip)} | ${format(chart.gzip - blank.gzip)} | ${format(chart.gzip - granular.gzip)} |`, ) } @@ -108,7 +116,7 @@ await writeFile( `${JSON.stringify( { schemaVersion: 1, - note: 'Metro production JS only. This excludes react-native-svg native binary code.', + note: 'Metro production JS only. The chart and granular variants share one UI and definition factory while their application entries use @tanstack/charts/universal and granular definition imports respectively; this excludes react-native-svg native binary code.', bundles, }, null, @@ -116,13 +124,38 @@ await writeFile( )}\n`, ) -function assertNativeBoundary(platform, sources) { +function assertNativeBoundary(platform, sources, requiresUniversal) { const nativeSources = sources.filter((source) => source.includes('packages/react-native-charts/src/'), ) if (!nativeSources.length) { throw new Error(`${platform} bundle did not include the native host`) } + const includesUniversal = sources.some((source) => + source.includes('packages/charts-core/src/universal.ts'), + ) + if (requiresUniversal && !includesUniversal) { + throw new Error(`${platform} bundle did not exercise the universal entry`) + } + if (!requiresUniversal && includesUniversal) { + throw new Error(`${platform} granular bundle included the universal entry`) + } + const retainedUniversalSources = universalRetainedSources.filter( + (candidate) => sources.some((source) => source.includes(candidate)), + ) + if ( + requiresUniversal && + retainedUniversalSources.length !== universalRetainedSources.length + ) { + throw new Error( + `${platform} universal bundle did not retain its static SVG serializer`, + ) + } + if (!requiresUniversal && retainedUniversalSources.length) { + throw new Error( + `${platform} granular bundle retained broad universal modules:\n${retainedUniversalSources.join('\n')}`, + ) + } const forbidden = sources.filter((source) => forbiddenSources.some((candidate) => source.includes(candidate)), ) From 710ffecbad98810a6dacc47a46c64f9d8c0bf366 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Fri, 31 Jul 2026 19:29:46 -0600 Subject: [PATCH 3/5] Publish experimental React Native charts adapter --- .changeset/README.md | 2 +- .changeset/config.json | 1 + .changeset/native-svg-host.md | 8 + API-FRICTION.md | 47 +- NATIVE-PLATFORM-SUPPORT-SPIKE.md | 48 +- REACT-NATIVE-HOST-POC.md | 65 +- README.md | 25 +- docs/installation.md | 57 +- docs/overview.md | 30 +- examples/charts-expo/App.tsx | 44 + examples/charts-expo/app.json | 6 + examples/charts-expo/index.ts | 4 + examples/charts-expo/metro.config.cjs | 3 + examples/charts-expo/package.json | 28 + examples/charts-expo/tsconfig.json | 8 + examples/charts-react-native/package.json | 13 +- nx.json | 3 + packages/charts-core/docs/installation.md | 57 +- packages/charts-core/docs/overview.md | 30 +- packages/react-native-charts/CHANGELOG.md | 1 + packages/react-native-charts/README.md | 59 +- packages/react-native-charts/package.json | 38 +- .../react-native-charts/src/index.native.ts | 1 + .../src/tooltip-entry.native.ts | 1 + pnpm-lock.yaml | 2170 +++++++++++++++-- scripts/check-packed-consumers.mjs | 38 +- scripts/check-react-native-types.mjs | 1 + scripts/docs-contract.mjs | 2 + scripts/packed-react-native-consumers.mjs | 540 ++++ scripts/release-package-config.mjs | 1 + scripts/release-workflow.test.mjs | 1 + 31 files changed, 2946 insertions(+), 386 deletions(-) create mode 100644 .changeset/native-svg-host.md create mode 100644 examples/charts-expo/App.tsx create mode 100644 examples/charts-expo/app.json create mode 100644 examples/charts-expo/index.ts create mode 100644 examples/charts-expo/metro.config.cjs create mode 100644 examples/charts-expo/package.json create mode 100644 examples/charts-expo/tsconfig.json create mode 100644 packages/react-native-charts/CHANGELOG.md create mode 100644 packages/react-native-charts/src/index.native.ts create mode 100644 packages/react-native-charts/src/tooltip-entry.native.ts create mode 100644 scripts/packed-react-native-consumers.mjs diff --git a/.changeset/README.md b/.changeset/README.md index 042fc7a8..9ab5c86d 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -6,6 +6,6 @@ Add a changeset for every user-visible package change: pnpm changeset ``` -All eleven public Charts packages release as one fixed version. Documentation, +All twelve public Charts packages release as one fixed version. Documentation, tests, benchmarks, and build-only changes do not need a changeset unless they change the published package contract. diff --git a/.changeset/config.json b/.changeset/config.json index 73e3ddd2..60f4275e 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -17,6 +17,7 @@ "@tanstack/charts", "@tanstack/charts-scales", "@tanstack/react-charts", + "@tanstack/react-native-charts", "@tanstack/octane-charts", "@tanstack/preact-charts", "@tanstack/vue-charts", diff --git a/.changeset/native-svg-host.md b/.changeset/native-svg-host.md new file mode 100644 index 00000000..9b7b1cd4 --- /dev/null +++ b/.changeset/native-svg-host.md @@ -0,0 +1,8 @@ +--- +'@tanstack/react-native-charts': minor +--- + +Add the experimental React Native SVG host with responsive scene rendering, +focus, selection, accessibility actions, and an optional native tooltip entry. +Ship compiled ESM and declarations, and verify the packed package in bare React +Native and Expo Metro consumers. diff --git a/API-FRICTION.md b/API-FRICTION.md index f3f26f4b..ec111e23 100644 --- a/API-FRICTION.md +++ b/API-FRICTION.md @@ -206,9 +206,10 @@ Each entry records: | F-167 | Native interaction copied DOM-renderer policy | API | monitoring | | F-168 | CSS theme defaults reach the native scene compiler | API | monitoring | | F-169 | Text measurement omits native typography | API | monitoring | -| F-170 | Packed declarations assume one platform global set | Tooling | monitoring | +| F-170 | Packed declarations assume one platform global set | Tooling | resolved | | F-171 | Metro skipped the fixture-owned Babel runtime | Tooling | resolved | | F-172 | Metro retained the complete universal barrel | API/Tooling | monitoring | +| F-173 | OIDC release cannot claim a new npm package name | Tooling | monitoring | ## Findings @@ -4132,19 +4133,29 @@ Each entry records: ### F-170 — Packed declarations assume one platform global set -- Status: monitoring +- Status: resolved - Severity: medium - Owner: Tooling -- Observed in: evaluating a release gate for the private React Native package +- Observed in: making the React Native package publishable - Friction: the existing packed fixture compiles web packages under DOM libraries. Loading React Native declarations in that same TypeScript program introduces incompatible duplicate globals. Removing DOM libraries makes the web contracts invalid and also exposes F-166. -- Current decision: keep the private proof out of the publishable-package - matrix. Its source package, native consumer, isolated bundle, Metro bundles, - and no-browser source-map boundary are checked separately. -- Follow-up: add a native-specific build, pack, install, declaration, Metro, - and platform-condition fixture before making the package publishable. +- Decision: build and pack the native adapter in the release artifact matrix, + but keep its declarations and consumers outside the DOM fixture's TypeScript + program. The package publishes compiled ESM and declarations with `types`, + `react-native`, and `import` conditions. A native-specific gate deploys clean + bare React Native and Expo dependency trees, installs the packed core and + adapter tarballs, and runs each platform's normal Metro configuration. +- Verification: the staged package emits both root and optional-tooltip + declarations, contains no source or tests, and retains no `workspace:` + ranges. Node resolution selects the import build normally and the native + shims under `--conditions=react-native`. Bare React Native 0.86.2 with + `react-native-svg` 15.15.5 and Expo 57 with Expo's 15.15.4 build both + typecheck and produce iOS and Android bundles. All four source maps resolve + the adapter and `/universal` from installed `dist`, include the native + conditional entries, exclude workspace source and guarded browser modules, + and retain only F-166's two known strict dependency diagnostics. ### F-171 — Metro skipped the fixture-owned Babel runtime @@ -4187,3 +4198,23 @@ Each entry records: `packages/charts-core/src/universal.ts`, measure 102.94 and 102.99 KiB gzip over blank respectively, and exclude DOM hosts, browser adapters, Canvas, reconciliation, SVG resources/surface, web tooltip code, and `react-dom`. + +### F-173 — OIDC release cannot claim a new npm package name + +- Status: monitoring +- Severity: high +- Owner: Tooling +- Observed in: adding `@tanstack/react-native-charts` to the fixed release set +- Friction: the package name is not present in the npm registry, while the + aggregate release uses npm trusted publishing. npm configures that trust from + an existing package's settings, so the normal tokenless workflow cannot be + authorized for this package before its registry entry exists. +- Current decision: keep the package in release artifacts and the fixed + changeset, but require a maintainer-controlled direct public publish of the + checked `0.3.1` tarball. Configure the repository's release workflow as the + trusted publisher immediately afterward; the aggregate changeset can then + publish `0.4.0` through OIDC. +- Verification: `npm view @tanstack/react-native-charts` currently returns + `E404`. Close this entry only after the public package exists, its trusted + publisher names the repository release workflow, and an aggregate release + publishes it without a long-lived write token. diff --git a/NATIVE-PLATFORM-SUPPORT-SPIKE.md b/NATIVE-PLATFORM-SUPPORT-SPIKE.md index 1aebcf9b..a1ad4832 100644 --- a/NATIVE-PLATFORM-SUPPORT-SPIKE.md +++ b/NATIVE-PLATFORM-SUPPORT-SPIKE.md @@ -206,33 +206,32 @@ cross-runtime consumers opt into `@tanstack/charts/universal` and As of this research, React Native 0.86 is current stable. React Native 0.82 made the New Architecture mandatory. Set the initial support floor to React -Native 0.85 and test Expo SDK 56 / React Native 0.85 plus bare React Native -0.86. Supporting 0.82–0.84 later requires adding those CI lanes; a nominal -floor without tests is not support. Version-one product scope is iOS and -Android. Renderer dependencies may also run on macOS, Windows, web, or TV, but -those platforms need their own input, accessibility, packaging, and -conformance gates. +Native 0.86 and test Expo SDK 57 plus bare React Native 0.86. Supporting older +minors later requires adding those CI lanes; a nominal floor without tests is +not support. Version-one product scope is iOS and Android. Renderer +dependencies may also run on macOS, Windows, web, or TV, but those platforms +need their own input, accessibility, packaging, and conformance gates. [React Native versions](https://reactnative.dev/versions.html) · [React Native 0.82](https://reactnative.dev/blog/2025/10/08/react-native-0.82) · -[Expo SDK 56](https://docs.expo.dev/versions/v56.0.0/) +[Expo SDK 57](https://docs.expo.dev/versions/v57.0.0/) The two supported dependency lanes differ: -| Dependency | Expo SDK 56 / RN 0.85 | Bare RN 0.86 | +| Dependency | Expo SDK 57 / RN 0.86 | Bare RN 0.86 | | ------------------ | -------------------------------------------- | ----------------------------------------------------- | | `react-native-svg` | Expo-pinned 15.15.4 | current compatible 15.15.x | | Skia | Expo-pinned 2.6.2 | current compatible 2.x | -| Reanimated | Expo-pinned 4.3.1 | 4.4+ line that declares RN 0.86 support | +| Reanimated | Expo-pinned 4.5.1 | matching RN 0.86-compatible line | | Worklets | managed with the Expo/Reanimated combination | matching line from the Reanimated compatibility table | -| Gesture Handler | Expo-pinned ~2.31.1 | current RN 0.86-compatible line | +| Gesture Handler | Expo-pinned ~2.32.0 | current RN 0.86-compatible line | Reanimated 4 is New-Architecture-only. Expo configures its supported plugin combination; bare apps must install the matching Worklets package and plugin. Gesture Handler also requires `GestureHandlerRootView`. -[Expo Reanimated](https://docs.expo.dev/versions/v56.0.0/sdk/reanimated/) · -[Expo Gesture Handler](https://docs.expo.dev/versions/v56.0.0/sdk/gesture-handler/) · -[Expo SVG](https://docs.expo.dev/versions/v56.0.0/sdk/svg/) · -[Expo Skia](https://docs.expo.dev/versions/v56.0.0/sdk/skia/) · +[Expo Reanimated](https://docs.expo.dev/versions/v57.0.0/sdk/reanimated/) · +[Expo Gesture Handler](https://docs.expo.dev/versions/v57.0.0/sdk/gesture-handler/) · +[Expo SVG](https://docs.expo.dev/versions/v57.0.0/sdk/svg/) · +[Expo Skia](https://docs.expo.dev/versions/v57.0.0/sdk/skia/) · [Reanimated compatibility](https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/) D3 is not expected to be the blocker. The imported `d3-array`, `d3-scale`, @@ -554,12 +553,13 @@ SVG chart does not acquire or autolink unrelated native modules. Do not use `optionalDependencies`. The base implementation and declaration graph must have no static reference to optional peers. -Package exports need explicit `browser`, `react-native`, and `default` -conditions, with `browser` before `react-native`, plus matching type -declarations. Once an export matches, Metro does not append `.native` or `.web` -to that target. Test resolution through Metro/Expo, Vite or Webpack, Jest, and -TypeScript. An export target cannot point into another package, so a browser -re-export needs a local shim and declared dependency or peer. +The native-only preview needs explicit `types`, `react-native`, and `import` +conditions. A future entry that serves different browser and native +implementations would also need an explicit `browser` condition before +`react-native`. Once an export matches, Metro does not append `.native` or +`.web` to that target. Test resolution through Metro/Expo, Node, and +TypeScript. An export target cannot point into another package, so any future +browser re-export needs a local shim and declared dependency or peer. [Metro package exports](https://metrobundler.dev/docs/package-exports/) ## NativeScript @@ -782,8 +782,8 @@ count from intuition. ### Stop conditions -Pause a public native package if any of these remain unresolved after the -proof: +Do not claim supported native parity if any of these remain unresolved after +the proof: - text measurement causes repeated layout oscillation or materially wrong guides, or the measuring and painting stacks disagree on shaped text; @@ -835,8 +835,8 @@ Ongoing maintenance is material: ## Recommended first commitment -Fund a two-week, two-engineer device and shared-behavior proof rather than -announce the private package. +Fund a two-week, two-engineer device and shared-behavior proof before treating +the experimental package as supported. Engineer A: diff --git a/REACT-NATIVE-HOST-POC.md b/REACT-NATIVE-HOST-POC.md index 61285f5e..fb1d46bd 100644 --- a/REACT-NATIVE-HOST-POC.md +++ b/REACT-NATIVE-HOST-POC.md @@ -36,7 +36,7 @@ production support. ## Implemented proof -The private `@tanstack/react-native-charts` package includes: +The publishable experimental `@tanstack/react-native-charts` package includes: - a generic React Native `Chart` component that owns `createChartRuntime`; - responsive sizing from explicit dimensions, aspect ratio, or `onLayout`; @@ -52,7 +52,9 @@ The private `@tanstack/react-native-charts` package includes: custom anchors, collision-aware placement, custom content, and a custom React body; - an optional injected text measurer; -- a Metro fixture using React Native 0.86.0 and `react-native-svg` 15.15.5; +- a bare Metro fixture using React Native 0.86.2 and `react-native-svg` + 15.15.5; +- an Expo 57 Metro fixture using Expo's `react-native-svg` 15.15.4; - source-map checks that reject browser renderer code in iOS and Android bundles. @@ -245,10 +247,10 @@ Prerequisite changes delivered by the universal-barrel PR: - mechanical split between universal and DOM host types, with root re-exports preserved. -This proof adds a separate private React Native package, base component -contract, and optional tooltip subpath. +This proof adds a separate React Native package, base component contract, and +optional tooltip subpath. -Additive changes likely required before release: +Additive changes likely required before a supported release: - a shared, renderer-neutral interaction state module; - a shared tooltip content/anchor/placement model; @@ -263,8 +265,8 @@ Changes to avoid: - making string prerendering optional inside that renderer contract; - importing React Native from the core package; - shipping CSS tokens to native and silently substituting arbitrary colors; -- claiming compatibility outside the tested React Native 0.86.0 and - `react-native-svg` 15.15.5 pair; +- claiming compatibility outside the tested Expo 57 and bare React Native + 0.86.2 lanes or the `react-native-svg` 15.15.4–15.15.5 pair; - adding Skia before an on-device density/performance crossover is measured. The root type API remains compatible. Consumers that want a DOM-free @@ -273,10 +275,13 @@ replace browser-root imports with `@tanstack/charts/universal`; granular entries remain the bundle-sensitive option. Neither path changes existing published web behavior. -The private package is not publishable as it stands. Metro resolves its -workspace source, and the package has no production build or published export -map. A native-specific build, declaration, tarball, install, -conditional-export, and Metro-consumer gate is part of productionization. +The package now ships compiled ESM and declarations for the root and optional +tooltip entries. Published exports put `types` first, select explicit native +shims through the `react-native` condition, and retain `import` fallbacks. The +release gate builds and packs the adapter with the fixed package set, then +installs the core and native tarballs into isolated bare React Native and Expo +consumers. Their default Metro configurations must resolve installed `dist` +files rather than workspace source. ## Pros and cons @@ -303,8 +308,8 @@ conditional-export, and Metro-consumer gate is part of productionization. and two platform-specific failure surfaces. - Current interaction and tooltip ownership must be refactored out of mature DOM host implementations without regressing web behavior. -- A publishable native package needs a separate packed-declaration gate because - React Native and DOM global declarations conflict in the current web fixture. +- The native package needs its separate packed-declaration program because + React Native and DOM global declarations conflict in one TypeScript program. ## Verification performed @@ -315,12 +320,18 @@ conditional-export, and Metro-consumer gate is part of productionization. native modules mocked; they are structural tests, not native renderer tests. - The native package and the normal React Native application configuration typecheck. +- Packed root and tooltip declarations typecheck in isolated bare and Expo + consumers. Normal and `react-native` conditional resolution both select the + installed `dist` files. - The repository-wide typecheck passes with the native dependency graph. - The prerequisite PR's packed gate validates the supported environment-safe entries without changing the browser root. - Existing locked web bundle baselines remain unchanged. - Production Metro bundles complete for iOS and Android, and the full-chart variants must resolve `/universal`. +- Packed bare React Native and Expo consumers produce iOS and Android bundles + without workspace aliases. Their source maps include the native conditional + entries and exclude workspace source and guarded browser modules. - Source-map gates prove the full native entries do not include guarded browser implementation files, including the web tooltip and portal runtimes. - Retained-input gates prove the base native host and line consumer omit the @@ -335,9 +346,10 @@ only those two known errors, or a clean result after the upstream declaration is fixed. The POC does not add a fake global or pull DOM libraries into native to hide the upstream declaration problem. -The isolated esbuild boundary runs in `pnpm validate`. GitHub runs the native -declaration check as a separate workflow step. The ten-build iOS/Android Metro -measurement remains a local spike command rather than a mandatory CI gate. +The isolated esbuild boundary and packed bare/Expo Metro gate run in +`pnpm validate`. GitHub also runs the source native declaration check as a +separate workflow step. The ten-build comparative Metro measurement remains a +local spike command rather than a mandatory CI gate. Not performed: @@ -348,25 +360,26 @@ Not performed: - 1k/10k-point interaction and memory tests; - release application binary comparison; - VoiceOver and TalkBack validation; -- Expo managed-workflow validation; +- Expo prebuild, simulator, or device validation; - motion, export, or Skia implementation. ## Production path -### Phase 1: shared behavior and a releasable SVG host +### Phase 1: shared behavior and a supported SVG host Extract interaction and tooltip policy, add native theme ownership, complete -the typography contract, replace the proof's responder policy, and add a -native-specific package gate. Keep the package scoped to the tested RN/RNSVG -pair. +the typography contract, and replace the proof's responder policy. Maintain +the native-specific package gate and keep the package scoped to tested +RN/RNSVG lanes. Estimated effort: 3–5 engineering weeks. ### Phase 2: device confidence -Add bare and Expo fixtures, iOS and Android release builds, a platform-neutral -definition corpus, screenshot/geometry comparison, VoiceOver/TalkBack flows, -binary-size measurement, and sustained interaction benchmarks. +Add generated native projects for bare and Expo applications, iOS and Android +release builds, a platform-neutral definition corpus, screenshot/geometry +comparison, VoiceOver/TalkBack flows, binary-size measurement, and sustained +interaction benchmarks. Estimated effort: 3–5 engineering weeks. @@ -387,7 +400,7 @@ not schedule commitments. Proceed to Phase 1 if a real React Native product is planned. The architecture is sound and the JavaScript cost is reasonable for a charting package. Keep the -package private if the immediate goal is only optional ecosystem coverage. +published package experimental until the device-confidence work is complete. Do not start a NativeScript adapter in parallel. The earlier [native platform support spike](./NATIVE-PLATFORM-SUPPORT-SPIKE.md) remains the @@ -399,6 +412,8 @@ interaction surface were exercised. - [React Native 0.86 release](https://reactnative.dev/blog/2026/06/11/react-native-0.86) - [React Native version support status](https://reactnative.dev/versions.html) +- [Expo SDK version matrix](https://docs.expo.dev/versions/latest/) +- [Expo 57 SVG renderer](https://docs.expo.dev/versions/v57.0.0/sdk/svg/) - [React Native layout events](https://reactnative.dev/docs/layoutevent) - [React Native accessibility](https://reactnative.dev/docs/accessibility) - [`react-native-svg` support and compatibility](https://github.com/software-mansion/react-native-svg) diff --git a/README.md b/README.md index 8c7a6e8c..67bfc53b 100644 --- a/README.md +++ b/README.md @@ -130,18 +130,19 @@ bounded representation. ## Packages -| Package | Role | -| ------------------------------------------------------- | ------------------------------------- | -| [`@tanstack/charts`](./packages/charts-core) | Framework-neutral grammar and runtime | -| [`@tanstack/react-charts`](./packages/react-charts) | React adapter | -| [`@tanstack/preact-charts`](./packages/preact-charts) | Preact adapter | -| [`@tanstack/vue-charts`](./packages/vue-charts) | Vue adapter | -| [`@tanstack/solid-charts`](./packages/solid-charts) | Solid adapter | -| [`@tanstack/svelte-charts`](./packages/svelte-charts) | Svelte adapter | -| [`@tanstack/angular-charts`](./packages/angular-charts) | Angular standalone-component adapter | -| [`@tanstack/lit-charts`](./packages/lit-charts) | Lit custom-element adapter | -| [`@tanstack/alpine-charts`](./packages/alpine-charts) | Alpine directive adapter | -| [`@tanstack/octane-charts`](./packages/octane-charts) | Octane adapter | +| Package | Role | +| ----------------------------------------------------------------- | ------------------------------------- | +| [`@tanstack/charts`](./packages/charts-core) | Framework-neutral grammar and runtime | +| [`@tanstack/react-charts`](./packages/react-charts) | React adapter | +| [`@tanstack/react-native-charts`](./packages/react-native-charts) | Experimental React Native SVG adapter | +| [`@tanstack/preact-charts`](./packages/preact-charts) | Preact adapter | +| [`@tanstack/vue-charts`](./packages/vue-charts) | Vue adapter | +| [`@tanstack/solid-charts`](./packages/solid-charts) | Solid adapter | +| [`@tanstack/svelte-charts`](./packages/svelte-charts) | Svelte adapter | +| [`@tanstack/angular-charts`](./packages/angular-charts) | Angular standalone-component adapter | +| [`@tanstack/lit-charts`](./packages/lit-charts) | Lit custom-element adapter | +| [`@tanstack/alpine-charts`](./packages/alpine-charts) | Alpine directive adapter | +| [`@tanstack/octane-charts`](./packages/octane-charts) | Octane adapter | The earlier host experiment remains under `@plot-poc/*` for migration evidence and benchmark comparison. The private diff --git a/docs/installation.md b/docs/installation.md index 3fcbb600..1f893f03 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -17,6 +17,9 @@ Then add one adapter if the application needs it: # React pnpm add @tanstack/react-charts react react-dom +# React Native +pnpm add @tanstack/react-native-charts react react-native react-native-svg + # Preact pnpm add @tanstack/preact-charts preact @@ -46,22 +49,54 @@ The adapters intentionally do not replace the core package. Definitions and mark ## Framework compatibility -| Adapter package | Framework peers | -| -------------------------- | ---------------------------------------- | -| `@tanstack/react-charts` | React and React DOM `^19.0.0` | -| `@tanstack/preact-charts` | Preact `>=10` | -| `@tanstack/vue-charts` | Vue `>=3.5` | -| `@tanstack/solid-charts` | Solid `>=1.8` | -| `@tanstack/svelte-charts` | Svelte `^5.20.0` | -| `@tanstack/angular-charts` | Angular core and platform browser `>=19` | -| `@tanstack/lit-charts` | Lit `>=3.1.3` | -| `@tanstack/alpine-charts` | Alpine `>=3.15` | -| `@tanstack/octane-charts` | Octane `^0.1.13` | +| Adapter package | Framework peers | +| ------------------------------- | ------------------------------------------------------------------------------- | +| `@tanstack/react-charts` | React and React DOM `^19.0.0` | +| `@tanstack/react-native-charts` | React `^19.2.3`, React Native `^0.86.0`, and `react-native-svg` `>=15.15.4 <16` | +| `@tanstack/preact-charts` | Preact `>=10` | +| `@tanstack/vue-charts` | Vue `>=3.5` | +| `@tanstack/solid-charts` | Solid `>=1.8` | +| `@tanstack/svelte-charts` | Svelte `^5.20.0` | +| `@tanstack/angular-charts` | Angular core and platform browser `>=19` | +| `@tanstack/lit-charts` | Lit `>=3.1.3` | +| `@tanstack/alpine-charts` | Alpine `>=3.15` | +| `@tanstack/octane-charts` | Octane `^0.1.13` | These ranges are the package peer contracts. Use the selected framework's normal renderer or application package beside the adapter when the application needs browser mounting or server rendering. +## React Native and Expo + +The React Native adapter is experimental and renders through +`react-native-svg`. Expo 57 applications can install the package and the SVG +version selected by Expo: + +```sh +pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale +pnpm exec expo install react-native-svg +``` + +Bare React Native 0.86 applications install the renderer directly: + +```sh +pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale react-native-svg +``` + +Run `bundle exec pod install` from `ios/` after adding it to a bare iOS +application. Import shared definitions through the universal entry and choose +the native host explicitly: + +```tsx +import { defineChart, lineY } from '@tanstack/charts/universal' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' +``` + +Packed tarballs are typechecked and bundled through default bare React Native +and Expo Metro configurations on iOS and Android. Simulator, physical-device, +gesture, visual, and screen-reader validation is not yet a support claim. + ## Install the D3 modules you import TanStack Charts accepts D3 scale factories, configured scale instances, and diff --git a/docs/overview.md b/docs/overview.md index 46864bd5..66a81c62 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -22,8 +22,9 @@ The library is designed for two equally important authors: - People should get polished, responsive charts from a short declaration. - AI should be able to compose, inspect, and modify charts without learning an application-specific series model or guessing at hidden behavior. -The same definition works with the vanilla DOM host and every framework -adapter. React and Octane also provide optional Canvas entries. +The same definition can feed the vanilla DOM host and framework adapters. +React and Octane also provide optional Canvas entries; the experimental React +Native adapter consumes definitions from the universal entry. ## A chart is a composition @@ -156,18 +157,19 @@ Every automatic behavior has an explicit escape hatch. The [Guides](./guides/res ## Packages -| Package | Use it for | -| -------------------------- | ---------------------------------------------------------------- | -| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM | -| `@tanstack/react-charts` | React `` | -| `@tanstack/preact-charts` | Preact `` | -| `@tanstack/vue-charts` | Vue `` | -| `@tanstack/solid-charts` | Solid `` | -| `@tanstack/svelte-charts` | Svelte `` | -| `@tanstack/angular-charts` | Angular `` | -| `@tanstack/lit-charts` | Lit `` | -| `@tanstack/alpine-charts` | Alpine `x-chart` | -| `@tanstack/octane-charts` | Octane `` | +| Package | Use it for | +| ------------------------------- | ---------------------------------------------------------------- | +| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM | +| `@tanstack/react-charts` | React `` | +| `@tanstack/react-native-charts` | Experimental React Native SVG `` | +| `@tanstack/preact-charts` | Preact `` | +| `@tanstack/vue-charts` | Vue `` | +| `@tanstack/solid-charts` | Solid `` | +| `@tanstack/svelte-charts` | Svelte `` | +| `@tanstack/angular-charts` | Angular `` | +| `@tanstack/lit-charts` | Lit `` | +| `@tanstack/alpine-charts` | Alpine `x-chart` | +| `@tanstack/octane-charts` | Octane `` | All packages are ESM and tree-shakeable. Built-in marks and optional capabilities also have subpath exports when a library or design system needs tighter bundle boundaries. diff --git a/examples/charts-expo/App.tsx b/examples/charts-expo/App.tsx new file mode 100644 index 00000000..08067151 --- /dev/null +++ b/examples/charts-expo/App.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' +import { SafeAreaView, View } from 'react-native' +import { scaleLinear } from 'd3-scale' +import { defineChart, lineY } from '@tanstack/charts/universal' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' + +const rows = [ + { month: 1, revenue: 12 }, + { month: 2, revenue: 18 }, + { month: 3, revenue: 15 }, + { month: 4, revenue: 26 }, + { month: 5, revenue: 31 }, +] + +const definition = defineChart({ + marks: [ + lineY(rows, { + x: 'month', + y: 'revenue', + stroke: '#2563eb', + strokeWidth: 3, + points: true, + }), + ], + x: { label: 'Month', scale: scaleLinear().domain([1, 5]) }, + y: { label: 'Revenue', scale: scaleLinear().domain([0, 35]) }, + focus: 'nearest-x', + tooltip: { use: tooltip, sticky: true }, +}) + +export default function App() { + return ( + + + + + + ) +} diff --git a/examples/charts-expo/app.json b/examples/charts-expo/app.json new file mode 100644 index 00000000..af08ba59 --- /dev/null +++ b/examples/charts-expo/app.json @@ -0,0 +1,6 @@ +{ + "expo": { + "name": "TanStack Charts Expo", + "slug": "tanstack-charts-expo" + } +} diff --git a/examples/charts-expo/index.ts b/examples/charts-expo/index.ts new file mode 100644 index 00000000..40906434 --- /dev/null +++ b/examples/charts-expo/index.ts @@ -0,0 +1,4 @@ +import { registerRootComponent } from 'expo' +import App from './App' + +registerRootComponent(App) diff --git a/examples/charts-expo/metro.config.cjs b/examples/charts-expo/metro.config.cjs new file mode 100644 index 00000000..9f8f3c43 --- /dev/null +++ b/examples/charts-expo/metro.config.cjs @@ -0,0 +1,3 @@ +const { getDefaultConfig } = require('expo/metro-config') + +module.exports = getDefaultConfig(__dirname) diff --git a/examples/charts-expo/package.json b/examples/charts-expo/package.json new file mode 100644 index 00000000..ad79c448 --- /dev/null +++ b/examples/charts-expo/package.json @@ -0,0 +1,28 @@ +{ + "name": "@charts-poc/expo-example", + "version": "0.0.0", + "private": true, + "license": "MIT", + "main": "index.ts", + "scripts": { + "start": "expo start", + "bundle": "expo export --platform all --output-dir dist --clear" + }, + "dependencies": { + "@tanstack/charts": "workspace:*", + "@tanstack/react-native-charts": "workspace:*", + "d3-scale": "4.0.2", + "expo": "~57.0.9", + "react": "19.2.3", + "react-native": "0.86.2", + "react-native-svg": "15.15.4" + }, + "devDependencies": { + "@types/d3-scale": "^4.0.9", + "@types/react": "~19.2.2", + "typescript": "~6.0.3" + }, + "engines": { + "node": ">=22.13.0" + } +} diff --git a/examples/charts-expo/tsconfig.json b/examples/charts-expo/tsconfig.json new file mode 100644 index 00000000..d8a90988 --- /dev/null +++ b/examples/charts-expo/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "skipLibCheck": true + }, + "include": ["App.tsx", "index.ts"] +} diff --git a/examples/charts-react-native/package.json b/examples/charts-react-native/package.json index e2ad3e6d..fcf782a5 100644 --- a/examples/charts-react-native/package.json +++ b/examples/charts-react-native/package.json @@ -13,16 +13,21 @@ "@tanstack/react-native-charts": "workspace:*", "d3-scale": "4.0.2", "react": "19.2.3", - "react-native": "0.86.0", + "react-native": "0.86.2", "react-native-svg": "15.15.5" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/runtime": "^7.25.0", "@react-native-community/cli": "20.1.0", - "@react-native/babel-preset": "0.86.0", - "@react-native/metro-config": "0.86.0", - "@react-native/typescript-config": "0.86.0" + "@react-native-community/cli-platform-android": "20.1.0", + "@react-native-community/cli-platform-ios": "20.1.0", + "@react-native/babel-preset": "0.86.2", + "@react-native/metro-config": "0.86.2", + "@react-native/typescript-config": "0.86.2", + "@types/d3-scale": "^4.0.9", + "@types/react": "~19.2.2", + "typescript": "~6.0.3" }, "engines": { "node": ">=22.11.0" diff --git a/nx.json b/nx.json index 44671a45..f46ad7ea 100644 --- a/nx.json +++ b/nx.json @@ -61,11 +61,14 @@ "{workspaceRoot}/docs/**/*", "{workspaceRoot}/packages/charts-core/**/*", "{workspaceRoot}/packages/*-charts/**/*", + "{workspaceRoot}/examples/charts-react-native/**/*", + "{workspaceRoot}/examples/charts-expo/**/*", "!{workspaceRoot}/packages/*/dist/**/*", "{workspaceRoot}/scripts/*package*.mjs", "{workspaceRoot}/scripts/*release*.mjs", "{workspaceRoot}/scripts/check-framework-adapters.mjs", "{workspaceRoot}/scripts/check-packed-consumers.mjs", + "{workspaceRoot}/scripts/packed-react-native-consumers.mjs", "{workspaceRoot}/scripts/packed-markdown-links.mjs" ], "testSolid": [ diff --git a/packages/charts-core/docs/installation.md b/packages/charts-core/docs/installation.md index 3fcbb600..1f893f03 100644 --- a/packages/charts-core/docs/installation.md +++ b/packages/charts-core/docs/installation.md @@ -17,6 +17,9 @@ Then add one adapter if the application needs it: # React pnpm add @tanstack/react-charts react react-dom +# React Native +pnpm add @tanstack/react-native-charts react react-native react-native-svg + # Preact pnpm add @tanstack/preact-charts preact @@ -46,22 +49,54 @@ The adapters intentionally do not replace the core package. Definitions and mark ## Framework compatibility -| Adapter package | Framework peers | -| -------------------------- | ---------------------------------------- | -| `@tanstack/react-charts` | React and React DOM `^19.0.0` | -| `@tanstack/preact-charts` | Preact `>=10` | -| `@tanstack/vue-charts` | Vue `>=3.5` | -| `@tanstack/solid-charts` | Solid `>=1.8` | -| `@tanstack/svelte-charts` | Svelte `^5.20.0` | -| `@tanstack/angular-charts` | Angular core and platform browser `>=19` | -| `@tanstack/lit-charts` | Lit `>=3.1.3` | -| `@tanstack/alpine-charts` | Alpine `>=3.15` | -| `@tanstack/octane-charts` | Octane `^0.1.13` | +| Adapter package | Framework peers | +| ------------------------------- | ------------------------------------------------------------------------------- | +| `@tanstack/react-charts` | React and React DOM `^19.0.0` | +| `@tanstack/react-native-charts` | React `^19.2.3`, React Native `^0.86.0`, and `react-native-svg` `>=15.15.4 <16` | +| `@tanstack/preact-charts` | Preact `>=10` | +| `@tanstack/vue-charts` | Vue `>=3.5` | +| `@tanstack/solid-charts` | Solid `>=1.8` | +| `@tanstack/svelte-charts` | Svelte `^5.20.0` | +| `@tanstack/angular-charts` | Angular core and platform browser `>=19` | +| `@tanstack/lit-charts` | Lit `>=3.1.3` | +| `@tanstack/alpine-charts` | Alpine `>=3.15` | +| `@tanstack/octane-charts` | Octane `^0.1.13` | These ranges are the package peer contracts. Use the selected framework's normal renderer or application package beside the adapter when the application needs browser mounting or server rendering. +## React Native and Expo + +The React Native adapter is experimental and renders through +`react-native-svg`. Expo 57 applications can install the package and the SVG +version selected by Expo: + +```sh +pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale +pnpm exec expo install react-native-svg +``` + +Bare React Native 0.86 applications install the renderer directly: + +```sh +pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale react-native-svg +``` + +Run `bundle exec pod install` from `ios/` after adding it to a bare iOS +application. Import shared definitions through the universal entry and choose +the native host explicitly: + +```tsx +import { defineChart, lineY } from '@tanstack/charts/universal' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' +``` + +Packed tarballs are typechecked and bundled through default bare React Native +and Expo Metro configurations on iOS and Android. Simulator, physical-device, +gesture, visual, and screen-reader validation is not yet a support claim. + ## Install the D3 modules you import TanStack Charts accepts D3 scale factories, configured scale instances, and diff --git a/packages/charts-core/docs/overview.md b/packages/charts-core/docs/overview.md index 46864bd5..66a81c62 100644 --- a/packages/charts-core/docs/overview.md +++ b/packages/charts-core/docs/overview.md @@ -22,8 +22,9 @@ The library is designed for two equally important authors: - People should get polished, responsive charts from a short declaration. - AI should be able to compose, inspect, and modify charts without learning an application-specific series model or guessing at hidden behavior. -The same definition works with the vanilla DOM host and every framework -adapter. React and Octane also provide optional Canvas entries. +The same definition can feed the vanilla DOM host and framework adapters. +React and Octane also provide optional Canvas entries; the experimental React +Native adapter consumes definitions from the universal entry. ## A chart is a composition @@ -156,18 +157,19 @@ Every automatic behavior has an explicit escape hatch. The [Guides](./guides/res ## Packages -| Package | Use it for | -| -------------------------- | ---------------------------------------------------------------- | -| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM | -| `@tanstack/react-charts` | React `` | -| `@tanstack/preact-charts` | Preact `` | -| `@tanstack/vue-charts` | Vue `` | -| `@tanstack/solid-charts` | Solid `` | -| `@tanstack/svelte-charts` | Svelte `` | -| `@tanstack/angular-charts` | Angular `` | -| `@tanstack/lit-charts` | Lit `` | -| `@tanstack/alpine-charts` | Alpine `x-chart` | -| `@tanstack/octane-charts` | Octane `` | +| Package | Use it for | +| ------------------------------- | ---------------------------------------------------------------- | +| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM | +| `@tanstack/react-charts` | React `` | +| `@tanstack/react-native-charts` | Experimental React Native SVG `` | +| `@tanstack/preact-charts` | Preact `` | +| `@tanstack/vue-charts` | Vue `` | +| `@tanstack/solid-charts` | Solid `` | +| `@tanstack/svelte-charts` | Svelte `` | +| `@tanstack/angular-charts` | Angular `` | +| `@tanstack/lit-charts` | Lit `` | +| `@tanstack/alpine-charts` | Alpine `x-chart` | +| `@tanstack/octane-charts` | Octane `` | All packages are ESM and tree-shakeable. Built-in marks and optional capabilities also have subpath exports when a library or design system needs tighter bundle boundaries. diff --git a/packages/react-native-charts/CHANGELOG.md b/packages/react-native-charts/CHANGELOG.md new file mode 100644 index 00000000..3a498b1c --- /dev/null +++ b/packages/react-native-charts/CHANGELOG.md @@ -0,0 +1 @@ +# @tanstack/react-native-charts diff --git a/packages/react-native-charts/README.md b/packages/react-native-charts/README.md index fbbb30e8..acb6a6ef 100644 --- a/packages/react-native-charts/README.md +++ b/packages/react-native-charts/README.md @@ -1,6 +1,57 @@ -# React Native Charts host spike +# TanStack React Native Charts -Experimental React Native host for the shared `@tanstack/charts` definition, -runtime, and scene graph. It renders with `react-native-svg`. +Experimental React Native SVG host for `@tanstack/charts` definitions and +scene graphs. -This package is a proof of concept, not a supported release. +## Install + +```sh +npm install @tanstack/react-native-charts @tanstack/charts d3-scale +npm install --save-dev @types/d3-scale +``` + +Expo applications also need the SDK-compatible SVG renderer: + +```sh +npx expo install react-native-svg +``` + +Bare React Native applications can install it directly: + +```sh +npm install react-native-svg +``` + +Run `bundle exec pod install` from `ios/` after adding it to a bare iOS +application. + +## Usage + +```tsx +import { scaleLinear } from 'd3-scale' +import { defineChart, lineY } from '@tanstack/charts/universal' +import { Chart } from '@tanstack/react-native-charts' +import { tooltip } from '@tanstack/react-native-charts/tooltip' + +const definition = defineChart({ + marks: [lineY([4, 9, 7])], + x: { scale: scaleLinear().domain([0, 2]) }, + y: { scale: scaleLinear().domain([0, 10]) }, + tooltip: { use: tooltip, sticky: true }, +}) + +export function RevenueChart() { + return ( + + ) +} +``` + +The package is tested with Expo 57 / React Native 0.86 and +`react-native-svg` 15.15.x. It remains experimental: simulator and physical +device visual, gesture, accessibility, and performance validation are still in +progress. diff --git a/packages/react-native-charts/package.json b/packages/react-native-charts/package.json index aa59b78b..0954ed49 100644 --- a/packages/react-native-charts/package.json +++ b/packages/react-native-charts/package.json @@ -1,20 +1,52 @@ { "name": "@tanstack/react-native-charts", - "version": "0.0.0", - "private": true, + "version": "0.3.1", + "private": false, "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/TanStack/charts.git", + "directory": "packages/react-native-charts" + }, "type": "module", "sideEffects": false, + "files": [ + "dist", + "CHANGELOG.md", + "LICENSE", + "README.md" + ], "exports": { ".": "./src/index.ts", "./tooltip": "./src/tooltip-entry.ts" }, + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "react-native": "./dist/index.native.js", + "import": "./dist/index.js" + }, + "./tooltip": { + "types": "./dist/tooltip-entry.d.ts", + "react-native": "./dist/tooltip-entry.native.js", + "import": "./dist/tooltip-entry.js" + } + } + }, "dependencies": { "@tanstack/charts": "workspace:*" }, + "devDependencies": { + "react": "19.2.3", + "react-native": "0.86.2", + "react-native-svg": "15.15.5" + }, "peerDependencies": { "react": "^19.2.3", "react-native": "^0.86.0", - "react-native-svg": "^15.15.5" + "react-native-svg": ">=15.15.4 <16" } } diff --git a/packages/react-native-charts/src/index.native.ts b/packages/react-native-charts/src/index.native.ts new file mode 100644 index 00000000..df7053ef --- /dev/null +++ b/packages/react-native-charts/src/index.native.ts @@ -0,0 +1 @@ +export * from './index' diff --git a/packages/react-native-charts/src/tooltip-entry.native.ts b/packages/react-native-charts/src/tooltip-entry.native.ts new file mode 100644 index 00000000..5a005128 --- /dev/null +++ b/packages/react-native-charts/src/tooltip-entry.native.ts @@ -0,0 +1 @@ +export * from './tooltip-entry' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c94dec9..607e1af4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,7 +132,7 @@ importers: version: 1.0.5 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) + version: 6.0.4(babel-plugin-react-compiler@1.0.0)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) chart.js: specifier: 4.5.1 version: 4.5.1 @@ -260,6 +260,40 @@ importers: specifier: 4.103.0 version: 4.103.0 + examples/charts-expo: + dependencies: + '@tanstack/charts': + specifier: workspace:* + version: link:../../packages/charts-core + '@tanstack/react-native-charts': + specifier: workspace:* + version: link:../../packages/react-native-charts + d3-scale: + specifier: 4.0.2 + version: 4.0.2 + expo: + specifier: ~57.0.9 + version: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react: + specifier: 19.2.3 + version: 19.2.3 + react-native: + specifier: 0.86.2 + version: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-native-svg: + specifier: 15.15.4 + version: 15.15.4(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + devDependencies: + '@types/d3-scale': + specifier: ^4.0.9 + version: 4.0.9 + '@types/react': + specifier: ~19.2.2 + version: 19.2.17 + typescript: + specifier: ~6.0.3 + version: 6.0.3 + examples/charts-octane: dependencies: '@charts-poc/demo-data': @@ -335,7 +369,7 @@ importers: version: 3.1.8 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) + version: 6.0.4(babel-plugin-react-compiler@1.0.0)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) @@ -355,11 +389,11 @@ importers: specifier: 19.2.3 version: 19.2.3 react-native: - specifier: 0.86.0 - version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + specifier: 0.86.2 + version: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) react-native-svg: specifier: 15.15.5 - version: 15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + version: 15.15.5(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) devDependencies: '@babel/core': specifier: ^7.25.2 @@ -370,15 +404,30 @@ importers: '@react-native-community/cli': specifier: 20.1.0 version: 20.1.0(supports-color@10.2.2)(typescript@6.0.3) + '@react-native-community/cli-platform-android': + specifier: 20.1.0 + version: 20.1.0 + '@react-native-community/cli-platform-ios': + specifier: 20.1.0 + version: 20.1.0 '@react-native/babel-preset': - specifier: 0.86.0 - version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + specifier: 0.86.2 + version: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@react-native/metro-config': - specifier: 0.86.0 - version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + specifier: 0.86.2 + version: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@react-native/typescript-config': - specifier: 0.86.0 - version: 0.86.0 + specifier: 0.86.2 + version: 0.86.2 + '@types/d3-scale': + specifier: ^4.0.9 + version: 4.0.9 + '@types/react': + specifier: ~19.2.2 + version: 19.2.17 + typescript: + specifier: ~6.0.3 + version: 6.0.3 examples/conformance: dependencies: @@ -459,7 +508,7 @@ importers: devDependencies: '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) + version: 6.0.4(babel-plugin-react-compiler@1.0.0)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) @@ -502,7 +551,7 @@ importers: version: 3.1.8 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) + version: 6.0.4(babel-plugin-react-compiler@1.0.0)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0)) vite: specifier: ^8.0.16 version: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) @@ -757,15 +806,16 @@ importers: '@tanstack/charts': specifier: workspace:* version: link:../charts-core + devDependencies: react: - specifier: ^19.2.3 + specifier: 19.2.3 version: 19.2.3 react-native: - specifier: ^0.86.0 - version: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + specifier: 0.86.2 + version: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) react-native-svg: - specifier: ^15.15.5 - version: 15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + specifier: 15.15.5 + version: 15.15.5(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) packages/solid-charts: dependencies: @@ -1108,6 +1158,15 @@ packages: engines: { node: '>=6.0.0' } hasBin: true + '@babel/plugin-proposal-decorators@7.29.7': + resolution: + { + integrity: sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-proposal-export-default-from@7.29.7': resolution: { @@ -1117,6 +1176,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-decorators@7.29.7': + resolution: + { + integrity: sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-dynamic-import@7.8.3': resolution: { @@ -1213,6 +1281,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-static-block@7.29.7': + resolution: + { + integrity: sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.12.0 + '@babel/plugin-transform-classes@7.29.7': resolution: { @@ -1231,6 +1308,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-export-namespace-from@7.29.7': + resolution: + { + integrity: sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-flow-strip-types@7.29.7': resolution: { @@ -1249,6 +1335,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-logical-assignment-operators@7.29.7': + resolution: + { + integrity: sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.29.7': resolution: { @@ -1276,6 +1371,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-rest-spread@7.29.7': + resolution: + { + integrity: sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-catch-binding@7.29.7': resolution: { @@ -1294,6 +1398,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-parameters@7.29.7': + resolution: + { + integrity: sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-methods@7.29.7': resolution: { @@ -1321,6 +1434,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-development@7.29.7': + resolution: + { + integrity: sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.29.7': resolution: { @@ -1348,6 +1470,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-pure-annotations@7.29.7': + resolution: + { + integrity: sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-regenerator@7.29.7': resolution: { @@ -1384,6 +1515,15 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/preset-typescript@7.29.7': + resolution: + { + integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.29.7': resolution: { @@ -2181,226 +2321,475 @@ packages: '@noble/hashes': optional: true - '@hapi/hoek@9.3.0': + '@expo/cli@57.0.11': resolution: { - integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==, + integrity: sha512-ENXCwRyL8Q9qbabUmm0L6w9kXTmdGotW7eDEEWmUDXLPux+nEzNDqw0MzWQ5K3ZsXS51QmUJZg5yETB+6SnNRg==, } + hasBin: true + peerDependencies: + expo: '*' + expo-router: '*' + react-native: '*' + peerDependenciesMeta: + expo-router: + optional: true + react-native: + optional: true - '@hapi/topo@5.1.0': + '@expo/code-signing-certificates@0.0.6': resolution: { - integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==, + integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==, } - '@img/colour@1.1.0': + '@expo/config-plugins@57.0.6': resolution: { - integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==, + integrity: sha512-7CmKrS5Rnu8aSZyNlxH2qzA7Ls1HEa4EQvEVOAkHDKPr1e4Cg/nz7I7dUl09QDTVjMvkKYDH4Th0DuAsgqASaw==, } - engines: { node: '>=18' } - '@img/sharp-darwin-arm64@0.34.5': + '@expo/config-types@57.0.2': resolution: { - integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, + integrity: sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [arm64] - os: [darwin] - '@img/sharp-darwin-x64@0.34.5': + '@expo/config@57.0.6': resolution: { - integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, + integrity: sha512-VpMJpB/De/fb9bBFVVBiK6Ntg9lt0kAleLH9hcZz85CYRUQ3jVFVA8rNC5f8y4cp2+FiiPNFp62+kEOFI6pDiw==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [x64] - os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@expo/devcert@1.2.1': resolution: { - integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, + integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==, } - cpu: [arm64] - os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': + '@expo/devtools@57.0.1': resolution: { - integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, + integrity: sha512-GyUf+wFNkbttaX0jR7MZa9bm77U0IrLg6d2AjpxdyoXw/w4abHoXG0oFufwLMgP9zLTd5+Ct4X/ffNUTnlzZgg==, } - cpu: [x64] - os: [darwin] + peerDependencies: + react: '*' + react-native: '*' + peerDependenciesMeta: + react: + optional: true + react-native: + optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@expo/dom-webview@57.0.1': resolution: { - integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, + integrity: sha512-lAKsME4SAq+8sf56oN0DX5TBYyruupoRxbWbD2xf9RnKY8y6x8eb9LCE5pxSN0qyWdqnp+0wmyWzDkKboThKAw==, } - cpu: [arm64] - os: [linux] - libc: [glibc] + peerDependencies: + expo: '*' + react: '*' + react-native: '*' - '@img/sharp-libvips-linux-arm@1.2.4': + '@expo/env@2.4.2': resolution: { - integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, + integrity: sha512-28pqaEqwnmLduZ00Pq9HkSzE5wbj1MTwp5/n8nm8rD8MCjR9eUnVOwmNksPI3Be2ReAPO/DbPn1puy0mvoocsQ==, } - cpu: [arm] - os: [linux] - libc: [glibc] + engines: { node: '>=20.12.0' } - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@expo/expo-modules-macros-plugin@0.6.1': resolution: { - integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, + integrity: sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==, } - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@expo/fingerprint@0.20.6': resolution: { - integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, + integrity: sha512-cmC/6BOPRbdKr77Mgjwszb8aM0hY2RKBpMRCmjSdn9zIcn2FGor/ic4fHVr46cQFa1G6RDGg1GyAjRw3US4CCQ==, } - cpu: [riscv64] - os: [linux] - libc: [glibc] + hasBin: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@expo/image-utils@0.11.4': resolution: { - integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, + integrity: sha512-pn/4770DIEOcYZr484uazuwg20FX/qaDkeMRF6J+oxejynDmEmO8wLsCudaNShFE0BhyKGQTYrs2rsRhqrqESw==, } - cpu: [s390x] - os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': + '@expo/inline-modules@0.1.4': resolution: { - integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, + integrity: sha512-8bPSCm//dv8raYfrQ4x79rCX52vMw0QzmnYYl4eSOAvEbGvDPPRGGdbrhZZ7oihU+hI1sZNS5kYEgqODgFwfsw==, } - cpu: [x64] - os: [linux] - libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@expo/json-file@11.0.1': resolution: { - integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, + integrity: sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==, } - cpu: [arm64] - os: [linux] - libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@expo/local-build-cache-provider@57.0.5': resolution: { - integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, + integrity: sha512-OwiNC0Uxu67TOH7TEQ94GLa4oNzNfbbItKGdy3QMfX+hCSZv2VvjcjRo5vttMHfXCnXa9KZIu3GBS9pvtDHWhA==, } - cpu: [x64] - os: [linux] - libc: [musl] - '@img/sharp-linux-arm64@0.34.5': + '@expo/log-box@57.0.2': resolution: { - integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, + integrity: sha512-ZsFyfIR7YCbQAdVLzuTUmMHofZC7ZS9ywYCJNPlLc78x59cI8GwXFEIVbRjjC0uJERpNtXx/tsNNnkhexXlzMw==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [arm64] - os: [linux] - libc: [glibc] + peerDependencies: + '@expo/dom-webview': ^57.0.1 + expo: '*' + react: '*' + react-native: '*' - '@img/sharp-linux-arm@0.34.5': + '@expo/metro-config@57.0.7': resolution: { - integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, + integrity: sha512-bVfEkg4zF1cA62OqAdYXmFOooJ6TB/I+REi7Se6Ct+PbSC+89TwSqWXnYx34L08eIs4z+1ilgbATakTZpgefmQ==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [arm] - os: [linux] - libc: [glibc] + peerDependencies: + expo: '*' + peerDependenciesMeta: + expo: + optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@expo/metro-file-map@57.0.1': resolution: { - integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, + integrity: sha512-8JXfVstZN7QnP4NianZZnlTVboOWR0sG8trUDNajOjnbGlPln29vponXM84tY+3tAHapz5/TxE53L0ixUwqPtA==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': + '@expo/metro@56.0.0': resolution: { - integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, + integrity: sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [riscv64] - os: [linux] - libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': + '@expo/osascript@2.7.1': resolution: { - integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, + integrity: sha512-Zn03EX6In7ts2lPUW2ESUSkEhEWQN1qqsiXjadtZMJOuZRkMiAg1ZQHuvz9DjByDWNJ2pBwAGyrts9lj9k389g==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [s390x] - os: [linux] - libc: [glibc] + engines: { node: '>=12' } - '@img/sharp-linux-x64@0.34.5': + '@expo/package-manager@1.13.1': resolution: { - integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, + integrity: sha512-y/K+CaYYpZpNGZhSX4HyLT/vyIunFjNfyoxNysPBCefeLKI/VCx6f9LNPzrxayr3rCYO5bl9O8H+HRQK265Nkg==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [x64] - os: [linux] - libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': + '@expo/plist@0.8.1': resolution: { - integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, + integrity: sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [arm64] - os: [linux] - libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': + '@expo/prebuild-config@57.0.10': resolution: { - integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, + integrity: sha512-myrS5NolFAQWD8g7QuqkettnkyJx3GRl603N6rlmqAMxmO5EU7sZu4EX2EsIKkva8QtpX84B0E17PsM9xXMsTQ==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [x64] - os: [linux] - libc: [musl] - '@img/sharp-wasm32@0.34.5': + '@expo/require-utils@57.0.4': resolution: { - integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, + integrity: sha512-e7xbg/9BTQcsZE/oErafZXtI7kh5IgfasLJ97J5sFSzX2cA74pDvdlhW1KHVSaDkQyQv6h1LSLhsY7dEeOk7hw==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [wasm32] + peerDependencies: + typescript: ^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@img/sharp-win32-arm64@0.34.5': + '@expo/router-server@57.0.4': resolution: { - integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, + integrity: sha512-ucqCP0hK8nZb9+S8QJYdQxNCkfRClzkKdg2RpWYDKDYgRIHyoRyxEDRgDgvbhH+q78yfY83abU8OTx8MMOrf1g==, } - engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } - cpu: [arm64] + peerDependencies: + '@expo/metro-runtime': ^57.0.7 + expo: '*' + expo-constants: ^57.0.7 + expo-font: ^57.0.1 + expo-router: '*' + expo-server: ^57.0.1 + react: '*' + react-dom: '*' + react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 + peerDependenciesMeta: + '@expo/metro-runtime': + optional: true + expo-router: + optional: true + react-dom: + optional: true + react-server-dom-webpack: + optional: true + + '@expo/schema-utils@57.0.2': + resolution: + { + integrity: sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw==, + } + + '@expo/sdk-runtime-versions@1.0.0': + resolution: + { + integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==, + } + + '@expo/spawn-async@1.8.0': + resolution: + { + integrity: sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==, + } + engines: { node: '>=12' } + + '@expo/sudo-prompt@9.3.2': + resolution: + { + integrity: sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==, + } + + '@expo/ws-tunnel@2.0.0': + resolution: + { + integrity: sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw==, + } + peerDependencies: + ws: ^8.0.0 + + '@expo/xcpretty@4.4.4': + resolution: + { + integrity: sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==, + } + hasBin: true + + '@hapi/hoek@9.3.0': + resolution: + { + integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==, + } + + '@hapi/topo@5.1.0': + resolution: + { + integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==, + } + + '@img/colour@1.1.0': + resolution: + { + integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==, + } + engines: { node: '>=18' } + + '@img/sharp-darwin-arm64@0.34.5': + resolution: + { + integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: + { + integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: + { + integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, + } + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: + { + integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, + } + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: + { + integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: + { + integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: + { + integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: + { + integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: + { + integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: + { + integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: + { + integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: + { + integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: + { + integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: + { + integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: + { + integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: + { + integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: + { + integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: + { + integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: + { + integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: + { + integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: + { + integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: + { + integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] os: [win32] '@img/sharp-win32-ia32@0.34.5': @@ -3060,126 +3449,126 @@ packages: engines: { node: '>=20.19.4' } hasBin: true - '@react-native/assets-registry@0.86.0': + '@react-native/assets-registry@0.86.2': resolution: { - integrity: sha512-nIaXbm2jX1OTYp0qbviJ3O6KZivoE8z3BnhUQ2LsqfZSWRoOK/n1qsiAr6oALiNKWnXY3j2KPwtYORnZzp8xew==, + integrity: sha512-vcX/mBjWAVnWofu7KecotquI2unZ/tITwA7OGdq/mdY/zmGXIEvYhfEYyOQij/LRqi9WAL+iizInTBWnxDhK/Q==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/babel-plugin-codegen@0.86.0': + '@react-native/babel-plugin-codegen@0.86.2': resolution: { - integrity: sha512-qdsABWNW7uTll90l4Vh03gjeyu3WVDi2CyiiyvYGMRDcoYbjbQi6df3BMAm9lQI2yslZ1T14LlDDAsgTwNxplA==, + integrity: sha512-NNDZqOlNbH5SzgPks1jFDYH3234Rpa5e/nhZymxhIiBH3NcE3uD+rGj/HWXhH7nHF2ToGK6XbUpqy7nmJPeh+g==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/babel-preset@0.86.0': + '@react-native/babel-preset@0.86.2': resolution: { - integrity: sha512-bYQcWiPySNvF4dns9Ls9gMmwgq66ohvM9Fwc/Kn8r85t66UNHxch3p1QwPiSorDelFauZwJbgo9+ReibTgvpbA==, + integrity: sha512-4XKEJ6jKW9lXMB1O5o47gBoGgolde1fbX13gLW/erlcn+1ky+MHHo5UjuM3RWGdPJHIvIzekDDumSUHhB9x5iQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } peerDependencies: '@babel/core': '*' - '@react-native/codegen@0.86.0': + '@react-native/codegen@0.86.2': resolution: { - integrity: sha512-uTs9DBo3+/lUqinsGZK0FKJRBVClrwMXoZToaDxE1Q2SL2e55vs2GwyZfIKzPl5uJnbu4PfFMIp0/mLXLWUMuA==, + integrity: sha512-xKkudsahUJ1n//55g4fXk5BStVqqmZlz8HQveL45ZxcfDnwvhuYe2GymksQANFsSN+slvrarjrfq8kIxJzbceA==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } peerDependencies: '@babel/core': '*' - '@react-native/community-cli-plugin@0.86.0': + '@react-native/community-cli-plugin@0.86.2': resolution: { - integrity: sha512-Jv8p1ebEPfTzs8gmrjsdT2XMXFfeAg45Pman+XPLFGaSeGAZkutRFRyX9Cs9aGTSOyIA9YPJ6vDNb1ayTf1FKQ==, + integrity: sha512-YHXNKoM6Y/HjREySZ5arET2xgiHgg67r1MdwJB//MPJAJ0Xc5g0u6UHxY9VzsHO3Y07dre6s0BinYwjt1SEWvQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } peerDependencies: '@react-native-community/cli': '*' - '@react-native/metro-config': 0.86.0 + '@react-native/metro-config': 0.86.2 peerDependenciesMeta: '@react-native-community/cli': optional: true '@react-native/metro-config': optional: true - '@react-native/debugger-frontend@0.86.0': + '@react-native/debugger-frontend@0.86.2': resolution: { - integrity: sha512-7Mb3nDfyJeys+ELF75Ageu7VKERlnIMoO+aNPoXqTXvz+b41L6l2CqMyLpDHxkBSlenij6gEepPNgaIyWHbJZw==, + integrity: sha512-KGS1aV5F6cIqpnoIUhLBXyVzy1oAj8jBFGau6vX4Vy0HXRJN7p+68RU7x6NuyraHvQcR14ccMGT5TkFuNjQ4gA==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/debugger-shell@0.86.0': + '@react-native/debugger-shell@0.86.2': resolution: { - integrity: sha512-Y0zEkZzLz8ou6o/VLml1A31X/rMgc6DRjwxwzPMa94qRTMY070WeBCNTITQo4kKTBAUgbxh07oXPQqp0Tpja8w==, + integrity: sha512-/TaVJ2+gGajZPJGrFaObUQmHmlaxAlfmOPZicl6pNKDUjzSgFMpcLkdTOExvb+USYTVdGX1XwxXyvjQdUO2bvg==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/dev-middleware@0.86.0': + '@react-native/dev-middleware@0.86.2': resolution: { - integrity: sha512-20pTO6yTybmvXvro520H6C7jydIQnLKOl5qFtVEcHSdFrY63r3OGei+Rx9bILgSRmH6jgnfEcijcMx7pwWuQtw==, + integrity: sha512-B7L0vKvg+IcEElT7Vpqh1xj5yJAqWUegjbP+bQRaorJMAYnv11GkliTnZV2AdTDfZQJWgOEx8i8LGkHkUg7bnA==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/gradle-plugin@0.86.0': + '@react-native/gradle-plugin@0.86.2': resolution: { - integrity: sha512-a1RcfaEDqWExCGfCwadIxt4l8FvKYgFqeMf2uzeKyAOnb+vTGNIeCvifFL2MqvgaeYxlER437HbMIajGcuJ1pQ==, + integrity: sha512-2F6x14NcHMpVmfTTFKfMkpV5dZedZrLiv6PE+c3vgnesV2bjleUBydr4U+NI8VkI7OwW71L0A5qQ76I9LCrfoQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/js-polyfills@0.86.0': + '@react-native/js-polyfills@0.86.2': resolution: { - integrity: sha512-zYy/Cjd1VTnZ2iCNaG9bDF9C3l2ntESiPRscjIlI5FKugu6aeTwsDSv1aI8Bc4Kp3vEdoVg+UQhLAhE4svREaQ==, + integrity: sha512-bIwNcGBaQ74shB5z1mRkxOpjikimuwsnOCEkZSzL67Z1FTyK1ObpENfyd2QvcvVW9Cjl+tHuw9ynpBnb2jPoJQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/metro-babel-transformer@0.86.0': + '@react-native/metro-babel-transformer@0.86.2': resolution: { - integrity: sha512-SjKej3E5qIahqo/G+rSOrmJUQM44RyKtWtO+VfmKAAMoJWkBFomM22hTLKCIS5cdbIAJ9COAmU+KAi2wVSO0wQ==, + integrity: sha512-mX1wgLErdb2hDgXJr9zM9SWLe+ZteZTFTwRWGOQ53yEJwc9DVSnxdTlAtVdMeOj2ntycKh0R8jYdat2Am43cwQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } peerDependencies: '@babel/core': '*' - '@react-native/metro-config@0.86.0': + '@react-native/metro-config@0.86.2': resolution: { - integrity: sha512-7v+xbTeEci9ZcQ/Z1OqI4RXcqN69wSMDYL5BAMvOReZ7U04+aDQ0/SQhClYPn6x2/RxM4WzMKSAuNyLKqvYVtw==, + integrity: sha512-hJno256j+MS0b3JD1aD3ouTGZVacKNVBuXL2atMQQ8BZ060vl1ptnZ83y569aDW+/rgFSOcqn6ydKeSz4uUKQQ==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } - '@react-native/normalize-colors@0.86.0': + '@react-native/normalize-colors@0.86.2': resolution: { - integrity: sha512-kG0wfCGghUKlfxkJyyHCDVutWVYWK7/DG58ojA/4v9EfulgF+osuSQmlbNb3rcKX58qutm7JcldSeVLgGFha9g==, + integrity: sha512-EzPFc9Y6lzYOWeso2almwXI7f8+qReHxWvT+algsOczb2UhWXIWXDoSvkdwoSfiwwmGt/ijJgKJoeHlzPkLwRg==, } - '@react-native/typescript-config@0.86.0': + '@react-native/typescript-config@0.86.2': resolution: { - integrity: sha512-oSuFIEMVAVEXdIvDnrdXsWmIF4fYdgtvAEr2ofn8OY534m7XWm9QAqHHpGUzoK0iwDPlPZ5n2Rb25gqF1SZ0rg==, + integrity: sha512-DcIsPc652AD10sSKWZPv2QjsEB63DEXW20XYwDzk3zdl94XbTlTSn1+VZbtx7MzHk0kkSQcaX30yTdVkNUAz8Q==, } - '@react-native/virtualized-lists@0.86.0': + '@react-native/virtualized-lists@0.86.2': resolution: { - integrity: sha512-4/ZLXdf/OSpPDVO0AsQ1SJdRIzt5t9BNQ46QwGgxvX7/cirYR5k8KXctNGGgW8lQo2gZChEfY2zFCZg9nM/jiw==, + integrity: sha512-uO0J72gh3EvE+1/GHRk18QRyBDTRHRB0AraAfojsRjbT7VMuJwKrZYaKGshavoaEud6aw00ZB9/8mTMIKjjcAw==, } engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } peerDependencies: '@types/react': ^19.2.0 react: '*' - react-native: 0.86.0 + react-native: 0.86.2 peerDependenciesMeta: '@types/react': optional: true @@ -3981,6 +4370,12 @@ packages: integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==, } + '@ungap/structured-clone@1.3.3': + resolution: + { + integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==, + } + '@vitejs/plugin-react@6.0.4': resolution: { @@ -4119,6 +4514,20 @@ packages: integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==, } + '@xmldom/xmldom@0.8.13': + resolution: + { + integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==, + } + engines: { node: '>=10.0.0' } + + '@xmldom/xmldom@0.9.10': + resolution: + { + integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==, + } + engines: { node: '>=14.6' } + '@yarnpkg/lockfile@1.1.0': resolution: { @@ -4168,6 +4577,14 @@ packages: } engines: { node: '>= 14' } + agent-cli-detector@0.1.4: + resolution: + { + integrity: sha512-qPgevFvpaQoBaRJVKzr8R7h1WPvV3DtbgRIQlne4le66KBzXx5hNBwo/+NTw67LgkKBlhCzksrdautpUdlls0Q==, + } + engines: { node: '>=18.18' } + hasBin: true + ajv@8.20.0: resolution: { @@ -4193,6 +4610,13 @@ packages: } engines: { node: '>=6' } + ansi-escapes@4.3.2: + resolution: + { + integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, + } + engines: { node: '>=8' } + ansi-fragments@0.2.1: resolution: { @@ -4254,6 +4678,12 @@ packages: integrity: sha512-8zl1xlxeS4a0/36CT6LOaVioPOL8TeLT1b9OHk0j9xSbzmPBuM7lUgWMSTh6SbuF8fbwjcP1rr30OCLpd1fl+A==, } + arg@5.0.2: + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } + argparse@1.0.10: resolution: { @@ -4357,6 +4787,18 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-react-compiler@1.0.0: + resolution: + { + integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==, + } + + babel-plugin-react-native-web@0.21.2: + resolution: + { + integrity: sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==, + } + babel-plugin-syntax-hermes-parser@0.36.0: resolution: { @@ -4369,6 +4811,24 @@ packages: integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==, } + babel-preset-expo@57.0.5: + resolution: + { + integrity: sha512-sz9ZBTiUAlu5P9VORVNKoeAaY2qKFQRC6eQV5Y8aMkqcorvXKEv97UeCkFMLmMBEPKA+QeWImREKkX9/H21WQA==, + } + peerDependencies: + '@babel/runtime': ^7.20.0 + expo: '*' + expo-widgets: ^57.0.7 + react-refresh: '>=0.14.0 <1.0.0' + peerDependenciesMeta: + '@babel/runtime': + optional: true + expo: + optional: true + expo-widgets: + optional: true + babel-preset-solid@1.9.12: resolution: { @@ -4415,6 +4875,13 @@ packages: integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==, } + big-integer@1.6.52: + resolution: + { + integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==, + } + engines: { node: '>=0.6' } + binary-search-bounds@2.0.5: resolution: { @@ -4446,6 +4913,26 @@ packages: integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, } + bplist-creator@0.1.0: + resolution: + { + integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==, + } + + bplist-parser@0.3.1: + resolution: + { + integrity: sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==, + } + engines: { node: '>= 5.10.0' } + + bplist-parser@0.3.2: + resolution: + { + integrity: sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==, + } + engines: { node: '>= 5.10.0' } + brace-expansion@5.0.6: resolution: { @@ -4548,6 +5035,13 @@ packages: } engines: { node: '>=18' } + chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: '>=4' } + chalk@4.1.2: resolution: { @@ -4616,6 +5110,13 @@ packages: } engines: { node: '>=8' } + cli-cursor@2.1.0: + resolution: + { + integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==, + } + engines: { node: '>=4' } + cli-cursor@3.1.0: resolution: { @@ -5283,6 +5784,12 @@ packages: } engines: { node: '>=8' } + dnssd-advertise@1.1.6: + resolution: + { + integrity: sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==, + } + dom-serializer@2.0.0: resolution: { @@ -5637,6 +6144,114 @@ packages: } engines: { node: '>=12.0.0' } + expo-asset@57.0.8: + resolution: + { + integrity: sha512-sGocG+Wd2WcZ1KjKyB2LfUZXzrBM0VHEATGcpJKF9T3HM56M/sMbH73vv+n85u5Zr0FkJjEbV1DWhGPimCR1QQ==, + } + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + + expo-constants@57.0.8: + resolution: + { + integrity: sha512-ts+B7E5076BtkblrKGy7+Sm/R2obHfTwqhmYQVYbWRtilv3+C/xNwHZhyNEnAvzM/JjKqx7UdaITUBYaeFreZw==, + } + peerDependencies: + expo: '*' + react-native: '*' + + expo-file-system@57.0.1: + resolution: + { + integrity: sha512-w7/ERvQFrGP2apTO9lDtZ+O6JQIhfakL7+Xqzh+rfMO9B4LB4qwrz+YvLgir8KFRVX64JHBnRuYBVLY1oQZcqw==, + } + peerDependencies: + expo: '*' + react-native: '*' + + expo-font@57.0.1: + resolution: + { + integrity: sha512-QyS9L1Kh9sKJg4gfU6rdbpxpmH+DyzBX8z6jVvXMUDoqLr1GqmkO/Wu379KCXjL///kWbhpNlbi7AgBuj4VdIQ==, + } + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + + expo-keep-awake@57.0.1: + resolution: + { + integrity: sha512-28lkFImeXTS+bhAjuCFV7w7tW5bXg27BJVrxv+nC/nyYa86qEa0oFeHwqol6ha5k4pdVDQgBF09GM4A1k76Ssg==, + } + peerDependencies: + expo: '*' + react: '*' + + expo-modules-autolinking@57.0.9: + resolution: + { + integrity: sha512-lj2nsAKMMRLXSFnGgaaQrWJ2fdSpLPc/bca6Rkiw4g8zYPn7qX4MRUJgavvzm/hBrzvMnlhXVgJtidOGuwBh+w==, + } + hasBin: true + + expo-modules-core@57.0.8: + resolution: + { + integrity: sha512-ZUU943Oso3B8jFggC+2+LOk8oa+im66IQlleYay6WP5iexbdF2fqpgC4BcYsN4xhCkDKh7KDINSt1FlcxyRRjQ==, + } + peerDependencies: + react: '*' + react-native: '*' + react-native-worklets: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0 + peerDependenciesMeta: + react-native-worklets: + optional: true + + expo-modules-jsi@57.0.4: + resolution: + { + integrity: sha512-vt7FyqUqqFXiRVnBqYD7y+GSPTgeua5Ocoy0+SYt+RSHkZEA2Fyop7If3g1TYDzQObYybPRo7TG2Rle1XLaWFw==, + } + peerDependencies: + react-native: '*' + + expo-server@57.0.1: + resolution: + { + integrity: sha512-sBfVDH6dmKVHZxqUxbfkzS00PZELMZt1IpnHKxcOTMZtR/t7CtRAFrbXcisG+EyzeqHSVDacZT+1tbYfZt5D8w==, + } + engines: { node: '>=20.16.0' } + + expo@57.0.9: + resolution: + { + integrity: sha512-NDEvnU+vjRdMbtOyDC25OSok9/E97al97pyx+bMphQgNRGAED0D7oF8ha7oGYsLE+7jFzpPADVM9S60dGbpHIA==, + } + hasBin: true + peerDependencies: + '@expo/dom-webview': '*' + '@expo/metro-runtime': '*' + react: '*' + react-dom: '*' + react-native: '*' + react-native-web: '*' + react-native-webview: '*' + peerDependenciesMeta: + '@expo/dom-webview': + optional: true + '@expo/metro-runtime': + optional: true + react-dom: + optional: true + react-native-web: + optional: true + react-native-webview: + optional: true + exponential-backoff@3.1.3: resolution: { @@ -5707,6 +6322,12 @@ packages: picomatch: optional: true + fetch-nodeshim@0.4.10: + resolution: + { + integrity: sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==, + } + figures@3.2.0: resolution: { @@ -5781,6 +6402,12 @@ packages: debug: optional: true + fontfaceobserver@2.3.0: + resolution: + { + integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==, + } + form-data@4.0.5: resolution: { @@ -5886,6 +6513,13 @@ packages: } engines: { node: '>=10' } + getenv@2.0.0: + resolution: + { + integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==, + } + engines: { node: '>=6' } + glob-parent@5.1.2: resolution: { @@ -5893,6 +6527,13 @@ packages: } engines: { node: '>= 6' } + glob@13.0.6: + resolution: + { + integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==, + } + engines: { node: 18 || 20 || >=22 } + globby@11.1.0: resolution: { @@ -5913,6 +6554,13 @@ packages: integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, } + has-flag@3.0.0: + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: '>=4' } + has-flag@4.0.0: resolution: { @@ -5948,10 +6596,10 @@ packages: } engines: { node: '>= 0.4' } - hermes-compiler@250829098.0.14: + hermes-compiler@250829098.0.16: resolution: { - integrity: sha512-5meXwsZxgiqFaJjNzwjzI9IyUkuGGBisu+z9BvQWmGVpjH6nz11hgqkyxe4dl8UAdyIV4lTbz91+Dlnjz0VxqA==, + integrity: sha512-xsgzk+mUyvt9t1nUbF8USBlYxajTUtPJhVZ86q85s/SEoMKCF+52YZcudb0ENSnV3T3lV9mgB3s6R7+pH90zgw==, } hermes-estree@0.35.0: @@ -5978,6 +6626,13 @@ packages: integrity: sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==, } + hosted-git-info@7.0.2: + resolution: + { + integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==, + } + engines: { node: ^16.14.0 || >=18.0.0 } + html-encoding-sniffer@6.0.0: resolution: { @@ -6302,6 +6957,12 @@ packages: } engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + jimp-compact@0.16.1: + resolution: + { + integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==, + } + joi@17.13.4: resolution: { @@ -6406,6 +7067,13 @@ packages: } engines: { node: '>=6' } + lan-network@0.2.1: + resolution: + { + integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==, + } + hasBin: true + launch-editor@2.14.1: resolution: { @@ -6618,6 +7286,13 @@ packages: integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==, } + log-symbols@2.2.0: + resolution: + { + integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==, + } + engines: { node: '>=4' } + log-symbols@4.1.0: resolution: { @@ -6646,6 +7321,12 @@ packages: } hasBin: true + lru-cache@10.4.3: + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } + lru-cache@11.5.2: resolution: { @@ -6887,6 +7568,13 @@ packages: engines: { node: '>=4.0.0' } hasBin: true + mimic-fn@1.2.0: + resolution: + { + integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==, + } + engines: { node: '>=4' } + mimic-fn@2.1.0: resolution: { @@ -6922,6 +7610,13 @@ packages: integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, } + minipass@7.1.3: + resolution: + { + integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==, + } + engines: { node: '>=16 || 14 >=14.17' } + mkdirp@1.0.4: resolution: { @@ -6949,6 +7644,12 @@ packages: integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, } + multitars@1.0.0: + resolution: + { + integrity: sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg==, + } + nanoid@3.3.16: resolution: { @@ -7035,6 +7736,13 @@ packages: encoding: optional: true + node-forge@1.4.0: + resolution: + { + integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==, + } + engines: { node: '>= 6.13.0' } + node-int64@0.4.0: resolution: { @@ -7055,6 +7763,13 @@ packages: } engines: { node: '>=0.12.0' } + npm-package-arg@11.0.3: + resolution: + { + integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==, + } + engines: { node: ^16.14.0 || >=18.0.0 } + npm-run-path@4.0.1: resolution: { @@ -7155,6 +7870,13 @@ packages: integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, } + onetime@2.0.1: + resolution: + { + integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==, + } + engines: { node: '>=4' } + onetime@5.1.2: resolution: { @@ -7190,6 +7912,13 @@ packages: } engines: { node: '>=12' } + ora@3.4.0: + resolution: + { + integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==, + } + engines: { node: '>=6' } + ora@5.3.0: resolution: { @@ -7293,6 +8022,13 @@ packages: } engines: { node: '>= 0.10' } + parse-png@2.1.0: + resolution: + { + integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==, + } + engines: { node: '>=10' } + parse5@7.3.0: resolution: { @@ -7332,6 +8068,13 @@ packages: integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, } + path-scurry@2.0.2: + resolution: + { + integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==, + } + engines: { node: 18 || 20 || >=22 } + path-to-regexp@6.3.0: resolution: { @@ -7408,6 +8151,20 @@ packages: engines: { node: '>=20' } hasBin: true + plist@3.1.1: + resolution: + { + integrity: sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==, + } + engines: { node: '>=10.4.0' } + + pngjs@3.4.0: + resolution: + { + integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==, + } + engines: { node: '>=4.0.0' } + postcss@8.5.23: resolution: { @@ -7463,6 +8220,20 @@ packages: 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 } + + progress@2.0.3: + resolution: + { + integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==, + } + engines: { node: '>=0.4.0' } + promise@8.3.0: resolution: { @@ -7561,24 +8332,33 @@ packages: integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==, } - react-native-svg@15.15.5: + react-native-svg@15.15.4: resolution: { - integrity: sha512-L4go5jA+GWutdJ/JucuN20cjAbMg1HmMtAP+wZ+3JLCf6Jd0bhXQHxciRP/AQm/FlrIEZwkMcHNZP+FXAiic0w==, + integrity: sha512-boT/vIRgj6zZKBpfTPJJiYWMbZE9duBMOwPK6kCSTgxsS947IFMOq9OgIFkpWZTB7t229H24pDRkh3W9ZK/J1A==, } peerDependencies: react: '*' react-native: '*' - react-native@0.86.0: + react-native-svg@15.15.5: resolution: { - integrity: sha512-17ALh/dd6AO4pgOVmOO5Axll5PbErEo3XFyLokyzW6usyi+OShIEPwUW26wLPlhVifgSOIfECCH0WN+0IqtJ1w==, + integrity: sha512-L4go5jA+GWutdJ/JucuN20cjAbMg1HmMtAP+wZ+3JLCf6Jd0bhXQHxciRP/AQm/FlrIEZwkMcHNZP+FXAiic0w==, } - engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } + peerDependencies: + react: '*' + react-native: '*' + + react-native@0.86.2: + resolution: + { + integrity: sha512-zbJXGZpwfZGA79Z9ob6Atvfx4nAQL8yJBa35s58E4Oo+khPykfQP2sTeumkKbjwajFYfVayg8pj7Il9nIfTk7A==, + } + engines: { node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 } hasBin: true peerDependencies: - '@react-native/jest-preset': 0.86.0 + '@react-native/jest-preset': 0.86.2 '@types/react': ^19.1.1 react: ^19.2.3 peerDependenciesMeta: @@ -7754,6 +8534,12 @@ packages: } engines: { node: '>=8' } + resolve-workspace-root@2.0.1: + resolution: + { + integrity: sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==, + } + resolve.exports@2.0.3: resolution: { @@ -7769,6 +8555,13 @@ packages: engines: { node: '>= 0.4' } hasBin: true + restore-cursor@2.0.0: + resolution: + { + integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==, + } + engines: { node: '>=4' } + restore-cursor@3.1.0: resolution: { @@ -8040,6 +8833,12 @@ packages: } engines: { node: '>=14' } + simple-plist@1.3.1: + resolution: + { + integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==, + } + sisteransi@1.0.5: resolution: { @@ -8060,6 +8859,13 @@ packages: } engines: { node: '>=6' } + slugify@1.6.9: + resolution: + { + integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==, + } + engines: { node: '>=8.0.0' } + smol-toml@1.6.1: resolution: { @@ -8166,6 +8972,13 @@ packages: } engines: { node: '>=18' } + stream-buffers@2.2.0: + resolution: + { + integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==, + } + engines: { node: '>= 0.10.0' } + stream-parser@0.3.1: resolution: { @@ -8240,6 +9053,12 @@ packages: integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==, } + structured-headers@0.4.1: + resolution: + { + integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==, + } + supports-color@10.2.2: resolution: { @@ -8247,6 +9066,13 @@ packages: } engines: { node: '>=18' } + supports-color@5.5.0: + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: '>=4' } + supports-color@7.2.0: resolution: { @@ -8261,6 +9087,13 @@ packages: } engines: { node: '>=10' } + supports-hyperlinks@2.3.0: + resolution: + { + integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==, + } + engines: { node: '>=8' } + supports-preserve-symlinks-flag@1.0.0: resolution: { @@ -8315,6 +9148,13 @@ packages: } engines: { node: '>=8' } + terminal-link@2.1.1: + resolution: + { + integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==, + } + engines: { node: '>=8' } + terser@5.49.0: resolution: { @@ -8409,6 +9249,12 @@ packages: } hasBin: true + toqr@0.1.1: + resolution: + { + integrity: sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==, + } + tough-cookie@6.0.2: resolution: { @@ -8455,6 +9301,13 @@ packages: integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, } + type-fest@0.21.3: + resolution: + { + integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, + } + engines: { node: '>=10' } + type-fest@0.7.1: resolution: { @@ -8581,6 +9434,21 @@ packages: } engines: { node: '>= 0.4.0' } + uuid@7.0.3: + resolution: + { + integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==, + } + 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 + + validate-npm-package-name@5.0.1: + resolution: + { + integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==, + } + engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + vary@1.1.2: resolution: { @@ -8738,6 +9606,12 @@ packages: integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, } + warn-once@0.1.1: + resolution: + { + integrity: sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==, + } + wcwidth@1.0.1: resolution: { @@ -8770,6 +9644,12 @@ packages: } engines: { node: '>=20' } + whatwg-url-minimum@0.1.2: + resolution: + { + integrity: sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==, + } + whatwg-url@16.0.1: resolution: { @@ -8903,6 +9783,13 @@ packages: utf-8-validate: optional: true + xcode@3.0.1: + resolution: + { + integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==, + } + engines: { node: '>=10.0.0' } + xml-name-validator@5.0.0: resolution: { @@ -8910,6 +9797,27 @@ packages: } engines: { node: '>=18' } + xml2js@0.6.0: + resolution: + { + integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==, + } + engines: { node: '>=4.0.0' } + + xmlbuilder@11.0.1: + resolution: + { + integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, + } + engines: { node: '>=4.0' } + + xmlbuilder@15.1.1: + resolution: + { + integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==, + } + engines: { node: '>=8.0' } + xmlchars@2.2.0: resolution: { @@ -9017,6 +9925,12 @@ packages: integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==, } + zod@3.25.76: + resolution: + { + integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, + } + zrender@6.1.0: resolution: { @@ -9258,11 +10172,25 @@ snapshots: dependencies: '@babel/types': 7.29.7 + '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + transitivePeerDependencies: + - supports-color + '@babel/plugin-proposal-export-default-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9329,6 +10257,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9349,6 +10285,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-flow-strip-types@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9363,6 +10304,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9382,6 +10328,17 @@ snapshots: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/traverse': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9395,6 +10352,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9417,6 +10379,13 @@ snapshots: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-react-jsx-development@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9438,6 +10407,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-pure-annotations@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -9472,6 +10447,17 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/helper-plugin-utils': 7.29.7 + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.29.7': {} '@babel/template@7.29.7': @@ -9859,42 +10845,390 @@ snapshots: '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.28.1': - optional: true + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@exodus/bytes@1.15.1(@noble/hashes@2.2.0)': + optionalDependencies: + '@noble/hashes': 2.2.0 + + '@expo/cli@57.0.11(db0d7a7e1f9ec962ef302cb8147809a2)': + dependencies: + '@expo/code-signing-certificates': 0.0.6 + '@expo/config': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/config-plugins': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/devcert': 1.2.1(supports-color@10.2.2) + '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/image-utils': 0.11.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/inline-modules': 0.1.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/json-file': 11.0.1 + '@expo/log-box': 57.0.2(@expo/dom-webview@57.0.1)(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/metro': 56.0.0(supports-color@10.2.2) + '@expo/metro-config': 57.0.7(expo@57.0.9)(supports-color@10.2.2)(typescript@6.0.3) + '@expo/metro-file-map': 57.0.1(supports-color@10.2.2) + '@expo/osascript': 2.7.1 + '@expo/package-manager': 1.13.1 + '@expo/plist': 0.8.1 + '@expo/prebuild-config': 57.0.10(supports-color@10.2.2)(typescript@6.0.3) + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/router-server': 57.0.4(expo-constants@57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2))(expo-font@57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2) + '@expo/schema-utils': 57.0.2 + '@expo/spawn-async': 1.8.0 + '@expo/ws-tunnel': 2.0.0(ws@8.21.0) + '@expo/xcpretty': 4.4.4 + '@react-native/dev-middleware': 0.86.2(supports-color@10.2.2) + accepts: 1.3.8 + agent-cli-detector: 0.1.4 + arg: 5.0.2 + bplist-creator: 0.1.0 + bplist-parser: 0.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + compression: 1.8.1(supports-color@10.2.2) + connect: 3.7.0(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) + dnssd-advertise: 1.1.6 + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + expo-server: 57.0.1 + fetch-nodeshim: 0.4.10 + getenv: 2.0.0 + glob: 13.0.6 + lan-network: 0.2.1 + multitars: 1.0.0 + node-forge: 1.4.0 + npm-package-arg: 11.0.3 + ora: 3.4.0 + picomatch: 4.0.5 + pretty-format: 29.7.0 + progress: 2.0.3 + prompts: 2.4.2 + resolve-from: 5.0.0 + semver: 7.8.5 + send: 0.19.2(supports-color@10.2.2) + slugify: 1.6.9 + stacktrace-parser: 0.1.11 + structured-headers: 0.4.1 + terminal-link: 2.1.1 + toqr: 0.1.1 + wrap-ansi: 7.0.0 + ws: 8.21.0 + zod: 3.25.76 + optionalDependencies: + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + transitivePeerDependencies: + - '@expo/dom-webview' + - '@expo/metro-runtime' + - bufferutil + - expo-constants + - expo-font + - react + - react-dom + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + + '@expo/code-signing-certificates@0.0.6': + dependencies: + node-forge: 1.4.0 + + '@expo/config-plugins@57.0.6(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/config-types': 57.0.2 + '@expo/json-file': 11.0.1 + '@expo/plist': 0.8.1 + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/sdk-runtime-versions': 1.0.0 + chalk: 4.1.2 + debug: 4.4.3(supports-color@10.2.2) + getenv: 2.0.0 + glob: 13.0.6 + semver: 7.8.5 + slugify: 1.6.9 + xcode: 3.0.1 + xml2js: 0.6.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/config-types@57.0.2': {} + + '@expo/config@57.0.6(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/config-plugins': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/config-types': 57.0.2 + '@expo/json-file': 11.0.1 + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + deepmerge: 4.3.1 + getenv: 2.0.0 + glob: 13.0.6 + resolve-workspace-root: 2.0.1 + semver: 7.8.5 + slugify: 1.6.9 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/devcert@1.2.1(supports-color@10.2.2)': + dependencies: + '@expo/sudo-prompt': 9.3.2 + debug: 3.2.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@expo/devtools@57.0.1(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + dependencies: + chalk: 4.1.2 + optionalDependencies: + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + '@expo/dom-webview@57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + dependencies: + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + '@expo/env@2.4.2(supports-color@10.2.2)': + dependencies: + chalk: 4.1.2 + debug: 4.4.3(supports-color@10.2.2) + getenv: 2.0.0 + transitivePeerDependencies: + - supports-color + + '@expo/expo-modules-macros-plugin@0.6.1': {} + + '@expo/fingerprint@0.20.6(supports-color@10.2.2)': + dependencies: + '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/spawn-async': 1.8.0 + arg: 5.0.2 + chalk: 4.1.2 + debug: 4.4.3(supports-color@10.2.2) + getenv: 2.0.0 + glob: 13.0.6 + ignore: 5.3.2 + minimatch: 10.2.5 + resolve-from: 5.0.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + '@expo/image-utils@0.11.4(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/spawn-async': 1.8.0 + chalk: 4.1.2 + getenv: 2.0.0 + jimp-compact: 0.16.1 + parse-png: 2.1.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/inline-modules@0.1.4(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/config-plugins': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/json-file@11.0.1': + dependencies: + '@babel/code-frame': 7.29.7 + json5: 2.2.3 + + '@expo/local-build-cache-provider@57.0.5(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/config': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + chalk: 4.1.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/log-box@57.0.2(@expo/dom-webview@57.0.1)(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + dependencies: + '@expo/dom-webview': 57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + anser: 1.4.10 + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + stacktrace-parser: 0.1.11 + + '@expo/metro-config@57.0.7(expo@57.0.9)(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/generator': 7.29.7 + '@expo/config': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/json-file': 11.0.1 + '@expo/metro': 56.0.0(supports-color@10.2.2) + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/spawn-async': 1.8.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + browserslist: 4.28.7 + chalk: 4.1.2 + debug: 4.4.3(supports-color@10.2.2) + getenv: 2.0.0 + glob: 13.0.6 + hermes-parser: 0.36.0 + jsc-safe-url: 0.2.4 + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.23 + resolve-from: 5.0.0 + optionalDependencies: + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + + '@expo/metro-file-map@57.0.1(supports-color@10.2.2)': + dependencies: + debug: 4.4.3(supports-color@10.2.2) + fb-watchman: 2.0.2 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + '@expo/metro@56.0.0(supports-color@10.2.2)': + dependencies: + metro: 0.84.4(supports-color@10.2.2) + metro-babel-transformer: 0.84.4(supports-color@10.2.2) + metro-cache: 0.84.4(supports-color@10.2.2) + metro-cache-key: 0.84.4 + metro-config: 0.84.4(supports-color@10.2.2) + metro-core: 0.84.4 + metro-file-map: 0.84.4(supports-color@10.2.2) + metro-minify-terser: 0.84.4 + metro-resolver: 0.84.4 + metro-runtime: 0.84.4 + metro-source-map: 0.84.4(supports-color@10.2.2) + metro-symbolicate: 0.84.4(supports-color@10.2.2) + metro-transform-plugins: 0.84.4(supports-color@10.2.2) + metro-transform-worker: 0.84.4(supports-color@10.2.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@expo/osascript@2.7.1': + dependencies: + '@expo/spawn-async': 1.8.0 - '@esbuild/openharmony-arm64@0.27.7': - optional: true + '@expo/package-manager@1.13.1': + dependencies: + '@expo/json-file': 11.0.1 + '@expo/spawn-async': 1.8.0 + chalk: 4.1.2 + npm-package-arg: 11.0.3 + ora: 3.4.0 + resolve-workspace-root: 2.0.1 - '@esbuild/openharmony-arm64@0.28.1': - optional: true + '@expo/plist@0.8.1': + dependencies: + '@xmldom/xmldom': 0.8.13 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 - '@esbuild/sunos-x64@0.27.7': - optional: true + '@expo/prebuild-config@57.0.10(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@expo/config': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/config-plugins': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/config-types': 57.0.2 + '@expo/image-utils': 0.11.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/json-file': 11.0.1 + '@react-native/normalize-colors': 0.86.2 + debug: 4.4.3(supports-color@10.2.2) + expo-modules-autolinking: 57.0.9(supports-color@10.2.2)(typescript@6.0.3) + resolve-from: 5.0.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + - typescript - '@esbuild/sunos-x64@0.28.1': - optional: true + '@expo/require-utils@57.0.4(supports-color@10.2.2)(typescript@6.0.3)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@esbuild/win32-arm64@0.27.7': - optional: true + '@expo/router-server@57.0.4(expo-constants@57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2))(expo-font@57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2)': + dependencies: + debug: 4.4.3(supports-color@10.2.2) + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + expo-constants: 57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-font: 57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-server: 57.0.1 + react: 19.2.3 + optionalDependencies: + react-dom: 19.2.3(react@19.2.3) + transitivePeerDependencies: + - supports-color - '@esbuild/win32-arm64@0.28.1': - optional: true + '@expo/schema-utils@57.0.2': {} - '@esbuild/win32-ia32@0.27.7': - optional: true + '@expo/sdk-runtime-versions@1.0.0': {} - '@esbuild/win32-ia32@0.28.1': - optional: true + '@expo/spawn-async@1.8.0': + dependencies: + cross-spawn: 7.0.6 - '@esbuild/win32-x64@0.27.7': - optional: true + '@expo/sudo-prompt@9.3.2': {} - '@esbuild/win32-x64@0.28.1': - optional: true + '@expo/ws-tunnel@2.0.0(ws@8.21.0)': + dependencies: + ws: 8.21.0 - '@exodus/bytes@1.15.1(@noble/hashes@2.2.0)': - optionalDependencies: - '@noble/hashes': 2.2.0 + '@expo/xcpretty@4.4.4': + dependencies: + '@babel/code-frame': 7.29.7 + chalk: 4.1.2 + js-yaml: 4.3.0 '@hapi/hoek@9.3.0': {} @@ -10412,17 +11746,17 @@ snapshots: - typescript - utf-8-validate - '@react-native/assets-registry@0.86.0': {} + '@react-native/assets-registry@0.86.2': {} - '@react-native/babel-plugin-codegen@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@react-native/babel-plugin-codegen@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/traverse': 7.29.7(supports-color@10.2.2) - '@react-native/codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2)) + '@react-native/codegen': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2)) transitivePeerDependencies: - '@babel/core' - supports-color - '@react-native/babel-preset@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@react-native/babel-preset@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) @@ -10453,14 +11787,14 @@ snapshots: '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) - '@react-native/babel-plugin-codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/babel-plugin-codegen': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) babel-plugin-syntax-hermes-parser: 0.36.0 babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.7(supports-color@10.2.2)) react-refresh: 0.14.2 transitivePeerDependencies: - supports-color - '@react-native/codegen@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))': + '@react-native/codegen@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/parser': 7.29.7 @@ -10470,9 +11804,9 @@ snapshots: tinyglobby: 0.2.17 yargs: 17.7.2 - '@react-native/community-cli-plugin@0.86.0(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2)': + '@react-native/community-cli-plugin@0.86.2(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@react-native/dev-middleware': 0.86.0(supports-color@10.2.2) + '@react-native/dev-middleware': 0.86.2(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2) invariant: 2.2.4 metro: 0.84.4(supports-color@10.2.2) @@ -10481,15 +11815,15 @@ snapshots: semver: 7.8.5 optionalDependencies: '@react-native-community/cli': 20.1.0(supports-color@10.2.2)(typescript@6.0.3) - '@react-native/metro-config': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/metro-config': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.86.0': {} + '@react-native/debugger-frontend@0.86.2': {} - '@react-native/debugger-shell@0.86.0(supports-color@10.2.2)': + '@react-native/debugger-shell@0.86.2(supports-color@10.2.2)': dependencies: cross-spawn: 7.0.6 debug: 4.4.3(supports-color@10.2.2) @@ -10497,11 +11831,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/dev-middleware@0.86.0(supports-color@10.2.2)': + '@react-native/dev-middleware@0.86.2(supports-color@10.2.2)': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.86.0 - '@react-native/debugger-shell': 0.86.0(supports-color@10.2.2) + '@react-native/debugger-frontend': 0.86.2 + '@react-native/debugger-shell': 0.86.2(supports-color@10.2.2) chrome-launcher: 0.15.2(supports-color@10.2.2) chromium-edge-launcher: 0.3.0(supports-color@10.2.2) connect: 3.7.0(supports-color@10.2.2) @@ -10516,23 +11850,23 @@ snapshots: - supports-color - utf-8-validate - '@react-native/gradle-plugin@0.86.0': {} + '@react-native/gradle-plugin@0.86.2': {} - '@react-native/js-polyfills@0.86.0': {} + '@react-native/js-polyfills@0.86.2': {} - '@react-native/metro-babel-transformer@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@react-native/metro-babel-transformer@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) - '@react-native/babel-preset': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/babel-preset': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) hermes-parser: 0.36.0 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - '@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + '@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@react-native/js-polyfills': 0.86.0 - '@react-native/metro-babel-transformer': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/js-polyfills': 0.86.2 + '@react-native/metro-babel-transformer': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) metro-config: 0.84.4(supports-color@10.2.2) metro-runtime: 0.84.4 transitivePeerDependencies: @@ -10541,16 +11875,16 @@ snapshots: - supports-color - utf-8-validate - '@react-native/normalize-colors@0.86.0': {} + '@react-native/normalize-colors@0.86.2': {} - '@react-native/typescript-config@0.86.0': {} + '@react-native/typescript-config@0.86.2': {} - '@react-native/virtualized-lists@0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + '@react-native/virtualized-lists@0.86.2(@types/react@19.2.17)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 19.2.3 - react-native: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) optionalDependencies: '@types/react': 19.2.17 @@ -10944,10 +12278,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@vitejs/plugin-react@6.0.4(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': + '@ungap/structured-clone@1.3.3': {} + + '@vitejs/plugin-react@6.0.4(babel-plugin-react-compiler@1.0.0)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 vite: 8.1.5(@types/node@25.9.5)(esbuild@0.27.7)(less@4.8.1(supports-color@10.2.2))(sass@1.102.0)(terser@5.49.0)(yaml@2.9.0) + optionalDependencies: + babel-plugin-react-compiler: 1.0.0 '@vitest/expect@4.1.10': dependencies: @@ -11052,6 +12390,10 @@ snapshots: '@vue/shared@3.5.40': {} + '@xmldom/xmldom@0.8.13': {} + + '@xmldom/xmldom@0.9.10': {} + '@yarnpkg/lockfile@1.1.0': {} '@zkochan/js-yaml@0.0.7': @@ -11076,6 +12418,8 @@ snapshots: agent-base@7.1.4: {} + agent-cli-detector@0.1.4: {} + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -11091,6 +12435,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-fragments@0.2.1: dependencies: colorette: 1.4.0 @@ -11117,6 +12465,8 @@ snapshots: appdirsjs@1.2.8: {} + arg@5.0.2: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -11180,6 +12530,12 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-react-compiler@1.0.0: + dependencies: + '@babel/types': 7.29.7 + + babel-plugin-react-native-web@0.21.2: {} + babel-plugin-syntax-hermes-parser@0.36.0: dependencies: hermes-parser: 0.36.0 @@ -11190,6 +12546,58 @@ snapshots: transitivePeerDependencies: - '@babel/core' + babel-preset-expo@57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.9)(react-refresh@0.14.2)(supports-color@10.2.2): + dependencies: + '@babel/generator': 7.29.7 + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-export-default-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-flow-strip-types': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/babel-plugin-codegen': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-react-compiler: 1.0.0 + babel-plugin-react-native-web: 0.21.2 + babel-plugin-syntax-hermes-parser: 0.36.0 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.7(supports-color@10.2.2)) + debug: 4.4.3(supports-color@10.2.2) + react-refresh: 0.14.2 + optionalDependencies: + '@babel/runtime': 7.29.7 + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + transitivePeerDependencies: + - '@babel/core' + - supports-color + babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@10.2.2))(solid-js@1.9.14): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) @@ -11211,6 +12619,8 @@ snapshots: dependencies: require-from-string: 2.0.2 + big-integer@1.6.52: {} + binary-search-bounds@2.0.5: {} bl@4.1.0: @@ -11240,6 +12650,18 @@ snapshots: boolbase@1.0.0: {} + bplist-creator@0.1.0: + dependencies: + stream-buffers: 2.2.0 + + bplist-parser@0.3.1: + dependencies: + big-integer: 1.6.52 + + bplist-parser@0.3.2: + dependencies: + big-integer: 1.6.52 + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.3 @@ -11293,6 +12715,12 @@ snapshots: chai@6.2.2: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -11337,6 +12765,10 @@ snapshots: ci-info@3.9.0: {} + cli-cursor@2.1.0: + dependencies: + restore-cursor: 2.0.0 + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -11405,7 +12837,7 @@ snapshots: compressible@2.0.18: dependencies: - mime-db: 1.52.0 + mime-db: 1.54.0 compression@1.8.1(supports-color@10.2.2): dependencies: @@ -11672,7 +13104,6 @@ snapshots: ms: 2.1.3 optionalDependencies: supports-color: 10.2.2 - optional: true debug@4.4.3(supports-color@10.2.2): dependencies: @@ -11718,6 +13149,8 @@ snapshots: dependencies: path-type: 4.0.0 + dnssd-advertise@1.1.6: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -11933,6 +13366,106 @@ snapshots: expect-type@1.4.0: {} + expo-asset@57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): + dependencies: + '@expo/image-utils': 0.11.4(supports-color@10.2.2)(typescript@6.0.3) + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + expo-constants: 57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + - typescript + + expo-constants@57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2): + dependencies: + '@expo/env': 2.4.2(supports-color@10.2.2) + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + expo-file-system@57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2)): + dependencies: + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + expo-font@57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + dependencies: + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + fontfaceobserver: 2.3.0 + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + expo-keep-awake@57.0.1(expo@57.0.9)(react@19.2.3): + dependencies: + expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + react: 19.2.3 + + expo-modules-autolinking@57.0.9(supports-color@10.2.2)(typescript@6.0.3): + dependencies: + '@expo/require-utils': 57.0.4(supports-color@10.2.2)(typescript@6.0.3) + '@expo/spawn-async': 1.8.0 + chalk: 4.1.2 + commander: 7.2.0 + transitivePeerDependencies: + - supports-color + - typescript + + expo-modules-core@57.0.8(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + dependencies: + '@expo/expo-modules-macros-plugin': 0.6.1 + expo-modules-jsi: 57.0.4(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2)) + invariant: 2.2.4 + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + expo-modules-jsi@57.0.4(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2)): + dependencies: + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + + expo-server@57.0.1: {} + + expo@57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@expo/dom-webview@57.0.1)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): + dependencies: + '@babel/runtime': 7.29.7 + '@expo/cli': 57.0.11(db0d7a7e1f9ec962ef302cb8147809a2) + '@expo/config': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/config-plugins': 57.0.6(supports-color@10.2.2)(typescript@6.0.3) + '@expo/devtools': 57.0.1(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/fingerprint': 0.20.6(supports-color@10.2.2) + '@expo/local-build-cache-provider': 57.0.5(supports-color@10.2.2)(typescript@6.0.3) + '@expo/log-box': 57.0.2(@expo/dom-webview@57.0.1)(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/metro': 56.0.0(supports-color@10.2.2) + '@expo/metro-config': 57.0.7(expo@57.0.9)(supports-color@10.2.2)(typescript@6.0.3) + '@ungap/structured-clone': 1.3.3 + babel-preset-expo: 57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.9)(react-refresh@0.14.2)(supports-color@10.2.2) + expo-asset: 57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + expo-constants: 57.0.8(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-file-system: 57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2)) + expo-font: 57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-keep-awake: 57.0.1(expo@57.0.9)(react@19.2.3) + expo-modules-autolinking: 57.0.9(supports-color@10.2.2)(typescript@6.0.3) + expo-modules-core: 57.0.8(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + pretty-format: 29.7.0 + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-refresh: 0.14.2 + whatwg-url-minimum: 0.1.2 + optionalDependencies: + '@expo/dom-webview': 57.0.1(expo@57.0.9)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + react-dom: 19.2.3(react@19.2.3) + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - expo-router + - expo-widgets + - react-native-worklets + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + exponential-backoff@3.1.3: {} extendable-error@0.1.7: {} @@ -11967,6 +13500,8 @@ snapshots: optionalDependencies: picomatch: 4.0.5 + fetch-nodeshim@0.4.10: {} + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -12012,6 +13547,8 @@ snapshots: optionalDependencies: debug: 4.4.3(supports-color@10.2.2) + fontfaceobserver@2.3.0: {} + form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -12078,10 +13615,18 @@ snapshots: get-stream@6.0.1: {} + getenv@2.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -12095,6 +13640,8 @@ snapshots: graceful-fs@4.2.11: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -12111,7 +13658,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hermes-compiler@250829098.0.14: {} + hermes-compiler@250829098.0.16: {} hermes-estree@0.35.0: {} @@ -12125,6 +13672,10 @@ snapshots: dependencies: hermes-estree: 0.36.0 + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + html-encoding-sniffer@6.0.0(@noble/hashes@2.2.0): dependencies: '@exodus/bytes': 1.15.1(@noble/hashes@2.2.0) @@ -12282,6 +13833,8 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jimp-compact@0.16.1: {} + joi@17.13.4: dependencies: '@hapi/hoek': 9.3.0 @@ -12349,6 +13902,8 @@ snapshots: kleur@4.1.5: {} + lan-network@0.2.1: {} + launch-editor@2.14.1: dependencies: picocolors: 1.1.1 @@ -12466,6 +14021,10 @@ snapshots: lodash.throttle@4.1.1: {} + log-symbols@2.2.0: + dependencies: + chalk: 2.4.2 + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -12486,6 +14045,8 @@ snapshots: dependencies: js-tokens: 4.0.0 + lru-cache@10.4.3: {} + lru-cache@11.5.2: {} lru-cache@5.1.1: @@ -12718,6 +14279,8 @@ snapshots: mime@2.6.0: {} + mimic-fn@1.2.0: {} + mimic-fn@2.1.0: {} mimic-function@5.0.1: {} @@ -12740,6 +14303,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.3: {} + mkdirp@1.0.4: {} mri@1.2.0: {} @@ -12748,6 +14313,8 @@ snapshots: ms@2.1.3: {} + multitars@1.0.0: {} + nanoid@3.3.16: {} needle@2.9.1(supports-color@10.2.2): @@ -12810,12 +14377,21 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-forge@1.4.0: {} + node-int64@0.4.0: {} node-releases@2.0.51: {} node-stream-zip@1.16.0: {} + npm-package-arg@11.0.3: + dependencies: + hosted-git-info: 7.0.2 + proc-log: 4.2.0 + semver: 7.8.5 + validate-npm-package-name: 5.0.1 + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -13000,6 +14576,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@2.0.1: + dependencies: + mimic-fn: 1.2.0 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -13023,6 +14603,15 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + ora@3.4.0: + dependencies: + chalk: 2.4.2 + cli-cursor: 2.1.0 + cli-spinners: 2.6.1 + log-symbols: 2.2.0 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + ora@5.3.0: dependencies: bl: 4.1.0 @@ -13100,6 +14689,10 @@ snapshots: parse-node-version@1.0.1: {} + parse-png@2.1.0: + dependencies: + pngjs: 3.4.0 + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -13116,6 +14709,11 @@ snapshots: path-parse@1.0.7: {} + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + path-to-regexp@6.3.0: {} path-type@4.0.0: {} @@ -13146,6 +14744,14 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + plist@3.1.1: + dependencies: + '@xmldom/xmldom': 0.9.10 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + pngjs@3.4.0: {} + postcss@8.5.23: dependencies: nanoid: 3.3.16 @@ -13179,6 +14785,10 @@ snapshots: - supports-color optional: true + proc-log@4.2.0: {} + + progress@2.0.3: {} + promise@8.3.0: dependencies: asap: 2.0.6 @@ -13234,22 +14844,30 @@ snapshots: react-is@19.2.8: {} - react-native-svg@15.15.5(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + react-native-svg@15.15.4(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + dependencies: + css-select: 5.2.2 + css-tree: 1.1.3 + react: 19.2.3 + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + warn-once: 0.1.1 + + react-native-svg@15.15.5(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: css-select: 5.2.2 css-tree: 1.1.3 react: 19.2.3 - react-native: 0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) + react-native: 0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2) - react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2): + react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2): dependencies: - '@react-native/assets-registry': 0.86.0 - '@react-native/codegen': 0.86.0(@babel/core@7.29.7(supports-color@10.2.2)) - '@react-native/community-cli-plugin': 0.86.0(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2) - '@react-native/gradle-plugin': 0.86.0 - '@react-native/js-polyfills': 0.86.0 - '@react-native/normalize-colors': 0.86.0 - '@react-native/virtualized-lists': 0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@react-native/assets-registry': 0.86.2 + '@react-native/codegen': 0.86.2(@babel/core@7.29.7(supports-color@10.2.2)) + '@react-native/community-cli-plugin': 0.86.2(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(supports-color@10.2.2) + '@react-native/gradle-plugin': 0.86.2 + '@react-native/js-polyfills': 0.86.2 + '@react-native/normalize-colors': 0.86.2 + '@react-native/virtualized-lists': 0.86.2(@types/react@19.2.17)(react-native@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(@react-native-community/cli@20.1.0(supports-color@10.2.2)(typescript@6.0.3))(@react-native/metro-config@0.86.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.17)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -13257,7 +14875,7 @@ snapshots: base64-js: 1.5.1 commander: 12.1.0 flow-enums-runtime: 0.0.6 - hermes-compiler: 250829098.0.14 + hermes-compiler: 250829098.0.16 invariant: 2.2.4 memoize-one: 5.2.1 metro-runtime: 0.84.4 @@ -13379,6 +14997,8 @@ snapshots: resolve-from@5.0.0: {} + resolve-workspace-root@2.0.1: {} + resolve.exports@2.0.3: {} resolve@1.22.12: @@ -13388,6 +15008,11 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@2.0.0: + dependencies: + onetime: 2.0.1 + signal-exit: 3.0.7 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -13491,8 +15116,7 @@ snapshots: optionalDependencies: '@parcel/watcher': 2.6.0 - sax@1.6.1: - optional: true + sax@1.6.1: {} saxes@6.0.0: dependencies: @@ -13620,6 +15244,12 @@ snapshots: signal-exit@4.1.0: {} + simple-plist@1.3.1: + dependencies: + bplist-creator: 0.1.0 + bplist-parser: 0.3.1 + plist: 3.1.1 + sisteransi@1.0.5: {} slash@3.0.0: {} @@ -13630,6 +15260,8 @@ snapshots: astral-regex: 1.0.0 is-fullwidth-code-point: 2.0.0 + slugify@1.6.9: {} + smol-toml@1.6.1: {} solid-js@1.9.14: @@ -13681,6 +15313,8 @@ snapshots: stdin-discarder@0.3.2: {} + stream-buffers@2.2.0: {} + stream-parser@0.3.1(supports-color@10.2.2): dependencies: debug: 2.6.9(supports-color@10.2.2) @@ -13727,8 +15361,14 @@ snapshots: strnum@1.1.2: {} + structured-headers@0.4.1: {} + supports-color@10.2.2: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -13737,6 +15377,11 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} svelte-check@4.7.4(picomatch@4.0.5)(svelte@5.56.8)(typescript@6.0.3): @@ -13792,6 +15437,11 @@ snapshots: term-size@2.2.1: {} + terminal-link@2.1.1: + dependencies: + ansi-escapes: 4.3.2 + supports-hyperlinks: 2.3.0 + terser@5.49.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -13834,6 +15484,8 @@ snapshots: dependencies: commander: 2.20.3 + toqr@0.1.1: {} + tough-cookie@6.0.2: dependencies: tldts: 7.4.9 @@ -13856,6 +15508,8 @@ snapshots: tslib@2.8.1: {} + type-fest@0.21.3: {} + type-fest@0.7.1: {} type-is@1.6.18: @@ -13906,6 +15560,10 @@ snapshots: utils-merge@1.0.1: {} + uuid@7.0.3: {} + + validate-npm-package-name@5.0.1: {} + vary@1.1.2: {} victory-vendor@37.3.6: @@ -14039,6 +15697,8 @@ snapshots: dependencies: makeerror: 1.0.12 + warn-once@0.1.1: {} + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -14051,6 +15711,8 @@ snapshots: whatwg-mimetype@5.0.0: {} + whatwg-url-minimum@0.1.2: {} + whatwg-url@16.0.1(@noble/hashes@2.2.0): dependencies: '@exodus/bytes': 1.15.1(@noble/hashes@2.2.0) @@ -14129,8 +15791,22 @@ snapshots: ws@8.21.0: {} + xcode@3.0.1: + dependencies: + simple-plist: 1.3.1 + uuid: 7.0.3 + xml-name-validator@5.0.0: {} + xml2js@0.6.0: + dependencies: + sax: 1.6.1 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + + xmlbuilder@15.1.1: {} + xmlchars@2.2.0: {} y18n@4.0.3: {} @@ -14202,6 +15878,8 @@ snapshots: zimmerframe@1.1.4: {} + zod@3.25.76: {} + zrender@6.1.0: dependencies: tslib: 2.3.0 diff --git a/scripts/check-packed-consumers.mjs b/scripts/check-packed-consumers.mjs index 62c084f3..7a4fc5e4 100644 --- a/scripts/check-packed-consumers.mjs +++ b/scripts/check-packed-consumers.mjs @@ -19,6 +19,7 @@ import { compile as compileOctane } from 'octane/compiler' import { build, transform } from 'esbuild' import ts from 'typescript' import { validatePackedMarkdownLinks } from './packed-markdown-links.mjs' +import { verifyPackedReactNativeConsumers } from './packed-react-native-consumers.mjs' const execFileAsync = promisify(execFile) const root = resolve(import.meta.dirname, '..') @@ -31,12 +32,14 @@ const buildWorkspace = resolve(temporaryRoot, 'build') const tarballDirectory = artifactDirectory ?? resolve(temporaryRoot, 'tarballs') const fixtureDirectory = resolve(temporaryRoot, 'consumer') -const packages = [ +const webPackages = [ packageConfig('charts-scales', 'scale'), packageConfig('charts-core', 'core'), packageConfig('react-charts', 'react'), packageConfig('octane-charts', 'octane'), ] +const nativePackage = packageConfig('react-native-charts', 'react-native') +const packages = [...webPackages, nativePackage] try { await mkdir(resolve(buildWorkspace, 'packages'), { recursive: true }) @@ -72,15 +75,25 @@ try { await verifyEsmRuntime() await verifyDeclarations() const bundles = await verifyProductionBundles() + const nativeBundles = await verifyPackedReactNativeConsumers({ + repositoryRoot: root, + temporaryRoot, + tarballs, + }) console.log('Packed exports, declarations, and runtime gate passed.') - console.log('| Consumer | Minified | Gzip |') + console.log('| Consumer | Bytes | Gzip |') console.log('| --- | ---: | ---: |') for (const bundle of bundles) { console.log( `| ${bundle.label} | ${formatBytes(bundle.bytes)} | ${formatBytes(bundle.gzip)} |`, ) } + for (const bundle of nativeBundles) { + console.log( + `| ${bundle.label} | ${formatBytes(bundle.bytes)} | ${formatBytes(bundle.gzip)} |`, + ) + } } finally { await rm(temporaryRoot, { recursive: true, force: true }) } @@ -158,7 +171,7 @@ function validateManifest(packageInfo) { published.types?.startsWith('./dist/'), `${manifest.name} published export ${key} requires declarations`, ) - for (const condition of ['import', 'browser', 'node']) { + for (const condition of ['import', 'browser', 'node', 'react-native']) { if (published[condition] === undefined) continue assert.ok( published[condition].startsWith('./dist/'), @@ -207,7 +220,10 @@ async function buildRuntime(packageInfo) { platform: 'neutral', target: 'es2022', jsx: 'automatic', - jsxImportSource: packageInfo.kind === 'react' ? 'react' : undefined, + jsxImportSource: + packageInfo.kind === 'react' || packageInfo.kind === 'react-native' + ? 'react' + : undefined, legalComments: 'none', logLevel: 'silent', }) @@ -288,19 +304,23 @@ async function buildDeclarations(packageInfo) { ), ), ] + const isReactNative = packageInfo.kind === 'react-native' const options = { allowArbitraryExtensions: true, declaration: true, declarationMap: false, emitDeclarationOnly: true, jsx: ts.JsxEmit.ReactJSX, - lib: ['lib.es2022.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts'], + customConditions: isReactNative ? ['react-native'] : undefined, + lib: isReactNative + ? ['lib.es2022.d.ts'] + : ['lib.es2022.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts'], module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, noEmitOnError: true, outDir: outputRoot, rootDir: sourceRoot, - skipLibCheck: false, + skipLibCheck: isReactNative, strict: true, target: ts.ScriptTarget.ES2022, verbatimModuleSyntax: true, @@ -500,7 +520,7 @@ function publishedSpecifiers(packageInfo) { } async function verifyInstalledManifests() { - for (const packageInfo of packages) { + for (const packageInfo of webPackages) { const installedPath = resolve( fixtureDirectory, 'node_modules', @@ -530,7 +550,7 @@ async function verifyInstalledManifests() { } async function verifyEsmRuntime() { - const publishedSubpaths = packages.flatMap(publishedSpecifiers) + const publishedSubpaths = webPackages.flatMap(publishedSpecifiers) const source = ` import assert from 'node:assert/strict' import { realpathSync } from 'node:fs' @@ -669,7 +689,7 @@ async function verifyEsmRuntime() { } async function verifyDeclarations() { - const namespaceImports = packages + const namespaceImports = webPackages .flatMap(publishedSpecifiers) .map( (specifier, index) => diff --git a/scripts/check-react-native-types.mjs b/scripts/check-react-native-types.mjs index a524b052..fa55feda 100644 --- a/scripts/check-react-native-types.mjs +++ b/scripts/check-react-native-types.mjs @@ -6,6 +6,7 @@ const tsc = resolve(root, 'node_modules/typescript/bin/tsc') const passingConfigs = [ 'packages/react-native-charts/tsconfig.json', 'examples/charts-react-native/tsconfig.json', + 'examples/charts-expo/tsconfig.json', ] for (const config of passingConfigs) { diff --git a/scripts/docs-contract.mjs b/scripts/docs-contract.mjs index d493bf88..0f5d1d97 100644 --- a/scripts/docs-contract.mjs +++ b/scripts/docs-contract.mjs @@ -43,6 +43,7 @@ const publicEntryPaths = [ 'packages/charts-scales/README.md', 'packages/preact-charts/README.md', 'packages/react-charts/README.md', + 'packages/react-native-charts/README.md', 'packages/vue-charts/README.md', 'packages/solid-charts/README.md', 'packages/svelte-charts/README.md', @@ -480,6 +481,7 @@ async function validateDocumentedTanStackImports( ['packages/charts-scales', '@tanstack/charts-scales'], ['packages/preact-charts', '@tanstack/preact-charts'], ['packages/react-charts', '@tanstack/react-charts'], + ['packages/react-native-charts', '@tanstack/react-native-charts'], ['packages/vue-charts', '@tanstack/vue-charts'], ['packages/solid-charts', '@tanstack/solid-charts'], ['packages/svelte-charts', '@tanstack/svelte-charts'], diff --git a/scripts/packed-react-native-consumers.mjs b/scripts/packed-react-native-consumers.mjs new file mode 100644 index 00000000..26f5e074 --- /dev/null +++ b/scripts/packed-react-native-consumers.mjs @@ -0,0 +1,540 @@ +import assert from 'node:assert/strict' +import { execFile } from 'node:child_process' +import { + cp, + mkdir, + readFile, + readdir, + realpath, + stat, + writeFile, +} from 'node:fs/promises' +import { dirname, resolve } from 'node:path' +import { promisify } from 'node:util' +import { gzipSync } from 'node:zlib' + +const execFileAsync = promisify(execFile) + +const forbiddenNativeSources = [ + '/@tanstack/charts/dist/adapter.js', + '/@tanstack/charts/dist/adapter-renderer.js', + '/@tanstack/charts/dist/canvas.js', + '/@tanstack/charts/dist/dom.js', + '/@tanstack/charts/dist/dom-text.js', + '/@tanstack/charts/dist/export.js', + '/@tanstack/charts/dist/reconcile.js', + '/@tanstack/charts/dist/renderer.js', + '/@tanstack/charts/dist/svg-resources.js', + '/@tanstack/charts/dist/svg-surface.js', + '/@tanstack/charts/dist/tooltip.js', + '/@tanstack/charts/dist/tooltip-position.js', + '/@tanstack/charts/dist/tooltip-portal.js', + '/@tanstack/react-charts/', + '/react-dom/', +] + +export async function verifyPackedReactNativeConsumers({ + repositoryRoot, + temporaryRoot, + tarballs, +}) { + const coreTarball = requiredTarball(tarballs, '@tanstack/charts') + const nativeTarball = requiredTarball( + tarballs, + '@tanstack/react-native-charts', + ) + const consumersRoot = resolve(temporaryRoot, 'react-native-consumers') + const packageManager = JSON.parse( + await readFile(resolve(repositoryRoot, 'package.json'), 'utf8'), + ).packageManager + const consumerConfigs = [ + bareConsumerConfig(repositoryRoot), + expoConsumerConfig(repositoryRoot), + ] + const bundles = [] + + for (const config of consumerConfigs) { + const consumerRoot = resolve(consumersRoot, config.name) + await deployConsumer({ + config, + consumerRoot, + coreTarball, + nativeTarball, + packageManager, + repositoryRoot, + }) + await installConsumer(consumerRoot, repositoryRoot) + await verifyInstalledPackage({ consumerRoot, repositoryRoot }) + await verifyConsumerTypes({ config, consumerRoot, repositoryRoot }) + bundles.push(...(await bundleConsumer({ config, consumerRoot }))) + } + + console.log( + 'Packed React Native exports, declarations, bare Metro, and Expo Metro gates passed.', + ) + return bundles +} + +function bareConsumerConfig(repositoryRoot) { + return { + name: 'bare', + importerPath: 'examples/charts-react-native', + sourceDirectory: resolve(repositoryRoot, 'examples/charts-react-native'), + writeConfig: async (consumerRoot) => { + await writeFile( + resolve(consumerRoot, 'metro.config.cjs'), + "const { getDefaultConfig } = require('@react-native/metro-config')\n\nmodule.exports = getDefaultConfig(__dirname)\n", + ) + }, + strictTypes: true, + bundle: bundleBareConsumer, + } +} + +function expoConsumerConfig(repositoryRoot) { + return { + name: 'expo', + importerPath: 'examples/charts-expo', + sourceDirectory: resolve(repositoryRoot, 'examples/charts-expo'), + writeConfig: async () => {}, + strictTypes: false, + bundle: bundleExpoConsumer, + } +} + +async function deployConsumer({ + config, + consumerRoot, + coreTarball, + nativeTarball, + packageManager, + repositoryRoot, +}) { + await copyConsumerSource(config.sourceDirectory, consumerRoot) + await writeConsumerLock({ + consumerRoot, + importerPath: config.importerPath, + repositoryRoot, + }) + const manifest = JSON.parse( + await readFile(resolve(consumerRoot, 'package.json'), 'utf8'), + ) + manifest.packageManager = packageManager + manifest.dependencies['@tanstack/charts'] = `file:${coreTarball}` + manifest.dependencies['@tanstack/react-native-charts'] = + `file:${nativeTarball}` + await writeFile( + resolve(consumerRoot, 'package.json'), + `${JSON.stringify(manifest, null, 2)}\n`, + ) + await writeFile( + resolve(consumerRoot, 'pnpm-workspace.yaml'), + `packages:\n - '.'\n\noverrides:\n '@tanstack/charts': ${JSON.stringify(`file:${coreTarball}`)}\n\nverifyDepsBeforeRun: false\n\nallowBuilds:\n '@parcel/watcher': false\n esbuild: false\n nx: false\n sharp: false\n workerd: false\n`, + ) + await config.writeConfig(consumerRoot) +} + +async function copyConsumerSource(sourceDirectory, consumerRoot) { + await mkdir(consumerRoot, { recursive: true }) + for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) { + if (entry.name === 'node_modules' || entry.name.startsWith('dist')) continue + await cp( + resolve(sourceDirectory, entry.name), + resolve(consumerRoot, entry.name), + { recursive: entry.isDirectory() }, + ) + } +} + +async function writeConsumerLock({ + consumerRoot, + importerPath, + repositoryRoot, +}) { + const lockSource = await readFile( + resolve(repositoryRoot, 'pnpm-lock.yaml'), + 'utf8', + ) + const lines = lockSource.split('\n') + const importersIndex = lines.indexOf('importers:') + const packagesIndex = lines.indexOf('packages:') + const importerIndex = lines.indexOf(` ${importerPath}:`, importersIndex + 1) + assert.ok(importersIndex >= 0, 'Workspace lock has no importers section') + assert.ok( + packagesIndex > importersIndex, + 'Workspace lock has no packages section', + ) + assert.ok( + importerIndex > importersIndex && importerIndex < packagesIndex, + `Workspace lock has no ${importerPath} importer`, + ) + + let importerEnd = importerIndex + 1 + while (importerEnd < packagesIndex && !/^ \S.*:$/.test(lines[importerEnd])) { + importerEnd += 1 + } + const importer = lines.slice(importerIndex, importerEnd) + importer[0] = ' .:' + const consumerLock = [ + ...lines.slice(0, importersIndex + 1), + '', + ...importer, + '', + ...lines.slice(packagesIndex), + ].join('\n') + await writeFile(resolve(consumerRoot, 'pnpm-lock.yaml'), consumerLock) +} + +async function installConsumer(consumerRoot, repositoryRoot) { + const modulesState = JSON.parse( + await readFile( + resolve(repositoryRoot, 'node_modules/.modules.yaml'), + 'utf8', + ), + ) + assert.equal(typeof modulesState.storeDir, 'string') + await run( + 'pnpm', + [ + 'install', + '--offline', + '--ignore-scripts', + '--frozen-lockfile=false', + '--store-dir', + resolve(modulesState.storeDir, '..'), + ], + consumerRoot, + { + CI: 'true', + npm_config_offline: 'true', + }, + ) +} + +async function verifyInstalledPackage({ consumerRoot, repositoryRoot }) { + const sourceManifest = JSON.parse( + await readFile( + resolve(repositoryRoot, 'packages/react-native-charts/package.json'), + 'utf8', + ), + ) + const sourceCoreManifest = JSON.parse( + await readFile( + resolve(repositoryRoot, 'packages/charts-core/package.json'), + 'utf8', + ), + ) + const packageRoot = resolve( + consumerRoot, + 'node_modules/@tanstack/react-native-charts', + ) + const installedManifest = JSON.parse( + await readFile(resolve(packageRoot, 'package.json'), 'utf8'), + ) + const corePackageRoot = resolve(consumerRoot, 'node_modules/@tanstack/charts') + const installedCoreManifest = JSON.parse( + await readFile(resolve(corePackageRoot, 'package.json'), 'utf8'), + ) + assert.deepEqual( + installedManifest.exports, + sourceManifest.publishConfig.exports, + ) + assert.equal(installedManifest.private, false) + assert.equal(installedManifest.publishConfig?.exports, undefined) + assert.equal(installedManifest.publishConfig?.access, 'public') + assert.equal(installedManifest.publishConfig?.provenance, true) + assert.equal( + installedManifest.dependencies['@tanstack/charts'], + sourceManifest.version, + ) + assert.equal(installedCoreManifest.version, sourceCoreManifest.version) + assert.equal((await readdir(packageRoot)).includes('src'), false) + assert.equal((await readdir(corePackageRoot)).includes('src'), false) + + const nativePackageRealPath = await realpath(packageRoot) + const directCoreRealPath = await realpath(corePackageRoot) + const coreResolvedFromNative = await realpath( + resolve(dirname(dirname(nativePackageRealPath)), '@tanstack/charts'), + ) + assert.equal( + coreResolvedFromNative, + directCoreRealPath, + 'The native adapter did not resolve the installed core tarball', + ) + for (const range of Object.values(installedManifest.dependencies ?? {})) { + assert.equal(range.startsWith('workspace:'), false) + } + + const resolutionCheck = resolve(consumerRoot, 'resolve-exports.mjs') + await writeFile( + resolutionCheck, + `import assert from 'node:assert/strict'\nimport { realpathSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nconst expected = process.argv[2]\nfor (const [specifier, filename] of [\n ['@tanstack/react-native-charts', expected === 'native' ? 'index.native.js' : 'index.js'],\n ['@tanstack/react-native-charts/tooltip', expected === 'native' ? 'tooltip-entry.native.js' : 'tooltip-entry.js'],\n ['@tanstack/charts/universal', 'universal.js'],\n]) {\n const resolved = realpathSync(fileURLToPath(import.meta.resolve(specifier)))\n assert.ok(resolved.startsWith(realpathSync('./node_modules')), resolved)\n assert.ok(resolved.endsWith('/dist/' + filename), resolved)\n}\n`, + ) + await run('node', [resolutionCheck, 'import'], consumerRoot) + await run( + 'node', + ['--conditions=react-native', resolutionCheck, 'native'], + consumerRoot, + ) +} + +async function verifyConsumerTypes({ config, consumerRoot }) { + const tsc = resolve(consumerRoot, 'node_modules/typescript/bin/tsc') + await run( + process.execPath, + [tsc, '--noEmit', '-p', 'tsconfig.json', '--pretty', 'false'], + consumerRoot, + ) + if (!config.strictTypes) return + + const strict = await runAllowFailure( + process.execPath, + [tsc, '--noEmit', '-p', 'tsconfig.strict.json', '--pretty', 'false'], + consumerRoot, + ) + if (strict.status === 0) return + const diagnostics = strict.output + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.includes('error TS')) + const expected = diagnostics.every( + (line) => + line.includes('/@types/d3-array/') && + line.includes("Cannot find name 'ImageData'."), + ) + if (!expected || diagnostics.length !== 2) { + throw new Error( + `Packed strict React Native declarations failed beyond the known @types/d3-array boundary:\n${strict.output}`, + ) + } +} + +async function bundleConsumer({ config, consumerRoot }) { + const bundles = await config.bundle(consumerRoot) + for (const bundle of bundles) { + const sources = await readSourceMapSources(bundle.sourceMaps) + assertPackedNativeBoundary(bundle.label, sources, bundle.includesTooltip) + } + return bundles.map(({ label, bundle }) => ({ + label, + bytes: bundle.byteLength, + gzip: gzipSync(bundle).byteLength, + })) +} + +async function bundleBareConsumer(consumerRoot) { + const cli = resolve(consumerRoot, 'node_modules/.bin/react-native') + const outputRoot = resolve(consumerRoot, 'bundles') + await mkdir(outputRoot, { recursive: true }) + await writeFile( + resolve(consumerRoot, 'packed-base-entry.js'), + "import { defineChart, lineY } from '@tanstack/charts/universal'\nimport { Chart } from '@tanstack/react-native-charts'\nglobalThis.__tanstackChartsPackedBase = [defineChart, lineY, Chart]\n", + ) + + const entries = [ + { + entry: 'index.js', + name: 'bare', + platforms: ['ios', 'android'], + includesTooltip: true, + }, + { + entry: 'packed-base-entry.js', + name: 'bare-base', + platforms: ['ios'], + includesTooltip: false, + }, + ] + const bundles = [] + for (const entry of entries) { + for (const platform of entry.platforms) { + const output = resolve(outputRoot, `${entry.name}.${platform}.jsbundle`) + const sourceMap = resolve(outputRoot, `${entry.name}.${platform}.map`) + await run( + cli, + [ + 'bundle', + '--entry-file', + entry.entry, + '--platform', + platform, + '--dev', + 'false', + '--minify', + 'true', + '--bundle-output', + output, + '--sourcemap-output', + sourceMap, + '--config', + resolve(consumerRoot, 'metro.config.cjs'), + ], + consumerRoot, + ) + bundles.push({ + label: `Packed bare React Native ${entry.name === 'bare' ? '' : 'base '}${platform}`, + bundle: await readFile(output), + sourceMaps: [sourceMap], + includesTooltip: entry.includesTooltip, + }) + } + } + return bundles +} + +async function bundleExpoConsumer(consumerRoot) { + const cli = resolve(consumerRoot, 'node_modules/.bin/expo') + const bundles = [] + for (const platform of ['ios', 'android']) { + const outputRoot = resolve(consumerRoot, `dist-${platform}`) + await run( + cli, + [ + 'export', + '--platform', + platform, + '--output-dir', + outputRoot, + '--clear', + '--source-maps', + ], + consumerRoot, + { + CI: 'true', + EXPO_NO_TELEMETRY: '1', + }, + ) + const files = await walk(outputRoot) + const sourceMaps = files.filter((file) => file.endsWith('.map')) + assert.ok(sourceMaps.length, `Expo ${platform} emitted no source map`) + const bundlePath = await largestBundleFile(files) + bundles.push({ + label: `Packed Expo ${platform}`, + bundle: await readFile(bundlePath), + sourceMaps, + includesTooltip: true, + }) + } + return bundles +} + +async function largestBundleFile(files) { + const candidates = files.filter((file) => /\.(?:js|hbc|bundle)$/.test(file)) + assert.ok(candidates.length, 'Expo emitted no JavaScript or Hermes bundle') + const measured = await Promise.all( + candidates.map(async (file) => ({ file, size: (await stat(file)).size })), + ) + measured.sort((left, right) => right.size - left.size) + return measured[0].file +} + +async function readSourceMapSources(sourceMaps) { + const sources = [] + for (const sourceMap of sourceMaps) { + const parsed = JSON.parse(await readFile(sourceMap, 'utf8')) + sources.push(...(parsed.sources ?? []).map(normalize)) + } + return sources +} + +function assertPackedNativeBoundary(label, sources, includesTooltip) { + const requiredSources = [ + '/@tanstack/react-native-charts/dist/index.native.js', + '/@tanstack/charts/dist/universal.js', + ] + if (includesTooltip) { + requiredSources.push( + '/@tanstack/react-native-charts/dist/tooltip-entry.native.js', + '/@tanstack/react-native-charts/dist/Tooltip.js', + ) + } + for (const required of requiredSources) { + assert.ok( + sources.some((source) => source.includes(required)), + `${label} did not include packed ${required}`, + ) + } + if (!includesTooltip) { + const optionalTooltipSources = sources.filter( + (source) => + source.includes( + '/@tanstack/react-native-charts/dist/tooltip-entry.native.js', + ) || source.includes('/@tanstack/react-native-charts/dist/Tooltip.js'), + ) + assert.deepEqual( + optionalTooltipSources, + [], + `${label} retained the optional tooltip entry`, + ) + } + const leakedSource = sources.filter( + (source) => + source.includes('/packages/react-native-charts/src/') || + source.includes('/packages/charts-core/src/') || + source.includes('/@tanstack/react-native-charts/src/') || + source.includes('/@tanstack/charts/src/'), + ) + assert.deepEqual(leakedSource, [], `${label} resolved workspace source`) + assertSinglePackedPackage(label, sources, '@tanstack/react-native-charts') + assertSinglePackedPackage(label, sources, '@tanstack/charts') + const forbidden = sources.filter((source) => + forbiddenNativeSources.some((candidate) => source.includes(candidate)), + ) + assert.deepEqual(forbidden, [], `${label} crossed the browser boundary`) +} + +function assertSinglePackedPackage(label, sources, packageName) { + const marker = `/${packageName}/` + const packageSources = sources.filter((source) => source.includes(marker)) + assert.ok(packageSources.length, `${label} did not include ${packageName}`) + assert.ok( + packageSources.every((source) => source.includes(`${marker}dist/`)), + `${label} loaded a non-dist ${packageName} module`, + ) + const roots = new Set( + packageSources.map((source) => + source.slice(0, source.indexOf(marker) + marker.length - 1), + ), + ) + assert.equal(roots.size, 1, `${label} loaded multiple ${packageName} copies`) +} + +function requiredTarball(tarballs, packageName) { + const tarball = tarballs.get(packageName) + assert.ok(tarball, `Missing packed tarball for ${packageName}`) + return tarball +} + +async function walk(directory) { + const files = [] + for (const entry of await readdir(directory, { withFileTypes: true })) { + const path = resolve(directory, entry.name) + if (entry.isDirectory()) files.push(...(await walk(path))) + else files.push(path) + } + return files +} + +async function run(command, args, cwd, environment = {}) { + return execFileAsync(command, args, { + cwd, + env: { ...process.env, ...environment }, + maxBuffer: 20 * 1024 * 1024, + }) +} + +async function runAllowFailure(command, args, cwd) { + try { + const result = await run(command, args, cwd) + return { status: 0, output: `${result.stdout}${result.stderr}` } + } catch (error) { + return { + status: error.code ?? 1, + output: `${error.stdout ?? ''}${error.stderr ?? ''}`, + } + } +} + +function normalize(value) { + return value.replaceAll('\\', '/') +} diff --git a/scripts/release-package-config.mjs b/scripts/release-package-config.mjs index 7010fd0b..943f42c9 100644 --- a/scripts/release-package-config.mjs +++ b/scripts/release-package-config.mjs @@ -12,6 +12,7 @@ export const releasePackageConfigs = [ ['charts-core', '@tanstack/charts'], ['charts-scales', '@tanstack/charts-scales'], ['react-charts', '@tanstack/react-charts'], + ['react-native-charts', '@tanstack/react-native-charts'], ['octane-charts', '@tanstack/octane-charts'], ['preact-charts', '@tanstack/preact-charts'], ['vue-charts', '@tanstack/vue-charts'], diff --git a/scripts/release-workflow.test.mjs b/scripts/release-workflow.test.mjs index b04e11a1..5540ce92 100644 --- a/scripts/release-workflow.test.mjs +++ b/scripts/release-workflow.test.mjs @@ -32,6 +32,7 @@ describe('release workflow contract', () => { '@tanstack/charts', '@tanstack/charts-scales', '@tanstack/react-charts', + '@tanstack/react-native-charts', '@tanstack/octane-charts', '@tanstack/preact-charts', '@tanstack/vue-charts', From 9037ce1c1eb09492fbe499a3dc40fd2aa25720cf Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Fri, 31 Jul 2026 19:45:24 -0600 Subject: [PATCH 4/5] Allow packed consumers to fetch metadata --- scripts/packed-react-native-consumers.mjs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/packed-react-native-consumers.mjs b/scripts/packed-react-native-consumers.mjs index 26f5e074..7be594ba 100644 --- a/scripts/packed-react-native-consumers.mjs +++ b/scripts/packed-react-native-consumers.mjs @@ -197,17 +197,14 @@ async function installConsumer(consumerRoot, repositoryRoot) { 'pnpm', [ 'install', - '--offline', + '--prefer-offline', '--ignore-scripts', '--frozen-lockfile=false', '--store-dir', resolve(modulesState.storeDir, '..'), ], consumerRoot, - { - CI: 'true', - npm_config_offline: 'true', - }, + { CI: 'true' }, ) } From 1d63a116888d269312e3a927dc3ebe1747468db6 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Sat, 1 Aug 2026 12:32:08 -0600 Subject: [PATCH 5/5] Prepare React Native adapter for release --- .gitignore | 1 + API-FRICTION.md | 55 +++++++++++-------- REACT-NATIVE-HOST-POC.md | 28 ++++++---- benchmarks/comparison/bundle-baseline.json | 6 +- docs/comparison.md | 13 +++-- docs/installation.md | 6 +- packages/charts-core/docs/comparison.md | 13 +++-- packages/charts-core/docs/installation.md | 6 +- packages/react-native-charts/CHANGELOG.md | 9 +++ packages/react-native-charts/README.md | 7 ++- packages/react-native-charts/package.json | 2 +- .../react-native-charts/src/Tooltip.test.ts | 55 ++++++++++++++++++- packages/react-native-charts/src/Tooltip.tsx | 14 +++++ scripts/sync-release-version.mjs | 2 +- 14 files changed, 155 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index 075a9272..0c18d993 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ dist .benchmark-output .catalog-artifact .release-artifacts +.expo/ .nx/cache .nx/workspace-data coverage diff --git a/API-FRICTION.md b/API-FRICTION.md index ec111e23..119cf02f 100644 --- a/API-FRICTION.md +++ b/API-FRICTION.md @@ -5,7 +5,7 @@ observed difficulty from examples, production migrations, tests, and agent evaluations so later API, documentation, and TanStack Intent skill work is based on evidence. -Last updated: 2026-07-31 +Last updated: 2026-08-01 ## Triage rule @@ -202,14 +202,14 @@ Each entry records: | F-164 | Sankey widths required a custom scene renderer | API | resolved | | F-165 | Incidental D3 utilities leaked into core paths | API/Tooling | resolved | | F-166 | Grouped tooltip order diverged from mark position | API | resolved | -| F-166 | D3 declarations require a browser image global | Tooling | monitoring | -| F-167 | Native interaction copied DOM-renderer policy | API | monitoring | -| F-168 | CSS theme defaults reach the native scene compiler | API | monitoring | -| F-169 | Text measurement omits native typography | API | monitoring | -| F-170 | Packed declarations assume one platform global set | Tooling | resolved | -| F-171 | Metro skipped the fixture-owned Babel runtime | Tooling | resolved | -| F-172 | Metro retained the complete universal barrel | API/Tooling | monitoring | -| F-173 | OIDC release cannot claim a new npm package name | Tooling | monitoring | +| F-167 | D3 declarations require a browser image global | Tooling | monitoring | +| F-168 | Native interaction copied DOM-renderer policy | API | monitoring | +| F-169 | CSS theme defaults reach the native scene compiler | API | monitoring | +| F-170 | Text measurement omits native typography | API | monitoring | +| F-171 | Packed declarations assume one platform global set | Tooling | resolved | +| F-172 | Metro skipped the fixture-owned Babel runtime | Tooling | resolved | +| F-173 | Metro retained the complete universal barrel | API/Tooling | monitoring | +| F-174 | OIDC release cannot claim a new npm package name | Tooling | monitoring | ## Findings @@ -3767,7 +3767,7 @@ Each entry records: Native tooltip adds 3,381 bytes; portal adds 806 more. Retained-output graph checks prove base renderer and React entries contain none of the tooltip, portal, or React rich-body modules. The React Native base host is 10,468 gzip - bytes and adding its tooltip subpath costs 1,923 bytes; retained-input checks + bytes and adding its tooltip subpath costs 1,990 bytes; retained-input checks prove both the base host and line consumer omit `Tooltip.tsx`, all native entries omit web tooltip and portal code, and the base host retains no D3 runtime. Core, Lit, @@ -4022,7 +4022,7 @@ Each entry records: - Verification: runtime tests cover both axes with input and color-domain order opposed to the rendered mark order. -### F-166 — D3 declarations require a browser image global +### F-167 — D3 declarations require a browser image global - Status: monitoring - Severity: medium @@ -4040,7 +4040,7 @@ Each entry records: `@types/d3-array` diagnostics or a clean result after the upstream declaration is fixed. It rejects every other diagnostic. -### F-167 — Native interaction copied DOM-renderer policy +### F-168 — Native interaction copied DOM-renderer policy - Status: monitoring - Severity: high @@ -4065,6 +4065,9 @@ Each entry records: overlays, tooltips, and external callbacks attached to old point objects after responsive geometry changed. Callback prop identity could also retrigger restoration and incorrectly change the focus source. + Restacking onto the visual grouped-tooltip ordering change then exposed the + same drift again: the DOM host defaulted to visual order while the native + copy still used color-domain order. - Current decision: keep the duplication confined to the private proof. The native adapter exports a branded extension from its optional `/tooltip` subpath, accepts duplicate package copies and custom native implementations, @@ -4093,9 +4096,10 @@ Each entry records: regression verifies inactive focus-layer paint is absent from the native scene. Component regressions cover a primary point that sorts after another series, restored coordinates and callbacks after resize, and stable focus - source when only callback props change. + source when only callback props change. A grouped-tooltip regression now + verifies visual default order and explicit color-domain order in both hosts. -### F-168 — CSS theme defaults reach the native scene compiler +### F-169 — CSS theme defaults reach the native scene compiler - Status: monitoring - Severity: high @@ -4114,7 +4118,7 @@ Each entry records: variable or `currentColor` output. Device themes and dynamic native-theme builders remain unverified. -### F-169 — Text measurement omits native typography +### F-170 — Text measurement omits native typography - Status: monitoring - Severity: high @@ -4131,7 +4135,7 @@ Each entry records: - Verification: injected-measurer core tests pass. No iOS or Android font-scale and clipping matrix has been run. -### F-170 — Packed declarations assume one platform global set +### F-171 — Packed declarations assume one platform global set - Status: resolved - Severity: medium @@ -4140,7 +4144,7 @@ Each entry records: - Friction: the existing packed fixture compiles web packages under DOM libraries. Loading React Native declarations in that same TypeScript program introduces incompatible duplicate globals. Removing DOM libraries makes the - web contracts invalid and also exposes F-166. + web contracts invalid and also exposes F-167. - Decision: build and pack the native adapter in the release artifact matrix, but keep its declarations and consumers outside the DOM fixture's TypeScript program. The package publishes compiled ESM and declarations with `types`, @@ -4155,9 +4159,12 @@ Each entry records: typecheck and produce iOS and Android bundles. All four source maps resolve the adapter and `/universal` from installed `dist`, include the native conditional entries, exclude workspace source and guarded browser modules, - and retain only F-166's two known strict dependency diagnostics. + and retain only F-167's two known strict dependency diagnostics. Separately, + the workspace Expo 57 fixture boots in Expo Go on an iOS simulator and + renders its chart under Hermes; the packed artifact has not been run on that + simulator. -### F-171 — Metro skipped the fixture-owned Babel runtime +### F-172 — Metro skipped the fixture-owned Babel runtime - Status: resolved - Severity: medium @@ -4177,7 +4184,7 @@ Each entry records: variants require `/universal`, and source-map checks exclude every guarded browser implementation module. -### F-172 — Metro retained the complete universal barrel +### F-173 — Metro retained the complete universal barrel - Status: monitoring - Severity: medium @@ -4195,11 +4202,11 @@ Each entry records: own imports granular, publish granular entries as the bundle-sensitive path, and do not describe the broad barrel as cost-equivalent under Metro. - Verification: the iOS and Android full-chart bundles require - `packages/charts-core/src/universal.ts`, measure 102.94 and 102.99 KiB gzip over + `packages/charts-core/src/universal.ts`, measure 103.00 and 103.05 KiB gzip over blank respectively, and exclude DOM hosts, browser adapters, Canvas, reconciliation, SVG resources/surface, web tooltip code, and `react-dom`. -### F-173 — OIDC release cannot claim a new npm package name +### F-174 — OIDC release cannot claim a new npm package name - Status: monitoring - Severity: high @@ -4211,9 +4218,9 @@ Each entry records: authorized for this package before its registry entry exists. - Current decision: keep the package in release artifacts and the fixed changeset, but require a maintainer-controlled direct public publish of the - checked `0.3.1` tarball. Configure the repository's release workflow as the + checked `0.4.0` tarball. Configure the repository's release workflow as the trusted publisher immediately afterward; the aggregate changeset can then - publish `0.4.0` through OIDC. + publish `0.5.0` through OIDC. - Verification: `npm view @tanstack/react-native-charts` currently returns `E404`. Close this entry only after the public package exists, its trusted publisher names the repository release workflow, and an aggregate release diff --git a/REACT-NATIVE-HOST-POC.md b/REACT-NATIVE-HOST-POC.md index fb1d46bd..1f1026dd 100644 --- a/REACT-NATIVE-HOST-POC.md +++ b/REACT-NATIVE-HOST-POC.md @@ -124,7 +124,7 @@ external in the native entries. | Entry | Minified | Gzip | | ---------------------------------- | -------: | -------: | | React Native SVG host | 26.95 kB | 10.22 kB | -| React Native SVG host with tooltip | 32.50 kB | 12.10 kB | +| React Native SVG host with tooltip | 32.71 kB | 12.17 kB | | React Native line consumer | 49.18 kB | 19.03 kB | | Shared line scene | 38.17 kB | 14.82 kB | | Existing React web adapter | 39.98 kB | 14.57 kB | @@ -133,7 +133,7 @@ external in the native entries. The native host entry includes the host plus every shared runtime and D3 module reachable from exporting `Chart`; it is not isolated adapter-only overhead. The base host and line consumer omit `Tooltip.tsx`. Importing the tooltip -subpath adds 5.55 kB minified and 1.88 kB gzip. The native line consumer +subpath adds 5.76 kB minified and 1.94 kB gzip. The native line consumer additionally includes the line mark and D3 scale code while leaving platform peers external. It is the closest comparison to the existing React line entry, but the two platforms do not have identical runtime baselines. The native @@ -148,12 +148,12 @@ granular entries. | Platform | Full `/universal` chart minified JS delta | `react-native-svg` gzip delta | Core line gzip delta | Full `/universal` chart gzip delta | Full chart module delta | | -------- | ----------------------------------------: | ----------------------------: | -------------------: | ---------------------------------: | ----------------------: | -| iOS | 434.28 KiB | 27.75 KiB | 38.95 KiB | 102.94 KiB | 384 | -| Android | 434.42 KiB | 27.69 KiB | 38.94 KiB | 102.99 KiB | 384 | +| iOS | 434.49 KiB | 27.75 KiB | 38.94 KiB | 103.00 KiB | 384 | +| Android | 434.64 KiB | 27.69 KiB | 38.94 KiB | 103.05 KiB | 384 | -The full iOS bundle was 1,328,782 bytes and 319,792 bytes gzip, versus 884,080 -and 214,381 for blank. Android was 1,334,298 and 320,860, versus 889,448 and -215,395 for blank. Compared with the otherwise identical granular fixture, +The full iOS bundle was 1,328,999 bytes and 319,853 bytes gzip, versus 884,080 +and 214,383 for blank. Android was 1,334,515 and 320,921, versus 889,448 and +215,397 for blank. Compared with the otherwise identical granular fixture, `/universal` retains another 119.06 KiB minified and 28.91 KiB gzip on both iOS and Android, plus 102 modules per platform under this Metro version. @@ -313,7 +313,7 @@ files rather than workspace source. ## Verification performed -- 21 focused POC tests cover every scene primitive, gradients, clips, paint +- 22 focused POC tests cover every scene primitive, gradients, clips, paint resolution, focus modes, point and callback restoration, tooltip ordering, placement, chart compilation, extension ownership, inactive focus layers, and no-speculative-size behavior. Component mapping tests use React DOM with @@ -332,6 +332,11 @@ files rather than workspace source. - Packed bare React Native and Expo consumers produce iOS and Android bundles without workspace aliases. Their source maps include the native conditional entries and exclude workspace source and guarded browser modules. +- The workspace Expo 57 fixture boots in Expo Go on an iOS simulator and + renders its axes and line. Expo logs identify the Hermes engine, bytecode + transform, and running application. The packed artifact is compiled + separately; this smoke does not claim that the tarball itself ran in the + simulator. - Source-map gates prove the full native entries do not include guarded browser implementation files, including the web tooltip and portal runtimes. - Retained-input gates prove the base native host and line consumer omit the @@ -353,14 +358,15 @@ local spike command rather than a mandatory CI gate. Not performed: -- simulator or physical-device rendering; +- bare React Native or Android simulator rendering, and physical-device + rendering; - native component interaction tests; - visual comparison against the conformance corpus; -- Hermes execution or profiling; +- Hermes release-mode execution or profiling; - 1k/10k-point interaction and memory tests; - release application binary comparison; - VoiceOver and TalkBack validation; -- Expo prebuild, simulator, or device validation; +- Expo prebuild or dev-client validation; - motion, export, or Skia implementation. ## Production path diff --git a/benchmarks/comparison/bundle-baseline.json b/benchmarks/comparison/bundle-baseline.json index 633c24a4..cfdc957e 100644 --- a/benchmarks/comparison/bundle-baseline.json +++ b/benchmarks/comparison/bundle-baseline.json @@ -1,8 +1,8 @@ { "schemaVersion": 3, - "generatedAt": "2026-08-01T17:40:25.541Z", + "generatedAt": "2026-08-01T18:25:10.144Z", "packageVersions": { - "tanstack": "0.3.1", + "tanstack": "0.4.0", "chartjs": "4.5.1", "echarts": "6.1.0", "recharts": "3.10.1", @@ -11,7 +11,7 @@ "sources": { "tanstack": { "kind": "workspace", - "revision": "d563eba5d295dc3ddf60eecd2d8a9bd418aaf635" + "revision": "1a8b888822bb94be75b6416979d671a04218fe02" }, "chartjs": { "kind": "package", diff --git a/docs/comparison.md b/docs/comparison.md index 6e9b7057..3ef0a70e 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -4,22 +4,22 @@ description: Compare TanStack Charts with measured and documentation-reviewed ch --- TanStack Charts `0.4.0` is a pre-alpha release. Its results on this page measure -the exact workspace source included in this release and pinned competitor -packages. This comparison records architectural differences and reproducible -evidence without turning untested behavior into a checkmark. +the current workspace source and pinned competitor packages. This comparison +records architectural differences and reproducible evidence without turning +untested behavior into a checkmark. ## Tested versions | Library | Package | Measured source | | -------------------------------------------------------------------------------------- | -------------------- | ------------------- | -| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `d563eba` | +| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `1a8b888` | | [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` | | [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` | | [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` | | [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` | The competitor versions are exact package pins, not latest versions inferred -at page render time. The measured TanStack workspace revision is `d563eba`. +at page render time. The measured TanStack workspace revision is `1a8b888`. ## Capability matrix @@ -170,7 +170,8 @@ Canvas composition while keeping D3 and state ownership explicit. ## Evidence and reproduction - [Standard comparison protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/README.md) -- [Tracked bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json) +- [Current tracked bundle baseline](https://github.com/TanStack/charts/blob/main/benchmarks/comparison/bundle-baseline.json) +- [0.4.0 tagged bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json) - [Stress protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/stress/README.md) - [Catalog conformance protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/conformance/README.md) diff --git a/docs/installation.md b/docs/installation.md index 1f893f03..809705c8 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -94,8 +94,10 @@ import { tooltip } from '@tanstack/react-native-charts/tooltip' ``` Packed tarballs are typechecked and bundled through default bare React Native -and Expo Metro configurations on iOS and Android. Simulator, physical-device, -gesture, visual, and screen-reader validation is not yet a support claim. +and Expo Metro configurations on iOS and Android. The workspace Expo 57 +fixture also renders in Expo Go on an iOS simulator. Bare-native and Android +simulators, physical devices, gestures, visual parity, and screen readers are +not yet support claims. ## Install the D3 modules you import diff --git a/packages/charts-core/docs/comparison.md b/packages/charts-core/docs/comparison.md index 6e9b7057..3ef0a70e 100644 --- a/packages/charts-core/docs/comparison.md +++ b/packages/charts-core/docs/comparison.md @@ -4,22 +4,22 @@ description: Compare TanStack Charts with measured and documentation-reviewed ch --- TanStack Charts `0.4.0` is a pre-alpha release. Its results on this page measure -the exact workspace source included in this release and pinned competitor -packages. This comparison records architectural differences and reproducible -evidence without turning untested behavior into a checkmark. +the current workspace source and pinned competitor packages. This comparison +records architectural differences and reproducible evidence without turning +untested behavior into a checkmark. ## Tested versions | Library | Package | Measured source | | -------------------------------------------------------------------------------------- | -------------------- | ------------------- | -| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `d563eba` | +| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `1a8b888` | | [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` | | [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` | | [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` | | [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` | The competitor versions are exact package pins, not latest versions inferred -at page render time. The measured TanStack workspace revision is `d563eba`. +at page render time. The measured TanStack workspace revision is `1a8b888`. ## Capability matrix @@ -170,7 +170,8 @@ Canvas composition while keeping D3 and state ownership explicit. ## Evidence and reproduction - [Standard comparison protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/README.md) -- [Tracked bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json) +- [Current tracked bundle baseline](https://github.com/TanStack/charts/blob/main/benchmarks/comparison/bundle-baseline.json) +- [0.4.0 tagged bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json) - [Stress protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/stress/README.md) - [Catalog conformance protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/conformance/README.md) diff --git a/packages/charts-core/docs/installation.md b/packages/charts-core/docs/installation.md index 1f893f03..809705c8 100644 --- a/packages/charts-core/docs/installation.md +++ b/packages/charts-core/docs/installation.md @@ -94,8 +94,10 @@ import { tooltip } from '@tanstack/react-native-charts/tooltip' ``` Packed tarballs are typechecked and bundled through default bare React Native -and Expo Metro configurations on iOS and Android. Simulator, physical-device, -gesture, visual, and screen-reader validation is not yet a support claim. +and Expo Metro configurations on iOS and Android. The workspace Expo 57 +fixture also renders in Expo Go on an iOS simulator. Bare-native and Android +simulators, physical devices, gestures, visual parity, and screen readers are +not yet support claims. ## Install the D3 modules you import diff --git a/packages/react-native-charts/CHANGELOG.md b/packages/react-native-charts/CHANGELOG.md index 3a498b1c..ef86d90b 100644 --- a/packages/react-native-charts/CHANGELOG.md +++ b/packages/react-native-charts/CHANGELOG.md @@ -1 +1,10 @@ # @tanstack/react-native-charts + +## 0.4.0 + +### Minor Changes + +- Add the initial experimental React Native SVG host with responsive scene + rendering, focus, selection, accessibility actions, and an optional native + tooltip entry. Ship compiled ESM and declarations verified in packed bare + React Native and Expo Metro consumers. diff --git a/packages/react-native-charts/README.md b/packages/react-native-charts/README.md index acb6a6ef..9eb34c90 100644 --- a/packages/react-native-charts/README.md +++ b/packages/react-native-charts/README.md @@ -52,6 +52,7 @@ export function RevenueChart() { ``` The package is tested with Expo 57 / React Native 0.86 and -`react-native-svg` 15.15.x. It remains experimental: simulator and physical -device visual, gesture, accessibility, and performance validation are still in -progress. +`react-native-svg` 15.15.x. The workspace fixture also renders in Expo Go on an +iOS simulator. It remains experimental: bare-native and Android simulators, +physical devices, gestures, accessibility, release builds, and performance +still need validation. diff --git a/packages/react-native-charts/package.json b/packages/react-native-charts/package.json index 0954ed49..9c0970c4 100644 --- a/packages/react-native-charts/package.json +++ b/packages/react-native-charts/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-native-charts", - "version": "0.3.1", + "version": "0.4.0", "private": false, "license": "MIT", "repository": { diff --git a/packages/react-native-charts/src/Tooltip.test.ts b/packages/react-native-charts/src/Tooltip.test.ts index 3789b715..ef2b1078 100644 --- a/packages/react-native-charts/src/Tooltip.test.ts +++ b/packages/react-native-charts/src/Tooltip.test.ts @@ -1,5 +1,6 @@ import * as React from 'react' import { renderToStaticMarkup } from 'react-dom/server' +import type { ColorValue } from 'react-native' import { describe, expect, it, vi } from 'vitest' import type { ChartPoint, @@ -12,6 +13,7 @@ import { placeNativeTooltip, resolveNativeTooltipAnchor, } from './Tooltip' +import type { NativeChartTooltipRenderContext } from './Tooltip' vi.mock('react-native', () => ({ Text: 'span', @@ -163,12 +165,59 @@ describe('native tooltip model', () => { scales: currentScene.scales, }) }) + + it('orders grouped points visually unless color-domain order is requested', () => { + const right = point('alpha', 'Alpha', 4, { x: 80, xValue: 8, y: 20 }) + const left = point('beta', 'Beta', 4, { x: 20, xValue: 2, y: 20 }) + const focusedPoints = [right, left] + const currentScene = scene(focusedPoints) + const visualRender = vi.fn< + ( + context: NativeChartTooltipRenderContext, + ) => React.ReactNode + >(() => null) + const colorRender = vi.fn< + ( + context: NativeChartTooltipRenderContext, + ) => React.ReactNode + >(() => null) + const sharedProps = { + scene: currentScene, + width: 100, + height: 60, + points: focusedPoints, + pointer: null, + focusSource: 'keyboard' as const, + pinned: true, + color: '#111827', + resolvePaint: (value: ColorValue) => value, + dismiss: vi.fn(), + } + + renderToStaticMarkup( + React.createElement(NativeChartTooltip, { + ...sharedProps, + render: visualRender, + }), + ) + renderToStaticMarkup( + React.createElement(NativeChartTooltip, { + ...sharedProps, + options: { sort: 'color-domain' }, + render: colorRender, + }), + ) + + expect(visualRender.mock.calls[0]?.[0].points).toEqual([left, right]) + expect(colorRender.mock.calls[0]?.[0].points).toEqual([right, left]) + }) }) function point( key: string, groupLabel: string, yValue: number, + position: { x?: number; xValue?: number; y?: number } = {}, ): ChartPoint { return { key, @@ -177,10 +226,10 @@ function point( groupLabel, datum: null, datumIndex: 0, - xValue: 1, + xValue: position.xValue ?? 1, yValue, - x: 20, - y: yValue * 4, + x: position.x ?? 20, + y: position.y ?? yValue * 4, color: key === 'alpha' ? '#2563eb' : '#f97316', } } diff --git a/packages/react-native-charts/src/Tooltip.tsx b/packages/react-native-charts/src/Tooltip.tsx index 0e369a4e..ba79ce0a 100644 --- a/packages/react-native-charts/src/Tooltip.tsx +++ b/packages/react-native-charts/src/Tooltip.tsx @@ -272,6 +272,20 @@ function orderTooltipPoints< ) { if (sort === 'focus') return [...points] if (typeof sort === 'function') return [...points].sort(sort) + if (sort !== 'color-domain') { + const first = points[0] + const sharedX = + first !== undefined && + points.every((point) => chartValueEqual(point.xValue, first.xValue)) + const sharedY = + first !== undefined && + points.every((point) => chartValueEqual(point.yValue, first.yValue)) + return [...points].sort((left, right) => + sharedY && !sharedX + ? left.x - right.x || left.y - right.y + : left.y - right.y || left.x - right.x, + ) + } return [...points].sort( (left, right) => colorOrder(scene, left.group) - colorOrder(scene, right.group), diff --git a/scripts/sync-release-version.mjs b/scripts/sync-release-version.mjs index 28fe56f9..3ff9b9d7 100644 --- a/scripts/sync-release-version.mjs +++ b/scripts/sync-release-version.mjs @@ -9,7 +9,7 @@ export const releaseVersionSources = [ { path: 'MARKETING.md', references: 6 }, { path: 'docs/overview.md', references: 1 }, { path: 'docs/installation.md', references: 1 }, - { path: 'docs/comparison.md', references: 5 }, + { path: 'docs/comparison.md', references: 6 }, ] export function changelogVersions(source) {