mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-25 22:25:01 +00:00
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:
@@ -1,7 +1,4 @@
|
||||
export { useDialog } from './use-dialog'
|
||||
export { useActionExecutor } from './use-action-executor'
|
||||
export { useToggle } from './use-toggle'
|
||||
export { useForm } from './use-form'
|
||||
export type { UseDialogReturn } from './use-dialog'
|
||||
export type { UseToggleOptions } from './use-toggle'
|
||||
export type { UseFormOptions, FormField } from './use-form'
|
||||
export { useDataBinding } from './use-data-binding'
|
||||
export { useEventHandlers } from './use-event-handlers'
|
||||
export { useSchemaLoader } from './use-schema-loader'
|
||||
export { useComponentRegistry } from './use-component-registry'
|
||||
|
||||
49
src/hooks/ui/use-component-registry.ts
Normal file
49
src/hooks/ui/use-component-registry.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useMemo } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import * as Icons from '@phosphor-icons/react'
|
||||
|
||||
interface ComponentRegistryOptions {
|
||||
customComponents?: Record<string, React.ComponentType<any>>
|
||||
}
|
||||
|
||||
export function useComponentRegistry({ customComponents = {} }: ComponentRegistryOptions = {}) {
|
||||
const registry = useMemo(
|
||||
() => ({
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
Button,
|
||||
Badge,
|
||||
Input,
|
||||
Label,
|
||||
Separator,
|
||||
Progress,
|
||||
...customComponents,
|
||||
}),
|
||||
[customComponents]
|
||||
)
|
||||
|
||||
const getComponent = (type: string): React.ComponentType<any> | null => {
|
||||
return registry[type as keyof typeof registry] || null
|
||||
}
|
||||
|
||||
const getIcon = (iconName: string, props?: any) => {
|
||||
const IconComponent = (Icons as any)[iconName]
|
||||
if (!IconComponent) return null
|
||||
return <IconComponent size={24} weight="duotone" {...props} />
|
||||
}
|
||||
|
||||
return {
|
||||
registry,
|
||||
getComponent,
|
||||
getIcon,
|
||||
}
|
||||
}
|
||||
74
src/hooks/ui/use-data-binding.ts
Normal file
74
src/hooks/ui/use-data-binding.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
interface UseDataBindingOptions {
|
||||
data: Record<string, any>
|
||||
onError?: (error: Error, expression: string) => void
|
||||
}
|
||||
|
||||
export function useDataBinding({ data, onError }: UseDataBindingOptions) {
|
||||
const resolveBinding = useCallback(
|
||||
(expression: string, fallback?: any): any => {
|
||||
if (!expression) return fallback
|
||||
|
||||
try {
|
||||
const keys = Object.keys(data)
|
||||
const values = Object.values(data)
|
||||
const func = new Function(...keys, `"use strict"; return (${expression})`)
|
||||
return func(...values)
|
||||
} catch (error) {
|
||||
if (onError) {
|
||||
onError(error as Error, expression)
|
||||
}
|
||||
console.warn(`Failed to resolve binding: ${expression}`, error)
|
||||
return fallback
|
||||
}
|
||||
},
|
||||
[data, onError]
|
||||
)
|
||||
|
||||
const resolveCondition = useCallback(
|
||||
(condition: string): boolean => {
|
||||
try {
|
||||
const result = resolveBinding(condition, false)
|
||||
return Boolean(result)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
[resolveBinding]
|
||||
)
|
||||
|
||||
const resolveProps = useCallback(
|
||||
(props: Record<string, any>): Record<string, any> => {
|
||||
if (!props) return {}
|
||||
|
||||
const resolved: Record<string, any> = {}
|
||||
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
if (typeof value === 'string' && value.startsWith('{{') && value.endsWith('}}')) {
|
||||
const expression = value.slice(2, -2).trim()
|
||||
resolved[key] = resolveBinding(expression)
|
||||
} else if (typeof value === 'object' && value !== null && value.type === 'binding') {
|
||||
resolved[key] = resolveBinding(value.expression, value.fallback)
|
||||
} else {
|
||||
resolved[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return resolved
|
||||
},
|
||||
[resolveBinding]
|
||||
)
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
resolveBinding,
|
||||
resolveCondition,
|
||||
resolveProps,
|
||||
data,
|
||||
}),
|
||||
[resolveBinding, resolveCondition, resolveProps, data]
|
||||
)
|
||||
|
||||
return context
|
||||
}
|
||||
63
src/hooks/ui/use-event-handlers.ts
Normal file
63
src/hooks/ui/use-event-handlers.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
interface UseEventHandlersOptions {
|
||||
functions?: Record<string, (...args: any[]) => any>
|
||||
onError?: (error: Error, functionName: string) => void
|
||||
}
|
||||
|
||||
export function useEventHandlers({ functions = {}, onError }: UseEventHandlersOptions) {
|
||||
const createHandler = useCallback(
|
||||
(functionName: string) => {
|
||||
return (...args: any[]) => {
|
||||
const handler = functions[functionName]
|
||||
|
||||
if (!handler) {
|
||||
const error = new Error(`Function "${functionName}" not found`)
|
||||
if (onError) {
|
||||
onError(error, functionName)
|
||||
} else {
|
||||
console.error(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
return handler(...args)
|
||||
} catch (error) {
|
||||
if (onError) {
|
||||
onError(error as Error, functionName)
|
||||
} else {
|
||||
console.error(`Error executing function "${functionName}":`, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[functions, onError]
|
||||
)
|
||||
|
||||
const resolveEvents = useCallback(
|
||||
(events?: Record<string, string>): Record<string, (...args: any[]) => any> => {
|
||||
if (!events) return {}
|
||||
|
||||
const resolved: Record<string, (...args: any[]) => any> = {}
|
||||
|
||||
for (const [eventName, functionName] of Object.entries(events)) {
|
||||
resolved[eventName] = createHandler(functionName)
|
||||
}
|
||||
|
||||
return resolved
|
||||
},
|
||||
[createHandler]
|
||||
)
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
createHandler,
|
||||
resolveEvents,
|
||||
functions,
|
||||
}),
|
||||
[createHandler, resolveEvents, functions]
|
||||
)
|
||||
|
||||
return context
|
||||
}
|
||||
60
src/hooks/ui/use-schema-loader.ts
Normal file
60
src/hooks/ui/use-schema-loader.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import { PageSchemaType } from '@/schemas/ui-schema'
|
||||
|
||||
interface UseSchemaLoaderOptions {
|
||||
schemaUrl?: string
|
||||
schema?: PageSchemaType
|
||||
onError?: (error: Error) => void
|
||||
}
|
||||
|
||||
export function useSchemaLoader({ schemaUrl, schema: initialSchema, onError }: UseSchemaLoaderOptions) {
|
||||
const [schema, setSchema] = useState<PageSchemaType | null>(initialSchema || null)
|
||||
const [loading, setLoading] = useState(!!schemaUrl && !initialSchema)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
|
||||
const loadSchema = useCallback(
|
||||
async (url: string) => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load schema: ${response.statusText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
setSchema(data)
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err : new Error('Unknown error loading schema')
|
||||
setError(error)
|
||||
if (onError) {
|
||||
onError(error)
|
||||
}
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
},
|
||||
[onError]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (schemaUrl && !initialSchema) {
|
||||
loadSchema(schemaUrl)
|
||||
}
|
||||
}, [schemaUrl, initialSchema, loadSchema])
|
||||
|
||||
const reloadSchema = useCallback(() => {
|
||||
if (schemaUrl) {
|
||||
loadSchema(schemaUrl)
|
||||
}
|
||||
}, [schemaUrl, loadSchema])
|
||||
|
||||
return {
|
||||
schema,
|
||||
loading,
|
||||
error,
|
||||
reloadSchema,
|
||||
setSchema,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user