
Research
/Security News
9 Malicious NuGet Packages Deliver Time-Delayed Destructive Payloads
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.
@jamsch/react-mockups
Advanced tools
Tools to develop components in isolation for React & React Native
react-mockups is a lean (no runtime dependencies) alternative to Storybook that provides a similar API with CLI & IDE tooling for React & React Native to develop your components in isolation. It's primary goal is to be easily integrated in to your web & native projects (as a regular component) without requiring any custom build tools.

npm install -S @jamsch/react-mockups
This library makes heavy use of a mockups.js file to load your components. The spec of a mockups.js file is the following:
// mockups.js
import * as MockupName from './path/to/mockup';
export default {
'./path/to/mockup.js': MockupName,
// etc...
};
This package includes a CLI tool that finds all *.mockup.js/ts/tsx files in your project to generate a mockups.js file. You can configure it as a CLI argument or through package.json
package.jsonconfig key with the following options:// package.json
{
"scripts": {
"mockup:generate": "react-mockups generate"
},
"config": {
"react-mockups": {
"searchDir": ["./src"],
"pattern": "**/*.mockup.tsx",
"outputFile": "./src/mockups.ts",
// (optional) Server options
"port": "1337",
"host": "127.0.0.1"
}
}
}
npm run mockup:generate to generate the mockups.ts file.Alternatively, you can call the CLI directly in case you'd like to generate multiple mockup files for various parts of your app.
react-mockups [options]
Commands:
react-mockups server [-p 1337] Start the server
react-mockups generate Generate the mockups file
Options:
--version Show version number [boolean]
--help Show help [boolean]
react-mockups generate
Generate the mockups file
Options:
--searchDir The directory or directories, relative to the project root, to
search for files in. [array]
--pattern Pattern to search the search directories with. Note: if pattern
contains '**/*' it must be escaped with quotes [string]
--outputFile Path to the output file. [string]
--startServer Starts the server [boolean]
--debug Sets log level to debug [boolean]
--silent Silences all logging [boolean]
react-mockups server [-p 1337]
Start the server
Options:
-p, --port Port to listen on [number] [default: 1337]
-h, --host Hostname [string] [default: "127.0.0.1"]
// Button.mockup.jsx
import React from 'react';
import { Button, View } from 'react-native';
export default {
// What will be displayed on the root view
title: 'Buttons',
// What will be rendered when selected
component: () => {
return (
<View>
<Button title="Red button" style={{ backgroundColor: 'red' }} />
<Button title="Blue button" style={{ backgroundColor: 'blue' }} />
</View>
);
},
};
mockups file (or create one yourself using the spec above)MockupRoot and provide it the list of mockups// MockupApp.jsx
import React from 'react';
import { MockupRoot } from '@jamsch/react-mockups/native';
// for web: import { MockupRoot } from '@jamsch/react-mockups/web';
import mockups from './mockups'; // your generated file
export default function MockupApp() {
return <MockupRoot mockups={mockups} />;
}
Tip: For react-native projects you can conditionally load your Mockup view as the app root using
babel-plugin-transform-inline-environment-variables, for example:
// babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['transform-inline-environment-variables'],
};
// package.json
"scripts": {
"start": "react-native start",
"mockup": "cross-env MOCKUP=true npm start",
"premockup": "react-mockups generate"
}
// index.js
import App from './src/App';
if (process.env.MOCKUP) {
const MockupApp = require('./src/MockupApp').default;
AppRegistry.registerComponent('RnDiffApp', () => MockupApp);
} else {
AppRegistry.registerComponent('RnDiffApp', () => App);
}
You can import Meta to help assist typechecking exports on *.mockup.tsx files
// Button.mockup.tsx
import React from 'react';
import { Button, View } from 'react-native';
import type { Meta } from '@jamsch/react-mockups';
export default {
// What will be displayed on the root view
title: 'Buttons',
// What will be rendered when selected
component: () => {
return (
<View>
<Button title="Red button" style={{ backgroundColor: 'red' }} />
<Button title="Blue button" style={{ backgroundColor: 'blue' }} />
</View>
);
},
} as Meta;
In case you'd like to persist the same mockup view across refreshes, you'd probably want to use a package like @react-native-async-storage/async-storage to store the path. Here's a quick recipe.
import React, { useState, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { MockupRoot } from '@jamsch/react-mockups/native';
import mockups from './mockups'; // your generated file
const STORAGE_KEY = 'MOCKUP_INITIAL_PATH';
export default function MockupApp() {
const [initialPath, setInitialPath] = useState(null);
// Load from AsyncStorage
useEffect(() => {
AsyncStorage.getItem(STORAGE_KEY)
.then((path) => {
setInitialPath(path || '');
})
.catch(() => setInitialPath(''));
}, []);
// Wait till we've tried to fetch from AsyncStorage
if (typeof initialPath !== 'string') {
return null;
}
// Render the view
return (
<MockupRoot
mockups={mockups}
// When a navigation occurs, store the path in AsyncStorage
onNavigate={(path) => {
if (path) {
AsyncStorage.setItem(STORAGE_KEY, path);
} else {
// The user may navigate back to the root
AsyncStorage.removeItem(STORAGE_KEY);
}
}}
// Initial component to render
initialPath={initialPath}
/>
);
}
// MockupApp.jsx
import React from 'react';
import { Pressable, Text } from 'react-native';
import { MockupRoot } from '@jamsch/react-mockups/native';
import mockups from './mockups'; // your generated file
export default function MockupApp() {
return (
<MockupRoot
mockups={mockups}
// Customise the list item to render
renderItem={({ path, navigate, title }) => {
return (
<Pressable
key={path}
onPress={() => navigate(path)}
android_ripple={{ borderless: false }}
>
<Text>Mockup: {title}</Text>
</Pressable>
);
}}
/>
);
}
{
/** Initial path when mounting */
initialPath?: string;
/** List of mockups */
mockups: Record<string, NodeRequire>;
/** When a navigation occurs */
onNavigate?: (path: string | null) => void;
/** Customise item rendering */
renderItem?: (params: {
path: string;
title: string;
navigate: (path: string) => void;
}) => React.ReactNode;
/** Wrapper component to render a mockup component. Tip: call `navigate(null)` to navigate back to the root */
Wrapper?: FunctionComponent<{
title: string;
path: string;
Component: ComponentType<any>;
navigate: (path: string | null) => void;
}>;
/** Path to websocket server */
server?: string;
}
react-mockups includes a tiny Node.js http & websocket server to allow for integration with IDE tooling (VS code extensions) & web apps.
Preview:

react-mockups server (or npm run mockups:server as shown below) to start the server// package.json
{
"scripts": {
"mockups:server": "react-mockups server",
// alternatively, run server & your app using the same command
"dev": "npm-run-all --parallel mockups:server start"
}
}
server="[host]:[port]" to MockupRootimport React from 'react';
import { MockupRoot } from '@jamsch/react-mockups/native';
import mockups from './mockups';
export default function App() {
return (
<MockupRoot
mockups={mockups}
server="localhost:1337" // path to your server
/>
);
}
Note: for Android devices, you'll likely need to run the following command in order to connect to the websocket server.
adb reverse tcp:1337 tcp:1337
You can install the following VS Code extension if you'd like to navigate between mockup files in your local codebase and on your app. You'll need to be running the Mockup server (react-mockups server) to use this extension.
If you'd like to create your own IDE tooling, here's a quick starter.
/*
type Mockup = {
title: string;
path: string;
children?: Mockup[];
};
*/
let state = {
/** The project's root directory. Useful for navigating to individual mockup files */
projectRoot: "",
/** Whether the server has synced with any app client */
hasSynced: false,
/** {string|null} Current relative path to mockup. You can determine the active mockup by searching "mockups[x].path" */
path: null,
/** {Mockup[]} List of synced mockups with the app client */
mockups: [];
}
function createWebsocket() {
// Connect to websocket server
const websocket = new WebSocket('ws://localhost:1337/websocket');
websocket.onopen = () => {
// Ping the server to get the initial state
websocket.send(JSON.stringify({ type: 'PING' }));
};
websocket.onclose = () => {
// Notify user that they've lost connection to the mockup server
// call reconnect() once confirming with the user
};
websocket.onerror = (error) => {
// Notify user that they've failed to connect to the server
// call reconnect() once confirming with the user
};
websocket.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
// Once an app client has connected, you'll get a "SYNC_STATE" message
case 'SYNC_STATE': {
state = message.payload;
/* {
type: "SYNC_STATE",
payload: {
projectRoot: string;
hasSynced: boolean,
path: string;
mockups: Mockup[];
}>
}*/
break;
}
case 'NAVIGATE': {
// { type: "NAVIGATE", payload: "./src/components/ui/Button.tsx" }
state.path = message.payload;
break;
}
}
};
return websocket;
}
// create a websocket in some context (preferably in a class)
global.websocket = createWebsocket();
const reconnect = () => {
// Reset event listeners to avoid duplicate messages
global.websocket.onclose = () => {};
global.websocket.close();
global.websocket = createWebsocket();
// Re-render your UI
// render()
}
}
const onButtonPress = (mockup) => {
// Navigate to a mockup. This will be broadcasted to all clients
// mockup: { title: 'Button', path: './components/ui/Button.tsx' }
const message = { type: 'NAVIGATE', payload: mockup.path };
ws.send(JSON.stringify(message));
}
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT
FAQs
Tools to develop components in isolation for React & React Native
We found that @jamsch/react-mockups demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.