@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
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { For, Show } from 'solid-js';
|
|
2
|
+
import { MoreHorizontal } from 'lucide-solid';
|
|
3
|
+
import {
|
|
4
|
+
Dropdown, DropdownTrigger, DropdownContent, DropdownItem,
|
|
5
|
+
DropdownSeparator, DropdownLabel, DropdownCheckboxItem, DropdownRadioItem,
|
|
6
|
+
DropdownSub, DropdownSubTrigger, DropdownSubContent,
|
|
7
|
+
type DropdownController,
|
|
8
|
+
} from '../ui/dropdown';
|
|
9
|
+
import { renderIcon } from '../ui/icon';
|
|
10
|
+
import { Kbd } from '../ui/kbd';
|
|
11
|
+
import { cn } from '../utils/cn';
|
|
12
|
+
import { defineWebComponent } from './define';
|
|
13
|
+
import { wireDisclosure } from './disclosure';
|
|
14
|
+
|
|
15
|
+
export interface KaiMenuItem {
|
|
16
|
+
/** Emitted in `kai-select` for actionable items. */
|
|
17
|
+
id?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
/** Named icon (e.g. "paperclip"), image URL / data-URI, or plain text. */
|
|
20
|
+
icon?: string;
|
|
21
|
+
/** e.g. '⌘U' — shown right-aligned, muted. */
|
|
22
|
+
shortcut?: string;
|
|
23
|
+
/** Presence ⇒ a checkbox item (role=menuitemcheckbox). With `radioGroup` set,
|
|
24
|
+
* marks the SELECTED radio item in that group instead. */
|
|
25
|
+
checked?: boolean;
|
|
26
|
+
/** Membership in a single-select group (role=menuitemradio). Items sharing a
|
|
27
|
+
* `radioGroup` are mutually exclusive — the one with `checked: true` shows the
|
|
28
|
+
* checkmark; selecting one emits `{ id, radioGroup }` so the consumer moves
|
|
29
|
+
* the checkmark (the consumer owns state, like checkbox items). */
|
|
30
|
+
radioGroup?: string;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
/** A divider (ignores other fields). */
|
|
33
|
+
separator?: boolean;
|
|
34
|
+
/** A non-interactive section label (uses `label`). */
|
|
35
|
+
heading?: boolean;
|
|
36
|
+
/** ⇒ a submenu. */
|
|
37
|
+
items?: KaiMenuItem[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface Props extends Record<string, unknown> {
|
|
41
|
+
/** Tree of menu items. Set as a JS property — not an HTML attribute. */
|
|
42
|
+
items?: KaiMenuItem[];
|
|
43
|
+
/** Optional placement hint (unused by the underlying Dropdown which always
|
|
44
|
+
* positions bottom-start, kept for future extension). */
|
|
45
|
+
placement?: string;
|
|
46
|
+
/** Built-in trigger: leading icon (a named icon like `"plus"`, an image
|
|
47
|
+
* URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for
|
|
48
|
+
* the common case — a slotted trigger overrides it. */
|
|
49
|
+
triggerIcon?: string;
|
|
50
|
+
/** Built-in trigger: a text label (e.g. `"High"`). */
|
|
51
|
+
triggerLabel?: string;
|
|
52
|
+
/** Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). */
|
|
53
|
+
triggerIconTrailing?: string;
|
|
54
|
+
/** Accessible name for an icon-only trigger (no visible label). */
|
|
55
|
+
label?: string;
|
|
56
|
+
/** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
|
|
57
|
+
* attribute, the menu still self-manages on click/keyboard). Set `el.open = true`,
|
|
58
|
+
* or `<kai-menu open>`; listen for `kai-open-change`. */
|
|
59
|
+
open?: boolean;
|
|
60
|
+
/** Initial open state on mount (uncontrolled seed). */
|
|
61
|
+
defaultOpen?: boolean;
|
|
62
|
+
/** Disable the trigger — click/keyboard and `show()` no longer open the menu. */
|
|
63
|
+
disabled?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface Events {
|
|
67
|
+
/**
|
|
68
|
+
* Fired when the user selects a leaf item.
|
|
69
|
+
* - Plain items: `{ id }`.
|
|
70
|
+
* - Checkbox items: `{ id, checked }` where `checked` is the NEW state.
|
|
71
|
+
* - Radio items: `{ id, radioGroup }` — the consumer marks `id` as the selected
|
|
72
|
+
* one in `radioGroup` and clears the others.
|
|
73
|
+
*/
|
|
74
|
+
'kai-select': { id: string; checked?: boolean; radioGroup?: string };
|
|
75
|
+
/** The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). */
|
|
76
|
+
'kai-open-change': { open: boolean };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* `<kai-menu>` — a cascading action menu driven by a JSON items-tree.
|
|
81
|
+
*
|
|
82
|
+
* Set the `items` property in JavaScript (array, not attribute). The trigger
|
|
83
|
+
* is slotted — put your icon/button content in `slot="trigger"`:
|
|
84
|
+
*
|
|
85
|
+
* ```html
|
|
86
|
+
* <kai-menu>
|
|
87
|
+
* <button slot="trigger" aria-label="Open menu">+</button>
|
|
88
|
+
* </kai-menu>
|
|
89
|
+
* <script type="module">
|
|
90
|
+
* import '@kitn.ai/ui/elements';
|
|
91
|
+
* const menu = document.querySelector('kai-menu');
|
|
92
|
+
* menu.items = [
|
|
93
|
+
* { heading: true, label: 'Actions' },
|
|
94
|
+
* { id: 'attach', label: 'Add files', icon: 'paperclip', shortcut: 'Mod+U' },
|
|
95
|
+
* ];
|
|
96
|
+
* menu.addEventListener('kai-select', (e) => console.log(e.detail));
|
|
97
|
+
* </script>
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
defineWebComponent<Props, Events>('kai-menu', {
|
|
101
|
+
items: undefined,
|
|
102
|
+
placement: undefined,
|
|
103
|
+
triggerIcon: undefined,
|
|
104
|
+
triggerLabel: undefined,
|
|
105
|
+
triggerIconTrailing: undefined,
|
|
106
|
+
label: undefined,
|
|
107
|
+
open: undefined,
|
|
108
|
+
defaultOpen: undefined,
|
|
109
|
+
disabled: undefined,
|
|
110
|
+
}, (props, ctx) => {
|
|
111
|
+
const { dispatch, flag } = ctx;
|
|
112
|
+
let api: DropdownController | undefined;
|
|
113
|
+
|
|
114
|
+
// The standard overlay surface: settable+reflecting `open`, kai-open-change,
|
|
115
|
+
// show/hide/toggle, disabled-gating. See ./disclosure.
|
|
116
|
+
wireDisclosure(ctx, () => api, () => props.open);
|
|
117
|
+
|
|
118
|
+
function renderItems(items: KaiMenuItem[]) {
|
|
119
|
+
return (
|
|
120
|
+
<For each={items}>
|
|
121
|
+
{(item) => {
|
|
122
|
+
if (item.separator) {
|
|
123
|
+
return <DropdownSeparator />;
|
|
124
|
+
}
|
|
125
|
+
if (item.heading) {
|
|
126
|
+
return <DropdownLabel>{item.label}</DropdownLabel>;
|
|
127
|
+
}
|
|
128
|
+
if (item.items && item.items.length > 0) {
|
|
129
|
+
return (
|
|
130
|
+
<DropdownSub>
|
|
131
|
+
<DropdownSubTrigger>
|
|
132
|
+
<Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
|
|
133
|
+
{item.label}
|
|
134
|
+
</DropdownSubTrigger>
|
|
135
|
+
<DropdownSubContent>
|
|
136
|
+
{renderItems(item.items)}
|
|
137
|
+
</DropdownSubContent>
|
|
138
|
+
</DropdownSub>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (item.radioGroup !== undefined) {
|
|
142
|
+
return (
|
|
143
|
+
<DropdownRadioItem
|
|
144
|
+
checked={item.checked}
|
|
145
|
+
disabled={item.disabled}
|
|
146
|
+
onSelect={() => {
|
|
147
|
+
if (item.id) dispatch('kai-select', { id: item.id, radioGroup: item.radioGroup });
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
|
|
151
|
+
{item.label}
|
|
152
|
+
</DropdownRadioItem>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
if (item.checked !== undefined) {
|
|
156
|
+
return (
|
|
157
|
+
<DropdownCheckboxItem
|
|
158
|
+
checked={item.checked}
|
|
159
|
+
disabled={item.disabled}
|
|
160
|
+
onSelect={() => {
|
|
161
|
+
if (item.id) dispatch('kai-select', { id: item.id, checked: !item.checked });
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
<Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
|
|
165
|
+
{item.label}
|
|
166
|
+
</DropdownCheckboxItem>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return (
|
|
170
|
+
<DropdownItem
|
|
171
|
+
disabled={item.disabled}
|
|
172
|
+
onSelect={() => { if (item.id) dispatch('kai-select', { id: item.id }); }}
|
|
173
|
+
>
|
|
174
|
+
<Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
|
|
175
|
+
{item.label}
|
|
176
|
+
<Show when={item.shortcut}>
|
|
177
|
+
<span part="shortcut" class="ml-auto pl-4 text-muted-foreground">
|
|
178
|
+
<Kbd keys={item.shortcut!} platform="auto" size="sm" />
|
|
179
|
+
</span>
|
|
180
|
+
</Show>
|
|
181
|
+
</DropdownItem>
|
|
182
|
+
);
|
|
183
|
+
}}
|
|
184
|
+
</For>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<Dropdown
|
|
190
|
+
defaultOpen={flag('defaultOpen')}
|
|
191
|
+
disabled={flag('disabled')}
|
|
192
|
+
controllerRef={(a) => (api = a)}
|
|
193
|
+
>
|
|
194
|
+
<DropdownTrigger
|
|
195
|
+
class={cn(
|
|
196
|
+
'inline-flex items-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
197
|
+
props.triggerLabel
|
|
198
|
+
? 'gap-1.5 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
199
|
+
: 'justify-center p-1.5 text-foreground hover:bg-muted',
|
|
200
|
+
)}
|
|
201
|
+
aria-label={props.label ?? (props.triggerLabel ? undefined : 'Open menu')}
|
|
202
|
+
>
|
|
203
|
+
{/* Slotted trigger wins; otherwise build one from the trigger* props;
|
|
204
|
+
otherwise fall back to a "more" glyph. */}
|
|
205
|
+
<slot name="trigger">
|
|
206
|
+
<Show when={props.triggerIcon}>{renderIcon(props.triggerIcon, { class: 'size-4 shrink-0' })}</Show>
|
|
207
|
+
<Show when={props.triggerLabel}>{props.triggerLabel}</Show>
|
|
208
|
+
<Show when={props.triggerIconTrailing}>{renderIcon(props.triggerIconTrailing, { class: 'size-3.5 shrink-0 opacity-60' })}</Show>
|
|
209
|
+
<Show when={!props.triggerIcon && !props.triggerLabel}><MoreHorizontal class="size-4" /></Show>
|
|
210
|
+
</slot>
|
|
211
|
+
</DropdownTrigger>
|
|
212
|
+
<DropdownContent class="min-w-[15rem]">
|
|
213
|
+
{renderItems((props.items as KaiMenuItem[] | undefined) ?? [])}
|
|
214
|
+
</DropdownContent>
|
|
215
|
+
</Dropdown>
|
|
216
|
+
);
|
|
217
|
+
});
|
package/src/elements/message.tsx
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Show, createSignal, onMount, onCleanup } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
|
+
import { readSlots, MESSAGE_SLOTS } from './slots';
|
|
3
4
|
import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
|
|
4
|
-
import { Message, MessageAvatar,
|
|
5
|
-
import {
|
|
6
|
-
import { Tool } from '../components/tool';
|
|
7
|
-
import { Attachments, Attachment, AttachmentPreview, AttachmentInfo } from '../components/attachments';
|
|
5
|
+
import { Message, MessageAvatar, MessageBody } from '../components/message';
|
|
6
|
+
import { createMessageFeedback } from '../primitives/message-feedback';
|
|
8
7
|
import type { ChatMessage } from './chat-types';
|
|
9
8
|
|
|
10
9
|
interface Props extends Record<string, unknown> {
|
|
@@ -29,12 +28,19 @@ interface Props extends Record<string, unknown> {
|
|
|
29
28
|
avatarSrc?: string;
|
|
30
29
|
/** Convenience avatar fallback text (used when `message.avatar` is not set). */
|
|
31
30
|
avatarFallback?: string;
|
|
31
|
+
/** Avatar rail mode. `'none'` omits the avatar rail entirely so the body spans
|
|
32
|
+
* the full row (predictable layout when you never show avatars). Any other
|
|
33
|
+
* value keeps the default behaviour: the built-in avatar when one resolves, or
|
|
34
|
+
* your `slot="avatar"` content when projected (which REPLACES the built-in). */
|
|
35
|
+
avatar?: 'none' | string;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
/** Events fired by `<kai-message>`. */
|
|
35
39
|
interface Events {
|
|
36
|
-
/** An action button was clicked. `action` is the built-in name or custom id.
|
|
37
|
-
|
|
40
|
+
/** An action button was clicked. `action` is the built-in name or custom id.
|
|
41
|
+
* `state` is present only for the toggleable feedback votes: `'on'` when a
|
|
42
|
+
* like/dislike is set, `'off'` when re-tapped to clear. */
|
|
43
|
+
'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
/**
|
|
@@ -54,14 +60,36 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
54
60
|
actionsReveal: 'always',
|
|
55
61
|
avatarSrc: undefined,
|
|
56
62
|
avatarFallback: undefined,
|
|
57
|
-
|
|
63
|
+
avatar: undefined,
|
|
64
|
+
}, (props, { dispatch, flag, element, expose }) => {
|
|
58
65
|
const outer = useChatConfig();
|
|
59
66
|
const msg = (): ChatMessage =>
|
|
60
67
|
props.message ?? { id: 'message', role: props.role ?? 'assistant', content: props.content ?? '' };
|
|
68
|
+
// Copy + vote state lives here (above the rendered body) so it survives a
|
|
69
|
+
// re-render when the host swaps in a fresh `message` object during streaming.
|
|
70
|
+
const feedback = createMessageFeedback({
|
|
71
|
+
emit: (detail) => dispatch('kai-message-action', detail),
|
|
72
|
+
// No `target`: a STANDALONE <kai-message> must not anchor its copy/feedback
|
|
73
|
+
// toast to the individual message (that lands mid-thread in a compose-your-own
|
|
74
|
+
// list). Let them route to the global region (top of the viewport), which is
|
|
75
|
+
// where a confirmation belongs across a hand-built thread. (Inside <kai-chat>
|
|
76
|
+
// the chat owns feedback and targets ITSELF, so in-chat toasts still stay in-chat.)
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Imperative method API — `copy()` runs the exact path of the built-in copy
|
|
80
|
+
// action (`feedback.handleAction(msg, 'copy')`): writes the content to the
|
|
81
|
+
// clipboard, shows the transient copied-check on the bar, and emits
|
|
82
|
+
// `kai-message-action{action:'copy'}`.
|
|
83
|
+
expose({
|
|
84
|
+
/** Copy the message content to the clipboard and show the copied check. */
|
|
85
|
+
copy: () => feedback.handleAction(msg(), 'copy'),
|
|
86
|
+
});
|
|
61
87
|
|
|
62
88
|
// Read declarative <kai-action> children from light DOM.
|
|
63
89
|
// Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
|
|
64
90
|
const [slottedActions, setSlottedActions] = createSignal<import('../elements/chat-types').CustomAction[]>([]);
|
|
91
|
+
// Which composition slots (before-body / after-body / avatar) the consumer filled.
|
|
92
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
65
93
|
onMount(() => {
|
|
66
94
|
const read = () => {
|
|
67
95
|
const nodes = [...element.querySelectorAll('kai-action')];
|
|
@@ -71,6 +99,7 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
71
99
|
icon: n.getAttribute('icon') ?? undefined,
|
|
72
100
|
tooltip: n.getAttribute('tooltip') ?? undefined,
|
|
73
101
|
})));
|
|
102
|
+
setSlots(readSlots(element, MESSAGE_SLOTS));
|
|
74
103
|
};
|
|
75
104
|
read();
|
|
76
105
|
const observer = new MutationObserver(read);
|
|
@@ -83,56 +112,58 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
83
112
|
(props.avatarSrc || props.avatarFallback
|
|
84
113
|
? { src: props.avatarSrc as string | undefined, fallback: props.avatarFallback as string | undefined }
|
|
85
114
|
: undefined);
|
|
115
|
+
// Avatar rail state. `avatar="none"` omits the rail; a filled `slot="avatar"`
|
|
116
|
+
// REPLACES the built-in; otherwise the built-in renders when one resolves.
|
|
117
|
+
const noAvatar = () => props.avatar === 'none';
|
|
118
|
+
const hasAvatarSlot = () => !!slots()['avatar'];
|
|
119
|
+
// The rail shows when not suppressed and there's either a slot or a resolved avatar.
|
|
120
|
+
const showRail = () => !noAvatar() && (hasAvatarSlot() || !!avatar());
|
|
86
121
|
const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
|
|
87
122
|
// markdown: explicit prop/attribute wins; otherwise default by role.
|
|
88
123
|
const markdownExplicit = () =>
|
|
89
124
|
element.hasAttribute('markdown') || props.markdown === true || props.markdown === false;
|
|
90
125
|
const useMarkdown = () => (markdownExplicit() ? flag('markdown') : !isUser());
|
|
91
126
|
|
|
127
|
+
const mergedActions = () => [...(msg().actions ?? []), ...slottedActions()];
|
|
92
128
|
const body = () => (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<AttachmentPreview />
|
|
109
|
-
<AttachmentInfo />
|
|
110
|
-
</Attachment>
|
|
111
|
-
)}
|
|
112
|
-
</For>
|
|
113
|
-
</Attachments>
|
|
114
|
-
</Show>
|
|
115
|
-
<MessageContent
|
|
116
|
-
markdown={useMarkdown()}
|
|
117
|
-
class={isUser()
|
|
118
|
-
? 'bg-muted text-primary max-w-[85%] rounded-2xl px-4 py-2'
|
|
119
|
-
: 'bg-transparent p-0'}
|
|
120
|
-
>
|
|
121
|
-
{msg().content}
|
|
122
|
-
</MessageContent>
|
|
123
|
-
<Show when={(msg().actions?.length ?? 0) > 0 || slottedActions().length > 0}>
|
|
124
|
-
<MessageActionBar
|
|
125
|
-
actions={[...(msg().actions ?? []), ...slottedActions()]}
|
|
126
|
-
reveal={reveal()}
|
|
127
|
-
onAction={(action) => dispatch('kai-message-action', { messageId: msg().id, action })}
|
|
128
|
-
/>
|
|
129
|
-
</Show>
|
|
130
|
-
</>
|
|
129
|
+
<MessageBody
|
|
130
|
+
content={msg().content}
|
|
131
|
+
reasoning={msg().reasoning}
|
|
132
|
+
tools={msg().tools}
|
|
133
|
+
attachments={msg().attachments}
|
|
134
|
+
isUser={isUser()}
|
|
135
|
+
markdown={useMarkdown()}
|
|
136
|
+
actions={mergedActions()}
|
|
137
|
+
actionsReveal={reveal()}
|
|
138
|
+
activeFeedback={feedback.resolveFeedback(msg())}
|
|
139
|
+
copied={feedback.isCopied(msg().id)}
|
|
140
|
+
onAction={(action) => feedback.handleAction(msg(), action)}
|
|
141
|
+
beforeBody={slots()['before-body'] ? <slot name="before-body" /> : undefined}
|
|
142
|
+
afterBody={slots()['after-body'] ? <slot name="after-body" /> : undefined}
|
|
143
|
+
/>
|
|
131
144
|
);
|
|
132
145
|
|
|
133
146
|
// Row carries `group` so a hover-revealed action bar fades in on row hover.
|
|
134
147
|
const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
|
|
135
148
|
|
|
149
|
+
// The avatar rail: a filled `slot="avatar"` REPLACES the built-in MessageAvatar
|
|
150
|
+
// (the consumer owns that node, wrapped in `part="avatar"` so it's still
|
|
151
|
+
// styleable + consistent with the built-in part name).
|
|
152
|
+
const avatarRail = () => (
|
|
153
|
+
<Show
|
|
154
|
+
when={hasAvatarSlot()}
|
|
155
|
+
fallback={
|
|
156
|
+
<Show when={avatar()}>
|
|
157
|
+
{(av) => <MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />}
|
|
158
|
+
</Show>
|
|
159
|
+
}
|
|
160
|
+
>
|
|
161
|
+
<div part="avatar" class="shrink-0">
|
|
162
|
+
<slot name="avatar" />
|
|
163
|
+
</div>
|
|
164
|
+
</Show>
|
|
165
|
+
);
|
|
166
|
+
|
|
136
167
|
return (
|
|
137
168
|
<ChatConfig
|
|
138
169
|
proseSize={props.proseSize}
|
|
@@ -141,21 +172,19 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
141
172
|
portalMount={outer.portalMount()}
|
|
142
173
|
>
|
|
143
174
|
<Show
|
|
144
|
-
when={
|
|
175
|
+
when={showRail()}
|
|
145
176
|
fallback={
|
|
146
177
|
<Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
|
|
147
178
|
{body()}
|
|
148
179
|
</Message>
|
|
149
180
|
}
|
|
150
181
|
>
|
|
151
|
-
{(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
</Message>
|
|
158
|
-
)}
|
|
182
|
+
<Message class={rowGroup()}>
|
|
183
|
+
{avatarRail()}
|
|
184
|
+
<div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
|
|
185
|
+
{body()}
|
|
186
|
+
</div>
|
|
187
|
+
</Message>
|
|
159
188
|
</Show>
|
|
160
189
|
</ChatConfig>
|
|
161
190
|
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
3
|
import { ModelSwitcher } from '../components/model-switcher';
|
|
4
|
+
import { wireDisclosure } from './disclosure';
|
|
5
|
+
import type { DropdownController } from '../ui/dropdown';
|
|
4
6
|
import type { ModelOption } from '../types';
|
|
5
7
|
|
|
6
8
|
interface Props extends Record<string, unknown> {
|
|
@@ -8,12 +10,22 @@ interface Props extends Record<string, unknown> {
|
|
|
8
10
|
models: ModelOption[];
|
|
9
11
|
/** The currently-selected model id. Defaults to the first model. */
|
|
10
12
|
currentModel?: string;
|
|
13
|
+
/** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
|
|
14
|
+
* to the `open` attribute, the dropdown still self-manages on click/keyboard).
|
|
15
|
+
* Set `el.open = true`, or `<kai-model-switcher open>`; listen for `kai-open-change`. */
|
|
16
|
+
open?: boolean;
|
|
17
|
+
/** Initial open state on mount (uncontrolled seed). */
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
/** Disable the trigger — click/keyboard and `show()` no longer open the dropdown. */
|
|
20
|
+
disabled?: boolean;
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
/** Events fired by `<kai-model-switcher>`. */
|
|
14
24
|
interface Events {
|
|
15
25
|
/** A model was selected. */
|
|
16
26
|
'kai-model-change': { modelId: string };
|
|
27
|
+
/** The model dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). */
|
|
28
|
+
'kai-open-change': { open: boolean };
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
/**
|
|
@@ -65,7 +77,18 @@ export function parseKaiModelElement(n: Element): ModelOption {
|
|
|
65
77
|
defineWebComponent<Props, Events>('kai-model-switcher', {
|
|
66
78
|
models: [],
|
|
67
79
|
currentModel: undefined,
|
|
68
|
-
|
|
80
|
+
open: undefined,
|
|
81
|
+
defaultOpen: undefined,
|
|
82
|
+
disabled: undefined,
|
|
83
|
+
}, (props, ctx) => {
|
|
84
|
+
const { dispatch, element, flag } = ctx;
|
|
85
|
+
let api: DropdownController | undefined;
|
|
86
|
+
|
|
87
|
+
// The standard overlay surface: settable+reflecting `open`, kai-open-change,
|
|
88
|
+
// show/hide/toggle, disabled-gating. See ./disclosure. When <=1 model the inner
|
|
89
|
+
// Dropdown never mounts, so `api` stays undefined and these methods no-op.
|
|
90
|
+
wireDisclosure(ctx, () => api, () => props.open);
|
|
91
|
+
|
|
69
92
|
// Read declarative <kai-model> children from light DOM.
|
|
70
93
|
// Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
|
|
71
94
|
const [slottedModels, setSlottedModels] = createSignal<ModelOption[]>([]);
|
|
@@ -88,6 +111,9 @@ defineWebComponent<Props, Events>('kai-model-switcher', {
|
|
|
88
111
|
models={allModels()}
|
|
89
112
|
currentModelId={props.currentModel ?? allModels()[0]?.id ?? ''}
|
|
90
113
|
onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
|
|
114
|
+
defaultOpen={flag('defaultOpen')}
|
|
115
|
+
disabled={flag('disabled')}
|
|
116
|
+
controllerRef={(a) => (api = a)}
|
|
91
117
|
/>
|
|
92
118
|
);
|
|
93
119
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createSignal } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { Nav, type KaiNavItem } from '../ui/nav';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** The nav items. Set as a JS property (array, not an attribute). Each item may
|
|
7
|
+
* carry `children` (a collapsible group), a `status` dot, and trailing `meta`
|
|
8
|
+
* text. */
|
|
9
|
+
items?: KaiNavItem[];
|
|
10
|
+
/** Active item id (controlled). */
|
|
11
|
+
value?: string;
|
|
12
|
+
/** Initial active id when uncontrolled. */
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
/** Ids of group items collapsed on first render (groups default to expanded).
|
|
15
|
+
* Set as a JS property (array). */
|
|
16
|
+
defaultCollapsed?: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Events {
|
|
20
|
+
/** A nav item was activated. */
|
|
21
|
+
'kai-nav-select': { id: string };
|
|
22
|
+
/** A row's trailing `action` button was activated (not a select). `value` is
|
|
23
|
+
* the item id; `action` echoes the item's `{ icon, label }`. */
|
|
24
|
+
'kai-nav-item-action': { value: string; action?: { icon: string; label: string } };
|
|
25
|
+
/** A `closable` row's trailing close button was activated (not a select).
|
|
26
|
+
* `value` is the item id. */
|
|
27
|
+
'kai-nav-item-close': { value: string };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `<kai-nav>` — a vertical navigation list driven by a JSON `items` tree
|
|
32
|
+
* (id + label + optional leading `icon`, a trailing text `badge`, a trailing
|
|
33
|
+
* icon). Items may nest via `children` (a collapsible group with a disclosure
|
|
34
|
+
* chevron), carry a `status` dot (`{ tone, label?, pulse? }`), and a trailing
|
|
35
|
+
* `meta` string (e.g. a relative time). The active item is `value`; selecting a
|
|
36
|
+
* leaf fires `kai-nav-select` (group rows toggle expand/collapse instead).
|
|
37
|
+
*
|
|
38
|
+
* Items may also carry an `action` (`{ icon, label }`) or `closable: true`, which
|
|
39
|
+
* render a trailing button — firing `kai-nav-item-action` `{ value, action }` or
|
|
40
|
+
* `kai-nav-item-close` `{ value }` (never `kai-nav-select`). Style it via
|
|
41
|
+
* `::part(item-action)`.
|
|
42
|
+
*
|
|
43
|
+
* ```html
|
|
44
|
+
* <kai-nav default-value="home"></kai-nav>
|
|
45
|
+
* <script type="module">
|
|
46
|
+
* const nav = document.querySelector('kai-nav');
|
|
47
|
+
* nav.items = [
|
|
48
|
+
* { id: 'home', label: 'New task', icon: 'plus', trailing: 'pencil' },
|
|
49
|
+
* { id: 'acme', label: 'Acme', icon: 'folder', children: [
|
|
50
|
+
* { id: 't1', label: 'Refactor auth', status: { tone: 'info', label: 'Working', pulse: true }, meta: '2m' },
|
|
51
|
+
* { id: 't2', label: 'Landing page', status: { tone: 'success', label: 'Done' }, meta: '1d' },
|
|
52
|
+
* ] },
|
|
53
|
+
* { id: 'dispatch', label: 'Dispatch', icon: 'share', badge: 'Beta' },
|
|
54
|
+
* ];
|
|
55
|
+
* nav.addEventListener('kai-nav-select', (e) => console.log(e.detail.id));
|
|
56
|
+
* </script>
|
|
57
|
+
* ```
|
|
58
|
+
* Restyle via `::part(nav)` / `::part(item)` (active items carry `aria-current`),
|
|
59
|
+
* plus `::part(group)` / `::part(chevron)` / `::part(status)` / `::part(meta)`.
|
|
60
|
+
*/
|
|
61
|
+
defineWebComponent<Props, Events>('kai-nav', {
|
|
62
|
+
items: undefined,
|
|
63
|
+
value: undefined,
|
|
64
|
+
defaultValue: undefined,
|
|
65
|
+
defaultCollapsed: undefined,
|
|
66
|
+
}, (props, { dispatch, expose }) => {
|
|
67
|
+
const [internal, setInternal] = createSignal(props.defaultValue as string | undefined);
|
|
68
|
+
const value = () => (props.value as string | undefined) ?? internal();
|
|
69
|
+
const select = (id: string) => { setInternal(id); dispatch('kai-nav-select', { id }); };
|
|
70
|
+
|
|
71
|
+
expose({
|
|
72
|
+
/** Activate an item by id (fires kai-nav-select). */
|
|
73
|
+
select: (id: string) => select(id),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Nav
|
|
78
|
+
items={props.items as KaiNavItem[] | undefined}
|
|
79
|
+
value={value()}
|
|
80
|
+
defaultCollapsed={props.defaultCollapsed as string[] | undefined}
|
|
81
|
+
onItemSelect={select}
|
|
82
|
+
onItemAction={(id, action) => dispatch('kai-nav-item-action', { value: id, action })}
|
|
83
|
+
onItemClose={(id) => dispatch('kai-nav-item-close', { value: id })}
|
|
84
|
+
part="nav"
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Notice, noticeIconNode } from '../ui/notice';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
|
|
4
|
+
interface Props extends Record<string, unknown> {
|
|
5
|
+
/** `neutral` (default) · `info` · `warning` · `error` · `success`. Drives the
|
|
6
|
+
* leading icon's color and the a11y role (`alert` for errors, else `status`). */
|
|
7
|
+
severity?: 'neutral' | 'info' | 'warning' | 'error' | 'success';
|
|
8
|
+
/** Leading icon: omit for the severity default, `"none"` to hide it, or a named
|
|
9
|
+
* icon to override. */
|
|
10
|
+
icon?: string;
|
|
11
|
+
/** Show a dismiss (×) that hides the notice and emits `kai-dismiss`. */
|
|
12
|
+
dismissible?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Events fired by `<kai-notice>`. */
|
|
16
|
+
interface Events {
|
|
17
|
+
/** The notice was dismissed via its × (it also hides itself). */
|
|
18
|
+
'kai-dismiss': void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `<kai-notice>` — a self-contained inline notice / alert. Put the message as
|
|
23
|
+
* light-DOM text and an optional `slot="action"` (e.g. a link); it carries the
|
|
24
|
+
* severity icon, the right a11y role, and an optional self-dismissing ×.
|
|
25
|
+
*
|
|
26
|
+
* It owns the notice box, not its placement — you position it in your own layout
|
|
27
|
+
* (above a composer, at the top of a panel, …).
|
|
28
|
+
*
|
|
29
|
+
* For a custom leading icon, slot any inline SVG via `slot="icon"` (it wins over
|
|
30
|
+
* the severity/`icon` default — the same escape hatch as `kai-button`).
|
|
31
|
+
*
|
|
32
|
+
* ```html
|
|
33
|
+
* <kai-notice severity="warning" dismissible>
|
|
34
|
+
* Claude Fable 5 is currently unavailable.
|
|
35
|
+
* <a slot="action" href="#">Learn more</a>
|
|
36
|
+
* </kai-notice>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
defineWebComponent<Props, Events>('kai-notice', {
|
|
40
|
+
severity: 'neutral',
|
|
41
|
+
icon: undefined,
|
|
42
|
+
dismissible: false,
|
|
43
|
+
}, (props, { dispatch, flag }) => (
|
|
44
|
+
<Notice
|
|
45
|
+
severity={props.severity ?? 'neutral'}
|
|
46
|
+
iconSlot={<slot name="icon">{noticeIconNode(props.severity ?? 'neutral', props.icon)}</slot>}
|
|
47
|
+
dismissible={flag('dismissible')}
|
|
48
|
+
onDismiss={() => dispatch('kai-dismiss')}
|
|
49
|
+
action={<slot name="action" />}
|
|
50
|
+
>
|
|
51
|
+
<slot />
|
|
52
|
+
</Notice>
|
|
53
|
+
));
|