@swiftbrowser/react 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +435 -2
- package/dist/binding.d.ts +9 -0
- package/dist/binding.d.ts.map +1 -0
- package/dist/bridge.d.ts +17 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/components/animators.d.ts +40 -0
- package/dist/components/animators.d.ts.map +1 -0
- package/dist/components/canvas.d.ts +138 -0
- package/dist/components/canvas.d.ts.map +1 -0
- package/dist/components/charts.d.ts +100 -0
- package/dist/components/charts.d.ts.map +1 -0
- package/dist/components/containers.d.ts +78 -0
- package/dist/components/containers.d.ts.map +1 -0
- package/dist/components/controls.d.ts +106 -0
- package/dist/components/controls.d.ts.map +1 -0
- package/dist/components/geometry.d.ts +131 -0
- package/dist/components/geometry.d.ts.map +1 -0
- package/dist/components/host.d.ts +24 -0
- package/dist/components/host.d.ts.map +1 -0
- package/dist/components/images.d.ts +18 -0
- package/dist/components/images.d.ts.map +1 -0
- package/dist/components/lists.d.ts +26 -0
- package/dist/components/lists.d.ts.map +1 -0
- package/dist/components/media.d.ts +105 -0
- package/dist/components/media.d.ts.map +1 -0
- package/dist/components/menus.d.ts +20 -0
- package/dist/components/menus.d.ts.map +1 -0
- package/dist/components/navigation.d.ts +22 -0
- package/dist/components/navigation.d.ts.map +1 -0
- package/dist/components/row.d.ts +34 -0
- package/dist/components/row.d.ts.map +1 -0
- package/dist/components/shapes.d.ts +107 -0
- package/dist/components/shapes.d.ts.map +1 -0
- package/dist/components/split.d.ts +25 -0
- package/dist/components/split.d.ts.map +1 -0
- package/dist/components/stacks.d.ts +138 -0
- package/dist/components/stacks.d.ts.map +1 -0
- package/dist/components/system.d.ts +25 -0
- package/dist/components/system.d.ts.map +1 -0
- package/dist/components/table.d.ts +36 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/tabs.d.ts +20 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/text.d.ts +63 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/coordinateSpace.d.ts +20 -0
- package/dist/coordinateSpace.d.ts.map +1 -0
- package/dist/dragDrop.d.ts +16 -0
- package/dist/dragDrop.d.ts.map +1 -0
- package/dist/environment.d.ts +54 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/host/instance.d.ts +67 -0
- package/dist/host/instance.d.ts.map +1 -0
- package/dist/host/reconciler.d.ts +9 -0
- package/dist/host/reconciler.d.ts.map +1 -0
- package/dist/host/root.d.ts +29 -0
- package/dist/host/root.d.ts.map +1 -0
- package/dist/host/sb.d.ts +5 -0
- package/dist/host/sb.d.ts.map +1 -0
- package/dist/host/tree.d.ts +35 -0
- package/dist/host/tree.d.ts.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4038 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector.d.ts +11 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/island.d.ts +25 -0
- package/dist/island.d.ts.map +1 -0
- package/dist/lazy.d.ts +19 -0
- package/dist/lazy.d.ts.map +1 -0
- package/dist/lifecycle.d.ts +11 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/modifiers.d.ts +330 -0
- package/dist/modifiers.d.ts.map +1 -0
- package/dist/mount.d.ts +41 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/navigation-context.d.ts +15 -0
- package/dist/navigation-context.d.ts.map +1 -0
- package/dist/path.d.ts +48 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/pointer.d.ts +65 -0
- package/dist/pointer.d.ts.map +1 -0
- package/dist/presentation.d.ts +38 -0
- package/dist/presentation.d.ts.map +1 -0
- package/dist/scrollReader.d.ts +27 -0
- package/dist/scrollReader.d.ts.map +1 -0
- package/dist/values.d.ts +118 -0
- package/dist/values.d.ts.map +1 -0
- package/package.json +47 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,4038 @@
|
|
|
1
|
+
import { createContext, useContext, createElement, useRef, useLayoutEffect, useEffect, useState, useId, Fragment as Fragment$1, Children, isValidElement, cloneElement, useSyncExternalStore } from "react";
|
|
2
|
+
import { DefaultEventPriority, ConcurrentRoot } from "react-reconciler/constants";
|
|
3
|
+
import Reconciler from "react-reconciler";
|
|
4
|
+
import { horizontalSizeClassFor } from "@swiftbrowser/web/src/protocol";
|
|
5
|
+
import { Renderer } from "@swiftbrowser/web/src/renderer";
|
|
6
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
7
|
+
import { applyTypeSizeVariables } from "@swiftbrowser/web/src/typography";
|
|
8
|
+
import { registerHostContent, notifyHostContentChange, unregisterHostContent } from "@swiftbrowser/web/src/hostContent";
|
|
9
|
+
import { createRoot } from "react-dom/client";
|
|
10
|
+
import { flushSync } from "react-dom";
|
|
11
|
+
import { chooseColor } from "@swiftbrowser/web/src/colorPicker";
|
|
12
|
+
import { performHostRequest, browserEnvironment } from "@swiftbrowser/web/src/hostRequests";
|
|
13
|
+
import { timingFor } from "@swiftbrowser/web/src/animation";
|
|
14
|
+
const ViewEnvironmentContext = createContext({});
|
|
15
|
+
function useViewEnvironment() {
|
|
16
|
+
return useContext(ViewEnvironmentContext);
|
|
17
|
+
}
|
|
18
|
+
function withEnvironment(values, children) {
|
|
19
|
+
return createElement(EnvironmentExtender, { values }, children);
|
|
20
|
+
}
|
|
21
|
+
function EnvironmentExtender({ values, children }) {
|
|
22
|
+
const parent = useContext(ViewEnvironmentContext);
|
|
23
|
+
return createElement(ViewEnvironmentContext.Provider, { value: { ...parent, ...values } }, children);
|
|
24
|
+
}
|
|
25
|
+
const EnvironmentContext = createContext({
|
|
26
|
+
colorScheme: "light",
|
|
27
|
+
dynamicTypeSize: "large",
|
|
28
|
+
horizontalSizeClass: "compact"
|
|
29
|
+
});
|
|
30
|
+
function EnvironmentProvider({ value, children }) {
|
|
31
|
+
return createElement(EnvironmentContext.Provider, { value }, children);
|
|
32
|
+
}
|
|
33
|
+
function useColorScheme() {
|
|
34
|
+
return useContext(EnvironmentContext).colorScheme;
|
|
35
|
+
}
|
|
36
|
+
function useDynamicTypeSize() {
|
|
37
|
+
return useContext(EnvironmentContext).dynamicTypeSize;
|
|
38
|
+
}
|
|
39
|
+
const DismissContext = createContext(null);
|
|
40
|
+
function useDismiss() {
|
|
41
|
+
const dismiss = useContext(DismissContext);
|
|
42
|
+
return dismiss ?? (() => {
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function useHorizontalSizeClass() {
|
|
46
|
+
return useContext(EnvironmentContext).horizontalSizeClass;
|
|
47
|
+
}
|
|
48
|
+
function useRedacted() {
|
|
49
|
+
return useContext(ViewEnvironmentContext).redacted === true;
|
|
50
|
+
}
|
|
51
|
+
let currentUpdatePriority = 0;
|
|
52
|
+
function detach(parent, child) {
|
|
53
|
+
const at = parent.children.indexOf(child);
|
|
54
|
+
if (at >= 0) parent.children.splice(at, 1);
|
|
55
|
+
}
|
|
56
|
+
const hostConfig = {
|
|
57
|
+
supportsMutation: true,
|
|
58
|
+
supportsPersistence: false,
|
|
59
|
+
supportsHydration: false,
|
|
60
|
+
isPrimaryRenderer: true,
|
|
61
|
+
noTimeout: -1,
|
|
62
|
+
scheduleTimeout: setTimeout,
|
|
63
|
+
cancelTimeout: clearTimeout,
|
|
64
|
+
supportsMicrotasks: true,
|
|
65
|
+
scheduleMicrotask: queueMicrotask,
|
|
66
|
+
getRootHostContext: () => ({}),
|
|
67
|
+
getChildHostContext: (parent) => parent,
|
|
68
|
+
getPublicInstance: (instance) => instance,
|
|
69
|
+
prepareForCommit: () => null,
|
|
70
|
+
resetAfterCommit: (tree) => tree.commit(),
|
|
71
|
+
preparePortalMount: () => {
|
|
72
|
+
},
|
|
73
|
+
shouldSetTextContent: () => false,
|
|
74
|
+
createInstance: (type, props, tree) => {
|
|
75
|
+
if (type !== "sb") throw new Error(`Unknown host element <${type}>: only SwiftUI components render here.`);
|
|
76
|
+
return tree.createInstance(props);
|
|
77
|
+
},
|
|
78
|
+
createTextInstance: (text) => {
|
|
79
|
+
throw new Error(`Text strings must be rendered within a <Text> component (got ${JSON.stringify(text)}).`);
|
|
80
|
+
},
|
|
81
|
+
appendInitialChild: (parent, child) => parent.children.push(child),
|
|
82
|
+
finalizeInitialChildren: () => false,
|
|
83
|
+
commitMount: () => {
|
|
84
|
+
},
|
|
85
|
+
commitUpdate: (instance, _type, _prev, next, handle) => {
|
|
86
|
+
const tree = treeOf(handle);
|
|
87
|
+
if (tree) tree.updateInstance(instance, next);
|
|
88
|
+
else {
|
|
89
|
+
instance.props = next.props ?? {};
|
|
90
|
+
instance.on = next.on;
|
|
91
|
+
instance.target = next.target;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
appendChild: (parent, child) => {
|
|
95
|
+
detach(parent, child);
|
|
96
|
+
parent.children.push(child);
|
|
97
|
+
},
|
|
98
|
+
appendChildToContainer: (tree, child) => {
|
|
99
|
+
detach(tree.root, child);
|
|
100
|
+
tree.root.children.push(child);
|
|
101
|
+
},
|
|
102
|
+
insertBefore: (parent, child, before) => {
|
|
103
|
+
detach(parent, child);
|
|
104
|
+
const at = parent.children.indexOf(before);
|
|
105
|
+
parent.children.splice(at < 0 ? parent.children.length : at, 0, child);
|
|
106
|
+
},
|
|
107
|
+
insertInContainerBefore: (tree, child, before) => {
|
|
108
|
+
detach(tree.root, child);
|
|
109
|
+
const at = tree.root.children.indexOf(before);
|
|
110
|
+
tree.root.children.splice(at < 0 ? tree.root.children.length : at, 0, child);
|
|
111
|
+
},
|
|
112
|
+
removeChild: (parent, child) => detach(parent, child),
|
|
113
|
+
removeChildFromContainer: (tree, child) => detach(tree.root, child),
|
|
114
|
+
clearContainer: (tree) => {
|
|
115
|
+
tree.root.children = [];
|
|
116
|
+
},
|
|
117
|
+
resetTextContent: () => {
|
|
118
|
+
},
|
|
119
|
+
commitTextUpdate: () => {
|
|
120
|
+
},
|
|
121
|
+
hideInstance: (instance) => {
|
|
122
|
+
instance.hidden = true;
|
|
123
|
+
},
|
|
124
|
+
unhideInstance: (instance) => {
|
|
125
|
+
instance.hidden = false;
|
|
126
|
+
},
|
|
127
|
+
hideTextInstance: () => {
|
|
128
|
+
},
|
|
129
|
+
unhideTextInstance: () => {
|
|
130
|
+
},
|
|
131
|
+
detachDeletedInstance: () => {
|
|
132
|
+
},
|
|
133
|
+
getInstanceFromNode: () => null,
|
|
134
|
+
beforeActiveInstanceBlur: () => {
|
|
135
|
+
},
|
|
136
|
+
afterActiveInstanceBlur: () => {
|
|
137
|
+
},
|
|
138
|
+
prepareScopeUpdate: () => {
|
|
139
|
+
},
|
|
140
|
+
getInstanceFromScope: () => null,
|
|
141
|
+
setCurrentUpdatePriority: (priority) => {
|
|
142
|
+
currentUpdatePriority = priority;
|
|
143
|
+
},
|
|
144
|
+
getCurrentUpdatePriority: () => currentUpdatePriority,
|
|
145
|
+
resolveUpdatePriority: () => currentUpdatePriority !== 0 ? currentUpdatePriority : DefaultEventPriority,
|
|
146
|
+
resetFormInstance: () => {
|
|
147
|
+
},
|
|
148
|
+
requestPostPaintCallback: () => {
|
|
149
|
+
},
|
|
150
|
+
shouldAttemptEagerTransition: () => false,
|
|
151
|
+
trackSchedulerEvent: () => {
|
|
152
|
+
},
|
|
153
|
+
resolveEventType: () => null,
|
|
154
|
+
resolveEventTimeStamp: () => -1.1,
|
|
155
|
+
maySuspendCommit: () => false,
|
|
156
|
+
maySuspendCommitOnUpdate: () => false,
|
|
157
|
+
maySuspendCommitInSyncRender: () => false,
|
|
158
|
+
suspendOnActiveViewTransition: () => {
|
|
159
|
+
},
|
|
160
|
+
getSuspendedCommitReason: () => null,
|
|
161
|
+
bindToConsole: (methodName, args) => () => console[methodName]?.(...args),
|
|
162
|
+
preloadInstance: () => true,
|
|
163
|
+
startSuspendingCommit: () => null,
|
|
164
|
+
suspendInstance: () => {
|
|
165
|
+
},
|
|
166
|
+
waitForCommitToBeReady: () => null,
|
|
167
|
+
NotPendingTransition: null,
|
|
168
|
+
HostTransitionContext: createContext(null),
|
|
169
|
+
rendererVersion: "0.3.1",
|
|
170
|
+
rendererPackageName: "@swiftbrowser/react",
|
|
171
|
+
extraDevToolsConfig: null
|
|
172
|
+
};
|
|
173
|
+
function treeOf(handle) {
|
|
174
|
+
let fiber = handle;
|
|
175
|
+
while (fiber) {
|
|
176
|
+
if (fiber.tag === 3) return fiber.stateNode.containerInfo;
|
|
177
|
+
fiber = fiber.return;
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const reconciler = Reconciler(hostConfig);
|
|
182
|
+
const PREF_KIND = "$pref";
|
|
183
|
+
const HOIST_KIND = "$hoist";
|
|
184
|
+
class HostTree {
|
|
185
|
+
constructor(sink) {
|
|
186
|
+
this.sink = sink;
|
|
187
|
+
}
|
|
188
|
+
sink;
|
|
189
|
+
root = { id: 0, kind: "root", children: [], committedChildren: [] };
|
|
190
|
+
nextId = 1;
|
|
191
|
+
/** Emitted elements by id, for event dispatch. */
|
|
192
|
+
live = /* @__PURE__ */ new Map();
|
|
193
|
+
committedLive = /* @__PURE__ */ new Set();
|
|
194
|
+
/** Ids whose element changed kind: removed at the end of the next flush. */
|
|
195
|
+
retired = [];
|
|
196
|
+
/** `withAnimation`: stamped on the next `commit`. */
|
|
197
|
+
pendingAnimation;
|
|
198
|
+
/** The root's `colorScheme` last sent (`.preferredColorScheme`); undefined while none was. */
|
|
199
|
+
committedColorScheme;
|
|
200
|
+
createInstance(props) {
|
|
201
|
+
return {
|
|
202
|
+
id: this.nextId++,
|
|
203
|
+
kind: props.kind,
|
|
204
|
+
props: props.props ?? {},
|
|
205
|
+
on: props.on,
|
|
206
|
+
target: props.target,
|
|
207
|
+
children: [],
|
|
208
|
+
hidden: false,
|
|
209
|
+
created: false,
|
|
210
|
+
committedProps: null,
|
|
211
|
+
committedParent: null,
|
|
212
|
+
committedChildren: []
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
updateInstance(instance, next) {
|
|
216
|
+
if (next.kind !== instance.kind) {
|
|
217
|
+
if (instance.created) {
|
|
218
|
+
this.retired.push(instance.id);
|
|
219
|
+
this.live.delete(instance.id);
|
|
220
|
+
}
|
|
221
|
+
instance.id = this.nextId++;
|
|
222
|
+
instance.kind = next.kind;
|
|
223
|
+
instance.created = false;
|
|
224
|
+
instance.committedProps = null;
|
|
225
|
+
instance.committedParent = null;
|
|
226
|
+
instance.committedChildren = [];
|
|
227
|
+
}
|
|
228
|
+
instance.props = next.props ?? {};
|
|
229
|
+
instance.on = next.on;
|
|
230
|
+
instance.target = next.target;
|
|
231
|
+
}
|
|
232
|
+
/** Emit the ops for everything that changed since the last commit. */
|
|
233
|
+
commit() {
|
|
234
|
+
const ops = this.flush();
|
|
235
|
+
if (ops.length > 0) this.sink(ops);
|
|
236
|
+
}
|
|
237
|
+
flush() {
|
|
238
|
+
const animation = this.pendingAnimation;
|
|
239
|
+
this.pendingAnimation = void 0;
|
|
240
|
+
const effective = /* @__PURE__ */ new Map();
|
|
241
|
+
const rootEffective = { props: {}, children: [], hoisted: [] };
|
|
242
|
+
effective.set(this.root, rootEffective);
|
|
243
|
+
const visit = (child, sink, ctx) => {
|
|
244
|
+
if (child.hidden) return;
|
|
245
|
+
if (child.kind === PREF_KIND) {
|
|
246
|
+
const target = child.target === "root" || child.target === void 0 ? this.root : ctx[child.target];
|
|
247
|
+
const entry2 = target ? effective.get(target) : void 0;
|
|
248
|
+
if (entry2) Object.assign(entry2.props, child.props);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (child.kind === HOIST_KIND) {
|
|
252
|
+
const target = (child.target && child.target !== "root" ? ctx[child.target] : void 0) ?? this.root;
|
|
253
|
+
const entry2 = effective.get(target);
|
|
254
|
+
for (const grandchild of child.children) visit(grandchild, entry2.hoisted, ctx);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const entry = { props: { ...child.props }, children: [], hoisted: [] };
|
|
258
|
+
effective.set(child, entry);
|
|
259
|
+
sink.push(child);
|
|
260
|
+
const next2 = child.kind === "navscreen" ? { ...ctx, navscreen: child } : child.kind === "sheet" ? { ...ctx, sheet: child } : ctx;
|
|
261
|
+
for (const grandchild of child.children) visit(grandchild, entry.children, next2);
|
|
262
|
+
};
|
|
263
|
+
for (const child of this.root.children) visit(child, rootEffective.children, {});
|
|
264
|
+
for (const entry of effective.values()) {
|
|
265
|
+
if (entry.hoisted.length > 0) entry.children.push(...entry.hoisted);
|
|
266
|
+
}
|
|
267
|
+
const live = /* @__PURE__ */ new Set();
|
|
268
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
269
|
+
for (const [node, entry] of effective) {
|
|
270
|
+
for (const child of entry.children) {
|
|
271
|
+
live.add(child);
|
|
272
|
+
parentOf.set(child, node);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const ops = [];
|
|
276
|
+
const dead = /* @__PURE__ */ new Set();
|
|
277
|
+
for (const instance of this.committedLive) if (!live.has(instance)) dead.add(instance);
|
|
278
|
+
for (const instance of dead) {
|
|
279
|
+
const parent = instance.committedParent;
|
|
280
|
+
if (parent && parent !== this.root && dead.has(parent)) continue;
|
|
281
|
+
ops.push({ op: "remove", id: instance.id });
|
|
282
|
+
}
|
|
283
|
+
for (const instance of dead) {
|
|
284
|
+
this.live.delete(instance.id);
|
|
285
|
+
instance.created = false;
|
|
286
|
+
instance.committedProps = null;
|
|
287
|
+
instance.committedParent = null;
|
|
288
|
+
instance.committedChildren = [];
|
|
289
|
+
}
|
|
290
|
+
const emit = (parent, entry) => {
|
|
291
|
+
const current = parent.committedChildren.filter((child) => live.has(child) && parentOf.get(child) === parent);
|
|
292
|
+
entry.children.forEach((child, index) => {
|
|
293
|
+
const childEntry = effective.get(child);
|
|
294
|
+
if (!child.created) {
|
|
295
|
+
ops.push({ op: "create", id: child.id, kind: child.kind, props: childEntry.props });
|
|
296
|
+
child.created = true;
|
|
297
|
+
this.live.set(child.id, child);
|
|
298
|
+
} else if (!deepEqual(childEntry.props, child.committedProps)) {
|
|
299
|
+
ops.push({ op: "update", id: child.id, props: childEntry.props });
|
|
300
|
+
}
|
|
301
|
+
child.committedProps = childEntry.props;
|
|
302
|
+
if (current[index] !== child || child.committedParent !== parent) {
|
|
303
|
+
ops.push({ op: "insert", parent: parent.id, id: child.id, index });
|
|
304
|
+
const at = current.indexOf(child);
|
|
305
|
+
if (at >= 0) current.splice(at, 1);
|
|
306
|
+
current.splice(index, 0, child);
|
|
307
|
+
}
|
|
308
|
+
child.committedParent = parent;
|
|
309
|
+
emit(child, childEntry);
|
|
310
|
+
});
|
|
311
|
+
parent.committedChildren = entry.children;
|
|
312
|
+
};
|
|
313
|
+
emit(this.root, rootEffective);
|
|
314
|
+
for (const id of this.retired) ops.push({ op: "remove", id });
|
|
315
|
+
this.retired = [];
|
|
316
|
+
this.committedLive = live;
|
|
317
|
+
const scheme = rootEffective.props["colorScheme"];
|
|
318
|
+
const next = scheme === void 0 ? this.committedColorScheme === void 0 ? void 0 : null : scheme;
|
|
319
|
+
if (next !== void 0 && next !== this.committedColorScheme) {
|
|
320
|
+
ops.push({ op: "update", id: 0, props: { colorScheme: next } });
|
|
321
|
+
this.committedColorScheme = next === null ? void 0 : next;
|
|
322
|
+
}
|
|
323
|
+
if (ops.length === 0) return ops;
|
|
324
|
+
ops.push(animation ? { op: "commit", animation } : { op: "commit" });
|
|
325
|
+
return ops;
|
|
326
|
+
}
|
|
327
|
+
/** Hand a renderer event to the element's handler for its type. */
|
|
328
|
+
dispatch(event) {
|
|
329
|
+
if (event.type === "batch") {
|
|
330
|
+
for (const each of event.events) this.dispatch(each);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (!("id" in event)) return;
|
|
334
|
+
const instance = this.live.get(event.id);
|
|
335
|
+
const handler = instance?.on?.[event.type];
|
|
336
|
+
handler?.(event);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function deepEqual(a, b) {
|
|
340
|
+
if (a === b) return true;
|
|
341
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
342
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
343
|
+
if (Array.isArray(a)) {
|
|
344
|
+
const other = b;
|
|
345
|
+
return a.length === other.length && a.every((value, index) => deepEqual(value, other[index]));
|
|
346
|
+
}
|
|
347
|
+
const left = a;
|
|
348
|
+
const right = b;
|
|
349
|
+
const keys = Object.keys(left);
|
|
350
|
+
if (keys.length !== Object.keys(right).length) return false;
|
|
351
|
+
return keys.every((key) => key in right && deepEqual(left[key], right[key]));
|
|
352
|
+
}
|
|
353
|
+
const DEFAULT_ENVIRONMENT = { colorScheme: "light", dynamicTypeSize: "large", horizontalSizeClass: "compact" };
|
|
354
|
+
const roots = /* @__PURE__ */ new Set();
|
|
355
|
+
function createSwiftUIRoot(sink) {
|
|
356
|
+
const tree = new HostTree(sink);
|
|
357
|
+
roots.add(tree);
|
|
358
|
+
const container = reconciler.createContainer(
|
|
359
|
+
tree,
|
|
360
|
+
ConcurrentRoot,
|
|
361
|
+
null,
|
|
362
|
+
false,
|
|
363
|
+
null,
|
|
364
|
+
"",
|
|
365
|
+
(error) => {
|
|
366
|
+
throw error;
|
|
367
|
+
},
|
|
368
|
+
(error) => console.error(error),
|
|
369
|
+
(error) => console.warn(error),
|
|
370
|
+
() => {
|
|
371
|
+
},
|
|
372
|
+
null
|
|
373
|
+
);
|
|
374
|
+
let environment = DEFAULT_ENVIRONMENT;
|
|
375
|
+
let current = null;
|
|
376
|
+
const update = () => {
|
|
377
|
+
reconciler.updateContainerSync(createElement(EnvironmentProvider, { value: environment }, current), container, null, null);
|
|
378
|
+
reconciler.flushSyncWork();
|
|
379
|
+
};
|
|
380
|
+
return {
|
|
381
|
+
render(element) {
|
|
382
|
+
current = element;
|
|
383
|
+
update();
|
|
384
|
+
},
|
|
385
|
+
unmount() {
|
|
386
|
+
reconciler.updateContainerSync(null, container, null, null);
|
|
387
|
+
reconciler.flushSyncWork();
|
|
388
|
+
roots.delete(tree);
|
|
389
|
+
},
|
|
390
|
+
dispatch(event) {
|
|
391
|
+
reconciler.flushSyncFromReconciler(() => tree.dispatch(event));
|
|
392
|
+
},
|
|
393
|
+
setEnvironment(next) {
|
|
394
|
+
environment = { ...environment, ...next };
|
|
395
|
+
update();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function withAnimation(first, second) {
|
|
400
|
+
const animation = typeof first === "function" ? { type: "default" } : first ?? { type: "default" };
|
|
401
|
+
const body = typeof first === "function" ? first : second;
|
|
402
|
+
for (const tree of roots) tree.pendingAnimation = animation;
|
|
403
|
+
try {
|
|
404
|
+
return reconciler.flushSyncFromReconciler(body);
|
|
405
|
+
} finally {
|
|
406
|
+
for (const tree of roots) tree.pendingAnimation = void 0;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function mount(screen, element, options = {}) {
|
|
410
|
+
let renderer = null;
|
|
411
|
+
const root = createSwiftUIRoot((ops) => renderer?.applyOps(ops));
|
|
412
|
+
renderer = new Renderer(screen, (event) => root.dispatch(event));
|
|
413
|
+
let pageScheme = options.colorScheme ?? "light";
|
|
414
|
+
let preferred = null;
|
|
415
|
+
const environment = {
|
|
416
|
+
colorScheme: pageScheme,
|
|
417
|
+
dynamicTypeSize: options.dynamicTypeSize ?? "large",
|
|
418
|
+
horizontalSizeClass: horizontalSizeClassFor(screen.clientWidth || 393)
|
|
419
|
+
};
|
|
420
|
+
renderer.contentHeight = options.contentHeight ?? false;
|
|
421
|
+
if (options.assets) renderer.setAssetCatalog(options.assets);
|
|
422
|
+
renderer.setEnvironment({ colorScheme: environment.colorScheme, dynamicTypeSize: environment.dynamicTypeSize });
|
|
423
|
+
if (options.safeArea !== void 0) renderer.setSafeArea(options.safeArea);
|
|
424
|
+
root.setEnvironment(environment);
|
|
425
|
+
const applyScheme = () => {
|
|
426
|
+
const scheme = preferred ?? pageScheme;
|
|
427
|
+
const device = screen.closest(".device");
|
|
428
|
+
if (device) device.dataset["theme"] = scheme;
|
|
429
|
+
renderer?.setEnvironment({ colorScheme: scheme });
|
|
430
|
+
root.setEnvironment({ colorScheme: scheme });
|
|
431
|
+
};
|
|
432
|
+
const onPreferredScheme = (event) => {
|
|
433
|
+
const scheme = event.detail.colorScheme;
|
|
434
|
+
preferred = scheme;
|
|
435
|
+
queueMicrotask(applyScheme);
|
|
436
|
+
};
|
|
437
|
+
screen.addEventListener("sb:color-scheme", onPreferredScheme);
|
|
438
|
+
let sizeClass = environment.horizontalSizeClass;
|
|
439
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
440
|
+
const next = horizontalSizeClassFor(screen.clientWidth);
|
|
441
|
+
if (next === sizeClass) return;
|
|
442
|
+
sizeClass = next;
|
|
443
|
+
root.setEnvironment({ horizontalSizeClass: next });
|
|
444
|
+
}) : null;
|
|
445
|
+
observer?.observe(screen);
|
|
446
|
+
root.render(element);
|
|
447
|
+
const mounted = {
|
|
448
|
+
root,
|
|
449
|
+
renderer,
|
|
450
|
+
setEnvironment(next) {
|
|
451
|
+
if (next.colorScheme !== void 0) pageScheme = next.colorScheme;
|
|
452
|
+
const scheme = preferred ?? pageScheme;
|
|
453
|
+
renderer?.setEnvironment({ ...next, colorScheme: scheme });
|
|
454
|
+
root.setEnvironment({ ...next, colorScheme: scheme });
|
|
455
|
+
},
|
|
456
|
+
unmount() {
|
|
457
|
+
observer?.disconnect();
|
|
458
|
+
screen.removeEventListener("sb:color-scheme", onPreferredScheme);
|
|
459
|
+
root.unmount();
|
|
460
|
+
renderer?.dispose();
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
return mounted;
|
|
464
|
+
}
|
|
465
|
+
const NavigationContext = createContext(null);
|
|
466
|
+
function useNavigation() {
|
|
467
|
+
return useContext(NavigationContext);
|
|
468
|
+
}
|
|
469
|
+
function RegisterDestination({ destination }) {
|
|
470
|
+
const navigation = useContext(NavigationContext);
|
|
471
|
+
navigation?.registerDestination(destination);
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
const OWN = [
|
|
475
|
+
EnvironmentContext,
|
|
476
|
+
ViewEnvironmentContext,
|
|
477
|
+
NavigationContext,
|
|
478
|
+
DismissContext
|
|
479
|
+
];
|
|
480
|
+
function useContextBridge(contexts = [], options = {}) {
|
|
481
|
+
const own = options.environment === false ? OWN.filter((context) => context !== EnvironmentContext) : OWN;
|
|
482
|
+
const all = [...own, ...contexts];
|
|
483
|
+
const values = all.map((context) => useContext(context));
|
|
484
|
+
return (children) => all.reduceRight((inner, context, index) => createElement(context.Provider, { value: values[index] }, inner), children);
|
|
485
|
+
}
|
|
486
|
+
const NO_SAFE_AREA = { top: 0, leading: 0, bottom: 0, trailing: 0 };
|
|
487
|
+
function SwiftUIView({
|
|
488
|
+
children,
|
|
489
|
+
fit = "fill",
|
|
490
|
+
colorScheme = "light",
|
|
491
|
+
dynamicTypeSize = "large",
|
|
492
|
+
contexts,
|
|
493
|
+
assets,
|
|
494
|
+
className,
|
|
495
|
+
style
|
|
496
|
+
}) {
|
|
497
|
+
const device = useRef(null);
|
|
498
|
+
const screen = useRef(null);
|
|
499
|
+
const mounted = useRef(null);
|
|
500
|
+
const bridge = useContextBridge(contexts, { environment: false });
|
|
501
|
+
const tree = bridge(children);
|
|
502
|
+
const latest = useRef(tree);
|
|
503
|
+
latest.current = tree;
|
|
504
|
+
useLayoutEffect(() => {
|
|
505
|
+
if (!screen.current) return;
|
|
506
|
+
const instance = mount(screen.current, latest.current, {
|
|
507
|
+
colorScheme,
|
|
508
|
+
dynamicTypeSize,
|
|
509
|
+
safeArea: NO_SAFE_AREA,
|
|
510
|
+
contentHeight: fit === "content",
|
|
511
|
+
...assets ? { assets } : {}
|
|
512
|
+
});
|
|
513
|
+
mounted.current = instance;
|
|
514
|
+
return () => {
|
|
515
|
+
mounted.current = null;
|
|
516
|
+
instance.unmount();
|
|
517
|
+
};
|
|
518
|
+
}, [fit]);
|
|
519
|
+
useLayoutEffect(() => {
|
|
520
|
+
mounted.current?.root.render(tree);
|
|
521
|
+
});
|
|
522
|
+
useLayoutEffect(() => {
|
|
523
|
+
if (device.current) applyTypeSizeVariables(device.current, dynamicTypeSize);
|
|
524
|
+
mounted.current?.setEnvironment({ colorScheme, dynamicTypeSize });
|
|
525
|
+
}, [colorScheme, dynamicTypeSize]);
|
|
526
|
+
const classes = ["device", "sb-island", className].filter(Boolean).join(" ");
|
|
527
|
+
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" }) }) });
|
|
528
|
+
}
|
|
529
|
+
function readBinding(value, onChange) {
|
|
530
|
+
if (Array.isArray(value) && value.length === 2 && typeof value[1] === "function") {
|
|
531
|
+
const [current, set] = value;
|
|
532
|
+
return [current, set];
|
|
533
|
+
}
|
|
534
|
+
return [value, onChange ?? (() => {
|
|
535
|
+
})];
|
|
536
|
+
}
|
|
537
|
+
const HIERARCHY = { primary: 1, secondary: 2, tertiary: 3, quaternary: 4 };
|
|
538
|
+
function rgb(r2, g, b, a = 1) {
|
|
539
|
+
return { r: r2, g, b, a };
|
|
540
|
+
}
|
|
541
|
+
function hex(value) {
|
|
542
|
+
const digits = value.replace("#", "");
|
|
543
|
+
const wide = digits.length === 3 || digits.length === 4 ? [...digits].map((d) => d + d).join("") : digits;
|
|
544
|
+
const n = (at) => parseInt(wide.slice(at, at + 2), 16) / 255;
|
|
545
|
+
return { r: n(0), g: n(2), b: n(4), a: wide.length >= 8 ? n(6) : 1 };
|
|
546
|
+
}
|
|
547
|
+
function shapeStyle(value) {
|
|
548
|
+
if (typeof value !== "string") return value;
|
|
549
|
+
if (value in HIERARCHY) return { hierarchical: HIERARCHY[value] };
|
|
550
|
+
if (value === "white") return rgb(1, 1, 1);
|
|
551
|
+
if (value === "black") return rgb(0, 0, 0);
|
|
552
|
+
if (value.startsWith("#")) return hex(value);
|
|
553
|
+
return { name: value };
|
|
554
|
+
}
|
|
555
|
+
function color(value) {
|
|
556
|
+
return shapeStyle(value);
|
|
557
|
+
}
|
|
558
|
+
function opacity(value, a) {
|
|
559
|
+
const style = shapeStyle(value);
|
|
560
|
+
if ("r" in style) return { ...style, a: style.a * a };
|
|
561
|
+
if ("name" in style) return { ...style, a: (style.a ?? 1) * a };
|
|
562
|
+
if ("named" in style) return { ...style, opacity: style.opacity * a };
|
|
563
|
+
return { ...style, opacity: (style.opacity ?? 1) * a };
|
|
564
|
+
}
|
|
565
|
+
function gradient(value) {
|
|
566
|
+
return { colorGradient: color(value) };
|
|
567
|
+
}
|
|
568
|
+
const ColorValues = {
|
|
569
|
+
red: { name: "red" },
|
|
570
|
+
orange: { name: "orange" },
|
|
571
|
+
yellow: { name: "yellow" },
|
|
572
|
+
green: { name: "green" },
|
|
573
|
+
mint: { name: "mint" },
|
|
574
|
+
teal: { name: "teal" },
|
|
575
|
+
cyan: { name: "cyan" },
|
|
576
|
+
blue: { name: "blue" },
|
|
577
|
+
indigo: { name: "indigo" },
|
|
578
|
+
purple: { name: "purple" },
|
|
579
|
+
pink: { name: "pink" },
|
|
580
|
+
brown: { name: "brown" },
|
|
581
|
+
gray: { name: "gray" },
|
|
582
|
+
white: rgb(1, 1, 1),
|
|
583
|
+
black: rgb(0, 0, 0),
|
|
584
|
+
clear: { name: "clear" },
|
|
585
|
+
primary: { name: "primary" },
|
|
586
|
+
secondary: { name: "secondary" },
|
|
587
|
+
accent: { name: "accent" },
|
|
588
|
+
/** `Color(uiColor:)` / `Color(.name)`: a UIKit semantic color by its iOS name. */
|
|
589
|
+
system: (name) => ({ name }),
|
|
590
|
+
rgb,
|
|
591
|
+
hex,
|
|
592
|
+
opacity,
|
|
593
|
+
gradient
|
|
594
|
+
};
|
|
595
|
+
const UNIT_POINTS = {
|
|
596
|
+
center: { x: 0.5, y: 0.5 },
|
|
597
|
+
top: { x: 0.5, y: 0 },
|
|
598
|
+
bottom: { x: 0.5, y: 1 },
|
|
599
|
+
leading: { x: 0, y: 0.5 },
|
|
600
|
+
trailing: { x: 1, y: 0.5 },
|
|
601
|
+
topLeading: { x: 0, y: 0 },
|
|
602
|
+
topTrailing: { x: 1, y: 0 },
|
|
603
|
+
bottomLeading: { x: 0, y: 1 },
|
|
604
|
+
bottomTrailing: { x: 1, y: 1 }
|
|
605
|
+
};
|
|
606
|
+
function unitPoint(value) {
|
|
607
|
+
return typeof value === "string" ? UNIT_POINTS[value] : value;
|
|
608
|
+
}
|
|
609
|
+
function stops$1(spec) {
|
|
610
|
+
if (spec.stops) return spec.stops.map((stop) => ({ color: color(stop.color), location: stop.location }));
|
|
611
|
+
const colors = spec.colors ?? [];
|
|
612
|
+
const last = Math.max(colors.length - 1, 1);
|
|
613
|
+
return colors.map((value, index) => ({ color: color(value), location: index / last }));
|
|
614
|
+
}
|
|
615
|
+
function LinearGradient(spec) {
|
|
616
|
+
return { linearGradient: { stops: stops$1(spec), start: unitPoint(spec.startPoint), end: unitPoint(spec.endPoint) } };
|
|
617
|
+
}
|
|
618
|
+
function RadialGradient(spec) {
|
|
619
|
+
return {
|
|
620
|
+
radialGradient: { stops: stops$1(spec), center: unitPoint(spec.center), startRadius: spec.startRadius, endRadius: spec.endRadius }
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function AngularGradient(spec) {
|
|
624
|
+
return {
|
|
625
|
+
angularGradient: {
|
|
626
|
+
stops: stops$1(spec),
|
|
627
|
+
center: unitPoint(spec.center),
|
|
628
|
+
startAngle: spec.startAngle ?? 0,
|
|
629
|
+
endAngle: spec.endAngle ?? 360
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function font(value) {
|
|
634
|
+
return typeof value === "string" ? { textStyle: value } : value;
|
|
635
|
+
}
|
|
636
|
+
function system(first, second, third) {
|
|
637
|
+
const result = typeof first === "number" ? { size: first } : { textStyle: first };
|
|
638
|
+
const weight = typeof first === "number" ? second : third;
|
|
639
|
+
const design = typeof first === "number" ? third : second;
|
|
640
|
+
if (weight) result.weight = weight;
|
|
641
|
+
if (design) result.design = design;
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
function weighted(value, weight) {
|
|
645
|
+
return { ...font(value), weight };
|
|
646
|
+
}
|
|
647
|
+
const Font = { system, weighted, bold: (value) => weighted(value, "bold") };
|
|
648
|
+
function frame(value) {
|
|
649
|
+
const dimension = (n) => n === void 0 ? void 0 : n === Infinity ? "infinity" : n;
|
|
650
|
+
const result = { alignment: value.alignment ?? "center" };
|
|
651
|
+
if (value.width !== void 0) result.width = value.width;
|
|
652
|
+
if (value.height !== void 0) result.height = value.height;
|
|
653
|
+
const minWidth = dimension(value.minWidth);
|
|
654
|
+
const maxWidth = dimension(value.maxWidth);
|
|
655
|
+
const minHeight = dimension(value.minHeight);
|
|
656
|
+
const maxHeight = dimension(value.maxHeight);
|
|
657
|
+
if (minWidth !== void 0) result.minWidth = minWidth;
|
|
658
|
+
if (maxWidth !== void 0) result.maxWidth = maxWidth;
|
|
659
|
+
if (minHeight !== void 0) result.minHeight = minHeight;
|
|
660
|
+
if (maxHeight !== void 0) result.maxHeight = maxHeight;
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
const DEFAULT_PADDING = 16;
|
|
664
|
+
function padding(value) {
|
|
665
|
+
if (value === true) return insets(["all"], DEFAULT_PADDING);
|
|
666
|
+
if (typeof value === "number") return insets(["all"], value);
|
|
667
|
+
if (Array.isArray(value)) {
|
|
668
|
+
const [edges, amount] = value;
|
|
669
|
+
return insets(Array.isArray(edges) ? edges : [edges], amount ?? DEFAULT_PADDING);
|
|
670
|
+
}
|
|
671
|
+
return value;
|
|
672
|
+
}
|
|
673
|
+
function insets(edges, amount) {
|
|
674
|
+
const result = {};
|
|
675
|
+
for (const edge of edges) {
|
|
676
|
+
if (edge === "all" || edge === "vertical" || edge === "top") result.top = amount;
|
|
677
|
+
if (edge === "all" || edge === "vertical" || edge === "bottom") result.bottom = amount;
|
|
678
|
+
if (edge === "all" || edge === "horizontal" || edge === "leading") result.leading = amount;
|
|
679
|
+
if (edge === "all" || edge === "horizontal" || edge === "trailing") result.trailing = amount;
|
|
680
|
+
}
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
const r = (n) => {
|
|
684
|
+
const v = Math.round(n * 100) / 100;
|
|
685
|
+
return Object.is(v, -0) ? "0" : String(v);
|
|
686
|
+
};
|
|
687
|
+
class Path {
|
|
688
|
+
parts = [];
|
|
689
|
+
current = null;
|
|
690
|
+
start = null;
|
|
691
|
+
constructor(build) {
|
|
692
|
+
build?.(this);
|
|
693
|
+
}
|
|
694
|
+
/** `Path(rect)` */
|
|
695
|
+
static rect(rect) {
|
|
696
|
+
return new Path().addRect(rect);
|
|
697
|
+
}
|
|
698
|
+
/** `Path(roundedRect:cornerRadius:)` */
|
|
699
|
+
static roundedRect(rect, cornerRadius) {
|
|
700
|
+
return new Path().addRoundedRect(rect, cornerRadius);
|
|
701
|
+
}
|
|
702
|
+
/** `Path(ellipseIn:)` */
|
|
703
|
+
static ellipse(rect) {
|
|
704
|
+
return new Path().addEllipse(rect);
|
|
705
|
+
}
|
|
706
|
+
move(to) {
|
|
707
|
+
this.parts.push(`M${r(to.x)} ${r(to.y)}`);
|
|
708
|
+
this.current = to;
|
|
709
|
+
this.start = to;
|
|
710
|
+
return this;
|
|
711
|
+
}
|
|
712
|
+
addLine(to) {
|
|
713
|
+
if (!this.current) return this.move(to);
|
|
714
|
+
this.parts.push(`L${r(to.x)} ${r(to.y)}`);
|
|
715
|
+
this.current = to;
|
|
716
|
+
return this;
|
|
717
|
+
}
|
|
718
|
+
addLines(points) {
|
|
719
|
+
points.forEach((point, index) => index === 0 ? this.move(point) : this.addLine(point));
|
|
720
|
+
return this;
|
|
721
|
+
}
|
|
722
|
+
addQuadCurve(to, control) {
|
|
723
|
+
if (!this.current) this.move(control);
|
|
724
|
+
this.parts.push(`Q${r(control.x)} ${r(control.y)} ${r(to.x)} ${r(to.y)}`);
|
|
725
|
+
this.current = to;
|
|
726
|
+
return this;
|
|
727
|
+
}
|
|
728
|
+
addCurve(to, control1, control2) {
|
|
729
|
+
if (!this.current) this.move(control1);
|
|
730
|
+
this.parts.push(`C${r(control1.x)} ${r(control1.y)} ${r(control2.x)} ${r(control2.y)} ${r(to.x)} ${r(to.y)}`);
|
|
731
|
+
this.current = to;
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* `addArc(center:radius:startAngle:endAngle:clockwise:)`, angles in
|
|
736
|
+
* degrees. As in SwiftUI's flipped coordinates, `clockwise: false` draws
|
|
737
|
+
* clockwise on screen.
|
|
738
|
+
*/
|
|
739
|
+
addArc(center, radius, startAngle, endAngle, clockwise) {
|
|
740
|
+
const rad = (deg) => deg * Math.PI / 180;
|
|
741
|
+
const point = (deg) => ({ x: center.x + radius * Math.cos(rad(deg)), y: center.y + radius * Math.sin(rad(deg)) });
|
|
742
|
+
const from = point(startAngle);
|
|
743
|
+
if (this.current) this.addLine(from);
|
|
744
|
+
else this.move(from);
|
|
745
|
+
const sweepPositive = !clockwise;
|
|
746
|
+
let delta = endAngle - startAngle;
|
|
747
|
+
if (sweepPositive) while (delta < 0) delta += 360;
|
|
748
|
+
else while (delta > 0) delta -= 360;
|
|
749
|
+
if (Math.abs(delta) >= 360) {
|
|
750
|
+
const half = point(startAngle + (sweepPositive ? 180 : -180));
|
|
751
|
+
const flag = sweepPositive ? 1 : 0;
|
|
752
|
+
this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(half.x)} ${r(half.y)}`);
|
|
753
|
+
this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(from.x)} ${r(from.y)}`);
|
|
754
|
+
this.current = from;
|
|
755
|
+
return this;
|
|
756
|
+
}
|
|
757
|
+
const to = point(startAngle + delta);
|
|
758
|
+
const large = Math.abs(delta) > 180 ? 1 : 0;
|
|
759
|
+
this.parts.push(`A${r(radius)} ${r(radius)} 0 ${large} ${sweepPositive ? 1 : 0} ${r(to.x)} ${r(to.y)}`);
|
|
760
|
+
this.current = to;
|
|
761
|
+
return this;
|
|
762
|
+
}
|
|
763
|
+
addRect(rect) {
|
|
764
|
+
this.move({ x: rect.x, y: rect.y });
|
|
765
|
+
this.addLine({ x: rect.x + rect.width, y: rect.y });
|
|
766
|
+
this.addLine({ x: rect.x + rect.width, y: rect.y + rect.height });
|
|
767
|
+
this.addLine({ x: rect.x, y: rect.y + rect.height });
|
|
768
|
+
return this.closeSubpath();
|
|
769
|
+
}
|
|
770
|
+
addRoundedRect(rect, cornerRadius) {
|
|
771
|
+
const c = Math.max(0, Math.min(cornerRadius, rect.width / 2, rect.height / 2));
|
|
772
|
+
if (c === 0) return this.addRect(rect);
|
|
773
|
+
const { x, y, width: w, height: h } = rect;
|
|
774
|
+
this.move({ x: x + c, y });
|
|
775
|
+
this.addLine({ x: x + w - c, y });
|
|
776
|
+
this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w)} ${r(y + c)}`);
|
|
777
|
+
this.current = { x: x + w, y: y + c };
|
|
778
|
+
this.addLine({ x: x + w, y: y + h - c });
|
|
779
|
+
this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w - c)} ${r(y + h)}`);
|
|
780
|
+
this.current = { x: x + w - c, y: y + h };
|
|
781
|
+
this.addLine({ x: x + c, y: y + h });
|
|
782
|
+
this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x)} ${r(y + h - c)}`);
|
|
783
|
+
this.current = { x, y: y + h - c };
|
|
784
|
+
this.addLine({ x, y: y + c });
|
|
785
|
+
this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + c)} ${r(y)}`);
|
|
786
|
+
this.current = { x: x + c, y };
|
|
787
|
+
return this.closeSubpath();
|
|
788
|
+
}
|
|
789
|
+
addEllipse(rect) {
|
|
790
|
+
const rx = rect.width / 2;
|
|
791
|
+
const ry = rect.height / 2;
|
|
792
|
+
const cx = rect.x + rx;
|
|
793
|
+
const cy = rect.y + ry;
|
|
794
|
+
this.move({ x: cx + rx, y: cy });
|
|
795
|
+
this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx - rx)} ${r(cy)}`);
|
|
796
|
+
this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx + rx)} ${r(cy)}`);
|
|
797
|
+
this.current = { x: cx + rx, y: cy };
|
|
798
|
+
return this.closeSubpath();
|
|
799
|
+
}
|
|
800
|
+
addPath(path) {
|
|
801
|
+
this.parts.push(path.svg());
|
|
802
|
+
return this;
|
|
803
|
+
}
|
|
804
|
+
closeSubpath() {
|
|
805
|
+
this.parts.push("Z");
|
|
806
|
+
this.current = this.start;
|
|
807
|
+
return this;
|
|
808
|
+
}
|
|
809
|
+
get isEmpty() {
|
|
810
|
+
return this.parts.length === 0;
|
|
811
|
+
}
|
|
812
|
+
/** The SVG path data. */
|
|
813
|
+
svg() {
|
|
814
|
+
return this.parts.join("");
|
|
815
|
+
}
|
|
816
|
+
toString() {
|
|
817
|
+
return this.svg();
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
function sb(kind, props, on, children, target) {
|
|
821
|
+
const hostProps = { kind };
|
|
822
|
+
if (props) hostProps.props = props;
|
|
823
|
+
if (on) hostProps.on = on;
|
|
824
|
+
if (target) hostProps.target = target;
|
|
825
|
+
return children === void 0 ? createElement("sb", hostProps) : createElement("sb", hostProps, children);
|
|
826
|
+
}
|
|
827
|
+
let active = null;
|
|
828
|
+
function Draggable({ payload, children }) {
|
|
829
|
+
return sb(
|
|
830
|
+
"draggable",
|
|
831
|
+
{},
|
|
832
|
+
{
|
|
833
|
+
dragstart: (event) => {
|
|
834
|
+
active = { id: event.id, payload };
|
|
835
|
+
},
|
|
836
|
+
dragend: (event) => {
|
|
837
|
+
if (active?.id === event.id) active = null;
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
children
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
function itemValue(item) {
|
|
844
|
+
if (item.text !== void 0) {
|
|
845
|
+
if (item.type === "text/uri-list") {
|
|
846
|
+
try {
|
|
847
|
+
return new URL(item.text.split(/\r?\n/)[0].trim());
|
|
848
|
+
} catch {
|
|
849
|
+
return item.text;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return item.text;
|
|
853
|
+
}
|
|
854
|
+
const binary = atob(item.data ?? "");
|
|
855
|
+
const bytes = new Uint8Array(binary.length);
|
|
856
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
857
|
+
return typeof File !== "undefined" ? new File([bytes], item.name ?? "file", { type: item.type }) : bytes;
|
|
858
|
+
}
|
|
859
|
+
function DropDestination({ action, isTargeted, accepts, children }) {
|
|
860
|
+
return sb(
|
|
861
|
+
"dropdestination",
|
|
862
|
+
{ accepts: accepts ?? [] },
|
|
863
|
+
{
|
|
864
|
+
drop: (event) => {
|
|
865
|
+
if (event.phase === "entered") {
|
|
866
|
+
isTargeted?.(true);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
isTargeted?.(false);
|
|
870
|
+
if (event.phase !== "performed") return;
|
|
871
|
+
let items;
|
|
872
|
+
if (event.source !== void 0) items = active && active.id === event.source ? [active.payload] : [];
|
|
873
|
+
else items = (event.items ?? []).map(itemValue);
|
|
874
|
+
if (items.length > 0) action(items, { x: event.x, y: event.y });
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
children
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
|
|
881
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
882
|
+
if (!presented) return null;
|
|
883
|
+
const dismiss = () => {
|
|
884
|
+
setPresented(false);
|
|
885
|
+
onDismiss?.();
|
|
886
|
+
};
|
|
887
|
+
const detents = fullScreen ? ["full"] : ["large"];
|
|
888
|
+
return sb(
|
|
889
|
+
HOIST_KIND,
|
|
890
|
+
void 0,
|
|
891
|
+
void 0,
|
|
892
|
+
sb(
|
|
893
|
+
"sheet",
|
|
894
|
+
{ detents },
|
|
895
|
+
{ tap: dismiss },
|
|
896
|
+
/* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) })
|
|
897
|
+
),
|
|
898
|
+
"root"
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
function presentationDetents(detents) {
|
|
902
|
+
const encoded = detents.map(
|
|
903
|
+
(detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
|
|
904
|
+
);
|
|
905
|
+
return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
|
|
906
|
+
}
|
|
907
|
+
function AlertPresenter({ title, isPresented, message, actions, style }) {
|
|
908
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
909
|
+
if (!presented) return null;
|
|
910
|
+
const dismiss = () => setPresented(false);
|
|
911
|
+
return sb(
|
|
912
|
+
HOIST_KIND,
|
|
913
|
+
void 0,
|
|
914
|
+
void 0,
|
|
915
|
+
sb(
|
|
916
|
+
"alert",
|
|
917
|
+
{ title, message: message ?? null, style: style ?? "alert" },
|
|
918
|
+
{ tap: dismiss },
|
|
919
|
+
withEnvironment({ dismissAlert: dismiss }, actions)
|
|
920
|
+
),
|
|
921
|
+
"root"
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
function Lifecycle({ onAppear, onDisappear }) {
|
|
925
|
+
useEffect(() => {
|
|
926
|
+
onAppear?.();
|
|
927
|
+
return () => onDisappear?.();
|
|
928
|
+
}, []);
|
|
929
|
+
return null;
|
|
930
|
+
}
|
|
931
|
+
function Inspector({ isPresented, content, columnWidth, children }) {
|
|
932
|
+
const sizeClass = useHorizontalSizeClass();
|
|
933
|
+
const [presented, setPresented] = readBinding(isPresented);
|
|
934
|
+
if (sizeClass === "compact") {
|
|
935
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
936
|
+
children,
|
|
937
|
+
/* @__PURE__ */ jsx(SheetPresenter, { isPresented: [presented, setPresented], content })
|
|
938
|
+
] });
|
|
939
|
+
}
|
|
940
|
+
const panelContent = columnWidth !== void 0 ? sb("styled", { style: { inspectorColumnWidth: columnWidth } }, void 0, content) : content;
|
|
941
|
+
return sb("inspector", { presented }, void 0, [
|
|
942
|
+
/* @__PURE__ */ jsx(InspectorPart, { children }, "content"),
|
|
943
|
+
/* @__PURE__ */ jsx(InspectorPart, { children: sb("inspectorpanel", {}, void 0, panelContent) }, "panel")
|
|
944
|
+
]);
|
|
945
|
+
}
|
|
946
|
+
function InspectorPart({ children }) {
|
|
947
|
+
return children;
|
|
948
|
+
}
|
|
949
|
+
function Task({ id, action }) {
|
|
950
|
+
const latest = useRef(action);
|
|
951
|
+
latest.current = action;
|
|
952
|
+
useEffect(() => {
|
|
953
|
+
const controller = new AbortController();
|
|
954
|
+
Promise.resolve().then(() => latest.current(controller.signal)).catch((error) => {
|
|
955
|
+
if (!controller.signal.aborted) console.error(error);
|
|
956
|
+
});
|
|
957
|
+
return () => controller.abort();
|
|
958
|
+
}, [id]);
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
function OnChange({
|
|
962
|
+
value,
|
|
963
|
+
action,
|
|
964
|
+
initial
|
|
965
|
+
}) {
|
|
966
|
+
const previous = useRef(null);
|
|
967
|
+
const latest = useRef(action);
|
|
968
|
+
latest.current = action;
|
|
969
|
+
useEffect(() => {
|
|
970
|
+
const last = previous.current;
|
|
971
|
+
previous.current = { value };
|
|
972
|
+
if (last === null) {
|
|
973
|
+
if (initial) latest.current(value, value);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
if (!Object.is(last.value, value)) latest.current(last.value, value);
|
|
977
|
+
}, [value, initial]);
|
|
978
|
+
return null;
|
|
979
|
+
}
|
|
980
|
+
const CoordinateSpacesContext = createContext({});
|
|
981
|
+
function useCoordinateSpaces() {
|
|
982
|
+
return useContext(CoordinateSpacesContext);
|
|
983
|
+
}
|
|
984
|
+
function CoordinateSpace({ name, children }) {
|
|
985
|
+
const spaces = useContext(CoordinateSpacesContext);
|
|
986
|
+
const [frame2, setFrame] = useState(null);
|
|
987
|
+
return /* @__PURE__ */ jsx(CoordinateSpacesContext.Provider, { value: { ...spaces, [name]: frame2 }, children: sb(
|
|
988
|
+
"zstack",
|
|
989
|
+
{ alignment: "center", reportsSize: true, reportsFrame: true },
|
|
990
|
+
{
|
|
991
|
+
geometry: (event) => {
|
|
992
|
+
const next = { x: event.x ?? 0, y: event.y ?? 0, width: event.width, height: event.height };
|
|
993
|
+
if (!frame2 || frame2.x !== next.x || frame2.y !== next.y || frame2.width !== next.width || frame2.height !== next.height) setFrame(next);
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
children
|
|
997
|
+
) });
|
|
998
|
+
}
|
|
999
|
+
function Hover({ action, children }) {
|
|
1000
|
+
return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
|
|
1001
|
+
}
|
|
1002
|
+
const CURSORS = {
|
|
1003
|
+
link: "pointer",
|
|
1004
|
+
automatic: "auto",
|
|
1005
|
+
default: "default",
|
|
1006
|
+
text: "text",
|
|
1007
|
+
verticalText: "vertical-text",
|
|
1008
|
+
grabIdle: "grab",
|
|
1009
|
+
grabActive: "grabbing",
|
|
1010
|
+
rectSelection: "crosshair",
|
|
1011
|
+
columnResize: "col-resize",
|
|
1012
|
+
rowResize: "row-resize"
|
|
1013
|
+
};
|
|
1014
|
+
function cursorFor(style) {
|
|
1015
|
+
return CURSORS[style] ?? style;
|
|
1016
|
+
}
|
|
1017
|
+
function SymbolEffect({ spec, children }) {
|
|
1018
|
+
const serial = useRef(null);
|
|
1019
|
+
const discrete = "value" in spec;
|
|
1020
|
+
if (discrete) {
|
|
1021
|
+
if (!serial.current) serial.current = { value: spec.value, count: 0 };
|
|
1022
|
+
else if (!Object.is(serial.current.value, spec.value)) serial.current = { value: spec.value, count: serial.current.count + 1 };
|
|
1023
|
+
}
|
|
1024
|
+
if (!discrete && spec.isActive === false) return children;
|
|
1025
|
+
const effect = { effect: spec.effect };
|
|
1026
|
+
if (spec.direction) effect.direction = spec.direction;
|
|
1027
|
+
if (spec.speed !== void 0) effect.speed = spec.speed;
|
|
1028
|
+
if (spec.repeat !== void 0) effect.repeat = spec.repeat;
|
|
1029
|
+
if (discrete) effect.trigger = serial.current.count;
|
|
1030
|
+
return styled({ symbolEffect: effect }, children);
|
|
1031
|
+
}
|
|
1032
|
+
function useNamespace() {
|
|
1033
|
+
return useId();
|
|
1034
|
+
}
|
|
1035
|
+
const KEY_NAMES = {
|
|
1036
|
+
return: "Enter",
|
|
1037
|
+
escape: "Escape",
|
|
1038
|
+
delete: "Backspace",
|
|
1039
|
+
tab: "Tab",
|
|
1040
|
+
space: " ",
|
|
1041
|
+
upArrow: "ArrowUp",
|
|
1042
|
+
downArrow: "ArrowDown",
|
|
1043
|
+
leftArrow: "ArrowLeft",
|
|
1044
|
+
rightArrow: "ArrowRight"
|
|
1045
|
+
};
|
|
1046
|
+
const isApple = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
|
|
1047
|
+
function matchesKey(event, key) {
|
|
1048
|
+
const name = KEY_NAMES[key] ?? key;
|
|
1049
|
+
return name.length === 1 ? event.key.toLowerCase() === name.toLowerCase() : event.key === name;
|
|
1050
|
+
}
|
|
1051
|
+
function matchesShortcut(event, shortcut) {
|
|
1052
|
+
if (!matchesKey(event, shortcut.key)) return false;
|
|
1053
|
+
const wanted = new Set(shortcut.modifiers ?? ["command"]);
|
|
1054
|
+
const command = isApple() ? event.metaKey : event.ctrlKey;
|
|
1055
|
+
const control = isApple() ? event.ctrlKey : false;
|
|
1056
|
+
return command === wanted.has("command") && event.shiftKey === wanted.has("shift") && event.altKey === wanted.has("option") && control === (isApple() && wanted.has("control"));
|
|
1057
|
+
}
|
|
1058
|
+
function useKeyboardShortcut(shortcut, action) {
|
|
1059
|
+
const latest = useRef(action);
|
|
1060
|
+
latest.current = action;
|
|
1061
|
+
const key = shortcut ? `${shortcut.key}:${(shortcut.modifiers ?? ["command"]).join("+")}` : "";
|
|
1062
|
+
useEffect(() => {
|
|
1063
|
+
if (!shortcut || typeof document === "undefined") return;
|
|
1064
|
+
const onKey = (event) => {
|
|
1065
|
+
if (event.defaultPrevented || !matchesShortcut(event, shortcut)) return;
|
|
1066
|
+
event.preventDefault();
|
|
1067
|
+
latest.current();
|
|
1068
|
+
};
|
|
1069
|
+
document.addEventListener("keydown", onKey);
|
|
1070
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
1071
|
+
}, [key]);
|
|
1072
|
+
}
|
|
1073
|
+
function KeyPressListener({ spec }) {
|
|
1074
|
+
const latest = useRef(spec);
|
|
1075
|
+
latest.current = spec;
|
|
1076
|
+
useEffect(() => {
|
|
1077
|
+
if (typeof document === "undefined") return;
|
|
1078
|
+
const onKey = (event) => {
|
|
1079
|
+
const target = event.target;
|
|
1080
|
+
if (event.defaultPrevented || target?.closest("input, textarea, [contenteditable]")) return;
|
|
1081
|
+
const { keys, action } = latest.current;
|
|
1082
|
+
if (keys && !keys.some((key) => matchesKey(event, key))) return;
|
|
1083
|
+
const modifiers = [];
|
|
1084
|
+
if (event.metaKey) modifiers.push("command");
|
|
1085
|
+
if (event.shiftKey) modifiers.push("shift");
|
|
1086
|
+
if (event.altKey) modifiers.push("option");
|
|
1087
|
+
if (event.ctrlKey) modifiers.push("control");
|
|
1088
|
+
const result = action({ key: event.key, characters: event.key.length === 1 ? event.key : "", modifiers, phase: event.repeat ? "repeat" : "down" });
|
|
1089
|
+
if (result === "handled") event.preventDefault();
|
|
1090
|
+
};
|
|
1091
|
+
document.addEventListener("keydown", onKey);
|
|
1092
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
1093
|
+
}, []);
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
const PATTERNS = {
|
|
1097
|
+
success: [12, 60, 18],
|
|
1098
|
+
warning: [18, 80, 18],
|
|
1099
|
+
error: [24, 50, 24, 50, 24],
|
|
1100
|
+
selection: 8,
|
|
1101
|
+
increase: 10,
|
|
1102
|
+
decrease: 10,
|
|
1103
|
+
start: 14,
|
|
1104
|
+
stop: 14,
|
|
1105
|
+
alignment: 6,
|
|
1106
|
+
levelChange: 10,
|
|
1107
|
+
impact: 16
|
|
1108
|
+
};
|
|
1109
|
+
function SensoryFeedbackPlayer({ feedback, trigger }) {
|
|
1110
|
+
const first = useRef(true);
|
|
1111
|
+
useEffect(() => {
|
|
1112
|
+
if (first.current) {
|
|
1113
|
+
first.current = false;
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
if (typeof navigator !== "undefined" && typeof navigator.vibrate === "function") navigator.vibrate(PATTERNS[feedback]);
|
|
1117
|
+
}, [trigger, feedback]);
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
function toolbarPlacement(name) {
|
|
1121
|
+
switch (name) {
|
|
1122
|
+
case "topBarLeading":
|
|
1123
|
+
case "navigationBarLeading":
|
|
1124
|
+
case "cancellationAction":
|
|
1125
|
+
case "navigation":
|
|
1126
|
+
return "leading";
|
|
1127
|
+
case "principal":
|
|
1128
|
+
return "principal";
|
|
1129
|
+
case "bottomBar":
|
|
1130
|
+
return "bottom";
|
|
1131
|
+
default:
|
|
1132
|
+
return "trailing";
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
const MODIFIER_KEYS = /* @__PURE__ */ new Set([
|
|
1136
|
+
"padding",
|
|
1137
|
+
"font",
|
|
1138
|
+
"fontWeight",
|
|
1139
|
+
"bold",
|
|
1140
|
+
"foregroundStyle",
|
|
1141
|
+
"background",
|
|
1142
|
+
"overlay",
|
|
1143
|
+
"frame",
|
|
1144
|
+
"cornerRadius",
|
|
1145
|
+
"clipShape",
|
|
1146
|
+
"clipped",
|
|
1147
|
+
"opacity",
|
|
1148
|
+
"disabled",
|
|
1149
|
+
"hidden",
|
|
1150
|
+
"layoutPriority",
|
|
1151
|
+
"lineLimit",
|
|
1152
|
+
"multilineTextAlignment",
|
|
1153
|
+
"fixedSize",
|
|
1154
|
+
"offset",
|
|
1155
|
+
"rotationEffect",
|
|
1156
|
+
"scaleEffect",
|
|
1157
|
+
"shadow",
|
|
1158
|
+
"tint",
|
|
1159
|
+
"badge",
|
|
1160
|
+
"listRowInsets",
|
|
1161
|
+
"imageScale",
|
|
1162
|
+
"transition",
|
|
1163
|
+
"animation",
|
|
1164
|
+
"gridColumnAlignment",
|
|
1165
|
+
"gridCellColumns",
|
|
1166
|
+
"buttonStyle",
|
|
1167
|
+
"controlSize",
|
|
1168
|
+
"pickerStyle",
|
|
1169
|
+
"labelsHidden",
|
|
1170
|
+
"navigationTitle",
|
|
1171
|
+
"navigationBarTitleDisplayMode",
|
|
1172
|
+
"toolbar",
|
|
1173
|
+
"searchable",
|
|
1174
|
+
"navigationDestination",
|
|
1175
|
+
"sheet",
|
|
1176
|
+
"fullScreenCover",
|
|
1177
|
+
"alert",
|
|
1178
|
+
"confirmationDialog",
|
|
1179
|
+
"presentationDetents",
|
|
1180
|
+
"onTapGesture",
|
|
1181
|
+
"dragGesture",
|
|
1182
|
+
"onLongPressGesture",
|
|
1183
|
+
"contextMenu",
|
|
1184
|
+
"swipeActions",
|
|
1185
|
+
"onAppear",
|
|
1186
|
+
"onDisappear",
|
|
1187
|
+
"tag",
|
|
1188
|
+
"modifiers",
|
|
1189
|
+
"aspectRatio",
|
|
1190
|
+
"scaledToFit",
|
|
1191
|
+
"scaledToFill",
|
|
1192
|
+
"blur",
|
|
1193
|
+
"brightness",
|
|
1194
|
+
"contrast",
|
|
1195
|
+
"saturation",
|
|
1196
|
+
"grayscale",
|
|
1197
|
+
"hueRotation",
|
|
1198
|
+
"colorInvert",
|
|
1199
|
+
"colorMultiply",
|
|
1200
|
+
"blendMode",
|
|
1201
|
+
"mask",
|
|
1202
|
+
"position",
|
|
1203
|
+
"zIndex",
|
|
1204
|
+
"allowsHitTesting",
|
|
1205
|
+
"ignoresSafeArea",
|
|
1206
|
+
"rotation3DEffect",
|
|
1207
|
+
"gridCellAnchor",
|
|
1208
|
+
"alignmentGuide",
|
|
1209
|
+
"preferredColorScheme",
|
|
1210
|
+
"refreshable",
|
|
1211
|
+
"submitLabel",
|
|
1212
|
+
"labelStyle",
|
|
1213
|
+
"task",
|
|
1214
|
+
"onChangeOf",
|
|
1215
|
+
"scrollID",
|
|
1216
|
+
"draggable",
|
|
1217
|
+
"dropDestination",
|
|
1218
|
+
"inspector",
|
|
1219
|
+
"onHover",
|
|
1220
|
+
"help",
|
|
1221
|
+
"pointerStyle",
|
|
1222
|
+
"symbolEffect",
|
|
1223
|
+
"matchedGeometryEffect",
|
|
1224
|
+
"layoutValue",
|
|
1225
|
+
"safeAreaInset",
|
|
1226
|
+
"popover",
|
|
1227
|
+
"redacted",
|
|
1228
|
+
"keyboardShortcut",
|
|
1229
|
+
"onKeyPress",
|
|
1230
|
+
"sensoryFeedback",
|
|
1231
|
+
"textCase",
|
|
1232
|
+
"coordinateSpace",
|
|
1233
|
+
"contentTransition"
|
|
1234
|
+
]);
|
|
1235
|
+
function splitProps(props) {
|
|
1236
|
+
const own = {};
|
|
1237
|
+
const modifiers = [];
|
|
1238
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1239
|
+
if (MODIFIER_KEYS.has(key)) modifiers.push([key, value]);
|
|
1240
|
+
else own[key] = value;
|
|
1241
|
+
}
|
|
1242
|
+
return { own, modifiers };
|
|
1243
|
+
}
|
|
1244
|
+
function takeModifier(modifiers, key) {
|
|
1245
|
+
const at = modifiers.findIndex(([name]) => name === key);
|
|
1246
|
+
if (at < 0) return void 0;
|
|
1247
|
+
const [, value] = modifiers[at];
|
|
1248
|
+
modifiers.splice(at, 1);
|
|
1249
|
+
return value;
|
|
1250
|
+
}
|
|
1251
|
+
function styled(style, child) {
|
|
1252
|
+
return sb("styled", { style }, void 0, child);
|
|
1253
|
+
}
|
|
1254
|
+
function decorated(role, alignment, content, decoration) {
|
|
1255
|
+
return sb("decorated", { role, alignment }, void 0, [
|
|
1256
|
+
createElement(Fragment$1, { key: "content" }, content),
|
|
1257
|
+
createElement(Fragment$1, { key: "decoration" }, decoration)
|
|
1258
|
+
]);
|
|
1259
|
+
}
|
|
1260
|
+
function shapeSpecOf(element) {
|
|
1261
|
+
const spec = element.type.shape;
|
|
1262
|
+
if (!spec) return null;
|
|
1263
|
+
const radius = element.props.cornerRadius;
|
|
1264
|
+
return { kind: spec.kind, cornerRadius: spec.cornerRadius ?? radius ?? 0 };
|
|
1265
|
+
}
|
|
1266
|
+
function AnimatedStyle({ animation, value, children }) {
|
|
1267
|
+
const last = useRef({ value, token: 0 });
|
|
1268
|
+
if (!Object.is(last.current.value, value)) last.current = { value, token: last.current.token + 1 };
|
|
1269
|
+
return styled({ animation, animationToken: last.current.token }, children);
|
|
1270
|
+
}
|
|
1271
|
+
function Searchable({ text, onChange, prompt }) {
|
|
1272
|
+
const [value, setValue] = readBinding(text, onChange);
|
|
1273
|
+
return sb("searchfield", { text: value, placeholder: prompt ?? "Search" }, { text: (event) => setValue(event.value) });
|
|
1274
|
+
}
|
|
1275
|
+
function applyModifiers(element, modifiers) {
|
|
1276
|
+
const sides = [];
|
|
1277
|
+
const node = wrap(element, modifiers, sides);
|
|
1278
|
+
if (sides.length === 0) return node;
|
|
1279
|
+
return createElement(Fragment$1, null, node, ...sides);
|
|
1280
|
+
}
|
|
1281
|
+
function wrap(element, modifiers, sides) {
|
|
1282
|
+
let node = element;
|
|
1283
|
+
for (const [key, value] of modifiers) {
|
|
1284
|
+
if (value === void 0) continue;
|
|
1285
|
+
if (value === null && key !== "lineLimit" && key !== "badge") continue;
|
|
1286
|
+
node = apply(key, value, node, sides);
|
|
1287
|
+
}
|
|
1288
|
+
return node;
|
|
1289
|
+
}
|
|
1290
|
+
function apply(key, value, node, sides) {
|
|
1291
|
+
switch (key) {
|
|
1292
|
+
case "padding":
|
|
1293
|
+
return styled({ padding: padding(value) }, node);
|
|
1294
|
+
case "font":
|
|
1295
|
+
return styled({ font: font(value) }, node);
|
|
1296
|
+
case "fontWeight":
|
|
1297
|
+
return styled({ font: { weight: value } }, node);
|
|
1298
|
+
case "bold":
|
|
1299
|
+
return value ? styled({ font: { weight: "bold" } }, node) : node;
|
|
1300
|
+
case "foregroundStyle":
|
|
1301
|
+
return styled({ foreground: shapeStyle(value) }, node);
|
|
1302
|
+
case "background": {
|
|
1303
|
+
if (isValidElement(value)) return decorated("background", "center", node, value);
|
|
1304
|
+
const inShape = value;
|
|
1305
|
+
if (typeof inShape === "object" && inShape !== null && "in" in inShape && isValidElement(inShape.in)) {
|
|
1306
|
+
return decorated("background", "center", node, cloneElement(inShape.in, { fill: inShape.fill }));
|
|
1307
|
+
}
|
|
1308
|
+
return styled({ background: shapeStyle(value) }, node);
|
|
1309
|
+
}
|
|
1310
|
+
case "overlay": {
|
|
1311
|
+
if (isValidElement(value)) return decorated("overlay", "center", node, value);
|
|
1312
|
+
const spec = value;
|
|
1313
|
+
return decorated("overlay", spec.alignment ?? "center", node, spec.content);
|
|
1314
|
+
}
|
|
1315
|
+
case "frame":
|
|
1316
|
+
return styled({ frame: frame(value) }, node);
|
|
1317
|
+
case "cornerRadius":
|
|
1318
|
+
return styled({ cornerRadius: value }, node);
|
|
1319
|
+
case "clipShape": {
|
|
1320
|
+
const spec = isValidElement(value) ? shapeSpecOf(value) : null;
|
|
1321
|
+
return styled({ cornerRadius: spec?.cornerRadius ?? 0 }, node);
|
|
1322
|
+
}
|
|
1323
|
+
case "clipped":
|
|
1324
|
+
return value ? styled({ clipped: true }, node) : node;
|
|
1325
|
+
case "opacity":
|
|
1326
|
+
return styled({ opacity: value }, node);
|
|
1327
|
+
case "disabled":
|
|
1328
|
+
return value ? styled({ disabled: true }, node) : node;
|
|
1329
|
+
case "hidden":
|
|
1330
|
+
return value ? styled({ hidden: true }, node) : node;
|
|
1331
|
+
case "layoutPriority":
|
|
1332
|
+
return styled({ layoutPriority: value }, node);
|
|
1333
|
+
case "lineLimit": {
|
|
1334
|
+
if (Array.isArray(value)) {
|
|
1335
|
+
const [min, max] = value;
|
|
1336
|
+
return styled({ lineLimit: max, lineLimitMin: min }, node);
|
|
1337
|
+
}
|
|
1338
|
+
return styled({ lineLimit: value }, node);
|
|
1339
|
+
}
|
|
1340
|
+
case "multilineTextAlignment":
|
|
1341
|
+
return styled({ multilineTextAlignment: value }, node);
|
|
1342
|
+
case "fixedSize":
|
|
1343
|
+
return value ? styled({ fixedSize: value === true ? { horizontal: true, vertical: true } : value }, node) : node;
|
|
1344
|
+
case "offset": {
|
|
1345
|
+
const offset = value;
|
|
1346
|
+
return styled({ offset: { x: offset.x ?? 0, y: offset.y ?? 0 } }, node);
|
|
1347
|
+
}
|
|
1348
|
+
case "rotationEffect": {
|
|
1349
|
+
if (typeof value === "number") return styled({ rotation: value }, node);
|
|
1350
|
+
const spec = value;
|
|
1351
|
+
const style = { rotation: spec.degrees };
|
|
1352
|
+
if (spec.anchor !== void 0) style.rotationAnchor = unitPoint(spec.anchor);
|
|
1353
|
+
return styled(style, node);
|
|
1354
|
+
}
|
|
1355
|
+
case "scaleEffect": {
|
|
1356
|
+
if (typeof value === "number") return styled({ scale: { x: value, y: value } }, node);
|
|
1357
|
+
const spec = value;
|
|
1358
|
+
const style = { scale: { x: spec.x, y: spec.y } };
|
|
1359
|
+
if (spec.anchor !== void 0) style.scaleAnchor = unitPoint(spec.anchor);
|
|
1360
|
+
return styled(style, node);
|
|
1361
|
+
}
|
|
1362
|
+
case "shadow": {
|
|
1363
|
+
const shadow = value;
|
|
1364
|
+
return styled(
|
|
1365
|
+
{ shadow: { color: shadow.color ? color(shadow.color) : rgb(0, 0, 0, 0.33), radius: shadow.radius, x: shadow.x ?? 0, y: shadow.y ?? 0 } },
|
|
1366
|
+
node
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
case "tint":
|
|
1370
|
+
return styled({ tint: color(value) }, node);
|
|
1371
|
+
case "badge":
|
|
1372
|
+
return styled({ badge: value === null ? null : String(value) }, node);
|
|
1373
|
+
case "listRowInsets":
|
|
1374
|
+
return styled({ listRowInsets: value }, node);
|
|
1375
|
+
case "imageScale":
|
|
1376
|
+
return styled({ imageScale: value }, node);
|
|
1377
|
+
case "transition":
|
|
1378
|
+
return styled({ transition: value }, node);
|
|
1379
|
+
case "animation": {
|
|
1380
|
+
const spec = value;
|
|
1381
|
+
return createElement(AnimatedStyle, { animation: spec.animation ?? { type: "default" }, value: spec.value }, node);
|
|
1382
|
+
}
|
|
1383
|
+
case "gridColumnAlignment":
|
|
1384
|
+
return styled({ gridColumnAlignment: value }, node);
|
|
1385
|
+
case "gridCellColumns":
|
|
1386
|
+
return styled({ gridCellColumns: value }, node);
|
|
1387
|
+
case "buttonStyle":
|
|
1388
|
+
return withEnvironment({ buttonStyle: value === "borderless" ? "plain" : value }, node);
|
|
1389
|
+
case "controlSize":
|
|
1390
|
+
return withEnvironment({ controlSize: value }, node);
|
|
1391
|
+
case "pickerStyle":
|
|
1392
|
+
return withEnvironment({ pickerStyle: value }, node);
|
|
1393
|
+
case "labelsHidden":
|
|
1394
|
+
return withEnvironment({ labelsHidden: Boolean(value) }, node);
|
|
1395
|
+
case "navigationTitle":
|
|
1396
|
+
sides.push(sb(PREF_KIND, { title: value }, void 0, void 0, "navscreen"));
|
|
1397
|
+
return node;
|
|
1398
|
+
case "navigationBarTitleDisplayMode":
|
|
1399
|
+
sides.push(sb(PREF_KIND, { displayMode: value }, void 0, void 0, "navscreen"));
|
|
1400
|
+
return node;
|
|
1401
|
+
case "toolbar":
|
|
1402
|
+
sides.push(sb(HOIST_KIND, void 0, void 0, value, "navscreen"));
|
|
1403
|
+
return node;
|
|
1404
|
+
case "searchable":
|
|
1405
|
+
sides.push(sb(HOIST_KIND, void 0, void 0, createElement(Searchable, value), "navscreen"));
|
|
1406
|
+
return node;
|
|
1407
|
+
case "navigationDestination":
|
|
1408
|
+
sides.push(createElement(RegisterDestination, { destination: value }));
|
|
1409
|
+
return node;
|
|
1410
|
+
case "sheet":
|
|
1411
|
+
sides.push(createElement(SheetPresenter, value));
|
|
1412
|
+
return node;
|
|
1413
|
+
case "fullScreenCover":
|
|
1414
|
+
sides.push(createElement(SheetPresenter, { ...value, fullScreen: true }));
|
|
1415
|
+
return node;
|
|
1416
|
+
case "alert":
|
|
1417
|
+
sides.push(createElement(AlertPresenter, value));
|
|
1418
|
+
return node;
|
|
1419
|
+
case "confirmationDialog":
|
|
1420
|
+
sides.push(createElement(AlertPresenter, { ...value, style: "dialog" }));
|
|
1421
|
+
return node;
|
|
1422
|
+
case "presentationDetents":
|
|
1423
|
+
sides.push(presentationDetents(value));
|
|
1424
|
+
return node;
|
|
1425
|
+
case "onTapGesture":
|
|
1426
|
+
return sb("tapgesture", {}, { tap: value }, node);
|
|
1427
|
+
case "dragGesture": {
|
|
1428
|
+
const drag = value;
|
|
1429
|
+
return sb(
|
|
1430
|
+
"gesture",
|
|
1431
|
+
{ drag: true, longPress: false, minimumDistance: drag.minimumDistance ?? 10, minimumDuration: 0.5 },
|
|
1432
|
+
{
|
|
1433
|
+
drag: (event) => {
|
|
1434
|
+
const dragValue = {
|
|
1435
|
+
translation: event.translation,
|
|
1436
|
+
location: event.location,
|
|
1437
|
+
startLocation: event.startLocation,
|
|
1438
|
+
velocity: event.velocity
|
|
1439
|
+
};
|
|
1440
|
+
if (event.phase === "ended" || event.phase === "cancelled") drag.onEnded?.(dragValue);
|
|
1441
|
+
else drag.onChanged?.(dragValue);
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
node
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
case "onLongPressGesture": {
|
|
1448
|
+
const spec = typeof value === "function" ? { action: value } : value;
|
|
1449
|
+
return sb(
|
|
1450
|
+
"gesture",
|
|
1451
|
+
{ drag: false, longPress: true, minimumDistance: 10, minimumDuration: spec.minimumDuration ?? 0.5 },
|
|
1452
|
+
{ longpress: () => spec.action() },
|
|
1453
|
+
node
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
case "contextMenu":
|
|
1457
|
+
return sb("contextmenu", {}, void 0, [createElement(Fragment$1, { key: "content" }, node), createElement(Fragment$1, { key: "items" }, value)]);
|
|
1458
|
+
case "swipeActions": {
|
|
1459
|
+
const specs = Array.isArray(value) ? value : [value];
|
|
1460
|
+
const trailing = [];
|
|
1461
|
+
const leading = [];
|
|
1462
|
+
let fullSwipeTrailing = true;
|
|
1463
|
+
let fullSwipeLeading = true;
|
|
1464
|
+
for (const spec of specs) {
|
|
1465
|
+
const actions = Children.toArray(spec.children);
|
|
1466
|
+
if (spec.edge === "leading") {
|
|
1467
|
+
leading.push(...actions);
|
|
1468
|
+
fullSwipeLeading = spec.allowsFullSwipe ?? true;
|
|
1469
|
+
} else {
|
|
1470
|
+
trailing.push(...actions);
|
|
1471
|
+
fullSwipeTrailing = spec.allowsFullSwipe ?? true;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return sb(
|
|
1475
|
+
"swipeactions",
|
|
1476
|
+
{ trailing: trailing.length, leading: leading.length, fullSwipeTrailing, fullSwipeLeading },
|
|
1477
|
+
void 0,
|
|
1478
|
+
[createElement(Fragment$1, { key: "content" }, node), ...trailing, ...leading]
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
case "onAppear":
|
|
1482
|
+
sides.push(createElement(Lifecycle, { onAppear: value }));
|
|
1483
|
+
return node;
|
|
1484
|
+
case "onDisappear":
|
|
1485
|
+
sides.push(createElement(Lifecycle, { onDisappear: value }));
|
|
1486
|
+
return node;
|
|
1487
|
+
case "tag":
|
|
1488
|
+
return node;
|
|
1489
|
+
case "aspectRatio": {
|
|
1490
|
+
const spec = typeof value === "number" ? { ratio: value } : value;
|
|
1491
|
+
return styled({ aspectRatio: { ratio: spec.ratio ?? null, contentMode: spec.contentMode ?? "fit" } }, node);
|
|
1492
|
+
}
|
|
1493
|
+
case "scaledToFit":
|
|
1494
|
+
return value ? styled({ aspectRatio: { ratio: null, contentMode: "fit" } }, node) : node;
|
|
1495
|
+
case "scaledToFill":
|
|
1496
|
+
return value ? styled({ aspectRatio: { ratio: null, contentMode: "fill" } }, node) : node;
|
|
1497
|
+
case "blur":
|
|
1498
|
+
return styled({ blur: value }, node);
|
|
1499
|
+
case "brightness":
|
|
1500
|
+
return styled({ brightness: value }, node);
|
|
1501
|
+
case "contrast":
|
|
1502
|
+
return styled({ contrast: value }, node);
|
|
1503
|
+
case "saturation":
|
|
1504
|
+
return styled({ saturation: value }, node);
|
|
1505
|
+
case "grayscale":
|
|
1506
|
+
return styled({ grayscale: value }, node);
|
|
1507
|
+
case "hueRotation":
|
|
1508
|
+
return styled({ hueRotation: value }, node);
|
|
1509
|
+
case "colorInvert":
|
|
1510
|
+
return value ? styled({ colorInvert: true }, node) : node;
|
|
1511
|
+
case "colorMultiply":
|
|
1512
|
+
return styled({ colorMultiply: color(value) }, node);
|
|
1513
|
+
case "blendMode":
|
|
1514
|
+
return styled({ blendMode: value }, node);
|
|
1515
|
+
case "mask":
|
|
1516
|
+
return styled({ mask: shapeStyle(value) }, node);
|
|
1517
|
+
case "position":
|
|
1518
|
+
return styled({ position: value }, node);
|
|
1519
|
+
case "zIndex":
|
|
1520
|
+
return styled({ zIndex: value }, node);
|
|
1521
|
+
case "allowsHitTesting":
|
|
1522
|
+
return value === false ? styled({ hitTesting: false }, node) : node;
|
|
1523
|
+
case "ignoresSafeArea":
|
|
1524
|
+
return styled({ ignoresSafeArea: value === true ? "all" : value }, node);
|
|
1525
|
+
case "rotation3DEffect": {
|
|
1526
|
+
const spec = value;
|
|
1527
|
+
const rotation = { angle: spec.angle, axis: spec.axis };
|
|
1528
|
+
if (spec.anchor !== void 0) rotation.anchor = unitPoint(spec.anchor);
|
|
1529
|
+
if (spec.perspective !== void 0) rotation.perspective = spec.perspective;
|
|
1530
|
+
return styled({ rotation3D: rotation }, node);
|
|
1531
|
+
}
|
|
1532
|
+
case "gridCellAnchor":
|
|
1533
|
+
return styled({ gridCellAnchor: unitPoint(value) }, node);
|
|
1534
|
+
case "alignmentGuide": {
|
|
1535
|
+
const spec = value;
|
|
1536
|
+
const at = (width, height) => spec.value({ width, height });
|
|
1537
|
+
const a = at(0, 0);
|
|
1538
|
+
const round = (n) => Math.round(n * 1e6) / 1e6;
|
|
1539
|
+
const vertical = ["top", "bottom", "verticalCenter", "firstTextBaseline", "lastTextBaseline"].includes(spec.guide);
|
|
1540
|
+
const name = spec.guide === "horizontalCenter" || spec.guide === "verticalCenter" ? "center" : spec.guide;
|
|
1541
|
+
return styled(
|
|
1542
|
+
{
|
|
1543
|
+
alignmentGuide: {
|
|
1544
|
+
axis: vertical ? "vertical" : "horizontal",
|
|
1545
|
+
name,
|
|
1546
|
+
value: [round(a), round((at(100, 0) - a) / 100), round((at(0, 100) - a) / 100)]
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
node
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
case "preferredColorScheme":
|
|
1553
|
+
sides.push(sb(PREF_KIND, { colorScheme: value }, void 0, void 0, "root"));
|
|
1554
|
+
return node;
|
|
1555
|
+
case "refreshable":
|
|
1556
|
+
return withEnvironment({ refresh: value }, node);
|
|
1557
|
+
case "submitLabel":
|
|
1558
|
+
return withEnvironment({ submitLabel: value }, node);
|
|
1559
|
+
case "labelStyle":
|
|
1560
|
+
return withEnvironment({ labelStyle: value }, node);
|
|
1561
|
+
case "task": {
|
|
1562
|
+
const spec = typeof value === "function" ? { id: void 0, action: value } : value;
|
|
1563
|
+
sides.push(createElement(Task, spec));
|
|
1564
|
+
return node;
|
|
1565
|
+
}
|
|
1566
|
+
case "onChangeOf":
|
|
1567
|
+
sides.push(createElement(OnChange, value));
|
|
1568
|
+
return node;
|
|
1569
|
+
case "scrollID":
|
|
1570
|
+
return createElement(ScrollTarget, { id: value }, node);
|
|
1571
|
+
case "draggable":
|
|
1572
|
+
return createElement(Draggable, { payload: value }, node);
|
|
1573
|
+
case "dropDestination":
|
|
1574
|
+
return createElement(DropDestination, value, node);
|
|
1575
|
+
case "inspector":
|
|
1576
|
+
return createElement(Inspector, value, node);
|
|
1577
|
+
case "onHover":
|
|
1578
|
+
return createElement(Hover, { action: value }, node);
|
|
1579
|
+
case "help":
|
|
1580
|
+
return styled({ help: value }, node);
|
|
1581
|
+
case "pointerStyle":
|
|
1582
|
+
return styled({ pointerStyle: cursorFor(value) }, node);
|
|
1583
|
+
case "symbolEffect":
|
|
1584
|
+
return createElement(SymbolEffect, { spec: value }, node);
|
|
1585
|
+
case "matchedGeometryEffect": {
|
|
1586
|
+
const spec = value;
|
|
1587
|
+
return styled({ matchedGeometry: `${spec.namespace ?? ""}:${spec.id}` }, node);
|
|
1588
|
+
}
|
|
1589
|
+
case "layoutValue":
|
|
1590
|
+
return node;
|
|
1591
|
+
case "safeAreaInset": {
|
|
1592
|
+
const spec = value;
|
|
1593
|
+
const vertical = spec.edge === "top" || spec.edge === "bottom";
|
|
1594
|
+
const before = spec.edge === "top" || spec.edge === "leading";
|
|
1595
|
+
const children = before ? [createElement(Fragment$1, { key: "inset" }, spec.content), createElement(Fragment$1, { key: "content" }, node)] : [createElement(Fragment$1, { key: "content" }, node), createElement(Fragment$1, { key: "inset" }, spec.content)];
|
|
1596
|
+
return vertical ? sb("vstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children) : sb("hstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children);
|
|
1597
|
+
}
|
|
1598
|
+
case "popover":
|
|
1599
|
+
sides.push(createElement(SheetPresenter, value));
|
|
1600
|
+
return node;
|
|
1601
|
+
case "redacted":
|
|
1602
|
+
return withEnvironment({ redacted: Boolean(value) }, node);
|
|
1603
|
+
case "keyboardShortcut":
|
|
1604
|
+
return node;
|
|
1605
|
+
case "onKeyPress":
|
|
1606
|
+
sides.push(createElement(KeyPressListener, { spec: value }));
|
|
1607
|
+
return node;
|
|
1608
|
+
case "sensoryFeedback": {
|
|
1609
|
+
const spec = value;
|
|
1610
|
+
sides.push(createElement(SensoryFeedbackPlayer, spec));
|
|
1611
|
+
return node;
|
|
1612
|
+
}
|
|
1613
|
+
case "textCase":
|
|
1614
|
+
return withEnvironment({ textCase: value }, node);
|
|
1615
|
+
case "coordinateSpace":
|
|
1616
|
+
return createElement(CoordinateSpace, { name: value }, node);
|
|
1617
|
+
case "contentTransition": {
|
|
1618
|
+
if (value === "identity") return node;
|
|
1619
|
+
if (typeof value === "object") {
|
|
1620
|
+
const countsDown = value.numericText.countsDown;
|
|
1621
|
+
return styled({ contentTransition: { kind: "numericText", ...countsDown !== void 0 ? { countsDown } : {} } }, node);
|
|
1622
|
+
}
|
|
1623
|
+
return styled({ contentTransition: { kind: value } }, node);
|
|
1624
|
+
}
|
|
1625
|
+
case "modifiers": {
|
|
1626
|
+
let result = node;
|
|
1627
|
+
for (const extra of value) {
|
|
1628
|
+
result = wrap(result, Object.entries(extra), sides);
|
|
1629
|
+
}
|
|
1630
|
+
return result;
|
|
1631
|
+
}
|
|
1632
|
+
default: {
|
|
1633
|
+
const unknown = key;
|
|
1634
|
+
throw new Error(`Unknown modifier ${String(unknown)}`);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
const ScrollRequestContext = createContext(null);
|
|
1639
|
+
let nextSerial = 1;
|
|
1640
|
+
function ScrollViewReader({ children }) {
|
|
1641
|
+
const [request, setRequest] = useState(null);
|
|
1642
|
+
const proxy = {
|
|
1643
|
+
scrollTo: (id, anchor) => setRequest({ id, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++ })
|
|
1644
|
+
};
|
|
1645
|
+
return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
|
|
1646
|
+
}
|
|
1647
|
+
function ScrollTarget({ id, children }) {
|
|
1648
|
+
const request = useContext(ScrollRequestContext);
|
|
1649
|
+
if (request && request.id === id) return styled({ scrollID: true, scrollTo: { anchor: request.anchor, serial: request.serial } }, children);
|
|
1650
|
+
return styled({ scrollID: true }, children);
|
|
1651
|
+
}
|
|
1652
|
+
const ListSelectionContext = createContext(null);
|
|
1653
|
+
function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
|
|
1654
|
+
const selection = useContext(ListSelectionContext);
|
|
1655
|
+
const selectable = selection !== null && tag !== void 0;
|
|
1656
|
+
const canDelete = onDelete !== void 0 && deletable !== false;
|
|
1657
|
+
const canMove = onMove !== void 0 && movable !== false;
|
|
1658
|
+
if (!selectable && !canDelete && !canMove) return children;
|
|
1659
|
+
const props = {};
|
|
1660
|
+
if (selectable) {
|
|
1661
|
+
props["selectable"] = true;
|
|
1662
|
+
props["selected"] = selection.isSelected(tag);
|
|
1663
|
+
}
|
|
1664
|
+
if (canDelete) props["deletable"] = true;
|
|
1665
|
+
if (canMove) props["movable"] = true;
|
|
1666
|
+
return sb(
|
|
1667
|
+
"listrow",
|
|
1668
|
+
props,
|
|
1669
|
+
{
|
|
1670
|
+
tap: () => selectable && selection.select(tag),
|
|
1671
|
+
delete: () => onDelete?.(),
|
|
1672
|
+
move: (event) => {
|
|
1673
|
+
const start = (containerIndex ?? index ?? 0) - (index ?? 0);
|
|
1674
|
+
onMove?.(Math.max(0, event.to - start));
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
children
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
const LAZY_BATCH = 12;
|
|
1681
|
+
const LazyContext = createContext(null);
|
|
1682
|
+
function LazyGroup({ rows, start = 0, wrap: wrap2 }) {
|
|
1683
|
+
const axis = useContext(LazyContext);
|
|
1684
|
+
const request = useContext(ScrollRequestContext);
|
|
1685
|
+
const [count, setCount] = useState(LAZY_BATCH);
|
|
1686
|
+
const target = request ? rows.findIndex((row) => rowMatches(row, request.id)) : -1;
|
|
1687
|
+
const needed = target >= 0 ? Math.ceil((target + 1) / LAZY_BATCH) * LAZY_BATCH : 0;
|
|
1688
|
+
useEffect(() => {
|
|
1689
|
+
if (needed > count) setCount(needed);
|
|
1690
|
+
}, [needed, count]);
|
|
1691
|
+
const visible = Math.max(count, needed);
|
|
1692
|
+
const shown = axis === null ? rows : rows.slice(0, visible);
|
|
1693
|
+
const built = shown.map((row, index) => wrap2 ? wrap2(row, start + index) : row);
|
|
1694
|
+
if (axis === null || shown.length >= rows.length) return built;
|
|
1695
|
+
return [
|
|
1696
|
+
...built,
|
|
1697
|
+
createElement(
|
|
1698
|
+
LazySpacer,
|
|
1699
|
+
{ key: `lazy-${visible}`, axis, remaining: rows.length - shown.length, more: () => setCount(visible + LAZY_BATCH) }
|
|
1700
|
+
)
|
|
1701
|
+
];
|
|
1702
|
+
}
|
|
1703
|
+
function LazySpacer({ axis, remaining, more }) {
|
|
1704
|
+
return sb("lazyspacer", { axis, remaining }, { lazy: more });
|
|
1705
|
+
}
|
|
1706
|
+
function rowMatches(row, id) {
|
|
1707
|
+
if (row.key !== null && row.key === String(id)) return true;
|
|
1708
|
+
let element = row;
|
|
1709
|
+
for (let depth = 0; element && depth < 3; depth++) {
|
|
1710
|
+
const props = element.props;
|
|
1711
|
+
if (props.scrollID === id) return true;
|
|
1712
|
+
element = isValidElement(props.children) ? props.children : null;
|
|
1713
|
+
}
|
|
1714
|
+
return false;
|
|
1715
|
+
}
|
|
1716
|
+
function VStack(props) {
|
|
1717
|
+
const { own, modifiers } = splitProps(props);
|
|
1718
|
+
const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
|
|
1719
|
+
if (own.scrollTargetLayout) stack["scrollTarget"] = true;
|
|
1720
|
+
return applyModifiers(sb("vstack", stack, void 0, own.children), modifiers);
|
|
1721
|
+
}
|
|
1722
|
+
function HStack(props) {
|
|
1723
|
+
const { own, modifiers } = splitProps(props);
|
|
1724
|
+
const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
|
|
1725
|
+
if (own.scrollTargetLayout) stack["scrollTarget"] = true;
|
|
1726
|
+
return applyModifiers(sb("hstack", stack, void 0, own.children), modifiers);
|
|
1727
|
+
}
|
|
1728
|
+
function ZStack(props) {
|
|
1729
|
+
const { own, modifiers } = splitProps(props);
|
|
1730
|
+
return applyModifiers(sb("zstack", { alignment: own.alignment ?? "center" }, void 0, own.children), modifiers);
|
|
1731
|
+
}
|
|
1732
|
+
function Spacer(props) {
|
|
1733
|
+
const { own, modifiers } = splitProps(props);
|
|
1734
|
+
return applyModifiers(sb("spacer", { minLength: own.minLength ?? null }), modifiers);
|
|
1735
|
+
}
|
|
1736
|
+
function Divider(props) {
|
|
1737
|
+
const { modifiers } = splitProps(props);
|
|
1738
|
+
return applyModifiers(sb("divider", {}), modifiers);
|
|
1739
|
+
}
|
|
1740
|
+
function ScrollView(props) {
|
|
1741
|
+
const { own, modifiers } = splitProps(props);
|
|
1742
|
+
const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
|
|
1743
|
+
const scroll = { axes: own.axes ?? "vertical", ...refresh.props };
|
|
1744
|
+
if (own.scrollTargetBehavior) scroll["snap"] = own.scrollTargetBehavior;
|
|
1745
|
+
if (own.scrollDismissesKeyboard) scroll["dismissesKeyboard"] = true;
|
|
1746
|
+
return applyModifiers(sb("scrollview", scroll, refresh.handlers, own.children), modifiers);
|
|
1747
|
+
}
|
|
1748
|
+
function useRefreshable(own) {
|
|
1749
|
+
const environment = useViewEnvironment();
|
|
1750
|
+
const refresh = own ?? environment.refresh;
|
|
1751
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
1752
|
+
if (!refresh) return { props: {} };
|
|
1753
|
+
return {
|
|
1754
|
+
props: { refreshable: true, refreshing },
|
|
1755
|
+
handlers: {
|
|
1756
|
+
refresh: () => {
|
|
1757
|
+
if (refreshing) return;
|
|
1758
|
+
setRefreshing(true);
|
|
1759
|
+
Promise.resolve().then(refresh).catch((error) => console.error(error)).finally(() => setRefreshing(false));
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
function Group(props) {
|
|
1765
|
+
const { own, modifiers } = splitProps(props);
|
|
1766
|
+
if (modifiers.length === 0) return own.children;
|
|
1767
|
+
return Children.map(own.children, (child) => applyModifiers(child, modifiers));
|
|
1768
|
+
}
|
|
1769
|
+
function moveItems(items, offsets, to) {
|
|
1770
|
+
const moving = new Set(offsets);
|
|
1771
|
+
const picked = items.filter((_, index) => moving.has(index));
|
|
1772
|
+
const rest = items.filter((_, index) => !moving.has(index));
|
|
1773
|
+
const before = offsets.filter((offset) => offset < to).length;
|
|
1774
|
+
const at = to - before;
|
|
1775
|
+
return [...rest.slice(0, at), ...picked, ...rest.slice(at)];
|
|
1776
|
+
}
|
|
1777
|
+
function ForEach(props) {
|
|
1778
|
+
const { own, modifiers } = splitProps(props);
|
|
1779
|
+
const rows = own.data.map((element, index) => {
|
|
1780
|
+
const key = own.id ? own.id(element, index) : keyOf(element, index);
|
|
1781
|
+
const content = applyModifiers(own.children(element, index), modifiers);
|
|
1782
|
+
if (!own.onDelete && !own.onMove) return createElement(Fragment$1, { key }, content);
|
|
1783
|
+
const { onDelete, onMove } = own;
|
|
1784
|
+
const row = { tag: key, index };
|
|
1785
|
+
if (onDelete) {
|
|
1786
|
+
row.onDelete = () => onDelete([index]);
|
|
1787
|
+
row.deletable = !own.deleteDisabled?.(element, index);
|
|
1788
|
+
}
|
|
1789
|
+
if (onMove) {
|
|
1790
|
+
row.onMove = (to) => onMove([index], to);
|
|
1791
|
+
row.movable = !own.moveDisabled?.(element, index);
|
|
1792
|
+
}
|
|
1793
|
+
return createElement(Row, { key, ...row }, content);
|
|
1794
|
+
});
|
|
1795
|
+
return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
|
|
1796
|
+
}
|
|
1797
|
+
function keyOf(element, index) {
|
|
1798
|
+
if (typeof element === "string" || typeof element === "number") return element;
|
|
1799
|
+
if (typeof element === "object" && element !== null && "id" in element) {
|
|
1800
|
+
const id = element.id;
|
|
1801
|
+
if (typeof id === "string" || typeof id === "number") return id;
|
|
1802
|
+
}
|
|
1803
|
+
return index;
|
|
1804
|
+
}
|
|
1805
|
+
function flattenChildren(children, options = {}) {
|
|
1806
|
+
const result = [];
|
|
1807
|
+
const visit = (node) => {
|
|
1808
|
+
if (node === null || node === void 0 || typeof node === "boolean") return;
|
|
1809
|
+
if (Array.isArray(node)) {
|
|
1810
|
+
node.forEach(visit);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
if (!isValidElement(node)) return;
|
|
1814
|
+
const element = node;
|
|
1815
|
+
if (element.type === Fragment$1) {
|
|
1816
|
+
const inner = element.props["children"];
|
|
1817
|
+
if (element.key !== null && isValidElement(inner) && inner.key === null && inner.type !== Fragment$1) {
|
|
1818
|
+
visit({ ...inner, key: element.key });
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
visit(inner);
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (element.type === ForEach) {
|
|
1825
|
+
visit(ForEach(element.props));
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
if (element.type === LazyGroup && !options.keepLazy) {
|
|
1829
|
+
visit(element.props.rows);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
result.push(element);
|
|
1833
|
+
};
|
|
1834
|
+
visit(children);
|
|
1835
|
+
return result;
|
|
1836
|
+
}
|
|
1837
|
+
function GridItem(spec = {}) {
|
|
1838
|
+
const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
|
|
1839
|
+
let size;
|
|
1840
|
+
if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
|
|
1841
|
+
else if (spec.size && "adaptive" in spec.size) {
|
|
1842
|
+
size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
|
|
1843
|
+
} else {
|
|
1844
|
+
const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
|
|
1845
|
+
size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
|
|
1846
|
+
}
|
|
1847
|
+
return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
|
|
1848
|
+
}
|
|
1849
|
+
GridItem.flexible = (options = {}) => GridItem({ size: { flexible: options }, spacing: options.spacing, alignment: options.alignment });
|
|
1850
|
+
GridItem.fixed = (value, options = {}) => GridItem({ size: { fixed: value }, spacing: options.spacing, alignment: options.alignment });
|
|
1851
|
+
GridItem.adaptive = (options) => GridItem({ size: { adaptive: options }, spacing: options.spacing, alignment: options.alignment });
|
|
1852
|
+
function LazyVGrid(props) {
|
|
1853
|
+
const { own, modifiers } = splitProps(props);
|
|
1854
|
+
return applyModifiers(
|
|
1855
|
+
sb("lazyvgrid", { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
|
|
1856
|
+
modifiers
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
function Grid(props) {
|
|
1860
|
+
const { own, modifiers } = splitProps(props);
|
|
1861
|
+
return applyModifiers(
|
|
1862
|
+
sb(
|
|
1863
|
+
"grid",
|
|
1864
|
+
{ horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
|
|
1865
|
+
void 0,
|
|
1866
|
+
own.children
|
|
1867
|
+
),
|
|
1868
|
+
modifiers
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
function GridRow(props) {
|
|
1872
|
+
const { own, modifiers } = splitProps(props);
|
|
1873
|
+
return applyModifiers(sb("gridrow", { alignment: own.alignment ?? null }, void 0, own.children), modifiers);
|
|
1874
|
+
}
|
|
1875
|
+
function runStyleOf(props, inherited, nested) {
|
|
1876
|
+
const style = { ...inherited };
|
|
1877
|
+
if (props.italic) style.italic = true;
|
|
1878
|
+
if (props.underline) style.underline = typeof props.underline === "object" && props.underline.color ? { color: color(props.underline.color) } : {};
|
|
1879
|
+
if (props.strikethrough) {
|
|
1880
|
+
style.strikethrough = typeof props.strikethrough === "object" && props.strikethrough.color ? { color: color(props.strikethrough.color) } : {};
|
|
1881
|
+
}
|
|
1882
|
+
const kerning = props.tracking ?? props.kerning;
|
|
1883
|
+
if (kerning !== void 0) style.kerning = kerning;
|
|
1884
|
+
if (props.baselineOffset !== void 0) style.baselineOffset = props.baselineOffset;
|
|
1885
|
+
if (props.link) style.link = props.link;
|
|
1886
|
+
if (nested) {
|
|
1887
|
+
let runFont = props.font !== void 0 ? font(props.font) : void 0;
|
|
1888
|
+
if (props.bold) runFont = { ...runFont ?? {}, weight: "bold" };
|
|
1889
|
+
if (props.fontWeight) runFont = { ...runFont ?? {}, weight: props.fontWeight };
|
|
1890
|
+
if (runFont) style.font = { ...style.font ?? {}, ...runFont };
|
|
1891
|
+
if (props.foregroundStyle !== void 0) style.foreground = shapeStyle(props.foregroundStyle);
|
|
1892
|
+
}
|
|
1893
|
+
return style;
|
|
1894
|
+
}
|
|
1895
|
+
function segmentsOf(children, style, into) {
|
|
1896
|
+
const visit = (node) => {
|
|
1897
|
+
if (node === null || node === void 0 || typeof node === "boolean") return;
|
|
1898
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
1899
|
+
const last = into[into.length - 1];
|
|
1900
|
+
if (last && "text" in last && last.style === style) last.text += String(node);
|
|
1901
|
+
else into.push({ text: String(node), style });
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
if (Array.isArray(node)) {
|
|
1905
|
+
node.forEach(visit);
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
if (!isValidElement(node)) return;
|
|
1909
|
+
const element = node;
|
|
1910
|
+
if (element.type === Fragment$1) {
|
|
1911
|
+
visit(element.props["children"]);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (element.type === Text) {
|
|
1915
|
+
const props = element.props;
|
|
1916
|
+
segmentsOf(props.children, runStyleOf(props, style, true), into);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
if (element.type === Image$1) {
|
|
1920
|
+
const props = element.props;
|
|
1921
|
+
into.push({ image: imageProps(props), style });
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
visit(children);
|
|
1926
|
+
}
|
|
1927
|
+
function isPlainStyle(style) {
|
|
1928
|
+
return Object.keys(style).length === 0;
|
|
1929
|
+
}
|
|
1930
|
+
function Text(props) {
|
|
1931
|
+
const { own, modifiers } = splitProps(props);
|
|
1932
|
+
const environment = useViewEnvironment();
|
|
1933
|
+
const style = runStyleOf(props, {}, false);
|
|
1934
|
+
const segments = [];
|
|
1935
|
+
segmentsOf(own.children, style, segments);
|
|
1936
|
+
const textCase = takeModifier(modifiers, "textCase") ?? environment.textCase;
|
|
1937
|
+
if (textCase) {
|
|
1938
|
+
for (const segment of segments) {
|
|
1939
|
+
if ("text" in segment) segment.text = textCase === "uppercase" ? segment.text.toUpperCase() : segment.text.toLowerCase();
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
|
|
1943
|
+
const content = segments.map((segment) => "text" in segment ? segment.text : "").join("");
|
|
1944
|
+
const plain = segments.length <= 1 && (segments.length === 0 || "text" in segments[0] && isPlainStyle(segments[0].style));
|
|
1945
|
+
if (plain) return applyModifiers(placeholder(sb("text", { text: content }), redacted), modifiers);
|
|
1946
|
+
const runs = segments.map((segment) => {
|
|
1947
|
+
const run = { ...segment.style };
|
|
1948
|
+
if ("text" in segment) run["text"] = segment.text;
|
|
1949
|
+
else run["image"] = segment.image;
|
|
1950
|
+
return run;
|
|
1951
|
+
});
|
|
1952
|
+
const hasLinks = segments.some((segment) => segment.style.link);
|
|
1953
|
+
const handlers = hasLinks ? { link: (event) => openURL(event.value) } : void 0;
|
|
1954
|
+
return applyModifiers(placeholder(sb("text", { text: content, runs }, handlers), redacted), modifiers);
|
|
1955
|
+
}
|
|
1956
|
+
function placeholder(node, redacted) {
|
|
1957
|
+
if (!redacted) return node;
|
|
1958
|
+
return styled({ background: { hierarchical: 3 }, backgroundCornerRadius: 4 }, styled({ foreground: { name: "clear" } }, node));
|
|
1959
|
+
}
|
|
1960
|
+
function openURL(url) {
|
|
1961
|
+
if (typeof window !== "undefined") window.open(url, "_blank", "noopener");
|
|
1962
|
+
}
|
|
1963
|
+
function imageProps(props) {
|
|
1964
|
+
if (props.systemName !== void 0) return { systemName: props.systemName };
|
|
1965
|
+
if (props.url !== void 0) return { url: props.url, resizable: props.resizable ?? false, width: props.width ?? 0, height: props.height ?? 0 };
|
|
1966
|
+
return { name: props.name ?? "", resizable: props.resizable ?? false };
|
|
1967
|
+
}
|
|
1968
|
+
function Image$1(props) {
|
|
1969
|
+
const { modifiers } = splitProps(props);
|
|
1970
|
+
const environment = useViewEnvironment();
|
|
1971
|
+
const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
|
|
1972
|
+
return applyModifiers(placeholder(sb("image", imageProps(props)), redacted), modifiers);
|
|
1973
|
+
}
|
|
1974
|
+
function Label(props) {
|
|
1975
|
+
const { own, modifiers } = splitProps(props);
|
|
1976
|
+
const environment = useViewEnvironment();
|
|
1977
|
+
const style = takeModifier(modifiers, "labelStyle") ?? environment.labelStyle ?? "automatic";
|
|
1978
|
+
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);
|
|
1979
|
+
const title = typeof own.title === "string" || typeof own.title === "number" ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.title;
|
|
1980
|
+
if (style === "iconOnly") return applyModifiers(icon, modifiers);
|
|
1981
|
+
if (style === "titleOnly") return applyModifiers(title, modifiers);
|
|
1982
|
+
return applyModifiers(
|
|
1983
|
+
/* @__PURE__ */ jsxs(HStack, { spacing: 8, children: [
|
|
1984
|
+
styled({ labelIcon: true }, icon),
|
|
1985
|
+
title
|
|
1986
|
+
] }),
|
|
1987
|
+
modifiers
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
function LabeledContent(props) {
|
|
1991
|
+
const { own, modifiers } = splitProps(props);
|
|
1992
|
+
const label = typeof own.label === "string" || typeof own.label === "number" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
|
|
1993
|
+
const content = own.children ?? own.value;
|
|
1994
|
+
const value = typeof content === "string" || typeof content === "number" ? /* @__PURE__ */ jsx(Text, { children: content }) : content;
|
|
1995
|
+
return applyModifiers(
|
|
1996
|
+
/* @__PURE__ */ jsxs(HStack, { children: [
|
|
1997
|
+
label,
|
|
1998
|
+
sb("spacer", { minLength: null }),
|
|
1999
|
+
styled({ foreground: { hierarchical: 2 } }, value)
|
|
2000
|
+
] }),
|
|
2001
|
+
modifiers
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
function Link(props) {
|
|
2005
|
+
const { own, modifiers } = splitProps(props);
|
|
2006
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2007
|
+
return applyModifiers(sb("button", { role: null, style: "automatic" }, { tap: () => openURL(own.destination) }, label), modifiers);
|
|
2008
|
+
}
|
|
2009
|
+
function Button(props) {
|
|
2010
|
+
const { own, modifiers } = splitProps(props);
|
|
2011
|
+
const environment = useViewEnvironment();
|
|
2012
|
+
const ownStyle = takeModifier(modifiers, "buttonStyle");
|
|
2013
|
+
const ownSize = takeModifier(modifiers, "controlSize");
|
|
2014
|
+
const style = ownStyle === "borderless" ? "plain" : ownStyle ?? environment.buttonStyle ?? "automatic";
|
|
2015
|
+
const controlSize = ownSize ?? environment.controlSize;
|
|
2016
|
+
const buttonProps = { role: own.role ?? null, style };
|
|
2017
|
+
if (controlSize !== void 0 && controlSize !== "regular") buttonProps["controlSize"] = controlSize;
|
|
2018
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2019
|
+
const tap = () => {
|
|
2020
|
+
own.action?.();
|
|
2021
|
+
environment.dismissAlert?.();
|
|
2022
|
+
};
|
|
2023
|
+
const shortcut = takeModifier(modifiers, "keyboardShortcut");
|
|
2024
|
+
useKeyboardShortcut(typeof shortcut === "string" ? { key: shortcut } : shortcut, () => {
|
|
2025
|
+
if (!buttonDisabled(modifiers)) tap();
|
|
2026
|
+
});
|
|
2027
|
+
return applyModifiers(sb("button", buttonProps, { tap }, label), modifiers);
|
|
2028
|
+
}
|
|
2029
|
+
function Toggle(props) {
|
|
2030
|
+
const { own, modifiers } = splitProps(props);
|
|
2031
|
+
const [isOn, setOn] = readBinding(own.isOn, own.onChange);
|
|
2032
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2033
|
+
return applyModifiers(sb("toggle", { isOn }, { toggle: (event) => setOn(event.value) }, label), modifiers);
|
|
2034
|
+
}
|
|
2035
|
+
function Picker(props) {
|
|
2036
|
+
const { own, modifiers } = splitProps(props);
|
|
2037
|
+
const environment = useViewEnvironment();
|
|
2038
|
+
const ownStyle = takeModifier(modifiers, "pickerStyle");
|
|
2039
|
+
const style = ownStyle ?? environment.pickerStyle ?? "menu";
|
|
2040
|
+
const [selection, setSelection] = readBinding(own.selection, own.onChange);
|
|
2041
|
+
const options = pickerOptions(own.options, own.children);
|
|
2042
|
+
const selected = Math.max(
|
|
2043
|
+
0,
|
|
2044
|
+
options.findIndex((option) => Object.is(option.tag, selection))
|
|
2045
|
+
);
|
|
2046
|
+
return applyModifiers(
|
|
2047
|
+
sb(
|
|
2048
|
+
"picker",
|
|
2049
|
+
{ style, label: own.label, options: options.map((option) => option.label), selected },
|
|
2050
|
+
{ select: (event) => options[event.value] && setSelection(options[event.value].tag) }
|
|
2051
|
+
),
|
|
2052
|
+
modifiers
|
|
2053
|
+
);
|
|
2054
|
+
}
|
|
2055
|
+
function pickerOptions(options, children) {
|
|
2056
|
+
if (options) {
|
|
2057
|
+
return options.map(
|
|
2058
|
+
(option) => typeof option === "object" && option !== null && "label" in option && "tag" in option ? option : { label: String(option), tag: option }
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
return flattenChildren(children).map((element) => {
|
|
2062
|
+
const label = plainText(element);
|
|
2063
|
+
const tag = element.props.tag;
|
|
2064
|
+
return { label, tag: tag !== void 0 ? tag : label };
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
function plainText(element) {
|
|
2068
|
+
const props = element.props;
|
|
2069
|
+
if (element.type === Text) return collectText(props.children);
|
|
2070
|
+
if (typeof props.title === "string") return props.title;
|
|
2071
|
+
return "";
|
|
2072
|
+
}
|
|
2073
|
+
function collectText(node) {
|
|
2074
|
+
if (node === null || node === void 0 || typeof node === "boolean") return "";
|
|
2075
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
2076
|
+
if (Array.isArray(node)) return node.map(collectText).join("");
|
|
2077
|
+
if (typeof node === "object" && "props" in node) {
|
|
2078
|
+
const element = node;
|
|
2079
|
+
if (element.type === Fragment$1 || element.type === Text) return collectText(element.props.children);
|
|
2080
|
+
}
|
|
2081
|
+
return "";
|
|
2082
|
+
}
|
|
2083
|
+
function Slider(props) {
|
|
2084
|
+
const { own, modifiers } = splitProps(props);
|
|
2085
|
+
const environment = useViewEnvironment();
|
|
2086
|
+
const [value, setValue] = readBinding(own.value, own.onChange);
|
|
2087
|
+
const [min, max] = own.range ?? [0, 1];
|
|
2088
|
+
const labels = [];
|
|
2089
|
+
const children = [];
|
|
2090
|
+
if (own.label !== void 0 && !environment.labelsHidden) {
|
|
2091
|
+
labels.push("label");
|
|
2092
|
+
children.push(/* @__PURE__ */ jsx(Fragment$1, { children: own.label }, "label"));
|
|
2093
|
+
}
|
|
2094
|
+
if (own.minimumValueLabel !== void 0 || own.maximumValueLabel !== void 0) {
|
|
2095
|
+
labels.push("min", "max");
|
|
2096
|
+
children.push(/* @__PURE__ */ jsx(Fragment$1, { children: own.minimumValueLabel }, "min"), /* @__PURE__ */ jsx(Fragment$1, { children: own.maximumValueLabel }, "max"));
|
|
2097
|
+
}
|
|
2098
|
+
return applyModifiers(
|
|
2099
|
+
sb("slider", { value, min, max, step: own.step ?? null, labels }, { slide: (event) => setValue(event.value) }, children.length ? children : void 0),
|
|
2100
|
+
modifiers
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2103
|
+
function Stepper(props) {
|
|
2104
|
+
const { own, modifiers } = splitProps(props);
|
|
2105
|
+
const [value, setValue] = readBinding(own.value, own.onChange);
|
|
2106
|
+
const step = own.step ?? 1;
|
|
2107
|
+
const [min, max] = own.range ?? [-Infinity, Infinity];
|
|
2108
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2109
|
+
return applyModifiers(
|
|
2110
|
+
sb(
|
|
2111
|
+
"stepper",
|
|
2112
|
+
{ canIncrement: value < max, canDecrement: value > min },
|
|
2113
|
+
{ step: (event) => setValue(Math.min(max, Math.max(min, value + Math.sign(event.value) * step))) },
|
|
2114
|
+
label
|
|
2115
|
+
),
|
|
2116
|
+
modifiers
|
|
2117
|
+
);
|
|
2118
|
+
}
|
|
2119
|
+
function TextField(props) {
|
|
2120
|
+
const { own, modifiers } = splitProps(props);
|
|
2121
|
+
const environment = useViewEnvironment();
|
|
2122
|
+
const ownSubmitLabel = takeModifier(modifiers, "submitLabel");
|
|
2123
|
+
const [text, setText] = readBinding(own.text, own.onChange);
|
|
2124
|
+
const fieldProps = {
|
|
2125
|
+
text,
|
|
2126
|
+
placeholder: own.placeholder ?? "",
|
|
2127
|
+
style: own.textFieldStyle ?? "plain",
|
|
2128
|
+
secure: own.secure ?? false
|
|
2129
|
+
};
|
|
2130
|
+
if (own.onSubmit) fieldProps["submit"] = true;
|
|
2131
|
+
if (own.axis) fieldProps["axis"] = own.axis;
|
|
2132
|
+
const submitLabel = ownSubmitLabel ?? environment.submitLabel;
|
|
2133
|
+
if (submitLabel) fieldProps["submitLabel"] = submitLabel;
|
|
2134
|
+
const focus = own.focused !== void 0 ? readBinding(own.focused) : null;
|
|
2135
|
+
if (focus) fieldProps["focused"] = focus[0];
|
|
2136
|
+
return applyModifiers(
|
|
2137
|
+
sb("textfield", fieldProps, {
|
|
2138
|
+
text: (event) => setText(event.value),
|
|
2139
|
+
submit: () => own.onSubmit?.(),
|
|
2140
|
+
focus: (event) => focus?.[1](event.value)
|
|
2141
|
+
}),
|
|
2142
|
+
modifiers
|
|
2143
|
+
);
|
|
2144
|
+
}
|
|
2145
|
+
function SecureField(props) {
|
|
2146
|
+
return /* @__PURE__ */ jsx(TextField, { ...props, secure: true });
|
|
2147
|
+
}
|
|
2148
|
+
function ProgressView(props) {
|
|
2149
|
+
const { own, modifiers } = splitProps(props);
|
|
2150
|
+
if (own.value === void 0) {
|
|
2151
|
+
return applyModifiers(
|
|
2152
|
+
styled({ foreground: { hierarchical: 2 } }, styled({ font: { size: 20 } }, /* @__PURE__ */ jsx(Image$1, { systemName: "progress.indicator" }))),
|
|
2153
|
+
modifiers
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
const label = own.label ?? own.children;
|
|
2157
|
+
const children = [];
|
|
2158
|
+
if (label !== void 0 && label !== null) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: label }, "label"));
|
|
2159
|
+
if (own.currentValueLabel !== void 0 && own.currentValueLabel !== null) {
|
|
2160
|
+
children.push(/* @__PURE__ */ jsx(Fragment$1, { children: styled({ foreground: { hierarchical: 2 } }, own.currentValueLabel) }, "current"));
|
|
2161
|
+
}
|
|
2162
|
+
return applyModifiers(
|
|
2163
|
+
sb(
|
|
2164
|
+
"gauge",
|
|
2165
|
+
{ value: own.value / (own.total ?? 1), style: "progress", hasLabel: true, hasCurrentValueLabel: true },
|
|
2166
|
+
void 0,
|
|
2167
|
+
children.length ? children : void 0
|
|
2168
|
+
),
|
|
2169
|
+
modifiers
|
|
2170
|
+
);
|
|
2171
|
+
}
|
|
2172
|
+
function ToolbarItem(props) {
|
|
2173
|
+
return sb("toolbar", { placement: toolbarPlacement(props.placement) }, void 0, props.children);
|
|
2174
|
+
}
|
|
2175
|
+
const ToolbarItemGroup = ToolbarItem;
|
|
2176
|
+
function DatePicker(props) {
|
|
2177
|
+
const { own, modifiers } = splitProps(props);
|
|
2178
|
+
const environment = useViewEnvironment();
|
|
2179
|
+
const [date, setDate] = readBinding(own.selection, own.onChange);
|
|
2180
|
+
const labelsHidden = takeModifier(modifiers, "labelsHidden") ?? environment.labelsHidden ?? false;
|
|
2181
|
+
const seconds = (value) => value ? Math.floor(value.getTime() / 1e3) : null;
|
|
2182
|
+
const pickerProps = {
|
|
2183
|
+
seconds: seconds(date) ?? 0,
|
|
2184
|
+
components: own.displayedComponents ?? "date",
|
|
2185
|
+
min: seconds(own.range?.[0]),
|
|
2186
|
+
max: seconds(own.range?.[1])
|
|
2187
|
+
};
|
|
2188
|
+
if (labelsHidden) pickerProps["labelsHidden"] = true;
|
|
2189
|
+
const label = labelsHidden || own.label === void 0 ? void 0 : /* @__PURE__ */ jsx(Text, { children: own.label });
|
|
2190
|
+
return applyModifiers(sb("datepicker", pickerProps, { date: (event) => setDate(new Date(event.value * 1e3)) }, label), modifiers);
|
|
2191
|
+
}
|
|
2192
|
+
function TextEditor(props) {
|
|
2193
|
+
const { own, modifiers } = splitProps(props);
|
|
2194
|
+
const [text, setText] = readBinding(own.text, own.onChange);
|
|
2195
|
+
const focus = own.focused !== void 0 ? readBinding(own.focused) : null;
|
|
2196
|
+
const editor = { text };
|
|
2197
|
+
if (focus) editor["focused"] = focus[0];
|
|
2198
|
+
return applyModifiers(
|
|
2199
|
+
sb("texteditor", editor, { text: (event) => setText(event.value), focus: (event) => focus?.[1](event.value) }),
|
|
2200
|
+
modifiers
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
function buttonDisabled(modifiers) {
|
|
2204
|
+
return modifiers.some(([key, value]) => key === "disabled" && value === true);
|
|
2205
|
+
}
|
|
2206
|
+
const isPushedView = (value) => typeof value === "object" && value !== null && "view" in value && Object.keys(value).length === 1;
|
|
2207
|
+
function NavigationStack(props) {
|
|
2208
|
+
const enclosing = useNavigation();
|
|
2209
|
+
if (enclosing) return /* @__PURE__ */ jsx(FlattenedStack, { ...props });
|
|
2210
|
+
return /* @__PURE__ */ jsx(OwnStack, { ...props });
|
|
2211
|
+
}
|
|
2212
|
+
function FlattenedStack(props) {
|
|
2213
|
+
const { own, modifiers } = splitProps(props);
|
|
2214
|
+
return applyModifiers(
|
|
2215
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2216
|
+
own.destination && /* @__PURE__ */ jsx(RegisterDestination, { destination: own.destination }),
|
|
2217
|
+
own.children
|
|
2218
|
+
] }),
|
|
2219
|
+
modifiers
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
function OwnStack(props) {
|
|
2223
|
+
const { own, modifiers } = splitProps(props);
|
|
2224
|
+
const [internalPath, setInternalPath] = useState([]);
|
|
2225
|
+
const [path, setPath] = own.path !== void 0 ? readBinding(own.path, own.onPathChange) : [internalPath, setInternalPath];
|
|
2226
|
+
const destination = useRef(null);
|
|
2227
|
+
destination.current = own.destination ?? null;
|
|
2228
|
+
const context = {
|
|
2229
|
+
push: (value) => setPath([...path, value]),
|
|
2230
|
+
pop: () => setPath(path.slice(0, -1)),
|
|
2231
|
+
registerDestination: (builder) => {
|
|
2232
|
+
destination.current = builder;
|
|
2233
|
+
}
|
|
2234
|
+
};
|
|
2235
|
+
const screens = [
|
|
2236
|
+
/* @__PURE__ */ jsx(Fragment$1, { children: sb("navscreen", { title: "", displayMode: "automatic", depth: 0 }, { tap: context.pop }, own.children) }, "root")
|
|
2237
|
+
];
|
|
2238
|
+
path.forEach((value, index) => {
|
|
2239
|
+
const pop = () => setPath(path.slice(0, index));
|
|
2240
|
+
screens.push(
|
|
2241
|
+
/* @__PURE__ */ jsx(Fragment$1, { children: sb(
|
|
2242
|
+
"navscreen",
|
|
2243
|
+
{ title: "", displayMode: "automatic", depth: index + 1 },
|
|
2244
|
+
{ tap: pop },
|
|
2245
|
+
/* @__PURE__ */ jsx(DismissContext.Provider, { value: pop, children: /* @__PURE__ */ jsx(PathScreen, { value, destination }) })
|
|
2246
|
+
) }, index + 1)
|
|
2247
|
+
);
|
|
2248
|
+
});
|
|
2249
|
+
return applyModifiers(
|
|
2250
|
+
sb("navstack", {}, void 0, /* @__PURE__ */ jsx(NavigationContext.Provider, { value: context, children: screens })),
|
|
2251
|
+
modifiers
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
function PathScreen({ value, destination }) {
|
|
2255
|
+
if (isPushedView(value)) return value.view;
|
|
2256
|
+
return destination.current ? destination.current(value) : null;
|
|
2257
|
+
}
|
|
2258
|
+
function NavigationLink(props) {
|
|
2259
|
+
const { own, modifiers } = splitProps(props);
|
|
2260
|
+
const navigation = useNavigation();
|
|
2261
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
|
|
2262
|
+
const tap = () => {
|
|
2263
|
+
if (!navigation) return;
|
|
2264
|
+
if (own.destination !== void 0) navigation.push({ view: own.destination });
|
|
2265
|
+
else navigation.push(own.value);
|
|
2266
|
+
};
|
|
2267
|
+
return applyModifiers(sb("navlink", {}, { tap }, label), modifiers);
|
|
2268
|
+
}
|
|
2269
|
+
const SplitSelectionContext = createContext(null);
|
|
2270
|
+
function NavigationSplitView(props) {
|
|
2271
|
+
const { own, modifiers } = splitProps(props);
|
|
2272
|
+
const sizeClass = useHorizontalSizeClass();
|
|
2273
|
+
const [selected, setSelected] = useState(false);
|
|
2274
|
+
const clearRef = useRef(() => {
|
|
2275
|
+
});
|
|
2276
|
+
const report = {
|
|
2277
|
+
report: (nowSelected, clear2) => {
|
|
2278
|
+
clearRef.current = clear2;
|
|
2279
|
+
if (nowSelected !== selected) setSelected(nowSelected);
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
const clear = () => clearRef.current();
|
|
2283
|
+
const [internal, setInternal] = useState("automatic");
|
|
2284
|
+
const [visibility, setVisibility] = own.columnVisibility !== void 0 ? readBinding(own.columnVisibility, own.onColumnVisibilityChange) : [internal, setInternal];
|
|
2285
|
+
if (sizeClass === "compact") {
|
|
2286
|
+
return applyModifiers(
|
|
2287
|
+
/* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children: /* @__PURE__ */ jsx(CompactSplit, { sidebar: own.sidebar, detail: own.detail, selected, clear }) }),
|
|
2288
|
+
modifiers
|
|
2289
|
+
);
|
|
2290
|
+
}
|
|
2291
|
+
const sidebarVisible = visibility !== "detailOnly";
|
|
2292
|
+
const toggle = () => withAnimation(() => setVisibility(sidebarVisible ? "detailOnly" : "all"));
|
|
2293
|
+
const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
|
|
2294
|
+
return applyModifiers(
|
|
2295
|
+
sb("navsplit", { sidebarVisible }, { tap: toggle }, [
|
|
2296
|
+
/* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: own.sidebar }) }, "sidebar"),
|
|
2297
|
+
/* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
|
|
2298
|
+
]),
|
|
2299
|
+
modifiers
|
|
2300
|
+
);
|
|
2301
|
+
}
|
|
2302
|
+
function SplitColumn({ report, children }) {
|
|
2303
|
+
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children }) });
|
|
2304
|
+
}
|
|
2305
|
+
function CompactSplit({ sidebar, detail, selected, clear }) {
|
|
2306
|
+
const [extra, setExtra] = useState([]);
|
|
2307
|
+
const base = selected ? [{ view: /* @__PURE__ */ jsx(DetailScope, { children: detail }) }] : [];
|
|
2308
|
+
const path = [...base, ...extra];
|
|
2309
|
+
const setPath = (next) => {
|
|
2310
|
+
if (selected && next.length === 0) {
|
|
2311
|
+
setExtra([]);
|
|
2312
|
+
clear();
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
setExtra(next.slice(base.length));
|
|
2316
|
+
};
|
|
2317
|
+
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(NavigationStack, { path: [path, setPath], children: sidebar }) });
|
|
2318
|
+
}
|
|
2319
|
+
function DetailScope({ children }) {
|
|
2320
|
+
return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
|
|
2321
|
+
}
|
|
2322
|
+
function useReportSplitSelection(split, selected, clear) {
|
|
2323
|
+
useLayoutEffect(() => {
|
|
2324
|
+
split?.report(selected, clear);
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
const NO_CLEAR = () => {
|
|
2328
|
+
};
|
|
2329
|
+
function List(props) {
|
|
2330
|
+
const { own, modifiers } = splitProps(props);
|
|
2331
|
+
const [editing] = own.editing !== void 0 ? readBinding(own.editing) : [false];
|
|
2332
|
+
const listProps = { style: own.listStyle ?? "insetGrouped" };
|
|
2333
|
+
if (editing) listProps["editing"] = true;
|
|
2334
|
+
let selection = null;
|
|
2335
|
+
const split = useContext(SplitSelectionContext);
|
|
2336
|
+
let selected = false;
|
|
2337
|
+
let clearSelection = NO_CLEAR;
|
|
2338
|
+
if (own.selection !== void 0) {
|
|
2339
|
+
const [value, setValue] = readBinding(own.selection, own.onSelectionChange);
|
|
2340
|
+
selected = value instanceof Set ? value.size > 0 : value !== null && value !== void 0;
|
|
2341
|
+
clearSelection = () => setValue(value instanceof Set ? /* @__PURE__ */ new Set() : null);
|
|
2342
|
+
selection = {
|
|
2343
|
+
editing,
|
|
2344
|
+
isSelected: (tag) => value instanceof Set ? value.has(tag) : value !== null && Object.is(value, tag),
|
|
2345
|
+
select: (tag) => {
|
|
2346
|
+
if (value instanceof Set) {
|
|
2347
|
+
const next = new Set(value);
|
|
2348
|
+
if (next.has(tag)) next.delete(tag);
|
|
2349
|
+
else next.add(tag);
|
|
2350
|
+
setValue(next);
|
|
2351
|
+
} else {
|
|
2352
|
+
setValue(editing && Object.is(value, tag) ? null : tag);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
useReportSplitSelection(split, selected, clearSelection);
|
|
2358
|
+
const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
|
|
2359
|
+
Object.assign(listProps, refresh.props);
|
|
2360
|
+
const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, wrapRows(own.children)) });
|
|
2361
|
+
return applyModifiers(
|
|
2362
|
+
selection ? /* @__PURE__ */ jsx(ListSelectionContext.Provider, { value: selection, children: element }) : element,
|
|
2363
|
+
modifiers
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
function Form(props) {
|
|
2367
|
+
return /* @__PURE__ */ jsx(List, { ...props });
|
|
2368
|
+
}
|
|
2369
|
+
function Section(props) {
|
|
2370
|
+
const { own, modifiers } = splitProps(props);
|
|
2371
|
+
const header = supplement(own.header);
|
|
2372
|
+
const footer = supplement(own.footer);
|
|
2373
|
+
const children = [];
|
|
2374
|
+
if (header.view) children.push(sb("sectionheader", {}, void 0, header.view));
|
|
2375
|
+
if (own.children !== void 0) children.push(wrapRows(own.children));
|
|
2376
|
+
if (footer.view) children.push(sb("sectionfooter", {}, void 0, footer.view));
|
|
2377
|
+
return applyModifiers(sb("section", { header: header.text, footer: footer.text }, void 0, children), modifiers);
|
|
2378
|
+
}
|
|
2379
|
+
function wrapRows(children) {
|
|
2380
|
+
let offset = 0;
|
|
2381
|
+
return flattenChildren(children, { keepLazy: true }).map((element, index) => {
|
|
2382
|
+
const at = index + offset;
|
|
2383
|
+
if (element.type === LazyGroup) {
|
|
2384
|
+
const group = element.props;
|
|
2385
|
+
offset += group.rows.length - 1;
|
|
2386
|
+
return { ...withKey(element, index), props: { ...group, start: at, wrap: wrapRow } };
|
|
2387
|
+
}
|
|
2388
|
+
return wrapRow(withKey(element, index), at);
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2391
|
+
function wrapRow(element, containerIndex) {
|
|
2392
|
+
if (element.type === Section) return element;
|
|
2393
|
+
if (element.type === Row) return { ...element, props: { ...element.props, containerIndex } };
|
|
2394
|
+
const props = element.props;
|
|
2395
|
+
const tag = props.tag !== void 0 ? props.tag : element.type === NavigationLink ? props.value : void 0;
|
|
2396
|
+
if (tag === void 0) return element;
|
|
2397
|
+
return /* @__PURE__ */ jsx(Row, { tag, containerIndex, children: element }, element.key ?? containerIndex);
|
|
2398
|
+
}
|
|
2399
|
+
function withKey(element, index) {
|
|
2400
|
+
return element.key !== null ? element : { ...element, key: String(index) };
|
|
2401
|
+
}
|
|
2402
|
+
function supplement(node) {
|
|
2403
|
+
if (node === void 0 || node === null || node === false) return { text: null, view: null };
|
|
2404
|
+
if (typeof node === "string" || typeof node === "number") return { text: String(node), view: null };
|
|
2405
|
+
if (isValidElement(node) && node.type === Text) {
|
|
2406
|
+
const props = node.props;
|
|
2407
|
+
const only = Object.keys(props).every((key) => key === "children");
|
|
2408
|
+
if (only) return { text: plainText(node), view: null };
|
|
2409
|
+
}
|
|
2410
|
+
return { text: null, view: isValidElement(node) ? node : null };
|
|
2411
|
+
}
|
|
2412
|
+
function TabView(props) {
|
|
2413
|
+
const { own, modifiers } = splitProps(props);
|
|
2414
|
+
const tabs = flattenChildren(own.children);
|
|
2415
|
+
const tags = tabs.map((tab, index) => {
|
|
2416
|
+
const tag = tab.props.tag;
|
|
2417
|
+
return tag !== void 0 ? tag : index;
|
|
2418
|
+
});
|
|
2419
|
+
const [internal, setInternal] = useState(tags[0]);
|
|
2420
|
+
const [selection, setSelection] = own.selection !== void 0 ? readBinding(own.selection, own.onChange) : [internal, setInternal];
|
|
2421
|
+
const selected = Math.max(
|
|
2422
|
+
0,
|
|
2423
|
+
tags.findIndex((tag) => Object.is(tag, selection))
|
|
2424
|
+
);
|
|
2425
|
+
return applyModifiers(
|
|
2426
|
+
sb("tabview", { selected }, { select: (event) => tags[event.value] !== void 0 && setSelection(tags[event.value]) }, tabs),
|
|
2427
|
+
modifiers
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
function Tab(props) {
|
|
2431
|
+
const { own, modifiers } = splitProps(props);
|
|
2432
|
+
const badge = takeModifier(modifiers, "badge");
|
|
2433
|
+
const tabProps = { title: own.title, systemImage: own.systemImage ?? null };
|
|
2434
|
+
if (badge !== void 0 && badge !== null) tabProps["badge"] = String(badge);
|
|
2435
|
+
if (own.role) tabProps["role"] = own.role;
|
|
2436
|
+
return applyModifiers(sb("tab", tabProps, void 0, own.children), modifiers);
|
|
2437
|
+
}
|
|
2438
|
+
const STYLE_KEYS = ["r", "name", "named", "hierarchical", "linearGradient", "radialGradient", "angularGradient", "colorGradient", "material"];
|
|
2439
|
+
function strokeOf(value, inset) {
|
|
2440
|
+
if (value === void 0) return null;
|
|
2441
|
+
const isSpec = typeof value === "object" && value !== null && !STYLE_KEYS.some((key) => key in value);
|
|
2442
|
+
const spec = isSpec ? value : { style: value };
|
|
2443
|
+
const stroke = { color: shapeStyle(spec.style ?? "primary"), lineWidth: spec.lineWidth ?? 1 };
|
|
2444
|
+
if (inset) stroke.inset = true;
|
|
2445
|
+
if (spec.dash) stroke.dash = spec.dash;
|
|
2446
|
+
if (spec.dashPhase !== void 0) stroke.dashPhase = spec.dashPhase;
|
|
2447
|
+
if (spec.lineCap) stroke.lineCap = spec.lineCap;
|
|
2448
|
+
if (spec.lineJoin) stroke.lineJoin = spec.lineJoin;
|
|
2449
|
+
if (spec.miterLimit !== void 0) stroke.miterLimit = spec.miterLimit;
|
|
2450
|
+
return stroke;
|
|
2451
|
+
}
|
|
2452
|
+
function shape(kind, cornerRadius, props) {
|
|
2453
|
+
const { own, modifiers } = splitProps(props);
|
|
2454
|
+
const shapeProps = {
|
|
2455
|
+
shape: kind,
|
|
2456
|
+
cornerRadius,
|
|
2457
|
+
fill: own.fill !== void 0 ? shapeStyle(own.fill) : null,
|
|
2458
|
+
stroke: strokeOf(own.strokeBorder, true) ?? strokeOf(own.stroke, false)
|
|
2459
|
+
};
|
|
2460
|
+
if (own.trim) shapeProps["trim"] = own.trim;
|
|
2461
|
+
return applyModifiers(sb("shape", shapeProps), modifiers);
|
|
2462
|
+
}
|
|
2463
|
+
const ROUND = 9999;
|
|
2464
|
+
function Rectangle(props) {
|
|
2465
|
+
return shape("rectangle", 0, props);
|
|
2466
|
+
}
|
|
2467
|
+
Rectangle.shape = { kind: "rectangle", cornerRadius: 0 };
|
|
2468
|
+
function RoundedRectangle(props) {
|
|
2469
|
+
const { cornerRadius, ...rest } = props;
|
|
2470
|
+
return shape("roundedRectangle", cornerRadius, rest);
|
|
2471
|
+
}
|
|
2472
|
+
RoundedRectangle.shape = { kind: "roundedRectangle", cornerRadius: null };
|
|
2473
|
+
function Circle(props) {
|
|
2474
|
+
return shape("circle", ROUND, props);
|
|
2475
|
+
}
|
|
2476
|
+
Circle.shape = { kind: "circle", cornerRadius: ROUND };
|
|
2477
|
+
function Capsule(props) {
|
|
2478
|
+
return shape("capsule", ROUND, props);
|
|
2479
|
+
}
|
|
2480
|
+
Capsule.shape = { kind: "capsule", cornerRadius: ROUND };
|
|
2481
|
+
function Ellipse(props) {
|
|
2482
|
+
return shape("ellipse", ROUND, props);
|
|
2483
|
+
}
|
|
2484
|
+
Ellipse.shape = { kind: "ellipse", cornerRadius: ROUND };
|
|
2485
|
+
function ContainerRelativeShape(props) {
|
|
2486
|
+
const { cornerRadius, ...rest } = props;
|
|
2487
|
+
return shape("containerRelative", cornerRadius ?? 0, rest);
|
|
2488
|
+
}
|
|
2489
|
+
ContainerRelativeShape.shape = { kind: "containerRelative", cornerRadius: null };
|
|
2490
|
+
function Shape(props) {
|
|
2491
|
+
const { own, modifiers } = splitProps(props);
|
|
2492
|
+
const [size, setSize] = useState(null);
|
|
2493
|
+
const shapeProps = {
|
|
2494
|
+
shape: "path",
|
|
2495
|
+
cornerRadius: 0,
|
|
2496
|
+
fill: own.fill !== void 0 ? shapeStyle(own.fill) : null,
|
|
2497
|
+
// A custom shape's border is its path stroked as is (the shim insets an InsettableShape first).
|
|
2498
|
+
stroke: strokeOf(own.strokeBorder ?? own.stroke, false),
|
|
2499
|
+
reportsSize: true,
|
|
2500
|
+
path: size ? own.path({ x: 0, y: 0, width: size.width, height: size.height }).svg() : "",
|
|
2501
|
+
size: size ?? { width: 0, height: 0 }
|
|
2502
|
+
};
|
|
2503
|
+
if (own.evenOdd) shapeProps["fillRule"] = "evenodd";
|
|
2504
|
+
return applyModifiers(
|
|
2505
|
+
sb("shape", shapeProps, {
|
|
2506
|
+
geometry: (event) => {
|
|
2507
|
+
if (!size || size.width !== event.width || size.height !== event.height) setSize({ width: event.width, height: event.height });
|
|
2508
|
+
}
|
|
2509
|
+
}),
|
|
2510
|
+
modifiers
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
function UnevenRoundedRectangle(props) {
|
|
2514
|
+
const { topLeadingRadius = 0, bottomLeadingRadius = 0, bottomTrailingRadius = 0, topTrailingRadius = 0, trim: _trim, ...rest } = props;
|
|
2515
|
+
const path = (rect) => {
|
|
2516
|
+
const clamp2 = (radius) => Math.max(0, Math.min(radius, rect.width / 2, rect.height / 2));
|
|
2517
|
+
const tl = clamp2(topLeadingRadius);
|
|
2518
|
+
const tr = clamp2(topTrailingRadius);
|
|
2519
|
+
const br = clamp2(bottomTrailingRadius);
|
|
2520
|
+
const bl = clamp2(bottomLeadingRadius);
|
|
2521
|
+
const { width: w, height: h } = rect;
|
|
2522
|
+
const p = new Path().move({ x: tl, y: 0 }).addLine({ x: w - tr, y: 0 });
|
|
2523
|
+
if (tr) p.addArc({ x: w - tr, y: tr }, tr, -90, 0, false);
|
|
2524
|
+
p.addLine({ x: w, y: h - br });
|
|
2525
|
+
if (br) p.addArc({ x: w - br, y: h - br }, br, 0, 90, false);
|
|
2526
|
+
p.addLine({ x: bl, y: h });
|
|
2527
|
+
if (bl) p.addArc({ x: bl, y: h - bl }, bl, 90, 180, false);
|
|
2528
|
+
p.addLine({ x: 0, y: tl });
|
|
2529
|
+
if (tl) p.addArc({ x: tl, y: tl }, tl, 180, 270, false);
|
|
2530
|
+
return p.closeSubpath();
|
|
2531
|
+
};
|
|
2532
|
+
return /* @__PURE__ */ jsx(Shape, { ...rest, path });
|
|
2533
|
+
}
|
|
2534
|
+
function ColorView(props) {
|
|
2535
|
+
const { own, modifiers } = splitProps(props);
|
|
2536
|
+
return applyModifiers(sb("color", { color: color(own.color) }), modifiers);
|
|
2537
|
+
}
|
|
2538
|
+
const Color = Object.assign(ColorView, ColorValues);
|
|
2539
|
+
function Host(props) {
|
|
2540
|
+
const { own, modifiers } = splitProps(props);
|
|
2541
|
+
const key = useId();
|
|
2542
|
+
const [content] = useState(() => {
|
|
2543
|
+
if (typeof document === "undefined") return null;
|
|
2544
|
+
const element = document.createElement("div");
|
|
2545
|
+
element.className = "sb-host-content";
|
|
2546
|
+
registerHostContent(key, element);
|
|
2547
|
+
return element;
|
|
2548
|
+
});
|
|
2549
|
+
const bridge = useContextBridge(own.contexts);
|
|
2550
|
+
const root = useRef(null);
|
|
2551
|
+
const sizing = own.sizing ?? "content";
|
|
2552
|
+
const style = sizing === "fill" ? { height: "100%", ...own.style } : own.style;
|
|
2553
|
+
const tree = bridge(
|
|
2554
|
+
/* @__PURE__ */ jsx("div", { className: own.className, style, children: own.children })
|
|
2555
|
+
);
|
|
2556
|
+
useLayoutEffect(() => {
|
|
2557
|
+
if (!content) return;
|
|
2558
|
+
root.current ??= createRoot(content);
|
|
2559
|
+
const current = root.current;
|
|
2560
|
+
queueMicrotask(() => {
|
|
2561
|
+
if (root.current !== current) return;
|
|
2562
|
+
flushSync(() => current.render(tree));
|
|
2563
|
+
notifyHostContentChange(key);
|
|
2564
|
+
});
|
|
2565
|
+
});
|
|
2566
|
+
useEffect(
|
|
2567
|
+
() => () => {
|
|
2568
|
+
const current = root.current;
|
|
2569
|
+
root.current = null;
|
|
2570
|
+
unregisterHostContent(key);
|
|
2571
|
+
queueMicrotask(() => current?.unmount());
|
|
2572
|
+
},
|
|
2573
|
+
[key]
|
|
2574
|
+
);
|
|
2575
|
+
return applyModifiers(sb("host", { content: key, sizing }), modifiers);
|
|
2576
|
+
}
|
|
2577
|
+
const NO_INSETS = { top: 0, leading: 0, bottom: 0, trailing: 0 };
|
|
2578
|
+
function GeometryReader(props) {
|
|
2579
|
+
const { own, modifiers } = splitProps(props);
|
|
2580
|
+
const [reported, setReported] = useState({ size: { width: 0, height: 0 }, origin: null, safeArea: NO_INSETS });
|
|
2581
|
+
const [needsFrame, setNeedsFrame] = useState(false);
|
|
2582
|
+
const spaces = useCoordinateSpaces();
|
|
2583
|
+
let readFrame = false;
|
|
2584
|
+
const proxy = {
|
|
2585
|
+
size: reported.size,
|
|
2586
|
+
frame: (space = "local") => {
|
|
2587
|
+
if (space === "local") return { x: 0, y: 0, ...reported.size };
|
|
2588
|
+
readFrame = true;
|
|
2589
|
+
const origin = reported.origin ?? { x: 0, y: 0 };
|
|
2590
|
+
if (space === "global") return { ...origin, ...reported.size };
|
|
2591
|
+
const named = spaces[space.named];
|
|
2592
|
+
return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
|
|
2593
|
+
},
|
|
2594
|
+
get safeAreaInsets() {
|
|
2595
|
+
readFrame = true;
|
|
2596
|
+
return reported.safeArea;
|
|
2597
|
+
}
|
|
2598
|
+
};
|
|
2599
|
+
const content = own.children(proxy);
|
|
2600
|
+
useEffect(() => {
|
|
2601
|
+
if (readFrame && !needsFrame) setNeedsFrame(true);
|
|
2602
|
+
});
|
|
2603
|
+
return applyModifiers(
|
|
2604
|
+
sb(
|
|
2605
|
+
"geometry",
|
|
2606
|
+
needsFrame ? { reportsFrame: true } : {},
|
|
2607
|
+
{
|
|
2608
|
+
geometry: (event) => {
|
|
2609
|
+
const next = {
|
|
2610
|
+
size: { width: event.width, height: event.height },
|
|
2611
|
+
origin: event.x !== void 0 && event.y !== void 0 ? { x: event.x, y: event.y } : reported.origin,
|
|
2612
|
+
safeArea: event.safeArea ?? reported.safeArea
|
|
2613
|
+
};
|
|
2614
|
+
if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
|
|
2615
|
+
}
|
|
2616
|
+
},
|
|
2617
|
+
content
|
|
2618
|
+
),
|
|
2619
|
+
modifiers
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
const DEFAULT_VIEW_SPACING = { distance: () => 8 };
|
|
2623
|
+
function subviewTraits(children) {
|
|
2624
|
+
return flattenChildren(children).map((element) => {
|
|
2625
|
+
const props = element.props;
|
|
2626
|
+
return { priority: props.layoutPriority ?? 0, values: props.layoutValue ?? {} };
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
const fromDimension = (value) => value === "infinity" ? Infinity : value;
|
|
2630
|
+
const toDimension = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : "infinity";
|
|
2631
|
+
const toSize = (size) => ({
|
|
2632
|
+
width: fromDimension(size.width) ?? 0,
|
|
2633
|
+
height: fromDimension(size.height) ?? 0
|
|
2634
|
+
});
|
|
2635
|
+
const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
|
|
2636
|
+
function clamp(value, min, max) {
|
|
2637
|
+
return Math.min(Math.max(value, min), max);
|
|
2638
|
+
}
|
|
2639
|
+
function answerLayout(layout, record, traits = []) {
|
|
2640
|
+
const frames = record.children.map(() => null);
|
|
2641
|
+
const subviews = record.children.map((measurement, index) => {
|
|
2642
|
+
const min = toSize(measurement.min);
|
|
2643
|
+
const ideal = toSize(measurement.ideal);
|
|
2644
|
+
const max = toSize(measurement.max);
|
|
2645
|
+
const sizeThatFits = (proposal) => ({
|
|
2646
|
+
width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
|
|
2647
|
+
height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
|
|
2648
|
+
});
|
|
2649
|
+
return {
|
|
2650
|
+
min,
|
|
2651
|
+
ideal,
|
|
2652
|
+
max,
|
|
2653
|
+
priority: traits[index]?.priority ?? 0,
|
|
2654
|
+
values: traits[index]?.values ?? {},
|
|
2655
|
+
spacing: DEFAULT_VIEW_SPACING,
|
|
2656
|
+
sizeThatFits,
|
|
2657
|
+
place: ({ x, y, anchor, proposal }) => {
|
|
2658
|
+
const size2 = sizeThatFits(proposal ?? { width: null, height: null });
|
|
2659
|
+
const point = unitPoint(anchor ?? "topLeading");
|
|
2660
|
+
frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
});
|
|
2664
|
+
const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
|
|
2665
|
+
const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
|
|
2666
|
+
const size = measure(record.proposal);
|
|
2667
|
+
layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
|
|
2668
|
+
const placed = frames.map((frame2, index) => {
|
|
2669
|
+
if (frame2) return frame2;
|
|
2670
|
+
const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
|
|
2671
|
+
return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
|
|
2672
|
+
});
|
|
2673
|
+
const guides = {};
|
|
2674
|
+
if (layout.explicitAlignment) {
|
|
2675
|
+
const bounds = { x: 0, y: 0, ...size };
|
|
2676
|
+
for (const guide of GUIDES) {
|
|
2677
|
+
const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
|
|
2678
|
+
if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
return {
|
|
2682
|
+
size,
|
|
2683
|
+
frames: placed,
|
|
2684
|
+
guides,
|
|
2685
|
+
sizes: {
|
|
2686
|
+
min: measure({ width: 0, height: 0 }),
|
|
2687
|
+
ideal: measure({ width: null, height: null }),
|
|
2688
|
+
max: measure({ width: Infinity, height: Infinity })
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
function Layout(props) {
|
|
2693
|
+
const { own, modifiers } = splitProps(props);
|
|
2694
|
+
const [record, setRecord] = useState(null);
|
|
2695
|
+
let layoutProps = { proposal: null, size: null, frames: null };
|
|
2696
|
+
const guideModifiers = [];
|
|
2697
|
+
if (record) {
|
|
2698
|
+
const answer = answerLayout(own.layout, record, subviewTraits(own.children));
|
|
2699
|
+
for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
|
|
2700
|
+
const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
|
|
2701
|
+
const round = (value) => Math.round(value * 100) / 100;
|
|
2702
|
+
layoutProps = {
|
|
2703
|
+
proposal: {
|
|
2704
|
+
width: record.proposal.width === null ? null : toDimension(record.proposal.width),
|
|
2705
|
+
height: record.proposal.height === null ? null : toDimension(record.proposal.height)
|
|
2706
|
+
},
|
|
2707
|
+
size: { width: round(answer.size.width), height: round(answer.size.height) },
|
|
2708
|
+
frames: answer.frames.map((frame2) => ({ x: round(frame2.x), y: round(frame2.y), width: round(frame2.width), height: round(frame2.height) })),
|
|
2709
|
+
sizes: { min: encode(answer.sizes.min), ideal: encode(answer.sizes.ideal), max: encode(answer.sizes.max) }
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
return applyModifiers(
|
|
2713
|
+
sb(
|
|
2714
|
+
"layout",
|
|
2715
|
+
layoutProps,
|
|
2716
|
+
{
|
|
2717
|
+
layout: (event) => {
|
|
2718
|
+
const proposal = event.proposal;
|
|
2719
|
+
setRecord({
|
|
2720
|
+
proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
|
|
2721
|
+
children: event.children
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
},
|
|
2725
|
+
own.children
|
|
2726
|
+
),
|
|
2727
|
+
[...guideModifiers, ...modifiers]
|
|
2728
|
+
);
|
|
2729
|
+
}
|
|
2730
|
+
function Menu(props) {
|
|
2731
|
+
const { own, modifiers } = splitProps(props);
|
|
2732
|
+
const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.label;
|
|
2733
|
+
return applyModifiers(
|
|
2734
|
+
sb("menu", {}, void 0, [
|
|
2735
|
+
/* @__PURE__ */ jsx(Fragment$1, { children: sb("zstack", { alignment: "center" }, void 0, label) }, "label"),
|
|
2736
|
+
/* @__PURE__ */ jsx(Fragment$1, { children: own.children }, "items")
|
|
2737
|
+
]),
|
|
2738
|
+
modifiers
|
|
2739
|
+
);
|
|
2740
|
+
}
|
|
2741
|
+
function EditButton(props) {
|
|
2742
|
+
const { own, modifiers } = splitProps(props);
|
|
2743
|
+
const [editing, setEditing] = readBinding(own.editMode, own.onChange);
|
|
2744
|
+
return applyModifiers(/* @__PURE__ */ jsx(Button, { title: editing ? "Done" : "Edit", action: () => setEditing(!editing) }), modifiers);
|
|
2745
|
+
}
|
|
2746
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
2747
|
+
function AsyncImage(props) {
|
|
2748
|
+
const { own, modifiers } = splitProps(props);
|
|
2749
|
+
const [state, setState] = useState(() => loaded.get(own.url) ?? null);
|
|
2750
|
+
useEffect(() => {
|
|
2751
|
+
const cached = loaded.get(own.url);
|
|
2752
|
+
if (cached) {
|
|
2753
|
+
setState(cached);
|
|
2754
|
+
return;
|
|
2755
|
+
}
|
|
2756
|
+
if (typeof Image === "undefined") return;
|
|
2757
|
+
let live = true;
|
|
2758
|
+
const image = new Image();
|
|
2759
|
+
image.onload = () => {
|
|
2760
|
+
const result = { url: own.url, width: image.naturalWidth, height: image.naturalHeight };
|
|
2761
|
+
loaded.set(own.url, result);
|
|
2762
|
+
if (live) setState(result);
|
|
2763
|
+
};
|
|
2764
|
+
image.onerror = () => {
|
|
2765
|
+
loaded.set(own.url, "failed");
|
|
2766
|
+
if (live) setState("failed");
|
|
2767
|
+
};
|
|
2768
|
+
image.src = own.url;
|
|
2769
|
+
return () => {
|
|
2770
|
+
live = false;
|
|
2771
|
+
};
|
|
2772
|
+
}, [own.url]);
|
|
2773
|
+
if (state === null) return own.placeholder ?? null;
|
|
2774
|
+
if (state === "failed") return own.failure ?? own.placeholder ?? null;
|
|
2775
|
+
return applyModifiers(
|
|
2776
|
+
sb("image", { url: state.url, resizable: own.resizable ?? false, width: state.width, height: state.height }),
|
|
2777
|
+
modifiers
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
function BarMark(_props) {
|
|
2781
|
+
return null;
|
|
2782
|
+
}
|
|
2783
|
+
function LineMark(_props) {
|
|
2784
|
+
return null;
|
|
2785
|
+
}
|
|
2786
|
+
function AreaMark(_props) {
|
|
2787
|
+
return null;
|
|
2788
|
+
}
|
|
2789
|
+
function PointMark(_props) {
|
|
2790
|
+
return null;
|
|
2791
|
+
}
|
|
2792
|
+
function RuleMark(_props) {
|
|
2793
|
+
return null;
|
|
2794
|
+
}
|
|
2795
|
+
const PALETTE = ["blue", "green", "orange", "purple", "red", "teal", "yellow", "pink", "indigo", "mint", "cyan", "brown"];
|
|
2796
|
+
const SYMBOLS = ["circle", "square", "triangle", "diamond", "cross", "plus", "asterisk"];
|
|
2797
|
+
function declaredMarks(children) {
|
|
2798
|
+
const kinds = /* @__PURE__ */ new Map([
|
|
2799
|
+
[BarMark, "bar"],
|
|
2800
|
+
[LineMark, "line"],
|
|
2801
|
+
[AreaMark, "area"],
|
|
2802
|
+
[PointMark, "point"],
|
|
2803
|
+
[RuleMark, "rule"]
|
|
2804
|
+
]);
|
|
2805
|
+
const result = [];
|
|
2806
|
+
for (const element of flattenChildren(children)) {
|
|
2807
|
+
const kind = kinds.get(element.type);
|
|
2808
|
+
if (kind) result.push({ kind, props: element.props });
|
|
2809
|
+
}
|
|
2810
|
+
return result;
|
|
2811
|
+
}
|
|
2812
|
+
const asNumber = (value) => value instanceof Date ? value.getTime() : typeof value === "number" ? value : NaN;
|
|
2813
|
+
function bandScale(categories) {
|
|
2814
|
+
const n = Math.max(categories.length, 1);
|
|
2815
|
+
const index = new Map(categories.map((c, i) => [c, i]));
|
|
2816
|
+
const center = (value) => ((index.get(String(value)) ?? 0) + 0.5) / n;
|
|
2817
|
+
return {
|
|
2818
|
+
kind: "band",
|
|
2819
|
+
unit: center,
|
|
2820
|
+
band: (value) => {
|
|
2821
|
+
const i = index.get(String(value)) ?? 0;
|
|
2822
|
+
return [i / n, (i + 1) / n];
|
|
2823
|
+
},
|
|
2824
|
+
ticks: categories.map((_, i) => (i + 0.5) / n),
|
|
2825
|
+
gridLines: [],
|
|
2826
|
+
labels: categories.map((text, i) => ({ at: (i + 0.5) / n, text })),
|
|
2827
|
+
domain: [0, n]
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2830
|
+
function niceStep(span, desired = 5) {
|
|
2831
|
+
if (!(span > 0)) return 1;
|
|
2832
|
+
const raw = span / Math.max(desired - 1, 1);
|
|
2833
|
+
const magnitude = 10 ** Math.floor(Math.log10(raw));
|
|
2834
|
+
let best = magnitude;
|
|
2835
|
+
for (const candidate of [1, 2, 2.5, 5, 10].map((m) => m * magnitude)) {
|
|
2836
|
+
if (Math.abs(candidate - raw) <= Math.abs(best - raw)) best = candidate;
|
|
2837
|
+
}
|
|
2838
|
+
return best;
|
|
2839
|
+
}
|
|
2840
|
+
function decimalsOf(step) {
|
|
2841
|
+
const text = step.toString();
|
|
2842
|
+
const dot = text.indexOf(".");
|
|
2843
|
+
return dot < 0 ? 0 : text.length - dot - 1;
|
|
2844
|
+
}
|
|
2845
|
+
function numberScale(values, options = {}) {
|
|
2846
|
+
let min = Math.min(...values);
|
|
2847
|
+
let max = Math.max(...values);
|
|
2848
|
+
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
2849
|
+
min = 0;
|
|
2850
|
+
max = 1;
|
|
2851
|
+
}
|
|
2852
|
+
if (options.includesZero) {
|
|
2853
|
+
min = Math.min(min, 0);
|
|
2854
|
+
max = Math.max(max, 0);
|
|
2855
|
+
}
|
|
2856
|
+
if (min === max) {
|
|
2857
|
+
if (min === 0) max = 1;
|
|
2858
|
+
else {
|
|
2859
|
+
min = Math.min(min, 0);
|
|
2860
|
+
max = Math.max(max, 0);
|
|
2861
|
+
if (min === max) max = min + 1;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
const step = niceStep(max - min);
|
|
2865
|
+
let lo;
|
|
2866
|
+
let hi;
|
|
2867
|
+
if (options.domain) [lo, hi] = options.domain;
|
|
2868
|
+
else {
|
|
2869
|
+
lo = Math.floor(min / step + 1e-9) * step;
|
|
2870
|
+
hi = Math.ceil(max / step - 1e-9) * step;
|
|
2871
|
+
}
|
|
2872
|
+
const ticks = [];
|
|
2873
|
+
const first = Math.ceil(lo / step - 1e-9) * step;
|
|
2874
|
+
for (let value = first; value <= hi + 1e-9; value += step) ticks.push(Number(value.toFixed(10)));
|
|
2875
|
+
const decimals = decimalsOf(step);
|
|
2876
|
+
const unit = (value) => (asNumber(value) - lo) / (hi - lo || 1);
|
|
2877
|
+
const format = new Intl.NumberFormat("en-US", { maximumFractionDigits: decimals });
|
|
2878
|
+
return {
|
|
2879
|
+
kind: "number",
|
|
2880
|
+
unit,
|
|
2881
|
+
band: (value) => [unit(value), unit(value)],
|
|
2882
|
+
ticks: ticks.map(unit),
|
|
2883
|
+
gridLines: ticks.map(unit),
|
|
2884
|
+
labels: ticks.map((value) => ({ at: unit(value), text: format.format(value) })),
|
|
2885
|
+
domain: [lo, hi]
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
const HOUR = 36e5;
|
|
2889
|
+
const DAY = 24 * HOUR;
|
|
2890
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
2891
|
+
function timeTicks(min, max, desired = 8) {
|
|
2892
|
+
const span = Math.max(max - min, 1);
|
|
2893
|
+
const pick = (strides, unit) => strides.find((s) => span / (s * unit) <= desired + 1) ?? strides[strides.length - 1];
|
|
2894
|
+
const ticks = [];
|
|
2895
|
+
if (span <= 3 * DAY) {
|
|
2896
|
+
const hours = pick([1, 3, 6, 12], HOUR);
|
|
2897
|
+
const start = Math.floor(min / (hours * HOUR)) * hours * HOUR;
|
|
2898
|
+
for (let t = start; t <= max; t += hours * HOUR) if (t >= min) ticks.push(t);
|
|
2899
|
+
return {
|
|
2900
|
+
ticks,
|
|
2901
|
+
format: (ms) => {
|
|
2902
|
+
const h = new Date(ms).getUTCHours();
|
|
2903
|
+
const minute = new Date(ms).getUTCMinutes();
|
|
2904
|
+
const suffix = h < 12 ? "AM" : "PM";
|
|
2905
|
+
const hour12 = h % 12 === 0 ? 12 : h % 12;
|
|
2906
|
+
return minute === 0 ? `${hour12} ${suffix}` : `${hour12}:${String(minute).padStart(2, "0")} ${suffix}`;
|
|
2907
|
+
}
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
if (span <= 45 * DAY) {
|
|
2911
|
+
const days = pick([1, 2, 7, 14], DAY);
|
|
2912
|
+
const start = Math.floor(min / DAY) * DAY;
|
|
2913
|
+
for (let t = start; t <= max; t += days * DAY) if (t >= min) ticks.push(t);
|
|
2914
|
+
return { ticks, format: (ms) => `${MONTHS[new Date(ms).getUTCMonth()]} ${new Date(ms).getUTCDate()}` };
|
|
2915
|
+
}
|
|
2916
|
+
const months = span / (30.4 * DAY);
|
|
2917
|
+
if (months <= 6 * (desired + 1)) {
|
|
2918
|
+
const stride2 = pick([1, 2, 3, 6], 30.4 * DAY);
|
|
2919
|
+
const first = new Date(min);
|
|
2920
|
+
let year = first.getUTCFullYear();
|
|
2921
|
+
let month = Math.floor(first.getUTCMonth() / stride2) * stride2;
|
|
2922
|
+
for (; ; ) {
|
|
2923
|
+
const t = Date.UTC(year, month, 1);
|
|
2924
|
+
if (t > max) break;
|
|
2925
|
+
if (t >= min) ticks.push(t);
|
|
2926
|
+
month += stride2;
|
|
2927
|
+
if (month >= 12) {
|
|
2928
|
+
month -= 12;
|
|
2929
|
+
year += 1;
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
const years = new Set(ticks.map((t) => new Date(t).getUTCFullYear()));
|
|
2933
|
+
return {
|
|
2934
|
+
ticks,
|
|
2935
|
+
format: (ms) => {
|
|
2936
|
+
const d = new Date(ms);
|
|
2937
|
+
return years.size > 1 ? `${MONTHS[d.getUTCMonth()]} ${d.getUTCFullYear()}` : MONTHS[d.getUTCMonth()];
|
|
2938
|
+
}
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
const stride = pick([1, 2, 5, 10], 365.25 * DAY);
|
|
2942
|
+
const startYear = Math.floor(new Date(min).getUTCFullYear() / stride) * stride;
|
|
2943
|
+
for (let year = startYear; ; year += stride) {
|
|
2944
|
+
const t = Date.UTC(year, 0, 1);
|
|
2945
|
+
if (t > max) break;
|
|
2946
|
+
if (t >= min) ticks.push(t);
|
|
2947
|
+
}
|
|
2948
|
+
return { ticks, format: (ms) => String(new Date(ms).getUTCFullYear()) };
|
|
2949
|
+
}
|
|
2950
|
+
function timeScale(values, domain) {
|
|
2951
|
+
let lo = domain ? asNumber(domain[0]) : Math.min(...values);
|
|
2952
|
+
let hi = domain ? asNumber(domain[1]) : Math.max(...values);
|
|
2953
|
+
if (!Number.isFinite(lo) || !Number.isFinite(hi)) {
|
|
2954
|
+
lo = 0;
|
|
2955
|
+
hi = DAY;
|
|
2956
|
+
}
|
|
2957
|
+
if (lo === hi) hi = lo + DAY;
|
|
2958
|
+
const { ticks, format } = timeTicks(lo, hi);
|
|
2959
|
+
const unit = (value) => (asNumber(value) - lo) / (hi - lo);
|
|
2960
|
+
return {
|
|
2961
|
+
kind: "time",
|
|
2962
|
+
unit,
|
|
2963
|
+
band: (value) => [unit(value), unit(value)],
|
|
2964
|
+
ticks: ticks.map(unit),
|
|
2965
|
+
gridLines: ticks.map(unit),
|
|
2966
|
+
labels: ticks.map((t) => ({ at: unit(t), text: format(t), anchor: "leading" })),
|
|
2967
|
+
domain: [lo, hi]
|
|
2968
|
+
};
|
|
2969
|
+
}
|
|
2970
|
+
function scaleFor(values, options) {
|
|
2971
|
+
const domain = options.domain;
|
|
2972
|
+
if (domain && domain.length > 2) return bandScale([...domain]);
|
|
2973
|
+
if (domain && domain.length === 2 && typeof domain[0] === "string") return bandScale([...domain]);
|
|
2974
|
+
if (values.some((v) => typeof v === "string")) {
|
|
2975
|
+
const categories = [];
|
|
2976
|
+
for (const v of values) if (!categories.includes(String(v))) categories.push(String(v));
|
|
2977
|
+
return bandScale(categories);
|
|
2978
|
+
}
|
|
2979
|
+
if (values.some((v) => v instanceof Date)) return timeScale(values.map(asNumber), domain);
|
|
2980
|
+
return numberScale(values.map(asNumber), { includesZero: options.includesZero, domain });
|
|
2981
|
+
}
|
|
2982
|
+
function Chart(props) {
|
|
2983
|
+
const { own, modifiers } = splitProps(props);
|
|
2984
|
+
const marks = declaredMarks(own.children);
|
|
2985
|
+
const series = [];
|
|
2986
|
+
for (const mark of marks) {
|
|
2987
|
+
const key = mark.props.foregroundStyleBy;
|
|
2988
|
+
if (key !== void 0 && !series.includes(key)) series.push(key);
|
|
2989
|
+
}
|
|
2990
|
+
const styleOf = (mark) => {
|
|
2991
|
+
if (mark.props.foregroundStyle !== void 0) return shapeStyle(mark.props.foregroundStyle);
|
|
2992
|
+
const key = mark.props.foregroundStyleBy;
|
|
2993
|
+
if (key !== void 0) return { name: PALETTE[series.indexOf(key) % PALETTE.length] };
|
|
2994
|
+
return { name: "blue" };
|
|
2995
|
+
};
|
|
2996
|
+
const xValues = [];
|
|
2997
|
+
const yValues = [];
|
|
2998
|
+
for (const { kind, props: p } of marks) {
|
|
2999
|
+
if (p.x !== void 0) xValues.push(p.x);
|
|
3000
|
+
if (p.xStart !== void 0) xValues.push(p.xStart);
|
|
3001
|
+
if (p.xEnd !== void 0) xValues.push(p.xEnd);
|
|
3002
|
+
if (p.y !== void 0) yValues.push(p.y);
|
|
3003
|
+
if (p.yStart !== void 0) yValues.push(p.yStart);
|
|
3004
|
+
if (p.yEnd !== void 0) yValues.push(p.yEnd);
|
|
3005
|
+
if (kind === "bar" || kind === "area") yValues.push(p.yStart ?? 0);
|
|
3006
|
+
}
|
|
3007
|
+
const xScale = scaleFor(xValues, { domain: own.xScale?.domain });
|
|
3008
|
+
const yScale = scaleFor(yValues, { includesZero: own.yScale?.includesZero ?? true, domain: own.yScale?.domain });
|
|
3009
|
+
const round = (n) => Math.round(n * 1e6) / 1e6;
|
|
3010
|
+
const ux = (v) => round(xScale.unit(v));
|
|
3011
|
+
const uy = (v) => round(1 - yScale.unit(v));
|
|
3012
|
+
let continuousBand = 1;
|
|
3013
|
+
if (xScale.kind !== "band") {
|
|
3014
|
+
const centers = [...new Set(marks.filter((m) => m.kind === "bar").map((m) => ux(m.props.x)))].sort((a, b) => a - b);
|
|
3015
|
+
for (let i = 1; i < centers.length; i++) continuousBand = Math.min(continuousBand, centers[i] - centers[i - 1]);
|
|
3016
|
+
}
|
|
3017
|
+
const encoded = [];
|
|
3018
|
+
const items = [];
|
|
3019
|
+
const annotate = (mark, rect) => {
|
|
3020
|
+
const annotation = mark.props.annotation;
|
|
3021
|
+
if (!annotation) return;
|
|
3022
|
+
items.push(
|
|
3023
|
+
/* @__PURE__ */ jsx(Fragment$1, { children: sb(
|
|
3024
|
+
"chartitem",
|
|
3025
|
+
{
|
|
3026
|
+
role: "annotation",
|
|
3027
|
+
...rect,
|
|
3028
|
+
position: annotation.position ?? "top",
|
|
3029
|
+
alignment: annotation.alignment ?? "center",
|
|
3030
|
+
spacing: annotation.spacing ?? 4
|
|
3031
|
+
},
|
|
3032
|
+
void 0,
|
|
3033
|
+
annotation.content
|
|
3034
|
+
) }, items.length)
|
|
3035
|
+
);
|
|
3036
|
+
};
|
|
3037
|
+
const common = (mark) => {
|
|
3038
|
+
const base = { style: styleOf(mark) };
|
|
3039
|
+
if (mark.props.opacity !== void 0) base.opacity = mark.props.opacity;
|
|
3040
|
+
return base;
|
|
3041
|
+
};
|
|
3042
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3043
|
+
for (const mark of marks) {
|
|
3044
|
+
if (mark.kind !== "line" && mark.kind !== "area") continue;
|
|
3045
|
+
const key = `${mark.kind}:${mark.props.series ?? mark.props.foregroundStyleBy ?? ""}`;
|
|
3046
|
+
const group = groups.get(key);
|
|
3047
|
+
if (group) group.push(mark);
|
|
3048
|
+
else groups.set(key, [mark]);
|
|
3049
|
+
}
|
|
3050
|
+
const emittedGroups = /* @__PURE__ */ new Set();
|
|
3051
|
+
for (const mark of marks) {
|
|
3052
|
+
const p = mark.props;
|
|
3053
|
+
switch (mark.kind) {
|
|
3054
|
+
case "bar": {
|
|
3055
|
+
const style = common(mark);
|
|
3056
|
+
const [b0, b1] = xScale.kind === "band" ? xScale.band(p.x) : [ux(p.x) - continuousBand / 2, ux(p.x) + continuousBand / 2];
|
|
3057
|
+
const center = round((b0 + b1) / 2);
|
|
3058
|
+
const half = round((b1 - b0) * 0.8 / 2);
|
|
3059
|
+
const top = uy(Math.max(asNumber(p.y), p.yStart ?? 0));
|
|
3060
|
+
const bottom = uy(Math.min(asNumber(p.y), p.yStart ?? 0));
|
|
3061
|
+
const rect = {
|
|
3062
|
+
kind: "rect",
|
|
3063
|
+
...style,
|
|
3064
|
+
x0: p.width !== void 0 ? center : round(center - half),
|
|
3065
|
+
x1: p.width !== void 0 ? center : round(center + half),
|
|
3066
|
+
y0: top,
|
|
3067
|
+
y1: bottom,
|
|
3068
|
+
cornerRadius: p.cornerRadius ?? 0,
|
|
3069
|
+
fixedWidth: p.width ?? null
|
|
3070
|
+
};
|
|
3071
|
+
encoded.push(rect);
|
|
3072
|
+
annotate(mark, { x0: rect.x0, x1: rect.x1, y0: top, y1: bottom });
|
|
3073
|
+
break;
|
|
3074
|
+
}
|
|
3075
|
+
case "line":
|
|
3076
|
+
case "area": {
|
|
3077
|
+
const key = `${mark.kind}:${p.series ?? p.foregroundStyleBy ?? ""}`;
|
|
3078
|
+
if (emittedGroups.has(key)) {
|
|
3079
|
+
annotate(mark, { x0: ux(p.x), x1: ux(p.x), y0: uy(p.y), y1: uy(p.y) });
|
|
3080
|
+
break;
|
|
3081
|
+
}
|
|
3082
|
+
emittedGroups.add(key);
|
|
3083
|
+
const group = [...groups.get(key)].sort((a, b) => ux(a.props.x) - ux(b.props.x));
|
|
3084
|
+
const first = group[0];
|
|
3085
|
+
if (mark.kind === "line") {
|
|
3086
|
+
const line = {
|
|
3087
|
+
kind: "line",
|
|
3088
|
+
...common(first),
|
|
3089
|
+
points: group.map((m) => ({ x: ux(m.props.x), y: uy(m.props.y) })),
|
|
3090
|
+
lineWidth: first.props.lineWidth ?? 2,
|
|
3091
|
+
interpolation: first.props.interpolation ?? "linear",
|
|
3092
|
+
symbol: first.props.symbol ?? (first.props.foregroundStyleBy !== void 0 && marks.some((m) => m.props.symbol) ? SYMBOLS[series.indexOf(first.props.foregroundStyleBy) % SYMBOLS.length] : null),
|
|
3093
|
+
symbolSize: first.props.symbolSize ?? 8
|
|
3094
|
+
};
|
|
3095
|
+
encoded.push(line);
|
|
3096
|
+
} else {
|
|
3097
|
+
const area = {
|
|
3098
|
+
kind: "area",
|
|
3099
|
+
...common(first),
|
|
3100
|
+
points: group.map((m) => ({
|
|
3101
|
+
x: ux(m.props.x),
|
|
3102
|
+
y0: uy(Math.max(m.props.y, m.props.yStart ?? 0)),
|
|
3103
|
+
y1: uy(Math.min(m.props.y, m.props.yStart ?? 0))
|
|
3104
|
+
})),
|
|
3105
|
+
interpolation: first.props.interpolation ?? "linear"
|
|
3106
|
+
};
|
|
3107
|
+
encoded.push(area);
|
|
3108
|
+
}
|
|
3109
|
+
annotate(mark, { x0: ux(p.x), x1: ux(p.x), y0: uy(p.y), y1: uy(p.y) });
|
|
3110
|
+
break;
|
|
3111
|
+
}
|
|
3112
|
+
case "point": {
|
|
3113
|
+
const point = { kind: "point", ...common(mark), x: ux(p.x), y: uy(p.y), symbol: p.symbol ?? "circle", symbolSize: p.symbolSize ?? 8 };
|
|
3114
|
+
encoded.push(point);
|
|
3115
|
+
annotate(mark, { x0: point.x, x1: point.x, y0: point.y, y1: point.y });
|
|
3116
|
+
break;
|
|
3117
|
+
}
|
|
3118
|
+
case "rule": {
|
|
3119
|
+
const vertical = p.x !== void 0;
|
|
3120
|
+
const rule = {
|
|
3121
|
+
kind: "rule",
|
|
3122
|
+
...common(mark),
|
|
3123
|
+
x0: vertical ? ux(p.x) : p.xStart !== void 0 ? ux(p.xStart) : 0,
|
|
3124
|
+
x1: vertical ? ux(p.x) : p.xEnd !== void 0 ? ux(p.xEnd) : 1,
|
|
3125
|
+
y0: vertical ? p.yEnd !== void 0 ? uy(p.yEnd) : 0 : uy(p.y ?? 0),
|
|
3126
|
+
y1: vertical ? p.yStart !== void 0 ? uy(p.yStart) : 1 : uy(p.y ?? 0),
|
|
3127
|
+
lineWidth: p.lineWidth ?? 1
|
|
3128
|
+
};
|
|
3129
|
+
encoded.push(rule);
|
|
3130
|
+
annotate(mark, { x0: rule.x0, x1: rule.x1, y0: rule.y0, y1: rule.y1 });
|
|
3131
|
+
break;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
const axis = (scale, position, flipY) => {
|
|
3136
|
+
const flip = (u) => round(flipY ? 1 - u : u);
|
|
3137
|
+
return {
|
|
3138
|
+
position,
|
|
3139
|
+
gridLines: scale.gridLines.map(flip),
|
|
3140
|
+
ticks: scale.ticks.map(flip),
|
|
3141
|
+
labels: scale.labels.map((label) => ({ ...label, at: flip(label.at) }))
|
|
3142
|
+
};
|
|
3143
|
+
};
|
|
3144
|
+
const chartProps = {
|
|
3145
|
+
marks: encoded,
|
|
3146
|
+
xAxis: own.xAxis === null ? null : axis(xScale, own.xAxis ?? "bottom", false),
|
|
3147
|
+
yAxis: own.yAxis === null ? null : axis(yScale, own.yAxis ?? "trailing", true),
|
|
3148
|
+
legend: own.legend === null || series.length === 0 ? null : {
|
|
3149
|
+
position: own.legend ?? "top",
|
|
3150
|
+
items: series.map((label, index) => ({ label, style: { name: PALETTE[index % PALETTE.length] }, symbol: null }))
|
|
3151
|
+
}
|
|
3152
|
+
};
|
|
3153
|
+
return applyModifiers(sb("chart", chartProps, void 0, items.length ? items : void 0), modifiers);
|
|
3154
|
+
}
|
|
3155
|
+
function Gauge(props) {
|
|
3156
|
+
const { own, modifiers } = splitProps(props);
|
|
3157
|
+
const [min, max] = own.range ?? [0, 1];
|
|
3158
|
+
const value = (own.value - min) / (max - min || 1);
|
|
3159
|
+
const children = [];
|
|
3160
|
+
const asView = (node) => typeof node === "string" || typeof node === "number" ? /* @__PURE__ */ jsx(Text, { children: node }) : node;
|
|
3161
|
+
if (own.label !== void 0) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: asView(own.label) }, "label"));
|
|
3162
|
+
if (own.currentValueLabel !== void 0) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: asView(own.currentValueLabel) }, "current"));
|
|
3163
|
+
return applyModifiers(
|
|
3164
|
+
sb(
|
|
3165
|
+
"gauge",
|
|
3166
|
+
{
|
|
3167
|
+
value: Math.min(1, Math.max(0, value)),
|
|
3168
|
+
style: own.gaugeStyle ?? "automatic",
|
|
3169
|
+
hasLabel: own.label !== void 0,
|
|
3170
|
+
hasCurrentValueLabel: own.currentValueLabel !== void 0
|
|
3171
|
+
},
|
|
3172
|
+
void 0,
|
|
3173
|
+
children.length ? children : void 0
|
|
3174
|
+
),
|
|
3175
|
+
modifiers
|
|
3176
|
+
);
|
|
3177
|
+
}
|
|
3178
|
+
function ViewThatFits(props) {
|
|
3179
|
+
const { own, modifiers } = splitProps(props);
|
|
3180
|
+
return applyModifiers(sb("viewthatfits", { axes: own.axes ?? "both" }, void 0, own.children), modifiers);
|
|
3181
|
+
}
|
|
3182
|
+
function LazyVStack(props) {
|
|
3183
|
+
return /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: /* @__PURE__ */ jsx(VStack, { ...props }) });
|
|
3184
|
+
}
|
|
3185
|
+
function LazyHStack(props) {
|
|
3186
|
+
return /* @__PURE__ */ jsx(LazyContext.Provider, { value: "horizontal", children: /* @__PURE__ */ jsx(HStack, { ...props }) });
|
|
3187
|
+
}
|
|
3188
|
+
function ContentUnavailableView(props) {
|
|
3189
|
+
const { own, modifiers } = splitProps(props);
|
|
3190
|
+
const title = typeof own.title === "string" ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.title;
|
|
3191
|
+
const description = typeof own.description === "string" ? /* @__PURE__ */ jsx(Text, { children: own.description }) : own.description;
|
|
3192
|
+
return applyModifiers(
|
|
3193
|
+
/* @__PURE__ */ jsxs(VStack, { spacing: 16, padding: ["horizontal", 32], frame: { maxWidth: Infinity, maxHeight: Infinity }, children: [
|
|
3194
|
+
/* @__PURE__ */ jsxs(VStack, { spacing: 8, children: [
|
|
3195
|
+
/* @__PURE__ */ jsxs(VStack, { spacing: 12, children: [
|
|
3196
|
+
own.systemImage !== void 0 && /* @__PURE__ */ jsx(Image$1, { systemName: own.systemImage, font: { size: 48 }, foregroundStyle: "secondary" }),
|
|
3197
|
+
styled({ multilineTextAlignment: "center" }, styled({ font: { textStyle: "title2", weight: "bold" } }, title))
|
|
3198
|
+
] }),
|
|
3199
|
+
description !== void 0 && styled({ multilineTextAlignment: "center" }, styled({ foreground: { hierarchical: 2 } }, styled({ font: { textStyle: "callout" } }, description)))
|
|
3200
|
+
] }),
|
|
3201
|
+
own.actions
|
|
3202
|
+
] }),
|
|
3203
|
+
modifiers
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
ContentUnavailableView.search = (text) => /* @__PURE__ */ jsx(
|
|
3207
|
+
ContentUnavailableView,
|
|
3208
|
+
{
|
|
3209
|
+
title: text ? `No Results for “${text}”` : "No Results",
|
|
3210
|
+
systemImage: "magnifyingglass",
|
|
3211
|
+
description: "Check the spelling or try a new search."
|
|
3212
|
+
}
|
|
3213
|
+
);
|
|
3214
|
+
function GroupBox(props) {
|
|
3215
|
+
const { own, modifiers } = splitProps(props);
|
|
3216
|
+
const label = typeof own.label === "string" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
|
|
3217
|
+
return applyModifiers(
|
|
3218
|
+
/* @__PURE__ */ jsxs(
|
|
3219
|
+
VStack,
|
|
3220
|
+
{
|
|
3221
|
+
alignment: "leading",
|
|
3222
|
+
spacing: 8,
|
|
3223
|
+
padding: 16,
|
|
3224
|
+
background: { fill: "secondarySystemBackground", in: /* @__PURE__ */ jsx(RoundedRectangle, { cornerRadius: 8 }) },
|
|
3225
|
+
children: [
|
|
3226
|
+
label !== void 0 && styled({ font: { textStyle: "headline" } }, label),
|
|
3227
|
+
own.children
|
|
3228
|
+
]
|
|
3229
|
+
}
|
|
3230
|
+
),
|
|
3231
|
+
modifiers
|
|
3232
|
+
);
|
|
3233
|
+
}
|
|
3234
|
+
function ControlGroup(props) {
|
|
3235
|
+
const { own, modifiers } = splitProps(props);
|
|
3236
|
+
return modifiers.length ? applyModifiers(/* @__PURE__ */ jsx(Fragment, { children: own.children }), modifiers) : own.children;
|
|
3237
|
+
}
|
|
3238
|
+
function DisclosureGroup(props) {
|
|
3239
|
+
const { own, modifiers } = splitProps(props);
|
|
3240
|
+
const [internal, setInternal] = useState(false);
|
|
3241
|
+
const [expanded, setExpanded] = own.isExpanded !== void 0 ? readBinding(own.isExpanded, own.onExpandedChange) : [internal, setInternal];
|
|
3242
|
+
const label = typeof own.label === "string" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
|
|
3243
|
+
const toggle = () => withAnimation({ type: "easeInOut", duration: 0.25 }, () => setExpanded(!expanded));
|
|
3244
|
+
return applyModifiers(
|
|
3245
|
+
/* @__PURE__ */ jsxs(VStack, { alignment: "leading", spacing: 0, children: [
|
|
3246
|
+
/* @__PURE__ */ jsx(Button, { action: toggle, buttonStyle: "plain", children: /* @__PURE__ */ jsxs(HStack, { children: [
|
|
3247
|
+
styled({ foreground: { hierarchical: 1 } }, label),
|
|
3248
|
+
/* @__PURE__ */ jsx(Spacer, {}),
|
|
3249
|
+
/* @__PURE__ */ jsx(
|
|
3250
|
+
Image$1,
|
|
3251
|
+
{
|
|
3252
|
+
systemName: "chevron.right",
|
|
3253
|
+
font: { textStyle: "footnote", weight: "semibold" },
|
|
3254
|
+
foregroundStyle: "tint",
|
|
3255
|
+
rotationEffect: expanded ? 90 : 0
|
|
3256
|
+
}
|
|
3257
|
+
)
|
|
3258
|
+
] }) }),
|
|
3259
|
+
expanded && /* @__PURE__ */ jsx(VStack, { alignment: "leading", spacing: 8, padding: ["top", 8], transition: { kind: "opacity" }, children: own.children })
|
|
3260
|
+
] }),
|
|
3261
|
+
modifiers
|
|
3262
|
+
);
|
|
3263
|
+
}
|
|
3264
|
+
const COLUMN_SPACING = 12;
|
|
3265
|
+
function cell(column, content) {
|
|
3266
|
+
if (column.width !== void 0) return styled({ layoutPriority: 0 }, styled({ frame: { width: column.width, alignment: "leading" } }, content));
|
|
3267
|
+
return styled(
|
|
3268
|
+
{ layoutPriority: 0 },
|
|
3269
|
+
styled({ frame: { minWidth: column.minWidth ?? 0, maxWidth: column.maxWidth ?? "infinity", alignment: "leading" } }, content)
|
|
3270
|
+
);
|
|
3271
|
+
}
|
|
3272
|
+
function cellContent(column, row) {
|
|
3273
|
+
if (typeof column.content === "function") return column.content(row);
|
|
3274
|
+
return /* @__PURE__ */ jsx(Text, { children: String(row[column.content] ?? "") });
|
|
3275
|
+
}
|
|
3276
|
+
function Table(props) {
|
|
3277
|
+
const { own, modifiers } = splitProps(props);
|
|
3278
|
+
const compact = useHorizontalSizeClass() !== "regular";
|
|
3279
|
+
const sort = own.sortOrder !== void 0 ? readBinding(own.sortOrder) : null;
|
|
3280
|
+
const keyOf2 = (row2, index) => {
|
|
3281
|
+
if (own.id) return own.id(row2, index);
|
|
3282
|
+
const id = row2.id;
|
|
3283
|
+
return typeof id === "string" || typeof id === "number" ? id : index;
|
|
3284
|
+
};
|
|
3285
|
+
const row = (value) => {
|
|
3286
|
+
const first = own.columns[0];
|
|
3287
|
+
if (!first) return null;
|
|
3288
|
+
if (compact) return cellContent(first, value);
|
|
3289
|
+
return /* @__PURE__ */ jsx(HStack, { spacing: COLUMN_SPACING, children: own.columns.map((column, index) => /* @__PURE__ */ jsx(ColumnCell, { children: cell(column, cellContent(column, value)) }, index)) });
|
|
3290
|
+
};
|
|
3291
|
+
const title = (column) => {
|
|
3292
|
+
if (!sort || column.sortKey === void 0) return /* @__PURE__ */ jsx(Text, { children: column.title });
|
|
3293
|
+
const [order, setOrder] = sort;
|
|
3294
|
+
const current = order[0]?.key === column.sortKey ? order[0] : null;
|
|
3295
|
+
const tap = () => {
|
|
3296
|
+
const rest = order.filter((descriptor) => descriptor.key !== column.sortKey);
|
|
3297
|
+
setOrder([{ key: column.sortKey, ascending: current ? !current.ascending : true }, ...rest]);
|
|
3298
|
+
};
|
|
3299
|
+
return /* @__PURE__ */ jsx(Button, { action: tap, buttonStyle: "plain", children: /* @__PURE__ */ jsxs(HStack, { spacing: 4, children: [
|
|
3300
|
+
/* @__PURE__ */ jsx(Text, { children: column.title }),
|
|
3301
|
+
current && /* @__PURE__ */ jsx(Image$1, { systemName: current.ascending ? "chevron.up" : "chevron.down", font: { textStyle: "caption2", weight: "bold" } })
|
|
3302
|
+
] }) });
|
|
3303
|
+
};
|
|
3304
|
+
const list = /* @__PURE__ */ jsx(List, { selection: own.selection, onSelectionChange: own.onSelectionChange, children: /* @__PURE__ */ jsx(ForEach, { data: own.data, id: keyOf2, children: (value, index) => /* @__PURE__ */ jsx(TableRow, { tag: keyOf2(value, index), children: row(value) }) }) });
|
|
3305
|
+
if (compact) return applyModifiers(list, modifiers);
|
|
3306
|
+
return applyModifiers(
|
|
3307
|
+
/* @__PURE__ */ jsxs(VStack, { spacing: 0, children: [
|
|
3308
|
+
/* @__PURE__ */ jsx(
|
|
3309
|
+
HStack,
|
|
3310
|
+
{
|
|
3311
|
+
spacing: COLUMN_SPACING,
|
|
3312
|
+
font: { textStyle: "subheadline", weight: "semibold" },
|
|
3313
|
+
foregroundStyle: "secondary",
|
|
3314
|
+
padding: ["horizontal", 20],
|
|
3315
|
+
modifiers: [{ padding: ["vertical", 8] }],
|
|
3316
|
+
children: own.columns.map((column, index) => /* @__PURE__ */ jsx(ColumnCell, { children: cell(column, title(column)) }, index))
|
|
3317
|
+
}
|
|
3318
|
+
),
|
|
3319
|
+
list
|
|
3320
|
+
] }),
|
|
3321
|
+
modifiers
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
function ColumnCell({ children }) {
|
|
3325
|
+
return children;
|
|
3326
|
+
}
|
|
3327
|
+
function TableRow({ children }) {
|
|
3328
|
+
return children;
|
|
3329
|
+
}
|
|
3330
|
+
const hexOf = (c) => "#" + [c.r, c.g, c.b].map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0")).join("");
|
|
3331
|
+
function ColorPicker(props) {
|
|
3332
|
+
const { own, modifiers } = splitProps(props);
|
|
3333
|
+
const [selection, setSelection] = readBinding(own.selection, own.onChange);
|
|
3334
|
+
const label = own.label ?? (own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : null);
|
|
3335
|
+
const pick = () => {
|
|
3336
|
+
chooseColor(hexOf(selection)).then((chosen) => {
|
|
3337
|
+
if (chosen) setSelection({ ...Color.hex(chosen), a: selection.a });
|
|
3338
|
+
}).catch((error) => console.error(error));
|
|
3339
|
+
};
|
|
3340
|
+
return applyModifiers(
|
|
3341
|
+
/* @__PURE__ */ jsx(Button, { action: pick, buttonStyle: "plain", children: /* @__PURE__ */ jsxs(HStack, { children: [
|
|
3342
|
+
label,
|
|
3343
|
+
/* @__PURE__ */ jsx(Spacer, {}),
|
|
3344
|
+
/* @__PURE__ */ jsx(
|
|
3345
|
+
Circle,
|
|
3346
|
+
{
|
|
3347
|
+
fill: selection,
|
|
3348
|
+
frame: { width: 28, height: 28 },
|
|
3349
|
+
overlay: /* @__PURE__ */ jsx(Circle, { strokeBorder: { style: Color.opacity("secondary", 0.3), lineWidth: 1 } })
|
|
3350
|
+
}
|
|
3351
|
+
)
|
|
3352
|
+
] }) }),
|
|
3353
|
+
modifiers
|
|
3354
|
+
);
|
|
3355
|
+
}
|
|
3356
|
+
function ShareLink(props) {
|
|
3357
|
+
const { own, modifiers } = splitProps(props);
|
|
3358
|
+
const share = () => {
|
|
3359
|
+
const isURL = own.item instanceof URL || /^[a-z][a-z0-9+.-]*:\/\//i.test(own.item);
|
|
3360
|
+
const params = {};
|
|
3361
|
+
if (own.subject) params["title"] = own.subject;
|
|
3362
|
+
if (isURL) params["url"] = String(own.item);
|
|
3363
|
+
const text = [own.message, isURL ? null : String(own.item)].filter(Boolean).join("\n");
|
|
3364
|
+
if (text) params["text"] = text;
|
|
3365
|
+
performHostRequest({ op: "request", id: 0, kind: "share", params }, browserEnvironment).catch((error) => console.error(error));
|
|
3366
|
+
};
|
|
3367
|
+
return applyModifiers(
|
|
3368
|
+
/* @__PURE__ */ jsx(Button, { action: share, children: own.children ?? /* @__PURE__ */ jsx(Label, { title: own.title ?? "Share", systemImage: "square.and.arrow.up" }) }),
|
|
3369
|
+
modifiers
|
|
3370
|
+
);
|
|
3371
|
+
}
|
|
3372
|
+
const IDENTITY = [1, 0, 0, 1, 0, 0];
|
|
3373
|
+
function multiply(m, n) {
|
|
3374
|
+
const [a, b, c, d, tx, ty] = m;
|
|
3375
|
+
const [a2, b2, c2, d2, tx2, ty2] = n;
|
|
3376
|
+
return [a2 * a + b2 * c, a2 * b + b2 * d, c2 * a + d2 * c, c2 * b + d2 * d, tx2 * a + ty2 * c + tx, tx2 * b + ty2 * d + ty];
|
|
3377
|
+
}
|
|
3378
|
+
function stops(spec) {
|
|
3379
|
+
if (spec.stops) return spec.stops.map((s) => ({ color: color(s.color), location: s.location }));
|
|
3380
|
+
const colors = spec.colors ?? [];
|
|
3381
|
+
const last = Math.max(colors.length - 1, 1);
|
|
3382
|
+
return colors.map((c, i) => ({ color: color(c), location: i / last }));
|
|
3383
|
+
}
|
|
3384
|
+
const LABEL_COLORS = {
|
|
3385
|
+
primary: { name: "primary" },
|
|
3386
|
+
secondary: { name: "secondary" },
|
|
3387
|
+
tertiary: { name: "tertiaryLabel" },
|
|
3388
|
+
quaternary: { name: "quaternaryLabel" }
|
|
3389
|
+
};
|
|
3390
|
+
function shading(value) {
|
|
3391
|
+
if (typeof value === "string" && value in LABEL_COLORS) return LABEL_COLORS[value];
|
|
3392
|
+
if (typeof value === "object" && value !== null) {
|
|
3393
|
+
if ("linearGradient" in value) {
|
|
3394
|
+
const g = value.linearGradient;
|
|
3395
|
+
if (isCanvasGradient(g)) return { canvasLinearGradient: { stops: stops(g), start: g.start, end: g.end } };
|
|
3396
|
+
}
|
|
3397
|
+
if ("radialGradient" in value) {
|
|
3398
|
+
const g = value.radialGradient;
|
|
3399
|
+
if (isCanvasGradient(g)) return { canvasRadialGradient: { stops: stops(g), center: g.center, startRadius: g.startRadius, endRadius: g.endRadius } };
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
return shapeStyle(value);
|
|
3403
|
+
}
|
|
3404
|
+
function isCanvasGradient(g) {
|
|
3405
|
+
if (Array.isArray(g.colors)) return true;
|
|
3406
|
+
return Array.isArray(g.stops) && g.stops.some((s) => typeof s.color === "string");
|
|
3407
|
+
}
|
|
3408
|
+
class GraphicsContext {
|
|
3409
|
+
constructor(size) {
|
|
3410
|
+
this.size = size;
|
|
3411
|
+
}
|
|
3412
|
+
size;
|
|
3413
|
+
commands = [];
|
|
3414
|
+
symbolDraws = [];
|
|
3415
|
+
symbolIds = /* @__PURE__ */ new Set();
|
|
3416
|
+
/** @internal The ids `symbols` gave the canvas. */
|
|
3417
|
+
setSymbols(ids) {
|
|
3418
|
+
this.symbolIds = new Set(ids);
|
|
3419
|
+
}
|
|
3420
|
+
/** `resolveSymbol(id:)`: the view the canvas was given under `id`, or null. */
|
|
3421
|
+
resolveSymbol(id) {
|
|
3422
|
+
return this.symbolIds.has(id) ? { symbol: id } : null;
|
|
3423
|
+
}
|
|
3424
|
+
/**
|
|
3425
|
+
* `draw(symbol, at:)`: the symbol's view centered on the point. Symbols are
|
|
3426
|
+
* views laid over the drawing, so they draw above its other commands.
|
|
3427
|
+
*/
|
|
3428
|
+
drawSymbol(symbol, at) {
|
|
3429
|
+
const [a, b, c, d, tx, ty] = this.state.transform;
|
|
3430
|
+
const scaleX = Math.hypot(a, b);
|
|
3431
|
+
const scaleY = scaleX > 0 ? (a * d - b * c) / scaleX : Math.hypot(c, d);
|
|
3432
|
+
this.symbolDraws.push({
|
|
3433
|
+
id: symbol.symbol,
|
|
3434
|
+
x: a * at.x + c * at.y + tx,
|
|
3435
|
+
y: b * at.x + d * at.y + ty,
|
|
3436
|
+
rotation: Math.atan2(b, a) * 180 / Math.PI,
|
|
3437
|
+
scale: { x: scaleX, y: scaleY },
|
|
3438
|
+
opacity: this.state.opacity
|
|
3439
|
+
});
|
|
3440
|
+
return this;
|
|
3441
|
+
}
|
|
3442
|
+
state = { transform: IDENTITY, opacity: 1, blendMode: void 0, clips: [], filters: [] };
|
|
3443
|
+
get opacity() {
|
|
3444
|
+
return this.state.opacity;
|
|
3445
|
+
}
|
|
3446
|
+
set opacity(value) {
|
|
3447
|
+
this.state.opacity = value;
|
|
3448
|
+
}
|
|
3449
|
+
get blendMode() {
|
|
3450
|
+
return this.state.blendMode;
|
|
3451
|
+
}
|
|
3452
|
+
set blendMode(value) {
|
|
3453
|
+
this.state.blendMode = value;
|
|
3454
|
+
}
|
|
3455
|
+
translateBy(x, y) {
|
|
3456
|
+
this.state.transform = multiply(this.state.transform, [1, 0, 0, 1, x, y]);
|
|
3457
|
+
return this;
|
|
3458
|
+
}
|
|
3459
|
+
scaleBy(x, y = x) {
|
|
3460
|
+
this.state.transform = multiply(this.state.transform, [x, 0, 0, y, 0, 0]);
|
|
3461
|
+
return this;
|
|
3462
|
+
}
|
|
3463
|
+
/** Degrees, clockwise on screen. */
|
|
3464
|
+
rotate(degrees) {
|
|
3465
|
+
const r2 = degrees * Math.PI / 180;
|
|
3466
|
+
this.state.transform = multiply(this.state.transform, [Math.cos(r2), Math.sin(r2), -Math.sin(r2), Math.cos(r2), 0, 0]);
|
|
3467
|
+
return this;
|
|
3468
|
+
}
|
|
3469
|
+
concatenate(matrix) {
|
|
3470
|
+
this.state.transform = multiply(this.state.transform, matrix);
|
|
3471
|
+
return this;
|
|
3472
|
+
}
|
|
3473
|
+
clip(to) {
|
|
3474
|
+
this.state.clips = [...this.state.clips, to.svg()];
|
|
3475
|
+
return this;
|
|
3476
|
+
}
|
|
3477
|
+
addFilter(filter) {
|
|
3478
|
+
this.state.filters = [...this.state.filters, filter];
|
|
3479
|
+
return this;
|
|
3480
|
+
}
|
|
3481
|
+
/** `drawLayer { }`: draws with a copy of the state, restored after. */
|
|
3482
|
+
drawLayer(body) {
|
|
3483
|
+
const saved = { ...this.state, clips: [...this.state.clips], filters: [...this.state.filters] };
|
|
3484
|
+
body(this);
|
|
3485
|
+
this.state = saved;
|
|
3486
|
+
return this;
|
|
3487
|
+
}
|
|
3488
|
+
fill(path, with_, options = {}) {
|
|
3489
|
+
this.push({ op: "fill", path: path.svg(), shading: shading(with_), ...options.eoFill ? { evenOdd: true } : {} });
|
|
3490
|
+
return this;
|
|
3491
|
+
}
|
|
3492
|
+
stroke(path, with_, options = {}) {
|
|
3493
|
+
const o = typeof options === "number" ? { lineWidth: options } : options;
|
|
3494
|
+
const command = { op: "stroke", path: path.svg(), shading: shading(with_), lineWidth: o.lineWidth ?? 1 };
|
|
3495
|
+
if (o.lineCap) command.lineCap = o.lineCap;
|
|
3496
|
+
if (o.lineJoin) command.lineJoin = o.lineJoin;
|
|
3497
|
+
if (o.miterLimit !== void 0) command.miterLimit = o.miterLimit;
|
|
3498
|
+
if (o.dash) command.dash = o.dash;
|
|
3499
|
+
if (o.dashPhase !== void 0) command.dashPhase = o.dashPhase;
|
|
3500
|
+
this.push(command);
|
|
3501
|
+
return this;
|
|
3502
|
+
}
|
|
3503
|
+
/** `draw(Text(...), at:anchor:)` */
|
|
3504
|
+
drawText(text, at, options = {}) {
|
|
3505
|
+
const command = {
|
|
3506
|
+
op: "text",
|
|
3507
|
+
text,
|
|
3508
|
+
x: at.x,
|
|
3509
|
+
y: at.y,
|
|
3510
|
+
anchor: unitPoint(options.anchor ?? "center"),
|
|
3511
|
+
shading: shading(options.color ?? "primary")
|
|
3512
|
+
};
|
|
3513
|
+
if (options.font !== void 0) command.font = font(options.font);
|
|
3514
|
+
this.push(command);
|
|
3515
|
+
return this;
|
|
3516
|
+
}
|
|
3517
|
+
/** `draw(Image(...), at:anchor:)` or `draw(_:in:)` with `size`. */
|
|
3518
|
+
drawImage(image, at, options = {}) {
|
|
3519
|
+
const props = "url" in image ? { ...image, resizable: true } : "name" in image ? { name: image.name, resizable: true } : image;
|
|
3520
|
+
const command = {
|
|
3521
|
+
op: "image",
|
|
3522
|
+
image: props,
|
|
3523
|
+
x: at.x,
|
|
3524
|
+
y: at.y,
|
|
3525
|
+
anchor: unitPoint(options.anchor ?? (options.size ? "topLeading" : "center")),
|
|
3526
|
+
...options.size ? { width: options.size.width, height: options.size.height } : {},
|
|
3527
|
+
...options.color !== void 0 ? { shading: shading(options.color) } : {}
|
|
3528
|
+
};
|
|
3529
|
+
this.push(command);
|
|
3530
|
+
return this;
|
|
3531
|
+
}
|
|
3532
|
+
push(command) {
|
|
3533
|
+
const state = {};
|
|
3534
|
+
if (this.state.transform.some((v, i) => v !== IDENTITY[i])) state.transform = this.state.transform.map((v) => Math.round(v * 1e4) / 1e4);
|
|
3535
|
+
if (this.state.opacity !== 1) state.opacity = this.state.opacity;
|
|
3536
|
+
if (this.state.blendMode) state.blendMode = this.state.blendMode;
|
|
3537
|
+
if (this.state.clips.length) state.clips = [...this.state.clips];
|
|
3538
|
+
if (this.state.filters.length) state.filters = [...this.state.filters];
|
|
3539
|
+
this.commands.push({ ...state, ...command });
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
function Canvas(props) {
|
|
3543
|
+
const { own, modifiers } = splitProps(props);
|
|
3544
|
+
const [size, setSize] = useState(null);
|
|
3545
|
+
let canvas = null;
|
|
3546
|
+
let draws = [];
|
|
3547
|
+
if (size) {
|
|
3548
|
+
const context = new GraphicsContext(size);
|
|
3549
|
+
if (own.symbols) context.setSymbols(Object.keys(own.symbols));
|
|
3550
|
+
own.renderer(context, size);
|
|
3551
|
+
canvas = sb("canvas", { width: size.width, height: size.height, commands: context.commands });
|
|
3552
|
+
draws = context.symbolDraws;
|
|
3553
|
+
}
|
|
3554
|
+
const reader = sb(
|
|
3555
|
+
"geometry",
|
|
3556
|
+
{},
|
|
3557
|
+
{
|
|
3558
|
+
geometry: (event) => {
|
|
3559
|
+
if (!size || size.width !== event.width || size.height !== event.height) setSize({ width: event.width, height: event.height });
|
|
3560
|
+
}
|
|
3561
|
+
},
|
|
3562
|
+
canvas
|
|
3563
|
+
);
|
|
3564
|
+
if (!own.symbols) return applyModifiers(reader, modifiers);
|
|
3565
|
+
const symbols = draws.map((draw, index) => {
|
|
3566
|
+
let view = own.symbols[draw.id];
|
|
3567
|
+
if (draw.scale.x !== 1 || draw.scale.y !== 1) view = styled({ scale: draw.scale }, view);
|
|
3568
|
+
if (Math.abs(draw.rotation) > 1e-6) view = styled({ rotation: draw.rotation }, view);
|
|
3569
|
+
if (draw.opacity !== 1) view = styled({ opacity: draw.opacity }, view);
|
|
3570
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: styled({ position: { x: draw.x, y: draw.y } }, view) }, index);
|
|
3571
|
+
});
|
|
3572
|
+
return applyModifiers(
|
|
3573
|
+
sb("zstack", { alignment: "topLeading" }, void 0, [/* @__PURE__ */ jsx(Fragment$1, { children: reader }, "canvas"), ...symbols]),
|
|
3574
|
+
modifiers
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
function TimelineView({ schedule, children }) {
|
|
3578
|
+
const [date, setDate] = useState(() => /* @__PURE__ */ new Date());
|
|
3579
|
+
const key = typeof schedule === "string" ? schedule : JSON.stringify(schedule);
|
|
3580
|
+
useEffect(() => {
|
|
3581
|
+
if (schedule === "everyMinute") {
|
|
3582
|
+
let interval;
|
|
3583
|
+
const timeout = setTimeout(() => {
|
|
3584
|
+
setDate(/* @__PURE__ */ new Date());
|
|
3585
|
+
interval = setInterval(() => setDate(/* @__PURE__ */ new Date()), 6e4);
|
|
3586
|
+
}, 6e4 - Date.now() % 6e4);
|
|
3587
|
+
return () => {
|
|
3588
|
+
clearTimeout(timeout);
|
|
3589
|
+
if (interval) clearInterval(interval);
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
if (typeof schedule === "object" && "periodic" in schedule) {
|
|
3593
|
+
const every = Math.max(schedule.periodic.by, 0.01) * 1e3;
|
|
3594
|
+
const from = schedule.periodic.from?.getTime() ?? Date.now();
|
|
3595
|
+
let timer;
|
|
3596
|
+
const tick = () => {
|
|
3597
|
+
const now = Date.now();
|
|
3598
|
+
const next = from + Math.ceil((now - from + 1) / every) * every;
|
|
3599
|
+
timer = setTimeout(() => {
|
|
3600
|
+
setDate(new Date(next));
|
|
3601
|
+
tick();
|
|
3602
|
+
}, Math.max(0, next - now));
|
|
3603
|
+
};
|
|
3604
|
+
tick();
|
|
3605
|
+
return () => clearTimeout(timer);
|
|
3606
|
+
}
|
|
3607
|
+
const options = typeof schedule === "object" ? schedule.animation : {};
|
|
3608
|
+
if (options.paused) return;
|
|
3609
|
+
const minimum = (options.minimumInterval ?? 1 / 20) * 1e3;
|
|
3610
|
+
let last = 0;
|
|
3611
|
+
let frame2 = 0;
|
|
3612
|
+
const loop = (time) => {
|
|
3613
|
+
if (time - last >= minimum) {
|
|
3614
|
+
last = time;
|
|
3615
|
+
setDate(/* @__PURE__ */ new Date());
|
|
3616
|
+
}
|
|
3617
|
+
frame2 = requestAnimationFrame(loop);
|
|
3618
|
+
};
|
|
3619
|
+
frame2 = requestAnimationFrame(loop);
|
|
3620
|
+
return () => cancelAnimationFrame(frame2);
|
|
3621
|
+
}, [key]);
|
|
3622
|
+
return children({ date });
|
|
3623
|
+
}
|
|
3624
|
+
class AVPlayer {
|
|
3625
|
+
state;
|
|
3626
|
+
listeners = /* @__PURE__ */ new Set();
|
|
3627
|
+
timeListeners = /* @__PURE__ */ new Set();
|
|
3628
|
+
time = 0;
|
|
3629
|
+
serial = 0;
|
|
3630
|
+
constructor(url = null, options = {}) {
|
|
3631
|
+
this.state = {
|
|
3632
|
+
url,
|
|
3633
|
+
rate: 0,
|
|
3634
|
+
muted: false,
|
|
3635
|
+
volume: 1,
|
|
3636
|
+
loop: options.loop ?? false,
|
|
3637
|
+
seek: { time: 0, serial: 0 },
|
|
3638
|
+
duration: null,
|
|
3639
|
+
size: null,
|
|
3640
|
+
status: "paused",
|
|
3641
|
+
failed: null
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
get url() {
|
|
3645
|
+
return this.state.url;
|
|
3646
|
+
}
|
|
3647
|
+
get rate() {
|
|
3648
|
+
return this.state.rate;
|
|
3649
|
+
}
|
|
3650
|
+
get isPlaying() {
|
|
3651
|
+
return this.state.rate > 0;
|
|
3652
|
+
}
|
|
3653
|
+
get isMuted() {
|
|
3654
|
+
return this.state.muted;
|
|
3655
|
+
}
|
|
3656
|
+
get volume() {
|
|
3657
|
+
return this.state.volume;
|
|
3658
|
+
}
|
|
3659
|
+
get duration() {
|
|
3660
|
+
return this.state.duration;
|
|
3661
|
+
}
|
|
3662
|
+
get presentationSize() {
|
|
3663
|
+
return this.state.size;
|
|
3664
|
+
}
|
|
3665
|
+
get timeControlStatus() {
|
|
3666
|
+
return this.state.status;
|
|
3667
|
+
}
|
|
3668
|
+
get error() {
|
|
3669
|
+
return this.state.failed;
|
|
3670
|
+
}
|
|
3671
|
+
get currentTime() {
|
|
3672
|
+
return this.time;
|
|
3673
|
+
}
|
|
3674
|
+
/** @internal */
|
|
3675
|
+
get snapshot() {
|
|
3676
|
+
return this.state;
|
|
3677
|
+
}
|
|
3678
|
+
play() {
|
|
3679
|
+
this.update({ rate: 1 });
|
|
3680
|
+
}
|
|
3681
|
+
pause() {
|
|
3682
|
+
this.update({ rate: 0 });
|
|
3683
|
+
}
|
|
3684
|
+
seek(time) {
|
|
3685
|
+
this.time = time;
|
|
3686
|
+
this.update({ seek: { time, serial: ++this.serial } });
|
|
3687
|
+
}
|
|
3688
|
+
replaceCurrentItem(url) {
|
|
3689
|
+
this.time = 0;
|
|
3690
|
+
this.update({ url, duration: null, size: null, failed: null, seek: { time: 0, serial: ++this.serial } });
|
|
3691
|
+
}
|
|
3692
|
+
set isMuted(muted) {
|
|
3693
|
+
this.update({ muted });
|
|
3694
|
+
}
|
|
3695
|
+
set volume(volume) {
|
|
3696
|
+
this.update({ volume: Math.min(1, Math.max(0, volume)) });
|
|
3697
|
+
}
|
|
3698
|
+
set rate(rate) {
|
|
3699
|
+
this.update({ rate });
|
|
3700
|
+
}
|
|
3701
|
+
set loop(loop) {
|
|
3702
|
+
this.update({ loop });
|
|
3703
|
+
}
|
|
3704
|
+
subscribe = (listener) => {
|
|
3705
|
+
this.listeners.add(listener);
|
|
3706
|
+
return () => this.listeners.delete(listener);
|
|
3707
|
+
};
|
|
3708
|
+
/** `addPeriodicTimeObserver`: told the position as the page reports it. */
|
|
3709
|
+
onTime(listener) {
|
|
3710
|
+
this.timeListeners.add(listener);
|
|
3711
|
+
return () => this.timeListeners.delete(listener);
|
|
3712
|
+
}
|
|
3713
|
+
/** @internal The page's report for a view showing this player. */
|
|
3714
|
+
handle(event) {
|
|
3715
|
+
if (event.time !== void 0) {
|
|
3716
|
+
this.time = event.time;
|
|
3717
|
+
for (const listener of this.timeListeners) listener(event.time);
|
|
3718
|
+
}
|
|
3719
|
+
switch (event.event) {
|
|
3720
|
+
case "ready":
|
|
3721
|
+
this.update({
|
|
3722
|
+
duration: event.duration ?? null,
|
|
3723
|
+
size: event.width && event.height ? { width: event.width, height: event.height } : this.state.size
|
|
3724
|
+
});
|
|
3725
|
+
break;
|
|
3726
|
+
case "status":
|
|
3727
|
+
if (event.status) this.update({ status: event.status });
|
|
3728
|
+
break;
|
|
3729
|
+
case "play":
|
|
3730
|
+
if (this.state.rate === 0) this.update({ rate: 1 });
|
|
3731
|
+
break;
|
|
3732
|
+
case "pause":
|
|
3733
|
+
if (this.state.rate !== 0) this.update({ rate: 0 });
|
|
3734
|
+
break;
|
|
3735
|
+
case "volume":
|
|
3736
|
+
this.update({ muted: event.muted ?? this.state.muted, volume: event.volume ?? this.state.volume });
|
|
3737
|
+
break;
|
|
3738
|
+
case "rate":
|
|
3739
|
+
if (event.rate !== void 0) this.update({ rate: event.rate });
|
|
3740
|
+
break;
|
|
3741
|
+
case "ended":
|
|
3742
|
+
if (!this.state.loop) this.update({ rate: 0 });
|
|
3743
|
+
break;
|
|
3744
|
+
case "error":
|
|
3745
|
+
this.update({ failed: event.message ?? "error", rate: 0 });
|
|
3746
|
+
break;
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
update(changes) {
|
|
3750
|
+
this.state = { ...this.state, ...changes };
|
|
3751
|
+
for (const listener of this.listeners) listener();
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
function useAVPlayer(url = null, options = {}) {
|
|
3755
|
+
const ref = useRef(null);
|
|
3756
|
+
ref.current ??= new AVPlayer(url, options);
|
|
3757
|
+
const player = ref.current;
|
|
3758
|
+
useSyncExternalStore(player.subscribe, () => player.snapshot, () => player.snapshot);
|
|
3759
|
+
useEffect(() => {
|
|
3760
|
+
if (player.url !== url) player.replaceCurrentItem(url);
|
|
3761
|
+
}, [player, url]);
|
|
3762
|
+
return player;
|
|
3763
|
+
}
|
|
3764
|
+
function VideoPlayer(props) {
|
|
3765
|
+
const { own, modifiers } = splitProps(props);
|
|
3766
|
+
const player = own.player;
|
|
3767
|
+
const state = useSyncExternalStore(
|
|
3768
|
+
player?.subscribe ?? NO_SUBSCRIBE,
|
|
3769
|
+
() => player?.snapshot ?? null,
|
|
3770
|
+
() => player?.snapshot ?? null
|
|
3771
|
+
);
|
|
3772
|
+
if (!player || !state || !state.url) return applyModifiers(sb("color", { color: { r: 0, g: 0, b: 0, a: 1 } }), modifiers);
|
|
3773
|
+
const video = sb(
|
|
3774
|
+
"video",
|
|
3775
|
+
{
|
|
3776
|
+
url: state.url,
|
|
3777
|
+
playing: state.rate > 0 && !state.failed,
|
|
3778
|
+
muted: state.muted,
|
|
3779
|
+
volume: state.volume,
|
|
3780
|
+
rate: state.rate > 0 ? state.rate : 1,
|
|
3781
|
+
loop: state.loop,
|
|
3782
|
+
gravity: own.gravity ?? "resizeAspect",
|
|
3783
|
+
controls: own.controls ?? true,
|
|
3784
|
+
seek: state.seek,
|
|
3785
|
+
...state.size ? { width: state.size.width, height: state.size.height } : {}
|
|
3786
|
+
},
|
|
3787
|
+
{ video: (event) => player.handle(event) }
|
|
3788
|
+
);
|
|
3789
|
+
if (own.videoOverlay === void 0) return applyModifiers(video, modifiers);
|
|
3790
|
+
return applyModifiers(
|
|
3791
|
+
sb("zstack", { alignment: "center" }, void 0, [/* @__PURE__ */ jsx(Fragment$1, { children: video }, "video"), /* @__PURE__ */ jsx(Fragment$1, { children: own.videoOverlay }, "overlay")]),
|
|
3792
|
+
modifiers
|
|
3793
|
+
);
|
|
3794
|
+
}
|
|
3795
|
+
const NO_SUBSCRIBE = () => () => {
|
|
3796
|
+
};
|
|
3797
|
+
function PhaseAnimator({ phases, trigger, animation, children }) {
|
|
3798
|
+
const [index, setIndex] = useState(0);
|
|
3799
|
+
const hasTrigger = trigger !== void 0;
|
|
3800
|
+
const latest = useRef({ phases, animation });
|
|
3801
|
+
latest.current = { phases, animation };
|
|
3802
|
+
const first = useRef(true);
|
|
3803
|
+
useEffect(() => {
|
|
3804
|
+
if (hasTrigger && first.current) {
|
|
3805
|
+
first.current = false;
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
first.current = false;
|
|
3809
|
+
let cancelled = false;
|
|
3810
|
+
let timer;
|
|
3811
|
+
let step = 0;
|
|
3812
|
+
const count = latest.current.phases.length;
|
|
3813
|
+
if (count < 2) return;
|
|
3814
|
+
const advance = () => {
|
|
3815
|
+
if (cancelled) return;
|
|
3816
|
+
step += 1;
|
|
3817
|
+
const next = step % count;
|
|
3818
|
+
const { phases: current, animation: animationFor } = latest.current;
|
|
3819
|
+
const into = animationFor?.(current[next]) ?? { type: "default" };
|
|
3820
|
+
withAnimation(into, () => setIndex(next));
|
|
3821
|
+
if (hasTrigger && next === 0) return;
|
|
3822
|
+
const timing = timingFor(into);
|
|
3823
|
+
timer = setTimeout(advance, timing.duration + timing.delay);
|
|
3824
|
+
};
|
|
3825
|
+
timer = setTimeout(advance, 0);
|
|
3826
|
+
return () => {
|
|
3827
|
+
cancelled = true;
|
|
3828
|
+
if (timer) clearTimeout(timer);
|
|
3829
|
+
};
|
|
3830
|
+
}, [hasTrigger, trigger]);
|
|
3831
|
+
return children(phases[index % Math.max(phases.length, 1)]);
|
|
3832
|
+
}
|
|
3833
|
+
function ease(curve, t) {
|
|
3834
|
+
switch (curve) {
|
|
3835
|
+
case "move":
|
|
3836
|
+
return 1;
|
|
3837
|
+
case "cubic":
|
|
3838
|
+
return t * t * (3 - 2 * t);
|
|
3839
|
+
case "spring": {
|
|
3840
|
+
const omega = 7;
|
|
3841
|
+
return 1 - (1 + omega * t) * Math.exp(-omega * t);
|
|
3842
|
+
}
|
|
3843
|
+
default:
|
|
3844
|
+
return t;
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
function keyframeValues(initial, tracks, elapsed) {
|
|
3848
|
+
const value = { ...initial };
|
|
3849
|
+
for (const key of Object.keys(tracks)) {
|
|
3850
|
+
const frames = tracks[key] ?? [];
|
|
3851
|
+
let from = initial[key];
|
|
3852
|
+
let start = 0;
|
|
3853
|
+
let current = from;
|
|
3854
|
+
for (const frame2 of frames) {
|
|
3855
|
+
const end = start + frame2.duration;
|
|
3856
|
+
if (elapsed >= end) {
|
|
3857
|
+
current = frame2.to;
|
|
3858
|
+
} else {
|
|
3859
|
+
const t = frame2.duration > 0 ? Math.max(0, (elapsed - start) / frame2.duration) : 1;
|
|
3860
|
+
current = from + (frame2.to - from) * ease(frame2.curve ?? "spring", t);
|
|
3861
|
+
break;
|
|
3862
|
+
}
|
|
3863
|
+
from = frame2.to;
|
|
3864
|
+
start = end;
|
|
3865
|
+
}
|
|
3866
|
+
value[key] = current;
|
|
3867
|
+
}
|
|
3868
|
+
return value;
|
|
3869
|
+
}
|
|
3870
|
+
function totalDuration(tracks) {
|
|
3871
|
+
return Math.max(0, ...Object.values(tracks).map((frames) => (frames ?? []).reduce((sum, frame2) => sum + frame2.duration, 0)));
|
|
3872
|
+
}
|
|
3873
|
+
function KeyframeAnimator({
|
|
3874
|
+
initialValue,
|
|
3875
|
+
keyframes,
|
|
3876
|
+
trigger,
|
|
3877
|
+
repeating,
|
|
3878
|
+
children
|
|
3879
|
+
}) {
|
|
3880
|
+
const [value, setValue] = useState(initialValue);
|
|
3881
|
+
const latest = useRef({ initialValue, keyframes });
|
|
3882
|
+
latest.current = { initialValue, keyframes };
|
|
3883
|
+
const first = useRef(true);
|
|
3884
|
+
const hasTrigger = trigger !== void 0;
|
|
3885
|
+
useEffect(() => {
|
|
3886
|
+
if (hasTrigger && first.current) {
|
|
3887
|
+
first.current = false;
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
first.current = false;
|
|
3891
|
+
if (!hasTrigger && !repeating) return;
|
|
3892
|
+
let frame2 = 0;
|
|
3893
|
+
let start = null;
|
|
3894
|
+
const tick = (now) => {
|
|
3895
|
+
start ??= now;
|
|
3896
|
+
const { initialValue: initial, keyframes: tracks } = latest.current;
|
|
3897
|
+
const total = totalDuration(tracks);
|
|
3898
|
+
let elapsed = (now - start) / 1e3;
|
|
3899
|
+
if (!hasTrigger && repeating && total > 0) elapsed %= total;
|
|
3900
|
+
setValue(keyframeValues(initial, tracks, elapsed));
|
|
3901
|
+
if (hasTrigger && elapsed >= total) return;
|
|
3902
|
+
frame2 = requestAnimationFrame(tick);
|
|
3903
|
+
};
|
|
3904
|
+
frame2 = requestAnimationFrame(tick);
|
|
3905
|
+
return () => cancelAnimationFrame(frame2);
|
|
3906
|
+
}, [hasTrigger, trigger, repeating]);
|
|
3907
|
+
return children(value);
|
|
3908
|
+
}
|
|
3909
|
+
export {
|
|
3910
|
+
AVPlayer,
|
|
3911
|
+
AngularGradient,
|
|
3912
|
+
AreaMark,
|
|
3913
|
+
AsyncImage,
|
|
3914
|
+
BarMark,
|
|
3915
|
+
Button,
|
|
3916
|
+
Canvas,
|
|
3917
|
+
Capsule,
|
|
3918
|
+
Chart,
|
|
3919
|
+
Circle,
|
|
3920
|
+
Color,
|
|
3921
|
+
ColorPicker,
|
|
3922
|
+
ColorValues,
|
|
3923
|
+
ContainerRelativeShape,
|
|
3924
|
+
ContentUnavailableView,
|
|
3925
|
+
ControlGroup,
|
|
3926
|
+
DEFAULT_PADDING,
|
|
3927
|
+
DEFAULT_VIEW_SPACING,
|
|
3928
|
+
DatePicker,
|
|
3929
|
+
DisclosureGroup,
|
|
3930
|
+
Divider,
|
|
3931
|
+
EditButton,
|
|
3932
|
+
Ellipse,
|
|
3933
|
+
Font,
|
|
3934
|
+
ForEach,
|
|
3935
|
+
Form,
|
|
3936
|
+
Gauge,
|
|
3937
|
+
GeometryReader,
|
|
3938
|
+
GraphicsContext,
|
|
3939
|
+
Grid,
|
|
3940
|
+
GridItem,
|
|
3941
|
+
GridRow,
|
|
3942
|
+
Group,
|
|
3943
|
+
GroupBox,
|
|
3944
|
+
HStack,
|
|
3945
|
+
Host,
|
|
3946
|
+
Image$1 as Image,
|
|
3947
|
+
KeyframeAnimator,
|
|
3948
|
+
Label,
|
|
3949
|
+
LabeledContent,
|
|
3950
|
+
Layout,
|
|
3951
|
+
LazyHStack,
|
|
3952
|
+
LazyVGrid,
|
|
3953
|
+
LazyVStack,
|
|
3954
|
+
LineMark,
|
|
3955
|
+
LinearGradient,
|
|
3956
|
+
Link,
|
|
3957
|
+
List,
|
|
3958
|
+
Menu,
|
|
3959
|
+
NavigationLink,
|
|
3960
|
+
NavigationSplitView,
|
|
3961
|
+
NavigationStack,
|
|
3962
|
+
Path,
|
|
3963
|
+
PhaseAnimator,
|
|
3964
|
+
Picker,
|
|
3965
|
+
PointMark,
|
|
3966
|
+
ProgressView,
|
|
3967
|
+
RadialGradient,
|
|
3968
|
+
Rectangle,
|
|
3969
|
+
RoundedRectangle,
|
|
3970
|
+
Row,
|
|
3971
|
+
RuleMark,
|
|
3972
|
+
ScrollView,
|
|
3973
|
+
ScrollViewReader,
|
|
3974
|
+
Section,
|
|
3975
|
+
SecureField,
|
|
3976
|
+
Shape,
|
|
3977
|
+
ShareLink,
|
|
3978
|
+
Slider,
|
|
3979
|
+
Spacer,
|
|
3980
|
+
SplitSelectionContext,
|
|
3981
|
+
Stepper,
|
|
3982
|
+
SwiftUIView,
|
|
3983
|
+
Tab,
|
|
3984
|
+
TabView,
|
|
3985
|
+
Table,
|
|
3986
|
+
Text,
|
|
3987
|
+
TextEditor,
|
|
3988
|
+
TextField,
|
|
3989
|
+
TimelineView,
|
|
3990
|
+
Toggle,
|
|
3991
|
+
ToolbarItem,
|
|
3992
|
+
ToolbarItemGroup,
|
|
3993
|
+
UnevenRoundedRectangle,
|
|
3994
|
+
VStack,
|
|
3995
|
+
VideoPlayer,
|
|
3996
|
+
ViewThatFits,
|
|
3997
|
+
ZStack,
|
|
3998
|
+
answerLayout,
|
|
3999
|
+
color,
|
|
4000
|
+
createSwiftUIRoot,
|
|
4001
|
+
flattenChildren,
|
|
4002
|
+
font,
|
|
4003
|
+
frame,
|
|
4004
|
+
gradient,
|
|
4005
|
+
hex,
|
|
4006
|
+
insets,
|
|
4007
|
+
keyframeValues,
|
|
4008
|
+
mount,
|
|
4009
|
+
moveItems,
|
|
4010
|
+
niceStep,
|
|
4011
|
+
opacity,
|
|
4012
|
+
openURL,
|
|
4013
|
+
padding,
|
|
4014
|
+
placeholder,
|
|
4015
|
+
plainText,
|
|
4016
|
+
readBinding,
|
|
4017
|
+
rgb,
|
|
4018
|
+
shapeStyle,
|
|
4019
|
+
system,
|
|
4020
|
+
timeTicks,
|
|
4021
|
+
unitPoint,
|
|
4022
|
+
useAVPlayer,
|
|
4023
|
+
useColorScheme,
|
|
4024
|
+
useContextBridge,
|
|
4025
|
+
useCoordinateSpaces,
|
|
4026
|
+
useDismiss,
|
|
4027
|
+
useDynamicTypeSize,
|
|
4028
|
+
useHorizontalSizeClass,
|
|
4029
|
+
useNamespace,
|
|
4030
|
+
useNavigation,
|
|
4031
|
+
useRedacted,
|
|
4032
|
+
useRefreshable,
|
|
4033
|
+
useReportSplitSelection,
|
|
4034
|
+
useViewEnvironment,
|
|
4035
|
+
weighted,
|
|
4036
|
+
withAnimation
|
|
4037
|
+
};
|
|
4038
|
+
//# sourceMappingURL=index.js.map
|