=
+ z.output<(typeof antdComponentDefinitions)[K]["props"]>;
+
+/**
+ * Bindings configuration for state binding paths.
+ * Used for two-way data binding with state management.
+ */
+export type BindingsConfig = {
+ [key: string]: string | undefined;
+};
+
+/**
+ * Event emit function type
+ */
+export type EmitFunction = (eventName: string) => void;
diff --git a/packages/antd/src/components.tsx b/packages/antd/src/components.tsx
new file mode 100644
index 00000000..8c33acbc
--- /dev/null
+++ b/packages/antd/src/components.tsx
@@ -0,0 +1,2121 @@
+"use client";
+
+import { Children, useState } from "react";
+import dayjs from "dayjs";
+import {
+ useBoundProp,
+ useStateBinding,
+ useFieldValidation,
+ type BaseComponentProps,
+} from "@json-render/react";
+import type { ReactNode } from "react";
+
+/** BaseComponentProps extended with slots for components that use slotted content. */
+type SlottedComponentProps = BaseComponentProps
& {
+ slots?: Record;
+};
+
+import {
+ Card,
+ Space,
+ Divider,
+ Row,
+ Col,
+ Masonry,
+ Layout,
+ Tabs,
+ Collapse,
+ Menu,
+ Modal,
+ Drawer,
+ Popover,
+ Tooltip,
+ Dropdown,
+ Table,
+ Typography,
+ Image,
+ Avatar,
+ Badge,
+ Tag,
+ Alert,
+ Progress,
+ Skeleton,
+ Spin,
+ Empty,
+ Statistic,
+ Descriptions,
+ Timeline,
+ Carousel,
+ Calendar,
+ List,
+ Tree,
+ QRCode,
+ Input,
+ InputNumber,
+ Select,
+ Checkbox,
+ Radio,
+ Switch,
+ Slider,
+ Rate,
+ DatePicker,
+ TimePicker,
+ Upload,
+ Transfer,
+ AutoComplete,
+ Cascader,
+ ColorPicker,
+ Mentions,
+ TreeSelect,
+ Button,
+ Pagination,
+ Segmented,
+ Steps,
+ Result,
+ Flex,
+ Form,
+ Affix,
+ Anchor,
+ Breadcrumb,
+ BackTop,
+} from "antd";
+import type { UploadFile } from "antd/es/upload/interface";
+import type { AntdProps } from "./catalog";
+
+const {
+ Title,
+ Text: AntText,
+ Paragraph: AntParagraph,
+ Link: AntLink,
+} = Typography;
+
+// =============================================================================
+// Standard Component Implementations
+// =============================================================================
+
+/**
+ * Ant Design component implementations for json-render.
+ *
+ * Pass to `defineRegistry()` from `@json-render/react` to create a
+ * component registry for rendering JSON specs with Ant Design components.
+ *
+ * @example
+ * ```ts
+ * import { defineRegistry } from "@json-render/react";
+ * import { antdComponents } from "@json-render/antd";
+ *
+ * const { registry } = defineRegistry(catalog, {
+ * components: {
+ * Card: antdComponents.Card,
+ * Button: antdComponents.Button,
+ * },
+ * });
+ * ```
+ */
+export const antdComponents = {
+ // ── Layout ────────────────────────────────────────────────────────────
+
+ Layout: ({ props, children }: BaseComponentProps>) => {
+ return {children};
+ },
+
+ LayoutHeader: ({
+ children,
+ }: BaseComponentProps>) => {
+ return {children};
+ },
+
+ LayoutContent: ({
+ children,
+ }: BaseComponentProps>) => {
+ return {children};
+ },
+
+ LayoutFooter: ({
+ children,
+ }: BaseComponentProps>) => {
+ return {children};
+ },
+
+ LayoutSider: ({
+ props,
+ children,
+ emit,
+ }: BaseComponentProps>) => {
+ return (
+ emit("collapse")}
+ >
+ {children}
+
+ );
+ },
+
+ Card: ({
+ props,
+ children,
+ slots,
+ }: SlottedComponentProps>) => {
+ const extraSlot = slots?.extra?.[0];
+ const coverSlot = slots?.cover?.[0];
+ const actionsSlots = slots?.actions ?? [];
+
+ return (
+ {props.extra} : undefined)
+ }
+ variant={props.variant ?? "outlined"}
+ hoverable={props.hoverable ?? false}
+ loading={props.loading ?? false}
+ size={props.size ?? "default"}
+ cover={
+ coverSlot ??
+ (props.cover ?
: undefined)
+ }
+ actions={
+ actionsSlots.length > 0
+ ? actionsSlots
+ : props.actions
+ ? props.actions.map((action, idx) => (
+ {action}
+ ))
+ : undefined
+ }
+ >
+ {children}
+
+ );
+ },
+
+ Flex: ({ props, children }: BaseComponentProps>) => {
+ return (
+
+ {children}
+
+ );
+ },
+
+ Stack: ({ props, children }: BaseComponentProps>) => {
+ return (
+
+ {children}
+
+ );
+ },
+
+ Grid: ({ props, children }: BaseComponentProps>) => {
+ const columns = props.columns ?? 3;
+ const span = Math.floor(24 / Math.min(Math.max(columns, 1), 6));
+ const gapMap = { sm: 8, md: 16, lg: 24 } as const;
+ const gutter = props.gap ? gapMap[props.gap] : 16;
+ const childArray = Children.toArray(children);
+ return (
+
+ {childArray.map((child, i) => (
+
+ {child}
+
+ ))}
+
+ );
+ },
+
+ Row: ({ props, children }: BaseComponentProps>) => {
+ return (
+
+ {children}
+
+ );
+ },
+
+ Col: ({ props, children }: BaseComponentProps>) => {
+ return (
+
+ {children}
+
+ );
+ },
+
+ Masonry: ({ props, children }: BaseComponentProps>) => {
+ const childArray = Array.isArray(children)
+ ? children
+ : children
+ ? [children]
+ : [];
+ const items = childArray.map((child, index) => ({
+ key: index,
+ children: child,
+ data: {},
+ }));
+
+ return (
+
+ );
+ },
+
+ Divider: ({ props }: BaseComponentProps>) => {
+ return (
+
+ {props.text}
+
+ );
+ },
+
+ Space: ({ props, children }: BaseComponentProps>) => {
+ const sizeMap: Record = {
+ small: 8,
+ middle: 16,
+ large: 24,
+ };
+
+ return (
+
+ {children}
+
+ );
+ },
+
+ // ── Navigation ─────────────────────────────────────────────────────────
+
+ Tabs: ({
+ props,
+ slots,
+ bindings,
+ emit,
+ }: SlottedComponentProps>) => {
+ const tabs = props.tabs ?? [];
+ const tabContents = slots?.tabs ?? [];
+ const [boundValue, setBoundValue] = useBoundProp(
+ props.value as string | undefined,
+ bindings?.value,
+ );
+ const [localValue, setLocalValue] = useState(
+ props.defaultValue ?? tabs[0]?.value ?? "",
+ );
+ const isBound = !!bindings?.value;
+ const value = isBound ? (boundValue ?? tabs[0]?.value ?? "") : localValue;
+ const setValue = isBound ? setBoundValue : setLocalValue;
+
+ const items = tabs.map((tab, index) => ({
+ key: tab.value,
+ label: tab.label,
+ children: tabContents[index] ?? null,
+ }));
+
+ return (
+ {
+ setValue(key);
+ emit("change");
+ }}
+ tabPosition={props.position ?? "top"}
+ type={props.type ?? "line"}
+ centered={props.centered ?? false}
+ size={props.size ?? undefined}
+ tabBarGutter={props.tabBarGutter ?? undefined}
+ destroyInactiveTabPane={props.destroyInactiveTabPane ?? false}
+ items={items}
+ />
+ );
+ },
+
+ Collapse: ({
+ props,
+ slots,
+ }: SlottedComponentProps>) => {
+ const items = props.items ?? [];
+ const itemContents = slots?.items ?? [];
+
+ const collapseItems = items.map((item, idx) => ({
+ key: String(idx),
+ label: item.title,
+ children: itemContents[idx] ?? null,
+ }));
+
+ return (
+
+ );
+ },
+
+ Menu: ({ props, emit }: BaseComponentProps>) => {
+ const items = props.items ?? [];
+
+ const menuItems = items.map((item) => ({
+ key: item.key,
+ label: item.label,
+ icon: item.icon ? : undefined,
+ }));
+
+ return (
+