@amritanshu3011/mdx-renderer 1.0.9 → 1.0.11

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.
package/README.md CHANGED
@@ -1,142 +1,236 @@
1
+
1
2
  ```markdown
2
3
  # MDX Renderer
3
4
 
4
- A robust, theme-able visualization and MDX rendering system for React applications. It supports both direct MDX file rendering and programmatic visualization injection (Intent-based UI).
5
+ A flexible, extensible rendering engine for React. It transforms data (JSON) and MDX content into rich, interactive UI components.
6
+
7
+ Designed for **Data-Driven UI**, it allows you to render specific components dynamically based on backend responses, while giving you the power to inject your own custom components or override built-in ones.
5
8
 
6
- ## Installation
9
+ ## 📦 Installation
7
10
 
8
11
  ```bash
9
- npm install @amritanshu3011/mdx-renderer
12
+ npm install @amritanshu3011/mdx-renderer echarts recharts lucide-react
13
+
14
+ ```
15
+
16
+ ### ⚠️ Import Styles
17
+
18
+ You **must** import the base CSS in your application's entry point (e.g., `main.jsx` or `App.jsx`) for components to render correctly.
19
+
20
+ ```javascript
21
+ import '@amritanshu3011/mdx-renderer/styles/base.css';
10
22
 
11
23
  ```
12
24
 
13
- ## 1. Intent-Based Usage (Programmatic)
25
+ ---
14
26
 
15
- Use this pattern when you want to render specific components based on backend data (e.g., from an LLM or API). This effectively turns JSON responses into React UI.
27
+ ## 🚀 Quick Start (Data-Driven Mode)
16
28
 
17
- ### Step 1: Wrap your App
29
+ The core principle is simple: You provide an array of data objects, and the library renders the corresponding components.
18
30
 
19
31
  ```tsx
20
- import { VisualizationProvider } from '@amritanshu3011/mdx-renderer';
32
+ import { IntentProvider, MDXRenderer } from '@amritanshu3011/mdx-renderer';
33
+ import Content from './content.mdx'; // Optional MDX file
21
34
 
22
35
  function App() {
36
+ // Data from your API, Backend, or LLM
37
+ const dashboardData = [
38
+ {
39
+ type: 'line_chart',
40
+ data: {
41
+ title: 'Monthly Revenue',
42
+ xKey: 'month',
43
+ yKey: 'value',
44
+ points: [{ month: 'Jan', value: 4000 }, { month: 'Feb', value: 3000 }]
45
+ }
46
+ }
47
+ ];
48
+
23
49
  return (
24
- <VisualizationProvider>
25
- <YourAppContent />
26
- </VisualizationProvider>
50
+ // IntentProvider handles Data, Theme, and Registry
51
+ <IntentProvider data={dashboardData}>
52
+
53
+ {/* 1. Render content from MDX files */}
54
+ <MDXRenderer>
55
+ <Content />
56
+ </MDXRenderer>
57
+
58
+ </IntentProvider>
27
59
  );
28
60
  }
29
61
 
30
62
  ```
31
63
 
32
- ### Step 2: Inject & Render
64
+ In your `.mdx` file, simply use the dynamic tag:
33
65
 
34
- ```tsx
35
- import { useVisualizations, visualizationRegistry } from '@amritanshu3011/mdx-renderer';
66
+ ```mdx
67
+ # Dashboard
36
68
 
37
- function ResultsPage() {
38
- const { visualizations, addVisualization } = useVisualizations();
69
+ import { DynamicVisualizations } from '@amritanshu3011/mdx-renderer';
39
70
 
40
- // Simulate receiving data from a backend
41
- const handleLoadData = () => {
42
- addVisualization({
43
- type: 'pros_cons', // Key must match the registry (see table below)
44
- data: {
45
- title: 'React vs Angular',
46
- pros: ['Virtual DOM', 'Huge Ecosystem'],
47
- cons: ['Steep Learning Curve']
48
- }
49
- });
50
- };
71
+ Below is the dynamic analysis:
51
72
 
52
- return (
53
- <div>
54
- <button onClick={handleLoadData}>Load Analysis</button>
55
-
56
- {/* Render the Dynamic Components */}
57
- <div className="results-container">
58
- {visualizations.map((viz, index) => {
59
- const Component = visualizationRegistry[viz.type];
60
-
61
- if (!Component) return null;
62
-
63
- return <Component key={index} {...viz.data} />;
64
- })}
65
- </div>
66
- </div>
67
- );
68
- }
73
+ <DynamicVisualizations />
69
74
 
70
75
  ```
71
76
 
72
- ## 2. Standard MDX Usage
77
+ ---
73
78
 
74
- Use this pattern if you are importing and rendering `.mdx` files directly.
79
+ ## 🧩 Reusability & Extension (The Registry Pattern)
75
80
 
76
- ```tsx
77
- import { MDXRenderer, ThemeProvider } from '@amritanshu3011/mdx-renderer';
78
- import Content from './document.mdx';
81
+ This library is designed to be **extended**. You are not limited to the built-in components. You can use the `registry` prop to:
82
+
83
+ 1. **Add** entirely new components (e.g., a Video Player, Map, or KPI Card).
84
+ 2. **Override** built-in components to match your design system.
85
+ 3. **Adapt** backend data structures to match component props.
86
+
87
+ ### Example: Adding a Custom Component
88
+
89
+ **1. Create your component**
90
+
91
+ ```jsx
92
+ // src/components/ImageViewer.jsx
93
+ export const ImageViewer = ({ src, caption }) => (
94
+ <div className="card">
95
+ <img src={src} alt="Custom" />
96
+ <p>{caption}</p>
97
+ </div>
98
+ );
99
+
100
+ ```
101
+
102
+ **2. Register it in your App**
103
+
104
+ ```jsx
105
+ import { ImageViewer } from './components/ImageViewer';
106
+
107
+ const myRegistry = {
108
+ // Map the backend 'type' string to your React Component
109
+ 'image_viewer': ImageViewer
110
+ };
111
+
112
+ function App() {
113
+ const data = [
114
+ {
115
+ type: 'image_viewer', // Matches your registry key
116
+ data: { src: 'demo.jpg', caption: 'Injected Component' }
117
+ }
118
+ ];
79
119
 
80
- function DocumentPage() {
81
120
  return (
82
- <ThemeProvider>
83
- <MDXRenderer>
84
- <Content />
85
- </MDXRenderer>
86
- </ThemeProvider>
121
+ <IntentProvider data={data} registry={myRegistry}>
122
+ <MDXRenderer><Content /></MDXRenderer>
123
+ </IntentProvider>
87
124
  );
88
125
  }
89
126
 
90
127
  ```
91
128
 
92
- ## Component Registry & Data Structures
129
+ ### Example: Adapting Data (Adapter Pattern)
93
130
 
94
- When using the intent-based approach, your backend must return the correct `type` string.
131
+ If your backend API returns data that doesn't match the library's expected props, don't change the API. Just wrap the component!
95
132
 
96
- ### Smart Analysis Blocks
133
+ ```jsx
134
+ import { LineChart } from '@amritanshu3011/mdx-renderer';
97
135
 
98
- | Component | Type Key | Required Data Structure |
99
- | --- | --- | --- |
100
- | **Pros & Cons** | `pros_cons` | `{ title: string, pros: string[], cons: string[] }` |
101
- | **Comparison** | `comparison` | `{ title: string, items: [{ name, price, features[] }] }` |
102
- | **Flow Chart** | `flow` | `{ title: string, steps: [{ id, label, status }] }` |
103
- | **Concept Tree** | `concept_tree` | `{ title: string, data: { name, children: [] } }` |
104
- | **Sunburst** | `sunburst` | `{ title: string, data: { name, children: [{ name, value }] } }` |
105
- | **Composite** | `interactive_composite` | `{ title: string, selector: object, views: object }` |
136
+ // Backend sends 'history', Library expects 'points'
137
+ const CustomChartAdapter = (props) => {
138
+ const adaptedProps = {
139
+ ...props,
140
+ points: props.history // Remap the data
141
+ };
142
+ return <LineChart {...adaptedProps} />;
143
+ };
106
144
 
107
- ### Data Visualizations
145
+ const myRegistry = {
146
+ 'line_chart': CustomChartAdapter // Override the default handler
147
+ };
148
+
149
+ ```
150
+
151
+ ---
108
152
 
109
- | Component | Type Key | Required Data Structure |
153
+ ## 📚 Built-in Component Reference
154
+
155
+ The library comes with a suite of "Smart Components" ready to use.
156
+
157
+ | Component Key | Description | Required Data Structure |
110
158
  | --- | --- | --- |
111
- | **Line Chart** | `line_chart` | `{ title: string, xAxisKey: string, data: object[], series: [{ key, color }] }` |
159
+ | **`line_chart`** | Simple Line Chart | `{ title, xKey, yKey, points: [{x, y}] }` |
160
+ | **`pros_cons`** | Two-column list | `{ title, pros: [], cons: [] }` |
161
+ | **`comparison`** | Feature comparison table | `{ title, items: [{ name, price, features[] }] }` |
162
+ | **`flow`** | Process flow diagram | `{ title, steps: [{ id, label, status }] }` |
163
+ | **`concept_tree`** | Hierarchical tree view | `{ title, data: { name, children: [] } }` |
164
+ | **`sunburst`** | Radial hierarchy chart | `{ title, data: { name, children: [{ name, value }] } }` |
165
+ | **`interactive_composite`** | Tabbed view container | `{ title, selector: {}, views: {} }` |
166
+
167
+ ---
168
+ ## 🎨 Theming
169
+
170
+ The `IntentProvider` accepts a theme object to customize your application's look. You can override colors, spacing, typography, and border radius.
112
171
 
113
- ## Theme Customization
172
+ ### 1. Basic Customization (Safe Merging)
114
173
 
115
- You can inject a custom theme to match your brand colors.
174
+ **Important:** To prevent errors, always merge your overrides with the `defaultTheme`. This ensures that required properties (like spacing or typography) are not missing.
116
175
 
117
176
  ```tsx
118
- import { ThemeProvider } from '@amritanshu3011/mdx-renderer';
177
+ import { IntentProvider, defaultTheme } from '@amritanshu3011/mdx-renderer';
119
178
 
120
- const myTheme = {
179
+ // Create your custom theme by overriding specific values
180
+ const myBrandTheme = {
181
+ ...defaultTheme, // 1. Keep default structure
121
182
  colors: {
122
- primary: '#007bff',
123
- secondary: '#6c757d',
124
- background: '#ffffff',
125
- text: '#333333'
183
+ ...defaultTheme.colors, // 2. Keep default colors (like charts)
184
+ primary: '#ec4899', // 3. Override Primary (Pink)
185
+ background: '#111827', // Override Background
186
+ text: '#f9fafb'
126
187
  },
127
- spacing: {
128
- small: '8px',
129
- medium: '16px',
130
- large: '24px'
188
+ borderRadius: {
189
+ ...defaultTheme.borderRadius,
190
+ medium: '12px' // Rounder corners
131
191
  }
132
192
  };
133
193
 
134
- <ThemeProvider initialTheme={myTheme}>
135
- <App />
136
- </ThemeProvider>
137
-
194
+ function App() {
195
+ return (
196
+ <IntentProvider theme={myBrandTheme} data={...}>
197
+ <AppContent />
198
+ </IntentProvider>
199
+ );
200
+ }
138
201
  ```
202
+ **Important:** Here is the full type definition for reference:
139
203
 
140
- ```
141
204
 
205
+ ```tsx
206
+ type Theme = {
207
+ colors: {
208
+ primary: string;
209
+ secondary: string;
210
+ text: string;
211
+ textSecondary: string;
212
+ background: string;
213
+ cardBackground: string;
214
+ border: string;
215
+ chartLine: string;
216
+ chartBar: string;
217
+ };
218
+ spacing: {
219
+ small: string; // e.g. '8px'
220
+ medium: string; // e.g. '16px'
221
+ large: string; // e.g. '32px'
222
+ xlarge: string; // e.g. '48px'
223
+ };
224
+ typography: {
225
+ fontFamily: string;
226
+ h1Size: string;
227
+ h2Size: string;
228
+ bodySize: string;
229
+ smallSize: string;
230
+ };
231
+ borderRadius: {
232
+ small: string;
233
+ medium: string;
234
+ };
235
+ };
142
236
  ```
@@ -3,6 +3,7 @@ interface IntentProviderProps {
3
3
  children: React.ReactNode;
4
4
  data?: any[];
5
5
  theme?: any;
6
+ registry?: Record<string, React.ComponentType<any>>;
6
7
  }
7
8
  export declare const IntentProvider: React.FC<IntentProviderProps>;
8
9
  export {};
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ThemeProvider } from './theme/ThemeContext';
3
3
  import { VisualizationProvider } from './context/VisualizationContext';
4
- export const IntentProvider = ({ children, data = [], theme }) => {
5
- return (_jsx(ThemeProvider, { initialTheme: theme, children: _jsx(VisualizationProvider, { initialVisualizations: data, children: children }) }));
4
+ export const IntentProvider = ({ children, data = [], theme, registry = {} // Default to empty
5
+ }) => {
6
+ return (_jsx(ThemeProvider, { initialTheme: theme, children: _jsx(VisualizationProvider, { initialVisualizations: data, customRegistry: registry, children: children }) }));
6
7
  };
@@ -1,17 +1,19 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useVisualizations } from '../context/VisualizationContext';
3
- import { visualizationRegistry } from '../registry/visualizationRegistry';
4
3
  export const DynamicVisualizations = () => {
5
- const { visualizations } = useVisualizations();
6
- if (visualizations.length === 0)
4
+ // 1. Get the MERGED registry from Context (Defaults + User Custom)
5
+ const { visualizations, registry } = useVisualizations();
6
+ if (!visualizations || visualizations.length === 0)
7
7
  return null;
8
- return (_jsx("div", { children: visualizations.map((viz, index) => {
9
- const vizType = viz.type;
10
- const Component = visualizationRegistry[vizType];
8
+ return (_jsx("div", { className: "w-full flex flex-col gap-8 my-8", children: visualizations.map((viz, index) => {
9
+ // 2. Look up component in the Context Registry
10
+ // We use string indexing because users can add ANY key
11
+ const Component = registry[viz.type];
11
12
  if (!Component) {
12
- console.warn(`Unknown visualization type: ${viz.type}`);
13
- return null;
13
+ console.warn(`MDX Renderer: Unknown visualization type "${viz.type}"`);
14
+ // Render a helpful error for the developer/user
15
+ return (_jsxs("div", { className: "p-4 border border-red-200 bg-red-50 text-red-600 rounded-lg text-sm font-mono", children: ["\u26A0\uFE0F Unknown component type: ", _jsx("strong", { children: viz.type })] }, index));
14
16
  }
15
- return (_jsx("div", { children: _jsx(Component, { ...viz.data }) }, index));
17
+ return (_jsx("div", { className: "mdx-viz-block w-full", children: _jsx(Component, { ...viz.data }) }, index));
16
18
  }) }));
17
19
  };
@@ -1,13 +1,19 @@
1
- import React from 'react';
2
- import type { LLMResponse } from '../types/mockLLM';
1
+ import { ReactNode, ComponentType } from 'react';
2
+ export interface VisualizationItem {
3
+ type: string;
4
+ data: any;
5
+ }
3
6
  interface VisualizationContextType {
4
- visualizations: LLMResponse[];
5
- addVisualization: (viz: LLMResponse) => void;
7
+ visualizations: VisualizationItem[];
8
+ addVisualization: (viz: VisualizationItem) => void;
6
9
  clearVisualizations: () => void;
10
+ registry: Record<string, ComponentType<any>>;
11
+ }
12
+ export interface VisualizationProviderProps {
13
+ children: ReactNode;
14
+ initialVisualizations?: VisualizationItem[];
15
+ customRegistry?: Record<string, ComponentType<any>>;
7
16
  }
8
- export declare const VisualizationProvider: ({ children, initialVisualizations }: {
9
- children: React.ReactNode;
10
- initialVisualizations?: any[];
11
- }) => import("react/jsx-runtime").JSX.Element;
17
+ export declare const VisualizationProvider: ({ children, initialVisualizations, customRegistry }: VisualizationProviderProps) => import("react/jsx-runtime").JSX.Element;
12
18
  export declare const useVisualizations: () => VisualizationContextType;
13
19
  export {};
@@ -1,21 +1,32 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import React, { createContext, useContext } from 'react';
2
+ import React, { createContext, useContext, useState } from 'react';
3
+ // Import your default registry to use as a base
4
+ import { visualizationRegistry as defaultRegistry } from '../registry/visualizationRegistry';
3
5
  const VisualizationContext = createContext(undefined);
4
- export const VisualizationProvider = ({ children, initialVisualizations = [] }) => {
5
- const [visualizations, setVisualizations] = React.useState(initialVisualizations);
6
+ export const VisualizationProvider = ({ children, initialVisualizations = [], customRegistry = {} }) => {
7
+ const [visualizations, setVisualizations] = useState(initialVisualizations);
8
+ // 1. MERGE LOGIC: Combine defaults with user overrides
9
+ // Using useMemo is good practice here to prevent recreation on every render,
10
+ // but for simplicity, direct object spread works too.
11
+ const mergedRegistry = { ...defaultRegistry, ...customRegistry };
12
+ // 2. Reactive State Update
6
13
  React.useEffect(() => {
7
14
  if (initialVisualizations.length > 0) {
8
15
  setVisualizations(initialVisualizations);
9
16
  }
10
17
  }, [initialVisualizations]);
11
18
  const addVisualization = (viz) => {
12
- console.log('Storing visualization:', viz);
13
19
  setVisualizations(prev => [...prev, viz]);
14
20
  };
15
21
  const clearVisualizations = () => {
16
22
  setVisualizations([]);
17
23
  };
18
- return (_jsx(VisualizationContext.Provider, { value: { visualizations, addVisualization, clearVisualizations }, children: children }));
24
+ return (_jsx(VisualizationContext.Provider, { value: {
25
+ visualizations,
26
+ addVisualization,
27
+ clearVisualizations,
28
+ registry: mergedRegistry // <--- Pass the merged registry to the app
29
+ }, children: children }));
19
30
  };
20
31
  export const useVisualizations = () => {
21
32
  const context = useContext(VisualizationContext);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritanshu3011/mdx-renderer",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Reusable MDX visualization library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",