@notapublicfigureanymore/relay-sdk 0.0.4 → 0.0.5
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/README.md +313 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -1
- package/dist/index.d.ts +104 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# @notapublicfigureanymore/relay-sdk
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/%40notapublicfigureanymore%2Frelay-sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Complete documentation for building Relay Apps with `@notapublicfigureanymore/relay-sdk`.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Platform Components: Keyboard avoiding views, safe area support, haptic feedback
|
|
11
|
+
- UI Components: Complete component library with 40+ modern components
|
|
12
|
+
- Modern Hooks: Device sensors, notifications, clipboard, camera access
|
|
13
|
+
- TypeScript: Full TypeScript support with comprehensive type definitions
|
|
14
|
+
- Fast: Built with modern React and optimized for performance
|
|
15
|
+
- Small: Tree-shakable with minimal bundle impact
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install the SDK in your Relay App project.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @notapublicfigureanymore/relay-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Peer dependencies required:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install react@^19.0.0 react-dom@^19.0.0 tailwindcss@>=3
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Platform & UI
|
|
33
|
+
|
|
34
|
+
Core components for handling safe areas and device capabilities.
|
|
35
|
+
|
|
36
|
+
### SafeAreaProvider
|
|
37
|
+
|
|
38
|
+
Essential provider that handles notch and safe area insets. Wrap your app in this.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { SafeAreaProvider } from '@notapublicfigureanymore/relay-sdk';
|
|
42
|
+
|
|
43
|
+
export default function App() {
|
|
44
|
+
return (
|
|
45
|
+
<SafeAreaProvider>
|
|
46
|
+
<YourApp />
|
|
47
|
+
</SafeAreaProvider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### usePlatform()
|
|
53
|
+
|
|
54
|
+
Get information about the current device environment.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { usePlatform } from '@notapublicfigureanymore/relay-sdk';
|
|
58
|
+
|
|
59
|
+
const { os, isMobile } = usePlatform();
|
|
60
|
+
|
|
61
|
+
if (isMobile) {
|
|
62
|
+
// Render mobile layout
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## UI Components
|
|
67
|
+
|
|
68
|
+
Complete component library with 40+ modern components including Button, Card, Dialog, Input, Select, Tabs, etc.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import {
|
|
72
|
+
Button,
|
|
73
|
+
Card,
|
|
74
|
+
Dialog,
|
|
75
|
+
Input,
|
|
76
|
+
Select,
|
|
77
|
+
Tabs,
|
|
78
|
+
// ... and 30+ more components
|
|
79
|
+
} from '@notapublicfigureanymore/relay-sdk';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Notifications
|
|
83
|
+
|
|
84
|
+
Send system notifications and manage app badges. The SDK automatically uses your app's icon if available.
|
|
85
|
+
|
|
86
|
+
### useNotifications()
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { useNotifications } from '@notapublicfigureanymore/relay-sdk';
|
|
90
|
+
|
|
91
|
+
export function NotificationDemo() {
|
|
92
|
+
const {
|
|
93
|
+
requestPermission,
|
|
94
|
+
sendNotification,
|
|
95
|
+
setBadge,
|
|
96
|
+
permission
|
|
97
|
+
} = useNotifications();
|
|
98
|
+
|
|
99
|
+
const handleNotify = async () => {
|
|
100
|
+
// 1. Check/Request Permission
|
|
101
|
+
if (permission !== 'granted') {
|
|
102
|
+
await requestPermission();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 2. Send Notification
|
|
106
|
+
// Note: Automatically uses app icon from <link rel="icon">
|
|
107
|
+
sendNotification('New Message', {
|
|
108
|
+
body: 'You have a new message from Relay',
|
|
109
|
+
tag: 'message-1' // Prevents duplicates
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// 3. Update App Badge
|
|
113
|
+
await setBadge(1);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Clipboard
|
|
119
|
+
|
|
120
|
+
Access the system clipboard with built-in history management.
|
|
121
|
+
|
|
122
|
+
### useClipboard()
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { useClipboard } from '@notapublicfigureanymore/relay-sdk';
|
|
126
|
+
|
|
127
|
+
export function ClipboardDemo() {
|
|
128
|
+
const {
|
|
129
|
+
copyText,
|
|
130
|
+
readText,
|
|
131
|
+
history
|
|
132
|
+
} = useClipboard();
|
|
133
|
+
|
|
134
|
+
const handleCopy = async () => {
|
|
135
|
+
await copyText('Copied from Relay!');
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const handlePaste = async () => {
|
|
139
|
+
const text = await readText();
|
|
140
|
+
console.log('Clipboard content:', text);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Access history
|
|
144
|
+
// history = [{ type: 'text', content: '...', timestamp: 123 }, ...]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Geolocation
|
|
149
|
+
|
|
150
|
+
Access device location and calculate distances.
|
|
151
|
+
|
|
152
|
+
### useGeolocation()
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { useGeolocation } from '@notapublicfigureanymore/relay-sdk';
|
|
156
|
+
|
|
157
|
+
export function LocationDemo() {
|
|
158
|
+
const {
|
|
159
|
+
latitude,
|
|
160
|
+
longitude,
|
|
161
|
+
loading,
|
|
162
|
+
error,
|
|
163
|
+
getLocation
|
|
164
|
+
} = useGeolocation();
|
|
165
|
+
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
getLocation();
|
|
168
|
+
}, []);
|
|
169
|
+
|
|
170
|
+
if (loading) return <div>Locating...</div>;
|
|
171
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<div>
|
|
175
|
+
Position: {latitude}, {longitude}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Camera Access
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
import { useCamera } from '@notapublicfigureanymore/relay-sdk';
|
|
185
|
+
|
|
186
|
+
function CameraExample() {
|
|
187
|
+
const { devices, startCamera, stopCamera, capturePhoto } = useCamera();
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div>
|
|
191
|
+
<select onChange={(e) => startCamera(e.target.value)}>
|
|
192
|
+
<option>Select Camera</option>
|
|
193
|
+
{devices.map(device => (
|
|
194
|
+
<option key={device.deviceId} value={device.deviceId}>
|
|
195
|
+
{device.label}
|
|
196
|
+
</option>
|
|
197
|
+
))}
|
|
198
|
+
</select>
|
|
199
|
+
<Button onClick={capturePhoto}>Take Photo</Button>
|
|
200
|
+
<Button onClick={stopCamera}>Stop Camera</Button>
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Platform Detection
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
import {
|
|
210
|
+
useColorScheme,
|
|
211
|
+
useSafeArea,
|
|
212
|
+
useAppState,
|
|
213
|
+
useStatusBar
|
|
214
|
+
} from '@notapublicfigureanymore/relay-sdk';
|
|
215
|
+
|
|
216
|
+
function PlatformExample() {
|
|
217
|
+
const colorScheme = useColorScheme();
|
|
218
|
+
const safeArea = useSafeArea();
|
|
219
|
+
const appState = useAppState();
|
|
220
|
+
|
|
221
|
+
// Set status bar color based on theme
|
|
222
|
+
useStatusBar(colorScheme === 'dark' ? '#000000' : '#ffffff');
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<div>
|
|
226
|
+
<p>Theme: {colorScheme}</p>
|
|
227
|
+
<p>App State: {appState}</p>
|
|
228
|
+
<p>Safe Area Top: {safeArea.top}px</p>
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Platform Hooks
|
|
235
|
+
|
|
236
|
+
Additional platform utilities for device interaction.
|
|
237
|
+
|
|
238
|
+
### useKeyboard()
|
|
239
|
+
|
|
240
|
+
Track virtual keyboard state for mobile devices.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
import { useKeyboard } from '@notapublicfigureanymore/relay-sdk';
|
|
244
|
+
|
|
245
|
+
const keyboard = useKeyboard();
|
|
246
|
+
|
|
247
|
+
// Adjust layout based on keyboard state
|
|
248
|
+
<div style={{
|
|
249
|
+
paddingBottom: keyboard.isOpen ? keyboard.height : 0
|
|
250
|
+
}}>
|
|
251
|
+
<Input placeholder="Type here..." />
|
|
252
|
+
</div>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### useBackHandler()
|
|
256
|
+
|
|
257
|
+
Handle back navigation with custom behavior.
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import { useBackHandler } from '@notapublicfigureanymore/relay-sdk';
|
|
261
|
+
|
|
262
|
+
useBackHandler(() => {
|
|
263
|
+
// Return true to prevent default back behavior
|
|
264
|
+
const shouldPrevent = confirm('Are you sure you want to go back?');
|
|
265
|
+
return shouldPrevent;
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Styling
|
|
270
|
+
|
|
271
|
+
The SDK uses Tailwind CSS for styling. Make sure your `tailwind.config.js` includes:
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
/** @type {import('tailwindcss').Config} */
|
|
275
|
+
module.exports = {
|
|
276
|
+
content: [
|
|
277
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
278
|
+
'./node_modules/@notapublicfigureanymore/relay-sdk/dist/**/*.{js,ts,jsx,tsx}'
|
|
279
|
+
],
|
|
280
|
+
// ... rest of your config
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## API Reference
|
|
285
|
+
|
|
286
|
+
### Platform Hooks
|
|
287
|
+
- `useSafeArea()` - Get device safe area insets
|
|
288
|
+
- `useColorScheme()` - Get current color scheme preference
|
|
289
|
+
- `useStatusBar(color)` - Control status bar appearance
|
|
290
|
+
- `useBackHandler(handler)` - Handle back navigation
|
|
291
|
+
- `useAppState()` - Track app foreground/background state
|
|
292
|
+
- `useKeyboard()` - Track virtual keyboard state
|
|
293
|
+
- `usePlatform()` - Get device environment information
|
|
294
|
+
|
|
295
|
+
### Device Hooks
|
|
296
|
+
- `useNotifications()` - Send and schedule notifications
|
|
297
|
+
- `useClipboard()` - Read/write clipboard content
|
|
298
|
+
- `useGeolocation()` - Access device location
|
|
299
|
+
- `useCamera()` - Camera and media capture
|
|
300
|
+
|
|
301
|
+
### UI Components
|
|
302
|
+
- 40+ components including Button, Card, Dialog, Input, Select, Tabs, etc.
|
|
303
|
+
|
|
304
|
+
## Links
|
|
305
|
+
|
|
306
|
+
- [Relay Platform](https://relay.notapublicfigureanymore.com) - Learn more about Relay
|
|
307
|
+
- [Documentation](https://relay.notapublicfigureanymore.com/docs/sdk) - Full API documentation
|
|
308
|
+
- [Examples](https://github.com/Jaseunda/clips/tree/main/open) - Example apps
|
|
309
|
+
- [Issues](https://github.com/Jaseunda/clips/issues) - Report bugs
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunk7RGKC52Kcjs = require('./chunk-7RGKC52K.cjs');var _react = require('react');function
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunk7RGKC52Kcjs = require('./chunk-7RGKC52K.cjs');var _react = require('react');function L(){let[t,e]=_react.useState.call(void 0, {isOpen:!1,height:0});return _react.useEffect.call(void 0, ()=>{if(!/iPad|iPhone|iPod|Android/.test(navigator.userAgent))return;let o=()=>{if(!window.visualViewport)return;let u=window.visualViewport,d=window.innerHeight-u.height,p=d>100;e({isOpen:p,height:p?d:0})};window.visualViewport&&(window.visualViewport.addEventListener("resize",o),window.visualViewport.addEventListener("scroll",o));let n=u=>{let d=u.target;(d.tagName==="INPUT"||d.tagName==="TEXTAREA")&&setTimeout(o,100)},l=()=>{setTimeout(()=>{e({isOpen:!1,height:0})},100)};return document.addEventListener("focusin",n),document.addEventListener("focusout",l),o(),()=>{_optionalChain([window, 'access', _2 => _2.visualViewport, 'optionalAccess', _3 => _3.removeEventListener, 'call', _4 => _4("resize",o)]),_optionalChain([window, 'access', _5 => _5.visualViewport, 'optionalAccess', _6 => _6.removeEventListener, 'call', _7 => _7("scroll",o)]),document.removeEventListener("focusin",n),document.removeEventListener("focusout",l)}},[]),t}function Di(){return _react.useCallback.call(void 0, ()=>{window.parent!==window&&window.parent.postMessage("relay:close","*"),window.opener&&window.opener.postMessage("relay:close","*"),window.close()},[])}var _jsxruntime = require('react/jsx-runtime');var R={top:0,bottom:0,left:0,right:0},O=_react.createContext.call(void 0, R);function Ki({children:t}){let[e,a]=_react.useState.call(void 0, R);return _react.useEffect.call(void 0, ()=>{let o=()=>{let l=getComputedStyle(document.documentElement),u=r=>{let s=l.getPropertyValue(`--safe-area-inset-${r}`);return parseInt(s)||0},d=u("top"),p=u("bottom"),f=u("left"),i=u("right");if(d===0&&p===0){let r=document.createElement("div");r.style.cssText=`
|
|
2
2
|
position: fixed;
|
|
3
3
|
top: env(safe-area-inset-top, 0px);
|
|
4
4
|
bottom: env(safe-area-inset-bottom, 0px);
|
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
right: env(safe-area-inset-right, 0px);
|
|
7
7
|
pointer-events: none;
|
|
8
8
|
visibility: hidden;
|
|
9
|
-
`,document.body.appendChild(d);let u=d.getBoundingClientRect();a=u.top,l=window.innerHeight-u.bottom,h=u.left,p=window.innerWidth-u.right,document.body.removeChild(d)}r({top:a,bottom:l,left:h,right:p})},n=s=>{_optionalChain([s, 'access', _8 => _8.data, 'optionalAccess', _9 => _9.type])==="relay:safearea"&&r(s.data.insets)};return o(),window.addEventListener("message",n),window.addEventListener("resize",o),()=>{window.removeEventListener("message",n),window.removeEventListener("resize",o)}},[]),_jsxruntime.jsx.call(void 0, y.Provider,{value:e,children:t})}function E(){return _react.useContext.call(void 0, y)}function ks(){let[t,e]=_react.useState.call(void 0, ()=>window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return _react.useEffect.call(void 0, ()=>{let r=window.matchMedia("(prefers-color-scheme: dark)"),o=n=>{e(n.matches?"dark":"light")};return r.addEventListener("change",o),()=>r.removeEventListener("change",o)},[]),t}function Ls(t){_react.useEffect.call(void 0, ()=>{let e=document.querySelector('meta[name="theme-color"]');e||(e=document.createElement("meta"),e.setAttribute("name","theme-color"),document.head.appendChild(e)),e.setAttribute("content",t),_optionalChain([window, 'access', _10 => _10.parent, 'optionalAccess', _11 => _11.postMessage, 'call', _12 => _12({type:"relay:statusbar",color:t},"*")])},[t])}function Cs(t){_react.useEffect.call(void 0, ()=>{let e=o=>{o.data==="relay:back"&&(t()||_optionalChain([window, 'access', _13 => _13.parent, 'optionalAccess', _14 => _14.postMessage, 'call', _15 => _15("relay:close","*")]))},r=o=>{t()&&window.history.pushState(null,"",window.location.href)};return window.history.pushState(null,"",window.location.href),window.addEventListener("message",e),window.addEventListener("popstate",r),()=>{window.removeEventListener("message",e),window.removeEventListener("popstate",r)}},[t])}function Ps(){let[t,e]=_react.useState.call(void 0, "active");return _react.useEffect.call(void 0, ()=>{let r=()=>{e(document.hidden?"background":"active")},o=n=>{n.data==="relay:foreground"&&e("active"),n.data==="relay:background"&&e("background")};return document.addEventListener("visibilitychange",r),window.addEventListener("message",o),()=>{document.removeEventListener("visibilitychange",r),window.removeEventListener("message",o)}},[]),t}function Bs({children:t,behavior:e="padding",keyboardVerticalOffset:r=0,style:o,className:n}){let s=S(),i=s.height+r,a={...o,transition:"all 0.2s ease-out"};if(s.isOpen)switch(e){case"padding":a.paddingBottom=i;break;case"height":a.height=`calc(100% - ${i}px)`;break;case"position":a.transform=`translateY(-${i}px)`;break}return _jsxruntime.jsx.call(void 0, "div",{style:a,className:n,children:t})}function Ns({children:t,edges:e=["top","bottom","left","right"],style:r,className:o}){let n=E(),s={...r,paddingTop:e.includes("top")?n.top:_optionalChain([r, 'optionalAccess', _16 => _16.paddingTop]),paddingBottom:e.includes("bottom")?n.bottom:_optionalChain([r, 'optionalAccess', _17 => _17.paddingBottom]),paddingLeft:e.includes("left")?n.left:_optionalChain([r, 'optionalAccess', _18 => _18.paddingLeft]),paddingRight:e.includes("right")?n.right:_optionalChain([r, 'optionalAccess', _19 => _19.paddingRight])};return _jsxruntime.jsx.call(void 0, "div",{style:s,className:o,children:t})}function Hs(){let[t,e]=_react.useState.call(void 0, 1500),[r,o]=_react.useState.call(void 0, 1500),[n,s]=_react.useState.call(void 0, !1),[i,a]=_react.useState.call(void 0, "focus"),[l,h]=_react.useState.call(void 0, ""),[p,d]=_react.useState.call(void 0, "egg"),[u,k]=_react.useState.call(void 0, !1);_react.useEffect.call(void 0, ()=>{let c=null;if(n&&t>0)c=setInterval(()=>{e(f=>f-1)},1e3);else if(t===0&&n&&(s(!1),i==="focus")){let f=Math.random()<.01;d(f?"alien":"chick")}return()=>{c&&clearInterval(c)}},[n,t,i]),_react.useEffect.call(void 0, ()=>{if(!n&&(p==="chick"||p==="alien"||p==="ghost")||i!=="focus")return;let c=1-t/r;c<.5?d("egg"):c>=.5&&c<1&&d("cracked")},[t,r,n,p,i]);let L=()=>s(!n),C=()=>{s(!1),d("ghost")},w=c=>{s(!1),a(c),d("egg");let f=1500;c==="shortBreak"&&(f=300),c==="longBreak"&&(f=900),e(f),o(f)};return{seconds:t,initialTime:r,isActive:n,mode:i,task:l,storyState:p,soundEnabled:u,setSeconds:e,setInitialTime:o,setIsActive:s,setMode:a,setTask:h,setStoryState:d,setSoundEnabled:k,toggleTimer:L,giveUp:C,switchMode:w,resetTimer:()=>{s(!1),w(i)},setCustomTime:c=>{s(!1),e(c*60),o(c*60),d("egg")}}}exports.Accordion = _chunk7RGKC52Kcjs.b; exports.AccordionContent = _chunk7RGKC52Kcjs.e; exports.AccordionItem = _chunk7RGKC52Kcjs.c; exports.AccordionTrigger = _chunk7RGKC52Kcjs.d; exports.Alert = _chunk7RGKC52Kcjs.t; exports.AlertAction = _chunk7RGKC52Kcjs.w; exports.AlertDescription = _chunk7RGKC52Kcjs.v; exports.AlertDialog = _chunk7RGKC52Kcjs.h; exports.AlertDialogAction = _chunk7RGKC52Kcjs.r; exports.AlertDialogCancel = _chunk7RGKC52Kcjs.s; exports.AlertDialogContent = _chunk7RGKC52Kcjs.l; exports.AlertDialogDescription = _chunk7RGKC52Kcjs.q; exports.AlertDialogFooter = _chunk7RGKC52Kcjs.n; exports.AlertDialogHeader = _chunk7RGKC52Kcjs.m; exports.AlertDialogMedia = _chunk7RGKC52Kcjs.o; exports.AlertDialogOverlay = _chunk7RGKC52Kcjs.k; exports.AlertDialogPortal = _chunk7RGKC52Kcjs.j; exports.AlertDialogTitle = _chunk7RGKC52Kcjs.p; exports.AlertDialogTrigger = _chunk7RGKC52Kcjs.i; exports.AlertTitle = _chunk7RGKC52Kcjs.u; exports.AspectRatio = _chunk7RGKC52Kcjs.x; exports.Avatar = _chunk7RGKC52Kcjs.y; exports.AvatarBadge = _chunk7RGKC52Kcjs.B; exports.AvatarFallback = _chunk7RGKC52Kcjs.A; exports.AvatarGroup = _chunk7RGKC52Kcjs.C; exports.AvatarGroupCount = _chunk7RGKC52Kcjs.D; exports.AvatarImage = _chunk7RGKC52Kcjs.z; exports.Badge = _chunk7RGKC52Kcjs.F; exports.Breadcrumb = _chunk7RGKC52Kcjs.G; exports.BreadcrumbEllipsis = _chunk7RGKC52Kcjs.M; exports.BreadcrumbItem = _chunk7RGKC52Kcjs.I; exports.BreadcrumbLink = _chunk7RGKC52Kcjs.J; exports.BreadcrumbList = _chunk7RGKC52Kcjs.H; exports.BreadcrumbPage = _chunk7RGKC52Kcjs.K; exports.BreadcrumbSeparator = _chunk7RGKC52Kcjs.L; exports.Button = _chunk7RGKC52Kcjs.g; exports.ButtonGroup = _chunk7RGKC52Kcjs.P; exports.ButtonGroupSeparator = _chunk7RGKC52Kcjs.R; exports.ButtonGroupText = _chunk7RGKC52Kcjs.Q; exports.Calendar = _chunk7RGKC52Kcjs.S; exports.CalendarDayButton = _chunk7RGKC52Kcjs.T; exports.Card = _chunk7RGKC52Kcjs.U; exports.CardAction = _chunk7RGKC52Kcjs.Y; exports.CardContent = _chunk7RGKC52Kcjs.Z; exports.CardDescription = _chunk7RGKC52Kcjs.X; exports.CardFooter = _chunk7RGKC52Kcjs._; exports.CardHeader = _chunk7RGKC52Kcjs.V; exports.CardTitle = _chunk7RGKC52Kcjs.W; exports.Carousel = _chunk7RGKC52Kcjs.aa; exports.CarouselContent = _chunk7RGKC52Kcjs.ba; exports.CarouselItem = _chunk7RGKC52Kcjs.ca; exports.CarouselNext = _chunk7RGKC52Kcjs.ea; exports.CarouselPrevious = _chunk7RGKC52Kcjs.da; exports.ChartContainer = _chunk7RGKC52Kcjs.fa; exports.ChartLegend = _chunk7RGKC52Kcjs.ja; exports.ChartLegendContent = _chunk7RGKC52Kcjs.ka; exports.ChartStyle = _chunk7RGKC52Kcjs.ga; exports.ChartTooltip = _chunk7RGKC52Kcjs.ha; exports.ChartTooltipContent = _chunk7RGKC52Kcjs.ia; exports.Checkbox = _chunk7RGKC52Kcjs.la; exports.Collapsible = _chunk7RGKC52Kcjs.ma; exports.CollapsibleContent = _chunk7RGKC52Kcjs.oa; exports.CollapsibleTrigger = _chunk7RGKC52Kcjs.na; exports.Combobox = _chunk7RGKC52Kcjs.xa; exports.ComboboxChip = _chunk7RGKC52Kcjs.Ka; exports.ComboboxChips = _chunk7RGKC52Kcjs.Ja; exports.ComboboxChipsInput = _chunk7RGKC52Kcjs.La; exports.ComboboxCollection = _chunk7RGKC52Kcjs.Ga; exports.ComboboxContent = _chunk7RGKC52Kcjs.Ba; exports.ComboboxEmpty = _chunk7RGKC52Kcjs.Ha; exports.ComboboxGroup = _chunk7RGKC52Kcjs.Ea; exports.ComboboxInput = _chunk7RGKC52Kcjs.Aa; exports.ComboboxItem = _chunk7RGKC52Kcjs.Da; exports.ComboboxLabel = _chunk7RGKC52Kcjs.Fa; exports.ComboboxList = _chunk7RGKC52Kcjs.Ca; exports.ComboboxSeparator = _chunk7RGKC52Kcjs.Ia; exports.ComboboxTrigger = _chunk7RGKC52Kcjs.za; exports.ComboboxValue = _chunk7RGKC52Kcjs.ya; exports.Command = _chunk7RGKC52Kcjs.Xa; exports.CommandDialog = _chunk7RGKC52Kcjs.Ya; exports.CommandEmpty = _chunk7RGKC52Kcjs.$a; exports.CommandGroup = _chunk7RGKC52Kcjs.ab; exports.CommandInput = _chunk7RGKC52Kcjs.Za; exports.CommandItem = _chunk7RGKC52Kcjs.cb; exports.CommandList = _chunk7RGKC52Kcjs._a; exports.CommandSeparator = _chunk7RGKC52Kcjs.bb; exports.CommandShortcut = _chunk7RGKC52Kcjs.db; exports.ContextMenu = _chunk7RGKC52Kcjs.eb; exports.ContextMenuCheckboxItem = _chunk7RGKC52Kcjs.ob; exports.ContextMenuContent = _chunk7RGKC52Kcjs.kb; exports.ContextMenuGroup = _chunk7RGKC52Kcjs.gb; exports.ContextMenuItem = _chunk7RGKC52Kcjs.lb; exports.ContextMenuLabel = _chunk7RGKC52Kcjs.qb; exports.ContextMenuPortal = _chunk7RGKC52Kcjs.hb; exports.ContextMenuRadioGroup = _chunk7RGKC52Kcjs.jb; exports.ContextMenuRadioItem = _chunk7RGKC52Kcjs.pb; exports.ContextMenuSeparator = _chunk7RGKC52Kcjs.rb; exports.ContextMenuShortcut = _chunk7RGKC52Kcjs.sb; exports.ContextMenuSub = _chunk7RGKC52Kcjs.ib; exports.ContextMenuSubContent = _chunk7RGKC52Kcjs.nb; exports.ContextMenuSubTrigger = _chunk7RGKC52Kcjs.mb; exports.ContextMenuTrigger = _chunk7RGKC52Kcjs.fb; exports.Dialog = _chunk7RGKC52Kcjs.Na; exports.DialogClose = _chunk7RGKC52Kcjs.Qa; exports.DialogContent = _chunk7RGKC52Kcjs.Sa; exports.DialogDescription = _chunk7RGKC52Kcjs.Wa; exports.DialogFooter = _chunk7RGKC52Kcjs.Ua; exports.DialogHeader = _chunk7RGKC52Kcjs.Ta; exports.DialogOverlay = _chunk7RGKC52Kcjs.Ra; exports.DialogPortal = _chunk7RGKC52Kcjs.Pa; exports.DialogTitle = _chunk7RGKC52Kcjs.Va; exports.DialogTrigger = _chunk7RGKC52Kcjs.Oa; exports.Drawer = _chunk7RGKC52Kcjs.tb; exports.DrawerClose = _chunk7RGKC52Kcjs.wb; exports.DrawerContent = _chunk7RGKC52Kcjs.yb; exports.DrawerDescription = _chunk7RGKC52Kcjs.Cb; exports.DrawerFooter = _chunk7RGKC52Kcjs.Ab; exports.DrawerHeader = _chunk7RGKC52Kcjs.zb; exports.DrawerOverlay = _chunk7RGKC52Kcjs.xb; exports.DrawerPortal = _chunk7RGKC52Kcjs.vb; exports.DrawerTitle = _chunk7RGKC52Kcjs.Bb; exports.DrawerTrigger = _chunk7RGKC52Kcjs.ub; exports.DropdownMenu = _chunk7RGKC52Kcjs.Db; exports.DropdownMenuCheckboxItem = _chunk7RGKC52Kcjs.Jb; exports.DropdownMenuContent = _chunk7RGKC52Kcjs.Gb; exports.DropdownMenuGroup = _chunk7RGKC52Kcjs.Hb; exports.DropdownMenuItem = _chunk7RGKC52Kcjs.Ib; exports.DropdownMenuLabel = _chunk7RGKC52Kcjs.Mb; exports.DropdownMenuPortal = _chunk7RGKC52Kcjs.Eb; exports.DropdownMenuRadioGroup = _chunk7RGKC52Kcjs.Kb; exports.DropdownMenuRadioItem = _chunk7RGKC52Kcjs.Lb; exports.DropdownMenuSeparator = _chunk7RGKC52Kcjs.Nb; exports.DropdownMenuShortcut = _chunk7RGKC52Kcjs.Ob; exports.DropdownMenuSub = _chunk7RGKC52Kcjs.Pb; exports.DropdownMenuSubContent = _chunk7RGKC52Kcjs.Rb; exports.DropdownMenuSubTrigger = _chunk7RGKC52Kcjs.Qb; exports.DropdownMenuTrigger = _chunk7RGKC52Kcjs.Fb; exports.Empty = _chunk7RGKC52Kcjs.Sb; exports.EmptyContent = _chunk7RGKC52Kcjs.Xb; exports.EmptyDescription = _chunk7RGKC52Kcjs.Wb; exports.EmptyHeader = _chunk7RGKC52Kcjs.Tb; exports.EmptyMedia = _chunk7RGKC52Kcjs.Ub; exports.EmptyTitle = _chunk7RGKC52Kcjs.Vb; exports.Field = _chunk7RGKC52Kcjs.ac; exports.FieldContent = _chunk7RGKC52Kcjs.bc; exports.FieldDescription = _chunk7RGKC52Kcjs.ec; exports.FieldError = _chunk7RGKC52Kcjs.gc; exports.FieldGroup = _chunk7RGKC52Kcjs.$b; exports.FieldLabel = _chunk7RGKC52Kcjs.cc; exports.FieldLegend = _chunk7RGKC52Kcjs._b; exports.FieldSeparator = _chunk7RGKC52Kcjs.fc; exports.FieldSet = _chunk7RGKC52Kcjs.Zb; exports.FieldTitle = _chunk7RGKC52Kcjs.dc; exports.HoverCard = _chunk7RGKC52Kcjs.hc; exports.HoverCardContent = _chunk7RGKC52Kcjs.jc; exports.HoverCardTrigger = _chunk7RGKC52Kcjs.ic; exports.Input = _chunk7RGKC52Kcjs.pa; exports.InputGroup = _chunk7RGKC52Kcjs.ra; exports.InputGroupAddon = _chunk7RGKC52Kcjs.sa; exports.InputGroupButton = _chunk7RGKC52Kcjs.ta; exports.InputGroupInput = _chunk7RGKC52Kcjs.va; exports.InputGroupText = _chunk7RGKC52Kcjs.ua; exports.InputGroupTextarea = _chunk7RGKC52Kcjs.wa; exports.InputOTP = _chunk7RGKC52Kcjs.kc; exports.InputOTPGroup = _chunk7RGKC52Kcjs.lc; exports.InputOTPSeparator = _chunk7RGKC52Kcjs.nc; exports.InputOTPSlot = _chunk7RGKC52Kcjs.mc; exports.Item = _chunk7RGKC52Kcjs.qc; exports.ItemActions = _chunk7RGKC52Kcjs.vc; exports.ItemContent = _chunk7RGKC52Kcjs.sc; exports.ItemDescription = _chunk7RGKC52Kcjs.uc; exports.ItemFooter = _chunk7RGKC52Kcjs.xc; exports.ItemGroup = _chunk7RGKC52Kcjs.oc; exports.ItemHeader = _chunk7RGKC52Kcjs.wc; exports.ItemMedia = _chunk7RGKC52Kcjs.rc; exports.ItemSeparator = _chunk7RGKC52Kcjs.pc; exports.ItemTitle = _chunk7RGKC52Kcjs.tc; exports.Kbd = _chunk7RGKC52Kcjs.yc; exports.KbdGroup = _chunk7RGKC52Kcjs.zc; exports.KeyboardAvoidingView = Bs; exports.Label = _chunk7RGKC52Kcjs.Yb; exports.Menubar = _chunk7RGKC52Kcjs.Ac; exports.MenubarCheckboxItem = _chunk7RGKC52Kcjs.Ic; exports.MenubarContent = _chunk7RGKC52Kcjs.Gc; exports.MenubarGroup = _chunk7RGKC52Kcjs.Cc; exports.MenubarItem = _chunk7RGKC52Kcjs.Hc; exports.MenubarLabel = _chunk7RGKC52Kcjs.Kc; exports.MenubarMenu = _chunk7RGKC52Kcjs.Bc; exports.MenubarPortal = _chunk7RGKC52Kcjs.Dc; exports.MenubarRadioGroup = _chunk7RGKC52Kcjs.Ec; exports.MenubarRadioItem = _chunk7RGKC52Kcjs.Jc; exports.MenubarSeparator = _chunk7RGKC52Kcjs.Lc; exports.MenubarShortcut = _chunk7RGKC52Kcjs.Mc; exports.MenubarSub = _chunk7RGKC52Kcjs.Nc; exports.MenubarSubContent = _chunk7RGKC52Kcjs.Pc; exports.MenubarSubTrigger = _chunk7RGKC52Kcjs.Oc; exports.MenubarTrigger = _chunk7RGKC52Kcjs.Fc; exports.NavigationMenu = _chunk7RGKC52Kcjs.Qc; exports.NavigationMenuContent = _chunk7RGKC52Kcjs.Vc; exports.NavigationMenuIndicator = _chunk7RGKC52Kcjs.Yc; exports.NavigationMenuItem = _chunk7RGKC52Kcjs.Sc; exports.NavigationMenuLink = _chunk7RGKC52Kcjs.Xc; exports.NavigationMenuList = _chunk7RGKC52Kcjs.Rc; exports.NavigationMenuTrigger = _chunk7RGKC52Kcjs.Uc; exports.NavigationMenuViewport = _chunk7RGKC52Kcjs.Wc; exports.Pagination = _chunk7RGKC52Kcjs.Zc; exports.PaginationContent = _chunk7RGKC52Kcjs._c; exports.PaginationEllipsis = _chunk7RGKC52Kcjs.dd; exports.PaginationItem = _chunk7RGKC52Kcjs.$c; exports.PaginationLink = _chunk7RGKC52Kcjs.ad; exports.PaginationNext = _chunk7RGKC52Kcjs.cd; exports.PaginationPrevious = _chunk7RGKC52Kcjs.bd; exports.Popover = _chunk7RGKC52Kcjs.ed; exports.PopoverAnchor = _chunk7RGKC52Kcjs.hd; exports.PopoverContent = _chunk7RGKC52Kcjs.gd; exports.PopoverDescription = _chunk7RGKC52Kcjs.kd; exports.PopoverHeader = _chunk7RGKC52Kcjs.id; exports.PopoverTitle = _chunk7RGKC52Kcjs.jd; exports.PopoverTrigger = _chunk7RGKC52Kcjs.fd; exports.Progress = _chunk7RGKC52Kcjs.ld; exports.RadioGroup = _chunk7RGKC52Kcjs.md; exports.RadioGroupItem = _chunk7RGKC52Kcjs.nd; exports.ResizableHandle = _chunk7RGKC52Kcjs.qd; exports.ResizablePanel = _chunk7RGKC52Kcjs.pd; exports.ResizablePanelGroup = _chunk7RGKC52Kcjs.od; exports.SafeAreaProvider = As; exports.SafeAreaView = Ns; exports.ScrollArea = _chunk7RGKC52Kcjs.rd; exports.ScrollBar = _chunk7RGKC52Kcjs.sd; exports.Select = _chunk7RGKC52Kcjs.td; exports.SelectContent = _chunk7RGKC52Kcjs.xd; exports.SelectGroup = _chunk7RGKC52Kcjs.ud; exports.SelectItem = _chunk7RGKC52Kcjs.zd; exports.SelectLabel = _chunk7RGKC52Kcjs.yd; exports.SelectScrollDownButton = _chunk7RGKC52Kcjs.Cd; exports.SelectScrollUpButton = _chunk7RGKC52Kcjs.Bd; exports.SelectSeparator = _chunk7RGKC52Kcjs.Ad; exports.SelectTrigger = _chunk7RGKC52Kcjs.wd; exports.SelectValue = _chunk7RGKC52Kcjs.vd; exports.Separator = _chunk7RGKC52Kcjs.N; exports.Sheet = _chunk7RGKC52Kcjs.Dd; exports.SheetClose = _chunk7RGKC52Kcjs.Fd; exports.SheetContent = _chunk7RGKC52Kcjs.Gd; exports.SheetDescription = _chunk7RGKC52Kcjs.Kd; exports.SheetFooter = _chunk7RGKC52Kcjs.Id; exports.SheetHeader = _chunk7RGKC52Kcjs.Hd; exports.SheetTitle = _chunk7RGKC52Kcjs.Jd; exports.SheetTrigger = _chunk7RGKC52Kcjs.Ed; exports.Sidebar = _chunk7RGKC52Kcjs.Td; exports.SidebarContent = _chunk7RGKC52Kcjs.$d; exports.SidebarFooter = _chunk7RGKC52Kcjs.Zd; exports.SidebarGroup = _chunk7RGKC52Kcjs.ae; exports.SidebarGroupAction = _chunk7RGKC52Kcjs.ce; exports.SidebarGroupContent = _chunk7RGKC52Kcjs.de; exports.SidebarGroupLabel = _chunk7RGKC52Kcjs.be; exports.SidebarHeader = _chunk7RGKC52Kcjs.Yd; exports.SidebarInput = _chunk7RGKC52Kcjs.Xd; exports.SidebarInset = _chunk7RGKC52Kcjs.Wd; exports.SidebarMenu = _chunk7RGKC52Kcjs.ee; exports.SidebarMenuAction = _chunk7RGKC52Kcjs.he; exports.SidebarMenuBadge = _chunk7RGKC52Kcjs.ie; exports.SidebarMenuButton = _chunk7RGKC52Kcjs.ge; exports.SidebarMenuItem = _chunk7RGKC52Kcjs.fe; exports.SidebarMenuSkeleton = _chunk7RGKC52Kcjs.je; exports.SidebarMenuSub = _chunk7RGKC52Kcjs.ke; exports.SidebarMenuSubButton = _chunk7RGKC52Kcjs.me; exports.SidebarMenuSubItem = _chunk7RGKC52Kcjs.le; exports.SidebarProvider = _chunk7RGKC52Kcjs.Sd; exports.SidebarRail = _chunk7RGKC52Kcjs.Vd; exports.SidebarSeparator = _chunk7RGKC52Kcjs._d; exports.SidebarTrigger = _chunk7RGKC52Kcjs.Ud; exports.Skeleton = _chunk7RGKC52Kcjs.Ld; exports.Slider = _chunk7RGKC52Kcjs.ne; exports.Spinner = _chunk7RGKC52Kcjs.pe; exports.Switch = _chunk7RGKC52Kcjs.qe; exports.Table = _chunk7RGKC52Kcjs.re; exports.TableBody = _chunk7RGKC52Kcjs.te; exports.TableCaption = _chunk7RGKC52Kcjs.ye; exports.TableCell = _chunk7RGKC52Kcjs.xe; exports.TableFooter = _chunk7RGKC52Kcjs.ue; exports.TableHead = _chunk7RGKC52Kcjs.we; exports.TableHeader = _chunk7RGKC52Kcjs.se; exports.TableRow = _chunk7RGKC52Kcjs.ve; exports.Tabs = _chunk7RGKC52Kcjs.ze; exports.TabsContent = _chunk7RGKC52Kcjs.De; exports.TabsList = _chunk7RGKC52Kcjs.Be; exports.TabsTrigger = _chunk7RGKC52Kcjs.Ce; exports.Textarea = _chunk7RGKC52Kcjs.qa; exports.Toaster = _chunk7RGKC52Kcjs.oe; exports.Toggle = _chunk7RGKC52Kcjs.Fe; exports.ToggleGroup = _chunk7RGKC52Kcjs.Ge; exports.ToggleGroupItem = _chunk7RGKC52Kcjs.He; exports.Tooltip = _chunk7RGKC52Kcjs.Nd; exports.TooltipContent = _chunk7RGKC52Kcjs.Pd; exports.TooltipProvider = _chunk7RGKC52Kcjs.Md; exports.TooltipTrigger = _chunk7RGKC52Kcjs.Od; exports.badgeVariants = _chunk7RGKC52Kcjs.E; exports.buttonGroupVariants = _chunk7RGKC52Kcjs.O; exports.buttonVariants = _chunk7RGKC52Kcjs.f; exports.cn = _chunk7RGKC52Kcjs.a; exports.navigationMenuTriggerStyle = _chunk7RGKC52Kcjs.Tc; exports.tabsListVariants = _chunk7RGKC52Kcjs.Ae; exports.toggleVariants = _chunk7RGKC52Kcjs.Ee; exports.useAppState = Ps; exports.useBackHandler = Cs; exports.useCarousel = _chunk7RGKC52Kcjs.$; exports.useColorScheme = ks; exports.useComboboxAnchor = _chunk7RGKC52Kcjs.Ma; exports.useFocusTimer = Hs; exports.useIsMobile = _chunk7RGKC52Kcjs.Qd; exports.useKeyboard = S; exports.useRelayClose = Ss; exports.useSafeArea = E; exports.useSidebar = _chunk7RGKC52Kcjs.Rd; exports.useStatusBar = Ls;
|
|
9
|
+
`,document.body.appendChild(r);let s=r.getBoundingClientRect();d=s.top,p=window.innerHeight-s.bottom,f=s.left,i=window.innerWidth-s.right,document.body.removeChild(r)}a({top:d,bottom:p,left:f,right:i})},n=l=>{_optionalChain([l, 'access', _8 => _8.data, 'optionalAccess', _9 => _9.type])==="relay:safearea"&&a(l.data.insets)};return o(),window.addEventListener("message",n),window.addEventListener("resize",o),()=>{window.removeEventListener("message",n),window.removeEventListener("resize",o)}},[]),_jsxruntime.jsx.call(void 0, O.Provider,{value:e,children:t})}function I(){return _react.useContext.call(void 0, O)}function Fi(){let[t,e]=_react.useState.call(void 0, ()=>window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return _react.useEffect.call(void 0, ()=>{let a=window.matchMedia("(prefers-color-scheme: dark)"),o=n=>{e(n.matches?"dark":"light")};return a.addEventListener("change",o),()=>a.removeEventListener("change",o)},[]),t}function qi(t){_react.useEffect.call(void 0, ()=>{let e=document.querySelector('meta[name="theme-color"]');e||(e=document.createElement("meta"),e.setAttribute("name","theme-color"),document.head.appendChild(e)),e.setAttribute("content",t),_optionalChain([window, 'access', _10 => _10.parent, 'optionalAccess', _11 => _11.postMessage, 'call', _12 => _12({type:"relay:statusbar",color:t},"*")])},[t])}function Wi(t){_react.useEffect.call(void 0, ()=>{let e=o=>{o.data==="relay:back"&&(t()||_optionalChain([window, 'access', _13 => _13.parent, 'optionalAccess', _14 => _14.postMessage, 'call', _15 => _15("relay:close","*")]))},a=o=>{t()&&window.history.pushState(null,"",window.location.href)};return window.history.pushState(null,"",window.location.href),window.addEventListener("message",e),window.addEventListener("popstate",a),()=>{window.removeEventListener("message",e),window.removeEventListener("popstate",a)}},[t])}function zi(){let[t,e]=_react.useState.call(void 0, "active");return _react.useEffect.call(void 0, ()=>{let a=()=>{e(document.hidden?"background":"active")},o=n=>{n.data==="relay:foreground"&&e("active"),n.data==="relay:background"&&e("background")};return document.addEventListener("visibilitychange",a),window.addEventListener("message",o),()=>{document.removeEventListener("visibilitychange",a),window.removeEventListener("message",o)}},[]),t}function ji({children:t,behavior:e="padding",keyboardVerticalOffset:a=0,style:o,className:n}){let l=L(),u=l.height+a,d={...o,transition:"all 0.2s ease-out"};if(l.isOpen)switch(e){case"padding":d.paddingBottom=u;break;case"height":d.height=`calc(100% - ${u}px)`;break;case"position":d.transform=`translateY(-${u}px)`;break}return _jsxruntime.jsx.call(void 0, "div",{style:d,className:n,children:t})}function Qi({children:t,edges:e=["top","bottom","left","right"],style:a,className:o}){let n=I(),l={...a,paddingTop:e.includes("top")?n.top:_optionalChain([a, 'optionalAccess', _16 => _16.paddingTop]),paddingBottom:e.includes("bottom")?n.bottom:_optionalChain([a, 'optionalAccess', _17 => _17.paddingBottom]),paddingLeft:e.includes("left")?n.left:_optionalChain([a, 'optionalAccess', _18 => _18.paddingLeft]),paddingRight:e.includes("right")?n.right:_optionalChain([a, 'optionalAccess', _19 => _19.paddingRight])};return _jsxruntime.jsx.call(void 0, "div",{style:l,className:o,children:t})}function Zi({title:t,showBack:e=!0,onBack:a,className:o,rightElement:n}){let l=I();return _jsxruntime.jsx.call(void 0, "div",{className:_chunk7RGKC52Kcjs.a.call(void 0, "bg-background border-b flex flex-col z-50",o),style:{paddingTop:l.top},children:_jsxruntime.jsxs.call(void 0, "div",{className:"h-14 flex items-center justify-between px-4",children:[_jsxruntime.jsxs.call(void 0, "div",{className:"flex items-center gap-4 flex-1",children:[e&&_jsxruntime.jsx.call(void 0, "button",{onClick:a||(()=>window.history.back()),className:"p-2 -ml-2 hover:bg-muted rounded-full transition-colors",children:_jsxruntime.jsx.call(void 0, "svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:_jsxruntime.jsx.call(void 0, "path",{d:"M19 12H5M12 19l-7-7 7-7"})})}),_jsxruntime.jsx.call(void 0, "h1",{className:"text-lg font-semibold truncate",children:t})]}),n&&_jsxruntime.jsx.call(void 0, "div",{className:"flex-none",children:n})]})})}function ra(){let[t,e]=_react.useState.call(void 0, 1500),[a,o]=_react.useState.call(void 0, 1500),[n,l]=_react.useState.call(void 0, !1),[u,d]=_react.useState.call(void 0, "focus"),[p,f]=_react.useState.call(void 0, ""),[i,r]=_react.useState.call(void 0, "egg"),[s,c]=_react.useState.call(void 0, !1);_react.useEffect.call(void 0, ()=>{let g=null;if(n&&t>0)g=setInterval(()=>{e(h=>h-1)},1e3);else if(t===0&&n&&(l(!1),u==="focus")){let h=Math.random()<.01;r(h?"alien":"chick")}return()=>{g&&clearInterval(g)}},[n,t,u]),_react.useEffect.call(void 0, ()=>{if(!n&&(i==="chick"||i==="alien"||i==="ghost")||u!=="focus")return;let g=1-t/a;g<.5?r("egg"):g>=.5&&g<1&&r("cracked")},[t,a,n,i,u]);let m=()=>l(!n),v=()=>{l(!1),r("ghost")},y=g=>{l(!1),d(g),r("egg");let h=1500;g==="shortBreak"&&(h=300),g==="longBreak"&&(h=900),e(h),o(h)};return{seconds:t,initialTime:a,isActive:n,mode:u,task:p,storyState:i,soundEnabled:s,setSeconds:e,setInitialTime:o,setIsActive:l,setMode:d,setTask:f,setStoryState:r,setSoundEnabled:c,toggleTimer:m,giveUp:v,switchMode:y,resetTimer:()=>{l(!1),y(u)},setCustomTime:g=>{l(!1),e(g*60),o(g*60),r("egg")}}}function aa(){let[t,e]=_react.useState.call(void 0, "default");_react.useEffect.call(void 0, ()=>{"Notification"in window&&e(Notification.permission)},[]);let a=_react.useCallback.call(void 0, async()=>{if(!("Notification"in window))return console.warn("Notifications not supported"),"denied";let d=await Notification.requestPermission();return e(d),d},[]),o=_react.useCallback.call(void 0, (d,p)=>{if(!("Notification"in window))return;let f=p;if(!_optionalChain([p, 'optionalAccess', _20 => _20.icon])){let i=document.querySelector('link[rel="apple-touch-icon"]')||document.querySelector('link[rel="icon"]');i&&(f={...p,icon:i.href})}Notification.permission==="granted"?new Notification(d,f):Notification.permission!=="denied"&&Notification.requestPermission().then(i=>{i==="granted"&&new Notification(d,f)})},[]),n=_react.useCallback.call(void 0, (d,p,f)=>{setTimeout(()=>{o(d,f)},p)},[o]),l=_react.useCallback.call(void 0, async d=>{if("setAppBadge"in navigator)try{await navigator.setAppBadge(d)}catch(p){console.error("Error setting badge:",p)}},[]),u=_react.useCallback.call(void 0, async()=>{if("clearAppBadge"in navigator)try{await navigator.clearAppBadge()}catch(d){console.error("Error clearing badge:",d)}},[]);return{permission:t,requestPermission:a,sendNotification:o,scheduleNotification:n,setBadge:l,clearBadge:u}}var A="relay_clipboard_history",J=10;function da(){let[t,e]=_react.useState.call(void 0, null),[a,o]=_react.useState.call(void 0, []);_react.useEffect.call(void 0, ()=>{try{let i=localStorage.getItem(A);if(i){let r=JSON.parse(i);o(r)}}catch(i){console.error("Failed to load clipboard history",i)}},[]);let n=_react.useCallback.call(void 0, i=>{o(r=>{let s=[i,...r].slice(0,J),c=s.filter(m=>m.type==="text");try{localStorage.setItem(A,JSON.stringify(c))}catch(m){console.error("Failed to save clipboard history",m)}return s})},[]),l=_react.useCallback.call(void 0, async i=>{if(!navigator.clipboard){console.warn("Clipboard API not supported");return}try{await navigator.clipboard.writeText(i),e(i),n({type:"text",content:i,timestamp:Date.now()})}catch(r){throw console.error("Failed to copy text:",r),r}},[n]),u=_react.useCallback.call(void 0, async i=>{if(!navigator.clipboard){console.warn("Clipboard API not supported");return}try{await navigator.clipboard.write([new ClipboardItem({[i.type]:i})]),n({type:"image",content:i,timestamp:Date.now()})}catch(r){throw console.error("Failed to copy image:",r),r}},[n]),d=_react.useCallback.call(void 0, async()=>{if(!navigator.clipboard)return console.warn("Clipboard API not supported"),"";try{let i=await navigator.clipboard.readText();return e(i),i}catch(i){throw console.error("Failed to read text:",i),i}},[]),p=_react.useCallback.call(void 0, async()=>{if(!navigator.clipboard)return console.warn("Clipboard API not supported"),[];try{return await navigator.clipboard.read()}catch(i){throw console.error("Failed to read content:",i),i}},[]),f=_react.useCallback.call(void 0, ()=>{o([]),localStorage.removeItem(A)},[]);return _react.useEffect.call(void 0, ()=>{let i=()=>{d().catch(()=>{})};return window.addEventListener("focus",i),()=>window.removeEventListener("focus",i)},[d]),{clipboardContent:t,history:a,copyText:l,copyImage:u,readText:d,readContent:p,clearHistory:f}}function ma(t){let[e,a]=_react.useState.call(void 0, {loading:!0,accuracy:null,altitude:null,altitudeAccuracy:null,heading:null,latitude:null,longitude:null,speed:null,timestamp:null,error:null}),o=_react.useRef.call(void 0, null),n=_react.useCallback.call(void 0, r=>{a({loading:!1,accuracy:r.coords.accuracy,altitude:r.coords.altitude,altitudeAccuracy:r.coords.altitudeAccuracy,heading:r.coords.heading,latitude:r.coords.latitude,longitude:r.coords.longitude,speed:r.coords.speed,timestamp:r.timestamp,error:null})},[]),l=_react.useCallback.call(void 0, r=>{a(s=>({...s,loading:!1,error:r}))},[]),u=_react.useCallback.call(void 0, ()=>{if(!navigator.geolocation){a(r=>({...r,loading:!1,error:{code:0,message:"Geolocation not supported",PERMISSION_DENIED:1,POSITION_UNAVAILABLE:2,TIMEOUT:3}}));return}a(r=>({...r,loading:!0})),navigator.geolocation.getCurrentPosition(n,l,t)},[n,l,t]),d=_react.useCallback.call(void 0, r=>{navigator.geolocation&&(o.current!==null&&navigator.geolocation.clearWatch(o.current),o.current=navigator.geolocation.watchPosition(n,l,r||t))},[n,l,t]),p=_react.useCallback.call(void 0, ()=>{o.current!==null&&(navigator.geolocation.clearWatch(o.current),o.current=null)},[]),f=_react.useCallback.call(void 0, (r,s)=>{if(e.latitude===null||e.longitude===null)return 1/0;let c=6371e3,m=e.latitude*Math.PI/180,v=r*Math.PI/180,y=(r-e.latitude)*Math.PI/180,k=(s-e.longitude)*Math.PI/180,N=Math.sin(y/2)*Math.sin(y/2)+Math.cos(m)*Math.cos(v)*Math.sin(k/2)*Math.sin(k/2),g=2*Math.atan2(Math.sqrt(N),Math.sqrt(1-N));return c*g},[e.latitude,e.longitude]),i=_react.useCallback.call(void 0, r=>f(r.latitude,r.longitude)<=r.radius,[f]);return _react.useEffect.call(void 0, ()=>()=>{o.current!==null&&navigator.geolocation.clearWatch(o.current)},[]),{...e,getLocation:u,watchLocation:d,clearWatch:p,checkGeofence:i,distanceTo:f}}function ga(){let[t,e]=_react.useState.call(void 0, {stream:null,error:null,permission:"unknown",isRecording:!1,devices:[]}),a=_react.useRef.call(void 0, null),o=_react.useRef.call(void 0, []),n=_react.useCallback.call(void 0, async()=>{if(!_optionalChain([navigator, 'access', _21 => _21.mediaDevices, 'optionalAccess', _22 => _22.enumerateDevices]))return[];try{let s=await navigator.mediaDevices.enumerateDevices();return e(c=>({...c,devices:s})),s}catch(s){return console.error("Error enumerating devices:",s),[]}},[]);_react.useEffect.call(void 0, ()=>(n(),_optionalChain([navigator, 'access', _23 => _23.mediaDevices, 'optionalAccess', _24 => _24.addEventListener, 'call', _25 => _25("devicechange",n)]),()=>{_optionalChain([navigator, 'access', _26 => _26.mediaDevices, 'optionalAccess', _27 => _27.removeEventListener, 'call', _28 => _28("devicechange",n)])}),[n]);let l=_react.useCallback.call(void 0, async(s={video:!0,audio:!1})=>{try{let c=await navigator.mediaDevices.getUserMedia(s);return e(m=>({...m,stream:c,error:null,permission:"granted"})),c}catch(c){let m=c;e(v=>({...v,error:m,permission:"denied"})),console.error("Error starting camera:",c)}},[]),u=_react.useCallback.call(void 0, ()=>{t.stream&&(t.stream.getTracks().forEach(s=>s.stop()),e(s=>({...s,stream:null,isRecording:!1})))},[t.stream]),d=_react.useCallback.call(void 0, async(s={video:!0})=>{try{let c=await navigator.mediaDevices.getDisplayMedia(s);return e(m=>({...m,stream:c,error:null,permission:"granted"})),c}catch(c){let m=c;e(v=>({...v,error:m,permission:"denied"})),console.error("Error starting screen share:",c)}},[]),p=_react.useCallback.call(void 0, async()=>{if(!t.stream||!t.stream.getVideoTracks()[0])return;let c=document.createElement("video");c.srcObject=t.stream,await c.play();let m=document.createElement("canvas");m.width=c.videoWidth,m.height=c.videoHeight;let v=m.getContext("2d");if(!v)return;v.drawImage(c,0,0);let y=m.toDataURL("image/png");return c.pause(),c.srcObject=null,y},[t.stream]),f=_react.useCallback.call(void 0, ()=>{if(t.stream)try{let s=new MediaRecorder(t.stream);a.current=s,o.current=[],s.ondataavailable=c=>{c.data.size>0&&o.current.push(c.data)},s.start(),e(c=>({...c,isRecording:!0}))}catch(s){console.error("Error starting recording:",s),e(c=>({...c,error:s}))}},[t.stream]),i=_react.useCallback.call(void 0, async()=>{if(!(!a.current||a.current.state==="inactive"))return new Promise(s=>{a.current&&(a.current.onstop=()=>{let c=new Blob(o.current,{type:"video/webm"});e(m=>({...m,isRecording:!1})),s(c)},a.current.stop())})},[]),r=_react.useCallback.call(void 0, async(s,c)=>{u();let m={[c]:{deviceId:{exact:s}}};await l(m)},[l,u]);return _react.useEffect.call(void 0, ()=>()=>{u()},[]),{...t,startCamera:l,stopCamera:u,takePhoto:p,startRecording:f,stopRecording:i,startScreenShare:d,switchDevice:r,getDevices:n}}exports.Accordion = _chunk7RGKC52Kcjs.b; exports.AccordionContent = _chunk7RGKC52Kcjs.e; exports.AccordionItem = _chunk7RGKC52Kcjs.c; exports.AccordionTrigger = _chunk7RGKC52Kcjs.d; exports.Alert = _chunk7RGKC52Kcjs.t; exports.AlertAction = _chunk7RGKC52Kcjs.w; exports.AlertDescription = _chunk7RGKC52Kcjs.v; exports.AlertDialog = _chunk7RGKC52Kcjs.h; exports.AlertDialogAction = _chunk7RGKC52Kcjs.r; exports.AlertDialogCancel = _chunk7RGKC52Kcjs.s; exports.AlertDialogContent = _chunk7RGKC52Kcjs.l; exports.AlertDialogDescription = _chunk7RGKC52Kcjs.q; exports.AlertDialogFooter = _chunk7RGKC52Kcjs.n; exports.AlertDialogHeader = _chunk7RGKC52Kcjs.m; exports.AlertDialogMedia = _chunk7RGKC52Kcjs.o; exports.AlertDialogOverlay = _chunk7RGKC52Kcjs.k; exports.AlertDialogPortal = _chunk7RGKC52Kcjs.j; exports.AlertDialogTitle = _chunk7RGKC52Kcjs.p; exports.AlertDialogTrigger = _chunk7RGKC52Kcjs.i; exports.AlertTitle = _chunk7RGKC52Kcjs.u; exports.AspectRatio = _chunk7RGKC52Kcjs.x; exports.Avatar = _chunk7RGKC52Kcjs.y; exports.AvatarBadge = _chunk7RGKC52Kcjs.B; exports.AvatarFallback = _chunk7RGKC52Kcjs.A; exports.AvatarGroup = _chunk7RGKC52Kcjs.C; exports.AvatarGroupCount = _chunk7RGKC52Kcjs.D; exports.AvatarImage = _chunk7RGKC52Kcjs.z; exports.Badge = _chunk7RGKC52Kcjs.F; exports.Breadcrumb = _chunk7RGKC52Kcjs.G; exports.BreadcrumbEllipsis = _chunk7RGKC52Kcjs.M; exports.BreadcrumbItem = _chunk7RGKC52Kcjs.I; exports.BreadcrumbLink = _chunk7RGKC52Kcjs.J; exports.BreadcrumbList = _chunk7RGKC52Kcjs.H; exports.BreadcrumbPage = _chunk7RGKC52Kcjs.K; exports.BreadcrumbSeparator = _chunk7RGKC52Kcjs.L; exports.Button = _chunk7RGKC52Kcjs.g; exports.ButtonGroup = _chunk7RGKC52Kcjs.P; exports.ButtonGroupSeparator = _chunk7RGKC52Kcjs.R; exports.ButtonGroupText = _chunk7RGKC52Kcjs.Q; exports.Calendar = _chunk7RGKC52Kcjs.S; exports.CalendarDayButton = _chunk7RGKC52Kcjs.T; exports.Card = _chunk7RGKC52Kcjs.U; exports.CardAction = _chunk7RGKC52Kcjs.Y; exports.CardContent = _chunk7RGKC52Kcjs.Z; exports.CardDescription = _chunk7RGKC52Kcjs.X; exports.CardFooter = _chunk7RGKC52Kcjs._; exports.CardHeader = _chunk7RGKC52Kcjs.V; exports.CardTitle = _chunk7RGKC52Kcjs.W; exports.Carousel = _chunk7RGKC52Kcjs.aa; exports.CarouselContent = _chunk7RGKC52Kcjs.ba; exports.CarouselItem = _chunk7RGKC52Kcjs.ca; exports.CarouselNext = _chunk7RGKC52Kcjs.ea; exports.CarouselPrevious = _chunk7RGKC52Kcjs.da; exports.ChartContainer = _chunk7RGKC52Kcjs.fa; exports.ChartLegend = _chunk7RGKC52Kcjs.ja; exports.ChartLegendContent = _chunk7RGKC52Kcjs.ka; exports.ChartStyle = _chunk7RGKC52Kcjs.ga; exports.ChartTooltip = _chunk7RGKC52Kcjs.ha; exports.ChartTooltipContent = _chunk7RGKC52Kcjs.ia; exports.Checkbox = _chunk7RGKC52Kcjs.la; exports.Collapsible = _chunk7RGKC52Kcjs.ma; exports.CollapsibleContent = _chunk7RGKC52Kcjs.oa; exports.CollapsibleTrigger = _chunk7RGKC52Kcjs.na; exports.Combobox = _chunk7RGKC52Kcjs.xa; exports.ComboboxChip = _chunk7RGKC52Kcjs.Ka; exports.ComboboxChips = _chunk7RGKC52Kcjs.Ja; exports.ComboboxChipsInput = _chunk7RGKC52Kcjs.La; exports.ComboboxCollection = _chunk7RGKC52Kcjs.Ga; exports.ComboboxContent = _chunk7RGKC52Kcjs.Ba; exports.ComboboxEmpty = _chunk7RGKC52Kcjs.Ha; exports.ComboboxGroup = _chunk7RGKC52Kcjs.Ea; exports.ComboboxInput = _chunk7RGKC52Kcjs.Aa; exports.ComboboxItem = _chunk7RGKC52Kcjs.Da; exports.ComboboxLabel = _chunk7RGKC52Kcjs.Fa; exports.ComboboxList = _chunk7RGKC52Kcjs.Ca; exports.ComboboxSeparator = _chunk7RGKC52Kcjs.Ia; exports.ComboboxTrigger = _chunk7RGKC52Kcjs.za; exports.ComboboxValue = _chunk7RGKC52Kcjs.ya; exports.Command = _chunk7RGKC52Kcjs.Xa; exports.CommandDialog = _chunk7RGKC52Kcjs.Ya; exports.CommandEmpty = _chunk7RGKC52Kcjs.$a; exports.CommandGroup = _chunk7RGKC52Kcjs.ab; exports.CommandInput = _chunk7RGKC52Kcjs.Za; exports.CommandItem = _chunk7RGKC52Kcjs.cb; exports.CommandList = _chunk7RGKC52Kcjs._a; exports.CommandSeparator = _chunk7RGKC52Kcjs.bb; exports.CommandShortcut = _chunk7RGKC52Kcjs.db; exports.ContextMenu = _chunk7RGKC52Kcjs.eb; exports.ContextMenuCheckboxItem = _chunk7RGKC52Kcjs.ob; exports.ContextMenuContent = _chunk7RGKC52Kcjs.kb; exports.ContextMenuGroup = _chunk7RGKC52Kcjs.gb; exports.ContextMenuItem = _chunk7RGKC52Kcjs.lb; exports.ContextMenuLabel = _chunk7RGKC52Kcjs.qb; exports.ContextMenuPortal = _chunk7RGKC52Kcjs.hb; exports.ContextMenuRadioGroup = _chunk7RGKC52Kcjs.jb; exports.ContextMenuRadioItem = _chunk7RGKC52Kcjs.pb; exports.ContextMenuSeparator = _chunk7RGKC52Kcjs.rb; exports.ContextMenuShortcut = _chunk7RGKC52Kcjs.sb; exports.ContextMenuSub = _chunk7RGKC52Kcjs.ib; exports.ContextMenuSubContent = _chunk7RGKC52Kcjs.nb; exports.ContextMenuSubTrigger = _chunk7RGKC52Kcjs.mb; exports.ContextMenuTrigger = _chunk7RGKC52Kcjs.fb; exports.Dialog = _chunk7RGKC52Kcjs.Na; exports.DialogClose = _chunk7RGKC52Kcjs.Qa; exports.DialogContent = _chunk7RGKC52Kcjs.Sa; exports.DialogDescription = _chunk7RGKC52Kcjs.Wa; exports.DialogFooter = _chunk7RGKC52Kcjs.Ua; exports.DialogHeader = _chunk7RGKC52Kcjs.Ta; exports.DialogOverlay = _chunk7RGKC52Kcjs.Ra; exports.DialogPortal = _chunk7RGKC52Kcjs.Pa; exports.DialogTitle = _chunk7RGKC52Kcjs.Va; exports.DialogTrigger = _chunk7RGKC52Kcjs.Oa; exports.Drawer = _chunk7RGKC52Kcjs.tb; exports.DrawerClose = _chunk7RGKC52Kcjs.wb; exports.DrawerContent = _chunk7RGKC52Kcjs.yb; exports.DrawerDescription = _chunk7RGKC52Kcjs.Cb; exports.DrawerFooter = _chunk7RGKC52Kcjs.Ab; exports.DrawerHeader = _chunk7RGKC52Kcjs.zb; exports.DrawerOverlay = _chunk7RGKC52Kcjs.xb; exports.DrawerPortal = _chunk7RGKC52Kcjs.vb; exports.DrawerTitle = _chunk7RGKC52Kcjs.Bb; exports.DrawerTrigger = _chunk7RGKC52Kcjs.ub; exports.DropdownMenu = _chunk7RGKC52Kcjs.Db; exports.DropdownMenuCheckboxItem = _chunk7RGKC52Kcjs.Jb; exports.DropdownMenuContent = _chunk7RGKC52Kcjs.Gb; exports.DropdownMenuGroup = _chunk7RGKC52Kcjs.Hb; exports.DropdownMenuItem = _chunk7RGKC52Kcjs.Ib; exports.DropdownMenuLabel = _chunk7RGKC52Kcjs.Mb; exports.DropdownMenuPortal = _chunk7RGKC52Kcjs.Eb; exports.DropdownMenuRadioGroup = _chunk7RGKC52Kcjs.Kb; exports.DropdownMenuRadioItem = _chunk7RGKC52Kcjs.Lb; exports.DropdownMenuSeparator = _chunk7RGKC52Kcjs.Nb; exports.DropdownMenuShortcut = _chunk7RGKC52Kcjs.Ob; exports.DropdownMenuSub = _chunk7RGKC52Kcjs.Pb; exports.DropdownMenuSubContent = _chunk7RGKC52Kcjs.Rb; exports.DropdownMenuSubTrigger = _chunk7RGKC52Kcjs.Qb; exports.DropdownMenuTrigger = _chunk7RGKC52Kcjs.Fb; exports.Empty = _chunk7RGKC52Kcjs.Sb; exports.EmptyContent = _chunk7RGKC52Kcjs.Xb; exports.EmptyDescription = _chunk7RGKC52Kcjs.Wb; exports.EmptyHeader = _chunk7RGKC52Kcjs.Tb; exports.EmptyMedia = _chunk7RGKC52Kcjs.Ub; exports.EmptyTitle = _chunk7RGKC52Kcjs.Vb; exports.Field = _chunk7RGKC52Kcjs.ac; exports.FieldContent = _chunk7RGKC52Kcjs.bc; exports.FieldDescription = _chunk7RGKC52Kcjs.ec; exports.FieldError = _chunk7RGKC52Kcjs.gc; exports.FieldGroup = _chunk7RGKC52Kcjs.$b; exports.FieldLabel = _chunk7RGKC52Kcjs.cc; exports.FieldLegend = _chunk7RGKC52Kcjs._b; exports.FieldSeparator = _chunk7RGKC52Kcjs.fc; exports.FieldSet = _chunk7RGKC52Kcjs.Zb; exports.FieldTitle = _chunk7RGKC52Kcjs.dc; exports.HoverCard = _chunk7RGKC52Kcjs.hc; exports.HoverCardContent = _chunk7RGKC52Kcjs.jc; exports.HoverCardTrigger = _chunk7RGKC52Kcjs.ic; exports.Input = _chunk7RGKC52Kcjs.pa; exports.InputGroup = _chunk7RGKC52Kcjs.ra; exports.InputGroupAddon = _chunk7RGKC52Kcjs.sa; exports.InputGroupButton = _chunk7RGKC52Kcjs.ta; exports.InputGroupInput = _chunk7RGKC52Kcjs.va; exports.InputGroupText = _chunk7RGKC52Kcjs.ua; exports.InputGroupTextarea = _chunk7RGKC52Kcjs.wa; exports.InputOTP = _chunk7RGKC52Kcjs.kc; exports.InputOTPGroup = _chunk7RGKC52Kcjs.lc; exports.InputOTPSeparator = _chunk7RGKC52Kcjs.nc; exports.InputOTPSlot = _chunk7RGKC52Kcjs.mc; exports.Item = _chunk7RGKC52Kcjs.qc; exports.ItemActions = _chunk7RGKC52Kcjs.vc; exports.ItemContent = _chunk7RGKC52Kcjs.sc; exports.ItemDescription = _chunk7RGKC52Kcjs.uc; exports.ItemFooter = _chunk7RGKC52Kcjs.xc; exports.ItemGroup = _chunk7RGKC52Kcjs.oc; exports.ItemHeader = _chunk7RGKC52Kcjs.wc; exports.ItemMedia = _chunk7RGKC52Kcjs.rc; exports.ItemSeparator = _chunk7RGKC52Kcjs.pc; exports.ItemTitle = _chunk7RGKC52Kcjs.tc; exports.Kbd = _chunk7RGKC52Kcjs.yc; exports.KbdGroup = _chunk7RGKC52Kcjs.zc; exports.KeyboardAvoidingView = ji; exports.Label = _chunk7RGKC52Kcjs.Yb; exports.Menubar = _chunk7RGKC52Kcjs.Ac; exports.MenubarCheckboxItem = _chunk7RGKC52Kcjs.Ic; exports.MenubarContent = _chunk7RGKC52Kcjs.Gc; exports.MenubarGroup = _chunk7RGKC52Kcjs.Cc; exports.MenubarItem = _chunk7RGKC52Kcjs.Hc; exports.MenubarLabel = _chunk7RGKC52Kcjs.Kc; exports.MenubarMenu = _chunk7RGKC52Kcjs.Bc; exports.MenubarPortal = _chunk7RGKC52Kcjs.Dc; exports.MenubarRadioGroup = _chunk7RGKC52Kcjs.Ec; exports.MenubarRadioItem = _chunk7RGKC52Kcjs.Jc; exports.MenubarSeparator = _chunk7RGKC52Kcjs.Lc; exports.MenubarShortcut = _chunk7RGKC52Kcjs.Mc; exports.MenubarSub = _chunk7RGKC52Kcjs.Nc; exports.MenubarSubContent = _chunk7RGKC52Kcjs.Pc; exports.MenubarSubTrigger = _chunk7RGKC52Kcjs.Oc; exports.MenubarTrigger = _chunk7RGKC52Kcjs.Fc; exports.NavigationMenu = _chunk7RGKC52Kcjs.Qc; exports.NavigationMenuContent = _chunk7RGKC52Kcjs.Vc; exports.NavigationMenuIndicator = _chunk7RGKC52Kcjs.Yc; exports.NavigationMenuItem = _chunk7RGKC52Kcjs.Sc; exports.NavigationMenuLink = _chunk7RGKC52Kcjs.Xc; exports.NavigationMenuList = _chunk7RGKC52Kcjs.Rc; exports.NavigationMenuTrigger = _chunk7RGKC52Kcjs.Uc; exports.NavigationMenuViewport = _chunk7RGKC52Kcjs.Wc; exports.Pagination = _chunk7RGKC52Kcjs.Zc; exports.PaginationContent = _chunk7RGKC52Kcjs._c; exports.PaginationEllipsis = _chunk7RGKC52Kcjs.dd; exports.PaginationItem = _chunk7RGKC52Kcjs.$c; exports.PaginationLink = _chunk7RGKC52Kcjs.ad; exports.PaginationNext = _chunk7RGKC52Kcjs.cd; exports.PaginationPrevious = _chunk7RGKC52Kcjs.bd; exports.PlatformHeader = Zi; exports.Popover = _chunk7RGKC52Kcjs.ed; exports.PopoverAnchor = _chunk7RGKC52Kcjs.hd; exports.PopoverContent = _chunk7RGKC52Kcjs.gd; exports.PopoverDescription = _chunk7RGKC52Kcjs.kd; exports.PopoverHeader = _chunk7RGKC52Kcjs.id; exports.PopoverTitle = _chunk7RGKC52Kcjs.jd; exports.PopoverTrigger = _chunk7RGKC52Kcjs.fd; exports.Progress = _chunk7RGKC52Kcjs.ld; exports.RadioGroup = _chunk7RGKC52Kcjs.md; exports.RadioGroupItem = _chunk7RGKC52Kcjs.nd; exports.ResizableHandle = _chunk7RGKC52Kcjs.qd; exports.ResizablePanel = _chunk7RGKC52Kcjs.pd; exports.ResizablePanelGroup = _chunk7RGKC52Kcjs.od; exports.SafeAreaProvider = Ki; exports.SafeAreaView = Qi; exports.ScrollArea = _chunk7RGKC52Kcjs.rd; exports.ScrollBar = _chunk7RGKC52Kcjs.sd; exports.Select = _chunk7RGKC52Kcjs.td; exports.SelectContent = _chunk7RGKC52Kcjs.xd; exports.SelectGroup = _chunk7RGKC52Kcjs.ud; exports.SelectItem = _chunk7RGKC52Kcjs.zd; exports.SelectLabel = _chunk7RGKC52Kcjs.yd; exports.SelectScrollDownButton = _chunk7RGKC52Kcjs.Cd; exports.SelectScrollUpButton = _chunk7RGKC52Kcjs.Bd; exports.SelectSeparator = _chunk7RGKC52Kcjs.Ad; exports.SelectTrigger = _chunk7RGKC52Kcjs.wd; exports.SelectValue = _chunk7RGKC52Kcjs.vd; exports.Separator = _chunk7RGKC52Kcjs.N; exports.Sheet = _chunk7RGKC52Kcjs.Dd; exports.SheetClose = _chunk7RGKC52Kcjs.Fd; exports.SheetContent = _chunk7RGKC52Kcjs.Gd; exports.SheetDescription = _chunk7RGKC52Kcjs.Kd; exports.SheetFooter = _chunk7RGKC52Kcjs.Id; exports.SheetHeader = _chunk7RGKC52Kcjs.Hd; exports.SheetTitle = _chunk7RGKC52Kcjs.Jd; exports.SheetTrigger = _chunk7RGKC52Kcjs.Ed; exports.Sidebar = _chunk7RGKC52Kcjs.Td; exports.SidebarContent = _chunk7RGKC52Kcjs.$d; exports.SidebarFooter = _chunk7RGKC52Kcjs.Zd; exports.SidebarGroup = _chunk7RGKC52Kcjs.ae; exports.SidebarGroupAction = _chunk7RGKC52Kcjs.ce; exports.SidebarGroupContent = _chunk7RGKC52Kcjs.de; exports.SidebarGroupLabel = _chunk7RGKC52Kcjs.be; exports.SidebarHeader = _chunk7RGKC52Kcjs.Yd; exports.SidebarInput = _chunk7RGKC52Kcjs.Xd; exports.SidebarInset = _chunk7RGKC52Kcjs.Wd; exports.SidebarMenu = _chunk7RGKC52Kcjs.ee; exports.SidebarMenuAction = _chunk7RGKC52Kcjs.he; exports.SidebarMenuBadge = _chunk7RGKC52Kcjs.ie; exports.SidebarMenuButton = _chunk7RGKC52Kcjs.ge; exports.SidebarMenuItem = _chunk7RGKC52Kcjs.fe; exports.SidebarMenuSkeleton = _chunk7RGKC52Kcjs.je; exports.SidebarMenuSub = _chunk7RGKC52Kcjs.ke; exports.SidebarMenuSubButton = _chunk7RGKC52Kcjs.me; exports.SidebarMenuSubItem = _chunk7RGKC52Kcjs.le; exports.SidebarProvider = _chunk7RGKC52Kcjs.Sd; exports.SidebarRail = _chunk7RGKC52Kcjs.Vd; exports.SidebarSeparator = _chunk7RGKC52Kcjs._d; exports.SidebarTrigger = _chunk7RGKC52Kcjs.Ud; exports.Skeleton = _chunk7RGKC52Kcjs.Ld; exports.Slider = _chunk7RGKC52Kcjs.ne; exports.Spinner = _chunk7RGKC52Kcjs.pe; exports.Switch = _chunk7RGKC52Kcjs.qe; exports.Table = _chunk7RGKC52Kcjs.re; exports.TableBody = _chunk7RGKC52Kcjs.te; exports.TableCaption = _chunk7RGKC52Kcjs.ye; exports.TableCell = _chunk7RGKC52Kcjs.xe; exports.TableFooter = _chunk7RGKC52Kcjs.ue; exports.TableHead = _chunk7RGKC52Kcjs.we; exports.TableHeader = _chunk7RGKC52Kcjs.se; exports.TableRow = _chunk7RGKC52Kcjs.ve; exports.Tabs = _chunk7RGKC52Kcjs.ze; exports.TabsContent = _chunk7RGKC52Kcjs.De; exports.TabsList = _chunk7RGKC52Kcjs.Be; exports.TabsTrigger = _chunk7RGKC52Kcjs.Ce; exports.Textarea = _chunk7RGKC52Kcjs.qa; exports.Toaster = _chunk7RGKC52Kcjs.oe; exports.Toggle = _chunk7RGKC52Kcjs.Fe; exports.ToggleGroup = _chunk7RGKC52Kcjs.Ge; exports.ToggleGroupItem = _chunk7RGKC52Kcjs.He; exports.Tooltip = _chunk7RGKC52Kcjs.Nd; exports.TooltipContent = _chunk7RGKC52Kcjs.Pd; exports.TooltipProvider = _chunk7RGKC52Kcjs.Md; exports.TooltipTrigger = _chunk7RGKC52Kcjs.Od; exports.badgeVariants = _chunk7RGKC52Kcjs.E; exports.buttonGroupVariants = _chunk7RGKC52Kcjs.O; exports.buttonVariants = _chunk7RGKC52Kcjs.f; exports.cn = _chunk7RGKC52Kcjs.a; exports.navigationMenuTriggerStyle = _chunk7RGKC52Kcjs.Tc; exports.tabsListVariants = _chunk7RGKC52Kcjs.Ae; exports.toggleVariants = _chunk7RGKC52Kcjs.Ee; exports.useAppState = zi; exports.useBackHandler = Wi; exports.useCamera = ga; exports.useCarousel = _chunk7RGKC52Kcjs.$; exports.useClipboard = da; exports.useColorScheme = Fi; exports.useComboboxAnchor = _chunk7RGKC52Kcjs.Ma; exports.useFocusTimer = ra; exports.useGeolocation = ma; exports.useIsMobile = _chunk7RGKC52Kcjs.Qd; exports.useKeyboard = L; exports.useNotifications = aa; exports.useRelayClose = Di; exports.useSafeArea = I; exports.useSidebar = _chunk7RGKC52Kcjs.Rd; exports.useStatusBar = qi;
|
|
10
10
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/jas/Desktop/relay/sdk/dist/index.cjs","../src/hooks/use-keyboard.ts","../src/hooks/use-platform.tsx","../src/hooks/use-focus-timer.ts"],"names":["useKeyboard","state","setState","useState","useEffect","updateKeyboardState","viewport","keyboardHeight","isOpen","handleFocusIn","e","target","handleFocusOut","useRelayClose","useCallback","defaultInsets","SafeAreaContext","createContext","SafeAreaProvider","children","insets","setInsets","computeInsets","style","getEnv","name","value"],"mappings":"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","file":"/Users/jas/Desktop/relay/sdk/dist/index.cjs","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\n\ninterface KeyboardState {\n isOpen: boolean;\n height: number;\n}\n\n/**\n * useKeyboard - Track virtual keyboard state on mobile devices\n * \n * Uses visualViewport API to detect keyboard height and provides\n * a safe area offset for positioning UI elements above the keyboard.\n * \n * @returns {KeyboardState} - { isOpen: boolean, height: number }\n */\nexport function useKeyboard(): KeyboardState {\n const [state, setState] = useState<KeyboardState>({\n isOpen: false,\n height: 0\n });\n\n useEffect(() => {\n // Check if we're on a mobile device\n const isMobile = /iPad|iPhone|iPod|Android/.test(navigator.userAgent);\n if (!isMobile) return;\n\n const updateKeyboardState = () => {\n if (!window.visualViewport) return;\n\n const viewport = window.visualViewport;\n // Calculate keyboard height: difference between window and viewport height\n const keyboardHeight = window.innerHeight - viewport.height;\n // Consider keyboard open if height is more than 100px (threshold for accessory bars)\n const isOpen = keyboardHeight > 100;\n\n setState({\n isOpen,\n height: isOpen ? keyboardHeight : 0\n });\n };\n\n // Listen to visualViewport changes\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', updateKeyboardState);\n window.visualViewport.addEventListener('scroll', updateKeyboardState);\n }\n\n // Also listen for focus/blur on inputs as fallback\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n // Small delay to let keyboard animate\n setTimeout(updateKeyboardState, 100);\n }\n };\n\n const handleFocusOut = () => {\n // Small delay to let keyboard animate closed\n setTimeout(() => {\n setState({ isOpen: false, height: 0 });\n }, 100);\n };\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n\n // Initial check\n updateKeyboardState();\n\n return () => {\n window.visualViewport?.removeEventListener('resize', updateKeyboardState);\n window.visualViewport?.removeEventListener('scroll', updateKeyboardState);\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }, []);\n\n return state;\n}\n\n/**\n * useRelayClose - Get the close function for closing the current app\n * \n * Works with both iframe and blob URL contexts.\n * \n * @returns {() => void} - Function to close the current app\n */\nexport function useRelayClose(): () => void {\n const close = useCallback(() => {\n // Try multiple methods to close\n // 1. PostMessage to parent (works in iframe)\n if (window.parent !== window) {\n window.parent.postMessage('relay:close', '*');\n }\n // 2. PostMessage with opener (works if opened as popup)\n if (window.opener) {\n window.opener.postMessage('relay:close', '*');\n }\n // 3. Try self-closing (may not work in all contexts)\n window.close();\n }, []);\n\n return close;\n}\n","import { useState, useEffect, useCallback, createContext, useContext, ReactNode } from 'react';\n\n// ============================================\n// SAFE AREA TYPES & CONTEXT\n// ============================================\n\nexport interface SafeAreaInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nconst defaultInsets: SafeAreaInsets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0\n};\n\nconst SafeAreaContext = createContext<SafeAreaInsets>(defaultInsets);\n\n// ============================================\n// SAFE AREA PROVIDER\n// ============================================\n\ninterface SafeAreaProviderProps {\n children: ReactNode;\n}\n\n/**\n * SafeAreaProvider - Provides safe area insets to child components\n * \n * Automatically detects safe areas from:\n * 1. CSS env() values (iOS Safari)\n * 2. Parent Shell postMessage (when running in Relay Shell)\n */\nexport function SafeAreaProvider({ children }: SafeAreaProviderProps) {\n const [insets, setInsets] = useState<SafeAreaInsets>(defaultInsets);\n\n useEffect(() => {\n // Method 1: Read from CSS env() values\n const computeInsets = () => {\n const style = getComputedStyle(document.documentElement);\n const getEnv = (name: string) => {\n const value = style.getPropertyValue(`--safe-area-inset-${name}`);\n return parseInt(value) || 0;\n };\n\n // Try to get from CSS custom properties first\n let top = getEnv('top');\n let bottom = getEnv('bottom');\n let left = getEnv('left');\n let right = getEnv('right');\n\n // If CSS props not set, try to read from env() directly\n if (top === 0 && bottom === 0) {\n // Create a temp element to measure env() values\n const temp = document.createElement('div');\n temp.style.cssText = `\n position: fixed;\n top: env(safe-area-inset-top, 0px);\n bottom: env(safe-area-inset-bottom, 0px);\n left: env(safe-area-inset-left, 0px);\n right: env(safe-area-inset-right, 0px);\n pointer-events: none;\n visibility: hidden;\n `;\n document.body.appendChild(temp);\n const rect = temp.getBoundingClientRect();\n top = rect.top;\n bottom = window.innerHeight - rect.bottom;\n left = rect.left;\n right = window.innerWidth - rect.right;\n document.body.removeChild(temp);\n }\n\n setInsets({ top, bottom, left, right });\n };\n\n // Method 2: Listen for Shell messages\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'relay:safearea') {\n setInsets(event.data.insets);\n }\n };\n\n computeInsets();\n window.addEventListener('message', handleMessage);\n window.addEventListener('resize', computeInsets);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('resize', computeInsets);\n };\n }, []);\n\n return (\n <SafeAreaContext.Provider value={insets}>\n {children}\n </SafeAreaContext.Provider>\n );\n}\n\n// ============================================\n// SAFE AREA HOOKS\n// ============================================\n\n/**\n * useSafeArea - Get safe area insets\n * \n * @returns SafeAreaInsets with top, bottom, left, right values in pixels\n */\nexport function useSafeArea(): SafeAreaInsets {\n return useContext(SafeAreaContext);\n}\n\n// ============================================\n// COLOR SCHEME\n// ============================================\n\nexport type ColorScheme = 'light' | 'dark';\n\n/**\n * useColorScheme - Get current system color scheme\n * \n * @returns 'light' | 'dark'\n */\nexport function useColorScheme(): ColorScheme {\n const [scheme, setScheme] = useState<ColorScheme>(() =>\n window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n );\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => {\n setScheme(e.matches ? 'dark' : 'light');\n };\n media.addEventListener('change', handler);\n return () => media.removeEventListener('change', handler);\n }, []);\n\n return scheme;\n}\n\n// ============================================\n// STATUS BAR\n// ============================================\n\n/**\n * useStatusBar - Control the status bar appearance\n * \n * @param color - Hex color for the status bar\n */\nexport function useStatusBar(color: string): void {\n useEffect(() => {\n // Update meta theme-color\n let meta = document.querySelector('meta[name=\"theme-color\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', color);\n\n // Notify parent Shell\n window.parent?.postMessage({ type: 'relay:statusbar', color }, '*');\n }, [color]);\n}\n\n// ============================================\n// BACK HANDLER\n// ============================================\n\n/**\n * useBackHandler - Handle back navigation\n * \n * @param handler - Return true to prevent default back behavior\n */\nexport function useBackHandler(handler: () => boolean): void {\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:back') {\n const handled = handler();\n if (!handled) {\n // Allow default close behavior\n window.parent?.postMessage('relay:close', '*');\n }\n }\n };\n\n // Also handle browser back button\n const handlePopState = (event: PopStateEvent) => {\n const handled = handler();\n if (handled) {\n // Push a dummy state to prevent navigation\n window.history.pushState(null, '', window.location.href);\n }\n };\n\n // Push initial state for popstate handling\n window.history.pushState(null, '', window.location.href);\n\n window.addEventListener('message', handleMessage);\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('popstate', handlePopState);\n };\n }, [handler]);\n}\n\n// ============================================\n// APP STATE\n// ============================================\n\nexport type AppState = 'active' | 'background' | 'inactive';\n\n/**\n * useAppState - Track app foreground/background state\n * \n * @returns Current app state\n */\nexport function useAppState(): AppState {\n const [state, setState] = useState<AppState>('active');\n\n useEffect(() => {\n const handleVisibility = () => {\n setState(document.hidden ? 'background' : 'active');\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:foreground') setState('active');\n if (event.data === 'relay:background') setState('background');\n };\n\n document.addEventListener('visibilitychange', handleVisibility);\n window.addEventListener('message', handleMessage);\n\n return () => {\n document.removeEventListener('visibilitychange', handleVisibility);\n window.removeEventListener('message', handleMessage);\n };\n }, []);\n\n return state;\n}\n","import { useState, useEffect } from 'react';\n\nexport type TimerMode = 'focus' | 'shortBreak' | 'longBreak';\nexport type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';\n\nexport function useFocusTimer() {\n const [seconds, setSeconds] = useState(25 * 60);\n const [initialTime, setInitialTime] = useState(25 * 60);\n const [isActive, setIsActive] = useState(false);\n const [mode, setMode] = useState<TimerMode>('focus');\n const [task, setTask] = useState('');\n const [storyState, setStoryState] = useState<StoryState>('egg');\n const [soundEnabled, setSoundEnabled] = useState(false);\n\n useEffect(() => {\n let interval: any = null;\n\n if (isActive && seconds > 0) {\n interval = setInterval(() => {\n setSeconds((s) => s - 1);\n }, 1000);\n } else if (seconds === 0 && isActive) {\n // Timer Finished\n setIsActive(false);\n if (mode === 'focus') {\n const isAbducted = Math.random() < 0.01;\n setStoryState(isAbducted ? 'alien' : 'chick');\n }\n }\n\n return () => {\n if (interval) clearInterval(interval);\n };\n }, [isActive, seconds, mode]);\n\n // Update Visuals based on progress\n useEffect(() => {\n if (!isActive && (storyState === 'chick' || storyState === 'alien' || storyState === 'ghost')) return;\n\n // Don't change chick state during break\n if (mode !== 'focus') return;\n\n const progress = 1 - (seconds / initialTime);\n\n if (progress < 0.5) {\n setStoryState('egg');\n } else if (progress >= 0.5 && progress < 1) {\n setStoryState('cracked');\n }\n }, [seconds, initialTime, isActive, storyState, mode]);\n\n const toggleTimer = () => setIsActive(!isActive);\n\n const giveUp = () => {\n setIsActive(false);\n setStoryState('ghost');\n };\n\n const switchMode = (newMode: TimerMode) => {\n setIsActive(false);\n setMode(newMode);\n setStoryState('egg'); // Reset chick for new session\n\n // Set Times\n let newTime = 25 * 60;\n if (newMode === 'shortBreak') newTime = 5 * 60;\n if (newMode === 'longBreak') newTime = 15 * 60;\n\n setSeconds(newTime);\n setInitialTime(newTime);\n };\n\n const resetTimer = () => {\n setIsActive(false);\n switchMode(mode); // Re-init current mode\n };\n\n const setCustomTime = (mins: number) => {\n setIsActive(false);\n setSeconds(mins * 60);\n setInitialTime(mins * 60);\n setStoryState('egg');\n };\n\n return {\n seconds,\n initialTime,\n isActive,\n mode,\n task,\n storyState,\n soundEnabled,\n setSeconds,\n setInitialTime,\n setIsActive,\n setMode,\n setTask,\n setStoryState,\n setSoundEnabled,\n toggleTimer,\n giveUp,\n switchMode,\n resetTimer,\n setCustomTime,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/jas/Desktop/relay/sdk/dist/index.cjs","../src/hooks/use-keyboard.ts","../src/hooks/use-platform.tsx","../src/hooks/use-focus-timer.ts"],"names":["useKeyboard","state","setState","useState","useEffect","updateKeyboardState","viewport","keyboardHeight","isOpen","handleFocusIn","e","target","handleFocusOut","useRelayClose","useCallback","defaultInsets","SafeAreaContext","createContext","SafeAreaProvider","children","insets","setInsets","computeInsets","style","getEnv","name","value","setSeconds"],"mappings":"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","file":"/Users/jas/Desktop/relay/sdk/dist/index.cjs","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\n\ninterface KeyboardState {\n isOpen: boolean;\n height: number;\n}\n\n/**\n * useKeyboard - Track virtual keyboard state on mobile devices\n * \n * Uses visualViewport API to detect keyboard height and provides\n * a safe area offset for positioning UI elements above the keyboard.\n * \n * @returns {KeyboardState} - { isOpen: boolean, height: number }\n */\nexport function useKeyboard(): KeyboardState {\n const [state, setState] = useState<KeyboardState>({\n isOpen: false,\n height: 0\n });\n\n useEffect(() => {\n // Check if we're on a mobile device\n const isMobile = /iPad|iPhone|iPod|Android/.test(navigator.userAgent);\n if (!isMobile) return;\n\n const updateKeyboardState = () => {\n if (!window.visualViewport) return;\n\n const viewport = window.visualViewport;\n // Calculate keyboard height: difference between window and viewport height\n const keyboardHeight = window.innerHeight - viewport.height;\n // Consider keyboard open if height is more than 100px (threshold for accessory bars)\n const isOpen = keyboardHeight > 100;\n\n setState({\n isOpen,\n height: isOpen ? keyboardHeight : 0\n });\n };\n\n // Listen to visualViewport changes\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', updateKeyboardState);\n window.visualViewport.addEventListener('scroll', updateKeyboardState);\n }\n\n // Also listen for focus/blur on inputs as fallback\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n // Small delay to let keyboard animate\n setTimeout(updateKeyboardState, 100);\n }\n };\n\n const handleFocusOut = () => {\n // Small delay to let keyboard animate closed\n setTimeout(() => {\n setState({ isOpen: false, height: 0 });\n }, 100);\n };\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n\n // Initial check\n updateKeyboardState();\n\n return () => {\n window.visualViewport?.removeEventListener('resize', updateKeyboardState);\n window.visualViewport?.removeEventListener('scroll', updateKeyboardState);\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }, []);\n\n return state;\n}\n\n/**\n * useRelayClose - Get the close function for closing the current app\n * \n * Works with both iframe and blob URL contexts.\n * \n * @returns {() => void} - Function to close the current app\n */\nexport function useRelayClose(): () => void {\n const close = useCallback(() => {\n // Try multiple methods to close\n // 1. PostMessage to parent (works in iframe)\n if (window.parent !== window) {\n window.parent.postMessage('relay:close', '*');\n }\n // 2. PostMessage with opener (works if opened as popup)\n if (window.opener) {\n window.opener.postMessage('relay:close', '*');\n }\n // 3. Try self-closing (may not work in all contexts)\n window.close();\n }, []);\n\n return close;\n}\n","import { useState, useEffect, useCallback, createContext, useContext, ReactNode } from 'react';\n\n// ============================================\n// SAFE AREA TYPES & CONTEXT\n// ============================================\n\nexport interface SafeAreaInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nconst defaultInsets: SafeAreaInsets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0\n};\n\nconst SafeAreaContext = createContext<SafeAreaInsets>(defaultInsets);\n\n// ============================================\n// SAFE AREA PROVIDER\n// ============================================\n\ninterface SafeAreaProviderProps {\n children: ReactNode;\n}\n\n/**\n * SafeAreaProvider - Provides safe area insets to child components\n * \n * Automatically detects safe areas from:\n * 1. CSS env() values (iOS Safari)\n * 2. Parent Shell postMessage (when running in Relay Shell)\n */\nexport function SafeAreaProvider({ children }: SafeAreaProviderProps) {\n const [insets, setInsets] = useState<SafeAreaInsets>(defaultInsets);\n\n useEffect(() => {\n // Method 1: Read from CSS env() values\n const computeInsets = () => {\n const style = getComputedStyle(document.documentElement);\n const getEnv = (name: string) => {\n const value = style.getPropertyValue(`--safe-area-inset-${name}`);\n return parseInt(value) || 0;\n };\n\n // Try to get from CSS custom properties first\n let top = getEnv('top');\n let bottom = getEnv('bottom');\n let left = getEnv('left');\n let right = getEnv('right');\n\n // If CSS props not set, try to read from env() directly\n if (top === 0 && bottom === 0) {\n // Create a temp element to measure env() values\n const temp = document.createElement('div');\n temp.style.cssText = `\n position: fixed;\n top: env(safe-area-inset-top, 0px);\n bottom: env(safe-area-inset-bottom, 0px);\n left: env(safe-area-inset-left, 0px);\n right: env(safe-area-inset-right, 0px);\n pointer-events: none;\n visibility: hidden;\n `;\n document.body.appendChild(temp);\n const rect = temp.getBoundingClientRect();\n top = rect.top;\n bottom = window.innerHeight - rect.bottom;\n left = rect.left;\n right = window.innerWidth - rect.right;\n document.body.removeChild(temp);\n }\n\n setInsets({ top, bottom, left, right });\n };\n\n // Method 2: Listen for Shell messages\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'relay:safearea') {\n setInsets(event.data.insets);\n }\n };\n\n computeInsets();\n window.addEventListener('message', handleMessage);\n window.addEventListener('resize', computeInsets);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('resize', computeInsets);\n };\n }, []);\n\n return (\n <SafeAreaContext.Provider value={insets}>\n {children}\n </SafeAreaContext.Provider>\n );\n}\n\n// ============================================\n// SAFE AREA HOOKS\n// ============================================\n\n/**\n * useSafeArea - Get safe area insets\n * \n * @returns SafeAreaInsets with top, bottom, left, right values in pixels\n */\nexport function useSafeArea(): SafeAreaInsets {\n return useContext(SafeAreaContext);\n}\n\n// ============================================\n// COLOR SCHEME\n// ============================================\n\nexport type ColorScheme = 'light' | 'dark';\n\n/**\n * useColorScheme - Get current system color scheme\n * \n * @returns 'light' | 'dark'\n */\nexport function useColorScheme(): ColorScheme {\n const [scheme, setScheme] = useState<ColorScheme>(() =>\n window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n );\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => {\n setScheme(e.matches ? 'dark' : 'light');\n };\n media.addEventListener('change', handler);\n return () => media.removeEventListener('change', handler);\n }, []);\n\n return scheme;\n}\n\n// ============================================\n// STATUS BAR\n// ============================================\n\n/**\n * useStatusBar - Control the status bar appearance\n * \n * @param color - Hex color for the status bar\n */\nexport function useStatusBar(color: string): void {\n useEffect(() => {\n // Update meta theme-color\n let meta = document.querySelector('meta[name=\"theme-color\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', color);\n\n // Notify parent Shell\n window.parent?.postMessage({ type: 'relay:statusbar', color }, '*');\n }, [color]);\n}\n\n// ============================================\n// BACK HANDLER\n// ============================================\n\n/**\n * useBackHandler - Handle back navigation\n * \n * @param handler - Return true to prevent default back behavior\n */\nexport function useBackHandler(handler: () => boolean): void {\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:back') {\n const handled = handler();\n if (!handled) {\n // Allow default close behavior\n window.parent?.postMessage('relay:close', '*');\n }\n }\n };\n\n // Also handle browser back button\n const handlePopState = (event: PopStateEvent) => {\n const handled = handler();\n if (handled) {\n // Push a dummy state to prevent navigation\n window.history.pushState(null, '', window.location.href);\n }\n };\n\n // Push initial state for popstate handling\n window.history.pushState(null, '', window.location.href);\n\n window.addEventListener('message', handleMessage);\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('popstate', handlePopState);\n };\n }, [handler]);\n}\n\n// ============================================\n// APP STATE\n// ============================================\n\nexport type AppState = 'active' | 'background' | 'inactive';\n\n/**\n * useAppState - Track app foreground/background state\n * \n * @returns Current app state\n */\nexport function useAppState(): AppState {\n const [state, setState] = useState<AppState>('active');\n\n useEffect(() => {\n const handleVisibility = () => {\n setState(document.hidden ? 'background' : 'active');\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:foreground') setState('active');\n if (event.data === 'relay:background') setState('background');\n };\n\n document.addEventListener('visibilitychange', handleVisibility);\n window.addEventListener('message', handleMessage);\n\n return () => {\n document.removeEventListener('visibilitychange', handleVisibility);\n window.removeEventListener('message', handleMessage);\n };\n }, []);\n\n return state;\n}\n","import { useState, useEffect } from 'react';\n\nexport type TimerMode = 'focus' | 'shortBreak' | 'longBreak';\nexport type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';\n\nexport function useFocusTimer() {\n const [seconds, setSeconds] = useState(25 * 60);\n const [initialTime, setInitialTime] = useState(25 * 60);\n const [isActive, setIsActive] = useState(false);\n const [mode, setMode] = useState<TimerMode>('focus');\n const [task, setTask] = useState('');\n const [storyState, setStoryState] = useState<StoryState>('egg');\n const [soundEnabled, setSoundEnabled] = useState(false);\n\n useEffect(() => {\n let interval: any = null;\n\n if (isActive && seconds > 0) {\n interval = setInterval(() => {\n setSeconds((s) => s - 1);\n }, 1000);\n } else if (seconds === 0 && isActive) {\n // Timer Finished\n setIsActive(false);\n if (mode === 'focus') {\n const isAbducted = Math.random() < 0.01;\n setStoryState(isAbducted ? 'alien' : 'chick');\n }\n }\n\n return () => {\n if (interval) clearInterval(interval);\n };\n }, [isActive, seconds, mode]);\n\n // Update Visuals based on progress\n useEffect(() => {\n if (!isActive && (storyState === 'chick' || storyState === 'alien' || storyState === 'ghost')) return;\n\n // Don't change chick state during break\n if (mode !== 'focus') return;\n\n const progress = 1 - (seconds / initialTime);\n\n if (progress < 0.5) {\n setStoryState('egg');\n } else if (progress >= 0.5 && progress < 1) {\n setStoryState('cracked');\n }\n }, [seconds, initialTime, isActive, storyState, mode]);\n\n const toggleTimer = () => setIsActive(!isActive);\n\n const giveUp = () => {\n setIsActive(false);\n setStoryState('ghost');\n };\n\n const switchMode = (newMode: TimerMode) => {\n setIsActive(false);\n setMode(newMode);\n setStoryState('egg'); // Reset chick for new session\n\n // Set Times\n let newTime = 25 * 60;\n if (newMode === 'shortBreak') newTime = 5 * 60;\n if (newMode === 'longBreak') newTime = 15 * 60;\n\n setSeconds(newTime);\n setInitialTime(newTime);\n };\n\n const resetTimer = () => {\n setIsActive(false);\n switchMode(mode); // Re-init current mode\n };\n\n const setCustomTime = (mins: number) => {\n setIsActive(false);\n setSeconds(mins * 60);\n setInitialTime(mins * 60);\n setStoryState('egg');\n };\n\n return {\n seconds,\n initialTime,\n isActive,\n mode,\n task,\n storyState,\n soundEnabled,\n setSeconds,\n setInitialTime,\n setIsActive,\n setMode,\n setTask,\n setStoryState,\n setSoundEnabled,\n toggleTimer,\n giveUp,\n switchMode,\n resetTimer,\n setCustomTime,\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -45,6 +45,14 @@ interface SafeAreaViewProps {
|
|
|
45
45
|
* @param edges - Which edges to apply safe area to (default: all)
|
|
46
46
|
*/
|
|
47
47
|
declare function SafeAreaView({ children, edges, style, className }: SafeAreaViewProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
interface PlatformHeaderProps {
|
|
49
|
+
title: string;
|
|
50
|
+
showBack?: boolean;
|
|
51
|
+
onBack?: () => void;
|
|
52
|
+
className?: string;
|
|
53
|
+
rightElement?: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
declare function PlatformHeader({ title, showBack, onBack, className, rightElement }: PlatformHeaderProps): react_jsx_runtime.JSX.Element;
|
|
48
56
|
|
|
49
57
|
type TimerMode = 'focus' | 'shortBreak' | 'longBreak';
|
|
50
58
|
type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';
|
|
@@ -144,4 +152,99 @@ type AppState = 'active' | 'background' | 'inactive';
|
|
|
144
152
|
*/
|
|
145
153
|
declare function useAppState(): AppState;
|
|
146
154
|
|
|
147
|
-
|
|
155
|
+
interface NotificationOptions {
|
|
156
|
+
body?: string;
|
|
157
|
+
icon?: string;
|
|
158
|
+
image?: string;
|
|
159
|
+
badge?: string;
|
|
160
|
+
tag?: string;
|
|
161
|
+
data?: any;
|
|
162
|
+
vibrate?: number[];
|
|
163
|
+
timestamp?: number;
|
|
164
|
+
renotify?: boolean;
|
|
165
|
+
silent?: boolean;
|
|
166
|
+
requireInteraction?: boolean;
|
|
167
|
+
actions?: NotificationAction[];
|
|
168
|
+
}
|
|
169
|
+
interface NotificationAction {
|
|
170
|
+
action: string;
|
|
171
|
+
title: string;
|
|
172
|
+
icon?: string;
|
|
173
|
+
}
|
|
174
|
+
interface UseNotificationsReturn {
|
|
175
|
+
permission: NotificationPermission;
|
|
176
|
+
requestPermission: () => Promise<NotificationPermission>;
|
|
177
|
+
sendNotification: (title: string, options?: NotificationOptions) => void;
|
|
178
|
+
scheduleNotification: (title: string, delayMs: number, options?: NotificationOptions) => void;
|
|
179
|
+
clearBadge: () => Promise<void>;
|
|
180
|
+
setBadge: (count: number) => Promise<void>;
|
|
181
|
+
}
|
|
182
|
+
declare function useNotifications(): UseNotificationsReturn;
|
|
183
|
+
|
|
184
|
+
interface ClipboardItem {
|
|
185
|
+
type: 'text' | 'image' | 'html';
|
|
186
|
+
content: string | Blob;
|
|
187
|
+
timestamp: number;
|
|
188
|
+
}
|
|
189
|
+
interface UseClipboardReturn {
|
|
190
|
+
clipboardContent: string | null;
|
|
191
|
+
history: ClipboardItem[];
|
|
192
|
+
copyText: (text: string) => Promise<void>;
|
|
193
|
+
copyImage: (blob: Blob) => Promise<void>;
|
|
194
|
+
readText: () => Promise<string>;
|
|
195
|
+
readContent: () => Promise<ClipboardItems>;
|
|
196
|
+
clearHistory: () => void;
|
|
197
|
+
}
|
|
198
|
+
declare function useClipboard(): UseClipboardReturn;
|
|
199
|
+
|
|
200
|
+
interface LocationState {
|
|
201
|
+
loading: boolean;
|
|
202
|
+
accuracy: number | null;
|
|
203
|
+
altitude: number | null;
|
|
204
|
+
altitudeAccuracy: number | null;
|
|
205
|
+
heading: number | null;
|
|
206
|
+
latitude: number | null;
|
|
207
|
+
longitude: number | null;
|
|
208
|
+
speed: number | null;
|
|
209
|
+
timestamp: number | null;
|
|
210
|
+
error: GeolocationPositionError | null;
|
|
211
|
+
}
|
|
212
|
+
interface Geofence {
|
|
213
|
+
id: string;
|
|
214
|
+
latitude: number;
|
|
215
|
+
longitude: number;
|
|
216
|
+
radius: number;
|
|
217
|
+
}
|
|
218
|
+
interface UseGeolocationReturn extends LocationState {
|
|
219
|
+
getLocation: () => void;
|
|
220
|
+
watchLocation: (options?: PositionOptions) => void;
|
|
221
|
+
clearWatch: () => void;
|
|
222
|
+
checkGeofence: (fence: Geofence) => boolean;
|
|
223
|
+
distanceTo: (lat: number, lng: number) => number;
|
|
224
|
+
}
|
|
225
|
+
declare function useGeolocation(options?: PositionOptions): UseGeolocationReturn;
|
|
226
|
+
|
|
227
|
+
interface CameraState {
|
|
228
|
+
stream: MediaStream | null;
|
|
229
|
+
error: Error | null;
|
|
230
|
+
permission: PermissionState | 'unknown';
|
|
231
|
+
isRecording: boolean;
|
|
232
|
+
devices: MediaDeviceInfo[];
|
|
233
|
+
}
|
|
234
|
+
interface CameraOptions {
|
|
235
|
+
video?: boolean | MediaTrackConstraints;
|
|
236
|
+
audio?: boolean | MediaTrackConstraints;
|
|
237
|
+
}
|
|
238
|
+
interface UseCameraReturn extends CameraState {
|
|
239
|
+
startCamera: (options?: CameraOptions) => Promise<MediaStream | undefined>;
|
|
240
|
+
stopCamera: () => void;
|
|
241
|
+
takePhoto: () => Promise<string | undefined>;
|
|
242
|
+
startRecording: () => void;
|
|
243
|
+
stopRecording: () => Promise<Blob | undefined>;
|
|
244
|
+
startScreenShare: (options?: DisplayMediaStreamOptions) => Promise<MediaStream | undefined>;
|
|
245
|
+
switchDevice: (deviceId: string, kind: 'video' | 'audio') => Promise<void>;
|
|
246
|
+
getDevices: () => Promise<MediaDeviceInfo[]>;
|
|
247
|
+
}
|
|
248
|
+
declare function useCamera(): UseCameraReturn;
|
|
249
|
+
|
|
250
|
+
export { type AppState, type CameraOptions, type CameraState, type ClipboardItem, type ColorScheme, type Geofence, KeyboardAvoidingView, type LocationState, type NotificationAction, type NotificationOptions, PlatformHeader, type SafeAreaInsets, SafeAreaProvider, SafeAreaView, type StoryState, type TimerMode, type UseCameraReturn, type UseClipboardReturn, type UseGeolocationReturn, type UseNotificationsReturn, cn, useAppState, useBackHandler, useCamera, useClipboard, useColorScheme, useFocusTimer, useGeolocation, useIsMobile, useKeyboard, useNotifications, useRelayClose, useSafeArea, useStatusBar };
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,14 @@ interface SafeAreaViewProps {
|
|
|
45
45
|
* @param edges - Which edges to apply safe area to (default: all)
|
|
46
46
|
*/
|
|
47
47
|
declare function SafeAreaView({ children, edges, style, className }: SafeAreaViewProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
interface PlatformHeaderProps {
|
|
49
|
+
title: string;
|
|
50
|
+
showBack?: boolean;
|
|
51
|
+
onBack?: () => void;
|
|
52
|
+
className?: string;
|
|
53
|
+
rightElement?: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
declare function PlatformHeader({ title, showBack, onBack, className, rightElement }: PlatformHeaderProps): react_jsx_runtime.JSX.Element;
|
|
48
56
|
|
|
49
57
|
type TimerMode = 'focus' | 'shortBreak' | 'longBreak';
|
|
50
58
|
type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';
|
|
@@ -144,4 +152,99 @@ type AppState = 'active' | 'background' | 'inactive';
|
|
|
144
152
|
*/
|
|
145
153
|
declare function useAppState(): AppState;
|
|
146
154
|
|
|
147
|
-
|
|
155
|
+
interface NotificationOptions {
|
|
156
|
+
body?: string;
|
|
157
|
+
icon?: string;
|
|
158
|
+
image?: string;
|
|
159
|
+
badge?: string;
|
|
160
|
+
tag?: string;
|
|
161
|
+
data?: any;
|
|
162
|
+
vibrate?: number[];
|
|
163
|
+
timestamp?: number;
|
|
164
|
+
renotify?: boolean;
|
|
165
|
+
silent?: boolean;
|
|
166
|
+
requireInteraction?: boolean;
|
|
167
|
+
actions?: NotificationAction[];
|
|
168
|
+
}
|
|
169
|
+
interface NotificationAction {
|
|
170
|
+
action: string;
|
|
171
|
+
title: string;
|
|
172
|
+
icon?: string;
|
|
173
|
+
}
|
|
174
|
+
interface UseNotificationsReturn {
|
|
175
|
+
permission: NotificationPermission;
|
|
176
|
+
requestPermission: () => Promise<NotificationPermission>;
|
|
177
|
+
sendNotification: (title: string, options?: NotificationOptions) => void;
|
|
178
|
+
scheduleNotification: (title: string, delayMs: number, options?: NotificationOptions) => void;
|
|
179
|
+
clearBadge: () => Promise<void>;
|
|
180
|
+
setBadge: (count: number) => Promise<void>;
|
|
181
|
+
}
|
|
182
|
+
declare function useNotifications(): UseNotificationsReturn;
|
|
183
|
+
|
|
184
|
+
interface ClipboardItem {
|
|
185
|
+
type: 'text' | 'image' | 'html';
|
|
186
|
+
content: string | Blob;
|
|
187
|
+
timestamp: number;
|
|
188
|
+
}
|
|
189
|
+
interface UseClipboardReturn {
|
|
190
|
+
clipboardContent: string | null;
|
|
191
|
+
history: ClipboardItem[];
|
|
192
|
+
copyText: (text: string) => Promise<void>;
|
|
193
|
+
copyImage: (blob: Blob) => Promise<void>;
|
|
194
|
+
readText: () => Promise<string>;
|
|
195
|
+
readContent: () => Promise<ClipboardItems>;
|
|
196
|
+
clearHistory: () => void;
|
|
197
|
+
}
|
|
198
|
+
declare function useClipboard(): UseClipboardReturn;
|
|
199
|
+
|
|
200
|
+
interface LocationState {
|
|
201
|
+
loading: boolean;
|
|
202
|
+
accuracy: number | null;
|
|
203
|
+
altitude: number | null;
|
|
204
|
+
altitudeAccuracy: number | null;
|
|
205
|
+
heading: number | null;
|
|
206
|
+
latitude: number | null;
|
|
207
|
+
longitude: number | null;
|
|
208
|
+
speed: number | null;
|
|
209
|
+
timestamp: number | null;
|
|
210
|
+
error: GeolocationPositionError | null;
|
|
211
|
+
}
|
|
212
|
+
interface Geofence {
|
|
213
|
+
id: string;
|
|
214
|
+
latitude: number;
|
|
215
|
+
longitude: number;
|
|
216
|
+
radius: number;
|
|
217
|
+
}
|
|
218
|
+
interface UseGeolocationReturn extends LocationState {
|
|
219
|
+
getLocation: () => void;
|
|
220
|
+
watchLocation: (options?: PositionOptions) => void;
|
|
221
|
+
clearWatch: () => void;
|
|
222
|
+
checkGeofence: (fence: Geofence) => boolean;
|
|
223
|
+
distanceTo: (lat: number, lng: number) => number;
|
|
224
|
+
}
|
|
225
|
+
declare function useGeolocation(options?: PositionOptions): UseGeolocationReturn;
|
|
226
|
+
|
|
227
|
+
interface CameraState {
|
|
228
|
+
stream: MediaStream | null;
|
|
229
|
+
error: Error | null;
|
|
230
|
+
permission: PermissionState | 'unknown';
|
|
231
|
+
isRecording: boolean;
|
|
232
|
+
devices: MediaDeviceInfo[];
|
|
233
|
+
}
|
|
234
|
+
interface CameraOptions {
|
|
235
|
+
video?: boolean | MediaTrackConstraints;
|
|
236
|
+
audio?: boolean | MediaTrackConstraints;
|
|
237
|
+
}
|
|
238
|
+
interface UseCameraReturn extends CameraState {
|
|
239
|
+
startCamera: (options?: CameraOptions) => Promise<MediaStream | undefined>;
|
|
240
|
+
stopCamera: () => void;
|
|
241
|
+
takePhoto: () => Promise<string | undefined>;
|
|
242
|
+
startRecording: () => void;
|
|
243
|
+
stopRecording: () => Promise<Blob | undefined>;
|
|
244
|
+
startScreenShare: (options?: DisplayMediaStreamOptions) => Promise<MediaStream | undefined>;
|
|
245
|
+
switchDevice: (deviceId: string, kind: 'video' | 'audio') => Promise<void>;
|
|
246
|
+
getDevices: () => Promise<MediaDeviceInfo[]>;
|
|
247
|
+
}
|
|
248
|
+
declare function useCamera(): UseCameraReturn;
|
|
249
|
+
|
|
250
|
+
export { type AppState, type CameraOptions, type CameraState, type ClipboardItem, type ColorScheme, type Geofence, KeyboardAvoidingView, type LocationState, type NotificationAction, type NotificationOptions, PlatformHeader, type SafeAreaInsets, SafeAreaProvider, SafeAreaView, type StoryState, type TimerMode, type UseCameraReturn, type UseClipboardReturn, type UseGeolocationReturn, type UseNotificationsReturn, cn, useAppState, useBackHandler, useCamera, useClipboard, useColorScheme, useFocusTimer, useGeolocation, useIsMobile, useKeyboard, useNotifications, useRelayClose, useSafeArea, useStatusBar };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{$ as
|
|
1
|
+
import{$ as Qe,$a as Qt,$b as Zo,$c as Zr,$d as ei,A as Ce,Aa as Ct,Ab as ko,Ac as kr,Ad as Nn,Ae as Ni,B as ke,Ba as kt,Bb as No,Bc as Nr,Bd as Mn,Be as Mi,C as Ne,Ca as Nt,Cb as Mo,Cc as Mr,Cd as In,Ce as Ii,D as Me,Da as Mt,Db as Io,Dc as Ir,Dd as An,De as Ai,E as Ie,Ea as It,Eb as Ao,Ec as Ar,Ed as Tn,Ee as Ti,F as Ae,Fa as At,Fb as To,Fc as Tr,Fd as Ln,Fe as Li,G as Te,Ga as Tt,Gb as Lo,Gc as Lr,Gd as Rn,Ge as Ri,H as Le,Ha as Lt,Hb as Ro,Hc as Rr,Hd as On,He as Oi,I as Re,Ia as Rt,Ib as Oo,Ic as Or,Id as Bn,J as Oe,Ja as Ot,Jb as Bo,Jc as Br,Jd as Dn,K as Be,Ka as Bt,Kb as Do,Kc as Dr,Kd as Hn,L as De,La as Dt,Lb as Ho,Lc as Hr,Ld as Vn,M as He,Ma as Ht,Mb as Vo,Mc as Vr,Md as Un,N as Ve,Na as Vt,Nb as Uo,Nc as Ur,Nd as Gn,O as Ue,Oa as Ut,Ob as Go,Oc as Gr,Od as Kn,P as Ge,Pa as Gt,Pb as Ko,Pc as Kr,Pd as Fn,Q as Ke,Qa as Kt,Qb as Fo,Qc as Fr,Qd as qn,R as Fe,Ra as Ft,Rb as qo,Rc as qr,Rd as Wn,S as qe,Sa as qt,Sb as Wo,Sc as Wr,Sd as zn,T as We,Ta as Wt,Tb as zo,Tc as zr,Td as _n,U as ze,Ua as zt,Ub as _o,Uc as _r,Ud as Yn,V as _e,Va as _t,Vb as Yo,Vc as Yr,Vd as $n,W as Ye,Wa as Yt,Wb as $o,Wc as $r,Wd as Jn,X as $e,Xa as $t,Xb as Jo,Xc as Jr,Xd as Xn,Y as Je,Ya as Jt,Yb as Xo,Yc as Xr,Yd as jn,Z as Xe,Za as Xt,Zb as jo,Zc as jr,Zd as Qn,_ as je,_a as jt,_b as Qo,_c as Qr,_d as Zn,a as T,aa as Ze,ab as Zt,ac as er,ad as en,ae as ti,b as ee,ba as et,bb as eo,bc as tr,bd as tn,be as oi,c as te,ca as tt,cb as to,cc as or,cd as on,ce as ri,d as oe,da as ot,db as oo,dc as rr,dd as rn,de as ni,e as re,ea as rt,eb as ro,ec as nr,ed as nn,ee as ii,f as ne,fa as nt,fb as no,fc as ir,fd as an,fe as ai,g as ie,ga as it,gb as io,gc as ar,gd as sn,ge as si,h as ae,ha as at,hb as ao,hc as sr,hd as cn,he as ci,i as se,ia as st,ib as so,ic as cr,id as dn,ie as di,j as ce,ja as ct,jb as co,jc as dr,jd as ln,je as li,k as de,ka as dt,kb as lo,kc as lr,kd as un,ke as ui,l as le,la as lt,lb as uo,lc as ur,ld as mn,le as mi,m as ue,ma as ut,mb as mo,mc as mr,md as pn,me as pi,n as me,na as mt,nb as po,nc as pr,nd as fn,ne as fi,o as pe,oa as pt,ob as fo,oc as fr,od as gn,oe as gi,p as fe,pa as ft,pb as go,pc as gr,pd as vn,pe as vi,q as ge,qa as gt,qb as vo,qc as vr,qd as hn,qe as hi,r as ve,ra as vt,rb as ho,rc as hr,rd as bn,re as bi,s as he,sa as ht,sb as bo,sc as br,sd as wn,se as wi,t as be,ta as bt,tb as wo,tc as wr,td as yn,te as yi,u as we,ua as wt,ub as yo,uc as yr,ud as Sn,ue as Si,v as ye,va as yt,vb as So,vc as Sr,vd as xn,ve as xi,w as Se,wa as St,wb as xo,wc as xr,wd as En,we as Ei,x as xe,xa as xt,xb as Eo,xc as Er,xd as Pn,xe as Pi,y as Ee,ya as Et,yb as Po,yc as Pr,yd as Cn,ye as Ci,z as Pe,za as Pt,zb as Co,zc as Cr,zd as kn,ze as ki}from"./chunk-6VSTRIAD.js";import{useState as K,useEffect as F,useCallback as q}from"react";function L(){let[t,e]=K({isOpen:!1,height:0});return F(()=>{if(!/iPad|iPhone|iPod|Android/.test(navigator.userAgent))return;let o=()=>{if(!window.visualViewport)return;let u=window.visualViewport,d=window.innerHeight-u.height,p=d>100;e({isOpen:p,height:p?d:0})};window.visualViewport&&(window.visualViewport.addEventListener("resize",o),window.visualViewport.addEventListener("scroll",o));let n=u=>{let d=u.target;(d.tagName==="INPUT"||d.tagName==="TEXTAREA")&&setTimeout(o,100)},l=()=>{setTimeout(()=>{e({isOpen:!1,height:0})},100)};return document.addEventListener("focusin",n),document.addEventListener("focusout",l),o(),()=>{window.visualViewport?.removeEventListener("resize",o),window.visualViewport?.removeEventListener("scroll",o),document.removeEventListener("focusin",n),document.removeEventListener("focusout",l)}},[]),t}function Di(){return q(()=>{window.parent!==window&&window.parent.postMessage("relay:close","*"),window.opener&&window.opener.postMessage("relay:close","*"),window.close()},[])}import{useState as M,useEffect as P,createContext as W,useContext as z}from"react";import{jsx as _}from"react/jsx-runtime";var R={top:0,bottom:0,left:0,right:0},O=W(R);function Ki({children:t}){let[e,a]=M(R);return P(()=>{let o=()=>{let l=getComputedStyle(document.documentElement),u=r=>{let s=l.getPropertyValue(`--safe-area-inset-${r}`);return parseInt(s)||0},d=u("top"),p=u("bottom"),f=u("left"),i=u("right");if(d===0&&p===0){let r=document.createElement("div");r.style.cssText=`
|
|
2
2
|
position: fixed;
|
|
3
3
|
top: env(safe-area-inset-top, 0px);
|
|
4
4
|
bottom: env(safe-area-inset-bottom, 0px);
|
|
@@ -6,5 +6,5 @@ import{$ as Ke,$a as Kt,$b as Ro,$c as On,$d as Or,A as de,Aa as dt,Ab as co,Ac
|
|
|
6
6
|
right: env(safe-area-inset-right, 0px);
|
|
7
7
|
pointer-events: none;
|
|
8
8
|
visibility: hidden;
|
|
9
|
-
`,document.body.appendChild(d);let u=d.getBoundingClientRect();a=u.top,l=window.innerHeight-u.bottom,h=u.left,p=window.innerWidth-u.right,document.body.removeChild(d)}r({top:a,bottom:l,left:h,right:p})},n=s=>{s.data?.type==="relay:safearea"&&r(s.data.insets)};return o(),window.addEventListener("message",n),window.addEventListener("resize",o),()=>{window.removeEventListener("message",n),window.removeEventListener("resize",o)}},[]),B(y.Provider,{value:e,children:t})}function E(){return I(y)}function ks(){let[t,e]=v(()=>window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return g(()=>{let r=window.matchMedia("(prefers-color-scheme: dark)"),o=n=>{e(n.matches?"dark":"light")};return r.addEventListener("change",o),()=>r.removeEventListener("change",o)},[]),t}function Ls(t){g(()=>{let e=document.querySelector('meta[name="theme-color"]');e||(e=document.createElement("meta"),e.setAttribute("name","theme-color"),document.head.appendChild(e)),e.setAttribute("content",t),window.parent?.postMessage({type:"relay:statusbar",color:t},"*")},[t])}function Cs(t){g(()=>{let e=o=>{o.data==="relay:back"&&(t()||window.parent?.postMessage("relay:close","*"))},r=o=>{t()&&window.history.pushState(null,"",window.location.href)};return window.history.pushState(null,"",window.location.href),window.addEventListener("message",e),window.addEventListener("popstate",r),()=>{window.removeEventListener("message",e),window.removeEventListener("popstate",r)}},[t])}function Ps(){let[t,e]=v("active");return g(()=>{let r=()=>{e(document.hidden?"background":"active")},o=n=>{n.data==="relay:foreground"&&e("active"),n.data==="relay:background"&&e("background")};return document.addEventListener("visibilitychange",r),window.addEventListener("message",o),()=>{document.removeEventListener("visibilitychange",r),window.removeEventListener("message",o)}},[]),t}import{jsx as x}from"react/jsx-runtime";function Bs({children:t,behavior:e="padding",keyboardVerticalOffset:r=0,style:o,className:n}){let s=S(),i=s.height+r,a={...o,transition:"all 0.2s ease-out"};if(s.isOpen)switch(e){case"padding":a.paddingBottom=i;break;case"height":a.height=`calc(100% - ${i}px)`;break;case"position":a.transform=`translateY(-${i}px)`;break}return x("div",{style:a,className:n,children:t})}function Ns({children:t,edges:e=["top","bottom","left","right"],style:r,className:o}){let n=E(),s={...r,paddingTop:e.includes("top")?n.top:r?.paddingTop,paddingBottom:e.includes("bottom")?n.bottom:r?.paddingBottom,paddingLeft:e.includes("left")?n.left:r?.paddingLeft,paddingRight:e.includes("right")?n.right:r?.paddingRight};return x("div",{style:s,className:o,children:t})}import{useState as m,useEffect as A}from"react";function Hs(){let[t,e]=m(1500),[r,o]=m(1500),[n,s]=m(!1),[i,a]=m("focus"),[l,h]=m(""),[p,d]=m("egg"),[u,k]=m(!1);A(()=>{let c=null;if(n&&t>0)c=setInterval(()=>{e(f=>f-1)},1e3);else if(t===0&&n&&(s(!1),i==="focus")){let f=Math.random()<.01;d(f?"alien":"chick")}return()=>{c&&clearInterval(c)}},[n,t,i]),A(()=>{if(!n&&(p==="chick"||p==="alien"||p==="ghost")||i!=="focus")return;let c=1-t/r;c<.5?d("egg"):c>=.5&&c<1&&d("cracked")},[t,r,n,p,i]);let L=()=>s(!n),C=()=>{s(!1),d("ghost")},w=c=>{s(!1),a(c),d("egg");let f=1500;c==="shortBreak"&&(f=300),c==="longBreak"&&(f=900),e(f),o(f)};return{seconds:t,initialTime:r,isActive:n,mode:i,task:l,storyState:p,soundEnabled:u,setSeconds:e,setInitialTime:o,setIsActive:s,setMode:a,setTask:h,setStoryState:d,setSoundEnabled:k,toggleTimer:L,giveUp:C,switchMode:w,resetTimer:()=>{s(!1),w(i)},setCustomTime:c=>{s(!1),e(c*60),o(c*60),d("egg")}}}export{O as Accordion,F as AccordionContent,H as AccordionItem,z as AccordionTrigger,te as Alert,re as AlertAction,ne as AlertDescription,q as AlertDialog,j as AlertDialogAction,ee as AlertDialogCancel,Y as AlertDialogContent,_ as AlertDialogDescription,G as AlertDialogFooter,D as AlertDialogHeader,J as AlertDialogMedia,X as AlertDialogOverlay,W as AlertDialogPortal,Z as AlertDialogTitle,Q as AlertDialogTrigger,oe as AlertTitle,se as AspectRatio,ie as Avatar,ce as AvatarBadge,de as AvatarFallback,le as AvatarGroup,pe as AvatarGroupCount,ae as AvatarImage,fe as Badge,me as Breadcrumb,be as BreadcrumbEllipsis,he as BreadcrumbItem,ve as BreadcrumbLink,ge as BreadcrumbList,we as BreadcrumbPage,Se as BreadcrumbSeparator,U as Button,xe as ButtonGroup,ke as ButtonGroupSeparator,Ae as ButtonGroupText,Le as Calendar,Ce as CalendarDayButton,Pe as Card,Ie as CardAction,Be as CardContent,Ve as CardDescription,Ne as CardFooter,Te as CardHeader,Me as CardTitle,Re as Carousel,Oe as CarouselContent,He as CarouselItem,Fe as CarouselNext,ze as CarouselPrevious,$e as ChartContainer,We as ChartLegend,Xe as ChartLegendContent,Ue as ChartStyle,qe as ChartTooltip,Qe as ChartTooltipContent,Ye as Checkbox,De as Collapsible,Je as CollapsibleContent,Ge as CollapsibleTrigger,st as Combobox,wt as ComboboxChip,vt as ComboboxChips,St as ComboboxChipsInput,mt as ComboboxCollection,ct as ComboboxContent,gt as ComboboxEmpty,ut as ComboboxGroup,dt as ComboboxInput,pt as ComboboxItem,ft as ComboboxLabel,lt as ComboboxList,ht as ComboboxSeparator,at as ComboboxTrigger,it as ComboboxValue,Vt as Command,It as CommandDialog,Kt as CommandEmpty,Rt as CommandGroup,Bt as CommandInput,Ht as CommandItem,Nt as CommandList,Ot as CommandSeparator,zt as CommandShortcut,Ft as ContextMenu,Jt as ContextMenuCheckboxItem,Xt as ContextMenuContent,Ut as ContextMenuGroup,Yt as ContextMenuItem,_t as ContextMenuLabel,qt as ContextMenuPortal,Wt as ContextMenuRadioGroup,Zt as ContextMenuRadioItem,jt as ContextMenuSeparator,eo as ContextMenuShortcut,Qt as ContextMenuSub,Gt as ContextMenuSubContent,Dt as ContextMenuSubTrigger,$t as ContextMenuTrigger,yt as Dialog,At as DialogClose,Lt as DialogContent,Mt as DialogDescription,Pt as DialogFooter,Ct as DialogHeader,kt as DialogOverlay,xt as DialogPortal,Tt as DialogTitle,Et as DialogTrigger,to as Drawer,ro as DrawerClose,io as DrawerContent,po as DrawerDescription,co as DrawerFooter,ao as DrawerHeader,so as DrawerOverlay,no as DrawerPortal,lo as DrawerTitle,oo as DrawerTrigger,uo as DropdownMenu,wo as DropdownMenuCheckboxItem,go as DropdownMenuContent,ho as DropdownMenuGroup,vo as DropdownMenuItem,yo as DropdownMenuLabel,fo as DropdownMenuPortal,So as DropdownMenuRadioGroup,bo as DropdownMenuRadioItem,Eo as DropdownMenuSeparator,xo as DropdownMenuShortcut,Ao as DropdownMenuSub,Lo as DropdownMenuSubContent,ko as DropdownMenuSubTrigger,mo as DropdownMenuTrigger,Co as Empty,Io as EmptyContent,Vo as EmptyDescription,Po as EmptyHeader,To as EmptyMedia,Mo as EmptyTitle,Oo as Field,Ho as FieldContent,$o as FieldDescription,qo as FieldError,Ro as FieldGroup,zo as FieldLabel,Ko as FieldLegend,Uo as FieldSeparator,No as FieldSet,Fo as FieldTitle,Qo as HoverCard,Xo as HoverCardContent,Wo as HoverCardTrigger,Ze as Input,je as InputGroup,et as InputGroupAddon,tt as InputGroupButton,nt as InputGroupInput,ot as InputGroupText,rt as InputGroupTextarea,Yo as InputOTP,Do as InputOTPGroup,Jo as InputOTPSeparator,Go as InputOTPSlot,jo as Item,rn as ItemActions,tn as ItemContent,nn as ItemDescription,an as ItemFooter,Zo as ItemGroup,sn as ItemHeader,en as ItemMedia,_o as ItemSeparator,on as ItemTitle,dn as Kbd,cn as KbdGroup,Bs as KeyboardAvoidingView,Bo as Label,ln as Menubar,wn as MenubarCheckboxItem,hn as MenubarContent,un as MenubarGroup,vn as MenubarItem,bn as MenubarLabel,pn as MenubarMenu,fn as MenubarPortal,mn as MenubarRadioGroup,Sn as MenubarRadioItem,yn as MenubarSeparator,En as MenubarShortcut,xn as MenubarSub,kn as MenubarSubContent,An as MenubarSubTrigger,gn as MenubarTrigger,Ln as NavigationMenu,Vn as NavigationMenuContent,Nn as NavigationMenuIndicator,Pn as NavigationMenuItem,Bn as NavigationMenuLink,Cn as NavigationMenuList,Mn as NavigationMenuTrigger,In as NavigationMenuViewport,Kn as Pagination,Rn as PaginationContent,$n as PaginationEllipsis,On as PaginationItem,Hn as PaginationLink,Fn as PaginationNext,zn as PaginationPrevious,Un as Popover,Wn as PopoverAnchor,Qn as PopoverContent,Dn as PopoverDescription,Xn as PopoverHeader,Yn as PopoverTitle,qn as PopoverTrigger,Gn as Progress,Jn as RadioGroup,Zn as RadioGroupItem,er as ResizableHandle,jn as ResizablePanel,_n as ResizablePanelGroup,As as SafeAreaProvider,Ns as SafeAreaView,tr as ScrollArea,or as ScrollBar,nr as Select,ar as SelectContent,rr as SelectGroup,cr as SelectItem,dr as SelectLabel,ur as SelectScrollDownButton,pr as SelectScrollUpButton,lr as SelectSeparator,ir as SelectTrigger,sr as SelectValue,ye as Separator,fr as Sheet,gr as SheetClose,hr as SheetContent,br as SheetDescription,wr as SheetFooter,vr as SheetHeader,Sr as SheetTitle,mr as SheetTrigger,Tr as Sidebar,Or as SidebarContent,Kr as SidebarFooter,Hr as SidebarGroup,Fr as SidebarGroupAction,$r as SidebarGroupContent,zr as SidebarGroupLabel,Nr as SidebarHeader,Br as SidebarInput,Ir as SidebarInset,Ur as SidebarMenu,Wr as SidebarMenuAction,Xr as SidebarMenuBadge,Qr as SidebarMenuButton,qr as SidebarMenuItem,Yr as SidebarMenuSkeleton,Dr as SidebarMenuSub,Jr as SidebarMenuSubButton,Gr as SidebarMenuSubItem,Pr as SidebarProvider,Vr as SidebarRail,Rr as SidebarSeparator,Mr as SidebarTrigger,yr as Skeleton,Zr as Slider,jr as Spinner,es as Switch,ts as Table,ns as TableBody,ds as TableCaption,as as TableCell,rs as TableFooter,is as TableHead,os as TableHeader,ss as TableRow,cs as Tabs,fs as TabsContent,ps as TabsList,us as TabsTrigger,_e as Textarea,_r as Toaster,gs as Toggle,hs as ToggleGroup,vs as ToggleGroupItem,xr as Tooltip,kr as TooltipContent,Er as TooltipProvider,Ar as TooltipTrigger,ue as badgeVariants,Ee as buttonGroupVariants,$ as buttonVariants,R as cn,Tn as navigationMenuTriggerStyle,ls as tabsListVariants,ms as toggleVariants,Ps as useAppState,Cs as useBackHandler,Ke as useCarousel,ks as useColorScheme,bt as useComboboxAnchor,Hs as useFocusTimer,Lr as useIsMobile,S as useKeyboard,Ss as useRelayClose,E as useSafeArea,Cr as useSidebar,Ls as useStatusBar};
|
|
9
|
+
`,document.body.appendChild(r);let s=r.getBoundingClientRect();d=s.top,p=window.innerHeight-s.bottom,f=s.left,i=window.innerWidth-s.right,document.body.removeChild(r)}a({top:d,bottom:p,left:f,right:i})},n=l=>{l.data?.type==="relay:safearea"&&a(l.data.insets)};return o(),window.addEventListener("message",n),window.addEventListener("resize",o),()=>{window.removeEventListener("message",n),window.removeEventListener("resize",o)}},[]),_(O.Provider,{value:e,children:t})}function I(){return z(O)}function Fi(){let[t,e]=M(()=>window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return P(()=>{let a=window.matchMedia("(prefers-color-scheme: dark)"),o=n=>{e(n.matches?"dark":"light")};return a.addEventListener("change",o),()=>a.removeEventListener("change",o)},[]),t}function qi(t){P(()=>{let e=document.querySelector('meta[name="theme-color"]');e||(e=document.createElement("meta"),e.setAttribute("name","theme-color"),document.head.appendChild(e)),e.setAttribute("content",t),window.parent?.postMessage({type:"relay:statusbar",color:t},"*")},[t])}function Wi(t){P(()=>{let e=o=>{o.data==="relay:back"&&(t()||window.parent?.postMessage("relay:close","*"))},a=o=>{t()&&window.history.pushState(null,"",window.location.href)};return window.history.pushState(null,"",window.location.href),window.addEventListener("message",e),window.addEventListener("popstate",a),()=>{window.removeEventListener("message",e),window.removeEventListener("popstate",a)}},[t])}function zi(){let[t,e]=M("active");return P(()=>{let a=()=>{e(document.hidden?"background":"active")},o=n=>{n.data==="relay:foreground"&&e("active"),n.data==="relay:background"&&e("background")};return document.addEventListener("visibilitychange",a),window.addEventListener("message",o),()=>{document.removeEventListener("visibilitychange",a),window.removeEventListener("message",o)}},[]),t}import{jsx as b,jsxs as B}from"react/jsx-runtime";function ji({children:t,behavior:e="padding",keyboardVerticalOffset:a=0,style:o,className:n}){let l=L(),u=l.height+a,d={...o,transition:"all 0.2s ease-out"};if(l.isOpen)switch(e){case"padding":d.paddingBottom=u;break;case"height":d.height=`calc(100% - ${u}px)`;break;case"position":d.transform=`translateY(-${u}px)`;break}return b("div",{style:d,className:n,children:t})}function Qi({children:t,edges:e=["top","bottom","left","right"],style:a,className:o}){let n=I(),l={...a,paddingTop:e.includes("top")?n.top:a?.paddingTop,paddingBottom:e.includes("bottom")?n.bottom:a?.paddingBottom,paddingLeft:e.includes("left")?n.left:a?.paddingLeft,paddingRight:e.includes("right")?n.right:a?.paddingRight};return b("div",{style:l,className:o,children:t})}function Zi({title:t,showBack:e=!0,onBack:a,className:o,rightElement:n}){let l=I();return b("div",{className:T("bg-background border-b flex flex-col z-50",o),style:{paddingTop:l.top},children:B("div",{className:"h-14 flex items-center justify-between px-4",children:[B("div",{className:"flex items-center gap-4 flex-1",children:[e&&b("button",{onClick:a||(()=>window.history.back()),className:"p-2 -ml-2 hover:bg-muted rounded-full transition-colors",children:b("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:b("path",{d:"M19 12H5M12 19l-7-7 7-7"})})}),b("h1",{className:"text-lg font-semibold truncate",children:t})]}),n&&b("div",{className:"flex-none",children:n})]})})}import{useState as S,useEffect as D}from"react";function ra(){let[t,e]=S(1500),[a,o]=S(1500),[n,l]=S(!1),[u,d]=S("focus"),[p,f]=S(""),[i,r]=S("egg"),[s,c]=S(!1);D(()=>{let g=null;if(n&&t>0)g=setInterval(()=>{e(h=>h-1)},1e3);else if(t===0&&n&&(l(!1),u==="focus")){let h=Math.random()<.01;r(h?"alien":"chick")}return()=>{g&&clearInterval(g)}},[n,t,u]),D(()=>{if(!n&&(i==="chick"||i==="alien"||i==="ghost")||u!=="focus")return;let g=1-t/a;g<.5?r("egg"):g>=.5&&g<1&&r("cracked")},[t,a,n,i,u]);let m=()=>l(!n),v=()=>{l(!1),r("ghost")},y=g=>{l(!1),d(g),r("egg");let h=1500;g==="shortBreak"&&(h=300),g==="longBreak"&&(h=900),e(h),o(h)};return{seconds:t,initialTime:a,isActive:n,mode:u,task:p,storyState:i,soundEnabled:s,setSeconds:e,setInitialTime:o,setIsActive:l,setMode:d,setTask:f,setStoryState:r,setSoundEnabled:c,toggleTimer:m,giveUp:v,switchMode:y,resetTimer:()=>{l(!1),y(u)},setCustomTime:g=>{l(!1),e(g*60),o(g*60),r("egg")}}}import{useState as Y,useCallback as C,useEffect as $}from"react";function aa(){let[t,e]=Y("default");$(()=>{"Notification"in window&&e(Notification.permission)},[]);let a=C(async()=>{if(!("Notification"in window))return console.warn("Notifications not supported"),"denied";let d=await Notification.requestPermission();return e(d),d},[]),o=C((d,p)=>{if(!("Notification"in window))return;let f=p;if(!p?.icon){let i=document.querySelector('link[rel="apple-touch-icon"]')||document.querySelector('link[rel="icon"]');i&&(f={...p,icon:i.href})}Notification.permission==="granted"?new Notification(d,f):Notification.permission!=="denied"&&Notification.requestPermission().then(i=>{i==="granted"&&new Notification(d,f)})},[]),n=C((d,p,f)=>{setTimeout(()=>{o(d,f)},p)},[o]),l=C(async d=>{if("setAppBadge"in navigator)try{await navigator.setAppBadge(d)}catch(p){console.error("Error setting badge:",p)}},[]),u=C(async()=>{if("clearAppBadge"in navigator)try{await navigator.clearAppBadge()}catch(d){console.error("Error clearing badge:",d)}},[]);return{permission:t,requestPermission:a,sendNotification:o,scheduleNotification:n,setBadge:l,clearBadge:u}}import{useState as H,useCallback as E,useEffect as V}from"react";var A="relay_clipboard_history",J=10;function da(){let[t,e]=H(null),[a,o]=H([]);V(()=>{try{let i=localStorage.getItem(A);if(i){let r=JSON.parse(i);o(r)}}catch(i){console.error("Failed to load clipboard history",i)}},[]);let n=E(i=>{o(r=>{let s=[i,...r].slice(0,J),c=s.filter(m=>m.type==="text");try{localStorage.setItem(A,JSON.stringify(c))}catch(m){console.error("Failed to save clipboard history",m)}return s})},[]),l=E(async i=>{if(!navigator.clipboard){console.warn("Clipboard API not supported");return}try{await navigator.clipboard.writeText(i),e(i),n({type:"text",content:i,timestamp:Date.now()})}catch(r){throw console.error("Failed to copy text:",r),r}},[n]),u=E(async i=>{if(!navigator.clipboard){console.warn("Clipboard API not supported");return}try{await navigator.clipboard.write([new ClipboardItem({[i.type]:i})]),n({type:"image",content:i,timestamp:Date.now()})}catch(r){throw console.error("Failed to copy image:",r),r}},[n]),d=E(async()=>{if(!navigator.clipboard)return console.warn("Clipboard API not supported"),"";try{let i=await navigator.clipboard.readText();return e(i),i}catch(i){throw console.error("Failed to read text:",i),i}},[]),p=E(async()=>{if(!navigator.clipboard)return console.warn("Clipboard API not supported"),[];try{return await navigator.clipboard.read()}catch(i){throw console.error("Failed to read content:",i),i}},[]),f=E(()=>{o([]),localStorage.removeItem(A)},[]);return V(()=>{let i=()=>{d().catch(()=>{})};return window.addEventListener("focus",i),()=>window.removeEventListener("focus",i)},[d]),{clipboardContent:t,history:a,copyText:l,copyImage:u,readText:d,readContent:p,clearHistory:f}}import{useState as X,useCallback as x,useEffect as j,useRef as Q}from"react";function ma(t){let[e,a]=X({loading:!0,accuracy:null,altitude:null,altitudeAccuracy:null,heading:null,latitude:null,longitude:null,speed:null,timestamp:null,error:null}),o=Q(null),n=x(r=>{a({loading:!1,accuracy:r.coords.accuracy,altitude:r.coords.altitude,altitudeAccuracy:r.coords.altitudeAccuracy,heading:r.coords.heading,latitude:r.coords.latitude,longitude:r.coords.longitude,speed:r.coords.speed,timestamp:r.timestamp,error:null})},[]),l=x(r=>{a(s=>({...s,loading:!1,error:r}))},[]),u=x(()=>{if(!navigator.geolocation){a(r=>({...r,loading:!1,error:{code:0,message:"Geolocation not supported",PERMISSION_DENIED:1,POSITION_UNAVAILABLE:2,TIMEOUT:3}}));return}a(r=>({...r,loading:!0})),navigator.geolocation.getCurrentPosition(n,l,t)},[n,l,t]),d=x(r=>{navigator.geolocation&&(o.current!==null&&navigator.geolocation.clearWatch(o.current),o.current=navigator.geolocation.watchPosition(n,l,r||t))},[n,l,t]),p=x(()=>{o.current!==null&&(navigator.geolocation.clearWatch(o.current),o.current=null)},[]),f=x((r,s)=>{if(e.latitude===null||e.longitude===null)return 1/0;let c=6371e3,m=e.latitude*Math.PI/180,v=r*Math.PI/180,y=(r-e.latitude)*Math.PI/180,k=(s-e.longitude)*Math.PI/180,N=Math.sin(y/2)*Math.sin(y/2)+Math.cos(m)*Math.cos(v)*Math.sin(k/2)*Math.sin(k/2),g=2*Math.atan2(Math.sqrt(N),Math.sqrt(1-N));return c*g},[e.latitude,e.longitude]),i=x(r=>f(r.latitude,r.longitude)<=r.radius,[f]);return j(()=>()=>{o.current!==null&&navigator.geolocation.clearWatch(o.current)},[]),{...e,getLocation:u,watchLocation:d,clearWatch:p,checkGeofence:i,distanceTo:f}}import{useState as Z,useCallback as w,useRef as U,useEffect as G}from"react";function ga(){let[t,e]=Z({stream:null,error:null,permission:"unknown",isRecording:!1,devices:[]}),a=U(null),o=U([]),n=w(async()=>{if(!navigator.mediaDevices?.enumerateDevices)return[];try{let s=await navigator.mediaDevices.enumerateDevices();return e(c=>({...c,devices:s})),s}catch(s){return console.error("Error enumerating devices:",s),[]}},[]);G(()=>(n(),navigator.mediaDevices?.addEventListener("devicechange",n),()=>{navigator.mediaDevices?.removeEventListener("devicechange",n)}),[n]);let l=w(async(s={video:!0,audio:!1})=>{try{let c=await navigator.mediaDevices.getUserMedia(s);return e(m=>({...m,stream:c,error:null,permission:"granted"})),c}catch(c){let m=c;e(v=>({...v,error:m,permission:"denied"})),console.error("Error starting camera:",c)}},[]),u=w(()=>{t.stream&&(t.stream.getTracks().forEach(s=>s.stop()),e(s=>({...s,stream:null,isRecording:!1})))},[t.stream]),d=w(async(s={video:!0})=>{try{let c=await navigator.mediaDevices.getDisplayMedia(s);return e(m=>({...m,stream:c,error:null,permission:"granted"})),c}catch(c){let m=c;e(v=>({...v,error:m,permission:"denied"})),console.error("Error starting screen share:",c)}},[]),p=w(async()=>{if(!t.stream||!t.stream.getVideoTracks()[0])return;let c=document.createElement("video");c.srcObject=t.stream,await c.play();let m=document.createElement("canvas");m.width=c.videoWidth,m.height=c.videoHeight;let v=m.getContext("2d");if(!v)return;v.drawImage(c,0,0);let y=m.toDataURL("image/png");return c.pause(),c.srcObject=null,y},[t.stream]),f=w(()=>{if(t.stream)try{let s=new MediaRecorder(t.stream);a.current=s,o.current=[],s.ondataavailable=c=>{c.data.size>0&&o.current.push(c.data)},s.start(),e(c=>({...c,isRecording:!0}))}catch(s){console.error("Error starting recording:",s),e(c=>({...c,error:s}))}},[t.stream]),i=w(async()=>{if(!(!a.current||a.current.state==="inactive"))return new Promise(s=>{a.current&&(a.current.onstop=()=>{let c=new Blob(o.current,{type:"video/webm"});e(m=>({...m,isRecording:!1})),s(c)},a.current.stop())})},[]),r=w(async(s,c)=>{u();let m={[c]:{deviceId:{exact:s}}};await l(m)},[l,u]);return G(()=>()=>{u()},[]),{...t,startCamera:l,stopCamera:u,takePhoto:p,startRecording:f,stopRecording:i,startScreenShare:d,switchDevice:r,getDevices:n}}export{ee as Accordion,re as AccordionContent,te as AccordionItem,oe as AccordionTrigger,be as Alert,Se as AlertAction,ye as AlertDescription,ae as AlertDialog,ve as AlertDialogAction,he as AlertDialogCancel,le as AlertDialogContent,ge as AlertDialogDescription,me as AlertDialogFooter,ue as AlertDialogHeader,pe as AlertDialogMedia,de as AlertDialogOverlay,ce as AlertDialogPortal,fe as AlertDialogTitle,se as AlertDialogTrigger,we as AlertTitle,xe as AspectRatio,Ee as Avatar,ke as AvatarBadge,Ce as AvatarFallback,Ne as AvatarGroup,Me as AvatarGroupCount,Pe as AvatarImage,Ae as Badge,Te as Breadcrumb,He as BreadcrumbEllipsis,Re as BreadcrumbItem,Oe as BreadcrumbLink,Le as BreadcrumbList,Be as BreadcrumbPage,De as BreadcrumbSeparator,ie as Button,Ge as ButtonGroup,Fe as ButtonGroupSeparator,Ke as ButtonGroupText,qe as Calendar,We as CalendarDayButton,ze as Card,Je as CardAction,Xe as CardContent,$e as CardDescription,je as CardFooter,_e as CardHeader,Ye as CardTitle,Ze as Carousel,et as CarouselContent,tt as CarouselItem,rt as CarouselNext,ot as CarouselPrevious,nt as ChartContainer,ct as ChartLegend,dt as ChartLegendContent,it as ChartStyle,at as ChartTooltip,st as ChartTooltipContent,lt as Checkbox,ut as Collapsible,pt as CollapsibleContent,mt as CollapsibleTrigger,xt as Combobox,Bt as ComboboxChip,Ot as ComboboxChips,Dt as ComboboxChipsInput,Tt as ComboboxCollection,kt as ComboboxContent,Lt as ComboboxEmpty,It as ComboboxGroup,Ct as ComboboxInput,Mt as ComboboxItem,At as ComboboxLabel,Nt as ComboboxList,Rt as ComboboxSeparator,Pt as ComboboxTrigger,Et as ComboboxValue,$t as Command,Jt as CommandDialog,Qt as CommandEmpty,Zt as CommandGroup,Xt as CommandInput,to as CommandItem,jt as CommandList,eo as CommandSeparator,oo as CommandShortcut,ro as ContextMenu,fo as ContextMenuCheckboxItem,lo as ContextMenuContent,io as ContextMenuGroup,uo as ContextMenuItem,vo as ContextMenuLabel,ao as ContextMenuPortal,co as ContextMenuRadioGroup,go as ContextMenuRadioItem,ho as ContextMenuSeparator,bo as ContextMenuShortcut,so as ContextMenuSub,po as ContextMenuSubContent,mo as ContextMenuSubTrigger,no as ContextMenuTrigger,Vt as Dialog,Kt as DialogClose,qt as DialogContent,Yt as DialogDescription,zt as DialogFooter,Wt as DialogHeader,Ft as DialogOverlay,Gt as DialogPortal,_t as DialogTitle,Ut as DialogTrigger,wo as Drawer,xo as DrawerClose,Po as DrawerContent,Mo as DrawerDescription,ko as DrawerFooter,Co as DrawerHeader,Eo as DrawerOverlay,So as DrawerPortal,No as DrawerTitle,yo as DrawerTrigger,Io as DropdownMenu,Bo as DropdownMenuCheckboxItem,Lo as DropdownMenuContent,Ro as DropdownMenuGroup,Oo as DropdownMenuItem,Vo as DropdownMenuLabel,Ao as DropdownMenuPortal,Do as DropdownMenuRadioGroup,Ho as DropdownMenuRadioItem,Uo as DropdownMenuSeparator,Go as DropdownMenuShortcut,Ko as DropdownMenuSub,qo as DropdownMenuSubContent,Fo as DropdownMenuSubTrigger,To as DropdownMenuTrigger,Wo as Empty,Jo as EmptyContent,$o as EmptyDescription,zo as EmptyHeader,_o as EmptyMedia,Yo as EmptyTitle,er as Field,tr as FieldContent,nr as FieldDescription,ar as FieldError,Zo as FieldGroup,or as FieldLabel,Qo as FieldLegend,ir as FieldSeparator,jo as FieldSet,rr as FieldTitle,sr as HoverCard,dr as HoverCardContent,cr as HoverCardTrigger,ft as Input,vt as InputGroup,ht as InputGroupAddon,bt as InputGroupButton,yt as InputGroupInput,wt as InputGroupText,St as InputGroupTextarea,lr as InputOTP,ur as InputOTPGroup,pr as InputOTPSeparator,mr as InputOTPSlot,vr as Item,Sr as ItemActions,br as ItemContent,yr as ItemDescription,Er as ItemFooter,fr as ItemGroup,xr as ItemHeader,hr as ItemMedia,gr as ItemSeparator,wr as ItemTitle,Pr as Kbd,Cr as KbdGroup,ji as KeyboardAvoidingView,Xo as Label,kr as Menubar,Or as MenubarCheckboxItem,Lr as MenubarContent,Mr as MenubarGroup,Rr as MenubarItem,Dr as MenubarLabel,Nr as MenubarMenu,Ir as MenubarPortal,Ar as MenubarRadioGroup,Br as MenubarRadioItem,Hr as MenubarSeparator,Vr as MenubarShortcut,Ur as MenubarSub,Kr as MenubarSubContent,Gr as MenubarSubTrigger,Tr as MenubarTrigger,Fr as NavigationMenu,Yr as NavigationMenuContent,Xr as NavigationMenuIndicator,Wr as NavigationMenuItem,Jr as NavigationMenuLink,qr as NavigationMenuList,_r as NavigationMenuTrigger,$r as NavigationMenuViewport,jr as Pagination,Qr as PaginationContent,rn as PaginationEllipsis,Zr as PaginationItem,en as PaginationLink,on as PaginationNext,tn as PaginationPrevious,Zi as PlatformHeader,nn as Popover,cn as PopoverAnchor,sn as PopoverContent,un as PopoverDescription,dn as PopoverHeader,ln as PopoverTitle,an as PopoverTrigger,mn as Progress,pn as RadioGroup,fn as RadioGroupItem,hn as ResizableHandle,vn as ResizablePanel,gn as ResizablePanelGroup,Ki as SafeAreaProvider,Qi as SafeAreaView,bn as ScrollArea,wn as ScrollBar,yn as Select,Pn as SelectContent,Sn as SelectGroup,kn as SelectItem,Cn as SelectLabel,In as SelectScrollDownButton,Mn as SelectScrollUpButton,Nn as SelectSeparator,En as SelectTrigger,xn as SelectValue,Ve as Separator,An as Sheet,Ln as SheetClose,Rn as SheetContent,Hn as SheetDescription,Bn as SheetFooter,On as SheetHeader,Dn as SheetTitle,Tn as SheetTrigger,_n as Sidebar,ei as SidebarContent,Qn as SidebarFooter,ti as SidebarGroup,ri as SidebarGroupAction,ni as SidebarGroupContent,oi as SidebarGroupLabel,jn as SidebarHeader,Xn as SidebarInput,Jn as SidebarInset,ii as SidebarMenu,ci as SidebarMenuAction,di as SidebarMenuBadge,si as SidebarMenuButton,ai as SidebarMenuItem,li as SidebarMenuSkeleton,ui as SidebarMenuSub,pi as SidebarMenuSubButton,mi as SidebarMenuSubItem,zn as SidebarProvider,$n as SidebarRail,Zn as SidebarSeparator,Yn as SidebarTrigger,Vn as Skeleton,fi as Slider,vi as Spinner,hi as Switch,bi as Table,yi as TableBody,Ci as TableCaption,Pi as TableCell,Si as TableFooter,Ei as TableHead,wi as TableHeader,xi as TableRow,ki as Tabs,Ai as TabsContent,Mi as TabsList,Ii as TabsTrigger,gt as Textarea,gi as Toaster,Li as Toggle,Ri as ToggleGroup,Oi as ToggleGroupItem,Gn as Tooltip,Fn as TooltipContent,Un as TooltipProvider,Kn as TooltipTrigger,Ie as badgeVariants,Ue as buttonGroupVariants,ne as buttonVariants,T as cn,zr as navigationMenuTriggerStyle,Ni as tabsListVariants,Ti as toggleVariants,zi as useAppState,Wi as useBackHandler,ga as useCamera,Qe as useCarousel,da as useClipboard,Fi as useColorScheme,Ht as useComboboxAnchor,ra as useFocusTimer,ma as useGeolocation,qn as useIsMobile,L as useKeyboard,aa as useNotifications,Di as useRelayClose,I as useSafeArea,Wn as useSidebar,qi as useStatusBar};
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-keyboard.ts","../src/hooks/use-platform.tsx","../src/components/platform.tsx","../src/hooks/use-focus-timer.ts"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\n\ninterface KeyboardState {\n isOpen: boolean;\n height: number;\n}\n\n/**\n * useKeyboard - Track virtual keyboard state on mobile devices\n * \n * Uses visualViewport API to detect keyboard height and provides\n * a safe area offset for positioning UI elements above the keyboard.\n * \n * @returns {KeyboardState} - { isOpen: boolean, height: number }\n */\nexport function useKeyboard(): KeyboardState {\n const [state, setState] = useState<KeyboardState>({\n isOpen: false,\n height: 0\n });\n\n useEffect(() => {\n // Check if we're on a mobile device\n const isMobile = /iPad|iPhone|iPod|Android/.test(navigator.userAgent);\n if (!isMobile) return;\n\n const updateKeyboardState = () => {\n if (!window.visualViewport) return;\n\n const viewport = window.visualViewport;\n // Calculate keyboard height: difference between window and viewport height\n const keyboardHeight = window.innerHeight - viewport.height;\n // Consider keyboard open if height is more than 100px (threshold for accessory bars)\n const isOpen = keyboardHeight > 100;\n\n setState({\n isOpen,\n height: isOpen ? keyboardHeight : 0\n });\n };\n\n // Listen to visualViewport changes\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', updateKeyboardState);\n window.visualViewport.addEventListener('scroll', updateKeyboardState);\n }\n\n // Also listen for focus/blur on inputs as fallback\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n // Small delay to let keyboard animate\n setTimeout(updateKeyboardState, 100);\n }\n };\n\n const handleFocusOut = () => {\n // Small delay to let keyboard animate closed\n setTimeout(() => {\n setState({ isOpen: false, height: 0 });\n }, 100);\n };\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n\n // Initial check\n updateKeyboardState();\n\n return () => {\n window.visualViewport?.removeEventListener('resize', updateKeyboardState);\n window.visualViewport?.removeEventListener('scroll', updateKeyboardState);\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }, []);\n\n return state;\n}\n\n/**\n * useRelayClose - Get the close function for closing the current app\n * \n * Works with both iframe and blob URL contexts.\n * \n * @returns {() => void} - Function to close the current app\n */\nexport function useRelayClose(): () => void {\n const close = useCallback(() => {\n // Try multiple methods to close\n // 1. PostMessage to parent (works in iframe)\n if (window.parent !== window) {\n window.parent.postMessage('relay:close', '*');\n }\n // 2. PostMessage with opener (works if opened as popup)\n if (window.opener) {\n window.opener.postMessage('relay:close', '*');\n }\n // 3. Try self-closing (may not work in all contexts)\n window.close();\n }, []);\n\n return close;\n}\n","import { useState, useEffect, useCallback, createContext, useContext, ReactNode } from 'react';\n\n// ============================================\n// SAFE AREA TYPES & CONTEXT\n// ============================================\n\nexport interface SafeAreaInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nconst defaultInsets: SafeAreaInsets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0\n};\n\nconst SafeAreaContext = createContext<SafeAreaInsets>(defaultInsets);\n\n// ============================================\n// SAFE AREA PROVIDER\n// ============================================\n\ninterface SafeAreaProviderProps {\n children: ReactNode;\n}\n\n/**\n * SafeAreaProvider - Provides safe area insets to child components\n * \n * Automatically detects safe areas from:\n * 1. CSS env() values (iOS Safari)\n * 2. Parent Shell postMessage (when running in Relay Shell)\n */\nexport function SafeAreaProvider({ children }: SafeAreaProviderProps) {\n const [insets, setInsets] = useState<SafeAreaInsets>(defaultInsets);\n\n useEffect(() => {\n // Method 1: Read from CSS env() values\n const computeInsets = () => {\n const style = getComputedStyle(document.documentElement);\n const getEnv = (name: string) => {\n const value = style.getPropertyValue(`--safe-area-inset-${name}`);\n return parseInt(value) || 0;\n };\n\n // Try to get from CSS custom properties first\n let top = getEnv('top');\n let bottom = getEnv('bottom');\n let left = getEnv('left');\n let right = getEnv('right');\n\n // If CSS props not set, try to read from env() directly\n if (top === 0 && bottom === 0) {\n // Create a temp element to measure env() values\n const temp = document.createElement('div');\n temp.style.cssText = `\n position: fixed;\n top: env(safe-area-inset-top, 0px);\n bottom: env(safe-area-inset-bottom, 0px);\n left: env(safe-area-inset-left, 0px);\n right: env(safe-area-inset-right, 0px);\n pointer-events: none;\n visibility: hidden;\n `;\n document.body.appendChild(temp);\n const rect = temp.getBoundingClientRect();\n top = rect.top;\n bottom = window.innerHeight - rect.bottom;\n left = rect.left;\n right = window.innerWidth - rect.right;\n document.body.removeChild(temp);\n }\n\n setInsets({ top, bottom, left, right });\n };\n\n // Method 2: Listen for Shell messages\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'relay:safearea') {\n setInsets(event.data.insets);\n }\n };\n\n computeInsets();\n window.addEventListener('message', handleMessage);\n window.addEventListener('resize', computeInsets);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('resize', computeInsets);\n };\n }, []);\n\n return (\n <SafeAreaContext.Provider value={insets}>\n {children}\n </SafeAreaContext.Provider>\n );\n}\n\n// ============================================\n// SAFE AREA HOOKS\n// ============================================\n\n/**\n * useSafeArea - Get safe area insets\n * \n * @returns SafeAreaInsets with top, bottom, left, right values in pixels\n */\nexport function useSafeArea(): SafeAreaInsets {\n return useContext(SafeAreaContext);\n}\n\n// ============================================\n// COLOR SCHEME\n// ============================================\n\nexport type ColorScheme = 'light' | 'dark';\n\n/**\n * useColorScheme - Get current system color scheme\n * \n * @returns 'light' | 'dark'\n */\nexport function useColorScheme(): ColorScheme {\n const [scheme, setScheme] = useState<ColorScheme>(() =>\n window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n );\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => {\n setScheme(e.matches ? 'dark' : 'light');\n };\n media.addEventListener('change', handler);\n return () => media.removeEventListener('change', handler);\n }, []);\n\n return scheme;\n}\n\n// ============================================\n// STATUS BAR\n// ============================================\n\n/**\n * useStatusBar - Control the status bar appearance\n * \n * @param color - Hex color for the status bar\n */\nexport function useStatusBar(color: string): void {\n useEffect(() => {\n // Update meta theme-color\n let meta = document.querySelector('meta[name=\"theme-color\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', color);\n\n // Notify parent Shell\n window.parent?.postMessage({ type: 'relay:statusbar', color }, '*');\n }, [color]);\n}\n\n// ============================================\n// BACK HANDLER\n// ============================================\n\n/**\n * useBackHandler - Handle back navigation\n * \n * @param handler - Return true to prevent default back behavior\n */\nexport function useBackHandler(handler: () => boolean): void {\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:back') {\n const handled = handler();\n if (!handled) {\n // Allow default close behavior\n window.parent?.postMessage('relay:close', '*');\n }\n }\n };\n\n // Also handle browser back button\n const handlePopState = (event: PopStateEvent) => {\n const handled = handler();\n if (handled) {\n // Push a dummy state to prevent navigation\n window.history.pushState(null, '', window.location.href);\n }\n };\n\n // Push initial state for popstate handling\n window.history.pushState(null, '', window.location.href);\n\n window.addEventListener('message', handleMessage);\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('popstate', handlePopState);\n };\n }, [handler]);\n}\n\n// ============================================\n// APP STATE\n// ============================================\n\nexport type AppState = 'active' | 'background' | 'inactive';\n\n/**\n * useAppState - Track app foreground/background state\n * \n * @returns Current app state\n */\nexport function useAppState(): AppState {\n const [state, setState] = useState<AppState>('active');\n\n useEffect(() => {\n const handleVisibility = () => {\n setState(document.hidden ? 'background' : 'active');\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:foreground') setState('active');\n if (event.data === 'relay:background') setState('background');\n };\n\n document.addEventListener('visibilitychange', handleVisibility);\n window.addEventListener('message', handleMessage);\n\n return () => {\n document.removeEventListener('visibilitychange', handleVisibility);\n window.removeEventListener('message', handleMessage);\n };\n }, []);\n\n return state;\n}\n","import React, { ReactNode, CSSProperties } from 'react';\nimport { useKeyboard } from '../hooks/use-keyboard';\nimport { useSafeArea } from '../hooks/use-platform';\n\n// ============================================\n// KEYBOARD AVOIDING VIEW\n// ============================================\n\ntype KeyboardBehavior = 'padding' | 'height' | 'position';\n\ninterface KeyboardAvoidingViewProps {\n children: ReactNode;\n behavior?: KeyboardBehavior;\n keyboardVerticalOffset?: number;\n style?: CSSProperties;\n className?: string;\n}\n\n/**\n * KeyboardAvoidingView - Automatically adjusts content when keyboard opens\n * \n * @param behavior - How to adjust: 'padding' | 'height' | 'position'\n * @param keyboardVerticalOffset - Additional offset to add\n */\nexport function KeyboardAvoidingView({\n children,\n behavior = 'padding',\n keyboardVerticalOffset = 0,\n style,\n className\n}: KeyboardAvoidingViewProps) {\n const keyboard = useKeyboard();\n const offset = keyboard.height + keyboardVerticalOffset;\n\n const computedStyle: CSSProperties = {\n ...style,\n transition: 'all 0.2s ease-out',\n };\n\n if (keyboard.isOpen) {\n switch (behavior) {\n case 'padding':\n computedStyle.paddingBottom = offset;\n break;\n case 'height':\n computedStyle.height = `calc(100% - ${offset}px)`;\n break;\n case 'position':\n computedStyle.transform = `translateY(-${offset}px)`;\n break;\n }\n }\n\n return (\n <div style={computedStyle} className={className}>\n {children}\n </div>\n );\n}\n\n// ============================================\n// SAFE AREA VIEW\n// ============================================\n\ntype SafeAreaEdge = 'top' | 'bottom' | 'left' | 'right';\n\ninterface SafeAreaViewProps {\n children: ReactNode;\n edges?: SafeAreaEdge[];\n style?: CSSProperties;\n className?: string;\n}\n\n/**\n * SafeAreaView - Container that respects safe area insets\n * \n * @param edges - Which edges to apply safe area to (default: all)\n */\nexport function SafeAreaView({\n children,\n edges = ['top', 'bottom', 'left', 'right'],\n style,\n className\n}: SafeAreaViewProps) {\n const insets = useSafeArea();\n\n const computedStyle: CSSProperties = {\n ...style,\n paddingTop: edges.includes('top') ? insets.top : style?.paddingTop,\n paddingBottom: edges.includes('bottom') ? insets.bottom : style?.paddingBottom,\n paddingLeft: edges.includes('left') ? insets.left : style?.paddingLeft,\n paddingRight: edges.includes('right') ? insets.right : style?.paddingRight,\n };\n\n return (\n <div style={computedStyle} className={className}>\n {children}\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\n\nexport type TimerMode = 'focus' | 'shortBreak' | 'longBreak';\nexport type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';\n\nexport function useFocusTimer() {\n const [seconds, setSeconds] = useState(25 * 60);\n const [initialTime, setInitialTime] = useState(25 * 60);\n const [isActive, setIsActive] = useState(false);\n const [mode, setMode] = useState<TimerMode>('focus');\n const [task, setTask] = useState('');\n const [storyState, setStoryState] = useState<StoryState>('egg');\n const [soundEnabled, setSoundEnabled] = useState(false);\n\n useEffect(() => {\n let interval: any = null;\n\n if (isActive && seconds > 0) {\n interval = setInterval(() => {\n setSeconds((s) => s - 1);\n }, 1000);\n } else if (seconds === 0 && isActive) {\n // Timer Finished\n setIsActive(false);\n if (mode === 'focus') {\n const isAbducted = Math.random() < 0.01;\n setStoryState(isAbducted ? 'alien' : 'chick');\n }\n }\n\n return () => {\n if (interval) clearInterval(interval);\n };\n }, [isActive, seconds, mode]);\n\n // Update Visuals based on progress\n useEffect(() => {\n if (!isActive && (storyState === 'chick' || storyState === 'alien' || storyState === 'ghost')) return;\n\n // Don't change chick state during break\n if (mode !== 'focus') return;\n\n const progress = 1 - (seconds / initialTime);\n\n if (progress < 0.5) {\n setStoryState('egg');\n } else if (progress >= 0.5 && progress < 1) {\n setStoryState('cracked');\n }\n }, [seconds, initialTime, isActive, storyState, mode]);\n\n const toggleTimer = () => setIsActive(!isActive);\n\n const giveUp = () => {\n setIsActive(false);\n setStoryState('ghost');\n };\n\n const switchMode = (newMode: TimerMode) => {\n setIsActive(false);\n setMode(newMode);\n setStoryState('egg'); // Reset chick for new session\n\n // Set Times\n let newTime = 25 * 60;\n if (newMode === 'shortBreak') newTime = 5 * 60;\n if (newMode === 'longBreak') newTime = 15 * 60;\n\n setSeconds(newTime);\n setInitialTime(newTime);\n };\n\n const resetTimer = () => {\n setIsActive(false);\n switchMode(mode); // Re-init current mode\n };\n\n const setCustomTime = (mins: number) => {\n setIsActive(false);\n setSeconds(mins * 60);\n setInitialTime(mins * 60);\n setStoryState('egg');\n };\n\n return {\n seconds,\n initialTime,\n isActive,\n mode,\n task,\n storyState,\n soundEnabled,\n setSeconds,\n setInitialTime,\n setIsActive,\n setMode,\n setTask,\n setStoryState,\n setSoundEnabled,\n toggleTimer,\n giveUp,\n switchMode,\n resetTimer,\n setCustomTime,\n };\n}\n"],"mappings":"yoFAAA,OAAS,YAAAA,EAAU,aAAAC,EAAW,eAAAC,MAAmB,QAe1C,SAASC,GAA6B,CACzC,GAAM,CAACC,EAAOC,CAAQ,EAAIL,EAAwB,CAC9C,OAAQ,GACR,OAAQ,CACZ,CAAC,EAED,OAAAC,EAAU,IAAM,CAGZ,GAAI,CADa,2BAA2B,KAAK,UAAU,SAAS,EACrD,OAEf,IAAMK,EAAsB,IAAM,CAC9B,GAAI,CAAC,OAAO,eAAgB,OAE5B,IAAMC,EAAW,OAAO,eAElBC,EAAiB,OAAO,YAAcD,EAAS,OAE/CE,EAASD,EAAiB,IAEhCH,EAAS,CACL,OAAAI,EACA,OAAQA,EAASD,EAAiB,CACtC,CAAC,CACL,EAGI,OAAO,iBACP,OAAO,eAAe,iBAAiB,SAAUF,CAAmB,EACpE,OAAO,eAAe,iBAAiB,SAAUA,CAAmB,GAIxE,IAAMI,EAAiBC,GAAkB,CACrC,IAAMC,EAASD,EAAE,QACbC,EAAO,UAAY,SAAWA,EAAO,UAAY,aAEjD,WAAWN,EAAqB,GAAG,CAE3C,EAEMO,EAAiB,IAAM,CAEzB,WAAW,IAAM,CACbR,EAAS,CAAE,OAAQ,GAAO,OAAQ,CAAE,CAAC,CACzC,EAAG,GAAG,CACV,EAEA,gBAAS,iBAAiB,UAAWK,CAAa,EAClD,SAAS,iBAAiB,WAAYG,CAAc,EAGpDP,EAAoB,EAEb,IAAM,CACT,OAAO,gBAAgB,oBAAoB,SAAUA,CAAmB,EACxE,OAAO,gBAAgB,oBAAoB,SAAUA,CAAmB,EACxE,SAAS,oBAAoB,UAAWI,CAAa,EACrD,SAAS,oBAAoB,WAAYG,CAAc,CAC3D,CACJ,EAAG,CAAC,CAAC,EAEET,CACX,CASO,SAASU,IAA4B,CAexC,OAdcZ,EAAY,IAAM,CAGxB,OAAO,SAAW,QAClB,OAAO,OAAO,YAAY,cAAe,GAAG,EAG5C,OAAO,QACP,OAAO,OAAO,YAAY,cAAe,GAAG,EAGhD,OAAO,MAAM,CACjB,EAAG,CAAC,CAAC,CAGT,CCvGA,OAAS,YAAAa,EAAU,aAAAC,EAAwB,iBAAAC,EAAe,cAAAC,MAA6B,QAkG/E,cAAAC,MAAA,oBArFR,IAAMC,EAAgC,CAClC,IAAK,EACL,OAAQ,EACR,KAAM,EACN,MAAO,CACX,EAEMC,EAAkBJ,EAA8BG,CAAa,EAiB5D,SAASE,GAAiB,CAAE,SAAAC,CAAS,EAA0B,CAClE,GAAM,CAACC,EAAQC,CAAS,EAAIV,EAAyBK,CAAa,EAElE,OAAAJ,EAAU,IAAM,CAEZ,IAAMU,EAAgB,IAAM,CACxB,IAAMC,EAAQ,iBAAiB,SAAS,eAAe,EACjDC,EAAUC,GAAiB,CAC7B,IAAMC,EAAQH,EAAM,iBAAiB,qBAAqBE,CAAI,EAAE,EAChE,OAAO,SAASC,CAAK,GAAK,CAC9B,EAGIC,EAAMH,EAAO,KAAK,EAClBI,EAASJ,EAAO,QAAQ,EACxBK,EAAOL,EAAO,MAAM,EACpBM,EAAQN,EAAO,OAAO,EAG1B,GAAIG,IAAQ,GAAKC,IAAW,EAAG,CAE3B,IAAMG,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UASrB,SAAS,KAAK,YAAYA,CAAI,EAC9B,IAAMC,EAAOD,EAAK,sBAAsB,EACxCJ,EAAMK,EAAK,IACXJ,EAAS,OAAO,YAAcI,EAAK,OACnCH,EAAOG,EAAK,KACZF,EAAQ,OAAO,WAAaE,EAAK,MACjC,SAAS,KAAK,YAAYD,CAAI,CAClC,CAEAV,EAAU,CAAE,IAAAM,EAAK,OAAAC,EAAQ,KAAAC,EAAM,MAAAC,CAAM,CAAC,CAC1C,EAGMG,EAAiBC,GAAwB,CACvCA,EAAM,MAAM,OAAS,kBACrBb,EAAUa,EAAM,KAAK,MAAM,CAEnC,EAEA,OAAAZ,EAAc,EACd,OAAO,iBAAiB,UAAWW,CAAa,EAChD,OAAO,iBAAiB,SAAUX,CAAa,EAExC,IAAM,CACT,OAAO,oBAAoB,UAAWW,CAAa,EACnD,OAAO,oBAAoB,SAAUX,CAAa,CACtD,CACJ,EAAG,CAAC,CAAC,EAGDP,EAACE,EAAgB,SAAhB,CAAyB,MAAOG,EAC5B,SAAAD,EACL,CAER,CAWO,SAASgB,GAA8B,CAC1C,OAAOrB,EAAWG,CAAe,CACrC,CAaO,SAASmB,IAA8B,CAC1C,GAAM,CAACC,EAAQC,CAAS,EAAI3B,EAAsB,IAC9C,OAAO,WAAW,8BAA8B,EAAE,QAAU,OAAS,OACzE,EAEA,OAAAC,EAAU,IAAM,CACZ,IAAM2B,EAAQ,OAAO,WAAW,8BAA8B,EACxDC,EAAWC,GAA2B,CACxCH,EAAUG,EAAE,QAAU,OAAS,OAAO,CAC1C,EACA,OAAAF,EAAM,iBAAiB,SAAUC,CAAO,EACjC,IAAMD,EAAM,oBAAoB,SAAUC,CAAO,CAC5D,EAAG,CAAC,CAAC,EAEEH,CACX,CAWO,SAASK,GAAaC,EAAqB,CAC9C/B,EAAU,IAAM,CAEZ,IAAIgC,EAAO,SAAS,cAAc,0BAA0B,EACvDA,IACDA,EAAO,SAAS,cAAc,MAAM,EACpCA,EAAK,aAAa,OAAQ,aAAa,EACvC,SAAS,KAAK,YAAYA,CAAI,GAElCA,EAAK,aAAa,UAAWD,CAAK,EAGlC,OAAO,QAAQ,YAAY,CAAE,KAAM,kBAAmB,MAAAA,CAAM,EAAG,GAAG,CACtE,EAAG,CAACA,CAAK,CAAC,CACd,CAWO,SAASE,GAAeL,EAA8B,CACzD5B,EAAU,IAAM,CACZ,IAAMqB,EAAiBC,GAAwB,CACvCA,EAAM,OAAS,eACCM,EAAQ,GAGpB,OAAO,QAAQ,YAAY,cAAe,GAAG,EAGzD,EAGMM,EAAkBZ,GAAyB,CAC7BM,EAAQ,GAGpB,OAAO,QAAQ,UAAU,KAAM,GAAI,OAAO,SAAS,IAAI,CAE/D,EAGA,cAAO,QAAQ,UAAU,KAAM,GAAI,OAAO,SAAS,IAAI,EAEvD,OAAO,iBAAiB,UAAWP,CAAa,EAChD,OAAO,iBAAiB,WAAYa,CAAc,EAE3C,IAAM,CACT,OAAO,oBAAoB,UAAWb,CAAa,EACnD,OAAO,oBAAoB,WAAYa,CAAc,CACzD,CACJ,EAAG,CAACN,CAAO,CAAC,CAChB,CAaO,SAASO,IAAwB,CACpC,GAAM,CAACC,EAAOC,CAAQ,EAAItC,EAAmB,QAAQ,EAErD,OAAAC,EAAU,IAAM,CACZ,IAAMsC,EAAmB,IAAM,CAC3BD,EAAS,SAAS,OAAS,aAAe,QAAQ,CACtD,EAEMhB,EAAiBC,GAAwB,CACvCA,EAAM,OAAS,oBAAoBe,EAAS,QAAQ,EACpDf,EAAM,OAAS,oBAAoBe,EAAS,YAAY,CAChE,EAEA,gBAAS,iBAAiB,mBAAoBC,CAAgB,EAC9D,OAAO,iBAAiB,UAAWjB,CAAa,EAEzC,IAAM,CACT,SAAS,oBAAoB,mBAAoBiB,CAAgB,EACjE,OAAO,oBAAoB,UAAWjB,CAAa,CACvD,CACJ,EAAG,CAAC,CAAC,EAEEe,CACX,CCjMQ,cAAAG,MAAA,oBA9BD,SAASC,GAAqB,CACjC,SAAAC,EACA,SAAAC,EAAW,UACX,uBAAAC,EAAyB,EACzB,MAAAC,EACA,UAAAC,CACJ,EAA8B,CAC1B,IAAMC,EAAWC,EAAY,EACvBC,EAASF,EAAS,OAASH,EAE3BM,EAA+B,CACjC,GAAGL,EACH,WAAY,mBAChB,EAEA,GAAIE,EAAS,OACT,OAAQJ,EAAU,CACd,IAAK,UACDO,EAAc,cAAgBD,EAC9B,MACJ,IAAK,SACDC,EAAc,OAAS,eAAeD,CAAM,MAC5C,MACJ,IAAK,WACDC,EAAc,UAAY,eAAeD,CAAM,MAC/C,KACR,CAGJ,OACIT,EAAC,OAAI,MAAOU,EAAe,UAAWJ,EACjC,SAAAJ,EACL,CAER,CAoBO,SAASS,GAAa,CACzB,SAAAT,EACA,MAAAU,EAAQ,CAAC,MAAO,SAAU,OAAQ,OAAO,EACzC,MAAAP,EACA,UAAAC,CACJ,EAAsB,CAClB,IAAMO,EAASC,EAAY,EAErBJ,EAA+B,CACjC,GAAGL,EACH,WAAYO,EAAM,SAAS,KAAK,EAAIC,EAAO,IAAMR,GAAO,WACxD,cAAeO,EAAM,SAAS,QAAQ,EAAIC,EAAO,OAASR,GAAO,cACjE,YAAaO,EAAM,SAAS,MAAM,EAAIC,EAAO,KAAOR,GAAO,YAC3D,aAAcO,EAAM,SAAS,OAAO,EAAIC,EAAO,MAAQR,GAAO,YAClE,EAEA,OACIL,EAAC,OAAI,MAAOU,EAAe,UAAWJ,EACjC,SAAAJ,EACL,CAER,CCnGA,OAAS,YAAAa,EAAU,aAAAC,MAAiB,QAK7B,SAASC,IAAgB,CAC5B,GAAM,CAACC,EAASC,CAAU,EAAIJ,EAAS,IAAO,EACxC,CAACK,EAAaC,CAAc,EAAIN,EAAS,IAAO,EAChD,CAACO,EAAUC,CAAW,EAAIR,EAAS,EAAK,EACxC,CAACS,EAAMC,CAAO,EAAIV,EAAoB,OAAO,EAC7C,CAACW,EAAMC,CAAO,EAAIZ,EAAS,EAAE,EAC7B,CAACa,EAAYC,CAAa,EAAId,EAAqB,KAAK,EACxD,CAACe,EAAcC,CAAe,EAAIhB,EAAS,EAAK,EAEtDC,EAAU,IAAM,CACZ,IAAIgB,EAAgB,KAEpB,GAAIV,GAAYJ,EAAU,EACtBc,EAAW,YAAY,IAAM,CACzBb,EAAYc,GAAMA,EAAI,CAAC,CAC3B,EAAG,GAAI,UACAf,IAAY,GAAKI,IAExBC,EAAY,EAAK,EACbC,IAAS,SAAS,CAClB,IAAMU,EAAa,KAAK,OAAO,EAAI,IACnCL,EAAcK,EAAa,QAAU,OAAO,CAChD,CAGJ,MAAO,IAAM,CACLF,GAAU,cAAcA,CAAQ,CACxC,CACJ,EAAG,CAACV,EAAUJ,EAASM,CAAI,CAAC,EAG5BR,EAAU,IAAM,CAIZ,GAHI,CAACM,IAAaM,IAAe,SAAWA,IAAe,SAAWA,IAAe,UAGjFJ,IAAS,QAAS,OAEtB,IAAMW,EAAW,EAAKjB,EAAUE,EAE5Be,EAAW,GACXN,EAAc,KAAK,EACZM,GAAY,IAAOA,EAAW,GACrCN,EAAc,SAAS,CAE/B,EAAG,CAACX,EAASE,EAAaE,EAAUM,EAAYJ,CAAI,CAAC,EAErD,IAAMY,EAAc,IAAMb,EAAY,CAACD,CAAQ,EAEzCe,EAAS,IAAM,CACjBd,EAAY,EAAK,EACjBM,EAAc,OAAO,CACzB,EAEMS,EAAcC,GAAuB,CACvChB,EAAY,EAAK,EACjBE,EAAQc,CAAO,EACfV,EAAc,KAAK,EAGnB,IAAIW,EAAU,KACVD,IAAY,eAAcC,EAAU,KACpCD,IAAY,cAAaC,EAAU,KAEvCrB,EAAWqB,CAAO,EAClBnB,EAAemB,CAAO,CAC1B,EAcA,MAAO,CACH,QAAAtB,EACA,YAAAE,EACA,SAAAE,EACA,KAAAE,EACA,KAAAE,EACA,WAAAE,EACA,aAAAE,EACA,WAAAX,EACA,eAAAE,EACA,YAAAE,EACA,QAAAE,EACA,QAAAE,EACA,cAAAE,EACA,gBAAAE,EACA,YAAAK,EACA,OAAAC,EACA,WAAAC,EACA,WA9Be,IAAM,CACrBf,EAAY,EAAK,EACjBe,EAAWd,CAAI,CACnB,EA4BI,cA1BmBiB,GAAiB,CACpClB,EAAY,EAAK,EACjBJ,EAAWsB,EAAO,EAAE,EACpBpB,EAAeoB,EAAO,EAAE,EACxBZ,EAAc,KAAK,CACvB,CAsBA,CACJ","names":["useState","useEffect","useCallback","useKeyboard","state","setState","updateKeyboardState","viewport","keyboardHeight","isOpen","handleFocusIn","e","target","handleFocusOut","useRelayClose","useState","useEffect","createContext","useContext","jsx","defaultInsets","SafeAreaContext","SafeAreaProvider","children","insets","setInsets","computeInsets","style","getEnv","name","value","top","bottom","left","right","temp","rect","handleMessage","event","useSafeArea","useColorScheme","scheme","setScheme","media","handler","e","useStatusBar","color","meta","useBackHandler","handlePopState","useAppState","state","setState","handleVisibility","jsx","KeyboardAvoidingView","children","behavior","keyboardVerticalOffset","style","className","keyboard","useKeyboard","offset","computedStyle","SafeAreaView","edges","insets","useSafeArea","useState","useEffect","useFocusTimer","seconds","setSeconds","initialTime","setInitialTime","isActive","setIsActive","mode","setMode","task","setTask","storyState","setStoryState","soundEnabled","setSoundEnabled","interval","s","isAbducted","progress","toggleTimer","giveUp","switchMode","newMode","newTime","mins"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-keyboard.ts","../src/hooks/use-platform.tsx","../src/components/platform.tsx","../src/hooks/use-focus-timer.ts","../src/hooks/use-notifications.ts","../src/hooks/use-clipboard.ts","../src/hooks/use-geolocation.ts","../src/hooks/use-camera.ts"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\n\ninterface KeyboardState {\n isOpen: boolean;\n height: number;\n}\n\n/**\n * useKeyboard - Track virtual keyboard state on mobile devices\n * \n * Uses visualViewport API to detect keyboard height and provides\n * a safe area offset for positioning UI elements above the keyboard.\n * \n * @returns {KeyboardState} - { isOpen: boolean, height: number }\n */\nexport function useKeyboard(): KeyboardState {\n const [state, setState] = useState<KeyboardState>({\n isOpen: false,\n height: 0\n });\n\n useEffect(() => {\n // Check if we're on a mobile device\n const isMobile = /iPad|iPhone|iPod|Android/.test(navigator.userAgent);\n if (!isMobile) return;\n\n const updateKeyboardState = () => {\n if (!window.visualViewport) return;\n\n const viewport = window.visualViewport;\n // Calculate keyboard height: difference between window and viewport height\n const keyboardHeight = window.innerHeight - viewport.height;\n // Consider keyboard open if height is more than 100px (threshold for accessory bars)\n const isOpen = keyboardHeight > 100;\n\n setState({\n isOpen,\n height: isOpen ? keyboardHeight : 0\n });\n };\n\n // Listen to visualViewport changes\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', updateKeyboardState);\n window.visualViewport.addEventListener('scroll', updateKeyboardState);\n }\n\n // Also listen for focus/blur on inputs as fallback\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n // Small delay to let keyboard animate\n setTimeout(updateKeyboardState, 100);\n }\n };\n\n const handleFocusOut = () => {\n // Small delay to let keyboard animate closed\n setTimeout(() => {\n setState({ isOpen: false, height: 0 });\n }, 100);\n };\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n\n // Initial check\n updateKeyboardState();\n\n return () => {\n window.visualViewport?.removeEventListener('resize', updateKeyboardState);\n window.visualViewport?.removeEventListener('scroll', updateKeyboardState);\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }, []);\n\n return state;\n}\n\n/**\n * useRelayClose - Get the close function for closing the current app\n * \n * Works with both iframe and blob URL contexts.\n * \n * @returns {() => void} - Function to close the current app\n */\nexport function useRelayClose(): () => void {\n const close = useCallback(() => {\n // Try multiple methods to close\n // 1. PostMessage to parent (works in iframe)\n if (window.parent !== window) {\n window.parent.postMessage('relay:close', '*');\n }\n // 2. PostMessage with opener (works if opened as popup)\n if (window.opener) {\n window.opener.postMessage('relay:close', '*');\n }\n // 3. Try self-closing (may not work in all contexts)\n window.close();\n }, []);\n\n return close;\n}\n","import { useState, useEffect, useCallback, createContext, useContext, ReactNode } from 'react';\n\n// ============================================\n// SAFE AREA TYPES & CONTEXT\n// ============================================\n\nexport interface SafeAreaInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nconst defaultInsets: SafeAreaInsets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0\n};\n\nconst SafeAreaContext = createContext<SafeAreaInsets>(defaultInsets);\n\n// ============================================\n// SAFE AREA PROVIDER\n// ============================================\n\ninterface SafeAreaProviderProps {\n children: ReactNode;\n}\n\n/**\n * SafeAreaProvider - Provides safe area insets to child components\n * \n * Automatically detects safe areas from:\n * 1. CSS env() values (iOS Safari)\n * 2. Parent Shell postMessage (when running in Relay Shell)\n */\nexport function SafeAreaProvider({ children }: SafeAreaProviderProps) {\n const [insets, setInsets] = useState<SafeAreaInsets>(defaultInsets);\n\n useEffect(() => {\n // Method 1: Read from CSS env() values\n const computeInsets = () => {\n const style = getComputedStyle(document.documentElement);\n const getEnv = (name: string) => {\n const value = style.getPropertyValue(`--safe-area-inset-${name}`);\n return parseInt(value) || 0;\n };\n\n // Try to get from CSS custom properties first\n let top = getEnv('top');\n let bottom = getEnv('bottom');\n let left = getEnv('left');\n let right = getEnv('right');\n\n // If CSS props not set, try to read from env() directly\n if (top === 0 && bottom === 0) {\n // Create a temp element to measure env() values\n const temp = document.createElement('div');\n temp.style.cssText = `\n position: fixed;\n top: env(safe-area-inset-top, 0px);\n bottom: env(safe-area-inset-bottom, 0px);\n left: env(safe-area-inset-left, 0px);\n right: env(safe-area-inset-right, 0px);\n pointer-events: none;\n visibility: hidden;\n `;\n document.body.appendChild(temp);\n const rect = temp.getBoundingClientRect();\n top = rect.top;\n bottom = window.innerHeight - rect.bottom;\n left = rect.left;\n right = window.innerWidth - rect.right;\n document.body.removeChild(temp);\n }\n\n setInsets({ top, bottom, left, right });\n };\n\n // Method 2: Listen for Shell messages\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'relay:safearea') {\n setInsets(event.data.insets);\n }\n };\n\n computeInsets();\n window.addEventListener('message', handleMessage);\n window.addEventListener('resize', computeInsets);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('resize', computeInsets);\n };\n }, []);\n\n return (\n <SafeAreaContext.Provider value={insets}>\n {children}\n </SafeAreaContext.Provider>\n );\n}\n\n// ============================================\n// SAFE AREA HOOKS\n// ============================================\n\n/**\n * useSafeArea - Get safe area insets\n * \n * @returns SafeAreaInsets with top, bottom, left, right values in pixels\n */\nexport function useSafeArea(): SafeAreaInsets {\n return useContext(SafeAreaContext);\n}\n\n// ============================================\n// COLOR SCHEME\n// ============================================\n\nexport type ColorScheme = 'light' | 'dark';\n\n/**\n * useColorScheme - Get current system color scheme\n * \n * @returns 'light' | 'dark'\n */\nexport function useColorScheme(): ColorScheme {\n const [scheme, setScheme] = useState<ColorScheme>(() =>\n window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n );\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => {\n setScheme(e.matches ? 'dark' : 'light');\n };\n media.addEventListener('change', handler);\n return () => media.removeEventListener('change', handler);\n }, []);\n\n return scheme;\n}\n\n// ============================================\n// STATUS BAR\n// ============================================\n\n/**\n * useStatusBar - Control the status bar appearance\n * \n * @param color - Hex color for the status bar\n */\nexport function useStatusBar(color: string): void {\n useEffect(() => {\n // Update meta theme-color\n let meta = document.querySelector('meta[name=\"theme-color\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', color);\n\n // Notify parent Shell\n window.parent?.postMessage({ type: 'relay:statusbar', color }, '*');\n }, [color]);\n}\n\n// ============================================\n// BACK HANDLER\n// ============================================\n\n/**\n * useBackHandler - Handle back navigation\n * \n * @param handler - Return true to prevent default back behavior\n */\nexport function useBackHandler(handler: () => boolean): void {\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:back') {\n const handled = handler();\n if (!handled) {\n // Allow default close behavior\n window.parent?.postMessage('relay:close', '*');\n }\n }\n };\n\n // Also handle browser back button\n const handlePopState = (event: PopStateEvent) => {\n const handled = handler();\n if (handled) {\n // Push a dummy state to prevent navigation\n window.history.pushState(null, '', window.location.href);\n }\n };\n\n // Push initial state for popstate handling\n window.history.pushState(null, '', window.location.href);\n\n window.addEventListener('message', handleMessage);\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n window.removeEventListener('popstate', handlePopState);\n };\n }, [handler]);\n}\n\n// ============================================\n// APP STATE\n// ============================================\n\nexport type AppState = 'active' | 'background' | 'inactive';\n\n/**\n * useAppState - Track app foreground/background state\n * \n * @returns Current app state\n */\nexport function useAppState(): AppState {\n const [state, setState] = useState<AppState>('active');\n\n useEffect(() => {\n const handleVisibility = () => {\n setState(document.hidden ? 'background' : 'active');\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data === 'relay:foreground') setState('active');\n if (event.data === 'relay:background') setState('background');\n };\n\n document.addEventListener('visibilitychange', handleVisibility);\n window.addEventListener('message', handleMessage);\n\n return () => {\n document.removeEventListener('visibilitychange', handleVisibility);\n window.removeEventListener('message', handleMessage);\n };\n }, []);\n\n return state;\n}\n","import React, { ReactNode, CSSProperties } from 'react';\nimport { useKeyboard } from '../hooks/use-keyboard';\nimport { useSafeArea } from '../hooks/use-platform';\nimport { cn } from '../lib/utils';\n\n// ============================================\n// KEYBOARD AVOIDING VIEW\n// ============================================\n\ntype KeyboardBehavior = 'padding' | 'height' | 'position';\n\ninterface KeyboardAvoidingViewProps {\n children: ReactNode;\n behavior?: KeyboardBehavior;\n keyboardVerticalOffset?: number;\n style?: CSSProperties;\n className?: string;\n}\n\n/**\n * KeyboardAvoidingView - Automatically adjusts content when keyboard opens\n * \n * @param behavior - How to adjust: 'padding' | 'height' | 'position'\n * @param keyboardVerticalOffset - Additional offset to add\n */\nexport function KeyboardAvoidingView({\n children,\n behavior = 'padding',\n keyboardVerticalOffset = 0,\n style,\n className\n}: KeyboardAvoidingViewProps) {\n const keyboard = useKeyboard();\n const offset = keyboard.height + keyboardVerticalOffset;\n\n const computedStyle: CSSProperties = {\n ...style,\n transition: 'all 0.2s ease-out',\n };\n\n if (keyboard.isOpen) {\n switch (behavior) {\n case 'padding':\n computedStyle.paddingBottom = offset;\n break;\n case 'height':\n computedStyle.height = `calc(100% - ${offset}px)`;\n break;\n case 'position':\n computedStyle.transform = `translateY(-${offset}px)`;\n break;\n }\n }\n\n return (\n <div style={computedStyle} className={className}>\n {children}\n </div>\n );\n}\n\n// ============================================\n// SAFE AREA VIEW\n// ============================================\n\ntype SafeAreaEdge = 'top' | 'bottom' | 'left' | 'right';\n\ninterface SafeAreaViewProps {\n children: ReactNode;\n edges?: SafeAreaEdge[];\n style?: CSSProperties;\n className?: string;\n}\n\n/**\n * SafeAreaView - Container that respects safe area insets\n * \n * @param edges - Which edges to apply safe area to (default: all)\n */\nexport function SafeAreaView({\n children,\n edges = ['top', 'bottom', 'left', 'right'],\n style,\n className\n}: SafeAreaViewProps) {\n const insets = useSafeArea();\n\n const computedStyle: CSSProperties = {\n ...style,\n paddingTop: edges.includes('top') ? insets.top : style?.paddingTop,\n paddingBottom: edges.includes('bottom') ? insets.bottom : style?.paddingBottom,\n paddingLeft: edges.includes('left') ? insets.left : style?.paddingLeft,\n paddingRight: edges.includes('right') ? insets.right : style?.paddingRight,\n };\n\n return (\n <div style={computedStyle} className={className}>\n {children}\n </div>\n );\n}\n\n// ============================================\n// PLATFORM HEADER\n// ============================================\n\ninterface PlatformHeaderProps {\n title: string;\n showBack?: boolean;\n onBack?: () => void;\n className?: string;\n rightElement?: ReactNode;\n}\n\nexport function PlatformHeader({\n title,\n showBack = true,\n onBack,\n className,\n rightElement\n}: PlatformHeaderProps) {\n const insets = useSafeArea();\n\n return (\n <div \n className={cn(\"bg-background border-b flex flex-col z-50\", className)}\n style={{ paddingTop: insets.top }}\n >\n <div className=\"h-14 flex items-center justify-between px-4\">\n <div className=\"flex items-center gap-4 flex-1\">\n {showBack && (\n <button \n onClick={onBack || (() => window.history.back())}\n className=\"p-2 -ml-2 hover:bg-muted rounded-full transition-colors\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n </button>\n )}\n <h1 className=\"text-lg font-semibold truncate\">{title}</h1>\n </div>\n {rightElement && (\n <div className=\"flex-none\">\n {rightElement}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\n\nexport type TimerMode = 'focus' | 'shortBreak' | 'longBreak';\nexport type StoryState = 'egg' | 'cracked' | 'chick' | 'alien' | 'ghost';\n\nexport function useFocusTimer() {\n const [seconds, setSeconds] = useState(25 * 60);\n const [initialTime, setInitialTime] = useState(25 * 60);\n const [isActive, setIsActive] = useState(false);\n const [mode, setMode] = useState<TimerMode>('focus');\n const [task, setTask] = useState('');\n const [storyState, setStoryState] = useState<StoryState>('egg');\n const [soundEnabled, setSoundEnabled] = useState(false);\n\n useEffect(() => {\n let interval: any = null;\n\n if (isActive && seconds > 0) {\n interval = setInterval(() => {\n setSeconds((s) => s - 1);\n }, 1000);\n } else if (seconds === 0 && isActive) {\n // Timer Finished\n setIsActive(false);\n if (mode === 'focus') {\n const isAbducted = Math.random() < 0.01;\n setStoryState(isAbducted ? 'alien' : 'chick');\n }\n }\n\n return () => {\n if (interval) clearInterval(interval);\n };\n }, [isActive, seconds, mode]);\n\n // Update Visuals based on progress\n useEffect(() => {\n if (!isActive && (storyState === 'chick' || storyState === 'alien' || storyState === 'ghost')) return;\n\n // Don't change chick state during break\n if (mode !== 'focus') return;\n\n const progress = 1 - (seconds / initialTime);\n\n if (progress < 0.5) {\n setStoryState('egg');\n } else if (progress >= 0.5 && progress < 1) {\n setStoryState('cracked');\n }\n }, [seconds, initialTime, isActive, storyState, mode]);\n\n const toggleTimer = () => setIsActive(!isActive);\n\n const giveUp = () => {\n setIsActive(false);\n setStoryState('ghost');\n };\n\n const switchMode = (newMode: TimerMode) => {\n setIsActive(false);\n setMode(newMode);\n setStoryState('egg'); // Reset chick for new session\n\n // Set Times\n let newTime = 25 * 60;\n if (newMode === 'shortBreak') newTime = 5 * 60;\n if (newMode === 'longBreak') newTime = 15 * 60;\n\n setSeconds(newTime);\n setInitialTime(newTime);\n };\n\n const resetTimer = () => {\n setIsActive(false);\n switchMode(mode); // Re-init current mode\n };\n\n const setCustomTime = (mins: number) => {\n setIsActive(false);\n setSeconds(mins * 60);\n setInitialTime(mins * 60);\n setStoryState('egg');\n };\n\n return {\n seconds,\n initialTime,\n isActive,\n mode,\n task,\n storyState,\n soundEnabled,\n setSeconds,\n setInitialTime,\n setIsActive,\n setMode,\n setTask,\n setStoryState,\n setSoundEnabled,\n toggleTimer,\n giveUp,\n switchMode,\n resetTimer,\n setCustomTime,\n };\n}\n","import { useState, useCallback, useEffect } from 'react';\n\nexport interface NotificationOptions {\n body?: string;\n icon?: string;\n image?: string;\n badge?: string;\n tag?: string;\n data?: any;\n vibrate?: number[];\n timestamp?: number;\n renotify?: boolean;\n silent?: boolean;\n requireInteraction?: boolean;\n actions?: NotificationAction[];\n}\n\nexport interface NotificationAction {\n action: string;\n title: string;\n icon?: string;\n}\n\nexport interface UseNotificationsReturn {\n permission: NotificationPermission;\n requestPermission: () => Promise<NotificationPermission>;\n sendNotification: (title: string, options?: NotificationOptions) => void;\n scheduleNotification: (title: string, delayMs: number, options?: NotificationOptions) => void;\n clearBadge: () => Promise<void>;\n setBadge: (count: number) => Promise<void>;\n}\n\nexport function useNotifications(): UseNotificationsReturn {\n const [permission, setPermission] = useState<NotificationPermission>('default');\n\n useEffect(() => {\n if ('Notification' in window) {\n setPermission(Notification.permission);\n }\n }, []);\n\n const requestPermission = useCallback(async () => {\n if (!('Notification' in window)) {\n console.warn('Notifications not supported');\n return 'denied';\n }\n const perm = await Notification.requestPermission();\n setPermission(perm);\n return perm;\n }, []);\n\n const sendNotification = useCallback((title: string, options?: NotificationOptions) => {\n if (!('Notification' in window)) return;\n \n // Auto-detect icon if not provided\n let notificationOptions = options;\n if (!options?.icon) {\n // Try to find apple-touch-icon or shortcut icon\n const iconLink = document.querySelector('link[rel=\"apple-touch-icon\"]') || \n document.querySelector('link[rel=\"icon\"]');\n if (iconLink) {\n notificationOptions = {\n ...options,\n icon: (iconLink as HTMLLinkElement).href\n };\n }\n }\n\n if (Notification.permission === 'granted') {\n new Notification(title, notificationOptions);\n } else if (Notification.permission !== 'denied') {\n Notification.requestPermission().then((perm) => {\n if (perm === 'granted') {\n new Notification(title, notificationOptions);\n }\n });\n }\n }, []);\n\n const scheduleNotification = useCallback((title: string, delayMs: number, options?: NotificationOptions) => {\n setTimeout(() => {\n sendNotification(title, options);\n }, delayMs);\n }, [sendNotification]);\n\n const setBadge = useCallback(async (count: number) => {\n if ('setAppBadge' in navigator) {\n try {\n await (navigator as any).setAppBadge(count);\n } catch (e) {\n console.error('Error setting badge:', e);\n }\n }\n }, []);\n\n const clearBadge = useCallback(async () => {\n if ('clearAppBadge' in navigator) {\n try {\n await (navigator as any).clearAppBadge();\n } catch (e) {\n console.error('Error clearing badge:', e);\n }\n }\n }, []);\n\n return {\n permission,\n requestPermission,\n sendNotification,\n scheduleNotification,\n setBadge,\n clearBadge\n };\n}\n","import { useState, useCallback, useEffect } from 'react';\n\nexport interface ClipboardItem {\n type: 'text' | 'image' | 'html';\n content: string | Blob;\n timestamp: number;\n}\n\nexport interface UseClipboardReturn {\n clipboardContent: string | null;\n history: ClipboardItem[];\n copyText: (text: string) => Promise<void>;\n copyImage: (blob: Blob) => Promise<void>;\n readText: () => Promise<string>;\n readContent: () => Promise<ClipboardItems>;\n clearHistory: () => void;\n}\n\nconst HISTORY_KEY = 'relay_clipboard_history';\nconst MAX_HISTORY = 10;\n\nexport function useClipboard(): UseClipboardReturn {\n const [clipboardContent, setClipboardContent] = useState<string | null>(null);\n const [history, setHistory] = useState<ClipboardItem[]>([]);\n\n // Load history from local storage on mount\n useEffect(() => {\n try {\n const savedHistory = localStorage.getItem(HISTORY_KEY);\n if (savedHistory) {\n // Note: We can only restore text items easily from localStorage\n const parsed = JSON.parse(savedHistory);\n setHistory(parsed);\n }\n } catch (e) {\n console.error('Failed to load clipboard history', e);\n }\n }, []);\n\n const addToHistory = useCallback((item: ClipboardItem) => {\n setHistory(prev => {\n const newHistory = [item, ...prev].slice(0, MAX_HISTORY);\n // Only save text items to localStorage to avoid quota issues\n const textOnlyHistory = newHistory.filter(i => i.type === 'text');\n try {\n localStorage.setItem(HISTORY_KEY, JSON.stringify(textOnlyHistory));\n } catch (e) {\n console.error('Failed to save clipboard history', e);\n }\n return newHistory;\n });\n }, []);\n\n const copyText = useCallback(async (text: string) => {\n if (!navigator.clipboard) {\n console.warn('Clipboard API not supported');\n return;\n }\n try {\n await navigator.clipboard.writeText(text);\n setClipboardContent(text);\n addToHistory({\n type: 'text',\n content: text,\n timestamp: Date.now()\n });\n } catch (e) {\n console.error('Failed to copy text:', e);\n throw e;\n }\n }, [addToHistory]);\n\n const copyImage = useCallback(async (blob: Blob) => {\n if (!navigator.clipboard) {\n console.warn('Clipboard API not supported');\n return;\n }\n try {\n await navigator.clipboard.write([\n new ClipboardItem({\n [blob.type]: blob\n })\n ]);\n addToHistory({\n type: 'image',\n content: blob, // Note: This won't be persisted to localStorage\n timestamp: Date.now()\n });\n } catch (e) {\n console.error('Failed to copy image:', e);\n throw e;\n }\n }, [addToHistory]);\n\n const readText = useCallback(async () => {\n if (!navigator.clipboard) {\n console.warn('Clipboard API not supported');\n return '';\n }\n try {\n const text = await navigator.clipboard.readText();\n setClipboardContent(text);\n return text;\n } catch (e) {\n console.error('Failed to read text:', e);\n throw e;\n }\n }, []);\n\n const readContent = useCallback(async () => {\n if (!navigator.clipboard) {\n console.warn('Clipboard API not supported');\n return [] as unknown as ClipboardItems;\n }\n try {\n return await navigator.clipboard.read();\n } catch (e) {\n console.error('Failed to read content:', e);\n throw e;\n }\n }, []);\n\n const clearHistory = useCallback(() => {\n setHistory([]);\n localStorage.removeItem(HISTORY_KEY);\n }, []);\n\n // Listen for clipboard changes (focus based)\n useEffect(() => {\n const handleFocus = () => {\n readText().catch(() => {});\n };\n window.addEventListener('focus', handleFocus);\n return () => window.removeEventListener('focus', handleFocus);\n }, [readText]);\n\n return {\n clipboardContent,\n history,\n copyText,\n copyImage,\n readText,\n readContent,\n clearHistory\n };\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\n\nexport interface LocationState {\n loading: boolean;\n accuracy: number | null;\n altitude: number | null;\n altitudeAccuracy: number | null;\n heading: number | null;\n latitude: number | null;\n longitude: number | null;\n speed: number | null;\n timestamp: number | null;\n error: GeolocationPositionError | null;\n}\n\nexport interface Geofence {\n id: string;\n latitude: number;\n longitude: number;\n radius: number; // meters\n}\n\nexport interface UseGeolocationReturn extends LocationState {\n getLocation: () => void;\n watchLocation: (options?: PositionOptions) => void;\n clearWatch: () => void;\n checkGeofence: (fence: Geofence) => boolean;\n distanceTo: (lat: number, lng: number) => number;\n}\n\nexport function useGeolocation(options?: PositionOptions): UseGeolocationReturn {\n const [state, setState] = useState<LocationState>({\n loading: true,\n accuracy: null,\n altitude: null,\n altitudeAccuracy: null,\n heading: null,\n latitude: null,\n longitude: null,\n speed: null,\n timestamp: null,\n error: null,\n });\n\n const watchId = useRef<number | null>(null);\n\n const onEvent = useCallback((position: GeolocationPosition) => {\n setState({\n loading: false,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n heading: position.coords.heading,\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n speed: position.coords.speed,\n timestamp: position.timestamp,\n error: null,\n });\n }, []);\n\n const onError = useCallback((error: GeolocationPositionError) => {\n setState((s) => ({\n ...s,\n loading: false,\n error,\n }));\n }, []);\n\n const getLocation = useCallback(() => {\n if (!navigator.geolocation) {\n setState((s) => ({\n ...s,\n loading: false,\n error: {\n code: 0,\n message: 'Geolocation not supported',\n PERMISSION_DENIED: 1,\n POSITION_UNAVAILABLE: 2,\n TIMEOUT: 3,\n } as GeolocationPositionError,\n }));\n return;\n }\n\n setState((s) => ({ ...s, loading: true }));\n navigator.geolocation.getCurrentPosition(onEvent, onError, options);\n }, [onEvent, onError, options]);\n\n const watchLocation = useCallback((watchOptions?: PositionOptions) => {\n if (!navigator.geolocation) return;\n \n if (watchId.current !== null) {\n navigator.geolocation.clearWatch(watchId.current);\n }\n\n watchId.current = navigator.geolocation.watchPosition(\n onEvent,\n onError,\n watchOptions || options\n );\n }, [onEvent, onError, options]);\n\n const clearWatch = useCallback(() => {\n if (watchId.current !== null) {\n navigator.geolocation.clearWatch(watchId.current);\n watchId.current = null;\n }\n }, []);\n\n // Helper to calculate distance in meters (Haversine formula)\n const distanceTo = useCallback((lat: number, lng: number) => {\n if (state.latitude === null || state.longitude === null) return Infinity;\n\n const R = 6371e3; // metres\n const φ1 = state.latitude * Math.PI / 180;\n const φ2 = lat * Math.PI / 180;\n const Δφ = (lat - state.latitude) * Math.PI / 180;\n const Δλ = (lng - state.longitude) * Math.PI / 180;\n\n const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +\n Math.cos(φ1) * Math.cos(φ2) *\n Math.sin(Δλ / 2) * Math.sin(Δλ / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n }, [state.latitude, state.longitude]);\n\n const checkGeofence = useCallback((fence: Geofence) => {\n const distance = distanceTo(fence.latitude, fence.longitude);\n return distance <= fence.radius;\n }, [distanceTo]);\n\n useEffect(() => {\n return () => {\n if (watchId.current !== null) {\n navigator.geolocation.clearWatch(watchId.current);\n }\n };\n }, []);\n\n return {\n ...state,\n getLocation,\n watchLocation,\n clearWatch,\n checkGeofence,\n distanceTo,\n };\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\n\nexport interface CameraState {\n stream: MediaStream | null;\n error: Error | null;\n permission: PermissionState | 'unknown';\n isRecording: boolean;\n devices: MediaDeviceInfo[];\n}\n\nexport interface CameraOptions {\n video?: boolean | MediaTrackConstraints;\n audio?: boolean | MediaTrackConstraints;\n}\n\nexport interface UseCameraReturn extends CameraState {\n startCamera: (options?: CameraOptions) => Promise<MediaStream | undefined>;\n stopCamera: () => void;\n takePhoto: () => Promise<string | undefined>;\n startRecording: () => void;\n stopRecording: () => Promise<Blob | undefined>;\n startScreenShare: (options?: DisplayMediaStreamOptions) => Promise<MediaStream | undefined>;\n switchDevice: (deviceId: string, kind: 'video' | 'audio') => Promise<void>;\n getDevices: () => Promise<MediaDeviceInfo[]>;\n}\n\nexport function useCamera(): UseCameraReturn {\n const [state, setState] = useState<CameraState>({\n stream: null,\n error: null,\n permission: 'unknown',\n isRecording: false,\n devices: []\n });\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n\n const getDevices = useCallback(async () => {\n if (!navigator.mediaDevices?.enumerateDevices) return [];\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n setState(s => ({ ...s, devices }));\n return devices;\n } catch (e) {\n console.error('Error enumerating devices:', e);\n return [];\n }\n }, []);\n\n // Initial device list\n useEffect(() => {\n getDevices();\n navigator.mediaDevices?.addEventListener('devicechange', getDevices);\n return () => {\n navigator.mediaDevices?.removeEventListener('devicechange', getDevices);\n };\n }, [getDevices]);\n\n const startCamera = useCallback(async (options: CameraOptions = { video: true, audio: false }) => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia(options);\n setState(s => ({ ...s, stream, error: null, permission: 'granted' }));\n return stream;\n } catch (e) {\n const error = e as Error;\n setState(s => ({ ...s, error, permission: 'denied' }));\n console.error('Error starting camera:', e);\n }\n }, []);\n\n const stopCamera = useCallback(() => {\n if (state.stream) {\n state.stream.getTracks().forEach(track => track.stop());\n setState(s => ({ ...s, stream: null, isRecording: false }));\n }\n }, [state.stream]);\n\n const startScreenShare = useCallback(async (options: DisplayMediaStreamOptions = { video: true }) => {\n try {\n const stream = await navigator.mediaDevices.getDisplayMedia(options);\n setState(s => ({ ...s, stream, error: null, permission: 'granted' }));\n return stream;\n } catch (e) {\n const error = e as Error;\n setState(s => ({ ...s, error, permission: 'denied' }));\n console.error('Error starting screen share:', e);\n }\n }, []);\n\n const takePhoto = useCallback(async () => {\n if (!state.stream) return;\n\n const videoTrack = state.stream.getVideoTracks()[0];\n if (!videoTrack) return;\n\n // Create a video element to capture the frame\n const video = document.createElement('video');\n video.srcObject = state.stream;\n await video.play();\n\n const canvas = document.createElement('canvas');\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n \n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n \n ctx.drawImage(video, 0, 0);\n const dataUrl = canvas.toDataURL('image/png');\n \n // Cleanup\n video.pause();\n video.srcObject = null;\n \n return dataUrl;\n }, [state.stream]);\n\n const startRecording = useCallback(() => {\n if (!state.stream) return;\n\n try {\n const mediaRecorder = new MediaRecorder(state.stream);\n mediaRecorderRef.current = mediaRecorder;\n chunksRef.current = [];\n\n mediaRecorder.ondataavailable = (e) => {\n if (e.data.size > 0) {\n chunksRef.current.push(e.data);\n }\n };\n\n mediaRecorder.start();\n setState(s => ({ ...s, isRecording: true }));\n } catch (e) {\n console.error('Error starting recording:', e);\n setState(s => ({ ...s, error: e as Error }));\n }\n }, [state.stream]);\n\n const stopRecording = useCallback(async () => {\n if (!mediaRecorderRef.current || mediaRecorderRef.current.state === 'inactive') return;\n\n return new Promise<Blob>((resolve) => {\n if (!mediaRecorderRef.current) return;\n \n mediaRecorderRef.current.onstop = () => {\n const blob = new Blob(chunksRef.current, { type: 'video/webm' });\n setState(s => ({ ...s, isRecording: false }));\n resolve(blob);\n };\n\n mediaRecorderRef.current.stop();\n });\n }, []);\n\n const switchDevice = useCallback(async (deviceId: string, kind: 'video' | 'audio') => {\n stopCamera();\n const constraints = {\n [kind]: { deviceId: { exact: deviceId } }\n };\n await startCamera(constraints);\n }, [startCamera, stopCamera]);\n\n useEffect(() => {\n return () => {\n stopCamera();\n };\n }, []);\n\n return {\n ...state,\n startCamera,\n stopCamera,\n takePhoto,\n startRecording,\n stopRecording,\n startScreenShare,\n switchDevice,\n getDevices\n };\n}\n"],"mappings":"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","names":["useState","useEffect","useCallback","useKeyboard","state","setState","updateKeyboardState","viewport","keyboardHeight","isOpen","handleFocusIn","e","target","handleFocusOut","useRelayClose","useState","useEffect","createContext","useContext","jsx","defaultInsets","SafeAreaContext","SafeAreaProvider","children","insets","setInsets","computeInsets","style","getEnv","name","value","top","bottom","left","right","temp","rect","handleMessage","event","useSafeArea","useColorScheme","scheme","setScheme","media","handler","e","useStatusBar","color","meta","useBackHandler","handlePopState","useAppState","state","setState","handleVisibility","jsx","jsxs","KeyboardAvoidingView","children","behavior","keyboardVerticalOffset","style","className","keyboard","useKeyboard","offset","computedStyle","SafeAreaView","edges","insets","useSafeArea","PlatformHeader","title","showBack","onBack","rightElement","cn","useState","useEffect","useFocusTimer","seconds","setSeconds","initialTime","setInitialTime","isActive","setIsActive","mode","setMode","task","setTask","storyState","setStoryState","soundEnabled","setSoundEnabled","interval","s","isAbducted","progress","toggleTimer","giveUp","switchMode","newMode","newTime","mins","useState","useCallback","useEffect","useNotifications","permission","setPermission","requestPermission","perm","sendNotification","title","options","notificationOptions","iconLink","scheduleNotification","delayMs","setBadge","count","e","clearBadge","useState","useCallback","useEffect","HISTORY_KEY","MAX_HISTORY","useClipboard","clipboardContent","setClipboardContent","history","setHistory","savedHistory","parsed","e","addToHistory","item","prev","newHistory","textOnlyHistory","i","copyText","text","copyImage","blob","readText","readContent","clearHistory","handleFocus","useState","useCallback","useEffect","useRef","useGeolocation","options","state","setState","watchId","onEvent","position","onError","error","getLocation","s","watchLocation","watchOptions","clearWatch","distanceTo","lat","lng","R","φ1","φ2","Δφ","Δλ","a","c","checkGeofence","fence","useState","useCallback","useRef","useEffect","useCamera","state","setState","mediaRecorderRef","chunksRef","getDevices","devices","s","e","startCamera","options","stream","error","stopCamera","track","startScreenShare","takePhoto","video","canvas","ctx","dataUrl","startRecording","mediaRecorder","stopRecording","resolve","blob","switchDevice","deviceId","kind","constraints"]}
|