@swiftbrowser/react 0.18.1 → 0.18.2
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 +133 -4
- package/dist/appleSignIn.d.ts +53 -0
- package/dist/appleSignIn.d.ts.map +1 -0
- package/dist/components/geometry.d.ts +6 -1
- package/dist/components/geometry.d.ts.map +1 -1
- package/dist/environment.d.ts +16 -2
- package/dist/environment.d.ts.map +1 -1
- package/dist/fileExporter.d.ts +31 -0
- package/dist/fileExporter.d.ts.map +1 -0
- package/dist/fileManager.d.ts +17 -2
- package/dist/fileManager.d.ts.map +1 -1
- package/dist/fileStorage.d.ts +25 -0
- package/dist/fileStorage.d.ts.map +1 -0
- package/dist/geolocation.d.ts +44 -0
- package/dist/geolocation.d.ts.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +737 -306
- package/dist/index.js.map +1 -1
- package/dist/modifiers.d.ts +19 -1
- package/dist/modifiers.d.ts.map +1 -1
- package/dist/mount.d.ts +2 -1
- package/dist/mount.d.ts.map +1 -1
- package/dist/speech.d.ts +52 -0
- package/dist/speech.d.ts.map +1 -0
- package/dist/wakeLock.d.ts +11 -0
- package/dist/wakeLock.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,10 +4,12 @@ import Reconciler from "react-reconciler";
|
|
|
4
4
|
import { horizontalSizeClassFor } from "@swiftbrowser/web/src/protocol";
|
|
5
5
|
import { BrowserHistory } from "@swiftbrowser/web/src/browserHistory";
|
|
6
6
|
import { watchKeyboard } from "@swiftbrowser/web/src/deviceMode";
|
|
7
|
-
import { browserEnvironment, loadableURL, performHostRequest } from "@swiftbrowser/web/src/hostRequests";
|
|
7
|
+
import { browserEnvironment, exportFiles, loadableURL, performHostRequest } from "@swiftbrowser/web/src/hostRequests";
|
|
8
8
|
import { Renderer } from "@swiftbrowser/web/src/renderer";
|
|
9
|
+
import { currentScenePhase, watchScenePhase } from "@swiftbrowser/web/src/scenePhase";
|
|
9
10
|
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
10
11
|
import { applyTypeSizeVariables } from "@swiftbrowser/web/src/typography";
|
|
12
|
+
import { configureSignInWithApple } from "@swiftbrowser/web/src/appleSignIn";
|
|
11
13
|
import { fileURL } from "@swiftbrowser/web/src/files";
|
|
12
14
|
import { registerHostContent, notifyHostContentChange, unregisterHostContent } from "@swiftbrowser/web/src/hostContent";
|
|
13
15
|
import { createRoot } from "react-dom/client";
|
|
@@ -28,7 +30,8 @@ function EnvironmentExtender({ values, children }) {
|
|
|
28
30
|
const EnvironmentContext = createContext({
|
|
29
31
|
colorScheme: "light",
|
|
30
32
|
dynamicTypeSize: "large",
|
|
31
|
-
horizontalSizeClass: "compact"
|
|
33
|
+
horizontalSizeClass: "compact",
|
|
34
|
+
scenePhase: "active"
|
|
32
35
|
});
|
|
33
36
|
function EnvironmentProvider({ value, children }) {
|
|
34
37
|
return createElement(EnvironmentContext.Provider, { value }, children);
|
|
@@ -48,6 +51,9 @@ function useDismiss() {
|
|
|
48
51
|
function useHorizontalSizeClass() {
|
|
49
52
|
return useContext(EnvironmentContext).horizontalSizeClass;
|
|
50
53
|
}
|
|
54
|
+
function useScenePhase() {
|
|
55
|
+
return useContext(EnvironmentContext).scenePhase;
|
|
56
|
+
}
|
|
51
57
|
function useRedacted() {
|
|
52
58
|
return useContext(ViewEnvironmentContext).redacted === true;
|
|
53
59
|
}
|
|
@@ -392,7 +398,7 @@ function deepEqual(a, b) {
|
|
|
392
398
|
if (keys.length !== Object.keys(right).length) return false;
|
|
393
399
|
return keys.every((key) => key in right && deepEqual(left[key], right[key]));
|
|
394
400
|
}
|
|
395
|
-
const DEFAULT_ENVIRONMENT = { colorScheme: "light", dynamicTypeSize: "large", horizontalSizeClass: "compact" };
|
|
401
|
+
const DEFAULT_ENVIRONMENT = { colorScheme: "light", dynamicTypeSize: "large", horizontalSizeClass: "compact", scenePhase: "active" };
|
|
396
402
|
const roots = /* @__PURE__ */ new Set();
|
|
397
403
|
function createSwiftUIRoot(sink) {
|
|
398
404
|
const tree = new HostTree(sink);
|
|
@@ -647,7 +653,8 @@ function mount(screen, element, options = {}) {
|
|
|
647
653
|
const environment = {
|
|
648
654
|
colorScheme: pageScheme,
|
|
649
655
|
dynamicTypeSize: options.dynamicTypeSize ?? "large",
|
|
650
|
-
horizontalSizeClass: horizontalSizeClassFor(screen.clientWidth || 393)
|
|
656
|
+
horizontalSizeClass: horizontalSizeClassFor(screen.clientWidth || 393),
|
|
657
|
+
scenePhase: typeof document !== "undefined" ? currentScenePhase() : "active"
|
|
651
658
|
};
|
|
652
659
|
renderer.contentHeight = options.contentHeight ?? false;
|
|
653
660
|
if (options.assets) renderer.setAssetCatalog(options.assets);
|
|
@@ -679,6 +686,7 @@ function mount(screen, element, options = {}) {
|
|
|
679
686
|
root.setEnvironment({ horizontalSizeClass: next });
|
|
680
687
|
}) : null;
|
|
681
688
|
observer?.observe(screen);
|
|
689
|
+
const stopScenePhase = typeof document !== "undefined" ? watchScenePhase((scenePhase) => root.setEnvironment({ scenePhase })) : null;
|
|
682
690
|
root.render(element);
|
|
683
691
|
const mounted = {
|
|
684
692
|
root,
|
|
@@ -691,6 +699,7 @@ function mount(screen, element, options = {}) {
|
|
|
691
699
|
},
|
|
692
700
|
unmount() {
|
|
693
701
|
observer?.disconnect();
|
|
702
|
+
stopScenePhase?.();
|
|
694
703
|
stopKeyboard?.();
|
|
695
704
|
browserHistory?.dispose();
|
|
696
705
|
screen.removeEventListener("sb:color-scheme", onPreferredScheme);
|
|
@@ -1112,6 +1121,61 @@ function FileImporterPresenter(spec) {
|
|
|
1112
1121
|
}, [presented, setPresented]);
|
|
1113
1122
|
return null;
|
|
1114
1123
|
}
|
|
1124
|
+
const EXTENSIONS = {
|
|
1125
|
+
"text/plain": "txt",
|
|
1126
|
+
"text/csv": "csv",
|
|
1127
|
+
"text/markdown": "md",
|
|
1128
|
+
"text/html": "html",
|
|
1129
|
+
"application/json": "json",
|
|
1130
|
+
"application/pdf": "pdf",
|
|
1131
|
+
"image/png": "png",
|
|
1132
|
+
"image/jpeg": "jpg",
|
|
1133
|
+
"image/svg+xml": "svg",
|
|
1134
|
+
"audio/mp4": "m4a",
|
|
1135
|
+
"video/mp4": "mp4"
|
|
1136
|
+
};
|
|
1137
|
+
function exportFile(document2, contentType, defaultFilename, index = 0) {
|
|
1138
|
+
const type = document2 instanceof Blob && document2.type || contentType || "application/octet-stream";
|
|
1139
|
+
let name = defaultFilename ?? (document2 instanceof File ? document2.name : index === 0 ? "Untitled" : `Untitled ${index + 1}`);
|
|
1140
|
+
name = name.replace(/[\\/:*?"<>|]+/g, "-").trim() || "Untitled";
|
|
1141
|
+
const extension = EXTENSIONS[type.split(";")[0].trim()];
|
|
1142
|
+
if (extension && !/\.[A-Za-z0-9]{1,8}$/.test(name)) name = `${name}.${extension}`;
|
|
1143
|
+
if (document2 instanceof File && document2.name === name && document2.type === type) return document2;
|
|
1144
|
+
const bytes = typeof document2 === "string" ? new TextEncoder().encode(document2) : document2;
|
|
1145
|
+
return new File([bytes], name, { type });
|
|
1146
|
+
}
|
|
1147
|
+
function FileExporterPresenter(spec) {
|
|
1148
|
+
const [presented, setPresented] = readBinding(spec.isPresented);
|
|
1149
|
+
const latest = useRef(spec);
|
|
1150
|
+
latest.current = spec;
|
|
1151
|
+
const exporting = useRef(false);
|
|
1152
|
+
useLayoutEffect(() => {
|
|
1153
|
+
if (!presented || exporting.current) return;
|
|
1154
|
+
const { document: document2, contentType, defaultFilename } = latest.current;
|
|
1155
|
+
const documents = document2 === null ? [] : Array.isArray(document2) ? document2 : [document2];
|
|
1156
|
+
if (documents.length === 0) {
|
|
1157
|
+
setPresented(false);
|
|
1158
|
+
latest.current.onCancellation?.();
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
exporting.current = true;
|
|
1162
|
+
const files = documents.map((item, index) => exportFile(item, contentType, defaultFilename, index));
|
|
1163
|
+
exportFiles(files).then(
|
|
1164
|
+
(result) => {
|
|
1165
|
+
exporting.current = false;
|
|
1166
|
+
setPresented(false);
|
|
1167
|
+
if (result.outcome === "cancelled") latest.current.onCancellation?.();
|
|
1168
|
+
else latest.current.onCompletion?.(result);
|
|
1169
|
+
},
|
|
1170
|
+
(error) => {
|
|
1171
|
+
exporting.current = false;
|
|
1172
|
+
setPresented(false);
|
|
1173
|
+
latest.current.onError?.(error);
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}, [presented, setPresented]);
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1115
1179
|
const isPoint = (value) => typeof value === "object" && value !== null && ("x" in value || "y" in value);
|
|
1116
1180
|
function command(request) {
|
|
1117
1181
|
return request.axes ? { anchor: request.anchor, serial: request.serial, axes: request.axes } : { anchor: request.anchor, serial: request.serial };
|
|
@@ -2136,6 +2200,7 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
|
|
|
2136
2200
|
"magnifyGesture",
|
|
2137
2201
|
"rotateGesture",
|
|
2138
2202
|
"onLongPressGesture",
|
|
2203
|
+
"onTouches",
|
|
2139
2204
|
"simultaneousGesture",
|
|
2140
2205
|
"highPriorityGesture",
|
|
2141
2206
|
"contextMenu",
|
|
@@ -2188,6 +2253,7 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
|
|
|
2188
2253
|
"safeAreaInset",
|
|
2189
2254
|
"popover",
|
|
2190
2255
|
"fileImporter",
|
|
2256
|
+
"fileExporter",
|
|
2191
2257
|
"redacted",
|
|
2192
2258
|
"keyboardShortcut",
|
|
2193
2259
|
"onKeyPress",
|
|
@@ -2577,6 +2643,10 @@ function apply(key, value, node, sides) {
|
|
|
2577
2643
|
case "rotateGesture":
|
|
2578
2644
|
case "onLongPressGesture":
|
|
2579
2645
|
return gesture(key, value, node);
|
|
2646
|
+
case "onTouches": {
|
|
2647
|
+
const handler = value;
|
|
2648
|
+
return sb("touches", {}, { touches: (event) => handler(event.touches, event.phase) }, node);
|
|
2649
|
+
}
|
|
2580
2650
|
case "simultaneousGesture":
|
|
2581
2651
|
case "highPriorityGesture": {
|
|
2582
2652
|
const mode = key === "simultaneousGesture" ? "simultaneous" : "highPriority";
|
|
@@ -2747,6 +2817,9 @@ function apply(key, value, node, sides) {
|
|
|
2747
2817
|
case "fileImporter":
|
|
2748
2818
|
sides.push(createElement(FileImporterPresenter, value));
|
|
2749
2819
|
return node;
|
|
2820
|
+
case "fileExporter":
|
|
2821
|
+
sides.push(createElement(FileExporterPresenter, value));
|
|
2822
|
+
return node;
|
|
2750
2823
|
case "redacted":
|
|
2751
2824
|
return withEnvironment({ redacted: Boolean(value) }, node);
|
|
2752
2825
|
case "keyboardShortcut":
|
|
@@ -2880,10 +2953,10 @@ function GeometryChangeView({ handler, children }) {
|
|
|
2880
2953
|
});
|
|
2881
2954
|
const heard = reported !== NO_GEOMETRY;
|
|
2882
2955
|
const value = heard && typeof handler !== "function" ? handler.of(proxy) : void 0;
|
|
2883
|
-
|
|
2956
|
+
useLayoutEffect(() => {
|
|
2884
2957
|
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
2885
2958
|
});
|
|
2886
|
-
|
|
2959
|
+
useLayoutEffect(() => {
|
|
2887
2960
|
if (!heard) return;
|
|
2888
2961
|
if (typeof handler === "function") {
|
|
2889
2962
|
handler(proxy);
|
|
@@ -3501,175 +3574,53 @@ function useAudioRecorder(options = {}) {
|
|
|
3501
3574
|
);
|
|
3502
3575
|
return { available: host !== void 0, status, time, levels, error, record, pause, resume, stop, cancel, discard, trim };
|
|
3503
3576
|
}
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
if (!entries) {
|
|
3508
|
-
entries = /* @__PURE__ */ new Map();
|
|
3509
|
-
stores.set(store, entries);
|
|
3510
|
-
if (store === pageStorage) watchOtherTabs();
|
|
3511
|
-
}
|
|
3512
|
-
let entry = entries.get(key);
|
|
3513
|
-
if (!entry) {
|
|
3514
|
-
let raw = null;
|
|
3515
|
-
try {
|
|
3516
|
-
raw = store.getItem(key);
|
|
3517
|
-
} catch {
|
|
3518
|
-
}
|
|
3519
|
-
entry = { raw, value: void 0, decoded: false, decode: void 0, listeners: /* @__PURE__ */ new Set() };
|
|
3520
|
-
entries.set(key, entry);
|
|
3521
|
-
}
|
|
3522
|
-
return entry;
|
|
3523
|
-
}
|
|
3524
|
-
function valueOf(entry, absent) {
|
|
3525
|
-
if (entry.raw === null) return absent;
|
|
3526
|
-
if (!entry.decoded) {
|
|
3527
|
-
try {
|
|
3528
|
-
const parsed = JSON.parse(entry.raw);
|
|
3529
|
-
entry.value = entry.decode ? entry.decode(parsed) : parsed;
|
|
3530
|
-
} catch {
|
|
3531
|
-
entry.raw = null;
|
|
3532
|
-
return absent;
|
|
3533
|
-
}
|
|
3534
|
-
entry.decoded = true;
|
|
3535
|
-
}
|
|
3536
|
-
return entry.value;
|
|
3537
|
-
}
|
|
3538
|
-
function notify(entry) {
|
|
3539
|
-
for (const listener of [...entry.listeners]) listener();
|
|
3540
|
-
}
|
|
3541
|
-
function invalidate(entry, raw) {
|
|
3542
|
-
if (entry.raw === raw && entry.decoded) return;
|
|
3543
|
-
entry.raw = raw;
|
|
3544
|
-
entry.decoded = false;
|
|
3545
|
-
notify(entry);
|
|
3546
|
-
}
|
|
3547
|
-
function readPageStorage() {
|
|
3548
|
-
try {
|
|
3549
|
-
const storage = globalThis.localStorage;
|
|
3550
|
-
return storage && typeof storage.getItem === "function" ? storage : null;
|
|
3551
|
-
} catch {
|
|
3552
|
-
return null;
|
|
3553
|
-
}
|
|
3577
|
+
function wakeLockAPI() {
|
|
3578
|
+
const nav = globalThis.navigator;
|
|
3579
|
+
return nav?.wakeLock ?? null;
|
|
3554
3580
|
}
|
|
3555
|
-
|
|
3556
|
-
const
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
const appStorage = pageStorage ?? memoryStorage;
|
|
3563
|
-
let watching = false;
|
|
3564
|
-
function watchOtherTabs() {
|
|
3565
|
-
if (watching || !pageStorage) return;
|
|
3566
|
-
watching = true;
|
|
3567
|
-
const target = globalThis;
|
|
3568
|
-
if (typeof target.addEventListener !== "function") return;
|
|
3569
|
-
target.addEventListener("storage", (event) => {
|
|
3570
|
-
if (event.storageArea !== pageStorage) return;
|
|
3571
|
-
const entries = stores.get(pageStorage);
|
|
3572
|
-
if (!entries) return;
|
|
3573
|
-
if (event.key === null) {
|
|
3574
|
-
for (const entry of entries.values()) invalidate(entry, null);
|
|
3575
|
-
} else {
|
|
3576
|
-
const entry = entries.get(event.key);
|
|
3577
|
-
if (entry) invalidate(entry, event.newValue);
|
|
3581
|
+
function useWakeLock(active2 = true) {
|
|
3582
|
+
const [held, setHeld] = useState(false);
|
|
3583
|
+
useEffect(() => {
|
|
3584
|
+
const api = wakeLockAPI();
|
|
3585
|
+
if (!active2 || !api) {
|
|
3586
|
+
setHeld(false);
|
|
3587
|
+
return;
|
|
3578
3588
|
}
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
[store, key, fallback, onError]
|
|
3614
|
-
);
|
|
3615
|
-
return [value, set];
|
|
3616
|
-
}
|
|
3617
|
-
const NONE = {
|
|
3618
|
-
documents: "file:///data/Documents",
|
|
3619
|
-
applicationSupport: "file:///data/Library/Application%20Support",
|
|
3620
|
-
caches: "file:///data/Library/Caches",
|
|
3621
|
-
temporary: "file:///tmp"
|
|
3622
|
-
};
|
|
3623
|
-
async function bytesOf(contents) {
|
|
3624
|
-
if (typeof contents === "string") return new TextEncoder().encode(contents);
|
|
3625
|
-
if (contents instanceof Uint8Array) return contents;
|
|
3626
|
-
if (contents instanceof ArrayBuffer) return new Uint8Array(contents);
|
|
3627
|
-
const blob = contents;
|
|
3628
|
-
if (typeof blob.bytes === "function") return await blob.bytes();
|
|
3629
|
-
return new Uint8Array(await blob.arrayBuffer());
|
|
3630
|
-
}
|
|
3631
|
-
function createFileManager(host) {
|
|
3632
|
-
const required = () => {
|
|
3633
|
-
const files = host();
|
|
3634
|
-
if (!files) throw new Error("unsupported: this page keeps no files");
|
|
3635
|
-
return files;
|
|
3636
|
-
};
|
|
3637
|
-
const directories = () => host()?.directories ?? NONE;
|
|
3638
|
-
return {
|
|
3639
|
-
get available() {
|
|
3640
|
-
return host() !== void 0;
|
|
3641
|
-
},
|
|
3642
|
-
get documentsDirectory() {
|
|
3643
|
-
return directories().documents;
|
|
3644
|
-
},
|
|
3645
|
-
get applicationSupportDirectory() {
|
|
3646
|
-
return directories().applicationSupport;
|
|
3647
|
-
},
|
|
3648
|
-
get cachesDirectory() {
|
|
3649
|
-
return directories().caches;
|
|
3650
|
-
},
|
|
3651
|
-
get temporaryDirectory() {
|
|
3652
|
-
return directories().temporary;
|
|
3653
|
-
},
|
|
3654
|
-
url: (directory, path) => fileURL(directory, path),
|
|
3655
|
-
contents: async (url) => required().read(url),
|
|
3656
|
-
text: async (url) => new TextDecoder().decode(await required().read(url)),
|
|
3657
|
-
write: async (url, contents) => required().write(url, await bytesOf(contents)),
|
|
3658
|
-
contentsOfDirectory: async (url) => required().list(url),
|
|
3659
|
-
createDirectory: async (url) => required().createDirectory(url),
|
|
3660
|
-
fileExists: async (url) => await required().attributes(url) !== null,
|
|
3661
|
-
attributesOfItem: async (url) => {
|
|
3662
|
-
const attributes = await required().attributes(url);
|
|
3663
|
-
if (!attributes) throw new Error(`notFound: nothing at ${url}`);
|
|
3664
|
-
return attributes;
|
|
3665
|
-
},
|
|
3666
|
-
moveItem: async (from, to) => required().move(from, to),
|
|
3667
|
-
copyItem: async (from, to) => required().copy(from, to),
|
|
3668
|
-
removeItem: async (url) => required().remove(url),
|
|
3669
|
-
loadURL: async (url) => required().loadURL(url)
|
|
3670
|
-
};
|
|
3589
|
+
let sentinel = null;
|
|
3590
|
+
let stopped = false;
|
|
3591
|
+
const acquire = () => {
|
|
3592
|
+
if (stopped || sentinel && !sentinel.released) return;
|
|
3593
|
+
api.request("screen").then(
|
|
3594
|
+
(next) => {
|
|
3595
|
+
if (stopped) {
|
|
3596
|
+
void next.release();
|
|
3597
|
+
return;
|
|
3598
|
+
}
|
|
3599
|
+
sentinel = next;
|
|
3600
|
+
setHeld(true);
|
|
3601
|
+
next.addEventListener("release", () => {
|
|
3602
|
+
if (sentinel === next) setHeld(false);
|
|
3603
|
+
});
|
|
3604
|
+
},
|
|
3605
|
+
() => setHeld(false)
|
|
3606
|
+
);
|
|
3607
|
+
};
|
|
3608
|
+
const onVisible = () => {
|
|
3609
|
+
if (typeof document === "undefined" || document.visibilityState === "visible") acquire();
|
|
3610
|
+
};
|
|
3611
|
+
acquire();
|
|
3612
|
+
const doc = typeof document !== "undefined" ? document : null;
|
|
3613
|
+
doc?.addEventListener("visibilitychange", onVisible);
|
|
3614
|
+
return () => {
|
|
3615
|
+
stopped = true;
|
|
3616
|
+
doc?.removeEventListener("visibilitychange", onVisible);
|
|
3617
|
+
if (sentinel && !sentinel.released) void sentinel.release();
|
|
3618
|
+
sentinel = null;
|
|
3619
|
+
setHeld(false);
|
|
3620
|
+
};
|
|
3621
|
+
}, [active2]);
|
|
3622
|
+
return held;
|
|
3671
3623
|
}
|
|
3672
|
-
const fileManager = createFileManager(() => browserEnvironment.files);
|
|
3673
3624
|
function Button(props) {
|
|
3674
3625
|
const { own, modifiers } = splitProps(props);
|
|
3675
3626
|
const environment = useViewEnvironment();
|
|
@@ -3932,140 +3883,19 @@ function TextEditor(props) {
|
|
|
3932
3883
|
function buttonDisabled(modifiers) {
|
|
3933
3884
|
return modifiers.some(([key, value]) => key === "disabled" && value === true);
|
|
3934
3885
|
}
|
|
3935
|
-
const
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
const
|
|
3939
|
-
const
|
|
3940
|
-
const
|
|
3941
|
-
if (
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
if (
|
|
3947
|
-
|
|
3948
|
-
if (value instanceof Set) listProps["multiSelect"] = true;
|
|
3949
|
-
selected = value instanceof Set ? value.size > 0 : value !== null && value !== void 0;
|
|
3950
|
-
clearSelection = () => setValue(value instanceof Set ? /* @__PURE__ */ new Set() : null);
|
|
3951
|
-
selection = {
|
|
3952
|
-
editing,
|
|
3953
|
-
isSelected: (tag) => value instanceof Set ? value.has(tag) : value !== null && Object.is(value, tag),
|
|
3954
|
-
select: (tag) => {
|
|
3955
|
-
if (value instanceof Set) {
|
|
3956
|
-
const next = new Set(value);
|
|
3957
|
-
if (next.has(tag)) next.delete(tag);
|
|
3958
|
-
else next.add(tag);
|
|
3959
|
-
setValue(next);
|
|
3960
|
-
} else {
|
|
3961
|
-
setValue(editing && Object.is(value, tag) ? null : tag);
|
|
3962
|
-
}
|
|
3963
|
-
}
|
|
3964
|
-
};
|
|
3965
|
-
}
|
|
3966
|
-
useReportSplitSelection(split, selected, clearSelection, own.selection !== void 0);
|
|
3967
|
-
const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
|
|
3968
|
-
Object.assign(listProps, refresh.props);
|
|
3969
|
-
const ownSettings = takeScrollSettings(modifiers);
|
|
3970
|
-
const edgeEffect = edgeEffectProp(useScrollSettings(ownSettings));
|
|
3971
|
-
if (edgeEffect) listProps["edgeEffect"] = edgeEffect;
|
|
3972
|
-
const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, providingScrollSettings(ownSettings, wrapRows(own.children))) });
|
|
3973
|
-
return applyModifiers(
|
|
3974
|
-
selection ? /* @__PURE__ */ jsx(ListSelectionContext.Provider, { value: selection, children: element }) : element,
|
|
3975
|
-
modifiers
|
|
3976
|
-
);
|
|
3977
|
-
}
|
|
3978
|
-
function Form(props) {
|
|
3979
|
-
return /* @__PURE__ */ jsx(List, { ...props });
|
|
3980
|
-
}
|
|
3981
|
-
function Section(props) {
|
|
3982
|
-
const { own, modifiers } = splitProps(props);
|
|
3983
|
-
const pinned = useContext(PinnedContext);
|
|
3984
|
-
let header = supplement(own.header);
|
|
3985
|
-
let footer = supplement(own.footer);
|
|
3986
|
-
if (pinned?.includes("sectionHeaders") && header.text !== null && !header.view) header = { text: null, view: /* @__PURE__ */ jsx(Text, { children: header.text }) };
|
|
3987
|
-
if (pinned?.includes("sectionFooters") && footer.text !== null && !footer.view) footer = { text: null, view: /* @__PURE__ */ jsx(Text, { children: footer.text }) };
|
|
3988
|
-
const children = [];
|
|
3989
|
-
if (header.view) children.push(sb("sectionheader", {}, void 0, header.view));
|
|
3990
|
-
if (own.children !== void 0) children.push(wrapRows(own.children));
|
|
3991
|
-
if (footer.view) children.push(sb("sectionfooter", {}, void 0, footer.view));
|
|
3992
|
-
return applyModifiers(sb("section", { header: header.text, footer: footer.text }, void 0, children), modifiers);
|
|
3993
|
-
}
|
|
3994
|
-
function wrapRows(children) {
|
|
3995
|
-
let offset = 0;
|
|
3996
|
-
return flattenChildren(children, { keepLazy: true }).map((element, index) => {
|
|
3997
|
-
const at = index + offset;
|
|
3998
|
-
if (element.type === LazyGroup) {
|
|
3999
|
-
const group = element.props;
|
|
4000
|
-
offset += group.rows.length - 1;
|
|
4001
|
-
return { ...withKey(element, index), props: { ...group, start: at, wrap: wrapRow } };
|
|
4002
|
-
}
|
|
4003
|
-
return wrapRow(withKey(element, index), at);
|
|
4004
|
-
});
|
|
4005
|
-
}
|
|
4006
|
-
function wrapRow(row, containerIndex) {
|
|
4007
|
-
const inner = row.type === Fragment ? flattenChildren(row) : null;
|
|
4008
|
-
const element = inner?.length === 1 ? { ...inner[0], key: row.key } : row;
|
|
4009
|
-
if (element.type === Section) return element;
|
|
4010
|
-
if (element.type === Row) return { ...element, props: { ...element.props, containerIndex } };
|
|
4011
|
-
const props = element.props;
|
|
4012
|
-
const tag = props.tag !== void 0 ? props.tag : element.type === NavigationLink ? props.value : void 0;
|
|
4013
|
-
if (tag === void 0) return element;
|
|
4014
|
-
return /* @__PURE__ */ jsx(Row, { tag, containerIndex, children: element }, element.key ?? containerIndex);
|
|
4015
|
-
}
|
|
4016
|
-
function withKey(element, index) {
|
|
4017
|
-
return element.key !== null ? element : { ...element, key: String(index) };
|
|
4018
|
-
}
|
|
4019
|
-
function supplement(node) {
|
|
4020
|
-
if (node === void 0 || node === null || node === false) return { text: null, view: null };
|
|
4021
|
-
if (typeof node === "string" || typeof node === "number") return { text: String(node), view: null };
|
|
4022
|
-
if (isValidElement(node) && node.type === Text) {
|
|
4023
|
-
const props = node.props;
|
|
4024
|
-
const only = Object.keys(props).every((key) => key === "children");
|
|
4025
|
-
if (only) return { text: plainText(node), view: null };
|
|
4026
|
-
}
|
|
4027
|
-
return { text: null, view: isValidElement(node) ? node : null };
|
|
4028
|
-
}
|
|
4029
|
-
function TabView(props) {
|
|
4030
|
-
const { own, modifiers } = splitProps(props);
|
|
4031
|
-
const tabs = flattenChildren(own.children);
|
|
4032
|
-
const tags = tabs.map((tab, index) => {
|
|
4033
|
-
const tag = tab.props.tag;
|
|
4034
|
-
return tag !== void 0 ? tag : index;
|
|
4035
|
-
});
|
|
4036
|
-
const [internal, setInternal] = useState(tags[0]);
|
|
4037
|
-
const [selection, setSelection] = own.selection !== void 0 ? readBinding(own.selection, own.onChange) : [internal, setInternal];
|
|
4038
|
-
const selected = Math.max(
|
|
4039
|
-
0,
|
|
4040
|
-
tags.findIndex((tag) => Object.is(tag, selection))
|
|
4041
|
-
);
|
|
4042
|
-
return applyModifiers(
|
|
4043
|
-
sb("tabview", { selected }, { select: (event) => tags[event.value] !== void 0 && setSelection(tags[event.value]) }, tabs),
|
|
4044
|
-
modifiers
|
|
4045
|
-
);
|
|
4046
|
-
}
|
|
4047
|
-
function Tab(props) {
|
|
4048
|
-
const { own, modifiers } = splitProps(props);
|
|
4049
|
-
const badge = takeModifier(modifiers, "badge");
|
|
4050
|
-
const tabProps = { title: own.title, systemImage: own.systemImage ?? null };
|
|
4051
|
-
if (badge !== void 0 && badge !== null) tabProps["badge"] = String(badge);
|
|
4052
|
-
if (own.role) tabProps["role"] = own.role;
|
|
4053
|
-
if (own.image && !own.systemImage) tabProps["image"] = own.image;
|
|
4054
|
-
return applyModifiers(sb("tab", tabProps, void 0, own.children), modifiers);
|
|
4055
|
-
}
|
|
4056
|
-
const STYLE_KEYS = ["r", "name", "named", "hierarchical", "linearGradient", "radialGradient", "angularGradient", "colorGradient", "material"];
|
|
4057
|
-
function strokeOf(value, inset) {
|
|
4058
|
-
if (value === void 0) return null;
|
|
4059
|
-
const isSpec = typeof value === "object" && value !== null && !STYLE_KEYS.some((key) => key in value);
|
|
4060
|
-
const spec = isSpec ? value : { style: value };
|
|
4061
|
-
const stroke = { color: shapeStyle(spec.style ?? "primary"), lineWidth: spec.lineWidth ?? 1 };
|
|
4062
|
-
if (inset) stroke.inset = true;
|
|
4063
|
-
if (spec.dash) stroke.dash = spec.dash;
|
|
4064
|
-
if (spec.dashPhase !== void 0) stroke.dashPhase = spec.dashPhase;
|
|
4065
|
-
if (spec.lineCap) stroke.lineCap = spec.lineCap;
|
|
4066
|
-
if (spec.lineJoin) stroke.lineJoin = spec.lineJoin;
|
|
4067
|
-
if (spec.miterLimit !== void 0) stroke.miterLimit = spec.miterLimit;
|
|
4068
|
-
return stroke;
|
|
3886
|
+
const STYLE_KEYS = ["r", "name", "named", "hierarchical", "linearGradient", "radialGradient", "angularGradient", "colorGradient", "material"];
|
|
3887
|
+
function strokeOf(value, inset) {
|
|
3888
|
+
if (value === void 0) return null;
|
|
3889
|
+
const isSpec = typeof value === "object" && value !== null && !STYLE_KEYS.some((key) => key in value);
|
|
3890
|
+
const spec = isSpec ? value : { style: value };
|
|
3891
|
+
const stroke = { color: shapeStyle(spec.style ?? "primary"), lineWidth: spec.lineWidth ?? 1 };
|
|
3892
|
+
if (inset) stroke.inset = true;
|
|
3893
|
+
if (spec.dash) stroke.dash = spec.dash;
|
|
3894
|
+
if (spec.dashPhase !== void 0) stroke.dashPhase = spec.dashPhase;
|
|
3895
|
+
if (spec.lineCap) stroke.lineCap = spec.lineCap;
|
|
3896
|
+
if (spec.lineJoin) stroke.lineJoin = spec.lineJoin;
|
|
3897
|
+
if (spec.miterLimit !== void 0) stroke.miterLimit = spec.miterLimit;
|
|
3898
|
+
return stroke;
|
|
4069
3899
|
}
|
|
4070
3900
|
function shape(kind, cornerRadius, props) {
|
|
4071
3901
|
const { own, modifiers } = splitProps(props);
|
|
@@ -4154,6 +3984,595 @@ function ColorView(props) {
|
|
|
4154
3984
|
return applyModifiers(sb("color", { color: color(own.color) }), modifiers);
|
|
4155
3985
|
}
|
|
4156
3986
|
const Color = Object.assign(ColorView, ColorValues);
|
|
3987
|
+
function canSignInWithApple() {
|
|
3988
|
+
return browserEnvironment.appleSignIn !== void 0;
|
|
3989
|
+
}
|
|
3990
|
+
async function signInWithApple(options = {}) {
|
|
3991
|
+
const host = browserEnvironment.appleSignIn;
|
|
3992
|
+
if (!host) throw new Error("unsupported: Sign in with Apple is not available here (configureSignInWithApple on a page)");
|
|
3993
|
+
return host.signIn({ scopes: options.scopes ?? ["fullName", "email"], ...options.nonce ? { nonce: options.nonce } : {}, ...options.state ? { state: options.state } : {} });
|
|
3994
|
+
}
|
|
3995
|
+
async function appleCredentialState(user) {
|
|
3996
|
+
const host = browserEnvironment.appleSignIn;
|
|
3997
|
+
if (!host) return "unknown";
|
|
3998
|
+
return host.credentialState(user);
|
|
3999
|
+
}
|
|
4000
|
+
const LABELS = { signIn: "Sign in with Apple", signUp: "Sign up with Apple", continue: "Continue with Apple" };
|
|
4001
|
+
function SignInWithAppleButton(props) {
|
|
4002
|
+
const { own, modifiers } = splitProps(props);
|
|
4003
|
+
const style = own.style ?? "black";
|
|
4004
|
+
const background = style === "black" ? "black" : "white";
|
|
4005
|
+
const foreground = style === "black" ? "white" : "black";
|
|
4006
|
+
const action = () => {
|
|
4007
|
+
signInWithApple({ ...own.scopes ? { scopes: own.scopes } : {}, ...own.nonce ? { nonce: own.nonce } : {}, ...own.state ? { state: own.state } : {} }).then(
|
|
4008
|
+
(credential) => own.onCompletion({ credential }),
|
|
4009
|
+
(error) => own.onCompletion({ error: error instanceof Error ? error : new Error(String(error)) })
|
|
4010
|
+
);
|
|
4011
|
+
};
|
|
4012
|
+
return /* @__PURE__ */ jsx(
|
|
4013
|
+
Button,
|
|
4014
|
+
{
|
|
4015
|
+
action,
|
|
4016
|
+
buttonStyle: "plain",
|
|
4017
|
+
foregroundStyle: foreground,
|
|
4018
|
+
background: /* @__PURE__ */ jsx(RoundedRectangle, { cornerRadius: 8, fill: background }),
|
|
4019
|
+
...style === "whiteOutline" ? { overlay: /* @__PURE__ */ jsx(RoundedRectangle, { cornerRadius: 8, strokeBorder: { style: "black", lineWidth: 1 } }) } : {},
|
|
4020
|
+
...Object.fromEntries(modifiers),
|
|
4021
|
+
children: /* @__PURE__ */ jsxs(HStack, { spacing: 6, frame: { maxWidth: Infinity, height: 50 }, font: system(19, "medium"), children: [
|
|
4022
|
+
/* @__PURE__ */ jsx(Image$1, { systemName: "apple.logo" }),
|
|
4023
|
+
/* @__PURE__ */ jsx(Text, { children: LABELS[own.label ?? "signIn"] })
|
|
4024
|
+
] })
|
|
4025
|
+
}
|
|
4026
|
+
);
|
|
4027
|
+
}
|
|
4028
|
+
function geolocationAPI() {
|
|
4029
|
+
const nav = globalThis.navigator;
|
|
4030
|
+
return nav?.geolocation ?? null;
|
|
4031
|
+
}
|
|
4032
|
+
function useGeolocation(options = {}) {
|
|
4033
|
+
const { watch = false, immediate = false, enableHighAccuracy = false, timeout, maximumAge } = options;
|
|
4034
|
+
const api = geolocationAPI();
|
|
4035
|
+
const [status, setStatus] = useState("idle");
|
|
4036
|
+
const [position, setPosition] = useState(null);
|
|
4037
|
+
const [error, setError] = useState(null);
|
|
4038
|
+
const watching2 = useRef(null);
|
|
4039
|
+
const mounted = useRef(true);
|
|
4040
|
+
const stop = useCallback(() => {
|
|
4041
|
+
if (watching2.current !== null) {
|
|
4042
|
+
geolocationAPI()?.clearWatch(watching2.current);
|
|
4043
|
+
watching2.current = null;
|
|
4044
|
+
}
|
|
4045
|
+
}, []);
|
|
4046
|
+
const request = useCallback(() => {
|
|
4047
|
+
const geo = geolocationAPI();
|
|
4048
|
+
if (!geo) {
|
|
4049
|
+
setStatus("failed");
|
|
4050
|
+
setError("geolocation: not available");
|
|
4051
|
+
return;
|
|
4052
|
+
}
|
|
4053
|
+
stop();
|
|
4054
|
+
setStatus("locating");
|
|
4055
|
+
setError(null);
|
|
4056
|
+
const positionOptions = { enableHighAccuracy, ...timeout !== void 0 ? { timeout } : {}, ...maximumAge !== void 0 ? { maximumAge } : {} };
|
|
4057
|
+
const onFix = (p) => {
|
|
4058
|
+
if (!mounted.current) return;
|
|
4059
|
+
setPosition({
|
|
4060
|
+
latitude: p.coords.latitude,
|
|
4061
|
+
longitude: p.coords.longitude,
|
|
4062
|
+
accuracy: p.coords.accuracy,
|
|
4063
|
+
altitude: p.coords.altitude ?? null,
|
|
4064
|
+
heading: p.coords.heading ?? null,
|
|
4065
|
+
speed: p.coords.speed ?? null,
|
|
4066
|
+
timestamp: p.timestamp
|
|
4067
|
+
});
|
|
4068
|
+
setStatus("located");
|
|
4069
|
+
setError(null);
|
|
4070
|
+
};
|
|
4071
|
+
const onError = (e) => {
|
|
4072
|
+
if (!mounted.current) return;
|
|
4073
|
+
setStatus(e.code === 1 ? "denied" : "failed");
|
|
4074
|
+
setError(e.message);
|
|
4075
|
+
if (e.code === 1) stop();
|
|
4076
|
+
};
|
|
4077
|
+
if (watch) watching2.current = geo.watchPosition(onFix, onError, positionOptions);
|
|
4078
|
+
else geo.getCurrentPosition(onFix, onError, positionOptions);
|
|
4079
|
+
}, [watch, enableHighAccuracy, timeout, maximumAge, stop]);
|
|
4080
|
+
useEffect(() => {
|
|
4081
|
+
mounted.current = true;
|
|
4082
|
+
if (immediate) request();
|
|
4083
|
+
return () => {
|
|
4084
|
+
mounted.current = false;
|
|
4085
|
+
stop();
|
|
4086
|
+
};
|
|
4087
|
+
}, [immediate, request, stop]);
|
|
4088
|
+
return { available: api !== null, status, position, error, request, stop };
|
|
4089
|
+
}
|
|
4090
|
+
function synthesisAPI() {
|
|
4091
|
+
const g = globalThis;
|
|
4092
|
+
return g.speechSynthesis && g.SpeechSynthesisUtterance ? { synthesis: g.speechSynthesis, Utterance: g.SpeechSynthesisUtterance } : null;
|
|
4093
|
+
}
|
|
4094
|
+
function useSpeechSynthesis() {
|
|
4095
|
+
const api = synthesisAPI();
|
|
4096
|
+
const [speaking, setSpeaking] = useState(false);
|
|
4097
|
+
const [paused, setPaused] = useState(false);
|
|
4098
|
+
const mounted = useRef(true);
|
|
4099
|
+
const queued = useRef(0);
|
|
4100
|
+
useEffect(() => {
|
|
4101
|
+
mounted.current = true;
|
|
4102
|
+
return () => {
|
|
4103
|
+
mounted.current = false;
|
|
4104
|
+
if (queued.current > 0) synthesisAPI()?.synthesis.cancel();
|
|
4105
|
+
};
|
|
4106
|
+
}, []);
|
|
4107
|
+
const speak = useCallback((text, options = {}) => {
|
|
4108
|
+
const current = synthesisAPI();
|
|
4109
|
+
if (!current) return;
|
|
4110
|
+
const utterance = new current.Utterance(text);
|
|
4111
|
+
if (options.lang) utterance.lang = options.lang;
|
|
4112
|
+
if (options.rate !== void 0) utterance.rate = options.rate;
|
|
4113
|
+
if (options.pitch !== void 0) utterance.pitch = options.pitch;
|
|
4114
|
+
if (options.volume !== void 0) utterance.volume = options.volume;
|
|
4115
|
+
queued.current++;
|
|
4116
|
+
const done = () => {
|
|
4117
|
+
queued.current = Math.max(0, queued.current - 1);
|
|
4118
|
+
if (!mounted.current) return;
|
|
4119
|
+
if (queued.current === 0) {
|
|
4120
|
+
setSpeaking(false);
|
|
4121
|
+
setPaused(false);
|
|
4122
|
+
}
|
|
4123
|
+
};
|
|
4124
|
+
utterance.onstart = () => {
|
|
4125
|
+
if (!mounted.current) return;
|
|
4126
|
+
setSpeaking(true);
|
|
4127
|
+
setPaused(false);
|
|
4128
|
+
};
|
|
4129
|
+
utterance.onpause = () => mounted.current && setPaused(true);
|
|
4130
|
+
utterance.onresume = () => mounted.current && setPaused(false);
|
|
4131
|
+
utterance.onend = done;
|
|
4132
|
+
utterance.onerror = done;
|
|
4133
|
+
current.synthesis.speak(utterance);
|
|
4134
|
+
}, []);
|
|
4135
|
+
const cancel = useCallback(() => {
|
|
4136
|
+
synthesisAPI()?.synthesis.cancel();
|
|
4137
|
+
}, []);
|
|
4138
|
+
const pause = useCallback(() => synthesisAPI()?.synthesis.pause(), []);
|
|
4139
|
+
const resume = useCallback(() => synthesisAPI()?.synthesis.resume(), []);
|
|
4140
|
+
return { available: api !== null, speaking, paused, speak, cancel, pause, resume };
|
|
4141
|
+
}
|
|
4142
|
+
function recognitionAPI() {
|
|
4143
|
+
const g = globalThis;
|
|
4144
|
+
return g.SpeechRecognition ?? g.webkitSpeechRecognition ?? null;
|
|
4145
|
+
}
|
|
4146
|
+
function useSpeechRecognition(options = {}) {
|
|
4147
|
+
const { lang, continuous = false, interimResults = true } = options;
|
|
4148
|
+
const api = recognitionAPI();
|
|
4149
|
+
const [listening, setListening] = useState(false);
|
|
4150
|
+
const [transcript, setTranscript] = useState("");
|
|
4151
|
+
const [interim, setInterim] = useState("");
|
|
4152
|
+
const [error, setError] = useState(null);
|
|
4153
|
+
const current = useRef(null);
|
|
4154
|
+
const mounted = useRef(true);
|
|
4155
|
+
useEffect(() => {
|
|
4156
|
+
mounted.current = true;
|
|
4157
|
+
return () => {
|
|
4158
|
+
mounted.current = false;
|
|
4159
|
+
current.current?.abort();
|
|
4160
|
+
current.current = null;
|
|
4161
|
+
};
|
|
4162
|
+
}, []);
|
|
4163
|
+
const start = useCallback(() => {
|
|
4164
|
+
const Recognition = recognitionAPI();
|
|
4165
|
+
if (!Recognition) {
|
|
4166
|
+
setError("not-allowed");
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4169
|
+
if (current.current) return;
|
|
4170
|
+
const recognition = new Recognition();
|
|
4171
|
+
if (lang) recognition.lang = lang;
|
|
4172
|
+
recognition.continuous = continuous;
|
|
4173
|
+
recognition.interimResults = interimResults;
|
|
4174
|
+
setTranscript("");
|
|
4175
|
+
setInterim("");
|
|
4176
|
+
setError(null);
|
|
4177
|
+
recognition.onstart = () => mounted.current && setListening(true);
|
|
4178
|
+
recognition.onresult = (e) => {
|
|
4179
|
+
if (!mounted.current) return;
|
|
4180
|
+
const finals = [];
|
|
4181
|
+
let heard = "";
|
|
4182
|
+
for (let i = 0; i < e.results.length; i++) {
|
|
4183
|
+
const result = e.results[i];
|
|
4184
|
+
if (result.isFinal) finals.push(result[0].transcript.trim());
|
|
4185
|
+
else heard = result[0].transcript;
|
|
4186
|
+
}
|
|
4187
|
+
setTranscript(finals.filter(Boolean).join(" "));
|
|
4188
|
+
setInterim(heard);
|
|
4189
|
+
};
|
|
4190
|
+
recognition.onerror = (e) => mounted.current && setError(e.error);
|
|
4191
|
+
recognition.onend = () => {
|
|
4192
|
+
if (current.current === recognition) current.current = null;
|
|
4193
|
+
if (!mounted.current) return;
|
|
4194
|
+
setListening(false);
|
|
4195
|
+
setInterim("");
|
|
4196
|
+
};
|
|
4197
|
+
current.current = recognition;
|
|
4198
|
+
recognition.start();
|
|
4199
|
+
}, [lang, continuous, interimResults]);
|
|
4200
|
+
const stop = useCallback(() => current.current?.stop(), []);
|
|
4201
|
+
const abort = useCallback(() => current.current?.abort(), []);
|
|
4202
|
+
return { available: api !== null, listening, transcript, interim, error, start, stop, abort };
|
|
4203
|
+
}
|
|
4204
|
+
const stores = /* @__PURE__ */ new WeakMap();
|
|
4205
|
+
function entryFor(store, key) {
|
|
4206
|
+
let entries = stores.get(store);
|
|
4207
|
+
if (!entries) {
|
|
4208
|
+
entries = /* @__PURE__ */ new Map();
|
|
4209
|
+
stores.set(store, entries);
|
|
4210
|
+
if (store === pageStorage) watchOtherTabs();
|
|
4211
|
+
}
|
|
4212
|
+
let entry = entries.get(key);
|
|
4213
|
+
if (!entry) {
|
|
4214
|
+
let raw = null;
|
|
4215
|
+
try {
|
|
4216
|
+
raw = store.getItem(key);
|
|
4217
|
+
} catch {
|
|
4218
|
+
}
|
|
4219
|
+
entry = { raw, value: void 0, decoded: false, decode: void 0, listeners: /* @__PURE__ */ new Set() };
|
|
4220
|
+
entries.set(key, entry);
|
|
4221
|
+
}
|
|
4222
|
+
return entry;
|
|
4223
|
+
}
|
|
4224
|
+
function valueOf(entry, absent) {
|
|
4225
|
+
if (entry.raw === null) return absent;
|
|
4226
|
+
if (!entry.decoded) {
|
|
4227
|
+
try {
|
|
4228
|
+
const parsed = JSON.parse(entry.raw);
|
|
4229
|
+
entry.value = entry.decode ? entry.decode(parsed) : parsed;
|
|
4230
|
+
} catch {
|
|
4231
|
+
entry.raw = null;
|
|
4232
|
+
return absent;
|
|
4233
|
+
}
|
|
4234
|
+
entry.decoded = true;
|
|
4235
|
+
}
|
|
4236
|
+
return entry.value;
|
|
4237
|
+
}
|
|
4238
|
+
function notify(entry) {
|
|
4239
|
+
for (const listener of [...entry.listeners]) listener();
|
|
4240
|
+
}
|
|
4241
|
+
function invalidate(entry, raw) {
|
|
4242
|
+
if (entry.raw === raw && entry.decoded) return;
|
|
4243
|
+
entry.raw = raw;
|
|
4244
|
+
entry.decoded = false;
|
|
4245
|
+
notify(entry);
|
|
4246
|
+
}
|
|
4247
|
+
function readPageStorage() {
|
|
4248
|
+
try {
|
|
4249
|
+
const storage = globalThis.localStorage;
|
|
4250
|
+
return storage && typeof storage.getItem === "function" ? storage : null;
|
|
4251
|
+
} catch {
|
|
4252
|
+
return null;
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
const memory = /* @__PURE__ */ new Map();
|
|
4256
|
+
const memoryStorage = {
|
|
4257
|
+
getItem: (key) => memory.get(key) ?? null,
|
|
4258
|
+
setItem: (key, value) => void memory.set(key, value),
|
|
4259
|
+
removeItem: (key) => void memory.delete(key)
|
|
4260
|
+
};
|
|
4261
|
+
const pageStorage = readPageStorage();
|
|
4262
|
+
const appStorage = pageStorage ?? memoryStorage;
|
|
4263
|
+
let watching = false;
|
|
4264
|
+
function watchOtherTabs() {
|
|
4265
|
+
if (watching || !pageStorage) return;
|
|
4266
|
+
watching = true;
|
|
4267
|
+
const target = globalThis;
|
|
4268
|
+
if (typeof target.addEventListener !== "function") return;
|
|
4269
|
+
target.addEventListener("storage", (event) => {
|
|
4270
|
+
if (event.storageArea !== pageStorage) return;
|
|
4271
|
+
const entries = stores.get(pageStorage);
|
|
4272
|
+
if (!entries) return;
|
|
4273
|
+
if (event.key === null) {
|
|
4274
|
+
for (const entry of entries.values()) invalidate(entry, null);
|
|
4275
|
+
} else {
|
|
4276
|
+
const entry = entries.get(event.key);
|
|
4277
|
+
if (entry) invalidate(entry, event.newValue);
|
|
4278
|
+
}
|
|
4279
|
+
});
|
|
4280
|
+
}
|
|
4281
|
+
function useAppStorage(key, defaultValue, options = {}) {
|
|
4282
|
+
const { store = appStorage, decode, onError } = options;
|
|
4283
|
+
const [fallback] = useState(defaultValue);
|
|
4284
|
+
const entry = entryFor(store, key);
|
|
4285
|
+
entry.decode = decode;
|
|
4286
|
+
const subscribe = useCallback(
|
|
4287
|
+
(listener) => {
|
|
4288
|
+
const subscribed = entryFor(store, key);
|
|
4289
|
+
subscribed.listeners.add(listener);
|
|
4290
|
+
return () => void subscribed.listeners.delete(listener);
|
|
4291
|
+
},
|
|
4292
|
+
[store, key]
|
|
4293
|
+
);
|
|
4294
|
+
const read = useCallback(() => valueOf(entryFor(store, key), fallback), [store, key, fallback]);
|
|
4295
|
+
const value = useSyncExternalStore(subscribe, read, read);
|
|
4296
|
+
const set = useCallback(
|
|
4297
|
+
(next) => {
|
|
4298
|
+
const target = entryFor(store, key);
|
|
4299
|
+
const current = valueOf(target, fallback);
|
|
4300
|
+
const value2 = typeof next === "function" ? next(current) : next;
|
|
4301
|
+
const raw = value2 === void 0 ? null : JSON.stringify(value2);
|
|
4302
|
+
try {
|
|
4303
|
+
if (raw === null) store.removeItem(key);
|
|
4304
|
+
else store.setItem(key, raw);
|
|
4305
|
+
} catch (error) {
|
|
4306
|
+
onError?.(error);
|
|
4307
|
+
}
|
|
4308
|
+
target.raw = raw;
|
|
4309
|
+
target.value = value2;
|
|
4310
|
+
target.decoded = raw !== null;
|
|
4311
|
+
notify(target);
|
|
4312
|
+
},
|
|
4313
|
+
[store, key, fallback, onError]
|
|
4314
|
+
);
|
|
4315
|
+
return [value, set];
|
|
4316
|
+
}
|
|
4317
|
+
const NONE = {
|
|
4318
|
+
documents: "file:///data/Documents",
|
|
4319
|
+
applicationSupport: "file:///data/Library/Application%20Support",
|
|
4320
|
+
caches: "file:///data/Library/Caches",
|
|
4321
|
+
temporary: "file:///tmp"
|
|
4322
|
+
};
|
|
4323
|
+
async function bytesOf(contents) {
|
|
4324
|
+
if (typeof contents === "string") return new TextEncoder().encode(contents);
|
|
4325
|
+
if (contents instanceof Uint8Array) return contents;
|
|
4326
|
+
if (contents instanceof ArrayBuffer) return new Uint8Array(contents);
|
|
4327
|
+
const blob = contents;
|
|
4328
|
+
if (typeof blob.bytes === "function") return await blob.bytes();
|
|
4329
|
+
return new Uint8Array(await blob.arrayBuffer());
|
|
4330
|
+
}
|
|
4331
|
+
function createFileManager(host) {
|
|
4332
|
+
const required = () => {
|
|
4333
|
+
const files = host();
|
|
4334
|
+
if (!files) throw new Error("unsupported: this page keeps no files");
|
|
4335
|
+
return files;
|
|
4336
|
+
};
|
|
4337
|
+
const directories = () => host()?.directories ?? NONE;
|
|
4338
|
+
return {
|
|
4339
|
+
get available() {
|
|
4340
|
+
return host() !== void 0;
|
|
4341
|
+
},
|
|
4342
|
+
get documentsDirectory() {
|
|
4343
|
+
return directories().documents;
|
|
4344
|
+
},
|
|
4345
|
+
get applicationSupportDirectory() {
|
|
4346
|
+
return directories().applicationSupport;
|
|
4347
|
+
},
|
|
4348
|
+
get cachesDirectory() {
|
|
4349
|
+
return directories().caches;
|
|
4350
|
+
},
|
|
4351
|
+
get temporaryDirectory() {
|
|
4352
|
+
return directories().temporary;
|
|
4353
|
+
},
|
|
4354
|
+
url: (directory, path) => fileURL(directory, path),
|
|
4355
|
+
contents: async (url) => required().read(url),
|
|
4356
|
+
text: async (url) => new TextDecoder().decode(await required().read(url)),
|
|
4357
|
+
write: async (url, contents) => required().write(url, await bytesOf(contents)),
|
|
4358
|
+
contentsOfDirectory: async (url) => required().list(url),
|
|
4359
|
+
createDirectory: async (url) => required().createDirectory(url),
|
|
4360
|
+
fileExists: async (url) => await required().attributes(url) !== null,
|
|
4361
|
+
attributesOfItem: async (url) => {
|
|
4362
|
+
const attributes = await required().attributes(url);
|
|
4363
|
+
if (!attributes) throw new Error(`notFound: nothing at ${url}`);
|
|
4364
|
+
return attributes;
|
|
4365
|
+
},
|
|
4366
|
+
moveItem: async (from, to) => required().move(from, to),
|
|
4367
|
+
copyItem: async (from, to) => required().copy(from, to),
|
|
4368
|
+
removeItem: async (url) => required().remove(url),
|
|
4369
|
+
loadURL: async (url) => required().loadURL(url),
|
|
4370
|
+
iCloudDirectory: async () => await host()?.iCloud?.() ?? null,
|
|
4371
|
+
watch: (listener) => host()?.watch?.(listener) ?? (() => {
|
|
4372
|
+
})
|
|
4373
|
+
};
|
|
4374
|
+
}
|
|
4375
|
+
const fileManager = createFileManager(() => browserEnvironment.files);
|
|
4376
|
+
function useFileStorage(url, defaultValue, options = {}) {
|
|
4377
|
+
const manager = options.manager ?? fileManager;
|
|
4378
|
+
const [value, setValue] = useState(defaultValue);
|
|
4379
|
+
const [status, setStatus] = useState(url === null ? "ready" : "loading");
|
|
4380
|
+
const latest = useRef({ value, options, url, defaultValue });
|
|
4381
|
+
latest.current = { value, options, url, defaultValue };
|
|
4382
|
+
const shown = useRef(url);
|
|
4383
|
+
const known = useRef(null);
|
|
4384
|
+
const writing = useRef(Promise.resolve());
|
|
4385
|
+
const load = useCallback(
|
|
4386
|
+
async (target) => {
|
|
4387
|
+
let text;
|
|
4388
|
+
try {
|
|
4389
|
+
text = await manager.text(target);
|
|
4390
|
+
} catch (error) {
|
|
4391
|
+
if (latest.current.url !== target) return;
|
|
4392
|
+
if (error instanceof Error && error.message.startsWith("notFound:")) {
|
|
4393
|
+
known.current = null;
|
|
4394
|
+
setStatus("ready");
|
|
4395
|
+
return;
|
|
4396
|
+
}
|
|
4397
|
+
latest.current.options.onError?.(error);
|
|
4398
|
+
setStatus("error");
|
|
4399
|
+
return;
|
|
4400
|
+
}
|
|
4401
|
+
if (latest.current.url !== target) return;
|
|
4402
|
+
if (text !== known.current) {
|
|
4403
|
+
known.current = text;
|
|
4404
|
+
try {
|
|
4405
|
+
const stored = JSON.parse(text);
|
|
4406
|
+
setValue(latest.current.options.decode ? latest.current.options.decode(stored) : stored);
|
|
4407
|
+
} catch (error) {
|
|
4408
|
+
latest.current.options.onError?.(error);
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
setStatus("ready");
|
|
4412
|
+
},
|
|
4413
|
+
[manager]
|
|
4414
|
+
);
|
|
4415
|
+
useEffect(() => {
|
|
4416
|
+
known.current = null;
|
|
4417
|
+
if (shown.current !== url) {
|
|
4418
|
+
shown.current = url;
|
|
4419
|
+
const fresh = latest.current.defaultValue;
|
|
4420
|
+
const value2 = typeof fresh === "function" ? fresh() : fresh;
|
|
4421
|
+
latest.current.value = value2;
|
|
4422
|
+
setValue(value2);
|
|
4423
|
+
}
|
|
4424
|
+
if (url === null) {
|
|
4425
|
+
setStatus("ready");
|
|
4426
|
+
return;
|
|
4427
|
+
}
|
|
4428
|
+
setStatus("loading");
|
|
4429
|
+
void load(url);
|
|
4430
|
+
return manager.watch((urls) => {
|
|
4431
|
+
if (urls.includes(url)) void load(url);
|
|
4432
|
+
});
|
|
4433
|
+
}, [url, load, manager]);
|
|
4434
|
+
const set = useCallback(
|
|
4435
|
+
(next) => {
|
|
4436
|
+
const resolved = typeof next === "function" ? next(latest.current.value) : next;
|
|
4437
|
+
latest.current.value = resolved;
|
|
4438
|
+
setValue(resolved);
|
|
4439
|
+
const target = latest.current.url;
|
|
4440
|
+
if (target === null) return;
|
|
4441
|
+
const text = JSON.stringify(resolved);
|
|
4442
|
+
known.current = text;
|
|
4443
|
+
writing.current = writing.current.then(async () => {
|
|
4444
|
+
try {
|
|
4445
|
+
await manager.write(target, text);
|
|
4446
|
+
} catch (error) {
|
|
4447
|
+
latest.current.options.onError?.(error);
|
|
4448
|
+
}
|
|
4449
|
+
});
|
|
4450
|
+
},
|
|
4451
|
+
[manager]
|
|
4452
|
+
);
|
|
4453
|
+
return [value, set, status];
|
|
4454
|
+
}
|
|
4455
|
+
const NO_CLEAR = () => {
|
|
4456
|
+
};
|
|
4457
|
+
function List(props) {
|
|
4458
|
+
const { own, modifiers } = splitProps(props);
|
|
4459
|
+
const [editing] = own.editing !== void 0 ? readBinding(own.editing) : [false];
|
|
4460
|
+
const listProps = { style: own.listStyle ?? "insetGrouped" };
|
|
4461
|
+
if (editing) listProps["editing"] = true;
|
|
4462
|
+
let selection = null;
|
|
4463
|
+
const split = useContext(SplitSelectionContext);
|
|
4464
|
+
let selected = false;
|
|
4465
|
+
let clearSelection = NO_CLEAR;
|
|
4466
|
+
if (own.selection !== void 0) {
|
|
4467
|
+
const [value, setValue] = readBinding(own.selection, own.onSelectionChange);
|
|
4468
|
+
if (value instanceof Set) listProps["multiSelect"] = true;
|
|
4469
|
+
selected = value instanceof Set ? value.size > 0 : value !== null && value !== void 0;
|
|
4470
|
+
clearSelection = () => setValue(value instanceof Set ? /* @__PURE__ */ new Set() : null);
|
|
4471
|
+
selection = {
|
|
4472
|
+
editing,
|
|
4473
|
+
isSelected: (tag) => value instanceof Set ? value.has(tag) : value !== null && Object.is(value, tag),
|
|
4474
|
+
select: (tag) => {
|
|
4475
|
+
if (value instanceof Set) {
|
|
4476
|
+
const next = new Set(value);
|
|
4477
|
+
if (next.has(tag)) next.delete(tag);
|
|
4478
|
+
else next.add(tag);
|
|
4479
|
+
setValue(next);
|
|
4480
|
+
} else {
|
|
4481
|
+
setValue(editing && Object.is(value, tag) ? null : tag);
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
useReportSplitSelection(split, selected, clearSelection, own.selection !== void 0);
|
|
4487
|
+
const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
|
|
4488
|
+
Object.assign(listProps, refresh.props);
|
|
4489
|
+
const ownSettings = takeScrollSettings(modifiers);
|
|
4490
|
+
const edgeEffect = edgeEffectProp(useScrollSettings(ownSettings));
|
|
4491
|
+
if (edgeEffect) listProps["edgeEffect"] = edgeEffect;
|
|
4492
|
+
const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, providingScrollSettings(ownSettings, wrapRows(own.children))) });
|
|
4493
|
+
return applyModifiers(
|
|
4494
|
+
selection ? /* @__PURE__ */ jsx(ListSelectionContext.Provider, { value: selection, children: element }) : element,
|
|
4495
|
+
modifiers
|
|
4496
|
+
);
|
|
4497
|
+
}
|
|
4498
|
+
function Form(props) {
|
|
4499
|
+
return /* @__PURE__ */ jsx(List, { ...props });
|
|
4500
|
+
}
|
|
4501
|
+
function Section(props) {
|
|
4502
|
+
const { own, modifiers } = splitProps(props);
|
|
4503
|
+
const pinned = useContext(PinnedContext);
|
|
4504
|
+
let header = supplement(own.header);
|
|
4505
|
+
let footer = supplement(own.footer);
|
|
4506
|
+
if (pinned?.includes("sectionHeaders") && header.text !== null && !header.view) header = { text: null, view: /* @__PURE__ */ jsx(Text, { children: header.text }) };
|
|
4507
|
+
if (pinned?.includes("sectionFooters") && footer.text !== null && !footer.view) footer = { text: null, view: /* @__PURE__ */ jsx(Text, { children: footer.text }) };
|
|
4508
|
+
const children = [];
|
|
4509
|
+
if (header.view) children.push(sb("sectionheader", {}, void 0, header.view));
|
|
4510
|
+
if (own.children !== void 0) children.push(wrapRows(own.children));
|
|
4511
|
+
if (footer.view) children.push(sb("sectionfooter", {}, void 0, footer.view));
|
|
4512
|
+
return applyModifiers(sb("section", { header: header.text, footer: footer.text }, void 0, children), modifiers);
|
|
4513
|
+
}
|
|
4514
|
+
function wrapRows(children) {
|
|
4515
|
+
let offset = 0;
|
|
4516
|
+
return flattenChildren(children, { keepLazy: true }).map((element, index) => {
|
|
4517
|
+
const at = index + offset;
|
|
4518
|
+
if (element.type === LazyGroup) {
|
|
4519
|
+
const group = element.props;
|
|
4520
|
+
offset += group.rows.length - 1;
|
|
4521
|
+
return { ...withKey(element, index), props: { ...group, start: at, wrap: wrapRow } };
|
|
4522
|
+
}
|
|
4523
|
+
return wrapRow(withKey(element, index), at);
|
|
4524
|
+
});
|
|
4525
|
+
}
|
|
4526
|
+
function wrapRow(row, containerIndex) {
|
|
4527
|
+
const inner = row.type === Fragment ? flattenChildren(row) : null;
|
|
4528
|
+
const element = inner?.length === 1 ? { ...inner[0], key: row.key } : row;
|
|
4529
|
+
if (element.type === Section) return element;
|
|
4530
|
+
if (element.type === Row) return { ...element, props: { ...element.props, containerIndex } };
|
|
4531
|
+
const props = element.props;
|
|
4532
|
+
const tag = props.tag !== void 0 ? props.tag : element.type === NavigationLink ? props.value : void 0;
|
|
4533
|
+
if (tag === void 0) return element;
|
|
4534
|
+
return /* @__PURE__ */ jsx(Row, { tag, containerIndex, children: element }, element.key ?? containerIndex);
|
|
4535
|
+
}
|
|
4536
|
+
function withKey(element, index) {
|
|
4537
|
+
return element.key !== null ? element : { ...element, key: String(index) };
|
|
4538
|
+
}
|
|
4539
|
+
function supplement(node) {
|
|
4540
|
+
if (node === void 0 || node === null || node === false) return { text: null, view: null };
|
|
4541
|
+
if (typeof node === "string" || typeof node === "number") return { text: String(node), view: null };
|
|
4542
|
+
if (isValidElement(node) && node.type === Text) {
|
|
4543
|
+
const props = node.props;
|
|
4544
|
+
const only = Object.keys(props).every((key) => key === "children");
|
|
4545
|
+
if (only) return { text: plainText(node), view: null };
|
|
4546
|
+
}
|
|
4547
|
+
return { text: null, view: isValidElement(node) ? node : null };
|
|
4548
|
+
}
|
|
4549
|
+
function TabView(props) {
|
|
4550
|
+
const { own, modifiers } = splitProps(props);
|
|
4551
|
+
const tabs = flattenChildren(own.children);
|
|
4552
|
+
const tags = tabs.map((tab, index) => {
|
|
4553
|
+
const tag = tab.props.tag;
|
|
4554
|
+
return tag !== void 0 ? tag : index;
|
|
4555
|
+
});
|
|
4556
|
+
const [internal, setInternal] = useState(tags[0]);
|
|
4557
|
+
const [selection, setSelection] = own.selection !== void 0 ? readBinding(own.selection, own.onChange) : [internal, setInternal];
|
|
4558
|
+
const selected = Math.max(
|
|
4559
|
+
0,
|
|
4560
|
+
tags.findIndex((tag) => Object.is(tag, selection))
|
|
4561
|
+
);
|
|
4562
|
+
return applyModifiers(
|
|
4563
|
+
sb("tabview", { selected }, { select: (event) => tags[event.value] !== void 0 && setSelection(tags[event.value]) }, tabs),
|
|
4564
|
+
modifiers
|
|
4565
|
+
);
|
|
4566
|
+
}
|
|
4567
|
+
function Tab(props) {
|
|
4568
|
+
const { own, modifiers } = splitProps(props);
|
|
4569
|
+
const badge = takeModifier(modifiers, "badge");
|
|
4570
|
+
const tabProps = { title: own.title, systemImage: own.systemImage ?? null };
|
|
4571
|
+
if (badge !== void 0 && badge !== null) tabProps["badge"] = String(badge);
|
|
4572
|
+
if (own.role) tabProps["role"] = own.role;
|
|
4573
|
+
if (own.image && !own.systemImage) tabProps["image"] = own.image;
|
|
4574
|
+
return applyModifiers(sb("tab", tabProps, void 0, own.children), modifiers);
|
|
4575
|
+
}
|
|
4157
4576
|
function Host(props) {
|
|
4158
4577
|
const { own, modifiers } = splitProps(props);
|
|
4159
4578
|
const key = useId();
|
|
@@ -5579,6 +5998,7 @@ export {
|
|
|
5579
5998
|
SecureField,
|
|
5580
5999
|
Shape,
|
|
5581
6000
|
ShareLink,
|
|
6001
|
+
SignInWithAppleButton,
|
|
5582
6002
|
Slider,
|
|
5583
6003
|
Spacer,
|
|
5584
6004
|
SplitSelectionContext,
|
|
@@ -5605,10 +6025,14 @@ export {
|
|
|
5605
6025
|
ZStack,
|
|
5606
6026
|
answerLayout,
|
|
5607
6027
|
appStorage,
|
|
6028
|
+
appleCredentialState,
|
|
5608
6029
|
canMeasureText,
|
|
6030
|
+
canSignInWithApple,
|
|
5609
6031
|
color,
|
|
6032
|
+
configureSignInWithApple,
|
|
5610
6033
|
createFileManager,
|
|
5611
6034
|
createSwiftUIRoot,
|
|
6035
|
+
exportFile,
|
|
5612
6036
|
fileManager,
|
|
5613
6037
|
flattenChildren,
|
|
5614
6038
|
focusBinding,
|
|
@@ -5636,6 +6060,7 @@ export {
|
|
|
5636
6060
|
rgb,
|
|
5637
6061
|
scrollGeometryOf,
|
|
5638
6062
|
shapeStyle,
|
|
6063
|
+
signInWithApple,
|
|
5639
6064
|
system,
|
|
5640
6065
|
takeScrollSettings,
|
|
5641
6066
|
timeTicks,
|
|
@@ -5648,14 +6073,20 @@ export {
|
|
|
5648
6073
|
useCoordinateSpaces,
|
|
5649
6074
|
useDismiss,
|
|
5650
6075
|
useDynamicTypeSize,
|
|
6076
|
+
useFileStorage,
|
|
6077
|
+
useGeolocation,
|
|
5651
6078
|
useHorizontalSizeClass,
|
|
5652
6079
|
useNamespace,
|
|
5653
6080
|
useNavigation,
|
|
5654
6081
|
useRedacted,
|
|
5655
6082
|
useRefreshable,
|
|
5656
6083
|
useReportSplitSelection,
|
|
6084
|
+
useScenePhase,
|
|
6085
|
+
useSpeechRecognition,
|
|
6086
|
+
useSpeechSynthesis,
|
|
5657
6087
|
useUndoManager,
|
|
5658
6088
|
useViewEnvironment,
|
|
6089
|
+
useWakeLock,
|
|
5659
6090
|
weighted,
|
|
5660
6091
|
withAnimation
|
|
5661
6092
|
};
|