| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- import { z } from "zod";
- // =============================================================================
- // Standard Component Definitions for React Native
- // =============================================================================
- /**
- * Standard component definitions for React Native catalogs.
- *
- * These can be used directly or extended with custom components.
- * All components are built using React Native core primitives only.
- */
- export const standardComponentDefinitions = {
- // ==========================================================================
- // Layout Components
- // ==========================================================================
- Container: {
- props: z.object({
- padding: z.number().nullable(),
- paddingHorizontal: z.number().nullable(),
- paddingVertical: z.number().nullable(),
- margin: z.number().nullable(),
- backgroundColor: z.string().nullable(),
- borderRadius: z.number().nullable(),
- flex: z.number().nullable(),
- }),
- slots: ["default"],
- description:
- "Generic container wrapper. Use for grouping elements with padding, margin, and background color.",
- example: { padding: 16, backgroundColor: "#FFFFFF" },
- },
- Row: {
- props: z.object({
- gap: z.number().nullable(),
- alignItems: z
- .enum(["flex-start", "center", "flex-end", "stretch", "baseline"])
- .nullable(),
- justifyContent: z
- .enum([
- "flex-start",
- "center",
- "flex-end",
- "space-between",
- "space-around",
- "space-evenly",
- ])
- .nullable(),
- flexWrap: z.enum(["wrap", "nowrap"]).nullable(),
- padding: z.number().nullable(),
- flex: z.number().nullable(),
- }),
- slots: ["default"],
- description:
- "Horizontal flex layout. Use for placing elements side by side.",
- example: { gap: 12, alignItems: "center" },
- },
- Column: {
- props: z.object({
- gap: z.number().nullable(),
- alignItems: z
- .enum(["flex-start", "center", "flex-end", "stretch", "baseline"])
- .nullable(),
- justifyContent: z
- .enum([
- "flex-start",
- "center",
- "flex-end",
- "space-between",
- "space-around",
- "space-evenly",
- ])
- .nullable(),
- padding: z.number().nullable(),
- flex: z.number().nullable(),
- }),
- slots: ["default"],
- description:
- "Vertical flex layout. Use for stacking elements top to bottom.",
- example: { gap: 12, padding: 16 },
- },
- ScrollContainer: {
- props: z.object({
- horizontal: z.boolean().nullable(),
- showsScrollIndicator: z.boolean().nullable(),
- padding: z.number().nullable(),
- backgroundColor: z.string().nullable(),
- }),
- slots: ["default"],
- description:
- "Scrollable container. Use for content that may overflow the screen.",
- },
- SafeArea: {
- props: z.object({
- backgroundColor: z.string().nullable(),
- }),
- slots: ["default"],
- description:
- "Safe area container that respects device notches and system bars. Use as the outermost wrapper for screens.",
- },
- Spacer: {
- props: z.object({
- size: z.number().nullable(),
- flex: z.number().nullable(),
- }),
- slots: [],
- description:
- "Empty space between elements. Set size for fixed spacing or flex for flexible spacing.",
- },
- Pressable: {
- props: z.object({}),
- events: ["press", "longPress"],
- slots: ["default"],
- description:
- "Touchable wrapper that triggers events on press. Wrap any element to make it tappable. Bind on.press to setState to update state for visibility-driven UIs like tabs.",
- },
- Divider: {
- props: z.object({
- direction: z.enum(["horizontal", "vertical"]).nullable(),
- color: z.string().nullable(),
- thickness: z.number().nullable(),
- margin: z.number().nullable(),
- }),
- slots: [],
- description: "Thin line separator between content sections.",
- },
- // ==========================================================================
- // Content Components
- // ==========================================================================
- Heading: {
- props: z.object({
- text: z.string(),
- level: z.enum(["h1", "h2", "h3", "h4"]).nullable(),
- color: z.string().nullable(),
- align: z.enum(["left", "center", "right"]).nullable(),
- }),
- slots: [],
- description:
- "Heading text at various levels. h1 is largest, h4 is smallest.",
- example: { text: "Welcome", level: "h1" },
- },
- Paragraph: {
- props: z.object({
- text: z.string(),
- color: z.string().nullable(),
- align: z.enum(["left", "center", "right"]).nullable(),
- numberOfLines: z.number().nullable(),
- fontSize: z.number().nullable(),
- }),
- slots: [],
- description:
- "Body text paragraph. Use for descriptions and longer content.",
- example: { text: "This is a paragraph of body text." },
- },
- Label: {
- props: z.object({
- text: z.string(),
- color: z.string().nullable(),
- bold: z.boolean().nullable(),
- size: z.enum(["xs", "sm", "md"]).nullable(),
- }),
- slots: [],
- description:
- "Small utility text. Use for captions, form labels, and secondary information.",
- example: { text: "Status", size: "sm" },
- },
- Image: {
- props: z.object({
- src: z.string(),
- alt: z.string().nullable(),
- width: z.number().nullable(),
- height: z.number().nullable(),
- resizeMode: z.enum(["cover", "contain", "stretch", "center"]).nullable(),
- borderRadius: z.number().nullable(),
- }),
- slots: [],
- description: "Image display. Provide a source URL and optional dimensions.",
- example: {
- src: "https://picsum.photos/300/200",
- alt: "Photo",
- width: 300,
- height: 200,
- },
- },
- Avatar: {
- props: z.object({
- src: z.string().nullable(),
- initials: z.string().nullable(),
- size: z.enum(["sm", "md", "lg", "xl"]).nullable(),
- backgroundColor: z.string().nullable(),
- }),
- slots: [],
- description:
- "Circular avatar showing an image or initials. Use for user profiles and contacts.",
- example: { initials: "JD", size: "md" },
- },
- Badge: {
- props: z.object({
- label: z.string(),
- variant: z
- .enum(["default", "info", "success", "warning", "error"])
- .nullable(),
- }),
- slots: [],
- description:
- "Small colored indicator with a label. Use for status, counts, and categories.",
- example: { label: "New", variant: "info" },
- },
- Chip: {
- props: z.object({
- label: z.string(),
- selected: z.boolean().nullable(),
- backgroundColor: z.string().nullable(),
- }),
- events: ["press", "remove"],
- slots: [],
- description:
- "Tag or filter chip. Bind on.remove for removable chips, on.press for selectable chips.",
- },
- // ==========================================================================
- // Input Components
- // ==========================================================================
- Button: {
- props: z.object({
- label: z.string(),
- variant: z
- .enum(["primary", "secondary", "danger", "outline", "ghost"])
- .nullable(),
- size: z.enum(["sm", "md", "lg"]).nullable(),
- disabled: z.boolean().nullable(),
- loading: z.boolean().nullable(),
- }),
- events: ["press"],
- slots: [],
- description:
- "Pressable button with label. Set variant for styling. Bind on.press for the handler to call on press.",
- example: { label: "Submit", variant: "primary" },
- },
- TextInput: {
- props: z.object({
- placeholder: z.string().nullable(),
- value: z.string().nullable(),
- secureTextEntry: z.boolean().nullable(),
- keyboardType: z
- .enum(["default", "email-address", "numeric", "phone-pad", "url"])
- .nullable(),
- multiline: z.boolean().nullable(),
- numberOfLines: z.number().nullable(),
- label: z.string().nullable(),
- flex: z.number().nullable(),
- }),
- events: ["submit", "focus", "blur"],
- slots: [],
- description:
- "Text input field. Use $bindState to bind to the state model for two-way binding. The value typed by the user is stored at the bound path.",
- example: {
- placeholder: "Enter text...",
- label: "Name",
- },
- },
- Switch: {
- props: z.object({
- checked: z.boolean().nullable(),
- label: z.string().nullable(),
- disabled: z.boolean().nullable(),
- }),
- events: ["change"],
- slots: [],
- description: "Toggle switch. Use $bindState to bind to the state model.",
- },
- Checkbox: {
- props: z.object({
- checked: z.boolean().nullable(),
- label: z.string().nullable(),
- disabled: z.boolean().nullable(),
- }),
- events: ["change"],
- slots: [],
- description:
- "Checkbox for boolean selections. Use $bindState to bind to the state model.",
- },
- Slider: {
- props: z.object({
- min: z.number().nullable(),
- max: z.number().nullable(),
- step: z.number().nullable(),
- value: z.number().nullable(),
- label: z.string().nullable(),
- color: z.string().nullable(),
- }),
- slots: [],
- description:
- "Range slider for numeric values. Use $bindState to bind to the state model.",
- },
- SearchBar: {
- props: z.object({
- placeholder: z.string().nullable(),
- value: z.string().nullable(),
- }),
- events: ["submit"],
- slots: [],
- description:
- "Search input with icon. Bind on.submit to trigger search on submit.",
- },
- // ==========================================================================
- // Feedback Components
- // ==========================================================================
- Spinner: {
- props: z.object({
- size: z.enum(["small", "large"]).nullable(),
- color: z.string().nullable(),
- }),
- slots: [],
- description: "Loading spinner indicator. Use while content is loading.",
- },
- ProgressBar: {
- props: z.object({
- progress: z.number(),
- color: z.string().nullable(),
- trackColor: z.string().nullable(),
- height: z.number().nullable(),
- }),
- slots: [],
- description: "Horizontal progress bar. Set progress from 0 to 1.",
- },
- // ==========================================================================
- // Composite Components
- // ==========================================================================
- Card: {
- props: z.object({
- title: z.string().nullable(),
- subtitle: z.string().nullable(),
- padding: z.number().nullable(),
- backgroundColor: z.string().nullable(),
- borderRadius: z.number().nullable(),
- elevated: z.boolean().nullable(),
- }),
- slots: ["default"],
- description:
- "Elevated card container with optional title. Use for grouping related content.",
- example: { title: "Details", padding: 16, elevated: true },
- },
- ListItem: {
- props: z.object({
- title: z.string(),
- subtitle: z.string().nullable(),
- leading: z.string().nullable(),
- trailing: z.string().nullable(),
- showChevron: z.boolean().nullable(),
- }),
- events: ["press"],
- slots: [],
- description:
- "List row with title, subtitle, and optional leading/trailing text. Bind on.press for the press handler.",
- example: {
- title: "Settings",
- subtitle: "Manage your preferences",
- showChevron: true,
- },
- },
- Modal: {
- props: z.object({
- visible: z.boolean(),
- title: z.string().nullable(),
- animationType: z.enum(["slide", "fade", "none"]).nullable(),
- }),
- slots: ["default"],
- description:
- "Modal overlay dialog. Use $bindState on visible to bind visibility to the state model.",
- },
- };
- // =============================================================================
- // Standard Action Definitions for React Native
- // =============================================================================
- /**
- * Standard action definitions for React Native catalogs.
- *
- * These use React Native core APIs (Alert, Share, Linking) and
- * user-provided functions (navigate).
- */
- export const standardActionDefinitions = {
- navigate: {
- params: z.object({
- screen: z.string(),
- params: z.record(z.string(), z.unknown()).nullable(),
- }),
- description:
- "Navigate to a screen. Calls the user-provided navigation function.",
- },
- goBack: {
- params: z.object({}),
- description: "Navigate back to the previous screen.",
- },
- showAlert: {
- params: z.object({
- title: z.string(),
- message: z.string().nullable(),
- buttons: z
- .array(
- z.object({
- text: z.string(),
- style: z.enum(["default", "cancel", "destructive"]).nullable(),
- action: z.string().nullable(),
- }),
- )
- .nullable(),
- }),
- description: "Show a native alert dialog using Alert.alert().",
- },
- share: {
- params: z.object({
- message: z.string(),
- url: z.string().nullable(),
- title: z.string().nullable(),
- }),
- description: "Open the native share sheet using Share.share().",
- },
- openURL: {
- params: z.object({
- url: z.string(),
- }),
- description: "Open a URL in the default browser using Linking.openURL().",
- },
- setState: {
- params: z.object({
- statePath: z.string(),
- value: z.unknown(),
- }),
- description: "Update a value in the state model at the given statePath.",
- },
- pushState: {
- params: z.object({
- statePath: z.string(),
- value: z.unknown(),
- clearStatePath: z.string().optional(),
- }),
- description:
- 'Append an item to an array in the state model. The value can contain { $state: "/statePath" } references to read from current state, and "$id" to auto-generate a unique ID. Use clearStatePath to reset another path after pushing (e.g. clear an input field). Example: { statePath: "/todos", value: { id: "$id", title: { $state: "/newTodoText" }, completed: false }, clearStatePath: "/newTodoText" }.',
- },
- removeState: {
- params: z.object({
- statePath: z.string(),
- index: z.number(),
- }),
- description:
- "Remove an item from an array in the state model at the given index.",
- },
- refresh: {
- params: z.object({
- target: z.string().nullable(),
- }),
- description:
- "Trigger a data refresh. Optionally specify a target to refresh.",
- },
- };
- // =============================================================================
- // Types
- // =============================================================================
- /**
- * Type for a component definition
- */
- export type ComponentDefinition = {
- props: z.ZodType;
- slots: string[];
- events?: string[];
- description: string;
- };
- /**
- * Type for an action definition
- */
- export type ActionDefinition = {
- params: z.ZodType;
- description: string;
- };
|