@swiftbrowser/react 0.28.3 → 0.28.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/hostElement.d.ts +20 -0
- package/dist/components/hostElement.d.ts.map +1 -0
- package/dist/components/remoteTree.d.ts +11 -1
- package/dist/components/remoteTree.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1486 -1479
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import Reconciler from "react-reconciler";
|
|
|
4
4
|
import { base64Decode, base64Encode } from "@swiftbrowser/web/src/base64";
|
|
5
5
|
import { addLiveBitmap, forgetLiveBitmap } from "@swiftbrowser/web/src/bitmaps";
|
|
6
6
|
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
7
|
+
import { browserEnvironment, exportFiles, loadableURL, performHostRequest } from "@swiftbrowser/web/src/hostRequests";
|
|
7
8
|
import { horizontalSizeClassFor } from "@swiftbrowser/web/src/protocol";
|
|
8
9
|
import { BrowserHistory } from "@swiftbrowser/web/src/browserHistory";
|
|
9
10
|
import { watchKeyboard } from "@swiftbrowser/web/src/deviceMode";
|
|
10
|
-
import { browserEnvironment, exportFiles, loadableURL, performHostRequest } from "@swiftbrowser/web/src/hostRequests";
|
|
11
11
|
import { Renderer } from "@swiftbrowser/web/src/renderer";
|
|
12
12
|
import { currentScenePhase, watchScenePhase } from "@swiftbrowser/web/src/scenePhase";
|
|
13
13
|
import { applyTypeSizeVariables } from "@swiftbrowser/web/src/typography";
|
|
@@ -995,35 +995,37 @@ function findStack(node) {
|
|
|
995
995
|
return null;
|
|
996
996
|
}
|
|
997
997
|
const screensOf = (stack) => stack ? stack.children.filter((child) => child.kind === "navscreen") : [];
|
|
998
|
-
function renderNode(root, node, stack) {
|
|
998
|
+
function renderNode(root, node, stack, elements) {
|
|
999
999
|
if (node.kind === "host") return null;
|
|
1000
1000
|
if (node === stack) {
|
|
1001
1001
|
const first = screensOf(stack)[0];
|
|
1002
|
-
return createElement(Fragment, { key: node.id }, first ? renderScreen(root, first, stack) : null);
|
|
1002
|
+
return createElement(Fragment, { key: node.id }, first ? renderScreen(root, first, stack, elements) : null);
|
|
1003
1003
|
}
|
|
1004
|
-
const children = node.children.length ? node.children.map((child) => renderNode(root, child, stack)) : void 0;
|
|
1004
|
+
const children = node.children.length ? node.children.map((child) => renderNode(root, child, stack, elements)) : void 0;
|
|
1005
|
+
const own = elements && Object.prototype.hasOwnProperty.call(elements, node.kind) ? elements[node.kind] : void 0;
|
|
1006
|
+
if (own) return createElement(Fragment, { key: node.id }, own(node.props, children));
|
|
1005
1007
|
return createElement(Fragment, { key: node.id }, sb(node.kind, node.props, root.handlersFor(node.id), children));
|
|
1006
1008
|
}
|
|
1007
|
-
function renderSheet(root, node, stack, inherited) {
|
|
1008
|
-
const children = node.children.map((child) => renderNode(root, child, stack));
|
|
1009
|
+
function renderSheet(root, node, stack, inherited, elements) {
|
|
1010
|
+
const children = node.children.map((child) => renderNode(root, child, stack, elements));
|
|
1009
1011
|
return createElement(Fragment, { key: node.id }, sb(node.kind, node.props, root.handlersFor(node.id), replayStyles(inherited, children)));
|
|
1010
1012
|
}
|
|
1011
|
-
function renderScreen(root, screen, stack) {
|
|
1013
|
+
function renderScreen(root, screen, stack, elements) {
|
|
1012
1014
|
const out = [screenPrefs(screen.props, "$screen")];
|
|
1013
1015
|
for (const child of screen.children) {
|
|
1014
|
-
const drawn = renderNode(root, child, stack);
|
|
1016
|
+
const drawn = renderNode(root, child, stack, elements);
|
|
1015
1017
|
if (child.kind === "toolbar" || child.kind === "searchfield") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "navscreen")));
|
|
1016
1018
|
else out.push(drawn);
|
|
1017
1019
|
}
|
|
1018
1020
|
return createElement(Fragment, null, ...out);
|
|
1019
1021
|
}
|
|
1020
|
-
function RemoteScreen({ root, id }) {
|
|
1022
|
+
function RemoteScreen({ root, id, elements }) {
|
|
1021
1023
|
useSyncExternalStore(root.subscribe, root.getVersion, root.getVersion);
|
|
1022
1024
|
const screen = root.node(id);
|
|
1023
1025
|
if (!screen?.parent) return null;
|
|
1024
|
-
return renderScreen(root, screen, findStack(root.root));
|
|
1026
|
+
return renderScreen(root, screen, findStack(root.root), elements);
|
|
1025
1027
|
}
|
|
1026
|
-
function RemoteTree({ root, initialPath }) {
|
|
1028
|
+
function RemoteTree({ root, initialPath, elements }) {
|
|
1027
1029
|
useSyncExternalStore(root.subscribe, root.getVersion, root.getVersion);
|
|
1028
1030
|
const environment = useContext(EnvironmentContext);
|
|
1029
1031
|
const inherited = useInheritedStyles();
|
|
@@ -1047,7 +1049,7 @@ function RemoteTree({ root, initialPath }) {
|
|
|
1047
1049
|
const key = keyOf2(screen);
|
|
1048
1050
|
let value = values.current.get(key);
|
|
1049
1051
|
if (!value) {
|
|
1050
|
-
value = "route" in screen.props ? { view: /* @__PURE__ */ jsx(RemoteScreen, { root, id: screen.id }), route: screen.props["route"] } : { view: /* @__PURE__ */ jsx(RemoteScreen, { root, id: screen.id }) };
|
|
1052
|
+
value = "route" in screen.props ? { view: /* @__PURE__ */ jsx(RemoteScreen, { root, id: screen.id, elements }), route: screen.props["route"] } : { view: /* @__PURE__ */ jsx(RemoteScreen, { root, id: screen.id, elements }) };
|
|
1051
1053
|
values.current.set(key, value);
|
|
1052
1054
|
ours.current.add(value);
|
|
1053
1055
|
}
|
|
@@ -1082,13 +1084,192 @@ function RemoteTree({ root, initialPath }) {
|
|
|
1082
1084
|
if ("colorScheme" in root.rootProps)
|
|
1083
1085
|
out.push(createElement(Fragment, { key: "$scheme" }, sb(PREF_KIND, { colorScheme: root.rootProps["colorScheme"] }, void 0, void 0, "root")));
|
|
1084
1086
|
for (const child of root.root.children) {
|
|
1085
|
-
const drawn = child.kind === "sheet" && inherited.length > 0 ? renderSheet(root, child, stack, inherited) : renderNode(root, child, stack);
|
|
1087
|
+
const drawn = child.kind === "sheet" && inherited.length > 0 ? renderSheet(root, child, stack, inherited, elements) : renderNode(root, child, stack, elements);
|
|
1086
1088
|
if (child.kind === "sheet" || child.kind === "alert") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "root")));
|
|
1087
1089
|
else if (child.kind === "toolbar" || child.kind === "searchfield") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "navscreen")));
|
|
1088
1090
|
else out.push(drawn);
|
|
1089
1091
|
}
|
|
1090
1092
|
return createElement(Fragment, null, ...out);
|
|
1091
1093
|
}
|
|
1094
|
+
function readBinding(value, onChange) {
|
|
1095
|
+
if (Array.isArray(value) && value.length === 2 && typeof value[1] === "function") {
|
|
1096
|
+
const [current, set] = value;
|
|
1097
|
+
return [current, set];
|
|
1098
|
+
}
|
|
1099
|
+
return [value, onChange ?? (() => {
|
|
1100
|
+
})];
|
|
1101
|
+
}
|
|
1102
|
+
let active = null;
|
|
1103
|
+
function Draggable({ payload, children }) {
|
|
1104
|
+
return sb(
|
|
1105
|
+
"draggable",
|
|
1106
|
+
{},
|
|
1107
|
+
{
|
|
1108
|
+
dragstart: (event) => {
|
|
1109
|
+
active = { id: event.id, payload };
|
|
1110
|
+
},
|
|
1111
|
+
dragend: (event) => {
|
|
1112
|
+
if (active?.id === event.id) active = null;
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
children
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
function itemValue(item) {
|
|
1119
|
+
if (item.text !== void 0) {
|
|
1120
|
+
if (item.type === "text/uri-list") {
|
|
1121
|
+
try {
|
|
1122
|
+
return new URL(item.text.split(/\r?\n/)[0].trim());
|
|
1123
|
+
} catch {
|
|
1124
|
+
return item.text;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
return item.text;
|
|
1128
|
+
}
|
|
1129
|
+
const name = item.path ?? item.name ?? "file";
|
|
1130
|
+
if (item.file) {
|
|
1131
|
+
const file = item.file;
|
|
1132
|
+
return item.path !== void 0 && item.path !== file.name ? new File([file], item.path, { type: file.type, lastModified: file.lastModified }) : file;
|
|
1133
|
+
}
|
|
1134
|
+
if (item.url !== void 0 && item.data === void 0) {
|
|
1135
|
+
const fromReference = browserEnvironment.fileFromReference;
|
|
1136
|
+
if (fromReference) {
|
|
1137
|
+
return fromReference({ type: item.type, name, url: item.url, ...item.path !== void 0 ? { path: item.path } : {}, ...item.size !== void 0 ? { size: item.size } : {} });
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
const binary = atob(item.data ?? "");
|
|
1141
|
+
const bytes = new Uint8Array(binary.length);
|
|
1142
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1143
|
+
return typeof File !== "undefined" ? new File([bytes], name, { type: item.type }) : bytes;
|
|
1144
|
+
}
|
|
1145
|
+
function DropDestination({ action, isTargeted, accepts, children }) {
|
|
1146
|
+
return sb(
|
|
1147
|
+
"dropdestination",
|
|
1148
|
+
{ accepts: accepts ?? [] },
|
|
1149
|
+
{
|
|
1150
|
+
drop: (event) => {
|
|
1151
|
+
if (event.phase === "entered") {
|
|
1152
|
+
isTargeted?.(true);
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
isTargeted?.(false);
|
|
1156
|
+
if (event.phase !== "performed") return;
|
|
1157
|
+
let items;
|
|
1158
|
+
if (event.source !== void 0) items = active && active.id === event.source ? [active.payload] : [];
|
|
1159
|
+
else items = (event.items ?? []).map(itemValue);
|
|
1160
|
+
if (items.length > 0) action(items, { x: event.x, y: event.y });
|
|
1161
|
+
}
|
|
1162
|
+
},
|
|
1163
|
+
children
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
function FileImporterPresenter(spec) {
|
|
1167
|
+
const [presented, setPresented] = readBinding(spec.isPresented);
|
|
1168
|
+
const latest = useRef(spec);
|
|
1169
|
+
latest.current = spec;
|
|
1170
|
+
const choosing = useRef(false);
|
|
1171
|
+
useLayoutEffect(() => {
|
|
1172
|
+
if (!presented || choosing.current) return;
|
|
1173
|
+
const { allowedContentTypes, allowsMultipleSelection } = latest.current;
|
|
1174
|
+
const pick = browserEnvironment.pickFiles;
|
|
1175
|
+
if (!pick) {
|
|
1176
|
+
setPresented(false);
|
|
1177
|
+
latest.current.onCancellation?.();
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
choosing.current = true;
|
|
1181
|
+
void pick({ accept: allowedContentTypes.join(","), multiple: allowsMultipleSelection === true }).then((files) => {
|
|
1182
|
+
choosing.current = false;
|
|
1183
|
+
setPresented(false);
|
|
1184
|
+
if (files.length > 0) latest.current.onCompletion(files);
|
|
1185
|
+
else latest.current.onCancellation?.();
|
|
1186
|
+
});
|
|
1187
|
+
}, [presented, setPresented]);
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
const EXTENSIONS = {
|
|
1191
|
+
"text/plain": "txt",
|
|
1192
|
+
"text/csv": "csv",
|
|
1193
|
+
"text/markdown": "md",
|
|
1194
|
+
"text/html": "html",
|
|
1195
|
+
"application/json": "json",
|
|
1196
|
+
"application/pdf": "pdf",
|
|
1197
|
+
"image/png": "png",
|
|
1198
|
+
"image/jpeg": "jpg",
|
|
1199
|
+
"image/svg+xml": "svg",
|
|
1200
|
+
"audio/mp4": "m4a",
|
|
1201
|
+
"video/mp4": "mp4"
|
|
1202
|
+
};
|
|
1203
|
+
function exportFile(document2, contentType, defaultFilename, index = 0) {
|
|
1204
|
+
const type = document2 instanceof Blob && document2.type || contentType || "application/octet-stream";
|
|
1205
|
+
let name = defaultFilename ?? (document2 instanceof File ? document2.name : index === 0 ? "Untitled" : `Untitled ${index + 1}`);
|
|
1206
|
+
name = name.replace(/[\\/:*?"<>|]+/g, "-").trim() || "Untitled";
|
|
1207
|
+
const extension = EXTENSIONS[type.split(";")[0].trim()];
|
|
1208
|
+
if (extension && !/\.[A-Za-z0-9]{1,8}$/.test(name)) name = `${name}.${extension}`;
|
|
1209
|
+
if (document2 instanceof File && document2.name === name && document2.type === type) return document2;
|
|
1210
|
+
const bytes = typeof document2 === "string" ? new TextEncoder().encode(document2) : document2;
|
|
1211
|
+
return new File([bytes], name, { type });
|
|
1212
|
+
}
|
|
1213
|
+
function FileExporterPresenter(spec) {
|
|
1214
|
+
const [presented, setPresented] = readBinding(spec.isPresented);
|
|
1215
|
+
const latest = useRef(spec);
|
|
1216
|
+
latest.current = spec;
|
|
1217
|
+
const exporting = useRef(false);
|
|
1218
|
+
useLayoutEffect(() => {
|
|
1219
|
+
if (!presented || exporting.current) return;
|
|
1220
|
+
const { document: document2, contentType, defaultFilename } = latest.current;
|
|
1221
|
+
const documents = document2 === null ? [] : Array.isArray(document2) ? document2 : [document2];
|
|
1222
|
+
if (documents.length === 0) {
|
|
1223
|
+
setPresented(false);
|
|
1224
|
+
latest.current.onCancellation?.();
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
exporting.current = true;
|
|
1228
|
+
const files = documents.map((item, index) => exportFile(item, contentType, defaultFilename, index));
|
|
1229
|
+
exportFiles(files).then(
|
|
1230
|
+
(result) => {
|
|
1231
|
+
exporting.current = false;
|
|
1232
|
+
setPresented(false);
|
|
1233
|
+
if (result.outcome === "cancelled") latest.current.onCancellation?.();
|
|
1234
|
+
else latest.current.onCompletion?.(result);
|
|
1235
|
+
},
|
|
1236
|
+
(error) => {
|
|
1237
|
+
exporting.current = false;
|
|
1238
|
+
setPresented(false);
|
|
1239
|
+
latest.current.onError?.(error);
|
|
1240
|
+
}
|
|
1241
|
+
);
|
|
1242
|
+
}, [presented, setPresented]);
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
const ListSelectionContext = createContext(null);
|
|
1246
|
+
function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
|
|
1247
|
+
const selection = useContext(ListSelectionContext);
|
|
1248
|
+
const selectable = selection !== null && tag !== void 0;
|
|
1249
|
+
const canDelete = onDelete !== void 0 && deletable !== false;
|
|
1250
|
+
const canMove = onMove !== void 0 && movable !== false;
|
|
1251
|
+
if (!selectable && !canDelete && !canMove) return children;
|
|
1252
|
+
const props = {};
|
|
1253
|
+
if (selectable) {
|
|
1254
|
+
props["selectable"] = true;
|
|
1255
|
+
props["selected"] = selection.isSelected(tag);
|
|
1256
|
+
}
|
|
1257
|
+
if (canDelete) props["deletable"] = true;
|
|
1258
|
+
if (canMove) props["movable"] = true;
|
|
1259
|
+
return sb(
|
|
1260
|
+
"listrow",
|
|
1261
|
+
props,
|
|
1262
|
+
{
|
|
1263
|
+
tap: () => selectable && selection.select(tag),
|
|
1264
|
+
delete: () => onDelete?.(),
|
|
1265
|
+
move: (event) => {
|
|
1266
|
+
const start = (containerIndex ?? index ?? 0) - (index ?? 0);
|
|
1267
|
+
onMove?.(Math.max(0, event.to - start));
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
children
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1092
1273
|
const HIERARCHY = { primary: 1, secondary: 2, tertiary: 3, quaternary: 4 };
|
|
1093
1274
|
function rgb(r2, g, b, a = 1) {
|
|
1094
1275
|
return { r: r2, g, b, a };
|
|
@@ -1235,661 +1416,68 @@ function insets(edges, amount) {
|
|
|
1235
1416
|
}
|
|
1236
1417
|
return result;
|
|
1237
1418
|
}
|
|
1238
|
-
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1241
|
-
if (installed === measurer) installed = null;
|
|
1242
|
-
return;
|
|
1243
|
-
}
|
|
1244
|
-
installed = measurer;
|
|
1419
|
+
const isPoint = (value) => typeof value === "object" && value !== null && ("x" in value || "y" in value);
|
|
1420
|
+
function command(request) {
|
|
1421
|
+
return request.axes ? { anchor: request.anchor, serial: request.serial, axes: request.axes } : { anchor: request.anchor, serial: request.serial };
|
|
1245
1422
|
}
|
|
1246
|
-
function
|
|
1247
|
-
|
|
1423
|
+
function offsetCommand(request) {
|
|
1424
|
+
const out = { serial: request.serial };
|
|
1425
|
+
if (typeof request.point.x === "number") out.x = request.point.x;
|
|
1426
|
+
if (typeof request.point.y === "number") out.y = request.point.y;
|
|
1427
|
+
return out;
|
|
1248
1428
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1429
|
+
const ScrollRequestContext = createContext(null);
|
|
1430
|
+
let nextSerial = 1;
|
|
1431
|
+
function ScrollViewReader({ children }) {
|
|
1432
|
+
const [request, setRequest] = useState(null);
|
|
1433
|
+
const proxy = {
|
|
1434
|
+
scrollTo: (target, anchor, options) => {
|
|
1435
|
+
if (isPoint(target)) setRequest({ point: target, serial: nextSerial++ });
|
|
1436
|
+
else setRequest({ id: target, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++, ...options?.axes ? { axes: options.axes } : {} });
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
|
|
1253
1440
|
}
|
|
1254
|
-
function
|
|
1255
|
-
|
|
1441
|
+
function ScrollTarget({ id, children }) {
|
|
1442
|
+
const request = useContext(ScrollRequestContext);
|
|
1443
|
+
const position = useContext(ScrollPositionContext);
|
|
1444
|
+
const on = position ? { scrollposition: () => position.report(id) } : void 0;
|
|
1445
|
+
if (request && "id" in request && request.id === id) return sb("styled", { style: { scrollID: true, scrollTo: command(request) } }, on, children);
|
|
1446
|
+
if (on) return sb("styled", { style: { scrollID: true } }, on, children);
|
|
1447
|
+
return styled({ scrollID: true }, children);
|
|
1256
1448
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
const device = screen.closest(".device");
|
|
1290
|
-
if (device) device.dataset["theme"] = scheme;
|
|
1291
|
-
renderer?.setEnvironment({ colorScheme: scheme });
|
|
1292
|
-
root.setEnvironment({ colorScheme: scheme });
|
|
1293
|
-
};
|
|
1294
|
-
const onPreferredScheme = (event) => {
|
|
1295
|
-
const scheme = event.detail.colorScheme;
|
|
1296
|
-
preferred = scheme;
|
|
1297
|
-
queueMicrotask(applyScheme);
|
|
1298
|
-
};
|
|
1299
|
-
screen.addEventListener("sb:color-scheme", onPreferredScheme);
|
|
1300
|
-
let sizeClass = environment.horizontalSizeClass;
|
|
1301
|
-
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
1302
|
-
const next = horizontalSizeClassFor(screen.clientWidth);
|
|
1303
|
-
if (next === sizeClass) return;
|
|
1304
|
-
sizeClass = next;
|
|
1305
|
-
root.setEnvironment({ horizontalSizeClass: next });
|
|
1306
|
-
}) : null;
|
|
1307
|
-
observer?.observe(screen);
|
|
1308
|
-
const stopScenePhase = typeof document !== "undefined" ? watchScenePhase((scenePhase) => root.setEnvironment({ scenePhase })) : null;
|
|
1309
|
-
root.render(element);
|
|
1310
|
-
const mounted = {
|
|
1311
|
-
root,
|
|
1312
|
-
renderer,
|
|
1313
|
-
setEnvironment(next) {
|
|
1314
|
-
if (next.colorScheme !== void 0) pageScheme = next.colorScheme;
|
|
1315
|
-
const scheme = preferred ?? pageScheme;
|
|
1316
|
-
renderer?.setEnvironment({ ...next, colorScheme: scheme });
|
|
1317
|
-
root.setEnvironment({ ...next, colorScheme: scheme });
|
|
1318
|
-
},
|
|
1319
|
-
setSafeArea(insets2) {
|
|
1320
|
-
renderer?.setSafeArea(insets2);
|
|
1321
|
-
},
|
|
1322
|
-
viewportChanged() {
|
|
1323
|
-
renderer?.viewportChanged();
|
|
1324
|
-
},
|
|
1325
|
-
unmount() {
|
|
1326
|
-
observer?.disconnect();
|
|
1327
|
-
stopScenePhase?.();
|
|
1328
|
-
stopKeyboard?.();
|
|
1329
|
-
browserHistory?.dispose();
|
|
1330
|
-
screen.removeEventListener("sb:color-scheme", onPreferredScheme);
|
|
1331
|
-
installTextMeasurer(measurer, true);
|
|
1332
|
-
root.unmount();
|
|
1333
|
-
renderer?.dispose();
|
|
1334
|
-
}
|
|
1335
|
-
};
|
|
1336
|
-
return mounted;
|
|
1337
|
-
}
|
|
1338
|
-
const EMPTY = { canUndo: false, canRedo: false, undoActionName: "", redoActionName: "" };
|
|
1339
|
-
const defaultSchedule = (close) => {
|
|
1340
|
-
if (typeof queueMicrotask === "function") queueMicrotask(close);
|
|
1341
|
-
else void Promise.resolve().then(close);
|
|
1342
|
-
};
|
|
1343
|
-
class UndoManager {
|
|
1344
|
-
/** Whether registrations in one event (one task of the event loop) form one group; true, as `groupsByEvent`. */
|
|
1345
|
-
groupsByEvent = true;
|
|
1346
|
-
/** How many groups the undo stack keeps; 0 for no limit, as `levelsOfUndo`. */
|
|
1347
|
-
levelsOfUndo = 0;
|
|
1348
|
-
undoStack = [];
|
|
1349
|
-
redoStack = [];
|
|
1350
|
-
/** The group registrations go in: an explicit group, the event's group, or the inverse of what is being undone or redone. */
|
|
1351
|
-
open = null;
|
|
1352
|
-
/** How deep `beginGrouping` is; 0 when `open` is the event's group or an inverse. */
|
|
1353
|
-
depth = 0;
|
|
1354
|
-
/** Whether `open` is the event's group, which `schedule` closes. */
|
|
1355
|
-
byEvent = false;
|
|
1356
|
-
/** The last keyed group closed onto the undo stack, which a registration with its key joins. */
|
|
1357
|
-
coalescing = null;
|
|
1358
|
-
undoing = false;
|
|
1359
|
-
redoing = false;
|
|
1360
|
-
snapshot = EMPTY;
|
|
1361
|
-
listeners = /* @__PURE__ */ new Set();
|
|
1362
|
-
schedule;
|
|
1363
|
-
host;
|
|
1364
|
-
stopListening = null;
|
|
1365
|
-
constructor(options = {}) {
|
|
1366
|
-
this.schedule = options.schedule ?? defaultSchedule;
|
|
1367
|
-
this.host = options.host === void 0 ? browserEnvironment.undoManager ?? null : options.host;
|
|
1368
|
-
if (this.host) {
|
|
1369
|
-
this.stopListening = this.host.listen({ undo: () => this.undo(), redo: () => this.redo() });
|
|
1370
|
-
this.host.update(this.snapshot);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
get canUndo() {
|
|
1374
|
-
return this.undoStack.length > 0;
|
|
1375
|
-
}
|
|
1376
|
-
get canRedo() {
|
|
1377
|
-
return this.redoStack.length > 0;
|
|
1378
|
-
}
|
|
1379
|
-
/** The name of what `undo` takes back ('' for none): "Move" for an Edit menu's "Undo Move". */
|
|
1380
|
-
get undoActionName() {
|
|
1381
|
-
return this.undoStack[this.undoStack.length - 1]?.name ?? "";
|
|
1382
|
-
}
|
|
1383
|
-
get redoActionName() {
|
|
1384
|
-
return this.redoStack[this.redoStack.length - 1]?.name ?? "";
|
|
1385
|
-
}
|
|
1386
|
-
get isUndoing() {
|
|
1387
|
-
return this.undoing;
|
|
1388
|
-
}
|
|
1389
|
-
get isRedoing() {
|
|
1390
|
-
return this.redoing;
|
|
1391
|
-
}
|
|
1392
|
-
/** What the stacks can do, one object per change (for `useSyncExternalStore`). */
|
|
1393
|
-
get state() {
|
|
1394
|
-
return this.snapshot;
|
|
1395
|
-
}
|
|
1396
|
-
/**
|
|
1397
|
-
* Registers what undoes the change just made, under `name`. Run by `undo`,
|
|
1398
|
-
* the closure registers its own inverse the same way, which lands on the
|
|
1399
|
-
* redo stack because the manager is undoing.
|
|
1400
|
-
*/
|
|
1401
|
-
registerUndo(name, undo, options = {}) {
|
|
1402
|
-
const action = { name, undo, target: options.target };
|
|
1403
|
-
if (this.undoing || this.redoing) {
|
|
1404
|
-
this.open.actions.push(action);
|
|
1405
|
-
this.changed();
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
this.redoStack = [];
|
|
1409
|
-
this.coalescing = this.coalescing && this.undoStack[this.undoStack.length - 1] === this.coalescing ? this.coalescing : null;
|
|
1410
|
-
if (this.open) {
|
|
1411
|
-
if (!this.undoStack.includes(this.open)) this.push(this.open);
|
|
1412
|
-
this.open.actions.push(action);
|
|
1413
|
-
if (!this.open.named) this.open.name = name;
|
|
1414
|
-
} else if (this.coalescing && options.key !== void 0 && this.coalescing.key === options.key) {
|
|
1415
|
-
this.coalescing.actions.push(action);
|
|
1416
|
-
this.coalescing.name = name;
|
|
1417
|
-
} else {
|
|
1418
|
-
const group = { name, named: false, actions: [action], key: options.key };
|
|
1419
|
-
this.push(group);
|
|
1420
|
-
this.coalescing = null;
|
|
1421
|
-
if (this.groupsByEvent) {
|
|
1422
|
-
this.open = group;
|
|
1423
|
-
this.byEvent = true;
|
|
1424
|
-
this.schedule(() => {
|
|
1425
|
-
if (this.open === group && this.byEvent) this.close();
|
|
1426
|
-
});
|
|
1427
|
-
} else {
|
|
1428
|
-
this.coalescing = group.key !== void 0 ? group : null;
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
this.changed();
|
|
1432
|
-
}
|
|
1433
|
-
/** Takes back the top group of changes; its inverses become the top of the redo stack. */
|
|
1434
|
-
undo() {
|
|
1435
|
-
this.endOpenGroups();
|
|
1436
|
-
const group = this.undoStack.pop();
|
|
1437
|
-
if (!group) return;
|
|
1438
|
-
this.coalescing = null;
|
|
1439
|
-
this.run(group, "undo");
|
|
1440
|
-
}
|
|
1441
|
-
redo() {
|
|
1442
|
-
this.endOpenGroups();
|
|
1443
|
-
const group = this.redoStack.pop();
|
|
1444
|
-
if (!group) return;
|
|
1445
|
-
this.run(group, "redo");
|
|
1446
|
-
}
|
|
1447
|
-
/**
|
|
1448
|
-
* Starts a group: every registration until `endGrouping` undoes as one
|
|
1449
|
-
* (`beginUndoGrouping`). Nested calls join the outer group. The group is
|
|
1450
|
-
* named `name`, else after its last registration.
|
|
1451
|
-
*/
|
|
1452
|
-
beginGrouping(name) {
|
|
1453
|
-
if (this.undoing || this.redoing) return;
|
|
1454
|
-
this.depth += 1;
|
|
1455
|
-
if (this.depth > 1) return;
|
|
1456
|
-
if (this.open) this.close();
|
|
1457
|
-
this.open = { name: name ?? "", named: name !== void 0, actions: [], key: void 0 };
|
|
1458
|
-
this.byEvent = false;
|
|
1459
|
-
this.coalescing = null;
|
|
1460
|
-
}
|
|
1461
|
-
/** Ends the group `beginGrouping` started; one that registered nothing is dropped. */
|
|
1462
|
-
endGrouping() {
|
|
1463
|
-
if (this.depth === 0) return;
|
|
1464
|
-
this.depth -= 1;
|
|
1465
|
-
if (this.depth === 0) this.close();
|
|
1466
|
-
}
|
|
1467
|
-
/** `body` as one group named `name`. */
|
|
1468
|
-
group(name, body) {
|
|
1469
|
-
this.beginGrouping(name);
|
|
1470
|
-
try {
|
|
1471
|
-
return body();
|
|
1472
|
-
} finally {
|
|
1473
|
-
this.endGrouping();
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
/** Forgets every registration, or those `target` made (`removeAllActions(withTarget:)`), on both stacks and in the open group. */
|
|
1477
|
-
removeAllActions(target) {
|
|
1478
|
-
const mine = (action) => target === void 0 || action.target === target;
|
|
1479
|
-
const strip = (groups) => groups.filter((group) => {
|
|
1480
|
-
group.actions = group.actions.filter((action) => !mine(action));
|
|
1481
|
-
return group.actions.length > 0;
|
|
1482
|
-
});
|
|
1483
|
-
this.undoStack = strip(this.undoStack);
|
|
1484
|
-
this.redoStack = strip(this.redoStack);
|
|
1485
|
-
if (this.open) this.open.actions = this.open.actions.filter((action) => !mine(action));
|
|
1486
|
-
if (this.coalescing && !this.undoStack.includes(this.coalescing)) this.coalescing = null;
|
|
1487
|
-
this.changed();
|
|
1488
|
-
}
|
|
1489
|
-
/** Calls `listener` after each change to `state`; returns what stops it. */
|
|
1490
|
-
subscribe = (listener) => {
|
|
1491
|
-
this.listeners.add(listener);
|
|
1492
|
-
return () => {
|
|
1493
|
-
this.listeners.delete(listener);
|
|
1494
|
-
};
|
|
1495
|
-
};
|
|
1496
|
-
/** Stops listening to the host, for a manager made in a test. */
|
|
1497
|
-
dispose() {
|
|
1498
|
-
this.stopListening?.();
|
|
1499
|
-
this.stopListening = null;
|
|
1500
|
-
}
|
|
1501
|
-
push(group) {
|
|
1502
|
-
this.undoStack.push(group);
|
|
1503
|
-
if (this.levelsOfUndo > 0 && this.undoStack.length > this.levelsOfUndo) this.undoStack.splice(0, this.undoStack.length - this.levelsOfUndo);
|
|
1504
|
-
}
|
|
1505
|
-
/** Closes `open`; a keyed group on top stays open to its key. */
|
|
1506
|
-
close() {
|
|
1507
|
-
const group = this.open;
|
|
1508
|
-
this.open = null;
|
|
1509
|
-
this.byEvent = false;
|
|
1510
|
-
if (group && group.key !== void 0 && this.undoStack[this.undoStack.length - 1] === group) this.coalescing = group;
|
|
1511
|
-
}
|
|
1512
|
-
endOpenGroups() {
|
|
1513
|
-
this.depth = 0;
|
|
1514
|
-
if (this.open) this.close();
|
|
1515
|
-
}
|
|
1516
|
-
run(group, direction) {
|
|
1517
|
-
const inverse = { name: group.name, named: true, actions: [], key: void 0 };
|
|
1518
|
-
this.open = inverse;
|
|
1519
|
-
this.byEvent = false;
|
|
1520
|
-
if (direction === "undo") this.undoing = true;
|
|
1521
|
-
else this.redoing = true;
|
|
1522
|
-
try {
|
|
1523
|
-
for (let i = group.actions.length - 1; i >= 0; i -= 1) group.actions[i].undo();
|
|
1524
|
-
} finally {
|
|
1525
|
-
this.undoing = false;
|
|
1526
|
-
this.redoing = false;
|
|
1527
|
-
this.open = null;
|
|
1528
|
-
if (inverse.actions.length > 0) {
|
|
1529
|
-
if (direction === "undo") this.redoStack.push(inverse);
|
|
1530
|
-
else this.push(inverse);
|
|
1531
|
-
}
|
|
1532
|
-
this.changed();
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
changed() {
|
|
1536
|
-
const next = { canUndo: this.canUndo, canRedo: this.canRedo, undoActionName: this.undoActionName, redoActionName: this.redoActionName };
|
|
1537
|
-
const last = this.snapshot;
|
|
1538
|
-
if (next.canUndo === last.canUndo && next.canRedo === last.canRedo && next.undoActionName === last.undoActionName && next.redoActionName === last.redoActionName) return;
|
|
1539
|
-
this.snapshot = next;
|
|
1540
|
-
this.host?.update(next);
|
|
1541
|
-
for (const listener of [...this.listeners]) listener();
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
const UndoManagerContext = createContext(null);
|
|
1545
|
-
let shared = null;
|
|
1546
|
-
function sharedUndoManager() {
|
|
1547
|
-
shared ??= new UndoManager();
|
|
1548
|
-
return shared;
|
|
1549
|
-
}
|
|
1550
|
-
function useUndoManager() {
|
|
1551
|
-
const manager = useContext(UndoManagerContext) ?? sharedUndoManager();
|
|
1552
|
-
useSyncExternalStore(
|
|
1553
|
-
manager.subscribe,
|
|
1554
|
-
() => manager.state,
|
|
1555
|
-
() => manager.state
|
|
1556
|
-
);
|
|
1557
|
-
return manager;
|
|
1558
|
-
}
|
|
1559
|
-
const OWN = [
|
|
1560
|
-
EnvironmentContext,
|
|
1561
|
-
ViewEnvironmentContext,
|
|
1562
|
-
NavigationContext,
|
|
1563
|
-
DismissContext,
|
|
1564
|
-
UndoManagerContext
|
|
1565
|
-
];
|
|
1566
|
-
function useContextBridge(contexts = [], options = {}) {
|
|
1567
|
-
const own = options.environment === false ? OWN.filter((context) => context !== EnvironmentContext) : OWN;
|
|
1568
|
-
const all = [...own, ...contexts];
|
|
1569
|
-
const values = all.map((context) => useContext(context));
|
|
1570
|
-
return (children) => all.reduceRight((inner, context, index) => createElement(context.Provider, { value: values[index] }, inner), children);
|
|
1571
|
-
}
|
|
1572
|
-
const WINDOW_TOP_INSET = 10;
|
|
1573
|
-
function insetsOf(safeArea, fit) {
|
|
1574
|
-
const given = typeof safeArea === "number" ? { top: safeArea } : safeArea ?? { top: fit === "fill" ? WINDOW_TOP_INSET : 0 };
|
|
1575
|
-
return { top: given.top ?? 0, leading: given.leading ?? 0, bottom: given.bottom ?? 0, trailing: given.trailing ?? 0 };
|
|
1576
|
-
}
|
|
1577
|
-
function SwiftUIView({
|
|
1578
|
-
children,
|
|
1579
|
-
fit = "fill",
|
|
1580
|
-
colorScheme = "light",
|
|
1581
|
-
dynamicTypeSize = "large",
|
|
1582
|
-
contexts,
|
|
1583
|
-
assets,
|
|
1584
|
-
safeArea,
|
|
1585
|
-
history = true,
|
|
1586
|
-
keyboard = fit === "fill",
|
|
1587
|
-
sidebarTitleBar = true,
|
|
1588
|
-
className,
|
|
1589
|
-
style
|
|
1590
|
-
}) {
|
|
1591
|
-
const device = useRef(null);
|
|
1592
|
-
const screen = useRef(null);
|
|
1593
|
-
const mounted = useRef(null);
|
|
1594
|
-
const bridge = useContextBridge(contexts, { environment: false });
|
|
1595
|
-
const tree = bridge(children);
|
|
1596
|
-
const latest = useRef(tree);
|
|
1597
|
-
latest.current = tree;
|
|
1598
|
-
useLayoutEffect(() => {
|
|
1599
|
-
if (!screen.current) return;
|
|
1600
|
-
const instance = mount(screen.current, latest.current, {
|
|
1601
|
-
colorScheme,
|
|
1602
|
-
dynamicTypeSize,
|
|
1603
|
-
safeArea: insetsOf(safeArea, fit),
|
|
1604
|
-
contentHeight: fit === "content",
|
|
1605
|
-
history,
|
|
1606
|
-
keyboard,
|
|
1607
|
-
...assets ? { assets } : {}
|
|
1608
|
-
});
|
|
1609
|
-
mounted.current = instance;
|
|
1610
|
-
return () => {
|
|
1611
|
-
mounted.current = null;
|
|
1612
|
-
instance.unmount();
|
|
1613
|
-
};
|
|
1614
|
-
}, [fit, history, keyboard]);
|
|
1615
|
-
useLayoutEffect(() => {
|
|
1616
|
-
if (mounted.current) mounted.current.renderer.sidebarTitleBar = sidebarTitleBar;
|
|
1617
|
-
}, [sidebarTitleBar, fit, history, keyboard]);
|
|
1618
|
-
useLayoutEffect(() => {
|
|
1619
|
-
mounted.current?.root.render(tree);
|
|
1620
|
-
});
|
|
1621
|
-
const insets2 = insetsOf(safeArea, fit);
|
|
1622
|
-
const insetsKey = `${insets2.top},${insets2.leading},${insets2.bottom},${insets2.trailing}`;
|
|
1623
|
-
useLayoutEffect(() => {
|
|
1624
|
-
mounted.current?.renderer.setSafeArea(insets2);
|
|
1625
|
-
}, [insetsKey]);
|
|
1626
|
-
useLayoutEffect(() => {
|
|
1627
|
-
if (device.current) applyTypeSizeVariables(device.current, dynamicTypeSize, mounted.current?.renderer.platform);
|
|
1628
|
-
mounted.current?.setEnvironment({ colorScheme, dynamicTypeSize });
|
|
1629
|
-
}, [colorScheme, dynamicTypeSize]);
|
|
1630
|
-
const classes = ["device", "sb-island", className].filter(Boolean).join(" ");
|
|
1631
|
-
return /* @__PURE__ */ jsx("div", { ref: device, className: classes, "data-theme": colorScheme, "data-type-size": dynamicTypeSize, "data-state": "ready", "data-sb-fit": fit, style, children: /* @__PURE__ */ jsx("div", { className: "device-screen", children: /* @__PURE__ */ jsx("div", { ref: screen, className: "screen" }) }) });
|
|
1632
|
-
}
|
|
1633
|
-
function readBinding(value, onChange) {
|
|
1634
|
-
if (Array.isArray(value) && value.length === 2 && typeof value[1] === "function") {
|
|
1635
|
-
const [current, set] = value;
|
|
1636
|
-
return [current, set];
|
|
1637
|
-
}
|
|
1638
|
-
return [value, onChange ?? (() => {
|
|
1639
|
-
})];
|
|
1640
|
-
}
|
|
1641
|
-
const CoordinateSpacesContext = createContext({});
|
|
1642
|
-
function useCoordinateSpaces() {
|
|
1643
|
-
return useContext(CoordinateSpacesContext);
|
|
1644
|
-
}
|
|
1645
|
-
function CoordinateSpace({ name, children }) {
|
|
1646
|
-
const spaces = useContext(CoordinateSpacesContext);
|
|
1647
|
-
const [frame2, setFrame] = useState(null);
|
|
1648
|
-
return /* @__PURE__ */ jsx(CoordinateSpacesContext.Provider, { value: { ...spaces, [name]: frame2 }, children: sb(
|
|
1649
|
-
"zstack",
|
|
1650
|
-
{ alignment: "center", reportsSize: true, reportsFrame: true },
|
|
1651
|
-
{
|
|
1652
|
-
geometry: (event) => {
|
|
1653
|
-
const next = { x: event.x ?? 0, y: event.y ?? 0, width: event.width, height: event.height };
|
|
1654
|
-
if (!frame2 || frame2.x !== next.x || frame2.y !== next.y || frame2.width !== next.width || frame2.height !== next.height) setFrame(next);
|
|
1655
|
-
}
|
|
1656
|
-
},
|
|
1657
|
-
children
|
|
1658
|
-
) });
|
|
1659
|
-
}
|
|
1660
|
-
let active = null;
|
|
1661
|
-
function Draggable({ payload, children }) {
|
|
1662
|
-
return sb(
|
|
1663
|
-
"draggable",
|
|
1664
|
-
{},
|
|
1665
|
-
{
|
|
1666
|
-
dragstart: (event) => {
|
|
1667
|
-
active = { id: event.id, payload };
|
|
1668
|
-
},
|
|
1669
|
-
dragend: (event) => {
|
|
1670
|
-
if (active?.id === event.id) active = null;
|
|
1671
|
-
}
|
|
1672
|
-
},
|
|
1673
|
-
children
|
|
1674
|
-
);
|
|
1675
|
-
}
|
|
1676
|
-
function itemValue(item) {
|
|
1677
|
-
if (item.text !== void 0) {
|
|
1678
|
-
if (item.type === "text/uri-list") {
|
|
1679
|
-
try {
|
|
1680
|
-
return new URL(item.text.split(/\r?\n/)[0].trim());
|
|
1681
|
-
} catch {
|
|
1682
|
-
return item.text;
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
return item.text;
|
|
1686
|
-
}
|
|
1687
|
-
const name = item.path ?? item.name ?? "file";
|
|
1688
|
-
if (item.file) {
|
|
1689
|
-
const file = item.file;
|
|
1690
|
-
return item.path !== void 0 && item.path !== file.name ? new File([file], item.path, { type: file.type, lastModified: file.lastModified }) : file;
|
|
1691
|
-
}
|
|
1692
|
-
if (item.url !== void 0 && item.data === void 0) {
|
|
1693
|
-
const fromReference = browserEnvironment.fileFromReference;
|
|
1694
|
-
if (fromReference) {
|
|
1695
|
-
return fromReference({ type: item.type, name, url: item.url, ...item.path !== void 0 ? { path: item.path } : {}, ...item.size !== void 0 ? { size: item.size } : {} });
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
const binary = atob(item.data ?? "");
|
|
1699
|
-
const bytes = new Uint8Array(binary.length);
|
|
1700
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1701
|
-
return typeof File !== "undefined" ? new File([bytes], name, { type: item.type }) : bytes;
|
|
1702
|
-
}
|
|
1703
|
-
function DropDestination({ action, isTargeted, accepts, children }) {
|
|
1704
|
-
return sb(
|
|
1705
|
-
"dropdestination",
|
|
1706
|
-
{ accepts: accepts ?? [] },
|
|
1707
|
-
{
|
|
1708
|
-
drop: (event) => {
|
|
1709
|
-
if (event.phase === "entered") {
|
|
1710
|
-
isTargeted?.(true);
|
|
1711
|
-
return;
|
|
1712
|
-
}
|
|
1713
|
-
isTargeted?.(false);
|
|
1714
|
-
if (event.phase !== "performed") return;
|
|
1715
|
-
let items;
|
|
1716
|
-
if (event.source !== void 0) items = active && active.id === event.source ? [active.payload] : [];
|
|
1717
|
-
else items = (event.items ?? []).map(itemValue);
|
|
1718
|
-
if (items.length > 0) action(items, { x: event.x, y: event.y });
|
|
1719
|
-
}
|
|
1720
|
-
},
|
|
1721
|
-
children
|
|
1722
|
-
);
|
|
1723
|
-
}
|
|
1724
|
-
function FileImporterPresenter(spec) {
|
|
1725
|
-
const [presented, setPresented] = readBinding(spec.isPresented);
|
|
1726
|
-
const latest = useRef(spec);
|
|
1727
|
-
latest.current = spec;
|
|
1728
|
-
const choosing = useRef(false);
|
|
1729
|
-
useLayoutEffect(() => {
|
|
1730
|
-
if (!presented || choosing.current) return;
|
|
1731
|
-
const { allowedContentTypes, allowsMultipleSelection } = latest.current;
|
|
1732
|
-
const pick = browserEnvironment.pickFiles;
|
|
1733
|
-
if (!pick) {
|
|
1734
|
-
setPresented(false);
|
|
1735
|
-
latest.current.onCancellation?.();
|
|
1736
|
-
return;
|
|
1737
|
-
}
|
|
1738
|
-
choosing.current = true;
|
|
1739
|
-
void pick({ accept: allowedContentTypes.join(","), multiple: allowsMultipleSelection === true }).then((files) => {
|
|
1740
|
-
choosing.current = false;
|
|
1741
|
-
setPresented(false);
|
|
1742
|
-
if (files.length > 0) latest.current.onCompletion(files);
|
|
1743
|
-
else latest.current.onCancellation?.();
|
|
1744
|
-
});
|
|
1745
|
-
}, [presented, setPresented]);
|
|
1746
|
-
return null;
|
|
1747
|
-
}
|
|
1748
|
-
const EXTENSIONS = {
|
|
1749
|
-
"text/plain": "txt",
|
|
1750
|
-
"text/csv": "csv",
|
|
1751
|
-
"text/markdown": "md",
|
|
1752
|
-
"text/html": "html",
|
|
1753
|
-
"application/json": "json",
|
|
1754
|
-
"application/pdf": "pdf",
|
|
1755
|
-
"image/png": "png",
|
|
1756
|
-
"image/jpeg": "jpg",
|
|
1757
|
-
"image/svg+xml": "svg",
|
|
1758
|
-
"audio/mp4": "m4a",
|
|
1759
|
-
"video/mp4": "mp4"
|
|
1760
|
-
};
|
|
1761
|
-
function exportFile(document2, contentType, defaultFilename, index = 0) {
|
|
1762
|
-
const type = document2 instanceof Blob && document2.type || contentType || "application/octet-stream";
|
|
1763
|
-
let name = defaultFilename ?? (document2 instanceof File ? document2.name : index === 0 ? "Untitled" : `Untitled ${index + 1}`);
|
|
1764
|
-
name = name.replace(/[\\/:*?"<>|]+/g, "-").trim() || "Untitled";
|
|
1765
|
-
const extension = EXTENSIONS[type.split(";")[0].trim()];
|
|
1766
|
-
if (extension && !/\.[A-Za-z0-9]{1,8}$/.test(name)) name = `${name}.${extension}`;
|
|
1767
|
-
if (document2 instanceof File && document2.name === name && document2.type === type) return document2;
|
|
1768
|
-
const bytes = typeof document2 === "string" ? new TextEncoder().encode(document2) : document2;
|
|
1769
|
-
return new File([bytes], name, { type });
|
|
1770
|
-
}
|
|
1771
|
-
function FileExporterPresenter(spec) {
|
|
1772
|
-
const [presented, setPresented] = readBinding(spec.isPresented);
|
|
1773
|
-
const latest = useRef(spec);
|
|
1774
|
-
latest.current = spec;
|
|
1775
|
-
const exporting = useRef(false);
|
|
1776
|
-
useLayoutEffect(() => {
|
|
1777
|
-
if (!presented || exporting.current) return;
|
|
1778
|
-
const { document: document2, contentType, defaultFilename } = latest.current;
|
|
1779
|
-
const documents = document2 === null ? [] : Array.isArray(document2) ? document2 : [document2];
|
|
1780
|
-
if (documents.length === 0) {
|
|
1781
|
-
setPresented(false);
|
|
1782
|
-
latest.current.onCancellation?.();
|
|
1783
|
-
return;
|
|
1784
|
-
}
|
|
1785
|
-
exporting.current = true;
|
|
1786
|
-
const files = documents.map((item, index) => exportFile(item, contentType, defaultFilename, index));
|
|
1787
|
-
exportFiles(files).then(
|
|
1788
|
-
(result) => {
|
|
1789
|
-
exporting.current = false;
|
|
1790
|
-
setPresented(false);
|
|
1791
|
-
if (result.outcome === "cancelled") latest.current.onCancellation?.();
|
|
1792
|
-
else latest.current.onCompletion?.(result);
|
|
1793
|
-
},
|
|
1794
|
-
(error) => {
|
|
1795
|
-
exporting.current = false;
|
|
1796
|
-
setPresented(false);
|
|
1797
|
-
latest.current.onError?.(error);
|
|
1798
|
-
}
|
|
1799
|
-
);
|
|
1800
|
-
}, [presented, setPresented]);
|
|
1801
|
-
return null;
|
|
1802
|
-
}
|
|
1803
|
-
const ListSelectionContext = createContext(null);
|
|
1804
|
-
function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
|
|
1805
|
-
const selection = useContext(ListSelectionContext);
|
|
1806
|
-
const selectable = selection !== null && tag !== void 0;
|
|
1807
|
-
const canDelete = onDelete !== void 0 && deletable !== false;
|
|
1808
|
-
const canMove = onMove !== void 0 && movable !== false;
|
|
1809
|
-
if (!selectable && !canDelete && !canMove) return children;
|
|
1810
|
-
const props = {};
|
|
1811
|
-
if (selectable) {
|
|
1812
|
-
props["selectable"] = true;
|
|
1813
|
-
props["selected"] = selection.isSelected(tag);
|
|
1814
|
-
}
|
|
1815
|
-
if (canDelete) props["deletable"] = true;
|
|
1816
|
-
if (canMove) props["movable"] = true;
|
|
1817
|
-
return sb(
|
|
1818
|
-
"listrow",
|
|
1819
|
-
props,
|
|
1820
|
-
{
|
|
1821
|
-
tap: () => selectable && selection.select(tag),
|
|
1822
|
-
delete: () => onDelete?.(),
|
|
1823
|
-
move: (event) => {
|
|
1824
|
-
const start = (containerIndex ?? index ?? 0) - (index ?? 0);
|
|
1825
|
-
onMove?.(Math.max(0, event.to - start));
|
|
1826
|
-
}
|
|
1827
|
-
},
|
|
1828
|
-
children
|
|
1829
|
-
);
|
|
1830
|
-
}
|
|
1831
|
-
const isPoint = (value) => typeof value === "object" && value !== null && ("x" in value || "y" in value);
|
|
1832
|
-
function command(request) {
|
|
1833
|
-
return request.axes ? { anchor: request.anchor, serial: request.serial, axes: request.axes } : { anchor: request.anchor, serial: request.serial };
|
|
1834
|
-
}
|
|
1835
|
-
function offsetCommand(request) {
|
|
1836
|
-
const out = { serial: request.serial };
|
|
1837
|
-
if (typeof request.point.x === "number") out.x = request.point.x;
|
|
1838
|
-
if (typeof request.point.y === "number") out.y = request.point.y;
|
|
1839
|
-
return out;
|
|
1840
|
-
}
|
|
1841
|
-
const ScrollRequestContext = createContext(null);
|
|
1842
|
-
let nextSerial = 1;
|
|
1843
|
-
function ScrollViewReader({ children }) {
|
|
1844
|
-
const [request, setRequest] = useState(null);
|
|
1845
|
-
const proxy = {
|
|
1846
|
-
scrollTo: (target, anchor, options) => {
|
|
1847
|
-
if (isPoint(target)) setRequest({ point: target, serial: nextSerial++ });
|
|
1848
|
-
else setRequest({ id: target, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++, ...options?.axes ? { axes: options.axes } : {} });
|
|
1849
|
-
}
|
|
1850
|
-
};
|
|
1851
|
-
return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
|
|
1852
|
-
}
|
|
1853
|
-
function ScrollTarget({ id, children }) {
|
|
1854
|
-
const request = useContext(ScrollRequestContext);
|
|
1855
|
-
const position = useContext(ScrollPositionContext);
|
|
1856
|
-
const on = position ? { scrollposition: () => position.report(id) } : void 0;
|
|
1857
|
-
if (request && "id" in request && request.id === id) return sb("styled", { style: { scrollID: true, scrollTo: command(request) } }, on, children);
|
|
1858
|
-
if (on) return sb("styled", { style: { scrollID: true } }, on, children);
|
|
1859
|
-
return styled({ scrollID: true }, children);
|
|
1860
|
-
}
|
|
1861
|
-
const ScrollPositionContext = createContext(null);
|
|
1862
|
-
function useScrollPosition(binding, anchor, axes) {
|
|
1863
|
-
const bound = binding !== void 0;
|
|
1864
|
-
const [value, set] = bound ? readBinding(binding) : [null, () => void 0];
|
|
1865
|
-
const last = useRef(void 0);
|
|
1866
|
-
const reported = useRef(void 0);
|
|
1867
|
-
const request = useRef(null);
|
|
1868
|
-
const outer = useContext(ScrollRequestContext);
|
|
1869
|
-
const point = anchor === void 0 ? null : unitPoint(anchor);
|
|
1870
|
-
if (value !== last.current) {
|
|
1871
|
-
last.current = value;
|
|
1872
|
-
if (isPoint(value)) request.current = { point: value, serial: nextSerial++ };
|
|
1873
|
-
else if (value !== null && value !== reported.current) request.current = { id: value, anchor: point, serial: nextSerial++, axes };
|
|
1874
|
-
reported.current = void 0;
|
|
1875
|
-
}
|
|
1876
|
-
const own = request.current;
|
|
1877
|
-
const current = own && (!outer || own.serial > outer.serial) ? own : outer;
|
|
1878
|
-
const offset = useOffsetCommand(bound ? current : outer);
|
|
1879
|
-
if (!bound) return offset ? { props: offset, provide: (children) => children } : null;
|
|
1880
|
-
const props = { reportsPosition: true, ...offset };
|
|
1881
|
-
if (point) props["positionAnchor"] = point;
|
|
1882
|
-
const context = {
|
|
1883
|
-
report: (id) => {
|
|
1884
|
-
reported.current = id;
|
|
1885
|
-
set(id);
|
|
1886
|
-
}
|
|
1887
|
-
};
|
|
1888
|
-
const inner = current && "point" in current ? outer && "id" in outer ? outer : null : current;
|
|
1889
|
-
return {
|
|
1890
|
-
props,
|
|
1891
|
-
provide: (children) => /* @__PURE__ */ jsx(ScrollPositionContext.Provider, { value: context, children: /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: inner, children }) })
|
|
1892
|
-
};
|
|
1449
|
+
const ScrollPositionContext = createContext(null);
|
|
1450
|
+
function useScrollPosition(binding, anchor, axes) {
|
|
1451
|
+
const bound = binding !== void 0;
|
|
1452
|
+
const [value, set] = bound ? readBinding(binding) : [null, () => void 0];
|
|
1453
|
+
const last = useRef(void 0);
|
|
1454
|
+
const reported = useRef(void 0);
|
|
1455
|
+
const request = useRef(null);
|
|
1456
|
+
const outer = useContext(ScrollRequestContext);
|
|
1457
|
+
const point = anchor === void 0 ? null : unitPoint(anchor);
|
|
1458
|
+
if (value !== last.current) {
|
|
1459
|
+
last.current = value;
|
|
1460
|
+
if (isPoint(value)) request.current = { point: value, serial: nextSerial++ };
|
|
1461
|
+
else if (value !== null && value !== reported.current) request.current = { id: value, anchor: point, serial: nextSerial++, axes };
|
|
1462
|
+
reported.current = void 0;
|
|
1463
|
+
}
|
|
1464
|
+
const own = request.current;
|
|
1465
|
+
const current = own && (!outer || own.serial > outer.serial) ? own : outer;
|
|
1466
|
+
const offset = useOffsetCommand(bound ? current : outer);
|
|
1467
|
+
if (!bound) return offset ? { props: offset, provide: (children) => children } : null;
|
|
1468
|
+
const props = { reportsPosition: true, ...offset };
|
|
1469
|
+
if (point) props["positionAnchor"] = point;
|
|
1470
|
+
const context = {
|
|
1471
|
+
report: (id) => {
|
|
1472
|
+
reported.current = id;
|
|
1473
|
+
set(id);
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
const inner = current && "point" in current ? outer && "id" in outer ? outer : null : current;
|
|
1477
|
+
return {
|
|
1478
|
+
props,
|
|
1479
|
+
provide: (children) => /* @__PURE__ */ jsx(ScrollPositionContext.Provider, { value: context, children: /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: inner, children }) })
|
|
1480
|
+
};
|
|
1893
1481
|
}
|
|
1894
1482
|
function useOffsetCommand(request) {
|
|
1895
1483
|
const seen = useRef(null);
|
|
@@ -2114,573 +1702,932 @@ function moveItems(items, offsets, to) {
|
|
|
2114
1702
|
const at = to - before;
|
|
2115
1703
|
return [...rest.slice(0, at), ...picked, ...rest.slice(at)];
|
|
2116
1704
|
}
|
|
2117
|
-
function ForEach(props) {
|
|
1705
|
+
function ForEach(props) {
|
|
1706
|
+
const { own, modifiers } = splitProps(props);
|
|
1707
|
+
const rows = own.data.map((element, index) => {
|
|
1708
|
+
const key = own.id ? own.id(element, index) : keyOf(element, index);
|
|
1709
|
+
const content = applyModifiers(own.children(element, index), modifiers);
|
|
1710
|
+
if (!own.onDelete && !own.onMove) return createElement(Fragment, { key }, content);
|
|
1711
|
+
const { onDelete, onMove } = own;
|
|
1712
|
+
const row = { tag: key, index };
|
|
1713
|
+
if (onDelete) {
|
|
1714
|
+
row.onDelete = () => onDelete([index]);
|
|
1715
|
+
row.deletable = !own.deleteDisabled?.(element, index);
|
|
1716
|
+
}
|
|
1717
|
+
if (onMove) {
|
|
1718
|
+
row.onMove = (to) => onMove([index], to);
|
|
1719
|
+
row.movable = !own.moveDisabled?.(element, index);
|
|
1720
|
+
}
|
|
1721
|
+
return createElement(Row, { key, ...row }, content);
|
|
1722
|
+
});
|
|
1723
|
+
return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
|
|
1724
|
+
}
|
|
1725
|
+
function keyOf(element, index) {
|
|
1726
|
+
if (typeof element === "string" || typeof element === "number") return element;
|
|
1727
|
+
if (typeof element === "object" && element !== null && "id" in element) {
|
|
1728
|
+
const id = element.id;
|
|
1729
|
+
if (typeof id === "string" || typeof id === "number") return id;
|
|
1730
|
+
}
|
|
1731
|
+
return index;
|
|
1732
|
+
}
|
|
1733
|
+
function flattenChildren(children, options = {}) {
|
|
1734
|
+
const result = [];
|
|
1735
|
+
const visit = (node) => {
|
|
1736
|
+
if (node === null || node === void 0 || typeof node === "boolean") return;
|
|
1737
|
+
if (Array.isArray(node)) {
|
|
1738
|
+
node.forEach(visit);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
if (!isValidElement(node)) return;
|
|
1742
|
+
const element = node;
|
|
1743
|
+
if (element.type === Fragment) {
|
|
1744
|
+
const inner = element.props["children"];
|
|
1745
|
+
if (element.key !== null && isValidElement(inner) && inner.key === null && inner.type !== Fragment) {
|
|
1746
|
+
visit({ ...inner, key: element.key });
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
visit(inner);
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
if (element.type === ForEach) {
|
|
1753
|
+
visit(ForEach(element.props));
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
if (element.type === LazyGroup && !options.keepLazy) {
|
|
1757
|
+
visit(element.props.rows);
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
result.push(element);
|
|
1761
|
+
};
|
|
1762
|
+
visit(children);
|
|
1763
|
+
return result;
|
|
1764
|
+
}
|
|
1765
|
+
function GridItem(spec = {}) {
|
|
1766
|
+
const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
|
|
1767
|
+
let size;
|
|
1768
|
+
if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
|
|
1769
|
+
else if (spec.size && "adaptive" in spec.size) {
|
|
1770
|
+
size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
|
|
1771
|
+
} else {
|
|
1772
|
+
const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
|
|
1773
|
+
size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
|
|
1774
|
+
}
|
|
1775
|
+
return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
|
|
1776
|
+
}
|
|
1777
|
+
GridItem.flexible = (options = {}) => GridItem({ size: { flexible: options }, spacing: options.spacing, alignment: options.alignment });
|
|
1778
|
+
GridItem.fixed = (value, options = {}) => GridItem({ size: { fixed: value }, spacing: options.spacing, alignment: options.alignment });
|
|
1779
|
+
GridItem.adaptive = (options) => GridItem({ size: { adaptive: options }, spacing: options.spacing, alignment: options.alignment });
|
|
1780
|
+
function LazyVGrid(props) {
|
|
1781
|
+
const { own, modifiers } = splitProps(props);
|
|
1782
|
+
const grid = { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
|
|
1783
|
+
if (own.pinnedViews && own.pinnedViews.length > 0) grid["pinned"] = own.pinnedViews;
|
|
1784
|
+
return applyModifiers(sb("lazyvgrid", grid, void 0, pinning(own.pinnedViews, own.children)), modifiers);
|
|
1785
|
+
}
|
|
1786
|
+
function LazyHGrid(props) {
|
|
1787
|
+
const { own, modifiers } = splitProps(props);
|
|
1788
|
+
const grid = { rows: own.rows, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
|
|
1789
|
+
if (own.pinnedViews && own.pinnedViews.length > 0) grid["pinned"] = own.pinnedViews;
|
|
1790
|
+
return applyModifiers(sb("lazyhgrid", grid, void 0, pinning(own.pinnedViews, own.children)), modifiers);
|
|
1791
|
+
}
|
|
1792
|
+
function Grid(props) {
|
|
1793
|
+
const { own, modifiers } = splitProps(props);
|
|
1794
|
+
return applyModifiers(
|
|
1795
|
+
sb(
|
|
1796
|
+
"grid",
|
|
1797
|
+
{ horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
|
|
1798
|
+
void 0,
|
|
1799
|
+
own.children
|
|
1800
|
+
),
|
|
1801
|
+
modifiers
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
function GridRow(props) {
|
|
1805
|
+
const { own, modifiers } = splitProps(props);
|
|
1806
|
+
return applyModifiers(sb("gridrow", { alignment: own.alignment ?? null }, void 0, own.children), modifiers);
|
|
1807
|
+
}
|
|
1808
|
+
function runStyleOf(props, inherited, nested) {
|
|
1809
|
+
const style = { ...inherited };
|
|
1810
|
+
if (props.italic) style.italic = true;
|
|
1811
|
+
if (props.underline) style.underline = typeof props.underline === "object" && props.underline.color ? { color: color(props.underline.color) } : {};
|
|
1812
|
+
if (props.strikethrough) {
|
|
1813
|
+
style.strikethrough = typeof props.strikethrough === "object" && props.strikethrough.color ? { color: color(props.strikethrough.color) } : {};
|
|
1814
|
+
}
|
|
1815
|
+
const kerning = props.tracking ?? props.kerning;
|
|
1816
|
+
if (kerning !== void 0) style.kerning = kerning;
|
|
1817
|
+
if (props.baselineOffset !== void 0) style.baselineOffset = props.baselineOffset;
|
|
1818
|
+
if (props.link) style.link = props.link;
|
|
1819
|
+
if (nested) {
|
|
1820
|
+
let runFont2 = props.font !== void 0 ? font(props.font) : void 0;
|
|
1821
|
+
if (props.bold) runFont2 = { ...runFont2 ?? {}, weight: "bold" };
|
|
1822
|
+
if (props.fontWeight) runFont2 = { ...runFont2 ?? {}, weight: props.fontWeight };
|
|
1823
|
+
if (props.monospacedDigit) runFont2 = { ...runFont2 ?? {}, monospacedDigit: true };
|
|
1824
|
+
if (runFont2) style.font = { ...style.font ?? {}, ...runFont2 };
|
|
1825
|
+
if (props.foregroundStyle !== void 0) {
|
|
1826
|
+
style.foreground = shapeStyle(Array.isArray(props.foregroundStyle) ? props.foregroundStyle[0] : props.foregroundStyle);
|
|
1827
|
+
}
|
|
1828
|
+
const background = runBackground(props.background);
|
|
1829
|
+
if (background) style.background = background;
|
|
1830
|
+
}
|
|
1831
|
+
return style;
|
|
1832
|
+
}
|
|
1833
|
+
function runBackground(value) {
|
|
1834
|
+
if (typeof value === "string") {
|
|
1835
|
+
const made = color(value);
|
|
1836
|
+
return "hierarchical" in made ? void 0 : made;
|
|
1837
|
+
}
|
|
1838
|
+
if (typeof value !== "object" || value === null || isValidElement(value) || "in" in value) return void 0;
|
|
1839
|
+
return "r" in value || "name" in value || "named" in value ? value : void 0;
|
|
1840
|
+
}
|
|
1841
|
+
function segmentsOf(children, style, into) {
|
|
1842
|
+
const visit = (node) => {
|
|
1843
|
+
if (node === null || node === void 0 || typeof node === "boolean") return;
|
|
1844
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
1845
|
+
const last = into[into.length - 1];
|
|
1846
|
+
if (last && "text" in last && last.style === style) last.text += String(node);
|
|
1847
|
+
else into.push({ text: String(node), style });
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
if (Array.isArray(node)) {
|
|
1851
|
+
node.forEach(visit);
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
if (!isValidElement(node)) return;
|
|
1855
|
+
const element = node;
|
|
1856
|
+
if (element.type === Fragment) {
|
|
1857
|
+
visit(element.props["children"]);
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
if (element.type === Text) {
|
|
1861
|
+
const props = element.props;
|
|
1862
|
+
segmentsOf(props.children, runStyleOf(props, style, true), into);
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
if (element.type === Image$1) {
|
|
1866
|
+
const props = element.props;
|
|
1867
|
+
into.push({ image: imageProps$1(props), style });
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
visit(children);
|
|
1872
|
+
}
|
|
1873
|
+
function isPlainStyle(style) {
|
|
1874
|
+
return Object.keys(style).length === 0;
|
|
1875
|
+
}
|
|
1876
|
+
function Text(props) {
|
|
1877
|
+
const { own, modifiers } = splitProps(props);
|
|
1878
|
+
const environment = useViewEnvironment();
|
|
1879
|
+
const style = runStyleOf(props, {}, false);
|
|
1880
|
+
const segments = [];
|
|
1881
|
+
segmentsOf(own.children, style, segments);
|
|
1882
|
+
const textCase = takeModifier(modifiers, "textCase") ?? environment.textCase;
|
|
1883
|
+
if (textCase) {
|
|
1884
|
+
for (const segment of segments) {
|
|
1885
|
+
if ("text" in segment) segment.text = textCase === "uppercase" ? segment.text.toUpperCase() : segment.text.toLowerCase();
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
|
|
1889
|
+
const content = segments.map((segment) => "text" in segment ? segment.text : "").join("");
|
|
1890
|
+
const plain2 = segments.length <= 1 && (segments.length === 0 || "text" in segments[0] && isPlainStyle(segments[0].style));
|
|
1891
|
+
if (plain2) return applyModifiers(placeholder(sb("text", { text: content }), redacted), modifiers);
|
|
1892
|
+
const runs = segments.map((segment) => {
|
|
1893
|
+
const run = { ...segment.style };
|
|
1894
|
+
if ("text" in segment) run["text"] = segment.text;
|
|
1895
|
+
else run["image"] = segment.image;
|
|
1896
|
+
return run;
|
|
1897
|
+
});
|
|
1898
|
+
const hasLinks = segments.some((segment) => segment.style.link);
|
|
1899
|
+
const handlers = hasLinks ? { link: (event) => openURL(event.value) } : void 0;
|
|
1900
|
+
return applyModifiers(placeholder(sb("text", { text: content, runs }, handlers), redacted), modifiers);
|
|
1901
|
+
}
|
|
1902
|
+
function placeholder(node, redacted) {
|
|
1903
|
+
if (!redacted) return node;
|
|
1904
|
+
return styled({ background: { hierarchical: 3 }, backgroundCornerRadius: 4 }, styled({ foreground: { name: "clear" } }, node));
|
|
1905
|
+
}
|
|
1906
|
+
function openURL(url) {
|
|
1907
|
+
const native = globalThis.__sbNative;
|
|
1908
|
+
if (native?.openURL) {
|
|
1909
|
+
native.openURL(url);
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
if (typeof window !== "undefined") window.open(url, "_blank", "noopener");
|
|
1913
|
+
}
|
|
1914
|
+
function imageProps$1(props) {
|
|
1915
|
+
if (props.systemName !== void 0) return { systemName: props.systemName };
|
|
1916
|
+
if (props.bitmap !== void 0) {
|
|
1917
|
+
const { source, steps = [], version } = props.bitmap;
|
|
1918
|
+
const extent = bitmapExtent(source, steps);
|
|
1919
|
+
const finite = Number.isFinite(extent.width) && Number.isFinite(extent.height);
|
|
1920
|
+
const width = finite ? Math.max(0, Math.round(extent.width)) : 0;
|
|
1921
|
+
const height = finite ? Math.max(0, Math.round(extent.height)) : 0;
|
|
1922
|
+
const scale = props.scale !== void 0 && props.scale > 0 ? props.scale : 1;
|
|
1923
|
+
return {
|
|
1924
|
+
bitmap: { source: source?.key ?? null, steps, width, height, ...version !== void 0 ? { version } : {} },
|
|
1925
|
+
resizable: props.resizable ?? false,
|
|
1926
|
+
width: width / scale,
|
|
1927
|
+
height: height / scale,
|
|
1928
|
+
...props.interpolation === "none" ? { interpolation: "none" } : {}
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
if (props.url !== void 0) return { url: props.url, resizable: props.resizable ?? false, width: props.width ?? 0, height: props.height ?? 0 };
|
|
1932
|
+
return { name: props.name ?? "", resizable: props.resizable ?? false };
|
|
1933
|
+
}
|
|
1934
|
+
function Image$1(props) {
|
|
1935
|
+
const { modifiers } = splitProps(props);
|
|
1936
|
+
const environment = useViewEnvironment();
|
|
1937
|
+
const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
|
|
1938
|
+
const mode = takeModifier(modifiers, "symbolRenderingMode") ?? environment.symbolRenderingMode;
|
|
1939
|
+
const own = imageProps$1(props);
|
|
1940
|
+
const element = props.systemName !== void 0 && mode === "palette" ? { ...own, renderingMode: "palette" } : own;
|
|
1941
|
+
if (props.accessibilityLabel) element["accessibilityLabel"] = props.accessibilityLabel;
|
|
1942
|
+
return applyModifiers(placeholder(sb("image", element), redacted), modifiers);
|
|
1943
|
+
}
|
|
1944
|
+
function Label(props) {
|
|
1945
|
+
const { own, modifiers } = splitProps(props);
|
|
1946
|
+
const environment = useViewEnvironment();
|
|
1947
|
+
const style = takeModifier(modifiers, "labelStyle") ?? environment.labelStyle ?? "automatic";
|
|
1948
|
+
const icon = own.icon ?? (own.systemImage !== void 0 ? /* @__PURE__ */ jsx(Image$1, { systemName: own.systemImage }) : own.image !== void 0 ? /* @__PURE__ */ jsx(Image$1, { name: own.image }) : null);
|
|
1949
|
+
const title = typeof own.title === "string" || typeof own.title === "number" ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.title;
|
|
1950
|
+
if (style === "iconOnly") {
|
|
1951
|
+
const name = typeof own.title === "string" || typeof own.title === "number" ? String(own.title) : void 0;
|
|
1952
|
+
const named = own.icon === void 0 && name !== void 0 ? own.systemImage !== void 0 ? /* @__PURE__ */ jsx(Image$1, { systemName: own.systemImage, accessibilityLabel: name }) : own.image !== void 0 ? /* @__PURE__ */ jsx(Image$1, { name: own.image, accessibilityLabel: name }) : icon : icon;
|
|
1953
|
+
return applyModifiers(named, modifiers);
|
|
1954
|
+
}
|
|
1955
|
+
if (style === "titleOnly") return applyModifiers(title, modifiers);
|
|
1956
|
+
return applyModifiers(
|
|
1957
|
+
/* @__PURE__ */ jsxs(HStack, { spacing: 8, children: [
|
|
1958
|
+
style === "titleAndIcon" ? icon : styled({ labelIcon: true }, icon),
|
|
1959
|
+
title
|
|
1960
|
+
] }),
|
|
1961
|
+
modifiers
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
function LabeledContent(props) {
|
|
2118
1965
|
const { own, modifiers } = splitProps(props);
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
row.onMove = (to) => onMove([index], to);
|
|
2131
|
-
row.movable = !own.moveDisabled?.(element, index);
|
|
2132
|
-
}
|
|
2133
|
-
return createElement(Row, { key, ...row }, content);
|
|
2134
|
-
});
|
|
2135
|
-
return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
|
|
1966
|
+
const label = typeof own.label === "string" || typeof own.label === "number" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
|
|
1967
|
+
const content = own.children ?? own.value;
|
|
1968
|
+
const value = typeof content === "string" || typeof content === "number" ? /* @__PURE__ */ jsx(Text, { children: content }) : content;
|
|
1969
|
+
return applyModifiers(
|
|
1970
|
+
/* @__PURE__ */ jsxs(HStack, { children: [
|
|
1971
|
+
label,
|
|
1972
|
+
sb("spacer", { minLength: null }),
|
|
1973
|
+
styled({ foreground: { hierarchical: 2 } }, value)
|
|
1974
|
+
] }),
|
|
1975
|
+
modifiers
|
|
1976
|
+
);
|
|
2136
1977
|
}
|
|
2137
|
-
function
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
if (typeof id === "string" || typeof id === "number") return id;
|
|
2142
|
-
}
|
|
2143
|
-
return index;
|
|
1978
|
+
function Link(props) {
|
|
1979
|
+
const { own, modifiers } = splitProps(props);
|
|
1980
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
1981
|
+
return applyModifiers(sb("button", { role: null, style: "automatic" }, { tap: () => openURL(own.destination) }, label), modifiers);
|
|
2144
1982
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
}
|
|
2164
|
-
if (element.type === ForEach) {
|
|
2165
|
-
visit(ForEach(element.props));
|
|
2166
|
-
return;
|
|
2167
|
-
}
|
|
2168
|
-
if (element.type === LazyGroup && !options.keepLazy) {
|
|
2169
|
-
visit(element.props.rows);
|
|
2170
|
-
return;
|
|
1983
|
+
const isPushedView = (value) => typeof value === "object" && value !== null && "view" in value && isValidElement(value.view);
|
|
1984
|
+
function routeOf(value, depth = 0) {
|
|
1985
|
+
if (depth > 8) return void 0;
|
|
1986
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
1987
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
1988
|
+
if (Array.isArray(value)) {
|
|
1989
|
+
const items = value.map((item) => routeOf(item, depth + 1));
|
|
1990
|
+
return items.every((item) => item !== void 0) ? items : void 0;
|
|
1991
|
+
}
|
|
1992
|
+
if (typeof value === "object" && !isPushedView(value)) {
|
|
1993
|
+
const proto = Object.getPrototypeOf(value);
|
|
1994
|
+
if (proto !== Object.prototype && proto !== null) return void 0;
|
|
1995
|
+
const out = {};
|
|
1996
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1997
|
+
if (item === void 0) continue;
|
|
1998
|
+
const plain2 = routeOf(item, depth + 1);
|
|
1999
|
+
if (plain2 === void 0) return void 0;
|
|
2000
|
+
out[key] = plain2;
|
|
2171
2001
|
}
|
|
2172
|
-
|
|
2173
|
-
};
|
|
2174
|
-
visit(children);
|
|
2175
|
-
return result;
|
|
2176
|
-
}
|
|
2177
|
-
function GridItem(spec = {}) {
|
|
2178
|
-
const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
|
|
2179
|
-
let size;
|
|
2180
|
-
if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
|
|
2181
|
-
else if (spec.size && "adaptive" in spec.size) {
|
|
2182
|
-
size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
|
|
2183
|
-
} else {
|
|
2184
|
-
const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
|
|
2185
|
-
size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
|
|
2002
|
+
return out;
|
|
2186
2003
|
}
|
|
2187
|
-
return
|
|
2004
|
+
return void 0;
|
|
2188
2005
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
const { own, modifiers } = splitProps(props);
|
|
2194
|
-
const grid = { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
|
|
2195
|
-
if (own.pinnedViews && own.pinnedViews.length > 0) grid["pinned"] = own.pinnedViews;
|
|
2196
|
-
return applyModifiers(sb("lazyvgrid", grid, void 0, pinning(own.pinnedViews, own.children)), modifiers);
|
|
2006
|
+
function NavigationStack(props) {
|
|
2007
|
+
const enclosing = useNavigation();
|
|
2008
|
+
if (enclosing) return /* @__PURE__ */ jsx(FlattenedStack, { ...props });
|
|
2009
|
+
return /* @__PURE__ */ jsx(OwnStack, { ...props });
|
|
2197
2010
|
}
|
|
2198
|
-
function
|
|
2011
|
+
function FlattenedStack(props) {
|
|
2199
2012
|
const { own, modifiers } = splitProps(props);
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2013
|
+
return applyModifiers(
|
|
2014
|
+
/* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2015
|
+
own.destination && /* @__PURE__ */ jsx(RegisterDestination, { destination: own.destination }),
|
|
2016
|
+
own.children
|
|
2017
|
+
] }),
|
|
2018
|
+
modifiers
|
|
2019
|
+
);
|
|
2203
2020
|
}
|
|
2204
|
-
function
|
|
2021
|
+
function OwnStack(props) {
|
|
2205
2022
|
const { own, modifiers } = splitProps(props);
|
|
2023
|
+
const remote = useContext(HostTreeContext)?.remote ?? false;
|
|
2024
|
+
const [internalPath, setInternalPath] = useState([]);
|
|
2025
|
+
const [path, setPath] = own.path !== void 0 ? readBinding(own.path, own.onPathChange) : [internalPath, setInternalPath];
|
|
2026
|
+
const destination = useRef(null);
|
|
2027
|
+
destination.current = own.destination ?? null;
|
|
2028
|
+
const context = {
|
|
2029
|
+
push: (value) => setPath([...path, value]),
|
|
2030
|
+
pop: () => setPath(path.slice(0, -1)),
|
|
2031
|
+
path,
|
|
2032
|
+
setPath: (next) => setPath(next),
|
|
2033
|
+
registerDestination: (builder) => {
|
|
2034
|
+
destination.current = builder;
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
const screens = [
|
|
2038
|
+
/* @__PURE__ */ jsx(Fragment, { children: sb("navscreen", { title: "", displayMode: "automatic", depth: 0 }, { tap: context.pop }, /* @__PURE__ */ jsx(ScreenDepthContext.Provider, { value: 0, children: own.children })) }, "root")
|
|
2039
|
+
];
|
|
2040
|
+
path.forEach((value, index) => {
|
|
2041
|
+
const pop = () => setPath(path.slice(0, index));
|
|
2042
|
+
const route = remote ? routeOf(value) : void 0;
|
|
2043
|
+
screens.push(
|
|
2044
|
+
/* @__PURE__ */ jsx(Fragment, { children: sb(
|
|
2045
|
+
"navscreen",
|
|
2046
|
+
{ title: "", displayMode: "automatic", depth: index + 1, ...route === void 0 ? {} : { route } },
|
|
2047
|
+
{ tap: pop },
|
|
2048
|
+
/* @__PURE__ */ jsx(DismissContext.Provider, { value: pop, children: /* @__PURE__ */ jsx(ScreenDepthContext.Provider, { value: index + 1, children: /* @__PURE__ */ jsx(PathScreen, { value, destination }) }) })
|
|
2049
|
+
) }, index + 1)
|
|
2050
|
+
);
|
|
2051
|
+
});
|
|
2206
2052
|
return applyModifiers(
|
|
2207
|
-
sb(
|
|
2208
|
-
"grid",
|
|
2209
|
-
{ horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
|
|
2210
|
-
void 0,
|
|
2211
|
-
own.children
|
|
2212
|
-
),
|
|
2053
|
+
sb("navstack", {}, { setpath: (event) => setPath(Array.isArray(event.path) ? event.path : []) }, /* @__PURE__ */ jsx(NavigationContext.Provider, { value: context, children: screens })),
|
|
2213
2054
|
modifiers
|
|
2214
2055
|
);
|
|
2215
2056
|
}
|
|
2216
|
-
function
|
|
2057
|
+
function PathScreen({ value, destination }) {
|
|
2058
|
+
if (isPushedView(value)) return value.view;
|
|
2059
|
+
return destination.current ? destination.current(value) : null;
|
|
2060
|
+
}
|
|
2061
|
+
function NavigationLink(props) {
|
|
2217
2062
|
const { own, modifiers } = splitProps(props);
|
|
2218
|
-
|
|
2063
|
+
const navigation = useNavigation();
|
|
2064
|
+
const environment = useViewEnvironment();
|
|
2065
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2066
|
+
const listSelection = useContext(ListSelectionContext);
|
|
2067
|
+
const sidebar = useContext(SplitSelectionContext) !== null && listSelection !== null && own.destination === void 0 && own.value !== void 0;
|
|
2068
|
+
const tap = () => {
|
|
2069
|
+
if (sidebar) {
|
|
2070
|
+
listSelection.select(own.value);
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
if (!navigation) return;
|
|
2074
|
+
if (own.destination !== void 0) navigation.push({ view: own.destination });
|
|
2075
|
+
else navigation.push(own.value);
|
|
2076
|
+
};
|
|
2077
|
+
const style = takeModifier(modifiers, "buttonStyle") ?? environment.buttonStyle;
|
|
2078
|
+
const linkProps = style === "plain" ? { style: "plain" } : {};
|
|
2079
|
+
if (sidebar) linkProps["selects"] = true;
|
|
2080
|
+
return applyModifiers(sb("navlink", linkProps, { tap }, label), modifiers);
|
|
2219
2081
|
}
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
if (
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
}
|
|
2227
|
-
const
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2082
|
+
const SplitSelectionContext = createContext(null);
|
|
2083
|
+
function splitColumnWidthHint(width) {
|
|
2084
|
+
if (typeof width === "number") return { min: width, ideal: width, max: width };
|
|
2085
|
+
return { ...width.min !== void 0 ? { min: width.min } : {}, ideal: width.ideal, ...width.max !== void 0 ? { max: width.max } : {} };
|
|
2086
|
+
}
|
|
2087
|
+
function NavigationSplitView(props) {
|
|
2088
|
+
const { own, modifiers } = splitProps(props);
|
|
2089
|
+
const sizeClass = useHorizontalSizeClass();
|
|
2090
|
+
const [selected, setSelected] = useState(false);
|
|
2091
|
+
const reporters = useRef(/* @__PURE__ */ new Map());
|
|
2092
|
+
const settle = () => setSelected([...reporters.current.values()].some((entry) => entry.selected));
|
|
2093
|
+
const [report] = useState(() => {
|
|
2094
|
+
return {
|
|
2095
|
+
report: (key, nowSelected, clear2) => {
|
|
2096
|
+
reporters.current.set(key, { selected: nowSelected, clear: clear2 });
|
|
2097
|
+
settle();
|
|
2098
|
+
},
|
|
2099
|
+
retract: (key) => {
|
|
2100
|
+
if (reporters.current.delete(key)) settle();
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
});
|
|
2104
|
+
const clear = () => {
|
|
2105
|
+
for (const entry of reporters.current.values()) {
|
|
2106
|
+
if (!entry.selected) continue;
|
|
2107
|
+
entry.clear();
|
|
2108
|
+
entry.selected = false;
|
|
2239
2109
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2110
|
+
settle();
|
|
2111
|
+
};
|
|
2112
|
+
const [internal, setInternal] = useState("automatic");
|
|
2113
|
+
const [visibility, setVisibility] = own.columnVisibility !== void 0 ? readBinding(own.columnVisibility, own.onColumnVisibilityChange) : [internal, setInternal];
|
|
2114
|
+
if (sizeClass === "compact") {
|
|
2115
|
+
return applyModifiers(/* @__PURE__ */ jsx(CompactSplit, { sidebar: own.sidebar, detail: own.detail, report, selected, clear }), modifiers);
|
|
2242
2116
|
}
|
|
2243
|
-
|
|
2117
|
+
const sidebarVisible = visibility !== "detailOnly";
|
|
2118
|
+
const toggle = () => withAnimation(() => setVisibility(sidebarVisible ? "detailOnly" : "all"));
|
|
2119
|
+
const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
|
|
2120
|
+
const sidebar = own.sidebarWidth !== void 0 ? sb("styled", { style: { splitColumnWidth: splitColumnWidthHint(own.sidebarWidth) } }, void 0, own.sidebar) : own.sidebar;
|
|
2121
|
+
return applyModifiers(
|
|
2122
|
+
sb("navsplit", { sidebarVisible }, { tap: toggle, columnwidth: (event) => own.onSidebarWidthChange?.(event.width) }, [
|
|
2123
|
+
/* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: sidebar }) }, "sidebar"),
|
|
2124
|
+
/* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
|
|
2125
|
+
]),
|
|
2126
|
+
modifiers
|
|
2127
|
+
);
|
|
2244
2128
|
}
|
|
2245
|
-
function
|
|
2246
|
-
|
|
2247
|
-
const made = color(value);
|
|
2248
|
-
return "hierarchical" in made ? void 0 : made;
|
|
2249
|
-
}
|
|
2250
|
-
if (typeof value !== "object" || value === null || isValidElement(value) || "in" in value) return void 0;
|
|
2251
|
-
return "r" in value || "name" in value || "named" in value ? value : void 0;
|
|
2129
|
+
function SplitColumn({ report, children }) {
|
|
2130
|
+
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children }) });
|
|
2252
2131
|
}
|
|
2253
|
-
function
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
if (
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
visit(element.props["children"]);
|
|
2270
|
-
return;
|
|
2271
|
-
}
|
|
2272
|
-
if (element.type === Text) {
|
|
2273
|
-
const props = element.props;
|
|
2274
|
-
segmentsOf(props.children, runStyleOf(props, style, true), into);
|
|
2275
|
-
return;
|
|
2276
|
-
}
|
|
2277
|
-
if (element.type === Image$1) {
|
|
2278
|
-
const props = element.props;
|
|
2279
|
-
into.push({ image: imageProps$1(props), style });
|
|
2132
|
+
function CompactSplit({
|
|
2133
|
+
sidebar,
|
|
2134
|
+
detail,
|
|
2135
|
+
report,
|
|
2136
|
+
selected,
|
|
2137
|
+
clear
|
|
2138
|
+
}) {
|
|
2139
|
+
const [internal, setInternal] = useState([]);
|
|
2140
|
+
const detailStack = isValidElement(detail) && detail.type === NavigationStack ? detail.props : null;
|
|
2141
|
+
const [extra, setExtra] = detailStack?.path !== void 0 ? readBinding(detailStack.path, detailStack.onPathChange) : [internal, setInternal];
|
|
2142
|
+
const base = selected ? [{ view: detail }] : [];
|
|
2143
|
+
const path = [...base, ...extra];
|
|
2144
|
+
const setPath = (next) => {
|
|
2145
|
+
if (selected && next.length === 0) {
|
|
2146
|
+
setExtra([]);
|
|
2147
|
+
clear();
|
|
2280
2148
|
return;
|
|
2281
2149
|
}
|
|
2150
|
+
setExtra(next.slice(base.length));
|
|
2282
2151
|
};
|
|
2283
|
-
|
|
2284
|
-
}
|
|
2285
|
-
function isPlainStyle(style) {
|
|
2286
|
-
return Object.keys(style).length === 0;
|
|
2152
|
+
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children: /* @__PURE__ */ jsx(NavigationStack, { path: [path, setPath], children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children: sidebar }) }) }) });
|
|
2287
2153
|
}
|
|
2288
|
-
function
|
|
2289
|
-
const
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
segmentsOf(own.children, style, segments);
|
|
2294
|
-
const textCase = takeModifier(modifiers, "textCase") ?? environment.textCase;
|
|
2295
|
-
if (textCase) {
|
|
2296
|
-
for (const segment of segments) {
|
|
2297
|
-
if ("text" in segment) segment.text = textCase === "uppercase" ? segment.text.toUpperCase() : segment.text.toLowerCase();
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
|
|
2301
|
-
const content = segments.map((segment) => "text" in segment ? segment.text : "").join("");
|
|
2302
|
-
const plain2 = segments.length <= 1 && (segments.length === 0 || "text" in segments[0] && isPlainStyle(segments[0].style));
|
|
2303
|
-
if (plain2) return applyModifiers(placeholder(sb("text", { text: content }), redacted), modifiers);
|
|
2304
|
-
const runs = segments.map((segment) => {
|
|
2305
|
-
const run = { ...segment.style };
|
|
2306
|
-
if ("text" in segment) run["text"] = segment.text;
|
|
2307
|
-
else run["image"] = segment.image;
|
|
2308
|
-
return run;
|
|
2154
|
+
function useReportSplitSelection(split, selected, clear, active2 = true) {
|
|
2155
|
+
const key = useRef({}).current;
|
|
2156
|
+
useLayoutEffect(() => {
|
|
2157
|
+
if (active2) split?.report(key, selected, clear);
|
|
2158
|
+
else split?.retract(key);
|
|
2309
2159
|
});
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2160
|
+
useLayoutEffect(() => () => split?.retract(key), [split, key]);
|
|
2161
|
+
return (nowSelected, nowClear) => {
|
|
2162
|
+
if (active2) split?.report(key, nowSelected, nowClear);
|
|
2163
|
+
};
|
|
2313
2164
|
}
|
|
2314
|
-
function
|
|
2315
|
-
|
|
2316
|
-
return styled({ background: { hierarchical: 3 }, backgroundCornerRadius: 4 }, styled({ foreground: { name: "clear" } }, node));
|
|
2165
|
+
function OutsideSplit({ children }) {
|
|
2166
|
+
return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
|
|
2317
2167
|
}
|
|
2318
|
-
function
|
|
2319
|
-
const
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2168
|
+
function SheetPresenter({ isPresented, onDismiss, content, fullScreen, inherited }) {
|
|
2169
|
+
const around = useInheritedStyles();
|
|
2170
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
2171
|
+
if (!presented) return null;
|
|
2172
|
+
const dismiss = () => {
|
|
2173
|
+
setPresented(false);
|
|
2174
|
+
onDismiss?.();
|
|
2175
|
+
};
|
|
2176
|
+
const detents = fullScreen ? ["full"] : ["large"];
|
|
2177
|
+
return sb(
|
|
2178
|
+
HOIST_KIND,
|
|
2179
|
+
void 0,
|
|
2180
|
+
void 0,
|
|
2181
|
+
sb(
|
|
2182
|
+
"sheet",
|
|
2183
|
+
{ detents },
|
|
2184
|
+
{ tap: dismiss },
|
|
2185
|
+
replayStyles(
|
|
2186
|
+
inherited && inherited.length > 0 ? [...around, ...inherited] : around,
|
|
2187
|
+
/* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(OutsideSplit, { children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) }) })
|
|
2188
|
+
)
|
|
2189
|
+
),
|
|
2190
|
+
"root"
|
|
2191
|
+
);
|
|
2325
2192
|
}
|
|
2326
|
-
function
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
const finite = Number.isFinite(extent.width) && Number.isFinite(extent.height);
|
|
2332
|
-
const width = finite ? Math.max(0, Math.round(extent.width)) : 0;
|
|
2333
|
-
const height = finite ? Math.max(0, Math.round(extent.height)) : 0;
|
|
2334
|
-
const scale = props.scale !== void 0 && props.scale > 0 ? props.scale : 1;
|
|
2335
|
-
return {
|
|
2336
|
-
bitmap: { source: source?.key ?? null, steps, width, height, ...version !== void 0 ? { version } : {} },
|
|
2337
|
-
resizable: props.resizable ?? false,
|
|
2338
|
-
width: width / scale,
|
|
2339
|
-
height: height / scale,
|
|
2340
|
-
...props.interpolation === "none" ? { interpolation: "none" } : {}
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2343
|
-
if (props.url !== void 0) return { url: props.url, resizable: props.resizable ?? false, width: props.width ?? 0, height: props.height ?? 0 };
|
|
2344
|
-
return { name: props.name ?? "", resizable: props.resizable ?? false };
|
|
2193
|
+
function presentationDetents(detents) {
|
|
2194
|
+
const encoded = detents.map(
|
|
2195
|
+
(detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
|
|
2196
|
+
);
|
|
2197
|
+
return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
|
|
2345
2198
|
}
|
|
2346
|
-
function
|
|
2347
|
-
const
|
|
2348
|
-
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2199
|
+
function AlertPresenter({ title, isPresented, message, actions, style }) {
|
|
2200
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
2201
|
+
if (!presented) return null;
|
|
2202
|
+
const dismiss = () => setPresented(false);
|
|
2203
|
+
return sb(
|
|
2204
|
+
HOIST_KIND,
|
|
2205
|
+
void 0,
|
|
2206
|
+
void 0,
|
|
2207
|
+
sb(
|
|
2208
|
+
"alert",
|
|
2209
|
+
{ title, message: message ?? null, style: style ?? "alert" },
|
|
2210
|
+
{ tap: dismiss },
|
|
2211
|
+
withEnvironment({ dismissAlert: dismiss }, actions)
|
|
2212
|
+
),
|
|
2213
|
+
"root"
|
|
2214
|
+
);
|
|
2355
2215
|
}
|
|
2356
|
-
function
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2216
|
+
function Lifecycle({ onAppear, onDisappear }) {
|
|
2217
|
+
useEffect(() => {
|
|
2218
|
+
onAppear?.();
|
|
2219
|
+
return () => onDisappear?.();
|
|
2220
|
+
}, []);
|
|
2221
|
+
return null;
|
|
2222
|
+
}
|
|
2223
|
+
function Inspector({ isPresented, content, columnWidth, children }) {
|
|
2224
|
+
const sizeClass = useHorizontalSizeClass();
|
|
2225
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
2226
|
+
if (sizeClass === "compact") {
|
|
2227
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2228
|
+
children,
|
|
2229
|
+
/* @__PURE__ */ jsx(SheetPresenter, { isPresented: [presented, setPresented], content })
|
|
2230
|
+
] });
|
|
2366
2231
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2232
|
+
const outside = /* @__PURE__ */ jsx(OutsideSplit, { children: content });
|
|
2233
|
+
const panelContent = columnWidth !== void 0 ? sb("styled", { style: { inspectorColumnWidth: columnWidth } }, void 0, outside) : outside;
|
|
2234
|
+
return sb("inspector", { presented }, void 0, [
|
|
2235
|
+
/* @__PURE__ */ jsx(InspectorPart, { children }, "content"),
|
|
2236
|
+
/* @__PURE__ */ jsx(InspectorPart, { children: sb("inspectorpanel", {}, void 0, panelContent) }, "panel")
|
|
2237
|
+
]);
|
|
2238
|
+
}
|
|
2239
|
+
function InspectorPart({ children }) {
|
|
2240
|
+
return children;
|
|
2241
|
+
}
|
|
2242
|
+
function Task({ id, action }) {
|
|
2243
|
+
const latest = useRef(action);
|
|
2244
|
+
latest.current = action;
|
|
2245
|
+
useEffect(() => {
|
|
2246
|
+
const controller = new AbortController();
|
|
2247
|
+
Promise.resolve().then(() => latest.current(controller.signal)).catch((error) => {
|
|
2248
|
+
if (!controller.signal.aborted) console.error(error);
|
|
2249
|
+
});
|
|
2250
|
+
return () => controller.abort();
|
|
2251
|
+
}, [id]);
|
|
2252
|
+
return null;
|
|
2253
|
+
}
|
|
2254
|
+
function OnChange({
|
|
2255
|
+
value,
|
|
2256
|
+
action,
|
|
2257
|
+
initial
|
|
2258
|
+
}) {
|
|
2259
|
+
const previous = useRef(null);
|
|
2260
|
+
const latest = useRef(action);
|
|
2261
|
+
latest.current = action;
|
|
2262
|
+
useEffect(() => {
|
|
2263
|
+
const last = previous.current;
|
|
2264
|
+
previous.current = { value };
|
|
2265
|
+
if (last === null) {
|
|
2266
|
+
if (initial) latest.current(value, value);
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
if (!Object.is(last.value, value)) latest.current(last.value, value);
|
|
2270
|
+
}, [value, initial]);
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
const CoordinateSpacesContext = createContext({});
|
|
2274
|
+
function useCoordinateSpaces() {
|
|
2275
|
+
return useContext(CoordinateSpacesContext);
|
|
2375
2276
|
}
|
|
2376
|
-
function
|
|
2377
|
-
const
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2277
|
+
function CoordinateSpace({ name, children }) {
|
|
2278
|
+
const spaces = useContext(CoordinateSpacesContext);
|
|
2279
|
+
const [frame2, setFrame] = useState(null);
|
|
2280
|
+
return /* @__PURE__ */ jsx(CoordinateSpacesContext.Provider, { value: { ...spaces, [name]: frame2 }, children: sb(
|
|
2281
|
+
"zstack",
|
|
2282
|
+
{ alignment: "center", reportsSize: true, reportsFrame: true },
|
|
2283
|
+
{
|
|
2284
|
+
geometry: (event) => {
|
|
2285
|
+
const next = { x: event.x ?? 0, y: event.y ?? 0, width: event.width, height: event.height };
|
|
2286
|
+
if (!frame2 || frame2.x !== next.x || frame2.y !== next.y || frame2.width !== next.width || frame2.height !== next.height) setFrame(next);
|
|
2287
|
+
}
|
|
2288
|
+
},
|
|
2289
|
+
children
|
|
2290
|
+
) });
|
|
2389
2291
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2292
|
+
const NO_INSETS = { top: 0, leading: 0, bottom: 0, trailing: 0 };
|
|
2293
|
+
const NO_GEOMETRY = { size: { width: 0, height: 0 }, origin: null, safeArea: NO_INSETS, scrollView: null };
|
|
2294
|
+
function nextGeometry(event, reported) {
|
|
2295
|
+
const hasOrigin = event.x !== void 0 && event.y !== void 0;
|
|
2296
|
+
return {
|
|
2297
|
+
size: { width: event.width, height: event.height },
|
|
2298
|
+
origin: hasOrigin ? { x: event.x, y: event.y } : reported.origin,
|
|
2299
|
+
safeArea: event.safeArea ?? reported.safeArea,
|
|
2300
|
+
// A frame report without a scroll view means the reader is in none.
|
|
2301
|
+
scrollView: hasOrigin ? event.scrollView ?? null : reported.scrollView
|
|
2302
|
+
};
|
|
2394
2303
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
if (
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2304
|
+
function geometryProxy(reported, spaces, onReadFrame) {
|
|
2305
|
+
return {
|
|
2306
|
+
size: reported.size,
|
|
2307
|
+
frame: (space = "local") => {
|
|
2308
|
+
if (space === "local") return { x: 0, y: 0, ...reported.size };
|
|
2309
|
+
onReadFrame();
|
|
2310
|
+
const origin = reported.origin ?? { x: 0, y: 0 };
|
|
2311
|
+
if (space === "global") return { ...origin, ...reported.size };
|
|
2312
|
+
const named = spaces[space.named];
|
|
2313
|
+
return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
|
|
2314
|
+
},
|
|
2315
|
+
bounds: () => {
|
|
2316
|
+
onReadFrame();
|
|
2317
|
+
const view = reported.scrollView;
|
|
2318
|
+
if (!view || !reported.origin) return null;
|
|
2319
|
+
return { x: view.x - reported.origin.x, y: view.y - reported.origin.y, width: view.width, height: view.height };
|
|
2320
|
+
},
|
|
2321
|
+
get safeAreaInsets() {
|
|
2322
|
+
onReadFrame();
|
|
2323
|
+
return reported.safeArea;
|
|
2413
2324
|
}
|
|
2414
|
-
|
|
2415
|
-
}
|
|
2416
|
-
return void 0;
|
|
2417
|
-
}
|
|
2418
|
-
function NavigationStack(props) {
|
|
2419
|
-
const enclosing = useNavigation();
|
|
2420
|
-
if (enclosing) return /* @__PURE__ */ jsx(FlattenedStack, { ...props });
|
|
2421
|
-
return /* @__PURE__ */ jsx(OwnStack, { ...props });
|
|
2325
|
+
};
|
|
2422
2326
|
}
|
|
2423
|
-
function
|
|
2327
|
+
function GeometryReader(props) {
|
|
2424
2328
|
const { own, modifiers } = splitProps(props);
|
|
2329
|
+
const [reported, setReported] = useState(NO_GEOMETRY);
|
|
2330
|
+
const [needsFrame, setNeedsFrame] = useState(false);
|
|
2331
|
+
let readFrame = false;
|
|
2332
|
+
const proxy = geometryProxy(reported, useCoordinateSpaces(), () => {
|
|
2333
|
+
readFrame = true;
|
|
2334
|
+
});
|
|
2335
|
+
const content = own.children(proxy);
|
|
2336
|
+
useEffect(() => {
|
|
2337
|
+
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
2338
|
+
});
|
|
2425
2339
|
return applyModifiers(
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2340
|
+
sb(
|
|
2341
|
+
"geometry",
|
|
2342
|
+
needsFrame ? { reportsFrame: true } : {},
|
|
2343
|
+
{
|
|
2344
|
+
geometry: (event) => {
|
|
2345
|
+
const next = nextGeometry(event, reported);
|
|
2346
|
+
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
2347
|
+
}
|
|
2348
|
+
},
|
|
2349
|
+
content
|
|
2350
|
+
),
|
|
2430
2351
|
modifiers
|
|
2431
2352
|
);
|
|
2432
2353
|
}
|
|
2433
|
-
function
|
|
2434
|
-
const
|
|
2435
|
-
const
|
|
2436
|
-
const
|
|
2437
|
-
const
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2354
|
+
function GeometryChangeView({ handler, children }) {
|
|
2355
|
+
const [reported, setReported] = useState(NO_GEOMETRY);
|
|
2356
|
+
const [needsFrame, setNeedsFrame] = useState(false);
|
|
2357
|
+
const last = useRef(null);
|
|
2358
|
+
const spaces = useCoordinateSpaces();
|
|
2359
|
+
let readFrame = false;
|
|
2360
|
+
const proxy = geometryProxy(reported, spaces, () => {
|
|
2361
|
+
readFrame = true;
|
|
2362
|
+
});
|
|
2363
|
+
const heard = reported !== NO_GEOMETRY;
|
|
2364
|
+
const value = heard && typeof handler !== "function" ? handler.of(proxy) : void 0;
|
|
2365
|
+
useLayoutEffect(() => {
|
|
2366
|
+
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
2367
|
+
});
|
|
2368
|
+
useLayoutEffect(() => {
|
|
2369
|
+
if (!heard) return;
|
|
2370
|
+
if (typeof handler === "function") {
|
|
2371
|
+
handler(proxy);
|
|
2372
|
+
return;
|
|
2447
2373
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
path.forEach((value, index) => {
|
|
2453
|
-
const pop = () => setPath(path.slice(0, index));
|
|
2454
|
-
const route = remote ? routeOf(value) : void 0;
|
|
2455
|
-
screens.push(
|
|
2456
|
-
/* @__PURE__ */ jsx(Fragment, { children: sb(
|
|
2457
|
-
"navscreen",
|
|
2458
|
-
{ title: "", displayMode: "automatic", depth: index + 1, ...route === void 0 ? {} : { route } },
|
|
2459
|
-
{ tap: pop },
|
|
2460
|
-
/* @__PURE__ */ jsx(DismissContext.Provider, { value: pop, children: /* @__PURE__ */ jsx(ScreenDepthContext.Provider, { value: index + 1, children: /* @__PURE__ */ jsx(PathScreen, { value, destination }) }) })
|
|
2461
|
-
) }, index + 1)
|
|
2462
|
-
);
|
|
2374
|
+
const previous = last.current;
|
|
2375
|
+
if (previous && JSON.stringify(previous.value) === JSON.stringify(value)) return;
|
|
2376
|
+
last.current = { value };
|
|
2377
|
+
handler.action(value, previous ? previous.value : value);
|
|
2463
2378
|
});
|
|
2464
|
-
return
|
|
2465
|
-
|
|
2466
|
-
|
|
2379
|
+
return sb(
|
|
2380
|
+
"zstack",
|
|
2381
|
+
{ alignment: "center", reportsSize: true, ...needsFrame ? { reportsFrame: true } : {} },
|
|
2382
|
+
{
|
|
2383
|
+
geometry: (event) => {
|
|
2384
|
+
const next = nextGeometry(event, reported);
|
|
2385
|
+
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
2386
|
+
}
|
|
2387
|
+
},
|
|
2388
|
+
children
|
|
2467
2389
|
);
|
|
2468
2390
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
return
|
|
2391
|
+
const DEFAULT_VIEW_SPACING = { distance: () => 8 };
|
|
2392
|
+
function subviewTraits(children) {
|
|
2393
|
+
return flattenChildren(children).map((element) => {
|
|
2394
|
+
const props = element.props;
|
|
2395
|
+
return { priority: props.layoutPriority ?? 0, values: props.layoutValue ?? {} };
|
|
2396
|
+
});
|
|
2472
2397
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2398
|
+
const fromDimension = (value) => value === "infinity" ? Infinity : value;
|
|
2399
|
+
const toDimension = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : "infinity";
|
|
2400
|
+
const toSize = (size) => ({
|
|
2401
|
+
width: fromDimension(size.width) ?? 0,
|
|
2402
|
+
height: fromDimension(size.height) ?? 0
|
|
2403
|
+
});
|
|
2404
|
+
const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
|
|
2405
|
+
function clamp(value, min, max) {
|
|
2406
|
+
return Math.min(Math.max(value, min), max);
|
|
2407
|
+
}
|
|
2408
|
+
function answerLayout(layout, record, traits = []) {
|
|
2409
|
+
const frames = record.children.map(() => null);
|
|
2410
|
+
const subviews = record.children.map((measurement, index) => {
|
|
2411
|
+
const min = toSize(measurement.min);
|
|
2412
|
+
const ideal = toSize(measurement.ideal);
|
|
2413
|
+
const max = toSize(measurement.max);
|
|
2414
|
+
const sizeThatFits = (proposal) => ({
|
|
2415
|
+
width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
|
|
2416
|
+
height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
|
|
2417
|
+
});
|
|
2418
|
+
return {
|
|
2419
|
+
min,
|
|
2420
|
+
ideal,
|
|
2421
|
+
max,
|
|
2422
|
+
priority: traits[index]?.priority ?? 0,
|
|
2423
|
+
values: traits[index]?.values ?? {},
|
|
2424
|
+
spacing: DEFAULT_VIEW_SPACING,
|
|
2425
|
+
sizeThatFits,
|
|
2426
|
+
place: ({ x, y, anchor, proposal }) => {
|
|
2427
|
+
const size2 = sizeThatFits(proposal ?? { width: null, height: null });
|
|
2428
|
+
const point = unitPoint(anchor ?? "topLeading");
|
|
2429
|
+
frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
});
|
|
2433
|
+
const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
|
|
2434
|
+
const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
|
|
2435
|
+
const size = measure(record.proposal);
|
|
2436
|
+
layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
|
|
2437
|
+
const placed = frames.map((frame2, index) => {
|
|
2438
|
+
if (frame2) return frame2;
|
|
2439
|
+
const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
|
|
2440
|
+
return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
|
|
2441
|
+
});
|
|
2442
|
+
const guides = {};
|
|
2443
|
+
if (layout.explicitAlignment) {
|
|
2444
|
+
const bounds = { x: 0, y: 0, ...size };
|
|
2445
|
+
for (const guide of GUIDES) {
|
|
2446
|
+
const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
|
|
2447
|
+
if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
|
|
2484
2448
|
}
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2449
|
+
}
|
|
2450
|
+
const sizes = {
|
|
2451
|
+
min: measure({ width: 0, height: 0 }),
|
|
2452
|
+
ideal: measure({ width: null, height: null }),
|
|
2453
|
+
max: measure({ width: Infinity, height: Infinity })
|
|
2488
2454
|
};
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
return applyModifiers(sb("navlink", linkProps, { tap }, label), modifiers);
|
|
2493
|
-
}
|
|
2494
|
-
const SplitSelectionContext = createContext(null);
|
|
2495
|
-
function splitColumnWidthHint(width) {
|
|
2496
|
-
if (typeof width === "number") return { min: width, ideal: width, max: width };
|
|
2497
|
-
return { ...width.min !== void 0 ? { min: width.min } : {}, ideal: width.ideal, ...width.max !== void 0 ? { max: width.max } : {} };
|
|
2455
|
+
const { width, height } = record.proposal;
|
|
2456
|
+
if (width !== null && Number.isFinite(width) && height !== null) sizes.atWidth = measure({ width, height: null });
|
|
2457
|
+
return { size, frames: placed, guides, sizes };
|
|
2498
2458
|
}
|
|
2499
|
-
function
|
|
2459
|
+
function Layout(props) {
|
|
2500
2460
|
const { own, modifiers } = splitProps(props);
|
|
2501
|
-
const
|
|
2502
|
-
|
|
2503
|
-
const
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2461
|
+
const [record, setRecord] = useState(null);
|
|
2462
|
+
let layoutProps = { proposal: null, size: null, frames: null };
|
|
2463
|
+
const guideModifiers = [];
|
|
2464
|
+
if (record) {
|
|
2465
|
+
const answer = answerLayout(own.layout, record, subviewTraits(own.children));
|
|
2466
|
+
for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
|
|
2467
|
+
const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
|
|
2468
|
+
const round2 = (value) => Math.round(value * 100) / 100;
|
|
2469
|
+
layoutProps = {
|
|
2470
|
+
proposal: {
|
|
2471
|
+
width: record.proposal.width === null ? null : toDimension(record.proposal.width),
|
|
2472
|
+
height: record.proposal.height === null ? null : toDimension(record.proposal.height)
|
|
2510
2473
|
},
|
|
2511
|
-
|
|
2512
|
-
|
|
2474
|
+
size: { width: round2(answer.size.width), height: round2(answer.size.height) },
|
|
2475
|
+
frames: answer.frames.map((frame2) => ({ x: round2(frame2.x), y: round2(frame2.y), width: round2(frame2.width), height: round2(frame2.height) })),
|
|
2476
|
+
sizes: {
|
|
2477
|
+
min: encode(answer.sizes.min),
|
|
2478
|
+
ideal: encode(answer.sizes.ideal),
|
|
2479
|
+
max: encode(answer.sizes.max),
|
|
2480
|
+
...answer.sizes.atWidth ? { atWidth: encode(answer.sizes.atWidth) } : {}
|
|
2513
2481
|
}
|
|
2514
2482
|
};
|
|
2515
|
-
});
|
|
2516
|
-
const clear = () => {
|
|
2517
|
-
for (const entry of reporters.current.values()) {
|
|
2518
|
-
if (!entry.selected) continue;
|
|
2519
|
-
entry.clear();
|
|
2520
|
-
entry.selected = false;
|
|
2521
|
-
}
|
|
2522
|
-
settle();
|
|
2523
|
-
};
|
|
2524
|
-
const [internal, setInternal] = useState("automatic");
|
|
2525
|
-
const [visibility, setVisibility] = own.columnVisibility !== void 0 ? readBinding(own.columnVisibility, own.onColumnVisibilityChange) : [internal, setInternal];
|
|
2526
|
-
if (sizeClass === "compact") {
|
|
2527
|
-
return applyModifiers(/* @__PURE__ */ jsx(CompactSplit, { sidebar: own.sidebar, detail: own.detail, report, selected, clear }), modifiers);
|
|
2528
2483
|
}
|
|
2529
|
-
const sidebarVisible = visibility !== "detailOnly";
|
|
2530
|
-
const toggle = () => withAnimation(() => setVisibility(sidebarVisible ? "detailOnly" : "all"));
|
|
2531
|
-
const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
|
|
2532
|
-
const sidebar = own.sidebarWidth !== void 0 ? sb("styled", { style: { splitColumnWidth: splitColumnWidthHint(own.sidebarWidth) } }, void 0, own.sidebar) : own.sidebar;
|
|
2533
2484
|
return applyModifiers(
|
|
2534
|
-
sb("navsplit", { sidebarVisible }, { tap: toggle, columnwidth: (event) => own.onSidebarWidthChange?.(event.width) }, [
|
|
2535
|
-
/* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: sidebar }) }, "sidebar"),
|
|
2536
|
-
/* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
|
|
2537
|
-
]),
|
|
2538
|
-
modifiers
|
|
2539
|
-
);
|
|
2540
|
-
}
|
|
2541
|
-
function SplitColumn({ report, children }) {
|
|
2542
|
-
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children }) });
|
|
2543
|
-
}
|
|
2544
|
-
function CompactSplit({
|
|
2545
|
-
sidebar,
|
|
2546
|
-
detail,
|
|
2547
|
-
report,
|
|
2548
|
-
selected,
|
|
2549
|
-
clear
|
|
2550
|
-
}) {
|
|
2551
|
-
const [internal, setInternal] = useState([]);
|
|
2552
|
-
const detailStack = isValidElement(detail) && detail.type === NavigationStack ? detail.props : null;
|
|
2553
|
-
const [extra, setExtra] = detailStack?.path !== void 0 ? readBinding(detailStack.path, detailStack.onPathChange) : [internal, setInternal];
|
|
2554
|
-
const base = selected ? [{ view: detail }] : [];
|
|
2555
|
-
const path = [...base, ...extra];
|
|
2556
|
-
const setPath = (next) => {
|
|
2557
|
-
if (selected && next.length === 0) {
|
|
2558
|
-
setExtra([]);
|
|
2559
|
-
clear();
|
|
2560
|
-
return;
|
|
2561
|
-
}
|
|
2562
|
-
setExtra(next.slice(base.length));
|
|
2563
|
-
};
|
|
2564
|
-
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children: /* @__PURE__ */ jsx(NavigationStack, { path: [path, setPath], children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children: sidebar }) }) }) });
|
|
2565
|
-
}
|
|
2566
|
-
function useReportSplitSelection(split, selected, clear, active2 = true) {
|
|
2567
|
-
const key = useRef({}).current;
|
|
2568
|
-
useLayoutEffect(() => {
|
|
2569
|
-
if (active2) split?.report(key, selected, clear);
|
|
2570
|
-
else split?.retract(key);
|
|
2571
|
-
});
|
|
2572
|
-
useLayoutEffect(() => () => split?.retract(key), [split, key]);
|
|
2573
|
-
return (nowSelected, nowClear) => {
|
|
2574
|
-
if (active2) split?.report(key, nowSelected, nowClear);
|
|
2575
|
-
};
|
|
2576
|
-
}
|
|
2577
|
-
function OutsideSplit({ children }) {
|
|
2578
|
-
return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
|
|
2579
|
-
}
|
|
2580
|
-
function SheetPresenter({ isPresented, onDismiss, content, fullScreen, inherited }) {
|
|
2581
|
-
const around = useInheritedStyles();
|
|
2582
|
-
const [presented, setPresented] = readBinding(isPresented);
|
|
2583
|
-
if (!presented) return null;
|
|
2584
|
-
const dismiss = () => {
|
|
2585
|
-
setPresented(false);
|
|
2586
|
-
onDismiss?.();
|
|
2587
|
-
};
|
|
2588
|
-
const detents = fullScreen ? ["full"] : ["large"];
|
|
2589
|
-
return sb(
|
|
2590
|
-
HOIST_KIND,
|
|
2591
|
-
void 0,
|
|
2592
|
-
void 0,
|
|
2593
|
-
sb(
|
|
2594
|
-
"sheet",
|
|
2595
|
-
{ detents },
|
|
2596
|
-
{ tap: dismiss },
|
|
2597
|
-
replayStyles(
|
|
2598
|
-
inherited && inherited.length > 0 ? [...around, ...inherited] : around,
|
|
2599
|
-
/* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(OutsideSplit, { children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) }) })
|
|
2600
|
-
)
|
|
2601
|
-
),
|
|
2602
|
-
"root"
|
|
2603
|
-
);
|
|
2604
|
-
}
|
|
2605
|
-
function presentationDetents(detents) {
|
|
2606
|
-
const encoded = detents.map(
|
|
2607
|
-
(detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
|
|
2608
|
-
);
|
|
2609
|
-
return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
|
|
2610
|
-
}
|
|
2611
|
-
function AlertPresenter({ title, isPresented, message, actions, style }) {
|
|
2612
|
-
const [presented, setPresented] = readBinding(isPresented);
|
|
2613
|
-
if (!presented) return null;
|
|
2614
|
-
const dismiss = () => setPresented(false);
|
|
2615
|
-
return sb(
|
|
2616
|
-
HOIST_KIND,
|
|
2617
|
-
void 0,
|
|
2618
|
-
void 0,
|
|
2619
2485
|
sb(
|
|
2620
|
-
"
|
|
2621
|
-
|
|
2622
|
-
{
|
|
2623
|
-
|
|
2486
|
+
"layout",
|
|
2487
|
+
layoutProps,
|
|
2488
|
+
{
|
|
2489
|
+
layout: (event) => {
|
|
2490
|
+
const proposal = event.proposal;
|
|
2491
|
+
setRecord({
|
|
2492
|
+
proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
|
|
2493
|
+
children: event.children
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
},
|
|
2497
|
+
own.children
|
|
2624
2498
|
),
|
|
2625
|
-
|
|
2499
|
+
[...guideModifiers, ...modifiers]
|
|
2626
2500
|
);
|
|
2627
2501
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2502
|
+
const IDENTITY$1 = {
|
|
2503
|
+
offsetX: 0,
|
|
2504
|
+
offsetY: 0,
|
|
2505
|
+
scaleX: 1,
|
|
2506
|
+
scaleY: 1,
|
|
2507
|
+
rotation: 0,
|
|
2508
|
+
opacity: 1,
|
|
2509
|
+
blur: 0,
|
|
2510
|
+
brightness: 0,
|
|
2511
|
+
contrast: 1,
|
|
2512
|
+
saturation: 1,
|
|
2513
|
+
grayscale: 0,
|
|
2514
|
+
hueRotation: 0
|
|
2515
|
+
};
|
|
2516
|
+
class VisualEffect {
|
|
2517
|
+
/** @internal */
|
|
2518
|
+
constructor(values = IDENTITY$1) {
|
|
2519
|
+
this.values = values;
|
|
2520
|
+
}
|
|
2521
|
+
values;
|
|
2522
|
+
with(patch) {
|
|
2523
|
+
return new VisualEffect({ ...this.values, ...patch });
|
|
2524
|
+
}
|
|
2525
|
+
offset(offset) {
|
|
2526
|
+
return this.with({ offsetX: this.values.offsetX + (offset.x ?? 0), offsetY: this.values.offsetY + (offset.y ?? 0) });
|
|
2527
|
+
}
|
|
2528
|
+
scaleEffect(scale, anchor) {
|
|
2529
|
+
const x = typeof scale === "number" ? scale : scale.x ?? 1;
|
|
2530
|
+
const y = typeof scale === "number" ? scale : scale.y ?? 1;
|
|
2531
|
+
return this.with({ scaleX: this.values.scaleX * x, scaleY: this.values.scaleY * y, ...anchor !== void 0 ? { scaleAnchor: unitPoint(anchor) } : {} });
|
|
2532
|
+
}
|
|
2533
|
+
/** Degrees. */
|
|
2534
|
+
rotationEffect(degrees, anchor) {
|
|
2535
|
+
return this.with({ rotation: this.values.rotation + degrees, ...anchor !== void 0 ? { rotationAnchor: unitPoint(anchor) } : {} });
|
|
2536
|
+
}
|
|
2537
|
+
rotation3DEffect(spec) {
|
|
2538
|
+
const rotation = { angle: spec.angle, axis: spec.axis };
|
|
2539
|
+
if (spec.anchor !== void 0) rotation.anchor = unitPoint(spec.anchor);
|
|
2540
|
+
if (spec.perspective !== void 0) rotation.perspective = spec.perspective;
|
|
2541
|
+
return this.with({ rotation3D: rotation });
|
|
2542
|
+
}
|
|
2543
|
+
opacity(opacity2) {
|
|
2544
|
+
return this.with({ opacity: this.values.opacity * opacity2 });
|
|
2545
|
+
}
|
|
2546
|
+
blur(radius) {
|
|
2547
|
+
return this.with({ blur: this.values.blur + radius });
|
|
2548
|
+
}
|
|
2549
|
+
brightness(amount) {
|
|
2550
|
+
return this.with({ brightness: this.values.brightness + amount });
|
|
2551
|
+
}
|
|
2552
|
+
contrast(amount) {
|
|
2553
|
+
return this.with({ contrast: this.values.contrast * amount });
|
|
2554
|
+
}
|
|
2555
|
+
saturation(amount) {
|
|
2556
|
+
return this.with({ saturation: this.values.saturation * amount });
|
|
2557
|
+
}
|
|
2558
|
+
grayscale(amount) {
|
|
2559
|
+
return this.with({ grayscale: Math.min(1, this.values.grayscale + amount) });
|
|
2560
|
+
}
|
|
2561
|
+
/** Degrees. */
|
|
2562
|
+
hueRotation(degrees) {
|
|
2563
|
+
return this.with({ hueRotation: this.values.hueRotation + degrees });
|
|
2564
|
+
}
|
|
2634
2565
|
}
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2566
|
+
const EMPTY_EFFECT = new VisualEffect();
|
|
2567
|
+
const round = (value) => Math.round(value * 1e3) / 1e3;
|
|
2568
|
+
function effectStyle(values) {
|
|
2569
|
+
const style = {};
|
|
2570
|
+
if (values.offsetX !== 0 || values.offsetY !== 0) style.offset = { x: round(values.offsetX), y: round(values.offsetY) };
|
|
2571
|
+
if (values.scaleX !== 1 || values.scaleY !== 1) {
|
|
2572
|
+
style.scale = { x: round(values.scaleX), y: round(values.scaleY) };
|
|
2573
|
+
if (values.scaleAnchor) style.scaleAnchor = values.scaleAnchor;
|
|
2574
|
+
}
|
|
2575
|
+
if (values.rotation !== 0) {
|
|
2576
|
+
style.rotation = round(values.rotation);
|
|
2577
|
+
if (values.rotationAnchor) style.rotationAnchor = values.rotationAnchor;
|
|
2643
2578
|
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
return
|
|
2579
|
+
if (values.rotation3D && values.rotation3D.angle !== 0) style.rotation3D = { ...values.rotation3D, angle: round(values.rotation3D.angle) };
|
|
2580
|
+
if (values.opacity !== 1) style.opacity = round(values.opacity);
|
|
2581
|
+
if (values.blur !== 0) style.blur = round(values.blur);
|
|
2582
|
+
if (values.brightness !== 0) style.brightness = round(values.brightness);
|
|
2583
|
+
if (values.contrast !== 1) style.contrast = round(values.contrast);
|
|
2584
|
+
if (values.saturation !== 1) style.saturation = round(values.saturation);
|
|
2585
|
+
if (values.grayscale !== 0) style.grayscale = round(values.grayscale);
|
|
2586
|
+
if (values.hueRotation !== 0) style.hueRotation = round(values.hueRotation);
|
|
2587
|
+
return style;
|
|
2653
2588
|
}
|
|
2654
|
-
function
|
|
2655
|
-
const
|
|
2656
|
-
|
|
2589
|
+
function EffectBox({ render, children }) {
|
|
2590
|
+
const [reported, setReported] = useState(NO_GEOMETRY);
|
|
2591
|
+
const [needsFrame, setNeedsFrame] = useState(false);
|
|
2592
|
+
let readFrame = false;
|
|
2593
|
+
const style = render(reported, () => {
|
|
2594
|
+
readFrame = true;
|
|
2595
|
+
});
|
|
2657
2596
|
useEffect(() => {
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2597
|
+
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
2598
|
+
});
|
|
2599
|
+
const content = Object.keys(style).length > 0 ? sb("styled", { style }, void 0, children) : children;
|
|
2600
|
+
return sb(
|
|
2601
|
+
"zstack",
|
|
2602
|
+
{ alignment: "center", reportsSize: true, ...needsFrame ? { reportsFrame: true } : {} },
|
|
2603
|
+
{
|
|
2604
|
+
geometry: (event) => {
|
|
2605
|
+
const next = nextGeometry(event, reported);
|
|
2606
|
+
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
2607
|
+
}
|
|
2608
|
+
},
|
|
2609
|
+
content
|
|
2610
|
+
);
|
|
2665
2611
|
}
|
|
2666
|
-
function
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
}
|
|
2683
|
-
|
|
2612
|
+
function VisualEffectView({ effect, children }) {
|
|
2613
|
+
const spaces = useCoordinateSpaces();
|
|
2614
|
+
return /* @__PURE__ */ jsx(EffectBox, { render: (reported, markRead) => effectStyle(effect(EMPTY_EFFECT, geometryProxy(reported, spaces, markRead)).values), children });
|
|
2615
|
+
}
|
|
2616
|
+
const PHASES = {
|
|
2617
|
+
topLeading: { phase: "topLeading", value: -1, isIdentity: false },
|
|
2618
|
+
identity: { phase: "identity", value: 0, isIdentity: true },
|
|
2619
|
+
bottomTrailing: { phase: "bottomTrailing", value: 1, isIdentity: false }
|
|
2620
|
+
};
|
|
2621
|
+
function ScrollTransitionView({ spec, children }) {
|
|
2622
|
+
const phase = (which) => effectStyle(spec.transition(EMPTY_EFFECT, PHASES[which]).values);
|
|
2623
|
+
const transition = {
|
|
2624
|
+
configuration: spec.configuration ?? "interactive",
|
|
2625
|
+
identity: phase("identity"),
|
|
2626
|
+
topLeading: phase("topLeading"),
|
|
2627
|
+
bottomTrailing: phase("bottomTrailing")
|
|
2628
|
+
};
|
|
2629
|
+
if (spec.axis) transition.axis = spec.axis;
|
|
2630
|
+
return sb("styled", { style: { scrollTransition: transition } }, void 0, children);
|
|
2684
2631
|
}
|
|
2685
2632
|
function Hover({ action, children }) {
|
|
2686
2633
|
return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
|
|
@@ -3644,345 +3591,404 @@ function TextInputHint({ hint, children }) {
|
|
|
3644
3591
|
const outer = useViewEnvironment().textInputHints;
|
|
3645
3592
|
return withEnvironment({ textInputHints: { ...outer, ...hint } }, children);
|
|
3646
3593
|
}
|
|
3647
|
-
|
|
3648
|
-
const
|
|
3649
|
-
|
|
3650
|
-
const hasOrigin = event.x !== void 0 && event.y !== void 0;
|
|
3651
|
-
return {
|
|
3652
|
-
size: { width: event.width, height: event.height },
|
|
3653
|
-
origin: hasOrigin ? { x: event.x, y: event.y } : reported.origin,
|
|
3654
|
-
safeArea: event.safeArea ?? reported.safeArea,
|
|
3655
|
-
// A frame report without a scroll view means the reader is in none.
|
|
3656
|
-
scrollView: hasOrigin ? event.scrollView ?? null : reported.scrollView
|
|
3657
|
-
};
|
|
3594
|
+
function HostElement(props) {
|
|
3595
|
+
const { own, modifiers } = splitProps(props);
|
|
3596
|
+
return applyModifiers(sb(own.kind, own.props ? { ...own.props } : void 0, void 0, own.children), modifiers);
|
|
3658
3597
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
if (space === "global") return { ...origin, ...reported.size };
|
|
3667
|
-
const named = spaces[space.named];
|
|
3668
|
-
return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
|
|
3669
|
-
},
|
|
3670
|
-
bounds: () => {
|
|
3671
|
-
onReadFrame();
|
|
3672
|
-
const view = reported.scrollView;
|
|
3673
|
-
if (!view || !reported.origin) return null;
|
|
3674
|
-
return { x: view.x - reported.origin.x, y: view.y - reported.origin.y, width: view.width, height: view.height };
|
|
3675
|
-
},
|
|
3676
|
-
get safeAreaInsets() {
|
|
3677
|
-
onReadFrame();
|
|
3678
|
-
return reported.safeArea;
|
|
3679
|
-
}
|
|
3680
|
-
};
|
|
3598
|
+
let installed = null;
|
|
3599
|
+
function installTextMeasurer(measurer, remove = false) {
|
|
3600
|
+
if (remove) {
|
|
3601
|
+
if (installed === measurer) installed = null;
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
installed = measurer;
|
|
3681
3605
|
}
|
|
3682
|
-
function
|
|
3683
|
-
|
|
3684
|
-
const [reported, setReported] = useState(NO_GEOMETRY);
|
|
3685
|
-
const [needsFrame, setNeedsFrame] = useState(false);
|
|
3686
|
-
let readFrame = false;
|
|
3687
|
-
const proxy = geometryProxy(reported, useCoordinateSpaces(), () => {
|
|
3688
|
-
readFrame = true;
|
|
3689
|
-
});
|
|
3690
|
-
const content = own.children(proxy);
|
|
3691
|
-
useEffect(() => {
|
|
3692
|
-
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
3693
|
-
});
|
|
3694
|
-
return applyModifiers(
|
|
3695
|
-
sb(
|
|
3696
|
-
"geometry",
|
|
3697
|
-
needsFrame ? { reportsFrame: true } : {},
|
|
3698
|
-
{
|
|
3699
|
-
geometry: (event) => {
|
|
3700
|
-
const next = nextGeometry(event, reported);
|
|
3701
|
-
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
3702
|
-
}
|
|
3703
|
-
},
|
|
3704
|
-
content
|
|
3705
|
-
),
|
|
3706
|
-
modifiers
|
|
3707
|
-
);
|
|
3606
|
+
function canMeasureText() {
|
|
3607
|
+
return installed !== null;
|
|
3708
3608
|
}
|
|
3709
|
-
function
|
|
3710
|
-
|
|
3711
|
-
const
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
"
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3609
|
+
function measureText(text, font$1 = "body", width) {
|
|
3610
|
+
if (!installed) throw new Error("measureText: nothing measures text here yet (mount the app, or run it in a SwiftBrowser Native host)");
|
|
3611
|
+
const constrained = typeof width === "number" && Number.isFinite(width) && width > 0 ? width : null;
|
|
3612
|
+
return installed(text, font(font$1), constrained);
|
|
3613
|
+
}
|
|
3614
|
+
function decidePlatform(width, media = matchesMedia) {
|
|
3615
|
+
return horizontalSizeClassFor(width) === "regular" && media("(hover: hover) and (pointer: fine)") ? "macos" : "ios";
|
|
3616
|
+
}
|
|
3617
|
+
function matchesMedia(query) {
|
|
3618
|
+
return typeof matchMedia === "function" && matchMedia(query).matches;
|
|
3619
|
+
}
|
|
3620
|
+
function mount(screen, element, options = {}) {
|
|
3621
|
+
let renderer = null;
|
|
3622
|
+
const root = createSwiftUIRoot((ops) => renderer?.applyOps(ops));
|
|
3623
|
+
renderer = new Renderer(screen, (event) => root.dispatch(event));
|
|
3624
|
+
renderer.fileDrops = "reference";
|
|
3625
|
+
const measurer = (text, font2, width2) => renderer.measureText(text, font2, width2);
|
|
3626
|
+
installTextMeasurer(measurer);
|
|
3627
|
+
let pageScheme = options.colorScheme ?? "light";
|
|
3628
|
+
let preferred = null;
|
|
3629
|
+
const width = screen.clientWidth || 393;
|
|
3630
|
+
const environment = {
|
|
3631
|
+
colorScheme: pageScheme,
|
|
3632
|
+
dynamicTypeSize: options.dynamicTypeSize ?? "large",
|
|
3633
|
+
horizontalSizeClass: horizontalSizeClassFor(width),
|
|
3634
|
+
scenePhase: typeof document !== "undefined" ? currentScenePhase() : "active",
|
|
3635
|
+
platform: options.platform === void 0 || options.platform === "auto" ? decidePlatform(width) : options.platform
|
|
3636
|
+
};
|
|
3637
|
+
renderer.contentHeight = options.contentHeight ?? false;
|
|
3638
|
+
if (options.sidebarTitleBar === false) renderer.sidebarTitleBar = false;
|
|
3639
|
+
if (options.assets) renderer.setAssetCatalog(options.assets);
|
|
3640
|
+
if (options.app) browserEnvironment.files?.setApp?.(options.app);
|
|
3641
|
+
renderer.setEnvironment({ colorScheme: environment.colorScheme, dynamicTypeSize: environment.dynamicTypeSize, platform: environment.platform });
|
|
3642
|
+
if (options.safeArea !== void 0) renderer.setSafeArea(options.safeArea);
|
|
3643
|
+
root.setEnvironment(environment);
|
|
3644
|
+
const browserHistory = (options.history ?? true) && typeof window !== "undefined" ? new BrowserHistory(renderer, screen) : null;
|
|
3645
|
+
browserHistory?.enable();
|
|
3646
|
+
const stopKeyboard = options.keyboard && typeof window !== "undefined" ? watchKeyboard((height) => renderer?.setKeyboard(height), { root: screen }) : null;
|
|
3647
|
+
const applyScheme = () => {
|
|
3648
|
+
const scheme = preferred ?? pageScheme;
|
|
3649
|
+
const device = screen.closest(".device");
|
|
3650
|
+
if (device) device.dataset["theme"] = scheme;
|
|
3651
|
+
renderer?.setEnvironment({ colorScheme: scheme });
|
|
3652
|
+
root.setEnvironment({ colorScheme: scheme });
|
|
3653
|
+
};
|
|
3654
|
+
const onPreferredScheme = (event) => {
|
|
3655
|
+
const scheme = event.detail.colorScheme;
|
|
3656
|
+
preferred = scheme;
|
|
3657
|
+
queueMicrotask(applyScheme);
|
|
3658
|
+
};
|
|
3659
|
+
screen.addEventListener("sb:color-scheme", onPreferredScheme);
|
|
3660
|
+
let sizeClass = environment.horizontalSizeClass;
|
|
3661
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
3662
|
+
const next = horizontalSizeClassFor(screen.clientWidth);
|
|
3663
|
+
if (next === sizeClass) return;
|
|
3664
|
+
sizeClass = next;
|
|
3665
|
+
root.setEnvironment({ horizontalSizeClass: next });
|
|
3666
|
+
}) : null;
|
|
3667
|
+
observer?.observe(screen);
|
|
3668
|
+
const stopScenePhase = typeof document !== "undefined" ? watchScenePhase((scenePhase) => root.setEnvironment({ scenePhase })) : null;
|
|
3669
|
+
root.render(element);
|
|
3670
|
+
const mounted = {
|
|
3671
|
+
root,
|
|
3672
|
+
renderer,
|
|
3673
|
+
setEnvironment(next) {
|
|
3674
|
+
if (next.colorScheme !== void 0) pageScheme = next.colorScheme;
|
|
3675
|
+
const scheme = preferred ?? pageScheme;
|
|
3676
|
+
renderer?.setEnvironment({ ...next, colorScheme: scheme });
|
|
3677
|
+
root.setEnvironment({ ...next, colorScheme: scheme });
|
|
3742
3678
|
},
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
}
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
});
|
|
3759
|
-
const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
|
|
3760
|
-
function clamp(value, min, max) {
|
|
3761
|
-
return Math.min(Math.max(value, min), max);
|
|
3762
|
-
}
|
|
3763
|
-
function answerLayout(layout, record, traits = []) {
|
|
3764
|
-
const frames = record.children.map(() => null);
|
|
3765
|
-
const subviews = record.children.map((measurement, index) => {
|
|
3766
|
-
const min = toSize(measurement.min);
|
|
3767
|
-
const ideal = toSize(measurement.ideal);
|
|
3768
|
-
const max = toSize(measurement.max);
|
|
3769
|
-
const sizeThatFits = (proposal) => ({
|
|
3770
|
-
width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
|
|
3771
|
-
height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
|
|
3772
|
-
});
|
|
3773
|
-
return {
|
|
3774
|
-
min,
|
|
3775
|
-
ideal,
|
|
3776
|
-
max,
|
|
3777
|
-
priority: traits[index]?.priority ?? 0,
|
|
3778
|
-
values: traits[index]?.values ?? {},
|
|
3779
|
-
spacing: DEFAULT_VIEW_SPACING,
|
|
3780
|
-
sizeThatFits,
|
|
3781
|
-
place: ({ x, y, anchor, proposal }) => {
|
|
3782
|
-
const size2 = sizeThatFits(proposal ?? { width: null, height: null });
|
|
3783
|
-
const point = unitPoint(anchor ?? "topLeading");
|
|
3784
|
-
frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
|
|
3785
|
-
}
|
|
3786
|
-
};
|
|
3787
|
-
});
|
|
3788
|
-
const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
|
|
3789
|
-
const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
|
|
3790
|
-
const size = measure(record.proposal);
|
|
3791
|
-
layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
|
|
3792
|
-
const placed = frames.map((frame2, index) => {
|
|
3793
|
-
if (frame2) return frame2;
|
|
3794
|
-
const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
|
|
3795
|
-
return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
|
|
3796
|
-
});
|
|
3797
|
-
const guides = {};
|
|
3798
|
-
if (layout.explicitAlignment) {
|
|
3799
|
-
const bounds = { x: 0, y: 0, ...size };
|
|
3800
|
-
for (const guide of GUIDES) {
|
|
3801
|
-
const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
|
|
3802
|
-
if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
|
|
3679
|
+
setSafeArea(insets2) {
|
|
3680
|
+
renderer?.setSafeArea(insets2);
|
|
3681
|
+
},
|
|
3682
|
+
viewportChanged() {
|
|
3683
|
+
renderer?.viewportChanged();
|
|
3684
|
+
},
|
|
3685
|
+
unmount() {
|
|
3686
|
+
observer?.disconnect();
|
|
3687
|
+
stopScenePhase?.();
|
|
3688
|
+
stopKeyboard?.();
|
|
3689
|
+
browserHistory?.dispose();
|
|
3690
|
+
screen.removeEventListener("sb:color-scheme", onPreferredScheme);
|
|
3691
|
+
installTextMeasurer(measurer, true);
|
|
3692
|
+
root.unmount();
|
|
3693
|
+
renderer?.dispose();
|
|
3803
3694
|
}
|
|
3804
|
-
}
|
|
3805
|
-
const sizes = {
|
|
3806
|
-
min: measure({ width: 0, height: 0 }),
|
|
3807
|
-
ideal: measure({ width: null, height: null }),
|
|
3808
|
-
max: measure({ width: Infinity, height: Infinity })
|
|
3809
3695
|
};
|
|
3810
|
-
|
|
3811
|
-
if (width !== null && Number.isFinite(width) && height !== null) sizes.atWidth = measure({ width, height: null });
|
|
3812
|
-
return { size, frames: placed, guides, sizes };
|
|
3813
|
-
}
|
|
3814
|
-
function Layout(props) {
|
|
3815
|
-
const { own, modifiers } = splitProps(props);
|
|
3816
|
-
const [record, setRecord] = useState(null);
|
|
3817
|
-
let layoutProps = { proposal: null, size: null, frames: null };
|
|
3818
|
-
const guideModifiers = [];
|
|
3819
|
-
if (record) {
|
|
3820
|
-
const answer = answerLayout(own.layout, record, subviewTraits(own.children));
|
|
3821
|
-
for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
|
|
3822
|
-
const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
|
|
3823
|
-
const round2 = (value) => Math.round(value * 100) / 100;
|
|
3824
|
-
layoutProps = {
|
|
3825
|
-
proposal: {
|
|
3826
|
-
width: record.proposal.width === null ? null : toDimension(record.proposal.width),
|
|
3827
|
-
height: record.proposal.height === null ? null : toDimension(record.proposal.height)
|
|
3828
|
-
},
|
|
3829
|
-
size: { width: round2(answer.size.width), height: round2(answer.size.height) },
|
|
3830
|
-
frames: answer.frames.map((frame2) => ({ x: round2(frame2.x), y: round2(frame2.y), width: round2(frame2.width), height: round2(frame2.height) })),
|
|
3831
|
-
sizes: {
|
|
3832
|
-
min: encode(answer.sizes.min),
|
|
3833
|
-
ideal: encode(answer.sizes.ideal),
|
|
3834
|
-
max: encode(answer.sizes.max),
|
|
3835
|
-
...answer.sizes.atWidth ? { atWidth: encode(answer.sizes.atWidth) } : {}
|
|
3836
|
-
}
|
|
3837
|
-
};
|
|
3838
|
-
}
|
|
3839
|
-
return applyModifiers(
|
|
3840
|
-
sb(
|
|
3841
|
-
"layout",
|
|
3842
|
-
layoutProps,
|
|
3843
|
-
{
|
|
3844
|
-
layout: (event) => {
|
|
3845
|
-
const proposal = event.proposal;
|
|
3846
|
-
setRecord({
|
|
3847
|
-
proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
|
|
3848
|
-
children: event.children
|
|
3849
|
-
});
|
|
3850
|
-
}
|
|
3851
|
-
},
|
|
3852
|
-
own.children
|
|
3853
|
-
),
|
|
3854
|
-
[...guideModifiers, ...modifiers]
|
|
3855
|
-
);
|
|
3696
|
+
return mounted;
|
|
3856
3697
|
}
|
|
3857
|
-
const
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
scaleY: 1,
|
|
3862
|
-
rotation: 0,
|
|
3863
|
-
opacity: 1,
|
|
3864
|
-
blur: 0,
|
|
3865
|
-
brightness: 0,
|
|
3866
|
-
contrast: 1,
|
|
3867
|
-
saturation: 1,
|
|
3868
|
-
grayscale: 0,
|
|
3869
|
-
hueRotation: 0
|
|
3698
|
+
const EMPTY = { canUndo: false, canRedo: false, undoActionName: "", redoActionName: "" };
|
|
3699
|
+
const defaultSchedule = (close) => {
|
|
3700
|
+
if (typeof queueMicrotask === "function") queueMicrotask(close);
|
|
3701
|
+
else void Promise.resolve().then(close);
|
|
3870
3702
|
};
|
|
3871
|
-
class
|
|
3872
|
-
/**
|
|
3873
|
-
|
|
3874
|
-
|
|
3703
|
+
class UndoManager {
|
|
3704
|
+
/** Whether registrations in one event (one task of the event loop) form one group; true, as `groupsByEvent`. */
|
|
3705
|
+
groupsByEvent = true;
|
|
3706
|
+
/** How many groups the undo stack keeps; 0 for no limit, as `levelsOfUndo`. */
|
|
3707
|
+
levelsOfUndo = 0;
|
|
3708
|
+
undoStack = [];
|
|
3709
|
+
redoStack = [];
|
|
3710
|
+
/** The group registrations go in: an explicit group, the event's group, or the inverse of what is being undone or redone. */
|
|
3711
|
+
open = null;
|
|
3712
|
+
/** How deep `beginGrouping` is; 0 when `open` is the event's group or an inverse. */
|
|
3713
|
+
depth = 0;
|
|
3714
|
+
/** Whether `open` is the event's group, which `schedule` closes. */
|
|
3715
|
+
byEvent = false;
|
|
3716
|
+
/** The last keyed group closed onto the undo stack, which a registration with its key joins. */
|
|
3717
|
+
coalescing = null;
|
|
3718
|
+
undoing = false;
|
|
3719
|
+
redoing = false;
|
|
3720
|
+
snapshot = EMPTY;
|
|
3721
|
+
listeners = /* @__PURE__ */ new Set();
|
|
3722
|
+
schedule;
|
|
3723
|
+
host;
|
|
3724
|
+
stopListening = null;
|
|
3725
|
+
constructor(options = {}) {
|
|
3726
|
+
this.schedule = options.schedule ?? defaultSchedule;
|
|
3727
|
+
this.host = options.host === void 0 ? browserEnvironment.undoManager ?? null : options.host;
|
|
3728
|
+
if (this.host) {
|
|
3729
|
+
this.stopListening = this.host.listen({ undo: () => this.undo(), redo: () => this.redo() });
|
|
3730
|
+
this.host.update(this.snapshot);
|
|
3731
|
+
}
|
|
3875
3732
|
}
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
return new VisualEffect({ ...this.values, ...patch });
|
|
3733
|
+
get canUndo() {
|
|
3734
|
+
return this.undoStack.length > 0;
|
|
3879
3735
|
}
|
|
3880
|
-
|
|
3881
|
-
return this.
|
|
3736
|
+
get canRedo() {
|
|
3737
|
+
return this.redoStack.length > 0;
|
|
3882
3738
|
}
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
return this.with({ scaleX: this.values.scaleX * x, scaleY: this.values.scaleY * y, ...anchor !== void 0 ? { scaleAnchor: unitPoint(anchor) } : {} });
|
|
3739
|
+
/** The name of what `undo` takes back ('' for none): "Move" for an Edit menu's "Undo Move". */
|
|
3740
|
+
get undoActionName() {
|
|
3741
|
+
return this.undoStack[this.undoStack.length - 1]?.name ?? "";
|
|
3887
3742
|
}
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3743
|
+
get redoActionName() {
|
|
3744
|
+
return this.redoStack[this.redoStack.length - 1]?.name ?? "";
|
|
3745
|
+
}
|
|
3746
|
+
get isUndoing() {
|
|
3747
|
+
return this.undoing;
|
|
3748
|
+
}
|
|
3749
|
+
get isRedoing() {
|
|
3750
|
+
return this.redoing;
|
|
3751
|
+
}
|
|
3752
|
+
/** What the stacks can do, one object per change (for `useSyncExternalStore`). */
|
|
3753
|
+
get state() {
|
|
3754
|
+
return this.snapshot;
|
|
3755
|
+
}
|
|
3756
|
+
/**
|
|
3757
|
+
* Registers what undoes the change just made, under `name`. Run by `undo`,
|
|
3758
|
+
* the closure registers its own inverse the same way, which lands on the
|
|
3759
|
+
* redo stack because the manager is undoing.
|
|
3760
|
+
*/
|
|
3761
|
+
registerUndo(name, undo, options = {}) {
|
|
3762
|
+
const action = { name, undo, target: options.target };
|
|
3763
|
+
if (this.undoing || this.redoing) {
|
|
3764
|
+
this.open.actions.push(action);
|
|
3765
|
+
this.changed();
|
|
3766
|
+
return;
|
|
3767
|
+
}
|
|
3768
|
+
this.redoStack = [];
|
|
3769
|
+
this.coalescing = this.coalescing && this.undoStack[this.undoStack.length - 1] === this.coalescing ? this.coalescing : null;
|
|
3770
|
+
if (this.open) {
|
|
3771
|
+
if (!this.undoStack.includes(this.open)) this.push(this.open);
|
|
3772
|
+
this.open.actions.push(action);
|
|
3773
|
+
if (!this.open.named) this.open.name = name;
|
|
3774
|
+
} else if (this.coalescing && options.key !== void 0 && this.coalescing.key === options.key) {
|
|
3775
|
+
this.coalescing.actions.push(action);
|
|
3776
|
+
this.coalescing.name = name;
|
|
3777
|
+
} else {
|
|
3778
|
+
const group = { name, named: false, actions: [action], key: options.key };
|
|
3779
|
+
this.push(group);
|
|
3780
|
+
this.coalescing = null;
|
|
3781
|
+
if (this.groupsByEvent) {
|
|
3782
|
+
this.open = group;
|
|
3783
|
+
this.byEvent = true;
|
|
3784
|
+
this.schedule(() => {
|
|
3785
|
+
if (this.open === group && this.byEvent) this.close();
|
|
3786
|
+
});
|
|
3787
|
+
} else {
|
|
3788
|
+
this.coalescing = group.key !== void 0 ? group : null;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
this.changed();
|
|
3792
|
+
}
|
|
3793
|
+
/** Takes back the top group of changes; its inverses become the top of the redo stack. */
|
|
3794
|
+
undo() {
|
|
3795
|
+
this.endOpenGroups();
|
|
3796
|
+
const group = this.undoStack.pop();
|
|
3797
|
+
if (!group) return;
|
|
3798
|
+
this.coalescing = null;
|
|
3799
|
+
this.run(group, "undo");
|
|
3800
|
+
}
|
|
3801
|
+
redo() {
|
|
3802
|
+
this.endOpenGroups();
|
|
3803
|
+
const group = this.redoStack.pop();
|
|
3804
|
+
if (!group) return;
|
|
3805
|
+
this.run(group, "redo");
|
|
3891
3806
|
}
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3807
|
+
/**
|
|
3808
|
+
* Starts a group: every registration until `endGrouping` undoes as one
|
|
3809
|
+
* (`beginUndoGrouping`). Nested calls join the outer group. The group is
|
|
3810
|
+
* named `name`, else after its last registration.
|
|
3811
|
+
*/
|
|
3812
|
+
beginGrouping(name) {
|
|
3813
|
+
if (this.undoing || this.redoing) return;
|
|
3814
|
+
this.depth += 1;
|
|
3815
|
+
if (this.depth > 1) return;
|
|
3816
|
+
if (this.open) this.close();
|
|
3817
|
+
this.open = { name: name ?? "", named: name !== void 0, actions: [], key: void 0 };
|
|
3818
|
+
this.byEvent = false;
|
|
3819
|
+
this.coalescing = null;
|
|
3897
3820
|
}
|
|
3898
|
-
|
|
3899
|
-
|
|
3821
|
+
/** Ends the group `beginGrouping` started; one that registered nothing is dropped. */
|
|
3822
|
+
endGrouping() {
|
|
3823
|
+
if (this.depth === 0) return;
|
|
3824
|
+
this.depth -= 1;
|
|
3825
|
+
if (this.depth === 0) this.close();
|
|
3900
3826
|
}
|
|
3901
|
-
|
|
3902
|
-
|
|
3827
|
+
/** `body` as one group named `name`. */
|
|
3828
|
+
group(name, body) {
|
|
3829
|
+
this.beginGrouping(name);
|
|
3830
|
+
try {
|
|
3831
|
+
return body();
|
|
3832
|
+
} finally {
|
|
3833
|
+
this.endGrouping();
|
|
3834
|
+
}
|
|
3903
3835
|
}
|
|
3904
|
-
|
|
3905
|
-
|
|
3836
|
+
/** Forgets every registration, or those `target` made (`removeAllActions(withTarget:)`), on both stacks and in the open group. */
|
|
3837
|
+
removeAllActions(target) {
|
|
3838
|
+
const mine = (action) => target === void 0 || action.target === target;
|
|
3839
|
+
const strip = (groups) => groups.filter((group) => {
|
|
3840
|
+
group.actions = group.actions.filter((action) => !mine(action));
|
|
3841
|
+
return group.actions.length > 0;
|
|
3842
|
+
});
|
|
3843
|
+
this.undoStack = strip(this.undoStack);
|
|
3844
|
+
this.redoStack = strip(this.redoStack);
|
|
3845
|
+
if (this.open) this.open.actions = this.open.actions.filter((action) => !mine(action));
|
|
3846
|
+
if (this.coalescing && !this.undoStack.includes(this.coalescing)) this.coalescing = null;
|
|
3847
|
+
this.changed();
|
|
3906
3848
|
}
|
|
3907
|
-
|
|
3908
|
-
|
|
3849
|
+
/** Calls `listener` after each change to `state`; returns what stops it. */
|
|
3850
|
+
subscribe = (listener) => {
|
|
3851
|
+
this.listeners.add(listener);
|
|
3852
|
+
return () => {
|
|
3853
|
+
this.listeners.delete(listener);
|
|
3854
|
+
};
|
|
3855
|
+
};
|
|
3856
|
+
/** Stops listening to the host, for a manager made in a test. */
|
|
3857
|
+
dispose() {
|
|
3858
|
+
this.stopListening?.();
|
|
3859
|
+
this.stopListening = null;
|
|
3909
3860
|
}
|
|
3910
|
-
|
|
3911
|
-
|
|
3861
|
+
push(group) {
|
|
3862
|
+
this.undoStack.push(group);
|
|
3863
|
+
if (this.levelsOfUndo > 0 && this.undoStack.length > this.levelsOfUndo) this.undoStack.splice(0, this.undoStack.length - this.levelsOfUndo);
|
|
3912
3864
|
}
|
|
3913
|
-
|
|
3914
|
-
|
|
3865
|
+
/** Closes `open`; a keyed group on top stays open to its key. */
|
|
3866
|
+
close() {
|
|
3867
|
+
const group = this.open;
|
|
3868
|
+
this.open = null;
|
|
3869
|
+
this.byEvent = false;
|
|
3870
|
+
if (group && group.key !== void 0 && this.undoStack[this.undoStack.length - 1] === group) this.coalescing = group;
|
|
3915
3871
|
}
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3872
|
+
endOpenGroups() {
|
|
3873
|
+
this.depth = 0;
|
|
3874
|
+
if (this.open) this.close();
|
|
3919
3875
|
}
|
|
3920
|
-
|
|
3921
|
-
const
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3876
|
+
run(group, direction) {
|
|
3877
|
+
const inverse = { name: group.name, named: true, actions: [], key: void 0 };
|
|
3878
|
+
this.open = inverse;
|
|
3879
|
+
this.byEvent = false;
|
|
3880
|
+
if (direction === "undo") this.undoing = true;
|
|
3881
|
+
else this.redoing = true;
|
|
3882
|
+
try {
|
|
3883
|
+
for (let i = group.actions.length - 1; i >= 0; i -= 1) group.actions[i].undo();
|
|
3884
|
+
} finally {
|
|
3885
|
+
this.undoing = false;
|
|
3886
|
+
this.redoing = false;
|
|
3887
|
+
this.open = null;
|
|
3888
|
+
if (inverse.actions.length > 0) {
|
|
3889
|
+
if (direction === "undo") this.redoStack.push(inverse);
|
|
3890
|
+
else this.push(inverse);
|
|
3891
|
+
}
|
|
3892
|
+
this.changed();
|
|
3893
|
+
}
|
|
3929
3894
|
}
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3895
|
+
changed() {
|
|
3896
|
+
const next = { canUndo: this.canUndo, canRedo: this.canRedo, undoActionName: this.undoActionName, redoActionName: this.redoActionName };
|
|
3897
|
+
const last = this.snapshot;
|
|
3898
|
+
if (next.canUndo === last.canUndo && next.canRedo === last.canRedo && next.undoActionName === last.undoActionName && next.redoActionName === last.redoActionName) return;
|
|
3899
|
+
this.snapshot = next;
|
|
3900
|
+
this.host?.update(next);
|
|
3901
|
+
for (const listener of [...this.listeners]) listener();
|
|
3933
3902
|
}
|
|
3934
|
-
if (values.rotation3D && values.rotation3D.angle !== 0) style.rotation3D = { ...values.rotation3D, angle: round(values.rotation3D.angle) };
|
|
3935
|
-
if (values.opacity !== 1) style.opacity = round(values.opacity);
|
|
3936
|
-
if (values.blur !== 0) style.blur = round(values.blur);
|
|
3937
|
-
if (values.brightness !== 0) style.brightness = round(values.brightness);
|
|
3938
|
-
if (values.contrast !== 1) style.contrast = round(values.contrast);
|
|
3939
|
-
if (values.saturation !== 1) style.saturation = round(values.saturation);
|
|
3940
|
-
if (values.grayscale !== 0) style.grayscale = round(values.grayscale);
|
|
3941
|
-
if (values.hueRotation !== 0) style.hueRotation = round(values.hueRotation);
|
|
3942
|
-
return style;
|
|
3943
3903
|
}
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
"zstack",
|
|
3957
|
-
{ alignment: "center", reportsSize: true, ...needsFrame ? { reportsFrame: true } : {} },
|
|
3958
|
-
{
|
|
3959
|
-
geometry: (event) => {
|
|
3960
|
-
const next = nextGeometry(event, reported);
|
|
3961
|
-
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
3962
|
-
}
|
|
3963
|
-
},
|
|
3964
|
-
content
|
|
3904
|
+
const UndoManagerContext = createContext(null);
|
|
3905
|
+
let shared = null;
|
|
3906
|
+
function sharedUndoManager() {
|
|
3907
|
+
shared ??= new UndoManager();
|
|
3908
|
+
return shared;
|
|
3909
|
+
}
|
|
3910
|
+
function useUndoManager() {
|
|
3911
|
+
const manager = useContext(UndoManagerContext) ?? sharedUndoManager();
|
|
3912
|
+
useSyncExternalStore(
|
|
3913
|
+
manager.subscribe,
|
|
3914
|
+
() => manager.state,
|
|
3915
|
+
() => manager.state
|
|
3965
3916
|
);
|
|
3917
|
+
return manager;
|
|
3966
3918
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3919
|
+
const OWN = [
|
|
3920
|
+
EnvironmentContext,
|
|
3921
|
+
ViewEnvironmentContext,
|
|
3922
|
+
NavigationContext,
|
|
3923
|
+
DismissContext,
|
|
3924
|
+
UndoManagerContext
|
|
3925
|
+
];
|
|
3926
|
+
function useContextBridge(contexts = [], options = {}) {
|
|
3927
|
+
const own = options.environment === false ? OWN.filter((context) => context !== EnvironmentContext) : OWN;
|
|
3928
|
+
const all = [...own, ...contexts];
|
|
3929
|
+
const values = all.map((context) => useContext(context));
|
|
3930
|
+
return (children) => all.reduceRight((inner, context, index) => createElement(context.Provider, { value: values[index] }, inner), children);
|
|
3970
3931
|
}
|
|
3971
|
-
const
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
}
|
|
3976
|
-
function
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3932
|
+
const WINDOW_TOP_INSET = 10;
|
|
3933
|
+
function insetsOf(safeArea, fit) {
|
|
3934
|
+
const given = typeof safeArea === "number" ? { top: safeArea } : safeArea ?? { top: fit === "fill" ? WINDOW_TOP_INSET : 0 };
|
|
3935
|
+
return { top: given.top ?? 0, leading: given.leading ?? 0, bottom: given.bottom ?? 0, trailing: given.trailing ?? 0 };
|
|
3936
|
+
}
|
|
3937
|
+
function SwiftUIView({
|
|
3938
|
+
children,
|
|
3939
|
+
fit = "fill",
|
|
3940
|
+
colorScheme = "light",
|
|
3941
|
+
dynamicTypeSize = "large",
|
|
3942
|
+
contexts,
|
|
3943
|
+
assets,
|
|
3944
|
+
safeArea,
|
|
3945
|
+
history = true,
|
|
3946
|
+
keyboard = fit === "fill",
|
|
3947
|
+
sidebarTitleBar = true,
|
|
3948
|
+
className,
|
|
3949
|
+
style
|
|
3950
|
+
}) {
|
|
3951
|
+
const device = useRef(null);
|
|
3952
|
+
const screen = useRef(null);
|
|
3953
|
+
const mounted = useRef(null);
|
|
3954
|
+
const bridge = useContextBridge(contexts, { environment: false });
|
|
3955
|
+
const tree = bridge(children);
|
|
3956
|
+
const latest = useRef(tree);
|
|
3957
|
+
latest.current = tree;
|
|
3958
|
+
useLayoutEffect(() => {
|
|
3959
|
+
if (!screen.current) return;
|
|
3960
|
+
const instance = mount(screen.current, latest.current, {
|
|
3961
|
+
colorScheme,
|
|
3962
|
+
dynamicTypeSize,
|
|
3963
|
+
safeArea: insetsOf(safeArea, fit),
|
|
3964
|
+
contentHeight: fit === "content",
|
|
3965
|
+
history,
|
|
3966
|
+
keyboard,
|
|
3967
|
+
...assets ? { assets } : {}
|
|
3968
|
+
});
|
|
3969
|
+
mounted.current = instance;
|
|
3970
|
+
return () => {
|
|
3971
|
+
mounted.current = null;
|
|
3972
|
+
instance.unmount();
|
|
3973
|
+
};
|
|
3974
|
+
}, [fit, history, keyboard]);
|
|
3975
|
+
useLayoutEffect(() => {
|
|
3976
|
+
if (mounted.current) mounted.current.renderer.sidebarTitleBar = sidebarTitleBar;
|
|
3977
|
+
}, [sidebarTitleBar, fit, history, keyboard]);
|
|
3978
|
+
useLayoutEffect(() => {
|
|
3979
|
+
mounted.current?.root.render(tree);
|
|
3980
|
+
});
|
|
3981
|
+
const insets2 = insetsOf(safeArea, fit);
|
|
3982
|
+
const insetsKey = `${insets2.top},${insets2.leading},${insets2.bottom},${insets2.trailing}`;
|
|
3983
|
+
useLayoutEffect(() => {
|
|
3984
|
+
mounted.current?.renderer.setSafeArea(insets2);
|
|
3985
|
+
}, [insetsKey]);
|
|
3986
|
+
useLayoutEffect(() => {
|
|
3987
|
+
if (device.current) applyTypeSizeVariables(device.current, dynamicTypeSize, mounted.current?.renderer.platform);
|
|
3988
|
+
mounted.current?.setEnvironment({ colorScheme, dynamicTypeSize });
|
|
3989
|
+
}, [colorScheme, dynamicTypeSize]);
|
|
3990
|
+
const classes = ["device", "sb-island", className].filter(Boolean).join(" ");
|
|
3991
|
+
return /* @__PURE__ */ jsx("div", { ref: device, className: classes, "data-theme": colorScheme, "data-type-size": dynamicTypeSize, "data-state": "ready", "data-sb-fit": fit, style, children: /* @__PURE__ */ jsx("div", { className: "device-screen", children: /* @__PURE__ */ jsx("div", { ref: screen, className: "screen" }) }) });
|
|
3986
3992
|
}
|
|
3987
3993
|
const r = (n) => {
|
|
3988
3994
|
const v = Math.round(n * 100) / 100;
|
|
@@ -8209,6 +8215,7 @@ export {
|
|
|
8209
8215
|
GroupBox,
|
|
8210
8216
|
HStack,
|
|
8211
8217
|
Host,
|
|
8218
|
+
HostElement,
|
|
8212
8219
|
Image$1 as Image,
|
|
8213
8220
|
KeyframeAnimator,
|
|
8214
8221
|
LOADING_INDICATOR_DELAY_MS,
|