@ttt-productions/chat-react 0.13.15 → 0.13.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/ChatNameResolverContext.d.ts +3 -3
- package/dist/context/ChatNameResolverContext.d.ts.map +1 -1
- package/dist/context/ChatNameResolverContext.js +3 -3
- package/dist/context/ChatNameResolverContext.js.map +1 -1
- package/dist/firestore/queries.js +1 -1
- package/dist/firestore/queries.js.map +1 -1
- package/dist/hooks/useChatMessages.d.ts +3 -3
- package/dist/hooks/useChatMessages.d.ts.map +1 -1
- package/dist/hooks/useChatMessages.js +20 -12
- package/dist/hooks/useChatMessages.js.map +1 -1
- package/dist/index.d.ts +32 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -11
- package/dist/index.js.map +1 -1
- package/dist/realtime/channel-client.d.ts.map +1 -1
- package/dist/realtime/channel-client.js +97 -32
- package/dist/realtime/channel-client.js.map +1 -1
- package/dist/realtime/inbox-client.d.ts.map +1 -1
- package/dist/realtime/inbox-client.js +29 -11
- package/dist/realtime/inbox-client.js.map +1 -1
- package/dist/realtime/initial-load-budget.d.ts.map +1 -1
- package/dist/realtime/initial-load-budget.js.map +1 -1
- package/dist/realtime/map.d.ts +0 -2
- package/dist/realtime/map.d.ts.map +1 -1
- package/dist/realtime/map.js +3 -4
- package/dist/realtime/map.js.map +1 -1
- package/dist/realtime/shared.d.ts +0 -1
- package/dist/realtime/shared.d.ts.map +1 -1
- package/dist/realtime/shared.js +2 -6
- package/dist/realtime/shared.js.map +1 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/realtime/socket.js +1 -11
- package/dist/realtime/socket.js.map +1 -1
- package/dist/realtime/transport.d.ts +1 -2
- package/dist/realtime/transport.d.ts.map +1 -1
- package/dist/realtime/transport.js +1 -1
- package/dist/realtime/transport.js.map +1 -1
- package/dist/realtime/useRealtimeChatMessages.d.ts +4 -4
- package/dist/realtime/useRealtimeChatMessages.d.ts.map +1 -1
- package/dist/realtime/useRealtimeChatMessages.js +5 -5
- package/dist/realtime/useRealtimeChatMessages.js.map +1 -1
- package/dist/realtime/wire.d.ts +0 -2
- package/dist/realtime/wire.d.ts.map +1 -1
- package/dist/realtime/wire.js +0 -6
- package/dist/realtime/wire.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js.map +1 -1
- package/dist/ui/ChatShell.d.ts +5 -5
- package/dist/ui/ChatShell.d.ts.map +1 -1
- package/dist/ui/ChatShell.js +37 -34
- package/dist/ui/ChatShell.js.map +1 -1
- package/dist/ui/Composer.d.ts +1 -1
- package/dist/ui/Composer.js +12 -12
- package/dist/ui/Composer.js.map +1 -1
- package/dist/ui/MessageItemDefault.d.ts +2 -2
- package/dist/ui/MessageItemDefault.d.ts.map +1 -1
- package/dist/ui/MessageItemDefault.js +26 -24
- package/dist/ui/MessageItemDefault.js.map +1 -1
- package/dist/ui/MessageList.d.ts +3 -3
- package/dist/ui/MessageList.d.ts.map +1 -1
- package/dist/ui/MessageList.js +13 -16
- package/dist/ui/MessageList.js.map +1 -1
- package/dist/ui/SenderName.js +3 -3
- package/dist/ui/SenderName.js.map +1 -1
- package/dist/ui/menus.d.ts +1 -1
- package/dist/ui/menus.d.ts.map +1 -1
- package/dist/ui/menus.js +4 -4
- package/dist/ui/menus.js.map +1 -1
- package/package.json +10 -10
- package/dist/realtime/index.d.ts +0 -19
- package/dist/realtime/index.d.ts.map +0 -1
- package/dist/realtime/index.js +0 -15
- package/dist/realtime/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../src/ui/MessageList.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type { ChatMessageGroupKey, ChatMessageV1, ModerationHandlers } from \"@ttt-productions/chat-core\";\nimport { isContinuation } from \"@ttt-productions/chat-core\";\nimport type { MessageRendererRegistry } from \"../types.js\";\nimport { Button, Spinner } from \"@ttt-productions/ui-core/react\";\nimport { MessageItemDefault } from \"./MessageItemDefault.js\";\n\n/** What `MessageList` hands a custom scroll container: the element it must render as the scrollable\n * message region, with this ref, class, scroll handler, and children. */\nexport type ChatScrollContainerProps = {\n ref: React.Ref<HTMLDivElement>;\n className: string;\n onScroll: React.UIEventHandler<HTMLDivElement>;\n children: React.ReactNode;\n};\n\n/** The default scroll container: a plain div. */\nfunction DefaultScrollContainer({ ref, className, onScroll, children }: ChatScrollContainerProps) {\n return (\n <div ref={ref} className={className} onScroll={onScroll}>\n {children}\n </div>\n );\n}\n\nexport function MessageList(props: {\n messages: ChatMessageV1[];\n currentUserId: string;\n isAdmin: boolean;\n\n isFetchingOlder?: boolean;\n hasOlder?: boolean;\n onLoadOlder?: () => void;\n\n renderMessage?: (m: ChatMessageV1) => React.ReactNode;\n messageRenderers?: MessageRendererRegistry;\n\n showScrollToBottom?: boolean;\n onScrollToBottom?: () => void;\n /** Reports whether the list is scrolled to the bottom so the consumer can advance\n * authoritative read state only when the latest message is actually in view. */\n onAtBottomChange?: (atBottom: boolean) => void;\n /** Class for the scrollable message region. Overrides the default. The default is\n * `h-[400px]` (fixed-height card) unless `fillHeight` is set, in which case it is\n * `flex-1 min-h-0`. */\n scrollClassName?: string;\n /** Renders the scrollable message region in place of the default div, so the consumer can give it\n * its own surface component. It must render one element carrying the given ref, class, scroll\n * handler, and children. */\n scrollContainer?: React.ComponentType<ChatScrollContainerProps>;\n /** Fill the parent's height instead of a fixed `h-[400px]`. Makes the list a flex-col\n * that flexes to fill its container, so a bounded-height page panel scrolls inside.\n * The consuming layout must give MessageList's ancestor a bounded height (ChatShell's\n * `fillHeight` wires Card → CardContent → MessageList for this). */\n fillHeight?: boolean;\n\n handlers?: ModerationHandlers;\n onSenderClick?: (senderId: string) => void;\n /** The app's per-message grouping fact (chat-core `isContinuation`): a change in it breaks a\n * same-sender group, so the sender line — and its adornment — shows again. */\n messageGroupKey?: ChatMessageGroupKey;\n /** The app's adornment beside a message's sender name (default renderer only). */\n renderSenderAdornment?: (m: ChatMessageV1) => React.ReactNode;\n /** Retry a failed realtime send by clientMessageId (realtime transport only). */\n onRetrySend?: (clientMessageId: string) => void;\n /**\n * The failed older-page row (the consumer's error state with its retry). While set, it\n * renders at the top of the list and the list stops requesting older pages — a failed\n * page is retried only through the row, never by scrolling into it again.\n */\n olderLoadErrorRow?: React.ReactNode;\n}) {\n const {\n messages,\n currentUserId,\n isAdmin,\n isFetchingOlder,\n hasOlder,\n onLoadOlder,\n renderMessage,\n messageRenderers,\n showScrollToBottom,\n onScrollToBottom,\n onAtBottomChange,\n scrollClassName,\n scrollContainer: ScrollContainer = DefaultScrollContainer,\n fillHeight = false,\n handlers,\n onSenderClick,\n messageGroupKey,\n renderSenderAdornment,\n onRetrySend,\n olderLoadErrorRow,\n } = props;\n const olderLoadFailed = olderLoadErrorRow != null;\n\n const scrollClass = scrollClassName ?? (fillHeight ? \"flex-1 min-h-0\" : \"h-[400px]\");\n const outerClass = fillHeight ? \"relative flex flex-col flex-1 min-h-0\" : \"relative\";\n\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const topSentinelRef = React.useRef<HTMLDivElement>(null);\n\n const isAtBottomRef = React.useRef(true);\n const prevScrollHeightRef = React.useRef<number | null>(null);\n const prevCountRef = React.useRef(0);\n\n // Count of messages that arrived while the user was scrolled up — drives the\n // \"new messages\" pill. Reset when the user returns to the bottom.\n const [unseenCount, setUnseenCount] = React.useState(0);\n\n const scrollToBottom = React.useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n isAtBottomRef.current = true;\n setUnseenCount(0);\n onAtBottomChange?.(true);\n }, [onAtBottomChange]);\n\n // IntersectionObserver for infinite scroll (older messages)\n React.useEffect(() => {\n const root = scrollRef.current;\n const target = topSentinelRef.current;\n if (!root || !target) return;\n if (typeof IntersectionObserver === \"undefined\") return;\n\n const io = new IntersectionObserver(\n (entries) => {\n const e = entries[0];\n if (!e?.isIntersecting) return;\n if (!hasOlder || isFetchingOlder || olderLoadFailed) return;\n\n prevScrollHeightRef.current = root.scrollHeight;\n onLoadOlder?.();\n },\n { root, threshold: 0 }\n );\n\n io.observe(target);\n return () => io.disconnect();\n }, [hasOlder, isFetchingOlder, olderLoadFailed, onLoadOlder]);\n\n // Scroll management — FIXES accordion scroll jump\n React.useLayoutEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const count = messages.length;\n const prev = prevCountRef.current;\n\n if (prev === 0 && count > 0) {\n // Initial load — scroll to bottom WITHOUT triggering parent scroll\n requestAnimationFrame(() => {\n const savedScrollY = window.scrollY;\n el.scrollTop = el.scrollHeight;\n // Restore page scroll if the browser moved it\n if (window.scrollY !== savedScrollY) {\n window.scrollTo({ top: savedScrollY, behavior: \"instant\" as ScrollBehavior });\n }\n });\n isAtBottomRef.current = true;\n } else if (count > prev && prevScrollHeightRef.current != null) {\n // Older messages prepended — maintain scroll position\n const diff = el.scrollHeight - prevScrollHeightRef.current;\n el.scrollTop += diff;\n prevScrollHeightRef.current = null;\n } else if (count > prev && isAtBottomRef.current) {\n // New message at bottom, user is at bottom — scroll down\n // Use scrollTop assignment, NOT scrollTo with behavior:\"smooth\" (causes parent scroll jump)\n requestAnimationFrame(() => {\n const savedScrollY = window.scrollY;\n el.scrollTop = el.scrollHeight;\n if (window.scrollY !== savedScrollY) {\n window.scrollTo({ top: savedScrollY, behavior: \"instant\" as ScrollBehavior });\n }\n });\n } else if (count > prev) {\n // New message(s) arrived while the user was scrolled up — surface the pill\n // instead of yanking their scroll position.\n setUnseenCount((c) => c + (count - prev));\n }\n\n prevCountRef.current = count;\n }, [messages]);\n\n const onScroll = (e: React.UIEvent<HTMLDivElement>) => {\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\n const atBottom = scrollHeight - (scrollTop + clientHeight) < 50;\n if (atBottom !== isAtBottomRef.current) onAtBottomChange?.(atBottom);\n isAtBottomRef.current = atBottom;\n if (atBottom && unseenCount !== 0) setUnseenCount(0);\n };\n\n let lastDay: string | null = null;\n\n return (\n <div className={outerClass}>\n <ScrollContainer ref={scrollRef} className={`${scrollClass} overflow-y-auto p-4`} onScroll={onScroll}>\n {olderLoadFailed ? (\n <div className=\"mb-2\">{olderLoadErrorRow}</div>\n ) : isFetchingOlder ? (\n <div className=\"flex justify-center mb-2\">\n <Spinner size=\"xs\" label=\"Loading older messages\" />\n </div>\n ) : null}\n\n <div ref={topSentinelRef} />\n\n {messages.length === 0 ? (\n <div className=\"h-full flex items-center justify-center text-sm opacity-70\">No messages yet</div>\n ) : (\n <div className=\"flex flex-col\">\n {messages.map((m, idx) => {\n const day = new Date(m.createdAt).toDateString();\n const showDay = day !== lastDay;\n lastDay = day;\n\n const prevMsg = idx > 0 ? messages[idx - 1] : undefined;\n // Date separators always break grouping\n const continuation = showDay ? false : isContinuation(prevMsg, m, messageGroupKey);\n\n const byType =\n m.type && messageRenderers?.[m.type] ? messageRenderers[m.type]!(m) : null;\n\n const body =\n renderMessage?.(m) ??\n byType ?? (\n <MessageItemDefault\n m={m}\n currentUserId={currentUserId}\n isAdmin={isAdmin}\n handlers={handlers}\n isContinuation={continuation}\n onSenderClick={onSenderClick}\n senderAdornment={renderSenderAdornment?.(m)}\n onRetrySend={onRetrySend}\n />\n );\n\n return (\n <React.Fragment key={m.messageId}>\n {showDay && (\n <div className=\"my-2 flex justify-center\">\n {/* theme-core: components.css */}\n <div className=\"chat-date-separator\">\n {new Date(m.createdAt).toLocaleDateString()}\n </div>\n </div>\n )}\n {body}\n </React.Fragment>\n );\n })}\n </div>\n )}\n </ScrollContainer>\n\n {(unseenCount > 0 || showScrollToBottom) && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={unseenCount > 0 ? `${unseenCount} new messages, scroll to latest` : \"Scroll to latest\"}\n className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full elevation-raised gap-1\"\n onClick={() => {\n scrollToBottom();\n onScrollToBottom?.();\n }}\n >\n {unseenCount > 0\n ? `${unseenCount} new message${unseenCount > 1 ? \"s\" : \"\"} ↓`\n : \"↓\"}\n </Button>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../src/ui/MessageList.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7D,iDAAiD;AACjD,SAAS,sBAAsB,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAA4B;IAC9F,OAAO,CACL,cAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,YACpD,QAAQ,GACL,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KA8C3B;IACC,MAAM,EACJ,QAAQ,EACR,aAAa,EACb,OAAO,EACP,eAAe,EACf,QAAQ,EACR,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAAE,eAAe,GAAG,sBAAsB,EACzD,UAAU,GAAG,KAAK,EAClB,QAAQ,EACR,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,iBAAiB,GAClB,GAAG,KAAK,CAAC;IACV,MAAM,eAAe,GAAG,iBAAiB,IAAI,IAAI,CAAC;IAElD,MAAM,WAAW,GAAG,eAAe,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACrF,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,UAAU,CAAC;IAErF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAiB,IAAI,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAiB,IAAI,CAAC,CAAC;IAE1D,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,mBAAmB,GAAG,KAAK,CAAC,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAErC,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAExD,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC5C,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;QAC/B,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;QAC7B,cAAc,CAAC,CAAC,CAAC,CAAC;QAClB,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEvB,4DAA4D;IAC5D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC;QAC/B,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAC7B,IAAI,OAAO,oBAAoB,KAAK,WAAW;YAAE,OAAO;QAExD,MAAM,EAAE,GAAG,IAAI,oBAAoB,CACjC,CAAC,OAAO,EAAE,EAAE;YACV,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,CAAC,CAAC,EAAE,cAAc;gBAAE,OAAO;YAC/B,IAAI,CAAC,QAAQ,IAAI,eAAe,IAAI,eAAe;gBAAE,OAAO;YAE5D,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;YAChD,WAAW,EAAE,EAAE,CAAC;QAClB,CAAC,EACD,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,CACvB,CAAC;QAEF,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC;IAE9D,kDAAkD;IAClD,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;QACzB,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,EAAE;YAAE,OAAO;QAEhB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC9B,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC;QAElC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC5B,mEAAmE;YACnE,qBAAqB,CAAC,GAAG,EAAE;gBACzB,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;gBACpC,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;gBAC/B,8CAA8C;gBAC9C,IAAI,MAAM,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;oBACpC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,SAA2B,EAAE,CAAC,CAAC;gBAChF,CAAC;YACH,CAAC,CAAC,CAAC;YACH,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,CAAC;aAAM,IAAI,KAAK,GAAG,IAAI,IAAI,mBAAmB,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;YAC/D,sDAAsD;YACtD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC;YAC3D,EAAE,CAAC,SAAS,IAAI,IAAI,CAAC;YACrB,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC;QACrC,CAAC;aAAM,IAAI,KAAK,GAAG,IAAI,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;YACjD,yDAAyD;YACzD,4FAA4F;YAC5F,qBAAqB,CAAC,GAAG,EAAE;gBACzB,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;gBACpC,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;gBAC/B,IAAI,MAAM,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;oBACpC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,SAA2B,EAAE,CAAC,CAAC;gBAChF,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC;YACxB,2EAA2E;YAC3E,4CAA4C;YAC5C,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;IAC/B,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,QAAQ,GAAG,CAAC,CAAgC,EAAE,EAAE;QACpD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,aAAa,CAAC;QAClE,MAAM,QAAQ,GAAG,YAAY,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC;QAChE,IAAI,QAAQ,KAAK,aAAa,CAAC,OAAO;YAAE,gBAAgB,EAAE,CAAC,QAAQ,CAAC,CAAC;QACrE,aAAa,CAAC,OAAO,GAAG,QAAQ,CAAC;QACjC,IAAI,QAAQ,IAAI,WAAW,KAAK,CAAC;YAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,IAAI,OAAO,GAAkB,IAAI,CAAC;IAElC,OAAO,CACL,eAAK,SAAS,EAAE,UAAU,aACxB,MAAC,eAAe,IACd,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,GAAG,WAAW,sBAAsB,EAC/C,QAAQ,EAAE,QAAQ,aAEjB,eAAe,CAAC,CAAC,CAAC,CACjB,cAAK,SAAS,EAAC,MAAM,YAAE,iBAAiB,GAAO,CAChD,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CACpB,cAAK,SAAS,EAAC,0BAA0B,YACvC,KAAC,OAAO,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,wBAAwB,GAAG,GAChD,CACP,CAAC,CAAC,CAAC,IAAI,EAER,cAAK,GAAG,EAAE,cAAc,GAAI,EAE3B,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACvB,cAAK,SAAS,EAAC,4DAA4D,gCAErE,CACP,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,eAAe,YAC3B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;4BACvB,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,CAAC;4BACjD,MAAM,OAAO,GAAG,GAAG,KAAK,OAAO,CAAC;4BAChC,OAAO,GAAG,GAAG,CAAC;4BAEd,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BACxD,wCAAwC;4BACxC,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;4BAEnF,MAAM,MAAM,GACV,CAAC,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;4BAE7E,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,IAAI,CAC3C,KAAC,kBAAkB,IACjB,CAAC,EAAE,CAAC,EACJ,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,YAAY,EAC5B,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAC3C,WAAW,EAAE,WAAW,GACxB,CACH,CAAC;4BAEF,OAAO,CACL,MAAC,KAAK,CAAC,QAAQ,eACZ,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,0BAA0B,YAEvC,cAAK,SAAS,EAAC,qBAAqB,YACjC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,GACvC,GACF,CACP,EACA,IAAI,KATc,CAAC,CAAC,SAAS,CAUf,CAClB,CAAC;wBACJ,CAAC,CAAC,GACE,CACP,IACe,EAEjB,CAAC,WAAW,GAAG,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAC1C,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,gBAEP,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,EAExF,SAAS,EAAC,iFAAiF,EAC3F,OAAO,EAAE,GAAG,EAAE;oBACZ,cAAc,EAAE,CAAC;oBACjB,gBAAgB,EAAE,EAAE,CAAC;gBACvB,CAAC,YAEA,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,eAAe,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,GAC7E,CACV,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type {\n ChatMessageGroupKey,\n ChatMessageV1,\n ModerationHandlers,\n} from '@ttt-productions/chat-core';\nimport { isContinuation } from '@ttt-productions/chat-core';\nimport type { MessageRendererRegistry } from '../types.js';\nimport { Button, Spinner } from '@ttt-productions/ui-core/react';\nimport { MessageItemDefault } from './MessageItemDefault.js';\n\n/** What `MessageList` hands a custom scroll container: the element it must render as the scrollable\n * message region, with this ref, class, scroll handler, and children. */\nexport type ChatScrollContainerProps = {\n ref: React.Ref<HTMLDivElement>;\n className: string;\n onScroll: React.UIEventHandler<HTMLDivElement>;\n children: React.ReactNode;\n};\n\n/** The default scroll container: a plain div. */\nfunction DefaultScrollContainer({ ref, className, onScroll, children }: ChatScrollContainerProps) {\n return (\n <div ref={ref} className={className} onScroll={onScroll}>\n {children}\n </div>\n );\n}\n\nexport function MessageList(props: {\n messages: ChatMessageV1[];\n currentUserId: string;\n isAdmin: boolean;\n\n isFetchingOlder?: boolean;\n hasOlder?: boolean;\n onLoadOlder?: () => void;\n\n renderMessage?: (m: ChatMessageV1) => React.ReactNode;\n messageRenderers?: MessageRendererRegistry;\n\n showScrollToBottom?: boolean;\n onScrollToBottom?: () => void;\n /** Reports whether the list is scrolled to the bottom so the consumer can advance\n * authoritative read state only when the latest message is actually in view. */\n onAtBottomChange?: (atBottom: boolean) => void;\n /** Class for the scrollable message region. Overrides the default. The default is\n * `h-[400px]` (fixed-height card) unless `fillHeight` is set, in which case it is\n * `flex-1 min-h-0`. */\n scrollClassName?: string;\n /** Renders the scrollable message region in place of the default div, so the consumer can give it\n * its own surface component. It must render one element carrying the given ref, class, scroll\n * handler, and children. */\n scrollContainer?: React.ComponentType<ChatScrollContainerProps>;\n /** Fill the parent's height instead of a fixed `h-[400px]`. Makes the list a flex-col\n * that flexes to fill its container, so a bounded-height page panel scrolls inside.\n * The consuming layout must give MessageList's ancestor a bounded height (ChatShell's\n * `fillHeight` wires Card → CardContent → MessageList for this). */\n fillHeight?: boolean;\n\n handlers?: ModerationHandlers;\n onSenderClick?: (senderId: string) => void;\n /** The app's per-message grouping fact (chat-core `isContinuation`): a change in it breaks a\n * same-sender group, so the sender line — and its adornment — shows again. */\n messageGroupKey?: ChatMessageGroupKey;\n /** The app's adornment beside a message's sender name (default renderer only). */\n renderSenderAdornment?: (m: ChatMessageV1) => React.ReactNode;\n /** Retry a failed realtime send by clientMessageId (realtime transport only). */\n onRetrySend?: (clientMessageId: string) => void;\n /**\n * The failed older-page row (the consumer's error state with its retry). While set, it\n * renders at the top of the list and the list stops requesting older pages — a failed\n * page is retried only through the row, never by scrolling into it again.\n */\n olderLoadErrorRow?: React.ReactNode;\n}) {\n const {\n messages,\n currentUserId,\n isAdmin,\n isFetchingOlder,\n hasOlder,\n onLoadOlder,\n renderMessage,\n messageRenderers,\n showScrollToBottom,\n onScrollToBottom,\n onAtBottomChange,\n scrollClassName,\n scrollContainer: ScrollContainer = DefaultScrollContainer,\n fillHeight = false,\n handlers,\n onSenderClick,\n messageGroupKey,\n renderSenderAdornment,\n onRetrySend,\n olderLoadErrorRow,\n } = props;\n const olderLoadFailed = olderLoadErrorRow != null;\n\n const scrollClass = scrollClassName ?? (fillHeight ? 'flex-1 min-h-0' : 'h-[400px]');\n const outerClass = fillHeight ? 'relative flex flex-col flex-1 min-h-0' : 'relative';\n\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const topSentinelRef = React.useRef<HTMLDivElement>(null);\n\n const isAtBottomRef = React.useRef(true);\n const prevScrollHeightRef = React.useRef<number | null>(null);\n const prevCountRef = React.useRef(0);\n\n // Count of messages that arrived while the user was scrolled up — drives the\n // \"new messages\" pill. Reset when the user returns to the bottom.\n const [unseenCount, setUnseenCount] = React.useState(0);\n\n const scrollToBottom = React.useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n isAtBottomRef.current = true;\n setUnseenCount(0);\n onAtBottomChange?.(true);\n }, [onAtBottomChange]);\n\n // IntersectionObserver for infinite scroll (older messages)\n React.useEffect(() => {\n const root = scrollRef.current;\n const target = topSentinelRef.current;\n if (!root || !target) return;\n if (typeof IntersectionObserver === 'undefined') return;\n\n const io = new IntersectionObserver(\n (entries) => {\n const e = entries[0];\n if (!e?.isIntersecting) return;\n if (!hasOlder || isFetchingOlder || olderLoadFailed) return;\n\n prevScrollHeightRef.current = root.scrollHeight;\n onLoadOlder?.();\n },\n { root, threshold: 0 },\n );\n\n io.observe(target);\n return () => io.disconnect();\n }, [hasOlder, isFetchingOlder, olderLoadFailed, onLoadOlder]);\n\n // Scroll management — FIXES accordion scroll jump\n React.useLayoutEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const count = messages.length;\n const prev = prevCountRef.current;\n\n if (prev === 0 && count > 0) {\n // Initial load — scroll to bottom WITHOUT triggering parent scroll\n requestAnimationFrame(() => {\n const savedScrollY = window.scrollY;\n el.scrollTop = el.scrollHeight;\n // Restore page scroll if the browser moved it\n if (window.scrollY !== savedScrollY) {\n window.scrollTo({ top: savedScrollY, behavior: 'instant' as ScrollBehavior });\n }\n });\n isAtBottomRef.current = true;\n } else if (count > prev && prevScrollHeightRef.current != null) {\n // Older messages prepended — maintain scroll position\n const diff = el.scrollHeight - prevScrollHeightRef.current;\n el.scrollTop += diff;\n prevScrollHeightRef.current = null;\n } else if (count > prev && isAtBottomRef.current) {\n // New message at bottom, user is at bottom — scroll down\n // Use scrollTop assignment, NOT scrollTo with behavior:\"smooth\" (causes parent scroll jump)\n requestAnimationFrame(() => {\n const savedScrollY = window.scrollY;\n el.scrollTop = el.scrollHeight;\n if (window.scrollY !== savedScrollY) {\n window.scrollTo({ top: savedScrollY, behavior: 'instant' as ScrollBehavior });\n }\n });\n } else if (count > prev) {\n // New message(s) arrived while the user was scrolled up — surface the pill\n // instead of yanking their scroll position.\n setUnseenCount((c) => c + (count - prev));\n }\n\n prevCountRef.current = count;\n }, [messages]);\n\n const onScroll = (e: React.UIEvent<HTMLDivElement>) => {\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\n const atBottom = scrollHeight - (scrollTop + clientHeight) < 50;\n if (atBottom !== isAtBottomRef.current) onAtBottomChange?.(atBottom);\n isAtBottomRef.current = atBottom;\n if (atBottom && unseenCount !== 0) setUnseenCount(0);\n };\n\n let lastDay: string | null = null;\n\n return (\n <div className={outerClass}>\n <ScrollContainer\n ref={scrollRef}\n className={`${scrollClass} overflow-y-auto p-4`}\n onScroll={onScroll}\n >\n {olderLoadFailed ? (\n <div className=\"mb-2\">{olderLoadErrorRow}</div>\n ) : isFetchingOlder ? (\n <div className=\"flex justify-center mb-2\">\n <Spinner size=\"xs\" label=\"Loading older messages\" />\n </div>\n ) : null}\n\n <div ref={topSentinelRef} />\n\n {messages.length === 0 ? (\n <div className=\"h-full flex items-center justify-center text-sm opacity-70\">\n No messages yet\n </div>\n ) : (\n <div className=\"flex flex-col\">\n {messages.map((m, idx) => {\n const day = new Date(m.createdAt).toDateString();\n const showDay = day !== lastDay;\n lastDay = day;\n\n const prevMsg = idx > 0 ? messages[idx - 1] : undefined;\n // Date separators always break grouping\n const continuation = showDay ? false : isContinuation(prevMsg, m, messageGroupKey);\n\n const byType =\n m.type && messageRenderers?.[m.type] ? messageRenderers[m.type]!(m) : null;\n\n const body = renderMessage?.(m) ?? byType ?? (\n <MessageItemDefault\n m={m}\n currentUserId={currentUserId}\n isAdmin={isAdmin}\n handlers={handlers}\n isContinuation={continuation}\n onSenderClick={onSenderClick}\n senderAdornment={renderSenderAdornment?.(m)}\n onRetrySend={onRetrySend}\n />\n );\n\n return (\n <React.Fragment key={m.messageId}>\n {showDay && (\n <div className=\"my-2 flex justify-center\">\n {/* theme-core: components.css */}\n <div className=\"chat-date-separator\">\n {new Date(m.createdAt).toLocaleDateString()}\n </div>\n </div>\n )}\n {body}\n </React.Fragment>\n );\n })}\n </div>\n )}\n </ScrollContainer>\n\n {(unseenCount > 0 || showScrollToBottom) && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={\n unseenCount > 0 ? `${unseenCount} new messages, scroll to latest` : 'Scroll to latest'\n }\n className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full elevation-raised gap-1\"\n onClick={() => {\n scrollToBottom();\n onScrollToBottom?.();\n }}\n >\n {unseenCount > 0 ? `${unseenCount} new message${unseenCount > 1 ? 's' : ''} ↓` : '↓'}\n </Button>\n )}\n </div>\n );\n}\n"]}
|
package/dist/ui/SenderName.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useChatNameResolver } from
|
|
3
|
+
import { useChatNameResolver } from '../context/ChatNameResolverContext.js';
|
|
4
4
|
/**
|
|
5
5
|
* A message sender's name: the resolved name, or — when the app could not resolve it —
|
|
6
6
|
* whatever the app's `renderUnresolvedName` renders for that resolution. Never a stand-in
|
|
@@ -9,7 +9,7 @@ import { useChatNameResolver } from "../context/ChatNameResolverContext.js";
|
|
|
9
9
|
export function SenderName({ senderId }) {
|
|
10
10
|
const { resolveName, renderUnresolvedName } = useChatNameResolver();
|
|
11
11
|
const resolution = resolveName(senderId);
|
|
12
|
-
if (resolution.status ===
|
|
12
|
+
if (resolution.status === 'resolved')
|
|
13
13
|
return _jsx(_Fragment, { children: resolution.name });
|
|
14
14
|
return _jsx(_Fragment, { children: renderUnresolvedName?.(resolution) ?? null });
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SenderName.js","sourceRoot":"","sources":["../../src/ui/SenderName.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAwB;IAC3D,MAAM,EAAE,WAAW,EAAE,oBAAoB,EAAE,GAAG,mBAAmB,EAAE,CAAC;IACpE,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,4BAAG,UAAU,CAAC,IAAI,GAAI,CAAC;IACpE,OAAO,4BAAG,oBAAoB,EAAE,CAAC,UAAU,CAAC,IAAI,IAAI,GAAI,CAAC;AAC3D,CAAC","sourcesContent":["
|
|
1
|
+
{"version":3,"file":"SenderName.js","sourceRoot":"","sources":["../../src/ui/SenderName.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAwB;IAC3D,MAAM,EAAE,WAAW,EAAE,oBAAoB,EAAE,GAAG,mBAAmB,EAAE,CAAC;IACpE,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,4BAAG,UAAU,CAAC,IAAI,GAAI,CAAC;IACpE,OAAO,4BAAG,oBAAoB,EAAE,CAAC,UAAU,CAAC,IAAI,IAAI,GAAI,CAAC;AAC3D,CAAC","sourcesContent":["'use client';\n\nimport { useChatNameResolver } from '../context/ChatNameResolverContext.js';\n\n/**\n * A message sender's name: the resolved name, or — when the app could not resolve it —\n * whatever the app's `renderUnresolvedName` renders for that resolution. Never a stand-in\n * name: an unresolved sender with no slot renders nothing.\n */\nexport function SenderName({ senderId }: { senderId: string }) {\n const { resolveName, renderUnresolvedName } = useChatNameResolver();\n const resolution = resolveName(senderId);\n if (resolution.status === 'resolved') return <>{resolution.name}</>;\n return <>{renderUnresolvedName?.(resolution) ?? null}</>;\n}\n"]}
|
package/dist/ui/menus.d.ts
CHANGED
package/dist/ui/menus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menus.d.ts","sourceRoot":"","sources":["../../src/ui/menus.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"menus.d.ts","sourceRoot":"","sources":["../../src/ui/menus.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAmCrE,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,+BAaA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,+BAeA"}
|
package/dist/ui/menus.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Button, useAsyncAction } from
|
|
3
|
+
import { Button, useAsyncAction } from '@ttt-productions/ui-core/react';
|
|
4
4
|
// The consumer's handler owns its failure UX. The action only keeps a rejection
|
|
5
5
|
// from vanishing: it re-raises it on the global error channel, where monitoring
|
|
6
6
|
// sees it — exactly where an unawaited rejection would have gone.
|
|
@@ -20,12 +20,12 @@ export function MessageActions(props) {
|
|
|
20
20
|
const { messageId, isAdmin, handlers } = props;
|
|
21
21
|
const onReport = handlers?.onReportMessage;
|
|
22
22
|
const onDelete = handlers?.onDeleteMessage;
|
|
23
|
-
return (_jsxs("div", { className: "flex items-center gap-2", children: [onReport && _jsx(ModerationActionButton, { label: "Report", onAction: () => onReport(messageId) }), isAdmin && onDelete && _jsx(ModerationActionButton, { label: "Delete", onAction: () => onDelete(messageId) })] }));
|
|
23
|
+
return (_jsxs("div", { className: "flex items-center gap-2", children: [onReport && _jsx(ModerationActionButton, { label: "Report", onAction: () => onReport(messageId) }), isAdmin && onDelete && (_jsx(ModerationActionButton, { label: "Delete", onAction: () => onDelete(messageId) }))] }));
|
|
24
24
|
}
|
|
25
25
|
export function ThreadActions(props) {
|
|
26
26
|
const { threadId, isAdmin, handlers } = props;
|
|
27
27
|
const onReport = handlers?.onReportThread;
|
|
28
28
|
const onDelete = handlers?.onDeleteThread;
|
|
29
|
-
return (_jsxs("div", { className: "flex items-center gap-3", children: [onReport && _jsx(ModerationActionButton, { label: "Report thread", onAction: () => onReport(threadId) }), isAdmin && onDelete && _jsx(ModerationActionButton, { label: "Delete thread", onAction: () => onDelete(threadId) })] }));
|
|
29
|
+
return (_jsxs("div", { className: "flex items-center gap-3", children: [onReport && (_jsx(ModerationActionButton, { label: "Report thread", onAction: () => onReport(threadId) })), isAdmin && onDelete && (_jsx(ModerationActionButton, { label: "Delete thread", onAction: () => onDelete(threadId) }))] }));
|
|
30
30
|
}
|
|
31
31
|
//# sourceMappingURL=menus.js.map
|
package/dist/ui/menus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menus.js","sourceRoot":"","sources":["../../src/ui/menus.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAExE,gFAAgF;AAChF,gFAAgF;AAChF,kEAAkE;AAClE,SAAS,OAAO,CAAC,KAAc;IAC7B,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAAC,KAA8D;IAC5F,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAClC,MAAM,MAAM,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"menus.js","sourceRoot":"","sources":["../../src/ui/menus.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAExE,gFAAgF;AAChF,gFAAgF;AAChF,kEAAkE;AAClE,SAAS,OAAO,CAAC,KAAc;IAC7B,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAAC,KAA8D;IAC5F,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAClC,MAAM,MAAM,GAAG,cAAc,CAC3B,KAAK,IAAI,EAAE;QACT,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,EACD,EAAE,OAAO,EAAE,OAAO,EAAE,CACrB,CAAC;IAEF,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,MAAM,EACd,IAAI,EAAC,IAAI,EACT,SAAS,EAAC,iDAAiD,EAC3D,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,EAAE,EAChC,OAAO,EAAE,MAAM,CAAC,OAAO,YAEtB,KAAK,GACC,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAI9B;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,QAAQ,GAAG,QAAQ,EAAE,eAAe,CAAC;IAC3C,MAAM,QAAQ,GAAG,QAAQ,EAAE,eAAe,CAAC;IAE3C,OAAO,CACL,eAAK,SAAS,EAAC,yBAAyB,aACrC,QAAQ,IAAI,KAAC,sBAAsB,IAAC,KAAK,EAAC,QAAQ,EAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAI,EAC1F,OAAO,IAAI,QAAQ,IAAI,CACtB,KAAC,sBAAsB,IAAC,KAAK,EAAC,QAAQ,EAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAI,CAC/E,IACG,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAI7B;IACC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,EAAE,cAAc,CAAC;IAC1C,MAAM,QAAQ,GAAG,QAAQ,EAAE,cAAc,CAAC;IAE1C,OAAO,CACL,eAAK,SAAS,EAAC,yBAAyB,aACrC,QAAQ,IAAI,CACX,KAAC,sBAAsB,IAAC,KAAK,EAAC,eAAe,EAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAI,CACrF,EACA,OAAO,IAAI,QAAQ,IAAI,CACtB,KAAC,sBAAsB,IAAC,KAAK,EAAC,eAAe,EAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAI,CACrF,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport type { ModerationHandlers } from '@ttt-productions/chat-core';\nimport { Button, useAsyncAction } from '@ttt-productions/ui-core/react';\n\n// The consumer's handler owns its failure UX. The action only keeps a rejection\n// from vanishing: it re-raises it on the global error channel, where monitoring\n// sees it — exactly where an unawaited rejection would have gone.\nfunction reraise(error: unknown) {\n setTimeout(() => {\n throw error;\n });\n}\n\nfunction ModerationActionButton(props: { label: string; onAction: () => void | Promise<void> }) {\n const { label, onAction } = props;\n const action = useAsyncAction(\n async () => {\n await onAction();\n },\n { onError: reraise },\n );\n\n return (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n className=\"h-auto p-0 text-xs opacity-70 hover:opacity-100\"\n onClick={() => void action.run()}\n pending={action.pending}\n >\n {label}\n </Button>\n );\n}\n\nexport function MessageActions(props: {\n messageId: string;\n isAdmin: boolean;\n handlers?: ModerationHandlers;\n}) {\n const { messageId, isAdmin, handlers } = props;\n const onReport = handlers?.onReportMessage;\n const onDelete = handlers?.onDeleteMessage;\n\n return (\n <div className=\"flex items-center gap-2\">\n {onReport && <ModerationActionButton label=\"Report\" onAction={() => onReport(messageId)} />}\n {isAdmin && onDelete && (\n <ModerationActionButton label=\"Delete\" onAction={() => onDelete(messageId)} />\n )}\n </div>\n );\n}\n\nexport function ThreadActions(props: {\n threadId: string;\n isAdmin: boolean;\n handlers?: ModerationHandlers;\n}) {\n const { threadId, isAdmin, handlers } = props;\n const onReport = handlers?.onReportThread;\n const onDelete = handlers?.onDeleteThread;\n\n return (\n <div className=\"flex items-center gap-3\">\n {onReport && (\n <ModerationActionButton label=\"Report thread\" onAction={() => onReport(threadId)} />\n )}\n {isAdmin && onDelete && (\n <ModerationActionButton label=\"Delete thread\" onAction={() => onDelete(threadId)} />\n )}\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/chat-react",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.16",
|
|
4
4
|
"description": "Chat React UI, hooks, and Firebase-client adapter for TTT Productions apps (realtime newest window + infinite older pagination)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@tanstack/react-query": ">=5.0.0",
|
|
36
|
-
"@ttt-productions/query-core": "^0.14.
|
|
36
|
+
"@ttt-productions/query-core": "^0.14.22",
|
|
37
37
|
"firebase": ">=12.0.0",
|
|
38
38
|
"lucide-react": "^1.30.0",
|
|
39
39
|
"react": ">=19.0.0",
|
|
@@ -60,16 +60,16 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@ttt-productions/chat-core": "^0.11.
|
|
64
|
-
"@ttt-productions/chat-schemas": "^0.10.
|
|
65
|
-
"@ttt-productions/realtime-core": "^0.1.
|
|
66
|
-
"@ttt-productions/ui-core": "^0.11.
|
|
67
|
-
"@ttt-productions/upload-ui": "^0.7.
|
|
68
|
-
"@ttt-productions/mobile-core": "^0.9.
|
|
69
|
-
"@ttt-productions/firebase-helpers": "^0.12.
|
|
63
|
+
"@ttt-productions/chat-core": "^0.11.4",
|
|
64
|
+
"@ttt-productions/chat-schemas": "^0.10.7",
|
|
65
|
+
"@ttt-productions/realtime-core": "^0.1.4",
|
|
66
|
+
"@ttt-productions/ui-core": "^0.11.34",
|
|
67
|
+
"@ttt-productions/upload-ui": "^0.7.17",
|
|
68
|
+
"@ttt-productions/mobile-core": "^0.9.5",
|
|
69
|
+
"@ttt-productions/firebase-helpers": "^0.12.13"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@ttt-productions/query-core": "^0.14.
|
|
72
|
+
"@ttt-productions/query-core": "^0.14.22",
|
|
73
73
|
"@types/react": "^19.0.0",
|
|
74
74
|
"@types/react-dom": "^19.0.0",
|
|
75
75
|
"lucide-react": "^1.30.0",
|
package/dist/realtime/index.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export { CHAT_SUBPROTOCOL, CHAT_WIRE_VERSION, CHAT_CLOSE_CODES, CLIENT_FRAME, SERVER_FRAME, buildFrame, parseFrame, isInboxSnapshot, } from './wire.js';
|
|
2
|
-
export type { ChatCloseCode, WireMessageRow, WireChannelSnapshot, WireInboxSnapshot, WireRegistryEntry, ServerFrame, RevisionKind, } from './wire.js';
|
|
3
|
-
export type { RealtimeSocket, SocketFactory, SocketHandlers } from './socket.js';
|
|
4
|
-
export { browserSocketFactory } from './socket.js';
|
|
5
|
-
export type { GrantProvider, TransportTimers, RealtimeStatus } from './shared.js';
|
|
6
|
-
export { CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS, defaultTimers, ChatAccessDeniedError, isChatAccessDeniedError, HEARTBEAT_MS, TYPING_COALESCE_MS, HISTORY_PAGE_MAX, } from './shared.js';
|
|
7
|
-
export { wireRowToMessage, optimisticMessage, seqToMessageId, applyModerationOverlay, overlayFromRow, MODERATION_REDACTED_TEXT, } from './map.js';
|
|
8
|
-
export type { ModerationOverlay } from './map.js';
|
|
9
|
-
export { CHAT_CLIENT_DIAGNOSTIC_EVENTS } from './diagnostics.js';
|
|
10
|
-
export type { ChatClientDiagnosticsOption, ChatClientDiagnosticsSink, ChatClientDiagnosticEventName, } from './diagnostics.js';
|
|
11
|
-
export { ChannelClient } from './channel-client.js';
|
|
12
|
-
export type { ChannelClientState, ChannelClientConfig } from './channel-client.js';
|
|
13
|
-
export { InboxClient } from './inbox-client.js';
|
|
14
|
-
export type { InboxClientState, InboxClientConfig, ChatMarkReadOutcome } from './inbox-client.js';
|
|
15
|
-
export { createRealtimeChatClient, createInboxClient, } from './transport.js';
|
|
16
|
-
export type { RealtimeChatClient, RealtimeTransportConfig } from './transport.js';
|
|
17
|
-
export { useRealtimeChatMessages } from './useRealtimeChatMessages.js';
|
|
18
|
-
export type { UseRealtimeChatMessagesResult } from './useRealtimeChatMessages.js';
|
|
19
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,WAAW,CAAC;AAEnB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,mCAAmC,EACnC,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EACV,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAElG,OAAO,EACL,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/realtime/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// The realtime (Cloudflare Durable Object) chat transport — the client half of
|
|
2
|
-
// the chat Worker wire protocol (Contract A connection + Contract C wire). The
|
|
3
|
-
// FIRESTORE transport stays the unchanged default; this is opt-in via
|
|
4
|
-
// `ChatCoreConfig.transport === 'realtime'` + a `realtime.client` from
|
|
5
|
-
// `createRealtimeChatClient(...)`.
|
|
6
|
-
export { CHAT_SUBPROTOCOL, CHAT_WIRE_VERSION, CHAT_CLOSE_CODES, CLIENT_FRAME, SERVER_FRAME, buildFrame, parseFrame, isInboxSnapshot, } from './wire.js';
|
|
7
|
-
export { browserSocketFactory } from './socket.js';
|
|
8
|
-
export { CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS, defaultTimers, ChatAccessDeniedError, isChatAccessDeniedError, HEARTBEAT_MS, TYPING_COALESCE_MS, HISTORY_PAGE_MAX, } from './shared.js';
|
|
9
|
-
export { wireRowToMessage, optimisticMessage, seqToMessageId, applyModerationOverlay, overlayFromRow, MODERATION_REDACTED_TEXT, } from './map.js';
|
|
10
|
-
export { CHAT_CLIENT_DIAGNOSTIC_EVENTS } from './diagnostics.js';
|
|
11
|
-
export { ChannelClient } from './channel-client.js';
|
|
12
|
-
export { InboxClient } from './inbox-client.js';
|
|
13
|
-
export { createRealtimeChatClient, createInboxClient, } from './transport.js';
|
|
14
|
-
export { useRealtimeChatMessages } from './useRealtimeChatMessages.js';
|
|
15
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,sEAAsE;AACtE,uEAAuE;AACvE,mCAAmC;AAEnC,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,eAAe,GAChB,MAAM,WAAW,CAAC;AAYnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EACL,mCAAmC,EACnC,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAOjE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EACL,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC","sourcesContent":["// The realtime (Cloudflare Durable Object) chat transport — the client half of\n// the chat Worker wire protocol (Contract A connection + Contract C wire). The\n// FIRESTORE transport stays the unchanged default; this is opt-in via\n// `ChatCoreConfig.transport === 'realtime'` + a `realtime.client` from\n// `createRealtimeChatClient(...)`.\n\nexport {\n CHAT_SUBPROTOCOL,\n CHAT_WIRE_VERSION,\n CHAT_CLOSE_CODES,\n CLIENT_FRAME,\n SERVER_FRAME,\n buildFrame,\n parseFrame,\n isInboxSnapshot,\n} from './wire.js';\nexport type {\n ChatCloseCode,\n WireMessageRow,\n WireChannelSnapshot,\n WireInboxSnapshot,\n WireRegistryEntry,\n ServerFrame,\n RevisionKind,\n} from './wire.js';\n\nexport type { RealtimeSocket, SocketFactory, SocketHandlers } from './socket.js';\nexport { browserSocketFactory } from './socket.js';\n\nexport type { GrantProvider, TransportTimers, RealtimeStatus } from './shared.js';\nexport {\n CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS,\n defaultTimers,\n ChatAccessDeniedError,\n isChatAccessDeniedError,\n HEARTBEAT_MS,\n TYPING_COALESCE_MS,\n HISTORY_PAGE_MAX,\n} from './shared.js';\n\nexport {\n wireRowToMessage,\n optimisticMessage,\n seqToMessageId,\n applyModerationOverlay,\n overlayFromRow,\n MODERATION_REDACTED_TEXT,\n} from './map.js';\nexport type { ModerationOverlay } from './map.js';\n\nexport { CHAT_CLIENT_DIAGNOSTIC_EVENTS } from './diagnostics.js';\nexport type {\n ChatClientDiagnosticsOption,\n ChatClientDiagnosticsSink,\n ChatClientDiagnosticEventName,\n} from './diagnostics.js';\n\nexport { ChannelClient } from './channel-client.js';\nexport type { ChannelClientState, ChannelClientConfig } from './channel-client.js';\nexport { InboxClient } from './inbox-client.js';\nexport type { InboxClientState, InboxClientConfig, ChatMarkReadOutcome } from './inbox-client.js';\n\nexport {\n createRealtimeChatClient,\n createInboxClient,\n} from './transport.js';\nexport type { RealtimeChatClient, RealtimeTransportConfig } from './transport.js';\n\nexport { useRealtimeChatMessages } from './useRealtimeChatMessages.js';\nexport type { UseRealtimeChatMessagesResult } from './useRealtimeChatMessages.js';\n"]}
|