@factorialco/f0-react 7.33.0 → 7.35.0

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 (45) hide show
  1. package/dist/{ChatPdfThumbnail-CewvkWu-.js → ChatPdfThumbnail-BDgzIfCN.js} +1 -1
  2. package/dist/{ChatPostComposerDialog-CKwdWt5B.js → ChatPostComposerDialog-SVcKg-wn.js} +3 -3
  3. package/dist/{DocumentToolbar-BdgPc16e.js → DocumentToolbar-gJWaStGV.js} +2 -2
  4. package/dist/{DocxViewer-HWpF_G9w.js → DocxViewer-BXXgJXpj.js} +2 -2
  5. package/dist/{F0AiProcessingOverlay-DxlgF3Pt.js → F0AiProcessingOverlay-BsKOOcJf.js} +960 -957
  6. package/dist/{F0CanvasPanel-BCZjxhVB.js → F0CanvasPanel-B8GTWbHT.js} +12768 -12684
  7. package/dist/{F0Map-DZtgpSnS.js → F0Map-Bva6_CXT.js} +4 -4
  8. package/dist/{F0VideoPlayer-EqXupZV9.js → F0VideoPlayer-COE_GnIT.js} +356 -377
  9. package/dist/{MapProvider-C4K2ey4N.js → MapProvider-D7fCPtpO.js} +214 -189
  10. package/dist/{SheetViewer-yK40OmE1.js → SheetViewer-BX20kP4V.js} +2 -2
  11. package/dist/{TextViewer-BYFQn6S1.js → TextViewer-DUWw3Q54.js} +2 -2
  12. package/dist/ai.d.ts +16 -6
  13. package/dist/ai.js +2 -2
  14. package/dist/component-status.d.ts +6 -6
  15. package/dist/component-status.js +1 -1
  16. package/dist/{experimental-BKF7swb0.js → experimental-uK79fur-.js} +13406 -12580
  17. package/dist/experimental.d.ts +424 -38
  18. package/dist/experimental.js +274 -272
  19. package/dist/f0.d.ts +16 -6
  20. package/dist/f0.js +10 -10
  21. package/dist/i18n-provider-defaults.d.ts +16 -6
  22. package/dist/i18n-provider-defaults.js +13 -0
  23. package/dist/{index-Ca0rOdez.js → index-BDGCJ0_G.js} +3 -3
  24. package/dist/{index-C_LLYE_o.js → index-BJw_9Cag.js} +3 -3
  25. package/dist/index-Bgs0HZ5x.js +4 -0
  26. package/dist/{index-DlMbfdLc.js → index-C3iCeJK1.js} +1 -1
  27. package/dist/{index-BzA0lEl1.js → index-D7YSSoL3.js} +2 -2
  28. package/dist/{pdfWorker-CA3xmb-5.js → pdfWorker-DG2DNdLq.js} +2 -2
  29. package/dist/styles.css +1 -1
  30. package/icons/app/Floating.d.ts.map +1 -1
  31. package/icons/app/Floating.js +1 -1
  32. package/icons/app/Fullscreen.d.ts +4 -0
  33. package/icons/app/Fullscreen.d.ts.map +1 -0
  34. package/icons/app/Fullscreen.js +5 -0
  35. package/icons/app/PanelLeft.d.ts +4 -0
  36. package/icons/app/PanelLeft.d.ts.map +1 -0
  37. package/icons/app/PanelLeft.js +5 -0
  38. package/icons/app/PanelRight.d.ts +4 -0
  39. package/icons/app/PanelRight.d.ts.map +1 -0
  40. package/icons/app/PanelRight.js +5 -0
  41. package/icons/app/index.d.ts +3 -0
  42. package/icons/app/index.d.ts.map +1 -1
  43. package/icons/app/index.js +3 -0
  44. package/package.json +2 -2
  45. package/dist/index-Bt9DLm3D.js +0 -4
@@ -1682,9 +1682,18 @@ declare interface BreakType {
1682
1682
  }
1683
1683
 
1684
1684
  /**
1685
- * Flattens the roster into tiles, preserving the host's participant order.
1685
+ * Flattens the roster into tiles: shares, then everyone else, then you.
1686
+ *
1686
1687
  * Screen shares come first so they are never pushed off the visible page by a
1687
- * long roster.
1688
+ * long roster — your own included, because when you share, what you are
1689
+ * sharing is the thing the room is looking at.
1690
+ *
1691
+ * YOUR CAMERA GOES LAST, and it is the one place the host's order is not
1692
+ * preserved. Without it a one-to-one traded sides: the spotlight rule puts the
1693
+ * other person on the left, while the plain grid took the roster order, which
1694
+ * puts you first — so pinning and unpinning swapped the two of you over. Two
1695
+ * rules ordering the same room. This is the rule they now share, and it reads
1696
+ * the same way everywhere: the people you are talking to lead, you follow.
1688
1697
  */
1689
1698
  export declare const buildTiles: (participants: F0MeetingParticipant[]) => F0MeetingTile[];
1690
1699
 
@@ -5962,6 +5971,11 @@ declare const defaultTranslations: {
5962
5971
  readonly editing: "Editing";
5963
5972
  readonly edited: "edited";
5964
5973
  readonly aiAssisted: "by One";
5974
+ readonly translate: "Translate";
5975
+ readonly hideTranslation: "Hide translation";
5976
+ readonly translated: "Translated";
5977
+ readonly translatedFrom: "Translated from {{language}}";
5978
+ readonly upgrade: "Upgrade";
5965
5979
  readonly cancelEdit: "Cancel edit";
5966
5980
  readonly saveEdit: "Save";
5967
5981
  readonly you: "You";
@@ -6107,12 +6121,15 @@ declare const defaultTranslations: {
6107
6121
  readonly muted: "Muted";
6108
6122
  readonly waitingToJoin: "Waiting…";
6109
6123
  readonly sharingScreen: "Sharing screen";
6124
+ readonly audioRoom: "People in this call";
6110
6125
  readonly chatPanel: "Chat";
6111
6126
  readonly transcriptPanel: "Transcript";
6112
6127
  readonly notesPanel: "Notes";
6113
6128
  readonly openChat: "Open chat";
6114
6129
  readonly closeChat: "Close chat";
6115
6130
  readonly closePanel: "Close panel";
6131
+ readonly resizeChatPanel: "Resize chat panel";
6132
+ readonly chatPanelWidth: "{{width}} pixels";
6116
6133
  readonly notesPlaceholder: "Take notes for everyone in the call…";
6117
6134
  readonly roomChatPlaceholder: "Message this call…";
6118
6135
  readonly roomChatEmpty: "Messages here are only for this call and disappear when it ends.";
@@ -6175,6 +6192,8 @@ declare const defaultTranslations: {
6175
6192
  readonly movedToFloating: "Meeting in a floating window";
6176
6193
  readonly movedToSidePanel: "Meeting in the side panel";
6177
6194
  readonly movedToMinimized: "Meeting minimized";
6195
+ readonly audioOnlyAnnouncement: "Audio only. There is not enough room for video";
6196
+ readonly videoResumed: "Video is back";
6178
6197
  readonly movedInline: "Meeting on the page";
6179
6198
  readonly movedToPictureInPicture: "Meeting in a picture-in-picture window";
6180
6199
  };
@@ -7274,6 +7293,18 @@ declare type ExtractVisualizationSettings<T> = T extends {
7274
7293
  };
7275
7294
  } ? S : never;
7276
7295
 
7296
+ /**
7297
+ * WHERE A HOST HANGS SOMETHING OFF THE CONVERSATION'S NAME — a coachmark
7298
+ * explaining a limit, a tour step, a hint. F0 owns the header's markup, so it
7299
+ * owns the promise that there is a stable thing to point at; a host guessing
7300
+ * at class names would break on the next restyle.
7301
+ *
7302
+ * It resolves ONLY once the title has arrived (the skeleton does not carry it),
7303
+ * which is what makes an overlay anchored to it wait for a header worth
7304
+ * pointing at instead of opening over a pulsing grey bar.
7305
+ */
7306
+ export declare const F0_CHAT_HEADER_TITLE_SELECTOR = "[data-f0-chat-header-title]";
7307
+
7277
7308
  export declare const F0ActionBar: WithDataTestIdReturnType_2<ForwardRefExoticComponent<F0ActionBarProps & RefAttributes<F0ActionBarRef>>>;
7278
7309
 
7279
7310
  declare interface F0ActionBarProps {
@@ -7969,7 +8000,7 @@ export declare interface F0CarouselDialogProps extends Pick<F0DialogInternalProp
7969
8000
  * the {@link F0ChatRuntime} from a surrounding `F0ChatProvider`. Panel controls
7970
8001
  * (fullscreen / close) are wired by the host so F0Chat stays transport-agnostic.
7971
8002
  */
7972
- export declare const F0Chat: (props: F0ChatProps) => ReactNode;
8003
+ export declare const F0Chat: ({ surface, ...props }: F0ChatProps) => ReactNode;
7973
8004
 
7974
8005
  /** Attachment family, as the transcript classifies it (see
7975
8006
  * `utils/attachments.ts`). Note `video` is not an {@link F0ChatAttachment}
@@ -8088,6 +8119,12 @@ export declare type F0ChatCapabilities = {
8088
8119
  canViewInfo?: boolean;
8089
8120
  canEditMessage?: (message: F0ChatMessage) => boolean;
8090
8121
  canDeleteMessage?: (message: F0ChatMessage) => boolean;
8122
+ /**
8123
+ * Whether this message may be translated. Allowed when omitted, as long as the
8124
+ * host provides `translateMessage`. When it refuses, the row is hidden, or
8125
+ * shown as an upsell if the host also provides `requestTranslationUpsell`.
8126
+ */
8127
+ canTranslateMessage?: (message: F0ChatMessage) => boolean;
8091
8128
  };
8092
8129
 
8093
8130
  /**
@@ -8469,6 +8506,97 @@ export declare type F0ChatHeaderAction = {
8469
8506
  placement?: "menu" | "inline";
8470
8507
  /** Restrict the action to given channel types. Omit for all of them. */
8471
8508
  channelTypes?: F0ChatChannelType[];
8509
+ /**
8510
+ * TURNS AN INLINE ACTION INTO A TOGGLE, because that is what it has become:
8511
+ * something with an on and an off. Starting a huddle is a button until the
8512
+ * call exists — from then on the same control means "you are in it", and a
8513
+ * reader coming back to the conversation has to be able to see that without
8514
+ * pressing anything.
8515
+ *
8516
+ * Set it and F0 renders a real toggle with its `aria-pressed`, bordered so
8517
+ * the on state reads as a state rather than as a hover that stuck. Leave it
8518
+ * undefined for an action that only ever fires, which is most of them —
8519
+ * `false` is not the same thing as absent here.
8520
+ *
8521
+ * Ignored in the overflow menu: a menu item is a line of text you press, and
8522
+ * it has nowhere to wear a state.
8523
+ */
8524
+ active?: boolean;
8525
+ /** The glyph for the `active` half, when it differs. Omit to keep `icon` in
8526
+ * both states. */
8527
+ activeIcon?: IconType;
8528
+ /**
8529
+ * Marks the action as destructive, so it reads as one in the overflow menu.
8530
+ * Leaving a channel or archiving a conversation is not the same kind of thing
8531
+ * as muting it, and a menu that renders them identically says it is.
8532
+ * Ignored for `inline` actions — the row of icon buttons has no such state.
8533
+ */
8534
+ critical?: boolean;
8535
+ };
8536
+
8537
+ /**
8538
+ * THE HOST'S STATEMENT THAT HISTORY IS BEING WITHHELD. The loaded window has
8539
+ * reached a boundary behind which there IS older history the reader is not
8540
+ * allowed to see — a plan that only includes the last N days, a retention
8541
+ * policy, a legal hold.
8542
+ *
8543
+ * F0 neither computes nor enforces it: the host filters `messages` itself and
8544
+ * sets this together with `hasMoreOlder: false`. It cannot be derived here —
8545
+ * after the host has filtered, "the conversation started 10 days ago" and
8546
+ * "there are three years behind this" look identical from inside the panel.
8547
+ *
8548
+ * ABSENT ⇒ the oldest loaded message is the true beginning, or simply not
8549
+ * loaded yet. A conversation that genuinely started last week must never carry
8550
+ * one: the notice would claim something was taken away when nothing was.
8551
+ *
8552
+ * It is drawn as an `F0Card` whose only control is an upsell button, and the
8553
+ * host owns every part of it. The copy for the same reason
8554
+ * {@link F0ChatChannel.readOnlyNotice} is host-owned: only the host knows which
8555
+ * plan this is, and it is the one with the translations. And the button as the
8556
+ * WHOLE {@link UpsellingButtonProps} surface rather than a bare `onClick`,
8557
+ * because asking for a plan to change is a REQUEST with an outcome — the
8558
+ * loading label, the success and error copy and the next steps its confirmation
8559
+ * dialog shows are all part of what a host configures. An action that merely
8560
+ * navigates sets `showConfirmation: false`.
8561
+ */
8562
+ export declare type F0ChatHistoryLimit = {
8563
+ /** Headline. Says what is missing, not what to buy. */
8564
+ title: string;
8565
+ /** One sentence of context — which window is included, what lies behind it. */
8566
+ description?: string;
8567
+ /** Mark shown beside the copy. */
8568
+ icon?: IconType;
8569
+ /** The upsell request, whole — see above. */
8570
+ action: UpsellingButtonProps;
8571
+ };
8572
+
8573
+ /**
8574
+ * WHAT A CONVERSATION WITH A WITHHELD PAST SAYS FOR ITSELF — the card F0 puts
8575
+ * at the top of such a transcript, exported because the host needs THE SAME ONE
8576
+ * for the pop-up it floats over the conversation on arrival.
8577
+ *
8578
+ * Exported rather than left to each host to rebuild: two cards that must look
8579
+ * identical and are written twice are two cards that drift. They differ in one
8580
+ * thing only, and it is the one thing they should differ in — the floating copy
8581
+ * can be dismissed, the one at the top of history cannot. A close button there
8582
+ * would take the explanation away from a boundary the reader reaches again on
8583
+ * the next scroll, and F0 has nowhere to remember that it was closed.
8584
+ *
8585
+ * Its only standing control is an `UpsellingButton`: the request it sends and
8586
+ * everything its confirmation dialog says belong to the host — see
8587
+ * {@link F0ChatHistoryLimit}.
8588
+ */
8589
+ export declare const F0ChatHistoryLimitCard: ({ notice, dismissActions, }: {
8590
+ notice: F0ChatHistoryLimit;
8591
+ /** Rendered after the upsell, in the order given. Omit where there is no way
8592
+ * out — see above. */
8593
+ dismissActions?: F0ChatHistoryLimitDismissAction[];
8594
+ }) => ReactNode;
8595
+
8596
+ /** A way out of the card, for hosts that render it somewhere dismissable. */
8597
+ export declare type F0ChatHistoryLimitDismissAction = {
8598
+ label: string;
8599
+ onClick: () => void;
8472
8600
  };
8473
8601
 
8474
8602
  export declare type F0ChatImageAttachment = {
@@ -8612,6 +8740,12 @@ export declare type F0ChatMessage = {
8612
8740
  * reactions/read updates), so it never false-positives the label.
8613
8741
  */
8614
8742
  editedAt?: string;
8743
+ /**
8744
+ * Shown under `body`, which always stays the sent text, so copy, reply and
8745
+ * edit keep using the original. Clear it when the text is edited: it
8746
+ * translates the old text.
8747
+ */
8748
+ translation?: F0ChatMessageTranslation;
8615
8749
  /**
8616
8750
  * The message was drafted with One (Factorial's AI) and approved by its
8617
8751
  * author, who remains the sender. Drives the muted "by One" label
@@ -8644,6 +8778,16 @@ export declare type F0ChatMessageReply = {
8644
8778
  */
8645
8779
  export declare type F0ChatMessageStatus = "sending" | "sent" | "delivered" | "read" | "failed";
8646
8780
 
8781
+ /**
8782
+ * Only the message text is translated, not attachments or link previews.
8783
+ * `sourceLanguage` is the detected language of the original, as a BCP-47 code;
8784
+ * without it the label reads "Translated".
8785
+ */
8786
+ export declare type F0ChatMessageTranslation = {
8787
+ body: string;
8788
+ sourceLanguage?: string;
8789
+ };
8790
+
8647
8791
  /**
8648
8792
  * A pinned post as the bar needs it: enough to name it, and its id to jump to.
8649
8793
  * The post itself is fetched by the jump, not carried here.
@@ -8852,11 +8996,22 @@ export declare type F0ChatPostRequiredAction = {
8852
8996
  };
8853
8997
 
8854
8998
  export declare type F0ChatProps = {
8855
- /** Whether the hosting panel is in fullscreen (controls the header toggle icon). */
8999
+ /**
9000
+ * Where the chat is mounted — see {@link F0ChatSurface}. On `"page"` the
9001
+ * panel controls below are ignored, not merely unused: a conversation that is
9002
+ * the page has nothing to close and nowhere to expand to, and leaving that to
9003
+ * the convention of "don't pass the callback" is how it comes back.
9004
+ * @default "panel"
9005
+ */
9006
+ surface?: F0ChatSurface;
9007
+ /** Whether the hosting panel is in fullscreen (controls the header toggle
9008
+ * icon). Ignored on the `page` surface. */
8856
9009
  isFullscreen?: boolean;
8857
- /** Toggle the hosting panel's fullscreen. Hidden when omitted. */
9010
+ /** Toggle the hosting panel's fullscreen. Hidden when omitted, and always on
9011
+ * the `page` surface. */
8858
9012
  onToggleFullscreen?: () => void;
8859
- /** Close the hosting panel. Hidden when omitted. */
9013
+ /** Close the hosting panel. Hidden when omitted, and always on the `page`
9014
+ * surface. */
8860
9015
  onClose?: () => void;
8861
9016
  /**
8862
9017
  * Host-provided header actions (pin, mute, edit group…). Search is the only
@@ -8874,6 +9029,43 @@ export declare type F0ChatProps = {
8874
9029
  * Undefined keeps the default header, so no existing usage changes.
8875
9030
  */
8876
9031
  header?: ReactNode | null;
9032
+ /**
9033
+ * Host chrome pinned to the END of the built-in header's action row, after
9034
+ * the overflow menu and any inline actions.
9035
+ *
9036
+ * Not an `F0ChatHeaderAction`: those are things you do TO the conversation,
9037
+ * and they are labels and icons F0 lays out. This is a rendered control that
9038
+ * belongs to the app around the chat — the One switch on a full-page
9039
+ * conversation, where there is no page header left to carry it.
9040
+ *
9041
+ * Ignored when `header` replaces the built-in one; that host already owns
9042
+ * the whole row.
9043
+ */
9044
+ headerContent?: ReactNode;
9045
+ /**
9046
+ * THE HOST'S POP-UP OVER THE TOP OF THE CONVERSATION — full width, floating.
9047
+ *
9048
+ * Where a host says something ABOUT the conversation rather than in it:
9049
+ * "older messages aren't included in your plan", "this channel is archived on
9050
+ * Friday". It sits under the header and over the transcript, the width of the
9051
+ * panel, and it is the shape a warning like that wants: a popover anchored to
9052
+ * something in the header would be a fixed-width panel with an arrow pointing
9053
+ * at a title that has nothing to do with what it says.
9054
+ *
9055
+ * IT FLOATS, and that is the point. Taking layout space would push the whole
9056
+ * transcript down on arrival and pull it back up on dismissal — the reader's
9057
+ * place in the conversation moving twice for a message they are about to
9058
+ * close. Floating also means the virtualizer never measures around it, and
9059
+ * the sticky date pill steps below it on its own
9060
+ * (`CHAT_NOTICE_HEIGHT_PROPERTY`).
9061
+ *
9062
+ * It survives scrolling: this is a standing fact about the conversation, not
9063
+ * something tied to where the reader is in it. Dismissing is the host's — F0
9064
+ * renders what it is handed and remembers nothing, because when it shows and
9065
+ * whether a dismissal outlives the session both depend on things F0 cannot
9066
+ * see.
9067
+ */
9068
+ notice?: ReactNode;
8877
9069
  };
8878
9070
 
8879
9071
  /**
@@ -8919,6 +9111,17 @@ export declare type F0ChatRuntime = {
8919
9111
  typingUsers: F0ChatUser[];
8920
9112
  hasMoreOlder: boolean;
8921
9113
  loadingOlder: boolean;
9114
+ /**
9115
+ * Set ONLY once the window has reached a boundary the plan (or a retention
9116
+ * rule) puts on history — see {@link F0ChatHistoryLimit}. F0 renders it at
9117
+ * the very top of the transcript, and only in the settled state
9118
+ * (`!hasMoreOlder && !loadingOlder`), so it can never appear above rows that
9119
+ * are still being paginated in.
9120
+ *
9121
+ * It is the host's job to also report `hasMoreOlder: false` here: left true,
9122
+ * the transcript would keep asking for pages it is never going to get.
9123
+ */
9124
+ historyLimit?: F0ChatHistoryLimit;
8922
9125
  /**
8923
9126
  * Whether there are newer messages than the loaded window — true after jumping
8924
9127
  * to an old message (e.g. a search hit), so the transcript isn't anchored to
@@ -8991,6 +9194,18 @@ export declare type F0ChatRuntime = {
8991
9194
  * `client.partialUpdateMessage`.
8992
9195
  */
8993
9196
  editMessage?: (id: string, input: F0ChatEditInput) => void | Promise<void>;
9197
+ /**
9198
+ * Omit to disable translation. The host answers by setting `translation` on
9199
+ * the message; F0 stores no translated text.
9200
+ */
9201
+ translateMessage?: (id: string) => void | Promise<void>;
9202
+ /** Omit and a translation stays visible once shown. */
9203
+ hideMessageTranslation?: (id: string) => void;
9204
+ /**
9205
+ * When `canTranslateMessage` refuses, the Translate row still shows with an
9206
+ * Upgrade tag and calls this instead.
9207
+ */
9208
+ requestTranslationUpsell?: () => void;
8994
9209
  /**
8995
9210
  * How long after sending a message stays editable (ms). The "Edit" action is
8996
9211
  * hidden once a message is older than this. Omit for no limit (editable
@@ -9258,6 +9473,20 @@ export declare type F0ChatShelfAction = {
9258
9473
  */
9259
9474
  export declare type F0ChatStatus = "connecting" | "ready" | "reconnecting" | "offline" | "error";
9260
9475
 
9476
+ /**
9477
+ * Where the chat lives, which is the one thing it cannot work out for itself.
9478
+ *
9479
+ * `"panel"` (default) is a card inside the side panel: it can be closed and
9480
+ * expanded, and the panel draws the border around it.
9481
+ *
9482
+ * `"page"` is the main content of a route — the conversation IS the page, so
9483
+ * there is nothing to close and nowhere to expand to. `onClose`,
9484
+ * `onToggleFullscreen` and `isFullscreen` are ignored rather than merely
9485
+ * unused, the side panel is never consulted, and the header draws its own seam
9486
+ * against the transcript in place of the card border it no longer has.
9487
+ */
9488
+ export declare type F0ChatSurface = "panel" | "page";
9489
+
9261
9490
  /**
9262
9491
  * Membership / lifecycle events rendered as a centered system row. Closed
9263
9492
  * union — the host maps unknown transport event kinds to a body-only system
@@ -10926,8 +11155,10 @@ export declare type F0MeetingRuntime = {
10926
11155
  localParticipantId: string;
10927
11156
  /**
10928
11157
  * Everyone in the room INCLUDING the local participant, in a stable order the
10929
- * host controls (join order). F0 owns speaker promotion and pagination on top
10930
- * of this — a host that reorders on every speaker change makes the grid churn.
11158
+ * host controls (join order). F0 owns speaker promotion, pagination and the
11159
+ * local participant's own position on top of this — your camera is always the
11160
+ * last tile, whatever index you are at here. A host that reorders on every
11161
+ * speaker change makes the grid churn.
10931
11162
  */
10932
11163
  participants: F0MeetingParticipant[];
10933
11164
  localMedia: F0MeetingLocalMedia;
@@ -10992,6 +11223,16 @@ export declare type F0MeetingSidePanelTab = {
10992
11223
  export declare type F0MeetingSignal = {
10993
11224
  /** 0..1, smoothed by the host. LiveKit `Participant.audioLevel`. */
10994
11225
  audioLevel: number;
11226
+ /**
11227
+ * Energy per frequency band, 0..1 each, low to high — LiveKit's
11228
+ * `useMultibandTrackVolume`, or an `AnalyserNode` the host already has.
11229
+ *
11230
+ * Optional, and the waveform is honest about it: with a single `audioLevel`
11231
+ * five bars can only be one number drawn five times, so they rise and fall
11232
+ * together. Give it bands and each bar moves on its own, because each one is
11233
+ * actually a different measurement.
11234
+ */
11235
+ bands?: readonly number[];
10995
11236
  isSpeaking: boolean;
10996
11237
  quality: F0MeetingConnectionQuality;
10997
11238
  };
@@ -14452,7 +14693,7 @@ declare type MeetingRoomChatProps = {
14452
14693
  };
14453
14694
 
14454
14695
  /**
14455
- * The in-call panel: chat, transcript and notes beside the grid.
14696
+ * The in-call panel: chat, transcript and notes, beside the grid in fullscreen.
14456
14697
  *
14457
14698
  * F0 owns the bar, the selection and the close button because the control that
14458
14699
  * opens the panel lives in F0's own action bar and needs the tab labels and
@@ -14462,15 +14703,23 @@ declare type MeetingRoomChatProps = {
14462
14703
  * particular: its transcript is virtualized, and measuring rows inside a
14463
14704
  * display:none subtree yields zero heights that the list then has to correct
14464
14705
  * on reveal.
14706
+ *
14707
+ * The width comes from `plan`, never from a class. It used to be a literal
14708
+ * `w-[420px]` paired with a `SIDE_PANEL_WIDTH` nothing read — Tailwind cannot
14709
+ * take a number, the two had to agree, and nothing checked that they did.
14465
14710
  */
14466
- export declare const MeetingSidePanel: ({ panel }: MeetingSidePanelProps) => JSX_2.Element | null;
14711
+ export declare const MeetingSidePanel: ({ panel, plan }: MeetingSidePanelProps) => JSX_2.Element | null;
14467
14712
 
14468
14713
  declare type MeetingSidePanelProps = {
14469
14714
  panel: F0MeetingSidePanel;
14715
+ /** Where it sits and how wide, decided by `planSidePanel` from the room. */
14716
+ plan: SidePanelPlan;
14470
14717
  };
14471
14718
 
14472
14719
  export declare type MeetingSignalStore = F0MeetingSignalStore & {
14473
14720
  setAudioLevel: (participantId: string, level: number) => void;
14721
+ /** Per-band energy for the waveform. See `F0MeetingSignal.bands`. */
14722
+ setAudioBands: (participantId: string, bands: readonly number[]) => void;
14474
14723
  setSpeaking: (participantIds: readonly string[]) => void;
14475
14724
  setQuality: (participantId: string, quality: F0MeetingConnectionQuality) => void;
14476
14725
  remove: (participantId: string) => void;
@@ -14492,9 +14741,11 @@ declare type MeetingSurfaceContextValue = {
14492
14741
  /** What the user chose. Never mutated by the environment. */
14493
14742
  mode: F0MeetingSurfaceDestination;
14494
14743
  /**
14495
- * What actually renders. A small viewport or an unmounted inline slot derives
14496
- * a different mode without destroying the user's preference; so does an open
14497
- * picture-in-picture window, which is `pip` for as long as it is open.
14744
+ * What actually renders. It differs from `mode` for exactly two reasons, and
14745
+ * neither is the size of the screen: a place that is not there (an inline
14746
+ * slot nobody registered, a panel no frame provides) derives to `floating`,
14747
+ * and an open picture-in-picture window is `pip` for as long as it is open.
14748
+ * The user's pick is never overwritten, only stood aside from.
14498
14749
  */
14499
14750
  effectiveMode: F0MeetingSurfaceMode;
14500
14751
  setMode: (mode: F0MeetingSurfaceDestination) => void;
@@ -14506,15 +14757,6 @@ declare type MeetingSurfaceContextValue = {
14506
14757
  settleRect: (rect: F0Rect) => void;
14507
14758
  /** Commit a resize, keeping the current anchor. */
14508
14759
  resizeRect: (rect: F0Rect) => void;
14509
- /** True below the md breakpoint: no dragging, pill instead of window. */
14510
- isCompactViewport: boolean;
14511
- /**
14512
- * The frame's content area. `panel` mode does NOT use it — there the room is
14513
- * the side panel's content and the panel places itself. It is what a window
14514
- * sizes itself against when it has to sit BESIDE the panel (see
14515
- * `fitToContent`), and the viewport when no frame published one.
14516
- */
14517
- panelArea: F0Rect;
14518
14760
  /**
14519
14761
  * Whether there is a side panel for the call to be the content of.
14520
14762
  *
@@ -14524,15 +14766,16 @@ declare type MeetingSurfaceContextValue = {
14524
14766
  * `floating` and the switch stops offering it.
14525
14767
  */
14526
14768
  hasPanelSlot: boolean;
14527
- setPanelSlot: (available: boolean) => void;
14528
- /** Registered by `F0MeetingSlot` so `inline` knows where to fly to. */
14529
- setInlineRect: (rect: F0Rect | null) => void;
14530
14769
  /**
14531
- * The application frame's content region, published by the frame itself. The
14532
- * side panel lives inside it — between the navigation and the content —
14533
- * rather than on top of the whole viewport.
14770
+ * WHICH EDGE the slot is on, or `null` when there is none. The mode switch
14771
+ * draws the panel with the side it actually docks to, so the control shows
14772
+ * where the call is going rather than a generic panel that could be either.
14534
14773
  */
14535
- setFrameRect: (rect: F0Rect | null) => void;
14774
+ panelSide: "left" | "right" | null;
14775
+ /** `null` retires the slot; a side registers one. */
14776
+ setPanelSlot: (side: "left" | "right" | null) => void;
14777
+ /** Registered by `F0MeetingSlot` so `inline` knows where to fly to. */
14778
+ setInlineRect: (rect: F0Rect | null) => void;
14536
14779
  /** What the user asked the spotlight to do, if anything. */
14537
14780
  focusIntent: F0MeetingFocusIntent;
14538
14781
  setFocusIntent: (intent: F0MeetingFocusIntent) => void;
@@ -14541,6 +14784,18 @@ declare type MeetingSurfaceContextValue = {
14541
14784
  setSidePanelOpen: (open: boolean) => void;
14542
14785
  activeTabId: string | null;
14543
14786
  setActiveTabId: (id: string) => void;
14787
+ /**
14788
+ * The width the panel was last dragged to — a PREFERENCE, not the width it
14789
+ * draws at. `planSidePanel` clamps it against the room on every render and
14790
+ * the clamp is never written back, so shrinking the window does not destroy
14791
+ * a deliberate choice: widen it again and the panel returns to where it was.
14792
+ *
14793
+ * Not keyed by `roomId`, unlike the mode: how wide you like your chat is a
14794
+ * fact about you, not about this call.
14795
+ */
14796
+ sidePanelWidth: number;
14797
+ setSidePanelWidth: (width: number) => void;
14798
+ resetSidePanelWidth: () => void;
14544
14799
  announce: (message: string) => void;
14545
14800
  liveMessage: string;
14546
14801
  /** What the browser offers for picture-in-picture, after the host's opt-out. */
@@ -17019,6 +17274,24 @@ export declare type SidebarChat = {
17019
17274
  * chat resolves, flip this to false and pass the real `label`/`avatar`.
17020
17275
  */
17021
17276
  loading?: boolean;
17277
+ /**
17278
+ * Where the conversation lives. With it the row is a real link, rendered
17279
+ * through the host's router (`LinkProvider`), so cmd/middle-click, "open in
17280
+ * new tab" and Back all work, and the active row is resolved from the URL
17281
+ * rather than from `activeChatId`. Without it the row stays a button and
17282
+ * `onClick` is the only way in.
17283
+ *
17284
+ * The host must mount `LinkProvider` with a live `currentPath` for the
17285
+ * selection to follow the URL; if it does not, the row falls back to
17286
+ * `activeChatId` rather than going dead.
17287
+ */
17288
+ href?: string;
17289
+ /**
17290
+ * Match `href` exactly when resolving the active state. Leave it off for a
17291
+ * conversation with sub-routes (a thread, say) so the parent row stays lit.
17292
+ * @default false
17293
+ */
17294
+ exactMatch?: boolean;
17022
17295
  onClick?: () => void;
17023
17296
  /** When > 0, the chat is rendered as unread (darker, bolder name). */
17024
17297
  unreadCount?: number;
@@ -17199,6 +17472,18 @@ export declare type SidebarChatProviderProps = {
17199
17472
  export declare type SidebarChatStatus = {
17200
17473
  icon: IconType;
17201
17474
  label: string;
17475
+ /**
17476
+ * THE STATUS IS LIVE, so the whole row wears it: the glyph takes the selected
17477
+ * colour and the row takes the selected background — the same one the control
17478
+ * that started it wears in the conversation's own header. A call in progress
17479
+ * is the case this exists for, and it has to be findable from the list
17480
+ * without opening anything.
17481
+ *
17482
+ * At most one status per row should carry it. An accent that several things
17483
+ * share stops pointing at any of them, which is the whole job here: the row
17484
+ * is coloured because ONE thing about it is happening right now.
17485
+ */
17486
+ accent?: boolean;
17202
17487
  };
17203
17488
 
17204
17489
  /**
@@ -17209,9 +17494,13 @@ export declare type SidebarChatStatus = {
17209
17494
  export declare type SidebarChatStore = {
17210
17495
  groups: SidebarChatGroup[];
17211
17496
  /**
17212
- * Id of the currently active chat. Chats are not navigation links — you can
17213
- * be on any page (e.g. the dashboard) with a chat active — so the active
17214
- * state is driven from here, not from the router.
17497
+ * Id of the currently active chat, for rows with no `href`: you can be on any
17498
+ * page (e.g. the dashboard) with such a chat active, so its active state is
17499
+ * driven from here rather than from the router.
17500
+ *
17501
+ * A ROUTED row (one carrying `href`) takes its active state from the URL
17502
+ * instead. This stays the source for unrouted rows, and the fallback for
17503
+ * routed ones when no `LinkProvider` is mounted.
17215
17504
  */
17216
17505
  activeChatId?: string;
17217
17506
  /** Number of conversations with unread messages (across all groups). */
@@ -17386,6 +17675,18 @@ export declare type SidebarTab = {
17386
17675
  * tab (transparent background; the icon darkens on hover).
17387
17676
  */
17388
17677
  variant?: "default" | "ai";
17678
+ /**
17679
+ * Where this tab lives. With it the tab is a real link: cmd-click opens the
17680
+ * section in a new tab, and switching sections is a navigation rather than a
17681
+ * state change the host has to translate into one. The selection stays
17682
+ * controlled — `activeTab` is still the host's, derived from its own route.
17683
+ *
17684
+ * Declaring `href` on ANY tab also turns off the mount-time restore of
17685
+ * `persistKey` — see {@link usePersistedTab}.
17686
+ */
17687
+ href?: string;
17688
+ /** Match `href` exactly when resolving the active state. @default false */
17689
+ exactMatch?: boolean;
17389
17690
  };
17390
17691
 
17391
17692
  /**
@@ -17591,6 +17892,29 @@ declare type SidePanelContextValue = {
17591
17892
  */
17592
17893
  export declare type SidePanelLayout = "sidepanel" | "fullscreen";
17593
17894
 
17895
+ /**
17896
+ * Where the in-call panel sits, which is a question about the ROOM'S width and
17897
+ * never about the viewport's — the same rule the grid, the density table and
17898
+ * the control bar already follow.
17899
+ *
17900
+ * - `beside` the panel is a column in the row and the grid shrinks for it.
17901
+ * - `over` the panel floats on the grid's right edge; the grid keeps its
17902
+ * full width and never re-solves.
17903
+ * - `full` the panel takes the whole video area. The control bar is outside
17904
+ * the row, so leaving and muting are still there.
17905
+ */
17906
+ declare type SidePanelLayout_2 = "beside" | "over" | "full";
17907
+
17908
+ declare type SidePanelPlan = {
17909
+ layout: SidePanelLayout_2;
17910
+ /** The width to draw, already clamped. `full` reports the room's own. */
17911
+ width: number;
17912
+ min: number;
17913
+ max: number;
17914
+ /** A handle that cannot travel is worse than no handle. */
17915
+ canResize: boolean;
17916
+ };
17917
+
17594
17918
  /**
17595
17919
  * A product's claim on the panel.
17596
17920
  *
@@ -17612,6 +17936,20 @@ export declare type SidePanelViewDefinition = {
17612
17936
  available?: boolean;
17613
17937
  /** Edge this view docks to. Falls back to the panel's `side`. */
17614
17938
  side?: "left" | "right";
17939
+ /**
17940
+ * Can this view re-mount content persisted from a previous session? Only a
17941
+ * view whose host actually answers `restoringViewId` — by calling `present`
17942
+ * or `cancelRestore` — should say true.
17943
+ *
17944
+ * Default `false`, and deliberately so. With no restorer the panel holds a
17945
+ * skeleton for the full safety timeout on every reload, including — after a
17946
+ * product moves its content OUT of the panel — for an id nothing will ever
17947
+ * claim again. The safe default is that the panel does not hold itself
17948
+ * hostage for a host that never opted in; the host who wants the restore is
17949
+ * also the host in a position to notice this field.
17950
+ * @default false
17951
+ */
17952
+ restoresContent?: boolean;
17615
17953
  };
17616
17954
 
17617
17955
  /**
@@ -18757,6 +19095,54 @@ export declare type UpsellActionDefinition = {
18757
19095
  /** Returns the upsell action, or undefined to hide it. */
18758
19096
  export declare type UpsellActionDefinitionFn = () => UpsellActionDefinition | undefined;
18759
19097
 
19098
+ declare interface UpsellingButtonProps extends Omit<F0ButtonProps, "icon"> {
19099
+ variant?: "promote" | "outlinePromote";
19100
+ /**
19101
+ * The text to be displayed in the button
19102
+ */
19103
+ label: string;
19104
+ /**
19105
+ * Whether to show the Upsell icon. Defaults to true.
19106
+ */
19107
+ showIcon?: boolean;
19108
+ /**
19109
+ * Function to be executed when the button is clicked
19110
+ */
19111
+ onRequest?: () => Promise<void> | void;
19112
+ /**
19113
+ * Whether to show the confirmation dialog after the request
19114
+ */
19115
+ showConfirmation?: boolean;
19116
+ /**
19117
+ * The error message to be displayed in the confirmation dialog
19118
+ */
19119
+ errorMessage: ErrorMessageProps;
19120
+ /**
19121
+ * The success message to be displayed in the confirmation dialog
19122
+ */
19123
+ successMessage: SuccessMessageProps;
19124
+ /**
19125
+ * The label to be displayed in the button when the request is being processed
19126
+ */
19127
+ loadingState: LoadingStateProps;
19128
+ /**
19129
+ * The next steps to be displayed in the confirmation dialog
19130
+ */
19131
+ nextSteps: NextStepsProps;
19132
+ /**
19133
+ * The label to be displayed in the close button of the confirmation dialog
19134
+ */
19135
+ closeLabel: string;
19136
+ /**
19137
+ * Callback to notify when the modal state changes (open/closed)
19138
+ */
19139
+ onModalStateChange?: (isOpen: boolean) => void;
19140
+ /**
19141
+ * Portal container for the confirmation dialog
19142
+ */
19143
+ portalContainer?: HTMLElement | null;
19144
+ }
19145
+
18760
19146
  export declare function useAiPromotionChat(): AiPromotionChatProviderReturnValue;
18761
19147
 
18762
19148
  /**
@@ -20117,9 +20503,9 @@ declare namespace Calendar {
20117
20503
 
20118
20504
  declare module "@tiptap/core" {
20119
20505
  interface Commands<ReturnType> {
20120
- aiBlock: {
20121
- insertAIBlock: (data: AIBlockData, config: AIBlockConfig) => ReturnType;
20122
- executeAIAction: (actionType: string, config: AIBlockConfig) => ReturnType;
20506
+ fontSize: {
20507
+ setFontSize: (fontSize: string) => ReturnType;
20508
+ unsetFontSize: () => ReturnType;
20123
20509
  };
20124
20510
  }
20125
20511
  }
@@ -20127,9 +20513,9 @@ declare module "@tiptap/core" {
20127
20513
 
20128
20514
  declare module "@tiptap/core" {
20129
20515
  interface Commands<ReturnType> {
20130
- fontSize: {
20131
- setFontSize: (fontSize: string) => ReturnType;
20132
- unsetFontSize: () => ReturnType;
20516
+ aiBlock: {
20517
+ insertAIBlock: (data: AIBlockData, config: AIBlockConfig) => ReturnType;
20518
+ executeAIAction: (actionType: string, config: AIBlockConfig) => ReturnType;
20133
20519
  };
20134
20520
  }
20135
20521
  }