@kitn.ai/ui 0.20.1 → 0.22.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 +44 -45
- package/dist/components/artifact-card.d.ts +51 -0
- package/dist/components/artifact.d.ts +1 -1
- package/dist/components/attachments.d.ts +2 -2
- package/dist/components/audio-visualizer/index.d.ts +3 -3
- package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
- package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
- package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
- package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
- package/dist/components/card-fallback.d.ts +12 -2
- package/dist/components/card-renderer.d.ts +63 -2
- package/dist/components/chat-container.d.ts +3 -0
- package/dist/components/chat-scope-picker.d.ts +2 -2
- package/dist/components/chat-thread.d.ts +77 -18
- package/dist/components/choice-card.d.ts +3 -28
- package/dist/components/composer-dom.d.ts +1 -1
- package/dist/components/composer-highlight.d.ts +1 -1
- package/dist/components/composer-history.d.ts +1 -1
- package/dist/components/composer.d.ts +1 -1
- package/dist/components/confirm-card.d.ts +3 -18
- package/dist/components/context.d.ts +8 -4
- package/dist/components/conversation-item.d.ts +1 -1
- package/dist/components/conversation-list.d.ts +4 -3
- package/dist/components/embed.d.ts +3 -3
- package/dist/components/file-tree.d.ts +11 -22
- package/dist/components/form-widgets.d.ts +1 -1
- package/dist/components/form.d.ts +3 -44
- package/dist/components/link-preview.d.ts +3 -3
- package/dist/components/loader.d.ts +30 -48
- package/dist/components/message-skills.d.ts +4 -0
- package/dist/components/message.d.ts +84 -21
- package/dist/components/model-switcher.d.ts +2 -2
- package/dist/components/prompt-input.d.ts +2 -2
- package/dist/components/response-compare-types.d.ts +11 -2
- package/dist/components/response-compare.d.ts +3 -3
- package/dist/components/source.d.ts +12 -3
- package/dist/components/tasks-card.d.ts +3 -31
- package/dist/components/thread.d.ts +17 -5
- package/dist/components/toast.d.ts +2 -2
- package/dist/components/tool-classify.d.ts +8 -0
- package/dist/components/tool-types.d.ts +29 -1
- package/dist/components/tool.d.ts +3 -3
- package/dist/components/use-card-resolution.d.ts +1 -1
- package/dist/create-tween-COnPwAQN.js +338 -0
- package/dist/create-tween-DmTUaXWE.js +341 -0
- package/dist/create-tween-qs-jjvNA.js +7 -0
- package/dist/custom-elements.json +1726 -463
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- 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 +70 -10
- 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-Tj58ES_d.js → Icon-CHG5z5L7.js} +1 -1
- package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-BAtCEEgg.js} +1 -1
- package/dist/elements/chunks/arrow-left-CFPTeL1Y.js +1 -0
- package/dist/elements/chunks/artifact-fBZOE4SO.js +1 -0
- package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-DpYMe5VQ.js} +1 -1
- package/dist/elements/chunks/audio-visualizer-DFwzAcuL.js +1 -0
- package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-D6zodm6E.js} +1 -1
- package/dist/elements/chunks/{button-ZWNif3--.js → button-C42vrGvO.js} +1 -1
- package/dist/elements/chunks/card-renderer-DMZsSuvU.js +1 -0
- package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
- package/dist/elements/chunks/chat-thread-CNNEhol-.js +1 -0
- package/dist/elements/chunks/check-7Q3K-iXE.js +1 -0
- package/dist/elements/chunks/chevron-down-CpNYLn7E.js +1 -0
- package/dist/elements/chunks/chevron-right-DrH85Fha.js +1 -0
- package/dist/elements/chunks/choice-card-YoWjpsFV.js +1 -0
- package/dist/elements/chunks/circle-C9KRjKYv.js +1 -0
- package/dist/elements/chunks/circle-check-Dmi7Y4zw.js +1 -0
- package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-QIxXda6k.js} +1 -1
- package/dist/elements/chunks/code-block-CqeugReY.js +1 -0
- package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-sTv-_5lF.js} +1 -1
- package/dist/elements/chunks/{composer-BguS0QL_.js → composer-ldQyeVEB.js} +2 -2
- package/dist/elements/chunks/confirm-card-C0RNOwfn.js +1 -0
- package/dist/elements/chunks/context-5qgypNHC.js +1 -0
- package/dist/elements/chunks/conversation-list-DLzOacXz.js +1 -0
- package/dist/elements/chunks/create-tween-V4TXZ93X.js +7 -0
- package/dist/elements/chunks/default-input-DeeRSDHc.js +1 -0
- package/dist/elements/chunks/define-lE-QvQFn.js +1 -0
- package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DZSa9jog.js} +1 -1
- package/dist/elements/chunks/{download-Dsbg3ste.js → download-B2ZmnGqW.js} +1 -1
- package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-R3B7cSRE.js} +1 -1
- package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BmxceY4l.js} +1 -1
- package/dist/elements/chunks/embed-BVrtTZPo.js +1 -0
- package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-BbdR7YO7.js} +1 -1
- package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-D7dijo1A.js} +1 -1
- package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-0upJ5jeb.js} +1 -1
- package/dist/elements/chunks/{folder-glP5rha4.js → folder-D8z58t7B.js} +1 -1
- package/dist/elements/chunks/form-p5BKJNw5.js +1 -0
- package/dist/elements/chunks/hover-card-CN9s2md5.js +1 -0
- package/dist/elements/chunks/{icon-BLb8beoi.js → icon-CNiKP37E.js} +1 -1
- package/dist/elements/chunks/{info-CIsv92JK.js → info-BSnuJiHI.js} +1 -1
- package/dist/elements/chunks/{input-Dds1kFyt.js → input-BauDmzxX.js} +1 -1
- package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-BlHJaP9b.js} +1 -1
- package/dist/elements/chunks/{link-i4r_k7z4.js → link-DEi5iUWC.js} +1 -1
- package/dist/elements/chunks/link-preview-BaHyM6W4.js +1 -0
- package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-CmJG_Fkq.js} +1 -1
- package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-D2jaMpCN.js} +1 -1
- package/dist/elements/chunks/message-C5UfXZ2Z.js +1 -0
- package/dist/elements/chunks/message-CXWLmmLn.js +1 -0
- package/dist/elements/chunks/message-square-hXylwsy0.js +1 -0
- package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-C9ytZFMU.js} +1 -1
- package/dist/elements/chunks/model-switcher-CivGfD7-.js +1 -0
- package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-DJL_sbOm.js} +1 -1
- package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CFaB8naM.js} +1 -1
- package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-Br5SksfR.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-CMIvtAhU.js} +1 -1
- package/dist/elements/chunks/reasoning-DpZcNzLq.js +1 -0
- package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-Q8i3T9a_.js} +1 -1
- package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-B5IHCBFV.js} +1 -1
- package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-eLeydBje.js} +1 -1
- package/dist/elements/chunks/scroll-button-DWbz0yA1.js +1 -0
- package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-Xic78AD_.js} +1 -1
- package/dist/elements/chunks/{settings-B8lmec4D.js → settings-B8H51pAx.js} +1 -1
- package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-CsG9eYLe.js} +1 -1
- package/dist/elements/chunks/{share-C3lTiYGt.js → share-CNTx0z__.js} +1 -1
- package/dist/elements/chunks/skeleton-CLlHTcMI.js +1 -0
- package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
- package/dist/elements/chunks/source-BoVcU5ok.js +1 -0
- package/dist/elements/chunks/{star-CSJtGxgv.js → star-CxQVTVhI.js} +1 -1
- package/dist/elements/chunks/{store-CHyW95TP.js → store-CLtS5CUG.js} +1 -1
- package/dist/elements/chunks/tasks-card-CzlkLmUt.js +1 -0
- package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D5NhpIQ1.js} +1 -1
- package/dist/elements/chunks/textarea-x5Uxsmtm.js +1 -0
- package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-UobcJnx9.js} +1 -1
- package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-BOfs9eXq.js} +1 -1
- package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-Be6Dh_dt.js} +1 -1
- package/dist/elements/chunks/tooltip-RxMxyCLF.js +1 -0
- package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C4yxH2XN.js} +1 -1
- package/dist/elements/chunks/use-card-resolution-jva9ehH6.js +1 -0
- package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Dx4VRcjS.js} +2 -2
- package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-Y1ZTWgEa.js} +1 -1
- package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-B9gml9Cg.js} +2 -2
- package/dist/elements/chunks/{video-B7vmenoC.js → video-CrPHsytT.js} +1 -1
- package/dist/elements/chunks/x-_-OPHept.js +1 -0
- package/dist/elements/coachmark.js +1 -1
- package/dist/elements/code-block.js +1 -1
- package/dist/elements/command.js +1 -1
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.js +1 -1
- 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/default-input.d.ts +34 -7
- package/dist/elements/define.d.ts +1 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/disclosure.d.ts +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +107 -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.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- 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.js +1 -1
- 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.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-group.js +1 -1
- package/dist/elements/pane.js +1 -1
- package/dist/elements/popover.js +1 -1
- package/dist/elements/progress-bar.js +1 -1
- package/dist/elements/prompt-dock.js +1 -1
- 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.d.ts +8 -6
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +1 -1
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/separator.js +1 -1
- package/dist/elements/setting-item.js +1 -1
- package/dist/elements/settings-group.js +1 -1
- package/dist/elements/skeleton.js +1 -1
- package/dist/elements/slot-text.d.ts +51 -0
- package/dist/elements/slots.d.ts +21 -0
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- 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/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/validate-messages.d.ts +25 -0
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +2734 -217
- package/dist/index.d.ts +163 -125
- package/dist/index.js +6572 -5990
- package/dist/index.server.d.ts +5 -0
- package/dist/index.server.js +5403 -4860
- package/dist/kai-provider.es.d.ts +5 -0
- package/dist/kai-provider.es.js +79 -77
- package/dist/kai.es.d.ts +5 -0
- package/dist/kai.es.js +1 -1
- package/dist/llms/llms-full.txt +774 -151
- package/dist/llms/llms.txt +57 -5
- package/dist/mcp.es.js +4756 -782
- package/dist/primitives/card-component-types.d.ts +11 -0
- package/dist/primitives/card-data-types.d.ts +196 -0
- package/dist/primitives/card-host.d.ts +1 -1
- package/dist/primitives/card-recovery.d.ts +3 -3
- package/dist/primitives/card-registry.d.ts +4 -14
- package/dist/primitives/card-resolution.d.ts +1 -1
- package/dist/primitives/card-routing.d.ts +1 -1
- package/dist/primitives/card-tags.d.ts +11 -0
- package/dist/primitives/card-validate-cards.d.ts +57 -0
- package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
- package/dist/primitives/card-validate-schemas.d.ts +17 -0
- package/dist/primitives/card-validate.d.ts +24 -0
- package/dist/primitives/create-kai-chat.d.ts +3 -3
- package/dist/primitives/embed-providers.d.ts +1 -1
- package/dist/primitives/link-preview.d.ts +1 -1
- package/dist/primitives/message-feedback.d.ts +2 -2
- package/dist/primitives/toast-store.d.ts +1 -1
- package/dist/react/index.d.ts +730 -302
- package/dist/react/use-kai-chat.d.ts +8 -4
- package/dist/react.d.ts +5 -0
- package/dist/react.js +418 -317
- package/dist/register-impl-AxIlqjo7.js +145 -0
- package/dist/remote/host-embed.d.ts +1 -1
- package/dist/remote/index.d.ts +2 -2
- package/dist/remote/provider-runtime.d.ts +2 -2
- package/dist/remote/provider.d.ts +2 -2
- package/dist/remote/validate.d.ts +1 -1
- package/dist/remote/wire.d.ts +1 -1
- package/dist/schemas/artifact.schema.json +92 -0
- package/dist/schemas/embed.schema.json +0 -2
- package/dist/schemas/from-tool-call.d.ts +48 -0
- package/dist/schemas/index.d.ts +48 -0
- package/dist/schemas/link.schema.json +0 -2
- package/dist/schemas/provider-subsets.d.ts +136 -0
- package/dist/schemas/registry.d.ts +140 -0
- package/dist/schemas/tool-defs.d.ts +121 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.js +717 -0
- package/dist/solid-BGYSJyHG.js +22960 -0
- package/dist/solid-Dt2nEwfl.js +20194 -0
- package/dist/solid.d.ts +66 -0
- package/dist/solid.js +261 -0
- package/dist/solid.server.d.ts +5 -0
- package/dist/solid.server.js +261 -0
- package/dist/state/index.d.ts +14 -4
- package/dist/state/messages.d.ts +8 -3
- package/dist/state/mock.d.ts +46 -0
- package/dist/state/parts.d.ts +85 -0
- package/dist/state/stream.d.ts +15 -9
- package/dist/state.d.ts +5 -0
- package/dist/state.js +253 -84
- package/dist/ui/action-icons.d.ts +1 -1
- package/dist/ui/collapsible.d.ts +11 -6
- package/dist/ui/dropdown.d.ts +47 -42
- package/dist/ui/pane-group.d.ts +1 -1
- package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-B44X69AG.js} +1 -1
- package/dist/variant-aurora-BRhV8Flk.js +391 -0
- package/dist/variant-aurora-Ds5ou9BH.js +381 -0
- package/dist/variant-custom-B20FhtYj.js +170 -0
- package/dist/{variant-custom-Dif-IV4u.js → variant-custom-BvA1Schl.js} +1 -1
- package/dist/variant-custom-D6Rtvneb.js +200 -0
- package/dist/{variant-wave-DbfNdvSi.js → variant-wave-BUQtkryq.js} +1 -1
- package/dist/variant-wave-BVYnqy9L.js +218 -0
- package/dist/variant-wave-DXC6_LcH.js +208 -0
- package/dist/wire/chunk.d.ts +171 -0
- package/dist/wire/consume.d.ts +26 -0
- package/dist/wire/encode.d.ts +221 -0
- package/dist/wire/files.d.ts +116 -0
- package/dist/wire/formats/anthropic.d.ts +2 -0
- package/dist/wire/formats/openai.d.ts +5 -0
- package/dist/wire/index.d.ts +16 -0
- package/dist/wire/media-types.d.ts +106 -0
- package/dist/wire/read.d.ts +26 -0
- package/dist/wire/sink-helpers.d.ts +21 -0
- package/dist/wire/sse.d.ts +33 -0
- package/dist/wire.d.ts +5 -53
- package/dist/wire.js +1126 -0
- package/frameworks/react/index.tsx +191 -158
- package/frameworks/react/runtime.tsx +21 -1
- package/frameworks/react/use-kai-chat.tsx +11 -1
- package/llms-full.txt +774 -151
- package/llms.txt +57 -5
- package/package.json +62 -8
- package/src/agent-tooling/archetypes.ts +127 -0
- package/src/agent-tooling/integrations/anthropic.ts +436 -0
- package/src/agent-tooling/integrations/cloudflare.ts +141 -52
- package/src/agent-tooling/integrations/langgraph.ts +80 -13
- package/src/agent-tooling/integrations/mastra.ts +161 -12
- package/src/agent-tooling/integrations/mock.ts +47 -8
- package/src/agent-tooling/integrations/ollama.ts +68 -24
- package/src/agent-tooling/integrations/openai.ts +89 -0
- package/src/agent-tooling/integrations/openrouter.ts +58 -8
- package/src/agent-tooling/integrations/pi.ts +104 -23
- package/src/agent-tooling/integrations/pydantic-ai.ts +61 -5
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +120 -13
- package/src/agent-tooling/mcp/manifest.ts +206 -25
- package/src/agent-tooling/mcp/tools/debug.ts +13 -7
- package/src/agent-tooling/mcp/tools/reference.ts +285 -6
- package/src/agent-tooling/mcp/tools/scaffold.ts +4152 -661
- package/src/agent-tooling/registry.ts +74 -0
- package/src/agent-tooling/types.ts +361 -1
- package/src/components/artifact-card.tsx +120 -0
- package/src/components/audio-visualizer/index.tsx +9 -0
- package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
- package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
- package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
- package/src/components/card-fallback.tsx +42 -10
- package/src/components/card-renderer.tsx +146 -9
- package/src/components/chat-container.tsx +4 -0
- package/src/components/chat-thread.tsx +128 -52
- package/src/components/choice-card.tsx +17 -29
- package/src/components/composer.tsx +12 -2
- package/src/components/confirm-card.tsx +24 -20
- package/src/components/context.tsx +30 -16
- package/src/components/conversation-item.tsx +6 -0
- package/src/components/conversation-list.tsx +18 -2
- package/src/components/file-tree.tsx +11 -22
- package/src/components/file-upload.tsx +14 -8
- package/src/components/form.tsx +14 -47
- package/src/components/loader.tsx +39 -12
- package/src/components/message-skills.tsx +4 -0
- package/src/components/message.tsx +294 -46
- package/src/components/model-switcher.tsx +38 -8
- package/src/components/reasoning.tsx +92 -5
- package/src/components/response-compare-types.ts +25 -0
- package/src/components/response-compare.tsx +4 -9
- package/src/components/source.tsx +50 -24
- package/src/components/tasks-card.tsx +10 -33
- package/src/components/thread.tsx +84 -42
- package/src/components/toast.tsx +17 -6
- package/src/components/tool-classify.ts +26 -0
- package/src/components/tool-types.ts +31 -1
- package/src/elements/agent-card.tsx +11 -11
- package/src/elements/artifact.tsx +15 -7
- package/src/elements/attachments.tsx +6 -4
- package/src/elements/avatar.tsx +1 -1
- package/src/elements/button.tsx +29 -6
- package/src/elements/card.tsx +2 -2
- package/src/elements/cards.tsx +109 -14
- package/src/elements/chain-of-thought.tsx +14 -10
- package/src/elements/chat-scope-picker.tsx +9 -7
- package/src/elements/chat-types.ts +59 -6
- package/src/elements/chat-workspace.tsx +50 -9
- package/src/elements/chat.tsx +90 -3
- package/src/elements/choice.tsx +8 -8
- package/src/elements/coachmark.tsx +1 -1
- package/src/elements/command.tsx +8 -23
- package/src/elements/compare.tsx +7 -6
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +8 -8
- package/src/elements/confirm-card.tsx +9 -9
- package/src/elements/context-meter.tsx +4 -18
- package/src/elements/conversation-list.tsx +14 -9
- package/src/elements/default-input.tsx +131 -8
- package/src/elements/define.tsx +178 -43
- package/src/elements/editable-label.tsx +17 -2
- package/src/elements/element-data-types.ts +112 -0
- package/src/elements/element-meta.json +1624 -306
- package/src/elements/element-types.d.ts +2645 -214
- package/src/elements/feedback-bar.tsx +1 -1
- package/src/elements/file-tree.tsx +1 -1
- package/src/elements/file-upload.tsx +1 -1
- package/src/elements/form.tsx +14 -6
- package/src/elements/input.tsx +1 -1
- package/src/elements/kbd.tsx +1 -1
- package/src/elements/menu.tsx +40 -32
- package/src/elements/message-skills.tsx +7 -9
- package/src/elements/message.tsx +200 -32
- package/src/elements/model-switcher.tsx +5 -3
- package/src/elements/pane.tsx +1 -1
- package/src/elements/prompt-dock.tsx +8 -8
- package/src/elements/prompt-input.tsx +10 -10
- package/src/elements/prompt-suggestions.tsx +7 -4
- package/src/elements/reasoning.tsx +1 -1
- package/src/elements/register.ts +9 -0
- package/src/elements/resizable.globals.d.ts +36 -0
- package/src/elements/resizable.tsx +24 -13
- package/src/elements/response-stream.tsx +1 -1
- package/src/elements/scroll-button.tsx +1 -1
- package/src/elements/search.tsx +6 -1
- package/src/elements/segmented.tsx +5 -11
- package/src/elements/separator.tsx +1 -1
- package/src/elements/slot-text.ts +73 -0
- package/src/elements/slots.ts +67 -24
- package/src/elements/source.tsx +21 -22
- package/src/elements/switch.tsx +3 -3
- package/src/elements/tasks.tsx +5 -4
- package/src/elements/thread.tsx +36 -4
- package/src/elements/toast.tsx +3 -2
- package/src/elements/tool.tsx +1 -1
- package/src/elements/validate-messages.ts +76 -0
- package/src/elements/voice-input.tsx +7 -7
- package/src/elements/voice-output.tsx +4 -4
- package/src/index.ts +145 -6
- package/src/primitives/card-component-types.ts +63 -0
- package/src/primitives/card-data-types.ts +312 -0
- package/src/primitives/card-recovery.ts +13 -2
- package/src/primitives/card-registry.tsx +34 -23
- package/src/primitives/card-schemas/artifact.schema.json +92 -0
- package/src/primitives/card-schemas/embed.schema.json +0 -2
- package/src/primitives/card-schemas/link.schema.json +0 -2
- package/src/primitives/card-tags.ts +61 -0
- package/src/primitives/card-validate-cards.ts +255 -0
- package/src/primitives/card-validate-generator.testlib.ts +38 -0
- package/src/primitives/card-validate-schemas.ts +58 -0
- package/src/primitives/card-validate.ts +48 -20
- package/src/primitives/create-tween.ts +54 -2
- package/src/primitives/message-feedback.ts +3 -2
- package/src/primitives/use-audio-analysis.ts +20 -1
- package/src/primitives/use-sequencer.ts +20 -1
- package/src/schemas/from-tool-call.ts +151 -0
- package/src/schemas/index.ts +340 -0
- package/src/schemas/provider-subsets.ts +538 -0
- package/src/schemas/registry.ts +355 -0
- package/src/schemas/tool-defs.ts +492 -0
- package/src/solid.ts +150 -0
- package/src/state/index.ts +27 -1
- package/src/state/messages.ts +21 -4
- package/src/state/mock.ts +211 -0
- package/src/state/parts.ts +295 -0
- package/src/state/stream.ts +56 -58
- package/src/ui/collapsible.tsx +17 -5
- package/src/ui/dropdown.tsx +46 -12
- package/src/ui/overlay.tsx +10 -4
- package/src/wire/chunk.ts +201 -0
- package/src/wire/consume.ts +440 -0
- package/src/wire/encode.ts +689 -0
- package/src/wire/files.ts +342 -0
- package/src/wire/formats/anthropic.ts +267 -0
- package/src/wire/formats/openai.ts +187 -0
- package/src/wire/index.ts +73 -0
- package/src/wire/media-types.ts +344 -0
- package/src/wire/read.ts +152 -0
- package/src/wire/sink-helpers.ts +50 -0
- package/src/wire/sse.ts +140 -0
- package/dist/create-tween-hvpmSuwW.js +0 -7
- package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
- package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
- package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
- package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
- package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
- package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
- package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
- package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
- package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
- package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
- package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
- package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
- package/dist/elements/chunks/default-input-Cqqilg9t.js +0 -1
- package/dist/elements/chunks/define-D1din7Ld.js +0 -1
- package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
- package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
- package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
- package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
- package/dist/elements/chunks/model-switcher-B94YAKsM.js +0 -1
- package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
- package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
- package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
- package/dist/elements/chunks/slots--V19HwUb.js +0 -1
- package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
- package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
- package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
- package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
- package/dist/host-embed.d.ts +0 -33
- package/dist/kai-provider.d.ts +0 -2
- package/dist/origin.d.ts +0 -5
- package/dist/provider-runtime.d.ts +0 -27
- package/dist/register-impl-DQyejdfb.js +0 -145
- package/dist/validate.d.ts +0 -4
- package/dist/version.d.ts +0 -4
- package/src/components/component-meta.json +0 -4550
- package/src/elements/card-media.jpg +0 -0
- package/src/elements/resizable.d.ts +0 -27
- package/src/elements/video-poster.jpg +0 -0
|
@@ -3,7 +3,7 @@ import { FeedbackBar, type FeedbackValue, type FeedbackDetail } from '../compone
|
|
|
3
3
|
|
|
4
4
|
interface Props extends Record<string, unknown> {
|
|
5
5
|
/** The banner label (e.g. "Was this helpful?"). Attribute: `bar-title`
|
|
6
|
-
* (`title` is avoided
|
|
6
|
+
* (`title` is avoided because it is a global HTML attribute). */
|
|
7
7
|
barTitle?: string;
|
|
8
8
|
/** When set, a not-helpful vote opens an optional detail form before the
|
|
9
9
|
* thank-you confirmation. Attribute: `collect-detail`. */
|
|
@@ -4,7 +4,7 @@ import { FileTree, type FileTreeFile } from '../components/file-tree';
|
|
|
4
4
|
interface Props extends Record<string, unknown> {
|
|
5
5
|
/** The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type?, additions?, deletions?, status? }`). */
|
|
6
6
|
files: FileTreeFile[];
|
|
7
|
-
/** Selected file path
|
|
7
|
+
/** Selected file path, highlighted in the tree. */
|
|
8
8
|
activeFile?: string;
|
|
9
9
|
/** Folder paths expanded initially. Omit to start with all folders open. */
|
|
10
10
|
defaultExpanded?: string[];
|
|
@@ -7,7 +7,7 @@ interface Props extends Record<string, unknown> {
|
|
|
7
7
|
multiple?: boolean;
|
|
8
8
|
/** `accept` attribute for the file picker (e.g. `image/*`). */
|
|
9
9
|
accept?: string;
|
|
10
|
-
/** Disable the dropzone
|
|
10
|
+
/** Disable the dropzone: no clicking, no drag-and-drop. */
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
/** Default dropzone label (overridable via the default slot). */
|
|
13
13
|
label?: string;
|
package/src/elements/form.tsx
CHANGED
|
@@ -3,11 +3,18 @@ import { Form, type FormController, type FormDefinition } from '../components/fo
|
|
|
3
3
|
import type { CardResolution } from '../primitives/card-contract';
|
|
4
4
|
|
|
5
5
|
interface Props extends Record<string, unknown> {
|
|
6
|
-
/** The form definition
|
|
6
|
+
/** The form definition: a JSON Schema (`type:'object'`) + `x-kai-*` UI hints
|
|
7
7
|
* (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object',
|
|
8
8
|
* properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for
|
|
9
|
-
* the full shape
|
|
10
|
-
|
|
9
|
+
* the full shape.
|
|
10
|
+
*
|
|
11
|
+
* It IS self-referential (`FormField.properties` is another `FormField` map),
|
|
12
|
+
* and the generated `element-types.d.ts` inlines every named type, so the
|
|
13
|
+
* shipped declaration bottoms out in a `Record<string, unknown>` placeholder
|
|
14
|
+
* one level down rather than carrying the recursion. That is why
|
|
15
|
+
* `FormDefinition` is a `type` alias: an interface gets no implicit index
|
|
16
|
+
* signature, so it would not be assignable to that placeholder. */
|
|
17
|
+
data?: FormDefinition;
|
|
11
18
|
/** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */
|
|
12
19
|
cardId?: string;
|
|
13
20
|
/** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
|
|
@@ -27,7 +34,8 @@ interface Props extends Record<string, unknown> {
|
|
|
27
34
|
* contract event — `kai-values-change` is the live change signal, distinct from the
|
|
28
35
|
* terminal submit.) */
|
|
29
36
|
interface Events {
|
|
30
|
-
/** The form's values changed on input
|
|
37
|
+
/** The form's values changed on input. Carries the current coerced values +
|
|
38
|
+
* validity. */
|
|
31
39
|
'kai-values-change': { values: Record<string, unknown>; valid: boolean };
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -56,7 +64,7 @@ defineWebComponent<Props, Events>('kai-form', {
|
|
|
56
64
|
expose({
|
|
57
65
|
/** Focus the first control, or the first INVALID control after a failed validation. */
|
|
58
66
|
focus: (options?: FocusOptions) => controller?.focus(options),
|
|
59
|
-
/** Validate + submit programmatically
|
|
67
|
+
/** Validate + submit programmatically: focus the first invalid field on failure,
|
|
60
68
|
* else emit the `submit` CardEvent and resolve. Named `send`, not `submit`. */
|
|
61
69
|
send: () => controller?.send(),
|
|
62
70
|
/** Run client-side validation now and return `{ valid, errors? }` WITHOUT submitting. */
|
|
@@ -71,7 +79,7 @@ defineWebComponent<Props, Events>('kai-form', {
|
|
|
71
79
|
|
|
72
80
|
return (
|
|
73
81
|
<Form
|
|
74
|
-
data={props.data
|
|
82
|
+
data={props.data}
|
|
75
83
|
cardId={props.cardId ?? (element.id || 'kai-form')}
|
|
76
84
|
heading={props.heading}
|
|
77
85
|
resolution={props.resolution as CardResolution | undefined}
|
package/src/elements/input.tsx
CHANGED
|
@@ -6,7 +6,7 @@ interface Props extends Record<string, unknown> {
|
|
|
6
6
|
/** Native input type: `text` (default) · `email` · `url` · `search` · `tel` ·
|
|
7
7
|
* `password` · `number`. Single-line only. */
|
|
8
8
|
type?: string;
|
|
9
|
-
/** Controlled value
|
|
9
|
+
/** Controlled value. Settable and reflected to the `value` attribute. `el.value
|
|
10
10
|
* = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read
|
|
11
11
|
* `el.value` for live state. */
|
|
12
12
|
value?: string;
|
package/src/elements/kbd.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { defineWebComponent } from './define';
|
|
|
2
2
|
import { Kbd, type KbdPlatform } from '../ui/kbd';
|
|
3
3
|
|
|
4
4
|
interface Props extends Record<string, unknown> {
|
|
5
|
-
/** Shortcut spec
|
|
5
|
+
/** Shortcut spec: tokens joined by `+` (e.g. `Mod+Shift+K`). Omit it to show
|
|
6
6
|
* default-slot content instead. Display only; the element does not bind keys. */
|
|
7
7
|
keys?: string;
|
|
8
8
|
/** `mac` uses ⌘/⌥, `other` uses Ctrl. `auto` (default) sniffs the OS. */
|
package/src/elements/menu.tsx
CHANGED
|
@@ -11,47 +11,45 @@ import { Kbd } from '../ui/kbd';
|
|
|
11
11
|
import { cn } from '../utils/cn';
|
|
12
12
|
import { defineWebComponent } from './define';
|
|
13
13
|
import { wireDisclosure } from './disclosure';
|
|
14
|
+
import type { KaiMenuItem } from './element-data-types';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/** Named icon (e.g. "paperclip"), image URL / data-URI, or plain text. */
|
|
20
|
-
icon?: string;
|
|
21
|
-
/** e.g. '⌘U' — shown right-aligned, muted. */
|
|
22
|
-
shortcut?: string;
|
|
23
|
-
/** Presence ⇒ a checkbox item (role=menuitemcheckbox). With `radioGroup` set,
|
|
24
|
-
* marks the SELECTED radio item in that group instead. */
|
|
25
|
-
checked?: boolean;
|
|
26
|
-
/** Membership in a single-select group (role=menuitemradio). Items sharing a
|
|
27
|
-
* `radioGroup` are mutually exclusive — the one with `checked: true` shows the
|
|
28
|
-
* checkmark; selecting one emits `{ id, radioGroup }` so the consumer moves
|
|
29
|
-
* the checkmark (the consumer owns state, like checkbox items). */
|
|
30
|
-
radioGroup?: string;
|
|
31
|
-
disabled?: boolean;
|
|
32
|
-
/** A divider (ignores other fields). */
|
|
33
|
-
separator?: boolean;
|
|
34
|
-
/** A non-interactive section label (uses `label`). */
|
|
35
|
-
heading?: boolean;
|
|
36
|
-
/** ⇒ a submenu. */
|
|
37
|
-
items?: KaiMenuItem[];
|
|
38
|
-
}
|
|
16
|
+
// The item shape lives in ./element-data-types so the ROOT entry can re-export it
|
|
17
|
+
// (a per-element module's shipped .d.ts is `export {};`). Re-exported here so
|
|
18
|
+
// `import type { KaiMenuItem } from './menu'` keeps working.
|
|
19
|
+
export type { KaiMenuItem } from './element-data-types';
|
|
39
20
|
|
|
40
21
|
interface Props extends Record<string, unknown> {
|
|
41
|
-
/** Tree of menu items. Set as a JS property
|
|
22
|
+
/** Tree of menu items. Set as a JS property, not an HTML attribute. */
|
|
42
23
|
items?: KaiMenuItem[];
|
|
43
24
|
/** Optional placement hint (unused by the underlying Dropdown which always
|
|
44
25
|
* positions bottom-start, kept for future extension). */
|
|
45
26
|
placement?: string;
|
|
46
27
|
/** Built-in trigger: leading icon (a named icon like `"plus"`, an image
|
|
47
28
|
* URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for
|
|
48
|
-
* the common case
|
|
29
|
+
* the common case; a slotted trigger overrides it. */
|
|
49
30
|
triggerIcon?: string;
|
|
50
|
-
/** Built-in trigger: a text label (e.g. `"High"`).
|
|
31
|
+
/** Built-in trigger: a text label (e.g. `"High"`). This is the trigger's
|
|
32
|
+
* VISIBLE text, so it is also its accessible name, and `label` does not
|
|
33
|
+
* override it: an accessible name that does not contain the visible text is
|
|
34
|
+
* unreachable by speech input, which is what WCAG 2.5.3 (Label in Name)
|
|
35
|
+
* exists for. A slotted `slot="trigger"` replaces this built-in trigger
|
|
36
|
+
* entirely and is named differently; see `label`. */
|
|
51
37
|
triggerLabel?: string;
|
|
52
38
|
/** Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). */
|
|
53
39
|
triggerIconTrailing?: string;
|
|
54
|
-
/** Accessible name for
|
|
40
|
+
/** Accessible name for a trigger with no visible label. Ignored when
|
|
41
|
+
* `triggerLabel` is set, which is already the visible name.
|
|
42
|
+
*
|
|
43
|
+
* It DOES name a slotted `slot="trigger"`, and that is a difference in what
|
|
44
|
+
* the two slots MEAN, not a limitation. `<kai-button>`'s slot IS the button's
|
|
45
|
+
* label, so text slotted there is the name and `label` steps aside. This slot
|
|
46
|
+
* is VISUAL content, a `+` or an `<svg>`, with the name supplied separately:
|
|
47
|
+
* decoration beside a name, never a second name competing with one. So
|
|
48
|
+
* `label` names the trigger here by design.
|
|
49
|
+
*
|
|
50
|
+
* Slotting a real WORD rather than a glyph makes that word a visible label,
|
|
51
|
+
* and an accessible name has to contain the visible text. Then either drop
|
|
52
|
+
* `label` or make it contain the word you slotted. */
|
|
55
53
|
label?: string;
|
|
56
54
|
/** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
|
|
57
55
|
* attribute, the menu still self-manages on click/keyboard). Set `el.open = true`,
|
|
@@ -59,7 +57,7 @@ interface Props extends Record<string, unknown> {
|
|
|
59
57
|
open?: boolean;
|
|
60
58
|
/** Initial open state on mount (uncontrolled seed). */
|
|
61
59
|
defaultOpen?: boolean;
|
|
62
|
-
/** Disable the trigger
|
|
60
|
+
/** Disable the trigger: click/keyboard and `show()` no longer open the menu. */
|
|
63
61
|
disabled?: boolean;
|
|
64
62
|
}
|
|
65
63
|
|
|
@@ -68,8 +66,8 @@ interface Events {
|
|
|
68
66
|
* Fired when the user selects a leaf item.
|
|
69
67
|
* - Plain items: `{ id }`.
|
|
70
68
|
* - Checkbox items: `{ id, checked }` where `checked` is the NEW state.
|
|
71
|
-
* - Radio items: `{ id, radioGroup }
|
|
72
|
-
* one in `radioGroup` and clears the others.
|
|
69
|
+
* - Radio items: `{ id, radioGroup }`, where the consumer marks `id` as the
|
|
70
|
+
* selected one in `radioGroup` and clears the others.
|
|
73
71
|
*/
|
|
74
72
|
'kai-select': { id: string; checked?: boolean; radioGroup?: string };
|
|
75
73
|
/** The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). */
|
|
@@ -201,7 +199,17 @@ defineWebComponent<Props, Events>('kai-menu', {
|
|
|
201
199
|
? 'gap-1.5 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
202
200
|
: 'justify-center p-1.5 text-foreground hover:bg-muted',
|
|
203
201
|
)}
|
|
204
|
-
|
|
202
|
+
// A visible `triggerLabel` IS the name (name-from-contents reaches the
|
|
203
|
+
// slotted/shadow text), so `label` must not be layered over it: aria-label
|
|
204
|
+
// REPLACES the computed name, and a trigger reading "High" that answers to
|
|
205
|
+
// "Reasoning effort" locks speech-input users out (WCAG 2.5.3). Same rule
|
|
206
|
+
// kai-checkpoint and kai-button follow.
|
|
207
|
+
//
|
|
208
|
+
// A SLOTTED trigger keeps `label`, and that is the contract rather than a
|
|
209
|
+
// gap: kai-button's slot IS the label, so text there is the name; this
|
|
210
|
+
// slot is visual content with the name supplied separately. Two slots,
|
|
211
|
+
// two meanings, so the same rule should not apply to both. See `label`.
|
|
212
|
+
aria-label={props.triggerLabel ? undefined : (props.label ?? 'Open menu')}
|
|
205
213
|
>
|
|
206
214
|
{/* Slotted trigger wins; otherwise build one from the trigger* props;
|
|
207
215
|
otherwise fall back to a "more" glyph. */}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
|
-
|
|
3
|
+
// The badge shape is the Solid component's own `Skill` — one declaration, so the
|
|
4
|
+
// element and `<MessageSkills>` cannot drift, and the ROOT entry re-exports it.
|
|
5
|
+
import { MessageSkills, type Skill } from '../components/message-skills';
|
|
4
6
|
|
|
5
|
-
interface Skill {
|
|
6
|
-
/** Stable identifier for the skill. */
|
|
7
|
-
id: string;
|
|
8
|
-
/** Human-readable skill name shown on the badge. */
|
|
9
|
-
name: string;
|
|
10
|
-
}
|
|
11
7
|
|
|
12
8
|
interface Props extends Record<string, unknown> {
|
|
13
|
-
/** The active skills to badge. Set as a JS property.
|
|
14
|
-
|
|
9
|
+
/** The active skills to badge. Set as a JS property. Omit to supply them as
|
|
10
|
+
* `<kai-skill>` light-DOM children instead; when both are present the
|
|
11
|
+
* property's skills come first. Nothing renders when there are none. */
|
|
12
|
+
skills?: Skill[];
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
/**
|
package/src/elements/message.tsx
CHANGED
|
@@ -1,18 +1,76 @@
|
|
|
1
|
-
import { Show, createSignal, onMount, onCleanup } from 'solid-js';
|
|
1
|
+
import { Show, createSignal, createEffect, onMount, onCleanup, type JSX } from 'solid-js';
|
|
2
|
+
import { Dynamic } from 'solid-js/web';
|
|
2
3
|
import { defineWebComponent } from './define';
|
|
3
4
|
import { readSlots, MESSAGE_SLOTS } from './slots';
|
|
4
5
|
import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
|
|
5
6
|
import { Message, MessageAvatar, MessageBody } from '../components/message';
|
|
6
7
|
import { createMessageFeedback } from '../primitives/message-feedback';
|
|
8
|
+
import {
|
|
9
|
+
mergeCardTags,
|
|
10
|
+
BUILTIN_CARD_TAGS,
|
|
11
|
+
BUILTIN_CARD_COMPONENTS,
|
|
12
|
+
type CardTagMap,
|
|
13
|
+
type CardComponentMap,
|
|
14
|
+
} from '../primitives/card-registry';
|
|
15
|
+
import type { CardEnvelope } from '../primitives/card-contract';
|
|
16
|
+
import { hasParts } from './validate-messages';
|
|
7
17
|
import type { ChatMessage } from './chat-types';
|
|
8
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Bridges the web-component-facing `cardTypes` (envelope type -> custom-element
|
|
21
|
+
* TAG name, e.g. `{ 'my-widget': 'my-widget-el' }`) into the `CardComponentMap`
|
|
22
|
+
* that `MessageBody`/`Thread` expect. A type the consumer did NOT override keeps
|
|
23
|
+
* rendering its built-in Solid component directly (no extra custom-element
|
|
24
|
+
* indirection); an overridden built-in or a brand-new consumer type renders as a
|
|
25
|
+
* dynamically-created custom element instead, mirroring `<kai-cards>`'s
|
|
26
|
+
* `CardSlot`. A type with no tag at all (unregistered) simply gets no entry, so
|
|
27
|
+
* `CardRenderer`'s own fallback (`CardFallback`) takes over.
|
|
28
|
+
*/
|
|
29
|
+
export function cardComponentsFromTags(types?: CardTagMap, theme = 'auto'): CardComponentMap {
|
|
30
|
+
const tags = mergeCardTags(types);
|
|
31
|
+
const map: CardComponentMap = {};
|
|
32
|
+
for (const type of Object.keys(tags)) {
|
|
33
|
+
const tag = tags[type];
|
|
34
|
+
map[type] = tag === BUILTIN_CARD_TAGS[type] && BUILTIN_CARD_COMPONENTS[type]
|
|
35
|
+
? BUILTIN_CARD_COMPONENTS[type]
|
|
36
|
+
: (p) => <CardTagSlot tag={tag} envelope={p.envelope} theme={theme} />;
|
|
37
|
+
}
|
|
38
|
+
return map;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Renders one envelope as a dynamically-created custom element, setting the
|
|
42
|
+
* envelope's data/id/title/resolution as DOM properties (reactive) plus the
|
|
43
|
+
* `theme` + `data-card-id` chrome, mirroring `<kai-cards>`'s `CardSlot` so a
|
|
44
|
+
* custom card behaves identically whether it arrives via `<kai-cards>` or a
|
|
45
|
+
* `card` message part here. */
|
|
46
|
+
function CardTagSlot(props: { tag: string; envelope: CardEnvelope; theme: string }): JSX.Element {
|
|
47
|
+
let ref: HTMLElement | undefined;
|
|
48
|
+
createEffect(() => {
|
|
49
|
+
if (!ref) return;
|
|
50
|
+
(ref as unknown as { data: unknown }).data = props.envelope.data;
|
|
51
|
+
(ref as unknown as { cardId: string }).cardId = props.envelope.id;
|
|
52
|
+
if (props.envelope.title != null) (ref as unknown as { heading: string }).heading = props.envelope.title;
|
|
53
|
+
(ref as unknown as { resolution: unknown }).resolution = props.envelope.resolution;
|
|
54
|
+
ref.setAttribute('theme', props.theme);
|
|
55
|
+
ref.setAttribute('data-card-id', props.envelope.id);
|
|
56
|
+
});
|
|
57
|
+
return <Dynamic component={props.tag} ref={ref} />;
|
|
58
|
+
}
|
|
59
|
+
|
|
9
60
|
interface Props extends Record<string, unknown> {
|
|
10
61
|
/** The full message object. Set as a JS property. */
|
|
11
62
|
message?: ChatMessage;
|
|
12
|
-
/**
|
|
63
|
+
/** Who is speaking: `'user'` or `'assistant'`. Convenience for simple cases when
|
|
64
|
+
* not passing a `message` object.
|
|
65
|
+
*
|
|
66
|
+
* This is the SEMANTIC role of the message, not an ARIA role. The name collides
|
|
67
|
+
* with the global ARIA `role` attribute, which is why the facade lifts it off
|
|
68
|
+
* the host (see `liftRoleOffHost`). Neither speaker is a valid ARIA role,
|
|
69
|
+
* so a `role="user"` left on `<kai-message>` is a CRITICAL axe `aria-roles`
|
|
70
|
+
* violation. The accessible role lives on the row inside the shadow root
|
|
71
|
+
* instead: `role="article"` plus an `aria-label` naming the speaker, matching
|
|
72
|
+
* the SolidJS `<Message>` component. */
|
|
13
73
|
role?: 'user' | 'assistant';
|
|
14
|
-
/** Convenience content (used when `message` is not set). */
|
|
15
|
-
content?: string;
|
|
16
74
|
/** Force markdown on/off. Defaults to on for assistant, off for user. */
|
|
17
75
|
markdown?: boolean;
|
|
18
76
|
/** Text/markdown sizing for the message body. */
|
|
@@ -33,6 +91,65 @@ interface Props extends Record<string, unknown> {
|
|
|
33
91
|
* value keeps the default behaviour: the built-in avatar when one resolves, or
|
|
34
92
|
* your `slot="avatar"` content when projected (which REPLACES the built-in). */
|
|
35
93
|
avatar?: 'none' | string;
|
|
94
|
+
/** Optional card type -> custom-element tag overrides/additions for `card`
|
|
95
|
+
* parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a
|
|
96
|
+
* plain string map (not the `CardTagMap` alias) so the generated React
|
|
97
|
+
* wrapper inlines it instead of emitting an unresolved named type. */
|
|
98
|
+
cardTypes?: Record<string, string>;
|
|
99
|
+
/** JSON Schemas for the card types this app renders, keyed by envelope type. The
|
|
100
|
+
* companion of `cardTypes`, which says what DRAWS a card while this says what a
|
|
101
|
+
* VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas
|
|
102
|
+
* = { 'pricing-table': pricingSchema }`, never an attribute.
|
|
103
|
+
* `createCardRegistry(...).validationSchemas` is exactly this shape.
|
|
104
|
+
*
|
|
105
|
+
* Without it the kit validates its own seven built-ins and leaves your own card
|
|
106
|
+
* type, the one your app actually cares about, as the only unchecked thing on
|
|
107
|
+
* screen. A schema here WINS over a built-in of the same name.
|
|
108
|
+
*
|
|
109
|
+
* Typed `Record<string, object>` rather than `Record<string, JsonSchema>`
|
|
110
|
+
* deliberately: an imported `.json` schema widens `"type"` to `string`, and an
|
|
111
|
+
* authored one carries `$schema`/`title`/`description`/`additionalProperties`,
|
|
112
|
+
* so the tighter type would reject both of the normal ways to supply one. */
|
|
113
|
+
cardSchemas?: Record<string, object>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Move a `role` the consumer put on the host into the element's own prop store,
|
|
118
|
+
* and off the DOM.
|
|
119
|
+
*
|
|
120
|
+
* `role` names the SPEAKER here (`'user'` / `'assistant'`) — the correct domain
|
|
121
|
+
* word, and the documented attribute — but it is also the global ARIA `role`
|
|
122
|
+
* attribute, and neither speaker is a valid ARIA role. Measured in a real chromium:
|
|
123
|
+
* a host left carrying `role="user"` is a CRITICAL axe `aria-roles` violation
|
|
124
|
+
* ("Role must be one of the valid ARIA roles: user"), and chromium discards the
|
|
125
|
+
* unknown token and computes `generic`, so the row is left with no accessible role
|
|
126
|
+
* and no accessible name rather than a mis-announced one.
|
|
127
|
+
*
|
|
128
|
+
* Capture the value, remove the attribute, then write it back as a PROPERTY.
|
|
129
|
+
* component-register's prop accessors do not reflect, so the write cannot put it
|
|
130
|
+
* back on the DOM, and it feeds the same reactive prop the facade already reads.
|
|
131
|
+
*
|
|
132
|
+
* The ORDER is load-bearing: `removeAttribute` fires component-register's
|
|
133
|
+
* `attributeChangedCallback` with `null`, which sets the property to `null`. The
|
|
134
|
+
* write-back has to come after that, or the scrub destroys the speaker it was
|
|
135
|
+
* meant to preserve.
|
|
136
|
+
*
|
|
137
|
+
* NOTE — this covers every path where the attribute is still on the host by the
|
|
138
|
+
* time the facade runs (`setAttribute` before or after connection, and any later
|
|
139
|
+
* change, via the observer below). It does NOT cover an element authored in HTML
|
|
140
|
+
* and upgraded at registration time: `defineWebComponent` installs its
|
|
141
|
+
* non-reflecting `role` accessor AFTER `customElements.define()`, so for elements
|
|
142
|
+
* already in the document the native ARIAMixin setter runs first in the constructor
|
|
143
|
+
* (`this[prop] = undefined` → `role` is a nullable reflected IDL attribute →
|
|
144
|
+
* `removeAttribute`) and the value is gone before any of this code executes. That
|
|
145
|
+
* is a separate defect in `src/elements/define.tsx`, not something the facade can
|
|
146
|
+
* reach; this function composes correctly with the fix once it lands.
|
|
147
|
+
*/
|
|
148
|
+
function liftRoleOffHost(element: HTMLElement): void {
|
|
149
|
+
const attr = element.getAttribute('role');
|
|
150
|
+
if (attr === null) return;
|
|
151
|
+
element.removeAttribute('role');
|
|
152
|
+
(element as unknown as { role?: string }).role = attr;
|
|
36
153
|
}
|
|
37
154
|
|
|
38
155
|
/** Events fired by `<kai-message>`. */
|
|
@@ -52,7 +169,6 @@ interface Events {
|
|
|
52
169
|
defineWebComponent<Props, Events>('kai-message', {
|
|
53
170
|
message: undefined,
|
|
54
171
|
role: 'assistant',
|
|
55
|
-
content: undefined,
|
|
56
172
|
markdown: undefined,
|
|
57
173
|
proseSize: 'sm',
|
|
58
174
|
codeTheme: 'github-dark-dimmed',
|
|
@@ -61,10 +177,39 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
61
177
|
avatarSrc: undefined,
|
|
62
178
|
avatarFallback: undefined,
|
|
63
179
|
avatar: undefined,
|
|
180
|
+
cardTypes: undefined,
|
|
181
|
+
cardSchemas: undefined,
|
|
64
182
|
}, (props, { dispatch, flag, element, expose }) => {
|
|
65
183
|
const outer = useChatConfig();
|
|
184
|
+
// Do this FIRST, before anything reads `props.role`: it rewrites that prop as a
|
|
185
|
+
// side effect of taking the invalid ARIA role off the host.
|
|
186
|
+
liftRoleOffHost(element);
|
|
66
187
|
const msg = (): ChatMessage =>
|
|
67
|
-
props.message ?? {
|
|
188
|
+
props.message ?? {
|
|
189
|
+
id: 'message',
|
|
190
|
+
role: props.role ?? 'assistant',
|
|
191
|
+
parts: [],
|
|
192
|
+
};
|
|
193
|
+
// `message` is an untyped boundary: a consumer can hand it anything at
|
|
194
|
+
// runtime (a pre-0.20.0 `{ id, role, content }` object, in particular).
|
|
195
|
+
// `parts` is a REQUIRED field, so validate it here rather than let
|
|
196
|
+
// `MessageBody`/`groupMessageParts` throw deep inside a Solid render pass;
|
|
197
|
+
// an uncaught exception there blanks the whole element instead of just this
|
|
198
|
+
// one message. Warn once per bad message (not on every unrelated re-render)
|
|
199
|
+
// and render nothing for it, matching the old pre-parts fallback behavior
|
|
200
|
+
// (an unusable message rendered an empty body, not a crash).
|
|
201
|
+
let lastWarnedMessage: unknown;
|
|
202
|
+
const hasValidParts = (): boolean => {
|
|
203
|
+
const m = msg();
|
|
204
|
+
if (hasParts(m)) return true;
|
|
205
|
+
if (m !== lastWarnedMessage) {
|
|
206
|
+
lastWarnedMessage = m;
|
|
207
|
+
console.error(
|
|
208
|
+
"<kai-message>: 'message' must have a 'parts' array. The 'content' string field was removed in 0.20.0.",
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
};
|
|
68
213
|
// Copy + vote state lives here (above the rendered body) so it survives a
|
|
69
214
|
// re-render when the host swaps in a fresh `message` object during streaming.
|
|
70
215
|
const feedback = createMessageFeedback({
|
|
@@ -82,7 +227,7 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
82
227
|
// `kai-message-action{action:'copy'}`.
|
|
83
228
|
expose({
|
|
84
229
|
/** Copy the message content to the clipboard and show the copied check. */
|
|
85
|
-
copy: () => feedback.handleAction(msg(), 'copy'),
|
|
230
|
+
copy: () => { if (hasValidParts()) feedback.handleAction(msg(), 'copy'); },
|
|
86
231
|
});
|
|
87
232
|
|
|
88
233
|
// Read declarative <kai-action> children from light DOM.
|
|
@@ -106,6 +251,16 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
106
251
|
observer.observe(element, { childList: true, attributes: true, subtree: true });
|
|
107
252
|
onCleanup(() => observer.disconnect());
|
|
108
253
|
});
|
|
254
|
+
// A consumer can set `role` at any point after the element is live
|
|
255
|
+
// (`el.setAttribute('role', 'user')`), which puts the invalid ARIA role back on
|
|
256
|
+
// the host. Keep lifting it off. Scoped to the one attribute so this cannot be
|
|
257
|
+
// mistaken for general attribute handling; no loop, because the write-back is a
|
|
258
|
+
// property and the removal leaves nothing for the next callback to find.
|
|
259
|
+
onMount(() => {
|
|
260
|
+
const roleObserver = new MutationObserver(() => liftRoleOffHost(element));
|
|
261
|
+
roleObserver.observe(element, { attributes: true, attributeFilter: ['role'] });
|
|
262
|
+
onCleanup(() => roleObserver.disconnect());
|
|
263
|
+
});
|
|
109
264
|
const isUser = () => msg().role === 'user';
|
|
110
265
|
const avatar = () =>
|
|
111
266
|
msg().avatar ??
|
|
@@ -127,10 +282,9 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
127
282
|
const mergedActions = () => [...(msg().actions ?? []), ...slottedActions()];
|
|
128
283
|
const body = () => (
|
|
129
284
|
<MessageBody
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
attachments={msg().attachments}
|
|
285
|
+
parts={msg().parts}
|
|
286
|
+
cardTypes={cardComponentsFromTags(props.cardTypes, (props as { theme?: string }).theme)}
|
|
287
|
+
cardSchemas={props.cardSchemas}
|
|
134
288
|
isUser={isUser()}
|
|
135
289
|
markdown={useMarkdown()}
|
|
136
290
|
actions={mergedActions()}
|
|
@@ -165,27 +319,41 @@ defineWebComponent<Props, Events>('kai-message', {
|
|
|
165
319
|
);
|
|
166
320
|
|
|
167
321
|
return (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
fallback={
|
|
177
|
-
<Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
|
|
178
|
-
{body()}
|
|
179
|
-
</Message>
|
|
180
|
-
}
|
|
322
|
+
// No fallback: an invalid `message` (missing `parts`) renders nothing for
|
|
323
|
+
// this element rather than crashing. `hasValidParts()` already logged why.
|
|
324
|
+
<Show when={hasValidParts()}>
|
|
325
|
+
<ChatConfig
|
|
326
|
+
proseSize={props.proseSize}
|
|
327
|
+
codeTheme={props.codeTheme}
|
|
328
|
+
codeHighlight={flag('codeHighlight')}
|
|
329
|
+
portalMount={outer.portalMount()}
|
|
181
330
|
>
|
|
182
|
-
<
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
331
|
+
<Show
|
|
332
|
+
when={showRail()}
|
|
333
|
+
fallback={
|
|
334
|
+
// `role` here is `<Message>`'s SPEAKER prop, not an ARIA role: the
|
|
335
|
+
// component turns it into `role="article"` + an `aria-label` naming the
|
|
336
|
+
// speaker, so the row an assistive technology sees has a valid role and
|
|
337
|
+
// a name. This is the same treatment the SolidJS `<Message>` gets when
|
|
338
|
+
// used directly — the facade just always knows its speaker, so unlike
|
|
339
|
+
// the bare component (where `role` is optional and usually omitted) the
|
|
340
|
+
// row is never left unlabelled.
|
|
341
|
+
<Message
|
|
342
|
+
role={msg().role}
|
|
343
|
+
class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}
|
|
344
|
+
>
|
|
345
|
+
{body()}
|
|
346
|
+
</Message>
|
|
347
|
+
}
|
|
348
|
+
>
|
|
349
|
+
<Message role={msg().role} class={rowGroup()}>
|
|
350
|
+
{avatarRail()}
|
|
351
|
+
<div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
|
|
352
|
+
{body()}
|
|
353
|
+
</div>
|
|
354
|
+
</Message>
|
|
355
|
+
</Show>
|
|
356
|
+
</ChatConfig>
|
|
357
|
+
</Show>
|
|
190
358
|
);
|
|
191
359
|
});
|
|
@@ -6,8 +6,10 @@ import type { DropdownController } from '../ui/dropdown';
|
|
|
6
6
|
import type { ModelOption } from '../types';
|
|
7
7
|
|
|
8
8
|
interface Props extends Record<string, unknown> {
|
|
9
|
-
/** The selectable models. Set as a JS property (array).
|
|
10
|
-
|
|
9
|
+
/** The selectable models. Set as a JS property (array). Omit to supply them as
|
|
10
|
+
* `<kai-model>` light-DOM children instead; when both are present the
|
|
11
|
+
* property's models come first. */
|
|
12
|
+
models?: ModelOption[];
|
|
11
13
|
/** The currently-selected model id. Defaults to the first model. */
|
|
12
14
|
currentModel?: string;
|
|
13
15
|
/** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
|
|
@@ -16,7 +18,7 @@ interface Props extends Record<string, unknown> {
|
|
|
16
18
|
open?: boolean;
|
|
17
19
|
/** Initial open state on mount (uncontrolled seed). */
|
|
18
20
|
defaultOpen?: boolean;
|
|
19
|
-
/** Disable the trigger
|
|
21
|
+
/** Disable the trigger: click/keyboard and `show()` no longer open the dropdown. */
|
|
20
22
|
disabled?: boolean;
|
|
21
23
|
}
|
|
22
24
|
|
package/src/elements/pane.tsx
CHANGED
|
@@ -31,7 +31,7 @@ interface Props extends Record<string, unknown> {
|
|
|
31
31
|
/** Events fired by `<kai-pane>`. All non-bubbling — listen on the element. */
|
|
32
32
|
interface Events {
|
|
33
33
|
/** The maximize/restore control was clicked. `detail.maximized` is the
|
|
34
|
-
* intended NEXT state
|
|
34
|
+
* intended NEXT state. Drive the `maximized` prop yourself from it. */
|
|
35
35
|
'kai-maximize': { maximized: boolean };
|
|
36
36
|
/** The close (×) control was clicked. */
|
|
37
37
|
'kai-close': void;
|
|
@@ -3,15 +3,15 @@ import { defineWebComponent } from './define';
|
|
|
3
3
|
import { PromptDock, type PromptDockAppearance, type PromptDockFrame } from '../ui/prompt-dock';
|
|
4
4
|
|
|
5
5
|
interface Props extends Record<string, unknown> {
|
|
6
|
-
/** How the tray frames the input
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
/** How the tray frames the input, the SPATIAL inset axis: `inset` (default, the
|
|
7
|
+
* classic recessed frame on every side) | `edge` (top/bottom inset only; the
|
|
8
|
+
* input sits flush left/right so the lips span the full width) | `none` (no
|
|
9
|
+
* inset; the lips attach directly as a plain stack). Attribute: `frame`. */
|
|
10
10
|
frame?: PromptDockFrame;
|
|
11
|
-
/** How the tray surface looks
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
/** How the tray surface looks, the VISUAL axis orthogonal to `frame`: `soft`
|
|
12
|
+
* (default, sunken surface + border + radius) | `outlined` (transparent +
|
|
13
|
+
* border + radius) | `filled` (sunken, no border, + radius) | `plain`
|
|
14
|
+
* (bare). Attribute: `appearance`. */
|
|
15
15
|
appearance?: PromptDockAppearance;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -37,9 +37,9 @@ interface Props extends Record<string, unknown> {
|
|
|
37
37
|
* button (square icon, "Stop" aria-label). Clicking it fires `kai-stop`. */
|
|
38
38
|
stoppable?: boolean;
|
|
39
39
|
/** Send-button visibility. `'always'` (default) always shows it; `'auto'` shows
|
|
40
|
-
* it only when there's text/attachments (an empty composer hides it
|
|
41
|
-
* still submits). To hide it entirely (Enter-only), it's pure CSS:
|
|
42
|
-
* `::part(send){display:none}
|
|
40
|
+
* it only when there's text/attachments (an empty composer hides it, though
|
|
41
|
+
* Enter still submits). To hide it entirely (Enter-only), it's pure CSS:
|
|
42
|
+
* `::part(send){display:none}`, no prop needed. Restyle via `::part(send)`.
|
|
43
43
|
* The Stop button (`stoppable` + `loading`) is unaffected. */
|
|
44
44
|
submit?: 'always' | 'auto';
|
|
45
45
|
/** When `false`, hides the built-in paperclip attach button even though the
|
|
@@ -51,9 +51,9 @@ interface Props extends Record<string, unknown> {
|
|
|
51
51
|
* files without an upload). Set as a JS property; the element then manages its
|
|
52
52
|
* own attachment state from there (add via the paperclip, remove per chip). */
|
|
53
53
|
attachments?: AttachmentData[];
|
|
54
|
-
/** Rich entity triggers
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
/** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu
|
|
55
|
+
* that inserts an atomic pill. Convention: `/` → skills, `@` → agents (plugins
|
|
56
|
+
* are the grouping/provenance of those items). Set as a JS property. */
|
|
57
57
|
triggers?: TriggerDef[];
|
|
58
58
|
/** Default icon per entity kind (kind → image URL/data-URI) for pills/menu items
|
|
59
59
|
* without their own `icon`. Overrides the built-in agent/plugin glyphs. JS property. */
|
|
@@ -69,7 +69,7 @@ interface Events {
|
|
|
69
69
|
/** The input changed (fires on every edit). Carries the flattened `value`
|
|
70
70
|
* plus the structured `doc` + `entities`. */
|
|
71
71
|
'kai-value-change': { value: string; doc: ComposerDoc; entities: EntityRef[] };
|
|
72
|
-
/** The staged attachments changed
|
|
72
|
+
/** The staged attachments changed: a file was added (via the paperclip) or
|
|
73
73
|
* removed (per-chip ×). Carries the full current list so a consumer can react
|
|
74
74
|
* in real time (validate, show upload progress, toggle the send button). */
|
|
75
75
|
'kai-attachments-change': { attachments: AttachmentData[] };
|
|
@@ -198,9 +198,9 @@ defineWebComponent<Props, Events>('kai-prompt-input', {
|
|
|
198
198
|
handleChange('');
|
|
199
199
|
if (attachments().length) { setAttachments([]); dispatch('kai-attachments-change', { attachments: [] }); }
|
|
200
200
|
},
|
|
201
|
-
/** Send the current value programmatically
|
|
202
|
-
* button (fires kai-submit, then clears staged attachments). Named
|
|
203
|
-
* not `submit`, to avoid colliding with the `submit` prop. */
|
|
201
|
+
/** Send the current value programmatically, on the same path as Enter / the
|
|
202
|
+
* send button (fires kai-submit, then clears staged attachments). Named
|
|
203
|
+
* `send`, not `submit`, to avoid colliding with the `submit` prop. */
|
|
204
204
|
send: () => handleSubmit(),
|
|
205
205
|
});
|
|
206
206
|
|