hooktml
Version:
A reactive HTML component library with hooks-based lifecycle management
125 lines (107 loc) • 3.36 kB
JavaScript
import {
registerHook,
registerChainableHook,
getRegisteredHooks,
getRegisteredChainableHooks
} from './core/hookRegistry.js'
import { useEffect } from './core/hookContext.js'
import { useChildren } from './hooks/useChildren.js'
import { useEvents } from './hooks/useEvents.js'
import { useClasses } from './hooks/useClasses.js'
import { useAttributes } from './hooks/useAttributes.js'
import { useStyles } from './hooks/useStyles.js'
import { useText } from './hooks/useText.js'
import { with as withEl } from './core/with.js'
import { createObserver } from './core/observer.js'
import { scanComponents, initializeComponents } from './core/scanComponents.js'
import { scanDirectives } from './core/scanDirectives.js'
import { getRegisteredComponentNames, registerComponent, registerComponentByName } from './core/registry.js'
import { initConfig, getConfig } from './core/config.js'
import { signal } from './core/signal.js'
import { computed } from './core/computed.js'
import { autoRegisterComponents } from './core/autoRegister.js'
import { logger } from './utils/logger.js'
/**
* Observer instance for DOM mutations
* @type {Object}
*/
const observerRef = {
current: null
}
/**
* HookTML runtime instance
* @typedef {Object} HookTMLRuntime
* @property {Object} config - The runtime configuration
* @property {Array<Object>} components - The initialized component instances
*/
/**
* Starts the HookTML runtime
* @param {import('./core/config.js').HookTMLConfigOptions} [options] - Configuration options
* @returns {Promise<Object>} - Runtime object with API methods
*/
export const start = async (options) => {
// Configure
initConfig(options)
logger.log('Initializing...')
// Log the resolved configuration
const { componentPath, debug, attributePrefix } = getConfig()
if (attributePrefix) {
logger.log(`Using attribute prefix: "${attributePrefix}"`)
}
// Auto-register components if path is provided
if (componentPath) {
logger.log(`Auto-registering components from: "${componentPath}"`)
await autoRegisterComponents({
componentPath,
register: registerComponentByName,
debug
})
}
// Create and start the observer
observerRef.current = createObserver()
observerRef.current.start()
// Initial scan
scan()
// Log completion message
logger.log('Initialization complete')
// Return API for runtime management
return {
config: getConfig(),
scan,
stop: () => observerRef.current?.stop(),
components: getRegisteredComponentNames,
hooks: getRegisteredHooks,
chainableHooks: getRegisteredChainableHooks
}
}
/**
* Scans the DOM for new components and hooks and initializes them
* @returns {Array<Object>} Initialized component instances
*/
export const scan = () => {
// Scan for components
logger.log('Manual scan triggered')
const components = scanComponents()
const instances = initializeComponents(components)
// Scan for directives
scanDirectives()
logger.log(`Manual scan complete, initialized ${instances.length} new component(s)`)
return instances
}
// Export core API
export {
registerComponent,
registerHook,
registerChainableHook,
useEffect,
useChildren,
useEvents,
useClasses,
useAttributes,
useStyles,
useText,
withEl as with,
signal,
computed
}
export { getConfig }