import { Component, NewState, Util, $ } from '@apigo.cc/state'
import { HTTP } from './http.js'
Component.register('AutoForm', container => {
if (!container.state.schema) container.state.schema = []
container.vertical = container.hasAttribute('vertical')
container.inline = container.hasAttribute('inline')
container.nobutton = container.hasAttribute('nobutton')
container.request = { method: 'POST' }
container.response = {}
container.result = null
// Ensure data is reactive and mapped to state.data for template context
Object.defineProperty(container, 'data', {
get: () => container.state.data,
set: v => { container.state.data = (v?.__isProxy ? v : NewState(v || {})); }
})
container.data = container.data || {} // Initialize
container._thisObj = container
// TODO: $$ 双重计算机制暂不提供循环依赖保护,schema 编写者需确保 item.if 逻辑无副作用
container.form = $(container, 'form')
container.submit = (opt = {}) => {
if (!container.form.reportValidity()) return globalThis.UI?.toast?.('{#verify failed#}', { type: 'danger' })
if (!container.dispatchEvent(new CustomEvent('submit', { detail: container.data, cancelable: true, bubbles: false }))) return
const req = { ...container.request, data: container.data, noui: true, ...opt }
let task = null
if (container.api) task = container.api.do(req)
else if (container.request.url) task = HTTP.request(req)
else return console.warn('{#please config .api or .request.url to auto submit#}')
task.then(resp => {
container.response = resp
container.result = resp.result
if (typeof resp.result === 'object' && resp.result.error) throw new Error(resp.result.error)
container.dispatchEvent(new CustomEvent('response', { detail: resp, bubbles: false }))
}).catch(err => {
if (globalThis.UI?.toast) UI.toast(err.message, { type: 'danger' })
container.dispatchEvent(new CustomEvent('error', { detail: err, bubbles: true }))
})
}
}, Util.makeDom(/*html*/`
`), Util.makeDom(/*html*/``))
const _pendingAutoFormComponents = []
export const AutoForm = {
register: (name, typeName) => {
const entry = { name, typeName: typeName || name }
if (typeof document !== 'undefined') {
if (document.readyState !== 'loading' && Component.getTemplate('AutoForm')) AutoForm._addAutoFormComponent(entry)
else _pendingAutoFormComponents.push(entry)
}
},
_addAutoFormComponent: entry => {
const { name, typeName } = entry
const template = Component.getTemplate('AutoForm')
if (template) {
let container = $(template.content, '[control-wrapper]')
if (!container) {
const nested = $(template.content, 'template')
if (nested) container = $(nested.content, '[control-wrapper]')
}
if (container && !container.querySelector(name)) {
container.appendChild(Util.makeDom(`<${name} $if="item.type?.toLowerCase() === '${typeName.toLowerCase()}'" $name="item.name" $.="item.setting || {}" $bind="thisNode.closest('AutoForm').data[item.name]">${name}>`))
}
}
}
}
if (typeof document !== 'undefined') {
const initAutoForm = () => {
_pendingAutoFormComponents.forEach(entry => AutoForm._addAutoFormComponent(entry))
_pendingAutoFormComponents.length = 0
}
if (document.readyState !== 'loading') setTimeout(initAutoForm, 100)
else document.addEventListener('DOMContentLoaded', () => setTimeout(initAutoForm, 100), true)
}
Component.register('TagsInput', container => {
container.state = NewState({ tags: [] })
container.addEventListener('bind', e => {
container.state.tags = Array.isArray(e.detail) ? e.detail : []
})
// Handle direct property access
Object.defineProperty(container, 'value', {
get: () => container.state.tags,
set: v => { container.state.tags = Array.isArray(v) ? v : []; }
})
}, Util.makeDom(/*html*/`
`), Util.makeDom(/*html*/``))
AutoForm.register('TagsInput')