// browser-side evaluator snippets for CLI inspect commands. // // the rnx CLI ships some commands that need to observe the live // rnx tree or its rendered pixels. we send these strings over the rnx host's // `evaluate` handler. // // cropping happens once, in the capture module (`bridges.screenshot`), // via its `crop` option. these evals intentionally defer to that bridge // instead of reimplementing the dpr-aware crop math. export interface SampleRect { x: number y: number w: number h: number } // resolve a --id/--text matcher into a SampleRect using __sootsimTest. // returns null on miss so the caller can report a clear not-found error. export function buildResolveRectEval(matcher: { id?: string; text?: string }): string { return `(async () => { const __t = window.__sootsimTest if (!__t) throw new Error('__sootsimTest not available') const __id = ${JSON.stringify(matcher.id || '')} const __text = ${JSON.stringify(matcher.text || '')} let __node = null if (__id) { __node = (__t.findByTestId && await __t.findByTestId(__id)) || (__t.findById && await __t.findById(__id)) || null } else if (__text) { __node = __t.findByText ? await __t.findByText(__text) : null } if (!__node) return null const __pos = __node.absolutePosition || { x: __node.layout?.x || 0, y: __node.layout?.y || 0 } const __layout = __node.layout || {} return { x: __pos.x, y: __pos.y, w: __layout.width || 1, h: __layout.height || 1, } })()` } // sample-color averages rgba pixels across a logical-coord rect. the eval // asks the capture bridge for an already-cropped PNG and then averages the // decoded ImageData in one pass. export function buildSampleColorEval(rect: SampleRect): string { return `(async () => { const __rect = ${JSON.stringify(rect)} const __screenshot = window.__sootsimScreenshot if (typeof __screenshot !== 'function') { throw new Error('screenshot bridge not installed') } const __dataUrl = await __screenshot({ crop: __rect }) const __img = await new Promise((res, rej) => { const img = new Image() img.onload = () => res(img) img.onerror = () => rej(new Error('failed to decode cropped screenshot')) img.src = __dataUrl }) const __w = __img.naturalWidth const __h = __img.naturalHeight const __canvas = document.createElement('canvas') __canvas.width = __w __canvas.height = __h const __ctx = __canvas.getContext('2d') if (!__ctx) throw new Error('could not acquire 2d context') __ctx.drawImage(__img, 0, 0) const __data = __ctx.getImageData(0, 0, __w, __h).data const __n = __data.length / 4 let __r = 0, __g = 0, __b = 0, __a = 0 for (let __i = 0; __i < __data.length; __i += 4) { __r += __data[__i] __g += __data[__i + 1] __b += __data[__i + 2] __a += __data[__i + 3] } const __round = (v) => Math.round(v / __n) const __rr = __round(__r), __gg = __round(__g), __bb = __round(__b), __aa = __round(__a) const __hex = '#' + [__rr, __gg, __bb] .map((v) => v.toString(16).padStart(2, '0')) .join('') const __dpr = window.devicePixelRatio || 1 return { r: __rr, g: __gg, b: __bb, a: __aa, hex: __hex, samples: __n, rect: { x: __rect.x, y: __rect.y, w: __rect.w, h: __rect.h }, deviceWidth: __w / __dpr, deviceHeight: __h / __dpr, } })()` }