@kitn.ai/ui 0.17.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 +28 -5
- 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 +37 -12
- package/dist/components/choice-card.d.ts +26 -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/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 +12 -0
- 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.d.ts +14 -0
- package/dist/components/screen.d.ts +46 -0
- package/dist/components/tasks-card.d.ts +49 -1
- package/dist/components/toast.d.ts +12 -2
- package/dist/components/tool-types.d.ts +10 -0
- package/dist/components/tool.d.ts +8 -8
- 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 +8392 -1860
- package/dist/elements/agent-card.d.ts +1 -0
- package/dist/elements/agent-card.js +1 -0
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/autoloader.js +1 -1
- 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 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-types.d.ts +47 -0
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- 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/button-XDUM6lXs.js +1 -0
- package/dist/elements/chunks/card-CBlFZ-7I.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/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/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/hover-card-gE7iyXdW.js +1 -0
- package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
- package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
- package/dist/elements/chunks/info-B_toFS0l.js +1 -0
- package/dist/elements/chunks/input-gzbHYZvQ.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-CMTGx9r8.js → markdown-DBrcqq4S.js} +9 -9
- 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/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/use-card-resolution-VSVoxDeJ.js +1 -0
- package/dist/elements/chunks/video-DxTPZqT8.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 -1
- package/dist/elements/command.d.ts +1 -0
- package/dist/elements/command.js +1 -0
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.d.ts +1 -0
- package/dist/elements/composer.js +1 -0
- package/dist/elements/confirm-card.js +1 -1
- package/dist/elements/context-meter.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/css.d.ts +1 -0
- package/dist/elements/default-input.d.ts +51 -0
- package/dist/elements/define.d.ts +53 -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 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- 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 -1
- 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 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.d.ts +1 -0
- package/dist/elements/menu.js +1 -0
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- 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 -1
- 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.js +1 -1
- package/dist/elements/prompt-suggestions.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/register-impl.d.ts +0 -0
- package/dist/elements/register.d.ts +13 -0
- package/dist/elements/remote.d.ts +1 -0
- package/dist/elements/remote.js +1 -0
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +2 -2
- 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 -1
- 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.js +1 -1
- package/dist/elements/status.d.ts +1 -0
- package/dist/elements/status.js +1 -0
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.d.ts +1 -0
- package/dist/elements/tabs.js +1 -0
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.d.ts +1 -0
- package/dist/elements/tooltip.js +1 -0
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.d.ts +1 -0
- package/dist/elements/voice-output.js +1 -0
- package/dist/elements.d.ts +733 -58
- package/dist/engine-javascript-C1x7zo1_.js +141 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +8256 -5703
- package/dist/kai.es.js +1 -0
- package/dist/llms/llms-full.txt +1146 -64
- package/dist/llms/llms.txt +4 -4
- package/dist/mcp.es.js +62 -7
- 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/toast-store.d.ts +32 -2
- package/dist/primitives/use-speech-recognition.d.ts +26 -0
- package/dist/react/index.d.ts +1085 -97
- package/dist/react/runtime.d.ts +9 -2
- package/dist/react/use-kai-chat.d.ts +41 -0
- package/dist/react.js +572 -193
- package/dist/register-impl-CYWGkgbI.js +141 -0
- package/dist/schemas/tasks.schema.json +2 -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 +19 -1
- package/frameworks/react/index.tsx +1042 -157
- package/frameworks/react/runtime.tsx +30 -1
- package/frameworks/react/use-kai-chat.tsx +87 -0
- package/llms-full.txt +1146 -64
- package/llms.txt +4 -4
- package/package.json +23 -8
- package/src/agent-tooling/mcp/manifest.ts +14 -0
- package/src/agent-tooling/mcp/tools/debug.ts +10 -6
- package/src/agent-tooling/mcp/tools/reference.ts +32 -0
- package/src/agent-tooling/mcp/tools/scaffold.ts +30 -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 +225 -116
- package/src/components/choice-card.tsx +103 -11
- package/src/components/coachmark.tsx +245 -0
- package/src/components/component-meta.json +691 -102
- 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 +54 -1
- package/src/components/conversation-item.tsx +69 -7
- package/src/components/conversation-list.tsx +134 -37
- package/src/components/file-tree.tsx +197 -47
- package/src/components/form-widgets.tsx +9 -7
- package/src/components/form.tsx +140 -17
- 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 +23 -4
- 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.tsx +31 -2
- package/src/components/screen.tsx +176 -0
- package/src/components/tasks-card.tsx +342 -21
- package/src/components/toast.tsx +119 -31
- package/src/components/tool-types.ts +10 -0
- package/src/components/tool.tsx +22 -16
- 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/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 +2 -2
- package/src/elements/chat-workspace.tsx +153 -41
- package/src/elements/chat.tsx +45 -23
- 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 +24 -2
- 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 +129 -1
- package/src/elements/element-meta.json +5562 -1336
- package/src/elements/element-types.d.ts +732 -57
- 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 +58 -11
- 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 +38 -3
- package/src/elements/register.ts +11 -3
- 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/switch.tsx +89 -14
- package/src/elements/tabs.tsx +95 -0
- package/src/elements/tasks.tsx +70 -14
- package/src/elements/toast.tsx +17 -2
- 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 +5 -2
- package/src/primitives/card-schemas/tasks.schema.json +2 -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/toast-store.ts +43 -2
- 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 +52 -8
- package/theme.css +113 -0
- package/dist/components/slash-command.d.ts +0 -15
- package/dist/elements/chunks/Icon-D_Zmwmwh.js +0 -1
- package/dist/elements/chunks/action-icons-PVfIvcuG.js +0 -1
- package/dist/elements/chunks/attachments-Dp6vqtrc.js +0 -1
- package/dist/elements/chunks/button-CKyYD9G4.js +0 -1
- package/dist/elements/chunks/card-Cjho-PYk.js +0 -1
- package/dist/elements/chunks/chat-thread-RT808iPf.js +0 -1
- package/dist/elements/chunks/check-CDYaMYrM.js +0 -1
- package/dist/elements/chunks/chevron-down-3SBiq8HF.js +0 -1
- package/dist/elements/chunks/chevron-right-k2UFlIVK.js +0 -1
- package/dist/elements/chunks/cn-Dogu6PbV.js +0 -1
- package/dist/elements/chunks/code-block-BYUmfFSd.js +0 -1
- package/dist/elements/chunks/collapsible-BiNwdOn6.js +0 -1
- package/dist/elements/chunks/context-18g6oi4J.js +0 -1
- package/dist/elements/chunks/conversation-list-D9Y0NVdo.js +0 -1
- package/dist/elements/chunks/default-input-CSAoYYMd.js +0 -1
- package/dist/elements/chunks/download-D8K0Je8r.js +0 -1
- package/dist/elements/chunks/dropdown-bUs2iTia.js +0 -1
- package/dist/elements/chunks/external-link-6mA0wxab.js +0 -1
- package/dist/elements/chunks/file-text-DnaYk3Dm.js +0 -1
- package/dist/elements/chunks/file-tree-CgtRLlxK.js +0 -1
- package/dist/elements/chunks/hover-card-CIGw62gP.js +0 -1
- package/dist/elements/chunks/link-BlGSeoPy.js +0 -1
- package/dist/elements/chunks/loader-DvhR4qa0.js +0 -1
- package/dist/elements/chunks/message-CDZwXjhL.js +0 -1
- package/dist/elements/chunks/message-feedback-CYx81QiA.js +0 -1
- package/dist/elements/chunks/model-switcher-O_tUhoOT.js +0 -1
- package/dist/elements/chunks/overlay-DydXYMQW.js +0 -1
- package/dist/elements/chunks/prompt-suggestion-ldlWV5kd.js +0 -1
- package/dist/elements/chunks/reasoning-2PUnHlmr.js +0 -1
- package/dist/elements/chunks/resizable-B5WNbSeb.js +0 -1
- package/dist/elements/chunks/star-t9tI-P0q.js +0 -1
- package/dist/elements/chunks/store-C6rIooZz.js +0 -1
- package/dist/elements/chunks/text-shimmer-uh9V_KUh.js +0 -1
- package/dist/elements/chunks/textarea-3nm6Ia9U.js +0 -1
- package/dist/elements/chunks/thumbs-up-BBtguGld.js +0 -1
- package/dist/elements/chunks/toast-store-D8cL3fWl.js +0 -1
- package/dist/elements/chunks/tool-GJ3vwp1U.js +0 -1
- package/dist/elements/chunks/tooltip-DwKAz4XR.js +0 -1
- package/dist/elements/chunks/triangle-alert-Ct1zt2JL.js +0 -1
- package/dist/elements/chunks/use-card-resolution-D-_0Alzy.js +0 -1
- package/dist/elements/chunks/video-mVYiM99-.js +0 -1
- package/dist/elements/chunks/x-CzxL27Ch.js +0 -1
- package/dist/kitn-chat.es.js +0 -1
- package/dist/register-JyTglR6m.js +0 -1
- package/dist/register-impl-C6wlSsts.js +0 -77
- package/src/components/slash-command.tsx +0 -232
- package/src/elements/framework-usage.json +0 -588
- /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,5 +1,6 @@
|
|
|
1
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
5
|
import { Message, MessageAvatar, MessageBody } from '../components/message';
|
|
5
6
|
import { createMessageFeedback } from '../primitives/message-feedback';
|
|
@@ -27,6 +28,11 @@ interface Props extends Record<string, unknown> {
|
|
|
27
28
|
avatarSrc?: string;
|
|
28
29
|
/** Convenience avatar fallback text (used when `message.avatar` is not set). */
|
|
29
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;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
/** Events fired by `<kai-message>`. */
|
|
@@ -54,7 +60,8 @@ 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 ?? '' };
|
|
@@ -62,12 +69,27 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
62
69
|
// re-render when the host swaps in a fresh `message` object during streaming.
|
|
63
70
|
const feedback = createMessageFeedback({
|
|
64
71
|
emit: (detail) => dispatch('kai-message-action', detail),
|
|
65
|
-
target
|
|
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'),
|
|
66
86
|
});
|
|
67
87
|
|
|
68
88
|
// Read declarative <kai-action> children from light DOM.
|
|
69
89
|
// Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
|
|
70
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>>({});
|
|
71
93
|
onMount(() => {
|
|
72
94
|
const read = () => {
|
|
73
95
|
const nodes = [...element.querySelectorAll('kai-action')];
|
|
@@ -77,6 +99,7 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
77
99
|
icon: n.getAttribute('icon') ?? undefined,
|
|
78
100
|
tooltip: n.getAttribute('tooltip') ?? undefined,
|
|
79
101
|
})));
|
|
102
|
+
setSlots(readSlots(element, MESSAGE_SLOTS));
|
|
80
103
|
};
|
|
81
104
|
read();
|
|
82
105
|
const observer = new MutationObserver(read);
|
|
@@ -89,6 +112,12 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
89
112
|
(props.avatarSrc || props.avatarFallback
|
|
90
113
|
? { src: props.avatarSrc as string | undefined, fallback: props.avatarFallback as string | undefined }
|
|
91
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());
|
|
92
121
|
const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
|
|
93
122
|
// markdown: explicit prop/attribute wins; otherwise default by role.
|
|
94
123
|
const markdownExplicit = () =>
|
|
@@ -109,12 +138,32 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
109
138
|
activeFeedback={feedback.resolveFeedback(msg())}
|
|
110
139
|
copied={feedback.isCopied(msg().id)}
|
|
111
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}
|
|
112
143
|
/>
|
|
113
144
|
);
|
|
114
145
|
|
|
115
146
|
// Row carries `group` so a hover-revealed action bar fades in on row hover.
|
|
116
147
|
const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
|
|
117
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
|
+
|
|
118
167
|
return (
|
|
119
168
|
<ChatConfig
|
|
120
169
|
proseSize={props.proseSize}
|
|
@@ -123,21 +172,19 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
123
172
|
portalMount={outer.portalMount()}
|
|
124
173
|
>
|
|
125
174
|
<Show
|
|
126
|
-
when={
|
|
175
|
+
when={showRail()}
|
|
127
176
|
fallback={
|
|
128
177
|
<Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
|
|
129
178
|
{body()}
|
|
130
179
|
</Message>
|
|
131
180
|
}
|
|
132
181
|
>
|
|
133
|
-
{(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
</Message>
|
|
140
|
-
)}
|
|
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>
|
|
141
188
|
</Show>
|
|
142
189
|
</ChatConfig>
|
|
143
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
|
+
));
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createSignal, createEffect, Show } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { PaneGroup, type PaneTab } from '../ui/pane-group';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** The tabs to render. An array of `{ id, name, status?, needsAttention?, number? }`
|
|
7
|
+
* set as a JS PROPERTY (not an HTML attribute). */
|
|
8
|
+
tabs?: PaneTab[];
|
|
9
|
+
/** The active tab id (controlled, and reflected to the `active` ATTRIBUTE so
|
|
10
|
+
* `::part`/`[active]` selectors and the per-tab named slot follow it). Set it as
|
|
11
|
+
* the `active` attribute or drive it from `kai-tab-change`; omit for uncontrolled
|
|
12
|
+
* (the first tab). */
|
|
13
|
+
active?: string;
|
|
14
|
+
/** Highlight the frame as the ACTIVE group in a multi-group layout. Attribute:
|
|
15
|
+
* `focused`. */
|
|
16
|
+
focused?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Events fired by `<kai-pane-group>`. All non-bubbling — listen on the element. */
|
|
20
|
+
interface Events {
|
|
21
|
+
/** A tab was selected (click, Enter/Space, or arrow-key move). `detail.id` is
|
|
22
|
+
* the tab's id. */
|
|
23
|
+
'kai-tab-change': { id: string };
|
|
24
|
+
/** A tab's close (×) was clicked. Drop the tab from `tabs` yourself. */
|
|
25
|
+
'kai-tab-close': { id: string };
|
|
26
|
+
/** A tab's "…" overflow was clicked. Open your own menu from `detail.id`. */
|
|
27
|
+
'kai-tab-menu': { id: string };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `<kai-pane-group>` — an editor group: a TAB STRIP (numbered-status-badge tabs)
|
|
32
|
+
* over the active tab's pane content. The reusable "one column = a group of agents
|
|
33
|
+
* shown as tabs" primitive from the Multi-Agent Workspace. Composable: a `tabs`
|
|
34
|
+
* property + slots + parts + events, not a config blob — the group owns the tab UX,
|
|
35
|
+
* you own the pane content.
|
|
36
|
+
*
|
|
37
|
+
* Each tab leads with a tone-colored NUMBERED BADGE (color = status, digit = the
|
|
38
|
+
* keyboard ⌥-jump number), then the name, the status word (on the active tab / on
|
|
39
|
+
* hover / always for needs-attention), a "…" overflow, and a close "×".
|
|
40
|
+
*
|
|
41
|
+
* Set the `tabs` property in JavaScript (array, not attribute):
|
|
42
|
+
*
|
|
43
|
+
* ```html
|
|
44
|
+
* <kai-pane-group active="atlas">
|
|
45
|
+
* <!-- one named slot per tab id; the group shows the active one -->
|
|
46
|
+
* <div slot="atlas">…Atlas pane…</div>
|
|
47
|
+
* <div slot="otto">…Otto pane…</div>
|
|
48
|
+
* </kai-pane-group>
|
|
49
|
+
* <script type="module">
|
|
50
|
+
* import '@kitn.ai/ui/elements';
|
|
51
|
+
* const group = document.querySelector('kai-pane-group');
|
|
52
|
+
* group.tabs = [
|
|
53
|
+
* { id: 'atlas', name: 'Atlas', status: { tone: 'working', label: 'Running', pulse: true } },
|
|
54
|
+
* { id: 'otto', name: 'Otto', status: { tone: 'blocked', label: 'Needs input' }, needsAttention: true },
|
|
55
|
+
* ];
|
|
56
|
+
* group.addEventListener('kai-tab-change', (e) => console.log(e.detail.id));
|
|
57
|
+
* </script>
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* Pane content — TWO composable patterns:
|
|
61
|
+
* - NAMED SLOT PER TAB: give each pane `slot="<tab id>"`; the group projects the
|
|
62
|
+
* active tab's slot and swaps it itself on selection (no consumer JS needed).
|
|
63
|
+
* - DEFAULT SLOT: put one body in the default slot and swap it yourself in
|
|
64
|
+
* response to `kai-tab-change`. Both work; pick whichever fits.
|
|
65
|
+
*
|
|
66
|
+
* Methods: `el.select(id)` selects a tab (fires `kai-tab-change`); `el.focus()`
|
|
67
|
+
* focuses the active tab. Parts: `::part(tabs|tab|body)` (also `::part(menu|close)`).
|
|
68
|
+
*/
|
|
69
|
+
defineWebComponent<Props, Events>('kai-pane-group', {
|
|
70
|
+
tabs: undefined,
|
|
71
|
+
active: undefined,
|
|
72
|
+
focused: false,
|
|
73
|
+
}, (props, { element, dispatch, flag, expose }) => {
|
|
74
|
+
const tabs = () => (props.tabs as PaneTab[] | undefined) ?? [];
|
|
75
|
+
// Controlled/uncontrolled: the `active` prop/attribute wins; otherwise the
|
|
76
|
+
// element manages its own, falling back to the first tab. `change` always writes
|
|
77
|
+
// the internal value AND emits `kai-tab-change` so a controlling app can react.
|
|
78
|
+
const [internal, setInternal] = createSignal<string | undefined>(props.active as string | undefined);
|
|
79
|
+
const active = () => (props.active as string | undefined) ?? internal() ?? tabs()[0]?.id;
|
|
80
|
+
const change = (id: string) => {
|
|
81
|
+
setInternal(id);
|
|
82
|
+
dispatch('kai-tab-change', { id });
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Reflect the resolved active id to the `active` attribute so `[active="…"]` /
|
|
86
|
+
// `::part` selectors and the consumer's per-tab named slot follow selection.
|
|
87
|
+
// Writing the same value is idempotent, so no feedback loop with the prop.
|
|
88
|
+
createEffect(() => {
|
|
89
|
+
const a = active();
|
|
90
|
+
if (a != null) element.setAttribute('active', a);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expose({
|
|
94
|
+
/** Select a tab by id (fires `kai-tab-change`). Ignores unknown ids. */
|
|
95
|
+
select: (id: string) => {
|
|
96
|
+
if (tabs().some((t) => t.id === id)) change(id);
|
|
97
|
+
},
|
|
98
|
+
/** Focus the active tab in the strip. */
|
|
99
|
+
focus: () => {
|
|
100
|
+
element.shadowRoot?.querySelector<HTMLElement>('[part="tab"][tabindex="0"]')?.focus();
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<PaneGroup
|
|
106
|
+
tabs={tabs()}
|
|
107
|
+
active={active()}
|
|
108
|
+
focused={flag('focused')}
|
|
109
|
+
onTabChange={change}
|
|
110
|
+
onTabClose={(id) => dispatch('kai-tab-close', { id })}
|
|
111
|
+
onTabMenu={(id) => dispatch('kai-tab-menu', { id })}
|
|
112
|
+
>
|
|
113
|
+
{/* Active tab's content: the per-tab named slot, plus the default slot for the
|
|
114
|
+
swap-it-yourself pattern. A consumer uses one or the other. */}
|
|
115
|
+
<Show when={active()}>{(a) => <slot name={a()} />}</Show>
|
|
116
|
+
<slot />
|
|
117
|
+
</PaneGroup>
|
|
118
|
+
);
|
|
119
|
+
});
|