@q9labsai/chalk-react 5.1.0 → 5.2.1

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 (50) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/dist/bindings/hooks.d.ts +2 -0
  3. package/dist/{chunk-QDEKMRH2.js → chunk-53ZA776J.js} +72 -60
  4. package/dist/{chunk-ZFWIMKUC.js → chunk-HWQLW4JR.js} +55 -7
  5. package/dist/{chunk-XOHNIYSR.js → chunk-RQXFFDOS.js} +1865 -2870
  6. package/dist/components/board/Board.d.ts +3 -22
  7. package/dist/components/board/board-draw-policy.d.ts +15 -0
  8. package/dist/components/chalk/Chalk.d.ts +12 -0
  9. package/dist/components/chalk/ReportProblemDialog.d.ts +12 -0
  10. package/dist/components/chalk/StatusSurface.d.ts +8 -2
  11. package/dist/components/chalk-ui/ChalkSheet.d.ts +1 -1
  12. package/dist/components/chalk-ui/ChalkToast.d.ts +7 -1
  13. package/dist/components/chalk-ui/index.d.ts +6 -5
  14. package/dist/components/control-bar/command-failure.d.ts +105 -1
  15. package/dist/components/control-bar/control-bar-behavior.d.ts +5 -1
  16. package/dist/components/index.js +7 -3
  17. package/dist/components/offline-actions/OfflineActions.d.ts +2 -1
  18. package/dist/components/space-header/CallDetails.d.ts +4 -2
  19. package/dist/components/space-header/space-header-contract.d.ts +6 -0
  20. package/dist/components/space-view/SpaceView.d.ts +15 -3
  21. package/dist/components/space-view/countdown.d.ts +5 -0
  22. package/dist/components/stage/Stage.d.ts +1 -1
  23. package/dist/components/stage/stage-items.d.ts +4 -0
  24. package/dist/components/stage/stage-layout.d.ts +6 -2
  25. package/dist/components/toast-stack/CallEventIcon.d.ts +1 -1
  26. package/dist/components/toast-stack/NoticeButton.d.ts +7 -0
  27. package/dist/components/toast-stack/ToastStack.d.ts +13 -2
  28. package/dist/components/toast-stack/call-events.d.ts +2 -1
  29. package/dist/components/toast-stack/notice-announcement.d.ts +4 -0
  30. package/dist/components/toast-stack/toast-layout-snapshot.d.ts +4 -0
  31. package/dist/components/toast-stack/useToastCapacity.d.ts +7 -0
  32. package/dist/headless.js +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +24 -3
  35. package/dist/public-surface.contract.d.ts +1 -1
  36. package/dist/test-support/index.js +3 -3
  37. package/package.json +5 -5
  38. package/dist/components/board/BoardCursors.d.ts +0 -21
  39. package/dist/components/board/BoardIcon.d.ts +0 -46
  40. package/dist/components/board/BoardIsland.d.ts +0 -21
  41. package/dist/components/board/BoardMenu.d.ts +0 -15
  42. package/dist/components/board/BoardStyles.d.ts +0 -2
  43. package/dist/components/board/board-engine.d.ts +0 -31
  44. package/dist/components/board/board-history.d.ts +0 -7
  45. package/dist/components/board/board-model.d.ts +0 -86
  46. package/dist/components/board/board-toasts.d.ts +0 -6
  47. package/dist/components/board/board-view-versions.d.ts +0 -7
  48. package/dist/components/chalk-ui/ChalkMenu.d.ts +0 -20
  49. package/dist/components/chalk-ui/ChalkPopover.d.ts +0 -11
  50. package/dist/components/chalk-ui/ChalkTooltip.d.ts +0 -5
@@ -1,22 +1,3 @@
1
- import type { ChalkWhiteboardView } from "@q9labsai/chalk-client";
2
- import type { Participant } from "../participant-grid/ParticipantGrid";
3
- import type { WhiteboardViewProps } from "../whiteboard-view/WhiteboardView";
4
- import { type CallTheme } from "./board-model";
5
- export type BoardProps = {
6
- readonly board: WhiteboardViewProps;
7
- /** False for the Grid tile: the live drawing with no controls. */
8
- readonly primary: boolean;
9
- readonly visible: boolean;
10
- readonly colorScheme: CallTheme;
11
- readonly people: readonly Participant[];
12
- readonly following: string | null;
13
- readonly onFollow: (participantId: string | null) => void;
14
- /** Absent, or answering false, when the board service does not share views. */
15
- readonly sendView?: (view: ChalkWhiteboardView) => boolean;
16
- readonly onClose?: () => void;
17
- };
18
- /**
19
- * Chalk's board: Excalidraw draws, and every control around it is the call's own. Each person picks their own
20
- * surface and island place; the drawing, the cursors and the views are shared.
21
- */
22
- export declare function Board({ board, primary, visible, colorScheme, people, following, onFollow, sendView, onClose }: BoardProps): import("react").JSX.Element;
1
+ import { type BoardProps as SharedBoardProps } from "@q9labsai/chalk-whiteboard/react";
2
+ export type BoardProps = Omit<SharedBoardProps, "isHost" | "connectionStatus" | "sceneId" | "sceneStatus" | "ownParticipantId" | "viewBounds" | "renderCursorAvatar" | "onExport" | "participantIds" | "whoCanDraw">;
3
+ export declare function Board(props: BoardProps): import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import type { ChalkWhiteboardDrawPolicy } from "@q9labsai/chalk-client";
2
+ import type { BoardToast } from "@q9labsai/chalk-whiteboard/react";
3
+ export type WhoCanDraw = {
4
+ readonly policy: ChalkWhiteboardDrawPolicy;
5
+ /** Everyone in the call who is not a host, because hosts can always draw under hosts only and picked people. */
6
+ readonly people: readonly {
7
+ readonly id: string;
8
+ readonly name: string;
9
+ readonly picked: boolean;
10
+ }[];
11
+ readonly onPolicy: (policy: ChalkWhiteboardDrawPolicy) => void;
12
+ readonly onPick: (id: string, picked: boolean) => void;
13
+ };
14
+ /** The host's call-wide drawing control. Undefined for people who aren't hosts and on Sync servers without draw_policy_v1. */
15
+ export declare function useWhoCanDraw(toast: (toast: BoardToast) => void): WhoCanDraw | undefined;
@@ -1,6 +1,7 @@
1
1
  import { type ChatUploadFile, type ClientEventMap, type GetAccess, type SpaceClient } from "@q9labsai/chalk-client";
2
2
  import type React from "react";
3
3
  import { type ChalkColorScheme, type ChalkTheme } from "../../theme";
4
+ import { type SpaceViewProps } from "../space-view/SpaceView";
4
5
  export type SpaceLayout = "focus" | "grid";
5
6
  export type ChalkFeatures = {
6
7
  readonly chat?: boolean;
@@ -43,6 +44,10 @@ export type ChalkProps = SpaceIntegration & SpaceEventCallbacks & {
43
44
  readonly theme?: ChalkTheme;
44
45
  readonly shareUrl?: string;
45
46
  readonly onReportProblem?: import("../space-header/SpaceHeader").SpaceHeaderProps["onReportProblem"];
47
+ /** Opens an app-owned dialog that can outlive this call view. */
48
+ readonly onOpenReportProblem?: () => void;
49
+ /** Hides new report actions and disables Send without discarding an open report. */
50
+ readonly reportUnavailableReason?: string;
46
51
  readonly onColorSchemeChange?: (colorScheme: ChalkColorScheme) => void;
47
52
  readonly pickChatFiles?: () => Promise<readonly ChatUploadFile[]>;
48
53
  readonly spaceName?: string;
@@ -54,6 +59,13 @@ export type ChalkProps = SpaceIntegration & SpaceEventCallbacks & {
54
59
  readonly onRejoin?: () => void;
55
60
  /** Home on the pages shown after the call. Without it the page has no Home action. */
56
61
  readonly onHome?: () => void;
62
+ /** App-owned warning copy and actions for a call's duration limit. */
63
+ readonly timeLimit?: SpaceViewProps["timeLimit"] & {
64
+ readonly endAction?: {
65
+ readonly label: string;
66
+ readonly onClick: () => void;
67
+ };
68
+ };
57
69
  /** Host-provided terminal reason when the transport cannot distinguish it. */
58
70
  readonly terminalState?: "removed" | "full" | "elsewhere";
59
71
  };
@@ -0,0 +1,12 @@
1
+ import type { RefObject } from "react";
2
+ import type { ChalkProps } from "./Chalk";
3
+ /** The call report form for app-owned terminal screens outside Chalk. */
4
+ export declare function ReportProblemDialog({ open, onClose, onReportProblem, colorScheme, focusScope, diagnostics, unavailableReason, }: {
5
+ readonly diagnostics?: string;
6
+ readonly unavailableReason?: string;
7
+ readonly open: boolean;
8
+ readonly onClose: () => void;
9
+ readonly onReportProblem: NonNullable<ChalkProps["onReportProblem"]>;
10
+ readonly colorScheme: "light" | "dark";
11
+ readonly focusScope: RefObject<HTMLElement | null>;
12
+ }): import("react").JSX.Element;
@@ -1,12 +1,18 @@
1
1
  import type React from "react";
2
- import type { ErrorCode } from "@q9labsai/chalk-client";
2
+ import { type ClientFailure, type ErrorCode } from "@q9labsai/chalk-client";
3
3
  import { type ChalkTheme } from "../../theme";
4
4
  export type StatusSurfacePhase = "entering" | "left" | "episode-ended" | "failed" | "removed" | "full" | "elsewhere";
5
5
  export interface StatusSurfaceProps {
6
6
  readonly phase: StatusSurfacePhase;
7
7
  readonly callName?: string;
8
8
  readonly reason?: string;
9
+ readonly episodeEndReason?: string;
10
+ readonly endAction?: {
11
+ readonly label: string;
12
+ readonly onClick: () => void;
13
+ };
9
14
  readonly errorCode?: ErrorCode;
15
+ readonly sync?: ClientFailure["sync"];
10
16
  readonly theme?: ChalkTheme;
11
17
  readonly onRejoin?: () => void;
12
18
  readonly onHome?: () => void;
@@ -16,4 +22,4 @@ export interface StatusSurfaceProps {
16
22
  readonly retryPending?: boolean;
17
23
  }
18
24
  /** All terminal call states share the same quiet page and host-owned navigation. */
19
- export declare function StatusSurface({ phase, callName, reason, errorCode, theme, onRejoin, onHome, onRetry, onReportProblem, rejoinDisabled, retryPending }: StatusSurfaceProps): React.JSX.Element;
25
+ export declare function StatusSurface({ phase, callName, reason, episodeEndReason, endAction, errorCode, sync, theme, onRejoin, onHome, onRetry, onReportProblem, rejoinDisabled, retryPending }: StatusSurfaceProps): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  export interface ChalkSheetProps {
3
- readonly variant?: "default" | "details" | "panel" | "ready";
3
+ readonly variant?: "default" | "details" | "panel" | "ready" | "stage";
4
4
  readonly open: boolean;
5
5
  readonly onOpenChange: (open: boolean) => void;
6
6
  readonly title: string;
@@ -1,6 +1,10 @@
1
1
  import { type ReactNode } from "react";
2
2
  export interface ChalkToastProps {
3
3
  readonly message: ReactNode;
4
+ /** Stable semantic identity for rich message content. Change it when the message changes. */
5
+ readonly announcementKey?: string;
6
+ /** Plain speech text for custom message components. Literal text and markup are read without mounting them. */
7
+ readonly announcementText?: string;
4
8
  readonly icon?: ReactNode;
5
9
  readonly type?: "info" | "success" | "warning" | "error";
6
10
  readonly duration?: number;
@@ -8,6 +12,8 @@ export interface ChalkToastProps {
8
12
  readonly label: string;
9
13
  readonly onClick: () => void;
10
14
  };
15
+ /** Enables live announcements. Pass false for an already-announced notice; a replacement message can enable the same mounted toast later. */
16
+ readonly announce?: boolean;
11
17
  readonly onDismiss: () => void;
12
18
  }
13
- export declare function ChalkToast({ message, type, duration, action, icon, onDismiss }: ChalkToastProps): import("react").JSX.Element;
19
+ export declare function ChalkToast({ message, announcementKey, announcementText, type, duration, action, icon, announce, onDismiss }: ChalkToastProps): import("react").JSX.Element;
@@ -18,8 +18,8 @@ export { ChalkDialogPanel } from "./ChalkDialogPanel";
18
18
  export type { ChalkDialogPanelProps } from "./ChalkDialogPanel";
19
19
  export { ChalkBackdrop } from "./ChalkBackdrop";
20
20
  export type { ChalkBackdropProps } from "./ChalkBackdrop";
21
- export { ChalkMenu, ChalkMenuItem } from "./ChalkMenu";
22
- export type { ChalkMenuItemProps, ChalkMenuProps } from "./ChalkMenu";
21
+ export { ChalkMenu, ChalkMenuItem } from "@q9labsai/chalk-whiteboard/react";
22
+ export type { ChalkMenuItemProps, ChalkMenuProps } from "@q9labsai/chalk-whiteboard/react";
23
23
  export { ChalkAlert } from "./ChalkAlert";
24
24
  export type { ChalkAlertProps } from "./ChalkAlert";
25
25
  export { ChalkEmptyState } from "./ChalkEmptyState";
@@ -27,10 +27,11 @@ export type { ChalkEmptyStateProps } from "./ChalkEmptyState";
27
27
  export { ChalkSpinner } from "./ChalkSpinner";
28
28
  export type { ChalkSpinnerProps } from "./ChalkSpinner";
29
29
  export type { ChalkButtonVariant, ChalkTone } from "./common";
30
- export { ChalkMenuLabel } from "./ChalkMenu";
31
- export { ChalkPopover } from "./ChalkPopover";
30
+ export { ChalkMenuLabel } from "@q9labsai/chalk-whiteboard/react";
31
+ export { ChalkPopover } from "@q9labsai/chalk-whiteboard/react";
32
32
  export { ChalkSegmentedControl } from "./ChalkSegmentedControl";
33
33
  export { ChalkCopyButton } from "./ChalkCopyButton";
34
34
  export { ChalkSheet, type ChalkSheetProps } from "./ChalkSheet";
35
35
  export { ChalkToast, type ChalkToastProps } from "./ChalkToast";
36
- export { ChalkTooltip } from "./ChalkTooltip";
36
+ export { ChalkTooltip } from "@q9labsai/chalk-whiteboard/react";
37
+ export { ChalkMenuPrimitive, ChalkPopoverPrimitive } from "@q9labsai/chalk-whiteboard/react";
@@ -1,2 +1,106 @@
1
- import { type ClientFailure } from "@q9labsai/chalk-client";
1
+ import { type ClientFailure, type MediaSource } from "@q9labsai/chalk-client";
2
+ export type MediaCommandSource = MediaSource | "speaker";
3
+ export type MediaCommandAction = "start" | "stop" | "select" | "test" | "request";
4
+ type Operation = MediaCommandAction | "change";
5
+ type Context = {
6
+ readonly source?: MediaCommandSource;
7
+ readonly recoverable: boolean;
8
+ };
9
+ type Copy = (context: Context) => string;
10
+ type Rule = {
11
+ readonly copy: Readonly<Record<Operation, Copy>>;
12
+ readonly retry: boolean;
13
+ };
2
14
  export declare function commandFailure(cause: unknown): ClientFailure;
15
+ /** Every client code has a media-context policy. Non-media commands are preserved at the boundary below. */
16
+ export declare const MEDIA_FAILURE_POLICY: {
17
+ "access.invalid": Rule;
18
+ "access.unavailable": Rule;
19
+ "chat.cursor_reset_required": Rule;
20
+ "chat.payload_invalid": Rule;
21
+ "client.internal_error": Rule;
22
+ "collaboration.unavailable": Rule;
23
+ "command.rate_limited": Rule;
24
+ "command.rejected": Rule;
25
+ "connection.invalid_state": {
26
+ copy: {
27
+ test: (context: Context) => string;
28
+ request: (context: Context) => string;
29
+ start: (context: Context) => string;
30
+ stop: (context: Context) => string;
31
+ select: (context: Context) => string;
32
+ change: (context: Context) => string;
33
+ };
34
+ retry: true;
35
+ };
36
+ "connection.join_cleanup_unconfirmed": Rule;
37
+ "connection.leave_unconfirmed": Rule;
38
+ "connection.media_recovery_exhausted": Rule;
39
+ "connection.media_start_failed": Rule;
40
+ "connection.state_digest_recovery_failed": Rule;
41
+ "connection.sync_recovery_exhausted": Rule;
42
+ "connection.sync_start_failed": Rule;
43
+ "connection.sync_hello_timeout": Rule;
44
+ "environment.unsupported": {
45
+ copy: {
46
+ stop: (context: Context) => string;
47
+ start: () => string;
48
+ request: () => string;
49
+ select: (context: Context) => "Media capture is unavailable in this environment. Use a supported browser over HTTPS or the native app." | "This browser can’t change your speaker. Use your system sound settings to choose an output device.";
50
+ test: () => string;
51
+ change: (context: Context) => "Media capture is unavailable in this environment. Use a supported browser over HTTPS or the native app." | "This browser can’t change your speaker. Use your system sound settings to choose an output device.";
52
+ };
53
+ retry: false;
54
+ };
55
+ "episode.ended": {
56
+ copy: {
57
+ start: () => string;
58
+ stop: () => string;
59
+ select: () => string;
60
+ test: () => string;
61
+ request: () => string;
62
+ change: () => string;
63
+ };
64
+ retry: false;
65
+ };
66
+ "media.permission_denied": Rule;
67
+ "media.device_not_found": Rule;
68
+ "media.device_busy": {
69
+ copy: Readonly<Record<Operation, Copy>>;
70
+ retry: true;
71
+ };
72
+ "media.device_constraint_invalid": Rule;
73
+ "media.capture_failed": {
74
+ copy: {
75
+ stop: (context: Context) => string;
76
+ select: (context: Context) => string;
77
+ test: (context: Context) => string;
78
+ start: Copy;
79
+ request: Copy;
80
+ change: (context: Context) => string;
81
+ };
82
+ retry: true;
83
+ };
84
+ "media.request_invalid": {
85
+ copy: {
86
+ test: () => string;
87
+ request: () => string;
88
+ select: (context: Context) => string;
89
+ start: () => string;
90
+ stop: () => string;
91
+ change: () => string;
92
+ };
93
+ retry: false;
94
+ };
95
+ "media.timeout": Rule;
96
+ "offline.discarded": Rule;
97
+ "participant.invalid": Rule;
98
+ "reaction.invalid": Rule;
99
+ "whiteboard.unavailable": Rule;
100
+ };
101
+ export declare function commandFailurePresentation(failure: ClientFailure, source?: MediaCommandSource, operation?: Operation, hasExactRetry?: boolean): {
102
+ readonly message: string;
103
+ readonly retry: boolean;
104
+ };
105
+ export declare function commandFailureMessage(failure: ClientFailure, source?: MediaCommandSource, operation?: MediaCommandAction): string;
106
+ export {};
@@ -1,4 +1,5 @@
1
1
  import type React from "react";
2
+ import { type MediaCommandSource, type MediaCommandAction } from "./command-failure";
2
3
  import type { CameraPreview, ClientFailure, MediaSource, ScreenShareOptions } from "@q9labsai/chalk-client";
3
4
  import { type ParticipantGradientPreference } from "../../utils/colorGenerator";
4
5
  export interface MediaDevice {
@@ -93,7 +94,8 @@ export interface ControlBarProps {
93
94
  /** Set for hosts: the leave button opens a menu with Leave call and End call for everyone. */
94
95
  readonly onEndForEveryone?: () => void;
95
96
  readonly onLeft?: () => void;
96
- readonly onCommandError?: (failure: ClientFailure | null, source?: MediaSource) => void;
97
+ /** The second argument retains the published MediaSource contract; the third also identifies speaker commands. */
98
+ readonly onCommandError?: (failure: ClientFailure | null, source?: MediaSource, commandSource?: MediaCommandSource, action?: MediaCommandAction, retryCommand?: () => Promise<unknown>) => void;
97
99
  readonly participantColorSeed?: string;
98
100
  readonly participantGradientPreference?: ParticipantGradientPreference;
99
101
  readonly className?: string;
@@ -124,6 +126,8 @@ export declare function useControlBarSurfaceBehavior({ density, buttons, audioIn
124
126
  interface ConnectedControlBarBehavior {
125
127
  readonly surfaceProps: ControlBarSurfaceProps;
126
128
  readonly commandError: ClientFailure | null;
129
+ readonly commandSource?: MediaCommandSource;
130
+ readonly commandAction?: MediaCommandAction;
127
131
  }
128
132
  export declare function useConnectedControlBarBehavior(props: ControlBarProps): ConnectedControlBarBehavior;
129
133
  export {};
@@ -5,7 +5,7 @@ import {
5
5
  RecordingHistoryPanel,
6
6
  RecordingSpaceView,
7
7
  RecordingWhiteboardView
8
- } from "../chunk-QDEKMRH2.js";
8
+ } from "../chunk-53ZA776J.js";
9
9
  import {
10
10
  loadRecordingWhiteboardFiles,
11
11
  parseRecordingWhiteboardStateV1,
@@ -29,8 +29,10 @@ import {
29
29
  ChalkMenu,
30
30
  ChalkMenuItem,
31
31
  ChalkMenuLabel,
32
+ ChalkMenuPrimitive,
32
33
  ChalkPanel,
33
34
  ChalkPopover,
35
+ ChalkPopoverPrimitive,
34
36
  ChalkSegmentedControl,
35
37
  ChalkSheet,
36
38
  ChalkSpinner,
@@ -45,10 +47,10 @@ import {
45
47
  ReactionsOverlay,
46
48
  ScreenShareView,
47
49
  Stage
48
- } from "../chunk-XOHNIYSR.js";
50
+ } from "../chunk-RQXFFDOS.js";
49
51
  import {
50
52
  buildStageItems
51
- } from "../chunk-ZFWIMKUC.js";
53
+ } from "../chunk-HWQLW4JR.js";
52
54
  import "../chunk-4U7QZC72.js";
53
55
  export {
54
56
  AdmissionPanel,
@@ -67,8 +69,10 @@ export {
67
69
  ChalkMenu,
68
70
  ChalkMenuItem,
69
71
  ChalkMenuLabel,
72
+ ChalkMenuPrimitive,
70
73
  ChalkPanel,
71
74
  ChalkPopover,
75
+ ChalkPopoverPrimitive,
72
76
  ChalkSegmentedControl,
73
77
  ChalkSheet,
74
78
  ChalkSpinner,
@@ -3,6 +3,7 @@ import React from "react";
3
3
  export declare const RECONNECTING_GRACE_MS = 2000;
4
4
  export declare function offlineNoticeText(pendingCount: number, online: boolean): string;
5
5
  /** Keep queued actions automatic while preserving the reconnecting notice. */
6
- export declare function OfflineActions({ reconnecting: requestedReconnecting }?: {
6
+ export declare function OfflineActions({ reconnecting: requestedReconnecting, hasNotice }?: {
7
7
  readonly reconnecting?: boolean;
8
+ readonly hasNotice?: boolean;
8
9
  }): React.JSX.Element | null;
@@ -1,13 +1,15 @@
1
1
  import { type RefObject } from "react";
2
2
  import type { SpaceHeaderProps } from "./space-header-contract";
3
3
  export declare const CALL_SHORTCUTS: readonly [readonly ["Mute or unmute", "⌘ D"], readonly ["Turn camera on or off", "⌘ E"], readonly ["Raise or lower hand", "⌃ ⌘ H"], readonly ["Open or close chat", "⌃ ⌘ C"], readonly ["Open or close people", "⌃ ⌘ P"], readonly ["Switch layout", "⌃ ⌘ L"], readonly ["Talk while muted", "Hold Space"], readonly ["Show shortcuts", "?"], readonly ["Close a menu or panel", "Esc"]];
4
- export declare function CallDialog({ kind, open, onClose, onReportProblem, diagnostics, returnFocus, }: {
4
+ export declare function CallDialog({ kind, open, onClose, onReportProblem, diagnostics, returnFocus, focusScope, unavailableReason, }: {
5
5
  readonly kind: "shortcuts" | "report";
6
6
  readonly open: boolean;
7
7
  readonly onClose: () => void;
8
8
  readonly onReportProblem?: SpaceHeaderProps["onReportProblem"];
9
9
  readonly diagnostics: string;
10
- readonly returnFocus: RefObject<HTMLButtonElement | null>;
10
+ readonly returnFocus?: RefObject<HTMLButtonElement | null>;
11
+ readonly focusScope: RefObject<HTMLElement | null>;
12
+ readonly unavailableReason?: string;
11
13
  }): import("react").JSX.Element;
12
14
  export declare function CallDetails({ shareUrl, spaceName, onClose, diagnostics, colorScheme, onColorSchemeChange, sounds, onSoundsChange, onDialog, onReportProblem, }: Pick<SpaceHeaderProps, "spaceName" | "shareUrl" | "diagnostics" | "colorScheme" | "onColorSchemeChange" | "onReportProblem"> & {
13
15
  readonly onClose: () => void;
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from "react";
1
2
  export interface SpaceHeaderProps {
2
3
  spaceName: string;
3
4
  people?: readonly {
@@ -18,6 +19,8 @@ export interface SpaceHeaderProps {
18
19
  readonly description: string;
19
20
  readonly diagnostics?: string;
20
21
  }) => void | Promise<void>;
22
+ reportUnavailableReason?: string;
23
+ onOpenReportProblem?: () => void;
21
24
  shortcuts?: {
22
25
  readonly isMuted?: boolean;
23
26
  readonly onToggleMute?: () => void;
@@ -32,10 +35,13 @@ export interface SpaceHeaderProps {
32
35
  colorScheme?: "light" | "dark";
33
36
  onColorSchemeChange?: (colorScheme: "light" | "dark") => void;
34
37
  duration?: number;
38
+ timeLeft?: number | null;
35
39
  isRecording?: boolean;
36
40
  isTranscribing?: boolean;
37
41
  layout?: "grid" | "focus";
38
42
  onLayoutChange?: (layout: "grid" | "focus") => void;
43
+ /** A control for notices that have no room on the stage, placed at the header's end, before the people button. */
44
+ notices?: ReactNode;
39
45
  className?: string;
40
46
  }
41
47
  export declare function formatDuration(seconds: number): string;
@@ -1,4 +1,5 @@
1
- import { type ChalkWhiteboardView } from "@q9labsai/chalk-client";
1
+ import { type MediaCommandSource, type MediaCommandAction } from "../control-bar/command-failure";
2
+ import { type ChalkWhiteboardView, type ClientFailure } from "@q9labsai/chalk-client";
2
3
  import React from "react";
3
4
  import type { ChatUploadFile } from "@q9labsai/chalk-client";
4
5
  import { type ReconnectingOverlayProps } from "../reconnecting-overlay/ReconnectingOverlay";
@@ -23,6 +24,13 @@ export interface SpaceViewWhiteboard {
23
24
  readonly sendView?: (view: ChalkWhiteboardView) => boolean;
24
25
  }
25
26
  export interface SpaceViewProps {
27
+ readonly timeLimit?: {
28
+ readonly message: string;
29
+ readonly action?: {
30
+ readonly label: string;
31
+ readonly onClick: () => void;
32
+ };
33
+ };
26
34
  readonly colorScheme?: "light" | "dark";
27
35
  readonly onColorSchemeChange?: (colorScheme: "light" | "dark") => void;
28
36
  readonly spaceName: string;
@@ -30,6 +38,8 @@ export interface SpaceViewProps {
30
38
  readonly callLinkOpen?: boolean;
31
39
  readonly onCallLinkToggle?: () => void;
32
40
  readonly onReportProblem?: import("../space-header/SpaceHeader").SpaceHeaderProps["onReportProblem"];
41
+ readonly reportUnavailableReason?: string;
42
+ readonly onOpenReportProblem?: () => void;
33
43
  readonly inviteLink?: string;
34
44
  readonly pickChatFiles?: () => Promise<readonly ChatUploadFile[]>;
35
45
  readonly stageBackground?: boolean;
@@ -39,7 +49,9 @@ export interface SpaceViewProps {
39
49
  readonly initialPanel?: SpacePanel | null;
40
50
  readonly features?: SpaceViewFeatures;
41
51
  readonly generatedAvatars?: boolean;
42
- readonly commandError?: string;
52
+ readonly commandError?: string | ClientFailure;
53
+ readonly commandSource?: MediaCommandSource;
54
+ readonly commandAction?: MediaCommandAction;
43
55
  readonly onDismissCommandError?: () => void;
44
56
  readonly onToggleWhiteboard?: () => void;
45
57
  readonly whiteboard?: SpaceViewWhiteboard;
@@ -51,4 +63,4 @@ export interface SpaceViewProps {
51
63
  readonly onEndEpisode?: () => void | Promise<void>;
52
64
  readonly className?: string;
53
65
  }
54
- export declare function SpaceView({ colorScheme, onColorSchemeChange, spaceName, shareUrl, callLinkOpen, onCallLinkToggle, onReportProblem, inviteLink, pickChatFiles, stageBackground, layout: controlledLayout, onLayoutChange, initialPanel, features, generatedAvatars, commandError: externalCommandError, onDismissCommandError, onToggleWhiteboard, whiteboard, reconnecting, overlay, onLeft, onEndEpisode, className, }: SpaceViewProps): React.JSX.Element;
66
+ export declare function SpaceView({ timeLimit, colorScheme, onColorSchemeChange, spaceName, shareUrl, callLinkOpen, onCallLinkToggle, onReportProblem, reportUnavailableReason, onOpenReportProblem, inviteLink, pickChatFiles, stageBackground, layout: controlledLayout, onLayoutChange, initialPanel, features, generatedAvatars, commandError: externalCommandError, commandSource: externalCommandSource, commandAction: externalCommandAction, onDismissCommandError, onToggleWhiteboard, whiteboard, reconnecting, overlay, onLeft, onEndEpisode, className, }: SpaceViewProps): React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ /** The latest warning only: joining late or resuming a hidden tab never queues old warnings. */
2
+ export declare function callCountdown(deadline: string | null | undefined, now: number, previousSeconds?: number | null): {
3
+ seconds: number | null;
4
+ warning: 10 | 5 | 1 | null;
5
+ };
@@ -24,7 +24,7 @@ export interface StageProps {
24
24
  readonly followingId?: string | null;
25
25
  readonly onFollowChange?: (id: string) => void;
26
26
  readonly clickAction?: "pin" | "follow";
27
- /** Upper bound of visible tiles; the rest fold into a +N People tile. */
27
+ /** Upper bound of grid tiles, or secondary tiles in spotlight; overflow includes shared content. */
28
28
  readonly maxPerPage?: number;
29
29
  /** Tiles narrower than this fold the rest into overflow. */
30
30
  readonly minTileWidth?: number;
@@ -28,5 +28,9 @@ export interface PrimaryContext {
28
28
  }
29
29
  /** A pin wins; otherwise the first live share, board, then active speaker leads Spotlight. */
30
30
  export declare function choosePrimary(items: readonly StageItem[], context: PrimaryContext): StageItem | null;
31
+ /** Who is speaking now: the active speaker before anyone else speaking. */
32
+ export declare function speakingParticipantId(items: readonly StageItem[], accept?: (participant: Participant) => boolean): string | undefined;
33
+ /** The remote person whose face leads the floating column: whoever is speaking now, else the last remote speaker. */
34
+ export declare function floatingSpeakerId(items: readonly StageItem[], lastRemoteSpeakerId: string | null): string | null;
31
35
  /** Grid order: pinned item first, everything else in stable order. */
32
36
  export declare function gridOrder(items: readonly StageItem[], pinnedId: string | null): StageItem[];
@@ -3,7 +3,7 @@ export interface StageBox {
3
3
  readonly width: number;
4
4
  readonly height: number;
5
5
  }
6
- export type StageRole = "primary" | "strip" | "grid";
6
+ export type StageRole = "primary" | "strip" | "grid" | "float";
7
7
  export interface StageFrame {
8
8
  readonly id: string;
9
9
  readonly role: StageRole;
@@ -37,8 +37,12 @@ export interface SpotlightFitOptions {
37
37
  readonly content?: boolean;
38
38
  readonly wideIds?: readonly string[];
39
39
  readonly maxPerPage?: number;
40
- /** On a phone the board keeps the people to one slim row, so the drawing gets the screen. */
40
+ /** @deprecated Prefer floatingPhonePeople for boards. Preserves the 52px phone strip. */
41
41
  readonly slimPhoneStrip?: boolean;
42
+ /** On a phone the board keeps the whole stage, and people float in a short column at its right edge. */
43
+ readonly floatingPhonePeople?: boolean;
44
+ readonly speakerId?: string | null;
45
+ readonly localId?: string | null;
42
46
  }
43
47
  export declare const WIDESCREEN: number;
44
48
  export declare const MORE_TILE_ID = "stage:more";
@@ -1,4 +1,4 @@
1
1
  export declare function CallEventIcon({ kind, error }: {
2
- readonly kind: "microphone" | "microphone-on" | "camera" | "screen" | "recording" | "hand" | "host";
2
+ readonly kind: "speaker" | "microphone" | "microphone-on" | "camera" | "screen" | "recording" | "hand" | "host";
3
3
  readonly error?: boolean;
4
4
  }): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import type { Toast } from "./ToastStack";
2
+ export interface NoticeButtonProps {
3
+ readonly toasts: readonly Toast[];
4
+ readonly onDismiss: (id: string) => void;
5
+ }
6
+ /** The header's way into notices that have no room on the stage, such as on a short screen with the board's tools open. */
7
+ export declare function NoticeButton({ toasts, onDismiss }: NoticeButtonProps): import("react").JSX.Element | null;
@@ -1,5 +1,5 @@
1
1
  import { type ChalkToastProps } from "../chalk-ui/ChalkToast";
2
- export interface Toast extends Omit<ChalkToastProps, "onDismiss"> {
2
+ export interface Toast extends Omit<ChalkToastProps, "onDismiss" | "announce"> {
3
3
  readonly id: string;
4
4
  }
5
5
  export interface ToastStackProps {
@@ -7,5 +7,16 @@ export interface ToastStackProps {
7
7
  readonly onDismiss: (id: string) => void;
8
8
  readonly maxVisible?: number;
9
9
  readonly className?: string;
10
+ /**
11
+ * Called with the ids of the notices the stage has no room for, so the host can offer them elsewhere, such as from the header.
12
+ * With it, a call shorter than `FOLD_BELOW_PX` folds every notice. Taller calls fold notices past `maxVisible` or outside the available band, announcing each folded message once.
13
+ */
14
+ readonly onFold?: (folded: readonly string[]) => void;
10
15
  }
11
- export declare const ToastStack: import("react").MemoExoticComponent<({ toasts, onDismiss, maxVisible, className }: ToastStackProps) => import("react").JSX.Element>;
16
+ /**
17
+ * Calls shorter than this fold every notice. It is the height the mockup's three-notice stack needs at its tallest, on a phone with
18
+ * the board open: 108px for the header and the board's menu, an 8px gap, three camera errors wrapped to three lines (79px each, with
19
+ * 8px gaps), and the 242px the open drawing tools lift notices by, 611px in all.
20
+ */
21
+ export declare const FOLD_BELOW_PX = 620;
22
+ export declare const ToastStack: import("react").MemoExoticComponent<({ toasts, onDismiss, maxVisible, className, onFold }: ToastStackProps) => import("react").JSX.Element>;
@@ -1,5 +1,6 @@
1
+ import { type MediaCommandSource, type MediaCommandAction } from "../control-bar/command-failure";
1
2
  import type { ClientFailure, SpaceSnapshot } from "@q9labsai/chalk-client";
2
3
  import type { Toast } from "./ToastStack";
3
- export declare function mediaFailureToast(failure: ClientFailure | null, source?: "microphone" | "camera" | "screen"): Omit<Toast, "id"> | null;
4
+ export declare function mediaFailureToast(failure: ClientFailure | null, source?: MediaCommandSource, action?: MediaCommandAction, onRetry?: () => void): Omit<Toast, "id"> | null;
4
5
  /** Snapshot changes, not initial history, are events for the person already in the call. */
5
6
  export declare function callEventToasts(previous: SpaceSnapshot, next: SpaceSnapshot): Omit<Toast, "id">[];
@@ -0,0 +1,4 @@
1
+ import type { ChalkToastProps } from "../chalk-ui/ChalkToast";
2
+ export declare function noticeAnnouncement(toast: Pick<ChalkToastProps, "message" | "announcementText">): string;
3
+ /** Semantic speech/lifetime revision, independent of JSX and layout chrome. */
4
+ export declare function noticeIdentity(toast: Pick<ChalkToastProps, "message" | "announcementText" | "announcementKey" | "type">): string;
@@ -0,0 +1,4 @@
1
+ /** A layout-only DOM snapshot: never instantiate React callers, custom elements, or media resources. */
2
+ export declare function captureToastLayout(toast: HTMLElement): HTMLDivElement;
3
+ /** Reflow cached markup at the current band's width without mounting the folded caller tree. */
4
+ export declare function measureToastLayout(stack: HTMLElement, snapshot: HTMLDivElement): number;
@@ -0,0 +1,7 @@
1
+ import { type RefObject } from "react";
2
+ import type { Toast } from "./ToastStack";
3
+ /** Remember measured sizes when notices fold: resizing must not remount them to measure again. */
4
+ export declare function useToastCapacity(stack: RefObject<HTMLDivElement | null>, candidates: readonly Toast[], enabled: boolean, ownedIds: readonly string[]): {
5
+ readonly count: number;
6
+ readonly ready: boolean;
7
+ };
package/dist/headless.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  fitSpotlight,
14
14
  gridOrder,
15
15
  screenShareItemId
16
- } from "./chunk-ZFWIMKUC.js";
16
+ } from "./chunk-HWQLW4JR.js";
17
17
  export {
18
18
  DEFAULT_GRID_OPTIONS,
19
19
  DEFAULT_SPOTLIGHT_OPTIONS,
package/dist/index.d.ts CHANGED
@@ -31,3 +31,4 @@ export { SpaceHeader } from "./components/space-header/SpaceHeader";
31
31
  export type { SpaceHeaderProps } from "./components/space-header/SpaceHeader";
32
32
  export { CallReady, type CallReadyProps } from "./components/call-limbo/CallReady";
33
33
  export { StatusSurface, type StatusSurfaceProps, type StatusSurfacePhase } from "./components/chalk/StatusSurface";
34
+ export { ReportProblemDialog } from "./components/chalk/ReportProblemDialog";