@athenaintel/react 0.22.3 → 0.23.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.
- package/README.md +394 -4
- package/dist/chat/AthenaChat.cjs +389 -240
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +26 -8
- package/dist/chat/AthenaChat.js +394 -245
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +2 -1
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.js +2 -1
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +1 -0
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireClientToolBridge.js +1 -0
- package/dist/chat/StatewireClientToolBridge.js.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +1 -0
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.js +1 -0
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +100 -0
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -0
- package/dist/chat/WaitingOnYouBanner.d.ts +29 -0
- package/dist/chat/WaitingOnYouBanner.js +100 -0
- package/dist/chat/WaitingOnYouBanner.js.map +1 -0
- package/dist/chat/athena-chat-welcome.cjs +148 -0
- package/dist/chat/athena-chat-welcome.cjs.map +1 -0
- package/dist/chat/athena-chat-welcome.d.ts +54 -0
- package/dist/chat/athena-chat-welcome.js +148 -0
- package/dist/chat/athena-chat-welcome.js.map +1 -0
- package/dist/chat/athena-composer-controls.cjs +76 -0
- package/dist/chat/athena-composer-controls.cjs.map +1 -0
- package/dist/chat/athena-composer-controls.d.ts +21 -0
- package/dist/chat/athena-composer-controls.js +76 -0
- package/dist/chat/athena-composer-controls.js.map +1 -0
- package/dist/chat/composer-keyboard-hint.cjs +61 -0
- package/dist/chat/composer-keyboard-hint.cjs.map +1 -0
- package/dist/chat/composer-keyboard-hint.d.ts +33 -0
- package/dist/chat/composer-keyboard-hint.js +61 -0
- package/dist/chat/composer-keyboard-hint.js.map +1 -0
- package/dist/chat/message-time.cjs +64 -0
- package/dist/chat/message-time.cjs.map +1 -0
- package/dist/chat/message-time.d.ts +45 -0
- package/dist/chat/message-time.js +64 -0
- package/dist/chat/message-time.js.map +1 -0
- package/dist/chat/run-activity.cjs +38 -7
- package/dist/chat/run-activity.cjs.map +1 -1
- package/dist/chat/run-activity.d.ts +14 -3
- package/dist/chat/run-activity.js +39 -8
- package/dist/chat/run-activity.js.map +1 -1
- package/dist/chat/statewire-client-tools.cjs +2 -1
- package/dist/chat/statewire-client-tools.cjs.map +1 -1
- package/dist/chat/statewire-client-tools.js +2 -1
- package/dist/chat/statewire-client-tools.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +2 -1
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.js +2 -1
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/thread-scroll-to-bottom.cjs +24 -0
- package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -0
- package/dist/chat/thread-scroll-to-bottom.d.ts +11 -0
- package/dist/chat/thread-scroll-to-bottom.js +24 -0
- package/dist/chat/thread-scroll-to-bottom.js.map +1 -0
- package/dist/chat/tiptap-text.cjs +26 -99
- package/dist/chat/tiptap-text.cjs.map +1 -1
- package/dist/chat/tiptap-text.d.ts +13 -0
- package/dist/chat/tiptap-text.js +26 -99
- package/dist/chat/tiptap-text.js.map +1 -1
- package/dist/chat/use-athena-run-live.cjs +2 -1
- package/dist/chat/use-athena-run-live.cjs.map +1 -1
- package/dist/chat/use-athena-run-live.js +2 -1
- package/dist/chat/use-athena-run-live.js.map +1 -1
- package/dist/chat/use-statewire-approval-request.cjs +1 -0
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.js +1 -0
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +39 -4
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +21 -0
- package/dist/chat-ui/composer/tiptap-composer.js +39 -4
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/index.cjs +15 -1
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +6 -3
- package/dist/chat-ui/index.js +16 -2
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +31 -4
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.js +31 -4
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +19 -1
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.d.ts +13 -0
- package/dist/chat-ui/messages/message-components.js +19 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/runtime-message.cjs +2 -1
- package/dist/chat-ui/messages/runtime-message.cjs.map +1 -1
- package/dist/chat-ui/messages/runtime-message.js +2 -1
- package/dist/chat-ui/messages/runtime-message.js.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.cjs +1 -0
- package/dist/chat-ui/messages/statewire-continue-run.cjs.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.js +1 -0
- package/dist/chat-ui/messages/statewire-continue-run.js.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs +3 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.js +3 -1
- package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +84 -0
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -0
- package/dist/chat-ui/messages/wake-marker.d.ts +16 -0
- package/dist/chat-ui/messages/wake-marker.js +84 -0
- package/dist/chat-ui/messages/wake-marker.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-blocks.cjs +177 -0
- package/dist/chat-ui/rich-text/chat-blocks.cjs.map +1 -0
- package/dist/chat-ui/rich-text/chat-blocks.d.ts +58 -0
- package/dist/chat-ui/rich-text/chat-blocks.js +177 -0
- package/dist/chat-ui/rich-text/chat-blocks.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.cjs +69 -0
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.d.ts +24 -0
- package/dist/chat-ui/rich-text/chat-link.js +69 -0
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-message-body.cjs +144 -18
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.d.ts +10 -1
- package/dist/chat-ui/rich-text/chat-message-body.js +149 -23
- package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +84 -4
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.d.ts +12 -1
- package/dist/chat-ui/rich-text/chat-node-views.js +85 -5
- package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.cjs +21 -3
- package/dist/chat-ui/rich-text/chat-text-schema.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-text-schema.d.ts +17 -2
- package/dist/chat-ui/rich-text/chat-text-schema.js +21 -3
- package/dist/chat-ui/rich-text/chat-text-schema.js.map +1 -1
- package/dist/chat-ui/rich-text/citation-anchors.cjs +139 -0
- package/dist/chat-ui/rich-text/citation-anchors.cjs.map +1 -0
- package/dist/chat-ui/rich-text/citation-anchors.d.ts +74 -0
- package/dist/chat-ui/rich-text/citation-anchors.js +139 -0
- package/dist/chat-ui/rich-text/citation-anchors.js.map +1 -0
- package/dist/chat-ui/statewire.cjs +8 -1
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -0
- package/dist/chat-ui/statewire.js +8 -1
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/chat-composer-dock.cjs +27 -6
- package/dist/chat-ui/thread/chat-composer-dock.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-composer-dock.d.ts +21 -1
- package/dist/chat-ui/thread/chat-composer-dock.js +28 -7
- package/dist/chat-ui/thread/chat-composer-dock.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +12 -13
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +11 -10
- package/dist/chat-ui/thread/statewire-history-edge.js +13 -14
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/chat-ui/thread/thread-loading-overlay.cjs +31 -0
- package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -0
- package/dist/chat-ui/thread/thread-loading-overlay.d.ts +14 -0
- package/dist/chat-ui/thread/thread-loading-overlay.js +31 -0
- package/dist/chat-ui/thread/thread-loading-overlay.js.map +1 -0
- package/dist/composer/ComposerDropZone.cjs +8 -1
- package/dist/composer/ComposerDropZone.cjs.map +1 -1
- package/dist/composer/ComposerDropZone.d.ts +6 -0
- package/dist/composer/ComposerDropZone.js +9 -2
- package/dist/composer/ComposerDropZone.js.map +1 -1
- package/dist/diagnostics/errors.cjs +20 -0
- package/dist/diagnostics/errors.cjs.map +1 -1
- package/dist/diagnostics/errors.d.ts +20 -0
- package/dist/diagnostics/errors.js +20 -0
- package/dist/diagnostics/errors.js.map +1 -1
- package/dist/index.cjs +47 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +26 -7
- package/dist/index.js +51 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/use-prefers-reduced-motion.cjs +29 -0
- package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -0
- package/dist/lib/use-prefers-reduced-motion.d.ts +6 -0
- package/dist/lib/use-prefers-reduced-motion.js +29 -0
- package/dist/lib/use-prefers-reduced-motion.js.map +1 -0
- package/dist/packages/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-index.js.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-list.cjs +59 -0
- package/dist/packages/agent-runtime/src/conversation-list.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/conversation-list.js +60 -1
- package/dist/packages/agent-runtime/src/conversation-list.js.map +1 -1
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.cjs +5 -3
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.js +5 -3
- package/dist/packages/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.cjs +21 -17
- package/dist/packages/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.js +22 -18
- package/dist/packages/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +9 -11
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +9 -11
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/packages/agent-runtime/src/github-wake-event.cjs +86 -0
- package/dist/packages/agent-runtime/src/github-wake-event.cjs.map +1 -0
- package/dist/packages/agent-runtime/src/github-wake-event.js +86 -0
- package/dist/packages/agent-runtime/src/github-wake-event.js.map +1 -0
- package/dist/packages/agent-runtime/src/message-window.cjs +150 -42
- package/dist/packages/agent-runtime/src/message-window.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/message-window.js +151 -43
- package/dist/packages/agent-runtime/src/message-window.js.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs +13 -9
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js +13 -9
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/packages/agent-runtime/src/statewire-suspended.cjs +1 -3
- package/dist/packages/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/statewire-suspended.js +1 -3
- package/dist/packages/agent-runtime/src/statewire-suspended.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs +61 -30
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.js +59 -28
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.cjs +56 -36
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.js +59 -39
- package/dist/packages/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/packages/react/package.json.cjs +1 -1
- package/dist/packages/react/package.json.js +1 -1
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaContext.d.ts +3 -0
- package/dist/provider/AthenaContext.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +93 -45
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +6 -1
- package/dist/provider/AthenaProvider.js +97 -49
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +2 -1
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.js +2 -1
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +3 -2
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +8 -12
- package/dist/runtime/useAthenaStatewireRuntime.js +3 -2
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/search/useAthenaRepoSearch.cjs +94 -0
- package/dist/search/useAthenaRepoSearch.cjs.map +1 -0
- package/dist/search/useAthenaRepoSearch.d.ts +95 -0
- package/dist/search/useAthenaRepoSearch.js +94 -0
- package/dist/search/useAthenaRepoSearch.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/threads/SessionList.cjs +486 -0
- package/dist/threads/SessionList.cjs.map +1 -0
- package/dist/threads/SessionList.d.ts +60 -0
- package/dist/threads/SessionList.js +486 -0
- package/dist/threads/SessionList.js.map +1 -0
- package/dist/threads/api.cjs +112 -4
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.d.ts +128 -1
- package/dist/threads/api.js +113 -5
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/conversation-list-fetcher.cjs +27 -3
- package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +16 -3
- package/dist/threads/conversation-list-fetcher.js +27 -3
- package/dist/threads/conversation-list-fetcher.js.map +1 -1
- package/dist/threads/index.d.ts +5 -1
- package/dist/threads/session-list-model.cjs +130 -0
- package/dist/threads/session-list-model.cjs.map +1 -0
- package/dist/threads/session-list-model.d.ts +62 -0
- package/dist/threads/session-list-model.js +130 -0
- package/dist/threads/session-list-model.js.map +1 -0
- package/dist/threads/statewire-thread-list.cjs +220 -38
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +152 -2
- package/dist/threads/statewire-thread-list.js +222 -40
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-prefetcher.cjs +63 -0
- package/dist/threads/thread-prefetcher.cjs.map +1 -0
- package/dist/threads/thread-prefetcher.d.ts +54 -0
- package/dist/threads/thread-prefetcher.js +63 -0
- package/dist/threads/thread-prefetcher.js.map +1 -0
- package/dist/threads/use-athena-session-attention.cjs +22 -0
- package/dist/threads/use-athena-session-attention.cjs.map +1 -0
- package/dist/threads/use-athena-session-attention.d.ts +24 -0
- package/dist/threads/use-athena-session-attention.js +22 -0
- package/dist/threads/use-athena-session-attention.js.map +1 -0
- package/dist/threads/use-rest-conversation-history.cjs +25 -2
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +8 -1
- package/dist/threads/use-rest-conversation-history.js +25 -2
- package/dist/threads/use-rest-conversation-history.js.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +40 -16
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.d.ts +13 -0
- package/dist/threads/use-statewire-conversation-history.js +40 -16
- package/dist/threads/use-statewire-conversation-history.js.map +1 -1
- package/dist/threads/use-thread-archive.cjs +128 -0
- package/dist/threads/use-thread-archive.cjs.map +1 -0
- package/dist/threads/use-thread-archive.d.ts +26 -0
- package/dist/threads/use-thread-archive.js +128 -0
- package/dist/threads/use-thread-archive.js.map +1 -0
- package/dist/threads/use-thread-favorite.cjs +53 -0
- package/dist/threads/use-thread-favorite.cjs.map +1 -0
- package/dist/threads/use-thread-favorite.d.ts +49 -0
- package/dist/threads/use-thread-favorite.js +53 -0
- package/dist/threads/use-thread-favorite.js.map +1 -0
- package/dist/threads/use-thread-field-override.cjs +184 -0
- package/dist/threads/use-thread-field-override.cjs.map +1 -0
- package/dist/threads/use-thread-field-override.d.ts +55 -0
- package/dist/threads/use-thread-field-override.js +184 -0
- package/dist/threads/use-thread-field-override.js.map +1 -0
- package/dist/threads/use-thread-rename.cjs +53 -0
- package/dist/threads/use-thread-rename.cjs.map +1 -0
- package/dist/threads/use-thread-rename.d.ts +48 -0
- package/dist/threads/use-thread-rename.js +53 -0
- package/dist/threads/use-thread-rename.js.map +1 -0
- package/dist/tools/index.cjs +5 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +7 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -1
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.js +2 -1
- package/dist/tools/misc-tool-uis.js.map +1 -1
- package/dist/tools/primitives.cjs +25 -2
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/primitives.d.ts +9 -2
- package/dist/tools/primitives.js +26 -3
- package/dist/tools/primitives.js.map +1 -1
- package/dist/tools/tool-appearance.cjs +11 -0
- package/dist/tools/tool-appearance.cjs.map +1 -0
- package/dist/tools/tool-appearance.d.ts +29 -0
- package/dist/tools/tool-appearance.js +11 -0
- package/dist/tools/tool-appearance.js.map +1 -0
- package/dist/tools/tool-fallback.cjs +211 -13
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-fallback.d.ts +31 -4
- package/dist/tools/tool-fallback.js +214 -16
- package/dist/tools/tool-fallback.js.map +1 -1
- package/dist/tools/use-elapsed-seconds.cjs +24 -0
- package/dist/tools/use-elapsed-seconds.cjs.map +1 -0
- package/dist/tools/use-elapsed-seconds.d.ts +10 -0
- package/dist/tools/use-elapsed-seconds.js +24 -0
- package/dist/tools/use-elapsed-seconds.js.map +1 -0
- package/dist/tools/voice-update-tool-ui.cjs +2 -1
- package/dist/tools/voice-update-tool-ui.cjs.map +1 -1
- package/dist/tools/voice-update-tool-ui.js +2 -1
- package/dist/tools/voice-update-tool-ui.js.map +1 -1
- package/package.json +1 -1
- package/src/chat-ui/tailwind-preset.js +14 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"athena-chat-welcome.js","sources":["../../src/chat/athena-chat-welcome.tsx"],"sourcesContent":["import { ArrowRightIcon, FileTextIcon, PresentationIcon, SearchIcon } from 'lucide-react';\nimport { useCallback, type CSSProperties, type FC } from 'react';\nimport { useSendMessage } from '../composer/useSendMessage';\nimport { cn } from '../lib/utils';\nimport { usePrefersReducedMotion } from '../lib/use-prefers-reduced-motion';\n\nexport interface WelcomeSuggestion {\n icon: React.ElementType;\n title: string;\n prompt: string;\n}\n\nexport const DEFAULT_WELCOME_SUGGESTIONS: WelcomeSuggestion[] = [\n {\n icon: SearchIcon,\n title: 'Research a topic and draft a report',\n prompt:\n 'Search the web for the latest developments in enterprise AI adoption, then create a document summarizing the key trends, market data, and strategic implications.',\n },\n {\n icon: SearchIcon,\n title: 'Compare recent AI model launches',\n prompt:\n 'Search the web for the latest major AI model launches from OpenAI, Anthropic, and Google, then summarize the release dates, standout capabilities, and practical tradeoffs in a concise comparison table.',\n },\n {\n icon: PresentationIcon,\n title: 'Build a presentation from scratch',\n prompt:\n 'Create a 5-slide investor update presentation covering market opportunity, product traction, key metrics, competitive positioning, and next steps.',\n },\n {\n icon: FileTextIcon,\n title: 'Set up a structured spreadsheet',\n prompt:\n 'Create a project tracking spreadsheet with columns for task name, owner, priority, status, start date, due date, and completion percentage.',\n },\n];\n\n/**\n * The empty state's entrance schedule: the greeting first, the suggestion\n * cards staggered behind it, the composer last. Every value is an inline\n * `animation-delay`, so a host reading the DOM sees the schedule as-is.\n */\nexport const WELCOME_GREETING_SUBTEXT_DELAY_MS = 60;\nexport const WELCOME_SUGGESTION_STAGGER_BASE_MS = 120;\nexport const WELCOME_SUGGESTION_STAGGER_STEP_MS = 70;\nexport const WELCOME_COMPOSER_ENTER_DELAY_MS = 360;\n\nexport function welcomeSuggestionDelayMs(index: number): number {\n return WELCOME_SUGGESTION_STAGGER_BASE_MS + index * WELCOME_SUGGESTION_STAGGER_STEP_MS;\n}\n\n/** Gap between the last card and the composer, which always arrives last. */\nconst WELCOME_COMPOSER_AFTER_LAST_CARD_MS = 30;\n\n/**\n * When the composer enters: 360 ms behind the default four cards, and behind\n * the last card whenever a host supplies more (`welcomeSuggestions` is\n * unbounded), so the composer is always the final element to arrive.\n */\nexport function welcomeComposerDelayMs(suggestionCount: number): number {\n if (suggestionCount <= 0) return WELCOME_COMPOSER_ENTER_DELAY_MS;\n return Math.max(\n WELCOME_COMPOSER_ENTER_DELAY_MS,\n welcomeSuggestionDelayMs(suggestionCount - 1) + WELCOME_COMPOSER_AFTER_LAST_CARD_MS,\n );\n}\n\n/** Fade + short rise; `fill-mode-both` holds the hidden start through a delay. */\nexport const WELCOME_ENTER_CLASS =\n 'animate-in fade-in slide-in-from-bottom-2 fill-mode-both animation-duration-300';\n\n/**\n * Inline entrance schedule for one element, or nothing under reduced motion\n * (no classes, no delay — the element is simply there).\n */\nexport function welcomeEntrance(\n delayMs: number,\n reducedMotion: boolean,\n): { className: string | undefined; style: CSSProperties | undefined } {\n if (reducedMotion) return { className: undefined, style: undefined };\n return { className: WELCOME_ENTER_CLASS, style: { animationDelay: `${delayMs}ms` } };\n}\n\nconst SuggestionCard: FC<{\n suggestion: WelcomeSuggestion;\n index: number;\n reducedMotion: boolean;\n}> = ({ suggestion, index, reducedMotion }) => {\n const Icon = suggestion.icon;\n const sendMessage = useSendMessage();\n const entrance = welcomeEntrance(welcomeSuggestionDelayMs(index), reducedMotion);\n\n const handleClick = useCallback(() => {\n void sendMessage(suggestion.prompt);\n }, [sendMessage, suggestion.prompt]);\n\n // Icon row above the title: the card reads the same at a 2-column width\n // and in the one-row layout, where each card is about a quarter of the\n // thread and a side-by-side icon would leave the title a few words wide.\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(\n 'aui-thread-welcome-suggestion group flex flex-col items-start gap-2.5 rounded-xl border border-border/60 bg-card p-3.5 text-left shadow-sm transition-all duration-150 hover:border-border hover:bg-muted/40 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n entrance.className,\n )}\n style={entrance.style}\n data-welcome-suggestion={index}\n >\n <span className=\"flex w-full items-center justify-between\">\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted/60 text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary\">\n <Icon className=\"size-4\" />\n </span>\n <ArrowRightIcon className=\"size-3.5 shrink-0 text-muted-foreground/0 transition-all group-hover:text-muted-foreground\" />\n </span>\n <span className=\"text-[13px] font-medium leading-snug text-foreground\">\n {suggestion.title}\n </span>\n </button>\n );\n};\n\nexport interface AthenaChatWelcomeSuggestionsProps {\n suggestions: readonly WelcomeSuggestion[];\n className?: string;\n}\n\n/**\n * The suggestion cards, docked directly above the composer in the empty\n * state: equal-width in one row once the thread is 40rem wide, a two-column\n * grid below that (a container query on the thread root, so a chat embedded\n * in a narrow pane of a wide window wraps too). Cards stagger in at\n * 120 ms + 70 ms × index; none of it moves under reduced motion.\n */\nexport const AthenaChatWelcomeSuggestions: FC<AthenaChatWelcomeSuggestionsProps> = ({\n suggestions,\n className,\n}) => {\n const reducedMotion = usePrefersReducedMotion();\n if (suggestions.length === 0) return null;\n return (\n <div\n className={cn(\n 'aui-thread-welcome-suggestions grid w-full auto-rows-fr grid-cols-2 gap-2.5 @min-[40rem]:grid-flow-col @min-[40rem]:auto-cols-fr',\n className,\n )}\n data-testid=\"athena-welcome-suggestions\"\n >\n {suggestions.map((suggestion, index) => (\n <SuggestionCard\n key={suggestion.title}\n suggestion={suggestion}\n index={index}\n reducedMotion={reducedMotion}\n />\n ))}\n </div>\n );\n};\n\nexport interface AthenaChatWelcomeProps {\n welcomeMessage: string;\n welcomeSubtext?: string;\n}\n\n/**\n * The greeting, centred in the viewport's free space while the thread is\n * empty. Fades and rises in; the subtext follows a beat later.\n */\nexport const AthenaChatWelcome: FC<AthenaChatWelcomeProps> = ({\n welcomeMessage,\n welcomeSubtext,\n}) => {\n const reducedMotion = usePrefersReducedMotion();\n const greeting = welcomeEntrance(0, reducedMotion);\n const subtext = welcomeEntrance(WELCOME_GREETING_SUBTEXT_DELAY_MS, reducedMotion);\n return (\n <div className=\"aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col\">\n <div className=\"aui-thread-welcome-center flex w-full grow flex-col items-center justify-center\">\n <div className=\"aui-thread-welcome-message flex size-full flex-col justify-center px-4\">\n <h2\n className={cn(\n 'aui-thread-welcome-message-inner text-2xl font-semibold text-foreground',\n greeting.className,\n )}\n style={greeting.style}\n >\n {welcomeMessage}\n </h2>\n {welcomeSubtext && (\n <p\n className={cn(\n 'aui-thread-welcome-message-inner text-lg text-muted-foreground',\n subtext.className,\n )}\n style={subtext.style}\n >\n {welcomeSubtext}\n </p>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,8BAAmD;AAAA,EAC9D;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QACE;AAAA,EAAA;AAAA,EAEJ;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QACE;AAAA,EAAA;AAAA,EAEJ;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QACE;AAAA,EAAA;AAAA,EAEJ;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QACE;AAAA,EAAA;AAEN;AAOO,MAAM,oCAAoC;AAC1C,MAAM,qCAAqC;AAC3C,MAAM,qCAAqC;AAC3C,MAAM,kCAAkC;AAExC,SAAS,yBAAyB,OAAuB;AAC9D,SAAO,qCAAqC,QAAQ;AACtD;AAGA,MAAM,sCAAsC;AAOrC,SAAS,uBAAuB,iBAAiC;AACtE,MAAI,mBAAmB,EAAG,QAAO;AACjC,SAAO,KAAK;AAAA,IACV;AAAA,IACA,yBAAyB,kBAAkB,CAAC,IAAI;AAAA,EAAA;AAEpD;AAGO,MAAM,sBACX;AAMK,SAAS,gBACd,SACA,eACqE;AACrE,MAAI,cAAe,QAAO,EAAE,WAAW,QAAW,OAAO,OAAA;AACzD,SAAO,EAAE,WAAW,qBAAqB,OAAO,EAAE,gBAAgB,GAAG,OAAO,OAAK;AACnF;AAEA,MAAM,iBAID,CAAC,EAAE,YAAY,OAAO,oBAAoB;AAC7C,QAAM,OAAO,WAAW;AACxB,QAAM,cAAc,eAAA;AACpB,QAAM,WAAW,gBAAgB,yBAAyB,KAAK,GAAG,aAAa;AAE/E,QAAM,cAAc,YAAY,MAAM;AACpC,SAAK,YAAY,WAAW,MAAM;AAAA,EACpC,GAAG,CAAC,aAAa,WAAW,MAAM,CAAC;AAKnC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,WAAW;AAAA,QACT;AAAA,QACA,SAAS;AAAA,MAAA;AAAA,MAEX,OAAO,SAAS;AAAA,MAChB,2BAAyB;AAAA,MAEzB,UAAA;AAAA,QAAA,qBAAC,QAAA,EAAK,WAAU,4CACd,UAAA;AAAA,UAAA,oBAAC,UAAK,WAAU,sKACd,8BAAC,MAAA,EAAK,WAAU,UAAS,EAAA,CAC3B;AAAA,UACA,oBAAC,gBAAA,EAAe,WAAU,6FAAA,CAA6F;AAAA,QAAA,GACzH;AAAA,QACA,oBAAC,QAAA,EAAK,WAAU,wDACb,qBAAW,MAAA,CACd;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAcO,MAAM,+BAAsE,CAAC;AAAA,EAClF;AAAA,EACA;AACF,MAAM;AACJ,QAAM,gBAAgB,wBAAA;AACtB,MAAI,YAAY,WAAW,EAAG,QAAO;AACrC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,eAAY;AAAA,MAEX,UAAA,YAAY,IAAI,CAAC,YAAY,UAC5B;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAHK,WAAW;AAAA,MAAA,CAKnB;AAAA,IAAA;AAAA,EAAA;AAGP;AAWO,MAAM,oBAAgD,CAAC;AAAA,EAC5D;AAAA,EACA;AACF,MAAM;AACJ,QAAM,gBAAgB,wBAAA;AACtB,QAAM,WAAW,gBAAgB,GAAG,aAAa;AACjD,QAAM,UAAU,gBAAgB,mCAAmC,aAAa;AAChF,SACE,oBAAC,OAAA,EAAI,WAAU,gGACb,UAAA,oBAAC,OAAA,EAAI,WAAU,mFACb,UAAA,qBAAC,OAAA,EAAI,WAAU,0EACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,SAAS;AAAA,QAAA;AAAA,QAEX,OAAO,SAAS;AAAA,QAEf,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF,kBACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,QAAA;AAAA,QAEV,OAAO,QAAQ;AAAA,QAEd,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,EAAA,CAEJ,GACF,GACF;AAEJ;"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const lucideReact = require("lucide-react");
|
|
5
|
+
const tooltipIconButton = require("./tooltip-icon-button.cjs");
|
|
6
|
+
const button = require("../ui/button.cjs");
|
|
7
|
+
const AthenaComposerSendButton = ({
|
|
8
|
+
action,
|
|
9
|
+
onSend,
|
|
10
|
+
disabled,
|
|
11
|
+
title
|
|
12
|
+
}) => {
|
|
13
|
+
const label = action === "queue" ? "Queue message" : "Send message";
|
|
14
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15
|
+
tooltipIconButton.TooltipIconButton,
|
|
16
|
+
{
|
|
17
|
+
tooltip: title ?? label,
|
|
18
|
+
side: "bottom",
|
|
19
|
+
type: "button",
|
|
20
|
+
variant: "default",
|
|
21
|
+
size: "icon",
|
|
22
|
+
className: "aui-composer-send size-8 rounded-full disabled:opacity-30",
|
|
23
|
+
"aria-label": label,
|
|
24
|
+
"data-composer-action": action,
|
|
25
|
+
onClick: onSend,
|
|
26
|
+
disabled,
|
|
27
|
+
children: action === "queue" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListPlusIcon, { className: "aui-composer-send-icon size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
const AthenaComposerStopButton = ({
|
|
32
|
+
onStop,
|
|
33
|
+
disabled,
|
|
34
|
+
title
|
|
35
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36
|
+
button.Button,
|
|
37
|
+
{
|
|
38
|
+
type: "button",
|
|
39
|
+
variant: "default",
|
|
40
|
+
size: "icon",
|
|
41
|
+
className: "aui-composer-cancel size-8 rounded-full disabled:opacity-30",
|
|
42
|
+
"aria-label": "Stop generating",
|
|
43
|
+
"data-composer-action": "stop",
|
|
44
|
+
title,
|
|
45
|
+
onClick: onStop,
|
|
46
|
+
disabled,
|
|
47
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
const AthenaComposerMentionButton = ({
|
|
51
|
+
onClick,
|
|
52
|
+
disabled
|
|
53
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
54
|
+
tooltipIconButton.TooltipIconButton,
|
|
55
|
+
{
|
|
56
|
+
tooltip: "Mention an asset or tool",
|
|
57
|
+
side: "bottom",
|
|
58
|
+
type: "button",
|
|
59
|
+
variant: "ghost",
|
|
60
|
+
size: "icon",
|
|
61
|
+
className: "aui-composer-mention size-8 rounded-full text-muted-foreground hover:text-foreground disabled:opacity-30",
|
|
62
|
+
"aria-label": "Mention an asset or tool",
|
|
63
|
+
onClick,
|
|
64
|
+
disabled,
|
|
65
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AtSignIcon, { className: "size-4" })
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
const ATHENA_COMPOSER_COMPONENTS = {
|
|
69
|
+
SendButton: AthenaComposerSendButton,
|
|
70
|
+
StopButton: AthenaComposerStopButton
|
|
71
|
+
};
|
|
72
|
+
exports.ATHENA_COMPOSER_COMPONENTS = ATHENA_COMPOSER_COMPONENTS;
|
|
73
|
+
exports.AthenaComposerMentionButton = AthenaComposerMentionButton;
|
|
74
|
+
exports.AthenaComposerSendButton = AthenaComposerSendButton;
|
|
75
|
+
exports.AthenaComposerStopButton = AthenaComposerStopButton;
|
|
76
|
+
//# sourceMappingURL=athena-composer-controls.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"athena-composer-controls.cjs","sources":["../../src/chat/athena-composer-controls.tsx"],"sourcesContent":["import { ArrowUpIcon, AtSignIcon, ListPlusIcon, SquareIcon } from 'lucide-react';\nimport type { FC } from 'react';\nimport type {\n ComposerSendButtonProps,\n ComposerStopButtonProps,\n} from '../chat-ui/messages/message-components';\nimport { TooltipIconButton } from './tooltip-icon-button';\nimport { Button } from '../ui/button';\n\n/**\n * AthenaChat's composer rail controls, on the SDK's `aui-*` theming contract.\n *\n * Send is an ink circle with the arrow (a list-plus while a run is live and\n * the draft would queue); it reads as inert at 30% while there is nothing to\n * send. Stop is the same circle carrying a filled square. The `@` button\n * types the mention trigger for people who do not know the shortcut.\n */\nexport const AthenaComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled,\n title,\n}) => {\n const label = action === 'queue' ? 'Queue message' : 'Send message';\n return (\n <TooltipIconButton\n tooltip={title ?? label}\n side=\"bottom\"\n type=\"button\"\n variant=\"default\"\n size=\"icon\"\n className=\"aui-composer-send size-8 rounded-full disabled:opacity-30\"\n aria-label={label}\n data-composer-action={action}\n onClick={onSend}\n disabled={disabled}\n >\n {action === 'queue' ? (\n <ListPlusIcon className=\"aui-composer-send-icon size-4\" />\n ) : (\n <ArrowUpIcon className=\"aui-composer-send-icon size-4\" />\n )}\n </TooltipIconButton>\n );\n};\n\nexport const AthenaComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled,\n title,\n}) => (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"icon\"\n className=\"aui-composer-cancel size-8 rounded-full disabled:opacity-30\"\n aria-label=\"Stop generating\"\n data-composer-action=\"stop\"\n title={title}\n onClick={onStop}\n disabled={disabled}\n >\n <SquareIcon className=\"aui-composer-cancel-icon size-3 fill-current\" />\n </Button>\n);\n\nexport interface AthenaComposerMentionButtonProps {\n onClick: () => void;\n disabled?: boolean;\n}\n\nexport const AthenaComposerMentionButton: FC<AthenaComposerMentionButtonProps> = ({\n onClick,\n disabled,\n}) => (\n <TooltipIconButton\n tooltip=\"Mention an asset or tool\"\n side=\"bottom\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"aui-composer-mention size-8 rounded-full text-muted-foreground hover:text-foreground disabled:opacity-30\"\n aria-label=\"Mention an asset or tool\"\n onClick={onClick}\n disabled={disabled}\n >\n <AtSignIcon className=\"size-4\" />\n </TooltipIconButton>\n);\n\nexport const ATHENA_COMPOSER_COMPONENTS = {\n SendButton: AthenaComposerSendButton,\n StopButton: AthenaComposerStopButton,\n};\n"],"names":["jsx","TooltipIconButton","ListPlusIcon","ArrowUpIcon","Button","SquareIcon","AtSignIcon"],"mappings":";;;;;;AAiBO,MAAM,2BAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,WAAW,UAAU,kBAAkB;AACrD,SACEA,2BAAAA;AAAAA,IAACC,kBAAAA;AAAAA,IAAA;AAAA,MACC,SAAS,SAAS;AAAA,MAClB,MAAK;AAAA,MACL,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,WAAU;AAAA,MACV,cAAY;AAAA,MACZ,wBAAsB;AAAA,MACtB,SAAS;AAAA,MACT;AAAA,MAEC,UAAA,WAAW,UACVD,2BAAAA,IAACE,YAAAA,cAAA,EAAa,WAAU,iCAAgC,IAExDF,2BAAAA,IAACG,YAAAA,aAAA,EAAY,WAAU,gCAAA,CAAgC;AAAA,IAAA;AAAA,EAAA;AAI/D;AAEO,MAAM,2BAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AACF,MACEH,2BAAAA;AAAAA,EAACI,OAAAA;AAAAA,EAAA;AAAA,IACC,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,WAAU;AAAA,IACV,cAAW;AAAA,IACX,wBAAqB;AAAA,IACrB;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IAEA,UAAAJ,2BAAAA,IAACK,YAAAA,YAAA,EAAW,WAAU,+CAAA,CAA+C;AAAA,EAAA;AACvE;AAQK,MAAM,8BAAoE,CAAC;AAAA,EAChF;AAAA,EACA;AACF,MACEL,2BAAAA;AAAAA,EAACC,kBAAAA;AAAAA,EAAA;AAAA,IACC,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,WAAU;AAAA,IACV,cAAW;AAAA,IACX;AAAA,IACA;AAAA,IAEA,UAAAD,2BAAAA,IAACM,YAAAA,YAAA,EAAW,WAAU,SAAA,CAAS;AAAA,EAAA;AACjC;AAGK,MAAM,6BAA6B;AAAA,EACxC,YAAY;AAAA,EACZ,YAAY;AACd;;;;;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import type { ComposerSendButtonProps, ComposerStopButtonProps } from '../chat-ui/messages/message-components';
|
|
3
|
+
/**
|
|
4
|
+
* AthenaChat's composer rail controls, on the SDK's `aui-*` theming contract.
|
|
5
|
+
*
|
|
6
|
+
* Send is an ink circle with the arrow (a list-plus while a run is live and
|
|
7
|
+
* the draft would queue); it reads as inert at 30% while there is nothing to
|
|
8
|
+
* send. Stop is the same circle carrying a filled square. The `@` button
|
|
9
|
+
* types the mention trigger for people who do not know the shortcut.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AthenaComposerSendButton: FC<ComposerSendButtonProps>;
|
|
12
|
+
export declare const AthenaComposerStopButton: FC<ComposerStopButtonProps>;
|
|
13
|
+
export interface AthenaComposerMentionButtonProps {
|
|
14
|
+
onClick: () => void;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare const AthenaComposerMentionButton: FC<AthenaComposerMentionButtonProps>;
|
|
18
|
+
export declare const ATHENA_COMPOSER_COMPONENTS: {
|
|
19
|
+
SendButton: FC<ComposerSendButtonProps>;
|
|
20
|
+
StopButton: FC<ComposerStopButtonProps>;
|
|
21
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SquareIcon, ListPlusIcon, ArrowUpIcon, AtSignIcon } from "lucide-react";
|
|
3
|
+
import { TooltipIconButton } from "./tooltip-icon-button.js";
|
|
4
|
+
import { Button } from "../ui/button.js";
|
|
5
|
+
const AthenaComposerSendButton = ({
|
|
6
|
+
action,
|
|
7
|
+
onSend,
|
|
8
|
+
disabled,
|
|
9
|
+
title
|
|
10
|
+
}) => {
|
|
11
|
+
const label = action === "queue" ? "Queue message" : "Send message";
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
TooltipIconButton,
|
|
14
|
+
{
|
|
15
|
+
tooltip: title ?? label,
|
|
16
|
+
side: "bottom",
|
|
17
|
+
type: "button",
|
|
18
|
+
variant: "default",
|
|
19
|
+
size: "icon",
|
|
20
|
+
className: "aui-composer-send size-8 rounded-full disabled:opacity-30",
|
|
21
|
+
"aria-label": label,
|
|
22
|
+
"data-composer-action": action,
|
|
23
|
+
onClick: onSend,
|
|
24
|
+
disabled,
|
|
25
|
+
children: action === "queue" ? /* @__PURE__ */ jsx(ListPlusIcon, { className: "aui-composer-send-icon size-4" }) : /* @__PURE__ */ jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
const AthenaComposerStopButton = ({
|
|
30
|
+
onStop,
|
|
31
|
+
disabled,
|
|
32
|
+
title
|
|
33
|
+
}) => /* @__PURE__ */ jsx(
|
|
34
|
+
Button,
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
variant: "default",
|
|
38
|
+
size: "icon",
|
|
39
|
+
className: "aui-composer-cancel size-8 rounded-full disabled:opacity-30",
|
|
40
|
+
"aria-label": "Stop generating",
|
|
41
|
+
"data-composer-action": "stop",
|
|
42
|
+
title,
|
|
43
|
+
onClick: onStop,
|
|
44
|
+
disabled,
|
|
45
|
+
children: /* @__PURE__ */ jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
const AthenaComposerMentionButton = ({
|
|
49
|
+
onClick,
|
|
50
|
+
disabled
|
|
51
|
+
}) => /* @__PURE__ */ jsx(
|
|
52
|
+
TooltipIconButton,
|
|
53
|
+
{
|
|
54
|
+
tooltip: "Mention an asset or tool",
|
|
55
|
+
side: "bottom",
|
|
56
|
+
type: "button",
|
|
57
|
+
variant: "ghost",
|
|
58
|
+
size: "icon",
|
|
59
|
+
className: "aui-composer-mention size-8 rounded-full text-muted-foreground hover:text-foreground disabled:opacity-30",
|
|
60
|
+
"aria-label": "Mention an asset or tool",
|
|
61
|
+
onClick,
|
|
62
|
+
disabled,
|
|
63
|
+
children: /* @__PURE__ */ jsx(AtSignIcon, { className: "size-4" })
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
const ATHENA_COMPOSER_COMPONENTS = {
|
|
67
|
+
SendButton: AthenaComposerSendButton,
|
|
68
|
+
StopButton: AthenaComposerStopButton
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
ATHENA_COMPOSER_COMPONENTS,
|
|
72
|
+
AthenaComposerMentionButton,
|
|
73
|
+
AthenaComposerSendButton,
|
|
74
|
+
AthenaComposerStopButton
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=athena-composer-controls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"athena-composer-controls.js","sources":["../../src/chat/athena-composer-controls.tsx"],"sourcesContent":["import { ArrowUpIcon, AtSignIcon, ListPlusIcon, SquareIcon } from 'lucide-react';\nimport type { FC } from 'react';\nimport type {\n ComposerSendButtonProps,\n ComposerStopButtonProps,\n} from '../chat-ui/messages/message-components';\nimport { TooltipIconButton } from './tooltip-icon-button';\nimport { Button } from '../ui/button';\n\n/**\n * AthenaChat's composer rail controls, on the SDK's `aui-*` theming contract.\n *\n * Send is an ink circle with the arrow (a list-plus while a run is live and\n * the draft would queue); it reads as inert at 30% while there is nothing to\n * send. Stop is the same circle carrying a filled square. The `@` button\n * types the mention trigger for people who do not know the shortcut.\n */\nexport const AthenaComposerSendButton: FC<ComposerSendButtonProps> = ({\n action,\n onSend,\n disabled,\n title,\n}) => {\n const label = action === 'queue' ? 'Queue message' : 'Send message';\n return (\n <TooltipIconButton\n tooltip={title ?? label}\n side=\"bottom\"\n type=\"button\"\n variant=\"default\"\n size=\"icon\"\n className=\"aui-composer-send size-8 rounded-full disabled:opacity-30\"\n aria-label={label}\n data-composer-action={action}\n onClick={onSend}\n disabled={disabled}\n >\n {action === 'queue' ? (\n <ListPlusIcon className=\"aui-composer-send-icon size-4\" />\n ) : (\n <ArrowUpIcon className=\"aui-composer-send-icon size-4\" />\n )}\n </TooltipIconButton>\n );\n};\n\nexport const AthenaComposerStopButton: FC<ComposerStopButtonProps> = ({\n onStop,\n disabled,\n title,\n}) => (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"icon\"\n className=\"aui-composer-cancel size-8 rounded-full disabled:opacity-30\"\n aria-label=\"Stop generating\"\n data-composer-action=\"stop\"\n title={title}\n onClick={onStop}\n disabled={disabled}\n >\n <SquareIcon className=\"aui-composer-cancel-icon size-3 fill-current\" />\n </Button>\n);\n\nexport interface AthenaComposerMentionButtonProps {\n onClick: () => void;\n disabled?: boolean;\n}\n\nexport const AthenaComposerMentionButton: FC<AthenaComposerMentionButtonProps> = ({\n onClick,\n disabled,\n}) => (\n <TooltipIconButton\n tooltip=\"Mention an asset or tool\"\n side=\"bottom\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"aui-composer-mention size-8 rounded-full text-muted-foreground hover:text-foreground disabled:opacity-30\"\n aria-label=\"Mention an asset or tool\"\n onClick={onClick}\n disabled={disabled}\n >\n <AtSignIcon className=\"size-4\" />\n </TooltipIconButton>\n);\n\nexport const ATHENA_COMPOSER_COMPONENTS = {\n SendButton: AthenaComposerSendButton,\n StopButton: AthenaComposerStopButton,\n};\n"],"names":[],"mappings":";;;;AAiBO,MAAM,2BAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,WAAW,UAAU,kBAAkB;AACrD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAS,SAAS;AAAA,MAClB,MAAK;AAAA,MACL,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,WAAU;AAAA,MACV,cAAY;AAAA,MACZ,wBAAsB;AAAA,MACtB,SAAS;AAAA,MACT;AAAA,MAEC,UAAA,WAAW,UACV,oBAAC,cAAA,EAAa,WAAU,iCAAgC,IAExD,oBAAC,aAAA,EAAY,WAAU,gCAAA,CAAgC;AAAA,IAAA;AAAA,EAAA;AAI/D;AAEO,MAAM,2BAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,WAAU;AAAA,IACV,cAAW;AAAA,IACX,wBAAqB;AAAA,IACrB;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IAEA,UAAA,oBAAC,YAAA,EAAW,WAAU,+CAAA,CAA+C;AAAA,EAAA;AACvE;AAQK,MAAM,8BAAoE,CAAC;AAAA,EAChF;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,WAAU;AAAA,IACV,cAAW;AAAA,IACX;AAAA,IACA;AAAA,IAEA,UAAA,oBAAC,YAAA,EAAW,WAAU,SAAA,CAAS;AAAA,EAAA;AACjC;AAGK,MAAM,6BAA6B;AAAA,EACxC,YAAY;AAAA,EACZ,YAAY;AACd;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const cnfast = require("cnfast");
|
|
6
|
+
const COMPOSER_HINT_SEEN_STORAGE_KEY = "athena-sdk:composer-hint-seen";
|
|
7
|
+
function readHintSeen() {
|
|
8
|
+
try {
|
|
9
|
+
return window.localStorage.getItem(COMPOSER_HINT_SEEN_STORAGE_KEY) === "1";
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function writeHintSeen() {
|
|
15
|
+
try {
|
|
16
|
+
window.localStorage.setItem(COMPOSER_HINT_SEEN_STORAGE_KEY, "1");
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function useComposerKeyboardHint() {
|
|
21
|
+
const [visible, setVisible] = react.useState(false);
|
|
22
|
+
const visibleRef = react.useRef(false);
|
|
23
|
+
const onFocus = react.useCallback(() => {
|
|
24
|
+
if (visibleRef.current || readHintSeen()) return;
|
|
25
|
+
visibleRef.current = true;
|
|
26
|
+
setVisible(true);
|
|
27
|
+
}, []);
|
|
28
|
+
const onSubmitted = react.useCallback(() => {
|
|
29
|
+
if (!visibleRef.current) return;
|
|
30
|
+
writeHintSeen();
|
|
31
|
+
visibleRef.current = false;
|
|
32
|
+
setVisible(false);
|
|
33
|
+
}, []);
|
|
34
|
+
return { visible, onFocus, onSubmitted };
|
|
35
|
+
}
|
|
36
|
+
const KEY_CLASS = "rounded border border-border/70 bg-muted/60 px-1 py-px font-sans text-[10px] text-foreground/70";
|
|
37
|
+
const ComposerKeyboardHint = ({ visible, className }) => {
|
|
38
|
+
if (!visible) return null;
|
|
39
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
40
|
+
"p",
|
|
41
|
+
{
|
|
42
|
+
className: cnfast.cn(
|
|
43
|
+
"aui-composer-hint animate-in fade-in fill-mode-both px-3 pt-1.5 text-[11px] leading-4 text-muted-foreground motion-reduce:animate-none",
|
|
44
|
+
className
|
|
45
|
+
),
|
|
46
|
+
"data-testid": "athena-composer-keyboard-hint",
|
|
47
|
+
children: [
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: KEY_CLASS, children: "Enter" }),
|
|
49
|
+
" to send · ",
|
|
50
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: KEY_CLASS, children: "Shift" }),
|
|
51
|
+
"+",
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: KEY_CLASS, children: "Enter" }),
|
|
53
|
+
" for a new line"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
exports.COMPOSER_HINT_SEEN_STORAGE_KEY = COMPOSER_HINT_SEEN_STORAGE_KEY;
|
|
59
|
+
exports.ComposerKeyboardHint = ComposerKeyboardHint;
|
|
60
|
+
exports.useComposerKeyboardHint = useComposerKeyboardHint;
|
|
61
|
+
//# sourceMappingURL=composer-keyboard-hint.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-keyboard-hint.cjs","sources":["../../src/chat/composer-keyboard-hint.tsx"],"sourcesContent":["import { useCallback, useRef, useState, type FC } from 'react';\nimport { cn } from '../lib/utils';\n\n/**\n * Browser-local marker that the viewer has seen the Enter / Shift+Enter hint.\n * Namespaced so a host page's own storage keys cannot collide with it.\n */\nexport const COMPOSER_HINT_SEEN_STORAGE_KEY = 'athena-sdk:composer-hint-seen';\n\nexport const COMPOSER_KEYBOARD_HINT_TEXT = 'Enter to send · Shift+Enter for a new line';\n\nfunction readHintSeen(): boolean {\n try {\n return window.localStorage.getItem(COMPOSER_HINT_SEEN_STORAGE_KEY) === '1';\n } catch {\n // Storage can be denied (sandboxed iframes, privacy modes); treat as\n // unseen — the hint shows once more, which costs nothing.\n return false;\n }\n}\n\nfunction writeHintSeen(): void {\n try {\n window.localStorage.setItem(COMPOSER_HINT_SEEN_STORAGE_KEY, '1');\n } catch {\n // Same denial as above: the hint simply shows again next time.\n }\n}\n\nexport interface ComposerKeyboardHintController {\n /** Whether the hint is showing right now. */\n visible: boolean;\n /**\n * Attach to the composer's focus (React `onFocus` on a wrapper receives\n * the editor's focus, since it is delivered as `focusin`). Shows the hint\n * the first time the composer is focused in a browser that has not seen it.\n */\n onFocus: () => void;\n /** Call once a draft was sent: hides the hint and records it as seen. */\n onSubmitted: () => void;\n}\n\n/**\n * The one-time \"Enter to send · Shift+Enter for a new line\" hint: appears\n * under the composer on its first focus in this browser and stays until the\n * first send, which records it as seen (`localStorage`) so it never returns.\n * A send made before the composer was ever focused (a suggestion card) leaves\n * the hint unshown and unrecorded, so typing later still gets the hint.\n */\nexport function useComposerKeyboardHint(): ComposerKeyboardHintController {\n const [visible, setVisible] = useState(false);\n // Mirrors `visible` for the handlers, which run outside render.\n const visibleRef = useRef(false);\n\n const onFocus = useCallback(() => {\n if (visibleRef.current || readHintSeen()) return;\n visibleRef.current = true;\n setVisible(true);\n }, []);\n\n const onSubmitted = useCallback(() => {\n if (!visibleRef.current) return;\n writeHintSeen();\n visibleRef.current = false;\n setVisible(false);\n }, []);\n\n return { visible, onFocus, onSubmitted };\n}\n\nconst KEY_CLASS =\n 'rounded border border-border/70 bg-muted/60 px-1 py-px font-sans text-[10px] text-foreground/70';\n\nexport interface ComposerKeyboardHintProps {\n visible: boolean;\n className?: string;\n}\n\n/** The hint row under the composer surface; renders nothing while hidden. */\nexport const ComposerKeyboardHint: FC<ComposerKeyboardHintProps> = ({ visible, className }) => {\n if (!visible) return null;\n return (\n <p\n className={cn(\n 'aui-composer-hint animate-in fade-in fill-mode-both px-3 pt-1.5 text-[11px] leading-4 text-muted-foreground motion-reduce:animate-none',\n className,\n )}\n data-testid=\"athena-composer-keyboard-hint\"\n >\n <kbd className={KEY_CLASS}>Enter</kbd> to send · <kbd className={KEY_CLASS}>Shift</kbd>+\n <kbd className={KEY_CLASS}>Enter</kbd> for a new line\n </p>\n );\n};\n"],"names":["useState","useRef","useCallback","jsxs","cn","jsx"],"mappings":";;;;;AAOO,MAAM,iCAAiC;AAI9C,SAAS,eAAwB;AAC/B,MAAI;AACF,WAAO,OAAO,aAAa,QAAQ,8BAA8B,MAAM;AAAA,EACzE,QAAQ;AAGN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAsB;AAC7B,MAAI;AACF,WAAO,aAAa,QAAQ,gCAAgC,GAAG;AAAA,EACjE,QAAQ;AAAA,EAER;AACF;AAsBO,SAAS,0BAA0D;AACxE,QAAM,CAAC,SAAS,UAAU,IAAIA,MAAAA,SAAS,KAAK;AAE5C,QAAM,aAAaC,MAAAA,OAAO,KAAK;AAE/B,QAAM,UAAUC,MAAAA,YAAY,MAAM;AAChC,QAAI,WAAW,WAAW,eAAgB;AAC1C,eAAW,UAAU;AACrB,eAAW,IAAI;AAAA,EACjB,GAAG,CAAA,CAAE;AAEL,QAAM,cAAcA,MAAAA,YAAY,MAAM;AACpC,QAAI,CAAC,WAAW,QAAS;AACzB,kBAAA;AACA,eAAW,UAAU;AACrB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,SAAS,SAAS,YAAA;AAC7B;AAEA,MAAM,YACJ;AAQK,MAAM,uBAAsD,CAAC,EAAE,SAAS,gBAAgB;AAC7F,MAAI,CAAC,QAAS,QAAO;AACrB,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,OAAAA;AAAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAAC,2BAAAA,IAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,QAAWA,2BAAAA,IAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,QACvFA,2BAAAA,IAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG5C;;;;"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Browser-local marker that the viewer has seen the Enter / Shift+Enter hint.
|
|
4
|
+
* Namespaced so a host page's own storage keys cannot collide with it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const COMPOSER_HINT_SEEN_STORAGE_KEY = "athena-sdk:composer-hint-seen";
|
|
7
|
+
export declare const COMPOSER_KEYBOARD_HINT_TEXT = "Enter to send \u00B7 Shift+Enter for a new line";
|
|
8
|
+
export interface ComposerKeyboardHintController {
|
|
9
|
+
/** Whether the hint is showing right now. */
|
|
10
|
+
visible: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Attach to the composer's focus (React `onFocus` on a wrapper receives
|
|
13
|
+
* the editor's focus, since it is delivered as `focusin`). Shows the hint
|
|
14
|
+
* the first time the composer is focused in a browser that has not seen it.
|
|
15
|
+
*/
|
|
16
|
+
onFocus: () => void;
|
|
17
|
+
/** Call once a draft was sent: hides the hint and records it as seen. */
|
|
18
|
+
onSubmitted: () => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The one-time "Enter to send · Shift+Enter for a new line" hint: appears
|
|
22
|
+
* under the composer on its first focus in this browser and stays until the
|
|
23
|
+
* first send, which records it as seen (`localStorage`) so it never returns.
|
|
24
|
+
* A send made before the composer was ever focused (a suggestion card) leaves
|
|
25
|
+
* the hint unshown and unrecorded, so typing later still gets the hint.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useComposerKeyboardHint(): ComposerKeyboardHintController;
|
|
28
|
+
export interface ComposerKeyboardHintProps {
|
|
29
|
+
visible: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
}
|
|
32
|
+
/** The hint row under the composer surface; renders nothing while hidden. */
|
|
33
|
+
export declare const ComposerKeyboardHint: FC<ComposerKeyboardHintProps>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useCallback } from "react";
|
|
3
|
+
import { cn } from "cnfast";
|
|
4
|
+
const COMPOSER_HINT_SEEN_STORAGE_KEY = "athena-sdk:composer-hint-seen";
|
|
5
|
+
function readHintSeen() {
|
|
6
|
+
try {
|
|
7
|
+
return window.localStorage.getItem(COMPOSER_HINT_SEEN_STORAGE_KEY) === "1";
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function writeHintSeen() {
|
|
13
|
+
try {
|
|
14
|
+
window.localStorage.setItem(COMPOSER_HINT_SEEN_STORAGE_KEY, "1");
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function useComposerKeyboardHint() {
|
|
19
|
+
const [visible, setVisible] = useState(false);
|
|
20
|
+
const visibleRef = useRef(false);
|
|
21
|
+
const onFocus = useCallback(() => {
|
|
22
|
+
if (visibleRef.current || readHintSeen()) return;
|
|
23
|
+
visibleRef.current = true;
|
|
24
|
+
setVisible(true);
|
|
25
|
+
}, []);
|
|
26
|
+
const onSubmitted = useCallback(() => {
|
|
27
|
+
if (!visibleRef.current) return;
|
|
28
|
+
writeHintSeen();
|
|
29
|
+
visibleRef.current = false;
|
|
30
|
+
setVisible(false);
|
|
31
|
+
}, []);
|
|
32
|
+
return { visible, onFocus, onSubmitted };
|
|
33
|
+
}
|
|
34
|
+
const KEY_CLASS = "rounded border border-border/70 bg-muted/60 px-1 py-px font-sans text-[10px] text-foreground/70";
|
|
35
|
+
const ComposerKeyboardHint = ({ visible, className }) => {
|
|
36
|
+
if (!visible) return null;
|
|
37
|
+
return /* @__PURE__ */ jsxs(
|
|
38
|
+
"p",
|
|
39
|
+
{
|
|
40
|
+
className: cn(
|
|
41
|
+
"aui-composer-hint animate-in fade-in fill-mode-both px-3 pt-1.5 text-[11px] leading-4 text-muted-foreground motion-reduce:animate-none",
|
|
42
|
+
className
|
|
43
|
+
),
|
|
44
|
+
"data-testid": "athena-composer-keyboard-hint",
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ jsx("kbd", { className: KEY_CLASS, children: "Enter" }),
|
|
47
|
+
" to send · ",
|
|
48
|
+
/* @__PURE__ */ jsx("kbd", { className: KEY_CLASS, children: "Shift" }),
|
|
49
|
+
"+",
|
|
50
|
+
/* @__PURE__ */ jsx("kbd", { className: KEY_CLASS, children: "Enter" }),
|
|
51
|
+
" for a new line"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
export {
|
|
57
|
+
COMPOSER_HINT_SEEN_STORAGE_KEY,
|
|
58
|
+
ComposerKeyboardHint,
|
|
59
|
+
useComposerKeyboardHint
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=composer-keyboard-hint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-keyboard-hint.js","sources":["../../src/chat/composer-keyboard-hint.tsx"],"sourcesContent":["import { useCallback, useRef, useState, type FC } from 'react';\nimport { cn } from '../lib/utils';\n\n/**\n * Browser-local marker that the viewer has seen the Enter / Shift+Enter hint.\n * Namespaced so a host page's own storage keys cannot collide with it.\n */\nexport const COMPOSER_HINT_SEEN_STORAGE_KEY = 'athena-sdk:composer-hint-seen';\n\nexport const COMPOSER_KEYBOARD_HINT_TEXT = 'Enter to send · Shift+Enter for a new line';\n\nfunction readHintSeen(): boolean {\n try {\n return window.localStorage.getItem(COMPOSER_HINT_SEEN_STORAGE_KEY) === '1';\n } catch {\n // Storage can be denied (sandboxed iframes, privacy modes); treat as\n // unseen — the hint shows once more, which costs nothing.\n return false;\n }\n}\n\nfunction writeHintSeen(): void {\n try {\n window.localStorage.setItem(COMPOSER_HINT_SEEN_STORAGE_KEY, '1');\n } catch {\n // Same denial as above: the hint simply shows again next time.\n }\n}\n\nexport interface ComposerKeyboardHintController {\n /** Whether the hint is showing right now. */\n visible: boolean;\n /**\n * Attach to the composer's focus (React `onFocus` on a wrapper receives\n * the editor's focus, since it is delivered as `focusin`). Shows the hint\n * the first time the composer is focused in a browser that has not seen it.\n */\n onFocus: () => void;\n /** Call once a draft was sent: hides the hint and records it as seen. */\n onSubmitted: () => void;\n}\n\n/**\n * The one-time \"Enter to send · Shift+Enter for a new line\" hint: appears\n * under the composer on its first focus in this browser and stays until the\n * first send, which records it as seen (`localStorage`) so it never returns.\n * A send made before the composer was ever focused (a suggestion card) leaves\n * the hint unshown and unrecorded, so typing later still gets the hint.\n */\nexport function useComposerKeyboardHint(): ComposerKeyboardHintController {\n const [visible, setVisible] = useState(false);\n // Mirrors `visible` for the handlers, which run outside render.\n const visibleRef = useRef(false);\n\n const onFocus = useCallback(() => {\n if (visibleRef.current || readHintSeen()) return;\n visibleRef.current = true;\n setVisible(true);\n }, []);\n\n const onSubmitted = useCallback(() => {\n if (!visibleRef.current) return;\n writeHintSeen();\n visibleRef.current = false;\n setVisible(false);\n }, []);\n\n return { visible, onFocus, onSubmitted };\n}\n\nconst KEY_CLASS =\n 'rounded border border-border/70 bg-muted/60 px-1 py-px font-sans text-[10px] text-foreground/70';\n\nexport interface ComposerKeyboardHintProps {\n visible: boolean;\n className?: string;\n}\n\n/** The hint row under the composer surface; renders nothing while hidden. */\nexport const ComposerKeyboardHint: FC<ComposerKeyboardHintProps> = ({ visible, className }) => {\n if (!visible) return null;\n return (\n <p\n className={cn(\n 'aui-composer-hint animate-in fade-in fill-mode-both px-3 pt-1.5 text-[11px] leading-4 text-muted-foreground motion-reduce:animate-none',\n className,\n )}\n data-testid=\"athena-composer-keyboard-hint\"\n >\n <kbd className={KEY_CLASS}>Enter</kbd> to send · <kbd className={KEY_CLASS}>Shift</kbd>+\n <kbd className={KEY_CLASS}>Enter</kbd> for a new line\n </p>\n );\n};\n"],"names":[],"mappings":";;;AAOO,MAAM,iCAAiC;AAI9C,SAAS,eAAwB;AAC/B,MAAI;AACF,WAAO,OAAO,aAAa,QAAQ,8BAA8B,MAAM;AAAA,EACzE,QAAQ;AAGN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAsB;AAC7B,MAAI;AACF,WAAO,aAAa,QAAQ,gCAAgC,GAAG;AAAA,EACjE,QAAQ;AAAA,EAER;AACF;AAsBO,SAAS,0BAA0D;AACxE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,aAAa,OAAO,KAAK;AAE/B,QAAM,UAAU,YAAY,MAAM;AAChC,QAAI,WAAW,WAAW,eAAgB;AAC1C,eAAW,UAAU;AACrB,eAAW,IAAI;AAAA,EACjB,GAAG,CAAA,CAAE;AAEL,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,CAAC,WAAW,QAAS;AACzB,kBAAA;AACA,eAAW,UAAU;AACrB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,SAAS,SAAS,YAAA;AAC7B;AAEA,MAAM,YACJ;AAQK,MAAM,uBAAsD,CAAC,EAAE,SAAS,gBAAgB;AAC7F,MAAI,CAAC,QAAS,QAAO;AACrB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAA,oBAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,QAAW,oBAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,QACvF,oBAAC,OAAA,EAAI,WAAW,WAAW,UAAA,SAAK;AAAA,QAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG5C;"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const MESSAGE_CREATED_AT_KEY = "_created_at";
|
|
4
|
+
function parseMessageTime(value) {
|
|
5
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
6
|
+
const time = Date.parse(value);
|
|
7
|
+
return Number.isNaN(time) ? null : new Date(time);
|
|
8
|
+
}
|
|
9
|
+
function readMessageCreatedAt(custom) {
|
|
10
|
+
const value = custom == null ? void 0 : custom[MESSAGE_CREATED_AT_KEY];
|
|
11
|
+
return parseMessageTime(value) ? value : null;
|
|
12
|
+
}
|
|
13
|
+
function dayKey(date, timeZone) {
|
|
14
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
15
|
+
year: "numeric",
|
|
16
|
+
month: "2-digit",
|
|
17
|
+
day: "2-digit",
|
|
18
|
+
...timeZone ? { timeZone } : {}
|
|
19
|
+
}).format(date);
|
|
20
|
+
}
|
|
21
|
+
function isSameCalendarDay(a, b, timeZone) {
|
|
22
|
+
return dayKey(a, timeZone) === dayKey(b, timeZone);
|
|
23
|
+
}
|
|
24
|
+
function previousDayKey(key) {
|
|
25
|
+
const [year, month, day] = key.split("-").map(Number);
|
|
26
|
+
return dayKey(new Date(Date.UTC(year, month - 1, day - 1)), "UTC");
|
|
27
|
+
}
|
|
28
|
+
function formatMessageTime(date, { locale, timeZone } = {}) {
|
|
29
|
+
return new Intl.DateTimeFormat(locale, {
|
|
30
|
+
hour: "numeric",
|
|
31
|
+
minute: "2-digit",
|
|
32
|
+
...timeZone ? { timeZone } : {}
|
|
33
|
+
}).format(date);
|
|
34
|
+
}
|
|
35
|
+
function formatMessageDateTime(date, { locale, timeZone } = {}) {
|
|
36
|
+
return new Intl.DateTimeFormat(locale, {
|
|
37
|
+
dateStyle: "full",
|
|
38
|
+
timeStyle: "short",
|
|
39
|
+
...timeZone ? { timeZone } : {}
|
|
40
|
+
}).format(date);
|
|
41
|
+
}
|
|
42
|
+
function formatDayLabel(date, { now = /* @__PURE__ */ new Date(), locale, timeZone } = {}) {
|
|
43
|
+
const key = dayKey(date, timeZone);
|
|
44
|
+
const todayKey = dayKey(now, timeZone);
|
|
45
|
+
if (key === todayKey) return "Today";
|
|
46
|
+
if (key === previousDayKey(todayKey)) return "Yesterday";
|
|
47
|
+
const sameYear = key.slice(0, 4) === todayKey.slice(0, 4);
|
|
48
|
+
return new Intl.DateTimeFormat(locale, {
|
|
49
|
+
...sameYear ? { weekday: "short" } : { year: "numeric" },
|
|
50
|
+
month: "short",
|
|
51
|
+
day: "numeric",
|
|
52
|
+
...timeZone ? { timeZone } : {}
|
|
53
|
+
}).format(date);
|
|
54
|
+
}
|
|
55
|
+
exports.MESSAGE_CREATED_AT_KEY = MESSAGE_CREATED_AT_KEY;
|
|
56
|
+
exports.dayKey = dayKey;
|
|
57
|
+
exports.formatDayLabel = formatDayLabel;
|
|
58
|
+
exports.formatMessageDateTime = formatMessageDateTime;
|
|
59
|
+
exports.formatMessageTime = formatMessageTime;
|
|
60
|
+
exports.isSameCalendarDay = isSameCalendarDay;
|
|
61
|
+
exports.parseMessageTime = parseMessageTime;
|
|
62
|
+
exports.previousDayKey = previousDayKey;
|
|
63
|
+
exports.readMessageCreatedAt = readMessageCreatedAt;
|
|
64
|
+
//# sourceMappingURL=message-time.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-time.cjs","sources":["../../src/chat/message-time.ts"],"sourcesContent":["/**\n * When a message was created, for the thread's hover timestamps and day\n * separators.\n *\n * The runtime stamps every deep-agent message with `_created_at` (an ISO\n * instant) inside `additional_kwargs.metadata`, the one channel the shared\n * converter exposes as `message.metadata.custom`. That stamp is the only\n * truthful clock: assistant-ui fills `message.createdAt` with `new Date()` at\n * conversion time, which is \"now\" on every wire update — so a message without\n * the stamp shows no time rather than a wrong one.\n */\n\nexport const MESSAGE_CREATED_AT_KEY = \"_created_at\";\n\nexport interface MessageTimeFormatOptions {\n /** BCP 47 locale; the browser's by default. Tests pass one for determinism. */\n locale?: string;\n /** IANA time zone; the browser's by default. Tests pass one for determinism. */\n timeZone?: string;\n}\n\n/** The stamp as a `Date`, or `null` when absent or unparseable. */\nexport function parseMessageTime(value: unknown): Date | null {\n if (typeof value !== \"string\" || value.length === 0) return null;\n const time = Date.parse(value);\n return Number.isNaN(time) ? null : new Date(time);\n}\n\n/** The `_created_at` stamp off a message's `metadata.custom`, when it carries a valid one. */\nexport function readMessageCreatedAt(\n custom: Record<string, unknown> | undefined,\n): string | null {\n const value = custom?.[MESSAGE_CREATED_AT_KEY];\n return parseMessageTime(value) ? (value as string) : null;\n}\n\n/** A `YYYY-MM-DD` key for the calendar day `date` falls on in `timeZone`. */\nexport function dayKey(date: Date, timeZone?: string): string {\n // en-CA formats as YYYY-MM-DD, which sorts and compares as plain text.\n return new Intl.DateTimeFormat(\"en-CA\", {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/** Whether two instants fall on the same calendar day. */\nexport function isSameCalendarDay(a: Date, b: Date, timeZone?: string): boolean {\n return dayKey(a, timeZone) === dayKey(b, timeZone);\n}\n\n/**\n * The calendar day before a `YYYY-MM-DD` key. Computed on the calendar, not\n * by subtracting 24 hours from an instant: across a daylight-saving change a\n * local day is 23 or 25 hours long, so an instant a day earlier can land two\n * calendar days back (or on the same day) just after midnight.\n */\nexport function previousDayKey(key: string): string {\n const [year, month, day] = key.split(\"-\").map(Number);\n return dayKey(new Date(Date.UTC(year!, month! - 1, day! - 1)), \"UTC\");\n}\n\n/** The short clock time shown on hover (\"3:42 PM\"). */\nexport function formatMessageTime(\n date: Date,\n { locale, timeZone }: MessageTimeFormatOptions = {},\n): string {\n return new Intl.DateTimeFormat(locale, {\n hour: \"numeric\",\n minute: \"2-digit\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/** The full date and time for a `title` (\"Monday, September 21, 2026 at 3:42 PM\"). */\nexport function formatMessageDateTime(\n date: Date,\n { locale, timeZone }: MessageTimeFormatOptions = {},\n): string {\n return new Intl.DateTimeFormat(locale, {\n dateStyle: \"full\",\n timeStyle: \"short\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/**\n * The day separator's label: \"Today\", \"Yesterday\", else the weekday and date\n * (\"Mon, Sep 21\"), with the year once the day is not in the current year\n * (\"Sep 21, 2025\").\n */\nexport function formatDayLabel(\n date: Date,\n { now = new Date(), locale, timeZone }: MessageTimeFormatOptions & { now?: Date } = {},\n): string {\n const key = dayKey(date, timeZone);\n const todayKey = dayKey(now, timeZone);\n if (key === todayKey) return \"Today\";\n if (key === previousDayKey(todayKey)) return \"Yesterday\";\n const sameYear = key.slice(0, 4) === todayKey.slice(0, 4);\n return new Intl.DateTimeFormat(locale, {\n ...(sameYear ? { weekday: \"short\" } : { year: \"numeric\" }),\n month: \"short\",\n day: \"numeric\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n"],"names":[],"mappings":";;AAYO,MAAM,yBAAyB;AAU/B,SAAS,iBAAiB,OAA6B;AAC5D,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,EAAG,QAAO;AAC5D,QAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,SAAO,OAAO,MAAM,IAAI,IAAI,OAAO,IAAI,KAAK,IAAI;AAClD;AAGO,SAAS,qBACd,QACe;AACf,QAAM,QAAQ,iCAAS;AACvB,SAAO,iBAAiB,KAAK,IAAK,QAAmB;AACvD;AAGO,SAAS,OAAO,MAAY,UAA2B;AAE5D,SAAO,IAAI,KAAK,eAAe,SAAS;AAAA,IACtC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAGO,SAAS,kBAAkB,GAAS,GAAS,UAA4B;AAC9E,SAAO,OAAO,GAAG,QAAQ,MAAM,OAAO,GAAG,QAAQ;AACnD;AAQO,SAAS,eAAe,KAAqB;AAClD,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM;AACpD,SAAO,OAAO,IAAI,KAAK,KAAK,IAAI,MAAO,QAAS,GAAG,MAAO,CAAC,CAAC,GAAG,KAAK;AACtE;AAGO,SAAS,kBACd,MACA,EAAE,QAAQ,SAAA,IAAuC,CAAA,GACzC;AACR,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAGO,SAAS,sBACd,MACA,EAAE,QAAQ,SAAA,IAAuC,CAAA,GACzC;AACR,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,WAAW;AAAA,IACX,WAAW;AAAA,IACX,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAOO,SAAS,eACd,MACA,EAAE,MAAM,oBAAI,KAAA,GAAQ,QAAQ,SAAA,IAAwD,IAC5E;AACR,QAAM,MAAM,OAAO,MAAM,QAAQ;AACjC,QAAM,WAAW,OAAO,KAAK,QAAQ;AACrC,MAAI,QAAQ,SAAU,QAAO;AAC7B,MAAI,QAAQ,eAAe,QAAQ,EAAG,QAAO;AAC7C,QAAM,WAAW,IAAI,MAAM,GAAG,CAAC,MAAM,SAAS,MAAM,GAAG,CAAC;AACxD,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,GAAI,WAAW,EAAE,SAAS,YAAY,EAAE,MAAM,UAAA;AAAA,IAC9C,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;;;;;;;;;;"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When a message was created, for the thread's hover timestamps and day
|
|
3
|
+
* separators.
|
|
4
|
+
*
|
|
5
|
+
* The runtime stamps every deep-agent message with `_created_at` (an ISO
|
|
6
|
+
* instant) inside `additional_kwargs.metadata`, the one channel the shared
|
|
7
|
+
* converter exposes as `message.metadata.custom`. That stamp is the only
|
|
8
|
+
* truthful clock: assistant-ui fills `message.createdAt` with `new Date()` at
|
|
9
|
+
* conversion time, which is "now" on every wire update — so a message without
|
|
10
|
+
* the stamp shows no time rather than a wrong one.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MESSAGE_CREATED_AT_KEY = "_created_at";
|
|
13
|
+
export interface MessageTimeFormatOptions {
|
|
14
|
+
/** BCP 47 locale; the browser's by default. Tests pass one for determinism. */
|
|
15
|
+
locale?: string;
|
|
16
|
+
/** IANA time zone; the browser's by default. Tests pass one for determinism. */
|
|
17
|
+
timeZone?: string;
|
|
18
|
+
}
|
|
19
|
+
/** The stamp as a `Date`, or `null` when absent or unparseable. */
|
|
20
|
+
export declare function parseMessageTime(value: unknown): Date | null;
|
|
21
|
+
/** The `_created_at` stamp off a message's `metadata.custom`, when it carries a valid one. */
|
|
22
|
+
export declare function readMessageCreatedAt(custom: Record<string, unknown> | undefined): string | null;
|
|
23
|
+
/** A `YYYY-MM-DD` key for the calendar day `date` falls on in `timeZone`. */
|
|
24
|
+
export declare function dayKey(date: Date, timeZone?: string): string;
|
|
25
|
+
/** Whether two instants fall on the same calendar day. */
|
|
26
|
+
export declare function isSameCalendarDay(a: Date, b: Date, timeZone?: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The calendar day before a `YYYY-MM-DD` key. Computed on the calendar, not
|
|
29
|
+
* by subtracting 24 hours from an instant: across a daylight-saving change a
|
|
30
|
+
* local day is 23 or 25 hours long, so an instant a day earlier can land two
|
|
31
|
+
* calendar days back (or on the same day) just after midnight.
|
|
32
|
+
*/
|
|
33
|
+
export declare function previousDayKey(key: string): string;
|
|
34
|
+
/** The short clock time shown on hover ("3:42 PM"). */
|
|
35
|
+
export declare function formatMessageTime(date: Date, { locale, timeZone }?: MessageTimeFormatOptions): string;
|
|
36
|
+
/** The full date and time for a `title` ("Monday, September 21, 2026 at 3:42 PM"). */
|
|
37
|
+
export declare function formatMessageDateTime(date: Date, { locale, timeZone }?: MessageTimeFormatOptions): string;
|
|
38
|
+
/**
|
|
39
|
+
* The day separator's label: "Today", "Yesterday", else the weekday and date
|
|
40
|
+
* ("Mon, Sep 21"), with the year once the day is not in the current year
|
|
41
|
+
* ("Sep 21, 2025").
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatDayLabel(date: Date, { now, locale, timeZone }?: MessageTimeFormatOptions & {
|
|
44
|
+
now?: Date;
|
|
45
|
+
}): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const MESSAGE_CREATED_AT_KEY = "_created_at";
|
|
2
|
+
function parseMessageTime(value) {
|
|
3
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
4
|
+
const time = Date.parse(value);
|
|
5
|
+
return Number.isNaN(time) ? null : new Date(time);
|
|
6
|
+
}
|
|
7
|
+
function readMessageCreatedAt(custom) {
|
|
8
|
+
const value = custom == null ? void 0 : custom[MESSAGE_CREATED_AT_KEY];
|
|
9
|
+
return parseMessageTime(value) ? value : null;
|
|
10
|
+
}
|
|
11
|
+
function dayKey(date, timeZone) {
|
|
12
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
13
|
+
year: "numeric",
|
|
14
|
+
month: "2-digit",
|
|
15
|
+
day: "2-digit",
|
|
16
|
+
...timeZone ? { timeZone } : {}
|
|
17
|
+
}).format(date);
|
|
18
|
+
}
|
|
19
|
+
function isSameCalendarDay(a, b, timeZone) {
|
|
20
|
+
return dayKey(a, timeZone) === dayKey(b, timeZone);
|
|
21
|
+
}
|
|
22
|
+
function previousDayKey(key) {
|
|
23
|
+
const [year, month, day] = key.split("-").map(Number);
|
|
24
|
+
return dayKey(new Date(Date.UTC(year, month - 1, day - 1)), "UTC");
|
|
25
|
+
}
|
|
26
|
+
function formatMessageTime(date, { locale, timeZone } = {}) {
|
|
27
|
+
return new Intl.DateTimeFormat(locale, {
|
|
28
|
+
hour: "numeric",
|
|
29
|
+
minute: "2-digit",
|
|
30
|
+
...timeZone ? { timeZone } : {}
|
|
31
|
+
}).format(date);
|
|
32
|
+
}
|
|
33
|
+
function formatMessageDateTime(date, { locale, timeZone } = {}) {
|
|
34
|
+
return new Intl.DateTimeFormat(locale, {
|
|
35
|
+
dateStyle: "full",
|
|
36
|
+
timeStyle: "short",
|
|
37
|
+
...timeZone ? { timeZone } : {}
|
|
38
|
+
}).format(date);
|
|
39
|
+
}
|
|
40
|
+
function formatDayLabel(date, { now = /* @__PURE__ */ new Date(), locale, timeZone } = {}) {
|
|
41
|
+
const key = dayKey(date, timeZone);
|
|
42
|
+
const todayKey = dayKey(now, timeZone);
|
|
43
|
+
if (key === todayKey) return "Today";
|
|
44
|
+
if (key === previousDayKey(todayKey)) return "Yesterday";
|
|
45
|
+
const sameYear = key.slice(0, 4) === todayKey.slice(0, 4);
|
|
46
|
+
return new Intl.DateTimeFormat(locale, {
|
|
47
|
+
...sameYear ? { weekday: "short" } : { year: "numeric" },
|
|
48
|
+
month: "short",
|
|
49
|
+
day: "numeric",
|
|
50
|
+
...timeZone ? { timeZone } : {}
|
|
51
|
+
}).format(date);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
MESSAGE_CREATED_AT_KEY,
|
|
55
|
+
dayKey,
|
|
56
|
+
formatDayLabel,
|
|
57
|
+
formatMessageDateTime,
|
|
58
|
+
formatMessageTime,
|
|
59
|
+
isSameCalendarDay,
|
|
60
|
+
parseMessageTime,
|
|
61
|
+
previousDayKey,
|
|
62
|
+
readMessageCreatedAt
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=message-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-time.js","sources":["../../src/chat/message-time.ts"],"sourcesContent":["/**\n * When a message was created, for the thread's hover timestamps and day\n * separators.\n *\n * The runtime stamps every deep-agent message with `_created_at` (an ISO\n * instant) inside `additional_kwargs.metadata`, the one channel the shared\n * converter exposes as `message.metadata.custom`. That stamp is the only\n * truthful clock: assistant-ui fills `message.createdAt` with `new Date()` at\n * conversion time, which is \"now\" on every wire update — so a message without\n * the stamp shows no time rather than a wrong one.\n */\n\nexport const MESSAGE_CREATED_AT_KEY = \"_created_at\";\n\nexport interface MessageTimeFormatOptions {\n /** BCP 47 locale; the browser's by default. Tests pass one for determinism. */\n locale?: string;\n /** IANA time zone; the browser's by default. Tests pass one for determinism. */\n timeZone?: string;\n}\n\n/** The stamp as a `Date`, or `null` when absent or unparseable. */\nexport function parseMessageTime(value: unknown): Date | null {\n if (typeof value !== \"string\" || value.length === 0) return null;\n const time = Date.parse(value);\n return Number.isNaN(time) ? null : new Date(time);\n}\n\n/** The `_created_at` stamp off a message's `metadata.custom`, when it carries a valid one. */\nexport function readMessageCreatedAt(\n custom: Record<string, unknown> | undefined,\n): string | null {\n const value = custom?.[MESSAGE_CREATED_AT_KEY];\n return parseMessageTime(value) ? (value as string) : null;\n}\n\n/** A `YYYY-MM-DD` key for the calendar day `date` falls on in `timeZone`. */\nexport function dayKey(date: Date, timeZone?: string): string {\n // en-CA formats as YYYY-MM-DD, which sorts and compares as plain text.\n return new Intl.DateTimeFormat(\"en-CA\", {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/** Whether two instants fall on the same calendar day. */\nexport function isSameCalendarDay(a: Date, b: Date, timeZone?: string): boolean {\n return dayKey(a, timeZone) === dayKey(b, timeZone);\n}\n\n/**\n * The calendar day before a `YYYY-MM-DD` key. Computed on the calendar, not\n * by subtracting 24 hours from an instant: across a daylight-saving change a\n * local day is 23 or 25 hours long, so an instant a day earlier can land two\n * calendar days back (or on the same day) just after midnight.\n */\nexport function previousDayKey(key: string): string {\n const [year, month, day] = key.split(\"-\").map(Number);\n return dayKey(new Date(Date.UTC(year!, month! - 1, day! - 1)), \"UTC\");\n}\n\n/** The short clock time shown on hover (\"3:42 PM\"). */\nexport function formatMessageTime(\n date: Date,\n { locale, timeZone }: MessageTimeFormatOptions = {},\n): string {\n return new Intl.DateTimeFormat(locale, {\n hour: \"numeric\",\n minute: \"2-digit\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/** The full date and time for a `title` (\"Monday, September 21, 2026 at 3:42 PM\"). */\nexport function formatMessageDateTime(\n date: Date,\n { locale, timeZone }: MessageTimeFormatOptions = {},\n): string {\n return new Intl.DateTimeFormat(locale, {\n dateStyle: \"full\",\n timeStyle: \"short\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n\n/**\n * The day separator's label: \"Today\", \"Yesterday\", else the weekday and date\n * (\"Mon, Sep 21\"), with the year once the day is not in the current year\n * (\"Sep 21, 2025\").\n */\nexport function formatDayLabel(\n date: Date,\n { now = new Date(), locale, timeZone }: MessageTimeFormatOptions & { now?: Date } = {},\n): string {\n const key = dayKey(date, timeZone);\n const todayKey = dayKey(now, timeZone);\n if (key === todayKey) return \"Today\";\n if (key === previousDayKey(todayKey)) return \"Yesterday\";\n const sameYear = key.slice(0, 4) === todayKey.slice(0, 4);\n return new Intl.DateTimeFormat(locale, {\n ...(sameYear ? { weekday: \"short\" } : { year: \"numeric\" }),\n month: \"short\",\n day: \"numeric\",\n ...(timeZone ? { timeZone } : {}),\n }).format(date);\n}\n"],"names":[],"mappings":"AAYO,MAAM,yBAAyB;AAU/B,SAAS,iBAAiB,OAA6B;AAC5D,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,EAAG,QAAO;AAC5D,QAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,SAAO,OAAO,MAAM,IAAI,IAAI,OAAO,IAAI,KAAK,IAAI;AAClD;AAGO,SAAS,qBACd,QACe;AACf,QAAM,QAAQ,iCAAS;AACvB,SAAO,iBAAiB,KAAK,IAAK,QAAmB;AACvD;AAGO,SAAS,OAAO,MAAY,UAA2B;AAE5D,SAAO,IAAI,KAAK,eAAe,SAAS;AAAA,IACtC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAGO,SAAS,kBAAkB,GAAS,GAAS,UAA4B;AAC9E,SAAO,OAAO,GAAG,QAAQ,MAAM,OAAO,GAAG,QAAQ;AACnD;AAQO,SAAS,eAAe,KAAqB;AAClD,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM;AACpD,SAAO,OAAO,IAAI,KAAK,KAAK,IAAI,MAAO,QAAS,GAAG,MAAO,CAAC,CAAC,GAAG,KAAK;AACtE;AAGO,SAAS,kBACd,MACA,EAAE,QAAQ,SAAA,IAAuC,CAAA,GACzC;AACR,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAGO,SAAS,sBACd,MACA,EAAE,QAAQ,SAAA,IAAuC,CAAA,GACzC;AACR,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,WAAW;AAAA,IACX,WAAW;AAAA,IACX,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;AAOO,SAAS,eACd,MACA,EAAE,MAAM,oBAAI,KAAA,GAAQ,QAAQ,SAAA,IAAwD,IAC5E;AACR,QAAM,MAAM,OAAO,MAAM,QAAQ;AACjC,QAAM,WAAW,OAAO,KAAK,QAAQ;AACrC,MAAI,QAAQ,SAAU,QAAO;AAC7B,MAAI,QAAQ,eAAe,QAAQ,EAAG,QAAO;AAC7C,QAAM,WAAW,IAAI,MAAM,GAAG,CAAC,MAAM,SAAS,MAAM,GAAG,CAAC;AACxD,SAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,IACrC,GAAI,WAAW,EAAE,SAAS,YAAY,EAAE,MAAM,UAAA;AAAA,IAC9C,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC,CAChC,EAAE,OAAO,IAAI;AAChB;"}
|