@kitn.ai/ui 0.16.0 → 0.18.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 +55 -17
- package/dist/components/artifact.d.ts +39 -1
- package/dist/components/attachment-types.d.ts +12 -0
- package/dist/components/attachments.d.ts +2 -10
- package/dist/components/card.d.ts +27 -0
- package/dist/components/chain-of-thought.d.ts +78 -2
- package/dist/components/chat-scope-picker.d.ts +7 -0
- package/dist/components/chat-thread.d.ts +39 -16
- package/dist/components/choice-card.d.ts +27 -0
- package/dist/components/coachmark.d.ts +49 -0
- package/dist/components/composer-dom.d.ts +35 -0
- package/dist/components/composer-highlight.d.ts +48 -0
- package/dist/components/composer-history.d.ts +34 -0
- package/dist/components/composer.d.ts +86 -0
- package/dist/components/confirm-card.d.ts +17 -0
- package/dist/components/conversation-item.d.ts +9 -0
- package/dist/components/conversation-list.d.ts +36 -1
- package/dist/components/dismissed-stub.d.ts +22 -0
- package/dist/components/file-tree.d.ts +15 -0
- package/dist/components/form.d.ts +34 -0
- package/dist/components/markdown.d.ts +3 -0
- package/dist/components/message.d.ts +71 -2
- package/dist/components/model-switcher.d.ts +7 -0
- package/dist/components/prompt-input.d.ts +13 -4
- package/dist/components/prompt-suggestion.d.ts +9 -1
- package/dist/components/reasoning.d.ts +14 -1
- package/dist/components/response-compare-types.d.ts +66 -0
- package/dist/components/response-compare.d.ts +65 -0
- package/dist/components/screen.d.ts +46 -0
- package/dist/components/tasks-card.d.ts +50 -1
- package/dist/components/toast.d.ts +58 -0
- package/dist/components/tool-types.d.ts +10 -0
- package/dist/components/tool.d.ts +8 -8
- package/dist/components/use-card-resolution.d.ts +10 -6
- package/dist/components/voice-input.d.ts +27 -0
- package/dist/components/voice-output.d.ts +33 -0
- package/dist/core-C8fzo39E.js +12 -0
- package/dist/custom-elements.json +8472 -1691
- package/dist/elements/agent-card.d.ts +1 -0
- package/dist/elements/agent-card.js +1 -0
- package/dist/elements/artifact.js +1 -0
- package/dist/elements/attachments.js +1 -0
- package/dist/elements/autoloader.d.ts +2 -0
- package/dist/elements/autoloader.js +1 -0
- package/dist/elements/avatar.d.ts +1 -0
- package/dist/elements/avatar.js +1 -0
- package/dist/elements/badge.d.ts +1 -0
- package/dist/elements/badge.js +1 -0
- package/dist/elements/button.d.ts +1 -0
- package/dist/elements/button.js +1 -0
- package/dist/elements/card.js +1 -0
- package/dist/elements/cards.d.ts +1 -0
- package/dist/elements/cards.js +1 -0
- package/dist/elements/chain-of-thought.d.ts +0 -12
- package/dist/elements/chain-of-thought.js +1 -0
- package/dist/elements/chat-scope-picker.js +1 -0
- package/dist/elements/chat-types.d.ts +8 -2
- package/dist/elements/chat-workspace.js +1 -0
- package/dist/elements/chat.js +1 -0
- package/dist/elements/checkpoint.js +1 -0
- package/dist/elements/choice.js +1 -0
- package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
- package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
- package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
- package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
- package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
- package/dist/elements/chunks/bash-InADTalH.js +1 -0
- package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
- package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
- package/dist/elements/chunks/card-routing-C986KuUA.js +1 -0
- package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
- package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
- package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
- package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
- package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
- package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
- package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
- package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
- package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
- package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
- package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
- package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
- package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
- package/dist/elements/chunks/core-AYMC6_lb.js +12 -0
- package/dist/elements/chunks/css-M7EaDHN_.js +1 -0
- package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
- package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
- package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
- package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
- package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
- package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
- package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +141 -0
- package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
- package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
- package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
- package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
- package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +1 -0
- package/dist/elements/chunks/github-light-JYsPkUQd.js +1 -0
- package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
- package/dist/elements/chunks/html-CPZ3oZQ7.js +1 -0
- package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
- package/dist/elements/chunks/index-BCRhi84a.js +1 -0
- package/dist/elements/chunks/info-B_toFS0l.js +1 -0
- package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
- package/dist/elements/chunks/javascript-C25yR2R2.js +1 -0
- package/dist/elements/chunks/json-DxJze_jm.js +1 -0
- package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
- package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
- package/dist/elements/chunks/loader-q6MamGus.js +1 -0
- package/dist/elements/chunks/markdown-DBrcqq4S.js +64 -0
- package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
- package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
- package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
- package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
- package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
- package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
- package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
- package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
- package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
- package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
- package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
- package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
- package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
- package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
- package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
- package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
- package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
- package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
- package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
- package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
- package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
- package/dist/elements/chunks/svelte--5p79yCD.js +1 -0
- package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
- package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
- package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
- package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
- package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
- package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
- package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
- package/dist/elements/chunks/tsx-B8rCNbgL.js +1 -0
- package/dist/elements/chunks/typescript-RycA9KXf.js +1 -0
- package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
- package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
- package/dist/elements/chunks/vue-BmIZj4XD.js +1 -0
- package/dist/elements/chunks/x-C1qtndxn.js +1 -0
- package/dist/elements/coachmark.d.ts +1 -0
- package/dist/elements/coachmark.js +1 -0
- package/dist/elements/code-block.js +1 -0
- package/dist/elements/command.d.ts +1 -0
- package/dist/elements/command.js +1 -0
- package/dist/elements/compare.d.ts +1 -0
- package/dist/elements/compare.js +1 -0
- package/dist/elements/composer.d.ts +1 -0
- package/dist/elements/composer.js +1 -0
- package/dist/elements/confirm-card.js +1 -0
- package/dist/elements/context-meter.js +1 -0
- package/dist/elements/conversation-list.d.ts +1 -11
- package/dist/elements/conversation-list.js +1 -0
- package/dist/elements/default-input.d.ts +20 -9
- package/dist/elements/define.d.ts +11 -0
- package/dist/elements/dialog.d.ts +1 -0
- package/dist/elements/dialog.js +1 -0
- package/dist/elements/disclosure.d.ts +37 -0
- package/dist/elements/editable-label.d.ts +1 -0
- package/dist/elements/editable-label.js +1 -0
- package/dist/elements/embed.js +1 -0
- package/dist/elements/empty.js +1 -0
- package/dist/elements/feedback-bar.js +1 -0
- package/dist/elements/file-tree.js +1 -0
- package/dist/elements/file-upload.js +1 -0
- package/dist/elements/form.js +1 -0
- package/dist/elements/hover-card.d.ts +1 -0
- package/dist/elements/hover-card.js +1 -0
- package/dist/elements/icon.d.ts +1 -0
- package/dist/elements/icon.js +1 -0
- package/dist/elements/image.js +1 -0
- package/dist/elements/input.d.ts +1 -0
- package/dist/elements/input.js +1 -0
- package/dist/elements/kbd.d.ts +1 -0
- package/dist/elements/kbd.js +1 -0
- package/dist/elements/link-preview.js +1 -0
- package/dist/elements/loader.js +1 -0
- package/dist/elements/markdown.js +1 -0
- package/dist/elements/menu.d.ts +1 -0
- package/dist/elements/menu.js +1 -0
- package/dist/elements/message-skills.d.ts +0 -16
- package/dist/elements/message-skills.js +1 -0
- package/dist/elements/message.js +1 -0
- package/dist/elements/model-switcher.d.ts +1 -11
- package/dist/elements/model-switcher.js +1 -0
- package/dist/elements/nav.d.ts +1 -0
- package/dist/elements/nav.js +1 -0
- package/dist/elements/notice.d.ts +1 -0
- package/dist/elements/notice.js +1 -0
- package/dist/elements/pane-group.d.ts +1 -0
- package/dist/elements/pane-group.js +1 -0
- package/dist/elements/pane.d.ts +1 -0
- package/dist/elements/pane.js +1 -0
- package/dist/elements/popover.js +1 -0
- package/dist/elements/progress-bar.d.ts +1 -0
- package/dist/elements/progress-bar.js +1 -0
- package/dist/elements/prompt-dock.d.ts +1 -0
- package/dist/elements/prompt-dock.js +1 -0
- package/dist/elements/prompt-input.d.ts +1 -9
- package/dist/elements/prompt-input.js +1 -0
- package/dist/elements/prompt-suggestions.d.ts +0 -6
- package/dist/elements/prompt-suggestions.js +1 -0
- package/dist/elements/reasoning.js +1 -0
- package/dist/elements/register.d.ts +10 -0
- package/dist/elements/remote.js +1 -0
- package/dist/elements/resizable.d.ts +1 -17
- package/dist/elements/resizable.js +1 -0
- package/dist/elements/response-stream.js +14 -0
- package/dist/elements/screen.d.ts +1 -0
- package/dist/elements/screen.js +1 -0
- package/dist/elements/scroll-area.d.ts +1 -0
- package/dist/elements/scroll-area.js +1 -0
- package/dist/elements/scroll-button.js +1 -0
- package/dist/elements/search.d.ts +1 -0
- package/dist/elements/search.js +1 -0
- package/dist/elements/segmented.d.ts +1 -0
- package/dist/elements/segmented.js +1 -0
- package/dist/elements/separator.d.ts +1 -0
- package/dist/elements/separator.js +1 -0
- package/dist/elements/setting-item.d.ts +1 -0
- package/dist/elements/setting-item.js +1 -0
- package/dist/elements/settings-group.d.ts +1 -0
- package/dist/elements/settings-group.js +1 -0
- package/dist/elements/skeleton.d.ts +1 -0
- package/dist/elements/skeleton.js +1 -0
- package/dist/elements/slots.d.ts +176 -0
- package/dist/elements/source.d.ts +0 -17
- package/dist/elements/source.js +1 -0
- package/dist/elements/status.d.ts +1 -0
- package/dist/elements/status.js +1 -0
- package/dist/elements/switch.js +1 -0
- package/dist/elements/tabs.d.ts +1 -0
- package/dist/elements/tabs.js +1 -0
- package/dist/elements/tasks.js +1 -0
- package/dist/elements/text-shimmer.js +1 -0
- package/dist/elements/thinking-bar.js +1 -0
- package/dist/elements/toast.d.ts +1 -0
- package/dist/elements/toast.js +1 -0
- package/dist/elements/tool.js +1 -0
- package/dist/elements/tooltip.d.ts +1 -0
- package/dist/elements/tooltip.js +1 -0
- package/dist/elements/voice-input.js +1 -0
- package/dist/elements/voice-output.d.ts +1 -0
- package/dist/elements/voice-output.js +1 -0
- package/dist/elements.d.ts +772 -61
- package/dist/engine-javascript-C1x7zo1_.js +141 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +14405 -9810
- package/dist/kai.es.js +1 -0
- package/dist/llms/llms-full.txt +1234 -107
- package/dist/llms/llms.txt +4 -4
- package/dist/mcp.es.js +217 -6
- package/dist/primitives/card-contract.d.ts +20 -4
- package/dist/primitives/card-recovery.d.ts +55 -0
- package/dist/primitives/composer-model.d.ts +22 -0
- package/dist/primitives/composer-triggers.d.ts +19 -0
- package/dist/primitives/create-kai-chat.d.ts +38 -0
- package/dist/primitives/message-feedback.d.ts +35 -0
- package/dist/primitives/toast-store.d.ts +118 -0
- package/dist/primitives/use-speech-recognition.d.ts +26 -0
- package/dist/react/index.d.ts +1166 -98
- package/dist/react/runtime.d.ts +9 -2
- package/dist/react/use-kai-chat.d.ts +41 -0
- package/dist/react.js +575 -186
- package/dist/register-impl-CYWGkgbI.js +141 -0
- package/dist/schemas/choice.schema.json +5 -0
- package/dist/schemas/tasks.schema.json +7 -2
- package/dist/state/index.d.ts +4 -0
- package/dist/state/messages.d.ts +11 -0
- package/dist/state/stream.d.ts +22 -0
- package/dist/state/suggestions.d.ts +4 -0
- package/dist/state.js +117 -0
- package/dist/theme.tokens.css +87 -0
- package/dist/types.d.ts +4 -0
- package/dist/ui/agent-card.d.ts +61 -0
- package/dist/ui/button.d.ts +5 -2
- package/dist/ui/card.d.ts +61 -0
- package/dist/ui/collapsible.d.ts +15 -1
- package/dist/ui/command.d.ts +33 -0
- package/dist/ui/dialog.d.ts +42 -0
- package/dist/ui/dropdown.d.ts +95 -1
- package/dist/ui/editable-label.d.ts +26 -0
- package/dist/ui/hover-card.d.ts +13 -1
- package/dist/ui/icon.d.ts +18 -0
- package/dist/ui/input.d.ts +33 -0
- package/dist/ui/kbd.d.ts +21 -0
- package/dist/ui/nav.d.ts +62 -0
- package/dist/ui/notice.d.ts +31 -0
- package/dist/ui/overlay.d.ts +12 -0
- package/dist/ui/pane-grid.d.ts +58 -0
- package/dist/ui/pane-group.d.ts +75 -0
- package/dist/ui/pane.d.ts +78 -0
- package/dist/ui/popover.d.ts +11 -1
- package/dist/ui/progress-bar.d.ts +23 -0
- package/dist/ui/prompt-dock.d.ts +96 -0
- package/dist/ui/resizable.d.ts +12 -0
- package/dist/ui/scroll-area.d.ts +4 -0
- package/dist/ui/segmented.d.ts +28 -0
- package/dist/ui/settings-group.d.ts +32 -0
- package/dist/ui/skeleton.d.ts +12 -0
- package/dist/ui/stat.d.ts +16 -0
- package/dist/ui/status.d.ts +13 -0
- package/dist/ui/switch.d.ts +8 -1
- package/dist/ui/tabs.d.ts +35 -0
- package/dist/ui/tooltip.d.ts +20 -1
- package/frameworks/react/index.tsx +1100 -163
- package/frameworks/react/runtime.tsx +30 -1
- package/frameworks/react/use-kai-chat.tsx +87 -0
- package/llms-full.txt +1234 -107
- package/llms.txt +4 -4
- package/package.json +36 -12
- package/src/agent-tooling/mcp/manifest.ts +14 -0
- package/src/agent-tooling/mcp/tools/debug.ts +194 -6
- package/src/agent-tooling/mcp/tools/reference.ts +32 -0
- package/src/agent-tooling/mcp/tools/scaffold.ts +162 -1
- package/src/components/artifact.tsx +98 -13
- package/src/components/attachment-types.ts +13 -0
- package/src/components/attachments.tsx +4 -14
- package/src/components/card.tsx +109 -15
- package/src/components/chain-of-thought.tsx +210 -1
- package/src/components/chat-scope-picker.tsx +13 -3
- package/src/components/chat-thread.tsx +238 -137
- package/src/components/choice-card.tsx +136 -15
- package/src/components/coachmark.tsx +245 -0
- package/src/components/component-meta.json +921 -108
- package/src/components/composer-dom.ts +159 -0
- package/src/components/composer-highlight.ts +242 -0
- package/src/components/composer-history.ts +82 -0
- package/src/components/composer.tsx +979 -0
- package/src/components/confirm-card.tsx +69 -2
- package/src/components/conversation-item.tsx +69 -7
- package/src/components/conversation-list.tsx +134 -37
- package/src/components/dismissed-stub.tsx +80 -0
- package/src/components/file-tree.tsx +197 -47
- package/src/components/form-widgets.tsx +9 -7
- package/src/components/form.tsx +161 -20
- package/src/components/image.tsx +3 -5
- package/src/components/link-preview.tsx +5 -4
- package/src/components/markdown.tsx +5 -2
- package/src/components/message.tsx +174 -14
- package/src/components/model-switcher.tsx +19 -4
- package/src/components/prompt-input.tsx +46 -75
- package/src/components/prompt-suggestion.tsx +48 -16
- package/src/components/reasoning.tsx +29 -6
- package/src/components/response-compare-types.ts +127 -0
- package/src/components/response-compare.tsx +460 -0
- package/src/components/screen.tsx +176 -0
- package/src/components/tasks-card.tsx +374 -23
- package/src/components/toast.tsx +486 -0
- package/src/components/tool-types.ts +10 -0
- package/src/components/tool.tsx +22 -16
- package/src/components/use-card-resolution.ts +24 -8
- package/src/components/voice-input.tsx +102 -19
- package/src/components/voice-output.tsx +202 -0
- package/src/elements/agent-card.tsx +67 -0
- package/src/elements/artifact.tsx +53 -4
- package/src/elements/attachments.tsx +1 -0
- package/src/elements/autoloader.ts +89 -0
- package/src/elements/avatar.tsx +33 -0
- package/src/elements/badge.tsx +32 -0
- package/src/elements/button.tsx +126 -0
- package/src/elements/card-media.jpg +0 -0
- package/src/elements/card.tsx +124 -31
- package/src/elements/cards.tsx +81 -7
- package/src/elements/chain-of-thought.tsx +77 -32
- package/src/elements/chat-scope-picker.tsx +35 -8
- package/src/elements/chat-types.ts +9 -2
- package/src/elements/chat-workspace.tsx +157 -43
- package/src/elements/chat.tsx +49 -25
- package/src/elements/choice.tsx +71 -19
- package/src/elements/coachmark.tsx +90 -0
- package/src/elements/command.tsx +209 -0
- package/src/elements/compare.tsx +110 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +151 -0
- package/src/elements/confirm-card.tsx +36 -11
- package/src/elements/conversation-list.tsx +80 -11
- package/src/elements/default-input.tsx +75 -53
- package/src/elements/define.tsx +47 -6
- package/src/elements/dialog.tsx +98 -0
- package/src/elements/disclosure.ts +73 -0
- package/src/elements/editable-label.tsx +125 -0
- package/src/elements/element-manifest.json +310 -0
- package/src/elements/element-meta.json +5954 -1605
- package/src/elements/element-types.d.ts +771 -60
- package/src/elements/file-tree.tsx +12 -2
- package/src/elements/file-upload.tsx +1 -1
- package/src/elements/form.tsx +54 -11
- package/src/elements/hover-card.tsx +80 -0
- package/src/elements/icon-names.json +48 -0
- package/src/elements/icon.tsx +41 -0
- package/src/elements/input.tsx +203 -0
- package/src/elements/kbd.tsx +45 -0
- package/src/elements/menu.tsx +217 -0
- package/src/elements/message.tsx +84 -55
- package/src/elements/model-switcher.tsx +27 -1
- package/src/elements/nav.tsx +87 -0
- package/src/elements/notice.tsx +53 -0
- package/src/elements/pane-group.tsx +119 -0
- package/src/elements/pane.tsx +129 -0
- package/src/elements/popover.tsx +39 -17
- package/src/elements/progress-bar.tsx +39 -0
- package/src/elements/prompt-dock.tsx +81 -0
- package/src/elements/prompt-input.tsx +112 -63
- package/src/elements/prompt-suggestions.tsx +25 -9
- package/src/elements/reasoning.tsx +30 -9
- package/src/elements/register-impl.ts +41 -3
- package/src/elements/register.ts +20 -3
- package/src/elements/remote.tsx +4 -0
- package/src/elements/resizable.tsx +48 -11
- package/src/elements/screen.tsx +90 -0
- package/src/elements/scroll-area.tsx +33 -0
- package/src/elements/search.tsx +180 -0
- package/src/elements/segmented.tsx +135 -0
- package/src/elements/separator.tsx +36 -0
- package/src/elements/setting-item.tsx +50 -0
- package/src/elements/settings-group.tsx +37 -0
- package/src/elements/skeleton.tsx +45 -0
- package/src/elements/slots.ts +607 -0
- package/src/elements/source.tsx +13 -6
- package/src/elements/status.tsx +42 -0
- package/src/elements/styles.css +19 -0
- package/src/elements/switch.tsx +89 -14
- package/src/elements/tabs.tsx +95 -0
- package/src/elements/tasks.tsx +70 -14
- package/src/elements/toast.tsx +89 -0
- package/src/elements/tool.tsx +43 -9
- package/src/elements/tooltip.tsx +85 -0
- package/src/elements/video-poster.jpg +0 -0
- package/src/elements/voice-input.tsx +66 -16
- package/src/elements/voice-output.tsx +69 -0
- package/src/index.ts +35 -2
- package/src/primitives/card-contract.ts +14 -5
- package/src/primitives/card-recovery.ts +149 -0
- package/src/primitives/card-routing.ts +3 -0
- package/src/primitives/card-schemas/choice.schema.json +5 -0
- package/src/primitives/card-schemas/tasks.schema.json +7 -2
- package/src/primitives/composer-model.ts +49 -0
- package/src/primitives/composer-triggers.ts +35 -0
- package/src/primitives/create-kai-chat.ts +66 -0
- package/src/primitives/message-feedback.ts +123 -0
- package/src/primitives/toast-store.ts +276 -0
- package/src/primitives/use-speech-recognition.ts +135 -0
- package/src/state/index.ts +6 -0
- package/src/state/messages.ts +36 -0
- package/src/state/stream.ts +92 -0
- package/src/state/suggestions.ts +9 -0
- package/src/types.ts +4 -0
- package/src/ui/agent-card.tsx +212 -0
- package/src/ui/button.tsx +16 -5
- package/src/ui/card.tsx +245 -0
- package/src/ui/collapsible.tsx +30 -4
- package/src/ui/command.tsx +99 -0
- package/src/ui/dialog.tsx +217 -0
- package/src/ui/dropdown.tsx +375 -13
- package/src/ui/editable-label.tsx +112 -0
- package/src/ui/hover-card.tsx +28 -5
- package/src/ui/icon.tsx +110 -0
- package/src/ui/input.tsx +132 -0
- package/src/ui/kbd.tsx +118 -0
- package/src/ui/nav.tsx +282 -0
- package/src/ui/notice.tsx +84 -0
- package/src/ui/overlay.tsx +108 -2
- package/src/ui/pane-grid.tsx +116 -0
- package/src/ui/pane-group.tsx +280 -0
- package/src/ui/pane.tsx +193 -0
- package/src/ui/popover.tsx +16 -2
- package/src/ui/progress-bar.tsx +83 -0
- package/src/ui/prompt-dock.tsx +145 -0
- package/src/ui/resizable.tsx +69 -1
- package/src/ui/scroll-area.tsx +14 -3
- package/src/ui/segmented.tsx +109 -0
- package/src/ui/settings-group.tsx +67 -0
- package/src/ui/skeleton.tsx +62 -5
- package/src/ui/stat.tsx +41 -0
- package/src/ui/status.tsx +48 -0
- package/src/ui/switch.tsx +49 -23
- package/src/ui/tabs.tsx +168 -0
- package/src/ui/tooltip.tsx +57 -7
- package/theme.css +113 -0
- package/dist/components/slash-command.d.ts +0 -15
- package/dist/kitn-chat.es.js +0 -1
- package/dist/register-impl-wCsFPoh9.js +0 -77
- package/dist/register-ujhr1nBS.js +0 -1
- package/src/components/slash-command.tsx +0 -232
- package/src/elements/framework-usage.json +0 -563
- /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
- /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
createMemo,
|
|
8
8
|
createEffect,
|
|
9
9
|
on,
|
|
10
|
+
onMount,
|
|
10
11
|
ErrorBoundary,
|
|
11
12
|
} from 'solid-js';
|
|
12
13
|
import { cn } from '../utils/cn';
|
|
13
14
|
import { Button } from '../ui/button';
|
|
14
15
|
import { Card } from './card';
|
|
16
|
+
import { DismissedStub } from './dismissed-stub';
|
|
15
17
|
import type { CardEnvelope, CardEvent, CardHost, CardResolution } from '../primitives/card-contract';
|
|
16
18
|
import { useCardResolution } from './use-card-resolution';
|
|
17
19
|
import { emitCardEvent } from '../primitives/card-routing';
|
|
@@ -120,6 +122,21 @@ export function defaultActionId(actions: ConfirmAction[]): string | undefined {
|
|
|
120
122
|
// The <ConfirmCard> component.
|
|
121
123
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
122
124
|
|
|
125
|
+
/** Imperative handle exposed via `controllerRef` — surfaces the confirm card's
|
|
126
|
+
* latent action/dismiss capabilities so the `<kai-confirm>` facade can forward
|
|
127
|
+
* them as instance methods (focus/confirm/dismiss/reopen). */
|
|
128
|
+
export interface ConfirmController {
|
|
129
|
+
/** Focus the default action button (or the first action if none default). */
|
|
130
|
+
focus(options?: FocusOptions): void;
|
|
131
|
+
/** Activate an action by id (or the default action when omitted) — emits the
|
|
132
|
+
* `action` verb + resolves single-shot. */
|
|
133
|
+
confirm(actionId?: string): void;
|
|
134
|
+
/** Dismiss the card — emits `dismiss` + optimistically collapses to the stub. */
|
|
135
|
+
dismiss(): void;
|
|
136
|
+
/** Re-open a dismissed card from its stub — emits `reopen`. */
|
|
137
|
+
reopen(): void;
|
|
138
|
+
}
|
|
139
|
+
|
|
123
140
|
export interface ConfirmCardProps {
|
|
124
141
|
/** The confirm definition (CardEnvelope.data). */
|
|
125
142
|
data?: ConfirmCardData;
|
|
@@ -137,6 +154,9 @@ export interface ConfirmCardProps {
|
|
|
137
154
|
class?: string;
|
|
138
155
|
/** When set, render the chromed read-only view instead of the buttons. */
|
|
139
156
|
resolution?: CardResolution;
|
|
157
|
+
/** Receive the imperative controller once mounted. The `<kai-confirm>` facade
|
|
158
|
+
* forwards these as element methods (focus/confirm/dismiss/reopen). */
|
|
159
|
+
controllerRef?: (controller: ConfirmController) => void;
|
|
140
160
|
}
|
|
141
161
|
|
|
142
162
|
/**
|
|
@@ -158,6 +178,7 @@ export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
|
158
178
|
'autofocus',
|
|
159
179
|
'class',
|
|
160
180
|
'resolution',
|
|
181
|
+
'controllerRef',
|
|
161
182
|
]);
|
|
162
183
|
|
|
163
184
|
const ctxHost = useCardHost();
|
|
@@ -208,9 +229,50 @@ export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
|
208
229
|
});
|
|
209
230
|
};
|
|
210
231
|
|
|
211
|
-
|
|
232
|
+
// Dismiss: emit the contract `dismiss` AND optimistically flip to a `dismissed`
|
|
233
|
+
// resolution so the card collapses to its re-openable stub immediately (the host
|
|
234
|
+
// confirms/overrides via the resolution prop on the next render).
|
|
235
|
+
const onDismiss = (): void => {
|
|
236
|
+
if (res.isResolved()) return;
|
|
237
|
+
emit({ kind: 'dismiss', cardId: local.cardId });
|
|
238
|
+
res.setLocal({ kind: 'dismissed' });
|
|
239
|
+
};
|
|
240
|
+
const onReopen = (): void => emit({ kind: 'reopen', cardId: local.cardId });
|
|
212
241
|
|
|
213
242
|
let bodyRef: HTMLDivElement | undefined;
|
|
243
|
+
let actionsRef: HTMLDivElement | undefined;
|
|
244
|
+
|
|
245
|
+
// The default action button (or the first action button if none is marked
|
|
246
|
+
// default) — the same target the `autofocus` prop focuses on mount.
|
|
247
|
+
const focusTarget = (): HTMLButtonElement | null => {
|
|
248
|
+
if (!actionsRef) return null;
|
|
249
|
+
return (
|
|
250
|
+
actionsRef.querySelector<HTMLButtonElement>('button[data-kai-default="true"]') ??
|
|
251
|
+
actionsRef.querySelector<HTMLButtonElement>('button[data-action-id]')
|
|
252
|
+
);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// ── Imperative controller (Pattern C): hand the facade a handle over the
|
|
256
|
+
// card's latent action/dismiss capabilities. Every method drives the SAME
|
|
257
|
+
// internal path the buttons drive, so the same kai-card events fire. ──────────
|
|
258
|
+
onMount(() => {
|
|
259
|
+
local.controllerRef?.({
|
|
260
|
+
// Focus the default (or first) action button on demand.
|
|
261
|
+
focus: (options) => focusTarget()?.focus(options),
|
|
262
|
+
// Activate an action by id (or the default action with no id) — the button path.
|
|
263
|
+
confirm: (actionId) => {
|
|
264
|
+
const list = actions();
|
|
265
|
+
const id = actionId ?? defaultId();
|
|
266
|
+
if (id === undefined) return;
|
|
267
|
+
const action = list.find((a) => a.id === id);
|
|
268
|
+
if (action) onAction(action);
|
|
269
|
+
},
|
|
270
|
+
// Trigger the dismiss path (the X-button path).
|
|
271
|
+
dismiss: () => onDismiss(),
|
|
272
|
+
// Re-open a dismissed card (the stub's affordance path).
|
|
273
|
+
reopen: () => onReopen(),
|
|
274
|
+
});
|
|
275
|
+
});
|
|
214
276
|
|
|
215
277
|
// Surface the resolved action id for host styling.
|
|
216
278
|
createEffect(() => {
|
|
@@ -229,6 +291,10 @@ export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
|
229
291
|
return <Card heading={local.heading} errorMessage="The card failed to render." />;
|
|
230
292
|
}}
|
|
231
293
|
>
|
|
294
|
+
<Show
|
|
295
|
+
when={!res.isDeferred()}
|
|
296
|
+
fallback={<DismissedStub type={CONFIRM_CARD_TYPE} title={local.heading} onReopen={onReopen} />}
|
|
297
|
+
>
|
|
232
298
|
<Card
|
|
233
299
|
heading={local.heading}
|
|
234
300
|
actions={
|
|
@@ -256,7 +322,7 @@ export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
|
256
322
|
<X size={16} aria-hidden="true" />
|
|
257
323
|
</Button>
|
|
258
324
|
</Show>
|
|
259
|
-
<div class="ml-auto flex flex-wrap items-center gap-2">
|
|
325
|
+
<div ref={actionsRef} class="ml-auto flex flex-wrap items-center gap-2">
|
|
260
326
|
<For each={actions()}>
|
|
261
327
|
{(action) => (
|
|
262
328
|
<Button
|
|
@@ -309,6 +375,7 @@ export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
|
309
375
|
</Show>
|
|
310
376
|
</div>
|
|
311
377
|
</Card>
|
|
378
|
+
</Show>
|
|
312
379
|
</ErrorBoundary>
|
|
313
380
|
</Show>
|
|
314
381
|
);
|
|
@@ -1,16 +1,78 @@
|
|
|
1
|
-
import { splitProps } from 'solid-js';
|
|
1
|
+
import { Show, splitProps, createMemo } from 'solid-js';
|
|
2
|
+
import { MessageSquare } from 'lucide-solid';
|
|
2
3
|
import { cn } from '../utils/cn';
|
|
3
4
|
import type { ConversationSummary } from '../types';
|
|
4
5
|
|
|
5
|
-
export interface ConversationItemProps {
|
|
6
|
+
export interface ConversationItemProps {
|
|
7
|
+
conversation: ConversationSummary;
|
|
8
|
+
isActive: boolean;
|
|
9
|
+
onSelect: (id: string) => void;
|
|
10
|
+
/** Dense single-line row: a leading dot + title, no message count. */
|
|
11
|
+
compact?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Short relative time from an ISO date string: "just now", "5m ago", "3h ago",
|
|
17
|
+
* "2d ago", "24d ago". Pure — it snapshots `now` (defaults to `Date.now()`) at
|
|
18
|
+
* call time, so it re-derives whenever the list re-renders; there is no internal
|
|
19
|
+
* ticking clock. Returns '' for a missing or unparseable date.
|
|
20
|
+
*/
|
|
21
|
+
export function relativeTimeShort(iso?: string, now: number = Date.now()): string {
|
|
22
|
+
if (!iso) return '';
|
|
23
|
+
const then = Date.parse(iso);
|
|
24
|
+
if (Number.isNaN(then)) return '';
|
|
25
|
+
const secs = Math.max(0, Math.round((now - then) / 1000));
|
|
26
|
+
if (secs < 60) return 'just now';
|
|
27
|
+
const mins = Math.floor(secs / 60);
|
|
28
|
+
if (mins < 60) return `${mins}m ago`;
|
|
29
|
+
const hours = Math.floor(mins / 60);
|
|
30
|
+
if (hours < 24) return `${hours}h ago`;
|
|
31
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
32
|
+
}
|
|
6
33
|
|
|
7
34
|
export function ConversationItem(props: ConversationItemProps) {
|
|
8
|
-
const [local] = splitProps(props, ['conversation', 'isActive', 'onSelect', 'class']);
|
|
35
|
+
const [local] = splitProps(props, ['conversation', 'isActive', 'onSelect', 'compact', 'class']);
|
|
36
|
+
// The trailing text: the consumer's own `trailing` field, else an auto relative
|
|
37
|
+
// time from updatedAt (fallback lastMessageAt). REACTIVITY: this (and the auto
|
|
38
|
+
// time) update when the consumer re-assigns the `conversations` array with a new
|
|
39
|
+
// reference — the kit's standard reactivity model — not via an internal clock.
|
|
40
|
+
const trailing = createMemo(
|
|
41
|
+
() => local.conversation.trailing ?? relativeTimeShort(local.conversation.updatedAt ?? local.conversation.lastMessageAt),
|
|
42
|
+
);
|
|
9
43
|
return (
|
|
10
|
-
<button
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
44
|
+
<button
|
|
45
|
+
data-conversation-id={local.conversation.id}
|
|
46
|
+
onClick={() => local.onSelect(local.conversation.id)}
|
|
47
|
+
class={cn(
|
|
48
|
+
'w-full rounded-lg text-left transition-colors',
|
|
49
|
+
local.compact ? 'px-2.5 py-1.5' : 'px-2.5 py-2',
|
|
50
|
+
local.isActive ? 'bg-muted' : 'hover:bg-muted/50',
|
|
51
|
+
local.class,
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
<Show
|
|
55
|
+
when={local.compact}
|
|
56
|
+
fallback={
|
|
57
|
+
<>
|
|
58
|
+
<div class="flex items-center gap-2">
|
|
59
|
+
<div class={cn('min-w-0 flex-1 truncate text-sm', local.isActive ? 'font-medium text-foreground' : 'text-foreground/80')}>{local.conversation.title}</div>
|
|
60
|
+
<Show when={trailing()}>
|
|
61
|
+
<span part="trailing" class="ml-auto shrink-0 text-xs text-muted-foreground">{trailing()}</span>
|
|
62
|
+
</Show>
|
|
63
|
+
</div>
|
|
64
|
+
<div class={cn('mt-0.5 truncate text-xs', local.isActive ? 'text-foreground/70' : 'text-muted-foreground')}>{local.conversation.messageCount} messages</div>
|
|
65
|
+
</>
|
|
66
|
+
}
|
|
67
|
+
>
|
|
68
|
+
<div class="flex items-center gap-2.5">
|
|
69
|
+
<MessageSquare class={cn('size-3.5 shrink-0', local.isActive ? 'text-foreground' : 'text-muted-foreground')} />
|
|
70
|
+
<span class={cn('min-w-0 flex-1 truncate text-sm', local.isActive ? 'font-medium text-foreground' : 'text-foreground/80')}>{local.conversation.title}</span>
|
|
71
|
+
<Show when={trailing()}>
|
|
72
|
+
<span part="trailing" class="ml-auto shrink-0 text-xs text-muted-foreground">{trailing()}</span>
|
|
73
|
+
</Show>
|
|
74
|
+
</div>
|
|
75
|
+
</Show>
|
|
14
76
|
</button>
|
|
15
77
|
);
|
|
16
78
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { splitProps, For, Show, createSignal, createMemo } from 'solid-js';
|
|
1
|
+
import { splitProps, For, Show, createSignal, createMemo, onMount, type JSX } from 'solid-js';
|
|
2
|
+
import { PanelLeftOpen } from 'lucide-solid';
|
|
2
3
|
import { cn } from '../utils/cn';
|
|
3
4
|
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '../ui/collapsible';
|
|
4
5
|
import { Button } from '../ui/button';
|
|
@@ -7,6 +8,26 @@ import { ScrollArea } from '../ui/scroll-area';
|
|
|
7
8
|
import { ConversationItem } from './conversation-item';
|
|
8
9
|
import type { ConversationSummary, ConversationGroup } from '../types';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The collapsed-rail fallback: a floating reopen button shown when the
|
|
13
|
+
* conversation sidebar is collapsed. Shared by `kai-workspace` (its collapsed
|
|
14
|
+
* branch) and the standalone `kai-conversations` (collapsed mode), so the rail
|
|
15
|
+
* collapses identically in both. Renders only the button; the host owns the
|
|
16
|
+
* surrounding region (the workspace puts the thread beside it, the standalone
|
|
17
|
+
* element stands alone). `onExpand` reopens the rail.
|
|
18
|
+
*/
|
|
19
|
+
export function CollapsedRail(props: { onExpand: () => void; class?: string }) {
|
|
20
|
+
return (
|
|
21
|
+
<Button
|
|
22
|
+
variant="ghost" size="icon-sm" aria-label="Open sidebar"
|
|
23
|
+
class={cn('rounded-full bg-card/80 shadow-sm backdrop-blur', props.class)}
|
|
24
|
+
onClick={props.onExpand}
|
|
25
|
+
>
|
|
26
|
+
<PanelLeftOpen class="size-4" />
|
|
27
|
+
</Button>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
export interface ConversationListProps {
|
|
11
32
|
groups: ConversationGroup[];
|
|
12
33
|
conversations: ConversationSummary[];
|
|
@@ -14,12 +35,48 @@ export interface ConversationListProps {
|
|
|
14
35
|
onSelect: (id: string) => void;
|
|
15
36
|
onNewChat: () => void;
|
|
16
37
|
onToggleSidebar?: () => void;
|
|
38
|
+
/** Replaces the built-in title bar (toggle / "Chats" / New chat). */
|
|
39
|
+
header?: JSX.Element;
|
|
40
|
+
/** A row below the list (e.g. account / settings / usage). */
|
|
41
|
+
footer?: JSX.Element;
|
|
42
|
+
/** Replaces the built-in "no conversations yet" state. */
|
|
43
|
+
empty?: JSX.Element;
|
|
44
|
+
/** Dense single-line rows (a leading dot + title, no message count). */
|
|
45
|
+
compact?: boolean;
|
|
46
|
+
/** Fired whenever the built-in search box query changes (typing or a
|
|
47
|
+
* programmatic `clear()`). Lets the facade surface a `kai-search` event. */
|
|
48
|
+
onSearchChange?: (query: string) => void;
|
|
49
|
+
/** Receive the imperative controller once mounted. The `kai-conversations`
|
|
50
|
+
* facade uses it to focus / clear the internal search input. */
|
|
51
|
+
controllerRef?: (controller: ConversationListController) => void;
|
|
17
52
|
class?: string;
|
|
18
53
|
}
|
|
19
54
|
|
|
55
|
+
/** Imperative handle exposed via `controllerRef` — surfaces the internal search
|
|
56
|
+
* box to the `kai-conversations` facade (the searchQuery signal lives here). */
|
|
57
|
+
export interface ConversationListController {
|
|
58
|
+
/** Focus the built-in search `<input>`. */
|
|
59
|
+
focus(options?: FocusOptions): void;
|
|
60
|
+
/** Clear the internal search query (resets the list filter). */
|
|
61
|
+
clearSearch(): void;
|
|
62
|
+
}
|
|
63
|
+
|
|
20
64
|
export function ConversationList(props: ConversationListProps) {
|
|
21
|
-
const [local] = splitProps(props, ['groups', 'conversations', 'activeId', 'onSelect', 'onNewChat', 'onToggleSidebar', 'class']);
|
|
65
|
+
const [local] = splitProps(props, ['groups', 'conversations', 'activeId', 'onSelect', 'onNewChat', 'onToggleSidebar', 'header', 'footer', 'empty', 'compact', 'onSearchChange', 'controllerRef', 'class']);
|
|
22
66
|
const [searchQuery, setSearchQuery] = createSignal('');
|
|
67
|
+
const isEmpty = createMemo(() => local.conversations.length === 0);
|
|
68
|
+
// The search query is owned here; setQuery is the single mutation point so both
|
|
69
|
+
// typing and the imperative clearSearch() notify the facade (→ kai-search).
|
|
70
|
+
let searchInput: HTMLInputElement | undefined;
|
|
71
|
+
const setQuery = (q: string) => { setSearchQuery(q); local.onSearchChange?.(q); };
|
|
72
|
+
|
|
73
|
+
// Hand the imperative controller (focus / clear the search box) to the facade.
|
|
74
|
+
onMount(() => {
|
|
75
|
+
local.controllerRef?.({
|
|
76
|
+
focus: (options) => searchInput?.focus(options),
|
|
77
|
+
clearSearch: () => setQuery(''),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
23
80
|
|
|
24
81
|
const filteredConversations = createMemo(() => {
|
|
25
82
|
const q = searchQuery().toLowerCase();
|
|
@@ -41,45 +98,85 @@ export function ConversationList(props: ConversationListProps) {
|
|
|
41
98
|
|
|
42
99
|
return (
|
|
43
100
|
<div class={cn('flex flex-col h-full bg-sidebar', local.class)}>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
101
|
+
{/* header (replace): the consumer's own title bar, else the built-in one. */}
|
|
102
|
+
<Show
|
|
103
|
+
when={local.header}
|
|
104
|
+
fallback={
|
|
105
|
+
<div class="flex items-center justify-between p-3 pb-2">
|
|
106
|
+
<div class="flex items-center gap-2">
|
|
107
|
+
<Button variant="ghost" size="icon-sm" aria-label="Toggle sidebar" onClick={local.onToggleSidebar}>
|
|
108
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
|
109
|
+
</Button>
|
|
110
|
+
<span class="text-sm font-semibold text-foreground">Chats</span>
|
|
111
|
+
</div>
|
|
112
|
+
<Button variant="ghost" size="icon-sm" aria-label="New chat" onClick={local.onNewChat}>
|
|
113
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
114
|
+
</Button>
|
|
115
|
+
</div>
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
{local.header}
|
|
119
|
+
</Show>
|
|
120
|
+
<Show when={!isEmpty()}>
|
|
121
|
+
<div class="px-3 pb-2">
|
|
122
|
+
<div class="flex items-center gap-2 rounded-md bg-surface-strong px-2.5 py-1.5">
|
|
123
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-muted-foreground"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
|
124
|
+
<input ref={searchInput} type="text" value={searchQuery()} onInput={(e) => setQuery(e.currentTarget.value)} placeholder="Search chats..."
|
|
125
|
+
aria-label="Search chats"
|
|
126
|
+
class="bg-transparent text-[13px] text-foreground placeholder:text-muted-foreground rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring w-full" />
|
|
127
|
+
</div>
|
|
50
128
|
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
129
|
+
</Show>
|
|
130
|
+
{/* list, or the empty state (replace) when there are no conversations. */}
|
|
131
|
+
<Show
|
|
132
|
+
when={!isEmpty()}
|
|
133
|
+
fallback={
|
|
134
|
+
<Show
|
|
135
|
+
when={local.empty}
|
|
136
|
+
fallback={
|
|
137
|
+
<div class="flex flex-1 flex-col items-center justify-center gap-1 p-6 text-center text-sm text-muted-foreground">
|
|
138
|
+
No conversations yet
|
|
139
|
+
</div>
|
|
140
|
+
}
|
|
141
|
+
>
|
|
142
|
+
{local.empty}
|
|
143
|
+
</Show>
|
|
144
|
+
}
|
|
145
|
+
>
|
|
146
|
+
<ScrollArea class="flex-1 px-2">
|
|
147
|
+
<For each={local.groups}>
|
|
148
|
+
{(group) => {
|
|
149
|
+
const convs = createMemo(() => groupedConversations().get(group.id) ?? []);
|
|
150
|
+
return (
|
|
151
|
+
<Show when={convs().length > 0}>
|
|
152
|
+
<GroupSection name={group.name} count={convs().length} conversations={convs()} activeId={local.activeId} onSelect={local.onSelect} compact={local.compact} />
|
|
153
|
+
</Show>
|
|
154
|
+
);
|
|
155
|
+
}}
|
|
156
|
+
</For>
|
|
157
|
+
<Show when={ungrouped().length > 0}>
|
|
158
|
+
<Show
|
|
159
|
+
when={local.compact}
|
|
160
|
+
fallback={<GroupSection name="Ungrouped" count={ungrouped().length} conversations={ungrouped()} activeId={local.activeId} onSelect={local.onSelect} />}
|
|
161
|
+
>
|
|
162
|
+
<div class="space-y-0.5 py-1">
|
|
163
|
+
<For each={ungrouped()}>
|
|
164
|
+
{(conv) => <ConversationItem conversation={conv} isActive={conv.id === local.activeId} onSelect={local.onSelect} compact />}
|
|
165
|
+
</For>
|
|
166
|
+
</div>
|
|
167
|
+
</Show>
|
|
168
|
+
</Show>
|
|
169
|
+
</ScrollArea>
|
|
170
|
+
</Show>
|
|
171
|
+
{/* footer (inject): a row below the list (account / settings / …). */}
|
|
172
|
+
<Show when={local.footer}>
|
|
173
|
+
<div class="shrink-0 border-t border-border">{local.footer}</div>
|
|
174
|
+
</Show>
|
|
78
175
|
</div>
|
|
79
176
|
);
|
|
80
177
|
}
|
|
81
178
|
|
|
82
|
-
function GroupSection(props: { name: string; count: number; conversations: ConversationSummary[]; activeId?: string; onSelect: (id: string) => void }) {
|
|
179
|
+
function GroupSection(props: { name: string; count: number; conversations: ConversationSummary[]; activeId?: string; onSelect: (id: string) => void; compact?: boolean }) {
|
|
83
180
|
const [open, setOpen] = createSignal(true);
|
|
84
181
|
return (
|
|
85
182
|
<Collapsible open={open()} onOpenChange={setOpen}>
|
|
@@ -92,7 +189,7 @@ function GroupSection(props: { name: string; count: number; conversations: Conve
|
|
|
92
189
|
<CollapsibleContent>
|
|
93
190
|
<div class="pl-2 mt-0.5 space-y-0.5">
|
|
94
191
|
<For each={props.conversations}>
|
|
95
|
-
{(conv) => <ConversationItem conversation={conv} isActive={conv.id === props.activeId} onSelect={props.onSelect} />}
|
|
192
|
+
{(conv) => <ConversationItem conversation={conv} isActive={conv.id === props.activeId} onSelect={props.onSelect} compact={props.compact} />}
|
|
96
193
|
</For>
|
|
97
194
|
</div>
|
|
98
195
|
</CollapsibleContent>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type JSX, Show } from 'solid-js';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
import { Button } from '../ui/button';
|
|
4
|
+
import { Card } from './card';
|
|
5
|
+
import { RotateCcw } from 'lucide-solid';
|
|
6
|
+
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// DismissedStub — the collapsed, re-openable read-only view a card renders once
|
|
9
|
+
// the user has dismissed it (a DEFERRED resolution, not a terminal one). It's a
|
|
10
|
+
// dense `Card` showing "<intent>: <title> — dismissed" + a ghost Reopen button.
|
|
11
|
+
// Pure/presentational: the owning card wires `onReopen` to emit `{kind:'reopen'}`.
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/** The card types that render a dismissed stub, mapped to their intent verb. */
|
|
15
|
+
export type DismissedCardType = 'confirm' | 'choice' | 'form' | 'tasks';
|
|
16
|
+
|
|
17
|
+
const INTENT_LABELS: Record<DismissedCardType, string> = {
|
|
18
|
+
confirm: 'Proposed',
|
|
19
|
+
choice: 'Choose',
|
|
20
|
+
form: 'Form',
|
|
21
|
+
tasks: 'Tasks',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Map a card `type` to its dismissed-stub intent label ("Proposed:", "Choose:",
|
|
25
|
+
* "Form:", "Tasks:"). Falls back to a capitalized type for unknown card types. */
|
|
26
|
+
export function stubIntent(type: string): string {
|
|
27
|
+
const known = INTENT_LABELS[type as DismissedCardType];
|
|
28
|
+
if (known) return `${known}:`;
|
|
29
|
+
if (type.length === 0) return 'Card:';
|
|
30
|
+
return `${type.charAt(0).toUpperCase()}${type.slice(1)}:`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface DismissedStubProps {
|
|
34
|
+
/** The card type, used to derive the intent label ("Proposed:" etc.). */
|
|
35
|
+
type: string;
|
|
36
|
+
/** The card's title/heading; shown after the intent label. Falls back gracefully. */
|
|
37
|
+
title?: string;
|
|
38
|
+
/** Re-open handler. The owning card emits `{ kind:'reopen', cardId }`. */
|
|
39
|
+
onReopen: () => void;
|
|
40
|
+
/** The Reopen button label. Default 'Reopen'. */
|
|
41
|
+
reopenLabel?: string;
|
|
42
|
+
class?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* `DismissedStub` — the compact stub a card collapses to after it's been dismissed.
|
|
47
|
+
* Group-labelled for a11y; the Reopen affordance is a ghost button.
|
|
48
|
+
*/
|
|
49
|
+
export function DismissedStub(props: DismissedStubProps): JSX.Element {
|
|
50
|
+
const intent = (): string => stubIntent(props.type);
|
|
51
|
+
const title = (): string => props.title ?? 'this card';
|
|
52
|
+
const label = (): string => props.reopenLabel ?? 'Reopen';
|
|
53
|
+
const groupLabel = (): string => `${intent()} ${title()} — dismissed`;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Card dense class={props.class}>
|
|
57
|
+
<div
|
|
58
|
+
role="group"
|
|
59
|
+
aria-label={groupLabel()}
|
|
60
|
+
class="flex flex-wrap items-center gap-x-2 gap-y-1"
|
|
61
|
+
>
|
|
62
|
+
<span class="min-w-0 text-sm text-muted-foreground">
|
|
63
|
+
<span class="font-medium text-foreground">{intent()}</span>{' '}
|
|
64
|
+
<span class="text-foreground">{title()}</span>
|
|
65
|
+
<span class="text-muted-foreground"> — dismissed</span>
|
|
66
|
+
</span>
|
|
67
|
+
<Button
|
|
68
|
+
type="button"
|
|
69
|
+
variant="ghost"
|
|
70
|
+
size="sm"
|
|
71
|
+
class={cn('ml-auto gap-1.5')}
|
|
72
|
+
onClick={() => props.onReopen()}
|
|
73
|
+
>
|
|
74
|
+
<RotateCcw size={14} aria-hidden="true" />
|
|
75
|
+
<Show when={label()}>{label()}</Show>
|
|
76
|
+
</Button>
|
|
77
|
+
</div>
|
|
78
|
+
</Card>
|
|
79
|
+
);
|
|
80
|
+
}
|