Generate Ink (React for CLI) components for terminal UIs with hooks, state management, and layout components.
Generates React-based terminal UI components with hooks, state management, and interactive layouts.
npx claudepluginhub a5c-ai/babysitterThis skill is limited to using the following tools:
README.mdGenerate Ink (React) components for terminal UIs.
Invoke this skill when you need to:
| Parameter | Type | Required | Description |
|---|---|---|---|
| projectName | string | Yes | Project name |
| components | array | Yes | Component definitions |
| includeHooks | boolean | No | Generate custom hooks |
{
"components": [
{
"name": "SelectList",
"type": "interactive",
"props": ["items", "onSelect"],
"state": ["selectedIndex"]
}
]
}
import React, { useState, useCallback } from 'react';
import { Box, Text, useInput, useApp } from 'ink';
interface SelectListProps {
items: string[];
onSelect: (item: string, index: number) => void;
}
export const SelectList: React.FC<SelectListProps> = ({ items, onSelect }) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const { exit } = useApp();
useInput((input, key) => {
if (key.upArrow) {
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : items.length - 1));
} else if (key.downArrow) {
setSelectedIndex((prev) => (prev < items.length - 1 ? prev + 1 : 0));
} else if (key.return) {
onSelect(items[selectedIndex], selectedIndex);
} else if (input === 'q' || key.escape) {
exit();
}
});
return (
<Box flexDirection="column">
{items.map((item, index) => (
<Box key={item}>
<Text color={index === selectedIndex ? 'green' : undefined}>
{index === selectedIndex ? '> ' : ' '}
{item}
</Text>
</Box>
))}
<Box marginTop={1}>
<Text dimColor>Use arrow keys to navigate, Enter to select, q to quit</Text>
</Box>
</Box>
);
};
import React, { useState } from 'react';
import { Box, Text, useInput } from 'ink';
interface TextInputProps {
placeholder?: string;
onSubmit: (value: string) => void;
mask?: string;
}
export const TextInput: React.FC<TextInputProps> = ({
placeholder = '',
onSubmit,
mask,
}) => {
const [value, setValue] = useState('');
const [cursor, setCursor] = useState(0);
useInput((input, key) => {
if (key.return) {
onSubmit(value);
return;
}
if (key.backspace || key.delete) {
setValue((prev) => prev.slice(0, -1));
setCursor((prev) => Math.max(0, prev - 1));
return;
}
if (!key.ctrl && !key.meta && input) {
setValue((prev) => prev + input);
setCursor((prev) => prev + 1);
}
});
const displayValue = mask ? mask.repeat(value.length) : value;
return (
<Box>
<Text>
{displayValue || <Text dimColor>{placeholder}</Text>}
<Text backgroundColor="white"> </Text>
</Text>
</Box>
);
};
import React, { useState, useEffect } from 'react';
import { Text } from 'ink';
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
interface SpinnerProps {
label?: string;
}
export const Spinner: React.FC<SpinnerProps> = ({ label }) => {
const [frame, setFrame] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setFrame((prev) => (prev + 1) % frames.length);
}, 80);
return () => clearInterval(timer);
}, []);
return (
<Text>
<Text color="green">{frames[frame]}</Text>
{label && <Text> {label}</Text>}
</Text>
);
};
import { useState, useEffect, useCallback } from 'react';
interface AsyncState<T> {
data: T | null;
loading: boolean;
error: Error | null;
}
export function useAsync<T>(
asyncFn: () => Promise<T>,
deps: any[] = []
): AsyncState<T> & { refetch: () => void } {
const [state, setState] = useState<AsyncState<T>>({
data: null,
loading: true,
error: null,
});
const execute = useCallback(async () => {
setState({ data: null, loading: true, error: null });
try {
const data = await asyncFn();
setState({ data, loading: false, error: null });
} catch (error) {
setState({ data: null, loading: false, error: error as Error });
}
}, deps);
useEffect(() => {
execute();
}, [execute]);
return { ...state, refetch: execute };
}
{
"dependencies": {
"ink": "^4.0.0",
"react": "^18.0.0"
},
"devDependencies": {
"@types/react": "^18.0.0",
"ink-testing-library": "^3.0.0"
}
}
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.