@entropy-softworks/ui 2026.8.36 → 2026.8.37
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/components/index.d.ts +1 -0
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js +1 -0
- package/lib/components/index.js.map +1 -1
- package/lib/components/update-overlay.d.ts +41 -0
- package/lib/components/update-overlay.d.ts.map +1 -0
- package/lib/components/update-overlay.jsx +132 -0
- package/lib/components/update-overlay.jsx.map +1 -0
- package/package.json +1 -1
- package/src/components/index.ts +1 -0
- package/src/components/update-overlay.tsx +206 -0
|
@@ -8,6 +8,7 @@ export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuIte
|
|
|
8
8
|
export { EntropyMark, EntropyByline, ENTROPY_MARK_VIEWBOX, ENTROPY_MARK_ASPECT, ENTROPY_MARK_PATH, ENTROPY_MARK_STEP, type EntropyMarkProps, type EntropyBylineProps, } from "./entropy-mark";
|
|
9
9
|
export { EntropyBootSplash, type EntropyBootSplashProps } from "./entropy-boot-splash";
|
|
10
10
|
export { EntropyMarkAnimated, type EntropyMarkAnimatedProps } from "./entropy-mark-animated";
|
|
11
|
+
export { UpdateOverlay, type UpdateOverlayProps } from "./update-overlay";
|
|
11
12
|
export { EntropyMarkSequential, type EntropyMarkSequentialProps } from "./entropy-mark-sequential";
|
|
12
13
|
export { ErrorBoundary } from "./error-boundary";
|
|
13
14
|
export { Input, SearchInput, EmailInput, PasswordInput, TextArea, type InputProps } from "./input";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,EACL,IAAI,EACJ,UAAU,EACV,WAAW,EACX,UAAU,EACV,SAAS,EACT,eAAe,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5F,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
package/lib/components/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuIte
|
|
|
10
10
|
export { EntropyMark, EntropyByline, ENTROPY_MARK_VIEWBOX, ENTROPY_MARK_ASPECT, ENTROPY_MARK_PATH, ENTROPY_MARK_STEP, } from "./entropy-mark";
|
|
11
11
|
export { EntropyBootSplash } from "./entropy-boot-splash";
|
|
12
12
|
export { EntropyMarkAnimated } from "./entropy-mark-animated";
|
|
13
|
+
export { UpdateOverlay } from "./update-overlay";
|
|
13
14
|
export { EntropyMarkSequential } from "./entropy-mark-sequential";
|
|
14
15
|
export { ErrorBoundary } from "./error-boundary";
|
|
15
16
|
export { Input, SearchInput, EmailInput, PasswordInput, TextArea } from "./input";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,uDAAuD;AAEvD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAoB,MAAM,UAAU,CAAC;AAEhE,OAAO,EACL,IAAI,EACJ,UAAU,EACV,WAAW,EACX,UAAU,EACV,SAAS,EACT,eAAe,GAIhB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,GAIlB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5F,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAGlB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAA+B,MAAM,uBAAuB,CAAC;AAEvF,OAAO,EAAE,mBAAmB,EAAiC,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface UpdateOverlayProps {
|
|
3
|
+
/** "downloading" shows a progress-aware label; "restarting" is the moment
|
|
4
|
+
* between a finished download and the reload call that applies it. */
|
|
5
|
+
phase: "downloading" | "restarting";
|
|
6
|
+
/** 0-1, and only meaningful while downloading. Undefined when the update
|
|
7
|
+
* server sent no Content-Length for expo-updates to compute it from, which
|
|
8
|
+
* is why the percentage renders conditionally rather than defaulting to 0 —
|
|
9
|
+
* a "0%" that never moves reads as a stall. */
|
|
10
|
+
progress?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Glyph shown inside the ring. Defaults to the Entropy mark.
|
|
13
|
+
*
|
|
14
|
+
* A slot rather than a name or an icon set, because the consumers genuinely
|
|
15
|
+
* differ: vault shows its own product mark, wheatley and glados show the
|
|
16
|
+
* shared one. Whatever is passed must not derive its colour from the theme,
|
|
17
|
+
* for the reason in the header — pass an explicit ink.
|
|
18
|
+
*/
|
|
19
|
+
mark?: React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Force a colour scheme instead of following the system.
|
|
22
|
+
*
|
|
23
|
+
* Dark-only apps pass `"dark"`: without it the overlay would follow a light
|
|
24
|
+
* system setting and render a white flash before a dark app.
|
|
25
|
+
*/
|
|
26
|
+
scheme?: "light" | "dark";
|
|
27
|
+
/**
|
|
28
|
+
* Ground colour override.
|
|
29
|
+
*
|
|
30
|
+
* Defaults to the palette's own background. Worth setting when the native
|
|
31
|
+
* splash and window background use a specific value — matching it makes the
|
|
32
|
+
* overlay read as a continuation of the launch rather than a second screen.
|
|
33
|
+
*/
|
|
34
|
+
background?: string;
|
|
35
|
+
/** Label under the ring while downloading. */
|
|
36
|
+
downloadingLabel?: string;
|
|
37
|
+
/** Label under the ring while restarting. */
|
|
38
|
+
restartingLabel?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function UpdateOverlay({ phase, progress, mark, scheme, background, downloadingLabel, restartingLabel, }: UpdateOverlayProps): React.JSX.Element;
|
|
41
|
+
//# sourceMappingURL=update-overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-overlay.d.ts","sourceRoot":"","sources":["../../src/components/update-overlay.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,MAAM,WAAW,kBAAkB;IACjC;2EACuE;IACvE,KAAK,EAAE,aAAa,GAAG,YAAY,CAAC;IACpC;;;oDAGgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAuBD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,UAAU,EACV,gBAAuC,EACvC,eAA+B,GAChC,EAAE,kBAAkB,qBAuDpB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Full-screen overlay shown while an EAS Update downloads and applies.
|
|
2
|
+
//
|
|
3
|
+
// It exists because of what expo-updates does by DEFAULT, which is nothing
|
|
4
|
+
// visible. `fallbackToCacheTimeout: 0` means the app launches from the cached
|
|
5
|
+
// bundle immediately, fetches any new update in the background, and applies it
|
|
6
|
+
// on the NEXT cold start — so a tester relaunches once, sees the old build,
|
|
7
|
+
// relaunches again, and sees the new one. Every app here reacts to the pending
|
|
8
|
+
// update by reloading straight away instead; this component is what turns the
|
|
9
|
+
// resulting pause into a visible, explained wait rather than the app appearing
|
|
10
|
+
// to hang.
|
|
11
|
+
//
|
|
12
|
+
// # Why this is in the shared package
|
|
13
|
+
//
|
|
14
|
+
// It was written in vault, ported by hand into wheatley and glados, and then
|
|
15
|
+
// FIXED in the ports while vault kept the bug (see the colour note below).
|
|
16
|
+
// Three copies, one of which was wrong, of a component whose entire job is to
|
|
17
|
+
// render correctly in the worst conditions the app ever has. Sharing it is how
|
|
18
|
+
// the next fix reaches all three.
|
|
19
|
+
//
|
|
20
|
+
// # Every colour is a literal, and that is the fix
|
|
21
|
+
//
|
|
22
|
+
// This renders while the app is NOT ready — during a cold start whose update
|
|
23
|
+
// is still downloading, and during the reload that applies it. NativeWind's
|
|
24
|
+
// `dark:` variant and theme tokens like `text-foreground` only resolve once the
|
|
25
|
+
// provider tree has mounted and run its effects, which by definition has not
|
|
26
|
+
// happened yet. Asking the theme produced light-mode ink on a dark ground: an
|
|
27
|
+
// invisible label on what the user reads as a black screen. Observed for real
|
|
28
|
+
// on Android in both wheatley (2026-08-23) and vault (2026-08-29).
|
|
29
|
+
//
|
|
30
|
+
// The values ARE the palettes' own — this matches the theme, it just does not
|
|
31
|
+
// ask it. An overlay whose whole job is to render before the app is ready
|
|
32
|
+
// cannot depend on app state to be legible.
|
|
33
|
+
//
|
|
34
|
+
// reanimated rather than RN's `Animated`, matching the animation convention in
|
|
35
|
+
// every consumer.
|
|
36
|
+
import * as React from "react";
|
|
37
|
+
import { StyleSheet, Text, View, useColorScheme } from "react-native";
|
|
38
|
+
import Animated, { Easing, useAnimatedStyle, useSharedValue, withRepeat, withTiming, } from "react-native-reanimated";
|
|
39
|
+
import { EntropyMark } from "./entropy-mark";
|
|
40
|
+
/** How long one full turn takes. Slow enough to read as deliberate, fast
|
|
41
|
+
* enough to look like work rather than a frozen frame. */
|
|
42
|
+
const SPIN_MS = 1100;
|
|
43
|
+
const PALETTE = {
|
|
44
|
+
dark: {
|
|
45
|
+
ground: "#000000",
|
|
46
|
+
ink: "#EBEFEB",
|
|
47
|
+
muted: "#A3A3A3",
|
|
48
|
+
track: "#262626",
|
|
49
|
+
arc: "#FFFFFF",
|
|
50
|
+
},
|
|
51
|
+
light: {
|
|
52
|
+
ground: "#FFFFFF",
|
|
53
|
+
ink: "#0A0A0A",
|
|
54
|
+
muted: "#737373",
|
|
55
|
+
track: "#E5E5E5",
|
|
56
|
+
arc: "#000000",
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
export function UpdateOverlay({ phase, progress, mark, scheme, background, downloadingLabel = "Installing update…", restartingLabel = "Restarting…", }) {
|
|
60
|
+
// RN's own hook, not NativeWind's: this has to work before the NativeWind
|
|
61
|
+
// provider has done anything, which is the entire premise of the component.
|
|
62
|
+
const system = useColorScheme();
|
|
63
|
+
const isDark = (scheme ?? system) !== "light";
|
|
64
|
+
const c = isDark ? PALETTE.dark : PALETTE.light;
|
|
65
|
+
const rotation = useSharedValue(0);
|
|
66
|
+
// Started on mount rather than gated on a `visible` prop: the caller renders
|
|
67
|
+
// this conditionally, so mounting IS becoming visible, and a prop would be a
|
|
68
|
+
// second source of truth for the same fact.
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
rotation.value = withRepeat(withTiming(360, { duration: SPIN_MS, easing: Easing.linear }), -1, false);
|
|
71
|
+
}, [rotation]);
|
|
72
|
+
const ringStyle = useAnimatedStyle(() => ({
|
|
73
|
+
transform: [{ rotate: `${rotation.value}deg` }],
|
|
74
|
+
}));
|
|
75
|
+
return (<View style={[StyleSheet.absoluteFill, styles.ground, { backgroundColor: background ?? c.ground }]}
|
|
76
|
+
// Announced as one modal thing rather than as its parts: a screen reader
|
|
77
|
+
// reading "Installing update" then "43%" as separate nodes during a
|
|
78
|
+
// two-second wait is noise, and the percentage is decoration on top of
|
|
79
|
+
// the label rather than information of its own.
|
|
80
|
+
accessibilityViewIsModal accessibilityLabel={phase === "downloading" ? downloadingLabel : restartingLabel}>
|
|
81
|
+
<View style={styles.markWell}>
|
|
82
|
+
<Animated.View style={[
|
|
83
|
+
ringStyle,
|
|
84
|
+
styles.ring,
|
|
85
|
+
// The track, then one lit arc. A single contrasting border-top is
|
|
86
|
+
// what makes a plain rotation read as a spinner — a uniform ring
|
|
87
|
+
// rotating is indistinguishable from a static one.
|
|
88
|
+
{ borderColor: c.track, borderTopColor: c.arc },
|
|
89
|
+
]}/>
|
|
90
|
+
{mark ?? <EntropyMark size={32} variant="chroma"/>}
|
|
91
|
+
</View>
|
|
92
|
+
<Text style={[styles.label, { color: c.ink }]}>
|
|
93
|
+
{phase === "downloading" ? downloadingLabel : restartingLabel}
|
|
94
|
+
</Text>
|
|
95
|
+
{phase === "downloading" && typeof progress === "number" ? (<Text style={[styles.progress, { color: c.muted }]}>{Math.round(progress * 100)}%</Text>) : null}
|
|
96
|
+
</View>);
|
|
97
|
+
}
|
|
98
|
+
// StyleSheet rather than className throughout, deliberately: NativeWind classes
|
|
99
|
+
// resolve through the same provider this component cannot wait for. Plain RN
|
|
100
|
+
// styles are the only thing guaranteed to apply here. The ring also needs
|
|
101
|
+
// concrete numbers that agree with each other (a 72px box, a 36px radius, one
|
|
102
|
+
// 3px border), and its transform comes from an animated style anyway.
|
|
103
|
+
const styles = StyleSheet.create({
|
|
104
|
+
ground: {
|
|
105
|
+
alignItems: "center",
|
|
106
|
+
justifyContent: "center",
|
|
107
|
+
// Both, not either: zIndex orders within the JS view hierarchy and
|
|
108
|
+
// elevation is what Android's native compositor honours. A high zIndex
|
|
109
|
+
// alone can still be drawn under an elevated sibling.
|
|
110
|
+
zIndex: 10000,
|
|
111
|
+
elevation: 10000,
|
|
112
|
+
},
|
|
113
|
+
markWell: {
|
|
114
|
+
width: 72,
|
|
115
|
+
height: 72,
|
|
116
|
+
alignItems: "center",
|
|
117
|
+
justifyContent: "center",
|
|
118
|
+
},
|
|
119
|
+
ring: {
|
|
120
|
+
position: "absolute",
|
|
121
|
+
width: 72,
|
|
122
|
+
height: 72,
|
|
123
|
+
borderRadius: 36,
|
|
124
|
+
borderWidth: 3,
|
|
125
|
+
},
|
|
126
|
+
// No font family: the overlay can render before the app's fonts have loaded,
|
|
127
|
+
// and naming one that is not there yet gives a blank label rather than a
|
|
128
|
+
// system-font fallback.
|
|
129
|
+
label: { marginTop: 20, fontSize: 16, fontWeight: "500" },
|
|
130
|
+
progress: { marginTop: 4, fontSize: 12 },
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=update-overlay.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-overlay.jsx","sourceRoot":"","sources":["../../src/components/update-overlay.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/components/index.ts
CHANGED
|
@@ -61,6 +61,7 @@ export {
|
|
|
61
61
|
export { EntropyBootSplash, type EntropyBootSplashProps } from "./entropy-boot-splash";
|
|
62
62
|
|
|
63
63
|
export { EntropyMarkAnimated, type EntropyMarkAnimatedProps } from "./entropy-mark-animated";
|
|
64
|
+
export { UpdateOverlay, type UpdateOverlayProps } from "./update-overlay";
|
|
64
65
|
|
|
65
66
|
export { EntropyMarkSequential, type EntropyMarkSequentialProps } from "./entropy-mark-sequential";
|
|
66
67
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// Full-screen overlay shown while an EAS Update downloads and applies.
|
|
2
|
+
//
|
|
3
|
+
// It exists because of what expo-updates does by DEFAULT, which is nothing
|
|
4
|
+
// visible. `fallbackToCacheTimeout: 0` means the app launches from the cached
|
|
5
|
+
// bundle immediately, fetches any new update in the background, and applies it
|
|
6
|
+
// on the NEXT cold start — so a tester relaunches once, sees the old build,
|
|
7
|
+
// relaunches again, and sees the new one. Every app here reacts to the pending
|
|
8
|
+
// update by reloading straight away instead; this component is what turns the
|
|
9
|
+
// resulting pause into a visible, explained wait rather than the app appearing
|
|
10
|
+
// to hang.
|
|
11
|
+
//
|
|
12
|
+
// # Why this is in the shared package
|
|
13
|
+
//
|
|
14
|
+
// It was written in vault, ported by hand into wheatley and glados, and then
|
|
15
|
+
// FIXED in the ports while vault kept the bug (see the colour note below).
|
|
16
|
+
// Three copies, one of which was wrong, of a component whose entire job is to
|
|
17
|
+
// render correctly in the worst conditions the app ever has. Sharing it is how
|
|
18
|
+
// the next fix reaches all three.
|
|
19
|
+
//
|
|
20
|
+
// # Every colour is a literal, and that is the fix
|
|
21
|
+
//
|
|
22
|
+
// This renders while the app is NOT ready — during a cold start whose update
|
|
23
|
+
// is still downloading, and during the reload that applies it. NativeWind's
|
|
24
|
+
// `dark:` variant and theme tokens like `text-foreground` only resolve once the
|
|
25
|
+
// provider tree has mounted and run its effects, which by definition has not
|
|
26
|
+
// happened yet. Asking the theme produced light-mode ink on a dark ground: an
|
|
27
|
+
// invisible label on what the user reads as a black screen. Observed for real
|
|
28
|
+
// on Android in both wheatley (2026-08-23) and vault (2026-08-29).
|
|
29
|
+
//
|
|
30
|
+
// The values ARE the palettes' own — this matches the theme, it just does not
|
|
31
|
+
// ask it. An overlay whose whole job is to render before the app is ready
|
|
32
|
+
// cannot depend on app state to be legible.
|
|
33
|
+
//
|
|
34
|
+
// reanimated rather than RN's `Animated`, matching the animation convention in
|
|
35
|
+
// every consumer.
|
|
36
|
+
import * as React from "react";
|
|
37
|
+
import { StyleSheet, Text, View, useColorScheme } from "react-native";
|
|
38
|
+
import Animated, {
|
|
39
|
+
Easing,
|
|
40
|
+
useAnimatedStyle,
|
|
41
|
+
useSharedValue,
|
|
42
|
+
withRepeat,
|
|
43
|
+
withTiming,
|
|
44
|
+
} from "react-native-reanimated";
|
|
45
|
+
|
|
46
|
+
import { EntropyMark } from "./entropy-mark";
|
|
47
|
+
|
|
48
|
+
export interface UpdateOverlayProps {
|
|
49
|
+
/** "downloading" shows a progress-aware label; "restarting" is the moment
|
|
50
|
+
* between a finished download and the reload call that applies it. */
|
|
51
|
+
phase: "downloading" | "restarting";
|
|
52
|
+
/** 0-1, and only meaningful while downloading. Undefined when the update
|
|
53
|
+
* server sent no Content-Length for expo-updates to compute it from, which
|
|
54
|
+
* is why the percentage renders conditionally rather than defaulting to 0 —
|
|
55
|
+
* a "0%" that never moves reads as a stall. */
|
|
56
|
+
progress?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Glyph shown inside the ring. Defaults to the Entropy mark.
|
|
59
|
+
*
|
|
60
|
+
* A slot rather than a name or an icon set, because the consumers genuinely
|
|
61
|
+
* differ: vault shows its own product mark, wheatley and glados show the
|
|
62
|
+
* shared one. Whatever is passed must not derive its colour from the theme,
|
|
63
|
+
* for the reason in the header — pass an explicit ink.
|
|
64
|
+
*/
|
|
65
|
+
mark?: React.ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* Force a colour scheme instead of following the system.
|
|
68
|
+
*
|
|
69
|
+
* Dark-only apps pass `"dark"`: without it the overlay would follow a light
|
|
70
|
+
* system setting and render a white flash before a dark app.
|
|
71
|
+
*/
|
|
72
|
+
scheme?: "light" | "dark";
|
|
73
|
+
/**
|
|
74
|
+
* Ground colour override.
|
|
75
|
+
*
|
|
76
|
+
* Defaults to the palette's own background. Worth setting when the native
|
|
77
|
+
* splash and window background use a specific value — matching it makes the
|
|
78
|
+
* overlay read as a continuation of the launch rather than a second screen.
|
|
79
|
+
*/
|
|
80
|
+
background?: string;
|
|
81
|
+
/** Label under the ring while downloading. */
|
|
82
|
+
downloadingLabel?: string;
|
|
83
|
+
/** Label under the ring while restarting. */
|
|
84
|
+
restartingLabel?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** How long one full turn takes. Slow enough to read as deliberate, fast
|
|
88
|
+
* enough to look like work rather than a frozen frame. */
|
|
89
|
+
const SPIN_MS = 1100;
|
|
90
|
+
|
|
91
|
+
const PALETTE = {
|
|
92
|
+
dark: {
|
|
93
|
+
ground: "#000000",
|
|
94
|
+
ink: "#EBEFEB",
|
|
95
|
+
muted: "#A3A3A3",
|
|
96
|
+
track: "#262626",
|
|
97
|
+
arc: "#FFFFFF",
|
|
98
|
+
},
|
|
99
|
+
light: {
|
|
100
|
+
ground: "#FFFFFF",
|
|
101
|
+
ink: "#0A0A0A",
|
|
102
|
+
muted: "#737373",
|
|
103
|
+
track: "#E5E5E5",
|
|
104
|
+
arc: "#000000",
|
|
105
|
+
},
|
|
106
|
+
} as const;
|
|
107
|
+
|
|
108
|
+
export function UpdateOverlay({
|
|
109
|
+
phase,
|
|
110
|
+
progress,
|
|
111
|
+
mark,
|
|
112
|
+
scheme,
|
|
113
|
+
background,
|
|
114
|
+
downloadingLabel = "Installing update…",
|
|
115
|
+
restartingLabel = "Restarting…",
|
|
116
|
+
}: UpdateOverlayProps) {
|
|
117
|
+
// RN's own hook, not NativeWind's: this has to work before the NativeWind
|
|
118
|
+
// provider has done anything, which is the entire premise of the component.
|
|
119
|
+
const system = useColorScheme();
|
|
120
|
+
const isDark = (scheme ?? system) !== "light";
|
|
121
|
+
const c = isDark ? PALETTE.dark : PALETTE.light;
|
|
122
|
+
|
|
123
|
+
const rotation = useSharedValue(0);
|
|
124
|
+
|
|
125
|
+
// Started on mount rather than gated on a `visible` prop: the caller renders
|
|
126
|
+
// this conditionally, so mounting IS becoming visible, and a prop would be a
|
|
127
|
+
// second source of truth for the same fact.
|
|
128
|
+
React.useEffect(() => {
|
|
129
|
+
rotation.value = withRepeat(
|
|
130
|
+
withTiming(360, { duration: SPIN_MS, easing: Easing.linear }),
|
|
131
|
+
-1,
|
|
132
|
+
false
|
|
133
|
+
);
|
|
134
|
+
}, [rotation]);
|
|
135
|
+
|
|
136
|
+
const ringStyle = useAnimatedStyle(() => ({
|
|
137
|
+
transform: [{ rotate: `${rotation.value}deg` }],
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<View
|
|
142
|
+
style={[StyleSheet.absoluteFill, styles.ground, { backgroundColor: background ?? c.ground }]}
|
|
143
|
+
// Announced as one modal thing rather than as its parts: a screen reader
|
|
144
|
+
// reading "Installing update" then "43%" as separate nodes during a
|
|
145
|
+
// two-second wait is noise, and the percentage is decoration on top of
|
|
146
|
+
// the label rather than information of its own.
|
|
147
|
+
accessibilityViewIsModal
|
|
148
|
+
accessibilityLabel={phase === "downloading" ? downloadingLabel : restartingLabel}
|
|
149
|
+
>
|
|
150
|
+
<View style={styles.markWell}>
|
|
151
|
+
<Animated.View
|
|
152
|
+
style={[
|
|
153
|
+
ringStyle,
|
|
154
|
+
styles.ring,
|
|
155
|
+
// The track, then one lit arc. A single contrasting border-top is
|
|
156
|
+
// what makes a plain rotation read as a spinner — a uniform ring
|
|
157
|
+
// rotating is indistinguishable from a static one.
|
|
158
|
+
{ borderColor: c.track, borderTopColor: c.arc },
|
|
159
|
+
]}
|
|
160
|
+
/>
|
|
161
|
+
{mark ?? <EntropyMark size={32} variant="chroma" />}
|
|
162
|
+
</View>
|
|
163
|
+
<Text style={[styles.label, { color: c.ink }]}>
|
|
164
|
+
{phase === "downloading" ? downloadingLabel : restartingLabel}
|
|
165
|
+
</Text>
|
|
166
|
+
{phase === "downloading" && typeof progress === "number" ? (
|
|
167
|
+
<Text style={[styles.progress, { color: c.muted }]}>{Math.round(progress * 100)}%</Text>
|
|
168
|
+
) : null}
|
|
169
|
+
</View>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// StyleSheet rather than className throughout, deliberately: NativeWind classes
|
|
174
|
+
// resolve through the same provider this component cannot wait for. Plain RN
|
|
175
|
+
// styles are the only thing guaranteed to apply here. The ring also needs
|
|
176
|
+
// concrete numbers that agree with each other (a 72px box, a 36px radius, one
|
|
177
|
+
// 3px border), and its transform comes from an animated style anyway.
|
|
178
|
+
const styles = StyleSheet.create({
|
|
179
|
+
ground: {
|
|
180
|
+
alignItems: "center",
|
|
181
|
+
justifyContent: "center",
|
|
182
|
+
// Both, not either: zIndex orders within the JS view hierarchy and
|
|
183
|
+
// elevation is what Android's native compositor honours. A high zIndex
|
|
184
|
+
// alone can still be drawn under an elevated sibling.
|
|
185
|
+
zIndex: 10000,
|
|
186
|
+
elevation: 10000,
|
|
187
|
+
},
|
|
188
|
+
markWell: {
|
|
189
|
+
width: 72,
|
|
190
|
+
height: 72,
|
|
191
|
+
alignItems: "center",
|
|
192
|
+
justifyContent: "center",
|
|
193
|
+
},
|
|
194
|
+
ring: {
|
|
195
|
+
position: "absolute",
|
|
196
|
+
width: 72,
|
|
197
|
+
height: 72,
|
|
198
|
+
borderRadius: 36,
|
|
199
|
+
borderWidth: 3,
|
|
200
|
+
},
|
|
201
|
+
// No font family: the overlay can render before the app's fonts have loaded,
|
|
202
|
+
// and naming one that is not there yet gives a blank label rather than a
|
|
203
|
+
// system-font fallback.
|
|
204
|
+
label: { marginTop: 20, fontSize: 16, fontWeight: "500" },
|
|
205
|
+
progress: { marginTop: 4, fontSize: 12 },
|
|
206
|
+
});
|