Files
low-code-react-app-b/src/lib/json-ui/hooks.ts
johndoe6345789 809803283b feat: Add JSON definitions for menu, password input, and popover components
- Introduced `menu.json` for menu component structure with bindings for trigger and content.
- Created `password-input.json` for password input handling visibility and value changes.
- Added `popover.json` for popover component with trigger and content bindings.

feat: Implement custom hooks for UI interactions

- Added `useAccordion` for managing accordion state with single/multiple item support.
- Created `useBindingEditor` for managing bindings in a dynamic editor.
- Implemented `useCopyState` for clipboard copy functionality with feedback.
- Developed `useFileUpload` for handling file uploads with drag-and-drop support.
- Introduced `useFocusState` for managing focus state in components.
- Created `useImageState` for handling image loading and error states.
- Added `useMenuState` for managing menu interactions and item clicks.
- Implemented `usePasswordVisibility` for toggling password visibility.
- Developed `usePopoverState` for managing popover visibility and interactions.

feat: Add constants and interfaces for JSON UI components

- Introduced constants for sizes, placements, styles, and object-fit handling.
- Created interfaces for various components including Accordion, Binding Editor, Copy Button, Data Source Editor, File Upload, and more.
- Added type definitions for menu items, popover props, and other UI elements to enhance type safety and maintainability.
2026-01-19 01:30:42 +00:00

144 lines
3.4 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react'
import { useKV } from '@/hooks/use-kv'
import type { DataSourceConfig } from './schema'
export function useJSONDataSource<T = unknown>(
id: string,
config: DataSourceConfig<T>
) {
const kvConfig = config.type === 'kv' ? config.config : undefined
const apiConfig = config.type === 'api' ? config.config : undefined
const defaultValue =
config.type === 'static' ? config.config : config.config?.defaultValue
const [kvValue, setKVValue] = useKV<T>(
kvConfig?.key || id,
(kvConfig?.defaultValue ?? defaultValue) as T
)
const [apiValue, setApiValue] = useState<T | undefined>(defaultValue)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<Error | null>(null)
const fetchAPI = useCallback(async () => {
if (config.type !== 'api' || !apiConfig?.url) return
setLoading(true)
setError(null)
try {
const response = await fetch(apiConfig.url)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
let data = await response.json()
if (apiConfig.transform) {
data = apiConfig.transform(data)
}
setApiValue(data)
} catch (err) {
setError(err as Error)
} finally {
setLoading(false)
}
}, [apiConfig, config.type])
useEffect(() => {
if (config.type === 'api') {
fetchAPI()
}
}, [config.type, fetchAPI])
const getValue = () => {
switch (config.type) {
case 'kv':
return kvValue
case 'api':
return apiValue
case 'static':
return config.config
default:
return null
}
}
const setValue = (newValue: any) => {
switch (config.type) {
case 'kv':
setKVValue(newValue)
break
case 'api':
setApiValue(newValue)
break
default:
break
}
}
return {
value: getValue(),
setValue,
loading,
error,
refetch: fetchAPI,
}
}
export function useJSONDataSources<T = unknown>(
sources: Record<string, DataSourceConfig<T>>
) {
const [dataMap, setDataMap] = useState<Record<string, any>>({})
const [loadingMap, setLoadingMap] = useState<Record<string, boolean>>({})
const [errorMap, setErrorMap] = useState<Record<string, Error | null>>({})
const sourceIds = Object.keys(sources)
const updateData = useCallback((id: string, value: any) => {
setDataMap((prev) => ({ ...prev, [id]: value }))
}, [])
const getData = useCallback((id: string) => {
return dataMap[id]
}, [dataMap])
useEffect(() => {
sourceIds.forEach((id) => {
const config = sources[id]
if (config.type === 'static') {
updateData(id, config.config)
}
})
}, [sourceIds])
return {
dataMap,
loadingMap,
errorMap,
updateData,
getData,
}
}
export function useJSONActions() {
const [actionHandlers, setActionHandlers] = useState<Record<string, (...args: any[]) => void>>({})
const registerAction = useCallback((id: string, handler: (...args: any[]) => void) => {
setActionHandlers((prev) => ({ ...prev, [id]: handler }))
}, [])
const executeAction = useCallback((id: string, ...args: any[]) => {
const handler = actionHandlers[id]
if (handler) {
handler(...args)
} else {
console.warn(`Action handler not found: ${id}`)
}
}, [actionHandlers])
return {
registerAction,
executeAction,
}
}