@kitn.ai/ui 0.17.0 → 0.18.1
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-C2LTALdM.js +1 -0
- package/dist/elements/chunks/action-icons-Dtl8Ox5D.js +1 -0
- package/dist/elements/chunks/arrow-left-GbBceGBE.js +1 -0
- package/dist/elements/chunks/attachments-DLJcWCDV.js +1 -0
- package/dist/elements/chunks/badge-BTNZTODL.js +1 -0
- package/dist/elements/chunks/button-DBDZebGr.js +1 -0
- package/dist/elements/chunks/card-YfCyI4fH.js +1 -0
- package/dist/elements/chunks/chat-thread-Dz2qbzvI.js +1 -0
- package/dist/elements/chunks/check-fhmRksq_.js +1 -0
- package/dist/elements/chunks/chevron-down-DcRg1aRU.js +1 -0
- package/dist/elements/chunks/chevron-right-ChzBcNJ-.js +1 -0
- package/dist/elements/chunks/circle-B4fTe9v6.js +1 -0
- package/dist/elements/chunks/circle-check-CJV-3Rem.js +1 -0
- package/dist/elements/chunks/circle-x-pDtzlghQ.js +1 -0
- package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
- package/dist/elements/chunks/code-block-DZ6mz6vs.js +1 -0
- package/dist/elements/chunks/collapsible-CWUAShMC.js +1 -0
- package/dist/elements/chunks/composer-BZyPU6gD.js +65 -0
- package/dist/elements/chunks/context-Cx6eQA_G.js +1 -0
- package/dist/elements/chunks/conversation-list-C4xTQSpT.js +1 -0
- package/dist/elements/chunks/default-input-BZcwyKcP.js +1 -0
- package/dist/elements/chunks/define-CNSKFZCd.js +1 -0
- package/dist/elements/chunks/disclosure-BcBs--Jf.js +1 -0
- package/dist/elements/chunks/download-BDQwcFav.js +1 -0
- package/dist/elements/chunks/dropdown-wgs8xCJZ.js +1 -0
- package/dist/elements/chunks/ellipsis-CUiEJ6R1.js +1 -0
- package/dist/elements/chunks/external-link-DJUmC7g2.js +1 -0
- package/dist/elements/chunks/file-text-DOYfYvrh.js +1 -0
- package/dist/elements/chunks/file-tree-DQzNQrbr.js +1 -0
- package/dist/elements/chunks/folder-DBDUBANz.js +1 -0
- package/dist/elements/chunks/hover-card-BQGdGAQ3.js +1 -0
- package/dist/elements/chunks/icon-CAyRqVrg.js +1 -0
- package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
- package/dist/elements/chunks/info-DBQl-m6e.js +1 -0
- package/dist/elements/chunks/input-DZD67EvW.js +1 -0
- package/dist/elements/chunks/kbd-DbyVrlnU.js +1 -0
- package/dist/elements/chunks/link-vko7AttA.js +1 -0
- package/dist/elements/chunks/loader-Cg6rO8tQ.js +1 -0
- package/dist/elements/chunks/{markdown-CMTGx9r8.js → markdown-n3Xbj3PR.js} +9 -9
- package/dist/elements/chunks/message-CgKytiSB.js +1 -0
- package/dist/elements/chunks/message-feedback-Ds3-US0e.js +1 -0
- package/dist/elements/chunks/message-square-MmRkvc-M.js +1 -0
- package/dist/elements/chunks/minimize-2-3kCdE0q3.js +1 -0
- package/dist/elements/chunks/model-switcher-BMtXGwLU.js +1 -0
- package/dist/elements/chunks/overlay-B1-MBI6h.js +1 -0
- package/dist/elements/chunks/paperclip-DDEfmkHc.js +1 -0
- package/dist/elements/chunks/progress-bar-Dwbiyv3s.js +1 -0
- package/dist/elements/chunks/prompt-suggestion-9lvgFcEa.js +1 -0
- package/dist/elements/chunks/reasoning-DzHWsdAJ.js +1 -0
- package/dist/elements/chunks/resizable-Bq_eHxUm.js +1 -0
- package/dist/elements/chunks/rotate-cw-jpisOdOV.js +1 -0
- package/dist/elements/chunks/scroll-area-g5Ze3K6f.js +1 -0
- package/dist/elements/chunks/separator-Bmjc5XyX.js +1 -0
- package/dist/elements/chunks/settings-Cz1bMJP9.js +1 -0
- package/dist/elements/chunks/settings-group-9imY3kRA.js +1 -0
- package/dist/elements/chunks/share-BdenF0wQ.js +1 -0
- package/dist/elements/chunks/skeleton-Pjc5jiaY.js +1 -0
- package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
- package/dist/elements/chunks/star-DY6z1UUH.js +1 -0
- package/dist/elements/chunks/store-th4VyJXM.js +1 -0
- package/dist/elements/chunks/text-shimmer-CEi-tlXr.js +1 -0
- package/dist/elements/chunks/textarea-CboigarR.js +1 -0
- package/dist/elements/chunks/thumbs-up-BR33KLfA.js +1 -0
- package/dist/elements/chunks/toast-store-BEMda0fv.js +1 -0
- package/dist/elements/chunks/tool-TMued3WO.js +1 -0
- package/dist/elements/chunks/tooltip-Cft_Rxiw.js +1 -0
- package/dist/elements/chunks/triangle-alert-B07fX3Q8.js +1 -0
- package/dist/elements/chunks/use-card-resolution-M36zVciB.js +1 -0
- package/dist/elements/chunks/video-MKp3LmNT.js +1 -0
- package/dist/elements/chunks/x-Ckwicf6g.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 +8255 -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-cKscku5m.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 +77 -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 +31 -10
- package/src/agent-tooling/mcp/manifest.ts +14 -0
- package/src/agent-tooling/mcp/tools/debug.ts +11 -7
- 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 +249 -0
- package/src/components/component-meta.json +699 -110
- 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 +341 -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 +2 -2
- 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 +87 -7
- 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 +218 -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 +117 -0
- package/src/ui/pane-group.tsx +291 -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
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { Show } from 'solid-js';
|
|
1
|
+
import { Show, createSignal, onMount, onCleanup } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
3
|
import { createControllableSignal } from '../primitives/controllable';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { readSlots, WORKSPACE_SLOTS } from './slots';
|
|
5
|
+
import { ChatThread, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
|
|
6
|
+
import { ConversationList, CollapsedRail } from '../components/conversation-list';
|
|
6
7
|
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '../ui/resizable';
|
|
7
|
-
import { Button } from '../ui/button';
|
|
8
|
-
import { PanelLeftOpen } from 'lucide-solid';
|
|
9
8
|
import type { AttachmentData } from '../components/attachments';
|
|
10
|
-
import type {
|
|
9
|
+
import type { TriggerDef } from '../components/composer';
|
|
11
10
|
import type { ChatMessage } from './chat-types';
|
|
12
11
|
import type { ProseSize } from '../primitives/chat-config';
|
|
13
12
|
import type { ModelOption, ConversationGroup, ConversationSummary } from '../types';
|
|
@@ -36,12 +35,13 @@ interface Props extends Record<string, unknown> {
|
|
|
36
35
|
scrollButton?: boolean;
|
|
37
36
|
search?: boolean;
|
|
38
37
|
voice?: boolean;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
/** Rich entity triggers (`/` skills, `@` agents/plugins) forwarded to the input. */
|
|
39
|
+
triggers?: TriggerDef[];
|
|
40
|
+
/** Default icon per entity kind (kind → image src) forwarded to the input. */
|
|
41
|
+
kindIcons?: Record<string, string>;
|
|
42
|
+
/** Sidebar default width as a percent of the workspace (default 26). */
|
|
43
43
|
sidebarWidth?: number;
|
|
44
|
-
/** Sidebar min width in px (default
|
|
44
|
+
/** Sidebar min width in px (default 240). */
|
|
45
45
|
sidebarMinWidth?: number;
|
|
46
46
|
/** Sidebar max width in px (default 420). */
|
|
47
47
|
sidebarMaxWidth?: number;
|
|
@@ -52,6 +52,17 @@ interface Props extends Record<string, unknown> {
|
|
|
52
52
|
/** Initial collapsed state when uncontrolled (default false). Use the
|
|
53
53
|
* `default-sidebar-collapsed` attribute to start collapsed in plain HTML. */
|
|
54
54
|
defaultSidebarCollapsed?: boolean;
|
|
55
|
+
/** Auto-collapse the rail when the workspace's own width drops below this many
|
|
56
|
+
* px, and re-expand when it grows back above. Uncontrolled only (it never
|
|
57
|
+
* fights an app-driven `sidebarCollapsed`); omit to disable. Fires
|
|
58
|
+
* `kai-sidebar-toggle`. Attribute: `collapse-below`. */
|
|
59
|
+
collapseBelow?: number;
|
|
60
|
+
/** Render Recents as dense single-line rows (a leading dot + title, no count). */
|
|
61
|
+
compact?: boolean;
|
|
62
|
+
/** Suppress the built-in ConversationList so the `sidebar-header` slot owns the
|
|
63
|
+
* whole rail flex region (for apps that supply their own rail nav). Default
|
|
64
|
+
* false. Attribute: `no-conversations`. */
|
|
65
|
+
noConversations?: boolean;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
interface Events {
|
|
@@ -75,8 +86,6 @@ interface Events {
|
|
|
75
86
|
'kai-search': Record<string, never>;
|
|
76
87
|
/** The Mic / voice button was clicked. */
|
|
77
88
|
'kai-voice': Record<string, never>;
|
|
78
|
-
/** A slash command was chosen from the palette. */
|
|
79
|
-
'kai-slash-select': { command: SlashCommandItem };
|
|
80
89
|
/** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
|
|
81
90
|
'kai-suggestion-click': { value: string };
|
|
82
91
|
}
|
|
@@ -87,20 +96,83 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
87
96
|
suggestions: undefined, suggestionMode: 'submit', proseSize: 'sm',
|
|
88
97
|
codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
|
|
89
98
|
models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
|
|
90
|
-
search: false, voice: false,
|
|
91
|
-
sidebarWidth:
|
|
92
|
-
sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined,
|
|
93
|
-
|
|
99
|
+
search: false, voice: false, triggers: undefined, kindIcons: undefined,
|
|
100
|
+
sidebarWidth: 26, sidebarMinWidth: 240, sidebarMaxWidth: 420,
|
|
101
|
+
sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined, collapseBelow: undefined, compact: undefined,
|
|
102
|
+
noConversations: undefined,
|
|
103
|
+
}, (props, { dispatch, flag, expose, element }) => {
|
|
104
|
+
// Which injection slots the consumer has filled. A bare <slot> is always a
|
|
105
|
+
// truthy JSX node, so we render each region wrapper ONLY when readSlots reports
|
|
106
|
+
// projected light-DOM content (re-read on childList mutation).
|
|
107
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
108
|
+
onMount(() => {
|
|
109
|
+
const read = () => setSlots(readSlots(element, WORKSPACE_SLOTS));
|
|
110
|
+
read();
|
|
111
|
+
const observer = new MutationObserver(read);
|
|
112
|
+
observer.observe(element, { childList: true });
|
|
113
|
+
onCleanup(() => observer.disconnect());
|
|
114
|
+
});
|
|
115
|
+
|
|
94
116
|
// Controlled/uncontrolled collapse: `sidebarCollapsed` (when set) wins;
|
|
95
117
|
// otherwise the element manages its own state, seeded from
|
|
96
|
-
// `defaultSidebarCollapsed`. `
|
|
97
|
-
// visually while controlled) and emits `kai-sidebar-toggle` so a controlling
|
|
98
|
-
// can update its own state.
|
|
118
|
+
// `defaultSidebarCollapsed`. `setCollapsedTo` always writes the internal value (a
|
|
119
|
+
// no-op visually while controlled) and emits `kai-sidebar-toggle` so a controlling
|
|
120
|
+
// app can update its own state.
|
|
99
121
|
const [collapsed, setCollapsed] = createControllableSignal(
|
|
100
122
|
() => props.sidebarCollapsed as boolean | undefined,
|
|
101
123
|
flag('defaultSidebarCollapsed'),
|
|
102
124
|
);
|
|
103
|
-
const
|
|
125
|
+
const setCollapsedTo = (next: boolean) => { setCollapsed(next); dispatch('kai-sidebar-toggle', { collapsed: next }); };
|
|
126
|
+
const toggle = () => setCollapsedTo(!collapsed());
|
|
127
|
+
|
|
128
|
+
// Responsive auto-collapse. When `collapseBelow` is set, a ResizeObserver on the
|
|
129
|
+
// workspace root collapses the rail once the workspace's own width drops below
|
|
130
|
+
// it and re-expands above it. Uncontrolled only — bail while `sidebarCollapsed`
|
|
131
|
+
// is set so we never fight an app-driven collapse. `autoCollapsed` tracks whether
|
|
132
|
+
// WE collapsed it, so a user's manual expand isn't auto-undone on the next tick.
|
|
133
|
+
let rootEl!: HTMLDivElement;
|
|
134
|
+
let autoCollapsed = false;
|
|
135
|
+
onMount(() => {
|
|
136
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
137
|
+
const ro = new ResizeObserver((entries) => {
|
|
138
|
+
const below = props.collapseBelow as number | undefined;
|
|
139
|
+
if (below == null || props.sidebarCollapsed !== undefined) return;
|
|
140
|
+
const width = entries[0]?.contentRect.width ?? rootEl.clientWidth;
|
|
141
|
+
const isBelow = width < below;
|
|
142
|
+
if (isBelow && !collapsed()) {
|
|
143
|
+
autoCollapsed = true;
|
|
144
|
+
setCollapsedTo(true);
|
|
145
|
+
} else if (!isBelow && collapsed() && autoCollapsed) {
|
|
146
|
+
autoCollapsed = false;
|
|
147
|
+
setCollapsedTo(false);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
ro.observe(rootEl);
|
|
151
|
+
onCleanup(() => ro.disconnect());
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Imperative method API. The sidebar methods drive the same collapse path as the
|
|
155
|
+
// in-UI toggle (named *Sidebar to avoid the `sidebarCollapsed` prop accessor).
|
|
156
|
+
// The thread methods delegate to the embedded ChatThread's controller, captured
|
|
157
|
+
// once below — the thread node is shared across both <Show> branches, so a single
|
|
158
|
+
// controllerRef is stable across collapse/expand.
|
|
159
|
+
let controller: ChatThreadController | undefined;
|
|
160
|
+
expose({
|
|
161
|
+
/** Collapse/expand the conversation sidebar and fire `kai-sidebar-toggle`. */
|
|
162
|
+
toggleSidebar: () => toggle(),
|
|
163
|
+
/** Force the conversation sidebar collapsed (fires `kai-sidebar-toggle`). */
|
|
164
|
+
collapseSidebar: () => setCollapsedTo(true),
|
|
165
|
+
/** Force the conversation sidebar expanded (fires `kai-sidebar-toggle`). */
|
|
166
|
+
expandSidebar: () => setCollapsedTo(false),
|
|
167
|
+
/** Focus the thread's composer. */
|
|
168
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
169
|
+
/** Clear the thread draft + staged attachments. */
|
|
170
|
+
clear: () => controller?.clear(),
|
|
171
|
+
/** Submit the current thread draft programmatically (fires `kai-submit`). */
|
|
172
|
+
send: () => controller?.send(),
|
|
173
|
+
/** Scroll the thread to the newest message. */
|
|
174
|
+
scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
|
|
175
|
+
});
|
|
104
176
|
|
|
105
177
|
// Create the thread ONCE and reference the same node in both <Show> branches.
|
|
106
178
|
// It's owned by this component root (not by a Show branch), so toggling the
|
|
@@ -115,8 +187,8 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
115
187
|
chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
|
|
116
188
|
currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
|
|
117
189
|
scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
|
|
118
|
-
|
|
119
|
-
|
|
190
|
+
triggers={props.triggers as TriggerDef[] | undefined}
|
|
191
|
+
kindIcons={props.kindIcons as Record<string, string> | undefined}
|
|
120
192
|
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
121
193
|
onSubmit={(detail) => dispatch('kai-submit', detail)}
|
|
122
194
|
onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
|
|
@@ -124,38 +196,78 @@ defineWebComponent<Props, Events>('kai-workspace', {
|
|
|
124
196
|
onMessageAction={(detail) => dispatch('kai-message-action', detail)}
|
|
125
197
|
onSearch={() => dispatch('kai-search', {})}
|
|
126
198
|
onVoice={() => dispatch('kai-voice', {})}
|
|
127
|
-
|
|
199
|
+
controllerRef={(c) => (controller = c)}
|
|
128
200
|
/>
|
|
129
201
|
);
|
|
130
202
|
|
|
203
|
+
// The main region: an optional top-placed `main-header` band above the thread.
|
|
204
|
+
// Shared across both collapse branches (the thread node is the same instance).
|
|
205
|
+
const mainRegion = (
|
|
206
|
+
<div class="flex h-full flex-col overflow-hidden">
|
|
207
|
+
<Show when={slots()['main-header']}>
|
|
208
|
+
<div class="shrink-0 border-b border-border"><slot name="main-header" /></div>
|
|
209
|
+
</Show>
|
|
210
|
+
<div class="min-h-0 flex-1">
|
|
211
|
+
<Show when={slots()['main']} fallback={threadEl}>
|
|
212
|
+
<slot name="main" />
|
|
213
|
+
</Show>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
|
|
131
218
|
return (
|
|
132
|
-
<div class="h-full w-full overflow-hidden bg-background">
|
|
219
|
+
<div ref={rootEl} class="h-full w-full overflow-hidden bg-background">
|
|
133
220
|
<Show
|
|
134
221
|
when={!collapsed()}
|
|
135
222
|
fallback={
|
|
136
|
-
<div class="
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
223
|
+
<div class="flex h-full">
|
|
224
|
+
{/* Collapsed: the reopen control lives in its OWN thin rail column
|
|
225
|
+
(matching the sidebar's bg-surface) rather than floating over the
|
|
226
|
+
content. The previous `absolute` overlay sat on top of a
|
|
227
|
+
`main-header`'s leading title — see the t3code/codex/chatgpt apps,
|
|
228
|
+
all of which fill that slot — so it both overlapped the header and
|
|
229
|
+
competed with any in-header toggle. A dedicated column never
|
|
230
|
+
overlaps and reads as a collapsed sidebar. */}
|
|
231
|
+
<div class="flex w-11 shrink-0 flex-col items-center border-r border-border bg-surface pt-2.5">
|
|
232
|
+
<CollapsedRail onExpand={toggle} class="bg-transparent shadow-none backdrop-blur-none" />
|
|
233
|
+
</div>
|
|
234
|
+
<div class="min-w-0 flex-1">{mainRegion}</div>
|
|
145
235
|
</div>
|
|
146
236
|
}
|
|
147
237
|
>
|
|
148
238
|
<ResizablePanelGroup orientation="horizontal">
|
|
149
239
|
<ResizablePanel defaultSize={props.sidebarWidth as number} data-min-size={String(props.sidebarMinWidth)} data-max-size={String(props.sidebarMaxWidth)}>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
240
|
+
{/* The rail: an optional injected header above the list and footer
|
|
241
|
+
below it (upgrade card / Design trigger / user menu). Carries a
|
|
242
|
+
subtle, theme-aware default background (bg-surface), exposed as
|
|
243
|
+
::part(sidebar) so a consumer can override it. The inner list is
|
|
244
|
+
made transparent so the part background reads uniformly. */}
|
|
245
|
+
<div part="sidebar" class="flex h-full flex-col overflow-hidden bg-surface">
|
|
246
|
+
<Show when={slots()['sidebar-header']}>
|
|
247
|
+
{/* When `no-conversations` suppresses the built-in list, the
|
|
248
|
+
projected header owns the whole rail flex region; otherwise it
|
|
249
|
+
sits as a fixed band above the list. */}
|
|
250
|
+
<div class={flag('noConversations') ? 'min-h-0 flex-1' : 'shrink-0'}><slot name="sidebar-header" /></div>
|
|
251
|
+
</Show>
|
|
252
|
+
<Show when={!flag('noConversations')}>
|
|
253
|
+
<div class="min-h-0 flex-1">
|
|
254
|
+
<ConversationList
|
|
255
|
+
class="bg-transparent"
|
|
256
|
+
groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
|
|
257
|
+
compact={flag('compact')}
|
|
258
|
+
onSelect={(id) => dispatch('kai-conversation-select', { id })}
|
|
259
|
+
onNewChat={() => dispatch('kai-new-chat', {})}
|
|
260
|
+
onToggleSidebar={toggle}
|
|
261
|
+
/>
|
|
262
|
+
</div>
|
|
263
|
+
</Show>
|
|
264
|
+
<Show when={slots()['sidebar-footer']}>
|
|
265
|
+
<div class="shrink-0"><slot name="sidebar-footer" /></div>
|
|
266
|
+
</Show>
|
|
267
|
+
</div>
|
|
156
268
|
</ResizablePanel>
|
|
157
269
|
<ResizableHandle withHandle />
|
|
158
|
-
<ResizablePanel>{
|
|
270
|
+
<ResizablePanel>{mainRegion}</ResizablePanel>
|
|
159
271
|
</ResizablePanelGroup>
|
|
160
272
|
</Show>
|
|
161
273
|
</div>
|
package/src/elements/chat.tsx
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
1
|
+
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
|
-
import {
|
|
3
|
+
import { CHAT_SLOTS, readSlots } from './slots';
|
|
4
|
+
import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
|
|
4
5
|
import type { AttachmentData } from '../components/attachments';
|
|
5
|
-
import type {
|
|
6
|
+
import type { TriggerDef } from '../components/composer';
|
|
7
|
+
import type { ComposerDoc } from '../primitives/composer-model';
|
|
6
8
|
import type { ProseSize } from '../primitives/chat-config';
|
|
7
9
|
import type { ModelOption } from '../types';
|
|
8
10
|
|
|
9
11
|
type Props = Omit<ChatThreadProps,
|
|
10
|
-
'class' | 'onValueChange' | 'onSubmit' | 'onSuggestionClick' | 'onModelChange'
|
|
11
|
-
| 'onMessageAction' | 'onSearch' | 'onVoice' | '
|
|
12
|
+
'class' | 'onValueChange' | 'onSubmit' | 'onAttachmentsChange' | 'onSuggestionClick' | 'onModelChange'
|
|
13
|
+
| 'onMessageAction' | 'onSearch' | 'onVoice' | 'controllerRef'> & Record<string, unknown>;
|
|
12
14
|
|
|
13
15
|
interface Events {
|
|
14
16
|
/** User submitted a message. */
|
|
15
17
|
'kai-submit': { value: string; attachments: AttachmentData[] };
|
|
16
18
|
/** Fired on every input change. */
|
|
17
19
|
'kai-value-change': { value: string };
|
|
20
|
+
/** The staged attachments changed (file added or removed). Carries the full
|
|
21
|
+
* current list so a consumer can react in real time. */
|
|
22
|
+
'kai-attachments-change': { attachments: AttachmentData[] };
|
|
18
23
|
/** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
|
|
19
24
|
'kai-suggestion-click': { value: string };
|
|
20
25
|
/** An action button on a message was clicked. `action` is the built-in name or
|
|
@@ -23,8 +28,6 @@ interface Events {
|
|
|
23
28
|
'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
|
|
24
29
|
/** The header model switcher changed. */
|
|
25
30
|
'kai-model-change': { modelId: string };
|
|
26
|
-
/** A slash command was chosen from the palette. */
|
|
27
|
-
'kai-slash-select': { command: SlashCommandItem };
|
|
28
31
|
/** The Search button was clicked. */
|
|
29
32
|
'kai-search': Record<string, never>;
|
|
30
33
|
/** The Mic / voice button was clicked. */
|
|
@@ -36,27 +39,39 @@ defineWebComponent<Props, Events>('kai-chat', {
|
|
|
36
39
|
suggestions: undefined, suggestionMode: 'submit', persistSuggestions: false, proseSize: 'sm',
|
|
37
40
|
codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
|
|
38
41
|
models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
|
|
39
|
-
search: false, voice: false,
|
|
42
|
+
search: false, voice: false, triggers: undefined, kindIcons: undefined,
|
|
40
43
|
actionsReveal: 'always',
|
|
41
|
-
}, (props, { dispatch, flag, element }) => {
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
const [
|
|
45
|
-
const
|
|
44
|
+
}, (props, { dispatch, flag, element, expose }) => {
|
|
45
|
+
// Slot detection is driven by the CHAT_SLOTS registry (single source of truth)
|
|
46
|
+
// so slot names never drift between the view, the facade, and the docs.
|
|
47
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
48
|
+
const slot = (name: string) => slots()[name] === true;
|
|
46
49
|
onMount(() => {
|
|
47
|
-
const read = () =>
|
|
48
|
-
setHasHeaderStart(!!element.querySelector(':scope > [slot="header-start"]'));
|
|
49
|
-
setHasHeaderEnd(!!element.querySelector(':scope > [slot="header-end"]'));
|
|
50
|
-
};
|
|
50
|
+
const read = () => setSlots(readSlots(element, CHAT_SLOTS));
|
|
51
51
|
read();
|
|
52
52
|
const observer = new MutationObserver(read);
|
|
53
53
|
observer.observe(element, { childList: true });
|
|
54
54
|
onCleanup(() => observer.disconnect());
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Reflect streaming state to a host attribute so slotted composer/notice CSS
|
|
58
|
+
// can react without reading internals (e.g. :host([loading]) ::slotted(...)).
|
|
59
|
+
createEffect(() => { element.toggleAttribute('loading', flag('loading')); });
|
|
60
|
+
|
|
61
|
+
// Imperative method API — forward the chat-thread controller onto the host
|
|
62
|
+
// (focus the composer, clear it, send programmatically, scroll the thread).
|
|
63
|
+
let controller: ChatThreadController | undefined;
|
|
64
|
+
expose({
|
|
65
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
66
|
+
blur: () => (element.shadowRoot?.activeElement as HTMLElement | null)?.blur(),
|
|
67
|
+
clear: () => controller?.clear(),
|
|
68
|
+
send: () => controller?.send(),
|
|
69
|
+
scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
|
|
70
|
+
});
|
|
71
|
+
|
|
57
72
|
return (
|
|
58
73
|
<ChatThread
|
|
59
|
-
messages={props.messages} value={props.value as string | undefined} placeholder={props.placeholder as string}
|
|
74
|
+
messages={props.messages} value={props.value as string | ComposerDoc | undefined} placeholder={props.placeholder as string}
|
|
60
75
|
loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
|
|
61
76
|
suggestionMode={props.suggestionMode as 'submit' | 'fill'} persistSuggestions={flag('persistSuggestions')}
|
|
62
77
|
proseSize={props.proseSize as ProseSize}
|
|
@@ -64,19 +79,26 @@ defineWebComponent<Props, Events>('kai-chat', {
|
|
|
64
79
|
chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
|
|
65
80
|
currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
|
|
66
81
|
scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
triggers={props.triggers as TriggerDef[] | undefined}
|
|
83
|
+
kindIcons={props.kindIcons as Record<string, string> | undefined}
|
|
69
84
|
actionsReveal={props.actionsReveal as 'always' | 'hover'}
|
|
70
85
|
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
71
86
|
onSubmit={(detail) => dispatch('kai-submit', detail)}
|
|
87
|
+
onAttachmentsChange={(attachments) => dispatch('kai-attachments-change', { attachments })}
|
|
72
88
|
onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
|
|
73
89
|
onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
|
|
74
90
|
onMessageAction={(detail) => dispatch('kai-message-action', detail)}
|
|
75
91
|
onSearch={() => dispatch('kai-search', {})}
|
|
76
92
|
onVoice={() => dispatch('kai-voice', {})}
|
|
77
|
-
|
|
78
|
-
headerStart={
|
|
79
|
-
headerEnd={
|
|
93
|
+
controllerRef={(c) => (controller = c)}
|
|
94
|
+
headerStart={slot('header-start')}
|
|
95
|
+
headerEnd={slot('header-end')}
|
|
96
|
+
headerFull={slot('header')}
|
|
97
|
+
sidebar={slot('sidebar')}
|
|
98
|
+
empty={slot('empty')}
|
|
99
|
+
composer={slot('composer')}
|
|
100
|
+
composerActions={slot('composer-actions')}
|
|
101
|
+
footer={slot('footer')}
|
|
80
102
|
/>
|
|
81
103
|
);
|
|
82
104
|
});
|
package/src/elements/choice.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineWebComponent } from './define';
|
|
2
|
-
import { ChoiceCard, type ChoiceCardData } from '../components/choice-card';
|
|
2
|
+
import { ChoiceCard, type ChoiceCardData, type ChoiceController } from '../components/choice-card';
|
|
3
3
|
import type { CardResolution } from '../primitives/card-contract';
|
|
4
4
|
|
|
5
5
|
interface Props extends Record<string, unknown> {
|
|
@@ -14,35 +14,87 @@ interface Props extends Record<string, unknown> {
|
|
|
14
14
|
/** Set when the user resolved this card; renders the read-only view. Property:
|
|
15
15
|
* `el.resolution = { kind:'action', action:'…' }`. */
|
|
16
16
|
resolution?: Record<string, unknown>;
|
|
17
|
+
/** Controlled selection — the selected option id. When set, the consumer owns
|
|
18
|
+
* the current pick (RadioGroup `value`). Attribute: `value`. */
|
|
19
|
+
value?: string;
|
|
20
|
+
/** Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. */
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
/** Disable the whole radiogroup + Submit (e.g. while the agent is busy).
|
|
23
|
+
* Attribute: `disabled`. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Events fired by `<kai-choice>`. (The terminal submit/dismiss/reopen flow is
|
|
28
|
+
* emitted via the bubbling `kai-card` contract event — listen for `kai-card`.) */
|
|
29
|
+
interface Events {
|
|
30
|
+
/** The selection changed BEFORE submit (a row click or the `select()` method).
|
|
31
|
+
* Distinct from the terminal `action` verb on the `kai-card` contract event. */
|
|
32
|
+
'kai-value-change': { value: string };
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
/**
|
|
20
36
|
* `<kai-choice>` — a single-select **"pick one of N rich options"** card (set via the
|
|
21
37
|
* `data` property): a prompt + a radiogroup of list rows. Clicking a row **selects** it
|
|
22
|
-
* (no emit); the **Submit** button below then emits the Card
|
|
23
|
-
* up a bubbling **`kai-card`** CustomEvent (`{ kind:'action',
|
|
24
|
-
* payload? }`) and resolves the card so the same pick can't
|
|
25
|
-
* `allowOther` free-text escape appends a selectable "Other…" row
|
|
26
|
-
* input; the same Submit emits `action:'__other__'` with `{ text }`.
|
|
27
|
-
* mount and `error` for a malformed definition (inline error). Routes
|
|
28
|
-
* `CardProvider` when present, else the bubbling `kai-card` event. Isolated in
|
|
29
|
-
* theme-aware via the shared tokens.
|
|
38
|
+
* (no emit, fires `kai-value-change`); the **Submit** button below then emits the Card
|
|
39
|
+
* contract's **`action`** verb up a bubbling **`kai-card`** CustomEvent (`{ kind:'action',
|
|
40
|
+
* cardId, action: option.id, payload? }`) and resolves the card so the same pick can't
|
|
41
|
+
* double-fire. An optional `allowOther` free-text escape appends a selectable "Other…" row
|
|
42
|
+
* that reveals an inline input; the same Submit emits `action:'__other__'` with `{ text }`.
|
|
43
|
+
* Also emits `ready` on mount and `error` for a malformed definition (inline error). Routes
|
|
44
|
+
* through a `CardProvider` when present, else the bubbling `kai-card` event. Isolated in
|
|
45
|
+
* Shadow DOM; theme-aware via the shared tokens.
|
|
46
|
+
*
|
|
47
|
+
* Supports controlled selection (`value`), an uncontrolled seed (`defaultValue`), a
|
|
48
|
+
* group-level `disabled`, and instance methods `focus()`/`select(id)`/`send()`/
|
|
49
|
+
* `dismiss()`/`reopen()`.
|
|
30
50
|
*/
|
|
31
|
-
defineWebComponent<Props>(
|
|
51
|
+
defineWebComponent<Props, Events>(
|
|
32
52
|
'kai-choice',
|
|
33
53
|
{
|
|
34
54
|
data: undefined,
|
|
35
55
|
cardId: undefined,
|
|
36
56
|
heading: undefined,
|
|
37
57
|
resolution: undefined,
|
|
58
|
+
value: undefined,
|
|
59
|
+
defaultValue: undefined,
|
|
60
|
+
disabled: undefined,
|
|
61
|
+
},
|
|
62
|
+
(props, { element, dispatch, flag, expose }) => {
|
|
63
|
+
// Pattern C: the ChoiceCard owns selection/submit/dismiss state and hands up a
|
|
64
|
+
// controller; the facade captures it and exposes delegating methods. The card's
|
|
65
|
+
// own paths still fire (select → kai-value-change; send → kai-card `action`;
|
|
66
|
+
// dismiss/reopen → kai-card `dismiss`/`reopen`).
|
|
67
|
+
let controller: ChoiceController | undefined;
|
|
68
|
+
expose({
|
|
69
|
+
/** Focus the radiogroup roving tab stop (or the Other input when selected). */
|
|
70
|
+
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
71
|
+
/** Select an option by id locally — no emit, fires kai-value-change (same as
|
|
72
|
+
* a row click). Lets a consumer pre-highlight or drive selection externally. */
|
|
73
|
+
select: (optionId: string) => controller?.select(optionId),
|
|
74
|
+
/** Submit the current selection — emits the `action` verb on kai-card and
|
|
75
|
+
* resolves the card (single-shot). Named `send`, not `submit`, per the shared
|
|
76
|
+
* vocabulary. */
|
|
77
|
+
send: () => controller?.send(),
|
|
78
|
+
/** Trigger the dismiss path — emits `dismiss` on kai-card and optimistically
|
|
79
|
+
* collapses the card to its re-openable stub. */
|
|
80
|
+
dismiss: () => controller?.dismiss(),
|
|
81
|
+
/** Re-open a dismissed card from its stub — emits `reopen` on kai-card. */
|
|
82
|
+
reopen: () => controller?.reopen(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<ChoiceCard
|
|
87
|
+
data={props.data as ChoiceCardData | undefined}
|
|
88
|
+
cardId={props.cardId ?? (element.id || 'kai-choice')}
|
|
89
|
+
heading={props.heading}
|
|
90
|
+
resolution={props.resolution as CardResolution | undefined}
|
|
91
|
+
value={props.value}
|
|
92
|
+
defaultValue={props.defaultValue}
|
|
93
|
+
disabled={flag('disabled')}
|
|
94
|
+
onValueChange={(value) => dispatch('kai-value-change', { value })}
|
|
95
|
+
controllerRef={(c) => (controller = c)}
|
|
96
|
+
hostElement={element}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
38
99
|
},
|
|
39
|
-
(props, { element }) => (
|
|
40
|
-
<ChoiceCard
|
|
41
|
-
data={props.data as ChoiceCardData | undefined}
|
|
42
|
-
cardId={props.cardId ?? (element.id || 'kai-choice')}
|
|
43
|
-
heading={props.heading}
|
|
44
|
-
resolution={props.resolution as CardResolution | undefined}
|
|
45
|
-
hostElement={element}
|
|
46
|
-
/>
|
|
47
|
-
),
|
|
48
100
|
);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
|
+
import { Coachmark, type CoachmarkController } from '../components/coachmark';
|
|
3
|
+
import { wireDisclosure } from './disclosure';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
|
|
7
|
+
* attribute; the element still self-manages). Set `el.open = true`, or
|
|
8
|
+
* `<kai-coachmark open>`; listen for `kai-open-change`. */
|
|
9
|
+
open?: boolean;
|
|
10
|
+
/** Initial open state on mount (uncontrolled seed). */
|
|
11
|
+
defaultOpen?: boolean;
|
|
12
|
+
/** The bold title. Named `headline` because `title` collides with the global
|
|
13
|
+
* `HTMLElement.title` attribute (it throws at registration). */
|
|
14
|
+
headline?: string;
|
|
15
|
+
/** A small badge pill beside the headline (e.g. "New"). */
|
|
16
|
+
badge?: string;
|
|
17
|
+
/** Floating placement relative to the anchor (default `bottom`). */
|
|
18
|
+
placement?: string;
|
|
19
|
+
/** Color tone: `primary` (default, theme accent), `info` (blue), `success`
|
|
20
|
+
* (green), `warning` (amber), or `error` (red) — reusing the kit's tool hues. */
|
|
21
|
+
tone?: 'primary' | 'info' | 'success' | 'warning' | 'error';
|
|
22
|
+
/** Render the arrow that points at the anchor (default `true`). Set
|
|
23
|
+
* `arrow="false"` for a plain bubble with no pointer. */
|
|
24
|
+
arrow?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Events fired by `<kai-coachmark>`. */
|
|
28
|
+
interface Events {
|
|
29
|
+
/** The × dismiss button was pressed. The consumer records that this hint was
|
|
30
|
+
* seen so it won't show again. */
|
|
31
|
+
'kai-dismiss': Record<string, never>;
|
|
32
|
+
/** The coachmark opened or closed (a method, the ×, or a driven `open`). */
|
|
33
|
+
'kai-open-change': { open: boolean };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `<kai-coachmark>` — an anchored onboarding hint bubble with an arrow. It WRAPS
|
|
38
|
+
* a trigger (the default slot) and points a primary-colored bubble at it: a small
|
|
39
|
+
* `badge` pill, a bold `headline`, the `content` slot body, and a dismiss ×.
|
|
40
|
+
*
|
|
41
|
+
* ```html
|
|
42
|
+
* <kai-coachmark default-open headline="Cowork has a new home" badge="New">
|
|
43
|
+
* <button>Cowork</button>
|
|
44
|
+
* <span slot="content">Chat with Claude or switch to Cowork from here.</span>
|
|
45
|
+
* </kai-coachmark>
|
|
46
|
+
* <script type="module">
|
|
47
|
+
* document.querySelector('kai-coachmark')
|
|
48
|
+
* .addEventListener('kai-dismiss', () => localStorage.setItem('cowork-hint', 'seen'));
|
|
49
|
+
* </script>
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* Open state is the standard disclosure surface: settable+reflecting `open`,
|
|
53
|
+
* `kai-open-change`, and `show()`/`hide()`/`toggle()`; seed with `default-open`.
|
|
54
|
+
* Parts: `bubble` · `arrow` · `badge` · `title` · `dismiss`.
|
|
55
|
+
*/
|
|
56
|
+
defineWebComponent<Props, Events>('kai-coachmark', {
|
|
57
|
+
open: undefined,
|
|
58
|
+
defaultOpen: undefined,
|
|
59
|
+
headline: undefined,
|
|
60
|
+
badge: undefined,
|
|
61
|
+
placement: undefined,
|
|
62
|
+
tone: undefined,
|
|
63
|
+
arrow: true,
|
|
64
|
+
}, (props, ctx) => {
|
|
65
|
+
const { flag, dispatch } = ctx;
|
|
66
|
+
let api: CoachmarkController | undefined;
|
|
67
|
+
|
|
68
|
+
// The standard disclosure surface: settable+reflecting `open`, kai-open-change,
|
|
69
|
+
// show/hide/toggle. See ./disclosure. This is the SOLE emitter of kai-open-change.
|
|
70
|
+
wireDisclosure(ctx, () => api, () => props.open);
|
|
71
|
+
|
|
72
|
+
// headline/badge are scalar string props (NOT slots) — pass through directly so
|
|
73
|
+
// the component's own `Show when={…}` gating drives whether each region renders.
|
|
74
|
+
// The body is the `content` slot; an empty `<slot>` renders nothing.
|
|
75
|
+
return (
|
|
76
|
+
<Coachmark
|
|
77
|
+
defaultOpen={flag('defaultOpen')}
|
|
78
|
+
arrow={flag('arrow')}
|
|
79
|
+
placement={props.placement as never}
|
|
80
|
+
tone={props.tone as 'primary' | 'info' | 'success' | 'warning' | 'error' | undefined}
|
|
81
|
+
headline={props.headline as string | undefined}
|
|
82
|
+
badge={props.badge as string | undefined}
|
|
83
|
+
content={<slot name="content" />}
|
|
84
|
+
controllerRef={(a) => (api = a)}
|
|
85
|
+
onDismiss={() => dispatch('kai-dismiss', {})}
|
|
86
|
+
>
|
|
87
|
+
<slot />
|
|
88
|
+
</Coachmark>
|
|
89
|
+
);
|
|
90
|
+
});
|