@limrun/ui 0.4.0-rc.6 → 0.4.0-rc.8

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/index.html CHANGED
@@ -134,7 +134,8 @@
134
134
  .preview-item {
135
135
  flex: 1;
136
136
  min-width: 300px;
137
- max-width: 500px;
137
+ max-width: 800px;
138
+ max-height: 800px;
138
139
  }
139
140
 
140
141
  .preview-item h3 {
@@ -145,7 +146,8 @@
145
146
  }
146
147
 
147
148
  .device-wrapper {
148
- height: 700px;
149
+ height: 100%;
150
+ width: 100%;
149
151
  background: #f9fafb;
150
152
  border-radius: 12px;
151
153
  overflow: hidden;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limrun/ui",
3
- "version": "0.4.0-rc.6",
3
+ "version": "0.4.0-rc.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -12,10 +12,16 @@
12
12
  position: relative;
13
13
  z-index: 20;
14
14
  display: block;
15
- height: 100%;
16
15
  pointer-events: none;
17
16
  user-select: none;
18
- border-radius: 16.8% / 8.7%;
17
+ }
18
+
19
+ .rc-phone-frame-portrait {
20
+ height: 100%;
21
+ }
22
+
23
+ .rc-phone-frame-landscape {
24
+ width: 100%;
19
25
  }
20
26
 
21
27
  .rc-video {
@@ -27,18 +33,37 @@
27
33
  background-color: black;
28
34
  }
29
35
 
36
+ .rc-video-frameless {
37
+ position: relative;
38
+ height: 100%;
39
+ top: auto;
40
+ left: auto;
41
+ }
42
+
30
43
  .rc-video-loading {
31
44
  aspect-ratio: 9 / 19.5;
32
45
  }
33
46
 
34
- .rc-video-ios {
47
+ .rc-video-ios-portrait {
35
48
  top: 1.61%;
36
49
  left: 3.9%;
37
- height: 96.76%;
50
+ height: 96.78%;
38
51
  }
39
52
 
40
- .rc-video-android {
53
+ .rc-video-ios-landscape {
54
+ top: 3.9%;
55
+ left: 1.61%;
56
+ width: 96.78%;
57
+ }
58
+
59
+ .rc-video-android-portrait {
41
60
  top: 2.25%;
42
61
  left: 4.5%;
43
62
  height: 95.9%;
44
63
  }
64
+
65
+ .rc-video-android-landscape {
66
+ left: 2.25%;
67
+ top: 4.5%;
68
+ width: 95.9%;
69
+ }
@@ -6,6 +6,8 @@ import { ANDROID_KEYS, AMOTION_EVENT, codeMap } from '../core/constants';
6
6
 
7
7
  import iphoneFrameImage from '../assets/iphone16pro_black.webp';
8
8
  import pixelFrameImage from '../assets/pixel9_black.webp';
9
+ import pixelFrameImageLandscape from '../assets/pixel9_black_landscape.webp';
10
+ import iphoneFrameImageLandscape from '../assets/iphone16pro_black_landscape.webp';
9
11
  import appleLogoSvg from '../assets/Apple_logo_white.svg';
10
12
  import {
11
13
  createTouchControlMessage,
@@ -41,6 +43,10 @@ interface RemoteControlProps {
41
43
  //
42
44
  // If not provided, the component will not open any URL.
43
45
  openUrl?: string;
46
+
47
+ // showFrame controls whether to display the device frame
48
+ // around the video. Defaults to true.
49
+ showFrame?: boolean;
44
50
  }
45
51
 
46
52
  interface ScreenshotData {
@@ -88,12 +94,14 @@ const detectPlatform = (url: string): DevicePlatform => {
88
94
  const deviceConfig = {
89
95
  ios: {
90
96
  frameImage: iphoneFrameImage,
97
+ frameImageLandscape: iphoneFrameImageLandscape,
91
98
  frameWidthMultiplier: 1.0841,
92
99
  videoBorderRadiusMultiplier: 0.15,
93
100
  loadingLogo: appleLogoSvg,
94
101
  },
95
102
  android: {
96
103
  frameImage: pixelFrameImage,
104
+ frameImageLandscape: pixelFrameImageLandscape,
97
105
  frameWidthMultiplier: 1.107,
98
106
  videoBorderRadiusMultiplier: 0.13,
99
107
  loadingLogo: undefined,
@@ -131,10 +139,11 @@ function getAndroidKeycodeAndMeta(event: React.KeyboardEvent): { keycode: number
131
139
  }
132
140
 
133
141
  export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>(
134
- ({ className, url, token, sessionId: propSessionId, openUrl }: RemoteControlProps, ref) => {
142
+ ({ className, url, token, sessionId: propSessionId, openUrl, showFrame = true }: RemoteControlProps, ref) => {
135
143
  const videoRef = useRef<HTMLVideoElement>(null);
136
144
  const frameRef = useRef<HTMLImageElement>(null);
137
145
  const [videoLoaded, setVideoLoaded] = useState(false);
146
+ const [isLandscape, setIsLandscape] = useState(false);
138
147
  const wsRef = useRef<WebSocket | null>(null);
139
148
  const peerConnectionRef = useRef<RTCPeerConnection | null>(null);
140
149
  const dataChannelRef = useRef<RTCDataChannel | null>(null);
@@ -779,18 +788,22 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
779
788
  useEffect(() => {
780
789
  const video = videoRef.current;
781
790
  const frame = frameRef.current;
782
- if (!video || !frame) return;
791
+ if (!video || !frame || !showFrame) return;
783
792
 
784
793
  const resizeObserver = new ResizeObserver((entries) => {
785
794
  for (const entry of entries) {
795
+ const landscape = entry.contentRect.width > entry.contentRect.height;
796
+ setIsLandscape(landscape);
786
797
  const videoWidth = entry.contentRect.width;
798
+ const videoHeight = entry.contentRect.height;
787
799
  const originalFrameWidth = frame.clientWidth;
788
800
  const newFrameWidth = videoWidth * config.frameWidthMultiplier;
789
801
  // The video is too small up until the first frame is visible, so we need to make sure we don't scale the frame down too much.
790
- if (newFrameWidth > 0.9*originalFrameWidth) {
802
+ if (!landscape && newFrameWidth > 0.9*originalFrameWidth) {
803
+ // This is mostly for iOS where the video size is slightly inconsistent.
791
804
  frame.style.width = `${videoWidth * config.frameWidthMultiplier}px`;
792
805
  }
793
- video.style.borderRadius = `${videoWidth * config.videoBorderRadiusMultiplier}px`;
806
+ video.style.borderRadius = `${(entry.contentRect.width > entry.contentRect.height ? videoHeight : videoWidth) * config.videoBorderRadiusMultiplier}px`;
794
807
  }
795
808
  });
796
809
 
@@ -799,7 +812,7 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
799
812
  return () => {
800
813
  resizeObserver.disconnect();
801
814
  };
802
- }, [config]);
815
+ }, [config, showFrame]);
803
816
 
804
817
  const handleVideoClick = () => {
805
818
  if (videoRef.current) {
@@ -927,18 +940,20 @@ export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>
927
940
  onTouchEnd={handleInteraction}
928
941
  onTouchCancel={handleInteraction}
929
942
  >
930
- <img
931
- ref={frameRef}
932
- src={config.frameImage}
933
- alt=""
934
- className="rc-phone-frame"
935
- draggable={false}
936
- />
943
+ {showFrame && (
944
+ <img
945
+ ref={frameRef}
946
+ src={isLandscape ? config.frameImageLandscape : config.frameImage}
947
+ alt=""
948
+ className={clsx('rc-phone-frame', isLandscape ? 'rc-phone-frame-landscape' : 'rc-phone-frame-portrait')}
949
+ draggable={false}
950
+ />
951
+ )}
937
952
  <video
938
953
  ref={videoRef}
939
954
  className={clsx(
940
955
  'rc-video',
941
- platform === 'ios' ? 'rc-video-ios' : 'rc-video-android',
956
+ showFrame ? (platform === 'ios' ? (isLandscape ? 'rc-video-ios-landscape' : 'rc-video-ios-portrait') : isLandscape ? 'rc-video-android-landscape' : 'rc-video-android-portrait') : 'rc-video-frameless',
942
957
  !videoLoaded && 'rc-video-loading',
943
958
  )}
944
959
  style={
package/src/demo.tsx CHANGED
@@ -3,8 +3,8 @@ import { createRoot } from 'react-dom/client';
3
3
  import { RemoteControl, RemoteControlHandle } from './components/remote-control';
4
4
 
5
5
  function Demo() {
6
- const [url, setUrl] = useState('wss://eu-hel1-5-staging.limrun.dev/v1/organizations/org_01k3v8bvxvecfvscdhvcp3rga1/ios.limrun.com/v1/instances/ios_eustg_01kd5mjeb7fnc8d4yc3f8j8c37/endpointWebSocket');
7
- const [token, setToken] = useState('lim_3f6fc1574c8be1ee23afffe3601512d42f9b2ed486c7320a');
6
+ const [url, setUrl] = useState('wss://eu-hel1-5-staging.limrun.dev/v1/ios_eustg_01kd7xz7wnecrr3qtc0mp9pyb4/endpointWebSocket');
7
+ const [token, setToken] = useState('lim_e38efd8b6b38733e268514a866e7b568d1bdc106632bfc9f');
8
8
  const [platform, setPlatform] = useState<'ios' | 'android'>('ios');
9
9
  const [isConnected, setIsConnected] = useState(false);
10
10
  const [key, setKey] = useState(0);
package/src/image.png ADDED
Binary file
Binary file
Binary file