import { useTheme } from "../theme/ThemeContext.mjs"; import { useA2UIActions, useA2UIState } from "../core/A2UIProvider.mjs"; import { useCallback, useId, useMemo } from "react"; //#region src/react-renderer/hooks/useA2UIComponent.ts /** * Base hook for A2UI components. Provides data binding, theme access, * and action dispatching. * * @param node - The component node from the A2UI message processor * @param surfaceId - The surface ID this component belongs to * @returns Object with theme, data binding helpers, and action dispatcher * * @example * ```tsx * function TextField({ node, surfaceId }: A2UIComponentProps) { * const { theme, resolveString, setValue } = useA2UIComponent(node, surfaceId); * * const label = resolveString(node.properties.label); * const value = resolveString(node.properties.text) ?? ''; * * return ( *
* * setValue(node.properties.text?.path!, e.target.value)} * /> *
* ); * } * ``` */ function useA2UIComponent(node, surfaceId) { const actions = useA2UIActions(); const theme = useTheme(); const baseId = useId(); useA2UIState(); /** * Resolve a StringValue to its actual string value. * Checks literalString, literal, then path in that order. * Note: This reads from data model via stable actions reference. */ const resolveString = useCallback((value) => { if (!value) return null; if (typeof value !== "object") return null; if (value.literalString !== void 0) return value.literalString; if (value.literal !== void 0) return String(value.literal); if (value.path) { const data = actions.getData(node, value.path, surfaceId); return data !== null ? String(data) : null; } return null; }, [ actions, node, surfaceId ]); /** * Resolve a NumberValue to its actual number value. */ const resolveNumber = useCallback((value) => { if (!value) return null; if (typeof value !== "object") return null; if (value.literalNumber !== void 0) return value.literalNumber; if (value.literal !== void 0) return Number(value.literal); if (value.path) { const data = actions.getData(node, value.path, surfaceId); return data !== null ? Number(data) : null; } return null; }, [ actions, node, surfaceId ]); /** * Resolve a BooleanValue to its actual boolean value. */ const resolveBoolean = useCallback((value) => { if (!value) return null; if (typeof value !== "object") return null; if (value.literalBoolean !== void 0) return value.literalBoolean; if (value.literal !== void 0) return Boolean(value.literal); if (value.path) { const data = actions.getData(node, value.path, surfaceId); return data !== null ? Boolean(data) : null; } return null; }, [ actions, node, surfaceId ]); /** * Set a value in the data model for two-way binding. */ const setValue = useCallback((path, value) => { actions.setData(node, path, value, surfaceId); }, [ actions, node, surfaceId ]); /** * Get a value from the data model. */ const getValue = useCallback((path) => { return actions.getData(node, path, surfaceId); }, [ actions, node, surfaceId ]); /** * Dispatch a user action to the server. * Resolves all context bindings before dispatching. */ const sendAction = useCallback((action) => { const actionContext = {}; if (action.context) { for (const item of action.context) if (item.value.literalString !== void 0) actionContext[item.key] = item.value.literalString; else if (item.value.literalNumber !== void 0) actionContext[item.key] = item.value.literalNumber; else if (item.value.literalBoolean !== void 0) actionContext[item.key] = item.value.literalBoolean; else if (item.value.path) { const resolvedPath = actions.resolvePath(item.value.path, node.dataContextPath); actionContext[item.key] = actions.getData(node, resolvedPath, surfaceId); } } actions.dispatch({ userAction: { name: action.name, sourceComponentId: node.id, surfaceId, timestamp: (/* @__PURE__ */ new Date()).toISOString(), context: actionContext } }); }, [ actions, node, surfaceId ]); /** * Generate a unique ID for accessibility purposes. * Uses React's useId() for SSR and Concurrent Mode compatibility. */ const getUniqueId = useCallback((prefix) => { return `${prefix}${baseId}`; }, [baseId]); return useMemo(() => ({ theme, resolveString, resolveNumber, resolveBoolean, setValue, getValue, sendAction, getUniqueId }), [ theme, resolveString, resolveNumber, resolveBoolean, setValue, getValue, sendAction, getUniqueId ]); } //#endregion export { useA2UIComponent }; //# sourceMappingURL=useA2UIComponent.mjs.map