@q9labsai/chalk-react-native 5.2.0 → 5.2.2

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.
Files changed (48) hide show
  1. package/dist/{chunk-4L5GXJ36.js → chunk-BXDD5BE4.js} +23 -1
  2. package/dist/{chunk-MBZRE4US.js → chunk-PPQSOU35.js} +5 -5
  3. package/dist/client.js +5 -4
  4. package/dist/components/EmbeddedWhiteboard.d.ts +8 -4
  5. package/dist/frame/call-controls.d.ts +2 -0
  6. package/dist/frame/use-landscape-chrome.d.ts +8 -0
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +365 -101
  9. package/dist/invites.d.ts +5 -0
  10. package/dist/invites.js +3 -1
  11. package/dist/primitives/IconButton.d.ts +1 -0
  12. package/dist/primitives/NameTag.d.ts +2 -1
  13. package/dist/primitives/TileShell.d.ts +2 -1
  14. package/dist/stage/ParticipantTile.d.ts +3 -1
  15. package/dist/stage/TileSheet.d.ts +1 -1
  16. package/dist/stage/stage-view.d.ts +4 -0
  17. package/dist/status/StatusPage.d.ts +3 -1
  18. package/dist/ui.js +1 -1
  19. package/dist/whiteboard/export-board-image.d.ts +6 -0
  20. package/dist/whiteboard/native-board-session.d.ts +15 -0
  21. package/embedded/chalk-whiteboard/Figtree-Regular.ttf +0 -0
  22. package/embedded/chalk-whiteboard/Figtree-SemiBold.ttf +0 -0
  23. package/embedded/chalk-whiteboard/asset-manifest.json +19 -4
  24. package/embedded/chalk-whiteboard/chalk.css +44 -0
  25. package/embedded/chalk-whiteboard/licenses/Figtree.txt +93 -0
  26. package/embedded/chalk-whiteboard/renderer.js +1669 -1418
  27. package/package.json +11 -6
  28. package/src/components/EmbeddedWhiteboard.tsx +90 -6
  29. package/src/dock/Dock.tsx +14 -3
  30. package/src/dock/MoreSheet.tsx +23 -0
  31. package/src/frame/CallFrame.tsx +20 -33
  32. package/src/frame/call-controls.ts +4 -0
  33. package/src/frame/use-landscape-chrome.ts +22 -0
  34. package/src/index.ts +2 -2
  35. package/src/invites.ts +32 -1
  36. package/src/primitives/IconButton.tsx +6 -5
  37. package/src/primitives/NameTag.tsx +7 -1
  38. package/src/primitives/TileShell.tsx +3 -1
  39. package/src/space-client/create-native-space-client.ts +5 -4
  40. package/src/stage/ContentTile.tsx +64 -19
  41. package/src/stage/ParticipantTile.tsx +6 -4
  42. package/src/stage/Stage.tsx +37 -6
  43. package/src/stage/TileSheet.tsx +17 -2
  44. package/src/stage/stage-view.tsx +11 -1
  45. package/src/status/CallOverlays.tsx +1 -1
  46. package/src/status/StatusPage.tsx +12 -4
  47. package/src/whiteboard/export-board-image.ts +21 -0
  48. package/src/whiteboard/native-board-session.ts +29 -0
@@ -1,4 +1,5 @@
1
1
  // src/invites.ts
2
+ import { parseInviteCode } from "@q9labsai/chalk-client/invites";
2
3
  var CHALK_INVITE_HOSTS = ["chalkmeet.com", "chalk.q9labs.ai"];
3
4
  var CHALK_CUSTOM_PROTOCOLS = /* @__PURE__ */ new Set(["chalk:", "ai.q9labs.chalk.mobile:"]);
4
5
  var SPACE_SLUG_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/u;
@@ -27,6 +28,26 @@ function parseSpaceInviteLink(input) {
27
28
  return null;
28
29
  }
29
30
  }
31
+ function parseChalkInviteLink(input) {
32
+ const trimmed = input.trim();
33
+ const code = parseInviteCode(trimmed);
34
+ if (code) return { spaceInviteToken: code };
35
+ const legacy = parseSpaceInviteLink(trimmed);
36
+ if (legacy) return legacy;
37
+ const normalized = trimmed.includes("://") ? trimmed : CHALK_INVITE_HOSTS.some((host) => trimmed.startsWith(`${host}/`)) ? `https://${trimmed}` : null;
38
+ if (!normalized) return null;
39
+ try {
40
+ const parsed = new URL(normalized);
41
+ if (!CHALK_CUSTOM_PROTOCOLS.has(parsed.protocol) && !isAllowedWebInviteOrigin(parsed)) return null;
42
+ const pathSegments = parsed.pathname.split("/").filter(Boolean);
43
+ if (CHALK_CUSTOM_PROTOCOLS.has(parsed.protocol)) pathSegments.unshift(parsed.hostname);
44
+ if (pathSegments.length !== 1 || parsed.search || parsed.hash) return null;
45
+ const pathCode = parseInviteCode(decodeURIComponent(pathSegments[0] ?? ""));
46
+ return pathCode ? { spaceInviteToken: pathCode } : null;
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
30
51
  function isChalkInviteHost(hostname) {
31
52
  return CHALK_INVITE_HOSTS.some((host) => host === hostname);
32
53
  }
@@ -48,11 +69,12 @@ function getClipboardInviteSuggestion(clipboardText, currentInput = "") {
48
69
  if (normalizedClipboardText === currentInput.trim()) {
49
70
  return null;
50
71
  }
51
- return parseSpaceInviteLink(normalizedClipboardText) ? normalizedClipboardText : null;
72
+ return parseChalkInviteLink(normalizedClipboardText) ? normalizedClipboardText : null;
52
73
  }
53
74
 
54
75
  export {
55
76
  parseSpaceInviteLink,
77
+ parseChalkInviteLink,
56
78
  extractSpaceInviteFromLink,
57
79
  getClipboardInviteSuggestion
58
80
  };
@@ -507,11 +507,11 @@ function usePressAnimation(family) {
507
507
 
508
508
  // src/primitives/IconButton.tsx
509
509
  import { forwardRef, memo as memo2 } from "react";
510
- import { Pressable, StyleSheet, View } from "react-native";
510
+ import { ActivityIndicator, Pressable, StyleSheet, View } from "react-native";
511
511
  import Animated, { useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
512
512
  import { jsx as jsx5, jsxs } from "react/jsx-runtime";
513
513
  var IconButton = memo2(
514
- forwardRef(function IconButton2({ icon, accessibilityLabel, onPress, size = 44, tone = "raised", selected = false, off = false, caption, expanded, onCanvas = false, disabled = false, testID }, ref) {
514
+ forwardRef(function IconButton2({ icon, accessibilityLabel, onPress, size = 44, tone = "raised", selected = false, off = false, caption, expanded, onCanvas = false, disabled = false, busy = false, testID }, ref) {
515
515
  const { colors, elevation } = useTheme();
516
516
  const press = usePressAnimation("round");
517
517
  const base = selected ? colors.text : BASE[tone](colors);
@@ -530,8 +530,8 @@ var IconButton = memo2(
530
530
  {
531
531
  accessibilityLabel,
532
532
  accessibilityRole: "button",
533
- accessibilityState: { selected, disabled, expanded },
534
- disabled,
533
+ accessibilityState: { selected, disabled: disabled || busy, expanded, busy },
534
+ disabled: disabled || busy,
535
535
  hitSlop: size < 44 ? (44 - size) / 2 : void 0,
536
536
  onPress,
537
537
  onPressIn: press.onPressIn,
@@ -539,7 +539,7 @@ var IconButton = memo2(
539
539
  ref,
540
540
  testID,
541
541
  children: [
542
- /* @__PURE__ */ jsx5(Animated.View, { ref: roundRef, style: [roundStyle, background, press.scaleStyle], children: /* @__PURE__ */ jsx5(Icon, { color: iconColor, name: icon, size: tone === "ghost" ? 18 : 20 }) }),
542
+ /* @__PURE__ */ jsx5(Animated.View, { ref: roundRef, style: [roundStyle, background, press.scaleStyle], children: busy ? /* @__PURE__ */ jsx5(ActivityIndicator, { color: iconColor, size: "small" }) : /* @__PURE__ */ jsx5(Icon, { color: iconColor, name: icon, size: tone === "ghost" ? 18 : 20 }) }),
543
543
  caption ? /* @__PURE__ */ jsx5(View, { pointerEvents: "none", style: styles.captionBox, children: /* @__PURE__ */ jsx5(ChalkText, { numberOfLines: 1, tone: "textMuted", variant: "caption", children: caption }) }) : null
544
544
  ]
545
545
  }
package/dist/client.js CHANGED
@@ -39,7 +39,7 @@ function ensureRandomUUID() {
39
39
  function createNativeSpaceClient(options) {
40
40
  ensureRandomUUID();
41
41
  const { storage } = options;
42
- const syncStartupTimeoutMs = options.syncStartupTimeoutMs ?? 3e4;
42
+ const syncDialTimeoutMs = options.syncStartupTimeoutMs ?? 3e4;
43
43
  const apiBaseURL = options.baseUrl ?? "https://api.chalkmeet.com";
44
44
  const syncURL = options.syncUrl ?? defaultSyncURL(apiBaseURL);
45
45
  const fetch = globalThis.fetch;
@@ -62,9 +62,9 @@ function createNativeSpaceClient(options) {
62
62
  getDisplayMedia: async () => await mediaDevices.getDisplayMedia()
63
63
  },
64
64
  createMediaClient: (input) => createMediaClient(apiBaseURL, input, fetch),
65
- createSyncClient: (input) => createSyncClient(syncURL, input, lifecycle, webSocket, storage, syncStartupTimeoutMs),
65
+ createSyncClient: (input) => createSyncClient(syncURL, input, lifecycle, webSocket, storage, syncDialTimeoutMs),
66
66
  createChatFileTransport: (input) => createChatFileTransport(apiBaseURL, input, fetch),
67
- createWhiteboardClient: options.whiteboardURL === null ? void 0 : (input) => createWhiteboardClient(apiBaseURL, options.whiteboardURL ?? whiteboardURL(syncURL), input, fetch, lifecycle, webSocket, syncStartupTimeoutMs),
67
+ createWhiteboardClient: options.whiteboardURL === null ? void 0 : (input) => createWhiteboardClient(apiBaseURL, options.whiteboardURL ?? whiteboardURL(syncURL), input, fetch, lifecycle, webSocket, syncDialTimeoutMs),
68
68
  subscribeForeground: (listener) => {
69
69
  const subscription = AppState.addEventListener("change", (state) => {
70
70
  if (state === "active") listener();
@@ -80,7 +80,8 @@ function createNativeSpaceClient(options) {
80
80
  whiteboardUrl: options.whiteboardURL,
81
81
  dependencies,
82
82
  fetch,
83
- syncStartupTimeoutMs,
83
+ // Keep the 30s native dial allowance, plus time for its replacement.
84
+ syncStartupTimeoutMs: options.syncStartupTimeoutMs ?? 6e4,
84
85
  initialMicrophoneEnabled: options.microphone,
85
86
  initialCameraEnabled: options.camera
86
87
  }
@@ -1,6 +1,9 @@
1
- import { type ChalkEmbeddedWhiteboardTransport } from "@q9labsai/chalk-whiteboard/embedded";
1
+ import { type ChalkEmbeddedWhiteboardTransport, type ChalkEmbeddedBoardContext } from "@q9labsai/chalk-whiteboard/embedded";
2
2
  import { type StyleProp, type ViewStyle } from "react-native";
3
3
  export interface EmbeddedWhiteboardProps {
4
+ readonly board: ChalkEmbeddedBoardContext;
5
+ readonly onFollow?: (participantId: string | null) => void;
6
+ readonly onCloseBoard?: () => void;
4
7
  readonly transport: ChalkEmbeddedWhiteboardTransport;
5
8
  readonly journeyId: string;
6
9
  readonly traceparent?: string;
@@ -27,14 +30,15 @@ export interface EmbeddedWhiteboardProps {
27
30
  readonly format: "png" | "svg";
28
31
  readonly mimeType: string;
29
32
  readonly dataURL: string;
30
- }) => void;
33
+ readonly action?: "download" | "copy";
34
+ }) => void | Promise<void>;
31
35
  }
32
36
  export declare const embeddedWhiteboardWebViewSecurityPolicy: Readonly<{
33
37
  allowFileAccess: true;
34
38
  allowFileAccessFromFileURLs: false;
35
39
  allowUniversalAccessFromFileURLs: false;
36
40
  cacheEnabled: false;
37
- domStorageEnabled: false;
41
+ domStorageEnabled: true;
38
42
  javaScriptCanOpenWindowsAutomatically: false;
39
43
  javaScriptEnabled: true;
40
44
  mixedContentMode: "never";
@@ -42,4 +46,4 @@ export declare const embeddedWhiteboardWebViewSecurityPolicy: Readonly<{
42
46
  sharedCookiesEnabled: false;
43
47
  thirdPartyCookiesEnabled: false;
44
48
  }>;
45
- export declare function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, canDraw, canClear, theme: themeOverride, localParticipantColor, rendererURL: rendererURLOverride, style, testID, onMetric, onError, onUserExport }: EmbeddedWhiteboardProps): React.JSX.Element;
49
+ export declare function EmbeddedWhiteboard({ board, onFollow, onCloseBoard, transport, journeyId, traceparent, tracestate, canDraw, canClear, theme: themeOverride, localParticipantColor, rendererURL: rendererURLOverride, style, testID, onMetric, onError, onUserExport, }: EmbeddedWhiteboardProps): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ /** Landscape controls overlay the stage, so board tools need room above them. */
2
+ export declare const LandscapeControlsContext: import("react").Context<boolean>;
@@ -0,0 +1,8 @@
1
+ /** A visible board stays interactive instead of acquiring the tap-to-reveal overlay. */
2
+ export declare function useLandscapeChrome({ fades, boardVisible }: {
3
+ readonly fades: boolean;
4
+ readonly boardVisible: boolean;
5
+ }): {
6
+ hidden: boolean;
7
+ show: () => void;
8
+ };
package/dist/index.d.ts CHANGED
@@ -7,6 +7,6 @@ export type { ColorScheme, Palette } from "./theme/tokens";
7
7
  export { ChalkProvider, useSpaceClient } from "./context/space-client-context";
8
8
  export type { ChalkProviderProps } from "./context/space-client-context";
9
9
  export { useCan, useChat, useConnection, useMedia, useParticipants, useReactions, useRecording, useSelf, useWhiteboard } from "./hooks/space-hooks";
10
- export { extractSpaceInviteFromLink, getClipboardInviteSuggestion, parseSpaceInviteLink } from "./invites";
11
- export type { SpaceInviteLink } from "./invites";
10
+ export { extractSpaceInviteFromLink, getClipboardInviteSuggestion, parseChalkInviteLink, parseSpaceInviteLink } from "./invites";
11
+ export type { ChalkInviteLink, SpaceInviteLink } from "./invites";
12
12
  export { buildChalkInviteLink } from "./utils/build-chalk-invite-link";