@jini-ai/ui 0.4.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/features/charts/browser.d.ts +39 -0
  3. package/dist/features/charts/browser.js +142 -0
  4. package/dist/features/charts/contract.d.ts +223 -0
  5. package/dist/features/charts/contract.js +21 -0
  6. package/dist/features/charts/index.d.ts +5 -0
  7. package/dist/features/charts/index.js +5 -0
  8. package/dist/features/charts/react.d.ts +27 -0
  9. package/dist/features/charts/react.js +73 -0
  10. package/dist/features/charts/registry.d.ts +35 -0
  11. package/dist/features/charts/registry.js +36 -0
  12. package/dist/features/charts/table.d.ts +14 -0
  13. package/dist/features/charts/table.js +60 -0
  14. package/dist/features/charts/wire.d.ts +88 -0
  15. package/dist/features/charts/wire.js +38 -0
  16. package/dist/features/interactive-ui/index.d.ts +3 -18
  17. package/dist/features/interactive-ui/index.js +12 -6
  18. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  19. package/dist/features/interactive-ui/manifests.d.ts +3 -3
  20. package/dist/features/interactive-ui/manifests.js +6 -6
  21. package/dist/features/interactive-ui/registry.d.ts +12 -10
  22. package/dist/features/interactive-ui/registry.js +8 -6
  23. package/dist/styles/variables.css +1 -1
  24. package/package.json +24 -11
  25. package/dist/features/interactive-ui/providers/recharts/bar-chart.d.ts +0 -8
  26. package/dist/features/interactive-ui/providers/recharts/bar-chart.js +0 -12
  27. package/dist/features/interactive-ui/providers/recharts/bar-chart.manifest.d.ts +0 -21
  28. package/dist/features/interactive-ui/providers/recharts/bar-chart.manifest.js +0 -18
  29. package/dist/features/interactive-ui/providers/recharts/chart-config.d.ts +0 -40
  30. package/dist/features/interactive-ui/providers/recharts/chart-config.js +0 -32
  31. package/dist/features/interactive-ui/providers/recharts/chart-tokens.d.ts +0 -49
  32. package/dist/features/interactive-ui/providers/recharts/chart-tokens.js +0 -39
  33. package/dist/features/interactive-ui/providers/recharts/chart.d.ts +0 -31
  34. package/dist/features/interactive-ui/providers/recharts/chart.js +0 -34
  35. package/dist/features/interactive-ui/providers/recharts/index.d.ts +0 -7
  36. package/dist/features/interactive-ui/providers/recharts/index.js +0 -7
  37. package/dist/features/interactive-ui/providers/recharts/line-chart.d.ts +0 -8
  38. package/dist/features/interactive-ui/providers/recharts/line-chart.js +0 -14
  39. package/dist/features/interactive-ui/providers/recharts/line-chart.manifest.d.ts +0 -20
  40. package/dist/features/interactive-ui/providers/recharts/line-chart.manifest.js +0 -17
  41. package/dist/features/interactive-ui/providers/recharts/pie-chart.d.ts +0 -10
  42. package/dist/features/interactive-ui/providers/recharts/pie-chart.js +0 -12
  43. package/dist/features/interactive-ui/providers/recharts/pie-chart.manifest.d.ts +0 -41
  44. package/dist/features/interactive-ui/providers/recharts/pie-chart.manifest.js +0 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @jini-ai/ui
2
2
 
3
+ ## 0.5.0 — 2026-10-13
4
+
5
+ - Add framework-neutral chart contracts, browser/table and React hosts, provider-defined kinds and legacy chart wire aliases. Extract Recharts implementations and peers into the private browser artifact; chart component export wrappers are removed (no external consumers found).
6
+
3
7
  ## 0.4.6 — 2026-10-08
4
8
 
5
9
  - parse5 optional peer widened to `^7.3.0 || ^8.0.1`: 0.4.5 required ^8 while @jini-ai/cms 0.5.3 requires ^7.3, so hosts with both hit ERESOLVE. The srcdoc builder and html-editor source splice typecheck against parse5 7.
@@ -0,0 +1,39 @@
1
+ /** Framework-free mounting, failure recovery and table fallback. No React imports. */
2
+ import { type ChartInstance, type ChartProvider, type ChartSpec, type ChartTheme } from './contract.js';
3
+ import { type ChartProviderRegistry } from './registry.js';
4
+ export { applyChartTheme, renderChartTable } from './table.js';
5
+ export interface MountChartOptions {
6
+ readonly theme?: ChartTheme;
7
+ readonly siteProvider?: string | undefined;
8
+ readonly onProviderError?: (input: {
9
+ provider: string;
10
+ error: unknown;
11
+ }) => void;
12
+ }
13
+ export interface MountedChart extends ChartInstance {
14
+ readonly ready: Promise<void>;
15
+ update(input: {
16
+ spec: ChartSpec;
17
+ theme?: ChartTheme;
18
+ }, options?: Record<string, never>): Promise<void>;
19
+ }
20
+ /** Dynamic import is native; the host supplies an admitted immutable module URL and loads its CSS
21
+ * at the rendering boundary. No manifest URL is itself a trust grant.
22
+ */
23
+ export declare function loadChartProvider({ url }: {
24
+ url: string;
25
+ }, { importModule }?: {
26
+ importModule?: (input: {
27
+ url: string;
28
+ }, options?: Record<string, never>) => Promise<unknown>;
29
+ }): Promise<ChartProvider>;
30
+ /** Mount a vanilla provider into its own child node, keeping data visible until ready. Updates and
31
+ * teardown invalidate pending loads so stale completions never attach to an unmounted host.
32
+ * @example mountChart({ element, spec, registry }, { siteProvider: 'plugin.recharts' })
33
+ */
34
+ export declare function mountChart({ element, spec, registry }: {
35
+ element: HTMLElement;
36
+ spec: ChartSpec;
37
+ registry: ChartProviderRegistry;
38
+ }, options?: MountChartOptions): MountedChart;
39
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1,142 @@
1
+ /** Framework-free mounting, failure recovery and table fallback. No React imports. */
2
+ import { DEFAULT_CHART_THEME } from './contract.js';
3
+ import { selectChartProviders } from './registry.js';
4
+ import { applyChartTheme, renderChartTable } from './table.js';
5
+ export { applyChartTheme, renderChartTable } from './table.js';
6
+ /** Dynamic import is native; the host supplies an admitted immutable module URL and loads its CSS
7
+ * at the rendering boundary. No manifest URL is itself a trust grant.
8
+ */
9
+ export async function loadChartProvider({ url }, { importModule = ({ url }) => import(/* @vite-ignore */ url) } = {}) {
10
+ const module = await importModule({ url });
11
+ if (typeof module?.mount !== 'function')
12
+ throw new TypeError('Chart provider must export mount.');
13
+ return module;
14
+ }
15
+ /** Mount a vanilla provider into its own child node, keeping data visible until ready. Updates and
16
+ * teardown invalidate pending loads so stale completions never attach to an unmounted host.
17
+ * @example mountChart({ element, spec, registry }, { siteProvider: 'plugin.recharts' })
18
+ */
19
+ export function mountChart({ element, spec, registry }, options = {}) {
20
+ const fallback = element.ownerDocument.createElement('div');
21
+ fallback.dataset.chartFallback = '';
22
+ const renderer = element.ownerDocument.createElement('div');
23
+ renderer.dataset.chartRenderer = '';
24
+ element.append(fallback, renderer);
25
+ let input = { spec, theme: options.theme ?? DEFAULT_CHART_THEME };
26
+ let active;
27
+ let generation = 0;
28
+ let revision = 0;
29
+ let destroyed = false;
30
+ const failed = new Set();
31
+ /** Provider errors never prevent other providers or the data table from remaining usable. */
32
+ function report(entry, error) {
33
+ try {
34
+ options.onProviderError?.({ provider: entry.id, error });
35
+ }
36
+ catch {
37
+ // A host diagnostic failure must not strand a renderer or hide the data fallback.
38
+ }
39
+ }
40
+ function dispose() {
41
+ const previous = active;
42
+ active = undefined;
43
+ if (previous) {
44
+ try {
45
+ previous.instance.destroy({});
46
+ }
47
+ catch (error) {
48
+ report(previous.entry, error);
49
+ }
50
+ }
51
+ renderer.replaceChildren();
52
+ fallback.hidden = false;
53
+ }
54
+ function showData() {
55
+ applyChartTheme({ element, theme: input.theme });
56
+ renderChartTable({ element: fallback, spec: input.spec });
57
+ fallback.hidden = false;
58
+ }
59
+ function candidates() {
60
+ return selectChartProviders({ registry, spec: input.spec }, { siteProvider: options.siteProvider }).filter(({ id }) => !failed.has(id));
61
+ }
62
+ /** Async renderer errors arrive after mount; defer teardown outside the provider's commit. */
63
+ function renderError(entry, error, token) {
64
+ queueMicrotask(() => {
65
+ if (destroyed || token !== generation || active?.entry.id !== entry.id)
66
+ return;
67
+ failed.add(entry.id);
68
+ report(entry, error);
69
+ generation++;
70
+ dispose();
71
+ void attempt(generation);
72
+ });
73
+ }
74
+ async function attempt(token) {
75
+ for (const entry of candidates()) {
76
+ let renderRevision = revision;
77
+ try {
78
+ const provider = await entry.load({});
79
+ if (destroyed || token !== generation)
80
+ return;
81
+ const frame = element.ownerDocument.createElement('div');
82
+ renderer.replaceChildren(frame);
83
+ renderRevision = revision;
84
+ const instance = provider.mount({ element: frame, ...input }, { onError: (error) => renderError(entry, error, token) });
85
+ active = { entry, instance };
86
+ await instance.ready;
87
+ if (destroyed || token !== generation || renderRevision !== revision)
88
+ return;
89
+ fallback.hidden = true;
90
+ return;
91
+ }
92
+ catch (error) {
93
+ if (destroyed || token !== generation || renderRevision !== revision)
94
+ return;
95
+ failed.add(entry.id);
96
+ report(entry, error);
97
+ dispose();
98
+ }
99
+ }
100
+ }
101
+ showData();
102
+ const ready = attempt(generation);
103
+ return {
104
+ ready,
105
+ async update({ spec: nextSpec, theme = input.theme }, _options = {}) {
106
+ if (destroyed)
107
+ return;
108
+ const updateRevision = ++revision;
109
+ input = { spec: nextSpec, theme };
110
+ showData();
111
+ const preferred = candidates()[0];
112
+ if (active && preferred?.id === active.entry.id) {
113
+ const current = active;
114
+ try {
115
+ await current.instance.update(input);
116
+ if (!destroyed && active === current && updateRevision === revision)
117
+ fallback.hidden = true;
118
+ return;
119
+ }
120
+ catch (error) {
121
+ if (destroyed || active !== current || updateRevision !== revision)
122
+ return;
123
+ failed.add(current.entry.id);
124
+ report(current.entry, error);
125
+ }
126
+ }
127
+ generation++;
128
+ dispose();
129
+ await attempt(generation);
130
+ },
131
+ destroy(_input = {}, _options = {}) {
132
+ if (destroyed)
133
+ return;
134
+ destroyed = true;
135
+ generation++;
136
+ dispose();
137
+ fallback.remove();
138
+ renderer.remove();
139
+ },
140
+ };
141
+ }
142
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1,223 @@
1
+ /** Framework-neutral chart data and vanilla provider ABI. Providers declare their own kinds. */
2
+ import { z } from 'zod';
3
+ export type ChartKind = 'bar' | 'line' | 'pie' | (string & {});
4
+ export type ChartValue = string | number | boolean | null | ChartValue[] | {
5
+ [key: string]: ChartValue;
6
+ };
7
+ /** Serializable, provider-neutral specification; kind admission belongs to each provider. */
8
+ export declare const chartSpecSchema: z.ZodObject<{
9
+ kind: z.ZodString;
10
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodType<ChartValue, z.ZodTypeDef, ChartValue>>, "many">;
11
+ categoryKey: z.ZodOptional<z.ZodString>;
12
+ series: z.ZodArray<z.ZodObject<{
13
+ key: z.ZodString;
14
+ label: z.ZodOptional<z.ZodString>;
15
+ color: z.ZodOptional<z.ZodString>;
16
+ }, "strict", z.ZodTypeAny, {
17
+ key: string;
18
+ label?: string | undefined;
19
+ color?: string | undefined;
20
+ }, {
21
+ key: string;
22
+ label?: string | undefined;
23
+ color?: string | undefined;
24
+ }>, "many">;
25
+ title: z.ZodOptional<z.ZodString>;
26
+ description: z.ZodOptional<z.ZodString>;
27
+ axes: z.ZodOptional<z.ZodObject<{
28
+ x: z.ZodOptional<z.ZodObject<{
29
+ label: z.ZodOptional<z.ZodString>;
30
+ format: z.ZodOptional<z.ZodObject<{
31
+ locale: z.ZodOptional<z.ZodString>;
32
+ notation: z.ZodOptional<z.ZodEnum<["standard", "compact"]>>;
33
+ }, "strict", z.ZodTypeAny, {
34
+ locale?: string | undefined;
35
+ notation?: "compact" | "standard" | undefined;
36
+ }, {
37
+ locale?: string | undefined;
38
+ notation?: "compact" | "standard" | undefined;
39
+ }>>;
40
+ }, "strict", z.ZodTypeAny, {
41
+ label?: string | undefined;
42
+ format?: {
43
+ locale?: string | undefined;
44
+ notation?: "compact" | "standard" | undefined;
45
+ } | undefined;
46
+ }, {
47
+ label?: string | undefined;
48
+ format?: {
49
+ locale?: string | undefined;
50
+ notation?: "compact" | "standard" | undefined;
51
+ } | undefined;
52
+ }>>;
53
+ y: z.ZodOptional<z.ZodObject<{
54
+ label: z.ZodOptional<z.ZodString>;
55
+ format: z.ZodOptional<z.ZodObject<{
56
+ locale: z.ZodOptional<z.ZodString>;
57
+ notation: z.ZodOptional<z.ZodEnum<["standard", "compact"]>>;
58
+ }, "strict", z.ZodTypeAny, {
59
+ locale?: string | undefined;
60
+ notation?: "compact" | "standard" | undefined;
61
+ }, {
62
+ locale?: string | undefined;
63
+ notation?: "compact" | "standard" | undefined;
64
+ }>>;
65
+ }, "strict", z.ZodTypeAny, {
66
+ label?: string | undefined;
67
+ format?: {
68
+ locale?: string | undefined;
69
+ notation?: "compact" | "standard" | undefined;
70
+ } | undefined;
71
+ }, {
72
+ label?: string | undefined;
73
+ format?: {
74
+ locale?: string | undefined;
75
+ notation?: "compact" | "standard" | undefined;
76
+ } | undefined;
77
+ }>>;
78
+ }, "strict", z.ZodTypeAny, {
79
+ x?: {
80
+ label?: string | undefined;
81
+ format?: {
82
+ locale?: string | undefined;
83
+ notation?: "compact" | "standard" | undefined;
84
+ } | undefined;
85
+ } | undefined;
86
+ y?: {
87
+ label?: string | undefined;
88
+ format?: {
89
+ locale?: string | undefined;
90
+ notation?: "compact" | "standard" | undefined;
91
+ } | undefined;
92
+ } | undefined;
93
+ }, {
94
+ x?: {
95
+ label?: string | undefined;
96
+ format?: {
97
+ locale?: string | undefined;
98
+ notation?: "compact" | "standard" | undefined;
99
+ } | undefined;
100
+ } | undefined;
101
+ y?: {
102
+ label?: string | undefined;
103
+ format?: {
104
+ locale?: string | undefined;
105
+ notation?: "compact" | "standard" | undefined;
106
+ } | undefined;
107
+ } | undefined;
108
+ }>>;
109
+ format: z.ZodOptional<z.ZodObject<{
110
+ locale: z.ZodOptional<z.ZodString>;
111
+ notation: z.ZodOptional<z.ZodEnum<["standard", "compact"]>>;
112
+ }, "strict", z.ZodTypeAny, {
113
+ locale?: string | undefined;
114
+ notation?: "compact" | "standard" | undefined;
115
+ }, {
116
+ locale?: string | undefined;
117
+ notation?: "compact" | "standard" | undefined;
118
+ }>>;
119
+ provider: z.ZodOptional<z.ZodString>;
120
+ }, "strict", z.ZodTypeAny, {
121
+ kind: string;
122
+ data: Record<string, ChartValue>[];
123
+ series: {
124
+ key: string;
125
+ label?: string | undefined;
126
+ color?: string | undefined;
127
+ }[];
128
+ title?: string | undefined;
129
+ provider?: string | undefined;
130
+ description?: string | undefined;
131
+ format?: {
132
+ locale?: string | undefined;
133
+ notation?: "compact" | "standard" | undefined;
134
+ } | undefined;
135
+ categoryKey?: string | undefined;
136
+ axes?: {
137
+ x?: {
138
+ label?: string | undefined;
139
+ format?: {
140
+ locale?: string | undefined;
141
+ notation?: "compact" | "standard" | undefined;
142
+ } | undefined;
143
+ } | undefined;
144
+ y?: {
145
+ label?: string | undefined;
146
+ format?: {
147
+ locale?: string | undefined;
148
+ notation?: "compact" | "standard" | undefined;
149
+ } | undefined;
150
+ } | undefined;
151
+ } | undefined;
152
+ }, {
153
+ kind: string;
154
+ data: Record<string, ChartValue>[];
155
+ series: {
156
+ key: string;
157
+ label?: string | undefined;
158
+ color?: string | undefined;
159
+ }[];
160
+ title?: string | undefined;
161
+ provider?: string | undefined;
162
+ description?: string | undefined;
163
+ format?: {
164
+ locale?: string | undefined;
165
+ notation?: "compact" | "standard" | undefined;
166
+ } | undefined;
167
+ categoryKey?: string | undefined;
168
+ axes?: {
169
+ x?: {
170
+ label?: string | undefined;
171
+ format?: {
172
+ locale?: string | undefined;
173
+ notation?: "compact" | "standard" | undefined;
174
+ } | undefined;
175
+ } | undefined;
176
+ y?: {
177
+ label?: string | undefined;
178
+ format?: {
179
+ locale?: string | undefined;
180
+ notation?: "compact" | "standard" | undefined;
181
+ } | undefined;
182
+ } | undefined;
183
+ } | undefined;
184
+ }>;
185
+ export type ChartSpec = Omit<z.infer<typeof chartSpecSchema>, 'kind'> & {
186
+ readonly kind: ChartKind;
187
+ };
188
+ /** CSS token names are common across providers; no library props cross this boundary. */
189
+ export interface ChartTheme {
190
+ readonly mode: 'light' | 'dark' | 'auto';
191
+ readonly tokens?: Readonly<Record<string, string>>;
192
+ }
193
+ export declare const DEFAULT_CHART_THEME: ChartTheme;
194
+ export interface ChartRenderInput {
195
+ readonly spec: ChartSpec;
196
+ readonly theme: ChartTheme;
197
+ }
198
+ export interface ChartMountOptions {
199
+ /** Reports errors occurring after mount returns (for example a React commit failure). */
200
+ readonly onError?: (error: unknown) => void;
201
+ }
202
+ export interface ChartInstance {
203
+ /** Hosts retain the fallback until an asynchronous first render completes. */
204
+ readonly ready?: Promise<void>;
205
+ update(input: ChartRenderInput, options?: Record<string, never>): void | Promise<void>;
206
+ destroy(input: Record<string, never>, options?: Record<string, never>): void;
207
+ }
208
+ export interface ChartProvider {
209
+ mount(input: ChartRenderInput & {
210
+ readonly element: HTMLElement;
211
+ }, options?: ChartMountOptions): ChartInstance;
212
+ }
213
+ export interface ChartProviderEntry {
214
+ readonly id: string;
215
+ readonly kinds: readonly ChartKind[];
216
+ readonly enabled: boolean;
217
+ /** Optional stricter admission, e.g. rejecting multi-series specs until implemented. */
218
+ readonly supports?: (input: {
219
+ readonly spec: ChartSpec;
220
+ }, options?: Record<string, never>) => boolean;
221
+ load(input: Record<string, never>, options?: Record<string, never>): Promise<ChartProvider>;
222
+ }
223
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1,21 @@
1
+ /** Framework-neutral chart data and vanilla provider ABI. Providers declare their own kinds. */
2
+ import { z } from 'zod';
3
+ const chartValueSchema = z.lazy(() => z.union([
4
+ z.string(), z.number().finite(), z.boolean(), z.null(), z.array(chartValueSchema), z.record(chartValueSchema),
5
+ ]));
6
+ const formatSchema = z.object({ locale: z.string().optional(), notation: z.enum(['standard', 'compact']).optional() }).strict();
7
+ const axisSchema = z.object({ label: z.string().optional(), format: formatSchema.optional() }).strict();
8
+ /** Serializable, provider-neutral specification; kind admission belongs to each provider. */
9
+ export const chartSpecSchema = z.object({
10
+ kind: z.string().min(1),
11
+ data: z.array(z.record(chartValueSchema)),
12
+ categoryKey: z.string().optional(),
13
+ series: z.array(z.object({ key: z.string(), label: z.string().optional(), color: z.string().optional() }).strict()),
14
+ title: z.string().optional(),
15
+ description: z.string().optional(),
16
+ axes: z.object({ x: axisSchema.optional(), y: axisSchema.optional() }).strict().optional(),
17
+ format: formatSchema.optional(),
18
+ provider: z.string().min(1).optional(),
19
+ }).strict();
20
+ export const DEFAULT_CHART_THEME = { mode: 'auto' };
21
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1,5 @@
1
+ /** Headless chart contracts, schemas, theme tokens and registry selection (no React or DOM effects). */
2
+ export * from './contract.js';
3
+ export * from './registry.js';
4
+ export * from './wire.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** Headless chart contracts, schemas, theme tokens and registry selection (no React or DOM effects). */
2
+ export * from './contract.js';
3
+ export * from './registry.js';
4
+ export * from './wire.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,27 @@
1
+ /** The only React adapter for the vanilla chart lifecycle; providers own any internal roots. */
2
+ import { type ReactElement } from 'react';
3
+ import { InteractiveUiRegistry } from '../interactive-ui/registry.js';
4
+ import { type ChartSpec, type ChartTheme } from './contract.js';
5
+ import { type MountChartOptions } from './browser.js';
6
+ import { type ChartProviderRegistry } from './registry.js';
7
+ export interface ChartHostProps {
8
+ readonly spec: ChartSpec;
9
+ readonly registry: ChartProviderRegistry;
10
+ readonly theme?: ChartTheme;
11
+ readonly siteProvider?: string | undefined;
12
+ readonly onProviderError?: MountChartOptions['onProviderError'];
13
+ }
14
+ /** React owns only the container; mountChart owns its descendants and lifecycle. */
15
+ export declare function ChartHost({ spec, registry, theme, siteProvider, onProviderError }: ChartHostProps): ReactElement;
16
+ /** Create a snapshot for validation AND rendering. Resolve each legacy alias through its specific
17
+ * capability, then copy its wire id onto that same entry (same schema and Component).
18
+ * @example createChartInteractiveRegistry({ registry: base, providers }, { siteProvider: 'plugin.recharts' })
19
+ */
20
+ export declare function createChartInteractiveRegistry({ registry, providers }: {
21
+ registry: InteractiveUiRegistry;
22
+ providers: ChartProviderRegistry;
23
+ }, options?: {
24
+ siteProvider?: string | undefined;
25
+ theme?: ChartTheme;
26
+ }): InteractiveUiRegistry;
27
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /** The only React adapter for the vanilla chart lifecycle; providers own any internal roots. */
3
+ import { useEffect, useRef } from 'react';
4
+ import { z } from 'zod';
5
+ import { InteractiveUiRegistry } from '../interactive-ui/registry.js';
6
+ import { chartSpecSchema, DEFAULT_CHART_THEME } from './contract.js';
7
+ import { mountChart } from './browser.js';
8
+ import { chartCapability, chartProvidersByKind } from './registry.js';
9
+ import { chartWireManifests, legacyChartSpec } from './wire.js';
10
+ /** React owns only the container; mountChart owns its descendants and lifecycle. */
11
+ export function ChartHost({ spec, registry, theme = DEFAULT_CHART_THEME, siteProvider, onProviderError }) {
12
+ const element = useRef(null);
13
+ const instance = useRef(undefined);
14
+ const previous = useRef({ spec, theme });
15
+ useEffect(() => {
16
+ if (!element.current)
17
+ return;
18
+ const mounted = mountChart({ element: element.current, spec, registry }, {
19
+ theme, siteProvider, ...(onProviderError ? { onProviderError } : {}),
20
+ });
21
+ instance.current = mounted;
22
+ previous.current = { spec, theme };
23
+ return () => { mounted.destroy({}); instance.current = undefined; };
24
+ // Registry snapshots and site defaults define a lifecycle. Data/theme changes use update below.
25
+ }, [registry, siteProvider, onProviderError]);
26
+ useEffect(() => {
27
+ if (previous.current.spec === spec && previous.current.theme === theme)
28
+ return;
29
+ previous.current = { spec, theme };
30
+ void instance.current?.update({ spec, theme });
31
+ }, [spec, theme]);
32
+ return _jsx("div", { ref: element, className: "jini-chart-host" });
33
+ }
34
+ /** Known wire kinds use the established shapes. Other providers register spec-based entries without
35
+ * adding fields or kinds to the core grammar. This closure is built once per host snapshot.
36
+ */
37
+ function chartComponent(kind, providers, options) {
38
+ return function RegisteredChart(props) {
39
+ const legacyKind = kind === 'bar' ? 'bar' : kind === 'line' ? 'line' : kind === 'pie' ? 'pie' : undefined;
40
+ const spec = legacyKind ? legacyChartSpec({ kind: legacyKind, props }) : chartSpecSchema.parse(props.spec);
41
+ return _jsx(ChartHost, { spec: spec, registry: providers, ...options });
42
+ };
43
+ }
44
+ /** Create a snapshot for validation AND rendering. Resolve each legacy alias through its specific
45
+ * capability, then copy its wire id onto that same entry (same schema and Component).
46
+ * @example createChartInteractiveRegistry({ registry: base, providers }, { siteProvider: 'plugin.recharts' })
47
+ */
48
+ export function createChartInteractiveRegistry({ registry, providers }, options = {}) {
49
+ const kinds = [...new Set(['bar', 'line', 'pie', ...providers.list().flatMap(({ kinds }) => kinds)])];
50
+ const entries = [];
51
+ for (const kind of kinds) {
52
+ const capability = chartCapability({ kind });
53
+ const wire = chartWireManifests.find((manifest) => manifest.capabilities.includes(capability));
54
+ const Component = chartComponent(kind, providers, options);
55
+ const propsSchema = wire?.propsSchema ?? z.object({ spec: chartSpecSchema.extend({ kind: z.literal(kind) }) }).passthrough();
56
+ const selected = chartProvidersByKind({ registry: providers, kind }, options);
57
+ for (const provider of selected)
58
+ entries.push({
59
+ id: `${provider.id}.${capability}`, provider: provider.id, capabilities: ['chart', capability, 'graph'], propsSchema, Component,
60
+ });
61
+ if (wire)
62
+ entries.push({ ...wire, id: `core.table.${capability}`, Component });
63
+ }
64
+ const existing = registry.list().filter(({ capabilities }) => !capabilities.includes('chart'));
65
+ let snapshot = new InteractiveUiRegistry({ entries: [...entries, ...existing] });
66
+ for (const wire of chartWireManifests) {
67
+ const capability = wire.capabilities.find((capability) => capability.endsWith('-chart'));
68
+ const selected = snapshot.resolveByCapability({ capability })[0];
69
+ snapshot = snapshot.register({ entry: { ...selected, id: wire.id } });
70
+ }
71
+ return snapshot;
72
+ }
73
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1,35 @@
1
+ import { InteractiveUiRegistry } from '../interactive-ui/registry.js';
2
+ import type { InteractiveComponentManifest } from '../interactive-ui/types.js';
3
+ import type { ChartKind, ChartProviderEntry, ChartSpec } from './contract.js';
4
+ export type RegisteredChartProvider = ChartProviderEntry & InteractiveComponentManifest;
5
+ export type ChartProviderRegistry = InteractiveUiRegistry<RegisteredChartProvider>;
6
+ /** Each kind has a distinct capability, so a pie-only provider can never satisfy a bar request. */
7
+ export declare function chartCapability({ kind }: {
8
+ kind: ChartKind;
9
+ }, _options?: Record<string, never>): string;
10
+ /** Register providers in host-supplied preference order, reusing immutable replacement by id.
11
+ * @example createChartProviderRegistry({ providers: admittedProviders })
12
+ */
13
+ export declare function createChartProviderRegistry({ providers }: {
14
+ providers: readonly ChartProviderEntry[];
15
+ }, _options?: Record<string, never>): ChartProviderRegistry;
16
+ /** Apply the two explicit pins to the registry's capability order. Both catalog snapshots and
17
+ * runtime rendering use this owner; catalog construction never probes supports with invented data.
18
+ */
19
+ export declare function chartProvidersByKind({ registry, kind }: {
20
+ registry: ChartProviderRegistry;
21
+ kind: ChartKind;
22
+ }, { provider, siteProvider }?: {
23
+ provider?: string | undefined;
24
+ siteProvider?: string | undefined;
25
+ }): readonly RegisteredChartProvider[];
26
+ /** Skip unsupported specs after ordering. The browser supplies the final core table when this
27
+ * chain exhausts; provider capability declarations can include any non-empty kind.
28
+ */
29
+ export declare function selectChartProviders({ registry, spec }: {
30
+ registry: ChartProviderRegistry;
31
+ spec: ChartSpec;
32
+ }, { siteProvider }?: {
33
+ siteProvider?: string | undefined;
34
+ }): readonly RegisteredChartProvider[];
35
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1,36 @@
1
+ /** Capability ordering belongs to InteractiveUiRegistry, including framework-neutral entries. */
2
+ import { z } from 'zod';
3
+ import { InteractiveUiRegistry } from '../interactive-ui/registry.js';
4
+ /** Each kind has a distinct capability, so a pie-only provider can never satisfy a bar request. */
5
+ export function chartCapability({ kind }, _options = {}) {
6
+ return `${kind}-chart`;
7
+ }
8
+ /** Register providers in host-supplied preference order, reusing immutable replacement by id.
9
+ * @example createChartProviderRegistry({ providers: admittedProviders })
10
+ */
11
+ export function createChartProviderRegistry({ providers }, _options = {}) {
12
+ let registry = new InteractiveUiRegistry({ entries: [] });
13
+ for (const provider of providers) {
14
+ registry = registry.register({ entry: {
15
+ ...provider, provider: provider.id, kinds: Object.freeze([...provider.kinds]),
16
+ capabilities: provider.kinds.map((kind) => chartCapability({ kind })), propsSchema: z.object({}),
17
+ } });
18
+ }
19
+ return registry;
20
+ }
21
+ /** Apply the two explicit pins to the registry's capability order. Both catalog snapshots and
22
+ * runtime rendering use this owner; catalog construction never probes supports with invented data.
23
+ */
24
+ export function chartProvidersByKind({ registry, kind }, { provider, siteProvider } = {}) {
25
+ const candidates = registry.resolveByCapability({ capability: chartCapability({ kind }) }).filter((entry) => entry.enabled);
26
+ const pinned = [provider, siteProvider].flatMap((id) => candidates.filter((entry) => entry.id === id));
27
+ return [...new Set([...pinned, ...candidates])];
28
+ }
29
+ /** Skip unsupported specs after ordering. The browser supplies the final core table when this
30
+ * chain exhausts; provider capability declarations can include any non-empty kind.
31
+ */
32
+ export function selectChartProviders({ registry, spec }, { siteProvider } = {}) {
33
+ return chartProvidersByKind({ registry, kind: spec.kind }, { provider: spec.provider, siteProvider })
34
+ .filter((entry) => entry.supports?.({ spec }) ?? true);
35
+ }
36
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,14 @@
1
+ import type { ChartSpec, ChartTheme } from './contract.js';
2
+ /** Apply only chart tokens; a provider cannot use theme input to style unrelated host chrome. */
3
+ export declare function applyChartTheme({ element, theme }: {
4
+ element: HTMLElement;
5
+ theme: ChartTheme;
6
+ }, _options?: Record<string, never>): void;
7
+ /** Keep every row/key, including data from unsupported kinds. textContent supplies escaping;
8
+ * never feed agent data to innerHTML. Shared table CSS is already loaded at the admin boundary.
9
+ */
10
+ export declare function renderChartTable({ element, spec }: {
11
+ element: HTMLElement;
12
+ spec: ChartSpec;
13
+ }, _options?: Record<string, never>): void;
14
+ //# sourceMappingURL=table.d.ts.map