@mmtitanl/tablets-core 0.3.0 → 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 +93 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -46
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -691,6 +691,14 @@ function ensureBuiltinsRegistered() {
|
|
|
691
691
|
}
|
|
692
692
|
didAutoRegister = true;
|
|
693
693
|
}
|
|
694
|
+
var ROTATE_MS = 450;
|
|
695
|
+
var EASE = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
696
|
+
var SVG_FADE_MS = 240;
|
|
697
|
+
var SVG_FADE_DELAY_MS = 100;
|
|
698
|
+
var CONTENT_FADE_OUT_MS = 140;
|
|
699
|
+
var CONTENT_SWAP_MS = 180;
|
|
700
|
+
var CONTENT_FADE_IN_DELAY_MS = 220;
|
|
701
|
+
var CONTENT_FADE_IN_MS = 230;
|
|
694
702
|
function sendDeviceInfo(iframe, contract, orientation) {
|
|
695
703
|
if (!iframe?.contentWindow) return;
|
|
696
704
|
iframe.contentWindow.postMessage(
|
|
@@ -728,7 +736,24 @@ function DeviceFrame({
|
|
|
728
736
|
const resolvedId = device ?? deviceId;
|
|
729
737
|
if (!resolvedId) throw new Error("DeviceFrame requires `device` or `deviceId`");
|
|
730
738
|
const meta = (0, import_tablets3.getDeviceMetadata)(resolvedId);
|
|
731
|
-
const
|
|
739
|
+
const [contentOrientation, setContentOrientation] = (0, import_react11.useState)(orientation);
|
|
740
|
+
const [contentVisible, setContentVisible] = (0, import_react11.useState)(true);
|
|
741
|
+
const animTimers = (0, import_react11.useRef)([]);
|
|
742
|
+
const prevOrientation = (0, import_react11.useRef)(orientation);
|
|
743
|
+
(0, import_react11.useEffect)(() => {
|
|
744
|
+
if (prevOrientation.current === orientation) return;
|
|
745
|
+
prevOrientation.current = orientation;
|
|
746
|
+
for (const t of animTimers.current) window.clearTimeout(t);
|
|
747
|
+
setContentVisible(false);
|
|
748
|
+
animTimers.current = [
|
|
749
|
+
window.setTimeout(() => setContentOrientation(orientation), CONTENT_SWAP_MS),
|
|
750
|
+
window.setTimeout(() => setContentVisible(true), CONTENT_FADE_IN_DELAY_MS)
|
|
751
|
+
];
|
|
752
|
+
}, [orientation]);
|
|
753
|
+
(0, import_react11.useEffect)(() => () => {
|
|
754
|
+
for (const t of animTimers.current) window.clearTimeout(t);
|
|
755
|
+
}, []);
|
|
756
|
+
const contract = (0, import_react11.useMemo)(() => (0, import_tablets3.getDeviceContract)(resolvedId, contentOrientation), [resolvedId, contentOrientation]);
|
|
732
757
|
const portW = meta.screen.width;
|
|
733
758
|
const portH = meta.screen.height;
|
|
734
759
|
const rotateFrame = orientation === "landscape";
|
|
@@ -737,12 +762,36 @@ function DeviceFrame({
|
|
|
737
762
|
const sentinelRef = (0, import_react11.useRef)(null);
|
|
738
763
|
const frameContainerRef = (0, import_react11.useRef)(null);
|
|
739
764
|
const containerSize = useContainerSize(sentinelRef);
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
const
|
|
743
|
-
const
|
|
744
|
-
const
|
|
745
|
-
const
|
|
765
|
+
const svgEntry = getDeviceSVG(resolvedId);
|
|
766
|
+
const SVGComponent = svgEntry?.component ?? null;
|
|
767
|
+
const LandscapeSVGComponent = svgEntry?.landscapeComponent ?? null;
|
|
768
|
+
const registeredLandscapeFrame = svgEntry?.landscapeFrame;
|
|
769
|
+
const hasLandscapeSVG = !!LandscapeSVGComponent && !!registeredLandscapeFrame;
|
|
770
|
+
const portFrame = svgEntry?.frame ?? {
|
|
771
|
+
bezelTop: 0,
|
|
772
|
+
bezelBottom: 0,
|
|
773
|
+
bezelLeft: 0,
|
|
774
|
+
bezelRight: 0,
|
|
775
|
+
totalWidth: portW,
|
|
776
|
+
totalHeight: portH,
|
|
777
|
+
screenWidth: portW,
|
|
778
|
+
screenHeight: portH,
|
|
779
|
+
screenRadius: 0
|
|
780
|
+
};
|
|
781
|
+
const landFrame = hasLandscapeSVG && registeredLandscapeFrame ? registeredLandscapeFrame : {
|
|
782
|
+
bezelTop: portFrame.totalWidth - portFrame.bezelLeft - portFrame.screenWidth,
|
|
783
|
+
bezelBottom: portFrame.bezelLeft,
|
|
784
|
+
bezelLeft: portFrame.bezelTop,
|
|
785
|
+
bezelRight: portFrame.totalHeight - portFrame.bezelTop - portFrame.screenHeight,
|
|
786
|
+
totalWidth: portFrame.totalHeight,
|
|
787
|
+
totalHeight: portFrame.totalWidth,
|
|
788
|
+
screenWidth: portFrame.screenHeight,
|
|
789
|
+
screenHeight: portFrame.screenWidth,
|
|
790
|
+
screenRadius: portFrame.screenRadius
|
|
791
|
+
};
|
|
792
|
+
const activeFrame = rotateFrame ? landFrame : portFrame;
|
|
793
|
+
const fitW = activeFrame.totalWidth;
|
|
794
|
+
const fitH = activeFrame.totalHeight;
|
|
746
795
|
const fitResult = (0, import_react11.useMemo)(
|
|
747
796
|
() => computeFullScale(fitW, fitH, containerSize.width, containerSize.height, {
|
|
748
797
|
snapToSteps: scaleMode === "steps"
|
|
@@ -765,41 +814,32 @@ function DeviceFrame({
|
|
|
765
814
|
}, [scale, onScaleChange]);
|
|
766
815
|
(0, import_react11.useEffect)(() => {
|
|
767
816
|
if (!iframeRef?.current) return;
|
|
768
|
-
sendDeviceInfo(iframeRef.current, contract,
|
|
769
|
-
const onLoad = () => sendDeviceInfo(iframeRef.current, contract,
|
|
817
|
+
sendDeviceInfo(iframeRef.current, contract, contentOrientation);
|
|
818
|
+
const onLoad = () => sendDeviceInfo(iframeRef.current, contract, contentOrientation);
|
|
770
819
|
iframeRef.current.addEventListener("load", onLoad);
|
|
771
820
|
return () => iframeRef.current?.removeEventListener("load", onLoad);
|
|
772
|
-
}, [iframeRef, contract,
|
|
821
|
+
}, [iframeRef, contract, contentOrientation]);
|
|
773
822
|
(0, import_react11.useEffect)(() => {
|
|
774
823
|
if (!iframeRef) return;
|
|
775
824
|
const handler = (event) => {
|
|
776
825
|
const data = event.data;
|
|
777
826
|
if (!data || typeof data !== "object") return;
|
|
778
827
|
if (data.type === "biela:requestDeviceInfo") {
|
|
779
|
-
sendDeviceInfo(iframeRef.current, contract,
|
|
828
|
+
sendDeviceInfo(iframeRef.current, contract, contentOrientation);
|
|
780
829
|
} else if (data.type === "biela:colorScheme" && data.payload?.scheme) {
|
|
781
830
|
onColorSchemeChange?.(data.payload.scheme);
|
|
782
831
|
}
|
|
783
832
|
};
|
|
784
833
|
window.addEventListener("message", handler);
|
|
785
834
|
return () => window.removeEventListener("message", handler);
|
|
786
|
-
}, [iframeRef, contract,
|
|
787
|
-
const svgEntry = getDeviceSVG(resolvedId);
|
|
788
|
-
const SVGComponent = svgEntry?.component ?? null;
|
|
789
|
-
const portraitFrame = svgEntry?.frame;
|
|
790
|
-
const LandscapeSVGComponent = svgEntry?.landscapeComponent ?? null;
|
|
791
|
-
const landscapeFrame = svgEntry?.landscapeFrame;
|
|
792
|
-
const hasLandscapeSVG = !!LandscapeSVGComponent && !!landscapeFrame;
|
|
835
|
+
}, [iframeRef, contract, contentOrientation, onColorSchemeChange]);
|
|
793
836
|
const cssVarsStyle = contract.cssVariables;
|
|
794
|
-
const
|
|
795
|
-
const
|
|
796
|
-
const
|
|
797
|
-
const
|
|
798
|
-
const
|
|
799
|
-
const
|
|
800
|
-
const contentScreenH = activeFrame?.screenHeight ?? dh;
|
|
801
|
-
const useRotationFallback = rotateFrame && !hasLandscapeSVG;
|
|
802
|
-
const scalerTransform = useRotationFallback ? `scale(${scale}) translate(0px, ${scalerW}px) rotate(-90deg)` : `scale(${scale})`;
|
|
837
|
+
const scalerW = portFrame.totalWidth;
|
|
838
|
+
const scalerH = portFrame.totalHeight;
|
|
839
|
+
const scalerTransform = rotateFrame ? `scale(${scale}) translate(0px, ${landFrame.totalHeight}px) rotate(-90deg)` : `scale(${scale})`;
|
|
840
|
+
const contentLandscape = contentOrientation === "landscape";
|
|
841
|
+
const contentBox = contentLandscape ? { left: landFrame.totalHeight - landFrame.bezelTop, top: landFrame.bezelLeft, width: landFrame.screenWidth, height: landFrame.screenHeight } : { left: portFrame.bezelLeft, top: portFrame.bezelTop, width: portFrame.screenWidth, height: portFrame.screenHeight };
|
|
842
|
+
const contentRadius = contentLandscape ? landFrame.screenRadius : portFrame.screenRadius;
|
|
803
843
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
804
844
|
"div",
|
|
805
845
|
{
|
|
@@ -816,8 +856,10 @@ function DeviceFrame({
|
|
|
816
856
|
height: hostHeight,
|
|
817
857
|
position: "relative",
|
|
818
858
|
flexShrink: 0,
|
|
819
|
-
overflow:
|
|
820
|
-
|
|
859
|
+
// No overflow clipping: at rest the frame fits the host exactly; while
|
|
860
|
+
// rotating, the corners sweep outside and clipping them flat looks bad.
|
|
861
|
+
// The sentinel still clips at the component boundary.
|
|
862
|
+
transition: `width ${ROTATE_MS}ms ${EASE}, height ${ROTATE_MS}ms ${EASE}`
|
|
821
863
|
},
|
|
822
864
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
823
865
|
"div",
|
|
@@ -833,7 +875,7 @@ function DeviceFrame({
|
|
|
833
875
|
transform: scalerTransform,
|
|
834
876
|
transformOrigin: "top left",
|
|
835
877
|
willChange: "transform",
|
|
836
|
-
transition:
|
|
878
|
+
transition: `transform ${ROTATE_MS}ms ${EASE}`
|
|
837
879
|
},
|
|
838
880
|
children: [
|
|
839
881
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -842,24 +884,27 @@ function DeviceFrame({
|
|
|
842
884
|
className: "bielaframe-content",
|
|
843
885
|
style: {
|
|
844
886
|
position: "absolute",
|
|
845
|
-
left:
|
|
846
|
-
top:
|
|
847
|
-
width:
|
|
848
|
-
height:
|
|
887
|
+
left: contentBox.left,
|
|
888
|
+
top: contentBox.top,
|
|
889
|
+
width: contentBox.width,
|
|
890
|
+
height: contentBox.height,
|
|
891
|
+
...contentLandscape ? { transform: "rotate(90deg)", transformOrigin: "top left" } : null,
|
|
849
892
|
overflow: "hidden",
|
|
850
893
|
zIndex: 0,
|
|
851
894
|
background: colorScheme === "dark" ? "#000" : "#fff",
|
|
852
|
-
borderRadius:
|
|
895
|
+
borderRadius: contentRadius,
|
|
896
|
+
opacity: contentVisible ? 1 : 0,
|
|
897
|
+
transition: `opacity ${contentVisible ? CONTENT_FADE_IN_MS : CONTENT_FADE_OUT_MS}ms ${EASE}`,
|
|
853
898
|
...cssVarsStyle
|
|
854
899
|
},
|
|
855
900
|
children: [
|
|
856
901
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DeviceErrorBoundary, { children }),
|
|
857
|
-
showStatusBar && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DynamicStatusBar, { contract, orientation, colorScheme }),
|
|
858
|
-
showSafeAreaOverlay && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SafeAreaOverlay, { contract, orientation })
|
|
902
|
+
showStatusBar && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DynamicStatusBar, { contract, orientation: contentOrientation, colorScheme }),
|
|
903
|
+
showSafeAreaOverlay && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SafeAreaOverlay, { contract, orientation: contentOrientation })
|
|
859
904
|
]
|
|
860
905
|
}
|
|
861
906
|
),
|
|
862
|
-
SVGComponent &&
|
|
907
|
+
SVGComponent && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
863
908
|
"div",
|
|
864
909
|
{
|
|
865
910
|
"aria-hidden": true,
|
|
@@ -867,12 +912,12 @@ function DeviceFrame({
|
|
|
867
912
|
position: "absolute",
|
|
868
913
|
top: 0,
|
|
869
914
|
left: 0,
|
|
870
|
-
width:
|
|
871
|
-
height:
|
|
915
|
+
width: portFrame.totalWidth,
|
|
916
|
+
height: portFrame.totalHeight,
|
|
872
917
|
pointerEvents: "none",
|
|
873
918
|
zIndex: 1,
|
|
874
919
|
opacity: hasLandscapeSVG && rotateFrame ? 0 : 1,
|
|
875
|
-
transition:
|
|
920
|
+
transition: `opacity ${SVG_FADE_MS}ms ${EASE} ${SVG_FADE_DELAY_MS}ms`
|
|
876
921
|
},
|
|
877
922
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
878
923
|
SVGComponent,
|
|
@@ -883,20 +928,22 @@ function DeviceFrame({
|
|
|
883
928
|
)
|
|
884
929
|
}
|
|
885
930
|
),
|
|
886
|
-
hasLandscapeSVG && LandscapeSVGComponent &&
|
|
931
|
+
hasLandscapeSVG && LandscapeSVGComponent && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
887
932
|
"div",
|
|
888
933
|
{
|
|
889
934
|
"aria-hidden": true,
|
|
890
935
|
style: {
|
|
891
936
|
position: "absolute",
|
|
937
|
+
left: landFrame.totalHeight,
|
|
892
938
|
top: 0,
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
939
|
+
width: landFrame.totalWidth,
|
|
940
|
+
height: landFrame.totalHeight,
|
|
941
|
+
transform: "rotate(90deg)",
|
|
942
|
+
transformOrigin: "top left",
|
|
896
943
|
pointerEvents: "none",
|
|
897
944
|
zIndex: 1,
|
|
898
945
|
opacity: rotateFrame ? 1 : 0,
|
|
899
|
-
transition:
|
|
946
|
+
transition: `opacity ${SVG_FADE_MS}ms ${EASE} ${SVG_FADE_DELAY_MS}ms`
|
|
900
947
|
},
|
|
901
948
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
902
949
|
LandscapeSVGComponent,
|