Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374import { useEffect, useMemo, useState } from 'react'import type { App } from '../plugin/app'import type { TemplatePlugin } from '../plugins/templates'
interface UseReactiveTemplatePluginOptions { active: boolean app: App}
/** * Duck-typed shape check for TemplatePlugin. The bare `as` cast in getPlugin() * would let any plugin registered under 'reams-templates' through, including a * partial mock from a malformed plugin manifest. Guard with a duck-typed shape * check so consumers don't get TypeError when calling the required methods. * * Checks all methods used by FileTree and AppShell consumers: * - createFileFromTemplate (file creation) * - expandFilenamePattern (filename preview) * - getTemplates (template list) * - getDefaultTemplate (default template path) * - getFilenamePattern (pattern for filename preview) */export function isValidTemplatePlugin(candidate: unknown): candidate is TemplatePlugin { if (candidate === null || typeof candidate !== 'object') return false const obj = candidate as Record<string, unknown> return ( typeof obj.createFileFromTemplate === 'function' && typeof obj.expandFilenamePattern === 'function' && typeof obj.getTemplates === 'function' && typeof obj.getDefaultTemplate === 'function' && typeof obj.getFilenamePattern === 'function' )}
/** * React hook for reactively accessing the template plugin. * * Uses app.plugins.getPlugin('reams-templates') directly and subscribes to * plugin state changes via app.plugins.on('plugin-state-change', ...). * * @param options.active When true, subscribes to plugin state changes * @param options.app The App instance to get the plugin from * @returns { plugin, version } where plugin is the TemplatePlugin or null, * and version increments on state changes for useMemo dependency */export function useReactiveTemplatePlugin({ active, app,}: UseReactiveTemplatePluginOptions): { plugin: TemplatePlugin | null; version: number } { const [version, setVersion] = useState(0)
useEffect(() => { if (!active) return
const ref = app.plugins.on('plugin-state-change', (pluginId) => { if (pluginId === 'reams-templates') { setVersion(current => current + 1) } })
return () => { app.plugins.offref(ref) } }, [active, app])
const plugin = useMemo(() => { if (!active) return null const candidate = app.plugins.getPlugin('reams-templates') return isValidTemplatePlugin(candidate) ? candidate : null }, [active, app, version])
return { plugin, version }}