@biela.dev/devices 0.1.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.
@@ -0,0 +1,311 @@
1
+ import { D as DeviceMeta, a as DeviceLayoutData, b as DeviceLayoutContract, S as SafeAreaInsets, C as ContentRect, H as HardwareOverlayType, O as OverlayRect, R as RegisteredDevice } from './contract-types-Cw1rmF3b.js';
2
+ export { c as DeviceCSSVariables, d as DeviceFrameInfo, e as SVGCropRect, f as SVGScreenRect } from './contract-types-Cw1rmF3b.js';
3
+ export { IPHONE_16E_FRAME, IPHONE_16E_LAYOUT, IPHONE_16E_META, IPHONE_16_FRAME, IPHONE_16_LAYOUT, IPHONE_16_META, IPHONE_17_PRO_FRAME, IPHONE_17_PRO_LAYOUT, IPHONE_17_PRO_MAX_FRAME, IPHONE_17_PRO_MAX_LAYOUT, IPHONE_17_PRO_MAX_META, IPHONE_17_PRO_META, IPHONE_AIR_FRAME, IPHONE_AIR_LAYOUT, IPHONE_AIR_META, IPHONE_SE_3_FRAME, IPHONE_SE_3_LAYOUT, IPHONE_SE_3_META, IPhone16SVG, IPhone16eSVG, IPhone17ProMaxSVG, IPhone17ProSVG, IPhoneAirSVG, IPhoneSE3SVG } from './ios/index.js';
4
+ export { GALAXY_S25_EDGE_FRAME, GALAXY_S25_EDGE_LAYOUT, GALAXY_S25_EDGE_META, GALAXY_S25_FRAME, GALAXY_S25_LAYOUT, GALAXY_S25_META, GALAXY_S25_ULTRA_FRAME, GALAXY_S25_ULTRA_LAYOUT, GALAXY_S25_ULTRA_META, GalaxyS25EdgeSVG, GalaxyS25SVG, GalaxyS25UltraSVG, PIXEL_9_PRO_FRAME, PIXEL_9_PRO_LAYOUT, PIXEL_9_PRO_META, PIXEL_9_PRO_XL_FRAME, PIXEL_9_PRO_XL_LAYOUT, PIXEL_9_PRO_XL_META, Pixel9ProSVG, Pixel9ProXLSVG } from './android/index.js';
5
+ import 'react/jsx-runtime';
6
+
7
+ /**
8
+ * Built-in device metadata registry — 11 devices.
9
+ *
10
+ * Curated to cover every unique screen class (logical resolution).
11
+ * Duplicate resolutions across generations are represented by the latest model.
12
+ *
13
+ * ALL DIMENSIONS VERIFIED:
14
+ *
15
+ * iPhone 17 Pro Max: 440×956pt @3x (covers iPhone 16 Pro Max)
16
+ * iPhone 17 Pro: 402×874pt @3x (covers iPhone 16 Pro, iPhone 17)
17
+ * iPhone Air: 420×912pt @3x (unique new size class)
18
+ * iPhone 16: 393×852pt @3x (base Dynamic Island)
19
+ * iPhone 16e: 390×844pt @3x (notch, unique width)
20
+ * iPhone SE 3: 375×667pt @2x (legacy home-button form factor)
21
+ * Galaxy S25 Ultra: 384×824dp @3.75x (covers S24 Ultra)
22
+ * Galaxy S25: 360×780dp @3x (covers S24)
23
+ * Galaxy S25 Edge: 382×824dp @3.75x (unique narrow form factor)
24
+ * Pixel 9 Pro: 393×851dp @3x (covers Pixel 9, S25+)
25
+ * Pixel 9 Pro XL: 448×968dp @3x (largest Android)
26
+ */
27
+ declare const BUILTIN_DEVICES: Record<string, DeviceMeta>;
28
+ declare const DEVICE_LAYOUTS: Record<string, DeviceLayoutData>;
29
+ /**
30
+ * Look up device metadata — checks built-in first, then custom registry.
31
+ */
32
+ declare function getDeviceMetadata(deviceId: string): DeviceMeta;
33
+ /**
34
+ * Get all device IDs — built-in + custom.
35
+ */
36
+ declare function getAllDeviceIds(): string[];
37
+
38
+ /** Derive the content zone from screen dimensions and safe area insets */
39
+ declare function deriveContentZone(screenWidth: number, screenHeight: number, safeArea: SafeAreaInsets): ContentRect;
40
+ /** Build CSS variables from device data at REAL unscaled values */
41
+ declare function buildCSSVariables(screen: DeviceMeta["screen"], safeArea: SafeAreaInsets, statusBar: DeviceLayoutContract["statusBar"], homeIndicator: DeviceLayoutContract["homeIndicator"], hardwareOverlays: DeviceLayoutContract["hardwareOverlays"]): DeviceLayoutContract["cssVariables"];
42
+ /** Build the human-readable AI prompt constraints string */
43
+ declare function buildAIPromptConstraints(contract: Omit<DeviceLayoutContract, "aiPromptConstraints">): string;
44
+ /**
45
+ * Get the full Device Layout Contract for a device.
46
+ * This is the single source of truth that feeds both CSS variables and AI prompts.
47
+ */
48
+ declare function getDeviceContract(deviceId: string, orientation?: "portrait" | "landscape"): DeviceLayoutContract;
49
+
50
+ /**
51
+ * Extract the native coordinate space from an SVG string.
52
+ *
53
+ * Priority: viewBox → width/height attributes → fallback (390×844).
54
+ * This tells us what coordinate space the SVG was authored in,
55
+ * which may differ from the device's logical point dimensions.
56
+ */
57
+ interface SVGNativeDimensions {
58
+ width: number;
59
+ height: number;
60
+ hasViewBox: boolean;
61
+ source: "viewBox" | "widthHeight" | "fallback";
62
+ }
63
+ declare function parseSVGNativeDimensions(svgString: string): SVGNativeDimensions;
64
+
65
+ /**
66
+ * Normalize an SVG to the canonical logical-point coordinate space.
67
+ *
68
+ * Takes an SVG that may be authored at physical pixels (e.g., 1206×2622 for iPhone 16 Pro at 3x)
69
+ * and rewrites it to logical points (402×874). Also rescales all data-zone element coordinates.
70
+ */
71
+ interface NormalizationResult {
72
+ normalizedSVG: string;
73
+ scaleFactors: {
74
+ x: number;
75
+ y: number;
76
+ };
77
+ aspectRatioWarning: string | null;
78
+ wasAlreadyNormalized: boolean;
79
+ nativeDimensions: {
80
+ width: number;
81
+ height: number;
82
+ };
83
+ }
84
+ declare function normalizeSVGToLogicalPoints(svgString: string, targetWidth: number, targetHeight: number): NormalizationResult;
85
+
86
+ /**
87
+ * Parse an SVG with data-zone annotations into a DeviceLayoutContract.
88
+ *
89
+ * Reads `data-zone` attributes on SVG elements to extract:
90
+ * - screen-area → screen dimensions
91
+ * - safe-area-top / safe-area-bottom → safe area insets
92
+ * - hardware-overlay → Dynamic Island / notch / punch-hole rect
93
+ * - status-bar → status bar zone
94
+ * - home-indicator → home indicator zone
95
+ */
96
+
97
+ interface ParsedZone {
98
+ zone: string;
99
+ x: number;
100
+ y: number;
101
+ width: number;
102
+ height: number;
103
+ }
104
+ /**
105
+ * Extract all data-zone elements and their bounding attributes from SVG markup.
106
+ */
107
+ declare function extractZones(svgString: string): ParsedZone[];
108
+ interface ParseSVGContractOptions {
109
+ /** Device metadata (id, name, platform, year, screen info) */
110
+ meta: DeviceMeta;
111
+ /** Hardware overlay type if known */
112
+ overlayType?: HardwareOverlayType;
113
+ /** Override overlay shape */
114
+ overlayShape?: OverlayRect["shape"];
115
+ /** Status bar style override */
116
+ statusBarStyle?: DeviceLayoutContract["statusBar"]["style"];
117
+ /** Home indicator type override */
118
+ homeIndicatorType?: DeviceLayoutContract["homeIndicator"]["type"];
119
+ }
120
+ /**
121
+ * Build a full DeviceLayoutContract from a normalized SVG with data-zone annotations.
122
+ */
123
+ declare function parseSVGToContract(normalizedSVG: string, options: ParseSVGContractOptions): DeviceLayoutContract;
124
+
125
+ /**
126
+ * Pre-registration validation for normalized SVGs.
127
+ *
128
+ * Checks that the normalization result is sane before registering a custom device.
129
+ */
130
+
131
+ interface ValidationResult {
132
+ passed: boolean;
133
+ warnings: string[];
134
+ errors: string[];
135
+ }
136
+ /**
137
+ * Validate a normalized SVG before registration.
138
+ */
139
+ declare function validateNormalizedSVG(result: NormalizationResult, targetWidth: number, targetHeight: number): ValidationResult;
140
+
141
+ /**
142
+ * Scope all SVG IDs to a device-specific prefix to prevent collisions
143
+ * when multiple device frames are rendered on the same page.
144
+ *
145
+ * Rewrites:
146
+ * - id="foo" → id="deviceId__foo"
147
+ * - url(#foo) → url(#deviceId__foo)
148
+ * - href="#foo" → href="#deviceId__foo"
149
+ * - xlink:href="#foo" → xlink:href="#deviceId__foo"
150
+ */
151
+ declare function scopeSVGIds(svgString: string, deviceId: string): string;
152
+
153
+ /**
154
+ * Auto-detect device zones from SVG structure.
155
+ *
156
+ * Two-pass approach:
157
+ * 1. Name-based: scan element IDs/classes/data-attributes for known keywords
158
+ * 2. Geometric heuristics: analyze ALL rects by size, position, fill, and corner radius
159
+ * to identify screen area, dynamic island, phone body, and side buttons
160
+ *
161
+ * The geometric pass is critical for real-world Figma SVGs that use auto-generated
162
+ * IDs like "clip0_44_55" with no semantic naming.
163
+ */
164
+ interface DetectedZone {
165
+ id: string;
166
+ /** The zone type we inferred */
167
+ type: ZoneType;
168
+ /** The SVG element's original id/name that matched */
169
+ sourceLabel: string;
170
+ /** Which keyword matched */
171
+ matchedKeyword: string;
172
+ /** Confidence: "high" for exact keyword match, "medium" for partial */
173
+ confidence: "high" | "medium";
174
+ /** Bounding box in SVG coordinate space */
175
+ x: number;
176
+ y: number;
177
+ width: number;
178
+ height: number;
179
+ /** Corner radius (from SVG rx attribute), only for screen-area zones */
180
+ rx?: number;
181
+ }
182
+ type ZoneType = "screen-area" | "hardware-overlay" | "safe-area-top" | "safe-area-bottom" | "safe-area-left" | "safe-area-right" | "status-bar" | "home-indicator" | "hardware-button";
183
+ /**
184
+ * Result of analyzing the SVG geometry — includes both zones and structural info.
185
+ */
186
+ interface SVGAnalysis {
187
+ /** Detected zones for the Zone Tagger */
188
+ zones: DetectedZone[];
189
+ /** Phone body bounding rect (largest rounded rect), if found */
190
+ phoneBody: {
191
+ x: number;
192
+ y: number;
193
+ width: number;
194
+ height: number;
195
+ rx: number;
196
+ } | null;
197
+ /** Rects identified as external side buttons */
198
+ sideButtons: {
199
+ x: number;
200
+ y: number;
201
+ width: number;
202
+ height: number;
203
+ }[];
204
+ /** All extracted rects for debugging */
205
+ allRects: RectInfo[];
206
+ }
207
+ /** Internal rect representation with fill/rx info */
208
+ interface RectInfo {
209
+ x: number;
210
+ y: number;
211
+ width: number;
212
+ height: number;
213
+ rx: number;
214
+ fill: string | null;
215
+ id: string | null;
216
+ }
217
+ /**
218
+ * Auto-detect zones using both name-based and geometric approaches.
219
+ * Falls back to geometric heuristics when name-based detection finds nothing.
220
+ */
221
+ declare function autoDetectZones(svgString: string): DetectedZone[];
222
+ /**
223
+ * Full SVG analysis — returns zones plus structural info (phone body, side buttons).
224
+ * Used by the Registration Wizard for bezel calculation and button handling.
225
+ */
226
+ declare function analyzeSVGGeometry(svgString: string): SVGAnalysis;
227
+ /**
228
+ * Classify detected side buttons into specific hardware button types.
229
+ *
230
+ * Classification strategy based on real device button placement:
231
+ * - LEFT side (iOS): action button (top), volume up (middle-top), volume down (middle-bottom)
232
+ * - LEFT side (Android): volume up (top), volume down (bottom)
233
+ * - RIGHT side: power button (top/middle), camera control (lower, if present)
234
+ *
235
+ * Uses vertical position and size to distinguish buttons.
236
+ */
237
+ interface ClassifiedButton {
238
+ type: "volume-up" | "volume-down" | "power" | "action" | "camera";
239
+ side: "left" | "right";
240
+ x: number;
241
+ y: number;
242
+ width: number;
243
+ height: number;
244
+ }
245
+ declare function classifySideButtons(sideButtons: {
246
+ x: number;
247
+ y: number;
248
+ width: number;
249
+ height: number;
250
+ }[], phoneBody: {
251
+ x: number;
252
+ y: number;
253
+ width: number;
254
+ height: number;
255
+ } | null): ClassifiedButton[];
256
+ /**
257
+ * Get a list of all identifiable SVG element names for UI display.
258
+ */
259
+ declare function listSVGLayerNames(svgString: string): {
260
+ tag: string;
261
+ name: string;
262
+ }[];
263
+
264
+ /**
265
+ * Custom device registry — stores user-imported devices in localStorage.
266
+ *
267
+ * Provides CRUD operations for custom devices, persistence, and export/import.
268
+ * Custom devices are stored alongside built-in devices but tracked separately.
269
+ */
270
+
271
+ declare class DeviceRegistry {
272
+ private devices;
273
+ private storage;
274
+ constructor(storage?: Storage | null);
275
+ /** Register or update a custom device */
276
+ register(device: RegisteredDevice): void;
277
+ /** Get a custom device by ID */
278
+ get(deviceId: string): RegisteredDevice | undefined;
279
+ /** Get the metadata for a custom device */
280
+ getMeta(deviceId: string): DeviceMeta | undefined;
281
+ /** Get the contract for a custom device */
282
+ getContract(deviceId: string): DeviceLayoutContract | undefined;
283
+ /** List all custom devices */
284
+ list(): RegisteredDevice[];
285
+ /** List all custom device IDs */
286
+ listIds(): string[];
287
+ /** Check if a custom device exists */
288
+ has(deviceId: string): boolean;
289
+ /** Remove a custom device */
290
+ remove(deviceId: string): boolean;
291
+ /** Remove all custom devices */
292
+ clear(): void;
293
+ /** Get the number of custom devices */
294
+ get size(): number;
295
+ /** Export all custom devices as a JSON string */
296
+ exportAll(): string;
297
+ /** Import custom devices from a JSON string (merges with existing) */
298
+ importAll(json: string): {
299
+ imported: number;
300
+ skipped: string[];
301
+ };
302
+ /** Import and overwrite existing entries */
303
+ importAllOverwrite(json: string): number;
304
+ private load;
305
+ private save;
306
+ }
307
+ declare function getDeviceRegistry(): DeviceRegistry;
308
+ /** Reset the singleton (for testing) */
309
+ declare function resetDeviceRegistry(): void;
310
+
311
+ export { BUILTIN_DEVICES, type ClassifiedButton, ContentRect, DEVICE_LAYOUTS, type DetectedZone, DeviceLayoutContract, DeviceLayoutData, DeviceMeta, DeviceRegistry, HardwareOverlayType, type NormalizationResult, OverlayRect, type ParseSVGContractOptions, type ParsedZone, RegisteredDevice, type SVGAnalysis, type SVGNativeDimensions, SafeAreaInsets, type ValidationResult, type ZoneType, analyzeSVGGeometry, autoDetectZones, buildAIPromptConstraints, buildCSSVariables, classifySideButtons, deriveContentZone, extractZones, getAllDeviceIds, getDeviceContract, getDeviceMetadata, getDeviceRegistry, listSVGLayerNames, normalizeSVGToLogicalPoints, parseSVGNativeDimensions, parseSVGToContract, resetDeviceRegistry, scopeSVGIds, validateNormalizedSVG };