@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
package/dist/llms/llms.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- AUTO-GENERATED by scripts/gen-llms.mjs — do not edit by hand. Run `npm run build`. -->
|
|
2
2
|
# @kitn.ai/ui
|
|
3
3
|
|
|
4
|
-
> Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML.
|
|
4
|
+
> Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. 78 custom elements, every one prefixed `kai-` (e.g. `<kai-chat>`, `<kai-artifact>`): streaming responses, markdown + code rendering, reasoning/tool panels, attachments, conversation sidebar, voice input. Zero framework dependency for consumers; the SolidJS runtime it is authored in is bundled in, so the host needs nothing.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ npm install solid-js
|
|
|
13
13
|
|
|
14
14
|
## #1 rule: array/object data goes on JS PROPERTIES, not HTML attributes
|
|
15
15
|
|
|
16
|
-
This is the single most common mistake. Arrays and objects (`messages`, `models`, `context`, `suggestions`, `
|
|
16
|
+
This is the single most common mistake. Arrays and objects (`messages`, `models`, `context`, `suggestions`, `triggers`, …) MUST be assigned as JavaScript properties on the element. They CANNOT be passed as HTML attributes — an HTML attribute is always a string and will be ignored or mis-parsed.
|
|
17
17
|
|
|
18
18
|
```js
|
|
19
19
|
const chat = document.querySelector('kai-chat');
|
|
@@ -35,7 +35,7 @@ Drop an element into any framework (React, Vue, plain HTML). Data in via JS prop
|
|
|
35
35
|
- `<kai-prompt-input>` — standalone composer with send button.
|
|
36
36
|
|
|
37
37
|
**Layer 2 — composable primitives** (`import { … } from '@kitn.ai/ui'`):
|
|
38
|
-
All
|
|
38
|
+
All 78 elements are also exported individually. Use them for custom layouts or features `<kai-chat>` does not expose (ChainOfThought, FeedbackBar, ThinkingBar, VoiceInput, …). Your bundler tree-shakes the rest.
|
|
39
39
|
|
|
40
40
|
## Key rules for the web components
|
|
41
41
|
|
|
@@ -97,7 +97,7 @@ For Tailwind builds: `@import "@kitn.ai/ui/theme.css"` in your CSS.
|
|
|
97
97
|
|
|
98
98
|
## Docs
|
|
99
99
|
|
|
100
|
-
- Full element reference (all
|
|
100
|
+
- Full element reference (all 78 elements, every prop/event): ./llms-full.txt — https://kitn.dev/llms-full.txt
|
|
101
101
|
- Machine-readable Custom Elements Manifest: https://unpkg.com/@kitn.ai/ui/dist/custom-elements.json
|
|
102
102
|
- Working examples: https://github.com/kitn-ai/ui/tree/main/examples
|
|
103
103
|
- Storybook: https://storybook.kitn.dev
|
package/dist/mcp.es.js
CHANGED
|
@@ -113,6 +113,33 @@ Call component_reference with no name (or name: "list") to list all ${all.length
|
|
|
113
113
|
lines.push(`- **${prop.name}**${def}${desc ? ` — ${desc}` : ""}`);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
+
const slots = el.slots ?? [];
|
|
117
|
+
if (slots.length > 0) {
|
|
118
|
+
lines.push(
|
|
119
|
+
"",
|
|
120
|
+
"### Composition slots",
|
|
121
|
+
'Project your own markup into these named regions — add a light-DOM child with a `slot="…"` attribute (e.g. `<div slot="sidebar">…</div>`).'
|
|
122
|
+
);
|
|
123
|
+
for (const slot of slots) {
|
|
124
|
+
const desc = slot.description?.trim() ?? "";
|
|
125
|
+
lines.push(`- **${slot.name}**${desc ? ` — ${desc}` : ""}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const parts = el.cssParts ?? [];
|
|
129
|
+
if (parts.length > 0) {
|
|
130
|
+
lines.push(
|
|
131
|
+
"",
|
|
132
|
+
"### Styleable parts (`::part`)",
|
|
133
|
+
"Restyle these from outside the Shadow DOM via `" + tag + "::part(name) { … }`."
|
|
134
|
+
);
|
|
135
|
+
for (const part of parts) {
|
|
136
|
+
const desc = part.description?.trim() ?? "";
|
|
137
|
+
lines.push(`- **${part.name}**${desc ? ` — ${desc}` : ""}`);
|
|
138
|
+
if (part.recipe) {
|
|
139
|
+
lines.push(" ```css", ` ${part.recipe}`, " ```");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
116
143
|
return lines.join("\n");
|
|
117
144
|
}
|
|
118
145
|
const reference = {
|
|
@@ -1678,7 +1705,139 @@ function compose(archetype, integration, placement, framework, suggestions, audi
|
|
|
1678
1705
|
`Env vars to set:`,
|
|
1679
1706
|
envLines
|
|
1680
1707
|
].join("\n");
|
|
1681
|
-
|
|
1708
|
+
const block4 = [
|
|
1709
|
+
`=== LOADING OPTIONS ===`,
|
|
1710
|
+
``,
|
|
1711
|
+
`The scaffold uses \`import '@kitn.ai/ui/elements'\` (register-all) — the right`,
|
|
1712
|
+
`default: it registers every kai-* element and is SSR-safe, so leave it as is.`,
|
|
1713
|
+
`Two opt-in modes load less if a page only ever uses a few elements:`,
|
|
1714
|
+
``,
|
|
1715
|
+
` Per-element (bundler apps): import '@kitn.ai/ui/elements/<file>'`,
|
|
1716
|
+
` Registers just that element; your bundler tree-shakes the rest away.`,
|
|
1717
|
+
` Example: import '@kitn.ai/ui/elements/chat' (client-only — not for SSR)`,
|
|
1718
|
+
``,
|
|
1719
|
+
` Autoloader (no-build / CDN pages): a <script type="module"> tag pointing at`,
|
|
1720
|
+
` dist/elements/autoloader.js — loads each kai-* element on demand as it`,
|
|
1721
|
+
` appears in the DOM. A CDN/static-file tool; not importable through a bundler.`,
|
|
1722
|
+
``,
|
|
1723
|
+
`Run the debug tool with "reduce bundle size" for the full breakdown and sizes.`
|
|
1724
|
+
].join("\n");
|
|
1725
|
+
const block5 = interactionPatternsBlock();
|
|
1726
|
+
return [header, block1, block2, block3, block4, block5].join("\n\n");
|
|
1727
|
+
}
|
|
1728
|
+
function interactionPatternsBlock() {
|
|
1729
|
+
const toastPattern = [
|
|
1730
|
+
`--- Pattern: toast() — confirmation + Undo ---`,
|
|
1731
|
+
`// toast is IMPERATIVE — call it; there is no <kai-toast> to place. The first`,
|
|
1732
|
+
`// call auto-mounts one <kai-toast-region> on document.body. Exported from`,
|
|
1733
|
+
`// both '@kitn.ai/ui' and '@kitn.ai/ui/elements'.`,
|
|
1734
|
+
`import { toast } from '@kitn.ai/ui/elements';`,
|
|
1735
|
+
``,
|
|
1736
|
+
`toast('Copied to clipboard'); // neutral, auto-dismisses`,
|
|
1737
|
+
`toast.success('Saved'); // emerald success variant`,
|
|
1738
|
+
``,
|
|
1739
|
+
`// Undo affordance: an action floors the duration so there's time to act.`,
|
|
1740
|
+
`const t = toast('Item deleted', {`,
|
|
1741
|
+
` action: { label: 'Undo', onAction: () => restoreItem() },`,
|
|
1742
|
+
`});`,
|
|
1743
|
+
`// t.update({ message: 'Restored', variant: 'success' }); t.dismiss();`,
|
|
1744
|
+
``,
|
|
1745
|
+
`// Collapsed (Sonner-style) stacking — toasts pile + expand on hover/focus.`,
|
|
1746
|
+
`// Opt in once at startup, or per-region via <kai-toast-region stack="collapsed">.`,
|
|
1747
|
+
`import { configureToasts } from '@kitn.ai/ui/elements';`,
|
|
1748
|
+
`configureToasts({ stack: 'collapsed' });`
|
|
1749
|
+
].join("\n");
|
|
1750
|
+
const recoveryPattern = [
|
|
1751
|
+
`--- Pattern: dismissRecovery() — card dismiss + Undo (DEFERRED, not deleted) ---`,
|
|
1752
|
+
`// Dismissing a generative-UI card does NOT delete its envelope — it stamps a`,
|
|
1753
|
+
`// 'dismissed' resolution and collapses to a reopenable stub. Keep dismissed`,
|
|
1754
|
+
`// envelopes in your array; wire the policy with dismissRecovery().`,
|
|
1755
|
+
`import { dismissRecovery } from '@kitn.ai/ui';`,
|
|
1756
|
+
`import { toast } from '@kitn.ai/ui/elements';`,
|
|
1757
|
+
``,
|
|
1758
|
+
`// Adapter: map dismissRecovery's toast shape onto the imperative toast().`,
|
|
1759
|
+
`const toastAdapter = {`,
|
|
1760
|
+
` show: ({ message, action, durationMs }) => {`,
|
|
1761
|
+
` const h = toast(message, {`,
|
|
1762
|
+
` duration: durationMs,`,
|
|
1763
|
+
` action: action && { label: action.label, onAction: action.onClick },`,
|
|
1764
|
+
` });`,
|
|
1765
|
+
` return { dismiss: h.dismiss };`,
|
|
1766
|
+
` },`,
|
|
1767
|
+
`};`,
|
|
1768
|
+
``,
|
|
1769
|
+
`const { onDismiss, onReopen } = dismissRecovery({`,
|
|
1770
|
+
` get: () => cards, // your current envelopes`,
|
|
1771
|
+
` set: (next) => setCards(next), // a NEW array reference (never mutate in place)`,
|
|
1772
|
+
` toast: toastAdapter,`,
|
|
1773
|
+
`});`,
|
|
1774
|
+
`// Hand { onDismiss, onReopen } to the CardPolicy on <kai-cards> / <kai-remote>.`
|
|
1775
|
+
].join("\n");
|
|
1776
|
+
const preferencePattern = [
|
|
1777
|
+
`--- Pattern: kai-compare — capture an A/B preference pair ---`,
|
|
1778
|
+
`// <kai-compare> shows EXACTLY two candidates for one prompt. data is a JS`,
|
|
1779
|
+
`// PROPERTY; stream both columns with a fresh data ref per chunk; picking is`,
|
|
1780
|
+
`// terminal and fires kai-compare-select { chosenId, rejectedIds }.`,
|
|
1781
|
+
`import type { ResponseCompareData, CompareSelection } from '@kitn.ai/ui';`,
|
|
1782
|
+
``,
|
|
1783
|
+
`const el = document.querySelector('kai-compare')!;`,
|
|
1784
|
+
`el.data = {`,
|
|
1785
|
+
` prompt,`,
|
|
1786
|
+
` candidates: [`,
|
|
1787
|
+
` { id: 'a', content: '', streaming: true },`,
|
|
1788
|
+
` { id: 'b', content: '', streaming: true },`,
|
|
1789
|
+
` ],`,
|
|
1790
|
+
`} satisfies ResponseCompareData;`,
|
|
1791
|
+
``,
|
|
1792
|
+
`// Stream BOTH: replace data with a NEW object per chunk; clear streaming when`,
|
|
1793
|
+
`// a candidate settles. The pick unlocks once both have settled (kai-ready).`,
|
|
1794
|
+
`// el.data = { ...el.data, candidates: [{ ...a, content: aText }, { ...b, content: bText }] };`,
|
|
1795
|
+
``,
|
|
1796
|
+
`el.addEventListener('kai-compare-select', (e) => {`,
|
|
1797
|
+
` const { chosenId, rejectedIds } = (e as CustomEvent<CompareSelection>).detail;`,
|
|
1798
|
+
` recordPreference({ prompt, chosen: chosenId, rejected: rejectedIds });`,
|
|
1799
|
+
`});`
|
|
1800
|
+
].join("\n");
|
|
1801
|
+
const statePattern = [
|
|
1802
|
+
`--- Pattern: State helpers + streaming (new-array contract) ---`,
|
|
1803
|
+
`// Setter contract: always (prev) => next — every helper returns a new array.`,
|
|
1804
|
+
`// Vanilla adapter (works with any element ref):`,
|
|
1805
|
+
`// const set = (fn) => { el.messages = fn(el.messages ?? []); };`,
|
|
1806
|
+
``,
|
|
1807
|
+
`// Low-level helpers from @kitn.ai/ui/state:`,
|
|
1808
|
+
`// import { appendMessage, updateMessage, appendContent, createAssistantStream } from '@kitn.ai/ui/state';`,
|
|
1809
|
+
``,
|
|
1810
|
+
`// Streaming loop (framework-agnostic):`,
|
|
1811
|
+
`// const stream = createAssistantStream(set);`,
|
|
1812
|
+
`// stream.appendText(chunk); // text delta`,
|
|
1813
|
+
`// stream.appendReasoning(chunk); // reasoning delta`,
|
|
1814
|
+
`// stream.upsertTool(toolCall); // tool call delta`,
|
|
1815
|
+
`// stream.done(); // seal the message`,
|
|
1816
|
+
``,
|
|
1817
|
+
`// One-liner for React (batteries-included):`,
|
|
1818
|
+
`// import { useKaiChat } from '@kitn.ai/ui/react';`,
|
|
1819
|
+
`// const chat = useKaiChat();`,
|
|
1820
|
+
`// <Chat {...chat.bind} />`,
|
|
1821
|
+
``,
|
|
1822
|
+
`// One-liner for Solid (batteries-included):`,
|
|
1823
|
+
`// import { createKaiChat } from '@kitn.ai/ui';`,
|
|
1824
|
+
`// const chat = createKaiChat();`,
|
|
1825
|
+
`// <kai-chat {...chat.bind} on:kai-submit={chat.handleSubmit} />`
|
|
1826
|
+
].join("\n");
|
|
1827
|
+
return [
|
|
1828
|
+
`=== INTERACTION PATTERNS ===`,
|
|
1829
|
+
``,
|
|
1830
|
+
`Optional snippets for confirmations, card recovery, preference capture, and state/streaming helpers.`,
|
|
1831
|
+
`Drop in the one(s) you need; all imports resolve from @kitn.ai/ui.`,
|
|
1832
|
+
``,
|
|
1833
|
+
toastPattern,
|
|
1834
|
+
``,
|
|
1835
|
+
recoveryPattern,
|
|
1836
|
+
``,
|
|
1837
|
+
preferencePattern,
|
|
1838
|
+
``,
|
|
1839
|
+
statePattern
|
|
1840
|
+
].join("\n");
|
|
1682
1841
|
}
|
|
1683
1842
|
function rejectIntegration(id) {
|
|
1684
1843
|
const valid = listIntegrations().map((i) => `${i.id} (${i.title})`).join(", ");
|
|
@@ -1977,9 +2136,9 @@ const RULES = [
|
|
|
1977
2136
|
// Rule 1 — array/object data set as an HTML attribute
|
|
1978
2137
|
// Source: for-ai-agents.mdx §1; context7.json rule 2
|
|
1979
2138
|
id: "array-as-attribute",
|
|
1980
|
-
test: (t) => /\b(messages|models|context|suggestions|
|
|
2139
|
+
test: (t) => /\b(messages|models|context|suggestions|triggers)\s*=\s*["']/.test(t),
|
|
1981
2140
|
title: "Array/object prop set as an HTML attribute (silent failure)",
|
|
1982
|
-
cause: "An HTML attribute is always a string. Passing `messages`, `models`, `context`, `suggestions`, or `
|
|
2141
|
+
cause: "An HTML attribute is always a string. Passing `messages`, `models`, `context`, `suggestions`, or `triggers` as an HTML attribute silently fails — the element receives a stringified value it cannot parse.",
|
|
1983
2142
|
fix: "Set the property in JavaScript, not as an HTML attribute. Only scalar props (`placeholder`, `loading`, `theme`) work as attributes.\n\n```js\n// ✅ Works — set messages in JavaScript as a property\nconst chat = document.querySelector('kai-chat');\nchat.messages = [{ id: '1', role: 'assistant', content: 'Hello!' }];\n```\n\n```html\n<!-- ❌ Fails — messages cannot be an HTML attribute -->\n<kai-chat messages=\"[...]\"></kai-chat>\n```"
|
|
1984
2143
|
},
|
|
1985
2144
|
{
|
|
@@ -1989,7 +2148,7 @@ const RULES = [
|
|
|
1989
2148
|
test: (t) => /don'?t\s+update|doesn'?t\s+re.?render|no\s+re.?render|\.push\(|\bpush(?:es|ing)?\s+(?:to|into|onto)\b|mutate|in.place/.test(t),
|
|
1990
2149
|
title: "In-place mutation does not trigger a re-render",
|
|
1991
2150
|
cause: "Mutating an existing message object or array in place (e.g. `chat.messages.push(…)` or `chat.messages[i].content = …`) does not trigger a re-render. The element only reacts when it detects a new array/object reference.",
|
|
1992
|
-
fix: "Assign a NEW array (and a new object) on every change — never mutate in place.\n\n```js\n// ✅ Triggers re-render — new array + new object reference\nchat.messages = [\n ...chat.messages,\n { id: crypto.randomUUID(), role: 'user', content: userText },\n];\n\n// ✅ During streaming — replace with a new array + new object on every chunk\nchat.messages = chat.messages.map((m) =>\n m.id === assistantId ? { ...m, content: accumulated } : m\n);\n\n// ❌ Does NOT trigger re-render\nchat.messages.push(newMsg);\nchat.messages[i].content = accumulated;\n
|
|
2151
|
+
fix: "Assign a NEW array (and a new object) on every change — never mutate in place.\n\n```js\n// ✅ Triggers re-render — new array + new object reference\nchat.messages = [\n ...chat.messages,\n { id: crypto.randomUUID(), role: 'user', content: userText },\n];\n\n// ✅ During streaming — replace with a new array + new object on every chunk\nchat.messages = chat.messages.map((m) =>\n m.id === assistantId ? { ...m, content: accumulated } : m\n);\n\n// ❌ Does NOT trigger re-render\nchat.messages.push(newMsg);\nchat.messages[i].content = accumulated;\n```\n\nThe ergonomic path: helpers in `@kitn.ai/ui/state` (`appendMessage`, `updateMessage`, `appendContent`) and `createAssistantStream` handle the new-reference contract for you. `useKaiChat` (React) and `createKaiChat` (Solid) own state entirely so mutation is never an option.\n\n// setMessages((m) => appendMessage(m, msg)) // new array, no footgun"
|
|
1993
2152
|
},
|
|
1994
2153
|
{
|
|
1995
2154
|
// Rule 3 — listening for events on a parent / wrong element
|
|
@@ -2008,8 +2167,8 @@ const RULES = [
|
|
|
2008
2167
|
id: "wrong-prefix",
|
|
2009
2168
|
test: (t) => /\bkitn-/.test(t),
|
|
2010
2169
|
title: "Wrong element prefix `kitn-` (should be `kai-`)",
|
|
2011
|
-
cause: "The custom element prefix is `kai-` (e.g. `<kai-chat>`, `<kai-artifact>`). `kitn
|
|
2012
|
-
fix: "Replace the `kitn-` prefix with `kai-` everywhere.\n\n```html\n<!-- ✅ Correct element prefix -->\n<kai-chat></kai-chat>\n<kai-artifact></kai-artifact>\n\n<!-- ❌ Wrong — kitn-chat is
|
|
2170
|
+
cause: "The custom element prefix is `kai-` (e.g. `<kai-chat>`, `<kai-artifact>`). `kitn-` is a legacy name (the register-all bundle is `kai.es.js`) — it is not a registered element name. Using `<kitn-chat>` results in an unknown element that renders nothing.",
|
|
2171
|
+
fix: "Replace the `kitn-` prefix with `kai-` everywhere.\n\n```html\n<!-- ✅ Correct element prefix -->\n<kai-chat></kai-chat>\n<kai-artifact></kai-artifact>\n\n<!-- ❌ Wrong — kitn-chat is not an element (the bundle is kai.es.js) -->\n<kitn-chat></kitn-chat>\n```"
|
|
2013
2172
|
},
|
|
2014
2173
|
{
|
|
2015
2174
|
// Rule 6 — custom elements not registered / renders nothing (React #1 failure)
|
|
@@ -2053,6 +2212,17 @@ const RULES = [
|
|
|
2053
2212
|
cause: "A plain Vite/CRA React SPA has no server — there are no `/api` routes. A scaffolded Next.js route handler (`export async function POST`) does not run there, so `fetch('/api/chat')` 404s.",
|
|
2054
2213
|
fix: "Either run the backend somewhere real, or skip it entirely for local dev:\n\n```ts\n// Option A — use Next.js where route handlers are supported\n// app/api/chat/route.ts: export async function POST(req) { ... }\n\n// Option B — add a Vite dev-server middleware/proxy\n// vite.config.ts: server: { proxy: { '/api': 'http://localhost:3001' } }\n\n// Option C — run a separate Express/Hono server\n// framework: 'express' in your harness config\n\n// Option D — zero-config local dev with mock integration (no backend needed)\n// Use `integration: 'mock'` in the scaffold tool\n```"
|
|
2055
2214
|
},
|
|
2215
|
+
{
|
|
2216
|
+
// Rule 9 — reduce bundle size / footprint / "how much does @kitn.ai/ui add"
|
|
2217
|
+
// Source: dist/elements/<file>.js per-element exports; dist/autoloader.js
|
|
2218
|
+
id: "bundle-footprint",
|
|
2219
|
+
test: (t) => /bundle\s*size|footprint|tree.?shak|how\s+much.*does.*@kitn|reduce.*import|import.*only.*element|per.?element\s+import|autoload|cdn.*no.?build|no.?build.*cdn/i.test(
|
|
2220
|
+
t
|
|
2221
|
+
),
|
|
2222
|
+
title: "Reducing bundle footprint — three load modes",
|
|
2223
|
+
cause: "The default `import '@kitn.ai/ui/elements'` registers every `kai-*` element. If your page uses only one or two elements, that pulls in the full ~119 KB gz bundle. Two opt-in modes let you load only what you need.",
|
|
2224
|
+
fix: "**Mode 1 — register-all (default, SSR-safe):**\nBest for multi-element apps or any SSR/meta-framework. Load once and every `kai-*` element is available.\n\n```js\nimport '@kitn.ai/ui/elements'; // ~119 KB gz — registers everything\n```\n\n**Mode 2 — per-element import (tree-shaking, bundler apps):**\nUse `import '@kitn.ai/ui/elements/<file>'` to register only one element. A bundler (Vite, webpack, Rollup) will tree-shake to just its chunks (~73 KB gz for `kai-chat` alone). Client-only — do not use in SSR entry points.\n\n```js\n// Registers only <kai-chat> (~73 KB gz vs ~119 KB gz register-all)\nimport '@kitn.ai/ui/elements/chat';\n\n// Other examples:\nimport '@kitn.ai/ui/elements/code-block'; // <kai-code-block>\nimport '@kitn.ai/ui/elements/confirm-card'; // <kai-confirm>\n```\n\nThe file name is the element's source basename from `element-manifest.json` (e.g. `kai-chat` → `chat`, `kai-confirm` → `confirm-card`).\n\n**Mode 3 — autoloader (no-build / CDN pages only):**\nWatches the DOM and dynamically imports each `kai-*` element's module on demand. A page that uses only `<kai-chat>` never downloads the other elements. It is a CDN / static-file tool — load it from a `<script type=\"module\">` tag. It is NOT importable through a bundler: Vite/webpack relocate it and the on-demand imports 404. Client-only.\n\n```html\n<script type=\"module\" src=\"https://cdn.jsdelivr.net/npm/@kitn.ai/ui@<version>/dist/elements/autoloader.js\"><\/script>\n```\n\nIn a BUNDLED app (Vite/webpack/Next) use Mode 1 or Mode 2 instead — not the autoloader.\n\n**SSR note:** use Mode 1 (register-all) in SSR apps — per-element imports and the autoloader are client-only (they call DOM APIs at module eval). Modes 1 & 2 are side-effect imports; keep them even if your linter flags them as \"unused\"."
|
|
2225
|
+
},
|
|
2056
2226
|
{
|
|
2057
2227
|
// Rule 5 — SSR / server component / document is not defined
|
|
2058
2228
|
// Source: for-ai-agents.mdx (client-only import); context7.json rule 2 (property rule requires DOM)
|
|
@@ -2065,6 +2235,47 @@ const RULES = [
|
|
|
2065
2235
|
title: "SSR / server-side rendering — element requires the browser DOM",
|
|
2066
2236
|
cause: '`kai-*` elements are client-side web components. They require `document` and `customElements` to register and render. Importing them in a server component (Next.js App Router server component, Nuxt SSR, etc.) throws "document is not defined" or silently produces no output.',
|
|
2067
2237
|
fix: "Register the element on the client only. Use your framework's \"client-only\" / island / dynamic-import pattern.\n\n```js\n// ✅ Plain HTML / vanilla — import in a <script type=\"module\">\nimport '@kitn.ai/ui/elements';\n\n// ✅ Next.js App Router — mark the component with \"use client\"\n'use client';\nimport '@kitn.ai/ui/elements';\n\n// ✅ Next.js — dynamic import with ssr: false\nimport dynamic from 'next/dynamic';\nconst KaiChat = dynamic(() => import('@kitn.ai/ui/elements').then(() => 'kai-chat'), { ssr: false });\n\n// ✅ React wrapper (already client-safe)\nimport { Chat } from '@kitn.ai/ui/react';\n```"
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
// Rule 10 — toast() is the imperative API; there is no <kai-toast> to place
|
|
2241
|
+
// Source: src/primitives/toast-store.ts (the `toast` fn + auto-mounted region)
|
|
2242
|
+
id: "toast-imperative",
|
|
2243
|
+
test: (t) => {
|
|
2244
|
+
if (/<kai-toast(-region)?\b/.test(t)) return true;
|
|
2245
|
+
if (/\btoast(s)?\b|notification|snackbar/i.test(t) && /how.*(show|raise|trigger|fire|display)|show.*toast|raise.*toast|trigger.*toast|toast.*(not|isn'?t|won'?t).*(show|appear|render)|where.*toast|add.*toast|kai-|@kitn/i.test(t))
|
|
2246
|
+
return true;
|
|
2247
|
+
return false;
|
|
2248
|
+
},
|
|
2249
|
+
title: "Toast is an imperative call — `toast('…')`, not a `<kai-toast>` you place",
|
|
2250
|
+
cause: "Toasts are raised IMPERATIVELY by calling `toast(message)` — there is no `<kai-toast>` element you add to your markup. The first call lazily mounts ONE `<kai-toast-region>` on `document.body` (a real, kit-styled, viewport-positioned element) and every later toast feeds that same region. Trying to place a toast element by hand, or looking for a `messages`/`toasts` prop to push into, is the wrong model.",
|
|
2251
|
+
fix: "Import `toast` and call it. It is exported from BOTH the root `@kitn.ai/ui` and the `@kitn.ai/ui/elements` bundle, so the web-components-only consumer gets it too. It is SSR-safe (no DOM is touched until the first call on the client).\n\n```js\nimport { toast } from '@kitn.ai/ui/elements'; // or '@kitn.ai/ui'\n\n// ✅ Fire-and-forget\ntoast('Copied to clipboard');\ntoast.success('Saved');\n\n// ✅ With an Undo action + an imperative handle\nconst t = toast('Item deleted', {\n action: { label: 'Undo', onAction: () => restore() },\n});\nt.update({ message: 'Restored', variant: 'success' });\nt.dismiss();\n```\n\nThe auto-mounted `<kai-toast-region>` carries its own shadow root + kit styles — do NOT add a `<kai-toast-region>` tag yourself unless you deliberately want a second, declaratively-controlled region."
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
// Rule 11 — dismissed cards are DEFERRED (reopenable stub), not deleted
|
|
2255
|
+
// Source: src/primitives/card-recovery.ts (dismissRecovery) + the dismissed stub
|
|
2256
|
+
id: "card-dismiss-deferred",
|
|
2257
|
+
test: (t) => {
|
|
2258
|
+
const cardCtx = /\bcard(s)?\b|envelope|kai-card|kai-cards|kai-confirm|kai-choice|kai-tasks|kai-form|generative.?ui|resolution|dismissRecovery/i;
|
|
2259
|
+
if (!cardCtx.test(t)) return false;
|
|
2260
|
+
return /dismiss|reopen|re-?open|\bundo\b|disappear|remove.*card|card.*(gone|remove|delete|vanish)|filter.*out|stub/i.test(t);
|
|
2261
|
+
},
|
|
2262
|
+
title: "Dismissed cards are DEFERRED (a reopenable stub), not deleted",
|
|
2263
|
+
cause: "Dismissing a generative-UI card does NOT delete its envelope from history. The card stamps a `{ kind: 'dismissed' }` resolution onto its envelope and collapses to a small reopenable stub (\"Proposed: <title> — dismissed · Reopen\"). If you filter `dismissed` envelopes out of your cards array, the stub vanishes and the user can never reopen it — and you lose the audit trail of what was proposed.",
|
|
2264
|
+
fix: "Keep dismissed envelopes in the array. Wire dismiss/reopen with `dismissRecovery()` (from `@kitn.ai/ui`), which builds the `onDismiss`/`onReopen` half of a `CardPolicy` over your store and can show a \"Dismissed · Undo\" toast via an injected adapter.\n\n```ts\nimport { dismissRecovery } from '@kitn.ai/ui';\nimport { toast } from '@kitn.ai/ui/elements';\n\n// Adapter: map dismissRecovery's toast shape onto the imperative toast().\nconst toastAdapter = {\n show: ({ message, action, durationMs }) => {\n const handle = toast(message, {\n duration: durationMs,\n action: action && { label: action.label, onAction: action.onClick },\n });\n return { dismiss: handle.dismiss };\n },\n};\n\nconst { onDismiss, onReopen } = dismissRecovery({\n get: () => cards, // your current envelopes\n set: (next) => setCards(next), // NEW array reference (never mutate in place)\n toast: toastAdapter,\n});\n// Pass these on the CardPolicy you hand to <kai-cards> / <kai-remote>.\n```\n\n`onDismiss` writes `dismissed` immutably (Undo restores the prior resolution); `onReopen` clears it back to live (or stamps `expired` when the host says the card is no longer reopenable). Never mutate the array in place — re-render needs a new ref."
|
|
2265
|
+
},
|
|
2266
|
+
{
|
|
2267
|
+
// Rule 12 — kai-compare contract: two candidates, JS data prop, stream both, terminal pick
|
|
2268
|
+
// Source: src/elements/compare.tsx + src/components/response-compare-types.ts
|
|
2269
|
+
id: "compare-contract",
|
|
2270
|
+
test: (t) => {
|
|
2271
|
+
if (/<kai-compare\b|kai-compare-select|ResponseCompareData|response.?compare/i.test(t)) return true;
|
|
2272
|
+
if (/compar(e|ing|ison)|side.by.side|a\/b|two\s+(responses|candidates|answers|completions)|dual.?response/i.test(t) && /kai-|@kitn|candidate|prefer(ence)?|chosen|reject/i.test(t))
|
|
2273
|
+
return true;
|
|
2274
|
+
return false;
|
|
2275
|
+
},
|
|
2276
|
+
title: "`kai-compare` — two candidates, `data` as a JS property, terminal pick",
|
|
2277
|
+
cause: "`<kai-compare>` shows EXACTLY two assistant candidates for one prompt and lets the user pick the better one. The `data` value is an array/object, so it must be set as a JS PROPERTY (never an HTML attribute). Both candidates can stream — but, like `kai-chat`, that needs a NEW `data` reference per chunk (mutating in place will not re-render). The pick is a COMMIT (not a Submit): it fires once and the card collapses.",
|
|
2278
|
+
fix: "Set `data` in JS with two candidates, stream by reassigning a fresh `data` object per chunk, and listen for `kai-compare-select` directly on the element.\n\n```ts\nimport { toast } from '@kitn.ai/ui/elements';\nimport type { ResponseCompareData, CompareSelection } from '@kitn.ai/ui';\n\nconst el = document.querySelector('kai-compare')!;\n// data is a JS PROPERTY — exactly two candidates, each with a unique id.\nel.data = {\n prompt: 'Summarise the report',\n candidates: [\n { id: 'a', content: '', streaming: true },\n { id: 'b', content: '', streaming: true },\n ],\n} satisfies ResponseCompareData;\n\n// Stream BOTH columns: replace data with a NEW object per chunk.\nel.data = { ...el.data, candidates: [{ ...a, content: aText }, { ...b, content: bText }] };\n// Clear `streaming` on a candidate when it settles — the pick stays disabled\n// until BOTH have settled, then `kai-ready` fires.\n\n// Picking is terminal: emits { chosenId, rejectedIds, at } and collapses.\nel.addEventListener('kai-compare-select', (e) => {\n const { chosenId, rejectedIds } = (e as CustomEvent<CompareSelection>).detail;\n recordPreference({ prompt, chosen: chosenId, rejected: rejectedIds });\n});\n```\n\nA malformed definition (not two candidates, missing/duplicate ids) fires `kai-error` instead. The event is non-bubbling — listen on the element, not on `document`."
|
|
2068
2279
|
}
|
|
2069
2280
|
];
|
|
2070
2281
|
function buildText(matched) {
|
|
@@ -60,6 +60,9 @@ export type CardEvent = {
|
|
|
60
60
|
} | {
|
|
61
61
|
kind: 'dismiss';
|
|
62
62
|
cardId: string;
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'reopen';
|
|
65
|
+
cardId: string;
|
|
63
66
|
} | {
|
|
64
67
|
kind: 'error';
|
|
65
68
|
cardId: string;
|
|
@@ -67,10 +70,13 @@ export type CardEvent = {
|
|
|
67
70
|
};
|
|
68
71
|
export type CardEventKind = CardEvent['kind'];
|
|
69
72
|
/** How a card was resolved by the user — the re-hydration channel for the chromed
|
|
70
|
-
* read-only state.
|
|
71
|
-
* resolution is just the event that resolved the
|
|
72
|
-
*
|
|
73
|
-
*
|
|
73
|
+
* read-only state. The terminal kinds (`action`/`submit`) mirror the two terminal
|
|
74
|
+
* CardEvents (minus `cardId`): the resolution is just the event that resolved the
|
|
75
|
+
* card. `dismissed` is a DEFERRED (non-terminal) state — the user set the card
|
|
76
|
+
* aside; it can be re-opened. `expired` is terminal — a dismissed card the host
|
|
77
|
+
* decided can no longer be re-opened (e.g. the agent proceeded, or it went stale).
|
|
78
|
+
* `at` is optional ISO-8601 provenance (data only; never rendered). Additive —
|
|
79
|
+
* does not bump the contract version. */
|
|
74
80
|
export type CardResolution = {
|
|
75
81
|
kind: 'action';
|
|
76
82
|
action: string;
|
|
@@ -80,6 +86,13 @@ export type CardResolution = {
|
|
|
80
86
|
kind: 'submit';
|
|
81
87
|
data: unknown;
|
|
82
88
|
at?: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'dismissed';
|
|
91
|
+
at?: string;
|
|
92
|
+
} | {
|
|
93
|
+
kind: 'expired';
|
|
94
|
+
reason?: string;
|
|
95
|
+
at?: string;
|
|
83
96
|
};
|
|
84
97
|
/** What every card is handed (via native context or the iframe bridge). */
|
|
85
98
|
export interface CardHost {
|
|
@@ -97,6 +110,9 @@ export interface CardPolicy {
|
|
|
97
110
|
onOpen?: (url: string, target: 'tab' | 'artifact') => void;
|
|
98
111
|
onState?: (cardId: string, patch: unknown) => void;
|
|
99
112
|
onDismiss?: (cardId: string) => void;
|
|
113
|
+
/** A dismissed card asked to be re-opened. The host decides whether it can come
|
|
114
|
+
* back (clear the resolution → live again) or has expired (stamp `expired`). */
|
|
115
|
+
onReopen?: (cardId: string) => void;
|
|
100
116
|
onError?: (cardId: string, message: string) => void;
|
|
101
117
|
/** Cap on send-prompt: 'compose' (default) forbids silent sends. 'send' to allow. */
|
|
102
118
|
maxSendPromptMode?: 'compose' | 'send';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CardEnvelope, CardPolicy, CardResolution } from './card-contract';
|
|
2
|
+
/** The minimal toast surface this helper needs. Inject a real adapter (e.g. one
|
|
3
|
+
* backed by `kai-toast-region`) — this module never imports the toast itself. */
|
|
4
|
+
export interface RecoveryToast {
|
|
5
|
+
show(opts: {
|
|
6
|
+
message: string;
|
|
7
|
+
action?: {
|
|
8
|
+
label: string;
|
|
9
|
+
onClick: () => void;
|
|
10
|
+
};
|
|
11
|
+
durationMs?: number;
|
|
12
|
+
}): {
|
|
13
|
+
dismiss(): void;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Context handed to a custom `isReopenable` predicate. */
|
|
17
|
+
export interface ReopenEnv {
|
|
18
|
+
cardId: string;
|
|
19
|
+
/** The card's current resolution at reopen time (should be `dismissed`). */
|
|
20
|
+
resolution: CardResolution | undefined;
|
|
21
|
+
/** `Date.now()` at reopen time (injected for testability). */
|
|
22
|
+
now: number;
|
|
23
|
+
}
|
|
24
|
+
export interface DismissRecoveryOptions {
|
|
25
|
+
/** Read the current cards array. */
|
|
26
|
+
get: () => CardEnvelope[];
|
|
27
|
+
/** Write the next cards array (a NEW reference). */
|
|
28
|
+
set: (next: CardEnvelope[]) => void;
|
|
29
|
+
/** Optional injected toast adapter for the "Dismissed · Undo" affordance. */
|
|
30
|
+
toast?: RecoveryToast;
|
|
31
|
+
/** Override the default re-openable rule. Return false to expire instead. */
|
|
32
|
+
isReopenable?: (env: ReopenEnv) => boolean;
|
|
33
|
+
/** A dismissed card older than this (ms since `dismissed.at`) is no longer
|
|
34
|
+
* re-openable (→ expired). Omit/Infinity = never stale. */
|
|
35
|
+
staleAfterMs?: number;
|
|
36
|
+
/** Auto-dismiss the Undo toast after this long. Default 6000ms. */
|
|
37
|
+
undoMs?: number;
|
|
38
|
+
/** Injected clock (defaults to Date.now); keeps the helper testable. */
|
|
39
|
+
now?: () => number;
|
|
40
|
+
}
|
|
41
|
+
/** Default re-openable rule: a card can come back unless it carries a terminal
|
|
42
|
+
* resolution OR it has gone stale (`staleAfterMs` elapsed since `dismissed.at`).
|
|
43
|
+
* A `dismissed` card with no/invalid `at` is always re-openable. */
|
|
44
|
+
export declare function defaultIsReopenable(env: ReopenEnv, staleAfterMs?: number): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Build the `{ onDismiss, onReopen }` policy handlers for the card dismiss/recovery
|
|
47
|
+
* flow over a host store (`get`/`set`).
|
|
48
|
+
*
|
|
49
|
+
* - `onDismiss(cardId)` — stamps `{ kind:'dismissed', at }` immutably and, when a
|
|
50
|
+
* `toast` is injected, shows "Dismissed" with an Undo that restores the card's
|
|
51
|
+
* prior resolution (live again when there was none).
|
|
52
|
+
* - `onReopen(cardId)` — clears the resolution (live) when `isReopenable`, else
|
|
53
|
+
* stamps `{ kind:'expired', at }`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function dismissRecovery(opts: DismissRecoveryOptions): Pick<CardPolicy, 'onDismiss' | 'onReopen'>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface EntityRef {
|
|
2
|
+
kind: string;
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
promptText?: string;
|
|
7
|
+
data?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export type Segment = {
|
|
10
|
+
type: 'text';
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'entity';
|
|
14
|
+
entity: EntityRef;
|
|
15
|
+
};
|
|
16
|
+
export type ComposerDoc = Segment[];
|
|
17
|
+
export declare function normalizeValue(value: string | ComposerDoc | null | undefined): ComposerDoc;
|
|
18
|
+
export declare function serializeToText(doc: ComposerDoc, opts?: {
|
|
19
|
+
entity?: (e: EntityRef) => string;
|
|
20
|
+
}): string;
|
|
21
|
+
export declare function entitiesOf(doc: ComposerDoc): EntityRef[];
|
|
22
|
+
export declare function docIsEmpty(doc: ComposerDoc): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ActiveTrigger {
|
|
2
|
+
char: string;
|
|
3
|
+
query: string;
|
|
4
|
+
start: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function detectTrigger(text: string, caret: number, chars: string[]): ActiveTrigger | null;
|
|
7
|
+
/**
|
|
8
|
+
* Wraps detectTrigger with a list of trigger definitions.
|
|
9
|
+
* Returns { def, query, start } when a trigger is active, else null.
|
|
10
|
+
* Accepts generic defs so it does not import from composer.tsx (no cycle).
|
|
11
|
+
*/
|
|
12
|
+
export declare function activeTriggerFor<T extends {
|
|
13
|
+
char: string;
|
|
14
|
+
kind: string;
|
|
15
|
+
}>(text: string, caret: number, defs: T[]): {
|
|
16
|
+
def: T;
|
|
17
|
+
query: string;
|
|
18
|
+
start: number;
|
|
19
|
+
} | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ChatMessage } from '../elements/chat-types';
|
|
2
|
+
import { AttachmentData } from '../components/attachments';
|
|
3
|
+
import { AssistantStream, SetMessages } from '../state';
|
|
4
|
+
export interface CreateKaiChatOptions {
|
|
5
|
+
/** Seed messages, read once at creation and copied. Later changes are ignored — drive updates through the returned ops. */
|
|
6
|
+
initialMessages?: ChatMessage[];
|
|
7
|
+
/** Seed suggestions, read once at creation and copied. Later changes are ignored. */
|
|
8
|
+
initialSuggestions?: string[];
|
|
9
|
+
onSubmit?: (detail: {
|
|
10
|
+
value: string;
|
|
11
|
+
attachments: AttachmentData[];
|
|
12
|
+
}) => void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/** Solid store: consumer-owned chat state + the same ergonomic ops as `useKaiChat`. */
|
|
15
|
+
export interface KaiChatStore {
|
|
16
|
+
messages: () => ChatMessage[];
|
|
17
|
+
setMessages: SetMessages;
|
|
18
|
+
suggestions: () => string[];
|
|
19
|
+
loading: () => boolean;
|
|
20
|
+
append: (msg: ChatMessage) => void;
|
|
21
|
+
update: (id: string, patch: Partial<ChatMessage> | ((m: ChatMessage) => ChatMessage)) => void;
|
|
22
|
+
remove: (id: string) => void;
|
|
23
|
+
addSuggestion: (s: string) => void;
|
|
24
|
+
removeSuggestion: (s: string) => void;
|
|
25
|
+
clearSuggestions: () => void;
|
|
26
|
+
streamAssistant: (init?: Partial<ChatMessage>) => AssistantStream;
|
|
27
|
+
handleSubmit: (event: CustomEvent<{
|
|
28
|
+
value: string;
|
|
29
|
+
attachments: AttachmentData[];
|
|
30
|
+
}>) => void;
|
|
31
|
+
/** Spread onto `<kai-chat {...chat.bind} />` (reactive getters). Wire submit via `on:kai-submit={chat.handleSubmit}`. */
|
|
32
|
+
bind: {
|
|
33
|
+
readonly messages: ChatMessage[];
|
|
34
|
+
readonly loading: boolean;
|
|
35
|
+
readonly suggestions: string[];
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export declare function createKaiChat(options?: CreateKaiChatOptions): KaiChatStore;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ChatMessage, FeedbackVote } from '../elements/chat-types';
|
|
2
|
+
/** Detail shape emitted by the action row. `state` is present only for the
|
|
3
|
+
* toggleable feedback votes: `'on'` when a vote is set, `'off'` when cleared.
|
|
4
|
+
* Copy / regenerate / edit / custom actions omit it. */
|
|
5
|
+
export interface MessageActionDetail {
|
|
6
|
+
messageId: string;
|
|
7
|
+
action: string;
|
|
8
|
+
state?: 'on' | 'off';
|
|
9
|
+
}
|
|
10
|
+
export interface MessageFeedbackOptions {
|
|
11
|
+
/** Emit the `kai-message-action` detail (facade maps this to `dispatch` /
|
|
12
|
+
* `onMessageAction`). */
|
|
13
|
+
emit: (detail: MessageActionDetail) => void;
|
|
14
|
+
/** How long the copy check stays before auto-clearing. Defaults to 2000ms. */
|
|
15
|
+
copiedDuration?: number;
|
|
16
|
+
/** Container the copy/feedback toasts should be scoped to (the chat, by
|
|
17
|
+
* default) so they appear in-chat rather than at the page top. */
|
|
18
|
+
target?: () => HTMLElement | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface MessageFeedback {
|
|
21
|
+
/** Resolve the active vote for a message: a controlled `m.feedback` wins,
|
|
22
|
+
* else the facade's own optimistic map. */
|
|
23
|
+
resolveFeedback: (m: Pick<ChatMessage, 'id' | 'feedback'>) => FeedbackVote | undefined;
|
|
24
|
+
/** Whether a message's copy button should currently show its check. */
|
|
25
|
+
isCopied: (id: string) => boolean;
|
|
26
|
+
/** Route a clicked action through copy / vote / passthrough handling. */
|
|
27
|
+
handleAction: (m: Pick<ChatMessage, 'id' | 'content' | 'feedback'>, action: string) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create the action-row feedback controller for one message list (or one
|
|
31
|
+
* standalone message). Owns the optimistic `feedbackMap` + transient
|
|
32
|
+
* `copiedIds`, resolves the controlled-wins vote, and turns clicks into
|
|
33
|
+
* clipboard writes, toasts, and `kai-message-action` emissions.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createMessageFeedback(opts: MessageFeedbackOptions): MessageFeedback;
|