@mmtitanl/tablets-core 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +153 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +153 -81
- package/dist/index.js.map +1 -1
- package/package.json +16 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["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":["useMemo","useState","useCallback","useEffect","useState","useCallback","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","useState","useCallback","Component","useEffect","useMemo","useRef","useState","getDeviceContract","jsx","jsx","jsxs","jsx","jsxs","useEffect","useState","jsx","jsx","jsxs","useMemo","getDeviceContract","useRef","useState","useEffect","jsx","jsxs","jsx","jsx","useEffect","useState","Fragment","jsx","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../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":["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, type FrameInfo } 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\n// ─── Rotation animation (iPadOS-style) ──────────────────────────────────────\n// One coordinated move: the frame physically rotates ±90° while the app\n// content fades out, re-lays-out for the new orientation (while invisible),\n// then fades back in upright as the rotation settles.\nconst ROTATE_MS = 450;\nconst EASE = \"cubic-bezier(0.4, 0, 0.2, 1)\";\n// 2-SVG devices: crossfade between the portrait and landscape artwork while\n// the frame is in motion — the movement masks the swap.\nconst SVG_FADE_MS = 240;\nconst SVG_FADE_DELAY_MS = 100;\nconst CONTENT_FADE_OUT_MS = 140;\n// Content re-layout happens here, while it is invisible.\nconst CONTENT_SWAP_MS = 180;\nconst CONTENT_FADE_IN_DELAY_MS = 220;\n// Fade-in ends together with the rotation.\nconst CONTENT_FADE_IN_MS = 230;\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\n // The frame starts rotating the moment `orientation` changes; the CONTENT\n // lags behind: it fades out, swaps layout mid-rotation (while invisible),\n // then fades back in upright as the frame settles.\n const [contentOrientation, setContentOrientation] = useState(orientation);\n const [contentVisible, setContentVisible] = useState(true);\n const animTimers = useRef<number[]>([]);\n const prevOrientation = useRef(orientation);\n\n useEffect(() => {\n if (prevOrientation.current === orientation) return;\n prevOrientation.current = orientation;\n for (const t of animTimers.current) window.clearTimeout(t);\n setContentVisible(false);\n animTimers.current = [\n window.setTimeout(() => setContentOrientation(orientation), CONTENT_SWAP_MS),\n window.setTimeout(() => setContentVisible(true), CONTENT_FADE_IN_DELAY_MS),\n ];\n }, [orientation]);\n useEffect(() => () => { for (const t of animTimers.current) window.clearTimeout(t); }, []);\n\n // CSS vars / DLC follow the CONTENT orientation so the app re-lays-out at\n // the same moment its box swaps.\n const contract = useMemo(() => getDeviceContract(resolvedId, contentOrientation), [resolvedId, contentOrientation]);\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 svgEntry = getDeviceSVG(resolvedId);\n const SVGComponent: DeviceSVGComponent | null = svgEntry?.component ?? null;\n const LandscapeSVGComponent: DeviceSVGComponent | null = svgEntry?.landscapeComponent ?? null;\n const registeredLandscapeFrame = svgEntry?.landscapeFrame;\n const hasLandscapeSVG = !!LandscapeSVGComponent && !!registeredLandscapeFrame;\n\n // Portrait frame; screen-only fallback when no SVG is registered.\n const portFrame: FrameInfo = svgEntry?.frame ?? {\n bezelTop: 0, bezelBottom: 0, bezelLeft: 0, bezelRight: 0,\n totalWidth: portW, totalHeight: portH,\n screenWidth: portW, screenHeight: portH, screenRadius: 0,\n };\n // Landscape-equivalent frame: the real landscape artwork's frame for 2-SVG\n // devices; otherwise the portrait frame transposed (single-SVG devices show\n // the portrait artwork rotated -90°, so its top bezel becomes the left one).\n const landFrame: FrameInfo = hasLandscapeSVG && registeredLandscapeFrame\n ? registeredLandscapeFrame\n : {\n bezelTop: portFrame.totalWidth - portFrame.bezelLeft - portFrame.screenWidth,\n bezelBottom: portFrame.bezelLeft,\n bezelLeft: portFrame.bezelTop,\n bezelRight: portFrame.totalHeight - portFrame.bezelTop - portFrame.screenHeight,\n totalWidth: portFrame.totalHeight,\n totalHeight: portFrame.totalWidth,\n screenWidth: portFrame.screenHeight,\n screenHeight: portFrame.screenWidth,\n screenRadius: portFrame.screenRadius,\n };\n\n // The active frame's outer box drives the host size.\n const activeFrame = rotateFrame ? landFrame : portFrame;\n const fitW = activeFrame.totalWidth;\n const fitH = activeFrame.totalHeight;\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, contentOrientation);\n const onLoad = () => sendDeviceInfo(iframeRef.current, contract, contentOrientation);\n iframeRef.current.addEventListener(\"load\", onLoad);\n return () => iframeRef.current?.removeEventListener(\"load\", onLoad);\n }, [iframeRef, contract, contentOrientation]);\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, contentOrientation);\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, contentOrientation, onColorSchemeChange]);\n\n const cssVarsStyle = contract.cssVariables as unknown as React.CSSProperties;\n\n // The scaler is ALWAYS the portrait frame's box; landscape is that box\n // physically rotated -90° (iPadOS-style). For 2-SVG devices the landscape\n // artwork sits inside pre-rotated +90°, so during the rotation both SVGs\n // depict the device at the same physical angle — the mid-motion crossfade\n // between them stays aligned and the artwork ends perfectly upright.\n const scalerW = portFrame.totalWidth;\n const scalerH = portFrame.totalHeight;\n const scalerTransform = rotateFrame\n ? `scale(${scale}) translate(0px, ${landFrame.totalHeight}px) rotate(-90deg)`\n : `scale(${scale})`;\n\n // Content box per CONTENT orientation. The landscape box is counter-rotated\n // +90° inside the scaler so that after the scaler's -90° it ends upright,\n // laid out with real landscape dimensions, exactly on the landscape screen rect.\n const contentLandscape = contentOrientation === \"landscape\";\n const contentBox = contentLandscape\n ? { left: landFrame.totalHeight - landFrame.bezelTop, top: landFrame.bezelLeft, width: landFrame.screenWidth, height: landFrame.screenHeight }\n : { left: portFrame.bezelLeft, top: portFrame.bezelTop, width: portFrame.screenWidth, height: portFrame.screenHeight };\n const contentRadius = contentLandscape ? landFrame.screenRadius : portFrame.screenRadius;\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 // No overflow clipping: at rest the frame fits the host exactly; while\n // rotating, the corners sweep outside and clipping them flat looks bad.\n // The sentinel still clips at the component boundary.\n transition: `width ${ROTATE_MS}ms ${EASE}, height ${ROTATE_MS}ms ${EASE}`,\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 ${ROTATE_MS}ms ${EASE}`,\n }}\n >\n {/* iframe content: FIRST in DOM → naturally behind. In landscape it\n is counter-rotated +90° inside the -90°-rotated scaler, so it\n renders upright with real landscape dimensions. Opacity is\n choreographed: fade out → re-layout (hidden) → fade in. */}\n <div\n className=\"bielaframe-content\"\n style={{\n position: \"absolute\",\n left: contentBox.left,\n top: contentBox.top,\n width: contentBox.width,\n height: contentBox.height,\n ...(contentLandscape ? { transform: \"rotate(90deg)\", transformOrigin: \"top left\" } : null),\n overflow: \"hidden\",\n zIndex: 0,\n background: colorScheme === \"dark\" ? \"#000\" : \"#fff\",\n borderRadius: contentRadius,\n opacity: contentVisible ? 1 : 0,\n transition: `opacity ${contentVisible ? CONTENT_FADE_IN_MS : CONTENT_FADE_OUT_MS}ms ${EASE}`,\n ...cssVarsStyle,\n }}\n >\n <DeviceErrorBoundary>{children}</DeviceErrorBoundary>\n {showStatusBar && (\n <DynamicStatusBar contract={contract} orientation={contentOrientation} colorScheme={colorScheme} />\n )}\n {showSafeAreaOverlay && <SafeAreaOverlay contract={contract} orientation={contentOrientation} />}\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 && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: portFrame.totalWidth,\n height: portFrame.totalHeight,\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: hasLandscapeSVG && rotateFrame ? 0 : 1,\n transition: `opacity ${SVG_FADE_MS}ms ${EASE} ${SVG_FADE_DELAY_MS}ms`,\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 {/* Landscape artwork, pre-rotated +90° so it tracks the portrait\n artwork's physical angle throughout the scaler's rotation and\n lands upright when the rotation completes. */}\n {hasLandscapeSVG && LandscapeSVGComponent && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n left: landFrame.totalHeight,\n top: 0,\n width: landFrame.totalWidth,\n height: landFrame.totalHeight,\n transform: \"rotate(90deg)\",\n transformOrigin: \"top left\",\n pointerEvents: \"none\",\n zIndex: 1,\n opacity: rotateFrame ? 1 : 0,\n transition: `opacity ${SVG_FADE_MS}ms ${EASE} ${SVG_FADE_DELAY_MS}ms`,\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":["useMemo","useState","useCallback","useEffect","useState","useCallback","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","useState","useCallback","Component","useEffect","useMemo","useRef","useState","getDeviceContract","jsx","jsx","jsxs","jsx","jsxs","useEffect","useState","jsx","jsx","jsxs","useState","useRef","useEffect","useMemo","getDeviceContract","jsx","jsxs","jsx","jsx","useEffect","useState","Fragment","jsx","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmtitanl/tablets-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Core React components and hooks for tablet device frames — adaptive scaling and orientation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,15 +19,26 @@
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
-
"files": [
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": [
|
|
26
|
+
"./dist/registration.*",
|
|
27
|
+
"./src/registration.*"
|
|
28
|
+
],
|
|
29
|
+
"keywords": [
|
|
30
|
+
"tablet",
|
|
31
|
+
"device-frame",
|
|
32
|
+
"react",
|
|
33
|
+
"responsive",
|
|
34
|
+
"orientation"
|
|
35
|
+
],
|
|
25
36
|
"peerDependencies": {
|
|
26
37
|
"react": ">=18.0.0",
|
|
27
38
|
"react-dom": ">=18.0.0"
|
|
28
39
|
},
|
|
29
40
|
"dependencies": {
|
|
30
|
-
"@mmtitanl/tablets": "0.
|
|
41
|
+
"@mmtitanl/tablets": "0.4.0"
|
|
31
42
|
},
|
|
32
43
|
"scripts": {
|
|
33
44
|
"build": "tsup",
|