react-pebble 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/lib/compiler.cjs +2 -2
- package/dist/lib/compiler.cjs.map +1 -1
- package/dist/lib/compiler.js +4 -1
- package/dist/lib/compiler.js.map +1 -1
- package/dist/lib/components.cjs +1 -1
- package/dist/lib/components.cjs.map +1 -1
- package/dist/lib/components.js +44 -5
- package/dist/lib/components.js.map +1 -1
- package/dist/lib/hooks.cjs +1 -1
- package/dist/lib/hooks.cjs.map +1 -1
- package/dist/lib/hooks.js +198 -3
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.js +231 -108
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/plugin.cjs +25 -5
- package/dist/lib/plugin.cjs.map +1 -1
- package/dist/lib/plugin.js +62 -35
- package/dist/lib/plugin.js.map +1 -1
- package/dist/lib/src/compiler/index.d.ts +2 -0
- package/dist/lib/src/components/index.d.ts +28 -1
- package/dist/lib/src/hooks/index.d.ts +182 -0
- package/dist/lib/src/index.d.ts +4 -4
- package/dist/lib/src/pebble-output.d.ts +15 -0
- package/dist/lib/src/plugin/index.d.ts +6 -0
- package/package.json +10 -11
- package/scripts/compile-to-piu.ts +315 -26
- package/scripts/deploy.sh +0 -0
- package/scripts/test-emulator.sh +371 -0
- package/src/compiler/index.ts +8 -1
- package/src/components/index.tsx +75 -1
- package/src/hooks/index.ts +507 -19
- package/src/index.ts +26 -0
- package/src/pebble-output.ts +408 -48
- package/src/plugin/index.ts +101 -49
- package/src/types/moddable.d.ts +26 -4
package/dist/lib/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/pebble-dom.ts","../../src/pebble-output.ts","../../src/pebble-dom-shim.ts","../../src/pebble-reconciler.ts","../../src/pebble-render.ts"],"sourcesContent":["/**\n * pebble-dom.ts — Virtual DOM layer for React Pebble\n *\n * Modeled after Ink's dom.ts but stripped of Yoga layout.\n * Pebble uses absolute positioning (x, y, w, h) rather than flexbox,\n * so nodes are just plain JS objects with type, props, and children.\n *\n * Each node type maps to a Pebble drawing primitive:\n * pbl-root → Container root (the Window)\n * pbl-rect → fillRect / drawRect\n * pbl-circle → fillCircle / drawCircle\n * pbl-text → drawText\n * pbl-line → drawLine\n * pbl-image → drawImage (bitmap)\n * pbl-group → Logical grouping with offset (no draw call)\n * #text → Raw text content (only valid inside pbl-text)\n */\n\n// ---------------------------------------------------------------------------\n// Element types\n// ---------------------------------------------------------------------------\n\nexport type ElementType =\n | 'pbl-root'\n | 'pbl-rect'\n | 'pbl-circle'\n | 'pbl-text'\n | 'pbl-line'\n | 'pbl-image'\n | 'pbl-group'\n | 'pbl-statusbar'\n | 'pbl-actionbar';\n\nexport const ELEMENT_TYPES: ReadonlySet<ElementType> = new Set<ElementType>([\n 'pbl-root',\n 'pbl-rect',\n 'pbl-circle',\n 'pbl-text',\n 'pbl-line',\n 'pbl-image',\n 'pbl-group',\n 'pbl-statusbar',\n 'pbl-actionbar',\n]);\n\n// ---------------------------------------------------------------------------\n// Node shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Loose prop bag — element-specific shapes are documented on each component\n * wrapper, but the reconciler treats them uniformly.\n */\nexport type NodeProps = Record<string, unknown> & {\n _hidden?: boolean;\n};\n\nexport interface DOMElement {\n id: number;\n type: ElementType;\n props: NodeProps;\n children: Array<DOMElement | TextNode>;\n parent: DOMElement | null;\n /** Called by the reconciler after each commit; wired up by `render()`. */\n onRender: (() => void) | null;\n /** Optional layout pass; we currently don't use this. */\n onComputeLayout: (() => void) | null;\n /** Internal dirty flag (currently informational only). */\n _dirty: boolean;\n}\n\nexport interface TextNode {\n id: number;\n type: '#text';\n value: string;\n parent: DOMElement | null;\n /** Saved value while the node is hidden by Suspense. */\n _hiddenValue?: string;\n}\n\nexport type AnyNode = DOMElement | TextNode;\n\n// ---------------------------------------------------------------------------\n// Node creation\n// ---------------------------------------------------------------------------\n\nlet nextNodeId = 1;\n\nexport function createNode(type: ElementType): DOMElement {\n return {\n id: nextNodeId++,\n type,\n props: {},\n children: [],\n parent: null,\n onRender: null,\n onComputeLayout: null,\n _dirty: true,\n };\n}\n\nexport function createTextNode(text: string): TextNode {\n return {\n id: nextNodeId++,\n type: '#text',\n value: text,\n parent: null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tree manipulation\n// ---------------------------------------------------------------------------\n\nexport function appendChildNode(parent: DOMElement, child: AnyNode): void {\n if (child.parent) {\n removeChildNode(child.parent, child);\n }\n child.parent = parent;\n parent.children.push(child);\n}\n\nexport function insertBeforeNode(\n parent: DOMElement,\n child: AnyNode,\n beforeChild: AnyNode,\n): void {\n if (child.parent) {\n removeChildNode(child.parent, child);\n }\n child.parent = parent;\n const idx = parent.children.indexOf(beforeChild);\n if (idx >= 0) {\n parent.children.splice(idx, 0, child);\n } else {\n parent.children.push(child);\n }\n}\n\nexport function removeChildNode(parent: DOMElement, child: AnyNode): void {\n parent.children = parent.children.filter((c) => c !== child);\n child.parent = null;\n}\n\n// ---------------------------------------------------------------------------\n// Property / attribute helpers\n// ---------------------------------------------------------------------------\n\nexport function setAttribute(node: DOMElement, key: string, value: unknown): void {\n if (value === undefined) {\n delete node.props[key];\n } else {\n node.props[key] = value;\n }\n}\n\nexport function setTextNodeValue(node: TextNode, text: string): void {\n node.value = text;\n}\n\n// ---------------------------------------------------------------------------\n// Tree traversal helpers\n// ---------------------------------------------------------------------------\n\nexport function getTextContent(node: AnyNode): string {\n if (node.type === '#text') {\n return node.value;\n }\n return node.children.map(getTextContent).join('');\n}\n\nexport type Visitor = (node: AnyNode, depth: number) => void;\n\nexport function walkTree(root: AnyNode, visitor: Visitor, depth = 0): void {\n visitor(root, depth);\n if (root.type !== '#text') {\n for (const child of root.children) {\n walkTree(child, visitor, depth + 1);\n }\n }\n}\n\nexport function findRoot(node: AnyNode): DOMElement {\n let current: AnyNode = node;\n while (current.parent) {\n current = current.parent;\n }\n // The root is always a DOMElement (created via createNode).\n return current as DOMElement;\n}\n","/**\n * pebble-output.ts — Poco output layer for react-pebble on Pebble Alloy.\n *\n * Walks the virtual DOM tree (pebble-dom) and issues draw calls against\n * a `commodetto/Poco` renderer, which writes into the watch framebuffer.\n *\n * Key differences from a canvas-style API:\n *\n * - **No stateful color or font.** Every draw call takes the color (an int\n * produced by `poco.makeColor(r, g, b)`) and font (a `new poco.Font(...)`\n * object) as arguments. We maintain per-Poco caches so we resolve each\n * named color / font exactly once.\n * - **No native line, circle, or stroked rectangle.** Poco only has\n * `fillRectangle`, `drawText`, and bitmap draws. Outlines (stroke) are\n * emulated as four thin fillRectangles. Axis-aligned lines likewise.\n * Circles and diagonal lines would need the `commodetto/outline` extension\n * — they're currently stubbed (TODO for a later pass).\n * - **Text alignment is manual.** `drawText(text, font, color, x, y)` only\n * draws at a point. For center/right alignment we measure with\n * `getTextWidth` and compute the origin ourselves.\n */\n\nimport type Poco from 'commodetto/Poco';\nimport type { PocoColor, PocoFont } from 'commodetto/Poco';\nimport type { DOMElement, NodeProps } from './pebble-dom.js';\nimport { getTextContent } from './pebble-dom.js';\n\n// ---------------------------------------------------------------------------\n// Named palette — mapped to RGB, then resolved to PocoColor via a cache.\n// ---------------------------------------------------------------------------\n\nexport interface RGB {\n r: number;\n g: number;\n b: number;\n}\n\nexport const COLOR_PALETTE: Readonly<Record<string, RGB>> = {\n black: { r: 0, g: 0, b: 0 },\n white: { r: 255, g: 255, b: 255 },\n red: { r: 255, g: 0, b: 0 },\n green: { r: 0, g: 255, b: 0 },\n blue: { r: 0, g: 0, b: 255 },\n yellow: { r: 255, g: 255, b: 0 },\n orange: { r: 255, g: 128, b: 0 },\n cyan: { r: 0, g: 255, b: 255 },\n magenta: { r: 255, g: 0, b: 255 },\n clear: { r: 0, g: 0, b: 0 },\n lightGray: { r: 192, g: 192, b: 192 },\n darkGray: { r: 64, g: 64, b: 64 },\n};\n\n// ---------------------------------------------------------------------------\n// Named font shortcuts — mapped to (family, size) pairs.\n//\n// The family names here need to match fonts available in the Moddable\n// manifest. The Alloy scaffold ships \"Bitham-Black\" as a default — we use\n// it for every logical font for now. Revisit once we add custom font\n// resources to the library manifest.\n// ---------------------------------------------------------------------------\n\nexport interface FontSpec {\n family: string;\n size: number;\n}\n\nexport const FONT_PALETTE: Readonly<Record<string, FontSpec>> = {\n gothic14: { family: 'Bitham-Black', size: 14 },\n gothic14Bold: { family: 'Bitham-Black', size: 14 },\n gothic18: { family: 'Bitham-Black', size: 18 },\n gothic18Bold: { family: 'Bitham-Black', size: 18 },\n gothic24: { family: 'Bitham-Black', size: 24 },\n gothic24Bold: { family: 'Bitham-Black', size: 24 },\n gothic28: { family: 'Bitham-Black', size: 28 },\n gothic28Bold: { family: 'Bitham-Black', size: 28 },\n bitham30Black: { family: 'Bitham-Black', size: 30 },\n bitham42Bold: { family: 'Bitham-Black', size: 42 },\n bitham42Light: { family: 'Bitham-Black', size: 42 },\n bitham34MediumNumbers: { family: 'Bitham-Black', size: 34 },\n bitham42MediumNumbers: { family: 'Bitham-Black', size: 42 },\n};\n\nconst DEFAULT_FONT_KEY = 'gothic18';\n\n// ---------------------------------------------------------------------------\n// Prop accessors — the DOM is loosely typed so we coerce here.\n// ---------------------------------------------------------------------------\n\nfunction num(p: NodeProps, key: string): number {\n const v = p[key];\n return typeof v === 'number' ? v : 0;\n}\n\nfunction str(p: NodeProps, key: string): string | undefined {\n const v = p[key];\n return typeof v === 'string' ? v : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Renderer options\n// ---------------------------------------------------------------------------\n\nexport interface RenderOptions {\n backgroundColor?: string;\n /**\n * Incremental update region. If provided, `poco.begin(x, y, w, h)` is used\n * to clip drawing to just that region. Otherwise the full frame is redrawn.\n */\n dirty?: { x: number; y: number; w: number; h: number };\n}\n\n// ---------------------------------------------------------------------------\n// PocoRenderer — owns a Poco instance plus color/font caches\n// ---------------------------------------------------------------------------\n\nexport class PocoRenderer {\n readonly poco: Poco;\n private readonly colorCache = new Map<string, PocoColor>();\n private readonly fontCache = new Map<string, PocoFont>();\n\n constructor(poco: Poco) {\n this.poco = poco;\n }\n\n /**\n * Render the full tree into a fresh frame.\n */\n render(rootNode: DOMElement, options: RenderOptions = {}): void {\n const { poco } = this;\n const dirty = options.dirty;\n\n if (dirty) {\n poco.begin(dirty.x, dirty.y, dirty.w, dirty.h);\n } else {\n poco.begin();\n }\n\n // Clear to background\n const bg = this.getColor(options.backgroundColor ?? 'black');\n poco.fillRectangle(bg, 0, 0, poco.width, poco.height);\n\n // Walk the tree\n this.renderChildren(rootNode, 0, 0);\n\n poco.end();\n }\n\n /** Resolve a color name (or pass-through int) to a PocoColor. */\n getColor(name: string | undefined): PocoColor {\n const key = name ?? 'black';\n const cached = this.colorCache.get(key);\n if (cached !== undefined) return cached;\n\n const rgb = COLOR_PALETTE[key] ?? COLOR_PALETTE.white!;\n const color = this.poco.makeColor(rgb.r, rgb.g, rgb.b);\n this.colorCache.set(key, color);\n return color;\n }\n\n /** Resolve a font name to a PocoFont (cached). */\n getFont(name: string | undefined): PocoFont {\n const key = name ?? DEFAULT_FONT_KEY;\n const cached = this.fontCache.get(key);\n if (cached !== undefined) return cached;\n\n const spec = FONT_PALETTE[key] ?? FONT_PALETTE[DEFAULT_FONT_KEY]!;\n // `poco.Font` is a constructor hanging off the Poco instance.\n const FontCtor = this.poco.Font;\n const font = new FontCtor(spec.family, spec.size);\n this.fontCache.set(key, font);\n return font;\n }\n\n // -------------------------------------------------------------------------\n // Private: node renderers\n // -------------------------------------------------------------------------\n\n private renderChildren(node: DOMElement, ox: number, oy: number): void {\n for (const child of node.children) {\n if (child.type === '#text') continue;\n this.renderNode(child, ox, oy);\n }\n }\n\n private renderNode(node: DOMElement, ox: number, oy: number): void {\n const p = node.props;\n if (p._hidden) return;\n\n const x = num(p, 'x') + ox;\n const y = num(p, 'y') + oy;\n\n switch (node.type) {\n case 'pbl-rect': {\n const w = num(p, 'w') || num(p, 'width');\n const h = num(p, 'h') || num(p, 'height');\n const fill = str(p, 'fill');\n const stroke = str(p, 'stroke');\n\n if (fill) {\n this.poco.fillRectangle(this.getColor(fill), x, y, w, h);\n }\n if (stroke) {\n // Emulate outline with four thin fill rects.\n const sw = num(p, 'strokeWidth') || 1;\n const c = this.getColor(stroke);\n this.poco.fillRectangle(c, x, y, w, sw); // top\n this.poco.fillRectangle(c, x, y + h - sw, w, sw); // bottom\n this.poco.fillRectangle(c, x, y, sw, h); // left\n this.poco.fillRectangle(c, x + w - sw, y, sw, h); // right\n }\n\n this.renderChildren(node, x, y);\n break;\n }\n\n case 'pbl-text': {\n const text = getTextContent(node);\n if (!text) break;\n\n const boxW = num(p, 'w') || num(p, 'width') || this.poco.width - x;\n const font = this.getFont(str(p, 'font'));\n const color = this.getColor(str(p, 'color') ?? 'white');\n const align = str(p, 'align') ?? 'left';\n\n let tx = x;\n if (align === 'center' || align === 'right') {\n const tw = this.poco.getTextWidth(text, font);\n if (align === 'center') {\n tx = x + Math.floor((boxW - tw) / 2);\n } else {\n tx = x + boxW - tw;\n }\n }\n\n this.poco.drawText(text, font, color, tx, y);\n break;\n }\n\n case 'pbl-line': {\n // Only axis-aligned lines are supported natively. Diagonals would\n // need the commodetto/outline extension — TODO.\n const x2 = num(p, 'x2') + ox;\n const y2 = num(p, 'y2') + oy;\n const c = this.getColor(str(p, 'color') ?? str(p, 'stroke') ?? 'white');\n const sw = num(p, 'strokeWidth') || 1;\n\n if (x === x2) {\n // Vertical\n const top = Math.min(y, y2);\n const h = Math.abs(y2 - y) || 1;\n this.poco.fillRectangle(c, x, top, sw, h);\n } else if (y === y2) {\n // Horizontal\n const left = Math.min(x, x2);\n const w = Math.abs(x2 - x) || 1;\n this.poco.fillRectangle(c, left, y, w, sw);\n }\n // else: diagonal line — silently skipped for now\n break;\n }\n\n case 'pbl-circle': {\n // TODO: implement via commodetto/outline extension (blendOutline)\n // or a Bresenham-style approximation. Stubbed for now.\n break;\n }\n\n case 'pbl-image': {\n const bitmap = p.bitmap;\n if (bitmap) {\n this.poco.drawBitmap(bitmap as never, x, y);\n }\n break;\n }\n\n case 'pbl-group': {\n this.renderChildren(node, x, y);\n break;\n }\n\n case 'pbl-statusbar':\n case 'pbl-actionbar': {\n // Alloy has no built-in status/action bar UI; these are no-ops for now.\n // An app that wants a status bar should draw its own.\n break;\n }\n\n case 'pbl-root': {\n this.renderChildren(node, ox, oy);\n break;\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Compatibility shims — still useful for mock-mode tests that want to\n// resolve a color name without constructing a Poco. These return *names*\n// rather than native handles.\n// ---------------------------------------------------------------------------\n\nexport function resolveColorName(color: string | undefined): string {\n if (!color) return 'black';\n return color in COLOR_PALETTE ? color : 'black';\n}\n\nexport function resolveFontName(font: string | undefined): string {\n if (!font) return DEFAULT_FONT_KEY;\n return font in FONT_PALETTE ? font : DEFAULT_FONT_KEY;\n}\n","/**\n * pebble-dom-shim.ts — A minimal DOM-like adapter over `pebble-dom` so\n * Preact's `render(vnode, parentDom)` can drive it.\n *\n * Preact's diff loop mutates a tree of DOM-shaped nodes by calling:\n * - document.createElement(tag)\n * - document.createTextNode(text)\n * - parent.appendChild(child), .insertBefore(child, ref), .removeChild(child)\n * - element.setAttribute(name, value), .removeAttribute(name)\n * - element.addEventListener(name, handler), .removeEventListener(...)\n * - element.nodeType, .nodeName, .parentNode, .childNodes, .firstChild,\n * .nextSibling\n *\n * This file implements the minimum surface Preact actually touches when\n * rendering into a headless tree. Each \"element\" carries a reference to the\n * underlying pebble-dom node so the renderer can walk both views\n * interchangeably.\n *\n * The shim is deliberately NOT a full undom — it only does what Preact 10\n * needs. If we trip on a missing method, add it here rather than including\n * undom (which would push the bundle back up).\n */\n\nimport type { AnyNode, DOMElement, ElementType, TextNode } from './pebble-dom.js';\nimport {\n ELEMENT_TYPES,\n appendChildNode,\n createNode,\n createTextNode,\n insertBeforeNode,\n removeChildNode,\n setAttribute,\n setTextNodeValue,\n} from './pebble-dom.js';\n\n// ---------------------------------------------------------------------------\n// DOM node interfaces the shim exposes to Preact\n// ---------------------------------------------------------------------------\n\ninterface ShimNodeBase {\n readonly nodeType: number;\n nodeName: string;\n parentNode: ShimElement | null;\n childNodes: ShimNode[];\n firstChild: ShimNode | null;\n nextSibling: ShimNode | null;\n /** The backing pebble-dom node. */\n readonly _pbl: AnyNode;\n}\n\nexport interface ShimElement extends ShimNodeBase {\n readonly nodeType: 1;\n readonly localName: string;\n readonly tagName: string;\n readonly _pbl: DOMElement;\n attributes: Record<string, unknown>;\n\n appendChild<T extends ShimNode>(child: T): T;\n insertBefore<T extends ShimNode>(child: T, ref: ShimNode | null): T;\n removeChild<T extends ShimNode>(child: T): T;\n remove(): void;\n\n setAttribute(name: string, value: unknown): void;\n removeAttribute(name: string): void;\n getAttribute(name: string): unknown;\n\n addEventListener(name: string, handler: (...args: unknown[]) => unknown): void;\n removeEventListener(name: string, handler: (...args: unknown[]) => unknown): void;\n}\n\nexport interface ShimText extends ShimNodeBase {\n readonly nodeType: 3;\n readonly _pbl: TextNode;\n data: string;\n nodeValue: string;\n textContent: string;\n}\n\nexport type ShimNode = ShimElement | ShimText;\n\n// ---------------------------------------------------------------------------\n// Shim factories\n// ---------------------------------------------------------------------------\n\nfunction linkSiblings(parent: ShimElement): void {\n const kids = parent.childNodes;\n parent.firstChild = kids[0] ?? null;\n for (let i = 0; i < kids.length; i++) {\n const node = kids[i]!;\n node.parentNode = parent;\n node.nextSibling = kids[i + 1] ?? null;\n }\n}\n\nexport function createShimElement(tag: string): ShimElement {\n // Accept both 'pbl-rect' and friendly aliases from components. Unknown\n // tags are rejected loudly so typos surface at render time.\n const pblType = tag as ElementType;\n if (!ELEMENT_TYPES.has(pblType)) {\n throw new Error(`react-pebble: unknown element tag \"${tag}\"`);\n }\n\n const pbl = createNode(pblType);\n\n const el: ShimElement = {\n nodeType: 1,\n nodeName: tag.toUpperCase(),\n localName: tag,\n tagName: tag.toUpperCase(),\n _pbl: pbl,\n attributes: {},\n parentNode: null,\n childNodes: [],\n firstChild: null,\n nextSibling: null,\n\n appendChild(child) {\n // Detach from any prior parent in the shim view\n if (child.parentNode) {\n child.parentNode.removeChild(child);\n }\n this.childNodes.push(child);\n appendChildNode(pbl, child._pbl);\n linkSiblings(this);\n return child;\n },\n\n insertBefore(child, ref) {\n if (child.parentNode) {\n child.parentNode.removeChild(child);\n }\n if (ref === null) {\n return this.appendChild(child);\n }\n const idx = this.childNodes.indexOf(ref);\n if (idx < 0) {\n return this.appendChild(child);\n }\n this.childNodes.splice(idx, 0, child);\n insertBeforeNode(pbl, child._pbl, ref._pbl);\n linkSiblings(this);\n return child;\n },\n\n removeChild(child) {\n const idx = this.childNodes.indexOf(child);\n if (idx >= 0) {\n this.childNodes.splice(idx, 1);\n }\n removeChildNode(pbl, child._pbl);\n child.parentNode = null;\n child.nextSibling = null;\n linkSiblings(this);\n return child;\n },\n\n remove() {\n if (this.parentNode) {\n this.parentNode.removeChild(this);\n }\n },\n\n setAttribute(name, value) {\n this.attributes[name] = value;\n setAttribute(pbl, name, value);\n },\n\n removeAttribute(name) {\n delete this.attributes[name];\n setAttribute(pbl, name, undefined);\n },\n\n getAttribute(name) {\n return this.attributes[name];\n },\n\n addEventListener(name, handler) {\n // Event handlers are stored in props (on* style) so the button wiring\n // in pebble-render.ts can find them the same way React props do.\n const key = `on${name[0]?.toUpperCase()}${name.slice(1)}`;\n this.attributes[key] = handler;\n setAttribute(pbl, key, handler);\n },\n\n removeEventListener(name, _handler) {\n const key = `on${name[0]?.toUpperCase()}${name.slice(1)}`;\n delete this.attributes[key];\n setAttribute(pbl, key, undefined);\n },\n };\n\n return el;\n}\n\nexport function createShimText(data: string): ShimText {\n const pbl = createTextNode(data);\n\n const node: ShimText = {\n nodeType: 3,\n nodeName: '#text',\n _pbl: pbl,\n data,\n nodeValue: data,\n textContent: data,\n parentNode: null,\n childNodes: [],\n firstChild: null,\n nextSibling: null,\n };\n\n // Keep pebble-dom in sync whenever data/nodeValue/textContent is assigned.\n // Preact mutates `.data` directly on text updates.\n Object.defineProperty(node, 'data', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n Object.defineProperty(node, 'nodeValue', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n Object.defineProperty(node, 'textContent', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n\n return node;\n}\n\n// ---------------------------------------------------------------------------\n// Shim \"document\" — what Preact reaches via `parentDom.ownerDocument` etc.\n// ---------------------------------------------------------------------------\n\nexport interface ShimDocument {\n createElement(tag: string): ShimElement;\n createElementNS(ns: string | null, tag: string): ShimElement;\n createTextNode(data: string): ShimText;\n}\n\nexport const shimDocument: ShimDocument = {\n createElement: createShimElement,\n createElementNS: (_ns, tag) => createShimElement(tag),\n createTextNode: createShimText,\n};\n\n// ---------------------------------------------------------------------------\n// Root container — the \"parent DOM\" handed to preact.render().\n// ---------------------------------------------------------------------------\n\nexport function createShimRoot(): ShimElement {\n const root = createShimElement('pbl-root');\n // Preact reads `ownerDocument` off the parent.\n (root as unknown as { ownerDocument: ShimDocument }).ownerDocument = shimDocument;\n return root;\n}\n","/**\n * pebble-reconciler.ts — Preact-backed reconciler for react-pebble.\n *\n * Replaces the old react-reconciler host config. We don't need a custom\n * reconciler at all with Preact — Preact's `render(vnode, parentDom)` does\n * the diffing, and we provide a DOM-shaped container via `pebble-dom-shim`\n * so Preact writes into our pebble-dom tree instead of a real DOM.\n *\n * The public surface (for pebble-render.ts) is:\n * - createReconcilerContainer() → a pair of root shim + pebble-dom root\n * - updateContainer(vnode, container) → runs preact.render()\n * - unmountContainer(container) → runs preact.render(null, ...)\n */\n\nimport { render as preactRender } from 'preact';\nimport type { ComponentChild } from 'preact';\nimport type { DOMElement } from './pebble-dom.js';\nimport { createShimRoot, shimDocument } from './pebble-dom-shim.js';\nimport type { ShimElement } from './pebble-dom-shim.js';\n\n// Preact's render() references `document` internally. In non-browser\n// environments (Node mock mode, Alloy XS) we shim it with our pebble-dom\n// adapter so Preact doesn't crash.\nif (typeof document === 'undefined') {\n (globalThis as unknown as { document: unknown }).document = shimDocument;\n}\n\nexport interface PebbleContainer {\n shimRoot: ShimElement;\n pblRoot: DOMElement;\n}\n\nexport function createContainer(): PebbleContainer {\n const shimRoot = createShimRoot();\n return {\n shimRoot,\n pblRoot: shimRoot._pbl,\n };\n}\n\nexport function updateContainer(vnode: ComponentChild, container: PebbleContainer): void {\n preactRender(vnode, container.shimRoot as unknown as Element);\n}\n\nexport function unmountContainer(container: PebbleContainer): void {\n preactRender(null, container.shimRoot as unknown as Element);\n}\n\n// For backwards-compat with the old default export pattern.\nexport default {\n createContainer,\n updateContainer,\n unmountContainer,\n};\n","/**\n * pebble-render.ts — Entry point for react-pebble on Pebble Alloy.\n *\n * Bridges Preact's output (via a DOM-shim over pebble-dom) to Moddable's\n * Poco renderer, which draws into the watch framebuffer. Also hosts the\n * Node mock path used for unit tests and local development.\n *\n * Platform detection is via `typeof screen`:\n * - screen exists → Alloy/XS runtime → real Poco draws\n * - screen undefined → Node → mock Poco records calls to an in-memory log\n */\n\nimport { options } from 'preact';\nimport type { ComponentChild } from 'preact';\nimport type Poco from 'commodetto/Poco';\nimport type { PocoBitmap, PocoColor, PocoFont } from 'commodetto/Poco';\nimport type { DOMElement } from './pebble-dom.js';\nimport { PocoRenderer } from './pebble-output.js';\nimport type { PebbleButton, PebbleButtonHandler } from './hooks/index.js';\nimport { ButtonRegistry } from './hooks/index.js';\nimport type { PebbleContainer } from './pebble-reconciler.js';\nimport {\n createContainer,\n updateContainer,\n unmountContainer,\n} from './pebble-reconciler.js';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface PebblePlatformInfo {\n isReal: boolean;\n platform: 'alloy' | 'mock';\n screenWidth: number;\n screenHeight: number;\n}\n\nexport interface DrawCall {\n op: string;\n [key: string]: unknown;\n}\n\nexport interface RenderOptions {\n backgroundColor?: string;\n}\n\nexport interface PebbleApp {\n update(newElement: ComponentChild): void;\n unmount(): void;\n readonly platform: PebblePlatformInfo;\n readonly drawLog: readonly DrawCall[];\n readonly _root: DOMElement;\n}\n\n// ---------------------------------------------------------------------------\n// Mock Poco — records every draw call into a shared log so tests can assert.\n// ---------------------------------------------------------------------------\n\nclass MockPoco {\n readonly width: number;\n readonly height: number;\n readonly Font: new (name: string, size: number) => PocoFont;\n\n constructor(width: number, height: number, private readonly log: DrawCall[]) {\n this.width = width;\n this.height = height;\n const FontImpl = class {\n readonly name: string;\n readonly size: number;\n readonly height: number;\n constructor(name: string, size: number) {\n this.name = name;\n this.size = size;\n this.height = size;\n }\n };\n this.Font = FontImpl as unknown as new (name: string, size: number) => PocoFont;\n }\n\n begin(x?: number, y?: number, width?: number, height?: number): void {\n this.log.push({ op: 'begin', x, y, width, height });\n }\n end(): void {\n this.log.push({ op: 'end' });\n }\n continue(x: number, y: number, width: number, height: number): void {\n this.log.push({ op: 'continue', x, y, width, height });\n }\n clip(x?: number, y?: number, width?: number, height?: number): void {\n this.log.push({ op: 'clip', x, y, width, height });\n }\n origin(x?: number, y?: number): void {\n this.log.push({ op: 'origin', x, y });\n }\n\n makeColor(r: number, g: number, b: number): PocoColor {\n return ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);\n }\n\n fillRectangle(color: PocoColor, x: number, y: number, width: number, height: number): void {\n this.log.push({ op: 'fillRectangle', color, x, y, width, height });\n }\n blendRectangle(\n color: PocoColor,\n blend: number,\n x: number,\n y: number,\n width: number,\n height: number,\n ): void {\n this.log.push({ op: 'blendRectangle', color, blend, x, y, width, height });\n }\n drawPixel(color: PocoColor, x: number, y: number): void {\n this.log.push({ op: 'drawPixel', color, x, y });\n }\n drawBitmap(_bits: PocoBitmap, x: number, y: number): void {\n this.log.push({ op: 'drawBitmap', x, y });\n }\n drawMonochrome(\n _monochrome: PocoBitmap,\n fore: PocoColor,\n back: PocoColor | undefined,\n x: number,\n y: number,\n ): void {\n this.log.push({ op: 'drawMonochrome', fore, back, x, y });\n }\n\n drawText(text: string, font: PocoFont, color: PocoColor, x: number, y: number): void {\n this.log.push({ op: 'drawText', text, font, color, x, y });\n }\n getTextWidth(text: string, font: PocoFont): number {\n const size = (font as unknown as { size?: number }).size ?? 14;\n return Math.round(text.length * size * 0.6);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Poco construction — real on Alloy, mock in Node\n// ---------------------------------------------------------------------------\n\nfunction createPoco(\n log: DrawCall[],\n pocoCtor: typeof Poco | undefined,\n): { poco: Poco; info: PebblePlatformInfo } {\n if (typeof screen !== 'undefined' && screen && pocoCtor) {\n const poco = new pocoCtor(screen);\n return {\n poco,\n info: {\n isReal: true,\n platform: 'alloy',\n screenWidth: screen.width,\n screenHeight: screen.height,\n },\n };\n }\n\n const width = 200;\n const height = 228;\n const mock = new MockPoco(width, height, log);\n return {\n poco: mock as unknown as Poco,\n info: {\n isReal: false,\n platform: 'mock',\n screenWidth: width,\n screenHeight: height,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Button wiring — see moddable.d.ts for the known/unknown event names.\n// ---------------------------------------------------------------------------\n\nfunction wireWatchButtons(): () => void {\n if (typeof watch === 'undefined' || !watch) return () => undefined;\n\n const normalize = (raw: unknown): PebbleButton | undefined => {\n if (typeof raw !== 'string') return undefined;\n const low = raw.toLowerCase();\n if (low === 'up' || low === 'down' || low === 'select' || low === 'back') {\n return low;\n }\n return undefined;\n };\n\n const onShort = (payload?: { button?: unknown }) => {\n const b = normalize(payload?.button);\n if (b) ButtonRegistry.emit(b);\n };\n const onLong = (payload?: { button?: unknown }) => {\n const b = normalize(payload?.button);\n if (b) ButtonRegistry.emit(`long_${b}`);\n };\n\n watch.addEventListener('button', onShort);\n watch.addEventListener('buttonClick', onShort);\n watch.addEventListener('longClick', onLong);\n\n return () => {\n if (typeof watch === 'undefined' || !watch) return;\n watch.removeEventListener('button', onShort);\n watch.removeEventListener('buttonClick', onShort);\n watch.removeEventListener('longClick', onLong);\n };\n}\n\n// ---------------------------------------------------------------------------\n// Redraw scheduling\n//\n// Preact renders are synchronous; when any component calls setState, Preact\n// re-runs the diff and mutates the shim tree in place. We hook into that\n// by scheduling a Poco redraw on the next tick.\n// ---------------------------------------------------------------------------\n\nfunction scheduleMicrotask(fn: () => void): void {\n // Prefer Promise.resolve().then for microtask batching; fall back to\n // setTimeout(0) if Promise isn't wired up in some host.\n if (typeof Promise !== 'undefined') {\n Promise.resolve().then(fn);\n } else {\n setTimeout(fn, 0);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public render API\n// ---------------------------------------------------------------------------\n\nexport interface RenderOptionsExt extends RenderOptions {\n /**\n * Pre-imported Poco constructor. Alloy entry files must import Poco at\n * the top and pass it here so the Moddable bundler resolves it correctly.\n */\n poco?: typeof Poco;\n}\n\nexport function render(element: ComponentChild, options: RenderOptionsExt = {}): PebbleApp {\n const drawLog: DrawCall[] = [];\n const container: PebbleContainer = createContainer();\n const { poco, info } = createPoco(drawLog, options.poco);\n const renderer = new PocoRenderer(poco);\n\n let pending = false;\n const redraw = () => {\n pending = false;\n drawLog.length = 0;\n renderer.render(container.pblRoot, { backgroundColor: options.backgroundColor });\n };\n\n const schedule = () => {\n if (pending) return;\n pending = true;\n scheduleMicrotask(redraw);\n };\n\n // Monkey-patch the shim root to redraw on any mutation.\n // Preact calls appendChild/insertBefore/removeChild/setAttribute on the\n // tree during diff; we only need to schedule a redraw when the diff\n // settles, which is right after the top-level render() call returns.\n // For that we just trigger a redraw synchronously after updateContainer.\n\n // Hook Preact's commit phase so hook-driven state updates trigger a redraw\n // without polling. options._commit is an undocumented-but-stable hook that\n // fires once per root-level diff settle.\n type PreactOptionsWithCommit = typeof options & {\n _commit?: (root: unknown, queue: unknown[]) => void;\n __c?: (root: unknown, queue: unknown[]) => void;\n };\n const opts = options as PreactOptionsWithCommit;\n const prevCommit = opts._commit ?? opts.__c;\n const commitHook = (root: unknown, queue: unknown[]) => {\n if (prevCommit) prevCommit(root, queue);\n schedule();\n };\n opts._commit = commitHook;\n opts.__c = commitHook;\n\n updateContainer(element, container);\n // Always paint once on mount.\n redraw();\n\n // Subscribe to watch events on-device.\n const unwireButtons = wireWatchButtons();\n\n return {\n update(newElement) {\n updateContainer(newElement, container);\n schedule();\n },\n unmount() {\n unmountContainer(container);\n // Restore prior commit hook (in case another app was rendered).\n opts._commit = prevCommit;\n opts.__c = prevCommit;\n unwireButtons();\n },\n get platform() {\n return info;\n },\n get drawLog() {\n return drawLog as readonly DrawCall[];\n },\n get _root() {\n return container.pblRoot;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/pebble-dom.ts","../../src/pebble-output.ts","../../src/pebble-dom-shim.ts","../../src/pebble-reconciler.ts","../../src/pebble-render.ts"],"sourcesContent":["/**\n * pebble-dom.ts — Virtual DOM layer for React Pebble\n *\n * Modeled after Ink's dom.ts but stripped of Yoga layout.\n * Pebble uses absolute positioning (x, y, w, h) rather than flexbox,\n * so nodes are just plain JS objects with type, props, and children.\n *\n * Each node type maps to a Pebble drawing primitive:\n * pbl-root → Container root (the Window)\n * pbl-rect → fillRect / drawRect\n * pbl-circle → fillCircle / drawCircle\n * pbl-text → drawText\n * pbl-line → drawLine\n * pbl-image → drawImage (bitmap)\n * pbl-group → Logical grouping with offset (no draw call)\n * #text → Raw text content (only valid inside pbl-text)\n */\n\n// ---------------------------------------------------------------------------\n// Element types\n// ---------------------------------------------------------------------------\n\nexport type ElementType =\n | 'pbl-root'\n | 'pbl-rect'\n | 'pbl-circle'\n | 'pbl-text'\n | 'pbl-line'\n | 'pbl-image'\n | 'pbl-group'\n | 'pbl-statusbar'\n | 'pbl-actionbar';\n\nexport const ELEMENT_TYPES: ReadonlySet<ElementType> = new Set<ElementType>([\n 'pbl-root',\n 'pbl-rect',\n 'pbl-circle',\n 'pbl-text',\n 'pbl-line',\n 'pbl-image',\n 'pbl-group',\n 'pbl-statusbar',\n 'pbl-actionbar',\n]);\n\n// ---------------------------------------------------------------------------\n// Node shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Loose prop bag — element-specific shapes are documented on each component\n * wrapper, but the reconciler treats them uniformly.\n */\nexport type NodeProps = Record<string, unknown> & {\n _hidden?: boolean;\n};\n\nexport interface DOMElement {\n id: number;\n type: ElementType;\n props: NodeProps;\n children: Array<DOMElement | TextNode>;\n parent: DOMElement | null;\n /** Called by the reconciler after each commit; wired up by `render()`. */\n onRender: (() => void) | null;\n /** Optional layout pass; we currently don't use this. */\n onComputeLayout: (() => void) | null;\n /** Internal dirty flag (currently informational only). */\n _dirty: boolean;\n}\n\nexport interface TextNode {\n id: number;\n type: '#text';\n value: string;\n parent: DOMElement | null;\n /** Saved value while the node is hidden by Suspense. */\n _hiddenValue?: string;\n}\n\nexport type AnyNode = DOMElement | TextNode;\n\n// ---------------------------------------------------------------------------\n// Node creation\n// ---------------------------------------------------------------------------\n\nlet nextNodeId = 1;\n\nexport function createNode(type: ElementType): DOMElement {\n return {\n id: nextNodeId++,\n type,\n props: {},\n children: [],\n parent: null,\n onRender: null,\n onComputeLayout: null,\n _dirty: true,\n };\n}\n\nexport function createTextNode(text: string): TextNode {\n return {\n id: nextNodeId++,\n type: '#text',\n value: text,\n parent: null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tree manipulation\n// ---------------------------------------------------------------------------\n\nexport function appendChildNode(parent: DOMElement, child: AnyNode): void {\n if (child.parent) {\n removeChildNode(child.parent, child);\n }\n child.parent = parent;\n parent.children.push(child);\n}\n\nexport function insertBeforeNode(\n parent: DOMElement,\n child: AnyNode,\n beforeChild: AnyNode,\n): void {\n if (child.parent) {\n removeChildNode(child.parent, child);\n }\n child.parent = parent;\n const idx = parent.children.indexOf(beforeChild);\n if (idx >= 0) {\n parent.children.splice(idx, 0, child);\n } else {\n parent.children.push(child);\n }\n}\n\nexport function removeChildNode(parent: DOMElement, child: AnyNode): void {\n parent.children = parent.children.filter((c) => c !== child);\n child.parent = null;\n}\n\n// ---------------------------------------------------------------------------\n// Property / attribute helpers\n// ---------------------------------------------------------------------------\n\nexport function setAttribute(node: DOMElement, key: string, value: unknown): void {\n if (value === undefined) {\n delete node.props[key];\n } else {\n node.props[key] = value;\n }\n}\n\nexport function setTextNodeValue(node: TextNode, text: string): void {\n node.value = text;\n}\n\n// ---------------------------------------------------------------------------\n// Tree traversal helpers\n// ---------------------------------------------------------------------------\n\nexport function getTextContent(node: AnyNode): string {\n if (node.type === '#text') {\n return node.value;\n }\n return node.children.map(getTextContent).join('');\n}\n\nexport type Visitor = (node: AnyNode, depth: number) => void;\n\nexport function walkTree(root: AnyNode, visitor: Visitor, depth = 0): void {\n visitor(root, depth);\n if (root.type !== '#text') {\n for (const child of root.children) {\n walkTree(child, visitor, depth + 1);\n }\n }\n}\n\nexport function findRoot(node: AnyNode): DOMElement {\n let current: AnyNode = node;\n while (current.parent) {\n current = current.parent;\n }\n // The root is always a DOMElement (created via createNode).\n return current as DOMElement;\n}\n","/**\n * pebble-output.ts — Poco output layer for react-pebble on Pebble Alloy.\n *\n * Walks the virtual DOM tree (pebble-dom) and issues draw calls against\n * a `commodetto/Poco` renderer, which writes into the watch framebuffer.\n *\n * Key differences from a canvas-style API:\n *\n * - **No stateful color or font.** Every draw call takes the color (an int\n * produced by `poco.makeColor(r, g, b)`) and font (a `new poco.Font(...)`\n * object) as arguments. We maintain per-Poco caches so we resolve each\n * named color / font exactly once.\n * - **No native line, circle, or stroked rectangle.** Poco only has\n * `fillRectangle`, `drawText`, and bitmap draws. Outlines (stroke) are\n * emulated as four thin fillRectangles. Axis-aligned lines use\n * fillRectangles. Circles use a midpoint circle algorithm and diagonal\n * lines use Bresenham's algorithm — both decomposed into fillRectangle\n * calls so they work on mock and real Poco without requiring extensions.\n * - **Text alignment is manual.** `drawText(text, font, color, x, y)` only\n * draws at a point. For center/right alignment we measure with\n * `getTextWidth` and compute the origin ourselves.\n */\n\nimport type Poco from 'commodetto/Poco';\nimport type { PocoColor, PocoFont } from 'commodetto/Poco';\nimport type { DOMElement, NodeProps } from './pebble-dom.js';\nimport { getTextContent } from './pebble-dom.js';\n\n// ---------------------------------------------------------------------------\n// Named palette — mapped to RGB, then resolved to PocoColor via a cache.\n// ---------------------------------------------------------------------------\n\nexport interface RGB {\n r: number;\n g: number;\n b: number;\n}\n\nexport const COLOR_PALETTE: Readonly<Record<string, RGB>> = {\n black: { r: 0, g: 0, b: 0 },\n white: { r: 255, g: 255, b: 255 },\n red: { r: 255, g: 0, b: 0 },\n green: { r: 0, g: 255, b: 0 },\n blue: { r: 0, g: 0, b: 255 },\n yellow: { r: 255, g: 255, b: 0 },\n orange: { r: 255, g: 128, b: 0 },\n cyan: { r: 0, g: 255, b: 255 },\n magenta: { r: 255, g: 0, b: 255 },\n clear: { r: 0, g: 0, b: 0 },\n lightGray: { r: 192, g: 192, b: 192 },\n darkGray: { r: 64, g: 64, b: 64 },\n};\n\n// ---------------------------------------------------------------------------\n// Named font shortcuts — mapped to (family, size) pairs.\n//\n// The family names must match fonts available in the Moddable manifest.\n// These correspond to the Pebble system font families available in Alloy.\n// The piu compiler uses the same families via FONT_TO_PIU in compile-to-piu.ts.\n// ---------------------------------------------------------------------------\n\nexport interface FontSpec {\n family: string;\n size: number;\n}\n\nexport const FONT_PALETTE: Readonly<Record<string, FontSpec>> = {\n // Gothic family — standard UI text\n gothic14: { family: 'Gothic', size: 14 },\n gothic14Bold: { family: 'Gothic-Bold', size: 14 },\n gothic18: { family: 'Gothic', size: 18 },\n gothic18Bold: { family: 'Gothic-Bold', size: 18 },\n gothic24: { family: 'Gothic', size: 24 },\n gothic24Bold: { family: 'Gothic-Bold', size: 24 },\n gothic28: { family: 'Gothic', size: 28 },\n gothic28Bold: { family: 'Gothic-Bold', size: 28 },\n\n // Bitham family — large display fonts\n bitham30Black: { family: 'Bitham-Black', size: 30 },\n bitham42Bold: { family: 'Bitham-Bold', size: 42 },\n bitham42Light: { family: 'Bitham-Light', size: 42 },\n bitham34MediumNumbers: { family: 'Bitham', size: 34 },\n bitham42MediumNumbers: { family: 'Bitham', size: 42 },\n\n // Roboto family\n robotoCondensed21: { family: 'Roboto-Condensed', size: 21 },\n roboto21: { family: 'Roboto', size: 21 },\n\n // Droid Serif\n droid28: { family: 'Droid-Serif', size: 28 },\n\n // LECO family — LED-style numeric fonts\n leco20: { family: 'LECO', size: 20 },\n leco26: { family: 'LECO', size: 26 },\n leco28: { family: 'LECO', size: 28 },\n leco32: { family: 'LECO', size: 32 },\n leco36: { family: 'LECO', size: 36 },\n leco38: { family: 'LECO', size: 38 },\n leco42: { family: 'LECO', size: 42 },\n};\n\nconst DEFAULT_FONT_KEY = 'gothic18';\n\n// ---------------------------------------------------------------------------\n// Prop accessors — the DOM is loosely typed so we coerce here.\n// ---------------------------------------------------------------------------\n\nfunction num(p: NodeProps, key: string): number {\n const v = p[key];\n return typeof v === 'number' ? v : 0;\n}\n\nfunction str(p: NodeProps, key: string): string | undefined {\n const v = p[key];\n return typeof v === 'string' ? v : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Renderer options\n// ---------------------------------------------------------------------------\n\nexport interface RenderOptions {\n backgroundColor?: string;\n /**\n * Incremental update region. If provided, `poco.begin(x, y, w, h)` is used\n * to clip drawing to just that region. Otherwise the full frame is redrawn.\n */\n dirty?: { x: number; y: number; w: number; h: number };\n}\n\n// ---------------------------------------------------------------------------\n// PocoRenderer — owns a Poco instance plus color/font caches\n// ---------------------------------------------------------------------------\n\nexport class PocoRenderer {\n readonly poco: Poco;\n private readonly colorCache = new Map<string, PocoColor>();\n private readonly fontCache = new Map<string, PocoFont>();\n\n constructor(poco: Poco) {\n this.poco = poco;\n }\n\n /**\n * Render the full tree into a fresh frame.\n */\n render(rootNode: DOMElement, options: RenderOptions = {}): void {\n const { poco } = this;\n const dirty = options.dirty;\n\n if (dirty) {\n poco.begin(dirty.x, dirty.y, dirty.w, dirty.h);\n } else {\n poco.begin();\n }\n\n // Clear to background\n const bg = this.getColor(options.backgroundColor ?? 'black');\n poco.fillRectangle(bg, 0, 0, poco.width, poco.height);\n\n // Walk the tree\n this.renderChildren(rootNode, 0, 0);\n\n poco.end();\n }\n\n /** Resolve a color name (or pass-through int) to a PocoColor. */\n getColor(name: string | undefined): PocoColor {\n const key = name ?? 'black';\n const cached = this.colorCache.get(key);\n if (cached !== undefined) return cached;\n\n const rgb = COLOR_PALETTE[key] ?? COLOR_PALETTE.white!;\n const color = this.poco.makeColor(rgb.r, rgb.g, rgb.b);\n this.colorCache.set(key, color);\n return color;\n }\n\n /** Resolve a font name to a PocoFont (cached). */\n getFont(name: string | undefined): PocoFont {\n const key = name ?? DEFAULT_FONT_KEY;\n const cached = this.fontCache.get(key);\n if (cached !== undefined) return cached;\n\n const spec = FONT_PALETTE[key] ?? FONT_PALETTE[DEFAULT_FONT_KEY]!;\n // `poco.Font` is a constructor hanging off the Poco instance.\n const FontCtor = this.poco.Font;\n const font = new FontCtor(spec.family, spec.size);\n this.fontCache.set(key, font);\n return font;\n }\n\n // -------------------------------------------------------------------------\n // Private: node renderers\n // -------------------------------------------------------------------------\n\n private renderChildren(node: DOMElement, ox: number, oy: number): void {\n for (const child of node.children) {\n if (child.type === '#text') continue;\n this.renderNode(child, ox, oy);\n }\n }\n\n private renderNode(node: DOMElement, ox: number, oy: number): void {\n const p = node.props;\n if (p._hidden) return;\n\n const x = num(p, 'x') + ox;\n const y = num(p, 'y') + oy;\n\n switch (node.type) {\n case 'pbl-rect': {\n const w = num(p, 'w') || num(p, 'width');\n const h = num(p, 'h') || num(p, 'height');\n const fill = str(p, 'fill');\n const stroke = str(p, 'stroke');\n const br = num(p, 'borderRadius');\n\n if (br > 0) {\n // Rounded rectangle\n if (fill) {\n this.fillRoundRect(this.getColor(fill), x, y, w, h, br);\n }\n if (stroke) {\n const sw = num(p, 'strokeWidth') || 1;\n this.strokeRoundRect(this.getColor(stroke), x, y, w, h, br, sw);\n }\n } else {\n // Sharp rectangle\n if (fill) {\n this.poco.fillRectangle(this.getColor(fill), x, y, w, h);\n }\n if (stroke) {\n const sw = num(p, 'strokeWidth') || 1;\n const c = this.getColor(stroke);\n this.poco.fillRectangle(c, x, y, w, sw); // top\n this.poco.fillRectangle(c, x, y + h - sw, w, sw); // bottom\n this.poco.fillRectangle(c, x, y, sw, h); // left\n this.poco.fillRectangle(c, x + w - sw, y, sw, h); // right\n }\n }\n\n this.renderChildren(node, x, y);\n break;\n }\n\n case 'pbl-text': {\n const text = getTextContent(node);\n if (!text) break;\n\n const boxW = num(p, 'w') || num(p, 'width') || this.poco.width - x;\n const boxH = num(p, 'h') || num(p, 'height') || 0;\n const font = this.getFont(str(p, 'font'));\n const color = this.getColor(str(p, 'color') ?? 'white');\n const align = str(p, 'align') ?? 'left';\n const lineHeight = (font as unknown as { height: number }).height || 16;\n\n // Word-wrap text into lines that fit within boxW\n const lines = this.wrapText(text, font, boxW);\n\n let ty = y;\n for (const line of lines) {\n // Stop if we'd exceed the box height (when specified)\n if (boxH > 0 && ty - y + lineHeight > boxH) break;\n\n let tx = x;\n if (align === 'center' || align === 'right') {\n const tw = this.poco.getTextWidth(line, font);\n if (align === 'center') {\n tx = x + Math.floor((boxW - tw) / 2);\n } else {\n tx = x + boxW - tw;\n }\n }\n\n this.poco.drawText(line, font, color, tx, ty);\n ty += lineHeight;\n }\n break;\n }\n\n case 'pbl-line': {\n // Only axis-aligned lines are supported natively. Diagonals would\n // need the commodetto/outline extension — TODO.\n const x2 = num(p, 'x2') + ox;\n const y2 = num(p, 'y2') + oy;\n const c = this.getColor(str(p, 'color') ?? str(p, 'stroke') ?? 'white');\n const sw = num(p, 'strokeWidth') || 1;\n\n if (x === x2) {\n // Vertical\n const top = Math.min(y, y2);\n const h = Math.abs(y2 - y) || 1;\n this.poco.fillRectangle(c, x, top, sw, h);\n } else if (y === y2) {\n // Horizontal\n const left = Math.min(x, x2);\n const w = Math.abs(x2 - x) || 1;\n this.poco.fillRectangle(c, left, y, w, sw);\n }\n else {\n // Diagonal line via Bresenham's algorithm\n this.drawDiagonalLine(c, x, y, x2, y2, sw);\n }\n break;\n }\n\n case 'pbl-circle': {\n const r = num(p, 'r') || num(p, 'radius');\n if (r <= 0) break;\n const fill = str(p, 'fill');\n const stroke = str(p, 'stroke');\n const sw = num(p, 'strokeWidth') || 1;\n\n // Midpoint circle algorithm — works on any Poco (real or mock)\n // without requiring the commodetto/outline extension.\n if (fill) {\n const fc = this.getColor(fill);\n this.fillCircle(fc, x + r, y + r, r);\n }\n if (stroke) {\n const sc = this.getColor(stroke);\n this.strokeCircle(sc, x + r, y + r, r, sw);\n }\n break;\n }\n\n case 'pbl-image': {\n const bitmap = p.bitmap;\n if (bitmap) {\n const rotation = num(p, 'rotation');\n const scale = num(p, 'scale');\n if (rotation || (scale && scale !== 1)) {\n // Use Poco's extended drawBitmap with rotation/scale if available.\n // The mock Poco records the intent; the real Poco handles transforms.\n const bmp = bitmap as never;\n const poco = this.poco as Poco & {\n drawBitmapWithTransform?: (\n bmp: never, x: number, y: number, rotation: number, scale: number,\n ) => void;\n };\n if (poco.drawBitmapWithTransform) {\n poco.drawBitmapWithTransform(bmp, x, y, rotation, scale || 1);\n } else {\n // Fallback: draw without transform\n this.poco.drawBitmap(bmp, x, y);\n }\n } else {\n this.poco.drawBitmap(bitmap as never, x, y);\n }\n }\n break;\n }\n\n case 'pbl-group': {\n this.renderChildren(node, x, y);\n break;\n }\n\n case 'pbl-statusbar': {\n // Render a simple status bar: background + time text\n const sbBg = str(p, 'backgroundColor') ?? 'black';\n const sbColor = str(p, 'color') ?? 'white';\n const sbH = 16;\n const sbW = this.poco.width;\n\n this.poco.fillRectangle(this.getColor(sbBg), 0, 0, sbW, sbH);\n\n // Draw current time in the center\n const sbFont = this.getFont('gothic14');\n const now = new Date();\n const timeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;\n const tw = this.poco.getTextWidth(timeStr, sbFont);\n this.poco.drawText(timeStr, sbFont, this.getColor(sbColor), Math.floor((sbW - tw) / 2), 1);\n\n // Separator line\n const sep = str(p, 'separator') ?? 'none';\n if (sep === 'line') {\n this.poco.fillRectangle(this.getColor(sbColor), 0, sbH - 1, sbW, 1);\n } else if (sep === 'dotted') {\n for (let dx = 0; dx < sbW; dx += 3) {\n this.poco.fillRectangle(this.getColor(sbColor), dx, sbH - 1, 1, 1);\n }\n }\n break;\n }\n\n case 'pbl-actionbar': {\n // Render an action bar on the right edge: background column + icon placeholders\n const abBg = str(p, 'backgroundColor') ?? 'darkGray';\n const abW = 30;\n const abX = this.poco.width - abW;\n const abH = this.poco.height;\n\n this.poco.fillRectangle(this.getColor(abBg), abX, 0, abW, abH);\n\n // Draw dot placeholders for up/select/down icons\n const dotColor = this.getColor('white');\n const dotR = 3;\n const centerX = abX + Math.floor(abW / 2);\n // Up icon area (top third)\n this.poco.fillRectangle(dotColor, centerX - dotR, Math.floor(abH / 6) - dotR, dotR * 2, dotR * 2);\n // Select icon area (middle)\n this.poco.fillRectangle(dotColor, centerX - dotR, Math.floor(abH / 2) - dotR, dotR * 2, dotR * 2);\n // Down icon area (bottom third)\n this.poco.fillRectangle(dotColor, centerX - dotR, Math.floor(abH * 5 / 6) - dotR, dotR * 2, dotR * 2);\n break;\n }\n\n case 'pbl-root': {\n this.renderChildren(node, ox, oy);\n break;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Circle rendering — midpoint circle algorithm\n // -------------------------------------------------------------------------\n\n /** Fill a circle by drawing horizontal spans for each row. */\n private fillCircle(color: PocoColor, cx: number, cy: number, r: number): void {\n const { poco } = this;\n let x0 = r;\n let y0 = 0;\n let err = 1 - r;\n\n // Track the last drawn y to avoid duplicate spans\n let lastY1 = -1;\n let lastY2 = -1;\n\n while (x0 >= y0) {\n // Draw horizontal spans for each octant pair\n if (cy + y0 !== lastY1) {\n poco.fillRectangle(color, cx - x0, cy + y0, x0 * 2 + 1, 1);\n lastY1 = cy + y0;\n }\n if (cy - y0 !== lastY2 && y0 !== 0) {\n poco.fillRectangle(color, cx - x0, cy - y0, x0 * 2 + 1, 1);\n lastY2 = cy - y0;\n }\n if (cy + x0 !== lastY1) {\n poco.fillRectangle(color, cx - y0, cy + x0, y0 * 2 + 1, 1);\n lastY1 = cy + x0;\n }\n if (cy - x0 !== lastY2) {\n poco.fillRectangle(color, cx - y0, cy - x0, y0 * 2 + 1, 1);\n lastY2 = cy - x0;\n }\n\n y0++;\n if (err < 0) {\n err += 2 * y0 + 1;\n } else {\n x0--;\n err += 2 * (y0 - x0) + 1;\n }\n }\n }\n\n /** Stroke a circle outline by drawing small rects at each perimeter point. */\n private strokeCircle(color: PocoColor, cx: number, cy: number, r: number, sw: number): void {\n const { poco } = this;\n let x0 = r;\n let y0 = 0;\n let err = 1 - r;\n\n while (x0 >= y0) {\n // 8 octant points\n poco.fillRectangle(color, cx + x0, cy + y0, sw, sw);\n poco.fillRectangle(color, cx - x0, cy + y0, sw, sw);\n poco.fillRectangle(color, cx + x0, cy - y0, sw, sw);\n poco.fillRectangle(color, cx - x0, cy - y0, sw, sw);\n poco.fillRectangle(color, cx + y0, cy + x0, sw, sw);\n poco.fillRectangle(color, cx - y0, cy + x0, sw, sw);\n poco.fillRectangle(color, cx + y0, cy - x0, sw, sw);\n poco.fillRectangle(color, cx - y0, cy - x0, sw, sw);\n\n y0++;\n if (err < 0) {\n err += 2 * y0 + 1;\n } else {\n x0--;\n err += 2 * (y0 - x0) + 1;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Diagonal line rendering — Bresenham's line algorithm\n // -------------------------------------------------------------------------\n\n private drawDiagonalLine(\n color: PocoColor, x1: number, y1: number, x2: number, y2: number, sw: number,\n ): void {\n const { poco } = this;\n let dx = Math.abs(x2 - x1);\n let dy = Math.abs(y2 - y1);\n const sx = x1 < x2 ? 1 : -1;\n const sy = y1 < y2 ? 1 : -1;\n let err = dx - dy;\n let cx = x1;\n let cy = y1;\n\n for (;;) {\n poco.fillRectangle(color, cx, cy, sw, sw);\n if (cx === x2 && cy === y2) break;\n const e2 = 2 * err;\n if (e2 > -dy) {\n err -= dy;\n cx += sx;\n }\n if (e2 < dx) {\n err += dx;\n cy += sy;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Rounded rectangle rendering\n // -------------------------------------------------------------------------\n\n /** Fill a rounded rectangle by combining rects and quarter-circle corners. */\n private fillRoundRect(\n color: PocoColor, x: number, y: number, w: number, h: number, r: number,\n ): void {\n const { poco } = this;\n const cr = Math.min(r, Math.floor(w / 2), Math.floor(h / 2));\n\n // Center body\n poco.fillRectangle(color, x, y + cr, w, h - cr * 2);\n // Top strip (between corners)\n poco.fillRectangle(color, x + cr, y, w - cr * 2, cr);\n // Bottom strip (between corners)\n poco.fillRectangle(color, x + cr, y + h - cr, w - cr * 2, cr);\n\n // Four quarter-circle corners via midpoint algorithm\n this.fillQuarterCircles(color, x + cr, y + cr, x + w - cr - 1, y + h - cr - 1, cr);\n }\n\n /** Stroke a rounded rectangle outline. */\n private strokeRoundRect(\n color: PocoColor, x: number, y: number, w: number, h: number, r: number, sw: number,\n ): void {\n const { poco } = this;\n const cr = Math.min(r, Math.floor(w / 2), Math.floor(h / 2));\n\n // Straight edges\n poco.fillRectangle(color, x + cr, y, w - cr * 2, sw); // top\n poco.fillRectangle(color, x + cr, y + h - sw, w - cr * 2, sw); // bottom\n poco.fillRectangle(color, x, y + cr, sw, h - cr * 2); // left\n poco.fillRectangle(color, x + w - sw, y + cr, sw, h - cr * 2); // right\n\n // Corner arcs\n this.strokeQuarterCircles(color, x + cr, y + cr, x + w - cr - 1, y + h - cr - 1, cr, sw);\n }\n\n /** Fill four quarter-circles at the corners of a rounded rect. */\n private fillQuarterCircles(\n color: PocoColor, cx1: number, cy1: number, cx2: number, cy2: number, r: number,\n ): void {\n const { poco } = this;\n let x0 = r;\n let y0 = 0;\n let err = 1 - r;\n\n while (x0 >= y0) {\n // Top-left corner\n poco.fillRectangle(color, cx1 - x0, cy1 - y0, x0, 1);\n poco.fillRectangle(color, cx1 - y0, cy1 - x0, y0, 1);\n // Top-right corner\n poco.fillRectangle(color, cx2 + 1, cy1 - y0, x0, 1);\n poco.fillRectangle(color, cx2 + 1, cy1 - x0, y0, 1);\n // Bottom-left corner\n poco.fillRectangle(color, cx1 - x0, cy2 + y0, x0, 1);\n poco.fillRectangle(color, cx1 - y0, cy2 + x0, y0, 1);\n // Bottom-right corner\n poco.fillRectangle(color, cx2 + 1, cy2 + y0, x0, 1);\n poco.fillRectangle(color, cx2 + 1, cy2 + x0, y0, 1);\n\n y0++;\n if (err < 0) {\n err += 2 * y0 + 1;\n } else {\n x0--;\n err += 2 * (y0 - x0) + 1;\n }\n }\n }\n\n /** Stroke four quarter-circle arcs at the corners of a rounded rect. */\n private strokeQuarterCircles(\n color: PocoColor, cx1: number, cy1: number, cx2: number, cy2: number, r: number, sw: number,\n ): void {\n const { poco } = this;\n let x0 = r;\n let y0 = 0;\n let err = 1 - r;\n\n while (x0 >= y0) {\n // Top-left\n poco.fillRectangle(color, cx1 - x0, cy1 - y0, sw, sw);\n poco.fillRectangle(color, cx1 - y0, cy1 - x0, sw, sw);\n // Top-right\n poco.fillRectangle(color, cx2 + x0, cy1 - y0, sw, sw);\n poco.fillRectangle(color, cx2 + y0, cy1 - x0, sw, sw);\n // Bottom-left\n poco.fillRectangle(color, cx1 - x0, cy2 + y0, sw, sw);\n poco.fillRectangle(color, cx1 - y0, cy2 + x0, sw, sw);\n // Bottom-right\n poco.fillRectangle(color, cx2 + x0, cy2 + y0, sw, sw);\n poco.fillRectangle(color, cx2 + y0, cy2 + x0, sw, sw);\n\n y0++;\n if (err < 0) {\n err += 2 * y0 + 1;\n } else {\n x0--;\n err += 2 * (y0 - x0) + 1;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Text wrapping\n // -------------------------------------------------------------------------\n\n /** Break text into lines that fit within maxWidth. */\n private wrapText(text: string, font: PocoFont, maxWidth: number): string[] {\n // If the full text fits, skip wrapping\n if (this.poco.getTextWidth(text, font) <= maxWidth) {\n return [text];\n }\n\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n if (this.poco.getTextWidth(testLine, font) <= maxWidth) {\n currentLine = testLine;\n } else {\n if (currentLine) lines.push(currentLine);\n // If a single word exceeds maxWidth, it goes on its own line (truncated visually)\n currentLine = word;\n }\n }\n if (currentLine) lines.push(currentLine);\n\n return lines;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Compatibility shims — still useful for mock-mode tests that want to\n// resolve a color name without constructing a Poco. These return *names*\n// rather than native handles.\n// ---------------------------------------------------------------------------\n\nexport function resolveColorName(color: string | undefined): string {\n if (!color) return 'black';\n return color in COLOR_PALETTE ? color : 'black';\n}\n\nexport function resolveFontName(font: string | undefined): string {\n if (!font) return DEFAULT_FONT_KEY;\n return font in FONT_PALETTE ? font : DEFAULT_FONT_KEY;\n}\n","/**\n * pebble-dom-shim.ts — A minimal DOM-like adapter over `pebble-dom` so\n * Preact's `render(vnode, parentDom)` can drive it.\n *\n * Preact's diff loop mutates a tree of DOM-shaped nodes by calling:\n * - document.createElement(tag)\n * - document.createTextNode(text)\n * - parent.appendChild(child), .insertBefore(child, ref), .removeChild(child)\n * - element.setAttribute(name, value), .removeAttribute(name)\n * - element.addEventListener(name, handler), .removeEventListener(...)\n * - element.nodeType, .nodeName, .parentNode, .childNodes, .firstChild,\n * .nextSibling\n *\n * This file implements the minimum surface Preact actually touches when\n * rendering into a headless tree. Each \"element\" carries a reference to the\n * underlying pebble-dom node so the renderer can walk both views\n * interchangeably.\n *\n * The shim is deliberately NOT a full undom — it only does what Preact 10\n * needs. If we trip on a missing method, add it here rather than including\n * undom (which would push the bundle back up).\n */\n\nimport type { AnyNode, DOMElement, ElementType, TextNode } from './pebble-dom.js';\nimport {\n ELEMENT_TYPES,\n appendChildNode,\n createNode,\n createTextNode,\n insertBeforeNode,\n removeChildNode,\n setAttribute,\n setTextNodeValue,\n} from './pebble-dom.js';\n\n// ---------------------------------------------------------------------------\n// DOM node interfaces the shim exposes to Preact\n// ---------------------------------------------------------------------------\n\ninterface ShimNodeBase {\n readonly nodeType: number;\n nodeName: string;\n parentNode: ShimElement | null;\n childNodes: ShimNode[];\n firstChild: ShimNode | null;\n nextSibling: ShimNode | null;\n /** The backing pebble-dom node. */\n readonly _pbl: AnyNode;\n}\n\nexport interface ShimElement extends ShimNodeBase {\n readonly nodeType: 1;\n readonly localName: string;\n readonly tagName: string;\n readonly _pbl: DOMElement;\n attributes: Record<string, unknown>;\n\n appendChild<T extends ShimNode>(child: T): T;\n insertBefore<T extends ShimNode>(child: T, ref: ShimNode | null): T;\n removeChild<T extends ShimNode>(child: T): T;\n remove(): void;\n\n setAttribute(name: string, value: unknown): void;\n removeAttribute(name: string): void;\n getAttribute(name: string): unknown;\n\n addEventListener(name: string, handler: (...args: unknown[]) => unknown): void;\n removeEventListener(name: string, handler: (...args: unknown[]) => unknown): void;\n}\n\nexport interface ShimText extends ShimNodeBase {\n readonly nodeType: 3;\n readonly _pbl: TextNode;\n data: string;\n nodeValue: string;\n textContent: string;\n}\n\nexport type ShimNode = ShimElement | ShimText;\n\n// ---------------------------------------------------------------------------\n// Shim factories\n// ---------------------------------------------------------------------------\n\nfunction linkSiblings(parent: ShimElement): void {\n const kids = parent.childNodes;\n parent.firstChild = kids[0] ?? null;\n for (let i = 0; i < kids.length; i++) {\n const node = kids[i]!;\n node.parentNode = parent;\n node.nextSibling = kids[i + 1] ?? null;\n }\n}\n\nexport function createShimElement(tag: string): ShimElement {\n // Accept both 'pbl-rect' and friendly aliases from components. Unknown\n // tags are rejected loudly so typos surface at render time.\n const pblType = tag as ElementType;\n if (!ELEMENT_TYPES.has(pblType)) {\n throw new Error(`react-pebble: unknown element tag \"${tag}\"`);\n }\n\n const pbl = createNode(pblType);\n\n const el: ShimElement = {\n nodeType: 1,\n nodeName: tag.toUpperCase(),\n localName: tag,\n tagName: tag.toUpperCase(),\n _pbl: pbl,\n attributes: {},\n parentNode: null,\n childNodes: [],\n firstChild: null,\n nextSibling: null,\n\n appendChild(child) {\n // Detach from any prior parent in the shim view\n if (child.parentNode) {\n child.parentNode.removeChild(child);\n }\n this.childNodes.push(child);\n appendChildNode(pbl, child._pbl);\n linkSiblings(this);\n return child;\n },\n\n insertBefore(child, ref) {\n if (child.parentNode) {\n child.parentNode.removeChild(child);\n }\n if (ref === null) {\n return this.appendChild(child);\n }\n const idx = this.childNodes.indexOf(ref);\n if (idx < 0) {\n return this.appendChild(child);\n }\n this.childNodes.splice(idx, 0, child);\n insertBeforeNode(pbl, child._pbl, ref._pbl);\n linkSiblings(this);\n return child;\n },\n\n removeChild(child) {\n const idx = this.childNodes.indexOf(child);\n if (idx >= 0) {\n this.childNodes.splice(idx, 1);\n }\n removeChildNode(pbl, child._pbl);\n child.parentNode = null;\n child.nextSibling = null;\n linkSiblings(this);\n return child;\n },\n\n remove() {\n if (this.parentNode) {\n this.parentNode.removeChild(this);\n }\n },\n\n setAttribute(name, value) {\n this.attributes[name] = value;\n setAttribute(pbl, name, value);\n },\n\n removeAttribute(name) {\n delete this.attributes[name];\n setAttribute(pbl, name, undefined);\n },\n\n getAttribute(name) {\n return this.attributes[name];\n },\n\n addEventListener(name, handler) {\n // Event handlers are stored in props (on* style) so the button wiring\n // in pebble-render.ts can find them the same way React props do.\n const key = `on${name[0]?.toUpperCase()}${name.slice(1)}`;\n this.attributes[key] = handler;\n setAttribute(pbl, key, handler);\n },\n\n removeEventListener(name, _handler) {\n const key = `on${name[0]?.toUpperCase()}${name.slice(1)}`;\n delete this.attributes[key];\n setAttribute(pbl, key, undefined);\n },\n };\n\n return el;\n}\n\nexport function createShimText(data: string): ShimText {\n const pbl = createTextNode(data);\n\n const node: ShimText = {\n nodeType: 3,\n nodeName: '#text',\n _pbl: pbl,\n data,\n nodeValue: data,\n textContent: data,\n parentNode: null,\n childNodes: [],\n firstChild: null,\n nextSibling: null,\n };\n\n // Keep pebble-dom in sync whenever data/nodeValue/textContent is assigned.\n // Preact mutates `.data` directly on text updates.\n Object.defineProperty(node, 'data', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n Object.defineProperty(node, 'nodeValue', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n Object.defineProperty(node, 'textContent', {\n get() {\n return pbl.value;\n },\n set(next: string) {\n setTextNodeValue(pbl, next);\n },\n });\n\n return node;\n}\n\n// ---------------------------------------------------------------------------\n// Shim \"document\" — what Preact reaches via `parentDom.ownerDocument` etc.\n// ---------------------------------------------------------------------------\n\nexport interface ShimDocument {\n createElement(tag: string): ShimElement;\n createElementNS(ns: string | null, tag: string): ShimElement;\n createTextNode(data: string): ShimText;\n}\n\nexport const shimDocument: ShimDocument = {\n createElement: createShimElement,\n createElementNS: (_ns, tag) => createShimElement(tag),\n createTextNode: createShimText,\n};\n\n// ---------------------------------------------------------------------------\n// Root container — the \"parent DOM\" handed to preact.render().\n// ---------------------------------------------------------------------------\n\nexport function createShimRoot(): ShimElement {\n const root = createShimElement('pbl-root');\n // Preact reads `ownerDocument` off the parent.\n (root as unknown as { ownerDocument: ShimDocument }).ownerDocument = shimDocument;\n return root;\n}\n","/**\n * pebble-reconciler.ts — Preact-backed reconciler for react-pebble.\n *\n * Replaces the old react-reconciler host config. We don't need a custom\n * reconciler at all with Preact — Preact's `render(vnode, parentDom)` does\n * the diffing, and we provide a DOM-shaped container via `pebble-dom-shim`\n * so Preact writes into our pebble-dom tree instead of a real DOM.\n *\n * The public surface (for pebble-render.ts) is:\n * - createReconcilerContainer() → a pair of root shim + pebble-dom root\n * - updateContainer(vnode, container) → runs preact.render()\n * - unmountContainer(container) → runs preact.render(null, ...)\n */\n\nimport { render as preactRender } from 'preact';\nimport type { ComponentChild } from 'preact';\nimport type { DOMElement } from './pebble-dom.js';\nimport { createShimRoot, shimDocument } from './pebble-dom-shim.js';\nimport type { ShimElement } from './pebble-dom-shim.js';\n\n// Preact's render() references `document` internally. In non-browser\n// environments (Node mock mode, Alloy XS) we shim it with our pebble-dom\n// adapter so Preact doesn't crash.\nif (typeof document === 'undefined') {\n (globalThis as unknown as { document: unknown }).document = shimDocument;\n}\n\nexport interface PebbleContainer {\n shimRoot: ShimElement;\n pblRoot: DOMElement;\n}\n\nexport function createContainer(): PebbleContainer {\n const shimRoot = createShimRoot();\n return {\n shimRoot,\n pblRoot: shimRoot._pbl,\n };\n}\n\nexport function updateContainer(vnode: ComponentChild, container: PebbleContainer): void {\n preactRender(vnode, container.shimRoot as unknown as Element);\n}\n\nexport function unmountContainer(container: PebbleContainer): void {\n preactRender(null, container.shimRoot as unknown as Element);\n}\n\n// For backwards-compat with the old default export pattern.\nexport default {\n createContainer,\n updateContainer,\n unmountContainer,\n};\n","/**\n * pebble-render.ts — Entry point for react-pebble on Pebble Alloy.\n *\n * Bridges Preact's output (via a DOM-shim over pebble-dom) to Moddable's\n * Poco renderer, which draws into the watch framebuffer. Also hosts the\n * Node mock path used for unit tests and local development.\n *\n * Platform detection is via `typeof screen`:\n * - screen exists → Alloy/XS runtime → real Poco draws\n * - screen undefined → Node → mock Poco records calls to an in-memory log\n */\n\nimport { options } from 'preact';\nimport type { ComponentChild } from 'preact';\nimport type Poco from 'commodetto/Poco';\nimport type { PocoBitmap, PocoColor, PocoFont } from 'commodetto/Poco';\nimport type { DOMElement } from './pebble-dom.js';\nimport { PocoRenderer } from './pebble-output.js';\nimport type { PebbleButton, PebbleButtonHandler } from './hooks/index.js';\nimport { ButtonRegistry } from './hooks/index.js';\nimport type { PebbleContainer } from './pebble-reconciler.js';\nimport {\n createContainer,\n updateContainer,\n unmountContainer,\n} from './pebble-reconciler.js';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface PebblePlatformInfo {\n isReal: boolean;\n platform: 'alloy' | 'mock';\n screenWidth: number;\n screenHeight: number;\n}\n\nexport interface DrawCall {\n op: string;\n [key: string]: unknown;\n}\n\nexport interface RenderOptions {\n backgroundColor?: string;\n}\n\nexport interface PebbleApp {\n update(newElement: ComponentChild): void;\n unmount(): void;\n readonly platform: PebblePlatformInfo;\n readonly drawLog: readonly DrawCall[];\n readonly _root: DOMElement;\n}\n\n// ---------------------------------------------------------------------------\n// Mock Poco — records every draw call into a shared log so tests can assert.\n// ---------------------------------------------------------------------------\n\nclass MockPoco {\n readonly width: number;\n readonly height: number;\n readonly Font: new (name: string, size: number) => PocoFont;\n\n constructor(width: number, height: number, private readonly log: DrawCall[]) {\n this.width = width;\n this.height = height;\n const FontImpl = class {\n readonly name: string;\n readonly size: number;\n readonly height: number;\n constructor(name: string, size: number) {\n this.name = name;\n this.size = size;\n this.height = size;\n }\n };\n this.Font = FontImpl as unknown as new (name: string, size: number) => PocoFont;\n }\n\n begin(x?: number, y?: number, width?: number, height?: number): void {\n this.log.push({ op: 'begin', x, y, width, height });\n }\n end(): void {\n this.log.push({ op: 'end' });\n }\n continue(x: number, y: number, width: number, height: number): void {\n this.log.push({ op: 'continue', x, y, width, height });\n }\n clip(x?: number, y?: number, width?: number, height?: number): void {\n this.log.push({ op: 'clip', x, y, width, height });\n }\n origin(x?: number, y?: number): void {\n this.log.push({ op: 'origin', x, y });\n }\n\n makeColor(r: number, g: number, b: number): PocoColor {\n return ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);\n }\n\n fillRectangle(color: PocoColor, x: number, y: number, width: number, height: number): void {\n this.log.push({ op: 'fillRectangle', color, x, y, width, height });\n }\n blendRectangle(\n color: PocoColor,\n blend: number,\n x: number,\n y: number,\n width: number,\n height: number,\n ): void {\n this.log.push({ op: 'blendRectangle', color, blend, x, y, width, height });\n }\n drawPixel(color: PocoColor, x: number, y: number): void {\n this.log.push({ op: 'drawPixel', color, x, y });\n }\n drawBitmap(_bits: PocoBitmap, x: number, y: number): void {\n this.log.push({ op: 'drawBitmap', x, y });\n }\n drawMonochrome(\n _monochrome: PocoBitmap,\n fore: PocoColor,\n back: PocoColor | undefined,\n x: number,\n y: number,\n ): void {\n this.log.push({ op: 'drawMonochrome', fore, back, x, y });\n }\n\n drawText(text: string, font: PocoFont, color: PocoColor, x: number, y: number): void {\n this.log.push({ op: 'drawText', text, font, color, x, y });\n }\n getTextWidth(text: string, font: PocoFont): number {\n const size = (font as unknown as { size?: number }).size ?? 14;\n return Math.round(text.length * size * 0.6);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Poco construction — real on Alloy, mock in Node\n// ---------------------------------------------------------------------------\n\nfunction createPoco(\n log: DrawCall[],\n pocoCtor: typeof Poco | undefined,\n): { poco: Poco; info: PebblePlatformInfo } {\n if (typeof screen !== 'undefined' && screen && pocoCtor) {\n const poco = new pocoCtor(screen);\n return {\n poco,\n info: {\n isReal: true,\n platform: 'alloy',\n screenWidth: screen.width,\n screenHeight: screen.height,\n },\n };\n }\n\n const width = 200;\n const height = 228;\n const mock = new MockPoco(width, height, log);\n return {\n poco: mock as unknown as Poco,\n info: {\n isReal: false,\n platform: 'mock',\n screenWidth: width,\n screenHeight: height,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Button wiring — see moddable.d.ts for the known/unknown event names.\n// ---------------------------------------------------------------------------\n\nfunction wireWatchButtons(): () => void {\n if (typeof watch === 'undefined' || !watch) return () => undefined;\n\n const normalize = (raw: unknown): PebbleButton | undefined => {\n if (typeof raw !== 'string') return undefined;\n const low = raw.toLowerCase();\n if (low === 'up' || low === 'down' || low === 'select' || low === 'back') {\n return low;\n }\n return undefined;\n };\n\n const onShort = (payload?: { button?: unknown }) => {\n const b = normalize(payload?.button);\n if (b) ButtonRegistry.emit(b);\n };\n const onLong = (payload?: { button?: unknown }) => {\n const b = normalize(payload?.button);\n if (b) ButtonRegistry.emit(`long_${b}`);\n };\n\n watch.addEventListener('button', onShort);\n watch.addEventListener('buttonClick', onShort);\n watch.addEventListener('longClick', onLong);\n\n return () => {\n if (typeof watch === 'undefined' || !watch) return;\n watch.removeEventListener('button', onShort);\n watch.removeEventListener('buttonClick', onShort);\n watch.removeEventListener('longClick', onLong);\n };\n}\n\n// ---------------------------------------------------------------------------\n// Redraw scheduling\n//\n// Preact renders are synchronous; when any component calls setState, Preact\n// re-runs the diff and mutates the shim tree in place. We hook into that\n// by scheduling a Poco redraw on the next tick.\n// ---------------------------------------------------------------------------\n\nfunction scheduleMicrotask(fn: () => void): void {\n // Prefer Promise.resolve().then for microtask batching; fall back to\n // setTimeout(0) if Promise isn't wired up in some host.\n if (typeof Promise !== 'undefined') {\n Promise.resolve().then(fn);\n } else {\n setTimeout(fn, 0);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public render API\n// ---------------------------------------------------------------------------\n\nexport interface RenderOptionsExt extends RenderOptions {\n /**\n * Pre-imported Poco constructor. Alloy entry files must import Poco at\n * the top and pass it here so the Moddable bundler resolves it correctly.\n */\n poco?: typeof Poco;\n}\n\nexport function render(element: ComponentChild, options: RenderOptionsExt = {}): PebbleApp {\n const drawLog: DrawCall[] = [];\n const container: PebbleContainer = createContainer();\n const { poco, info } = createPoco(drawLog, options.poco);\n const renderer = new PocoRenderer(poco);\n\n let pending = false;\n const redraw = () => {\n pending = false;\n drawLog.length = 0;\n renderer.render(container.pblRoot, { backgroundColor: options.backgroundColor });\n };\n\n const schedule = () => {\n if (pending) return;\n pending = true;\n scheduleMicrotask(redraw);\n };\n\n // Monkey-patch the shim root to redraw on any mutation.\n // Preact calls appendChild/insertBefore/removeChild/setAttribute on the\n // tree during diff; we only need to schedule a redraw when the diff\n // settles, which is right after the top-level render() call returns.\n // For that we just trigger a redraw synchronously after updateContainer.\n\n // Hook Preact's commit phase so hook-driven state updates trigger a redraw\n // without polling. options._commit is an undocumented-but-stable hook that\n // fires once per root-level diff settle.\n type PreactOptionsWithCommit = typeof options & {\n _commit?: (root: unknown, queue: unknown[]) => void;\n __c?: (root: unknown, queue: unknown[]) => void;\n };\n const opts = options as PreactOptionsWithCommit;\n const prevCommit = opts._commit ?? opts.__c;\n const commitHook = (root: unknown, queue: unknown[]) => {\n if (prevCommit) prevCommit(root, queue);\n schedule();\n };\n opts._commit = commitHook;\n opts.__c = commitHook;\n\n updateContainer(element, container);\n // Always paint once on mount.\n redraw();\n\n // Subscribe to watch events on-device.\n const unwireButtons = wireWatchButtons();\n\n return {\n update(newElement) {\n updateContainer(newElement, container);\n schedule();\n },\n unmount() {\n unmountContainer(container);\n // Restore prior commit hook (in case another app was rendered).\n opts._commit = prevCommit;\n opts.__c = prevCommit;\n unwireButtons();\n },\n get platform() {\n return info;\n },\n get drawLog() {\n return drawLog as readonly DrawCall[];\n },\n get _root() {\n return container.pblRoot;\n },\n };\n}\n"],"mappings":"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"}
|