* refactor(dom-css): group sources into import, export, and runtime dom-css kept both conversion directions in one flat folder: HTML and CSS import next to SceneGraph export, a JSX runtime next to the Tailwind JSX printer, and CSS parsing and formatting in one file. Sources now live in `import/`, `export/`, and `runtime/`, with the CSS value helpers split by direction and `export/index.ts` as the `./export` entry. Tests mirror the new folders. Public entry points are unchanged. * docs(dom-css): add a package guide for the import, export, and runtime layout dom-css had no AGENTS.md. The guide records the source layout, the scene-graph-only dependency, the browser-safe `./export` entry, printed code generation, and Base64 validation for imported documents, and the root map links to it.
147 lines
5.6 KiB
TypeScript
147 lines
5.6 KiB
TypeScript
import type { SceneGraph } from '@open-pencil/scene-graph'
|
|
|
|
import { mergeCSSText } from './import/css-text'
|
|
import { jsxToDesignDocumentCore, type JSXChild } from './import/jsx/core'
|
|
import { designDocumentToSceneGraph, type ToSceneGraphOptions } from './import/scene-graph'
|
|
import type { CompileTailwindCSSOptions } from './import/tailwind'
|
|
import { createBrowserCSSRuntime, type BrowserCSSRuntimeOptions } from './runtime/browser'
|
|
import type { CSSComputeOptions, DesignDocument } from './types'
|
|
|
|
export { Fragment, jsx, jsxs } from './import/jsx/core'
|
|
export type { JSXChild, JSXElementProps, JSXStyleInput, JSXTag } from './import/jsx/core'
|
|
|
|
export interface BrowserToDesignDocumentOptions extends BrowserCSSRuntimeOptions {
|
|
cssText?: string
|
|
compute?: CSSComputeOptions
|
|
signal?: AbortSignal
|
|
}
|
|
|
|
export type BrowserHTMLToDesignDocumentOptions = BrowserToDesignDocumentOptions
|
|
|
|
export interface BrowserHTMLToSceneGraphOptions
|
|
extends BrowserToDesignDocumentOptions, ToSceneGraphOptions {}
|
|
|
|
export interface BrowserTailwindHTMLToDesignDocumentOptions
|
|
extends Omit<BrowserHTMLToDesignDocumentOptions, 'cssText'>, CompileTailwindCSSOptions {}
|
|
|
|
export interface BrowserTailwindHTMLToSceneGraphOptions
|
|
extends BrowserTailwindHTMLToDesignDocumentOptions, ToSceneGraphOptions {}
|
|
|
|
export interface BrowserToSceneGraphOptions
|
|
extends BrowserToDesignDocumentOptions, ToSceneGraphOptions {}
|
|
|
|
export interface BrowserTailwindToDesignDocumentOptions
|
|
extends Omit<BrowserToDesignDocumentOptions, 'cssText'>, CompileTailwindCSSOptions {}
|
|
|
|
export interface BrowserTailwindToSceneGraphOptions
|
|
extends BrowserTailwindToDesignDocumentOptions, ToSceneGraphOptions {}
|
|
|
|
function createRuntime(options: BrowserCSSRuntimeOptions) {
|
|
return createBrowserCSSRuntime({ sandbox: 'iframe', ...options })
|
|
}
|
|
|
|
async function compileBrowserTailwindCSS(
|
|
candidates: string | Iterable<string>,
|
|
options: CompileTailwindCSSOptions
|
|
): Promise<string> {
|
|
const { compileTailwindCSS } = await import('./import/tailwind')
|
|
return compileTailwindCSS(candidates, options)
|
|
}
|
|
|
|
function resolveBrowserDocument(documentOverride: Document | undefined): Document {
|
|
if (documentOverride) return documentOverride
|
|
if (typeof document === 'undefined') {
|
|
throw new TypeError('Browser DOM/CSS helpers require a DOM document')
|
|
}
|
|
return document
|
|
}
|
|
|
|
function extractEmbeddedCSSText(html: string, browserDocument: Document): string | undefined {
|
|
const Parser = browserDocument.defaultView?.DOMParser
|
|
if (!Parser) throw new TypeError('Browser DOM/CSS helpers require DOMParser')
|
|
const parsed = new Parser().parseFromString(html, 'text/html')
|
|
const styles = Array.from(parsed.querySelectorAll('style'))
|
|
.map((style) => (style.textContent ? style.textContent.trim() : ''))
|
|
.filter((css): css is string => !!css)
|
|
return styles.length > 0 ? styles.join('\n') : undefined
|
|
}
|
|
|
|
export async function browserHTMLToDesignDocument(
|
|
html: string,
|
|
options: BrowserHTMLToDesignDocumentOptions = {}
|
|
): Promise<DesignDocument> {
|
|
options.signal?.throwIfAborted()
|
|
const browserDocument = resolveBrowserDocument(options.document)
|
|
const runtime = createRuntime({ ...options, document: browserDocument })
|
|
const document = runtime.parseHTML(html)
|
|
const cssText = mergeCSSText(extractEmbeddedCSSText(html, browserDocument), options.cssText)
|
|
return runtime.computeStyles(document, cssText, options.compute)
|
|
}
|
|
|
|
export async function browserHTMLToSceneGraph(
|
|
html: string,
|
|
options: BrowserHTMLToSceneGraphOptions = {}
|
|
): Promise<SceneGraph> {
|
|
const document = await browserHTMLToDesignDocument(html, options)
|
|
options.signal?.throwIfAborted()
|
|
const graph = designDocumentToSceneGraph(document, options)
|
|
options.signal?.throwIfAborted()
|
|
return graph
|
|
}
|
|
|
|
export async function browserTailwindHTMLToDesignDocument(
|
|
html: string,
|
|
candidates: string | Iterable<string>,
|
|
options: BrowserTailwindHTMLToDesignDocumentOptions = {}
|
|
): Promise<DesignDocument> {
|
|
const cssText = await compileBrowserTailwindCSS(candidates, options)
|
|
return browserHTMLToDesignDocument(html, { ...options, cssText })
|
|
}
|
|
|
|
export async function browserTailwindHTMLToSceneGraph(
|
|
html: string,
|
|
candidates: string | Iterable<string>,
|
|
options: BrowserTailwindHTMLToSceneGraphOptions = {}
|
|
): Promise<SceneGraph> {
|
|
const document = await browserTailwindHTMLToDesignDocument(html, candidates, options)
|
|
options.signal?.throwIfAborted()
|
|
const graph = designDocumentToSceneGraph(document, options)
|
|
options.signal?.throwIfAborted()
|
|
return graph
|
|
}
|
|
|
|
export async function browserJSXToDesignDocument(
|
|
input: JSXChild,
|
|
options: BrowserToDesignDocumentOptions = {}
|
|
): Promise<DesignDocument> {
|
|
const document = jsxToDesignDocumentCore(input)
|
|
const runtime = createRuntime(options)
|
|
return runtime.computeStyles(document, options.cssText, options.compute)
|
|
}
|
|
|
|
export async function browserJSXToSceneGraph(
|
|
input: JSXChild,
|
|
options: BrowserToSceneGraphOptions = {}
|
|
): Promise<SceneGraph> {
|
|
const document = await browserJSXToDesignDocument(input, options)
|
|
return designDocumentToSceneGraph(document, options)
|
|
}
|
|
|
|
export async function browserTailwindJSXToDesignDocument(
|
|
input: JSXChild,
|
|
candidates: string | Iterable<string>,
|
|
options: BrowserTailwindToDesignDocumentOptions = {}
|
|
): Promise<DesignDocument> {
|
|
const cssText = await compileBrowserTailwindCSS(candidates, options)
|
|
return browserJSXToDesignDocument(input, { ...options, cssText })
|
|
}
|
|
|
|
export async function browserTailwindJSXToSceneGraph(
|
|
input: JSXChild,
|
|
candidates: string | Iterable<string>,
|
|
options: BrowserTailwindToSceneGraphOptions = {}
|
|
): Promise<SceneGraph> {
|
|
const document = await browserTailwindJSXToDesignDocument(input, candidates, options)
|
|
return designDocumentToSceneGraph(document, options)
|
|
}
|