@photon-ai/pho-ui 4.3.1 → 4.4.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 (70) hide show
  1. package/dist/chunks/{basic-page-OrUVXKrx.js → basic-page-ijv-ijUB.js} +534 -519
  2. package/dist/chunks/basic-page-ijv-ijUB.js.map +1 -0
  3. package/dist/chunks/bubble-eaoLJP4N.js +88 -0
  4. package/dist/chunks/bubble-eaoLJP4N.js.map +1 -0
  5. package/dist/chunks/{button-CdqS_t5a.js → button-CgUS0j3D.js} +4 -4
  6. package/dist/chunks/button-CgUS0j3D.js.map +1 -0
  7. package/dist/chunks/chat-DUqWlXqt.js +619 -0
  8. package/dist/chunks/chat-DUqWlXqt.js.map +1 -0
  9. package/dist/chunks/{code-block-BuDIo8Q0.js → code-block-BGgbp-6Q.js} +12 -12
  10. package/dist/chunks/{code-block-BuDIo8Q0.js.map → code-block-BGgbp-6Q.js.map} +1 -1
  11. package/dist/chunks/command-BfCCRaoc.js +225 -0
  12. package/dist/chunks/command-BfCCRaoc.js.map +1 -0
  13. package/dist/chunks/{copy-button-B_B15mEi.js → copy-button-D8XyP0oR.js} +10 -10
  14. package/dist/chunks/copy-button-D8XyP0oR.js.map +1 -0
  15. package/dist/chunks/{description-list-C-mwe4ki.js → description-list-8qm83WZB.js} +17 -17
  16. package/dist/chunks/description-list-8qm83WZB.js.map +1 -0
  17. package/dist/chunks/{dialog-BOz_xOrn.js → dialog-DeM4axJ6.js} +3 -3
  18. package/dist/chunks/{dialog-BOz_xOrn.js.map → dialog-DeM4axJ6.js.map} +1 -1
  19. package/dist/chunks/{error-BAQgnde7.js → error-VvHnteyf.js} +2 -2
  20. package/dist/chunks/{error-BAQgnde7.js.map → error-VvHnteyf.js.map} +1 -1
  21. package/dist/chunks/{filter-bar-Cr_1zBFq.js → filter-bar-BcpeTKCC.js} +38 -36
  22. package/dist/chunks/filter-bar-BcpeTKCC.js.map +1 -0
  23. package/dist/chunks/{log-list-BERiO4UJ.js → log-list-Didt-MV4.js} +2 -2
  24. package/dist/chunks/{log-list-BERiO4UJ.js.map → log-list-Didt-MV4.js.map} +1 -1
  25. package/dist/chunks/message-CTml-TrB.js +89 -0
  26. package/dist/chunks/message-CTml-TrB.js.map +1 -0
  27. package/dist/chunks/{scroll-area-Zik8t1Mk.js → scroll-area-DSwD9th7.js} +2 -2
  28. package/dist/chunks/{scroll-area-Zik8t1Mk.js.map → scroll-area-DSwD9th7.js.map} +1 -1
  29. package/dist/chunks/{sidebar-bLsjo_yb.js → sidebar-BmloUwJQ.js} +56 -56
  30. package/dist/chunks/sidebar-BmloUwJQ.js.map +1 -0
  31. package/dist/chunks/{toast-72Wwlzg9.js → toast-DUvjSZF7.js} +3 -3
  32. package/dist/chunks/{toast-72Wwlzg9.js.map → toast-DUvjSZF7.js.map} +1 -1
  33. package/dist/components/bubble.js +6 -0
  34. package/dist/components/button.js +1 -1
  35. package/dist/components/chat.js +5 -0
  36. package/dist/components/code-block.js +1 -1
  37. package/dist/components/command.js +1 -1
  38. package/dist/components/copy-button.js +1 -1
  39. package/dist/components/description-list.js +1 -1
  40. package/dist/components/dialog.js +1 -1
  41. package/dist/components/error.js +1 -1
  42. package/dist/components/filter-bar.js +1 -1
  43. package/dist/components/log-list.js +1 -1
  44. package/dist/components/message.js +7 -0
  45. package/dist/components/scroll-area.js +1 -1
  46. package/dist/components/toast.js +1 -1
  47. package/dist/index.js +145 -136
  48. package/dist/sections/basic-page.js +1 -1
  49. package/dist/sections/sidebar.js +1 -1
  50. package/dist/src/components/bubble/bubble.d.ts +112 -0
  51. package/dist/src/components/bubble/index.d.ts +1 -0
  52. package/dist/src/components/chat/chat.d.ts +301 -0
  53. package/dist/src/components/chat/index.d.ts +1 -0
  54. package/dist/src/components/command/command.d.ts +14 -4
  55. package/dist/src/components/command/index.d.ts +1 -1
  56. package/dist/src/components/filter-bar/filter-bar.d.ts +5 -0
  57. package/dist/src/components/message/index.d.ts +2 -0
  58. package/dist/src/components/message/message-status.d.ts +22 -0
  59. package/dist/src/components/message/message.d.ts +78 -0
  60. package/dist/src/index.d.ts +3 -0
  61. package/dist/src/sections/sidebar/sidebar.d.ts +10 -1
  62. package/package.json +13 -1
  63. package/dist/chunks/basic-page-OrUVXKrx.js.map +0 -1
  64. package/dist/chunks/button-CdqS_t5a.js.map +0 -1
  65. package/dist/chunks/command-Cn000hMK.js +0 -192
  66. package/dist/chunks/command-Cn000hMK.js.map +0 -1
  67. package/dist/chunks/copy-button-B_B15mEi.js.map +0 -1
  68. package/dist/chunks/description-list-C-mwe4ki.js.map +0 -1
  69. package/dist/chunks/filter-bar-Cr_1zBFq.js.map +0 -1
  70. package/dist/chunks/sidebar-bLsjo_yb.js.map +0 -1
@@ -0,0 +1,301 @@
1
+ import { AnchorHTMLAttributes, ButtonHTMLAttributes, ComponentProps, ReactNode, Ref } from 'react';
2
+ import { InputProps } from '../input';
3
+ import { StatusViewProps } from '../status-view';
4
+ /**
5
+ * Chat — an inbox in one card: the conversations down the left, the open
6
+ * thread on the right with its messages scrolling up from the composer.
7
+ * It composes the smaller parts (`Message` rows of `Bubble`s in a
8
+ * `ScrollArea`, an `Input` for search, `Button`s to send and go back) the
9
+ * way `Sidebar` composes a rail: rows that press, one active, links
10
+ * through the host's `LinkProvider`.
11
+ *
12
+ * Two layouts. `default` seats both panes side by side — the divider
13
+ * between them drags so either pane can grow, each down to a min width.
14
+ * `compact` shows one at a time — the list, then the thread with a way
15
+ * back — for a narrow column or a phone. Opening a conversation pushes
16
+ * the thread in from the right; back pops the list in from the left, a
17
+ * short drift on `TRAVEL_LINEAR` with a `FADE_SWAP` fade. `auto` is
18
+ * compact only while the frame is narrower than 42rem (a container
19
+ * query, so it follows the card, not the viewport). Which pane is up is
20
+ * `pane`, controlled or not; opening a conversation moves to the thread,
21
+ * the header's back button returns.
22
+ *
23
+ * Presentational, like every Pho part: the page fetches, formats times,
24
+ * and decides who is who. The thread stays pinned to its newest message
25
+ * while the reader is at the bottom, and keeps its place when earlier
26
+ * pages arrive above.
27
+ */
28
+ export type ChatLayout = "default" | "compact" | "auto";
29
+ export type ChatPane = "list" | "thread";
30
+ /** Push is 1 (thread from the right); pop is −1 (list from the left). */
31
+ export type ChatPaneDirection = 1 | -1;
32
+ /**
33
+ * The compact pane swap — incoming travels `PANE_TRAVEL_PX` on
34
+ * `TRAVEL_LINEAR`, fades and breathes `BLUR_PX` on `FADE_SWAP`; outgoing
35
+ * drifts `PANE_LEAVE_PX` the other way. Under reduced motion: opacity
36
+ * only, and instant.
37
+ */
38
+ export declare function paneSwapMotion(direction: ChatPaneDirection, reduceMotion?: boolean | null): {
39
+ initial: {
40
+ opacity: number;
41
+ x?: undefined;
42
+ filter?: undefined;
43
+ };
44
+ animate: {
45
+ opacity: number;
46
+ x?: undefined;
47
+ filter?: undefined;
48
+ };
49
+ exit: {
50
+ opacity: number;
51
+ x?: undefined;
52
+ filter?: undefined;
53
+ };
54
+ transition: {
55
+ duration: number;
56
+ x?: undefined;
57
+ opacity?: undefined;
58
+ filter?: undefined;
59
+ };
60
+ } | {
61
+ initial: {
62
+ x: number;
63
+ opacity: number;
64
+ filter: string;
65
+ };
66
+ animate: {
67
+ x: number;
68
+ opacity: number;
69
+ filter: string;
70
+ };
71
+ exit: {
72
+ x: number;
73
+ opacity: number;
74
+ filter: string;
75
+ };
76
+ transition: {
77
+ x: {
78
+ readonly duration: 0.2;
79
+ readonly ease: "linear";
80
+ };
81
+ opacity: {
82
+ readonly duration: 0.2;
83
+ readonly ease: "easeOut";
84
+ };
85
+ filter: {
86
+ readonly duration: 0.2;
87
+ readonly ease: "easeOut";
88
+ };
89
+ duration?: undefined;
90
+ };
91
+ };
92
+ /**
93
+ * DOM handlers whose React signatures clash with Motion's gesture props.
94
+ * Same omit list as `Button` — swap panes and conversation rows render
95
+ * through `motion.*`.
96
+ */
97
+ type MotionHandlerConflicts = "onAnimationStart" | "onAnimationEnd" | "onAnimationIteration" | "onDrag" | "onDragStart" | "onDragEnd" | "onDragEnter" | "onDragExit" | "onDragLeave" | "onDragOver" | "onDrop";
98
+ export interface ChatRootProps extends ComponentProps<"div"> {
99
+ /**
100
+ * `default` shows both panes; `compact` one at a time; `auto` is
101
+ * compact while the frame is narrower than 42rem.
102
+ * @default "default"
103
+ */
104
+ layout?: ChatLayout;
105
+ /** The pane that is up in a compact layout. Pair with `onPaneChange`. */
106
+ pane?: ChatPane;
107
+ /** Initial pane when uncontrolled. @default "list" */
108
+ defaultPane?: ChatPane;
109
+ /** Called with the next pane — a row opened a thread, back was pressed. */
110
+ onPaneChange?: (pane: ChatPane) => void;
111
+ ref?: Ref<HTMLDivElement>;
112
+ }
113
+ /**
114
+ * The card. Give it a height (`h-[32rem]`, or `min-h-0 flex-1` in a
115
+ * column that fills the page); the panes scroll inside it.
116
+ */
117
+ declare function Root({ layout, pane: paneProp, defaultPane, onPaneChange, className, style, ref, ...props }: ChatRootProps): import("react").JSX.Element;
118
+ /** The left pane — search above, conversations below, on the page wash. */
119
+ declare function List({ className, children, id: idProp, ...props }: ComponentProps<"aside">): import("react").JSX.Element;
120
+ export interface ChatSearchProps extends Omit<InputProps, "size" | "icon" | "label" | "hint" | "labelTrailing"> {
121
+ }
122
+ /** The search row pinned over the conversations — an `sm` `Input`. */
123
+ declare function Search({ className, placeholder, ...props }: ChatSearchProps): import("react").JSX.Element;
124
+ /**
125
+ * The scrolling part of the list. Put a `ConversationList` in it — or a
126
+ * `ConversationsLoading`, an `Empty` — and anything that belongs after
127
+ * the rows (a load-older button).
128
+ */
129
+ declare function Conversations({ className, children, ...props }: ComponentProps<"div">): import("react").JSX.Element;
130
+ /** The rows. */
131
+ declare function ConversationList({ className, ...props }: ComponentProps<"ul">): import("react").JSX.Element;
132
+ /**
133
+ * DOM handlers whose React signatures clash with Motion's gesture props.
134
+ * Same omit list as `Button` — rows render through `motion.*`.
135
+ */
136
+ interface ConversationBaseProps {
137
+ /** Who — a number, a name, the members of a group. */
138
+ title: ReactNode;
139
+ /** When — the page's relative time (`2d ago`), trailing. */
140
+ time?: ReactNode;
141
+ /** The latest message, one truncated line. */
142
+ preview?: ReactNode;
143
+ /** Replace the default avatar (a person, or people for a `group`). */
144
+ avatar?: ReactNode;
145
+ /** A group conversation — the default avatar shows people. */
146
+ group?: boolean;
147
+ /** The open conversation. */
148
+ active?: boolean;
149
+ className?: string;
150
+ }
151
+ export interface ChatConversationLinkProps extends ConversationBaseProps, Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ConversationBaseProps | MotionHandlerConflicts> {
152
+ /** Destination — rendered through the host's `LinkProvider`. */
153
+ href: string;
154
+ }
155
+ export interface ChatConversationButtonProps extends ConversationBaseProps, Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ConversationBaseProps | MotionHandlerConflicts> {
156
+ href?: undefined;
157
+ }
158
+ export type ChatConversationProps = ChatConversationLinkProps | ChatConversationButtonProps;
159
+ /**
160
+ * One conversation — a link when `href` is given (through the host's
161
+ * `LinkProvider`), otherwise a button. Opening it in a compact layout
162
+ * brings the thread up.
163
+ */
164
+ declare function Conversation({ title, time, preview, avatar, group, active, className, href, onClick, ...rest }: ChatConversationProps): import("react").JSX.Element;
165
+ /** The right pane — header, messages, and the docked footer, on the card. */
166
+ declare function Thread({ className, children, ...props }: ComponentProps<"section">): import("react").JSX.Element;
167
+ export interface ChatHeaderProps extends ComponentProps<"header"> {
168
+ /** The other side's avatar — an `Avatar.Root`. */
169
+ avatar?: ReactNode;
170
+ /** Controls at the trailing edge — a details button, a menu. */
171
+ actions?: ReactNode;
172
+ /** The back button's accessible name. @default "Back to conversations" */
173
+ backLabel?: string;
174
+ }
175
+ /**
176
+ * Who the thread is with. Children are a `Title` and a `Description`.
177
+ * In a compact layout a back button leads the row; `auto` shows it only
178
+ * while the frame is narrow.
179
+ */
180
+ declare function Header({ avatar, actions, backLabel, className, children, ...props }: ChatHeaderProps): import("react").JSX.Element;
181
+ /** The other side's name. Inline extras (a copy button, a badge) sit after it. */
182
+ declare function Title({ className, children, ...props }: ComponentProps<"h2">): import("react").JSX.Element;
183
+ /** One line under the title — from whom, a status. */
184
+ declare function Description({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
185
+ export interface ChatMessagesProps extends ComponentProps<"div"> {
186
+ /** Earlier pages exist — a button at the top asks for them. */
187
+ hasEarlier?: boolean;
188
+ /** The earlier page is on its way. */
189
+ loadingEarlier?: boolean;
190
+ /** Ask for the page before the first message shown. */
191
+ onLoadEarlier?: () => void;
192
+ /** The button's label. @default "Load earlier messages" */
193
+ earlierLabel?: ReactNode;
194
+ }
195
+ /**
196
+ * The messages, oldest to newest, on the thread surface. The pane starts at
197
+ * the bottom and stays there as messages arrive unless the reader has
198
+ * scrolled up; an earlier page keeps what they were reading in place.
199
+ * Children are `Message` rows and `Divider`s.
200
+ */
201
+ declare function Messages({ hasEarlier, loadingEarlier, onLoadEarlier, earlierLabel, className, children, ...props }: ChatMessagesProps): import("react").JSX.Element;
202
+ /** A centered caption in the thread — the day, "Unread". */
203
+ declare function Divider({ className, children, ...props }: ComponentProps<"div">): import("react").JSX.Element;
204
+ /** The docked bar under the messages — usually a `Composer`. */
205
+ declare function Footer({ className, ...props }: ComponentProps<"footer">): import("react").JSX.Element;
206
+ export interface ChatComposerProps extends Omit<ComponentProps<"form">, "onSubmit" | "prefix" | "children"> {
207
+ /** The draft. */
208
+ value: string;
209
+ onValueChange: (value: string) => void;
210
+ /** Enter, or the send button. Not called while `sending` or with nothing to send. */
211
+ onSend: () => void;
212
+ placeholder?: string;
213
+ /** The send is in flight — the button spins, the box waits. */
214
+ sending?: boolean;
215
+ disabled?: boolean;
216
+ /**
217
+ * There is something to send besides text (an attachment). By default
218
+ * the send button wakes when the draft has a non-blank character.
219
+ */
220
+ canSend?: boolean;
221
+ /** Controls at the start of the bottom row — an add-attachment button. */
222
+ prefix?: ReactNode;
223
+ /** A quiet line between `prefix` and the send button — a count, a size. */
224
+ meta?: ReactNode;
225
+ /** The send button's accessible name. @default "Send" */
226
+ sendLabel?: string;
227
+ /** Above the text — attachment thumbnails. */
228
+ children?: ReactNode;
229
+ /** The `<textarea>`. */
230
+ textareaRef?: Ref<HTMLTextAreaElement>;
231
+ }
232
+ /**
233
+ * The message box: text that grows with the draft, Enter to send and
234
+ * Shift+Enter for a new line, one round send button. Attachments are the
235
+ * page's: put their thumbnails in `children`, the button that adds them
236
+ * in `prefix`, and flip `canSend` when they alone should send.
237
+ */
238
+ declare function Composer({ value, onValueChange, onSend, placeholder, sending, disabled, canSend, prefix, meta, sendLabel, children, textareaRef, className, ...props }: ChatComposerProps): import("react").JSX.Element;
239
+ export interface ChatEmptyProps extends StatusViewProps {
240
+ }
241
+ /**
242
+ * The standing-in view for either pane — no conversations, no thread
243
+ * chosen, nothing said yet. `StatusView` at card size, centered in
244
+ * whatever room the pane has.
245
+ */
246
+ declare function Empty({ className, size, ...props }: ChatEmptyProps): import("react").JSX.Element;
247
+ /** Bones in the shape of conversation rows — avatar, who, when, preview. */
248
+ declare function ConversationsLoading({ rows }: {
249
+ rows?: number;
250
+ }): import("react").JSX.Element;
251
+ /** Bones in a thread's shape — theirs left, ours right. */
252
+ declare function MessagesLoading(): import("react").JSX.Element;
253
+ /**
254
+ * The composed inbox. Assemble the two panes and fill them:
255
+ *
256
+ * ```tsx
257
+ * <Chat.Root layout="auto" className="h-[32rem]">
258
+ * <Chat.List>
259
+ * <Chat.Search value={query} onChange={…} />
260
+ * <Chat.Conversations>
261
+ * <Chat.ConversationList>
262
+ * <Chat.Conversation title="+1 (315) 997-8332" time="2d ago" preview="…" active />
263
+ * </Chat.ConversationList>
264
+ * </Chat.Conversations>
265
+ * </Chat.List>
266
+ * <Chat.Thread>
267
+ * <Chat.Header avatar={<Avatar.Root size="md">…</Avatar.Root>}>
268
+ * <Chat.Title>+1 (315) 997-8332</Chat.Title>
269
+ * <Chat.Description>From …</Chat.Description>
270
+ * </Chat.Header>
271
+ * <Chat.Messages>
272
+ * <Chat.Divider>September 12</Chat.Divider>
273
+ * <Message.Root>…</Message.Root>
274
+ * </Chat.Messages>
275
+ * <Chat.Footer>
276
+ * <Chat.Composer value={draft} onValueChange={setDraft} onSend={send} />
277
+ * </Chat.Footer>
278
+ * </Chat.Thread>
279
+ * </Chat.Root>
280
+ * ```
281
+ */
282
+ export declare const Chat: {
283
+ Root: typeof Root;
284
+ List: typeof List;
285
+ Search: typeof Search;
286
+ Conversations: typeof Conversations;
287
+ ConversationList: typeof ConversationList;
288
+ Conversation: typeof Conversation;
289
+ Thread: typeof Thread;
290
+ Header: typeof Header;
291
+ Title: typeof Title;
292
+ Description: typeof Description;
293
+ Messages: typeof Messages;
294
+ Divider: typeof Divider;
295
+ Footer: typeof Footer;
296
+ Composer: typeof Composer;
297
+ Empty: typeof Empty;
298
+ ConversationsLoading: typeof ConversationsLoading;
299
+ MessagesLoading: typeof MessagesLoading;
300
+ };
301
+ export {};
@@ -0,0 +1 @@
1
+ export { Chat, type ChatComposerProps, type ChatConversationButtonProps, type ChatConversationLinkProps, type ChatConversationProps, type ChatEmptyProps, type ChatHeaderProps, type ChatLayout, type ChatMessagesProps, type ChatPane, type ChatRootProps, type ChatSearchProps, } from './chat';
@@ -18,6 +18,7 @@ declare function Group({ className, ...props }: ComponentProps<typeof CommandPri
18
18
  * - `result` — flat search hit (breadcrumb + trailing scope)
19
19
  */
20
20
  export type CommandItemLevel = "item" | "subitem" | "subsubitem" | "result";
21
+ export type CommandItemSize = "sm" | "md";
21
22
  type ItemPrimitiveProps = ComponentProps<typeof CommandPrimitive.Item>;
22
23
  export interface CommandItemProps extends Omit<ItemPrimitiveProps, "children" | "title"> {
23
24
  /**
@@ -39,6 +40,12 @@ export interface CommandItemProps extends Omit<ItemPrimitiveProps, "children" |
39
40
  * has an icon; omit when the whole result set is icon-less.
40
41
  */
41
42
  iconSlot?: boolean;
43
+ /**
44
+ * Row density. `sm` tightens padding and type for chip popovers
45
+ * (Filter Bar options). Palette destinations stay `md`.
46
+ * @default "md"
47
+ */
48
+ size?: CommandItemSize;
42
49
  /** Primary label. Prefer this over free-form children for the shared layout. */
43
50
  title?: ReactNode;
44
51
  /**
@@ -58,13 +65,16 @@ export interface CommandItemProps extends Omit<ItemPrimitiveProps, "children" |
58
65
  */
59
66
  children?: ReactNode;
60
67
  }
61
- /** Leading icon column — `size-4`, secondary ink. */
62
- declare function ItemIcon({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
68
+ /** Leading icon column — `size-4` at `md`, tighter at `sm`. */
69
+ declare function ItemIcon({ className, size, ...props }: ComponentProps<"span"> & {
70
+ size?: CommandItemSize;
71
+ }): import("react").JSX.Element;
63
72
  /** Primary label — medium + primary ink on `item` rows. */
64
- declare function ItemTitle({ className, level, ...props }: ComponentProps<"span"> & {
73
+ declare function ItemTitle({ className, level, size, ...props }: ComponentProps<"span"> & {
65
74
  level?: CommandItemLevel;
75
+ size?: CommandItemSize;
66
76
  }): import("react").JSX.Element;
67
- declare function Item({ className, level, icon, iconSlot, title, path, scope, external, children, value, ...props }: CommandItemProps): import("react").JSX.Element;
77
+ declare function Item({ className, level, size, icon, iconSlot, title, path, scope, external, children, value, ...props }: CommandItemProps): import("react").JSX.Element;
68
78
  declare function Separator({ className, ...props }: ComponentProps<typeof CommandPrimitive.Separator>): import("react").JSX.Element;
69
79
  declare function Loading({ className, ...props }: ComponentProps<typeof CommandPrimitive.Loading>): import("react").JSX.Element;
70
80
  type DialogRootProps = ComponentProps<typeof PhoDialog.Root>;
@@ -1 +1 @@
1
- export { Command, useCommandState, type CommandItemLevel, type CommandItemProps, } from './command';
1
+ export { Command, useCommandState, type CommandItemLevel, type CommandItemProps, type CommandItemSize, } from './command';
@@ -21,6 +21,11 @@ import { ComponentProps, ReactNode, Ref } from 'react';
21
21
  export interface FilterOption {
22
22
  value: string;
23
23
  label: string;
24
+ /**
25
+ * Rich option row (a badge, mono path). Search and the set chip still
26
+ * use `label` and `value` strings.
27
+ */
28
+ title?: ReactNode;
24
29
  }
25
30
  interface FilterDefinitionBase {
26
31
  /** The key in `filters` this chip reads and writes. */
@@ -0,0 +1,2 @@
1
+ export { Message, type MessageAlign, type MessageRootProps } from './message';
2
+ export { messageStatusKey, shouldShowMessageStatus, type MessageStatusItem, } from './message-status';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * One row in a thread, enough to decide whether its outbound status
3
+ * caption should show. Inbound rows leave `outbound` off.
4
+ */
5
+ export interface MessageStatusItem {
6
+ outbound?: boolean;
7
+ /** Delivered, Sent, Failed — or a token like `delivered`. */
8
+ status?: string | null;
9
+ }
10
+ /**
11
+ * The coalesce key for a row: outbound status word, lowercased. Inbound
12
+ * and empty statuses are `null`, so they break a run. A failure keeps its
13
+ * whole text (`failed. 30007`) so two different error codes never
14
+ * collapse into one caption.
15
+ */
16
+ export declare function messageStatusKey(outbound: boolean, status: string | null | undefined): string | null;
17
+ /**
18
+ * Whether this row should render its outbound status (Delivered, Sent,
19
+ * Failed). Only the last message in a consecutive same-status run shows
20
+ * it. Inbound never does.
21
+ */
22
+ export declare function shouldShowMessageStatus(messages: readonly MessageStatusItem[], index: number): boolean;
@@ -0,0 +1,78 @@
1
+ import { ComponentProps } from 'react';
2
+ /**
3
+ * Message — one turn in a thread: the row that seats an avatar beside a
4
+ * column of header, bubble, and footer, on the author's side. It owns the
5
+ * row layout and nothing else: the surface is `Bubble`'s, the scrolling
6
+ * and the composer are `Chat`'s.
7
+ *
8
+ * Design notes:
9
+ * - `align="end"` mirrors the row — avatar on the right, column
10
+ * right-aligned — for the reader's own messages.
11
+ * - The avatar sits at the row's bottom, level with the bubble. When a
12
+ * `Footer` (status) sits under the bubble, the avatar shifts up by one
13
+ * line so it stays beside the surface.
14
+ * - `Time` sits beside the bubble, last-line aligned — right of inbound,
15
+ * left of outbound — and is invisible until the row is hovered or
16
+ * focused. `Footer` is the status caption under the bubble (Delivered,
17
+ * Failed). Inbound has no status.
18
+ */
19
+ export type MessageAlign = "start" | "end";
20
+ /** Consecutive messages from one author, spaced as one turn. */
21
+ declare function Group({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
22
+ export interface MessageRootProps extends ComponentProps<"div"> {
23
+ /** Which side the author sits on. @default "start" */
24
+ align?: MessageAlign;
25
+ }
26
+ /** The row: avatar beside the content column, mirrored for `end`. */
27
+ declare function Root({ align, className, ...props }: MessageRootProps): import("react").JSX.Element;
28
+ /**
29
+ * The avatar's seat — pass an `Avatar.Root`. Bottom-aligned with the
30
+ * bubble; lifts by one footer line when the message has a `Footer`.
31
+ */
32
+ declare function Avatar({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
33
+ /**
34
+ * Header over the bubble; time beside it; status under it. Inbound is
35
+ * `[bubble][time]`. Outbound is `[time][bubble]` with `Footer` below
36
+ * the bubble column.
37
+ */
38
+ declare function Content({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
39
+ /** Who — the sender's name over the bubble, secondary ink. */
40
+ declare function Header({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
41
+ /**
42
+ * Clock beside the bubble, last-line aligned. Description ink, tabular.
43
+ * Inbound sits to the right; outbound to the left. The slot stays in
44
+ * layout; the digits show when the row is hovered or focused.
45
+ */
46
+ declare function Time({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
47
+ /**
48
+ * Status under the bubble — Delivered, Failed. Inbound leaves it off.
49
+ * Description ink.
50
+ */
51
+ declare function Footer({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
52
+ /**
53
+ * A turn in a thread. `Root` takes `align`; `Avatar` seats an
54
+ * `Avatar.Root`; `Content` places `Header` over the bubble, `Time`
55
+ * beside it, and `Footer` under it.
56
+ *
57
+ * ```tsx
58
+ * <Message.Root align="end">
59
+ * <Message.Content>
60
+ * <Bubble.Root variant="inverse" align="end">
61
+ * <Bubble.Content>On my way.</Bubble.Content>
62
+ * </Bubble.Root>
63
+ * <Message.Time>2:47 PM</Message.Time>
64
+ * <Message.Footer>Delivered.</Message.Footer>
65
+ * </Message.Content>
66
+ * </Message.Root>
67
+ * ```
68
+ */
69
+ export declare const Message: {
70
+ Root: typeof Root;
71
+ Group: typeof Group;
72
+ Avatar: typeof Avatar;
73
+ Content: typeof Content;
74
+ Header: typeof Header;
75
+ Time: typeof Time;
76
+ Footer: typeof Footer;
77
+ };
78
+ export {};
@@ -28,3 +28,6 @@ export * from './components/log-list';
28
28
  export * from './components/description-list';
29
29
  export * from './components/code-block';
30
30
  export * from './components/trace';
31
+ export * from './components/bubble';
32
+ export * from './components/message';
33
+ export * from './components/chat';
@@ -126,6 +126,13 @@ interface ItemBaseProps {
126
126
  icon?: Slottable;
127
127
  /** Marks the row as the current destination (adds `aria-current="page"`). */
128
128
  active?: boolean;
129
+ /**
130
+ * Let the label break onto two lines instead of truncating. Default
131
+ * rows stay a single truncated line so the rail keeps even height.
132
+ * The row still uses `min-h-9`; wrap only grows it when the text
133
+ * actually breaks. Caps at two lines.
134
+ */
135
+ wrap?: boolean;
129
136
  children?: ReactNode;
130
137
  className?: string;
131
138
  }
@@ -149,8 +156,10 @@ export type SidebarItemProps = SidebarItemLinkProps | SidebarItemButtonProps;
149
156
  * A nav row — a link when `href` is given (rendered through the host's
150
157
  * `LinkProvider`), otherwise a button. `active` lifts the row onto the
151
158
  * primary surface; `external` opens a new tab and appends a ↗ cue.
159
+ * `wrap` drops the single-line truncate so a long product name can sit
160
+ * on two lines; other rows stay one line.
152
161
  */
153
- declare function Item({ icon, active, className, children, href, external, ...rest }: SidebarItemProps): import("react").JSX.Element;
162
+ declare function Item({ icon, active, wrap, className, children, href, external, ...rest }: SidebarItemProps): import("react").JSX.Element;
154
163
  export interface SidebarSubmenuProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | MotionHandlerConflicts> {
155
164
  /** The parent row's label. */
156
165
  label: ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@photon-ai/pho-ui",
3
- "version": "4.3.1",
3
+ "version": "4.4.0",
4
4
  "description": "Pho Design System — Photon's React component library, built on Base UI",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -455,6 +455,18 @@
455
455
  "./components/date-picker": {
456
456
  "types": "./dist/src/components/date-picker/index.d.ts",
457
457
  "import": "./dist/components/date-picker.js"
458
+ },
459
+ "./components/bubble": {
460
+ "types": "./dist/src/components/bubble/index.d.ts",
461
+ "import": "./dist/components/bubble.js"
462
+ },
463
+ "./components/message": {
464
+ "types": "./dist/src/components/message/index.d.ts",
465
+ "import": "./dist/components/message.js"
466
+ },
467
+ "./components/chat": {
468
+ "types": "./dist/src/components/chat/index.d.ts",
469
+ "import": "./dist/components/chat.js"
458
470
  }
459
471
  },
460
472
  "peerDependencies": {