← All skills
Tencent SkillHub Β· Developer Tools

FOSMVVM React View Generator

Generate React components rendering FOSMVVM ViewModels with hooks, loading states, TypeScript types, test-first scaffolding, and .bind() server request integ...

skill openclawclawhub Free
0 Downloads
0 Stars
0 Installs
0 Score
High Signal

Generate React components rendering FOSMVVM ViewModels with hooks, loading states, TypeScript types, test-first scaffolding, and .bind() server request integ...

⬇ 0 downloads β˜… 0 stars Unverified but indexed

Install for OpenClaw

Quick setup
  1. Download the package from Yavira.
  2. Extract the archive and review SKILL.md first.
  3. Import or place the package into your OpenClaw setup.

Requirements

Target platform
OpenClaw
Install method
Manual import
Extraction
Extract archive
Prerequisites
OpenClaw
Primary doc
SKILL.md

Package facts

Download mode
Yavira redirect
Package format
ZIP package
Source platform
Tencent SkillHub
What's included
SKILL.md, reference.md

Validation

  • Use the Yavira download entry.
  • Review SKILL.md after the package is downloaded.
  • Confirm the extracted package contains the expected setup assets.

Install with your agent

Agent handoff

Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.

  1. Download the package from Yavira.
  2. Extract it into a folder your agent can access.
  3. Paste one of the prompts below and point your agent at the extracted folder.
New install

I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.

Upgrade existing

I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.

Trust & source

Release facts

Source
Tencent SkillHub
Verification
Indexed source record
Version
2.0.6

Documentation

ClawHub primary doc Primary doc: SKILL.md 40 sections Open source page

FOSMVVM React View Generator

Generate React components that render FOSMVVM ViewModels.

Conceptual Foundation

For full architecture context, see FOSMVVMArchitecture.md | OpenClaw reference In FOSMVVM, React components are thin rendering layers that display ViewModels: β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ViewModelView Pattern β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ ViewModel (Data) React Component β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ title: String │────►│ <h1>{vm.title} β”‚ β”‚ β”‚ β”‚ items: [Item] │────►│ {vm.items.map()} β”‚ β”‚ β”‚ β”‚ isEnabled: Bool │────►│ disabled={!...} β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ ServerRequest (Actions) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ processRequest() │◄────│ <Component.bind β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ requestType={} β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Key principle: Components don't transform or compute data. They render what the ViewModel provides.

View-ViewModel Alignment

The component filename should match the ViewModel it renders. src/ viewmodels/ {Feature}ViewModel.js ←──┐ {Entity}CardViewModel.js ←──┼── Same names β”‚ components/ β”‚ {Feature}/ β”‚ {Feature}View.jsx ───── (renders {Feature}ViewModel) {Entity}CardView.jsx β”€β”€β”€β”€β”˜ (renders {Entity}CardViewModel) This alignment provides: Discoverability - Find the component for any ViewModel instantly Consistency - Same naming discipline as SwiftUI and Leaf Maintainability - Changes to ViewModel are reflected in component location

TDD Workflow

This skill generates tests FIRST, implementation SECOND in a single invocation: 1. Reference ViewModel and ServerRequest details from conversation context 2. Generate .test.js file β†’ Tests FAIL (no implementation yet) 3. Generate .jsx file β†’ Tests PASS 4. Verify completeness (both files exist) 5. User runs `npm test` β†’ All tests pass βœ“ Context-aware: Skill references conversation understanding of requirements. No file parsing or Q&A needed.

1. viewModelComponent() Wrapper

Every component is wrapped with viewModelComponent(): const MyView = FOSMVVM.viewModelComponent(({ viewModel }) => { return <div>{viewModel.title}</div>; }); export default MyView; Required: Use FOSMVVM.viewModelComponent() from global namespace (loaded via script tag) Component function receives { viewModel } prop No imports needed - FOSMVVM utilities loaded via <script> tags

2. The .bind() Pattern

Parent components use .bind() to invoke ServerRequests: // Parent component function Dashboard() { return ( <div> <TaskList.bind({ requestType: 'GetTasksRequest', params: { status: 'active' } }) /> </div> ); } The .bind() pattern: Child components receive data via ServerRequest Parent specifies requestType and params WASM bridge handles request β†’ ViewModel β†’ component rendering No fetch() calls, no hardcoded URLs

3. Error ViewModel Handling

Error ViewModels are rendered like any other ViewModel: const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { // Handle error ViewModels if (viewModel.errorType === 'NotFoundError') { return ( <div className="error"> <p>{viewModel.message}</p> <p>{viewModel.suggestedAction}</p> </div> ); } if (viewModel.errorType === 'ValidationError') { return ( <div className="validation-error"> <h3>{viewModel.title}</h3> <ul> {viewModel.errors.map(err => ( <li key={err.field}>{err.message}</li> ))} </ul> </div> ); } // Render success ViewModel return ( <div className="task-card"> <h3>{viewModel.title}</h3> <p>{viewModel.description}</p> </div> ); }); Key principles: No generic error handling Each error type has its own ViewModel Component conditionally renders based on errorType property Error rendering is just data rendering

4. Navigation Intents (Not URLs)

Use navigation intents, not hardcoded paths: // FOSMVVM utilities loaded via <script> tag, available on global namespace // ❌ NEVER <a href="/tasks/123">View Task</a> // βœ… ALWAYS <FOSMVVM.Link to={{ intent: 'viewTask', id: viewModel.id }}> {viewModel.linkText} </FOSMVVM.Link> Navigation patterns: Use FOSMVVM.Link from global namespace (loaded via script tag) Use intent property, not hardcoded paths Router maps intents to routes Platform-independent navigation

Display-Only Components

Components that just render data (no user interactions): const InfoCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <div className="info-card"> <h2>{viewModel.title}</h2> <p>{viewModel.description}</p> {viewModel.isActive && ( <span className="badge">{viewModel.activeLabel}</span> )} </div> ); }); export default InfoCard; Characteristics: Just renders ViewModel properties No event handlers (onClick, onSubmit, etc.) May have conditional rendering based on ViewModel state No .bind() calls to child components

Interactive Components

Components with user actions that trigger ServerRequests: const ActionCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <div className="action-card"> <h2>{viewModel.title}</h2> <p>{viewModel.description}</p> <div className="actions"> <button onClick={() => viewModel.operations.performAction()} disabled={!viewModel.canPerformAction} > {viewModel.actionLabel} </button> <button onClick={() => viewModel.operations.cancel()}> {viewModel.cancelLabel} </button> </div> </div> ); }); export default ActionCard;

List Components

Components that render collections: const TaskList = FOSMVVM.viewModelComponent(({ viewModel }) => { if (viewModel.isEmpty) { return <div className="empty">{viewModel.emptyMessage}</div>; } return ( <div className="task-list"> <h2>{viewModel.title}</h2> <p>{viewModel.totalCount}</p> {viewModel.tasks.map(task => ( <TaskCard.bind({ requestType: 'GetTaskRequest', params: { id: task.id } }) /> ))} </div> ); }); export default TaskList;

Form Components

Components with validated input fields: const SignInForm = FOSMVVM.viewModelComponent(({ viewModel }) => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [errors, setErrors] = useState({}); const handleSubmit = async (e) => { e.preventDefault(); const result = await viewModel.operations.submit({ email, password }); if (result.validationErrors) { setErrors(result.validationErrors); } }; return ( <form onSubmit={handleSubmit}> <div> <label>{viewModel.emailLabel}</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder={viewModel.emailPlaceholder} /> {errors.email && <span className="error">{errors.email}</span>} </div> <div> <label>{viewModel.passwordLabel}</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder={viewModel.passwordPlaceholder} /> {errors.password && <span className="error">{errors.password}</span>} </div> <button type="submit" disabled={viewModel.submitDisabled}> {viewModel.submitLabel} </button> </form> ); }); export default SignInForm;

When to Use This Skill

Creating a new React component for a FOSMVVM app Building UI to render a ViewModel Migrating Leaf templates to React Following an implementation plan that requires new views Creating forms with validation Building list views that compose child components

What This Skill Generates

Two files per invocation: FileLocationPurpose{ViewName}View.test.jssrc/components/{Feature}/Jest + React Testing Library tests{ViewName}View.jsxsrc/components/{Feature}/React component Test file generated FIRST (tests fail initially) Implementation file generated SECOND (tests pass) Note: The corresponding ViewModel and ServerRequest should already exist (use other FOSMVVM generator skills).

Project Structure Configuration

PlaceholderDescriptionExample{ViewName}View name (without "View" suffix)TaskList, SignIn{Feature}Feature/module groupingTasks, Auth

Pattern Implementation

This skill references conversation context to determine component structure:

Component Type Detection

From conversation context, the skill identifies: ViewModel structure (from prior discussion or specifications read by Claude) ServerRequest details (from requirements already in context) Component category: Display-only, interactive, form, or list Error ViewModels to handle

Test Generation (FIRST)

Based on component type, generates .test.js with: All components: Success ViewModel rendering, error ViewModel rendering Interactive: Button clicks, operation verification Form: Input changes, validation errors, submission List: Empty state, multiple items, child binding

Component Generation (SECOND)

Generates .jsx following patterns: Import viewModelComponent wrapper Handle error ViewModels with conditional rendering Render success ViewModel Add interactions (if interactive) Add form state (if form) Add child .bind() calls (if container) Export wrapped component

Context Sources

Skill references information from: Prior conversation: Requirements discussed with user Specification files: If Claude has read specifications into context ViewModel definitions: From codebase or discussion

Step 5: Verify Completeness

Check: .test.js file exists .jsx file exists Component uses FOSMVVM.viewModelComponent() wrapper Component accesses FOSMVVM functions from global namespace Tests cover success and error ViewModels Tests cover user interactions (if applicable)

Pattern: No Business Logic in Components

// ❌ BAD - Component is transforming data const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { const daysLeft = Math.ceil((viewModel.dueDate - Date.now()) / 86400000); return <span>{daysLeft} days remaining</span>; }); // βœ… GOOD - ViewModel provides shaped result const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return <span>{viewModel.daysRemainingText}</span>; });

Pattern: No fetch() Calls

// ❌ BAD - Component making HTTP requests const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { const [data, setData] = useState(null); useEffect(() => { fetch(`/api/tasks/${viewModel.id}`) .then(r => r.json()) .then(setData); }, [viewModel.id]); return <div>{data?.title}</div>; }); // βœ… GOOD - Parent uses .bind() to invoke ServerRequest <TaskCard.bind({ requestType: 'GetTaskRequest', params: { id: taskId } }) />

Pattern: Error ViewModels Are Data

// ❌ BAD - Generic error handling const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { if (viewModel.error) { return <div>Error: {viewModel.error.message}</div>; } return <div>{viewModel.title}</div>; }); // βœ… GOOD - Specific error ViewModels const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { if (viewModel.errorType === 'NotFoundError') { return ( <div className="not-found"> <h3>{viewModel.errorTitle}</h3> <p>{viewModel.errorMessage}</p> <p>{viewModel.suggestedAction}</p> </div> ); } if (viewModel.errorType === 'ValidationError') { return ( <div className="validation-error"> <h3>{viewModel.errorTitle}</h3> <ul> {viewModel.validationErrors.map(err => ( <li key={err.field}>{err.message}</li> ))} </ul> </div> ); } return <div>{viewModel.title}</div>; });

Pattern: Navigation Intents

// ❌ BAD - Hardcoded URLs const TaskRow = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <div> <a href={`/tasks/${viewModel.id}`}>{viewModel.title}</a> </div> ); }); // βœ… GOOD - Navigation intents // FOSMVVM utilities loaded via <script> tag, available on global namespace const TaskRow = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <div> <FOSMVVM.Link to={{ intent: 'viewTask', id: viewModel.id }}> {viewModel.title} </FOSMVVM.Link> </div> ); });

File Organization

src/components/ β”œβ”€β”€ {Feature}/ β”‚ β”œβ”€β”€ {Feature}View.jsx # Full page β†’ {Feature}ViewModel β”‚ β”œβ”€β”€ {Feature}View.test.js # Tests for {Feature}View β”‚ β”œβ”€β”€ {Entity}CardView.jsx # Child component β†’ {Entity}CardViewModel β”‚ β”œβ”€β”€ {Entity}CardView.test.js # Tests for {Entity}CardView β”‚ └── {Entity}RowView.jsx # Child component β†’ {Entity}RowViewModel β”œβ”€β”€ Shared/ β”‚ β”œβ”€β”€ HeaderView.jsx # Shared components β”‚ └── FooterView.jsx

Computing Data in Components

// ❌ BAD - Component is transforming data const UserCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return <div>{viewModel.firstName} {viewModel.lastName}</div>; }); // βœ… GOOD - ViewModel provides shaped result const UserCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return <div>{viewModel.fullName}</div>; });

Making HTTP Requests Directly

// ❌ BAD - fetch() call in component const TaskList = FOSMVVM.viewModelComponent(({ viewModel }) => { const [tasks, setTasks] = useState([]); useEffect(() => { fetch('/api/tasks').then(r => r.json()).then(setTasks); }, []); return <div>{tasks.map(t => <div key={t.id}>{t.title}</div>)}</div>; }); // βœ… GOOD - Parent uses .bind() with ServerRequest <TaskList.bind({ requestType: 'GetTasksRequest', params: {} }) />

Hardcoding Text

// ❌ BAD - Not localizable const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <button onClick={viewModel.operations.submit}> Submit </button> ); }); // βœ… GOOD - ViewModel provides localized text const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <button onClick={viewModel.operations.submit}> {viewModel.submitLabel} </button> ); });

Using Hardcoded URLs

// ❌ BAD - Hardcoded path const TaskRow = FOSMVVM.viewModelComponent(({ viewModel }) => { return <a href={`/tasks/${viewModel.id}`}>{viewModel.title}</a>; }); // βœ… GOOD - Navigation intent // FOSMVVM utilities loaded via <script> tag, available on global namespace const TaskRow = FOSMVVM.viewModelComponent(({ viewModel }) => { return ( <FOSMVVM.Link to={{ intent: 'viewTask', id: viewModel.id }}> {viewModel.title} </FOSMVVM.Link> ); });

Not Wrapping with viewModelComponent()

// ❌ BAD - Missing viewModelComponent() wrapper const TaskCard = ({ viewModel }) => { return <div>{viewModel.title}</div>; }; export default TaskCard; // βœ… GOOD - Wrapped with viewModelComponent() const TaskCard = FOSMVVM.viewModelComponent(({ viewModel }) => { return <div>{viewModel.title}</div>; }); export default TaskCard;

Mismatched Filenames

// ❌ BAD - Filename doesn't match ViewModel ViewModel: TaskListViewModel Component: Tasks.jsx // βœ… GOOD - Aligned names ViewModel: TaskListViewModel Component: TaskListView.jsx

File Templates

See reference.md for complete file templates.

Naming Conventions

ConceptConventionExampleComponent file{Name}View.jsxTaskListView.jsx, SignInView.jsxTest file{Name}View.test.jsTaskListView.test.jsComponent function{Name}ViewTaskListView, SignInViewViewModel propviewModelAlways viewModel

Test: Rendering with Success ViewModel

it('renders task card with ViewModel', () => { const viewModel = { title: 'Test Task', description: 'Test Description', dueDate: 'Jan 30, 2026' }; render(<TaskCard viewModel={viewModel} />); expect(screen.getByText('Test Task')).toBeInTheDocument(); expect(screen.getByText('Test Description')).toBeInTheDocument(); });

Test: Rendering with Error ViewModel

it('renders NotFoundViewModel', () => { const viewModel = { errorType: 'NotFoundError', errorTitle: 'Task Not Found', errorMessage: 'The task you requested does not exist', suggestedAction: 'Try searching for a different task' }; render(<TaskCard viewModel={viewModel} />); expect(screen.getByText('Task Not Found')).toBeInTheDocument(); expect(screen.getByText(/does not exist/)).toBeInTheDocument(); });

Test: User Interaction

it('calls operation when button clicked', () => { const mockOperation = jest.fn(); const viewModel = { title: 'Test Task', submitLabel: 'Complete Task', operations: { complete: mockOperation } }; render(<TaskCard viewModel={viewModel} />); fireEvent.click(screen.getByText('Complete Task')); expect(mockOperation).toHaveBeenCalled(); });

How to Use This Skill

Invocation: /fosmvvm-react-view-generator Prerequisites: ViewModel and ServerRequest details are understood from conversation Optionally, specification files have been read into context Component requirements (display-only, interactive, form, list) are clear from discussion Output: {ComponentName}.test.js - Generated FIRST (tests fail) {ComponentName}.jsx - Generated SECOND (tests pass) Workflow integration: This skill is typically used after discussing requirements or reading specification files. The skill references that context automaticallyβ€”no file paths or Q&A needed.

See Also

Architecture Patterns - Mental models and patterns FOSMVVMArchitecture.md - Full FOSMVVM architecture fosmvvm-swiftui-view-generator - SwiftUI equivalent fosmvvm-leaf-view-generator - Leaf equivalent reference.md - Complete file templates

Version History

VersionDateChanges1.02026-01-23Initial skill for React view generation based on Kairos requirements

Category context

Code helpers, APIs, CLIs, browser automation, testing, and developer operations.

Source: Tencent SkillHub

Largest current source with strong distribution and engagement signals.

Package contents

Included in package
2 Docs
  • SKILL.md Primary doc
  • reference.md Docs