diff --git a/src/lib/json-ui/hooks.ts b/src/lib/json-ui/hooks.ts index 54b1ee9..3ca5916 100644 --- a/src/lib/json-ui/hooks.ts +++ b/src/lib/json-ui/hooks.ts @@ -1,33 +1,38 @@ import { useState, useEffect, useCallback } from 'react' import { useKV } from '@/hooks/use-kv' +import type { DataSourceConfig } from './schema' -export interface DataSourceConfig { - type: 'kv' | 'api' | 'computed' | 'static' - key?: string - url?: string - defaultValue?: any - transform?: (data: any) => any -} +export function useJSONDataSource( + id: string, + config: DataSourceConfig +) { + const kvConfig = config.type === 'kv' ? config.config : undefined + const apiConfig = config.type === 'api' ? config.config : undefined + const computedConfig = config.type === 'computed' ? config.config : undefined + const defaultValue = + config.type === 'static' ? config.config : config.config?.defaultValue -export function useJSONDataSource(id: string, config: DataSourceConfig) { - const [kvValue, setKVValue] = useKV(config.key || id, config.defaultValue) - const [apiValue, setApiValue] = useState(config.defaultValue) + const [kvValue, setKVValue] = useKV( + kvConfig?.key || id, + (kvConfig?.defaultValue ?? defaultValue) as T + ) + const [apiValue, setApiValue] = useState(defaultValue) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const fetchAPI = useCallback(async () => { - if (config.type !== 'api' || !config.url) return + if (config.type !== 'api' || !apiConfig?.url) return setLoading(true) setError(null) try { - const response = await fetch(config.url) + const response = await fetch(apiConfig.url) if (!response.ok) throw new Error(`HTTP ${response.status}`) let data = await response.json() - if (config.transform) { - data = config.transform(data) + if (apiConfig.transform) { + data = apiConfig.transform(data) } setApiValue(data) @@ -36,7 +41,7 @@ export function useJSONDataSource(id: string, config: DataSourceConfig) { } finally { setLoading(false) } - }, [config.type, config.url, config.transform]) + }, [apiConfig, config.type]) useEffect(() => { if (config.type === 'api') { @@ -51,9 +56,9 @@ export function useJSONDataSource(id: string, config: DataSourceConfig) { case 'api': return apiValue case 'static': - return config.defaultValue + return config.config case 'computed': - return config.defaultValue + return computedConfig?.defaultValue default: return null } @@ -81,7 +86,9 @@ export function useJSONDataSource(id: string, config: DataSourceConfig) { } } -export function useJSONDataSources(sources: Record) { +export function useJSONDataSources( + sources: Record> +) { const [dataMap, setDataMap] = useState>({}) const [loadingMap, setLoadingMap] = useState>({}) const [errorMap, setErrorMap] = useState>({}) @@ -101,7 +108,7 @@ export function useJSONDataSources(sources: Record) { const config = sources[id] if (config.type === 'static') { - updateData(id, config.defaultValue) + updateData(id, config.config) } }) }, [sourceIds]) diff --git a/src/lib/json-ui/schema.ts b/src/lib/json-ui/schema.ts index 1ba2959..f5b261c 100644 --- a/src/lib/json-ui/schema.ts +++ b/src/lib/json-ui/schema.ts @@ -185,6 +185,34 @@ export const PageUISchema = z.object({ })).optional(), }) +export type DataSourceConfig = + | { + type: 'kv' + config: { + key?: string + defaultValue?: T + } + } + | { + type: 'api' + config: { + url?: string + defaultValue?: T + transform?: (data: unknown) => T + } + } + | { + type: 'computed' + config: { + defaultValue?: T + transform?: (data: unknown) => T + } + } + | { + type: 'static' + config: T + } + export type UIValue = z.infer export type DataBinding = z.infer export type EventHandler = z.infer