@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,202 @@
|
|
|
1
|
+
import { splitProps, Show, createSignal, createEffect, on, onCleanup } from 'solid-js';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
import { Button } from '../ui/button';
|
|
4
|
+
import { Tooltip } from '../ui/tooltip';
|
|
5
|
+
|
|
6
|
+
/** Imperative handle exposed via `controllerRef` — surfaces the playback controls
|
|
7
|
+
* so the `<kai-voice-output>` facade can forward them as instance methods. Both
|
|
8
|
+
* the native (speechSynthesis) and model (synthesize → Audio) paths run through
|
|
9
|
+
* these, so manual clicks and programmatic calls behave identically. */
|
|
10
|
+
export interface VoiceOutputController {
|
|
11
|
+
/** Speak the current `text` (native by default, model if `synthesize` is set). */
|
|
12
|
+
speak(): void;
|
|
13
|
+
/** Pause playback (resumable). */
|
|
14
|
+
pause(): void;
|
|
15
|
+
/** Resume paused playback. */
|
|
16
|
+
resume(): void;
|
|
17
|
+
/** Stop playback and reset. */
|
|
18
|
+
stop(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface VoiceOutputProps {
|
|
22
|
+
/** The utterance to read aloud. */
|
|
23
|
+
text: string;
|
|
24
|
+
/** Speak automatically when `text` is set/changed. */
|
|
25
|
+
autoplay?: boolean;
|
|
26
|
+
/** TTS model seam: given text, return an audio Blob to play. When set, the
|
|
27
|
+
* native speechSynthesis path is bypassed. Mirrors VoiceInput's `onTranscribe`. */
|
|
28
|
+
onSynthesize?: (text: string) => Promise<Blob>;
|
|
29
|
+
/** Fires whenever playback starts or stops. */
|
|
30
|
+
onSpeakingChange?: (speaking: boolean) => void;
|
|
31
|
+
/** Fires once the model path resolves audio (model path only). */
|
|
32
|
+
onSynthesized?: (blob: Blob) => void;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
class?: string;
|
|
35
|
+
/** Receive the imperative controller once mounted. The `<kai-voice-output>`
|
|
36
|
+
* facade forwards these as element methods (speak/pause/resume/stop). */
|
|
37
|
+
controllerRef?: (controller: VoiceOutputController) => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** True when the browser exposes the Web Speech synthesis API. */
|
|
41
|
+
function hasSpeechSynthesis(): boolean {
|
|
42
|
+
return typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function VoiceOutput(props: VoiceOutputProps) {
|
|
46
|
+
const [local] = splitProps(props, ['text', 'disabled', 'class']);
|
|
47
|
+
const [isSpeaking, setIsSpeaking] = createSignal(false);
|
|
48
|
+
const [isLoading, setIsLoading] = createSignal(false);
|
|
49
|
+
|
|
50
|
+
// The model path plays through one reused <Audio>; the native path drives
|
|
51
|
+
// speechSynthesis. Only one is live at a time (branch on onSynthesize).
|
|
52
|
+
let audio: HTMLAudioElement | undefined;
|
|
53
|
+
let objectUrl: string | undefined;
|
|
54
|
+
let utterance: SpeechSynthesisUtterance | undefined;
|
|
55
|
+
|
|
56
|
+
// No way to speak at all → render disabled. A model seam OR native synthesis
|
|
57
|
+
// is enough; absent both, the control is inert (see the facade/spec).
|
|
58
|
+
const capable = () => !!props.onSynthesize || hasSpeechSynthesis();
|
|
59
|
+
|
|
60
|
+
const label = () =>
|
|
61
|
+
isLoading() ? 'Synthesizing...' : isSpeaking() ? 'Stop' : 'Read aloud';
|
|
62
|
+
|
|
63
|
+
function revokeUrl() {
|
|
64
|
+
if (objectUrl) {
|
|
65
|
+
URL.revokeObjectURL(objectUrl);
|
|
66
|
+
objectUrl = undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Native path: speechSynthesis.speak(new SpeechSynthesisUtterance(text)).
|
|
71
|
+
function speakNative() {
|
|
72
|
+
if (!hasSpeechSynthesis() || !local.text) return;
|
|
73
|
+
window.speechSynthesis.cancel();
|
|
74
|
+
utterance = new SpeechSynthesisUtterance(local.text);
|
|
75
|
+
utterance.onend = () => setIsSpeaking(false);
|
|
76
|
+
utterance.onerror = () => setIsSpeaking(false);
|
|
77
|
+
setIsSpeaking(true);
|
|
78
|
+
window.speechSynthesis.speak(utterance);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Model path: await onSynthesize(text) → play the Blob via an <Audio>.
|
|
82
|
+
async function speakModel() {
|
|
83
|
+
if (!props.onSynthesize || !local.text) return;
|
|
84
|
+
setIsLoading(true);
|
|
85
|
+
try {
|
|
86
|
+
const blob = await props.onSynthesize(local.text);
|
|
87
|
+
props.onSynthesized?.(blob);
|
|
88
|
+
revokeUrl();
|
|
89
|
+
objectUrl = URL.createObjectURL(blob);
|
|
90
|
+
audio ??= new Audio();
|
|
91
|
+
audio.src = objectUrl;
|
|
92
|
+
audio.onended = () => setIsSpeaking(false);
|
|
93
|
+
audio.onerror = () => setIsSpeaking(false);
|
|
94
|
+
setIsSpeaking(true);
|
|
95
|
+
await audio.play();
|
|
96
|
+
} catch {
|
|
97
|
+
setIsSpeaking(false);
|
|
98
|
+
} finally {
|
|
99
|
+
setIsLoading(false);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function speak() {
|
|
104
|
+
if (props.onSynthesize) void speakModel();
|
|
105
|
+
else speakNative();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function stop() {
|
|
109
|
+
if (props.onSynthesize) {
|
|
110
|
+
if (audio) {
|
|
111
|
+
audio.pause();
|
|
112
|
+
audio.currentTime = 0;
|
|
113
|
+
}
|
|
114
|
+
} else if (hasSpeechSynthesis()) {
|
|
115
|
+
window.speechSynthesis.cancel();
|
|
116
|
+
}
|
|
117
|
+
setIsSpeaking(false);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function pause() {
|
|
121
|
+
if (props.onSynthesize) audio?.pause();
|
|
122
|
+
else if (hasSpeechSynthesis()) window.speechSynthesis.pause();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function resume() {
|
|
126
|
+
if (props.onSynthesize) void audio?.play();
|
|
127
|
+
else if (hasSpeechSynthesis()) window.speechSynthesis.resume();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function handleClick() {
|
|
131
|
+
if (isSpeaking()) stop();
|
|
132
|
+
else speak();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Emit speaking transitions to the host. `defer: true` skips the spurious
|
|
136
|
+
// initial `false` — only real start/stop transitions fire.
|
|
137
|
+
createEffect(on(isSpeaking, (speaking) => {
|
|
138
|
+
props.onSpeakingChange?.(speaking);
|
|
139
|
+
}, { defer: true }));
|
|
140
|
+
|
|
141
|
+
// Autoplay: speak when text first arrives / changes (defer skips the mount
|
|
142
|
+
// value so an empty seed doesn't speak).
|
|
143
|
+
createEffect(on(() => local.text, (text) => {
|
|
144
|
+
if (props.autoplay && text) speak();
|
|
145
|
+
}, { defer: true }));
|
|
146
|
+
|
|
147
|
+
props.controllerRef?.({ speak, pause, resume, stop });
|
|
148
|
+
|
|
149
|
+
onCleanup(() => {
|
|
150
|
+
stop();
|
|
151
|
+
revokeUrl();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Speaker icon (idle)
|
|
155
|
+
const SpeakerIcon = () => (
|
|
156
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
157
|
+
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
|
|
158
|
+
<path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07" />
|
|
159
|
+
</svg>
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Square stop icon (speaking)
|
|
163
|
+
const StopIcon = () => (
|
|
164
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
|
|
165
|
+
<rect x="4" y="4" width="16" height="16" rx="2" />
|
|
166
|
+
</svg>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Spinner (model synthesis in flight)
|
|
170
|
+
const Spinner = () => (
|
|
171
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="animate-spin">
|
|
172
|
+
<path d="M21 12a9 9 0 11-6.219-8.56" />
|
|
173
|
+
</svg>
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div class={cn('relative inline-flex items-center justify-center', local.class)}>
|
|
178
|
+
<Tooltip content={label()}>
|
|
179
|
+
<Button
|
|
180
|
+
part="button"
|
|
181
|
+
variant="ghost"
|
|
182
|
+
size="icon-sm"
|
|
183
|
+
aria-label={label()}
|
|
184
|
+
aria-pressed={isSpeaking()}
|
|
185
|
+
onClick={handleClick}
|
|
186
|
+
disabled={local.disabled || !capable() || isLoading()}
|
|
187
|
+
class={cn('relative z-10 rounded-full transition-all duration-300')}
|
|
188
|
+
>
|
|
189
|
+
<Show when={isLoading()}>
|
|
190
|
+
<Spinner />
|
|
191
|
+
</Show>
|
|
192
|
+
<Show when={!isLoading() && isSpeaking()}>
|
|
193
|
+
<StopIcon />
|
|
194
|
+
</Show>
|
|
195
|
+
<Show when={!isLoading() && !isSpeaking()}>
|
|
196
|
+
<SpeakerIcon />
|
|
197
|
+
</Show>
|
|
198
|
+
</Button>
|
|
199
|
+
</Tooltip>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
|
+
import { AgentCard, type AgentStatus } from '../ui/agent-card';
|
|
3
|
+
|
|
4
|
+
interface Props extends Record<string, unknown> {
|
|
5
|
+
/** The agent's name — the primary label. Attribute: `name`. */
|
|
6
|
+
name?: string;
|
|
7
|
+
/** Selected / focused state: highlighted border + surface. Attribute: `active`. */
|
|
8
|
+
active?: boolean;
|
|
9
|
+
/** Raise a prominent "Needs you" pill plus a glowing amber edge — the
|
|
10
|
+
* attention-routing signal that pulls focus to this agent. Attribute:
|
|
11
|
+
* `needs-attention`. */
|
|
12
|
+
needsAttention?: boolean;
|
|
13
|
+
/** Run status — a JS PROPERTY (object), not an attribute. Shape:
|
|
14
|
+
* `{ tone, label?, pulse? }`, where `tone` is one of `working` | `idle` |
|
|
15
|
+
* `done` | `error` | `blocked` (maps to the kit's tool hues), `label` is an
|
|
16
|
+
* optional short string beside the dot, and `pulse` animates the dot. Set it
|
|
17
|
+
* with `el.status = { tone: 'working', label: 'Working', pulse: true }`. */
|
|
18
|
+
status?: AgentStatus;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Events fired by `<kai-agent-card>`. */
|
|
22
|
+
interface Events {
|
|
23
|
+
/** The card was activated — clicked, or Enter / Space while focused. Promote
|
|
24
|
+
* this agent back to focus. */
|
|
25
|
+
'kai-activate': void;
|
|
26
|
+
/** The trailing "..." kebab was clicked. The consumer opens its own menu; the
|
|
27
|
+
* card only surfaces the affordance (the click does not also activate the card). */
|
|
28
|
+
'kai-menu': void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `<kai-agent-card>` — the compact glanceable card for one agent in a multi-agent
|
|
33
|
+
* workspace. The agent name with a leading tone-colored status dot, an optional
|
|
34
|
+
* "Needs you" attention treatment, an `active` (selected) state, and a trailing
|
|
35
|
+
* "..." overflow button.
|
|
36
|
+
*
|
|
37
|
+
* Set `status` as a JS property (it's an object); `name` is a string attribute and
|
|
38
|
+
* `active` / `needs-attention` are boolean attributes. Listen for `kai-activate`
|
|
39
|
+
* (promote to focus) and `kai-menu` (open your own per-agent menu).
|
|
40
|
+
*
|
|
41
|
+
* ```html
|
|
42
|
+
* <kai-agent-card name="Refactor bot" active></kai-agent-card>
|
|
43
|
+
* <script type="module">
|
|
44
|
+
* import '@kitn.ai/ui/elements';
|
|
45
|
+
* const card = document.querySelector('kai-agent-card');
|
|
46
|
+
* card.status = { tone: 'working', label: 'Working', pulse: true };
|
|
47
|
+
* card.addEventListener('kai-activate', () => focusAgent());
|
|
48
|
+
* card.addEventListener('kai-menu', () => openMenu());
|
|
49
|
+
* </script>
|
|
50
|
+
* ```
|
|
51
|
+
* Recolor the status dot via `::part(status)` and the kebab via `::part(menu)`.
|
|
52
|
+
*/
|
|
53
|
+
defineWebComponent<Props, Events>('kai-agent-card', {
|
|
54
|
+
name: undefined,
|
|
55
|
+
active: undefined,
|
|
56
|
+
needsAttention: undefined,
|
|
57
|
+
status: undefined,
|
|
58
|
+
}, (props, { dispatch, flag }) => (
|
|
59
|
+
<AgentCard
|
|
60
|
+
name={(props.name as string) ?? ''}
|
|
61
|
+
active={flag('active')}
|
|
62
|
+
needsAttention={flag('needsAttention')}
|
|
63
|
+
status={(props.status as AgentStatus) ?? { tone: 'idle' }}
|
|
64
|
+
onActivate={() => dispatch('kai-activate')}
|
|
65
|
+
onMenu={() => dispatch('kai-menu')}
|
|
66
|
+
/>
|
|
67
|
+
));
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { createSignal, onMount, onCleanup } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
|
-
import { Artifact, type ArtifactFile, type ArtifactTab } from '../components/artifact';
|
|
3
|
+
import { Artifact, type ArtifactController, type ArtifactFile, type ArtifactTab } from '../components/artifact';
|
|
4
4
|
|
|
5
5
|
interface Props extends Record<string, unknown> {
|
|
6
6
|
/** URL the preview iframe frames. Consumer-controlled. */
|
|
7
7
|
src?: string;
|
|
8
8
|
/** Files for the Code tab tree + each file's preview `url`. Set as a JS property (array). */
|
|
9
9
|
files: ArtifactFile[];
|
|
10
|
-
/**
|
|
10
|
+
/** Controlled active tab: `preview` or `code`. When set, the artifact follows it
|
|
11
|
+
* (re-asserted on change). Leave unset for an uncontrolled tab (see `defaultTab`). */
|
|
11
12
|
tab?: ArtifactTab;
|
|
13
|
+
/** Uncontrolled INITIAL tab (used only when `tab` is unset). Default `preview`.
|
|
14
|
+
* Seeds the starting tab; the user can then switch freely without the consumer
|
|
15
|
+
* re-asserting a controlled `tab`. */
|
|
16
|
+
defaultTab?: ArtifactTab;
|
|
12
17
|
/** Selected file path — syncs the tree highlight, Code source, and preview. */
|
|
13
18
|
activeFile?: string;
|
|
14
19
|
/** iframe `sandbox` override. Secure default `allow-scripts allow-forms` (NOT `allow-same-origin`). */
|
|
@@ -35,6 +40,11 @@ interface Props extends Record<string, unknown> {
|
|
|
35
40
|
standalone?: boolean;
|
|
36
41
|
/** Show the address but make it read-only (visible, nav-tracking, non-editable). */
|
|
37
42
|
readonlyPath?: boolean;
|
|
43
|
+
/** Friendly address shown in the path field instead of the real current url
|
|
44
|
+
* (read-only, non-navigable). Use when the framed url is not consumer-facing
|
|
45
|
+
* (e.g. a `data:` blob) so a clean address shows instead of leaking it. Scalar
|
|
46
|
+
* string: set as the `display-url` attribute or the `displayUrl` property. */
|
|
47
|
+
displayUrl?: string;
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
interface Events extends Record<string, unknown> {
|
|
@@ -59,7 +69,8 @@ interface Events extends Record<string, unknown> {
|
|
|
59
69
|
defineWebComponent<Props, Events>('kai-artifact', {
|
|
60
70
|
src: undefined,
|
|
61
71
|
files: [],
|
|
62
|
-
tab:
|
|
72
|
+
tab: undefined,
|
|
73
|
+
defaultTab: undefined,
|
|
63
74
|
activeFile: undefined,
|
|
64
75
|
sandbox: 'allow-scripts allow-forms',
|
|
65
76
|
iframeTitle: undefined,
|
|
@@ -73,9 +84,44 @@ defineWebComponent<Props, Events>('kai-artifact', {
|
|
|
73
84
|
noTabs: false,
|
|
74
85
|
standalone: false,
|
|
75
86
|
readonlyPath: false,
|
|
76
|
-
|
|
87
|
+
displayUrl: undefined,
|
|
88
|
+
}, (props, { element, dispatch, flag, expose }) => {
|
|
77
89
|
const [maximized, setMaximized] = createSignal(flag('maximized'));
|
|
78
90
|
|
|
91
|
+
// ── Imperative API (instance methods on the host) ──────────────────────────
|
|
92
|
+
// Pattern C: the Artifact component owns the history stack + tab/file/maximize
|
|
93
|
+
// state and hands up a controller; the facade captures it and exposes delegating
|
|
94
|
+
// methods. Every internal handler still fires its event (navigate → kai-navigate;
|
|
95
|
+
// selectFile → kai-file-select; maximize/restore → kai-maximize-change). Names are
|
|
96
|
+
// collision-checked against the props: openExternal (not openInTab — a prop),
|
|
97
|
+
// maximize/restore (not maximized — a prop), navigate/selectFile (not src/activeFile
|
|
98
|
+
// — props); NO tab-switching method (tab is a prop → switch via `el.tab`).
|
|
99
|
+
let controller: ArtifactController | undefined;
|
|
100
|
+
expose({
|
|
101
|
+
/** Go back in the artifact's own history stack (no-op when there's no prior entry). */
|
|
102
|
+
back: () => controller?.back(),
|
|
103
|
+
/** Go forward in the history stack (no-op when there's no forward entry). */
|
|
104
|
+
forward: () => controller?.forward(),
|
|
105
|
+
/** Force-reload the current preview url (also re-renders an inline PDF). */
|
|
106
|
+
reload: () => controller?.reload(),
|
|
107
|
+
/** Navigate to the `src` home url (no-op when there's no `src`). */
|
|
108
|
+
home: () => controller?.home(),
|
|
109
|
+
/** Push + load a url in the preview — the path-field submit path (fires kai-navigate). */
|
|
110
|
+
navigate: (url: string) => controller?.navigate(url),
|
|
111
|
+
/** Select a file by path: highlights the tree, shows its source, navigates the
|
|
112
|
+
* preview (fires kai-file-select + kai-navigate). Named selectFile to avoid the
|
|
113
|
+
* `activeFile` prop. */
|
|
114
|
+
selectFile: (path: string) => controller?.selectFile(path),
|
|
115
|
+
/** Open the current url in a new browser tab (no-op when there's no concrete url).
|
|
116
|
+
* Named openExternal, NOT openInTab — that's a prop (toolbar button visibility). */
|
|
117
|
+
openExternal: () => controller?.openExternal(),
|
|
118
|
+
/** Enter the maximized view-state (fires kai-maximize-change{maximized:true}).
|
|
119
|
+
* Named maximize, NOT maximized — that's a prop. */
|
|
120
|
+
maximize: () => controller?.maximize(),
|
|
121
|
+
/** Exit the maximized view-state (fires kai-maximize-change{maximized:false}). */
|
|
122
|
+
restore: () => controller?.restore(),
|
|
123
|
+
});
|
|
124
|
+
|
|
79
125
|
const onMaximizeChange = (next: boolean) => {
|
|
80
126
|
setMaximized(next);
|
|
81
127
|
// 1) The PROTOCOL intent — raw, bubbling + composed (NOT via dispatch()).
|
|
@@ -113,6 +159,7 @@ defineWebComponent<Props, Events>('kai-artifact', {
|
|
|
113
159
|
src={props.src}
|
|
114
160
|
files={props.files}
|
|
115
161
|
tab={props.tab}
|
|
162
|
+
defaultTab={props.defaultTab}
|
|
116
163
|
activeFile={props.activeFile}
|
|
117
164
|
sandbox={props.sandbox}
|
|
118
165
|
iframeTitle={props.iframeTitle}
|
|
@@ -126,10 +173,12 @@ defineWebComponent<Props, Events>('kai-artifact', {
|
|
|
126
173
|
showTabs={!flag('noTabs')}
|
|
127
174
|
standalone={flag('standalone')}
|
|
128
175
|
readonlyPath={flag('readonlyPath')}
|
|
176
|
+
displayUrl={props.displayUrl}
|
|
129
177
|
onMaximizeChange={onMaximizeChange}
|
|
130
178
|
onNavigate={(url) => dispatch('kai-navigate', { url })}
|
|
131
179
|
onTabChange={(tab) => dispatch('kai-tab-change', { tab })}
|
|
132
180
|
onFileSelect={(path) => dispatch('kai-file-select', { path })}
|
|
181
|
+
controllerRef={(c) => (controller = c)}
|
|
133
182
|
/>
|
|
134
183
|
</div>
|
|
135
184
|
</>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Avatar } from '../ui/avatar';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
|
|
4
|
+
interface Props extends Record<string, unknown> {
|
|
5
|
+
/** Image URL/data-URI. When absent, the `fallback` initials show instead. */
|
|
6
|
+
src?: string;
|
|
7
|
+
/** Alt text for the image. Defaults to `fallback`. */
|
|
8
|
+
alt?: string;
|
|
9
|
+
/** Short text shown when there's no image — usually initials (e.g. "JD", "AI"). */
|
|
10
|
+
fallback?: string;
|
|
11
|
+
/** Size token: `sm` | `md` (default) | `lg`. */
|
|
12
|
+
size?: 'sm' | 'md' | 'lg';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `<kai-avatar>` — a person/entity avatar: a rounded image that falls back to
|
|
17
|
+
* initials when there's no `src`. This is an *identity* badge (the thing next to
|
|
18
|
+
* a message or in a conversation list), not a generic icon — for a glyph, use an
|
|
19
|
+
* `icon` prop on another element.
|
|
20
|
+
*
|
|
21
|
+
* ```html
|
|
22
|
+
* <kai-avatar src="/me.jpg" fallback="JD"></kai-avatar>
|
|
23
|
+
* <kai-avatar fallback="AI" size="sm"></kai-avatar>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
defineWebComponent<Props>('kai-avatar', {
|
|
27
|
+
src: undefined,
|
|
28
|
+
alt: undefined,
|
|
29
|
+
fallback: '',
|
|
30
|
+
size: 'md',
|
|
31
|
+
}, (props) => (
|
|
32
|
+
<Avatar src={props.src} alt={props.alt} fallback={props.fallback ?? ''} size={props.size ?? 'md'} />
|
|
33
|
+
));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Badge } from '../ui/badge';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
|
|
4
|
+
interface Props extends Record<string, unknown> {
|
|
5
|
+
/** `default` (muted pill) · `count` (compact number badge) · `citation`
|
|
6
|
+
* (filled primary, for inline citation markers). Defaults to `default`. */
|
|
7
|
+
variant?: 'default' | 'count' | 'citation';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `<kai-badge>` — a small pill for labels, status, counts, or citation markers.
|
|
12
|
+
* Put the content as light-DOM text.
|
|
13
|
+
*
|
|
14
|
+
* ```html
|
|
15
|
+
* <kai-badge>Beta</kai-badge>
|
|
16
|
+
* <kai-badge variant="count">3</kai-badge>
|
|
17
|
+
* <kai-badge variant="citation">1</kai-badge>
|
|
18
|
+
* ```
|
|
19
|
+
* Restyle via `::part(badge)`.
|
|
20
|
+
*/
|
|
21
|
+
defineWebComponent<Props>('kai-badge', {
|
|
22
|
+
variant: 'default',
|
|
23
|
+
}, (props) => (
|
|
24
|
+
<>
|
|
25
|
+
{/* Base sets `:host{display:block}`; a badge/pill flows inline with text and
|
|
26
|
+
beside sibling badges, so inline-flex like kai-button. */}
|
|
27
|
+
<style>{':host{display:inline-flex}'}</style>
|
|
28
|
+
<Badge variant={props.variant ?? 'default'} part="badge">
|
|
29
|
+
<slot />
|
|
30
|
+
</Badge>
|
|
31
|
+
</>
|
|
32
|
+
));
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Show } from 'solid-js';
|
|
2
|
+
import { Button } from '../ui/button';
|
|
3
|
+
import { renderIcon } from '../ui/icon';
|
|
4
|
+
import { defineWebComponent } from './define';
|
|
5
|
+
|
|
6
|
+
interface Props extends Record<string, unknown> {
|
|
7
|
+
/** Visual style. `default` (filled), `subtle` (muted text, hover tint — the
|
|
8
|
+
* toolbar icon look), `ghost` (transparent, hover fill), `outline`, or
|
|
9
|
+
* `destructive`. Defaults to `default`. */
|
|
10
|
+
variant?: 'default' | 'subtle' | 'ghost' | 'outline' | 'destructive';
|
|
11
|
+
/** Size token. `icon` / `icon-sm` are square (for icon-only buttons); `sm` /
|
|
12
|
+
* `md` / `lg` size text buttons. Defaults to `md`. */
|
|
13
|
+
size?: 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm';
|
|
14
|
+
/** Leading icon: a named icon (e.g. `"mic"`, `"plus"`), an image URL/data-URI,
|
|
15
|
+
* or plain text. Renders before any slotted label. */
|
|
16
|
+
icon?: string;
|
|
17
|
+
/** Trailing icon, after the label (e.g. `"chevron-down"` for a menu affordance). */
|
|
18
|
+
iconTrailing?: string;
|
|
19
|
+
/** Accessible name. REQUIRED for icon-only buttons (no visible text); ignored
|
|
20
|
+
* when you slot visible text, which already names the button. */
|
|
21
|
+
label?: string;
|
|
22
|
+
/** Disable the button (non-interactive, dimmed). */
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Stretch the button to the full width of its container (a block button) —
|
|
25
|
+
* e.g. a card CTA or a stacked action. Attribute: `full`. */
|
|
26
|
+
full?: boolean;
|
|
27
|
+
/** Justify the button's content: `start`, `center` (default), or `end`.
|
|
28
|
+
* Combine with `full` for a full-width, left-aligned button. */
|
|
29
|
+
align?: 'start' | 'center' | 'end';
|
|
30
|
+
/** Native button `type`. Defaults to `button` (so it never submits a form). */
|
|
31
|
+
type?: 'button' | 'submit' | 'reset';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Events fired by `<kai-button>`. */
|
|
35
|
+
interface Events {
|
|
36
|
+
/** The button was activated (pointer or keyboard). Carries no detail. The
|
|
37
|
+
* native `click` also bubbles (composed) for consumers who prefer it. */
|
|
38
|
+
'kai-click': void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `<kai-button>` — the kit's button as a drop-in element, so consumers compose
|
|
43
|
+
* polished, theme-aware controls instead of hand-rolling `<button>` + inline
|
|
44
|
+
* hover styles. Put the label as light-DOM text; use `icon` for a leading glyph
|
|
45
|
+
* and `label` to name an icon-only button.
|
|
46
|
+
*
|
|
47
|
+
* ```html
|
|
48
|
+
* <kai-button variant="subtle" size="icon" icon="mic" label="Voice input"></kai-button>
|
|
49
|
+
* <kai-button variant="ghost" icon-trailing="chevron-down">High</kai-button>
|
|
50
|
+
* <kai-button>Send</kai-button>
|
|
51
|
+
* <kai-button label="Ship"><svg slot="icon" viewBox="0 0 24 24">…</svg></kai-button>
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* The `icon` prop renders a curated/URL icon; for anything else, slot your own
|
|
55
|
+
* inline SVG via `slot="icon"` (it wins over `icon`). Restyle via `::part(button)`.
|
|
56
|
+
* Emits `kai-click`.
|
|
57
|
+
*/
|
|
58
|
+
defineWebComponent<Props, Events>('kai-button', {
|
|
59
|
+
variant: 'default',
|
|
60
|
+
size: 'md',
|
|
61
|
+
icon: undefined,
|
|
62
|
+
iconTrailing: undefined,
|
|
63
|
+
label: undefined,
|
|
64
|
+
disabled: false,
|
|
65
|
+
full: false,
|
|
66
|
+
align: 'center',
|
|
67
|
+
type: 'button',
|
|
68
|
+
}, (props, { dispatch, flag, element, expose }) => {
|
|
69
|
+
// `icon` / `icon-sm` are square, icon-ONLY sizes: suppress the text label and
|
|
70
|
+
// trailing icon so a stray label doesn't get cramped into the square (the
|
|
71
|
+
// `label` prop still names it for assistive tech).
|
|
72
|
+
const iconOnly = () => props.size === 'icon' || props.size === 'icon-sm';
|
|
73
|
+
|
|
74
|
+
// ── Imperative API (instance methods on the host) ──────────────────────────
|
|
75
|
+
// The real <button> lives in the shadow root, so native focus()/blur()/click()
|
|
76
|
+
// on the host hit the wrapper, not the control. Forward to the inner button.
|
|
77
|
+
// These shadow the inherited HTMLElement methods — intended; expose() uses
|
|
78
|
+
// defineProperty so the override sticks. No collision with the props above.
|
|
79
|
+
expose({
|
|
80
|
+
/** Focus the inner `<button>` (host.focus() would focus the wrapper). */
|
|
81
|
+
focus: (options?: FocusOptions) =>
|
|
82
|
+
element.shadowRoot?.querySelector('button')?.focus(options),
|
|
83
|
+
/** Blur the inner `<button>`. */
|
|
84
|
+
blur: () => element.shadowRoot?.querySelector('button')?.blur(),
|
|
85
|
+
/** Programmatically activate the button — runs the same path as a user
|
|
86
|
+
* click and fires kai-click. Forwarding to the inner button means
|
|
87
|
+
* `disabled` is respected automatically. */
|
|
88
|
+
click: () => element.shadowRoot?.querySelector('button')?.click(),
|
|
89
|
+
});
|
|
90
|
+
return (
|
|
91
|
+
<>
|
|
92
|
+
{/* The host shrinks to the label by default (inline-flex), so a text button
|
|
93
|
+
is only as wide as its content — until a parent stretches it. A text
|
|
94
|
+
button's inner control is w-full, so when the host IS stretched (a flex
|
|
95
|
+
column with items-stretch, e.g. a card's collapsed footer, or an explicit
|
|
96
|
+
`full`) the button fills it. `full` forces that standalone (a block CTA).
|
|
97
|
+
Icon buttons stay square (no w-full). */}
|
|
98
|
+
<style>{':host{display:inline-flex}:host([full]){display:block}'}</style>
|
|
99
|
+
<Button
|
|
100
|
+
part="button"
|
|
101
|
+
variant={props.variant ?? 'default'}
|
|
102
|
+
size={props.size ?? 'md'}
|
|
103
|
+
align={props.align ?? 'center'}
|
|
104
|
+
full={flag('full') || !iconOnly()}
|
|
105
|
+
type={props.type ?? 'button'}
|
|
106
|
+
disabled={flag('disabled')}
|
|
107
|
+
aria-label={props.label}
|
|
108
|
+
onClick={() => dispatch('kai-click')}
|
|
109
|
+
>
|
|
110
|
+
{/* Leading icon: a slotted SVG (slot="icon") wins — drop in any icon
|
|
111
|
+
library or your own; otherwise the `icon` prop renders a curated/URL one. */}
|
|
112
|
+
<slot name="icon">
|
|
113
|
+
<Show when={props.icon}>
|
|
114
|
+
{renderIcon(props.icon, { class: 'size-4 shrink-0', imgClass: 'size-4 shrink-0', spanClass: 'inline-flex size-4 shrink-0 items-center justify-center', ariaHidden: true })}
|
|
115
|
+
</Show>
|
|
116
|
+
</slot>
|
|
117
|
+
<Show when={!iconOnly()}>
|
|
118
|
+
<slot />
|
|
119
|
+
</Show>
|
|
120
|
+
<Show when={props.iconTrailing && !iconOnly()}>
|
|
121
|
+
{renderIcon(props.iconTrailing, { class: 'size-4 shrink-0 opacity-60', imgClass: 'size-4 shrink-0', spanClass: 'inline-flex size-4 shrink-0 items-center justify-center', ariaHidden: true })}
|
|
122
|
+
</Show>
|
|
123
|
+
</Button>
|
|
124
|
+
</>
|
|
125
|
+
);
|
|
126
|
+
});
|
|
Binary file
|