Generated by Spark: Load more of UI from JSON declarations and break up large components into atomic and create hooks as needed

This commit is contained in:
2026-01-17 12:35:17 +00:00
committed by GitHub
parent 55114937a7
commit 9fde2a100c
9 changed files with 689 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
export { useJSONRenderer } from './use-json-renderer'
export { useDataSources } from './use-data-sources'

View File

@@ -0,0 +1,73 @@
import { useState, useEffect, useMemo, useCallback } from 'react'
import { DataSource } from '@/types/json-ui'
export function useDataSources(dataSources: DataSource[]) {
const [data, setData] = useState<Record<string, any>>({})
const [loading, setLoading] = useState(true)
const staticSources = useMemo(
() => dataSources.filter((ds) => ds.type === 'static'),
[dataSources]
)
const computedSources = useMemo(
() => dataSources.filter((ds) => ds.type === 'computed'),
[dataSources]
)
useEffect(() => {
const loadData = async () => {
const initialData: Record<string, any> = {}
for (const ds of dataSources) {
if (ds.type === 'kv' && ds.key) {
try {
const value = await spark.kv.get(ds.key)
initialData[ds.id] = value !== undefined ? value : ds.defaultValue
} catch {
initialData[ds.id] = ds.defaultValue
}
} else if (ds.type === 'static') {
initialData[ds.id] = ds.defaultValue
}
}
setData(initialData)
setLoading(false)
}
loadData()
}, [dataSources])
const updateDataSource = useCallback(async (id: string, value: any) => {
setData((prev) => ({ ...prev, [id]: value }))
const kvSource = dataSources.find((ds) => ds.id === id && ds.type === 'kv')
if (kvSource && kvSource.key) {
await spark.kv.set(kvSource.key, value)
}
}, [dataSources])
const computedData = useMemo(() => {
const result: Record<string, any> = {}
computedSources.forEach((ds) => {
if (ds.compute && typeof ds.compute === 'function') {
result[ds.id] = ds.compute(data)
}
})
return result
}, [computedSources, data])
const allData = useMemo(
() => ({ ...data, ...computedData }),
[data, computedData]
)
return {
data: allData,
loading,
updateDataSource,
}
}

View File

@@ -0,0 +1,45 @@
import { useMemo } from 'react'
import { ComponentSchema } from '@/types/json-ui'
export function useJSONRenderer() {
const resolveBinding = useMemo(() => {
return (binding: string, data: Record<string, any>): any => {
if (!binding) return undefined
try {
const func = new Function(...Object.keys(data), `return ${binding}`)
return func(...Object.values(data))
} catch {
return binding
}
}
}, [])
const resolveValue = useMemo(() => {
return (value: any, data: Record<string, any>): any => {
if (typeof value === 'string' && value.startsWith('{{') && value.endsWith('}}')) {
const binding = value.slice(2, -2).trim()
return resolveBinding(binding, data)
}
return value
}
}, [resolveBinding])
const resolveProps = useMemo(() => {
return (props: Record<string, any>, data: Record<string, any>): Record<string, any> => {
const resolved: Record<string, any> = {}
for (const [key, value] of Object.entries(props)) {
resolved[key] = resolveValue(value, data)
}
return resolved
}
}, [resolveValue])
return {
resolveBinding,
resolveValue,
resolveProps,
}
}