mirror of
https://github.com/prodigist/ReactiveNotes.git
synced 2026-07-22 12:30:26 +00:00
Final Updated README for release, Added CDNjs imports
This commit is contained in:
parent
0cb1867ac7
commit
deab1a970c
6 changed files with 987 additions and 366 deletions
6
.env
6
.env
|
|
@ -1,6 +0,0 @@
|
|||
// .env file (Do NOT commit this file)
|
||||
ALPHA_VANTAGE_PRIMARY_KEY=7NMNWUG3QGNSK9J2
|
||||
ALPHA_VANTAGE_SECONDARY_KEY=9H7UI9KW24V8UXCW
|
||||
MARKET_DATA_CACHE_DURATION=86400000
|
||||
TIMEZONE=US/Eastern
|
||||
|
||||
BIN
.gitignore
vendored
BIN
.gitignore
vendored
Binary file not shown.
337
Contributing.md
Normal file
337
Contributing.md
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
# Contributing to ReactiveNotes
|
||||
|
||||
> ⚡️ Help us advance the Obsidian powerhouse
|
||||
|
||||
First off, thank you for considering contributing to ReactiveNotes! It's people like you who make ReactiveNotes an amazing tool for the Obsidian community.
|
||||
|
||||
## 🗺️ Development Roadmap
|
||||
|
||||
Before diving in, check our current focus areas:
|
||||
|
||||
- 📱 Mobile support optimization
|
||||
- 🎨 Enhanced visualization capabilities
|
||||
- 🔄 State management improvements
|
||||
- 🧪 Testing infrastructure
|
||||
- 📚 Documentation enhancements
|
||||
|
||||
## 🔧 Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js (v16.0.0 or higher)
|
||||
- npm or yarn
|
||||
- Git
|
||||
- Obsidian (v1.4.0 or higher)
|
||||
|
||||
### Local Development Environment
|
||||
|
||||
1. Fork and clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/ReactiveNotes.git
|
||||
cd ReactiveNotes
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
# or
|
||||
yarn install
|
||||
```
|
||||
|
||||
3. Create a development vault:
|
||||
```bash
|
||||
mkdir TestVault
|
||||
cd TestVault
|
||||
mkdir .obsidian/plugins/reactive-notes
|
||||
```
|
||||
|
||||
4. Link your development build:
|
||||
```bash
|
||||
# From project root
|
||||
npm run dev
|
||||
# This will watch for changes and rebuild
|
||||
```
|
||||
|
||||
5. Enable the plugin in Obsidian:
|
||||
- Open Obsidian settings
|
||||
- Go to Community Plugins
|
||||
- Enable ReactiveNotes
|
||||
|
||||
## 🏗️ Project Structure
|
||||
|
||||
```
|
||||
ReactiveNotes/
|
||||
├── src/
|
||||
│ ├── config/ # Configuration and registry
|
||||
│ │ └── componentRegistry.ts
|
||||
│ ├── components/ # React components
|
||||
│ │ ├── core/
|
||||
│ │ └── ui/
|
||||
│ ├── services/ # Core services
|
||||
│ │ ├── storage.ts
|
||||
│ │ └── marketData.ts
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ ├── utils/ # Utility functions
|
||||
│ └── main.tsx # Plugin entry point
|
||||
├── styles/ # CSS and Tailwind configs
|
||||
├── tests/ # Test files
|
||||
└── types/ # TypeScript definitions
|
||||
```
|
||||
|
||||
## 🧪 Testing Guidelines
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
Tests should be placed in the `tests` directory, mirroring the source structure:
|
||||
|
||||
```typescript
|
||||
// tests/components/MyComponent.test.ts
|
||||
describe('MyComponent', () => {
|
||||
it('should render correctly', () => {
|
||||
// Test code
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
```bash
|
||||
npm run test:integration
|
||||
```
|
||||
|
||||
Integration tests should focus on:
|
||||
- Component interactions
|
||||
- Plugin initialization
|
||||
- File system operations
|
||||
- State persistence
|
||||
|
||||
### Manual Testing Checklist
|
||||
|
||||
- [ ] Test in both light and dark themes
|
||||
- [ ] Verify mobile responsiveness
|
||||
- [ ] Check memory usage
|
||||
- [ ] Validate error handling
|
||||
- [ ] Test with different vault configurations
|
||||
## 📝 Code Style Guidelines
|
||||
|
||||
### TypeScript Standards
|
||||
|
||||
```typescript
|
||||
// Use explicit typing
|
||||
interface ComponentProps {
|
||||
data: DataType[];
|
||||
onUpdate: (newData: DataType) => void;
|
||||
}
|
||||
|
||||
// Prefer functional components
|
||||
const MyComponent: React.FC<ComponentProps> = ({ data, onUpdate }) => {
|
||||
// Implementation
|
||||
};
|
||||
|
||||
// Use proper type guards
|
||||
function isValidData(data: unknown): data is DataType {
|
||||
return (
|
||||
typeof data === 'object' &&
|
||||
data !== null &&
|
||||
'id' in data
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### React Best Practices
|
||||
|
||||
1. **Hooks Organization**
|
||||
```typescript
|
||||
const MyComponent: React.FC = () => {
|
||||
// 1. State hooks
|
||||
const [data, setData] = useState<DataType[]>([]);
|
||||
|
||||
// 2. Ref hooks
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 3. Memoization
|
||||
const processedData = useMemo(() =>
|
||||
data.map(processItem),
|
||||
[data]
|
||||
);
|
||||
|
||||
// 4. Effects
|
||||
useEffect(() => {
|
||||
// Effect logic
|
||||
return () => {
|
||||
// Cleanup
|
||||
};
|
||||
}, [dependencies]);
|
||||
|
||||
// 5. Event handlers
|
||||
const handleUpdate = useCallback(() => {
|
||||
// Handler logic
|
||||
}, [dependencies]);
|
||||
|
||||
// 6. Render
|
||||
return <div />;
|
||||
};
|
||||
```
|
||||
|
||||
2. **Component Structure**
|
||||
- One component per file
|
||||
- Clear prop interfaces
|
||||
- Proper error boundaries
|
||||
- Effective memo usage
|
||||
|
||||
### Documentation Requirements
|
||||
|
||||
1. **Component Documentation**
|
||||
```typescript
|
||||
/**
|
||||
* Visualizes data using an interactive chart.
|
||||
*
|
||||
* @component
|
||||
* @example
|
||||
* ```jsx
|
||||
* <DataVisualizer
|
||||
* data={[1, 2, 3]}
|
||||
* title="My Chart"
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {number[]} props.data - Data points to visualize
|
||||
* @param {string} props.title - Chart title
|
||||
*/
|
||||
```
|
||||
|
||||
2. **README Updates**
|
||||
- Document new features
|
||||
- Update API references
|
||||
- Add usage examples
|
||||
- Note breaking changes
|
||||
|
||||
## 🔄 Pull Request Process
|
||||
|
||||
### 1. Branch Naming
|
||||
```bash
|
||||
feature/description-of-feature
|
||||
bugfix/issue-being-fixed
|
||||
docs/documentation-updates
|
||||
test/testing-improvements
|
||||
```
|
||||
|
||||
### 2. Commit Messages
|
||||
```bash
|
||||
# Format
|
||||
<type>(<scope>): <description>
|
||||
|
||||
# Examples
|
||||
feat(components): add new visualization component
|
||||
fix(storage): resolve persistence issue
|
||||
docs(readme): update installation instructions
|
||||
test(core): add unit tests for storage service
|
||||
```
|
||||
|
||||
### 3. PR Template
|
||||
```markdown
|
||||
## Description
|
||||
Brief description of changes
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Breaking change
|
||||
- [ ] Documentation update
|
||||
|
||||
## Testing
|
||||
Describe testing performed
|
||||
|
||||
## Screenshots
|
||||
If applicable
|
||||
|
||||
## Checklist
|
||||
- [ ] Tests added/updated
|
||||
- [ ] Documentation updated
|
||||
- [ ] Code follows style guide
|
||||
- [ ] All tests passing
|
||||
```
|
||||
|
||||
## 📋 Review Process
|
||||
|
||||
### Code Review Checklist
|
||||
|
||||
1. **Functionality**
|
||||
- [ ] Meets requirements
|
||||
- [ ] Handles edge cases
|
||||
- [ ] Error handling implemented
|
||||
- [ ] Performance considered
|
||||
|
||||
2. **Code Quality**
|
||||
- [ ] Follows style guide
|
||||
- [ ] Properly typed
|
||||
- [ ] No unnecessary complexity
|
||||
- [ ] Clean architecture
|
||||
|
||||
3. **Testing**
|
||||
- [ ] Unit tests added
|
||||
- [ ] Integration tests updated
|
||||
- [ ] Edge cases covered
|
||||
- [ ] Performance tested
|
||||
|
||||
4. **Documentation**
|
||||
- [ ] API docs updated
|
||||
- [ ] Examples provided
|
||||
- [ ] Breaking changes noted
|
||||
- [ ] Migration guide if needed
|
||||
|
||||
## 🚀 Release Process
|
||||
|
||||
### Version Numbering
|
||||
We follow [Semantic Versioning](https://semver.org/):
|
||||
- MAJOR.MINOR.PATCH
|
||||
- Breaking.Feature.Fix
|
||||
|
||||
### Release Checklist
|
||||
|
||||
1. **Pre-release**
|
||||
- [ ] All tests passing
|
||||
- [ ] Documentation updated
|
||||
- [ ] CHANGELOG.md updated
|
||||
- [ ] Version bumped
|
||||
- [ ] Build artifacts verified
|
||||
|
||||
2. **Release**
|
||||
- [ ] GitHub release created
|
||||
- [ ] Tags pushed
|
||||
- [ ] NPM package published
|
||||
- [ ] Release notes completed
|
||||
|
||||
3. **Post-release**
|
||||
- [ ] Documentation deployed
|
||||
- [ ] Community notified
|
||||
- [ ] Version bumped to next dev version
|
||||
|
||||
## 🤝 Community Guidelines
|
||||
|
||||
### Communication
|
||||
- Be respectful and inclusive
|
||||
- Keep discussions technical
|
||||
- Provide context with questions
|
||||
- Use appropriate channels
|
||||
|
||||
### Support
|
||||
- Check existing issues first
|
||||
- Provide minimal reproduction
|
||||
- Include environment details
|
||||
- Follow issue templates
|
||||
|
||||
### Recognition
|
||||
Contributors are recognized in:
|
||||
- CONTRIBUTORS.md
|
||||
- Release notes
|
||||
- Community spotlights
|
||||
|
||||
## 📜 License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||
695
README.md
695
README.md
|
|
@ -1,29 +1,165 @@
|
|||
# ReactiveNotes - Dynamic React Components in Obsidian
|
||||
|
||||
|
||||
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||

|
||||
[](https://www.buymeacoffee.com/prodigist)
|
||||
|
||||
ReactiveNotes transforms your Obsidian notes into interactive documents by enabling full React component capabilities directly within your markdown files.
|
||||
Transform your Obsidian vault into a reactive computational environment. ReactiveNotes seamlessly integrates React's component ecosystem with Obsidian's powerful note-taking capabilities, enabling dynamic, interactive documents that evolve with your thoughts.
|
||||
> ⚠️ **Mobile Support**: Currently optimized for desktop use. Mobile support is under development.
|
||||
|
||||
## Core Capabilities
|
||||
## Why ReactiveNotes?
|
||||
|
||||
### 1. Interactive Components
|
||||
- Write and use React components directly in markdown
|
||||
- Full React 18 feature support including Hooks
|
||||
- Real-time component updates
|
||||
- TypeScript support
|
||||
- **Native Integration**: Built from the ground up for Obsidian
|
||||
- **Powerful Yet Simple**: Write React components directly in your notes
|
||||
- **Dynamic & Interactive**: Turn static notes into living documents
|
||||
- **Extensible Foundation**: Build your own tools and visualizations
|
||||
## Compatibility
|
||||
|
||||
- Obsidian v1.4.0 or higher
|
||||
- React v18.2.0
|
||||
- Libraries:
|
||||
- Recharts v2.10.0
|
||||
- Lightweight Charts v4.1.0
|
||||
- d3-force v3.0.0
|
||||
- lucide-react v0.263.1
|
||||
- shadcn/ui (latest components)
|
||||
|
||||
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Installation
|
||||
1. Open Obsidian Settings → Community Plugins
|
||||
2. Disable Safe Mode if necessary
|
||||
3. Search for "ReactiveNotes"
|
||||
4. Click Install and Enable
|
||||
|
||||
For manual installation:
|
||||
1. Download release from GitHub
|
||||
2. Extract to your vault's `.obsidian/plugins` folder
|
||||
3. Enable in Community Plugins settings
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Create a React component in any note:
|
||||
````markdown
|
||||
```react
|
||||
const Greeting = () => {
|
||||
const [name, setName] = useState("World");
|
||||
return <h1>Hello, {name}!</h1>;
|
||||
};
|
||||
|
||||
export default Greeting;
|
||||
```
|
||||
````
|
||||
|
||||
**Component Requirements:**
|
||||
- Must include a default export
|
||||
- Must be self-contained in one code block
|
||||
- Component name should match default export
|
||||
|
||||
### Component Structure
|
||||
|
||||
A typical component structure follows this basic structure:
|
||||
````
|
||||
```react
|
||||
// Optional: CDN imports at the top
|
||||
import ExternalLib from 'https://cdnjs.cloudflare.com/...';
|
||||
|
||||
// Component definition
|
||||
const MyComponent = () => {
|
||||
// 1. Hooks
|
||||
const [state, setState] = useState(null);
|
||||
const componentRef = useRef(null);
|
||||
|
||||
// 2. Effects & Lifecycle
|
||||
useEffect(() => {
|
||||
// Setup code
|
||||
return () => {
|
||||
// Cleanup code
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 3. Helper functions
|
||||
const handleEvent = () => {
|
||||
// Event handling logic
|
||||
};
|
||||
|
||||
// 4. Render
|
||||
return (
|
||||
<div>
|
||||
{/* Your JSX here */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Required: Default export
|
||||
export default MyComponent;
|
||||
```
|
||||
````
|
||||
**Key Structure Points**:
|
||||
1. Imports always at the top
|
||||
2. Component name matches default export
|
||||
3. Hooks before effects
|
||||
4. Helper functions before render
|
||||
5. Single default export at bottom
|
||||
|
||||
|
||||
|
||||
## 📚 Built-in Libraries & Components
|
||||
|
||||
### React Core & Hooks
|
||||
```javascript
|
||||
import React, { useState, useEffect, useRef, useMemo } from react';
|
||||
```
|
||||
### UI Components from shadcn/ui
|
||||
```javascript
|
||||
import {
|
||||
Card, CardHeader, CardTitle, CardContent,
|
||||
Tabs, TabsList, TabsTrigger,
|
||||
Button, Dialog, Form
|
||||
} from '@/components/ui';
|
||||
```
|
||||
### Visualization Libraries
|
||||
```javascript
|
||||
//Include Responsive containers
|
||||
// Recharts for data visualization
|
||||
import {
|
||||
LineChart, BarChart, PieChart,
|
||||
Line, Bar, Pie,
|
||||
Tooltip, Legend
|
||||
} from 'recharts';
|
||||
|
||||
// Lightweight Charts for financial charts
|
||||
import { createChart } from 'lightweight-charts';
|
||||
|
||||
// D3-force for network graphs
|
||||
import {
|
||||
forceSimulation,
|
||||
forceLink
|
||||
} from 'd3-force';
|
||||
```
|
||||
### Icons
|
||||
```javascript
|
||||
import {
|
||||
Upload, Activity, AlertCircle,
|
||||
TrendingUp, TrendingDown
|
||||
} from 'lucide-react';
|
||||
```
|
||||
## 💻 Core Features
|
||||
|
||||
### 1. Component Systems
|
||||
- Write React components directly in notes
|
||||
- Full TypeScript and React 18 support
|
||||
- Hot reloading during development
|
||||
|
||||
### 2. Data Visualization
|
||||
Built-in libraries:
|
||||
- **Recharts**: Full suite of chart components
|
||||
- Line, Bar, Area, Pie charts
|
||||
- Custom tooltips and legends
|
||||
- Responsive containers
|
||||
- **Lightweight Charts**: Professional-grade financial charts
|
||||
- Candlestick charts
|
||||
- Technical indicators
|
||||
- Custom overlays
|
||||
- Error Boundaries and Suspense
|
||||
- Resource cleanup and lifecycle management
|
||||
- Custom component registration
|
||||
- Real-time component updates
|
||||
- Error reporting
|
||||
|
||||
### 3. Canvas Manipulation
|
||||
- Direct canvas access for custom drawing
|
||||
|
|
@ -32,217 +168,424 @@ Built-in libraries:
|
|||
- Custom overlays and annotations
|
||||
- Interactive drawing tools
|
||||
|
||||
### 4. Data Processing
|
||||
- Real-time data manipulation
|
||||
- CSV/Excel file processing
|
||||
- Data transformation utilities
|
||||
- Pattern recognition
|
||||
- Statistical analysis
|
||||
|
||||
### 5. State Management
|
||||
|
||||
### 5. Performance
|
||||
- Efficient re-rendering
|
||||
- Memory leak prevention
|
||||
- Lazy loading support
|
||||
|
||||
### 2. State Management
|
||||
```javascript
|
||||
// Local state with React
|
||||
const [local, setLocal] = useState(0);
|
||||
|
||||
// Persistent state in note frontmatter
|
||||
const [stored, setStored] = useStorage('key', defaultValue);
|
||||
```
|
||||
- Persistent storage between sessions
|
||||
- State synchronization across components
|
||||
- Frontmatter integration
|
||||
- Cross-note state management
|
||||
|
||||
### 6. UI Components
|
||||
Ready-to-use components from shadcn/ui:
|
||||
- Cards
|
||||
- Tabs
|
||||
- Dialogs
|
||||
- Forms
|
||||
- Buttons
|
||||
- Alerts
|
||||
### Note-Specific Data Persistence
|
||||
- Each note maintains independent state through frontmatter
|
||||
- Component states persist across sessions
|
||||
- Data automatically travels with notes when shared
|
||||
- Multiple instances of same component can have different states
|
||||
- Perfect for creating reusable interactive templates
|
||||
|
||||
## Integration Features
|
||||
Example:
|
||||
|
||||
### 1. File System Integration
|
||||
```javascript
|
||||
// Access and manipulate files
|
||||
const fileContent = await window.fs.readFile('example.csv');
|
||||
const jsonData = await window.fs.readFile('data.json', { encoding: 'utf8' });
|
||||
// In Note1.md - counter starts at 0
|
||||
const Counter = () => {
|
||||
const [count1, setCount1] = useStorage('counter', 0);
|
||||
return <button onClick={() => setCount1(count1 + 1)}>Count: {count1}</button>;
|
||||
};
|
||||
|
||||
// In Note2.md - same component, independent state
|
||||
const Counter = () => {
|
||||
const [count2, setCount2] = useStorage('counter', 0);
|
||||
return <button onClick={() => setCount2(count2 + 1)}>Count: {count2}</button>;
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Theme Integration
|
||||
### 3. File System Integration
|
||||
```javascript
|
||||
// Automatic theme detection
|
||||
const theme = getTheme(); // 'dark' or 'light'
|
||||
// Read files with encoding
|
||||
const text = await window.fs.readFile('data.txt', {
|
||||
encoding: 'utf8'
|
||||
});
|
||||
|
||||
// Read binary files
|
||||
const binary = await window.fs.readFile('data.xlsx');
|
||||
```
|
||||
|
||||
### 4. CDN Library Support
|
||||
Import additional libraries from cdnjs:
|
||||
```javascript
|
||||
import Chart from 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js';
|
||||
```
|
||||
|
||||
Requirements:
|
||||
- HTTPS URLs from cdnjs.cloudflare.com only
|
||||
- Imports at component top
|
||||
- Browser-compatible libraries only
|
||||
|
||||
### 5. Theme Integration
|
||||
```javascript
|
||||
const theme = getTheme(); // Returns 'dark' or 'light'
|
||||
|
||||
// Theme-aware styling
|
||||
const styles = {
|
||||
background: theme === 'dark' ? '#1a1b1e' : '#ffffff',
|
||||
color: theme === 'dark' ? '#ffffff' : '#000000'
|
||||
background: theme === 'dark' ? 'var(--background-primary)' : 'white',
|
||||
color: theme === 'dark' ? 'var(--text-normal)' : 'black'
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Data Persistence
|
||||
|
||||
### File System Access
|
||||
```javascript
|
||||
// Persistent storage hook
|
||||
const [value, setValue] = useStorage('key', defaultValue);
|
||||
|
||||
// Automatic state persistence
|
||||
const [count, setCount] = useStorage('counter', 0);
|
||||
// Read files
|
||||
const csv = await window.fs.readFile('data.csv', { encoding: 'utf8' });
|
||||
const binary = await window.fs.readFile('data.xlsx');
|
||||
```
|
||||
|
||||
## Component Types
|
||||
## 🎨 Component Examples
|
||||
|
||||
### 1. Visualization Components
|
||||
### Interactive Data Visualization
|
||||
````
|
||||
```react
|
||||
// Interactive data visualization
|
||||
const DataVisualization = () => {
|
||||
return (
|
||||
<ResponsiveContainer>
|
||||
<LineChart data={data}>
|
||||
<Line type="monotone" dataKey="value" />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
const DataChart = () => {
|
||||
const data = [
|
||||
{ month: 'Jan', value: 100 },
|
||||
{ month: 'Feb', value: 150 },
|
||||
{ month: 'Mar', value: 120 }
|
||||
];
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<LineChart data={data}>
|
||||
<XAxis dataKey="month" />
|
||||
<YAxis />
|
||||
<Line type="monotone" dataKey="value" />
|
||||
<Tooltip />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
};
|
||||
```
|
||||
````
|
||||
### Canvas Manipulation
|
||||
````
|
||||
const DrawingCanvas = () => {
|
||||
const canvasRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvasRef.current.getContext('2d');
|
||||
ctx.fillStyle = getTheme() === 'dark' ? '#fff' : '#000';
|
||||
|
||||
// Your drawing code
|
||||
|
||||
return () => {
|
||||
// Cleanup
|
||||
};
|
||||
}, []);
|
||||
|
||||
### 2. Canvas Components
|
||||
return <canvas ref={canvasRef} className="w-full h-64" />;
|
||||
};
|
||||
````
|
||||
### Persistent State Component
|
||||
````
|
||||
```react
|
||||
// Interactive canvas usage
|
||||
const CanvasComponent = () => {
|
||||
const canvasRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvasRef.current.getContext('2d');
|
||||
// Custom drawing and animations
|
||||
}, []);
|
||||
|
||||
return <canvas ref={canvasRef} />;
|
||||
const NoteTracker = () => {
|
||||
const [notes, setNotes] = useStorage('notes', []);
|
||||
|
||||
const addNote = (text) => {
|
||||
setNotes(prev => [...prev, {
|
||||
id: Date.now(),
|
||||
text,
|
||||
created: new Date()
|
||||
}]);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>My Notes</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{notes.map(note => (
|
||||
<div key={note.id}>{note.text}</div>
|
||||
))}
|
||||
<Button onClick={() => addNote("New Note")}>
|
||||
Add Note
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
```
|
||||
````
|
||||
|
||||
### 3. Network Visualizations
|
||||
### Network Visualization
|
||||
````
|
||||
```react
|
||||
// Force-directed graphs
|
||||
const NetworkGraph = () => {
|
||||
return (
|
||||
<ForceGraph
|
||||
nodes={nodes}
|
||||
links={links}
|
||||
onNodeClick={handleClick}
|
||||
/>
|
||||
);
|
||||
const [nodes] = useState([
|
||||
{ id: 1, label: 'Node 1' },
|
||||
{ id: 2, label: 'Node 2' }
|
||||
]);
|
||||
|
||||
const [links] = useState([
|
||||
{ source: 1, target: 2 }
|
||||
]);
|
||||
|
||||
return (
|
||||
<ForceGraph
|
||||
graphData={{ nodes, links }}
|
||||
nodeAutoColorBy="label"
|
||||
nodeLabel="label"
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
````
|
||||
|
||||
## Technical Features
|
||||
|
||||
### 1. React Integration
|
||||
- Full React 18 support
|
||||
- Hooks support
|
||||
- Error Boundaries
|
||||
- Suspense support
|
||||
- TypeScript enabled
|
||||
|
||||
### 2. Performance
|
||||
- Efficient re-rendering
|
||||
- Automatic cleanup
|
||||
- Memory leak prevention
|
||||
- Resource management
|
||||
- Lazy loading support
|
||||
|
||||
### 3. Development Tools
|
||||
- Hot reloading
|
||||
- Error reporting
|
||||
- Debug mode
|
||||
- Performance monitoring
|
||||
|
||||
## API Access
|
||||
|
||||
### 1. Available Libraries
|
||||
- React + Hooks
|
||||
- Recharts
|
||||
- Lightweight Charts
|
||||
- d3-force
|
||||
- Lucide icons
|
||||
- shadcn/ui components
|
||||
|
||||
### 2. Utility Functions
|
||||
- File system operations
|
||||
- Data processing
|
||||
- Theme detection
|
||||
- State persistence
|
||||
- Math operations
|
||||
|
||||
### 3. Component Registry
|
||||
- Custom component registration
|
||||
- Component sharing
|
||||
- Dynamic loading
|
||||
- Type safety
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Component Design
|
||||
## 🛠️Development Guide
|
||||
### Component Structure
|
||||
```react
|
||||
const ResponsiveComponent = () => {
|
||||
// Use relative units
|
||||
return (
|
||||
<div className="w-full">
|
||||
<ResponsiveContainer width="100%" height={400}>
|
||||
{/* Component content */}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
// Basic component template
|
||||
const MyComponent = () => {
|
||||
// 1. Hooks and state
|
||||
const [data, setData] = useState(null);
|
||||
const componentRef = useRef(null);
|
||||
|
||||
// 2. Effects and lifecycle
|
||||
useEffect(() => {
|
||||
// Setup code
|
||||
return () => {
|
||||
// Cleanup code
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 3. Event handlers
|
||||
const handleUpdate = useCallback(() => {
|
||||
// Handler code
|
||||
}, []);
|
||||
|
||||
// 4. Render
|
||||
return (
|
||||
<div>
|
||||
{/* Component JSX */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
### 2. State Management
|
||||
```react
|
||||
const StatefulComponent = () => {
|
||||
// Use persistent storage for important state
|
||||
const [data, setData] = useStorage('data-key', initialData);
|
||||
|
||||
// Use local state for UI-only state
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
};
|
||||
```
|
||||
### Best Practices
|
||||
|
||||
1. **Component Design**
|
||||
```react
|
||||
const ResponsiveComponent = () => {
|
||||
return (
|
||||
<div className="w-full">
|
||||
<ResponsiveContainer width="100%" height={400}>
|
||||
{/* Content adapts to container */}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
2. **State Management**
|
||||
```react
|
||||
const DataComponent = () => {
|
||||
// Persistent data
|
||||
const [savedData, setSavedData] = useStorage('data-key', []);
|
||||
|
||||
// Temporary UI state
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
// Computed values
|
||||
const processedData = useMemo(() => {
|
||||
return savedData.map(item => /* process */);
|
||||
}, [savedData]);
|
||||
};
|
||||
```
|
||||
|
||||
3. **Error Handling**
|
||||
```react
|
||||
const SafeComponent = () => {
|
||||
return (
|
||||
<ErrorBoundary
|
||||
fallback={({ error }) => (
|
||||
<div className="text-red-500">
|
||||
Error: {error.message}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{/* Protected content */}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
```
|
||||
1. **Error Checking**:
|
||||
- Check browser console for errors
|
||||
- Verify imports are working
|
||||
- Ensure all required exports are present
|
||||
|
||||
2. **Performance**:
|
||||
- Keep components focused and minimal
|
||||
- Use CDN imports sparingly
|
||||
- Clean up resources in useEffect
|
||||
|
||||
3. **Testing**:
|
||||
- Test in both light and dark themes
|
||||
- Verify mobile responsiveness (Hasn't been tested for mobile yet)
|
||||
- Check CDN imports load correctly
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
1. **Component not rendering**
|
||||
- Verify default export is present
|
||||
- Check console for React errors
|
||||
- Ensure all imports are available and supported
|
||||
- Validate JSX syntax
|
||||
|
||||
2. **CDN imports not working**
|
||||
- Verify HTTPS URL
|
||||
- Check library compatibility
|
||||
- Confirm import syntax
|
||||
|
||||
3. **State persistence issues**
|
||||
- Check frontmatter permissions
|
||||
- Verify storage key uniqueness
|
||||
- Validate data serialization
|
||||
- Monitor storage size limits
|
||||
|
||||
4. **Performance Problems**
|
||||
- Use React DevTools for profiling
|
||||
- Implement proper cleanup in useEffect
|
||||
- Optimize re-renders with useMemo/useCallback
|
||||
- Monitor memory usage with large datasets
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
### Mobile Compatibility
|
||||
- Currently optimized for desktop use
|
||||
- Mobile support is under development
|
||||
- Test thoroughly on mobile devices
|
||||
|
||||
### Performance and Resource Management
|
||||
Best practices for optimal performance:
|
||||
|
||||
- Clean up subscriptions and intervals
|
||||
- Dispose of chart instances
|
||||
- Release canvas resources
|
||||
- Free up WebGL contexts
|
||||
- Use persistent storage thoughtfully
|
||||
|
||||
### Security Considerations
|
||||
- CDN imports are restricted to cdnjs.cloudflare.com
|
||||
- File system access is limited to vault
|
||||
- Component code runs in sandbox
|
||||
- No external network requests
|
||||
|
||||
## 📋 Technical Reference
|
||||
### Available APIs
|
||||
|
||||
1. **File System**
|
||||
```javascript
|
||||
// File operations
|
||||
await window.fs.readFile(path, options);
|
||||
const text = await window.fs.readFile(path, { encoding: 'utf8' });
|
||||
```
|
||||
|
||||
2. **Theme Management**
|
||||
```javascript
|
||||
// Theme utilities
|
||||
const theme = getTheme();
|
||||
const isDark = theme === 'dark';
|
||||
```
|
||||
|
||||
3. **Storage**
|
||||
```javascript
|
||||
// Storage hooks
|
||||
const [value, setValue] = useStorage(key, defaultValue);
|
||||
const stored = useStorage(key, null, storage);
|
||||
```
|
||||
|
||||
### 3. Error Handling
|
||||
```react
|
||||
const SafeComponent = () => {
|
||||
return (
|
||||
<ErrorBoundary fallback={<ErrorDisplay />}>
|
||||
{/* Component content */}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- No external package imports (use provided libraries)
|
||||
- Limited to frontend functionality
|
||||
- Storage is note-specific through frontmatter
|
||||
- Component code must be self-contained
|
||||
1. **Environment Constraints**
|
||||
- CDN imports limited to cdnjs.cloudflare.com
|
||||
- Components must be self-contained in one code block
|
||||
- Network requests follow Obsidian's security policies
|
||||
|
||||
## Future Plans
|
||||
2. **Performance Considerations**
|
||||
- Large datasets may impact performance
|
||||
- Heavy animations should be optimized
|
||||
- Memory usage needs monitoring
|
||||
- Mobile performance varies
|
||||
|
||||
- Additional visualization libraries
|
||||
- Enhanced state management
|
||||
- Component sharing mechanism
|
||||
- Template system
|
||||
- Enhanced debugging tools
|
||||
3. **Work in Progress**
|
||||
- Mobile support still under development
|
||||
- Some touch interactions need optimization
|
||||
- Advanced debugging tools coming soon
|
||||
|
||||
## Contributing
|
||||
## 🔮 Future Plans
|
||||
|
||||
Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md).
|
||||
### Upcoming Features
|
||||
1. Advanced Visualization
|
||||
- More chart types
|
||||
- Enhanced animations
|
||||
- 3D visualization support
|
||||
- Custom chart templates
|
||||
|
||||
## Support
|
||||
2. Developer Experience
|
||||
- Component templates
|
||||
- Debug tools
|
||||
- Performance monitoring
|
||||
- Testing utilities
|
||||
|
||||
- Report bugs through [GitHub Issues](https://github.com/YourUsername/ReactiveNotes/issues)
|
||||
- Request features in [Discussions](https://github.com/YourUsername/ReactiveNotes/discussions)
|
||||
- Join our [Discord community](your-discord-link)
|
||||
3. Mobile Support
|
||||
- Touch optimization
|
||||
- Responsive layouts
|
||||
- Performance improvements
|
||||
- Mobile-specific components
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions! Here's how to get started:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create your feature branch
|
||||
3. Make your changes
|
||||
4. Submit a pull request
|
||||
|
||||
Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
||||
|
||||
## 💬 Support
|
||||
|
||||
- Report bugs through [GitHub Issues](https://github.com/Prodigist/ReactiveNotes/issues)
|
||||
- Request features in [Discussions](https://github.com/Prodigist/ReactiveNotes/discussions)
|
||||
- Join our [Discord community](# "Discord link to be added")
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) for details
|
||||
MIT License - see [LICENSE](# "LICENSE") for details
|
||||
|
||||
---
|
||||
|
||||
<p align="center">Built with ❤️ for the Obsidian community</p>
|
||||
<p align="center">⚡️Built to advance the Obsidian powerhouse</p>
|
||||
|
||||
|
||||
|
||||
[](https://www.buymeacoffee.com/prodigist)
|
||||
76
main.tsx
76
main.tsx
|
|
@ -7,35 +7,14 @@ import tailwindcss from 'tailwindcss';
|
|||
import autoprefixer from 'autoprefixer';
|
||||
import { StorageManager } from 'src/core/storage';
|
||||
import { useStorage } from 'src/hooks/useStorage';
|
||||
import { createChart } from 'lightweight-charts';
|
||||
import { Card, CardHeader, CardTitle, CardContent } from 'src/components/ui/card';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from 'src/components/ui/tabs';
|
||||
import { ComponentRegistry } from 'src/components/componentRegistry';
|
||||
import { ErrorBoundary } from 'src/components/ErrorBoundary';
|
||||
|
||||
//Optional niche market analysis tools
|
||||
import { useMarketData } from 'src/core/useMarketData';
|
||||
import { createMarketDataHook } from 'src/core/useMarketData';
|
||||
import { MarketDataService } from 'src/services/marketDataService';
|
||||
import { Switch } from 'src/components/ui/switch';
|
||||
import { OrderBlockAnalysisService } from 'src/services/OrderBlockAnalysis';
|
||||
import { Upload, Activity,AlertCircle, TrendingUp, TrendingDown, } from 'lucide-react';
|
||||
import { forceSimulation, forceLink, forceManyBody, forceCenter } from 'd3-force';
|
||||
// Add all React components you want to make available
|
||||
import {
|
||||
PieChart,
|
||||
Pie,
|
||||
Cell,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
Legend,
|
||||
ComposedChart,
|
||||
BarChart,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Bar,
|
||||
Line,
|
||||
Area,
|
||||
ReferenceLine,
|
||||
LineChart,
|
||||
} from 'recharts';
|
||||
import { MarketDataStorage } from 'src/services/marketDataStorage';
|
||||
|
||||
class ReactComponentChild extends MarkdownRenderChild {
|
||||
|
|
@ -120,6 +99,14 @@ class ReactComponentChild extends MarkdownRenderChild {
|
|||
);
|
||||
};
|
||||
private preprocessCode(code: string): string {
|
||||
|
||||
// Replace CDN imports with script loading
|
||||
code = code.replace(
|
||||
/import\s+(\w+)\s+from\s+['"]https:\/\/cdnjs\.cloudflare\.com\/([^'"]+)['"]/g,
|
||||
(match, importName, cdnPath) => `
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdnjs.cloudflare.com/${cdnPath}';
|
||||
document.body.appendChild(script);`);
|
||||
// Remove imports more carefully
|
||||
code = code.replace(/import\s+.*?['"]\s*;?\s*$/gm, '');
|
||||
code = code.replace(/import\s*{[^}]*}\s*from\s*['"][^'"]*['"];?\s*$/gm, '');
|
||||
|
|
@ -251,49 +238,12 @@ class ReactComponentChild extends MarkdownRenderChild {
|
|||
const useMarketData = createMarketDataHook(this.storage, this.noteFile);
|
||||
// Create scope with all required dependencies
|
||||
const scope = {
|
||||
React,
|
||||
useState: React.useState,
|
||||
useEffect: React.useEffect,
|
||||
useRef: React.useRef,
|
||||
useMemo: React.useMemo,
|
||||
...ComponentRegistry,
|
||||
useStorage: boundUseStorage,
|
||||
useMarketData,
|
||||
useCallback:React.useCallback,
|
||||
MarketDataStorage,
|
||||
OrderBlockAnalysisService,
|
||||
MarketDataService,
|
||||
// Chart library
|
||||
createChart,
|
||||
// UI Components
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardContent,
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
Switch,
|
||||
PieChart,
|
||||
Pie,
|
||||
Cell,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
Legend,
|
||||
ComposedChart, // Add these chart components
|
||||
BarChart,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Bar,
|
||||
Upload,
|
||||
Area,
|
||||
Line,
|
||||
ReferenceLine,
|
||||
LineChart,
|
||||
Activity,
|
||||
AlertCircle,
|
||||
TrendingUp, TrendingDown,
|
||||
forceSimulation, forceLink, forceManyBody, forceCenter,
|
||||
getTheme: () => document.body.hasClass('theme-dark') ? 'dark' : 'light',
|
||||
// Add note context
|
||||
noteContext: {
|
||||
|
|
@ -354,7 +304,7 @@ class ReactComponentChild extends MarkdownRenderChild {
|
|||
}
|
||||
}
|
||||
|
||||
export default class ReactTestPlugin extends Plugin {
|
||||
export default class ReactNotesPlugin extends Plugin {
|
||||
async onload() {
|
||||
// Listen for theme changes
|
||||
this.registerEvent(
|
||||
|
|
|
|||
|
|
@ -1,133 +1,130 @@
|
|||
// src/components/ComponentRenderer.tsx
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { transform } from '@babel/standalone';
|
||||
import { ErrorBoundary } from './ErrorBoundary';
|
||||
import { App } from 'obsidian';
|
||||
import { useStorage } from '../hooks/useStorage';
|
||||
import { ComponentRegistry } from '../core/registry';
|
||||
import { StorageManager } from '../core/storage';
|
||||
// src/config/componentRegistry.ts
|
||||
import React from 'react';
|
||||
import {
|
||||
PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend,
|
||||
ComposedChart, BarChart, XAxis, YAxis, Bar, Line, Area,
|
||||
ReferenceLine, LineChart
|
||||
} from 'recharts';
|
||||
import { createChart } from 'lightweight-charts';
|
||||
import { forceSimulation, forceLink, forceManyBody, forceCenter } from 'd3-force';
|
||||
import {
|
||||
Upload, Activity, AlertCircle, TrendingUp, TrendingDown,
|
||||
// Add other icons as needed
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
Card, CardHeader, CardTitle, CardContent,
|
||||
Tabs, TabsContent, TabsList, TabsTrigger,
|
||||
Switch,
|
||||
} from 'src/components/ui/';
|
||||
|
||||
interface ComponentRendererProps {
|
||||
code: string;
|
||||
scopeId: string;
|
||||
inline?: boolean;
|
||||
storage: StorageManager; // Add storage prop
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
// Core React hooks wrapper
|
||||
// Type for React utilities (non-component exports)
|
||||
export const ReactUtils = {
|
||||
React,
|
||||
useState: React.useState,
|
||||
useEffect: React.useEffect,
|
||||
useRef: React.useRef,
|
||||
useMemo: React.useMemo,
|
||||
useCallback: React.useCallback,
|
||||
} as const;
|
||||
|
||||
interface TransformError {
|
||||
message: string;
|
||||
line?: number;
|
||||
column?: number;
|
||||
}
|
||||
// Only actual components
|
||||
export const Components = {
|
||||
// Chart Components
|
||||
PieChart,
|
||||
Pie,
|
||||
Cell,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
Legend,
|
||||
ComposedChart,
|
||||
BarChart,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Bar,
|
||||
Line,
|
||||
Area,
|
||||
ReferenceLine,
|
||||
LineChart,
|
||||
|
||||
// UI Components
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardContent,
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
Switch,
|
||||
|
||||
const ErrorDisplay: React.FC<{ error: TransformError }> = ({ error }) => {
|
||||
return (
|
||||
<div className="react-component-error">
|
||||
<p>Error in component:</p>
|
||||
<pre className="error-message">
|
||||
{error.message}
|
||||
{error.line && error.column &&
|
||||
`\nAt line ${error.line}, column ${error.column}`
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
// Icons
|
||||
Upload,
|
||||
Activity,
|
||||
AlertCircle,
|
||||
TrendingUp,
|
||||
TrendingDown,
|
||||
} as const;
|
||||
|
||||
// Utilities that aren't React components
|
||||
export const Utilities = {
|
||||
createChart,
|
||||
forceSimulation,
|
||||
forceLink,
|
||||
forceManyBody,
|
||||
forceCenter,
|
||||
} as const;
|
||||
|
||||
|
||||
|
||||
// All exports combined
|
||||
export const ComponentRegistry = {
|
||||
...ReactUtils,
|
||||
...Components,
|
||||
...Utilities,
|
||||
} as const;
|
||||
|
||||
|
||||
|
||||
// Optional: Type guard for checking if a component exists
|
||||
export const hasComponent = (name: string): name is keyof typeof ComponentRegistry => {
|
||||
return name in ComponentRegistry;
|
||||
};
|
||||
|
||||
export const ComponentRenderer: React.FC<ComponentRendererProps> = ({
|
||||
code,
|
||||
scopeId,
|
||||
storage, // Get storage from props
|
||||
inline = false
|
||||
}) => {
|
||||
const [Component, setComponent] = useState<React.ComponentType | null>(null);
|
||||
const [error, setError] = useState<TransformError | null>(null);
|
||||
// main.tsx can now be simplified to:
|
||||
// import { ComponentRegistry } from './config/componentRegistry';
|
||||
// const scope = ComponentRegistry;
|
||||
|
||||
useEffect(() => {
|
||||
const createComponent = async () => {
|
||||
try {
|
||||
const transformedCode = transform(code, {
|
||||
presets: ['env','react'],
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-jsx', // Add JSX syntax plugin explicitly
|
||||
'@babel/plugin-transform-react-jsx', // Transforms JSX into JS
|
||||
'@babel/plugin-proposal-class-properties', // Handles class properties
|
||||
'@babel/plugin-proposal-object-rest-spread', // Handles object spread syntax
|
||||
],
|
||||
filename: `component-${scopeId}`,
|
||||
sourceType: 'module',
|
||||
configFile: false,
|
||||
babelrc: false
|
||||
}).code;
|
||||
console.log('Transformed Code:', transformedCode);
|
||||
// Create storage hook bound to this storage instance
|
||||
const boundUseStorage = <T,>(key: string, defaultValue: T) =>
|
||||
useStorage(key, defaultValue, storage);
|
||||
|
||||
// Enhanced scope with registry and storage
|
||||
const scope = {
|
||||
React,
|
||||
useState: React.useState,
|
||||
useEffect: React.useEffect,
|
||||
useRef: React.useRef,
|
||||
useStorage: boundUseStorage, // Add bound storage hook
|
||||
...ComponentRegistry,
|
||||
};
|
||||
/* Optionol stuff
|
||||
// Type for actual components only
|
||||
type ComponentsOnly = {
|
||||
[K in keyof typeof Components]: typeof Components[K];
|
||||
};
|
||||
|
||||
const componentFn = new Function(
|
||||
...Object.keys(scope),
|
||||
`try {
|
||||
${transformedCode}
|
||||
return Component;
|
||||
} catch (err) {
|
||||
console.error('Error in component execution:', err);
|
||||
throw err;
|
||||
}`
|
||||
);
|
||||
// Type for props of actual components
|
||||
export type ComponentProps = {
|
||||
[K in keyof ComponentsOnly]: ComponentsOnly[K] extends ComponentType<infer P> ? P : never;
|
||||
};
|
||||
|
||||
const ComponentType = componentFn(...Object.values(scope));
|
||||
setComponent(() => ComponentType);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error('Component transformation failed:', err);
|
||||
setError({
|
||||
message: err instanceof Error ? err.message : 'Unknown error',
|
||||
line: (err as any).loc?.line,
|
||||
column: (err as any).loc?.column
|
||||
});
|
||||
setComponent(null);
|
||||
}
|
||||
};
|
||||
// Type guard for checking if something is a component
|
||||
export const isComponent = (name: keyof typeof ComponentRegistry): name is keyof ComponentsOnly => {
|
||||
return name in Components;
|
||||
};
|
||||
|
||||
createComponent();
|
||||
}, [code, scopeId, storage]); // Add storage to dependencies
|
||||
// Type guard for checking if something is a utility
|
||||
export const isUtility = (name: keyof typeof ComponentRegistry): name is keyof typeof Utilities => {
|
||||
return name in Utilities;
|
||||
};
|
||||
|
||||
const Wrapper: React.FC<{ children: React.ReactNode }> =
|
||||
inline ? ({ children }) => (
|
||||
<span className="inline-component">{children}</span>
|
||||
) : ({ children }) => (
|
||||
<div className="block-component">{children}</div>
|
||||
);
|
||||
// Helper to get component safely
|
||||
export function getComponent<K extends keyof ComponentsOnly>(name: K): ComponentsOnly[K] {
|
||||
return Components[name];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ErrorDisplay error={error} />;
|
||||
}
|
||||
|
||||
if (!Component) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<div
|
||||
className="component-sandbox"
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
<Component />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
// Optional: Type-safe hook usage
|
||||
type Hook<T> = (...args: any[]) => T;
|
||||
export const getHook = <T>(name: keyof typeof ReactUtils): Hook<T> | undefined => {
|
||||
const hook = ReactUtils[name];
|
||||
return typeof hook === 'function' ? hook as Hook<T> : undefined;
|
||||
};*/
|
||||
Loading…
Reference in a new issue