@buoy-gg/shared-ui 7.0.32 → 7.0.33
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/lib/commonjs/JsModal.js +13 -6
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/storage/devToolsStorageKeys.js +12 -0
- package/lib/commonjs/ui/components/EmptyState.js +10 -2
- package/lib/commonjs/ui/components/ToolEmptyState.js +154 -0
- package/lib/commonjs/ui/components/WindowControls.js +8 -5
- package/lib/commonjs/ui/components/index.js +13 -0
- package/lib/commonjs/ui/index.js +12 -0
- package/lib/commonjs/ui/otto/OttoSprite.js +510 -0
- package/lib/commonjs/ui/otto/index.js +38 -0
- package/lib/commonjs/ui/otto/ottoEngine.js +2734 -0
- package/lib/commonjs/ui/otto/ottoSheet.js +191 -0
- package/lib/module/JsModal.js +13 -6
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/storage/devToolsStorageKeys.js +12 -0
- package/lib/module/ui/components/EmptyState.js +10 -2
- package/lib/module/ui/components/ToolEmptyState.js +149 -0
- package/lib/module/ui/components/WindowControls.js +8 -5
- package/lib/module/ui/components/index.js +3 -0
- package/lib/module/ui/index.js +4 -1
- package/lib/module/ui/otto/OttoSprite.js +496 -0
- package/lib/module/ui/otto/index.js +20 -0
- package/lib/module/ui/otto/ottoEngine.js +2726 -0
- package/lib/module/ui/otto/ottoSheet.js +180 -0
- package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +12 -0
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EmptyState.d.ts +14 -1
- package/lib/typescript/commonjs/ui/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ToolEmptyState.d.ts +113 -0
- package/lib/typescript/commonjs/ui/components/ToolEmptyState.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/WindowControls.d.ts +7 -1
- package/lib/typescript/commonjs/ui/components/WindowControls.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/index.d.ts +2 -0
- package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +1 -0
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/otto/OttoSprite.d.ts +103 -0
- package/lib/typescript/commonjs/ui/otto/OttoSprite.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/otto/index.d.ts +19 -0
- package/lib/typescript/commonjs/ui/otto/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/otto/ottoEngine.d.ts +2205 -0
- package/lib/typescript/commonjs/ui/otto/ottoEngine.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/otto/ottoSheet.d.ts +73 -0
- package/lib/typescript/commonjs/ui/otto/ottoSheet.d.ts.map +1 -0
- package/lib/typescript/module/JsModal.d.ts.map +1 -1
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +12 -0
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EmptyState.d.ts +14 -1
- package/lib/typescript/module/ui/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ToolEmptyState.d.ts +113 -0
- package/lib/typescript/module/ui/components/ToolEmptyState.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/WindowControls.d.ts +7 -1
- package/lib/typescript/module/ui/components/WindowControls.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/index.d.ts +2 -0
- package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +1 -0
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/otto/OttoSprite.d.ts +103 -0
- package/lib/typescript/module/ui/otto/OttoSprite.d.ts.map +1 -0
- package/lib/typescript/module/ui/otto/index.d.ts +19 -0
- package/lib/typescript/module/ui/otto/index.d.ts.map +1 -0
- package/lib/typescript/module/ui/otto/ottoEngine.d.ts +2205 -0
- package/lib/typescript/module/ui/otto/ottoEngine.d.ts.map +1 -0
- package/lib/typescript/module/ui/otto/ottoSheet.d.ts +73 -0
- package/lib/typescript/module/ui/otto/ottoSheet.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Otto = Otto;
|
|
7
|
+
exports.OttoMotionView = void 0;
|
|
8
|
+
exports.OttoPixels = OttoPixels;
|
|
9
|
+
exports.OttoStill = OttoStill;
|
|
10
|
+
Object.defineProperty(exports, "WATER_FRAMES", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _ottoSheet.WATER_FRAMES;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
exports.motionUnits = motionUnits;
|
|
17
|
+
exports.useOttoAnchorMotion = useOttoAnchorMotion;
|
|
18
|
+
exports.useOttoReel = useOttoReel;
|
|
19
|
+
var _react = require("react");
|
|
20
|
+
var _reactNative = require("react-native");
|
|
21
|
+
var _ottoEngine = require("./ottoEngine.js");
|
|
22
|
+
var _ottoSheet = require("./ottoSheet.js");
|
|
23
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
24
|
+
/**
|
|
25
|
+
* Otto in React Native — core APIs only, so the same file runs in Expo, in a
|
|
26
|
+
* bare RN CLI app, and on the web through react-native-web.
|
|
27
|
+
*
|
|
28
|
+
* <Otto state="thinking" pixelSize={4} /> the shipping sprite
|
|
29
|
+
* <Otto state="reel" /> plays the demo schedule
|
|
30
|
+
* <OttoStill pixelSize={1} /> frame 0, no clock (icons, stills)
|
|
31
|
+
* <OttoPixels grid={…} pixelSize={…} /> paint any frame as Views
|
|
32
|
+
* useOttoAnchorMotion(state, …) move a prop in lock-step with
|
|
33
|
+
* Otto's hands (the tool scenes)
|
|
34
|
+
*
|
|
35
|
+
* How the shipping sprite works (winner of the buoy-optimize rounds, see
|
|
36
|
+
* OTTO_PERF_PLAN.md): each layer of a state's animation is a STRIP of its
|
|
37
|
+
* distinct frames, mounted once as static Views (merged rectangles), inside
|
|
38
|
+
* an overflow-hidden window one frame wide. A clock slides the strip:
|
|
39
|
+
*
|
|
40
|
+
* native core `Animated` on the native driver — one looping linear timing
|
|
41
|
+
* mapped to strip offsets by a step interpolation
|
|
42
|
+
* web CSS keyframes with `step-end` timing (react-native-web's
|
|
43
|
+
* `animationKeyframes` style), the zero-JS path in a browser
|
|
44
|
+
*
|
|
45
|
+
* Zero JS per tick on both, no React commits, and it keeps moving while the
|
|
46
|
+
* JS thread is blocked — exactly when a "working" Otto is on screen. On the
|
|
47
|
+
* iOS sim: 60 UI / 59 JS FPS at one sprite (the page's own floor) where the
|
|
48
|
+
* old per-tick renderer dropped UI frames.
|
|
49
|
+
*
|
|
50
|
+
* ONE TIMEBASE. Body, water and any anchored prop derive from the same
|
|
51
|
+
* `units` span (see `motionUnits`) at the same duration and start in the same
|
|
52
|
+
* commit, so they can never drift out of phase with each other.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
const IS_WEB = _reactNative.Platform.OS === "web";
|
|
56
|
+
|
|
57
|
+
/** Every anchor in the engine repeats within 16 ticks. */
|
|
58
|
+
const ANCHOR_PERIOD = 16;
|
|
59
|
+
/** The water wave holds each frame for 2 ticks. */
|
|
60
|
+
const WATER_UNITS_PER_STEP = 2;
|
|
61
|
+
function gcd(a, b) {
|
|
62
|
+
return b === 0 ? a : gcd(b, a % b);
|
|
63
|
+
}
|
|
64
|
+
function lcm(a, b) {
|
|
65
|
+
return a * b / gcd(a, b);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The tick span every layer of a state loops over. It is a common multiple of
|
|
70
|
+
* the body cycle and the anchor cycle, so a prop held in Otto's hand and the
|
|
71
|
+
* hand itself repeat together.
|
|
72
|
+
*/
|
|
73
|
+
function motionUnits(state, keyline = true) {
|
|
74
|
+
return lcm((0, _ottoSheet.ottoSheets)(state, keyline).period, ANCHOR_PERIOD);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ---------------------------------------------------------------- pixels --
|
|
78
|
+
|
|
79
|
+
/** Pure renderer: a frame → coloured run Views. Fine for stills; costly per tick. */
|
|
80
|
+
function OttoPixels({
|
|
81
|
+
grid,
|
|
82
|
+
pixelSize,
|
|
83
|
+
style
|
|
84
|
+
}) {
|
|
85
|
+
const side = _ottoEngine.OTTO_GRID * pixelSize;
|
|
86
|
+
const runs = (0, _ottoEngine.ottoRuns)(grid);
|
|
87
|
+
const spans = [];
|
|
88
|
+
let rowY = -1;
|
|
89
|
+
let rowIndex = 0;
|
|
90
|
+
for (const r of runs) {
|
|
91
|
+
if (r.y !== rowY) {
|
|
92
|
+
rowY = r.y;
|
|
93
|
+
rowIndex = 0;
|
|
94
|
+
}
|
|
95
|
+
spans.push(/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
96
|
+
style: {
|
|
97
|
+
position: "absolute",
|
|
98
|
+
left: r.x * pixelSize,
|
|
99
|
+
top: r.y * pixelSize,
|
|
100
|
+
width: r.w * pixelSize,
|
|
101
|
+
height: pixelSize,
|
|
102
|
+
backgroundColor: r.color
|
|
103
|
+
}
|
|
104
|
+
}, `${r.y}:${rowIndex++}`));
|
|
105
|
+
}
|
|
106
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
107
|
+
pointerEvents: "none",
|
|
108
|
+
style: [{
|
|
109
|
+
width: side,
|
|
110
|
+
height: side
|
|
111
|
+
}, style],
|
|
112
|
+
children: spans
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ---------------------------------------------------------------- still ---
|
|
117
|
+
|
|
118
|
+
/** Frame 0 of a state, no clock — safe on screens that must not re-render. */
|
|
119
|
+
function OttoStill({
|
|
120
|
+
state = "static",
|
|
121
|
+
pixelSize = 1,
|
|
122
|
+
water,
|
|
123
|
+
keyline,
|
|
124
|
+
style
|
|
125
|
+
}) {
|
|
126
|
+
const grid = (0, _ottoEngine.renderOttoFrame)(state, 0, {
|
|
127
|
+
water,
|
|
128
|
+
keyline
|
|
129
|
+
});
|
|
130
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(OttoPixels, {
|
|
131
|
+
grid: grid,
|
|
132
|
+
pixelSize: pixelSize,
|
|
133
|
+
style: style
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ---------------------------------------------------------------- reel ----
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Walks the demo reel: which state plays now. One React state change per
|
|
141
|
+
* schedule entry (every few seconds), nothing per tick.
|
|
142
|
+
*/
|
|
143
|
+
function useOttoReel(enabled, tickMs = 140, active = true) {
|
|
144
|
+
const [idx, setIdx] = (0, _react.useState)(0);
|
|
145
|
+
(0, _react.useEffect)(() => {
|
|
146
|
+
if (!enabled || !active) return;
|
|
147
|
+
const len = _ottoEngine.OTTO_REEL[idx % _ottoEngine.OTTO_REEL.length][1];
|
|
148
|
+
const id = setTimeout(() => setIdx(i => (i + 1) % _ottoEngine.OTTO_REEL.length), len * tickMs);
|
|
149
|
+
return () => clearTimeout(id);
|
|
150
|
+
}, [enabled, active, idx, tickMs]);
|
|
151
|
+
return _ottoEngine.OTTO_REEL[idx % _ottoEngine.OTTO_REEL.length][0];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------- clock ---
|
|
155
|
+
|
|
156
|
+
/** A style that moves a view through offsets in lock-step with Otto's clock. */
|
|
157
|
+
|
|
158
|
+
const EPS = 0.0001;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The layer the clock moves.
|
|
162
|
+
*
|
|
163
|
+
* On native this has to be an `Animated.View` — it carries interpolated
|
|
164
|
+
* values. On web the motion is a COMPILED CSS class (see `webStepStyle`), and
|
|
165
|
+
* `Animated.View` flattens its style prop into a fresh object, which loses the
|
|
166
|
+
* identity react-native-web looks the compiled rules up by; the keyframes are
|
|
167
|
+
* then silently dropped and the sprite sits on frame 0. So the web path takes
|
|
168
|
+
* a plain View, which passes the class straight through.
|
|
169
|
+
*/
|
|
170
|
+
const OttoMotionView = exports.OttoMotionView = IS_WEB ? _reactNative.View : _reactNative.Animated.View;
|
|
171
|
+
/**
|
|
172
|
+
* Web keyframes, compiled once per motion pattern.
|
|
173
|
+
*
|
|
174
|
+
* react-native-web only turns `animationKeyframes` into real `@keyframes`
|
|
175
|
+
* rules through `StyleSheet.create` — its inline-style path drops the prop
|
|
176
|
+
* without a warning. Patterns repeat heavily across a page of sprites (every
|
|
177
|
+
* Otto shares one water wave, every state of a group shares body cycles), so
|
|
178
|
+
* the cache keeps the sheet small and the render cheap.
|
|
179
|
+
*/
|
|
180
|
+
const webStyleCache = new Map();
|
|
181
|
+
function webStepStyle(offsets, unitsPerStep, units, tickMs, steps, at) {
|
|
182
|
+
const key = `${units}/${unitsPerStep}/${tickMs}/${offsets.map(o => `${o.x},${o.y}`).join("|")}`;
|
|
183
|
+
const cached = webStyleCache.get(key);
|
|
184
|
+
if (cached) return cached;
|
|
185
|
+
|
|
186
|
+
// Keyframe blocks skip react-native-web's style preprocessor, so the value
|
|
187
|
+
// has to be CSS already — an RN transform ARRAY compiles to an empty block.
|
|
188
|
+
const css = o => `translateX(${o.x}px) translateY(${o.y}px)`;
|
|
189
|
+
const keyframes = {};
|
|
190
|
+
for (let k = 0; k < steps; k++) {
|
|
191
|
+
const pct = k * unitsPerStep / units * 100;
|
|
192
|
+
keyframes[`${pct.toFixed(4)}%`] = {
|
|
193
|
+
transform: css(at(k))
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
keyframes["100%"] = {
|
|
197
|
+
transform: css(at(steps - 1))
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// react-native-web's CSS-animation style props (not part of RN's ViewStyle).
|
|
201
|
+
const style = _reactNative.StyleSheet.create({
|
|
202
|
+
motion: {
|
|
203
|
+
animationKeyframes: [keyframes],
|
|
204
|
+
animationDuration: `${units * tickMs}ms`,
|
|
205
|
+
animationTimingFunction: "step-end",
|
|
206
|
+
animationIterationCount: "infinite",
|
|
207
|
+
animationFillMode: "both"
|
|
208
|
+
}
|
|
209
|
+
}).motion;
|
|
210
|
+
webStyleCache.set(key, style);
|
|
211
|
+
return style;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Otto's timebase: a clock that runs `units` ticks and loops.
|
|
216
|
+
*
|
|
217
|
+
* native → one `Animated.Value` on the native driver (zero JS per tick)
|
|
218
|
+
* web → nothing to drive; CSS keyframes carry the motion (zero JS at all)
|
|
219
|
+
*
|
|
220
|
+
* Every consumer of the SAME state builds the same `units` and duration and
|
|
221
|
+
* starts in the same commit, which is what keeps layers in phase.
|
|
222
|
+
*/
|
|
223
|
+
function useOttoMotionClock(units, tickMs, active, restartKey) {
|
|
224
|
+
const value = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
|
|
225
|
+
(0, _react.useEffect)(() => {
|
|
226
|
+
if (IS_WEB) return;
|
|
227
|
+
value.setValue(0);
|
|
228
|
+
if (!active) return;
|
|
229
|
+
const loop = _reactNative.Animated.loop(_reactNative.Animated.timing(value, {
|
|
230
|
+
toValue: units,
|
|
231
|
+
duration: units * tickMs,
|
|
232
|
+
easing: _reactNative.Easing.linear,
|
|
233
|
+
useNativeDriver: true,
|
|
234
|
+
isInteraction: false
|
|
235
|
+
}), {
|
|
236
|
+
resetBeforeIteration: true
|
|
237
|
+
});
|
|
238
|
+
loop.start();
|
|
239
|
+
return () => loop.stop();
|
|
240
|
+
}, [value, units, tickMs, active, restartKey]);
|
|
241
|
+
return value;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Turn a repeating offset pattern into a style on that clock. `offsets[k]` is
|
|
246
|
+
* where the view sits during tick `k·unitsPerStep`; the pattern repeats until
|
|
247
|
+
* `units` is filled, so patterns of different lengths share one timebase.
|
|
248
|
+
*/
|
|
249
|
+
function stepStyle(value, offsets, unitsPerStep, units, tickMs, active) {
|
|
250
|
+
const steps = Math.max(1, Math.round(units / unitsPerStep));
|
|
251
|
+
const at = k => offsets[k % offsets.length] ?? {
|
|
252
|
+
x: 0,
|
|
253
|
+
y: 0
|
|
254
|
+
};
|
|
255
|
+
if (!active || offsets.length <= 1) {
|
|
256
|
+
const o = at(0);
|
|
257
|
+
return {
|
|
258
|
+
transform: [{
|
|
259
|
+
translateX: o.x
|
|
260
|
+
}, {
|
|
261
|
+
translateY: o.y
|
|
262
|
+
}]
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (IS_WEB) return webStepStyle(offsets, unitsPerStep, units, tickMs, steps, at);
|
|
266
|
+
const inputRange = [];
|
|
267
|
+
const xs = [];
|
|
268
|
+
const ys = [];
|
|
269
|
+
for (let k = 0; k < steps; k++) {
|
|
270
|
+
const o = at(k);
|
|
271
|
+
inputRange.push(k * unitsPerStep, (k + 1) * unitsPerStep - EPS);
|
|
272
|
+
xs.push(o.x, o.x);
|
|
273
|
+
ys.push(o.y, o.y);
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
transform: [{
|
|
277
|
+
translateX: value.interpolate({
|
|
278
|
+
inputRange,
|
|
279
|
+
outputRange: xs,
|
|
280
|
+
extrapolate: "clamp"
|
|
281
|
+
})
|
|
282
|
+
}, {
|
|
283
|
+
translateY: value.interpolate({
|
|
284
|
+
inputRange,
|
|
285
|
+
outputRange: ys,
|
|
286
|
+
extrapolate: "clamp"
|
|
287
|
+
})
|
|
288
|
+
}]
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Move a prop in lock-step with Otto's hands. `OTTO_ANCHORS[state]` publishes
|
|
293
|
+
* where the hand is each tick; this turns that into the same kind of clocked
|
|
294
|
+
* style the sprite itself uses, on the same timebase, so the two can't drift.
|
|
295
|
+
*
|
|
296
|
+
* Returns `null` for a state that has no anchor.
|
|
297
|
+
*/
|
|
298
|
+
function useOttoAnchorMotion(state, pixelSize, tickMs = 140, active = true, keyline = true) {
|
|
299
|
+
const anchorFn = _ottoEngine.OTTO_ANCHORS[state];
|
|
300
|
+
const units = motionUnits(state, keyline);
|
|
301
|
+
const value = useOttoMotionClock(units, tickMs, active && !!anchorFn, state);
|
|
302
|
+
if (!anchorFn) return null;
|
|
303
|
+
const first = anchorFn(0);
|
|
304
|
+
const offsets = [];
|
|
305
|
+
for (let t = 0; t < ANCHOR_PERIOD; t++) {
|
|
306
|
+
const a = anchorFn(t);
|
|
307
|
+
offsets.push({
|
|
308
|
+
x: (a.x - first.x) * pixelSize,
|
|
309
|
+
y: (a.y - first.y) * pixelSize
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
style: stepStyle(value, offsets, 1, units, tickMs, active),
|
|
314
|
+
over: first.over,
|
|
315
|
+
origin: {
|
|
316
|
+
x: first.x,
|
|
317
|
+
y: first.y
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ---------------------------------------------------------------- otto ----
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* The shipping sprite.
|
|
326
|
+
*
|
|
327
|
+
* Mounting is deferred on purpose. The strips are ~500 static Views for a
|
|
328
|
+
* typical state, and creating those is native COMMIT cost: measured at 128 ms
|
|
329
|
+
* for one sprite, against 28 ms for a still. A mascot almost always appears
|
|
330
|
+
* while something else is animating (a panel opening, a list settling), and
|
|
331
|
+
* 128 ms of commit dropped into that is a visible hitch.
|
|
332
|
+
*
|
|
333
|
+
* So the first commit paints `OttoStill` — frame 0, ~36 Views, the exact
|
|
334
|
+
* pixels the animation starts on — and the strips mount once the interaction
|
|
335
|
+
* has settled (an idle callback). Nothing pops, because the still IS frame 0.
|
|
336
|
+
* Pass `eager` when the sprite is the thing the user is waiting for.
|
|
337
|
+
*
|
|
338
|
+
* The two layers are siblings that each gate themselves with `return null`
|
|
339
|
+
* rather than a ternary swap, so this component's child slots never change
|
|
340
|
+
* shape (Fabric view-index safety).
|
|
341
|
+
*/
|
|
342
|
+
function Otto({
|
|
343
|
+
state,
|
|
344
|
+
pixelSize = 8,
|
|
345
|
+
water = true,
|
|
346
|
+
keyline = true,
|
|
347
|
+
tickMs = 140,
|
|
348
|
+
active = true,
|
|
349
|
+
eager = false,
|
|
350
|
+
style
|
|
351
|
+
}) {
|
|
352
|
+
const reelState = useOttoReel(state === "reel", tickMs, active);
|
|
353
|
+
const resolved = state === "reel" ? reelState : state;
|
|
354
|
+
const side = _ottoEngine.OTTO_GRID * pixelSize;
|
|
355
|
+
const [mounted, setMounted] = (0, _react.useState)(eager);
|
|
356
|
+
(0, _react.useEffect)(() => {
|
|
357
|
+
if (eager || mounted) return;
|
|
358
|
+
// requestIdleCallback, not InteractionManager: RN 0.85 deprecates the
|
|
359
|
+
// latter and warns on every use, and this runs in every host we support.
|
|
360
|
+
// The setTimeout fallback covers runtimes without the idle callback.
|
|
361
|
+
const idle = globalThis.requestIdleCallback;
|
|
362
|
+
const cancelIdle = globalThis.cancelIdleCallback;
|
|
363
|
+
if (idle) {
|
|
364
|
+
const handle = idle(() => setMounted(true));
|
|
365
|
+
return () => cancelIdle?.(handle);
|
|
366
|
+
}
|
|
367
|
+
const timer = setTimeout(() => setMounted(true), 0);
|
|
368
|
+
return () => clearTimeout(timer);
|
|
369
|
+
}, [eager, mounted]);
|
|
370
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
371
|
+
pointerEvents: "none",
|
|
372
|
+
style: [{
|
|
373
|
+
width: side,
|
|
374
|
+
height: side
|
|
375
|
+
}, style],
|
|
376
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(OttoStillLayer, {
|
|
377
|
+
show: !mounted,
|
|
378
|
+
state: resolved,
|
|
379
|
+
pixelSize: pixelSize,
|
|
380
|
+
water: water,
|
|
381
|
+
keyline: keyline
|
|
382
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(OttoStrips, {
|
|
383
|
+
show: mounted,
|
|
384
|
+
state: resolved,
|
|
385
|
+
pixelSize: pixelSize,
|
|
386
|
+
water: water,
|
|
387
|
+
keyline: keyline,
|
|
388
|
+
tickMs: tickMs,
|
|
389
|
+
active: active
|
|
390
|
+
})]
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** Frame 0 while the strips are still coming. */
|
|
395
|
+
function OttoStillLayer({
|
|
396
|
+
show,
|
|
397
|
+
state,
|
|
398
|
+
pixelSize,
|
|
399
|
+
water,
|
|
400
|
+
keyline
|
|
401
|
+
}) {
|
|
402
|
+
if (!show) return null;
|
|
403
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(OttoStill, {
|
|
404
|
+
state: state,
|
|
405
|
+
pixelSize: pixelSize,
|
|
406
|
+
water: water,
|
|
407
|
+
keyline: keyline
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** The animated strips and their clock. */
|
|
412
|
+
function OttoStrips({
|
|
413
|
+
show,
|
|
414
|
+
state,
|
|
415
|
+
pixelSize,
|
|
416
|
+
water,
|
|
417
|
+
keyline,
|
|
418
|
+
tickMs,
|
|
419
|
+
active
|
|
420
|
+
}) {
|
|
421
|
+
const sheets = (0, _ottoSheet.ottoSheets)(state, keyline);
|
|
422
|
+
const side = _ottoEngine.OTTO_GRID * pixelSize;
|
|
423
|
+
const waterH = _ottoSheet.WATER_ROWS * pixelSize;
|
|
424
|
+
const units = lcm(sheets.period, ANCHOR_PERIOD);
|
|
425
|
+
const value = useOttoMotionClock(units, tickMs, active && show, state);
|
|
426
|
+
const bodyStyle = stepStyle(value, stripOffsets(sheets.body, side), 1, units, tickMs, active);
|
|
427
|
+
const waterStyle = stepStyle(value, stripOffsets(sheets.water, side), WATER_UNITS_PER_STEP, units, tickMs, active);
|
|
428
|
+
if (!show) return null;
|
|
429
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
430
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(StripWindow, {
|
|
431
|
+
top: _ottoSheet.WATER_ROW0 * pixelSize,
|
|
432
|
+
width: side,
|
|
433
|
+
height: waterH,
|
|
434
|
+
strip: sheets.water,
|
|
435
|
+
px: pixelSize,
|
|
436
|
+
frameW: side,
|
|
437
|
+
motion: waterStyle,
|
|
438
|
+
visible: water
|
|
439
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(StripWindow, {
|
|
440
|
+
top: 0,
|
|
441
|
+
width: side,
|
|
442
|
+
height: side,
|
|
443
|
+
strip: sheets.body,
|
|
444
|
+
px: pixelSize,
|
|
445
|
+
frameW: side,
|
|
446
|
+
motion: bodyStyle,
|
|
447
|
+
visible: true
|
|
448
|
+
})]
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
function stripOffsets(strip, frameW) {
|
|
452
|
+
return strip.colOf.map(c => ({
|
|
453
|
+
x: -c * frameW,
|
|
454
|
+
y: 0
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
457
|
+
/** Pure UI: an overflow-hidden window over a strip of frames. */
|
|
458
|
+
function StripWindow({
|
|
459
|
+
top,
|
|
460
|
+
width,
|
|
461
|
+
height,
|
|
462
|
+
strip,
|
|
463
|
+
px,
|
|
464
|
+
frameW,
|
|
465
|
+
motion,
|
|
466
|
+
visible
|
|
467
|
+
}) {
|
|
468
|
+
const stripW = strip.frames.length * frameW;
|
|
469
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
470
|
+
style: {
|
|
471
|
+
position: "absolute",
|
|
472
|
+
left: 0,
|
|
473
|
+
top,
|
|
474
|
+
width,
|
|
475
|
+
height,
|
|
476
|
+
overflow: "hidden"
|
|
477
|
+
},
|
|
478
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(OttoMotionView, {
|
|
479
|
+
style: [{
|
|
480
|
+
width: stripW,
|
|
481
|
+
height
|
|
482
|
+
}, motion],
|
|
483
|
+
children: visible ? strip.frames.map((rects, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(FrameViews, {
|
|
484
|
+
rects: rects,
|
|
485
|
+
px: px,
|
|
486
|
+
offsetX: i * frameW
|
|
487
|
+
}, i)) : null
|
|
488
|
+
})
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** One frame as absolutely positioned rectangle Views. Static after mount. */
|
|
493
|
+
function FrameViews({
|
|
494
|
+
rects,
|
|
495
|
+
px,
|
|
496
|
+
offsetX
|
|
497
|
+
}) {
|
|
498
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
499
|
+
children: rects.map((r, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
500
|
+
style: {
|
|
501
|
+
position: "absolute",
|
|
502
|
+
left: offsetX + r.x * px,
|
|
503
|
+
top: r.y * px,
|
|
504
|
+
width: r.w * px,
|
|
505
|
+
height: r.h * px,
|
|
506
|
+
backgroundColor: r.color
|
|
507
|
+
}
|
|
508
|
+
}, i))
|
|
509
|
+
});
|
|
510
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _ottoEngine = require("./ottoEngine.js");
|
|
7
|
+
Object.keys(_ottoEngine).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _ottoEngine[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _ottoEngine[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
var _ottoSheet = require("./ottoSheet.js");
|
|
18
|
+
Object.keys(_ottoSheet).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _ottoSheet[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _ottoSheet[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
var _OttoSprite = require("./OttoSprite.js");
|
|
29
|
+
Object.keys(_OttoSprite).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _OttoSprite[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () {
|
|
35
|
+
return _OttoSprite[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|