@mmtitanl/tablets-core 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/math/scale.ts","../src/hooks/use-container-size.ts","../src/hooks/use-adaptive-scale.ts","../src/hooks/use-device-contract.ts","../src/hooks/use-orientation.ts","../src/hooks/use-volume-control.ts","../src/hooks/use-screen-power.ts","../src/hooks/use-device-frame.ts","../src/messages.ts","../src/hooks/use-fold-state.ts","../src/registration.tsx","../src/components/DeviceFrame.tsx","../src/components/DeviceErrorBoundary.tsx","../src/components/SafeAreaOverlay.tsx","../src/components/ScaleBar.tsx","../src/components/DynamicStatusBar.tsx","../src/components/DeviceCompare.tsx","../src/components/SafeAreaView.tsx","../src/components/VolumeHUD.tsx","../src/components/HardwareButtons.tsx","../src/components/StatusBarIndicators.tsx","../src/storage/custom-svg-store.ts"],"sourcesContent":["// Math\nexport {\n SCALE_STEPS,\n computeAdaptiveScale,\n computeFullScale,\n computeHostSize,\n ptsToPercent,\n ptsToPx,\n pxToPts,\n scaleValue,\n snapToStep,\n} from \"./math/scale.js\";\nexport type { AdaptiveScaleResult } from \"./math/scale.js\";\n\n// Hooks\nexport { useContainerSize } from \"./hooks/use-container-size.js\";\nexport { useAdaptiveScale } from \"./hooks/use-adaptive-scale.js\";\nexport type { UseAdaptiveScaleOptions } from \"./hooks/use-adaptive-scale.js\";\nexport { useDeviceContract } from \"./hooks/use-device-contract.js\";\nexport type { UseDeviceContractResult } from \"./hooks/use-device-contract.js\";\nexport { useOrientation } from \"./hooks/use-orientation.js\";\nexport type { UseOrientationResult } from \"./hooks/use-orientation.js\";\nexport { useVolumeControl } from \"./hooks/use-volume-control.js\";\nexport type { VolumeState } from \"./hooks/use-volume-control.js\";\nexport { useScreenPower } from \"./hooks/use-screen-power.js\";\nexport type { ScreenPowerState } from \"./hooks/use-screen-power.js\";\nexport { useDeviceFrame } from \"./hooks/use-device-frame.js\";\nexport type { DeviceFrameInfo, DeviceFrameInsets } from \"./hooks/use-device-frame.js\";\nexport { useFoldState } from \"./hooks/use-fold-state.js\";\nexport type { FoldState, UseFoldStateResult } from \"./hooks/use-fold-state.js\";\n\n// Messages\nexport { BIELA_PREFIX, isBielaMessage } from \"./messages.js\";\nexport type { BielaColorSchemeMessage, BielaDeviceInfoMessage, BielaRequestMessage } from \"./messages.js\";\n\n// Registration\nexport { registerCustomDeviceSVG, registerDeviceSVG } from \"./registration.js\";\nexport type { SVGCropArea } from \"./registration.js\";\n\n// Components\nexport { DeviceFrame } from \"./components/DeviceFrame.js\";\nexport type { DeviceFrameProps } from \"./components/DeviceFrame.js\";\nexport { DeviceCompare } from \"./components/DeviceCompare.js\";\nexport type { DeviceCompareProps } from \"./components/DeviceCompare.js\";\nexport { DeviceErrorBoundary } from \"./components/DeviceErrorBoundary.js\";\nexport { SafeAreaView } from \"./components/SafeAreaView.js\";\nexport { SafeAreaOverlay } from \"./components/SafeAreaOverlay.js\";\nexport { ScaleBar } from \"./components/ScaleBar.js\";\nexport { VolumeHUD } from \"./components/VolumeHUD.js\";\nexport { HardwareButtons } from \"./components/HardwareButtons.js\";\nexport type { ButtonName } from \"./components/HardwareButtons.js\";\nexport { DynamicStatusBar } from \"./components/DynamicStatusBar.js\";\nexport { StatusBarIndicators } from \"./components/StatusBarIndicators.js\";\n\n// Storage\nexport { CustomSVGStore, getCustomSVGStore } from \"./storage/custom-svg-store.js\";\nexport type { SVGOverrideEntry } from \"./storage/custom-svg-store.js\";\n\n// Re-export important types from @mmtitanl/tablets for convenience\nexport type { SVGScreenRect } from \"@mmtitanl/tablets\";\n","export function ptsToPx(pts: number, dpr: number): number {\n return pts * dpr;\n}\nexport function pxToPts(px: number, dpr: number): number {\n return px / dpr;\n}\nexport function ptsToPercent(pts: number, total: number): number {\n return (pts / total) * 100;\n}\nexport function scaleValue(value: number, scaleFactor: number): number {\n return value * scaleFactor;\n}\n\nexport const SCALE_STEPS = [0.25, 0.33, 0.5, 0.75, 1] as const;\n\nexport function computeAdaptiveScale(\n deviceWidth: number,\n deviceHeight: number,\n containerWidth: number,\n containerHeight: number,\n padding = 24,\n maxScale = 1,\n minScale = 0.1\n): number {\n const availW = Math.max(0, containerWidth - padding * 2);\n const availH = Math.max(0, containerHeight - padding * 2);\n if (availW <= 0 || availH <= 0) return minScale;\n const sx = availW / deviceWidth;\n const sy = availH / deviceHeight;\n const raw = Math.min(sx, sy, maxScale);\n return Math.max(raw, minScale);\n}\n\nexport function snapToStep(raw: number): number {\n const allowed = SCALE_STEPS.filter((s) => s <= raw);\n if (allowed.length === 0) return raw;\n return Math.max(...allowed);\n}\n\nexport function computeHostSize(deviceWidth: number, deviceHeight: number, scale: number) {\n return { width: deviceWidth * scale, height: deviceHeight * scale };\n}\n\nexport interface AdaptiveScaleResult {\n scale: number;\n scaledWidth: number;\n scaledHeight: number;\n deviceWidth: number;\n deviceHeight: number;\n isAtMaxScale: boolean;\n isConstrained: boolean;\n scalePercent: string;\n}\n\nexport function computeFullScale(\n deviceWidth: number,\n deviceHeight: number,\n containerWidth: number,\n containerHeight: number,\n options: { padding?: number; maxScale?: number; minScale?: number; snapToSteps?: boolean } = {}\n): AdaptiveScaleResult {\n const { padding = 24, maxScale = 1, minScale = 0.1, snapToSteps = false } = options;\n const raw = computeAdaptiveScale(deviceWidth, deviceHeight, containerWidth, containerHeight, padding, maxScale, minScale);\n const scale = snapToSteps ? snapToStep(raw) : raw;\n const { width: scaledWidth, height: scaledHeight } = computeHostSize(deviceWidth, deviceHeight, scale);\n return {\n scale,\n scaledWidth,\n scaledHeight,\n deviceWidth,\n deviceHeight,\n isAtMaxScale: scale >= maxScale - 0.0001,\n isConstrained: scale < maxScale - 0.0001,\n scalePercent: `${Math.round(scale * 100)}%`,\n };\n}\n","import { useEffect, useState, type RefObject } from \"react\";\n\nexport interface ContainerSize {\n width: number;\n height: number;\n}\n\nfunction clampToViewport(w: number, h: number): ContainerSize {\n if (typeof window === \"undefined\") return { width: w, height: h };\n const vw = window.visualViewport?.width ?? window.innerWidth;\n const vh = window.visualViewport?.height ?? window.innerHeight;\n return { width: Math.min(w, vw), height: Math.min(h, vh) };\n}\n\nfunction viewportFallback(): ContainerSize {\n if (typeof window === \"undefined\") return { width: 800, height: 600 };\n return {\n width: window.visualViewport?.width ?? window.innerWidth,\n height: window.visualViewport?.height ?? window.innerHeight,\n };\n}\n\nexport function useContainerSize(ref: RefObject<HTMLElement | null>): ContainerSize {\n const [size, setSize] = useState<ContainerSize>(() => viewportFallback());\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n let rafId: number | null = null;\n\n const measure = () => {\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n rafId = null;\n const rect = el.getBoundingClientRect();\n const raw = rect.height > 0 ? { width: rect.width, height: rect.height } : viewportFallback();\n setSize(clampToViewport(raw.width, raw.height));\n });\n };\n\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => {\n ro.disconnect();\n if (rafId !== null) cancelAnimationFrame(rafId);\n };\n }, [ref]);\n\n return size;\n}\n","import { useMemo } from \"react\";\nimport type { DeviceMeta } from \"@mmtitanl/tablets\";\nimport { computeFullScale, type AdaptiveScaleResult } from \"../math/scale.js\";\n\nexport interface UseAdaptiveScaleOptions {\n device: DeviceMeta;\n containerWidth: number;\n containerHeight: number;\n padding?: number;\n maxScale?: number;\n minScale?: number;\n snapToSteps?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n}\n\nexport function useAdaptiveScale(options: UseAdaptiveScaleOptions): AdaptiveScaleResult {\n const {\n device,\n containerWidth,\n containerHeight,\n padding = 24,\n maxScale = 1,\n minScale = 0.1,\n snapToSteps = false,\n orientation = \"portrait\",\n } = options;\n\n return useMemo(() => {\n const dw = orientation === \"portrait\" ? device.screen.width : device.screen.height;\n const dh = orientation === \"portrait\" ? device.screen.height : device.screen.width;\n return computeFullScale(dw, dh, containerWidth, containerHeight, { padding, maxScale, minScale, snapToSteps });\n }, [\n device.screen.width,\n device.screen.height,\n containerWidth,\n containerHeight,\n padding,\n maxScale,\n minScale,\n snapToSteps,\n orientation,\n ]);\n}\n","import { useMemo } from \"react\";\nimport { getDeviceContract, type DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface UseDeviceContractResult {\n contract: DeviceLayoutContract;\n cssVariables: DeviceLayoutContract[\"cssVariables\"];\n contentZone: DeviceLayoutContract[\"contentZone\"][\"portrait\"];\n}\n\nexport function useDeviceContract(\n deviceId: string,\n orientation: \"portrait\" | \"landscape\" = \"portrait\"\n): UseDeviceContractResult {\n return useMemo(() => {\n const contract = getDeviceContract(deviceId, orientation);\n return {\n contract,\n cssVariables: contract.cssVariables,\n contentZone: orientation === \"portrait\" ? contract.contentZone.portrait : contract.contentZone.landscape,\n };\n }, [deviceId, orientation]);\n}\n","import { useCallback, useState } from \"react\";\n\nexport interface UseOrientationResult {\n orientation: \"portrait\" | \"landscape\";\n isLandscape: boolean;\n toggle: () => void;\n setOrientation: (o: \"portrait\" | \"landscape\") => void;\n}\n\n/**\n * Hook for managing tablet orientation state with a toggle function.\n *\n * ```tsx\n * const { orientation, toggle } = useOrientation();\n * <button onClick={toggle}>Rotate</button>\n * <DeviceFrame deviceId=\"ipad-pro-13\" orientation={orientation} />\n * ```\n */\nexport function useOrientation(initial: \"portrait\" | \"landscape\" = \"portrait\"): UseOrientationResult {\n const [orientation, setOrientation] = useState<\"portrait\" | \"landscape\">(initial);\n const toggle = useCallback(() => {\n setOrientation((o) => (o === \"portrait\" ? \"landscape\" : \"portrait\"));\n }, []);\n return { orientation, isLandscape: orientation === \"landscape\", toggle, setOrientation };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nconst STEPS = 16;\n\nexport interface VolumeState {\n level: number;\n muted: boolean;\n hudVisible: boolean;\n volumeUp: () => void;\n volumeDown: () => void;\n toggleMute: () => void;\n}\n\nfunction applyToMedia(level: number, muted: boolean) {\n if (typeof document === \"undefined\") return;\n const nodes = document.querySelectorAll<HTMLMediaElement>(\".bielaframe-content audio, .bielaframe-content video\");\n nodes.forEach((el) => {\n el.volume = Math.max(0, Math.min(1, level));\n el.muted = muted;\n });\n}\n\nexport function useVolumeControl(initialVolume = 0.5): VolumeState {\n const [level, setLevel] = useState(initialVolume);\n const [muted, setMuted] = useState(false);\n const [hudVisible, setHudVisible] = useState(false);\n const timer = useRef<number | null>(null);\n\n const flashHUD = useCallback(() => {\n setHudVisible(true);\n if (timer.current) window.clearTimeout(timer.current);\n timer.current = window.setTimeout(() => setHudVisible(false), 1500);\n }, []);\n\n const volumeUp = useCallback(() => {\n setLevel((l) => Math.min(1, l + 1 / STEPS));\n flashHUD();\n }, [flashHUD]);\n const volumeDown = useCallback(() => {\n setLevel((l) => Math.max(0, l - 1 / STEPS));\n flashHUD();\n }, [flashHUD]);\n const toggleMute = useCallback(() => {\n setMuted((m) => !m);\n flashHUD();\n }, [flashHUD]);\n\n useEffect(() => {\n applyToMedia(level, muted);\n }, [level, muted]);\n\n return { level, muted, hudVisible, volumeUp, volumeDown, toggleMute };\n}\n","import { useCallback, useState } from \"react\";\n\nexport interface ScreenPowerState {\n isOff: boolean;\n toggle: () => void;\n}\n\nexport function useScreenPower(): ScreenPowerState {\n const [isOff, setIsOff] = useState(false);\n const toggle = useCallback(() => setIsOff((v) => !v), []);\n return { isOff, toggle };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { isBielaMessage, type BielaDeviceInfoMessage } from \"../messages.js\";\n\nexport interface DeviceFrameInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nexport interface DeviceFrameInfo {\n insets: DeviceFrameInsets;\n vars: Record<string, string>;\n platform: \"ios\" | \"android\" | null;\n deviceId: string | null;\n orientation: \"portrait\" | \"landscape\" | null;\n isReady: boolean;\n reportColorScheme: (scheme: \"light\" | \"dark\") => void;\n}\n\nfunction parsePx(value: string | undefined): number {\n if (!value) return 0;\n const n = parseFloat(value);\n return Number.isFinite(n) ? n : 0;\n}\n\nexport function useDeviceFrame(): DeviceFrameInfo {\n const [vars, setVars] = useState<Record<string, string>>({});\n const [platform, setPlatform] = useState<\"ios\" | \"android\" | null>(null);\n const [deviceId, setDeviceId] = useState<string | null>(null);\n const [orientation, setOrientation] = useState<\"portrait\" | \"landscape\" | null>(null);\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handler = (event: MessageEvent) => {\n if (!isBielaMessage(event.data)) return;\n if (event.data.type === \"biela:deviceInfo\") {\n const msg = event.data as BielaDeviceInfoMessage;\n setVars(msg.payload.vars);\n setPlatform(msg.payload.platform);\n setDeviceId(msg.payload.deviceId);\n setOrientation(msg.payload.orientation);\n setIsReady(true);\n }\n };\n window.addEventListener(\"message\", handler);\n window.parent?.postMessage({ type: \"biela:requestDeviceInfo\" }, \"*\");\n return () => window.removeEventListener(\"message\", handler);\n }, []);\n\n const reportColorScheme = useCallback((scheme: \"light\" | \"dark\") => {\n if (typeof window === \"undefined\") return;\n window.parent?.postMessage({ type: \"biela:colorScheme\", payload: { scheme } }, \"*\");\n }, []);\n\n const insets: DeviceFrameInsets = {\n top: parsePx(vars[\"--safe-top\"]),\n bottom: parsePx(vars[\"--safe-bottom\"]),\n left: parsePx(vars[\"--safe-left\"]),\n right: parsePx(vars[\"--safe-right\"]),\n };\n\n return { insets, vars, platform, deviceId, orientation, isReady, reportColorScheme };\n}\n","export const BIELA_PREFIX = \"biela:\" as const;\n\nexport interface BielaDeviceInfoMessage {\n type: \"biela:deviceInfo\";\n payload: {\n vars: Record<string, string>;\n platform: \"ios\" | \"android\";\n deviceId: string;\n orientation: \"portrait\" | \"landscape\";\n };\n}\nexport interface BielaRequestMessage {\n type: \"biela:requestDeviceInfo\";\n}\nexport interface BielaColorSchemeMessage {\n type: \"biela:colorScheme\";\n payload: { scheme: \"light\" | \"dark\" };\n}\n\nexport function isBielaMessage(data: unknown): data is { type: string } {\n return (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n typeof (data as { type: unknown }).type === \"string\" &&\n (data as { type: string }).type.startsWith(BIELA_PREFIX)\n );\n}\n","import { useState, useCallback } from \"react\";\n\nexport type FoldState = \"folded\" | \"open\";\n\nexport interface UseFoldStateResult {\n foldState: FoldState;\n isOpen: boolean;\n deviceId: string;\n toggle: () => void;\n setFoldState: (state: FoldState) => void;\n}\n\n/**\n * Manages fold state for foldable tablet devices.\n * Convention: the open variant uses `${baseDeviceId}-open`.\n */\nexport function useFoldState(\n baseDeviceId: string,\n initial: FoldState = \"folded\"\n): UseFoldStateResult {\n const [foldState, setFoldStateRaw] = useState<FoldState>(initial);\n\n const toggle = useCallback(() => {\n setFoldStateRaw((s) => (s === \"folded\" ? \"open\" : \"folded\"));\n }, []);\n\n const setFoldState = useCallback((state: FoldState) => {\n setFoldStateRaw(state);\n }, []);\n\n const isOpen = foldState === \"open\";\n const deviceId = isOpen ? `${baseDeviceId}-open` : baseDeviceId;\n\n return { foldState, isOpen, deviceId, toggle, setFoldState };\n}\n","import type { ComponentType, CSSProperties } from \"react\";\nimport { scopeSVGIds, type SVGScreenRect } from \"@mmtitanl/tablets\";\n\nexport type DeviceSVGComponent = ComponentType<{\n colorScheme?: \"light\" | \"dark\";\n style?: CSSProperties;\n}>;\n\nexport interface FrameInfo {\n bezelTop: number;\n bezelBottom: number;\n bezelLeft: number;\n bezelRight: number;\n totalWidth: number;\n totalHeight: number;\n screenWidth: number;\n screenHeight: number;\n screenRadius: number;\n /** Optional per-edge overrides. Fall back to screenRadius when unset. */\n screenRadiusTop?: number;\n screenRadiusBottom?: number;\n}\n\nexport interface SVGCropArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface LandscapeSVGRegistration {\n svgString: string;\n frame: FrameInfo;\n cropViewBox?: SVGCropArea;\n screenRect?: SVGScreenRect;\n}\n\nexport interface LandscapeBuiltinRegistration {\n component: DeviceSVGComponent;\n frame: FrameInfo;\n screenRect?: SVGScreenRect;\n}\n\ninterface RegistryEntry {\n component: DeviceSVGComponent;\n frame: FrameInfo;\n screenRect?: SVGScreenRect;\n landscapeComponent?: DeviceSVGComponent;\n landscapeFrame?: FrameInfo;\n landscapeScreenRect?: SVGScreenRect;\n}\n\nconst SVG_REGISTRY = new Map<string, RegistryEntry>();\n\nexport function registerDeviceSVG(\n deviceId: string,\n component: DeviceSVGComponent,\n frame: FrameInfo,\n screenRect?: SVGScreenRect,\n landscape?: LandscapeBuiltinRegistration\n): void {\n SVG_REGISTRY.set(deviceId, {\n component,\n frame,\n screenRect,\n landscapeComponent: landscape?.component,\n landscapeFrame: landscape?.frame,\n landscapeScreenRect: landscape?.screenRect,\n });\n}\n\nexport function getDeviceSVG(deviceId: string): RegistryEntry | undefined {\n return SVG_REGISTRY.get(deviceId);\n}\n\nfunction buildCustomComponent(\n deviceId: string,\n svgString: string,\n cropViewBox: SVGCropArea | undefined,\n screenRect: SVGScreenRect | undefined,\n suffix: string\n): DeviceSVGComponent {\n const scopeKey = suffix ? `${deviceId}${suffix}` : deviceId;\n let svg = scopeSVGIds(svgString, scopeKey);\n if (cropViewBox) {\n svg = svg.replace(\n /<svg\\b([^>]*)>/i,\n (_m, attrs: string) => {\n const stripped = attrs\n .replace(/\\sviewBox\\s*=\\s*[\"'][^\"']*[\"']/i, \"\")\n .replace(/\\swidth\\s*=\\s*[\"'][^\"']*[\"']/i, \"\")\n .replace(/\\sheight\\s*=\\s*[\"'][^\"']*[\"']/i, \"\");\n return `<svg${stripped} viewBox=\"${cropViewBox.x} ${cropViewBox.y} ${cropViewBox.width} ${cropViewBox.height}\" width=\"100%\" height=\"100%\">`;\n }\n );\n } else {\n svg = svg.replace(\n /<svg\\b([^>]*)>/i,\n (_m, attrs: string) => {\n const stripped = attrs.replace(/\\swidth\\s*=\\s*[\"'][^\"']*[\"']/i, \"\").replace(/\\sheight\\s*=\\s*[\"'][^\"']*[\"']/i, \"\");\n return `<svg${stripped} width=\"100%\" height=\"100%\">`;\n }\n );\n }\n\n // No mask needed — the iframe (bielaframe-content) is rendered ON TOP of\n // the SVG in DeviceFrame, clipped to the screen rect via clip-path.\n // The SVG just provides bezel/body decoration underneath.\n void screenRect;\n\n const Component: DeviceSVGComponent = ({ style }) => (\n <span\n style={{ display: \"block\", width: \"100%\", height: \"100%\", ...style }}\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n );\n Component.displayName = `CustomDeviceSVG(${scopeKey})`;\n return Component;\n}\n\nexport function registerCustomDeviceSVG(\n deviceId: string,\n svgString: string,\n frame: FrameInfo,\n cropViewBox?: SVGCropArea,\n screenRect?: SVGScreenRect,\n landscape?: LandscapeSVGRegistration\n): void {\n const portraitComponent = buildCustomComponent(deviceId, svgString, cropViewBox, screenRect, \"\");\n const landscapeComponent = landscape\n ? buildCustomComponent(deviceId, landscape.svgString, landscape.cropViewBox, landscape.screenRect, \"-landscape\")\n : undefined;\n\n SVG_REGISTRY.set(deviceId, {\n component: portraitComponent,\n frame,\n screenRect,\n landscapeComponent,\n landscapeFrame: landscape?.frame,\n landscapeScreenRect: landscape?.screenRect,\n });\n}\n","import { useEffect, useMemo, useRef, useState, type ReactNode, type RefObject } from \"react\";\nimport {\n getDeviceContract,\n getDeviceMetadata,\n type DeviceLayoutContract,\n} from \"@mmtitanl/tablets\";\nimport { computeFullScale, type AdaptiveScaleResult } from \"../math/scale.js\";\nimport { useContainerSize } from \"../hooks/use-container-size.js\";\nimport { DeviceErrorBoundary } from \"./DeviceErrorBoundary.js\";\nimport { SafeAreaOverlay } from \"./SafeAreaOverlay.js\";\nimport { ScaleBar } from \"./ScaleBar.js\";\nimport { DynamicStatusBar } from \"./DynamicStatusBar.js\";\nimport { getDeviceSVG, type DeviceSVGComponent } from \"../registration.js\";\nimport {\n // Tablets\n IPadPro13SVG, IPAD_PRO_13_FRAME, IPAD_PRO_13_SCREEN_RECT,\n IPadPro11SVG, IPAD_PRO_11_FRAME, IPAD_PRO_11_SCREEN_RECT,\n IPadAir13SVG, IPAD_AIR_13_FRAME, IPAD_AIR_13_SCREEN_RECT,\n IPadAir11SVG, IPAD_AIR_11_FRAME, IPAD_AIR_11_SCREEN_RECT,\n IPadMini7SVG, IPAD_MINI_7_FRAME, IPAD_MINI_7_SCREEN_RECT,\n GalaxyTabS10SVG, GALAXY_TAB_S10_FRAME, GALAXY_TAB_S10_SCREEN_RECT,\n GalaxyTabS10UltraSVG, GALAXY_TAB_S10_ULTRA_FRAME, GALAXY_TAB_S10_ULTRA_SCREEN_RECT,\n GalaxyTabS10FeSVG, GALAXY_TAB_S10_FE_FRAME, GALAXY_TAB_S10_FE_SCREEN_RECT,\n // Phones — iOS\n IPhone17ProMaxSVG, IPHONE_17_PRO_MAX_FRAME, IPHONE_17_PRO_MAX_SCREEN_RECT,\n IPhone17ProSVG, IPHONE_17_PRO_FRAME, IPHONE_17_PRO_SCREEN_RECT,\n IPhoneAirSVG, IPHONE_AIR_FRAME, IPHONE_AIR_SCREEN_RECT,\n IPhone16SVG, IPHONE_16_FRAME, IPHONE_16_SCREEN_RECT,\n IPhone16eSVG, IPHONE_16E_FRAME, IPHONE_16E_SCREEN_RECT,\n IPhoneSE3SVG, IPHONE_SE_3_FRAME, IPHONE_SE_3_SCREEN_RECT,\n // Phones — Android\n GalaxyS25SVG, GALAXY_S25_FRAME, GALAXY_S25_SCREEN_RECT,\n GalaxyS25EdgeSVG, GALAXY_S25_EDGE_FRAME,\n GalaxyS25UltraSVG, GALAXY_S25_ULTRA_FRAME, GALAXY_S25_ULTRA_SCREEN_RECT,\n Pixel9ProSVG, PIXEL_9_PRO_FRAME, PIXEL_9_PRO_SCREEN_RECT,\n Pixel9ProXLSVG, PIXEL_9_PRO_XL_FRAME, PIXEL_9_PRO_XL_SCREEN_RECT,\n // Foldables\n GalaxyZFold7SVG, GALAXY_Z_FOLD_7_FRAME, GALAXY_Z_FOLD_7_SCREEN_RECT,\n GalaxyZFold7OpenSVG, GALAXY_Z_FOLD_7_OPEN_FRAME, GALAXY_Z_FOLD_7_OPEN_SCREEN_RECT,\n // User-added custom devices baked into the package\n CUSTOM_DEVICES,\n} from \"@mmtitanl/tablets\";\nimport { registerDeviceSVG } from \"../registration.js\";\n\nlet didAutoRegister = false;\nfunction ensureBuiltinsRegistered() {\n if (didAutoRegister) return;\n // Tablets\n registerDeviceSVG(\"ipad-pro-13\", IPadPro13SVG as DeviceSVGComponent, IPAD_PRO_13_FRAME, IPAD_PRO_13_SCREEN_RECT);\n registerDeviceSVG(\"ipad-pro-11\", IPadPro11SVG as DeviceSVGComponent, IPAD_PRO_11_FRAME, IPAD_PRO_11_SCREEN_RECT);\n registerDeviceSVG(\"ipad-air-13\", IPadAir13SVG as DeviceSVGComponent, IPAD_AIR_13_FRAME, IPAD_AIR_13_SCREEN_RECT);\n registerDeviceSVG(\"ipad-air-11\", IPadAir11SVG as DeviceSVGComponent, IPAD_AIR_11_FRAME, IPAD_AIR_11_SCREEN_RECT);\n registerDeviceSVG(\"ipad-mini-7\", IPadMini7SVG as DeviceSVGComponent, IPAD_MINI_7_FRAME, IPAD_MINI_7_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10\", GalaxyTabS10SVG as DeviceSVGComponent, GALAXY_TAB_S10_FRAME, GALAXY_TAB_S10_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10-ultra\", GalaxyTabS10UltraSVG as DeviceSVGComponent, GALAXY_TAB_S10_ULTRA_FRAME, GALAXY_TAB_S10_ULTRA_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10-fe\", GalaxyTabS10FeSVG as DeviceSVGComponent, GALAXY_TAB_S10_FE_FRAME, GALAXY_TAB_S10_FE_SCREEN_RECT);\n // Phones — iOS\n registerDeviceSVG(\"iphone-17-pro-max\", IPhone17ProMaxSVG as DeviceSVGComponent, IPHONE_17_PRO_MAX_FRAME, IPHONE_17_PRO_MAX_SCREEN_RECT);\n registerDeviceSVG(\"iphone-17-pro\", IPhone17ProSVG as DeviceSVGComponent, IPHONE_17_PRO_FRAME, IPHONE_17_PRO_SCREEN_RECT);\n registerDeviceSVG(\"iphone-air\", IPhoneAirSVG as DeviceSVGComponent, IPHONE_AIR_FRAME, IPHONE_AIR_SCREEN_RECT);\n registerDeviceSVG(\"iphone-16\", IPhone16SVG as DeviceSVGComponent, IPHONE_16_FRAME, IPHONE_16_SCREEN_RECT);\n registerDeviceSVG(\"iphone-16e\", IPhone16eSVG as DeviceSVGComponent, IPHONE_16E_FRAME, IPHONE_16E_SCREEN_RECT);\n registerDeviceSVG(\"iphone-se-3\", IPhoneSE3SVG as DeviceSVGComponent, IPHONE_SE_3_FRAME, IPHONE_SE_3_SCREEN_RECT);\n // Phones — Android\n registerDeviceSVG(\"galaxy-s25\", GalaxyS25SVG as DeviceSVGComponent, GALAXY_S25_FRAME, GALAXY_S25_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-s25-edge\", GalaxyS25EdgeSVG as DeviceSVGComponent, GALAXY_S25_EDGE_FRAME);\n registerDeviceSVG(\"galaxy-s25-ultra\", GalaxyS25UltraSVG as DeviceSVGComponent, GALAXY_S25_ULTRA_FRAME, GALAXY_S25_ULTRA_SCREEN_RECT);\n registerDeviceSVG(\"pixel-9-pro\", Pixel9ProSVG as DeviceSVGComponent, PIXEL_9_PRO_FRAME, PIXEL_9_PRO_SCREEN_RECT);\n registerDeviceSVG(\"pixel-9-pro-xl\", Pixel9ProXLSVG as DeviceSVGComponent, PIXEL_9_PRO_XL_FRAME, PIXEL_9_PRO_XL_SCREEN_RECT);\n // Foldables\n registerDeviceSVG(\"galaxy-z-fold-7\", GalaxyZFold7SVG as DeviceSVGComponent, GALAXY_Z_FOLD_7_FRAME, GALAXY_Z_FOLD_7_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-z-fold-7-open\", GalaxyZFold7OpenSVG as DeviceSVGComponent, GALAXY_Z_FOLD_7_OPEN_FRAME, GALAXY_Z_FOLD_7_OPEN_SCREEN_RECT);\n // User-added custom devices, persisted in @mmtitanl/tablets src/custom/data.json\n for (const c of CUSTOM_DEVICES) {\n registerDeviceSVG(\n c.meta.id,\n c.Component as DeviceSVGComponent,\n c.frame,\n c.screenRect,\n c.LandscapeComponent && c.landscape\n ? { component: c.LandscapeComponent as DeviceSVGComponent, frame: c.landscape.frame, screenRect: c.landscape.screenRect }\n : undefined\n );\n }\n didAutoRegister = true;\n}\n\nexport interface DeviceFrameProps {\n device?: string;\n deviceId?: string;\n orientation?: \"portrait\" | \"landscape\";\n scaleMode?: \"fit\" | \"manual\" | \"steps\";\n manualScale?: number;\n showSafeAreaOverlay?: boolean;\n showDLCPanel?: boolean;\n showScaleBar?: boolean;\n showStatusBar?: boolean;\n colorScheme?: \"light\" | \"dark\";\n iframeRef?: RefObject<HTMLIFrameElement | null>;\n onColorSchemeChange?: (scheme: \"light\" | \"dark\") => void;\n onContractReady?: (dlc: DeviceLayoutContract) => void;\n onScaleChange?: (scale: number) => void;\n children?: ReactNode;\n}\n\nfunction sendDeviceInfo(\n iframe: HTMLIFrameElement | null,\n contract: DeviceLayoutContract,\n orientation: \"portrait\" | \"landscape\"\n) {\n if (!iframe?.contentWindow) return;\n iframe.contentWindow.postMessage(\n {\n type: \"biela:deviceInfo\",\n payload: {\n vars: contract.cssVariables,\n platform: contract.device.platform,\n deviceId: contract.device.id,\n orientation,\n },\n },\n \"*\"\n );\n}\n\nexport function DeviceFrame({\n device,\n deviceId,\n orientation = \"portrait\",\n scaleMode = \"fit\",\n manualScale = 1,\n showSafeAreaOverlay = false,\n showScaleBar = true,\n showStatusBar = true,\n colorScheme = \"light\",\n iframeRef,\n onColorSchemeChange,\n onContractReady,\n onScaleChange,\n children,\n}: DeviceFrameProps) {\n ensureBuiltinsRegistered();\n\n const resolvedId = device ?? deviceId;\n if (!resolvedId) throw new Error(\"DeviceFrame requires `device` or `deviceId`\");\n\n const meta = getDeviceMetadata(resolvedId);\n const contract = useMemo(() => getDeviceContract(resolvedId, orientation), [resolvedId, orientation]);\n\n const portW = meta.screen.width;\n const portH = meta.screen.height;\n const rotateFrame = orientation === \"landscape\";\n // Content dimensions swap for landscape.\n const dw = rotateFrame ? portH : portW;\n const dh = rotateFrame ? portW : portH;\n\n const sentinelRef = useRef<HTMLDivElement>(null);\n const frameContainerRef = useRef<HTMLDivElement>(null);\n const containerSize = useContainerSize(sentinelRef);\n\n const svgEntryEarly = getDeviceSVG(resolvedId);\n const portraitFrameEarly = svgEntryEarly?.frame;\n const landscapeFrameEarly = svgEntryEarly?.landscapeFrame;\n const hasLandscapeSVGEarly = !!svgEntryEarly?.landscapeComponent && !!landscapeFrameEarly;\n // Active frame total dims drive the host box.\n // - With 2-SVG: pick the matching frame for the current orientation.\n // - With 1-SVG (rotated): swap portrait dims when landscape.\n const fitW = portraitFrameEarly\n ? (rotateFrame\n ? (hasLandscapeSVGEarly ? landscapeFrameEarly!.totalWidth : portraitFrameEarly.totalHeight)\n : portraitFrameEarly.totalWidth)\n : (rotateFrame ? portH : portW);\n const fitH = portraitFrameEarly\n ? (rotateFrame\n ? (hasLandscapeSVGEarly ? landscapeFrameEarly!.totalHeight : portraitFrameEarly.totalWidth)\n : portraitFrameEarly.totalHeight)\n : (rotateFrame ? portW : portH);\n\n const fitResult: AdaptiveScaleResult = useMemo(\n () =>\n computeFullScale(fitW, fitH, containerSize.width, containerSize.height, {\n snapToSteps: scaleMode === \"steps\",\n }),\n [fitW, fitH, containerSize.width, containerSize.height, scaleMode]\n );\n\n const [overrideScale, setOverrideScale] = useState<number | null>(null);\n\n useEffect(() => {\n setOverrideScale(null);\n }, [orientation]);\n\n const scale =\n scaleMode === \"manual\" ? manualScale : overrideScale ?? fitResult.scale;\n const hostWidth = fitW * scale;\n const hostHeight = fitH * scale;\n const isAtMaxScale = scale >= 0.9999;\n\n useEffect(() => {\n onContractReady?.(contract);\n }, [contract, onContractReady]);\n\n useEffect(() => {\n onScaleChange?.(scale);\n }, [scale, onScaleChange]);\n\n useEffect(() => {\n if (!iframeRef?.current) return;\n sendDeviceInfo(iframeRef.current, contract, orientation);\n const onLoad = () => sendDeviceInfo(iframeRef.current, contract, orientation);\n iframeRef.current.addEventListener(\"load\", onLoad);\n return () => iframeRef.current?.removeEventListener(\"load\", onLoad);\n }, [iframeRef, contract, orientation]);\n\n useEffect(() => {\n if (!iframeRef) return;\n const handler = (event: MessageEvent) => {\n const data = event.data as { type?: string; payload?: { scheme?: \"light\" | \"dark\" } } | null;\n if (!data || typeof data !== \"object\") return;\n if (data.type === \"biela:requestDeviceInfo\") {\n sendDeviceInfo(iframeRef.current, contract, orientation);\n } else if (data.type === \"biela:colorScheme\" && data.payload?.scheme) {\n onColorSchemeChange?.(data.payload.scheme);\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }, [iframeRef, contract, orientation, onColorSchemeChange]);\n\n const svgEntry = getDeviceSVG(resolvedId);\n const SVGComponent: DeviceSVGComponent | null = svgEntry?.component ?? null;\n const portraitFrame = svgEntry?.frame;\n const LandscapeSVGComponent: DeviceSVGComponent | null = svgEntry?.landscapeComponent ?? null;\n const landscapeFrame = svgEntry?.landscapeFrame;\n const hasLandscapeSVG = !!LandscapeSVGComponent && !!landscapeFrame;\n\n const cssVarsStyle = contract.cssVariables as unknown as React.CSSProperties;\n\n // For 2-SVG devices, use a stable container sized to the maximum of portrait and\n // landscape frame dims. scalerW/scalerH never change between orientations — no layout\n // jump, no rotation tricks. The host clips to the correct visible rectangle via\n // overflow:hidden. For single-SVG devices the rotation fallback is unchanged.\n const activeFrame = hasLandscapeSVG && rotateFrame ? landscapeFrame! : portraitFrame;\n const scalerW = hasLandscapeSVG\n ? Math.max(portraitFrame?.totalWidth ?? dw, landscapeFrame?.totalWidth ?? dh)\n : (activeFrame?.totalWidth ?? (rotateFrame ? portW : dw));\n const scalerH = hasLandscapeSVG\n ? Math.max(portraitFrame?.totalHeight ?? dh, landscapeFrame?.totalHeight ?? dw)\n : (activeFrame?.totalHeight ?? (rotateFrame ? portH : dh));\n const contentBezelLeft = activeFrame?.bezelLeft ?? 0;\n const contentBezelTop = activeFrame?.bezelTop ?? 0;\n const contentScreenW = activeFrame?.screenWidth ?? dw;\n const contentScreenH = activeFrame?.screenHeight ?? dh;\n const baseRadius = activeFrame?.screenRadius ?? meta.screen.cornerRadius ?? 0;\n const radiusTop = activeFrame?.screenRadiusTop ?? baseRadius;\n const radiusBottom = activeFrame?.screenRadiusBottom ?? baseRadius;\n\n const useRotationFallback = rotateFrame && !hasLandscapeSVG;\n const scalerTransform = useRotationFallback\n ? `scale(${scale}) translate(0px, ${scalerW}px) rotate(-90deg)`\n : `scale(${scale})`;\n\n return (\n <div\n ref={sentinelRef}\n className=\"bielaframe-sentinel\"\n style={{ width: \"100%\", height: \"100%\", display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", overflow: \"hidden\" }}\n >\n <div\n className=\"bielaframe-host\"\n style={{\n width: hostWidth,\n height: hostHeight,\n position: \"relative\",\n flexShrink: 0,\n overflow: \"hidden\",\n transition: \"width 400ms cubic-bezier(0.4, 0, 0.2, 1), height 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <div\n className=\"bielaframe-scaler\"\n ref={frameContainerRef}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: scalerW,\n height: scalerH,\n transform: scalerTransform,\n transformOrigin: \"top left\",\n willChange: \"transform\",\n transition: \"transform 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n {SVGComponent && portraitFrame && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: portraitFrame.totalWidth,\n height: portraitFrame.totalHeight,\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: hasLandscapeSVG && rotateFrame ? 0 : 1,\n transition: \"opacity 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <SVGComponent\n colorScheme={colorScheme}\n style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\" }}\n />\n </div>\n )}\n\n {hasLandscapeSVG && LandscapeSVGComponent && landscapeFrame && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: landscapeFrame.totalWidth,\n height: landscapeFrame.totalHeight,\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: rotateFrame ? 1 : 0,\n transition: \"opacity 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <LandscapeSVGComponent\n colorScheme={colorScheme}\n style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\" }}\n />\n </div>\n )}\n\n <div\n className=\"bielaframe-content\"\n style={{\n position: \"absolute\",\n left: contentBezelLeft,\n top: contentBezelTop,\n width: contentScreenW,\n height: contentScreenH,\n // `border-radius + overflow:hidden` clips the <iframe> child\n // in every browser. clip-path is kept as belt-and-braces — some\n // engines apply it to the iframe, some don't. Per-edge radii\n // (top vs bottom) let devices with asymmetric corners — e.g.\n // flat-bottom — clip correctly.\n borderRadius: `${radiusTop}px ${radiusTop}px ${radiusBottom}px ${radiusBottom}px`,\n clipPath: `inset(0 round ${radiusTop}px ${radiusTop}px ${radiusBottom}px ${radiusBottom}px)`,\n overflow: \"hidden\",\n isolation: \"isolate\",\n backfaceVisibility: \"hidden\",\n transform: \"translateZ(0)\",\n background: colorScheme === \"dark\" ? \"#000\" : \"#fff\",\n zIndex: 5,\n ...cssVarsStyle,\n }}\n >\n <DeviceErrorBoundary>{children}</DeviceErrorBoundary>\n {showStatusBar && (\n <DynamicStatusBar contract={contract} orientation={orientation} colorScheme={colorScheme} />\n )}\n {showSafeAreaOverlay && <SafeAreaOverlay contract={contract} orientation={orientation} />}\n </div>\n </div>\n </div>\n\n {showScaleBar && (\n <ScaleBar\n deviceName={meta.name}\n deviceWidth={dw}\n deviceHeight={dh}\n scale={scale}\n scalePercent={`${Math.round(scale * 100)}%`}\n isAtMaxScale={isAtMaxScale}\n isConstrained={!isAtMaxScale}\n onScaleChange={(s) => setOverrideScale(s)}\n onFit={() => setOverrideScale(null)}\n onRealSize={() => setOverrideScale(1)}\n />\n )}\n </div>\n );\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class DeviceErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n console.error(\"[BielaFrame] device content crashed\", error, errorInfo);\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n return (\n this.props.fallback ?? (\n <div\n style={{\n padding: 20,\n fontFamily: \"system-ui\",\n color: \"#ff453a\",\n background: \"#1c1c1e\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n textAlign: \"center\",\n }}\n >\n <div>\n <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 8 }}>Component crashed</div>\n <div style={{ fontSize: 12, opacity: 0.8 }}>{this.state.error?.message}</div>\n </div>\n </div>\n )\n );\n }\n return this.props.children;\n }\n}\n","import type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface SafeAreaOverlayProps {\n contract: DeviceLayoutContract;\n orientation: \"portrait\" | \"landscape\";\n}\n\nexport function SafeAreaOverlay({ contract, orientation }: SafeAreaOverlayProps) {\n const safe = orientation === \"portrait\" ? contract.safeArea.portrait : contract.safeArea.landscape;\n const w = orientation === \"portrait\" ? contract.screen.width : contract.screen.height;\n const h = orientation === \"portrait\" ? contract.screen.height : contract.screen.width;\n const baseStyle = { position: \"absolute\" as const, pointerEvents: \"none\" as const };\n return (\n <>\n <div style={{ ...baseStyle, top: 0, left: 0, right: 0, height: safe.top, background: \"rgba(255,69,58,0.25)\" }} />\n <div\n style={{ ...baseStyle, bottom: 0, left: 0, right: 0, height: safe.bottom, background: \"rgba(255,69,58,0.25)\" }}\n />\n <div style={{ ...baseStyle, top: 0, left: 0, bottom: 0, width: safe.left, background: \"rgba(255,69,58,0.25)\" }} />\n <div\n style={{ ...baseStyle, top: 0, right: 0, bottom: 0, width: safe.right, background: \"rgba(255,69,58,0.25)\" }}\n />\n <div\n style={{\n ...baseStyle,\n top: safe.top,\n bottom: safe.bottom,\n left: safe.left,\n right: safe.right,\n outline: \"1px dashed rgba(48,209,88,0.6)\",\n }}\n />\n <div\n style={{\n ...baseStyle,\n top: 4,\n left: 8,\n color: \"white\",\n background: \"rgba(0,0,0,0.6)\",\n padding: \"2px 6px\",\n fontSize: 10,\n fontFamily: \"ui-monospace, monospace\",\n borderRadius: 4,\n }}\n >\n {w}×{h} · safe {safe.top}/{safe.bottom}/{safe.left}/{safe.right}\n </div>\n </>\n );\n}\n","import { SCALE_STEPS } from \"../math/scale.js\";\n\nexport interface ScaleBarProps {\n deviceName: string;\n deviceWidth: number;\n deviceHeight: number;\n scale: number;\n scalePercent: string;\n isAtMaxScale: boolean;\n isConstrained: boolean;\n onScaleChange?: (scale: number) => void;\n onFit?: () => void;\n onRealSize?: () => void;\n}\n\nexport function ScaleBar({\n deviceName,\n deviceWidth,\n deviceHeight,\n scale,\n scalePercent,\n isAtMaxScale,\n onScaleChange,\n onFit,\n onRealSize,\n}: ScaleBarProps) {\n return (\n <div\n role=\"region\"\n aria-label=\"Device scale controls\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: \"rgba(28,28,30,0.92)\",\n color: \"white\",\n borderRadius: 8,\n fontFamily: \"ui-monospace, monospace\",\n fontSize: 12,\n marginTop: 8,\n }}\n >\n <span>{deviceName}</span>\n <span style={{ opacity: 0.6 }}>·</span>\n <span>\n {deviceWidth}×{deviceHeight}pt\n </span>\n <input\n type=\"range\"\n min={0.1}\n max={2}\n step={0.01}\n value={scale}\n aria-label=\"Scale\"\n aria-valuenow={scale}\n role=\"slider\"\n onChange={(e) => onScaleChange?.(parseFloat(e.target.value))}\n style={{ flex: 1 }}\n />\n <span aria-live=\"polite\" style={{ width: 40, textAlign: \"right\" }}>\n {scalePercent}\n </span>\n <button onClick={onFit} type=\"button\" style={btn}>\n Fit\n </button>\n <button onClick={onRealSize} type=\"button\" style={{ ...btn, opacity: isAtMaxScale ? 0.5 : 1 }}>\n 1:1\n </button>\n </div>\n );\n}\n\nconst btn = {\n background: \"transparent\",\n color: \"white\",\n border: \"1px solid rgba(255,255,255,0.25)\",\n padding: \"2px 8px\",\n borderRadius: 4,\n cursor: \"pointer\",\n fontSize: 11,\n};\n","import { useEffect, useState, type CSSProperties } from \"react\";\nimport type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface DynamicStatusBarProps {\n contract: DeviceLayoutContract;\n orientation: \"portrait\" | \"landscape\";\n colorScheme: \"light\" | \"dark\";\n showLiveClock?: boolean;\n fixedTime?: string;\n}\n\nfunction formatNow(): string {\n const now = new Date();\n return `${now.getHours()}:${now.getMinutes().toString().padStart(2, \"0\")}`;\n}\n\nexport function DynamicStatusBar({\n contract,\n orientation,\n colorScheme,\n showLiveClock = true,\n fixedTime,\n}: DynamicStatusBarProps) {\n const [now, setNow] = useState(formatNow);\n\n useEffect(() => {\n if (!showLiveClock || fixedTime) return;\n const id = window.setInterval(() => setNow(formatNow()), 30_000);\n return () => window.clearInterval(id);\n }, [showLiveClock, fixedTime]);\n\n // iOS in landscape hides the status bar entirely.\n if (orientation === \"landscape\" && contract.device.platform === \"ios\") return null;\n\n const time = fixedTime ?? (showLiveClock ? now : \"9:41\");\n const platform = contract.device.platform;\n const statusBarStyle = contract.statusBar.style;\n const height = contract.statusBar.height;\n const textColor = colorScheme === \"dark\" ? \"#fff\" : \"#000\";\n const bgColor = colorScheme === \"dark\" ? \"#000\" : \"#fff\";\n const fontFamily = platform === \"ios\"\n ? \"-apple-system, 'SF Pro Text', 'Helvetica Neue', sans-serif\"\n : \"'Roboto', 'Google Sans', sans-serif\";\n const baseFontSize = platform === \"ios\" ? 15 : 12;\n const clockStyle: CSSProperties = {\n color: textColor,\n fontFamily,\n fontSize: baseFontSize,\n fontWeight: platform === \"ios\" ? 600 : 400,\n letterSpacing: platform === \"ios\" ? 0.3 : 0,\n lineHeight: `${height}px`,\n whiteSpace: \"nowrap\",\n };\n // Patch only the area around the clock — leave the rest of the bar alone so\n // the iframe app's own mock status bar (signal / wifi / battery) shows\n // through on the sides.\n const patchStyle: CSSProperties = {\n position: \"absolute\",\n top: 0,\n height,\n display: \"flex\",\n alignItems: \"center\",\n background: bgColor,\n pointerEvents: \"none\",\n };\n\n // iOS classic / fullwidth — centered narrow patch around the clock.\n if (platform === \"ios\" && statusBarStyle !== \"dynamic-island\" && statusBarStyle !== \"notch\") {\n return (\n <div\n aria-hidden\n style={{ ...patchStyle, left: \"50%\", transform: \"translateX(-50%)\", paddingLeft: 6, paddingRight: 6 }}\n >\n <span style={{ ...clockStyle, fontWeight: 500, fontSize: baseFontSize - 1 }}>{time}</span>\n </div>\n );\n }\n\n // iOS with Dynamic Island / notch — left-aligned with iOS spacing.\n if (platform === \"ios\") {\n return (\n <div aria-hidden style={{ ...patchStyle, left: 0, paddingLeft: 20, paddingRight: 8 }}>\n <span style={clockStyle}>{time}</span>\n </div>\n );\n }\n\n // Android — left-aligned.\n return (\n <div aria-hidden style={{ ...patchStyle, left: 0, paddingLeft: 16, paddingRight: 8 }}>\n <span style={clockStyle}>{time}</span>\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\nimport { DeviceFrame } from \"./DeviceFrame.js\";\n\nexport interface DeviceCompareProps {\n deviceA: string;\n deviceB: string;\n orientation?: \"portrait\" | \"landscape\";\n colorScheme?: \"light\" | \"dark\";\n showSafeAreaOverlay?: boolean;\n showScaleBar?: boolean;\n layout?: \"horizontal\" | \"vertical\" | \"auto\";\n gap?: number;\n children?: ReactNode;\n childrenA?: ReactNode;\n childrenB?: ReactNode;\n onContractReadyA?: (dlc: DeviceLayoutContract) => void;\n onContractReadyB?: (dlc: DeviceLayoutContract) => void;\n}\n\nexport function DeviceCompare({\n deviceA,\n deviceB,\n orientation = \"portrait\",\n colorScheme = \"light\",\n showSafeAreaOverlay,\n showScaleBar,\n layout = \"auto\",\n gap = 24,\n children,\n childrenA,\n childrenB,\n onContractReadyA,\n onContractReadyB,\n}: DeviceCompareProps) {\n const direction = layout === \"auto\" ? (orientation === \"portrait\" ? \"row\" : \"column\") : layout === \"horizontal\" ? \"row\" : \"column\";\n return (\n <div style={{ display: \"flex\", flexDirection: direction, gap, width: \"100%\", height: \"100%\" }}>\n <div style={{ flex: 1 }}>\n <DeviceFrame\n deviceId={deviceA}\n orientation={orientation}\n colorScheme={colorScheme}\n showSafeAreaOverlay={showSafeAreaOverlay}\n showScaleBar={showScaleBar}\n onContractReady={onContractReadyA}\n >\n {childrenA ?? children}\n </DeviceFrame>\n </div>\n <div style={{ flex: 1 }}>\n <DeviceFrame\n deviceId={deviceB}\n orientation={orientation}\n colorScheme={colorScheme}\n showSafeAreaOverlay={showSafeAreaOverlay}\n showScaleBar={showScaleBar}\n onContractReady={onContractReadyB}\n >\n {childrenB ?? children}\n </DeviceFrame>\n </div>\n </div>\n );\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\nexport interface SafeAreaViewProps {\n edges?: Array<\"top\" | \"bottom\" | \"left\" | \"right\">;\n children: ReactNode;\n style?: CSSProperties;\n}\n\nexport function SafeAreaView({ edges = [\"top\", \"bottom\", \"left\", \"right\"], children, style }: SafeAreaViewProps) {\n const padding: CSSProperties = {\n paddingTop: edges.includes(\"top\") ? \"var(--safe-top, 0px)\" : undefined,\n paddingBottom: edges.includes(\"bottom\") ? \"var(--safe-bottom, 0px)\" : undefined,\n paddingLeft: edges.includes(\"left\") ? \"var(--safe-left, 0px)\" : undefined,\n paddingRight: edges.includes(\"right\") ? \"var(--safe-right, 0px)\" : undefined,\n };\n return <div style={{ ...padding, ...style }}>{children}</div>;\n}\n","export interface VolumeHUDProps {\n level: number;\n muted: boolean;\n visible: boolean;\n platform: \"ios\" | \"android\";\n}\n\nexport function VolumeHUD({ level, muted, visible, platform }: VolumeHUDProps) {\n if (!visible) return null;\n const isIOS = platform === \"ios\";\n const pct = Math.round((muted ? 0 : level) * 100);\n return (\n <div\n role=\"status\"\n aria-label={`Volume ${pct}%`}\n style={{\n position: \"absolute\",\n ...(isIOS\n ? { top: \"12%\", left: \"50%\", transform: \"translateX(-50%)\", width: 6, height: 220, borderRadius: 3 }\n : { top: 16, left: \"50%\", transform: \"translateX(-50%)\", width: 240, height: 6, borderRadius: 3 }),\n background: \"rgba(255,255,255,0.2)\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n background: muted ? \"#8e8e93\" : \"white\",\n ...(isIOS ? { width: \"100%\", height: `${pct}%`, marginTop: `${100 - pct}%` } : { width: `${pct}%`, height: \"100%\" }),\n }}\n />\n </div>\n );\n}\n","import { useEffect, useState, type ReactElement, type RefObject } from \"react\";\n\nexport type ButtonName = \"volumeUp\" | \"volumeDown\" | \"power\" | \"actionButton\" | \"cameraControl\";\n\ninterface ButtonRect {\n name: ButtonName;\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport interface HardwareButtonsProps {\n frameContainerRef: RefObject<HTMLDivElement | null>;\n onButtonPress?: (button: ButtonName) => void;\n enabled?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n}\n\nexport function HardwareButtons({\n frameContainerRef,\n onButtonPress,\n enabled = true,\n orientation = \"portrait\",\n}: HardwareButtonsProps): ReactElement | null {\n const [rects, setRects] = useState<ButtonRect[]>([]);\n\n useEffect(() => {\n if (!enabled) return;\n const container = frameContainerRef.current;\n if (!container) return;\n const found: ButtonRect[] = [];\n const nodes = container.querySelectorAll<SVGElement>(\"[data-button]\");\n const containerRect = container.getBoundingClientRect();\n nodes.forEach((node) => {\n const name = node.getAttribute(\"data-button\") as ButtonName | null;\n if (!name) return;\n const r = node.getBoundingClientRect();\n found.push({\n name,\n left: r.left - containerRect.left,\n top: r.top - containerRect.top,\n width: r.width,\n height: r.height,\n });\n });\n setRects(found);\n }, [frameContainerRef, enabled, orientation]);\n\n if (!enabled || rects.length === 0) return null;\n\n return (\n <>\n {rects.map((r) => (\n <div\n key={r.name}\n role=\"button\"\n aria-label={r.name}\n onMouseDown={() => onButtonPress?.(r.name)}\n onTouchStart={() => onButtonPress?.(r.name)}\n style={{\n position: \"absolute\",\n left: r.left,\n top: r.top,\n width: r.width,\n height: r.height,\n cursor: \"pointer\",\n zIndex: 20,\n }}\n />\n ))}\n </>\n );\n}\n","export interface StatusBarIndicatorsProps {\n platform: \"ios\" | \"android\";\n colorScheme: \"light\" | \"dark\";\n}\n\nexport function StatusBarIndicators({ platform, colorScheme }: StatusBarIndicatorsProps) {\n const fill = colorScheme === \"dark\" ? \"white\" : \"black\";\n if (platform === \"ios\") {\n return (\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n <svg width=\"18\" height=\"10\" viewBox=\"0 0 18 10\">\n <rect x=\"0\" y=\"6\" width=\"3\" height=\"4\" fill={fill} rx=\"1\" />\n <rect x=\"5\" y=\"4\" width=\"3\" height=\"6\" fill={fill} rx=\"1\" />\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"8\" fill={fill} rx=\"1\" />\n <rect x=\"15\" y=\"0\" width=\"3\" height=\"10\" fill={fill} rx=\"1\" />\n </svg>\n <svg width=\"14\" height=\"10\" viewBox=\"0 0 14 10\">\n <path d=\"M7 9.5l3-3a4 4 0 0 0-6 0z\" fill={fill} />\n </svg>\n <svg width=\"26\" height=\"12\" viewBox=\"0 0 26 12\">\n <rect x=\"1\" y=\"1\" width=\"22\" height=\"10\" rx=\"2.5\" fill=\"none\" stroke={fill} strokeWidth=\"1\" />\n <rect x=\"24\" y=\"4\" width=\"1.5\" height=\"4\" rx=\"0.5\" fill={fill} />\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"6\" rx=\"1.5\" fill={fill} />\n </svg>\n </div>\n );\n }\n return (\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n <svg width=\"14\" height=\"10\" viewBox=\"0 0 14 10\">\n <path d=\"M0 9 L14 9 L14 1 Z\" fill={fill} />\n </svg>\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\n <rect x=\"1\" y=\"1\" width=\"16\" height=\"8\" rx=\"1.5\" fill=\"none\" stroke={fill} strokeWidth=\"1\" />\n <rect x=\"18\" y=\"3\" width=\"1.5\" height=\"4\" rx=\"0.5\" fill={fill} />\n <rect x=\"3\" y=\"3\" width=\"12\" height=\"4\" fill={fill} />\n </svg>\n </div>\n );\n}\n","import type { SVGScreenRect } from \"@mmtitanl/tablets\";\nimport { registerCustomDeviceSVG } from \"../registration.js\";\n\nexport interface SVGOverrideEntry {\n deviceId: string;\n name?: string;\n platform?: \"ios\" | \"android\";\n formFactor?: \"tablet\" | \"phone\" | \"foldable\";\n /** Reported logical-pt screen size (independent of SVG viewBox scale). */\n logicalScreenWidth?: number;\n logicalScreenHeight?: number;\n svgString: string;\n bezelTop: number;\n bezelBottom: number;\n bezelLeft: number;\n bezelRight: number;\n screenRect?: SVGScreenRect;\n // Optional landscape variant (separate SVG rendered when device is rotated)\n svgStringLandscape?: string;\n bezelTopLandscape?: number;\n bezelBottomLandscape?: number;\n bezelLeftLandscape?: number;\n bezelRightLandscape?: number;\n screenRectLandscape?: SVGScreenRect;\n updatedAt: string;\n}\n\nconst STORAGE_KEY = \"bielaframe-custom-tablet-svgs\";\n\nexport class CustomSVGStore {\n private storage: Storage | null;\n constructor(storage?: Storage | null) {\n this.storage = storage ?? (typeof localStorage !== \"undefined\" ? localStorage : null);\n }\n\n getAll(): Record<string, SVGOverrideEntry> {\n if (!this.storage) return {};\n try {\n const raw = this.storage.getItem(STORAGE_KEY);\n return raw ? (JSON.parse(raw) as Record<string, SVGOverrideEntry>) : {};\n } catch {\n return {};\n }\n }\n\n save(entry: SVGOverrideEntry): void {\n const all = this.getAll();\n all[entry.deviceId] = entry;\n this.persist(all);\n this.applyEntry(entry);\n }\n\n remove(deviceId: string): void {\n const all = this.getAll();\n delete all[deviceId];\n this.persist(all);\n }\n\n has(deviceId: string): boolean {\n return !!this.getAll()[deviceId];\n }\n\n get(deviceId: string): SVGOverrideEntry | undefined {\n return this.getAll()[deviceId];\n }\n\n applyAll(): void {\n const all = this.getAll();\n Object.values(all).forEach((entry) => this.applyEntry(entry));\n }\n\n private applyEntry(entry: SVGOverrideEntry): void {\n const rawW = entry.screenRect?.width ?? 0;\n const rawH = entry.screenRect?.height ?? 0;\n // Bezels + screenRect are persisted in SVG-viewBox units. If the entry\n // declared a logical screen size (the actual pt size the device reports),\n // uniformly scale everything so the iframe viewport reports logical dims\n // — otherwise the iframe gets a viewport of raw SVG units (huge) and the\n // app renders desktop-style. Uniform scale preserves bezel proportions;\n // the screen height ends up dictated by the SVG screen-rect aspect.\n // Legacy entries (no logicalScreenWidth) get inferred defaults per form\n // factor so they don't render at raw SVG pixel size.\n const FORM_FACTOR_LOGICAL_W: Record<NonNullable<SVGOverrideEntry[\"formFactor\"]>, number> = {\n tablet: 834,\n phone: 390,\n foldable: 374,\n };\n const logicalW =\n entry.logicalScreenWidth ??\n (entry.formFactor ? FORM_FACTOR_LOGICAL_W[entry.formFactor] : rawW);\n const scale = rawW > 0 ? logicalW / rawW : 1;\n\n const sr = entry.screenRect\n ? {\n x: entry.screenRect.x * scale,\n y: entry.screenRect.y * scale,\n width: rawW * scale,\n height: rawH * scale,\n rx: (entry.screenRect.rx ?? 0) * scale,\n rxTop: entry.screenRect.rxTop !== undefined\n ? entry.screenRect.rxTop * scale\n : undefined,\n rxBottom: entry.screenRect.rxBottom !== undefined\n ? entry.screenRect.rxBottom * scale\n : undefined,\n }\n : undefined;\n const portraitBezelTop = entry.bezelTop * scale;\n const portraitBezelBottom = entry.bezelBottom * scale;\n const portraitBezelLeft = entry.bezelLeft * scale;\n const portraitBezelRight = entry.bezelRight * scale;\n const portraitScreenW = sr?.width ?? logicalW;\n const portraitScreenH = sr?.height ?? (entry.logicalScreenHeight ?? rawH);\n\n let landscape: Parameters<typeof registerCustomDeviceSVG>[5];\n if (entry.svgStringLandscape && entry.screenRectLandscape) {\n const lRawW = entry.screenRectLandscape.width;\n const lRawH = entry.screenRectLandscape.height;\n // Landscape's logical width matches portrait's logical height.\n const lScale = lRawW > 0 ? (entry.logicalScreenHeight ?? lRawW) / lRawW : 1;\n const lsr = {\n x: entry.screenRectLandscape.x * lScale,\n y: entry.screenRectLandscape.y * lScale,\n width: lRawW * lScale,\n height: lRawH * lScale,\n rx: (entry.screenRectLandscape.rx ?? 0) * lScale,\n rxTop: entry.screenRectLandscape.rxTop !== undefined\n ? entry.screenRectLandscape.rxTop * lScale\n : undefined,\n rxBottom: entry.screenRectLandscape.rxBottom !== undefined\n ? entry.screenRectLandscape.rxBottom * lScale\n : undefined,\n };\n const lBezelTop = (entry.bezelTopLandscape ?? 0) * lScale;\n const lBezelBottom = (entry.bezelBottomLandscape ?? 0) * lScale;\n const lBezelLeft = (entry.bezelLeftLandscape ?? 0) * lScale;\n const lBezelRight = (entry.bezelRightLandscape ?? 0) * lScale;\n landscape = {\n svgString: entry.svgStringLandscape,\n frame: {\n bezelTop: lBezelTop,\n bezelBottom: lBezelBottom,\n bezelLeft: lBezelLeft,\n bezelRight: lBezelRight,\n totalWidth: lsr.width + lBezelLeft + lBezelRight,\n totalHeight: lsr.height + lBezelTop + lBezelBottom,\n screenWidth: lsr.width,\n screenHeight: lsr.height,\n screenRadius: lsr.rx,\n screenRadiusTop: lsr.rxTop,\n screenRadiusBottom: lsr.rxBottom,\n },\n screenRect: lsr,\n };\n }\n\n registerCustomDeviceSVG(\n entry.deviceId,\n entry.svgString,\n {\n bezelTop: portraitBezelTop,\n bezelBottom: portraitBezelBottom,\n bezelLeft: portraitBezelLeft,\n bezelRight: portraitBezelRight,\n totalWidth: portraitScreenW + portraitBezelLeft + portraitBezelRight,\n totalHeight: portraitScreenH + portraitBezelTop + portraitBezelBottom,\n screenWidth: portraitScreenW,\n screenHeight: portraitScreenH,\n screenRadius: sr?.rx ?? 0,\n screenRadiusTop: sr?.rxTop,\n screenRadiusBottom: sr?.rxBottom,\n },\n undefined,\n sr,\n landscape\n );\n }\n\n private persist(all: Record<string, SVGOverrideEntry>): void {\n if (!this.storage) return;\n try {\n this.storage.setItem(STORAGE_KEY, JSON.stringify(all));\n } catch {\n // ignore\n }\n }\n}\n\nlet singleton: CustomSVGStore | null = null;\nexport function getCustomSVGStore(): CustomSVGStore {\n if (!singleton) singleton = new CustomSVGStore();\n return singleton;\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_tablets","Component","import_react","import_tablets","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_tablets","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/math/scale.ts","../src/hooks/use-container-size.ts","../src/hooks/use-adaptive-scale.ts","../src/hooks/use-device-contract.ts","../src/hooks/use-orientation.ts","../src/hooks/use-volume-control.ts","../src/hooks/use-screen-power.ts","../src/hooks/use-device-frame.ts","../src/messages.ts","../src/hooks/use-fold-state.ts","../src/registration.tsx","../src/components/DeviceFrame.tsx","../src/components/DeviceErrorBoundary.tsx","../src/components/SafeAreaOverlay.tsx","../src/components/ScaleBar.tsx","../src/components/DynamicStatusBar.tsx","../src/components/DeviceCompare.tsx","../src/components/SafeAreaView.tsx","../src/components/VolumeHUD.tsx","../src/components/HardwareButtons.tsx","../src/components/StatusBarIndicators.tsx","../src/storage/custom-svg-store.ts"],"sourcesContent":["// Math\nexport {\n SCALE_STEPS,\n computeAdaptiveScale,\n computeFullScale,\n computeHostSize,\n ptsToPercent,\n ptsToPx,\n pxToPts,\n scaleValue,\n snapToStep,\n} from \"./math/scale.js\";\nexport type { AdaptiveScaleResult } from \"./math/scale.js\";\n\n// Hooks\nexport { useContainerSize } from \"./hooks/use-container-size.js\";\nexport { useAdaptiveScale } from \"./hooks/use-adaptive-scale.js\";\nexport type { UseAdaptiveScaleOptions } from \"./hooks/use-adaptive-scale.js\";\nexport { useDeviceContract } from \"./hooks/use-device-contract.js\";\nexport type { UseDeviceContractResult } from \"./hooks/use-device-contract.js\";\nexport { useOrientation } from \"./hooks/use-orientation.js\";\nexport type { UseOrientationResult } from \"./hooks/use-orientation.js\";\nexport { useVolumeControl } from \"./hooks/use-volume-control.js\";\nexport type { VolumeState } from \"./hooks/use-volume-control.js\";\nexport { useScreenPower } from \"./hooks/use-screen-power.js\";\nexport type { ScreenPowerState } from \"./hooks/use-screen-power.js\";\nexport { useDeviceFrame } from \"./hooks/use-device-frame.js\";\nexport type { DeviceFrameInfo, DeviceFrameInsets } from \"./hooks/use-device-frame.js\";\nexport { useFoldState } from \"./hooks/use-fold-state.js\";\nexport type { FoldState, UseFoldStateResult } from \"./hooks/use-fold-state.js\";\n\n// Messages\nexport { BIELA_PREFIX, isBielaMessage } from \"./messages.js\";\nexport type { BielaColorSchemeMessage, BielaDeviceInfoMessage, BielaRequestMessage } from \"./messages.js\";\n\n// Registration\nexport { registerCustomDeviceSVG, registerDeviceSVG } from \"./registration.js\";\nexport type { SVGCropArea } from \"./registration.js\";\n\n// Components\nexport { DeviceFrame } from \"./components/DeviceFrame.js\";\nexport type { DeviceFrameProps } from \"./components/DeviceFrame.js\";\nexport { DeviceCompare } from \"./components/DeviceCompare.js\";\nexport type { DeviceCompareProps } from \"./components/DeviceCompare.js\";\nexport { DeviceErrorBoundary } from \"./components/DeviceErrorBoundary.js\";\nexport { SafeAreaView } from \"./components/SafeAreaView.js\";\nexport { SafeAreaOverlay } from \"./components/SafeAreaOverlay.js\";\nexport { ScaleBar } from \"./components/ScaleBar.js\";\nexport { VolumeHUD } from \"./components/VolumeHUD.js\";\nexport { HardwareButtons } from \"./components/HardwareButtons.js\";\nexport type { ButtonName } from \"./components/HardwareButtons.js\";\nexport { DynamicStatusBar } from \"./components/DynamicStatusBar.js\";\nexport { StatusBarIndicators } from \"./components/StatusBarIndicators.js\";\n\n// Storage\nexport { CustomSVGStore, getCustomSVGStore } from \"./storage/custom-svg-store.js\";\nexport type { SVGOverrideEntry } from \"./storage/custom-svg-store.js\";\n\n// Re-export important types from @mmtitanl/tablets for convenience\nexport type { SVGScreenRect } from \"@mmtitanl/tablets\";\n","export function ptsToPx(pts: number, dpr: number): number {\n return pts * dpr;\n}\nexport function pxToPts(px: number, dpr: number): number {\n return px / dpr;\n}\nexport function ptsToPercent(pts: number, total: number): number {\n return (pts / total) * 100;\n}\nexport function scaleValue(value: number, scaleFactor: number): number {\n return value * scaleFactor;\n}\n\nexport const SCALE_STEPS = [0.25, 0.33, 0.5, 0.75, 1] as const;\n\nexport function computeAdaptiveScale(\n deviceWidth: number,\n deviceHeight: number,\n containerWidth: number,\n containerHeight: number,\n padding = 24,\n maxScale = 1,\n minScale = 0.1\n): number {\n const availW = Math.max(0, containerWidth - padding * 2);\n const availH = Math.max(0, containerHeight - padding * 2);\n if (availW <= 0 || availH <= 0) return minScale;\n const sx = availW / deviceWidth;\n const sy = availH / deviceHeight;\n const raw = Math.min(sx, sy, maxScale);\n return Math.max(raw, minScale);\n}\n\nexport function snapToStep(raw: number): number {\n const allowed = SCALE_STEPS.filter((s) => s <= raw);\n if (allowed.length === 0) return raw;\n return Math.max(...allowed);\n}\n\nexport function computeHostSize(deviceWidth: number, deviceHeight: number, scale: number) {\n return { width: deviceWidth * scale, height: deviceHeight * scale };\n}\n\nexport interface AdaptiveScaleResult {\n scale: number;\n scaledWidth: number;\n scaledHeight: number;\n deviceWidth: number;\n deviceHeight: number;\n isAtMaxScale: boolean;\n isConstrained: boolean;\n scalePercent: string;\n}\n\nexport function computeFullScale(\n deviceWidth: number,\n deviceHeight: number,\n containerWidth: number,\n containerHeight: number,\n options: { padding?: number; maxScale?: number; minScale?: number; snapToSteps?: boolean } = {}\n): AdaptiveScaleResult {\n const { padding = 24, maxScale = 1, minScale = 0.1, snapToSteps = false } = options;\n const raw = computeAdaptiveScale(deviceWidth, deviceHeight, containerWidth, containerHeight, padding, maxScale, minScale);\n const scale = snapToSteps ? snapToStep(raw) : raw;\n const { width: scaledWidth, height: scaledHeight } = computeHostSize(deviceWidth, deviceHeight, scale);\n return {\n scale,\n scaledWidth,\n scaledHeight,\n deviceWidth,\n deviceHeight,\n isAtMaxScale: scale >= maxScale - 0.0001,\n isConstrained: scale < maxScale - 0.0001,\n scalePercent: `${Math.round(scale * 100)}%`,\n };\n}\n","import { useEffect, useState, type RefObject } from \"react\";\n\nexport interface ContainerSize {\n width: number;\n height: number;\n}\n\nfunction clampToViewport(w: number, h: number): ContainerSize {\n if (typeof window === \"undefined\") return { width: w, height: h };\n const vw = window.visualViewport?.width ?? window.innerWidth;\n const vh = window.visualViewport?.height ?? window.innerHeight;\n return { width: Math.min(w, vw), height: Math.min(h, vh) };\n}\n\nfunction viewportFallback(): ContainerSize {\n if (typeof window === \"undefined\") return { width: 800, height: 600 };\n return {\n width: window.visualViewport?.width ?? window.innerWidth,\n height: window.visualViewport?.height ?? window.innerHeight,\n };\n}\n\nexport function useContainerSize(ref: RefObject<HTMLElement | null>): ContainerSize {\n const [size, setSize] = useState<ContainerSize>(() => viewportFallback());\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n let rafId: number | null = null;\n\n const measure = () => {\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n rafId = null;\n const rect = el.getBoundingClientRect();\n const raw = rect.height > 0 ? { width: rect.width, height: rect.height } : viewportFallback();\n setSize(clampToViewport(raw.width, raw.height));\n });\n };\n\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => {\n ro.disconnect();\n if (rafId !== null) cancelAnimationFrame(rafId);\n };\n }, [ref]);\n\n return size;\n}\n","import { useMemo } from \"react\";\nimport type { DeviceMeta } from \"@mmtitanl/tablets\";\nimport { computeFullScale, type AdaptiveScaleResult } from \"../math/scale.js\";\n\nexport interface UseAdaptiveScaleOptions {\n device: DeviceMeta;\n containerWidth: number;\n containerHeight: number;\n padding?: number;\n maxScale?: number;\n minScale?: number;\n snapToSteps?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n}\n\nexport function useAdaptiveScale(options: UseAdaptiveScaleOptions): AdaptiveScaleResult {\n const {\n device,\n containerWidth,\n containerHeight,\n padding = 24,\n maxScale = 1,\n minScale = 0.1,\n snapToSteps = false,\n orientation = \"portrait\",\n } = options;\n\n return useMemo(() => {\n const dw = orientation === \"portrait\" ? device.screen.width : device.screen.height;\n const dh = orientation === \"portrait\" ? device.screen.height : device.screen.width;\n return computeFullScale(dw, dh, containerWidth, containerHeight, { padding, maxScale, minScale, snapToSteps });\n }, [\n device.screen.width,\n device.screen.height,\n containerWidth,\n containerHeight,\n padding,\n maxScale,\n minScale,\n snapToSteps,\n orientation,\n ]);\n}\n","import { useMemo } from \"react\";\nimport { getDeviceContract, type DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface UseDeviceContractResult {\n contract: DeviceLayoutContract;\n cssVariables: DeviceLayoutContract[\"cssVariables\"];\n contentZone: DeviceLayoutContract[\"contentZone\"][\"portrait\"];\n}\n\nexport function useDeviceContract(\n deviceId: string,\n orientation: \"portrait\" | \"landscape\" = \"portrait\"\n): UseDeviceContractResult {\n return useMemo(() => {\n const contract = getDeviceContract(deviceId, orientation);\n return {\n contract,\n cssVariables: contract.cssVariables,\n contentZone: orientation === \"portrait\" ? contract.contentZone.portrait : contract.contentZone.landscape,\n };\n }, [deviceId, orientation]);\n}\n","import { useCallback, useState } from \"react\";\n\nexport interface UseOrientationResult {\n orientation: \"portrait\" | \"landscape\";\n isLandscape: boolean;\n toggle: () => void;\n setOrientation: (o: \"portrait\" | \"landscape\") => void;\n}\n\n/**\n * Hook for managing tablet orientation state with a toggle function.\n *\n * ```tsx\n * const { orientation, toggle } = useOrientation();\n * <button onClick={toggle}>Rotate</button>\n * <DeviceFrame deviceId=\"ipad-pro-13\" orientation={orientation} />\n * ```\n */\nexport function useOrientation(initial: \"portrait\" | \"landscape\" = \"portrait\"): UseOrientationResult {\n const [orientation, setOrientation] = useState<\"portrait\" | \"landscape\">(initial);\n const toggle = useCallback(() => {\n setOrientation((o) => (o === \"portrait\" ? \"landscape\" : \"portrait\"));\n }, []);\n return { orientation, isLandscape: orientation === \"landscape\", toggle, setOrientation };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nconst STEPS = 16;\n\nexport interface VolumeState {\n level: number;\n muted: boolean;\n hudVisible: boolean;\n volumeUp: () => void;\n volumeDown: () => void;\n toggleMute: () => void;\n}\n\nfunction applyToMedia(level: number, muted: boolean) {\n if (typeof document === \"undefined\") return;\n const nodes = document.querySelectorAll<HTMLMediaElement>(\".bielaframe-content audio, .bielaframe-content video\");\n nodes.forEach((el) => {\n el.volume = Math.max(0, Math.min(1, level));\n el.muted = muted;\n });\n}\n\nexport function useVolumeControl(initialVolume = 0.5): VolumeState {\n const [level, setLevel] = useState(initialVolume);\n const [muted, setMuted] = useState(false);\n const [hudVisible, setHudVisible] = useState(false);\n const timer = useRef<number | null>(null);\n\n const flashHUD = useCallback(() => {\n setHudVisible(true);\n if (timer.current) window.clearTimeout(timer.current);\n timer.current = window.setTimeout(() => setHudVisible(false), 1500);\n }, []);\n\n const volumeUp = useCallback(() => {\n setLevel((l) => Math.min(1, l + 1 / STEPS));\n flashHUD();\n }, [flashHUD]);\n const volumeDown = useCallback(() => {\n setLevel((l) => Math.max(0, l - 1 / STEPS));\n flashHUD();\n }, [flashHUD]);\n const toggleMute = useCallback(() => {\n setMuted((m) => !m);\n flashHUD();\n }, [flashHUD]);\n\n useEffect(() => {\n applyToMedia(level, muted);\n }, [level, muted]);\n\n return { level, muted, hudVisible, volumeUp, volumeDown, toggleMute };\n}\n","import { useCallback, useState } from \"react\";\n\nexport interface ScreenPowerState {\n isOff: boolean;\n toggle: () => void;\n}\n\nexport function useScreenPower(): ScreenPowerState {\n const [isOff, setIsOff] = useState(false);\n const toggle = useCallback(() => setIsOff((v) => !v), []);\n return { isOff, toggle };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { isBielaMessage, type BielaDeviceInfoMessage } from \"../messages.js\";\n\nexport interface DeviceFrameInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nexport interface DeviceFrameInfo {\n insets: DeviceFrameInsets;\n vars: Record<string, string>;\n platform: \"ios\" | \"android\" | null;\n deviceId: string | null;\n orientation: \"portrait\" | \"landscape\" | null;\n isReady: boolean;\n reportColorScheme: (scheme: \"light\" | \"dark\") => void;\n}\n\nfunction parsePx(value: string | undefined): number {\n if (!value) return 0;\n const n = parseFloat(value);\n return Number.isFinite(n) ? n : 0;\n}\n\nexport function useDeviceFrame(): DeviceFrameInfo {\n const [vars, setVars] = useState<Record<string, string>>({});\n const [platform, setPlatform] = useState<\"ios\" | \"android\" | null>(null);\n const [deviceId, setDeviceId] = useState<string | null>(null);\n const [orientation, setOrientation] = useState<\"portrait\" | \"landscape\" | null>(null);\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handler = (event: MessageEvent) => {\n if (!isBielaMessage(event.data)) return;\n if (event.data.type === \"biela:deviceInfo\") {\n const msg = event.data as BielaDeviceInfoMessage;\n setVars(msg.payload.vars);\n setPlatform(msg.payload.platform);\n setDeviceId(msg.payload.deviceId);\n setOrientation(msg.payload.orientation);\n setIsReady(true);\n }\n };\n window.addEventListener(\"message\", handler);\n window.parent?.postMessage({ type: \"biela:requestDeviceInfo\" }, \"*\");\n return () => window.removeEventListener(\"message\", handler);\n }, []);\n\n const reportColorScheme = useCallback((scheme: \"light\" | \"dark\") => {\n if (typeof window === \"undefined\") return;\n window.parent?.postMessage({ type: \"biela:colorScheme\", payload: { scheme } }, \"*\");\n }, []);\n\n const insets: DeviceFrameInsets = {\n top: parsePx(vars[\"--safe-top\"]),\n bottom: parsePx(vars[\"--safe-bottom\"]),\n left: parsePx(vars[\"--safe-left\"]),\n right: parsePx(vars[\"--safe-right\"]),\n };\n\n return { insets, vars, platform, deviceId, orientation, isReady, reportColorScheme };\n}\n","export const BIELA_PREFIX = \"biela:\" as const;\n\nexport interface BielaDeviceInfoMessage {\n type: \"biela:deviceInfo\";\n payload: {\n vars: Record<string, string>;\n platform: \"ios\" | \"android\";\n deviceId: string;\n orientation: \"portrait\" | \"landscape\";\n };\n}\nexport interface BielaRequestMessage {\n type: \"biela:requestDeviceInfo\";\n}\nexport interface BielaColorSchemeMessage {\n type: \"biela:colorScheme\";\n payload: { scheme: \"light\" | \"dark\" };\n}\n\nexport function isBielaMessage(data: unknown): data is { type: string } {\n return (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n typeof (data as { type: unknown }).type === \"string\" &&\n (data as { type: string }).type.startsWith(BIELA_PREFIX)\n );\n}\n","import { useState, useCallback } from \"react\";\n\nexport type FoldState = \"folded\" | \"open\";\n\nexport interface UseFoldStateResult {\n foldState: FoldState;\n isOpen: boolean;\n deviceId: string;\n toggle: () => void;\n setFoldState: (state: FoldState) => void;\n}\n\n/**\n * Manages fold state for foldable tablet devices.\n * Convention: the open variant uses `${baseDeviceId}-open`.\n */\nexport function useFoldState(\n baseDeviceId: string,\n initial: FoldState = \"folded\"\n): UseFoldStateResult {\n const [foldState, setFoldStateRaw] = useState<FoldState>(initial);\n\n const toggle = useCallback(() => {\n setFoldStateRaw((s) => (s === \"folded\" ? \"open\" : \"folded\"));\n }, []);\n\n const setFoldState = useCallback((state: FoldState) => {\n setFoldStateRaw(state);\n }, []);\n\n const isOpen = foldState === \"open\";\n const deviceId = isOpen ? `${baseDeviceId}-open` : baseDeviceId;\n\n return { foldState, isOpen, deviceId, toggle, setFoldState };\n}\n","import type { ComponentType, CSSProperties } from \"react\";\nimport { scopeSVGIds, type SVGScreenRect } from \"@mmtitanl/tablets\";\n\nexport type DeviceSVGComponent = ComponentType<{\n colorScheme?: \"light\" | \"dark\";\n style?: CSSProperties;\n}>;\n\nexport interface FrameInfo {\n bezelTop: number;\n bezelBottom: number;\n bezelLeft: number;\n bezelRight: number;\n totalWidth: number;\n totalHeight: number;\n screenWidth: number;\n screenHeight: number;\n screenRadius: number;\n /** Optional per-edge overrides. Fall back to screenRadius when unset. */\n screenRadiusTop?: number;\n screenRadiusBottom?: number;\n}\n\nexport interface SVGCropArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface LandscapeSVGRegistration {\n svgString: string;\n frame: FrameInfo;\n cropViewBox?: SVGCropArea;\n screenRect?: SVGScreenRect;\n}\n\nexport interface LandscapeBuiltinRegistration {\n component: DeviceSVGComponent;\n frame: FrameInfo;\n screenRect?: SVGScreenRect;\n}\n\ninterface RegistryEntry {\n component: DeviceSVGComponent;\n frame: FrameInfo;\n screenRect?: SVGScreenRect;\n landscapeComponent?: DeviceSVGComponent;\n landscapeFrame?: FrameInfo;\n landscapeScreenRect?: SVGScreenRect;\n}\n\nconst SVG_REGISTRY = new Map<string, RegistryEntry>();\n\nexport function registerDeviceSVG(\n deviceId: string,\n component: DeviceSVGComponent,\n frame: FrameInfo,\n screenRect?: SVGScreenRect,\n landscape?: LandscapeBuiltinRegistration\n): void {\n SVG_REGISTRY.set(deviceId, {\n component,\n frame,\n screenRect,\n landscapeComponent: landscape?.component,\n landscapeFrame: landscape?.frame,\n landscapeScreenRect: landscape?.screenRect,\n });\n}\n\nexport function getDeviceSVG(deviceId: string): RegistryEntry | undefined {\n return SVG_REGISTRY.get(deviceId);\n}\n\nfunction readSVGViewBox(svg: string): { x: number; y: number; w: number; h: number } | null {\n const vb = svg.match(/viewBox\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (vb) {\n const parts = vb[1].split(/[\\s,]+/).map(Number);\n if (parts.length === 4 && parts.every((n) => Number.isFinite(n))) {\n return { x: parts[0], y: parts[1], w: parts[2], h: parts[3] };\n }\n }\n const wm = svg.match(/<svg\\b[^>]*\\swidth\\s*=\\s*[\"']([\\d.]+)/i);\n const hm = svg.match(/<svg\\b[^>]*\\sheight\\s*=\\s*[\"']([\\d.]+)/i);\n if (wm && hm) return { x: 0, y: 0, w: parseFloat(wm[1]), h: parseFloat(hm[1]) };\n return null;\n}\n\n// Inject a <mask> into the SVG so the screen rectangle becomes transparent.\n// Works for ANY SVG (Figma exports with opaque screens, hand-built ones,\n// whatever). The frame is in scaled/logical space; we convert to viewBox\n// space so the mask aligns with the SVG content.\nfunction injectScreenMask(svg: string, frame: FrameInfo, suffix: string): string {\n if (frame.totalWidth <= 0 || frame.totalHeight <= 0) return svg;\n if (frame.screenWidth <= 0 || frame.screenHeight <= 0) return svg;\n const vb = readSVGViewBox(svg);\n if (!vb) return svg;\n\n // frame is in scaled units; SVG content is in viewBox units. Convert.\n const sx = vb.w / frame.totalWidth;\n const sy = vb.h / frame.totalHeight;\n const x = vb.x + frame.bezelLeft * sx;\n const y = vb.y + frame.bezelTop * sy;\n const w = frame.screenWidth * sx;\n const h = frame.screenHeight * sy;\n const rt = Math.max(0, (frame.screenRadiusTop ?? frame.screenRadius)) * Math.min(sx, sy);\n const rb = Math.max(0, (frame.screenRadiusBottom ?? frame.screenRadius)) * Math.min(sx, sy);\n\n const maskId = `biela-screen-mask-${suffix || \"default\"}`;\n const innerPath = `M${x + rt},${y} H${x + w - rt} a${rt},${rt} 0 0 1 ${rt},${rt} V${y + h - rb} a${rb},${rb} 0 0 1 ${-rb},${rb} H${x + rb} a${rb},${rb} 0 0 1 ${-rb},${-rb} V${y + rt} a${rt},${rt} 0 0 1 ${rt},${-rt} Z`;\n const maskDef = `<defs><mask id=\"${maskId}\" maskUnits=\"userSpaceOnUse\" x=\"${vb.x}\" y=\"${vb.y}\" width=\"${vb.w}\" height=\"${vb.h}\"><rect x=\"${vb.x}\" y=\"${vb.y}\" width=\"${vb.w}\" height=\"${vb.h}\" fill=\"white\"/><path d=\"${innerPath}\" fill=\"black\"/></mask></defs>`;\n\n // Insert the mask def + open a masked group right after the <svg> tag.\n let result = svg.replace(/(<svg\\b[^>]*>)/i, (m) => `${m}${maskDef}<g mask=\"url(#${maskId})\">`);\n // Close the masked group right before </svg>.\n result = result.replace(/<\\/svg\\s*>/i, `</g></svg>`);\n return result;\n}\n\nfunction buildCustomComponent(\n deviceId: string,\n svgString: string,\n cropViewBox: SVGCropArea | undefined,\n suffix: string,\n frame?: FrameInfo,\n dieCut = false\n): DeviceSVGComponent {\n const scopeKey = suffix ? `${deviceId}${suffix}` : deviceId;\n let svg = scopeSVGIds(svgString, scopeKey);\n if (cropViewBox) {\n svg = svg.replace(\n /<svg\\b([^>]*)>/i,\n (_m, attrs: string) => {\n const stripped = attrs\n .replace(/\\sviewBox\\s*=\\s*[\"'][^\"']*[\"']/i, \"\")\n .replace(/\\swidth\\s*=\\s*[\"'][^\"']*[\"']/i, \"\")\n .replace(/\\sheight\\s*=\\s*[\"'][^\"']*[\"']/i, \"\");\n return `<svg${stripped} viewBox=\"${cropViewBox.x} ${cropViewBox.y} ${cropViewBox.width} ${cropViewBox.height}\" width=\"100%\" height=\"100%\">`;\n }\n );\n } else {\n svg = svg.replace(\n /<svg\\b([^>]*)>/i,\n (_m, attrs: string) => {\n const stripped = attrs.replace(/\\swidth\\s*=\\s*[\"'][^\"']*[\"']/i, \"\").replace(/\\sheight\\s*=\\s*[\"'][^\"']*[\"']/i, \"\");\n return `<svg${stripped} width=\"100%\" height=\"100%\">`;\n }\n );\n }\n\n // Die-cut is OPT-IN. By default the raw SVG renders untouched on top of the\n // iframe — the iframe shows through wherever the SVG's screen area is already\n // transparent, and painted overlays (clock, Dynamic Island, battery) stay on\n // top. Only opaque-screen SVGs need the mask; enable it via dieCutScreen.\n if (frame && dieCut) svg = injectScreenMask(svg, frame, scopeKey);\n\n const Component: DeviceSVGComponent = ({ style }) => (\n <span\n style={{ display: \"block\", width: \"100%\", height: \"100%\", ...style }}\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n );\n Component.displayName = `CustomDeviceSVG(${scopeKey})`;\n return Component;\n}\n\nexport function registerCustomDeviceSVG(\n deviceId: string,\n svgString: string,\n frame: FrameInfo,\n cropViewBox?: SVGCropArea,\n screenRect?: SVGScreenRect,\n landscape?: LandscapeSVGRegistration,\n options?: { dieCutScreen?: boolean }\n): void {\n const dieCut = options?.dieCutScreen ?? false;\n const portraitComponent = buildCustomComponent(deviceId, svgString, cropViewBox, \"\", frame, dieCut);\n const landscapeComponent = landscape\n ? buildCustomComponent(deviceId, landscape.svgString, landscape.cropViewBox, \"-landscape\", landscape.frame, dieCut)\n : undefined;\n\n SVG_REGISTRY.set(deviceId, {\n component: portraitComponent,\n frame,\n screenRect,\n landscapeComponent,\n landscapeFrame: landscape?.frame,\n landscapeScreenRect: landscape?.screenRect,\n });\n}\n","import { useEffect, useMemo, useRef, useState, type ReactNode, type RefObject } from \"react\";\nimport {\n getDeviceContract,\n getDeviceMetadata,\n type DeviceLayoutContract,\n} from \"@mmtitanl/tablets\";\nimport { computeFullScale, type AdaptiveScaleResult } from \"../math/scale.js\";\nimport { useContainerSize } from \"../hooks/use-container-size.js\";\nimport { DeviceErrorBoundary } from \"./DeviceErrorBoundary.js\";\nimport { SafeAreaOverlay } from \"./SafeAreaOverlay.js\";\nimport { ScaleBar } from \"./ScaleBar.js\";\nimport { DynamicStatusBar } from \"./DynamicStatusBar.js\";\nimport { getDeviceSVG, type DeviceSVGComponent } from \"../registration.js\";\nimport {\n // Tablets\n IPadPro13SVG, IPAD_PRO_13_FRAME, IPAD_PRO_13_SCREEN_RECT,\n IPadPro11SVG, IPAD_PRO_11_FRAME, IPAD_PRO_11_SCREEN_RECT,\n IPadAir13SVG, IPAD_AIR_13_FRAME, IPAD_AIR_13_SCREEN_RECT,\n IPadAir11SVG, IPAD_AIR_11_FRAME, IPAD_AIR_11_SCREEN_RECT,\n IPadMini7SVG, IPAD_MINI_7_FRAME, IPAD_MINI_7_SCREEN_RECT,\n GalaxyTabS10SVG, GALAXY_TAB_S10_FRAME, GALAXY_TAB_S10_SCREEN_RECT,\n GalaxyTabS10UltraSVG, GALAXY_TAB_S10_ULTRA_FRAME, GALAXY_TAB_S10_ULTRA_SCREEN_RECT,\n GalaxyTabS10FeSVG, GALAXY_TAB_S10_FE_FRAME, GALAXY_TAB_S10_FE_SCREEN_RECT,\n // Phones — iOS\n IPhone17ProMaxSVG, IPHONE_17_PRO_MAX_FRAME, IPHONE_17_PRO_MAX_SCREEN_RECT,\n IPhone17ProSVG, IPHONE_17_PRO_FRAME, IPHONE_17_PRO_SCREEN_RECT,\n IPhoneAirSVG, IPHONE_AIR_FRAME, IPHONE_AIR_SCREEN_RECT,\n IPhone16SVG, IPHONE_16_FRAME, IPHONE_16_SCREEN_RECT,\n IPhone16eSVG, IPHONE_16E_FRAME, IPHONE_16E_SCREEN_RECT,\n IPhoneSE3SVG, IPHONE_SE_3_FRAME, IPHONE_SE_3_SCREEN_RECT,\n // Phones — Android\n GalaxyS25SVG, GALAXY_S25_FRAME, GALAXY_S25_SCREEN_RECT,\n GalaxyS25EdgeSVG, GALAXY_S25_EDGE_FRAME,\n GalaxyS25UltraSVG, GALAXY_S25_ULTRA_FRAME, GALAXY_S25_ULTRA_SCREEN_RECT,\n Pixel9ProSVG, PIXEL_9_PRO_FRAME, PIXEL_9_PRO_SCREEN_RECT,\n Pixel9ProXLSVG, PIXEL_9_PRO_XL_FRAME, PIXEL_9_PRO_XL_SCREEN_RECT,\n // Foldables\n GalaxyZFold7SVG, GALAXY_Z_FOLD_7_FRAME, GALAXY_Z_FOLD_7_SCREEN_RECT,\n GalaxyZFold7OpenSVG, GALAXY_Z_FOLD_7_OPEN_FRAME, GALAXY_Z_FOLD_7_OPEN_SCREEN_RECT,\n // User-added custom devices baked into the package\n CUSTOM_DEVICES,\n} from \"@mmtitanl/tablets\";\nimport { registerDeviceSVG } from \"../registration.js\";\n\nlet didAutoRegister = false;\nfunction ensureBuiltinsRegistered() {\n if (didAutoRegister) return;\n // Tablets\n registerDeviceSVG(\"ipad-pro-13\", IPadPro13SVG as DeviceSVGComponent, IPAD_PRO_13_FRAME, IPAD_PRO_13_SCREEN_RECT);\n registerDeviceSVG(\"ipad-pro-11\", IPadPro11SVG as DeviceSVGComponent, IPAD_PRO_11_FRAME, IPAD_PRO_11_SCREEN_RECT);\n registerDeviceSVG(\"ipad-air-13\", IPadAir13SVG as DeviceSVGComponent, IPAD_AIR_13_FRAME, IPAD_AIR_13_SCREEN_RECT);\n registerDeviceSVG(\"ipad-air-11\", IPadAir11SVG as DeviceSVGComponent, IPAD_AIR_11_FRAME, IPAD_AIR_11_SCREEN_RECT);\n registerDeviceSVG(\"ipad-mini-7\", IPadMini7SVG as DeviceSVGComponent, IPAD_MINI_7_FRAME, IPAD_MINI_7_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10\", GalaxyTabS10SVG as DeviceSVGComponent, GALAXY_TAB_S10_FRAME, GALAXY_TAB_S10_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10-ultra\", GalaxyTabS10UltraSVG as DeviceSVGComponent, GALAXY_TAB_S10_ULTRA_FRAME, GALAXY_TAB_S10_ULTRA_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-tab-s10-fe\", GalaxyTabS10FeSVG as DeviceSVGComponent, GALAXY_TAB_S10_FE_FRAME, GALAXY_TAB_S10_FE_SCREEN_RECT);\n // Phones — iOS\n registerDeviceSVG(\"iphone-17-pro-max\", IPhone17ProMaxSVG as DeviceSVGComponent, IPHONE_17_PRO_MAX_FRAME, IPHONE_17_PRO_MAX_SCREEN_RECT);\n registerDeviceSVG(\"iphone-17-pro\", IPhone17ProSVG as DeviceSVGComponent, IPHONE_17_PRO_FRAME, IPHONE_17_PRO_SCREEN_RECT);\n registerDeviceSVG(\"iphone-air\", IPhoneAirSVG as DeviceSVGComponent, IPHONE_AIR_FRAME, IPHONE_AIR_SCREEN_RECT);\n registerDeviceSVG(\"iphone-16\", IPhone16SVG as DeviceSVGComponent, IPHONE_16_FRAME, IPHONE_16_SCREEN_RECT);\n registerDeviceSVG(\"iphone-16e\", IPhone16eSVG as DeviceSVGComponent, IPHONE_16E_FRAME, IPHONE_16E_SCREEN_RECT);\n registerDeviceSVG(\"iphone-se-3\", IPhoneSE3SVG as DeviceSVGComponent, IPHONE_SE_3_FRAME, IPHONE_SE_3_SCREEN_RECT);\n // Phones — Android\n registerDeviceSVG(\"galaxy-s25\", GalaxyS25SVG as DeviceSVGComponent, GALAXY_S25_FRAME, GALAXY_S25_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-s25-edge\", GalaxyS25EdgeSVG as DeviceSVGComponent, GALAXY_S25_EDGE_FRAME);\n registerDeviceSVG(\"galaxy-s25-ultra\", GalaxyS25UltraSVG as DeviceSVGComponent, GALAXY_S25_ULTRA_FRAME, GALAXY_S25_ULTRA_SCREEN_RECT);\n registerDeviceSVG(\"pixel-9-pro\", Pixel9ProSVG as DeviceSVGComponent, PIXEL_9_PRO_FRAME, PIXEL_9_PRO_SCREEN_RECT);\n registerDeviceSVG(\"pixel-9-pro-xl\", Pixel9ProXLSVG as DeviceSVGComponent, PIXEL_9_PRO_XL_FRAME, PIXEL_9_PRO_XL_SCREEN_RECT);\n // Foldables\n registerDeviceSVG(\"galaxy-z-fold-7\", GalaxyZFold7SVG as DeviceSVGComponent, GALAXY_Z_FOLD_7_FRAME, GALAXY_Z_FOLD_7_SCREEN_RECT);\n registerDeviceSVG(\"galaxy-z-fold-7-open\", GalaxyZFold7OpenSVG as DeviceSVGComponent, GALAXY_Z_FOLD_7_OPEN_FRAME, GALAXY_Z_FOLD_7_OPEN_SCREEN_RECT);\n // User-added custom devices, persisted in @mmtitanl/tablets src/custom/data.json\n for (const c of CUSTOM_DEVICES) {\n registerDeviceSVG(\n c.meta.id,\n c.Component as DeviceSVGComponent,\n c.frame,\n c.screenRect,\n c.LandscapeComponent && c.landscape\n ? { component: c.LandscapeComponent as DeviceSVGComponent, frame: c.landscape.frame, screenRect: c.landscape.screenRect }\n : undefined\n );\n }\n didAutoRegister = true;\n}\n\nexport interface DeviceFrameProps {\n device?: string;\n deviceId?: string;\n orientation?: \"portrait\" | \"landscape\";\n scaleMode?: \"fit\" | \"manual\" | \"steps\";\n manualScale?: number;\n showSafeAreaOverlay?: boolean;\n showDLCPanel?: boolean;\n showScaleBar?: boolean;\n showStatusBar?: boolean;\n colorScheme?: \"light\" | \"dark\";\n iframeRef?: RefObject<HTMLIFrameElement | null>;\n onColorSchemeChange?: (scheme: \"light\" | \"dark\") => void;\n onContractReady?: (dlc: DeviceLayoutContract) => void;\n onScaleChange?: (scale: number) => void;\n children?: ReactNode;\n}\n\nfunction sendDeviceInfo(\n iframe: HTMLIFrameElement | null,\n contract: DeviceLayoutContract,\n orientation: \"portrait\" | \"landscape\"\n) {\n if (!iframe?.contentWindow) return;\n iframe.contentWindow.postMessage(\n {\n type: \"biela:deviceInfo\",\n payload: {\n vars: contract.cssVariables,\n platform: contract.device.platform,\n deviceId: contract.device.id,\n orientation,\n },\n },\n \"*\"\n );\n}\n\nexport function DeviceFrame({\n device,\n deviceId,\n orientation = \"portrait\",\n scaleMode = \"fit\",\n manualScale = 1,\n showSafeAreaOverlay = false,\n showScaleBar = true,\n // Implicit oprit: SVG-urile device-urilor au status bar-ul desenat în ramă\n // (ceas, semnal, baterie); cel sintetic ar apărea dublat peste conținut.\n showStatusBar = false,\n colorScheme = \"light\",\n iframeRef,\n onColorSchemeChange,\n onContractReady,\n onScaleChange,\n children,\n}: DeviceFrameProps) {\n ensureBuiltinsRegistered();\n\n const resolvedId = device ?? deviceId;\n if (!resolvedId) throw new Error(\"DeviceFrame requires `device` or `deviceId`\");\n\n const meta = getDeviceMetadata(resolvedId);\n const contract = useMemo(() => getDeviceContract(resolvedId, orientation), [resolvedId, orientation]);\n\n const portW = meta.screen.width;\n const portH = meta.screen.height;\n const rotateFrame = orientation === \"landscape\";\n // Content dimensions swap for landscape.\n const dw = rotateFrame ? portH : portW;\n const dh = rotateFrame ? portW : portH;\n\n const sentinelRef = useRef<HTMLDivElement>(null);\n const frameContainerRef = useRef<HTMLDivElement>(null);\n const containerSize = useContainerSize(sentinelRef);\n\n const svgEntryEarly = getDeviceSVG(resolvedId);\n const portraitFrameEarly = svgEntryEarly?.frame;\n const landscapeFrameEarly = svgEntryEarly?.landscapeFrame;\n const hasLandscapeSVGEarly = !!svgEntryEarly?.landscapeComponent && !!landscapeFrameEarly;\n // Active frame total dims drive the host box.\n // - With 2-SVG: pick the matching frame for the current orientation.\n // - With 1-SVG (rotated): swap portrait dims when landscape.\n const fitW = portraitFrameEarly\n ? (rotateFrame\n ? (hasLandscapeSVGEarly ? landscapeFrameEarly!.totalWidth : portraitFrameEarly.totalHeight)\n : portraitFrameEarly.totalWidth)\n : (rotateFrame ? portH : portW);\n const fitH = portraitFrameEarly\n ? (rotateFrame\n ? (hasLandscapeSVGEarly ? landscapeFrameEarly!.totalHeight : portraitFrameEarly.totalWidth)\n : portraitFrameEarly.totalHeight)\n : (rotateFrame ? portW : portH);\n\n const fitResult: AdaptiveScaleResult = useMemo(\n () =>\n computeFullScale(fitW, fitH, containerSize.width, containerSize.height, {\n snapToSteps: scaleMode === \"steps\",\n }),\n [fitW, fitH, containerSize.width, containerSize.height, scaleMode]\n );\n\n const [overrideScale, setOverrideScale] = useState<number | null>(null);\n\n useEffect(() => {\n setOverrideScale(null);\n }, [orientation]);\n\n const scale =\n scaleMode === \"manual\" ? manualScale : overrideScale ?? fitResult.scale;\n const hostWidth = fitW * scale;\n const hostHeight = fitH * scale;\n const isAtMaxScale = scale >= 0.9999;\n\n useEffect(() => {\n onContractReady?.(contract);\n }, [contract, onContractReady]);\n\n useEffect(() => {\n onScaleChange?.(scale);\n }, [scale, onScaleChange]);\n\n useEffect(() => {\n if (!iframeRef?.current) return;\n sendDeviceInfo(iframeRef.current, contract, orientation);\n const onLoad = () => sendDeviceInfo(iframeRef.current, contract, orientation);\n iframeRef.current.addEventListener(\"load\", onLoad);\n return () => iframeRef.current?.removeEventListener(\"load\", onLoad);\n }, [iframeRef, contract, orientation]);\n\n useEffect(() => {\n if (!iframeRef) return;\n const handler = (event: MessageEvent) => {\n const data = event.data as { type?: string; payload?: { scheme?: \"light\" | \"dark\" } } | null;\n if (!data || typeof data !== \"object\") return;\n if (data.type === \"biela:requestDeviceInfo\") {\n sendDeviceInfo(iframeRef.current, contract, orientation);\n } else if (data.type === \"biela:colorScheme\" && data.payload?.scheme) {\n onColorSchemeChange?.(data.payload.scheme);\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }, [iframeRef, contract, orientation, onColorSchemeChange]);\n\n const svgEntry = getDeviceSVG(resolvedId);\n const SVGComponent: DeviceSVGComponent | null = svgEntry?.component ?? null;\n const portraitFrame = svgEntry?.frame;\n const LandscapeSVGComponent: DeviceSVGComponent | null = svgEntry?.landscapeComponent ?? null;\n const landscapeFrame = svgEntry?.landscapeFrame;\n const hasLandscapeSVG = !!LandscapeSVGComponent && !!landscapeFrame;\n\n const cssVarsStyle = contract.cssVariables as unknown as React.CSSProperties;\n\n // For 2-SVG devices, use a stable container sized to the maximum of portrait and\n // landscape frame dims. scalerW/scalerH never change between orientations — no layout\n // jump, no rotation tricks. The host clips to the correct visible rectangle via\n // overflow:hidden. For single-SVG devices the rotation fallback is unchanged.\n const activeFrame = hasLandscapeSVG && rotateFrame ? landscapeFrame! : portraitFrame;\n const scalerW = hasLandscapeSVG\n ? Math.max(portraitFrame?.totalWidth ?? dw, landscapeFrame?.totalWidth ?? dh)\n : (activeFrame?.totalWidth ?? (rotateFrame ? portW : dw));\n const scalerH = hasLandscapeSVG\n ? Math.max(portraitFrame?.totalHeight ?? dh, landscapeFrame?.totalHeight ?? dw)\n : (activeFrame?.totalHeight ?? (rotateFrame ? portH : dh));\n const contentBezelLeft = activeFrame?.bezelLeft ?? 0;\n const contentBezelTop = activeFrame?.bezelTop ?? 0;\n const contentScreenW = activeFrame?.screenWidth ?? dw;\n const contentScreenH = activeFrame?.screenHeight ?? dh;\n\n const useRotationFallback = rotateFrame && !hasLandscapeSVG;\n const scalerTransform = useRotationFallback\n ? `scale(${scale}) translate(0px, ${scalerW}px) rotate(-90deg)`\n : `scale(${scale})`;\n\n return (\n <div\n ref={sentinelRef}\n className=\"bielaframe-sentinel\"\n style={{ width: \"100%\", height: \"100%\", display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", overflow: \"hidden\" }}\n >\n <div\n className=\"bielaframe-host\"\n style={{\n width: hostWidth,\n height: hostHeight,\n position: \"relative\",\n flexShrink: 0,\n overflow: \"hidden\",\n transition: \"width 400ms cubic-bezier(0.4, 0, 0.2, 1), height 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <div\n className=\"bielaframe-scaler\"\n ref={frameContainerRef}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: scalerW,\n height: scalerH,\n transform: scalerTransform,\n transformOrigin: \"top left\",\n willChange: \"transform\",\n transition: \"transform 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n {/* iframe content: FIRST in DOM → naturally behind. Positioned\n as a percentage of the scaler so it always lands exactly on the\n SVG's screen-rect regardless of total dims. Rounded corners\n match screenRadius. */}\n <div\n className=\"bielaframe-content\"\n style={{\n position: \"absolute\",\n left: `${(contentBezelLeft / scalerW) * 100}%`,\n top: `${(contentBezelTop / scalerH) * 100}%`,\n width: `${(contentScreenW / scalerW) * 100}%`,\n height: `${(contentScreenH / scalerH) * 100}%`,\n overflow: \"hidden\",\n zIndex: 0,\n background: colorScheme === \"dark\" ? \"#000\" : \"#fff\",\n borderRadius: activeFrame?.screenRadius ?? 0,\n ...cssVarsStyle,\n }}\n >\n <DeviceErrorBoundary>{children}</DeviceErrorBoundary>\n {showStatusBar && (\n <DynamicStatusBar contract={contract} orientation={orientation} colorScheme={colorScheme} />\n )}\n {showSafeAreaOverlay && <SafeAreaOverlay contract={contract} orientation={orientation} />}\n </div>\n\n {/* SVG bezel: LAST in DOM → naturally on top via DOM order.\n pointer-events:none so clicks pass through to iframe. Elements\n drawn in the SVG (clock, wifi, battery, notch) appear over the\n iframe. Transparent areas of the SVG let the iframe show through. */}\n {SVGComponent && portraitFrame && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: portraitFrame.totalWidth,\n height: portraitFrame.totalHeight,\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: hasLandscapeSVG && rotateFrame ? 0 : 1,\n transition: \"opacity 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <SVGComponent\n colorScheme={colorScheme}\n style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\" }}\n />\n </div>\n )}\n\n {hasLandscapeSVG && LandscapeSVGComponent && landscapeFrame && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: landscapeFrame.totalWidth,\n height: landscapeFrame.totalHeight,\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: rotateFrame ? 1 : 0,\n transition: \"opacity 400ms cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n <LandscapeSVGComponent\n colorScheme={colorScheme}\n style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\" }}\n />\n </div>\n )}\n </div>\n </div>\n\n {showScaleBar && (\n <ScaleBar\n deviceName={meta.name}\n deviceWidth={dw}\n deviceHeight={dh}\n scale={scale}\n scalePercent={`${Math.round(scale * 100)}%`}\n isAtMaxScale={isAtMaxScale}\n isConstrained={!isAtMaxScale}\n onScaleChange={(s) => setOverrideScale(s)}\n onFit={() => setOverrideScale(null)}\n onRealSize={() => setOverrideScale(1)}\n />\n )}\n </div>\n );\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class DeviceErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n console.error(\"[BielaFrame] device content crashed\", error, errorInfo);\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n return (\n this.props.fallback ?? (\n <div\n style={{\n padding: 20,\n fontFamily: \"system-ui\",\n color: \"#ff453a\",\n background: \"#1c1c1e\",\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n textAlign: \"center\",\n }}\n >\n <div>\n <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 8 }}>Component crashed</div>\n <div style={{ fontSize: 12, opacity: 0.8 }}>{this.state.error?.message}</div>\n </div>\n </div>\n )\n );\n }\n return this.props.children;\n }\n}\n","import type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface SafeAreaOverlayProps {\n contract: DeviceLayoutContract;\n orientation: \"portrait\" | \"landscape\";\n}\n\nexport function SafeAreaOverlay({ contract, orientation }: SafeAreaOverlayProps) {\n const safe = orientation === \"portrait\" ? contract.safeArea.portrait : contract.safeArea.landscape;\n const w = orientation === \"portrait\" ? contract.screen.width : contract.screen.height;\n const h = orientation === \"portrait\" ? contract.screen.height : contract.screen.width;\n const baseStyle = { position: \"absolute\" as const, pointerEvents: \"none\" as const };\n return (\n <>\n <div style={{ ...baseStyle, top: 0, left: 0, right: 0, height: safe.top, background: \"rgba(255,69,58,0.25)\" }} />\n <div\n style={{ ...baseStyle, bottom: 0, left: 0, right: 0, height: safe.bottom, background: \"rgba(255,69,58,0.25)\" }}\n />\n <div style={{ ...baseStyle, top: 0, left: 0, bottom: 0, width: safe.left, background: \"rgba(255,69,58,0.25)\" }} />\n <div\n style={{ ...baseStyle, top: 0, right: 0, bottom: 0, width: safe.right, background: \"rgba(255,69,58,0.25)\" }}\n />\n <div\n style={{\n ...baseStyle,\n top: safe.top,\n bottom: safe.bottom,\n left: safe.left,\n right: safe.right,\n outline: \"1px dashed rgba(48,209,88,0.6)\",\n }}\n />\n <div\n style={{\n ...baseStyle,\n top: 4,\n left: 8,\n color: \"white\",\n background: \"rgba(0,0,0,0.6)\",\n padding: \"2px 6px\",\n fontSize: 10,\n fontFamily: \"ui-monospace, monospace\",\n borderRadius: 4,\n }}\n >\n {w}×{h} · safe {safe.top}/{safe.bottom}/{safe.left}/{safe.right}\n </div>\n </>\n );\n}\n","import { SCALE_STEPS } from \"../math/scale.js\";\n\nexport interface ScaleBarProps {\n deviceName: string;\n deviceWidth: number;\n deviceHeight: number;\n scale: number;\n scalePercent: string;\n isAtMaxScale: boolean;\n isConstrained: boolean;\n onScaleChange?: (scale: number) => void;\n onFit?: () => void;\n onRealSize?: () => void;\n}\n\nexport function ScaleBar({\n deviceName,\n deviceWidth,\n deviceHeight,\n scale,\n scalePercent,\n isAtMaxScale,\n onScaleChange,\n onFit,\n onRealSize,\n}: ScaleBarProps) {\n return (\n <div\n role=\"region\"\n aria-label=\"Device scale controls\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: \"rgba(28,28,30,0.92)\",\n color: \"white\",\n borderRadius: 8,\n fontFamily: \"ui-monospace, monospace\",\n fontSize: 12,\n marginTop: 8,\n }}\n >\n <span>{deviceName}</span>\n <span style={{ opacity: 0.6 }}>·</span>\n <span>\n {deviceWidth}×{deviceHeight}pt\n </span>\n <input\n type=\"range\"\n min={0.1}\n max={2}\n step={0.01}\n value={scale}\n aria-label=\"Scale\"\n aria-valuenow={scale}\n role=\"slider\"\n onChange={(e) => onScaleChange?.(parseFloat(e.target.value))}\n style={{ flex: 1 }}\n />\n <span aria-live=\"polite\" style={{ width: 40, textAlign: \"right\" }}>\n {scalePercent}\n </span>\n <button onClick={onFit} type=\"button\" style={btn}>\n Fit\n </button>\n <button onClick={onRealSize} type=\"button\" style={{ ...btn, opacity: isAtMaxScale ? 0.5 : 1 }}>\n 1:1\n </button>\n </div>\n );\n}\n\nconst btn = {\n background: \"transparent\",\n color: \"white\",\n border: \"1px solid rgba(255,255,255,0.25)\",\n padding: \"2px 8px\",\n borderRadius: 4,\n cursor: \"pointer\",\n fontSize: 11,\n};\n","import { useEffect, useState, type CSSProperties } from \"react\";\nimport type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\n\nexport interface DynamicStatusBarProps {\n contract: DeviceLayoutContract;\n orientation: \"portrait\" | \"landscape\";\n colorScheme: \"light\" | \"dark\";\n showLiveClock?: boolean;\n fixedTime?: string;\n}\n\nfunction formatNow(): string {\n const now = new Date();\n return `${now.getHours()}:${now.getMinutes().toString().padStart(2, \"0\")}`;\n}\n\nexport function DynamicStatusBar({\n contract,\n orientation,\n colorScheme,\n showLiveClock = true,\n fixedTime,\n}: DynamicStatusBarProps) {\n const [now, setNow] = useState(formatNow);\n\n useEffect(() => {\n if (!showLiveClock || fixedTime) return;\n const id = window.setInterval(() => setNow(formatNow()), 30_000);\n return () => window.clearInterval(id);\n }, [showLiveClock, fixedTime]);\n\n // iOS in landscape hides the status bar entirely.\n if (orientation === \"landscape\" && contract.device.platform === \"ios\") return null;\n\n const time = fixedTime ?? (showLiveClock ? now : \"9:41\");\n const platform = contract.device.platform;\n const statusBarStyle = contract.statusBar.style;\n const height = contract.statusBar.height;\n const textColor = colorScheme === \"dark\" ? \"#fff\" : \"#000\";\n const bgColor = colorScheme === \"dark\" ? \"#000\" : \"#fff\";\n const fontFamily = platform === \"ios\"\n ? \"-apple-system, 'SF Pro Text', 'Helvetica Neue', sans-serif\"\n : \"'Roboto', 'Google Sans', sans-serif\";\n const baseFontSize = platform === \"ios\" ? 15 : 12;\n const clockStyle: CSSProperties = {\n color: textColor,\n fontFamily,\n fontSize: baseFontSize,\n fontWeight: platform === \"ios\" ? 600 : 400,\n letterSpacing: platform === \"ios\" ? 0.3 : 0,\n lineHeight: `${height}px`,\n whiteSpace: \"nowrap\",\n };\n // Patch only the area around the clock — leave the rest of the bar alone so\n // the iframe app's own mock status bar (signal / wifi / battery) shows\n // through on the sides.\n const patchStyle: CSSProperties = {\n position: \"absolute\",\n top: 0,\n height,\n display: \"flex\",\n alignItems: \"center\",\n background: bgColor,\n pointerEvents: \"none\",\n };\n\n // iOS classic / fullwidth — centered narrow patch around the clock.\n if (platform === \"ios\" && statusBarStyle !== \"dynamic-island\" && statusBarStyle !== \"notch\") {\n return (\n <div\n aria-hidden\n style={{ ...patchStyle, left: \"50%\", transform: \"translateX(-50%)\", paddingLeft: 6, paddingRight: 6 }}\n >\n <span style={{ ...clockStyle, fontWeight: 500, fontSize: baseFontSize - 1 }}>{time}</span>\n </div>\n );\n }\n\n // iOS with Dynamic Island / notch — left-aligned with iOS spacing.\n if (platform === \"ios\") {\n return (\n <div aria-hidden style={{ ...patchStyle, left: 0, paddingLeft: 20, paddingRight: 8 }}>\n <span style={clockStyle}>{time}</span>\n </div>\n );\n }\n\n // Android — left-aligned.\n return (\n <div aria-hidden style={{ ...patchStyle, left: 0, paddingLeft: 16, paddingRight: 8 }}>\n <span style={clockStyle}>{time}</span>\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { DeviceLayoutContract } from \"@mmtitanl/tablets\";\nimport { DeviceFrame } from \"./DeviceFrame.js\";\n\nexport interface DeviceCompareProps {\n deviceA: string;\n deviceB: string;\n orientation?: \"portrait\" | \"landscape\";\n colorScheme?: \"light\" | \"dark\";\n showSafeAreaOverlay?: boolean;\n showScaleBar?: boolean;\n layout?: \"horizontal\" | \"vertical\" | \"auto\";\n gap?: number;\n children?: ReactNode;\n childrenA?: ReactNode;\n childrenB?: ReactNode;\n onContractReadyA?: (dlc: DeviceLayoutContract) => void;\n onContractReadyB?: (dlc: DeviceLayoutContract) => void;\n}\n\nexport function DeviceCompare({\n deviceA,\n deviceB,\n orientation = \"portrait\",\n colorScheme = \"light\",\n showSafeAreaOverlay,\n showScaleBar,\n layout = \"auto\",\n gap = 24,\n children,\n childrenA,\n childrenB,\n onContractReadyA,\n onContractReadyB,\n}: DeviceCompareProps) {\n const direction = layout === \"auto\" ? (orientation === \"portrait\" ? \"row\" : \"column\") : layout === \"horizontal\" ? \"row\" : \"column\";\n return (\n <div style={{ display: \"flex\", flexDirection: direction, gap, width: \"100%\", height: \"100%\" }}>\n <div style={{ flex: 1 }}>\n <DeviceFrame\n deviceId={deviceA}\n orientation={orientation}\n colorScheme={colorScheme}\n showSafeAreaOverlay={showSafeAreaOverlay}\n showScaleBar={showScaleBar}\n onContractReady={onContractReadyA}\n >\n {childrenA ?? children}\n </DeviceFrame>\n </div>\n <div style={{ flex: 1 }}>\n <DeviceFrame\n deviceId={deviceB}\n orientation={orientation}\n colorScheme={colorScheme}\n showSafeAreaOverlay={showSafeAreaOverlay}\n showScaleBar={showScaleBar}\n onContractReady={onContractReadyB}\n >\n {childrenB ?? children}\n </DeviceFrame>\n </div>\n </div>\n );\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\nexport interface SafeAreaViewProps {\n edges?: Array<\"top\" | \"bottom\" | \"left\" | \"right\">;\n children: ReactNode;\n style?: CSSProperties;\n}\n\nexport function SafeAreaView({ edges = [\"top\", \"bottom\", \"left\", \"right\"], children, style }: SafeAreaViewProps) {\n const padding: CSSProperties = {\n paddingTop: edges.includes(\"top\") ? \"var(--safe-top, 0px)\" : undefined,\n paddingBottom: edges.includes(\"bottom\") ? \"var(--safe-bottom, 0px)\" : undefined,\n paddingLeft: edges.includes(\"left\") ? \"var(--safe-left, 0px)\" : undefined,\n paddingRight: edges.includes(\"right\") ? \"var(--safe-right, 0px)\" : undefined,\n };\n return <div style={{ ...padding, ...style }}>{children}</div>;\n}\n","export interface VolumeHUDProps {\n level: number;\n muted: boolean;\n visible: boolean;\n platform: \"ios\" | \"android\";\n}\n\nexport function VolumeHUD({ level, muted, visible, platform }: VolumeHUDProps) {\n if (!visible) return null;\n const isIOS = platform === \"ios\";\n const pct = Math.round((muted ? 0 : level) * 100);\n return (\n <div\n role=\"status\"\n aria-label={`Volume ${pct}%`}\n style={{\n position: \"absolute\",\n ...(isIOS\n ? { top: \"12%\", left: \"50%\", transform: \"translateX(-50%)\", width: 6, height: 220, borderRadius: 3 }\n : { top: 16, left: \"50%\", transform: \"translateX(-50%)\", width: 240, height: 6, borderRadius: 3 }),\n background: \"rgba(255,255,255,0.2)\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n background: muted ? \"#8e8e93\" : \"white\",\n ...(isIOS ? { width: \"100%\", height: `${pct}%`, marginTop: `${100 - pct}%` } : { width: `${pct}%`, height: \"100%\" }),\n }}\n />\n </div>\n );\n}\n","import { useEffect, useState, type ReactElement, type RefObject } from \"react\";\n\nexport type ButtonName = \"volumeUp\" | \"volumeDown\" | \"power\" | \"actionButton\" | \"cameraControl\";\n\ninterface ButtonRect {\n name: ButtonName;\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport interface HardwareButtonsProps {\n frameContainerRef: RefObject<HTMLDivElement | null>;\n onButtonPress?: (button: ButtonName) => void;\n enabled?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n}\n\nexport function HardwareButtons({\n frameContainerRef,\n onButtonPress,\n enabled = true,\n orientation = \"portrait\",\n}: HardwareButtonsProps): ReactElement | null {\n const [rects, setRects] = useState<ButtonRect[]>([]);\n\n useEffect(() => {\n if (!enabled) return;\n const container = frameContainerRef.current;\n if (!container) return;\n const found: ButtonRect[] = [];\n const nodes = container.querySelectorAll<SVGElement>(\"[data-button]\");\n const containerRect = container.getBoundingClientRect();\n nodes.forEach((node) => {\n const name = node.getAttribute(\"data-button\") as ButtonName | null;\n if (!name) return;\n const r = node.getBoundingClientRect();\n found.push({\n name,\n left: r.left - containerRect.left,\n top: r.top - containerRect.top,\n width: r.width,\n height: r.height,\n });\n });\n setRects(found);\n }, [frameContainerRef, enabled, orientation]);\n\n if (!enabled || rects.length === 0) return null;\n\n return (\n <>\n {rects.map((r) => (\n <div\n key={r.name}\n role=\"button\"\n aria-label={r.name}\n onMouseDown={() => onButtonPress?.(r.name)}\n onTouchStart={() => onButtonPress?.(r.name)}\n style={{\n position: \"absolute\",\n left: r.left,\n top: r.top,\n width: r.width,\n height: r.height,\n cursor: \"pointer\",\n zIndex: 20,\n }}\n />\n ))}\n </>\n );\n}\n","export interface StatusBarIndicatorsProps {\n platform: \"ios\" | \"android\";\n colorScheme: \"light\" | \"dark\";\n}\n\nexport function StatusBarIndicators({ platform, colorScheme }: StatusBarIndicatorsProps) {\n const fill = colorScheme === \"dark\" ? \"white\" : \"black\";\n if (platform === \"ios\") {\n return (\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n <svg width=\"18\" height=\"10\" viewBox=\"0 0 18 10\">\n <rect x=\"0\" y=\"6\" width=\"3\" height=\"4\" fill={fill} rx=\"1\" />\n <rect x=\"5\" y=\"4\" width=\"3\" height=\"6\" fill={fill} rx=\"1\" />\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"8\" fill={fill} rx=\"1\" />\n <rect x=\"15\" y=\"0\" width=\"3\" height=\"10\" fill={fill} rx=\"1\" />\n </svg>\n <svg width=\"14\" height=\"10\" viewBox=\"0 0 14 10\">\n <path d=\"M7 9.5l3-3a4 4 0 0 0-6 0z\" fill={fill} />\n </svg>\n <svg width=\"26\" height=\"12\" viewBox=\"0 0 26 12\">\n <rect x=\"1\" y=\"1\" width=\"22\" height=\"10\" rx=\"2.5\" fill=\"none\" stroke={fill} strokeWidth=\"1\" />\n <rect x=\"24\" y=\"4\" width=\"1.5\" height=\"4\" rx=\"0.5\" fill={fill} />\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"6\" rx=\"1.5\" fill={fill} />\n </svg>\n </div>\n );\n }\n return (\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n <svg width=\"14\" height=\"10\" viewBox=\"0 0 14 10\">\n <path d=\"M0 9 L14 9 L14 1 Z\" fill={fill} />\n </svg>\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\n <rect x=\"1\" y=\"1\" width=\"16\" height=\"8\" rx=\"1.5\" fill=\"none\" stroke={fill} strokeWidth=\"1\" />\n <rect x=\"18\" y=\"3\" width=\"1.5\" height=\"4\" rx=\"0.5\" fill={fill} />\n <rect x=\"3\" y=\"3\" width=\"12\" height=\"4\" fill={fill} />\n </svg>\n </div>\n );\n}\n","import type { SVGScreenRect } from \"@mmtitanl/tablets\";\nimport { registerCustomDeviceSVG } from \"../registration.js\";\n\nexport interface SVGOverrideEntry {\n deviceId: string;\n name?: string;\n platform?: \"ios\" | \"android\";\n formFactor?: \"tablet\" | \"phone\" | \"foldable\";\n /** Reported logical-pt screen size (independent of SVG viewBox scale). */\n logicalScreenWidth?: number;\n logicalScreenHeight?: number;\n svgString: string;\n bezelTop: number;\n bezelBottom: number;\n bezelLeft: number;\n bezelRight: number;\n screenRect?: SVGScreenRect;\n // Optional landscape variant (separate SVG rendered when device is rotated)\n svgStringLandscape?: string;\n bezelTopLandscape?: number;\n bezelBottomLandscape?: number;\n bezelLeftLandscape?: number;\n bezelRightLandscape?: number;\n screenRectLandscape?: SVGScreenRect;\n /** Opt-in: punch a transparent hole at the screen rect (for opaque-screen\n * artwork). Default false — raw SVG renders untouched over the iframe. */\n dieCutScreen?: boolean;\n updatedAt: string;\n}\n\nconst STORAGE_KEY = \"bielaframe-custom-tablet-svgs\";\n\nexport class CustomSVGStore {\n private storage: Storage | null;\n constructor(storage?: Storage | null) {\n this.storage = storage ?? (typeof localStorage !== \"undefined\" ? localStorage : null);\n }\n\n getAll(): Record<string, SVGOverrideEntry> {\n if (!this.storage) return {};\n try {\n const raw = this.storage.getItem(STORAGE_KEY);\n return raw ? (JSON.parse(raw) as Record<string, SVGOverrideEntry>) : {};\n } catch {\n return {};\n }\n }\n\n save(entry: SVGOverrideEntry): void {\n const all = this.getAll();\n all[entry.deviceId] = entry;\n this.persist(all);\n this.applyEntry(entry);\n }\n\n remove(deviceId: string): void {\n const all = this.getAll();\n delete all[deviceId];\n this.persist(all);\n }\n\n has(deviceId: string): boolean {\n return !!this.getAll()[deviceId];\n }\n\n get(deviceId: string): SVGOverrideEntry | undefined {\n return this.getAll()[deviceId];\n }\n\n applyAll(): void {\n const all = this.getAll();\n Object.values(all).forEach((entry) => this.applyEntry(entry));\n }\n\n private applyEntry(entry: SVGOverrideEntry): void {\n const rawW = entry.screenRect?.width ?? 0;\n const rawH = entry.screenRect?.height ?? 0;\n // Bezels + screenRect are persisted in SVG-viewBox units. If the entry\n // declared a logical screen size (the actual pt size the device reports),\n // uniformly scale everything so the iframe viewport reports logical dims\n // — otherwise the iframe gets a viewport of raw SVG units (huge) and the\n // app renders desktop-style. Uniform scale preserves bezel proportions;\n // the screen height ends up dictated by the SVG screen-rect aspect.\n // Legacy entries (no logicalScreenWidth) get inferred defaults per form\n // factor so they don't render at raw SVG pixel size.\n const FORM_FACTOR_LOGICAL_W: Record<NonNullable<SVGOverrideEntry[\"formFactor\"]>, number> = {\n tablet: 834,\n phone: 390,\n foldable: 374,\n };\n const logicalW =\n entry.logicalScreenWidth ??\n (entry.formFactor ? FORM_FACTOR_LOGICAL_W[entry.formFactor] : rawW);\n const scale = rawW > 0 ? logicalW / rawW : 1;\n\n const sr = entry.screenRect\n ? {\n x: entry.screenRect.x * scale,\n y: entry.screenRect.y * scale,\n width: rawW * scale,\n height: rawH * scale,\n rx: (entry.screenRect.rx ?? 0) * scale,\n rxTop: entry.screenRect.rxTop !== undefined\n ? entry.screenRect.rxTop * scale\n : undefined,\n rxBottom: entry.screenRect.rxBottom !== undefined\n ? entry.screenRect.rxBottom * scale\n : undefined,\n }\n : undefined;\n const portraitBezelTop = entry.bezelTop * scale;\n const portraitBezelBottom = entry.bezelBottom * scale;\n const portraitBezelLeft = entry.bezelLeft * scale;\n const portraitBezelRight = entry.bezelRight * scale;\n const portraitScreenW = sr?.width ?? logicalW;\n const portraitScreenH = sr?.height ?? (entry.logicalScreenHeight ?? rawH);\n\n let landscape: Parameters<typeof registerCustomDeviceSVG>[5];\n if (entry.svgStringLandscape && entry.screenRectLandscape) {\n const lRawW = entry.screenRectLandscape.width;\n const lRawH = entry.screenRectLandscape.height;\n // Landscape's logical width matches portrait's logical height.\n const lScale = lRawW > 0 ? (entry.logicalScreenHeight ?? lRawW) / lRawW : 1;\n const lsr = {\n x: entry.screenRectLandscape.x * lScale,\n y: entry.screenRectLandscape.y * lScale,\n width: lRawW * lScale,\n height: lRawH * lScale,\n rx: (entry.screenRectLandscape.rx ?? 0) * lScale,\n rxTop: entry.screenRectLandscape.rxTop !== undefined\n ? entry.screenRectLandscape.rxTop * lScale\n : undefined,\n rxBottom: entry.screenRectLandscape.rxBottom !== undefined\n ? entry.screenRectLandscape.rxBottom * lScale\n : undefined,\n };\n const lBezelTop = (entry.bezelTopLandscape ?? 0) * lScale;\n const lBezelBottom = (entry.bezelBottomLandscape ?? 0) * lScale;\n const lBezelLeft = (entry.bezelLeftLandscape ?? 0) * lScale;\n const lBezelRight = (entry.bezelRightLandscape ?? 0) * lScale;\n landscape = {\n svgString: entry.svgStringLandscape,\n frame: {\n bezelTop: lBezelTop,\n bezelBottom: lBezelBottom,\n bezelLeft: lBezelLeft,\n bezelRight: lBezelRight,\n totalWidth: lsr.width + lBezelLeft + lBezelRight,\n totalHeight: lsr.height + lBezelTop + lBezelBottom,\n screenWidth: lsr.width,\n screenHeight: lsr.height,\n screenRadius: lsr.rx,\n screenRadiusTop: lsr.rxTop,\n screenRadiusBottom: lsr.rxBottom,\n },\n screenRect: lsr,\n };\n }\n\n registerCustomDeviceSVG(\n entry.deviceId,\n entry.svgString,\n {\n bezelTop: portraitBezelTop,\n bezelBottom: portraitBezelBottom,\n bezelLeft: portraitBezelLeft,\n bezelRight: portraitBezelRight,\n totalWidth: portraitScreenW + portraitBezelLeft + portraitBezelRight,\n totalHeight: portraitScreenH + portraitBezelTop + portraitBezelBottom,\n screenWidth: portraitScreenW,\n screenHeight: portraitScreenH,\n screenRadius: sr?.rx ?? 0,\n screenRadiusTop: sr?.rxTop,\n screenRadiusBottom: sr?.rxBottom,\n },\n undefined,\n sr,\n landscape,\n { dieCutScreen: entry.dieCutScreen ?? false }\n );\n }\n\n private persist(all: Record<string, SVGOverrideEntry>): void {\n if (!this.storage) return;\n try {\n this.storage.setItem(STORAGE_KEY, JSON.stringify(all));\n } catch {\n // ignore\n }\n }\n}\n\nlet singleton: CustomSVGStore | null = null;\nexport function getCustomSVGStore(): CustomSVGStore {\n if (!singleton) singleton = new CustomSVGStore();\n return singleton;\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_tablets","Component","import_react","import_tablets","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_tablets","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -179,7 +179,9 @@ interface LandscapeBuiltinRegistration {
179
179
  screenRect?: SVGScreenRect;
180
180
  }
181
181
  declare function registerDeviceSVG(deviceId: string, component: DeviceSVGComponent, frame: FrameInfo, screenRect?: SVGScreenRect, landscape?: LandscapeBuiltinRegistration): void;
182
- declare function registerCustomDeviceSVG(deviceId: string, svgString: string, frame: FrameInfo, cropViewBox?: SVGCropArea, screenRect?: SVGScreenRect, landscape?: LandscapeSVGRegistration): void;
182
+ declare function registerCustomDeviceSVG(deviceId: string, svgString: string, frame: FrameInfo, cropViewBox?: SVGCropArea, screenRect?: SVGScreenRect, landscape?: LandscapeSVGRegistration, options?: {
183
+ dieCutScreen?: boolean;
184
+ }): void;
183
185
 
184
186
  interface DeviceFrameProps {
185
187
  device?: string;
@@ -311,6 +313,9 @@ interface SVGOverrideEntry {
311
313
  bezelLeftLandscape?: number;
312
314
  bezelRightLandscape?: number;
313
315
  screenRectLandscape?: SVGScreenRect;
316
+ /** Opt-in: punch a transparent hole at the screen rect (for opaque-screen
317
+ * artwork). Default false — raw SVG renders untouched over the iframe. */
318
+ dieCutScreen?: boolean;
314
319
  updatedAt: string;
315
320
  }
316
321
  declare class CustomSVGStore {
package/dist/index.d.ts CHANGED
@@ -179,7 +179,9 @@ interface LandscapeBuiltinRegistration {
179
179
  screenRect?: SVGScreenRect;
180
180
  }
181
181
  declare function registerDeviceSVG(deviceId: string, component: DeviceSVGComponent, frame: FrameInfo, screenRect?: SVGScreenRect, landscape?: LandscapeBuiltinRegistration): void;
182
- declare function registerCustomDeviceSVG(deviceId: string, svgString: string, frame: FrameInfo, cropViewBox?: SVGCropArea, screenRect?: SVGScreenRect, landscape?: LandscapeSVGRegistration): void;
182
+ declare function registerCustomDeviceSVG(deviceId: string, svgString: string, frame: FrameInfo, cropViewBox?: SVGCropArea, screenRect?: SVGScreenRect, landscape?: LandscapeSVGRegistration, options?: {
183
+ dieCutScreen?: boolean;
184
+ }): void;
183
185
 
184
186
  interface DeviceFrameProps {
185
187
  device?: string;
@@ -311,6 +313,9 @@ interface SVGOverrideEntry {
311
313
  bezelLeftLandscape?: number;
312
314
  bezelRightLandscape?: number;
313
315
  screenRectLandscape?: SVGScreenRect;
316
+ /** Opt-in: punch a transparent hole at the screen rect (for opaque-screen
317
+ * artwork). Default false — raw SVG renders untouched over the iframe. */
318
+ dieCutScreen?: boolean;
314
319
  updatedAt: string;
315
320
  }
316
321
  declare class CustomSVGStore {