@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
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { defineWebComponent } from './define';
|
|
2
2
|
import { ChatScopePicker } from '../components/chat-scope-picker';
|
|
3
|
+
import { wireDisclosure } from './disclosure';
|
|
4
|
+
import type { DropdownController } from '../ui/dropdown';
|
|
3
5
|
import type { SearchFilters } from '../types';
|
|
4
6
|
|
|
5
7
|
interface Props extends Record<string, unknown> {
|
|
@@ -9,12 +11,22 @@ interface Props extends Record<string, unknown> {
|
|
|
9
11
|
availableTags: string[];
|
|
10
12
|
/** The label shown on the trigger for the active scope. */
|
|
11
13
|
currentLabel?: string;
|
|
14
|
+
/** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
|
|
15
|
+
* to the `open` attribute, the dropdown still self-manages on click/keyboard).
|
|
16
|
+
* Set `el.open = true`, or `<kai-scope-picker open>`; listen for `kai-open-change`. */
|
|
17
|
+
open?: boolean;
|
|
18
|
+
/** Initial open state on mount (uncontrolled seed). */
|
|
19
|
+
defaultOpen?: boolean;
|
|
20
|
+
/** Disable the trigger — click/keyboard and `show()` no longer open the dropdown. */
|
|
21
|
+
disabled?: boolean;
|
|
12
22
|
}
|
|
13
23
|
|
|
14
24
|
/** Events fired by `<kai-scope-picker>`. */
|
|
15
25
|
interface Events {
|
|
16
26
|
/** A scope was chosen (`undefined` filters = "All Content"). */
|
|
17
27
|
'kai-scope-change': { filters: SearchFilters | undefined };
|
|
28
|
+
/** The scope dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). */
|
|
29
|
+
'kai-open-change': { open: boolean };
|
|
18
30
|
}
|
|
19
31
|
|
|
20
32
|
/**
|
|
@@ -26,11 +38,26 @@ defineWebComponent<Props, Events>('kai-scope-picker', {
|
|
|
26
38
|
availableAuthors: [],
|
|
27
39
|
availableTags: [],
|
|
28
40
|
currentLabel: 'All Content',
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
open: undefined,
|
|
42
|
+
defaultOpen: undefined,
|
|
43
|
+
disabled: undefined,
|
|
44
|
+
}, (props, ctx) => {
|
|
45
|
+
const { dispatch, flag } = ctx;
|
|
46
|
+
let api: DropdownController | undefined;
|
|
47
|
+
|
|
48
|
+
// The standard overlay surface: settable+reflecting `open`, kai-open-change,
|
|
49
|
+
// show/hide/toggle, disabled-gating. See ./disclosure.
|
|
50
|
+
wireDisclosure(ctx, () => api, () => props.open);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ChatScopePicker
|
|
54
|
+
currentLabel={props.currentLabel ?? 'All Content'}
|
|
55
|
+
availableAuthors={props.availableAuthors}
|
|
56
|
+
availableTags={props.availableTags}
|
|
57
|
+
onScopeChange={(filters) => dispatch('kai-scope-change', { filters })}
|
|
58
|
+
defaultOpen={flag('defaultOpen')}
|
|
59
|
+
disabled={flag('disabled')}
|
|
60
|
+
controllerRef={(a) => (api = a)}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import type { ToolPart } from '../components/tool';
|
|
2
|
-
import type { AttachmentData } from '../components/
|
|
1
|
+
import type { ToolPart } from '../components/tool-types';
|
|
2
|
+
import type { AttachmentData } from '../components/attachment-types';
|
|
3
3
|
|
|
4
4
|
/** The five built-in action buttons (each carries its own curated icon + label). */
|
|
5
5
|
export type ChatMessageAction = 'copy' | 'like' | 'dislike' | 'regenerate' | 'edit';
|
|
6
6
|
|
|
7
|
+
/** A like/dislike feedback vote on an assistant message. */
|
|
8
|
+
export type FeedbackVote = 'like' | 'dislike';
|
|
9
|
+
|
|
7
10
|
/** A host-defined action button. `icon` is a curated registry name (see
|
|
8
11
|
* `src/ui/action-icons.ts`); unknown/absent icons render label-only. */
|
|
9
12
|
export interface CustomAction {
|
|
@@ -39,4 +42,8 @@ export interface ChatMessage {
|
|
|
39
42
|
actions?: (ChatMessageAction | CustomAction)[];
|
|
40
43
|
/** Optional speaker avatar shown to the left of the message column. */
|
|
41
44
|
avatar?: AvatarData;
|
|
45
|
+
/** Controlled feedback vote. When set, it wins over the facade's internal
|
|
46
|
+
* optimistic state (`m.feedback ?? feedbackMap[m.id]`), so a host that
|
|
47
|
+
* persists votes can re-hydrate them. */
|
|
48
|
+
feedback?: FeedbackVote;
|
|
42
49
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { Show } from 'solid-js';
|
|
1
|
+
import { Show, createSignal, onMount, onCleanup } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
3
|
import { createControllableSignal } from '../primitives/controllable';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { readSlots, WORKSPACE_SLOTS } from './slots';
|
|
5
|
+
import { ChatThread, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
|
|
6
|
+
import { ConversationList, CollapsedRail } from '../components/conversation-list';
|
|
6
7
|
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '../ui/resizable';
|
|
7
|
-
import { Button } from '../ui/button';
|
|
8
|
-
import { PanelLeftOpen } from 'lucide-solid';
|
|
9
8
|
import type { AttachmentData } from '../components/attachments';
|
|
10
|
-
import type {
|
|
9
|
+
import type { TriggerDef } from '../components/composer';
|
|
11
10
|
import type { ChatMessage } from './chat-types';
|
|
12
11
|
import type { ProseSize } from '../primitives/chat-config';
|
|
13
12
|
import type { ModelOption, ConversationGroup, ConversationSummary } from '../types';
|
|
@@ -36,12 +35,13 @@ interface Props extends Record<string, unknown> {
|
|
|
36
35
|
scrollButton?: boolean;
|
|
37
36
|
search?: boolean;
|
|
38
37
|
voice?: boolean;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
/** Rich entity triggers (`/` skills, `@` agents/plugins) forwarded to the input. */
|
|
39
|
+
triggers?: TriggerDef[];
|
|
40
|
+
/** Default icon per entity kind (kind → image src) forwarded to the input. */
|
|
41
|
+
kindIcons?: Record<string, string>;
|
|
42
|
+
/** Sidebar default width as a percent of the workspace (default 26). */
|
|
43
43
|
sidebarWidth?: number;
|
|
44
|
-
/** Sidebar min width in px (default
|
|
44
|
+
/** Sidebar min width in px (default 240). */
|
|
45
45
|
sidebarMinWidth?: number;
|
|
46
46
|
/** Sidebar max width in px (default 420). */
|
|
47
47
|
sidebarMaxWidth?: number;
|
|
@@ -52,6 +52,17 @@ interface Props extends Record<string, unknown> {
|
|
|
52
52
|
/** Initial collapsed state when uncontrolled (default false). Use the
|
|
53
53
|
* `default-sidebar-collapsed` attribute to start collapsed in plain HTML. */
|
|
54
54
|
defaultSidebarCollapsed?: boolean;
|
|
55
|
+
/** Auto-collapse the rail when the workspace's own width drops below this many
|
|
56
|
+
* px, and re-expand when it grows back above. Uncontrolled only (it never
|
|
57
|
+
* fights an app-driven `sidebarCollapsed`); omit to disable. Fires
|
|
58
|
+
* `kai-sidebar-toggle`. Attribute: `collapse-below`. */
|
|
59
|
+
collapseBelow?: number;
|
|
60
|
+
/** Render Recents as dense single-line rows (a leading dot + title, no count). */
|
|
61
|
+
compact?: boolean;
|
|
62
|
+
/** Suppress the built-in ConversationList so the `sidebar-header` slot owns the
|
|
63
|
+
* whole rail flex region (for apps that supply their own rail nav). Default
|
|
64
|
+
* false. Attribute: `no-conversations`. */
|
|
65
|
+
noConversations?: boolean;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
interface Events {
|
|
@@ -67,14 +78,14 @@ interface Events {
|
|
|
67
78
|
'kai-value-change': { value: string };
|
|
68
79
|
/** The header model switcher changed. */
|
|
69
80
|
'kai-model-change': { modelId: string };
|
|
70
|
-
/** An action button on a message was clicked.
|
|
71
|
-
'
|
|
81
|
+
/** An action button on a message was clicked. `state` is present only for the
|
|
82
|
+
* toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when
|
|
83
|
+
* re-tapped to clear. */
|
|
84
|
+
'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
|
|
72
85
|
/** The Search button was clicked. */
|
|
73
86
|
'kai-search': Record<string, never>;
|
|
74
87
|
/** The Mic / voice button was clicked. */
|
|
75
88
|
'kai-voice': Record<string, never>;
|
|
76
|
-
/** A slash command was chosen from the palette. */
|
|
77
|
-
'kai-slash-select': { command: SlashCommandItem };
|
|
78
89
|
/** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
|
|
79
90
|
'kai-suggestion-click': { value: string };
|
|
80
91
|
}
|
|
@@ -85,20 +96,83 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
85
96
|
suggestions: undefined, suggestionMode: 'submit', proseSize: 'sm',
|
|
86
97
|
codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
|
|
87
98
|
models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
|
|
88
|
-
search: false, voice: false,
|
|
89
|
-
sidebarWidth:
|
|
90
|
-
sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined,
|
|
91
|
-
|
|
99
|
+
search: false, voice: false, triggers: undefined, kindIcons: undefined,
|
|
100
|
+
sidebarWidth: 26, sidebarMinWidth: 240, sidebarMaxWidth: 420,
|
|
101
|
+
sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined, collapseBelow: undefined, compact: undefined,
|
|
102
|
+
noConversations: undefined,
|
|
103
|
+
}, (props, { dispatch, flag, expose, element }) => {
|
|
104
|
+
// Which injection slots the consumer has filled. A bare <slot> is always a
|
|
105
|
+
// truthy JSX node, so we render each region wrapper ONLY when readSlots reports
|
|
106
|
+
// projected light-DOM content (re-read on childList mutation).
|
|
107
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
108
|
+
onMount(() => {
|
|
109
|
+
const read = () => setSlots(readSlots(element, WORKSPACE_SLOTS));
|
|
110
|
+
read();
|
|
111
|
+
const observer = new MutationObserver(read);
|
|
112
|
+
observer.observe(element, { childList: true });
|
|
113
|
+
onCleanup(() => observer.disconnect());
|
|
114
|
+
});
|
|
115
|
+
|
|
92
116
|
// Controlled/uncontrolled collapse: `sidebarCollapsed` (when set) wins;
|
|
93
117
|
// otherwise the element manages its own state, seeded from
|
|
94
|
-
// `defaultSidebarCollapsed`. `
|
|
95
|
-
// visually while controlled) and emits `kai-sidebar-toggle` so a controlling
|
|
96
|
-
// can update its own state.
|
|
118
|
+
// `defaultSidebarCollapsed`. `setCollapsedTo` always writes the internal value (a
|
|
119
|
+
// no-op visually while controlled) and emits `kai-sidebar-toggle` so a controlling
|
|
120
|
+
// app can update its own state.
|
|
97
121
|
const [collapsed, setCollapsed] = createControllableSignal(
|
|
98
122
|
() => props.sidebarCollapsed as boolean | undefined,
|
|
99
123
|
flag('defaultSidebarCollapsed'),
|
|
100
124
|
);
|
|
101
|
-
const
|
|
125
|
+
const setCollapsedTo = (next: boolean) => { setCollapsed(next); dispatch('kai-sidebar-toggle', { collapsed: next }); };
|
|
126
|
+
const toggle = () => setCollapsedTo(!collapsed());
|
|
127
|
+
|
|
128
|
+
// Responsive auto-collapse. When `collapseBelow` is set, a ResizeObserver on the
|
|
129
|
+
// workspace root collapses the rail once the workspace's own width drops below
|
|
130
|
+
// it and re-expands above it. Uncontrolled only — bail while `sidebarCollapsed`
|
|
131
|
+
// is set so we never fight an app-driven collapse. `autoCollapsed` tracks whether
|
|
132
|
+
// WE collapsed it, so a user's manual expand isn't auto-undone on the next tick.
|
|
133
|
+
let rootEl!: HTMLDivElement;
|
|
134
|
+
let autoCollapsed = false;
|
|
135
|
+
onMount(() => {
|
|
136
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
137
|
+
const ro = new ResizeObserver((entries) => {
|
|
138
|
+
const below = props.collapseBelow as number | undefined;
|
|
139
|
+
if (below == null || props.sidebarCollapsed !== undefined) return;
|
|
140
|
+
const width = entries[0]?.contentRect.width ?? rootEl.clientWidth;
|
|
141
|
+
const isBelow = width < below;
|
|
142
|
+
if (isBelow && !collapsed()) {
|
|
143
|
+
autoCollapsed = true;
|
|
144
|
+
setCollapsedTo(true);
|
|
145
|
+
} else if (!isBelow && collapsed() && autoCollapsed) {
|
|
146
|
+
autoCollapsed = false;
|
|
147
|
+
setCollapsedTo(false);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
ro.observe(rootEl);
|
|
151
|
+
onCleanup(() => ro.disconnect());
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Imperative method API. The sidebar methods drive the same collapse path as the
|
|
155
|
+
// in-UI toggle (named *Sidebar to avoid the `sidebarCollapsed` prop accessor).
|
|
156
|
+
// The thread methods delegate to the embedded ChatThread's controller, captured
|
|
157
|
+
// once below — the thread node is shared across both <Show> branches, so a single
|
|
158
|
+
// controllerRef is stable across collapse/expand.
|
|
159
|
+
let controller: ChatThreadController | undefined;
|
|
160
|
+
expose({
|
|
161
|
+
/** Collapse/expand the conversation sidebar and fire `kai-sidebar-toggle`. */
|
|
162
|
+
toggleSidebar: () => toggle(),
|
|
163
|
+
/** Force the conversation sidebar collapsed (fires `kai-sidebar-toggle`). */
|
|
164
|
+
collapseSidebar: () => setCollapsedTo(true),
|
|
165
|
+
/** Force the conversation sidebar expanded (fires `kai-sidebar-toggle`). */
|
|
166
|
+
expandSidebar: () => setCollapsedTo(false),
|
|
167
|
+
/** Focus the thread's composer. */
|
|
168
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
169
|
+
/** Clear the thread draft + staged attachments. */
|
|
170
|
+
clear: () => controller?.clear(),
|
|
171
|
+
/** Submit the current thread draft programmatically (fires `kai-submit`). */
|
|
172
|
+
send: () => controller?.send(),
|
|
173
|
+
/** Scroll the thread to the newest message. */
|
|
174
|
+
scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
|
|
175
|
+
});
|
|
102
176
|
|
|
103
177
|
// Create the thread ONCE and reference the same node in both <Show> branches.
|
|
104
178
|
// It's owned by this component root (not by a Show branch), so toggling the
|
|
@@ -113,8 +187,8 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
113
187
|
chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
|
|
114
188
|
currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
|
|
115
189
|
scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
|
|
116
|
-
|
|
117
|
-
|
|
190
|
+
triggers={props.triggers as TriggerDef[] | undefined}
|
|
191
|
+
kindIcons={props.kindIcons as Record<string, string> | undefined}
|
|
118
192
|
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
119
193
|
onSubmit={(detail) => dispatch('kai-submit', detail)}
|
|
120
194
|
onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
|
|
@@ -122,38 +196,78 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
122
196
|
onMessageAction={(detail) => dispatch('kai-message-action', detail)}
|
|
123
197
|
onSearch={() => dispatch('kai-search', {})}
|
|
124
198
|
onVoice={() => dispatch('kai-voice', {})}
|
|
125
|
-
|
|
199
|
+
controllerRef={(c) => (controller = c)}
|
|
126
200
|
/>
|
|
127
201
|
);
|
|
128
202
|
|
|
203
|
+
// The main region: an optional top-placed `main-header` band above the thread.
|
|
204
|
+
// Shared across both collapse branches (the thread node is the same instance).
|
|
205
|
+
const mainRegion = (
|
|
206
|
+
<div class="flex h-full flex-col overflow-hidden">
|
|
207
|
+
<Show when={slots()['main-header']}>
|
|
208
|
+
<div class="shrink-0 border-b border-border"><slot name="main-header" /></div>
|
|
209
|
+
</Show>
|
|
210
|
+
<div class="min-h-0 flex-1">
|
|
211
|
+
<Show when={slots()['main']} fallback={threadEl}>
|
|
212
|
+
<slot name="main" />
|
|
213
|
+
</Show>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
|
|
129
218
|
return (
|
|
130
|
-
<div class="h-full w-full overflow-hidden bg-background">
|
|
219
|
+
<div ref={rootEl} class="h-full w-full overflow-hidden bg-background">
|
|
131
220
|
<Show
|
|
132
221
|
when={!collapsed()}
|
|
133
222
|
fallback={
|
|
134
|
-
<div class="
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
223
|
+
<div class="flex h-full">
|
|
224
|
+
{/* Collapsed: the reopen control lives in its OWN thin rail column
|
|
225
|
+
(matching the sidebar's bg-surface) rather than floating over the
|
|
226
|
+
content. The previous `absolute` overlay sat on top of a
|
|
227
|
+
`main-header`'s leading title — see the t3code/codex/chatgpt apps,
|
|
228
|
+
all of which fill that slot — so it both overlapped the header and
|
|
229
|
+
competed with any in-header toggle. A dedicated column never
|
|
230
|
+
overlaps and reads as a collapsed sidebar. */}
|
|
231
|
+
<div class="flex w-11 shrink-0 flex-col items-center border-r border-border bg-surface pt-2.5">
|
|
232
|
+
<CollapsedRail onExpand={toggle} class="bg-transparent shadow-none backdrop-blur-none" />
|
|
233
|
+
</div>
|
|
234
|
+
<div class="min-w-0 flex-1">{mainRegion}</div>
|
|
143
235
|
</div>
|
|
144
236
|
}
|
|
145
237
|
>
|
|
146
238
|
<ResizablePanelGroup orientation="horizontal">
|
|
147
239
|
<ResizablePanel defaultSize={props.sidebarWidth as number} data-min-size={String(props.sidebarMinWidth)} data-max-size={String(props.sidebarMaxWidth)}>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
240
|
+
{/* The rail: an optional injected header above the list and footer
|
|
241
|
+
below it (upgrade card / Design trigger / user menu). Carries a
|
|
242
|
+
subtle, theme-aware default background (bg-surface), exposed as
|
|
243
|
+
::part(sidebar) so a consumer can override it. The inner list is
|
|
244
|
+
made transparent so the part background reads uniformly. */}
|
|
245
|
+
<div part="sidebar" class="flex h-full flex-col overflow-hidden bg-surface">
|
|
246
|
+
<Show when={slots()['sidebar-header']}>
|
|
247
|
+
{/* When `no-conversations` suppresses the built-in list, the
|
|
248
|
+
projected header owns the whole rail flex region; otherwise it
|
|
249
|
+
sits as a fixed band above the list. */}
|
|
250
|
+
<div class={flag('noConversations') ? 'min-h-0 flex-1' : 'shrink-0'}><slot name="sidebar-header" /></div>
|
|
251
|
+
</Show>
|
|
252
|
+
<Show when={!flag('noConversations')}>
|
|
253
|
+
<div class="min-h-0 flex-1">
|
|
254
|
+
<ConversationList
|
|
255
|
+
class="bg-transparent"
|
|
256
|
+
groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
|
|
257
|
+
compact={flag('compact')}
|
|
258
|
+
onSelect={(id) => dispatch('kai-conversation-select', { id })}
|
|
259
|
+
onNewChat={() => dispatch('kai-new-chat', {})}
|
|
260
|
+
onToggleSidebar={toggle}
|
|
261
|
+
/>
|
|
262
|
+
</div>
|
|
263
|
+
</Show>
|
|
264
|
+
<Show when={slots()['sidebar-footer']}>
|
|
265
|
+
<div class="shrink-0"><slot name="sidebar-footer" /></div>
|
|
266
|
+
</Show>
|
|
267
|
+
</div>
|
|
154
268
|
</ResizablePanel>
|
|
155
269
|
<ResizableHandle withHandle />
|
|
156
|
-
<ResizablePanel>{
|
|
270
|
+
<ResizablePanel>{mainRegion}</ResizablePanel>
|
|
157
271
|
</ResizablePanelGroup>
|
|
158
272
|
</Show>
|
|
159
273
|
</div>
|
package/src/elements/chat.tsx
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
1
|
+
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
|
-
import {
|
|
3
|
+
import { CHAT_SLOTS, readSlots } from './slots';
|
|
4
|
+
import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
|
|
4
5
|
import type { AttachmentData } from '../components/attachments';
|
|
5
|
-
import type {
|
|
6
|
+
import type { TriggerDef } from '../components/composer';
|
|
7
|
+
import type { ComposerDoc } from '../primitives/composer-model';
|
|
6
8
|
import type { ProseSize } from '../primitives/chat-config';
|
|
7
9
|
import type { ModelOption } from '../types';
|
|
8
10
|
|
|
9
11
|
type Props = Omit<ChatThreadProps,
|
|
10
|
-
'class' | 'onValueChange' | 'onSubmit' | 'onSuggestionClick' | 'onModelChange'
|
|
11
|
-
| 'onMessageAction' | 'onSearch' | 'onVoice' | '
|
|
12
|
+
'class' | 'onValueChange' | 'onSubmit' | 'onAttachmentsChange' | 'onSuggestionClick' | 'onModelChange'
|
|
13
|
+
| 'onMessageAction' | 'onSearch' | 'onVoice' | 'controllerRef'> & Record<string, unknown>;
|
|
12
14
|
|
|
13
15
|
interface Events {
|
|
14
16
|
/** User submitted a message. */
|
|
15
17
|
'kai-submit': { value: string; attachments: AttachmentData[] };
|
|
16
18
|
/** Fired on every input change. */
|
|
17
19
|
'kai-value-change': { value: string };
|
|
20
|
+
/** The staged attachments changed (file added or removed). Carries the full
|
|
21
|
+
* current list so a consumer can react in real time. */
|
|
22
|
+
'kai-attachments-change': { attachments: AttachmentData[] };
|
|
18
23
|
/** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
|
|
19
24
|
'kai-suggestion-click': { value: string };
|
|
20
|
-
/** An action button on a message was clicked. `action` is the built-in name or
|
|
21
|
-
|
|
25
|
+
/** An action button on a message was clicked. `action` is the built-in name or
|
|
26
|
+
* custom id. `state` is present only for the toggleable feedback votes:
|
|
27
|
+
* `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. */
|
|
28
|
+
'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
|
|
22
29
|
/** The header model switcher changed. */
|
|
23
30
|
'kai-model-change': { modelId: string };
|
|
24
|
-
/** A slash command was chosen from the palette. */
|
|
25
|
-
'kai-slash-select': { command: SlashCommandItem };
|
|
26
31
|
/** The Search button was clicked. */
|
|
27
32
|
'kai-search': Record<string, never>;
|
|
28
33
|
/** The Mic / voice button was clicked. */
|
|
@@ -34,27 +39,39 @@ defineWebComponent<Props, Events>('kai-chat', {
|
|
|
34
39
|
suggestions: undefined, suggestionMode: 'submit', persistSuggestions: false, proseSize: 'sm',
|
|
35
40
|
codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
|
|
36
41
|
models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
|
|
37
|
-
search: false, voice: false,
|
|
42
|
+
search: false, voice: false, triggers: undefined, kindIcons: undefined,
|
|
38
43
|
actionsReveal: 'always',
|
|
39
|
-
}, (props, { dispatch, flag, element }) => {
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
const [
|
|
43
|
-
const
|
|
44
|
+
}, (props, { dispatch, flag, element, expose }) => {
|
|
45
|
+
// Slot detection is driven by the CHAT_SLOTS registry (single source of truth)
|
|
46
|
+
// so slot names never drift between the view, the facade, and the docs.
|
|
47
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
48
|
+
const slot = (name: string) => slots()[name] === true;
|
|
44
49
|
onMount(() => {
|
|
45
|
-
const read = () =>
|
|
46
|
-
setHasHeaderStart(!!element.querySelector(':scope > [slot="header-start"]'));
|
|
47
|
-
setHasHeaderEnd(!!element.querySelector(':scope > [slot="header-end"]'));
|
|
48
|
-
};
|
|
50
|
+
const read = () => setSlots(readSlots(element, CHAT_SLOTS));
|
|
49
51
|
read();
|
|
50
52
|
const observer = new MutationObserver(read);
|
|
51
53
|
observer.observe(element, { childList: true });
|
|
52
54
|
onCleanup(() => observer.disconnect());
|
|
53
55
|
});
|
|
54
56
|
|
|
57
|
+
// Reflect streaming state to a host attribute so slotted composer/notice CSS
|
|
58
|
+
// can react without reading internals (e.g. :host([loading]) ::slotted(...)).
|
|
59
|
+
createEffect(() => { element.toggleAttribute('loading', flag('loading')); });
|
|
60
|
+
|
|
61
|
+
// Imperative method API — forward the chat-thread controller onto the host
|
|
62
|
+
// (focus the composer, clear it, send programmatically, scroll the thread).
|
|
63
|
+
let controller: ChatThreadController | undefined;
|
|
64
|
+
expose({
|
|
65
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
66
|
+
blur: () => (element.shadowRoot?.activeElement as HTMLElement | null)?.blur(),
|
|
67
|
+
clear: () => controller?.clear(),
|
|
68
|
+
send: () => controller?.send(),
|
|
69
|
+
scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
|
|
70
|
+
});
|
|
71
|
+
|
|
55
72
|
return (
|
|
56
73
|
<ChatThread
|
|
57
|
-
messages={props.messages} value={props.value as string | undefined} placeholder={props.placeholder as string}
|
|
74
|
+
messages={props.messages} value={props.value as string | ComposerDoc | undefined} placeholder={props.placeholder as string}
|
|
58
75
|
loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
|
|
59
76
|
suggestionMode={props.suggestionMode as 'submit' | 'fill'} persistSuggestions={flag('persistSuggestions')}
|
|
60
77
|
proseSize={props.proseSize as ProseSize}
|
|
@@ -62,19 +79,26 @@ defineWebComponent<Props, Events>('kai-chat', {
|
|
|
62
79
|
chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
|
|
63
80
|
currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
|
|
64
81
|
scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
triggers={props.triggers as TriggerDef[] | undefined}
|
|
83
|
+
kindIcons={props.kindIcons as Record<string, string> | undefined}
|
|
67
84
|
actionsReveal={props.actionsReveal as 'always' | 'hover'}
|
|
68
85
|
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
69
86
|
onSubmit={(detail) => dispatch('kai-submit', detail)}
|
|
87
|
+
onAttachmentsChange={(attachments) => dispatch('kai-attachments-change', { attachments })}
|
|
70
88
|
onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
|
|
71
89
|
onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
|
|
72
90
|
onMessageAction={(detail) => dispatch('kai-message-action', detail)}
|
|
73
91
|
onSearch={() => dispatch('kai-search', {})}
|
|
74
92
|
onVoice={() => dispatch('kai-voice', {})}
|
|
75
|
-
|
|
76
|
-
headerStart={
|
|
77
|
-
headerEnd={
|
|
93
|
+
controllerRef={(c) => (controller = c)}
|
|
94
|
+
headerStart={slot('header-start')}
|
|
95
|
+
headerEnd={slot('header-end')}
|
|
96
|
+
headerFull={slot('header')}
|
|
97
|
+
sidebar={slot('sidebar')}
|
|
98
|
+
empty={slot('empty')}
|
|
99
|
+
composer={slot('composer')}
|
|
100
|
+
composerActions={slot('composer-actions')}
|
|
101
|
+
footer={slot('footer')}
|
|
78
102
|
/>
|
|
79
103
|
);
|
|
80
104
|
});
|
package/src/elements/choice.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineWebComponent } from './define';
|
|
2
|
-
import { ChoiceCard, type ChoiceCardData } from '../components/choice-card';
|
|
2
|
+
import { ChoiceCard, type ChoiceCardData, type ChoiceController } from '../components/choice-card';
|
|
3
3
|
import type { CardResolution } from '../primitives/card-contract';
|
|
4
4
|
|
|
5
5
|
interface Props extends Record<string, unknown> {
|
|
@@ -14,35 +14,87 @@ interface Props extends Record<string, unknown> {
|
|
|
14
14
|
/** Set when the user resolved this card; renders the read-only view. Property:
|
|
15
15
|
* `el.resolution = { kind:'action', action:'…' }`. */
|
|
16
16
|
resolution?: Record<string, unknown>;
|
|
17
|
+
/** Controlled selection — the selected option id. When set, the consumer owns
|
|
18
|
+
* the current pick (RadioGroup `value`). Attribute: `value`. */
|
|
19
|
+
value?: string;
|
|
20
|
+
/** Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. */
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
/** Disable the whole radiogroup + Submit (e.g. while the agent is busy).
|
|
23
|
+
* Attribute: `disabled`. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Events fired by `<kai-choice>`. (The terminal submit/dismiss/reopen flow is
|
|
28
|
+
* emitted via the bubbling `kai-card` contract event — listen for `kai-card`.) */
|
|
29
|
+
interface Events {
|
|
30
|
+
/** The selection changed BEFORE submit (a row click or the `select()` method).
|
|
31
|
+
* Distinct from the terminal `action` verb on the `kai-card` contract event. */
|
|
32
|
+
'kai-value-change': { value: string };
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
/**
|
|
20
36
|
* `<kai-choice>` — a single-select **"pick one of N rich options"** card (set via the
|
|
21
37
|
* `data` property): a prompt + a radiogroup of list rows. Clicking a row **selects** it
|
|
22
|
-
* (no emit); the **Submit** button below then emits the Card
|
|
23
|
-
* up a bubbling **`kai-card`** CustomEvent (`{ kind:'action',
|
|
24
|
-
* payload? }`) and resolves the card so the same pick can't
|
|
25
|
-
* `allowOther` free-text escape appends a selectable "Other…" row
|
|
26
|
-
* input; the same Submit emits `action:'__other__'` with `{ text }`.
|
|
27
|
-
* mount and `error` for a malformed definition (inline error). Routes
|
|
28
|
-
* `CardProvider` when present, else the bubbling `kai-card` event. Isolated in
|
|
29
|
-
* theme-aware via the shared tokens.
|
|
38
|
+
* (no emit, fires `kai-value-change`); the **Submit** button below then emits the Card
|
|
39
|
+
* contract's **`action`** verb up a bubbling **`kai-card`** CustomEvent (`{ kind:'action',
|
|
40
|
+
* cardId, action: option.id, payload? }`) and resolves the card so the same pick can't
|
|
41
|
+
* double-fire. An optional `allowOther` free-text escape appends a selectable "Other…" row
|
|
42
|
+
* that reveals an inline input; the same Submit emits `action:'__other__'` with `{ text }`.
|
|
43
|
+
* Also emits `ready` on mount and `error` for a malformed definition (inline error). Routes
|
|
44
|
+
* through a `CardProvider` when present, else the bubbling `kai-card` event. Isolated in
|
|
45
|
+
* Shadow DOM; theme-aware via the shared tokens.
|
|
46
|
+
*
|
|
47
|
+
* Supports controlled selection (`value`), an uncontrolled seed (`defaultValue`), a
|
|
48
|
+
* group-level `disabled`, and instance methods `focus()`/`select(id)`/`send()`/
|
|
49
|
+
* `dismiss()`/`reopen()`.
|
|
30
50
|
*/
|
|
31
|
-
defineWebComponent<Props>(
|
|
51
|
+
defineWebComponent<Props, Events>(
|
|
32
52
|
'kai-choice',
|
|
33
53
|
{
|
|
34
54
|
data: undefined,
|
|
35
55
|
cardId: undefined,
|
|
36
56
|
heading: undefined,
|
|
37
57
|
resolution: undefined,
|
|
58
|
+
value: undefined,
|
|
59
|
+
defaultValue: undefined,
|
|
60
|
+
disabled: undefined,
|
|
61
|
+
},
|
|
62
|
+
(props, { element, dispatch, flag, expose }) => {
|
|
63
|
+
// Pattern C: the ChoiceCard owns selection/submit/dismiss state and hands up a
|
|
64
|
+
// controller; the facade captures it and exposes delegating methods. The card's
|
|
65
|
+
// own paths still fire (select → kai-value-change; send → kai-card `action`;
|
|
66
|
+
// dismiss/reopen → kai-card `dismiss`/`reopen`).
|
|
67
|
+
let controller: ChoiceController | undefined;
|
|
68
|
+
expose({
|
|
69
|
+
/** Focus the radiogroup roving tab stop (or the Other input when selected). */
|
|
70
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
71
|
+
/** Select an option by id locally — no emit, fires kai-value-change (same as
|
|
72
|
+
* a row click). Lets a consumer pre-highlight or drive selection externally. */
|
|
73
|
+
select: (optionId: string) => controller?.select(optionId),
|
|
74
|
+
/** Submit the current selection — emits the `action` verb on kai-card and
|
|
75
|
+
* resolves the card (single-shot). Named `send`, not `submit`, per the shared
|
|
76
|
+
* vocabulary. */
|
|
77
|
+
send: () => controller?.send(),
|
|
78
|
+
/** Trigger the dismiss path — emits `dismiss` on kai-card and optimistically
|
|
79
|
+
* collapses the card to its re-openable stub. */
|
|
80
|
+
dismiss: () => controller?.dismiss(),
|
|
81
|
+
/** Re-open a dismissed card from its stub — emits `reopen` on kai-card. */
|
|
82
|
+
reopen: () => controller?.reopen(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<ChoiceCard
|
|
87
|
+
data={props.data as ChoiceCardData | undefined}
|
|
88
|
+
cardId={props.cardId ?? (element.id || 'kai-choice')}
|
|
89
|
+
heading={props.heading}
|
|
90
|
+
resolution={props.resolution as CardResolution | undefined}
|
|
91
|
+
value={props.value}
|
|
92
|
+
defaultValue={props.defaultValue}
|
|
93
|
+
disabled={flag('disabled')}
|
|
94
|
+
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
95
|
+
controllerRef={(c) => (controller = c)}
|
|
96
|
+
hostElement={element}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
38
99
|
},
|
|
39
|
-
(props, { element }) => (
|
|
40
|
-
<ChoiceCard
|
|
41
|
-
data={props.data as ChoiceCardData | undefined}
|
|
42
|
-
cardId={props.cardId ?? (element.id || 'kai-choice')}
|
|
43
|
-
heading={props.heading}
|
|
44
|
-
resolution={props.resolution as CardResolution | undefined}
|
|
45
|
-
hostElement={element}
|
|
46
|
-
/>
|
|
47
|
-
),
|
|
48
100
|
);
|