@dragcraft/device-frames 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-PRESENT hackycy <https://github.com/hackycy>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,518 @@
1
+ import { LayoutPlan, StyleValueMap } from "@dragcraft/core";
2
+ import { Component, InjectionKey, PropType, Ref, VNode } from "vue";
3
+ //#region src/types.d.ts
4
+ type DeviceFrameSelectionPlane = 'root' | 'content' | 'viewport';
5
+ /** Structural counterpart of Renderer selection presentation registration. */
6
+ interface DeviceFrameSelectionPresentationHost {
7
+ registerPlane: (plane: DeviceFrameSelectionPlane, element: HTMLElement | null) => void;
8
+ }
9
+ /**
10
+ * Supported device frame identifiers.
11
+ */
12
+ type DeviceType = 'iphone' | 'android' | 'tablet' | 'desktop';
13
+ /**
14
+ * Complete description of a device frame preset.
15
+ */
16
+ interface DevicePreset {
17
+ /** Unique device identifier */
18
+ type: DeviceType;
19
+ /** Human-readable label for host-owned device controls. */
20
+ label: string;
21
+ /** Optional i18n key resolved by a host-provided translator. */
22
+ labelKey?: string;
23
+ /** Icon character or component for compact device buttons. */
24
+ icon: string | Component;
25
+ /** Content viewport width in CSS pixels */
26
+ width: number;
27
+ /** Content viewport height in CSS pixels */
28
+ height: number;
29
+ /** The Vue component rendering the frame chrome */
30
+ frameComponent: Component;
31
+ }
32
+ /**
33
+ * Reactive context provided to descendants via provide/inject.
34
+ * Controls which device frame is currently active.
35
+ */
36
+ interface DeviceFrameContext {
37
+ /** Reactive device type ref — mutate this to switch devices */
38
+ currentDevice: Ref<DeviceType>;
39
+ /** All registered presets */
40
+ presets: readonly DevicePreset[];
41
+ /** Lookup a preset by type */
42
+ getPreset: (type: DeviceType) => DevicePreset | undefined;
43
+ /** Switch to a device type */
44
+ setDevice: (type: DeviceType) => void;
45
+ }
46
+ /**
47
+ * Injection key for the device frame context.
48
+ */
49
+ declare const DEVICE_FRAME_CONTEXT_KEY: InjectionKey<DeviceFrameContext>;
50
+ /**
51
+ * Options for createDeviceFrameContext.
52
+ */
53
+ interface DeviceFrameOptions {
54
+ /** Initial device to display. Defaults to 'iphone'. */
55
+ initialDevice?: DeviceType;
56
+ /** Override or extend the default presets. */
57
+ presets?: DevicePreset[];
58
+ }
59
+ //#endregion
60
+ //#region src/components/DeviceFrameShell.d.ts
61
+ /**
62
+ * Stable container shell component for the renderer's containerShell extension.
63
+ *
64
+ * Reads the current device from DeviceFrameContext (provide/inject) and
65
+ * renders the corresponding frame component. Because this is a single
66
+ * stable component reference, RootRenderer's computed() never swaps
67
+ * components — only the internal render output changes reactively.
68
+ *
69
+ * Falls back to the iPhone frame if no context is provided.
70
+ */
71
+ declare const DeviceFrameShell: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
72
+ layoutPlan: {
73
+ type: PropType<LayoutPlan>;
74
+ default: undefined;
75
+ };
76
+ regionVNodes: {
77
+ type: PropType<Record<string, VNode[]>>;
78
+ default: () => {};
79
+ };
80
+ chromeVNodes: {
81
+ type: PropType<VNode[]>;
82
+ default: () => never[];
83
+ };
84
+ layerVNodes: {
85
+ type: PropType<Record<string, VNode[]>>;
86
+ default: () => {};
87
+ };
88
+ forbiddenOverlayVNode: {
89
+ type: PropType<VNode | null>;
90
+ default: null;
91
+ };
92
+ surfaceStyle: {
93
+ type: PropType<StyleValueMap>;
94
+ default: undefined;
95
+ };
96
+ selectionPresentation: {
97
+ type: PropType<DeviceFrameSelectionPresentationHost>;
98
+ default: undefined;
99
+ };
100
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
101
+ [key: string]: any;
102
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
103
+ layoutPlan: {
104
+ type: PropType<LayoutPlan>;
105
+ default: undefined;
106
+ };
107
+ regionVNodes: {
108
+ type: PropType<Record<string, VNode[]>>;
109
+ default: () => {};
110
+ };
111
+ chromeVNodes: {
112
+ type: PropType<VNode[]>;
113
+ default: () => never[];
114
+ };
115
+ layerVNodes: {
116
+ type: PropType<Record<string, VNode[]>>;
117
+ default: () => {};
118
+ };
119
+ forbiddenOverlayVNode: {
120
+ type: PropType<VNode | null>;
121
+ default: null;
122
+ };
123
+ surfaceStyle: {
124
+ type: PropType<StyleValueMap>;
125
+ default: undefined;
126
+ };
127
+ selectionPresentation: {
128
+ type: PropType<DeviceFrameSelectionPresentationHost>;
129
+ default: undefined;
130
+ };
131
+ }>> & Readonly<{}>, {
132
+ layoutPlan: LayoutPlan;
133
+ chromeVNodes: VNode<import("vue").RendererNode, import("vue").RendererElement, {
134
+ [key: string]: any;
135
+ }>[];
136
+ layerVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
137
+ [key: string]: any;
138
+ }>[]>;
139
+ forbiddenOverlayVNode: VNode<import("vue").RendererNode, import("vue").RendererElement, {
140
+ [key: string]: any;
141
+ }> | null;
142
+ surfaceStyle: StyleValueMap;
143
+ selectionPresentation: DeviceFrameSelectionPresentationHost;
144
+ regionVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
145
+ [key: string]: any;
146
+ }>[]>;
147
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
148
+ //#endregion
149
+ //#region src/components/DevicePicker.d.ts
150
+ type Translate = (key: string, fallback?: string) => string;
151
+ declare const _default$2: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
152
+ context: {
153
+ type: PropType<DeviceFrameContext>;
154
+ required: true;
155
+ };
156
+ translate: {
157
+ type: PropType<Translate>;
158
+ default: undefined;
159
+ };
160
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
161
+ [key: string]: any;
162
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
163
+ context: {
164
+ type: PropType<DeviceFrameContext>;
165
+ required: true;
166
+ };
167
+ translate: {
168
+ type: PropType<Translate>;
169
+ default: undefined;
170
+ };
171
+ }>> & Readonly<{}>, {
172
+ translate: Translate;
173
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
174
+ //#endregion
175
+ //#region src/components/frames/AndroidFrame.d.ts
176
+ /**
177
+ * Android phone frame with status bar and bottom navigation bar.
178
+ * Renders children via the default slot inside the content area.
179
+ */
180
+ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
181
+ layoutPlan: {
182
+ type: PropType<LayoutPlan>;
183
+ default: undefined;
184
+ };
185
+ chromeVNodes: {
186
+ type: PropType<VNode[]>;
187
+ default: () => never[];
188
+ };
189
+ layerVNodes: {
190
+ type: PropType<Record<string, VNode[]>>;
191
+ default: () => {};
192
+ };
193
+ forbiddenOverlayVNode: {
194
+ type: PropType<VNode | null>;
195
+ default: null;
196
+ };
197
+ surfaceStyle: {
198
+ type: PropType<StyleValueMap>;
199
+ default: undefined;
200
+ };
201
+ selectionPresentation: {
202
+ type: PropType<DeviceFrameSelectionPresentationHost>;
203
+ default: undefined;
204
+ };
205
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
206
+ [key: string]: any;
207
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
208
+ layoutPlan: {
209
+ type: PropType<LayoutPlan>;
210
+ default: undefined;
211
+ };
212
+ chromeVNodes: {
213
+ type: PropType<VNode[]>;
214
+ default: () => never[];
215
+ };
216
+ layerVNodes: {
217
+ type: PropType<Record<string, VNode[]>>;
218
+ default: () => {};
219
+ };
220
+ forbiddenOverlayVNode: {
221
+ type: PropType<VNode | null>;
222
+ default: null;
223
+ };
224
+ surfaceStyle: {
225
+ type: PropType<StyleValueMap>;
226
+ default: undefined;
227
+ };
228
+ selectionPresentation: {
229
+ type: PropType<DeviceFrameSelectionPresentationHost>;
230
+ default: undefined;
231
+ };
232
+ }>> & Readonly<{}>, {
233
+ layoutPlan: LayoutPlan;
234
+ chromeVNodes: VNode<import("vue").RendererNode, import("vue").RendererElement, {
235
+ [key: string]: any;
236
+ }>[];
237
+ layerVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
238
+ [key: string]: any;
239
+ }>[]>;
240
+ forbiddenOverlayVNode: VNode<import("vue").RendererNode, import("vue").RendererElement, {
241
+ [key: string]: any;
242
+ }> | null;
243
+ surfaceStyle: StyleValueMap;
244
+ selectionPresentation: DeviceFrameSelectionPresentationHost;
245
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
246
+ //#endregion
247
+ //#region src/components/frames/DesktopFrame.d.ts
248
+ /**
249
+ * Desktop browser chrome frame with title bar, traffic lights, and URL bar.
250
+ * Renders children via the default slot inside the content area.
251
+ */
252
+ declare const _default$1: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
253
+ layoutPlan: {
254
+ type: PropType<LayoutPlan>;
255
+ default: undefined;
256
+ };
257
+ chromeVNodes: {
258
+ type: PropType<VNode[]>;
259
+ default: () => never[];
260
+ };
261
+ layerVNodes: {
262
+ type: PropType<Record<string, VNode[]>>;
263
+ default: () => {};
264
+ };
265
+ forbiddenOverlayVNode: {
266
+ type: PropType<VNode | null>;
267
+ default: null;
268
+ };
269
+ surfaceStyle: {
270
+ type: PropType<StyleValueMap>;
271
+ default: undefined;
272
+ };
273
+ selectionPresentation: {
274
+ type: PropType<DeviceFrameSelectionPresentationHost>;
275
+ default: undefined;
276
+ };
277
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
278
+ [key: string]: any;
279
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
280
+ layoutPlan: {
281
+ type: PropType<LayoutPlan>;
282
+ default: undefined;
283
+ };
284
+ chromeVNodes: {
285
+ type: PropType<VNode[]>;
286
+ default: () => never[];
287
+ };
288
+ layerVNodes: {
289
+ type: PropType<Record<string, VNode[]>>;
290
+ default: () => {};
291
+ };
292
+ forbiddenOverlayVNode: {
293
+ type: PropType<VNode | null>;
294
+ default: null;
295
+ };
296
+ surfaceStyle: {
297
+ type: PropType<StyleValueMap>;
298
+ default: undefined;
299
+ };
300
+ selectionPresentation: {
301
+ type: PropType<DeviceFrameSelectionPresentationHost>;
302
+ default: undefined;
303
+ };
304
+ }>> & Readonly<{}>, {
305
+ layoutPlan: LayoutPlan;
306
+ chromeVNodes: VNode<import("vue").RendererNode, import("vue").RendererElement, {
307
+ [key: string]: any;
308
+ }>[];
309
+ layerVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
310
+ [key: string]: any;
311
+ }>[]>;
312
+ forbiddenOverlayVNode: VNode<import("vue").RendererNode, import("vue").RendererElement, {
313
+ [key: string]: any;
314
+ }> | null;
315
+ surfaceStyle: StyleValueMap;
316
+ selectionPresentation: DeviceFrameSelectionPresentationHost;
317
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
318
+ //#endregion
319
+ //#region src/components/frames/IPhoneFrame.d.ts
320
+ /**
321
+ * iPhone frame with Dynamic Island notch, status bar, and home indicator.
322
+ * Status bar uses a 3-column grid layout: time (left) | Dynamic Island (center) | icons (right),
323
+ * matching the real iPhone status bar layout.
324
+ * Renders children via the default slot inside the content area.
325
+ */
326
+ declare const _default$3: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
327
+ layoutPlan: {
328
+ type: PropType<LayoutPlan>;
329
+ default: undefined;
330
+ };
331
+ chromeVNodes: {
332
+ type: PropType<VNode[]>;
333
+ default: () => never[];
334
+ };
335
+ layerVNodes: {
336
+ type: PropType<Record<string, VNode[]>>;
337
+ default: () => {};
338
+ };
339
+ forbiddenOverlayVNode: {
340
+ type: PropType<VNode | null>;
341
+ default: null;
342
+ };
343
+ surfaceStyle: {
344
+ type: PropType<StyleValueMap>;
345
+ default: undefined;
346
+ };
347
+ selectionPresentation: {
348
+ type: PropType<DeviceFrameSelectionPresentationHost>;
349
+ default: undefined;
350
+ };
351
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
352
+ [key: string]: any;
353
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
354
+ layoutPlan: {
355
+ type: PropType<LayoutPlan>;
356
+ default: undefined;
357
+ };
358
+ chromeVNodes: {
359
+ type: PropType<VNode[]>;
360
+ default: () => never[];
361
+ };
362
+ layerVNodes: {
363
+ type: PropType<Record<string, VNode[]>>;
364
+ default: () => {};
365
+ };
366
+ forbiddenOverlayVNode: {
367
+ type: PropType<VNode | null>;
368
+ default: null;
369
+ };
370
+ surfaceStyle: {
371
+ type: PropType<StyleValueMap>;
372
+ default: undefined;
373
+ };
374
+ selectionPresentation: {
375
+ type: PropType<DeviceFrameSelectionPresentationHost>;
376
+ default: undefined;
377
+ };
378
+ }>> & Readonly<{}>, {
379
+ layoutPlan: LayoutPlan;
380
+ chromeVNodes: VNode<import("vue").RendererNode, import("vue").RendererElement, {
381
+ [key: string]: any;
382
+ }>[];
383
+ layerVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
384
+ [key: string]: any;
385
+ }>[]>;
386
+ forbiddenOverlayVNode: VNode<import("vue").RendererNode, import("vue").RendererElement, {
387
+ [key: string]: any;
388
+ }> | null;
389
+ surfaceStyle: StyleValueMap;
390
+ selectionPresentation: DeviceFrameSelectionPresentationHost;
391
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
392
+ //#endregion
393
+ //#region src/components/frames/TabletFrame.d.ts
394
+ /**
395
+ * Tablet / iPad frame with minimal chrome and thin bezels.
396
+ * Renders children via the default slot inside the content area.
397
+ */
398
+ declare const _default$4: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
399
+ layoutPlan: {
400
+ type: PropType<LayoutPlan>;
401
+ default: undefined;
402
+ };
403
+ chromeVNodes: {
404
+ type: PropType<VNode[]>;
405
+ default: () => never[];
406
+ };
407
+ layerVNodes: {
408
+ type: PropType<Record<string, VNode[]>>;
409
+ default: () => {};
410
+ };
411
+ forbiddenOverlayVNode: {
412
+ type: PropType<VNode | null>;
413
+ default: null;
414
+ };
415
+ surfaceStyle: {
416
+ type: PropType<StyleValueMap>;
417
+ default: undefined;
418
+ };
419
+ selectionPresentation: {
420
+ type: PropType<DeviceFrameSelectionPresentationHost>;
421
+ default: undefined;
422
+ };
423
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
424
+ [key: string]: any;
425
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
426
+ layoutPlan: {
427
+ type: PropType<LayoutPlan>;
428
+ default: undefined;
429
+ };
430
+ chromeVNodes: {
431
+ type: PropType<VNode[]>;
432
+ default: () => never[];
433
+ };
434
+ layerVNodes: {
435
+ type: PropType<Record<string, VNode[]>>;
436
+ default: () => {};
437
+ };
438
+ forbiddenOverlayVNode: {
439
+ type: PropType<VNode | null>;
440
+ default: null;
441
+ };
442
+ surfaceStyle: {
443
+ type: PropType<StyleValueMap>;
444
+ default: undefined;
445
+ };
446
+ selectionPresentation: {
447
+ type: PropType<DeviceFrameSelectionPresentationHost>;
448
+ default: undefined;
449
+ };
450
+ }>> & Readonly<{}>, {
451
+ layoutPlan: LayoutPlan;
452
+ chromeVNodes: VNode<import("vue").RendererNode, import("vue").RendererElement, {
453
+ [key: string]: any;
454
+ }>[];
455
+ layerVNodes: Record<string, VNode<import("vue").RendererNode, import("vue").RendererElement, {
456
+ [key: string]: any;
457
+ }>[]>;
458
+ forbiddenOverlayVNode: VNode<import("vue").RendererNode, import("vue").RendererElement, {
459
+ [key: string]: any;
460
+ }> | null;
461
+ surfaceStyle: StyleValueMap;
462
+ selectionPresentation: DeviceFrameSelectionPresentationHost;
463
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
464
+ //#endregion
465
+ //#region src/composables/useDeviceFrame.d.ts
466
+ /**
467
+ * Convenience composable for consuming device frame state in any descendant.
468
+ * Returns the full context plus commonly needed computed values.
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * const { currentDevice, setDevice, presets } = useDeviceFrame()
473
+ * ```
474
+ */
475
+ declare function useDeviceFrame(): {
476
+ /** Reactive current device type */
477
+ currentDevice: import("vue").Ref<DeviceType, DeviceType>;
478
+ /** Reactive current preset object */
479
+ currentPreset: import("vue").ComputedRef<DevicePreset | undefined>;
480
+ /** Reactive viewport width */
481
+ viewportWidth: import("vue").ComputedRef<number>;
482
+ /** Reactive viewport height */
483
+ viewportHeight: import("vue").ComputedRef<number>;
484
+ /** All available presets */
485
+ presets: readonly DevicePreset[];
486
+ /** Switch device */
487
+ setDevice: (type: DeviceType) => void;
488
+ };
489
+ //#endregion
490
+ //#region src/context.d.ts
491
+ /**
492
+ * Creates a DeviceFrameContext. The caller is responsible for calling
493
+ * `provide(DEVICE_FRAME_CONTEXT_KEY, ctx)` in their setup().
494
+ *
495
+ * @example
496
+ * ```ts
497
+ * const ctx = createDeviceFrameContext({ initialDevice: 'iphone' })
498
+ * provide(DEVICE_FRAME_CONTEXT_KEY, ctx)
499
+ * ```
500
+ */
501
+ declare function createDeviceFrameContext(options?: DeviceFrameOptions): DeviceFrameContext;
502
+ /**
503
+ * Injects the DeviceFrameContext from the nearest ancestor provider.
504
+ * Throws if not found.
505
+ */
506
+ declare function useDeviceFrameContext(): DeviceFrameContext;
507
+ //#endregion
508
+ //#region src/presets.d.ts
509
+ declare const IPHONE_PRESET: DevicePreset;
510
+ declare const ANDROID_PRESET: DevicePreset;
511
+ declare const TABLET_PRESET: DevicePreset;
512
+ declare const DESKTOP_PRESET: DevicePreset;
513
+ /**
514
+ * Returns the built-in device presets: iPhone, Android, Tablet, Desktop.
515
+ */
516
+ declare function getDefaultPresets(): DevicePreset[];
517
+ //#endregion
518
+ export { ANDROID_PRESET, _default as AndroidFrame, DESKTOP_PRESET, DEVICE_FRAME_CONTEXT_KEY, _default$1 as DesktopFrame, type DeviceFrameContext, type DeviceFrameOptions, type DeviceFrameSelectionPlane, type DeviceFrameSelectionPresentationHost, DeviceFrameShell, _default$2 as DevicePicker, type DevicePreset, type DeviceType, IPHONE_PRESET, _default$3 as IPhoneFrame, TABLET_PRESET, _default$4 as TabletFrame, createDeviceFrameContext, getDefaultPresets, useDeviceFrame, useDeviceFrameContext };