@mmtitanl/tablets-core 0.1.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.
@@ -0,0 +1,330 @@
1
+ import * as react from 'react';
2
+ import { RefObject, ComponentType, CSSProperties, ReactNode, Component, ErrorInfo, ReactElement } from 'react';
3
+ import { DeviceMeta, DeviceLayoutContract, SVGScreenRect } from '@mmtitanl/tablets';
4
+ export { SVGScreenRect } from '@mmtitanl/tablets';
5
+
6
+ declare function ptsToPx(pts: number, dpr: number): number;
7
+ declare function pxToPts(px: number, dpr: number): number;
8
+ declare function ptsToPercent(pts: number, total: number): number;
9
+ declare function scaleValue(value: number, scaleFactor: number): number;
10
+ declare const SCALE_STEPS: readonly [0.25, 0.33, 0.5, 0.75, 1];
11
+ declare function computeAdaptiveScale(deviceWidth: number, deviceHeight: number, containerWidth: number, containerHeight: number, padding?: number, maxScale?: number, minScale?: number): number;
12
+ declare function snapToStep(raw: number): number;
13
+ declare function computeHostSize(deviceWidth: number, deviceHeight: number, scale: number): {
14
+ width: number;
15
+ height: number;
16
+ };
17
+ interface AdaptiveScaleResult {
18
+ scale: number;
19
+ scaledWidth: number;
20
+ scaledHeight: number;
21
+ deviceWidth: number;
22
+ deviceHeight: number;
23
+ isAtMaxScale: boolean;
24
+ isConstrained: boolean;
25
+ scalePercent: string;
26
+ }
27
+ declare function computeFullScale(deviceWidth: number, deviceHeight: number, containerWidth: number, containerHeight: number, options?: {
28
+ padding?: number;
29
+ maxScale?: number;
30
+ minScale?: number;
31
+ snapToSteps?: boolean;
32
+ }): AdaptiveScaleResult;
33
+
34
+ interface ContainerSize {
35
+ width: number;
36
+ height: number;
37
+ }
38
+ declare function useContainerSize(ref: RefObject<HTMLElement | null>): ContainerSize;
39
+
40
+ interface UseAdaptiveScaleOptions {
41
+ device: DeviceMeta;
42
+ containerWidth: number;
43
+ containerHeight: number;
44
+ padding?: number;
45
+ maxScale?: number;
46
+ minScale?: number;
47
+ snapToSteps?: boolean;
48
+ orientation?: "portrait" | "landscape";
49
+ }
50
+ declare function useAdaptiveScale(options: UseAdaptiveScaleOptions): AdaptiveScaleResult;
51
+
52
+ interface UseDeviceContractResult {
53
+ contract: DeviceLayoutContract;
54
+ cssVariables: DeviceLayoutContract["cssVariables"];
55
+ contentZone: DeviceLayoutContract["contentZone"]["portrait"];
56
+ }
57
+ declare function useDeviceContract(deviceId: string, orientation?: "portrait" | "landscape"): UseDeviceContractResult;
58
+
59
+ interface UseOrientationResult {
60
+ orientation: "portrait" | "landscape";
61
+ isLandscape: boolean;
62
+ toggle: () => void;
63
+ setOrientation: (o: "portrait" | "landscape") => void;
64
+ }
65
+ /**
66
+ * Hook for managing tablet orientation state with a toggle function.
67
+ *
68
+ * ```tsx
69
+ * const { orientation, toggle } = useOrientation();
70
+ * <button onClick={toggle}>Rotate</button>
71
+ * <DeviceFrame deviceId="ipad-pro-13" orientation={orientation} />
72
+ * ```
73
+ */
74
+ declare function useOrientation(initial?: "portrait" | "landscape"): UseOrientationResult;
75
+
76
+ interface VolumeState {
77
+ level: number;
78
+ muted: boolean;
79
+ hudVisible: boolean;
80
+ volumeUp: () => void;
81
+ volumeDown: () => void;
82
+ toggleMute: () => void;
83
+ }
84
+ declare function useVolumeControl(initialVolume?: number): VolumeState;
85
+
86
+ interface ScreenPowerState {
87
+ isOff: boolean;
88
+ toggle: () => void;
89
+ }
90
+ declare function useScreenPower(): ScreenPowerState;
91
+
92
+ interface DeviceFrameInsets {
93
+ top: number;
94
+ bottom: number;
95
+ left: number;
96
+ right: number;
97
+ }
98
+ interface DeviceFrameInfo {
99
+ insets: DeviceFrameInsets;
100
+ vars: Record<string, string>;
101
+ platform: "ios" | "android" | null;
102
+ deviceId: string | null;
103
+ orientation: "portrait" | "landscape" | null;
104
+ isReady: boolean;
105
+ reportColorScheme: (scheme: "light" | "dark") => void;
106
+ }
107
+ declare function useDeviceFrame(): DeviceFrameInfo;
108
+
109
+ type FoldState = "folded" | "open";
110
+ interface UseFoldStateResult {
111
+ foldState: FoldState;
112
+ isOpen: boolean;
113
+ deviceId: string;
114
+ toggle: () => void;
115
+ setFoldState: (state: FoldState) => void;
116
+ }
117
+ /**
118
+ * Manages fold state for foldable tablet devices.
119
+ * Convention: the open variant uses `${baseDeviceId}-open`.
120
+ */
121
+ declare function useFoldState(baseDeviceId: string, initial?: FoldState): UseFoldStateResult;
122
+
123
+ declare const BIELA_PREFIX: "biela:";
124
+ interface BielaDeviceInfoMessage {
125
+ type: "biela:deviceInfo";
126
+ payload: {
127
+ vars: Record<string, string>;
128
+ platform: "ios" | "android";
129
+ deviceId: string;
130
+ orientation: "portrait" | "landscape";
131
+ };
132
+ }
133
+ interface BielaRequestMessage {
134
+ type: "biela:requestDeviceInfo";
135
+ }
136
+ interface BielaColorSchemeMessage {
137
+ type: "biela:colorScheme";
138
+ payload: {
139
+ scheme: "light" | "dark";
140
+ };
141
+ }
142
+ declare function isBielaMessage(data: unknown): data is {
143
+ type: string;
144
+ };
145
+
146
+ type DeviceSVGComponent = ComponentType<{
147
+ colorScheme?: "light" | "dark";
148
+ style?: CSSProperties;
149
+ }>;
150
+ interface FrameInfo {
151
+ bezelTop: number;
152
+ bezelBottom: number;
153
+ bezelLeft: number;
154
+ bezelRight: number;
155
+ totalWidth: number;
156
+ totalHeight: number;
157
+ screenWidth: number;
158
+ screenHeight: number;
159
+ screenRadius: number;
160
+ /** Optional per-edge overrides. Fall back to screenRadius when unset. */
161
+ screenRadiusTop?: number;
162
+ screenRadiusBottom?: number;
163
+ }
164
+ interface SVGCropArea {
165
+ x: number;
166
+ y: number;
167
+ width: number;
168
+ height: number;
169
+ }
170
+ interface LandscapeSVGRegistration {
171
+ svgString: string;
172
+ frame: FrameInfo;
173
+ cropViewBox?: SVGCropArea;
174
+ screenRect?: SVGScreenRect;
175
+ }
176
+ interface LandscapeBuiltinRegistration {
177
+ component: DeviceSVGComponent;
178
+ frame: FrameInfo;
179
+ screenRect?: SVGScreenRect;
180
+ }
181
+ declare function registerDeviceSVG(deviceId: string, component: DeviceSVGComponent, frame: FrameInfo, screenRect?: SVGScreenRect, landscape?: LandscapeBuiltinRegistration): void;
182
+ declare function registerCustomDeviceSVG(deviceId: string, svgString: string, frame: FrameInfo, cropViewBox?: SVGCropArea, screenRect?: SVGScreenRect, landscape?: LandscapeSVGRegistration): void;
183
+
184
+ interface DeviceFrameProps {
185
+ device?: string;
186
+ deviceId?: string;
187
+ orientation?: "portrait" | "landscape";
188
+ scaleMode?: "fit" | "manual" | "steps";
189
+ manualScale?: number;
190
+ showSafeAreaOverlay?: boolean;
191
+ showDLCPanel?: boolean;
192
+ showScaleBar?: boolean;
193
+ showStatusBar?: boolean;
194
+ colorScheme?: "light" | "dark";
195
+ iframeRef?: RefObject<HTMLIFrameElement | null>;
196
+ onColorSchemeChange?: (scheme: "light" | "dark") => void;
197
+ onContractReady?: (dlc: DeviceLayoutContract) => void;
198
+ onScaleChange?: (scale: number) => void;
199
+ children?: ReactNode;
200
+ }
201
+ declare function DeviceFrame({ device, deviceId, orientation, scaleMode, manualScale, showSafeAreaOverlay, showScaleBar, showStatusBar, colorScheme, iframeRef, onColorSchemeChange, onContractReady, onScaleChange, children, }: DeviceFrameProps): react.JSX.Element;
202
+
203
+ interface DeviceCompareProps {
204
+ deviceA: string;
205
+ deviceB: string;
206
+ orientation?: "portrait" | "landscape";
207
+ colorScheme?: "light" | "dark";
208
+ showSafeAreaOverlay?: boolean;
209
+ showScaleBar?: boolean;
210
+ layout?: "horizontal" | "vertical" | "auto";
211
+ gap?: number;
212
+ children?: ReactNode;
213
+ childrenA?: ReactNode;
214
+ childrenB?: ReactNode;
215
+ onContractReadyA?: (dlc: DeviceLayoutContract) => void;
216
+ onContractReadyB?: (dlc: DeviceLayoutContract) => void;
217
+ }
218
+ declare function DeviceCompare({ deviceA, deviceB, orientation, colorScheme, showSafeAreaOverlay, showScaleBar, layout, gap, children, childrenA, childrenB, onContractReadyA, onContractReadyB, }: DeviceCompareProps): react.JSX.Element;
219
+
220
+ interface Props {
221
+ children: ReactNode;
222
+ fallback?: ReactNode;
223
+ }
224
+ interface State {
225
+ hasError: boolean;
226
+ error: Error | null;
227
+ }
228
+ declare class DeviceErrorBoundary extends Component<Props, State> {
229
+ constructor(props: Props);
230
+ static getDerivedStateFromError(error: Error): State;
231
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
232
+ render(): ReactNode;
233
+ }
234
+
235
+ interface SafeAreaViewProps {
236
+ edges?: Array<"top" | "bottom" | "left" | "right">;
237
+ children: ReactNode;
238
+ style?: CSSProperties;
239
+ }
240
+ declare function SafeAreaView({ edges, children, style }: SafeAreaViewProps): react.JSX.Element;
241
+
242
+ interface SafeAreaOverlayProps {
243
+ contract: DeviceLayoutContract;
244
+ orientation: "portrait" | "landscape";
245
+ }
246
+ declare function SafeAreaOverlay({ contract, orientation }: SafeAreaOverlayProps): react.JSX.Element;
247
+
248
+ interface ScaleBarProps {
249
+ deviceName: string;
250
+ deviceWidth: number;
251
+ deviceHeight: number;
252
+ scale: number;
253
+ scalePercent: string;
254
+ isAtMaxScale: boolean;
255
+ isConstrained: boolean;
256
+ onScaleChange?: (scale: number) => void;
257
+ onFit?: () => void;
258
+ onRealSize?: () => void;
259
+ }
260
+ declare function ScaleBar({ deviceName, deviceWidth, deviceHeight, scale, scalePercent, isAtMaxScale, onScaleChange, onFit, onRealSize, }: ScaleBarProps): react.JSX.Element;
261
+
262
+ interface VolumeHUDProps {
263
+ level: number;
264
+ muted: boolean;
265
+ visible: boolean;
266
+ platform: "ios" | "android";
267
+ }
268
+ declare function VolumeHUD({ level, muted, visible, platform }: VolumeHUDProps): react.JSX.Element | null;
269
+
270
+ type ButtonName = "volumeUp" | "volumeDown" | "power" | "actionButton" | "cameraControl";
271
+ interface HardwareButtonsProps {
272
+ frameContainerRef: RefObject<HTMLDivElement | null>;
273
+ onButtonPress?: (button: ButtonName) => void;
274
+ enabled?: boolean;
275
+ orientation?: "portrait" | "landscape";
276
+ }
277
+ declare function HardwareButtons({ frameContainerRef, onButtonPress, enabled, orientation, }: HardwareButtonsProps): ReactElement | null;
278
+
279
+ interface DynamicStatusBarProps {
280
+ contract: DeviceLayoutContract;
281
+ orientation: "portrait" | "landscape";
282
+ colorScheme: "light" | "dark";
283
+ showLiveClock?: boolean;
284
+ fixedTime?: string;
285
+ }
286
+ declare function DynamicStatusBar({ contract, orientation, colorScheme, showLiveClock, fixedTime, }: DynamicStatusBarProps): react.JSX.Element | null;
287
+
288
+ interface StatusBarIndicatorsProps {
289
+ platform: "ios" | "android";
290
+ colorScheme: "light" | "dark";
291
+ }
292
+ declare function StatusBarIndicators({ platform, colorScheme }: StatusBarIndicatorsProps): react.JSX.Element;
293
+
294
+ interface SVGOverrideEntry {
295
+ deviceId: string;
296
+ name?: string;
297
+ platform?: "ios" | "android";
298
+ formFactor?: "tablet" | "phone" | "foldable";
299
+ /** Reported logical-pt screen size (independent of SVG viewBox scale). */
300
+ logicalScreenWidth?: number;
301
+ logicalScreenHeight?: number;
302
+ svgString: string;
303
+ bezelTop: number;
304
+ bezelBottom: number;
305
+ bezelLeft: number;
306
+ bezelRight: number;
307
+ screenRect?: SVGScreenRect;
308
+ svgStringLandscape?: string;
309
+ bezelTopLandscape?: number;
310
+ bezelBottomLandscape?: number;
311
+ bezelLeftLandscape?: number;
312
+ bezelRightLandscape?: number;
313
+ screenRectLandscape?: SVGScreenRect;
314
+ updatedAt: string;
315
+ }
316
+ declare class CustomSVGStore {
317
+ private storage;
318
+ constructor(storage?: Storage | null);
319
+ getAll(): Record<string, SVGOverrideEntry>;
320
+ save(entry: SVGOverrideEntry): void;
321
+ remove(deviceId: string): void;
322
+ has(deviceId: string): boolean;
323
+ get(deviceId: string): SVGOverrideEntry | undefined;
324
+ applyAll(): void;
325
+ private applyEntry;
326
+ private persist;
327
+ }
328
+ declare function getCustomSVGStore(): CustomSVGStore;
329
+
330
+ export { type AdaptiveScaleResult, BIELA_PREFIX, type BielaColorSchemeMessage, type BielaDeviceInfoMessage, type BielaRequestMessage, type ButtonName, CustomSVGStore, DeviceCompare, type DeviceCompareProps, DeviceErrorBoundary, DeviceFrame, type DeviceFrameInfo, type DeviceFrameInsets, type DeviceFrameProps, DynamicStatusBar, type FoldState, HardwareButtons, SCALE_STEPS, type SVGCropArea, type SVGOverrideEntry, SafeAreaOverlay, SafeAreaView, ScaleBar, type ScreenPowerState, StatusBarIndicators, type UseAdaptiveScaleOptions, type UseDeviceContractResult, type UseFoldStateResult, type UseOrientationResult, VolumeHUD, type VolumeState, computeAdaptiveScale, computeFullScale, computeHostSize, getCustomSVGStore, isBielaMessage, ptsToPercent, ptsToPx, pxToPts, registerCustomDeviceSVG, registerDeviceSVG, scaleValue, snapToStep, useAdaptiveScale, useContainerSize, useDeviceContract, useDeviceFrame, useFoldState, useOrientation, useScreenPower, useVolumeControl };