@q9labsai/chalk-react-native 4.1.12 → 4.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/android.js +2 -2
- package/dist/{chunk-FVHH65FR.js → chunk-4NLA35HE.js} +1 -1
- package/dist/{chunk-LZ67SXGB.js → chunk-MK6OO4V7.js} +6 -0
- package/dist/client.js +1 -1
- package/dist/index.js +2 -2
- package/dist/ios-pad.js +2 -2
- package/dist/ios-phone.js +2 -2
- package/dist/ios.js +2 -2
- package/dist/macos.js +2 -2
- package/package.json +4 -4
- package/src/callkit/callkit.test.ts +12 -10
- package/src/space-client/create-native-space-client.ts +8 -0
- package/dist/test-support/test-renderer.d.ts +0 -20
- package/dist/test-support/test-renderer.d.ts.map +0 -1
- package/src/android/connection-service.test.ts +0 -114
- package/src/callkit/resolve-space-callkit-options.test.ts +0 -68
- package/src/client.test.ts +0 -12
- package/src/clipboard.test.ts +0 -79
- package/src/components/Chalk.test.tsx +0 -223
- package/src/components/EmbeddedWhiteboard.test.tsx +0 -92
- package/src/components/Entrance.test.tsx +0 -26
- package/src/components/EntranceView.android.test.tsx +0 -100
- package/src/components/EntranceView.ios-pad.test.tsx +0 -160
- package/src/components/EntranceView.ios-phone.test.tsx +0 -137
- package/src/components/EntranceView.test.tsx +0 -15
- package/src/components/ReactionPicker.test.tsx +0 -19
- package/src/components/RtcVideoView.test.tsx +0 -12
- package/src/components/SpaceView.android.test.tsx +0 -11
- package/src/components/SpaceView.ios-pad.test.tsx +0 -11
- package/src/components/SpaceView.ios-phone.test.tsx +0 -11
- package/src/components/SpaceView.macos.test.tsx +0 -11
- package/src/components/SpaceView.shared.test.tsx +0 -116
- package/src/components/SpaceView.test.tsx +0 -15
- package/src/components/android-connection-service-controller.test.ts +0 -80
- package/src/components/episode-diagnostic-render-observer.test.ts +0 -24
- package/src/components/logo/Logo.test.tsx +0 -144
- package/src/components/native-animation-controller.test.ts +0 -47
- package/src/components/native-chat.test.ts +0 -22
- package/src/components/native-entrance/entrance-controller-store.test.ts +0 -75
- package/src/components/native-media-visibility.test.ts +0 -77
- package/src/components/native-space-callkit-controller.test.ts +0 -62
- package/src/components/native-space-view/AppearanceSettings.test.tsx +0 -56
- package/src/components/native-space-view/ParticipantActionSheet.test.tsx +0 -18
- package/src/components/native-space-view/SettingsSheet.test.tsx +0 -17
- package/src/components/native-space-view/SpaceActionMenu.test.tsx +0 -126
- package/src/components/native-space-view/SpaceBottomDock.android.test.tsx +0 -61
- package/src/components/native-space-view/SpaceChatSheet.test.tsx +0 -18
- package/src/components/native-space-view/SpaceMoreSheet.test.tsx +0 -15
- package/src/components/native-space-view/SpacePanelSheet.test.tsx +0 -15
- package/src/components/native-space-view/SpacePeopleSheet.test.tsx +0 -13
- package/src/components/native-space-view/SpaceSurfacePrimitives.test.tsx +0 -12
- package/src/components/native-space-view/SpaceTopBar.android.test.tsx +0 -50
- package/src/components/native-space-view/SpaceWhiteboardSurface.test.tsx +0 -85
- package/src/components/native-space-view/diagnostics.test.ts +0 -31
- package/src/components/native-space-view/format-space-duration.test.ts +0 -13
- package/src/components/native-space-view/native-space-grid-keys.test.ts +0 -11
- package/src/components/native-space-view/native-space-page-store.test.ts +0 -23
- package/src/components/native-space-view/space-chat-attachments.test.ts +0 -33
- package/src/components/native-space-view/space-progressive-surface-helpers.test.ts +0 -24
- package/src/components/native-space-view/useSpaceViewController.contract.test.ts +0 -10
- package/src/components/native-space-view/useSpaceViewController.test.ts +0 -106
- package/src/components/native-space-view/useSpaceViewDerived.test.ts +0 -58
- package/src/components/native-space-view/useSpaceViewPanels.controlled.test.ts +0 -40
- package/src/components/native-space-view/useSpaceViewPanels.test.ts +0 -73
- package/src/components/space-lifecycle.test.ts +0 -19
- package/src/context/space-client-context.test.tsx +0 -10
- package/src/diagnostics.test.ts +0 -29
- package/src/hooks/entrance-preview-store.test.ts +0 -79
- package/src/hooks/space-hooks.test.ts +0 -76
- package/src/hooks/useLayout.test.ts +0 -16
- package/src/invites.test.ts +0 -51
- package/src/public-surface.test.ts +0 -26
- package/src/runtime.test.ts +0 -83
- package/src/space-client/cloudflare-rtk-native.test.ts +0 -118
- package/src/space-client/create-native-space-client.test.ts +0 -300
- package/src/telemetry.test.ts +0 -143
- package/src/test-support/test-renderer.test.ts +0 -9
- package/src/test-support/test-renderer.ts +0 -28
- package/src/ui/appearance.test.ts +0 -61
- package/src/ui/native-appearance-context.controlled.test.tsx +0 -41
- package/src/ui/native-appearance-context.test.tsx +0 -14
- package/src/ui/native-theme.test.ts +0 -34
- package/src/ui/native-theme.test.tsx +0 -14
- package/src/ui/participant-avatar.test.ts +0 -29
- package/src/ui/theme-tokens.test.ts +0 -14
- package/src/ui/theme.test.ts +0 -36
- package/src/utils/build-chalk-invite-link.test.ts +0 -12
- package/src/utils/ios-simulator.test.ts +0 -96
- package/src/utils/native-space-layout.test.ts +0 -170
- package/src/whiteboard/embedded-whiteboard-assets.test.ts +0 -31
package/src/telemetry.test.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createTelemetry, getNativeJourneyContext, registerNativeJourneyContext, syncTransportCloseDiagnostic, type RtcPeerConnection, type TelemetryJourney } from "./telemetry";
|
|
3
|
-
|
|
4
|
-
describe("createTelemetry", () => {
|
|
5
|
-
it("bounds Sync transport close diagnostics without recording raw reasons", () => {
|
|
6
|
-
expect(syncTransportCloseDiagnostic({ code: 1008, reason: "invalid token" })).toEqual({
|
|
7
|
-
category: "network",
|
|
8
|
-
code: "sync_websocket_closed_1008_invalid_token",
|
|
9
|
-
phase: "signaling",
|
|
10
|
-
state: "failed",
|
|
11
|
-
});
|
|
12
|
-
expect(syncTransportCloseDiagnostic({ code: 1008, reason: "secret detail" }).code).toBe("sync_websocket_closed_1008_other");
|
|
13
|
-
expect(syncTransportCloseDiagnostic({ code: 1000, reason: "" }).state).toBe("observed");
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("propagates one journey through API and sync transport configuration", () => {
|
|
17
|
-
const journey = createJourney();
|
|
18
|
-
const telemetry = createTelemetry(journey);
|
|
19
|
-
|
|
20
|
-
expect(telemetry.connection).toEqual({
|
|
21
|
-
apiHeaders: journey.headers,
|
|
22
|
-
context: journey.context,
|
|
23
|
-
syncCorrelation: {
|
|
24
|
-
journey_id: journey.context.journeyId,
|
|
25
|
-
traceparent: journey.context.traceparent,
|
|
26
|
-
tracestate: journey.context.tracestate,
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
telemetry.recordSyncFrame({ direction: "client_to_server", frameType: "space.join" });
|
|
31
|
-
expect(journey.recordSyncFrame).toHaveBeenCalledWith({ direction: "client_to_server", frameType: "space.join" });
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("records production whiteboard metrics without forwarding renderer attributes", () => {
|
|
35
|
-
const journey = createJourney();
|
|
36
|
-
const telemetry = createTelemetry(journey);
|
|
37
|
-
|
|
38
|
-
telemetry.recordWhiteboardMetric({
|
|
39
|
-
name: "whiteboard.renderer.termination",
|
|
40
|
-
value: 1,
|
|
41
|
-
attributes: { renderer_generation: "private-cardinality-value" },
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(journey.recordDiagnostic).toHaveBeenCalledWith({
|
|
45
|
-
category: "whiteboard_renderer",
|
|
46
|
-
code: "whiteboard.renderer.termination",
|
|
47
|
-
metricValue: 1,
|
|
48
|
-
phase: "media",
|
|
49
|
-
state: "failed",
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("keeps the native client journey seam private and exact-client scoped", () => {
|
|
54
|
-
const journey = createJourney();
|
|
55
|
-
const telemetry = createTelemetry(journey);
|
|
56
|
-
const client = {};
|
|
57
|
-
registerNativeJourneyContext(client, journey, telemetry);
|
|
58
|
-
|
|
59
|
-
expect(getNativeJourneyContext(client)).toMatchObject({
|
|
60
|
-
journeyId: journey.context.journeyId,
|
|
61
|
-
traceparent: journey.context.traceparent,
|
|
62
|
-
tracestate: journey.context.tracestate,
|
|
63
|
-
});
|
|
64
|
-
getNativeJourneyContext(client)?.recordWhiteboardMetric({ name: "whiteboard.renderer.ready", value: 1 });
|
|
65
|
-
expect(journey.recordDiagnostic).toHaveBeenCalledWith({
|
|
66
|
-
category: "whiteboard_renderer",
|
|
67
|
-
code: "whiteboard.renderer.ready",
|
|
68
|
-
metricValue: 1,
|
|
69
|
-
phase: "media",
|
|
70
|
-
state: "observed",
|
|
71
|
-
});
|
|
72
|
-
expect(getNativeJourneyContext({})).toBeUndefined();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("records aggregate RTC summaries from native peer-connection stats", async () => {
|
|
76
|
-
const journey = createJourney();
|
|
77
|
-
const telemetry = createTelemetry(journey);
|
|
78
|
-
const peerConnection = createPeerConnection();
|
|
79
|
-
const stop = telemetry.observePeerConnection(peerConnection);
|
|
80
|
-
|
|
81
|
-
peerConnection.connectionState = "connected";
|
|
82
|
-
peerConnection.emit("connectionstatechange");
|
|
83
|
-
|
|
84
|
-
await vi.waitFor(() => expect(journey.recordRtcSummary).toHaveBeenCalled());
|
|
85
|
-
expect(journey.recordRtcSummary).toHaveBeenLastCalledWith({ connectionState: "connected", iceConnectionState: "completed", signalingState: "stable" }, [
|
|
86
|
-
{ type: "inbound-rtp", bytesReceived: 1200, packetsLost: 2 },
|
|
87
|
-
{ type: "candidate-pair", roundTripTime: 0.03 },
|
|
88
|
-
]);
|
|
89
|
-
|
|
90
|
-
stop();
|
|
91
|
-
peerConnection.emit("iceconnectionstatechange");
|
|
92
|
-
expect(journey.recordRtcSummary).toHaveBeenCalledTimes(2);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
function createJourney(): TelemetryJourney & {
|
|
97
|
-
recordDiagnostic: ReturnType<typeof vi.fn>;
|
|
98
|
-
recordRtcSummary: ReturnType<typeof vi.fn>;
|
|
99
|
-
recordSyncFrame: ReturnType<typeof vi.fn>;
|
|
100
|
-
} {
|
|
101
|
-
return {
|
|
102
|
-
context: {
|
|
103
|
-
journeyId: "00000000-0000-4000-8000-000000000001",
|
|
104
|
-
rootJourneyId: "00000000-0000-4000-8000-000000000001",
|
|
105
|
-
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
|
|
106
|
-
tracestate: "chalk=mobile",
|
|
107
|
-
},
|
|
108
|
-
headers: {
|
|
109
|
-
"x-chalk-journey-id": "00000000-0000-4000-8000-000000000001",
|
|
110
|
-
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
|
|
111
|
-
},
|
|
112
|
-
recordDiagnostic: vi.fn(),
|
|
113
|
-
recordRtcSummary: vi.fn(),
|
|
114
|
-
recordSyncFrame: vi.fn(),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function createPeerConnection(): RtcPeerConnection & { emit(event: "connectionstatechange" | "iceconnectionstatechange" | "signalingstatechange"): void; connectionState: string } {
|
|
119
|
-
const listeners = new Map<string, Set<() => void>>();
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
connectionState: "connecting",
|
|
123
|
-
iceConnectionState: "completed",
|
|
124
|
-
signalingState: "stable",
|
|
125
|
-
addEventListener(event, listener) {
|
|
126
|
-
const eventListeners = listeners.get(event) ?? new Set();
|
|
127
|
-
eventListeners.add(listener);
|
|
128
|
-
listeners.set(event, eventListeners);
|
|
129
|
-
},
|
|
130
|
-
removeEventListener(event, listener) {
|
|
131
|
-
listeners.get(event)?.delete(listener);
|
|
132
|
-
},
|
|
133
|
-
async getStats() {
|
|
134
|
-
return new Map([
|
|
135
|
-
["inbound", { type: "inbound-rtp", bytesReceived: 1200, packetsLost: 2 }],
|
|
136
|
-
["pair", { type: "candidate-pair", roundTripTime: 0.03 }],
|
|
137
|
-
]);
|
|
138
|
-
},
|
|
139
|
-
emit(event) {
|
|
140
|
-
for (const listener of listeners.get(event) ?? []) listener();
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import type { ComponentType, ReactNode } from "react";
|
|
6
|
-
|
|
7
|
-
type RenderHookOptions<Props> = {
|
|
8
|
-
readonly initialProps?: Props;
|
|
9
|
-
readonly wrapper?: ComponentType<{ readonly children?: ReactNode }>;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
type RenderHookResult<Result, Props> = {
|
|
13
|
-
readonly result: { readonly current: Result };
|
|
14
|
-
readonly rerender: (props?: Props) => void;
|
|
15
|
-
readonly unmount: () => void;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type RenderHook = <Result, Props = undefined>(callback: (props: Props) => Result, options?: RenderHookOptions<Props>) => RenderHookResult<Result, Props>;
|
|
19
|
-
type Act = (callback: () => void | Promise<void>) => void | Promise<void>;
|
|
20
|
-
type WaitFor = (callback: () => void | Promise<void>) => Promise<void>;
|
|
21
|
-
|
|
22
|
-
const testingLibrary = createRequire(import.meta.url)(join(process.cwd(), "../react/node_modules", "@" + "testing-library", "react")) as {
|
|
23
|
-
readonly act: Act;
|
|
24
|
-
readonly renderHook: RenderHook;
|
|
25
|
-
readonly waitFor: WaitFor;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const { act, renderHook, waitFor } = testingLibrary;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { THEME_PALETTES as REACT_THEME_PALETTES, THEME_TEXTURES as REACT_THEME_TEXTURES } from "../../../react/src/components/theme";
|
|
4
|
-
|
|
5
|
-
import { getThemeMode, isDarkThemePalette, resolveNativeAppearance, THEME_PALETTES, THEME_TEXTURES } from "./appearance";
|
|
6
|
-
|
|
7
|
-
describe("React Native appearance catalog", () => {
|
|
8
|
-
it("keeps palette and texture metadata in parity with React", () => {
|
|
9
|
-
expect(THEME_PALETTES.map(({ value, label, family, mode, swatch }) => ({ value, label, family, mode, swatch }))).toEqual(REACT_THEME_PALETTES);
|
|
10
|
-
expect(THEME_TEXTURES.map(({ value, label, description }) => ({ value, label, description }))).toEqual(REACT_THEME_TEXTURES);
|
|
11
|
-
expect(THEME_PALETTES).toHaveLength(16);
|
|
12
|
-
expect(THEME_PALETTES.filter((palette) => palette.mode === "light")).toHaveLength(8);
|
|
13
|
-
expect(THEME_PALETTES.filter((palette) => palette.mode === "dark")).toHaveLength(8);
|
|
14
|
-
expect(THEME_TEXTURES.map((texture) => texture.value)).toEqual(["none", "paper", "slate"]);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("carries every CSS appearance token as a native value", () => {
|
|
18
|
-
for (const palette of THEME_PALETTES) {
|
|
19
|
-
expect(palette.tokens.canvas).toMatch(/^#[0-9a-f]{6}$/);
|
|
20
|
-
expect(palette.tokens.tileColorStrength).toBeGreaterThan(0);
|
|
21
|
-
expect(palette.tokens.tileColorStrength).toBeLessThanOrEqual(1);
|
|
22
|
-
expect(palette.tokens.shadows.xs.offset.width).toBe(0);
|
|
23
|
-
expect(palette.tokens.shadows.sm.radius).toBeGreaterThanOrEqual(0);
|
|
24
|
-
expect(palette.tokens.shadows.control.elevation).toBeGreaterThanOrEqual(0);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
expect(THEME_PALETTES[0].tokens).toMatchObject({ canvas: "#f7f6f2", panel: "#ffffff", controlPrimary: "#202329", input: "#fbfaf7" });
|
|
28
|
-
expect(THEME_PALETTES.find((palette) => palette.value === "warm-porcelain")?.tokens).toMatchObject({ canvas: "#f2ebe2", stage: "#eee4dc", controlPrimary: "#51443c" });
|
|
29
|
-
expect(THEME_PALETTES.find((palette) => palette.value === "cosmic-chalk")?.tokens).toMatchObject({
|
|
30
|
-
canvas: "#080f20",
|
|
31
|
-
chrome: "#10182b",
|
|
32
|
-
panel: "#10182b",
|
|
33
|
-
stage: "#0b1427",
|
|
34
|
-
text: "#f4ecd7",
|
|
35
|
-
textMuted: "#aeb8c9",
|
|
36
|
-
controlActiveLine: "#8fdcff",
|
|
37
|
-
controlPrimary: "#8fdcff",
|
|
38
|
-
messageLocalText: "#080f20",
|
|
39
|
-
});
|
|
40
|
-
expect(THEME_PALETTES.find((palette) => palette.value === "oled-signal")?.tokens).toMatchObject({ canvas: "#000000", stage: "#000000", shadows: { xs: { opacity: 0 }, sm: { opacity: 0 } } });
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("resolves mode and native texture primitives independently", () => {
|
|
44
|
-
expect(isDarkThemePalette("warm-charcoal")).toBe(true);
|
|
45
|
-
expect(isDarkThemePalette("warm-porcelain")).toBe(false);
|
|
46
|
-
expect(getThemeMode("prism-nocturne")).toBe("dark");
|
|
47
|
-
expect(getThemeMode("prism-daylight")).toBe("light");
|
|
48
|
-
|
|
49
|
-
expect(resolveNativeAppearance()).toMatchObject({ palette: "light", mode: "light", texture: "none", textureDescriptor: { kind: "none", opacity: 0, tileSize: null } });
|
|
50
|
-
|
|
51
|
-
const lightSlate = resolveNativeAppearance({ palette: "warm-porcelain", texture: "slate" });
|
|
52
|
-
expect(lightSlate.mode).toBe("light");
|
|
53
|
-
expect(lightSlate.tokens.canvas).toBe("#f2ebe2");
|
|
54
|
-
expect(lightSlate.textureDescriptor).toMatchObject({ kind: "slate", blendMode: "multiply", opacity: 0.16, lines: { color: "#0c0e12", opacity: 0.022 } });
|
|
55
|
-
|
|
56
|
-
const darkSlate = resolveNativeAppearance({ palette: "oled-signal", texture: "slate" });
|
|
57
|
-
expect(darkSlate.mode).toBe("dark");
|
|
58
|
-
expect(darkSlate.tokens.canvas).toBe("#000000");
|
|
59
|
-
expect(darkSlate.textureDescriptor).toMatchObject({ kind: "slate", blendMode: "soft-light", opacity: 0.2, lines: { color: "#ffffff", opacity: 0.018 } });
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// @vitest-environment happy-dom
|
|
2
|
-
|
|
3
|
-
import type { ReactNode } from "react";
|
|
4
|
-
import { describe, expect, it, vi } from "vitest";
|
|
5
|
-
|
|
6
|
-
import { act, renderHook } from "../test-support/test-renderer";
|
|
7
|
-
|
|
8
|
-
vi.mock("react-native", () => ({
|
|
9
|
-
StyleSheet: { absoluteFill: {}, create: (styles: unknown) => styles },
|
|
10
|
-
View: ({ children }: { readonly children?: ReactNode }) => children,
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
import { NativeAppearanceProvider, useNativeAppearance } from "./native-appearance-context";
|
|
14
|
-
|
|
15
|
-
describe("NativeAppearanceProvider controlled initial appearance", () => {
|
|
16
|
-
it("updates palette and texture without replacing its child", () => {
|
|
17
|
-
let initialAppearance = { palette: "light" as const, texture: "none" as const };
|
|
18
|
-
const wrapper = ({ children }: { readonly children?: ReactNode }): React.JSX.Element => <NativeAppearanceProvider initialAppearance={initialAppearance}>{children}</NativeAppearanceProvider>;
|
|
19
|
-
const { result, rerender } = renderHook(() => useNativeAppearance(), { wrapper });
|
|
20
|
-
|
|
21
|
-
expect(result.current.appearance.palette).toBe("light");
|
|
22
|
-
expect(result.current.appearance.texture).toBe("none");
|
|
23
|
-
|
|
24
|
-
initialAppearance = { palette: "warm-porcelain", texture: "paper" };
|
|
25
|
-
rerender();
|
|
26
|
-
|
|
27
|
-
expect(result.current.appearance.palette).toBe("warm-porcelain");
|
|
28
|
-
expect(result.current.appearance.texture).toBe("paper");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("updates appearance when controls change", () => {
|
|
32
|
-
const wrapper = ({ children }: { readonly children?: ReactNode }): React.JSX.Element => <NativeAppearanceProvider>{children}</NativeAppearanceProvider>;
|
|
33
|
-
const { result } = renderHook(() => useNativeAppearance(), { wrapper });
|
|
34
|
-
|
|
35
|
-
act(() => result.current.setPalette("warm-porcelain"));
|
|
36
|
-
act(() => result.current.setTexture("paper"));
|
|
37
|
-
|
|
38
|
-
expect(result.current.appearance.palette).toBe("warm-porcelain");
|
|
39
|
-
expect(result.current.appearance.texture).toBe("paper");
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./native-appearance-context.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("NativeAppearanceProvider", () => {
|
|
7
|
-
it("resolves local selections and renders inert textures", () => {
|
|
8
|
-
expect(source).toContain("resolveNativeAppearance(selection)");
|
|
9
|
-
expect(source).toContain("setPalette:");
|
|
10
|
-
expect(source).toContain("setTexture:");
|
|
11
|
-
expect(source).toContain('pointerEvents="none"');
|
|
12
|
-
expect(source).toContain("must be used inside NativeAppearanceProvider");
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { resolveNativeAppearance } from "./appearance";
|
|
4
|
-
import { resolveNativeTheme } from "./native-theme";
|
|
5
|
-
|
|
6
|
-
describe("resolveNativeTheme", () => {
|
|
7
|
-
it("resolves the public color scheme, accent, and token overrides into semantic colors", () => {
|
|
8
|
-
const theme = resolveNativeTheme({
|
|
9
|
-
colorScheme: "light",
|
|
10
|
-
accent: "#7c3aed",
|
|
11
|
-
tokens: { canvas: "#fefce8", text: "#1c1917" },
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
expect(theme.colorScheme).toBe("light");
|
|
15
|
-
expect(theme.colors).toMatchObject({
|
|
16
|
-
background: "#fefce8",
|
|
17
|
-
foreground: "#1c1917",
|
|
18
|
-
primary: "#7c3aed",
|
|
19
|
-
ring: "#7c3aed",
|
|
20
|
-
stageBackground: "#e2e8f0",
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("projects the selected native palette into rendered theme colors", () => {
|
|
25
|
-
const appearance = resolveNativeAppearance({ palette: "warm-porcelain", texture: "paper" });
|
|
26
|
-
const theme = resolveNativeTheme(undefined, appearance);
|
|
27
|
-
|
|
28
|
-
expect(theme.colorScheme).toBe("light");
|
|
29
|
-
expect(theme.colors.background).toBe(appearance.tokens.canvas);
|
|
30
|
-
expect(theme.colors.foreground).toBe(appearance.tokens.text);
|
|
31
|
-
expect(theme.colors.stageBackground).toBe(appearance.tokens.stage);
|
|
32
|
-
expect(theme.colors.primary).toBe(appearance.tokens.controlPrimary);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { resolveNativeTheme } from "./native-theme";
|
|
4
|
-
|
|
5
|
-
describe("resolveNativeTheme", () => {
|
|
6
|
-
it("uses dark defaults while allowing semantic token overrides", () => {
|
|
7
|
-
const theme = resolveNativeTheme({ tokens: { focus: "#f59e0b", positive: "#15803d" } });
|
|
8
|
-
|
|
9
|
-
expect(theme.colorScheme).toBe("dark");
|
|
10
|
-
expect(theme.colors.darkCanvas).toBe("#0a0a0b");
|
|
11
|
-
expect(theme.colors.ring).toBe("#f59e0b");
|
|
12
|
-
expect(theme.colors.success).toBe("#15803d");
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { getParticipantAvatarRecipe, getParticipantColor, getParticipantInitials, PARTICIPANT_AVATAR_PALETTE } from "./participant-avatar";
|
|
3
|
-
|
|
4
|
-
describe("participant identity colors", () => {
|
|
5
|
-
it("chooses one approved flat identity color deterministically", () => {
|
|
6
|
-
const first = getParticipantColor("Avery Chen");
|
|
7
|
-
const second = getParticipantColor("Avery Chen");
|
|
8
|
-
|
|
9
|
-
expect(first).toEqual(second);
|
|
10
|
-
expect(PARTICIPANT_AVATAR_PALETTE.map(({ primary }) => primary)).toContain(first.primary);
|
|
11
|
-
expect(first.gradientEnd).toBe(first.primary);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("keeps avatar recipes flat for compatibility consumers", () => {
|
|
15
|
-
const recipe = getParticipantAvatarRecipe("Avery Chen");
|
|
16
|
-
|
|
17
|
-
expect(recipe.gradientStops).toEqual([
|
|
18
|
-
{ color: recipe.colors.primary, offset: "0%" },
|
|
19
|
-
{ color: recipe.colors.primary, offset: "100%" },
|
|
20
|
-
]);
|
|
21
|
-
expect(recipe.facehashColors).toEqual([recipe.colors.primary, recipe.colors.primary, recipe.colors.primary]);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("returns one or two initials without making identity noun assumptions", () => {
|
|
25
|
-
expect(getParticipantInitials("Avery Chen")).toBe("AC");
|
|
26
|
-
expect(getParticipantInitials("Avery")).toBe("A");
|
|
27
|
-
expect(getParticipantInitials()).toBe("?");
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { DEFAULT_CHALK_THEME_TOKENS, LIGHT_CHALK_THEME_TOKENS } from "./theme-tokens";
|
|
4
|
-
|
|
5
|
-
describe("Chalk theme tokens", () => {
|
|
6
|
-
it("keeps dark and light themes on the same semantic token contract", () => {
|
|
7
|
-
const tokenNames = ["canvas", "chrome", "surface", "stage", "text", "mutedText", "line", "accent", "accentText", "positive", "danger", "dangerSurface", "focus", "shadow"];
|
|
8
|
-
|
|
9
|
-
expect(Object.keys(DEFAULT_CHALK_THEME_TOKENS)).toEqual(tokenNames);
|
|
10
|
-
expect(Object.keys(LIGHT_CHALK_THEME_TOKENS)).toEqual(tokenNames);
|
|
11
|
-
expect(DEFAULT_CHALK_THEME_TOKENS.canvas).not.toBe(LIGHT_CHALK_THEME_TOKENS.canvas);
|
|
12
|
-
expect(DEFAULT_CHALK_THEME_TOKENS.accent).not.toBe(LIGHT_CHALK_THEME_TOKENS.accent);
|
|
13
|
-
});
|
|
14
|
-
});
|
package/src/ui/theme.test.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { createNativeTheme, Theme } from "./theme";
|
|
3
|
-
|
|
4
|
-
describe("native theme aliases", () => {
|
|
5
|
-
it("keeps progressive surfaces on the active token set", () => {
|
|
6
|
-
expect(Theme.colors.paper).toBe(Theme.colors.background);
|
|
7
|
-
expect(Theme.colors.ink).toBe(Theme.colors.foreground);
|
|
8
|
-
expect(Theme.colors.lineStrong).toBe(Theme.colors.border);
|
|
9
|
-
expect(Theme.colors.chalkGreen).toBe(Theme.colors.success);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it("resolves the same aliases for light mode", () => {
|
|
13
|
-
const light = createNativeTheme(
|
|
14
|
-
{
|
|
15
|
-
canvas: "#f8fafc",
|
|
16
|
-
chrome: "#ffffff",
|
|
17
|
-
surface: "#f1f5f9",
|
|
18
|
-
stage: "#e2e8f0",
|
|
19
|
-
text: "#0f172a",
|
|
20
|
-
mutedText: "#475569",
|
|
21
|
-
line: "#cbd5e1",
|
|
22
|
-
accent: "#0f766e",
|
|
23
|
-
accentText: "#ffffff",
|
|
24
|
-
positive: "#15803d",
|
|
25
|
-
danger: "#b91c1c",
|
|
26
|
-
dangerSurface: "#fee2e2",
|
|
27
|
-
focus: "#0f766e",
|
|
28
|
-
shadow: "#0f172a",
|
|
29
|
-
},
|
|
30
|
-
"light",
|
|
31
|
-
);
|
|
32
|
-
expect(light.colors.paper).toBe(light.colors.background);
|
|
33
|
-
expect(light.colors.ink).toBe(light.colors.foreground);
|
|
34
|
-
expect(light.colors.primary).toBe("#0f766e");
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { buildChalkInviteLink } from "./build-chalk-invite-link";
|
|
3
|
-
|
|
4
|
-
describe("buildChalkInviteLink", () => {
|
|
5
|
-
it("builds a canonical Space invite link with the public host", () => {
|
|
6
|
-
expect(buildChalkInviteLink("design-lab", "cspi1.key.payload.signature")).toBe("https://chalkmeet.com/space/design-lab#spaceInviteToken=cspi1.key.payload.signature");
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
it("normalizes trailing slashes on custom origins", () => {
|
|
10
|
-
expect(buildChalkInviteLink("design-lab", "cspi1.key.payload.signature", "https://chalk.q9labs.ai/")).toBe("https://chalk.q9labs.ai/space/design-lab#spaceInviteToken=cspi1.key.payload.signature");
|
|
11
|
-
});
|
|
12
|
-
});
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const nativeModules = {
|
|
4
|
-
ChalkRuntimeInfo: { isSimulator: true },
|
|
5
|
-
WebRTCModule: {
|
|
6
|
-
receiverGetCapabilities: vi.fn(() => {
|
|
7
|
-
throw new Error("native receiver call should be bypassed on simulator");
|
|
8
|
-
}),
|
|
9
|
-
senderGetCapabilities: vi.fn(() => {
|
|
10
|
-
throw new Error("native sender call should be bypassed on simulator");
|
|
11
|
-
}),
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const mockedMediaDevices = {
|
|
16
|
-
enumerateDevices: vi.fn(async () => {
|
|
17
|
-
throw new Error("mediaDevices.enumerateDevices should be bypassed on simulator");
|
|
18
|
-
}),
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
vi.mock("react-native", () => ({
|
|
22
|
-
NativeModules: nativeModules,
|
|
23
|
-
Platform: { OS: "ios" },
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
describe("ensureIosSimulatorWebRtcSafety", () => {
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
vi.resetModules();
|
|
29
|
-
nativeModules.ChalkRuntimeInfo.isSimulator = true;
|
|
30
|
-
nativeModules.WebRTCModule.receiverGetCapabilities = vi.fn(() => {
|
|
31
|
-
throw new Error("native receiver call should be bypassed on simulator");
|
|
32
|
-
});
|
|
33
|
-
nativeModules.WebRTCModule.senderGetCapabilities = vi.fn(() => {
|
|
34
|
-
throw new Error("native sender call should be bypassed on simulator");
|
|
35
|
-
});
|
|
36
|
-
delete (globalThis as Record<string, unknown>).RTCRtpReceiver;
|
|
37
|
-
delete (globalThis as Record<string, unknown>).RTCRtpSender;
|
|
38
|
-
mockedMediaDevices.enumerateDevices = vi.fn(async () => {
|
|
39
|
-
throw new Error("mediaDevices.enumerateDevices should be bypassed on simulator");
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("patches native capability lookups on the iOS simulator", async () => {
|
|
44
|
-
const { ensureIosSimulatorWebRtcSafety } = await import("./ios-simulator");
|
|
45
|
-
|
|
46
|
-
ensureIosSimulatorWebRtcSafety();
|
|
47
|
-
|
|
48
|
-
expect(nativeModules.WebRTCModule.receiverGetCapabilities("video")).toEqual({
|
|
49
|
-
codecs: [],
|
|
50
|
-
headerExtensions: [],
|
|
51
|
-
});
|
|
52
|
-
expect(nativeModules.WebRTCModule.senderGetCapabilities("audio")).toEqual({
|
|
53
|
-
codecs: [],
|
|
54
|
-
headerExtensions: [],
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("patches exported RTCRtp capability helpers when available", async () => {
|
|
59
|
-
const { ensureIosSimulatorWebRtcSafety } = await import("./ios-simulator");
|
|
60
|
-
|
|
61
|
-
const receiver = {
|
|
62
|
-
getCapabilities: vi.fn(() => {
|
|
63
|
-
throw new Error("receiver helper should be patched");
|
|
64
|
-
}),
|
|
65
|
-
};
|
|
66
|
-
const sender = {
|
|
67
|
-
getCapabilities: vi.fn(() => {
|
|
68
|
-
throw new Error("sender helper should be patched");
|
|
69
|
-
}),
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
ensureIosSimulatorWebRtcSafety({
|
|
73
|
-
RTCRtpReceiver: receiver,
|
|
74
|
-
RTCRtpSender: sender,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(receiver.getCapabilities("video")).toEqual({
|
|
78
|
-
codecs: [],
|
|
79
|
-
headerExtensions: [],
|
|
80
|
-
});
|
|
81
|
-
expect(sender.getCapabilities("audio")).toEqual({
|
|
82
|
-
codecs: [],
|
|
83
|
-
headerExtensions: [],
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("patches media device enumeration on the iOS simulator", async () => {
|
|
88
|
-
const { ensureIosSimulatorWebRtcSafety } = await import("./ios-simulator");
|
|
89
|
-
|
|
90
|
-
ensureIosSimulatorWebRtcSafety({
|
|
91
|
-
mediaDevices: mockedMediaDevices,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
await expect(mockedMediaDevices.enumerateDevices()).resolves.toEqual([]);
|
|
95
|
-
});
|
|
96
|
-
});
|