@q9labsai/chalk-react-native 5.2.2 → 5.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/embedded/chalk-whiteboard/asset-manifest.json +2 -2
- package/embedded/chalk-whiteboard/renderer.js +473 -473
- package/package.json +5 -5
- package/src/avatar/FaceAvatar.tsx +2 -0
- package/src/components/EmbeddedWhiteboard.tsx +5 -0
- package/src/components/useAndroidCallService.ts +2 -0
- package/src/dock/Dock.tsx +1 -0
- package/src/dock/MoreSheet.tsx +1 -0
- package/src/dock/ReactionBurst.tsx +1 -0
- package/src/dock/audio-route.ts +1 -0
- package/src/frame/CallFrame.tsx +3 -0
- package/src/frame/Chalk.tsx +1 -0
- package/src/frame/back-handler.ts +1 -0
- package/src/frame/measurement.ts +1 -0
- package/src/frame/use-landscape-chrome.ts +1 -0
- package/src/header/Header.tsx +1 -0
- package/src/limbo/Limbo.tsx +2 -0
- package/src/limbo/Veil.tsx +1 -0
- package/src/motion/MovingFrame.tsx +1 -0
- package/src/primitives/BottomSheet.tsx +2 -0
- package/src/primitives/CopyButton.tsx +2 -0
- package/src/primitives/Menu.tsx +5 -0
- package/src/primitives/Switch.tsx +1 -0
- package/src/primitives/TileShell.tsx +1 -0
- package/src/sheets/people-chat/ChatNotices.tsx +1 -0
- package/src/sheets/people-chat/PeopleChatSheet.tsx +1 -0
- package/src/sheets/people-chat/PhotoViewer.tsx +1 -0
- package/src/sheets/people-chat/attachments.tsx +1 -0
- package/src/stage/ContentTile.tsx +1 -0
- package/src/stage/ParticipantTile.tsx +1 -0
- package/src/stage/Stage.tsx +3 -0
- package/src/stage/stage-view.tsx +1 -0
- package/src/status/CallOverlays.tsx +1 -0
- package/src/status/StatusPage.tsx +1 -0
- package/src/toasts/CallEventToasts.tsx +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q9labsai/chalk-react-native",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -106,9 +106,9 @@
|
|
|
106
106
|
"registry": "https://registry.npmjs.org/"
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"@q9labsai/chalk-client": "^5.2.
|
|
110
|
-
"@q9labsai/chalk-whiteboard": "^5.2.
|
|
111
|
-
"@q9labsai/facehash": "^5.2.
|
|
109
|
+
"@q9labsai/chalk-client": "^5.2.4",
|
|
110
|
+
"@q9labsai/chalk-whiteboard": "^5.2.4",
|
|
111
|
+
"@q9labsai/facehash": "^5.2.4",
|
|
112
112
|
"uqr": "^0.1.3"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"build:types": "rm -f tsconfig.tsbuildinfo && tsc --build tsconfig.json",
|
|
156
156
|
"dev": "tsup ./src/index.ts ./src/client.ts ./src/runtime.ts ./src/clipboard.ts ./src/diagnostics.ts ./src/dev.ts ./src/invites.ts ./src/ui.ts --format esm --out-dir ./dist --platform browser --external react --external react-native --external react-native-webview --external @q9labsai/chalk-whiteboard --external @cloudflare/react-native-webrtc --external expo-audio --external expo-clipboard --external expo-crypto --external expo-document-picker --external expo-file-system --external expo-sharing --external expo-haptics --external react-native-gesture-handler --external react-native-reanimated --external react-native-safe-area-context --external react-native-svg --loader .wav=copy --watch",
|
|
157
157
|
"sync:whiteboard-assets": "node ./scripts/sync-whiteboard-assets.mjs",
|
|
158
|
-
"test": "pnpm exec vitest run",
|
|
158
|
+
"test": "node ../../../scripts/test/run.mjs pnpm exec vitest run",
|
|
159
159
|
"check-types": "tsc-rs --project tsconfig.check-types.json --noEmit",
|
|
160
160
|
"check:tokens": "node ./scripts/check-tokenized-styles.mjs",
|
|
161
161
|
"check:worklets": "node ./scripts/check-worklet-directives.mjs",
|
|
@@ -48,6 +48,7 @@ export const FaceAvatar = memo(function FaceAvatar({ name, size, style = "subtle
|
|
|
48
48
|
const lookX = useSharedValue(0);
|
|
49
49
|
const lookY = useSharedValue(0);
|
|
50
50
|
|
|
51
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native avatar fallback lifecycle.
|
|
51
52
|
useEffect(() => {
|
|
52
53
|
if (reduceMotion) {
|
|
53
54
|
blink.value = 1;
|
|
@@ -60,6 +61,7 @@ export const FaceAvatar = memo(function FaceAvatar({ name, size, style = "subtle
|
|
|
60
61
|
return () => cancelAnimation(blink);
|
|
61
62
|
}, [blink, reduceMotion, scene]);
|
|
62
63
|
|
|
64
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native avatar fallback lifecycle.
|
|
63
65
|
useEffect(() => {
|
|
64
66
|
if (!lookAround || reduceMotion) return;
|
|
65
67
|
const timer = setInterval(() => {
|
|
@@ -114,6 +114,7 @@ export function EmbeddedWhiteboard({
|
|
|
114
114
|
await exportBoardImage(value);
|
|
115
115
|
}, []);
|
|
116
116
|
|
|
117
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing embedded native board lifecycle and cleanup.
|
|
117
118
|
useEffect(() => {
|
|
118
119
|
let active = true;
|
|
119
120
|
setLoadError(null);
|
|
@@ -132,6 +133,7 @@ export function EmbeddedWhiteboard({
|
|
|
132
133
|
};
|
|
133
134
|
}, [loadAttempt, onError, rendererURLOverride]);
|
|
134
135
|
|
|
136
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing embedded native board lifecycle and cleanup.
|
|
135
137
|
useEffect(() => {
|
|
136
138
|
setCompatibilityNotice(null);
|
|
137
139
|
const controller = new ChalkWhiteboardController({
|
|
@@ -196,14 +198,17 @@ export function EmbeddedWhiteboard({
|
|
|
196
198
|
};
|
|
197
199
|
}, [clearNotices, toasts, handleControllerError, handleControllerMetric, handleControllerUserExport, journeyId, localParticipantColor, rendererPort, theme, traceparent, tracestate, transport]);
|
|
198
200
|
|
|
201
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing embedded native board lifecycle and cleanup.
|
|
199
202
|
useEffect(() => {
|
|
200
203
|
controllerRef.current?.setBoard(board);
|
|
201
204
|
}, [board]);
|
|
202
205
|
|
|
206
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing embedded native board lifecycle and cleanup.
|
|
203
207
|
useEffect(() => {
|
|
204
208
|
controllerRef.current?.setCapabilities({ canDraw, canClear });
|
|
205
209
|
}, [canClear, canDraw]);
|
|
206
210
|
|
|
211
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing embedded native board lifecycle and cleanup.
|
|
207
212
|
useEffect(() => {
|
|
208
213
|
if (viewport) controllerRef.current?.setViewport(viewport);
|
|
209
214
|
}, [viewport]);
|
|
@@ -16,6 +16,7 @@ export function useAndroidCallService(): void {
|
|
|
16
16
|
const microphoneOn = media.local.microphone.state === "enabled";
|
|
17
17
|
const cameraOn = media.local.camera.state === "enabled";
|
|
18
18
|
|
|
19
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing Android call-service ownership and cleanup.
|
|
19
20
|
useEffect(() => {
|
|
20
21
|
if (!inCall) return;
|
|
21
22
|
const start = () => {
|
|
@@ -30,6 +31,7 @@ export function useAndroidCallService(): void {
|
|
|
30
31
|
return () => subscription.remove();
|
|
31
32
|
}, [inCall, microphoneOn, cameraOn]);
|
|
32
33
|
|
|
34
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing Android call-service ownership and cleanup.
|
|
33
35
|
useEffect(() => {
|
|
34
36
|
if (!inCall) return;
|
|
35
37
|
return () => {
|
package/src/dock/Dock.tsx
CHANGED
|
@@ -67,6 +67,7 @@ function AudioOutputButton({ output, size, captioned }: { readonly output: Audio
|
|
|
67
67
|
const ref = useRef<View>(null);
|
|
68
68
|
const [open, setOpen] = useState(false);
|
|
69
69
|
const devScenario = useDevScenario();
|
|
70
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native dock motion and event subscriptions.
|
|
70
71
|
useEffect(() => {
|
|
71
72
|
if (devScenario.sheet === "route" || devScenario.menu === "route") setOpen(true);
|
|
72
73
|
}, [devScenario]);
|
package/src/dock/MoreSheet.tsx
CHANGED
|
@@ -164,6 +164,7 @@ function EmojiButton({ emoji, name, onPress, testID }: { readonly emoji: Reactio
|
|
|
164
164
|
function CopyLinkRow({ link }: { readonly link: string }): React.JSX.Element {
|
|
165
165
|
const [copied, setCopied] = useState(false);
|
|
166
166
|
const reset = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
167
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native sheet focus lifecycle.
|
|
167
168
|
useEffect(() => () => clearTimeout(reset.current ?? undefined), []);
|
|
168
169
|
const copy = useCallback(async () => {
|
|
169
170
|
await setStringAsync(link);
|
|
@@ -28,6 +28,7 @@ export const ReactionBurst = memo(function ReactionBurst({ participantId }: { re
|
|
|
28
28
|
function FloatingEmoji({ reaction }: { readonly reaction: ActiveReaction }): React.JSX.Element {
|
|
29
29
|
const reduceMotion = useReducedMotion();
|
|
30
30
|
const progress = useSharedValue(0);
|
|
31
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing cancellable native reaction animation.
|
|
31
32
|
useEffect(() => {
|
|
32
33
|
progress.value = withTiming(1, { duration: DURATION, easing: easings.easeOut });
|
|
33
34
|
}, [progress]);
|
package/src/dock/audio-route.ts
CHANGED
|
@@ -44,6 +44,7 @@ export function useAudioOutput(): AudioOutput | null {
|
|
|
44
44
|
const [state, setState] = useState<AudioRoutes | null>(null);
|
|
45
45
|
// In the harness, picking a route moves the check like a real switch would.
|
|
46
46
|
const [scenarioSelected, setScenarioSelected] = useState<string | null>(null);
|
|
47
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native audio-route subscription cleanup.
|
|
47
48
|
useEffect(() => {
|
|
48
49
|
if (!nativeModule || !emitter) return;
|
|
49
50
|
let live = true;
|
package/src/frame/CallFrame.tsx
CHANGED
|
@@ -76,6 +76,7 @@ export function CallFrame({ displayName, callName = "Call", inviteLink, onLeave,
|
|
|
76
76
|
setLeftByChoice(false);
|
|
77
77
|
client.join({ displayName, microphone: false, camera: false }).catch(() => undefined);
|
|
78
78
|
}, [client, displayName]);
|
|
79
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native frame accessibility and layout lifecycle.
|
|
79
80
|
useEffect(() => {
|
|
80
81
|
if (client.getSnapshot().connection.status === "idle") join();
|
|
81
82
|
}, [client, join]);
|
|
@@ -116,6 +117,7 @@ export function CallFrame({ displayName, callName = "Call", inviteLink, onLeave,
|
|
|
116
117
|
}, [canEnd, exit]);
|
|
117
118
|
|
|
118
119
|
const devScenario = useDevScenario();
|
|
120
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native frame accessibility and layout lifecycle.
|
|
119
121
|
useEffect(() => {
|
|
120
122
|
if (devScenario.sheet && devScenario.sheet !== "route") setSheet(devScenario.sheet);
|
|
121
123
|
if (devScenario.menu === "leave") setLeaveMenuOpen(true);
|
|
@@ -125,6 +127,7 @@ export function CallFrame({ displayName, callName = "Call", inviteLink, onLeave,
|
|
|
125
127
|
const boardVisible = useStageView().boardOpen ?? sharedBoard;
|
|
126
128
|
const chrome = useLandscapeChrome({ fades: layout.arrangement === "landscape" && sheet === null && !layered, boardVisible });
|
|
127
129
|
const chromeOpacity = useSharedValue(1);
|
|
130
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native frame accessibility and layout lifecycle.
|
|
128
131
|
useEffect(() => {
|
|
129
132
|
chromeOpacity.value = withTiming(chrome.hidden ? 0 : 1, timings.fade);
|
|
130
133
|
}, [chrome.hidden, chromeOpacity]);
|
package/src/frame/Chalk.tsx
CHANGED
|
@@ -52,6 +52,7 @@ export type ChalkProps = {
|
|
|
52
52
|
* off, and draws everything inside the safe area in portrait, landscape and on iPad.
|
|
53
53
|
*/
|
|
54
54
|
export function Chalk({ client, colorScheme, onColorSchemeChange, soundsEnabled, onSoundsEnabledChange, ...frame }: ChalkProps): React.JSX.Element {
|
|
55
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native client ownership and event subscriptions unchanged.
|
|
55
56
|
useEffect(() => releaseSounds, []);
|
|
56
57
|
return (
|
|
57
58
|
<GestureHandlerRootView style={styles.root}>
|
|
@@ -8,6 +8,7 @@ import { BackHandler } from "react-native";
|
|
|
8
8
|
export function useBackHandler(active: boolean, onBack: () => void): void {
|
|
9
9
|
const latest = useRef(onBack);
|
|
10
10
|
latest.current = onBack;
|
|
11
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native hardware-back listener cleanup.
|
|
11
12
|
useEffect(() => {
|
|
12
13
|
if (!active) return;
|
|
13
14
|
const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
|
package/src/frame/measurement.ts
CHANGED
|
@@ -25,6 +25,7 @@ export function setMeasurementRegistry(next: MeasurementRegistry | null): void {
|
|
|
25
25
|
/** A ref for the host view that carries `testID`; attach it to that view. */
|
|
26
26
|
export function useMeasuredRef<TNode extends MeasurableNode>(testID: string | undefined, style: StyleProp<ViewStyle | TextStyle>): RefObject<TNode | null> {
|
|
27
27
|
const ref = useRef<TNode>(null);
|
|
28
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native measurement registry lifetime.
|
|
28
29
|
useEffect(() => {
|
|
29
30
|
if (!registry || !testID) return;
|
|
30
31
|
const declared = StyleSheet.flatten(style) ?? {};
|
|
@@ -6,6 +6,7 @@ export function useLandscapeChrome({ fades, boardVisible }: { readonly fades: bo
|
|
|
6
6
|
const canHide = fades && !boardVisible;
|
|
7
7
|
const [hidden, setHidden] = useState(false);
|
|
8
8
|
const [shownAt, setShownAt] = useState(0);
|
|
9
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native landscape-chrome timer cleanup.
|
|
9
10
|
useEffect(() => {
|
|
10
11
|
if (!canHide) {
|
|
11
12
|
setHidden(false);
|
package/src/header/Header.tsx
CHANGED
|
@@ -68,6 +68,7 @@ function CallTimer(): React.JSX.Element | null {
|
|
|
68
68
|
const { episode } = useConnection();
|
|
69
69
|
const startedAt = episode?.startedAt ? Date.parse(episode.startedAt) : null;
|
|
70
70
|
const [now, setNow] = useState(Date.now);
|
|
71
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native elapsed-call clock cleanup.
|
|
71
72
|
useEffect(() => {
|
|
72
73
|
if (startedAt === null) return;
|
|
73
74
|
const timer = setInterval(() => setNow(Date.now()), 1000);
|
package/src/limbo/Limbo.tsx
CHANGED
|
@@ -31,6 +31,7 @@ export function Limbo({ state, callName, recording }: LimboProps): React.JSX.Ele
|
|
|
31
31
|
const actionRef = useRef<View>(null);
|
|
32
32
|
const consent = recording && (state.kind === "joining" || state.kind === "knocking") ? <Consent /> : null;
|
|
33
33
|
// The mockup moves focus to the card's button when a state with one appears.
|
|
34
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native accessibility focus and reduced-motion animation.
|
|
34
35
|
useEffect(() => {
|
|
35
36
|
const node = actionRef.current && findNodeHandle(actionRef.current);
|
|
36
37
|
if (node) AccessibilityInfo.setAccessibilityFocus(node);
|
|
@@ -132,6 +133,7 @@ function Spinner(): React.JSX.Element {
|
|
|
132
133
|
const { colors } = useTheme();
|
|
133
134
|
const reduceMotion = useReducedMotion();
|
|
134
135
|
const turn = useSharedValue(0);
|
|
136
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native accessibility focus and reduced-motion animation.
|
|
135
137
|
useEffect(() => {
|
|
136
138
|
if (reduceMotion) return;
|
|
137
139
|
turn.value = withRepeat(withTiming(1, { duration: 900, easing: Easing.linear }), -1);
|
package/src/limbo/Veil.tsx
CHANGED
|
@@ -19,6 +19,7 @@ const LIFT_FROM = 0.6;
|
|
|
19
19
|
export function Veil({ level }: { readonly level: VeilLevel }): React.JSX.Element {
|
|
20
20
|
const { colors } = useTheme();
|
|
21
21
|
const opacity = useSharedValue(OPACITY[level]);
|
|
22
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native veil transition lifecycle.
|
|
22
23
|
useEffect(() => {
|
|
23
24
|
if (level !== "none") {
|
|
24
25
|
opacity.value = OPACITY[level];
|
|
@@ -45,6 +45,7 @@ export function MovingFrame({ frame, children, style, testID }: MovingFrameProps
|
|
|
45
45
|
const mounted = useRef(false);
|
|
46
46
|
|
|
47
47
|
const { x, y, width, height } = frame;
|
|
48
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native layout animation lifecycle.
|
|
48
49
|
useEffect(() => {
|
|
49
50
|
if (!mounted.current) {
|
|
50
51
|
mounted.current = true;
|
|
@@ -94,6 +94,7 @@ export function BottomSheet({ open, onClose, accessibilityLabel, children, title
|
|
|
94
94
|
}, [height, layout.height, offset, reduceMotion, shown]);
|
|
95
95
|
|
|
96
96
|
const wasOpen = useRef(open);
|
|
97
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native sheet presentation and focus restoration.
|
|
97
98
|
useEffect(() => {
|
|
98
99
|
if (open === wasOpen.current) return;
|
|
99
100
|
wasOpen.current = open;
|
|
@@ -103,6 +104,7 @@ export function BottomSheet({ open, onClose, accessibilityLabel, children, title
|
|
|
103
104
|
}, [height, hide, open, show]);
|
|
104
105
|
|
|
105
106
|
const wasMounted = useRef(mounted);
|
|
107
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native sheet presentation and focus restoration.
|
|
106
108
|
useEffect(() => {
|
|
107
109
|
const closed = wasMounted.current && !mounted;
|
|
108
110
|
wasMounted.current = mounted;
|
|
@@ -25,9 +25,11 @@ export const CopyButton = memo(function CopyButton({ onCopy, accessibilityLabel,
|
|
|
25
25
|
const done = useSharedValue(0);
|
|
26
26
|
const reset = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
27
27
|
|
|
28
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native copy animation and feedback timer cleanup.
|
|
28
29
|
useEffect(() => {
|
|
29
30
|
done.value = withTiming(copied ? 1 : 0, timings.copyMorph);
|
|
30
31
|
}, [copied, done]);
|
|
32
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native copy animation and feedback timer cleanup.
|
|
31
33
|
useEffect(() => () => clearReset(reset), []);
|
|
32
34
|
|
|
33
35
|
const copy = useCallback(async () => {
|
package/src/primitives/Menu.tsx
CHANGED
|
@@ -43,6 +43,7 @@ export function Menu({ open, onClose, anchorRef, accessibilityLabel, children, m
|
|
|
43
43
|
|
|
44
44
|
useBackHandler(open, onClose);
|
|
45
45
|
|
|
46
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native menu focus, viewport, and keyboard cleanup.
|
|
46
47
|
useEffect(() => {
|
|
47
48
|
if (!open) {
|
|
48
49
|
firstItem.current = null;
|
|
@@ -57,12 +58,14 @@ export function Menu({ open, onClose, anchorRef, accessibilityLabel, children, m
|
|
|
57
58
|
// Like iOS menus, an open menu closes when the screen rotates or resizes, because its trigger moved.
|
|
58
59
|
const viewport = `${layout.width}x${layout.height}`;
|
|
59
60
|
const openedIn = useRef(viewport);
|
|
61
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native menu focus, viewport, and keyboard cleanup.
|
|
60
62
|
useEffect(() => {
|
|
61
63
|
if (!open) openedIn.current = viewport;
|
|
62
64
|
else if (viewport !== openedIn.current) onClose();
|
|
63
65
|
}, [onClose, open, viewport]);
|
|
64
66
|
|
|
65
67
|
const wasOpen = useRef(open);
|
|
68
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native menu focus, viewport, and keyboard cleanup.
|
|
66
69
|
useEffect(() => {
|
|
67
70
|
const closed = wasOpen.current && !open;
|
|
68
71
|
wasOpen.current = open;
|
|
@@ -81,6 +84,7 @@ export function Menu({ open, onClose, anchorRef, accessibilityLabel, children, m
|
|
|
81
84
|
[keyboardHeight, layout, placement, reduceMotion, shown, trigger],
|
|
82
85
|
);
|
|
83
86
|
|
|
87
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native menu focus, viewport, and keyboard cleanup.
|
|
84
88
|
useEffect(() => {
|
|
85
89
|
if (!placement || !firstItem.current) return;
|
|
86
90
|
const node = findNodeHandle(firstItem.current);
|
|
@@ -190,6 +194,7 @@ export function MenuSeparator(): React.JSX.Element {
|
|
|
190
194
|
|
|
191
195
|
function useKeyboardHeight(): number {
|
|
192
196
|
const [height, setHeight] = useState(0);
|
|
197
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native menu focus, viewport, and keyboard cleanup.
|
|
193
198
|
useEffect(() => {
|
|
194
199
|
const show = Keyboard.addListener("keyboardDidShow", (event) => setHeight(event.endCoordinates.height));
|
|
195
200
|
const hide = Keyboard.addListener("keyboardDidHide", () => setHeight(0));
|
|
@@ -16,6 +16,7 @@ export type SwitchProps = {
|
|
|
16
16
|
export const Switch = memo(function Switch({ value, onValueChange, accessibilityLabel, testID }: SwitchProps): React.JSX.Element {
|
|
17
17
|
const { colors } = useTheme();
|
|
18
18
|
const on = useSharedValue(value ? 1 : 0);
|
|
19
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native switch animation.
|
|
19
20
|
useEffect(() => {
|
|
20
21
|
on.value = withTiming(value ? 1 : 0, timings.switch);
|
|
21
22
|
}, [on, value]);
|
|
@@ -28,6 +28,7 @@ export const TileShell = memo(function TileShell({ children, selected = false, s
|
|
|
28
28
|
const radius = phone ? radii.tilePhone : radii.tile;
|
|
29
29
|
const live = useSharedValue(0);
|
|
30
30
|
const showRing = speaking && cameraOn;
|
|
31
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native speaking-ring animation.
|
|
31
32
|
useEffect(() => {
|
|
32
33
|
live.value = withTiming(showRing ? 1 : 0, timings.scrim);
|
|
33
34
|
}, [live, showRing]);
|
|
@@ -29,6 +29,7 @@ export function ChatNotices({ chatVisible, sheetOpen, onOpenChat }: ChatNoticesP
|
|
|
29
29
|
const latest = useRef({ chatVisible, sheetOpen, onOpenChat, soundsEnabled });
|
|
30
30
|
latest.current = { chatVisible, sheetOpen, onOpenChat, soundsEnabled };
|
|
31
31
|
|
|
32
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native chat-notice observation.
|
|
32
33
|
useEffect(() => {
|
|
33
34
|
if (status !== "ready") return;
|
|
34
35
|
const previous = seen.current;
|
|
@@ -81,6 +81,7 @@ function useMarkChatRead(reading: boolean): void {
|
|
|
81
81
|
const client = useSpaceClient();
|
|
82
82
|
const { messages, unreadCount } = useChat();
|
|
83
83
|
const last = messages[messages.length - 1]?.messageId;
|
|
84
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native read-receipt synchronization.
|
|
84
85
|
useEffect(() => {
|
|
85
86
|
if (!reading || !last || unreadCount === 0) return;
|
|
86
87
|
// A lost read receipt only leaves the unread dot up; the next message marks it again.
|
|
@@ -37,6 +37,7 @@ export function PhotoViewer({ viewing, onChange, onClose }: PhotoViewerProps): R
|
|
|
37
37
|
const photo = photos[index] ?? photos[0];
|
|
38
38
|
const count = photos.length;
|
|
39
39
|
useBackHandler(true, onClose);
|
|
40
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native photo-viewer accessibility focus.
|
|
40
41
|
useEffect(() => {
|
|
41
42
|
const node = closeRef.current && findNodeHandle(closeRef.current);
|
|
42
43
|
if (node) AccessibilityInfo.setAccessibilityFocus(node);
|
|
@@ -29,6 +29,7 @@ export type AttachmentSource = { readonly state: "loading" } | { readonly state:
|
|
|
29
29
|
export function useAttachmentSource(attachment: ChatAttachment): AttachmentSource {
|
|
30
30
|
const client = useSpaceClient();
|
|
31
31
|
const [source, setSource] = useState<AttachmentSource>({ state: "loading" });
|
|
32
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native attachment resolution and stale-result cleanup.
|
|
32
33
|
useEffect(() => {
|
|
33
34
|
let live = true;
|
|
34
35
|
resolveUrl(client, attachment)
|
|
@@ -87,6 +87,7 @@ function Board({ mini, onShowInSpotlight }: { readonly mini: boolean; readonly o
|
|
|
87
87
|
const toasts = useToasts();
|
|
88
88
|
const transport = useMemo(() => client.whiteboard.transport(), [client, status]);
|
|
89
89
|
const [capabilities, setCapabilities] = useState({ canDraw: false, canClear: false, viewsAvailable: false });
|
|
90
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native board-summary subscription cleanup.
|
|
90
91
|
useEffect(() => transport?.subscribeSummary?.((summary) => setCapabilities({ canDraw: summary.canDraw, canClear: summary.canClear, viewsAvailable: transport.supportsViews === true })), [transport]);
|
|
91
92
|
const board = useMemo(
|
|
92
93
|
() => ({
|
|
@@ -73,6 +73,7 @@ export const ParticipantTile = memo(function ParticipantTile({ id, width, height
|
|
|
73
73
|
const tile = useSpaceSelector(select, shallowEqual);
|
|
74
74
|
const slot = useDevScenario().videoSlots?.[id];
|
|
75
75
|
const level = useSharedValue(0);
|
|
76
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native speaking-level animation.
|
|
76
77
|
useEffect(() => {
|
|
77
78
|
level.value = withTiming(tile.speaking ? 0.6 : 0, timings.level);
|
|
78
79
|
}, [level, tile.speaking]);
|
package/src/stage/Stage.tsx
CHANGED
|
@@ -59,6 +59,7 @@ function selectStructure(snapshot: SpaceSnapshot): Structure {
|
|
|
59
59
|
export const Stage = memo(function Stage({ frame, onOpenPeople }: StageProps): React.JSX.Element {
|
|
60
60
|
const client = useSpaceClient();
|
|
61
61
|
const toasts = useToasts();
|
|
62
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing stage/board subscriptions and layout reconciliation.
|
|
62
63
|
useEffect(() => ownNativeBoardSession(client, () => toasts.show({ kind: "error", dismissible: true, message: "Couldn’t open the board. Try again from More." })), [client, toasts]);
|
|
63
64
|
const structure = useSpaceSelector(selectStructure, shallowEqual);
|
|
64
65
|
const selectViewsAvailable = useCallback(() => client.whiteboard.transport()?.supportsViews === true, [client]);
|
|
@@ -68,6 +69,7 @@ export const Stage = memo(function Stage({ frame, onOpenPeople }: StageProps): R
|
|
|
68
69
|
const { shareAspect } = useDevScenario();
|
|
69
70
|
const [sheet, setSheet] = useState<{ readonly id: string | null; readonly open: boolean }>({ id: null, open: false });
|
|
70
71
|
|
|
72
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing stage/board subscriptions and layout reconciliation.
|
|
71
73
|
useEffect(() => {
|
|
72
74
|
if (view.following && !structure.present.split("\n").includes(view.following)) view.setFollowing(null);
|
|
73
75
|
}, [structure.present, view.following, view.setFollowing]);
|
|
@@ -77,6 +79,7 @@ export const Stage = memo(function Stage({ frame, onOpenPeople }: StageProps): R
|
|
|
77
79
|
const next = nextStageOrder(order, present, structure.selfId, structure.speaker);
|
|
78
80
|
if (next !== order) setOrder(next);
|
|
79
81
|
|
|
82
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing stage/board subscriptions and layout reconciliation.
|
|
80
83
|
useEffect(() => {
|
|
81
84
|
view.setBoardOpen(null);
|
|
82
85
|
view.setFollowing(null);
|
package/src/stage/stage-view.tsx
CHANGED
|
@@ -34,6 +34,7 @@ export function StageViewProvider({ children }: { readonly children: ReactNode }
|
|
|
34
34
|
const [mirror, setMirror] = useState(true);
|
|
35
35
|
|
|
36
36
|
const dev = useDevScenario();
|
|
37
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native development-layout reconciliation.
|
|
37
38
|
useEffect(() => {
|
|
38
39
|
if (dev.layout) setLayout(dev.layout);
|
|
39
40
|
if (dev.pinned) setPinned(dev.pinned);
|
|
@@ -38,6 +38,7 @@ export function CallOverlays({ screen, callName, rejoining, onHold, onRejoin, on
|
|
|
38
38
|
// Notices belong to the live call; a status page or a fresh join starts without them.
|
|
39
39
|
const { clear } = useToasts();
|
|
40
40
|
const clearsNotices = screen.kind === "status" || screen.kind === "joining";
|
|
41
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native terminal-notice cleanup.
|
|
41
42
|
useEffect(() => {
|
|
42
43
|
if (clearsNotices) clear();
|
|
43
44
|
}, [clear, clearsNotices]);
|
|
@@ -54,6 +54,7 @@ export function StatusPage({ outcome, callName, failure, onRejoin, onHome }: Sta
|
|
|
54
54
|
const ref = useMeasuredRef<View>("status.page", pageStyle);
|
|
55
55
|
const firstAction = useRef<View>(null);
|
|
56
56
|
// The mockup moves focus to the first action when the page appears.
|
|
57
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing native status-page accessibility focus.
|
|
57
58
|
useEffect(() => {
|
|
58
59
|
const node = firstAction.current && findNodeHandle(firstAction.current);
|
|
59
60
|
if (node) AccessibilityInfo.setAccessibilityFocus(node);
|
|
@@ -46,6 +46,7 @@ export function useCallEventToasts({ onOpenSettings, resumedAfterSettings }: Cal
|
|
|
46
46
|
const latest = useRef({ colors, soundsEnabled });
|
|
47
47
|
latest.current = { colors, soundsEnabled };
|
|
48
48
|
|
|
49
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing client-event and native permission subscriptions.
|
|
49
50
|
useEffect(() => {
|
|
50
51
|
let previous = client.getSnapshot();
|
|
51
52
|
return client.subscribe(() => {
|
|
@@ -137,6 +138,7 @@ function useResumedAfterSettings(permission: Permission | undefined, toasts: Toa
|
|
|
137
138
|
const client = useSpaceClient();
|
|
138
139
|
const { colors } = useTheme();
|
|
139
140
|
const shown = useRef(false);
|
|
141
|
+
// nosemgrep: chalk.forbid-sdk-use-effect -- Keep existing client-event and native permission subscriptions.
|
|
140
142
|
useEffect(() => {
|
|
141
143
|
if (!permission) return;
|
|
142
144
|
const check = () => {
|