@kitn.ai/ui 0.25.2 → 0.26.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 +2 -2
- package/dist/components/attachment-types.d.ts +46 -1
- package/dist/components/attachments.d.ts +31 -0
- package/dist/components/audio-visualizer/fit-scale.d.ts +50 -0
- package/dist/components/audio-visualizer/index.d.ts +15 -1
- package/dist/components/audio-visualizer/variant-bar.d.ts +24 -1
- package/dist/components/chat-thread.d.ts +3 -41
- package/dist/components/code-block.d.ts +22 -0
- package/dist/components/conversation-item.d.ts +54 -1
- package/dist/components/conversation-list.d.ts +65 -0
- package/dist/components/form.d.ts +42 -0
- package/dist/components/message.d.ts +7 -0
- package/dist/components/toast.d.ts +2 -1
- package/dist/components/voice-input.d.ts +8 -0
- package/dist/components/voice-output.d.ts +12 -1
- package/dist/components/workspace-shell.d.ts +87 -0
- package/dist/{create-tween-B5Y4Im8G.js → create-tween-BFT6c-Y8.js} +1 -1
- package/dist/{create-tween-4z1XYLkR.js → create-tween-CJNlzoaO.js} +1 -1
- package/dist/{create-tween-CUzOlaMS.js → create-tween-CQED4T0g.js} +1 -1
- package/dist/custom-elements.json +2931 -2572
- package/dist/diagnostics/hook.d.ts +81 -0
- package/dist/diagnostics/index.d.ts +7 -0
- package/dist/diagnostics/report-request.d.ts +61 -0
- package/dist/diagnostics.d.ts +5 -0
- package/dist/diagnostics.js +209 -0
- 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/autoloader.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-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-b5A8hlHs.js → Icon--Y8vsFal.js} +1 -1
- package/dist/elements/chunks/action-icons-D9u3OzYW.js +1 -0
- package/dist/elements/chunks/arrow-left-CVh1TeN7.js +1 -0
- package/dist/elements/chunks/{artifact-BSuPYFHY.js → artifact-BkYcfIlZ.js} +1 -1
- package/dist/elements/chunks/attachments-DwfNlubq.js +1 -0
- package/dist/elements/chunks/audio-visualizer-D7lB6mvR.js +1 -0
- package/dist/elements/chunks/{badge-TIMiJFKc.js → badge-Q0-Cmwzz.js} +1 -1
- package/dist/elements/chunks/{button-B9okqG73.js → button-flUbeufF.js} +1 -1
- package/dist/elements/chunks/{card-renderer-CSoTL_e1.js → card-renderer-3Dyl-FpN.js} +1 -1
- package/dist/elements/chunks/check-B5kBPKeo.js +1 -0
- package/dist/elements/chunks/chevron-down-DZ1GS39h.js +1 -0
- package/dist/elements/chunks/chevron-right-CvP7OUd2.js +1 -0
- package/dist/elements/chunks/{choice-card-CGMc3kek.js → choice-card-D4QUIOWZ.js} +1 -1
- package/dist/elements/chunks/circle-CDf9g6MQ.js +1 -0
- package/dist/elements/chunks/circle-check-CA47Nqbz.js +1 -0
- package/dist/elements/chunks/{circle-x-mhH7pOK2.js → circle-x-CJ_HVbC8.js} +1 -1
- package/dist/elements/chunks/code-block-BdLiTitd.js +1 -0
- package/dist/elements/chunks/collapsible-BzbXpPzr.js +1 -0
- package/dist/elements/chunks/{composer-CZZmtYOT.js → composer-Byve-n8K.js} +2 -2
- package/dist/elements/chunks/{confirm-card-BWjf2-xo.js → confirm-card-B0flE3MN.js} +1 -1
- package/dist/elements/chunks/context-VLIL3sJ-.js +1 -0
- package/dist/elements/chunks/controllable-DTwTIlwp.js +1 -0
- package/dist/elements/chunks/conversation-item-BDztezOG.js +1 -0
- package/dist/elements/chunks/copy-Nf-kqxXH.js +1 -0
- package/dist/elements/chunks/{create-tween-CUrM6D_o.js → create-tween-c4Z8TDYz.js} +2 -2
- package/dist/elements/chunks/default-input-C2iLFq0b.js +1 -0
- package/dist/elements/chunks/define-wjHR1MkU.js +1 -0
- package/dist/elements/chunks/disclosure-CcNbyLy0.js +1 -0
- package/dist/elements/chunks/{download-DnCyWFJE.js → download-C4V7tBdb.js} +1 -1
- package/dist/elements/chunks/dropdown-BgWTthUx.js +1 -0
- package/dist/elements/chunks/{ellipsis-CVxqfsDZ.js → ellipsis-7gU33mL2.js} +1 -1
- package/dist/elements/chunks/embed-D3KewsIJ.js +1 -0
- package/dist/elements/chunks/{external-link-DG2sRdQL.js → external-link-CSOEsNlx.js} +1 -1
- package/dist/elements/chunks/{file-text-D0J9F6M7.js → file-text-D1G8khle.js} +1 -1
- package/dist/elements/chunks/{file-tree-yGWNK0Js.js → file-tree-zvB2i7P9.js} +1 -1
- package/dist/elements/chunks/{folder-NV1pi_ud.js → folder-WW2LGLid.js} +1 -1
- package/dist/elements/chunks/form-CQirdC4W.js +1 -0
- package/dist/elements/chunks/hover-card-CJJkfHTK.js +1 -0
- package/dist/elements/chunks/icon-Cfgmf4fa.js +1 -0
- package/dist/elements/chunks/{info-C8r5Q6cc.js → info-DX3YMOt6.js} +1 -1
- package/dist/elements/chunks/input-BtW9U6Sq.js +1 -0
- package/dist/elements/chunks/{kbd-OGJDUT-O.js → kbd-LGXwuT_V.js} +1 -1
- package/dist/elements/chunks/{link-BdsfLB7b.js → link-2My69BqT.js} +1 -1
- package/dist/elements/chunks/{link-preview-Cf5KOP-i.js → link-preview-OQ9IEq0f.js} +1 -1
- package/dist/elements/chunks/{loader-B5QzK_8_.js → loader-iOxc_Tu-.js} +1 -1
- package/dist/elements/chunks/{markdown-DbozyYqa.js → markdown-DgBFaGAz.js} +1 -1
- package/dist/elements/chunks/{message-DtXKPqiR.js → message-VMZohrXx.js} +1 -1
- package/dist/elements/chunks/message-circle-CpXMM-_n.js +1 -0
- package/dist/elements/chunks/message-square-DxcWtETQ.js +1 -0
- package/dist/elements/chunks/message-tZmV2A3p.js +1 -0
- package/dist/elements/chunks/{minimize-2-SegJ_oku.js → minimize-2-DPIUKTrT.js} +1 -1
- package/dist/elements/chunks/{model-switcher-D7JrFFHp.js → model-switcher-DsT8tFB0.js} +1 -1
- package/dist/elements/chunks/{overlay-CV7z2YuX.js → overlay-DuiwdXjm.js} +1 -1
- package/dist/elements/chunks/{paperclip-Bg0ITU3b.js → paperclip-CRZVp4z_.js} +1 -1
- package/dist/elements/chunks/{progress-bar-D1_rzt6N.js → progress-bar-DNy66e_E.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-D5Sm8xF1.js → prompt-suggestion-Bn64Nl7L.js} +1 -1
- package/dist/elements/chunks/reasoning-Emn9N4-T.js +1 -0
- package/dist/elements/chunks/{resizable-Dpzjlvp4.js → resizable-D181b4fM.js} +1 -1
- package/dist/elements/chunks/{rotate-cw-DzVDJOA1.js → rotate-cw-CPWe37D9.js} +1 -1
- package/dist/elements/chunks/{scroll-area-93A1bbeG.js → scroll-area-ClZkZxIk.js} +1 -1
- package/dist/elements/chunks/scroll-button-DPE-t3x_.js +1 -0
- package/dist/elements/chunks/{separator-DH2r_ZSZ.js → separator-CeJHQqLW.js} +1 -1
- package/dist/elements/chunks/{settings-BFMOd6yB.js → settings-CqaHgJF9.js} +1 -1
- package/dist/elements/chunks/{settings-group-B3VZKIcz.js → settings-group-CjqjLCOn.js} +1 -1
- package/dist/elements/chunks/share-CyfnNEqp.js +1 -0
- package/dist/elements/chunks/{skeleton-N8BuWYmf.js → skeleton-D8akBnKS.js} +1 -1
- package/dist/elements/chunks/slots-DaNjX0rc.js +1 -0
- package/dist/elements/chunks/{source-w9V0NnBn.js → source-UWCvmVak.js} +1 -1
- package/dist/elements/chunks/{star-DHvACxtm.js → star-DoHFAikQ.js} +1 -1
- package/dist/elements/chunks/store-Cjq0qwYN.js +1 -0
- package/dist/elements/chunks/{tasks-card-lPxoodlA.js → tasks-card-CmZ5xh6v.js} +1 -1
- package/dist/elements/chunks/{text-shimmer-BY_rI3s5.js → text-shimmer-DYn09zrz.js} +1 -1
- package/dist/elements/chunks/textarea-skiGHURM.js +1 -0
- package/dist/elements/chunks/{thumbs-up-DQe0hvkZ.js → thumbs-up-DX2Ijk3H.js} +1 -1
- package/dist/elements/chunks/{toast-store-VUZZBhzH.js → toast-store-CFnQpThX.js} +1 -1
- package/dist/elements/chunks/{tool-C1YtxwPu.js → tool-DKQ2D1DP.js} +1 -1
- package/dist/elements/chunks/{tooltip-BqwnFWhn.js → tooltip-B0G99y8w.js} +1 -1
- package/dist/elements/chunks/{triangle-alert-B6or7F5u.js → triangle-alert-F9cyUEyy.js} +1 -1
- package/dist/elements/chunks/{use-card-resolution-DJg32jGH.js → use-card-resolution-DoA2f_EU.js} +1 -1
- package/dist/elements/chunks/{variant-aurora-QXTZPyST.js → variant-aurora-qt6Zct8M.js} +2 -2
- package/dist/elements/chunks/variant-custom-tJp22_BQ.js +1 -0
- package/dist/{variant-wave-BwzrHD1s.js → elements/chunks/variant-wave-CaQ5ti39.js} +2 -2
- package/dist/elements/chunks/x-B6UnOiLw.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-item.d.ts +1 -0
- package/dist/elements/conversation-item.js +1 -0
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/default-input.d.ts +3 -3
- package/dist/elements/define.d.ts +27 -0
- package/dist/elements/diagnostic-events.d.ts +74 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.d.ts +1 -0
- package/dist/elements/dock.js +149 -0
- package/dist/elements/dropdown.d.ts +1 -0
- package/dist/elements/dropdown.js +1 -0
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-diagnostics.d.ts +81 -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 +2 -0
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +3 -3
- 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/slots.d.ts +35 -3
- 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/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +232 -148
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5456 -4931
- package/dist/index.server.js +4142 -3669
- package/dist/kai-provider.es.js +40 -40
- package/dist/kai.es.js +1 -1
- package/dist/llms/llms-full.txt +184 -69
- package/dist/llms/llms.txt +3 -3
- package/dist/mcp.es.js +2669 -546
- package/dist/primitives/use-resize-observer.d.ts +23 -0
- package/dist/primitives/use-speech-recognition.d.ts +8 -0
- package/dist/primitives/use-text-stream.d.ts +5 -0
- package/dist/react/index.d.ts +115 -266
- package/dist/react.js +247 -221
- package/dist/register-impl-DpE7icIb.js +293 -0
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/tool-defs.d.ts +35 -0
- package/dist/schemas.js +403 -310
- package/dist/{solid-BMuDmFo_.js → solid-BtdqNZI7.js} +8435 -7394
- package/dist/{solid-CGYNdLRR.js → solid-CnavwBye.js} +5987 -5035
- package/dist/solid.d.ts +5 -0
- package/dist/solid.js +210 -203
- package/dist/solid.server.js +210 -203
- package/dist/state/index.d.ts +4 -0
- package/dist/state/persistence.d.ts +51 -0
- package/dist/state/stream.d.ts +50 -0
- package/dist/state/threads.d.ts +71 -0
- package/dist/state.js +269 -169
- package/dist/types.d.ts +4 -2
- package/dist/ui/dock.d.ts +109 -0
- package/dist/ui/hover-card.d.ts +44 -0
- package/dist/{variant-aurora-DwSOfraQ.js → variant-aurora-B8II3-I1.js} +27 -27
- package/dist/{variant-aurora-wKvAQ5wp.js → variant-aurora-CMNWOSJR.js} +28 -28
- package/dist/{variant-aurora-XEkPT0_z.js → variant-aurora-CcuDMWwQ.js} +2 -2
- package/dist/{variant-custom-eFIg2XWQ.js → variant-custom-BdvYC7af.js} +40 -40
- package/dist/{variant-custom-BhS9wIpU.js → variant-custom-C714mqKl.js} +65 -65
- package/dist/variant-custom-L16JLLZy.js +1 -0
- package/dist/{elements/chunks/variant-wave-DDCwhLas.js → variant-wave-2S4La2Ka.js} +2 -2
- package/dist/{variant-wave-CbVsmgwT.js → variant-wave-D7ruiA1W.js} +25 -25
- package/dist/{variant-wave-CUWGx9Bn.js → variant-wave-ecwykeyL.js} +21 -21
- package/dist/wire/chunk.d.ts +47 -0
- package/dist/wire/diagnostics.d.ts +575 -0
- package/dist/wire/encode-probe.d.ts +70 -0
- package/dist/wire/encode.d.ts +24 -0
- package/dist/wire/index.d.ts +2 -0
- package/dist/wire/sse.d.ts +10 -2
- package/dist/wire.js +917 -480
- package/frameworks/react/index.tsx +132 -93
- package/llms-full.txt +184 -69
- package/llms.txt +3 -3
- package/package.json +26 -6
- package/src/agent-tooling/archetypes.ts +41 -9
- package/src/agent-tooling/catalog/README.md +676 -0
- package/src/agent-tooling/catalog/catalog-types.ts +231 -0
- package/src/agent-tooling/catalog/fabrications.ts +96 -0
- package/src/agent-tooling/catalog/invariants.ts +284 -0
- package/src/agent-tooling/catalog/labs-titles.ts +114 -0
- package/src/agent-tooling/catalog/scenarios.ts +87 -0
- package/src/agent-tooling/catalog/surfaces.ts +275 -0
- package/src/agent-tooling/integrations/anthropic.ts +7 -1
- package/src/agent-tooling/integrations/cloudflare.ts +43 -2
- package/src/agent-tooling/integrations/langgraph.ts +7 -1
- package/src/agent-tooling/integrations/mastra.ts +7 -1
- package/src/agent-tooling/integrations/mock.ts +92 -17
- package/src/agent-tooling/integrations/ollama.ts +7 -1
- package/src/agent-tooling/integrations/openai.ts +7 -1
- package/src/agent-tooling/integrations/openrouter.ts +7 -1
- package/src/agent-tooling/integrations/pi.ts +56 -1
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +7 -1
- package/src/agent-tooling/mcp/css-raw.d.ts +12 -0
- package/src/agent-tooling/mcp/manifest.ts +100 -1
- package/src/agent-tooling/mcp/server.ts +61 -5
- package/src/agent-tooling/mcp/tools/reference.ts +440 -4
- package/src/agent-tooling/mcp/tools/scaffold.ts +1834 -307
- package/src/agent-tooling/mcp/tools/theme.ts +146 -30
- package/src/agent-tooling/mcp/validate-args.ts +141 -0
- package/src/agent-tooling/registry.ts +19 -7
- package/src/agent-tooling/route-emit.ts +26 -2
- package/src/components/attachment-types.ts +47 -1
- package/src/components/attachments.tsx +169 -22
- package/src/components/audio-visualizer/fit-scale.ts +112 -0
- package/src/components/audio-visualizer/index.tsx +80 -3
- package/src/components/audio-visualizer/variant-aurora.tsx +10 -4
- package/src/components/audio-visualizer/variant-bar.tsx +38 -6
- package/src/components/audio-visualizer/variant-custom.tsx +8 -2
- package/src/components/audio-visualizer/variant-grid.tsx +16 -11
- package/src/components/audio-visualizer/variant-radial.tsx +15 -10
- package/src/components/audio-visualizer/variant-wave.tsx +7 -2
- package/src/components/chat-container.tsx +4 -1
- package/src/components/chat-thread.tsx +36 -7
- package/src/components/code-block.tsx +79 -3
- package/src/components/composer.tsx +8 -1
- package/src/components/conversation-item.tsx +114 -4
- package/src/components/conversation-list.tsx +212 -12
- package/src/components/embed.tsx +4 -0
- package/src/components/form.tsx +41 -14
- package/src/components/message.tsx +75 -5
- package/src/components/response-stream.tsx +13 -7
- package/src/components/screen.tsx +5 -0
- package/src/components/scroll-button.tsx +7 -0
- package/src/components/toast.tsx +11 -5
- package/src/components/voice-input.tsx +35 -3
- package/src/components/voice-output.tsx +46 -6
- package/src/components/workspace-shell.tsx +285 -0
- package/src/diagnostics/hook.ts +352 -0
- package/src/diagnostics/index.ts +82 -0
- package/src/diagnostics/report-request.ts +296 -0
- package/src/elements/attachments.tsx +6 -7
- package/src/elements/audio-visualizer.tsx +48 -4
- package/src/elements/chat-workspace.tsx +159 -287
- package/src/elements/chat.tsx +12 -9
- package/src/elements/code-block.tsx +19 -1
- package/src/elements/command.tsx +4 -1
- package/src/elements/compiled.css +1 -1
- package/src/elements/conversation-item.tsx +80 -0
- package/src/elements/conversation-list.tsx +60 -11
- package/src/elements/default-input.tsx +5 -5
- package/src/elements/define.tsx +168 -8
- package/src/elements/diagnostic-events.ts +114 -0
- package/src/elements/dialog.tsx +47 -0
- package/src/elements/disclosure.ts +34 -12
- package/src/elements/dock.tsx +204 -0
- package/src/elements/dropdown.tsx +123 -0
- package/src/elements/element-diagnostics.ts +392 -0
- package/src/elements/element-manifest.json +12 -0
- package/src/elements/element-meta.json +672 -439
- package/src/elements/element-nonscalar.json +170 -0
- package/src/elements/element-types.d.ts +232 -148
- package/src/elements/menu.tsx +13 -0
- package/src/elements/prompt-dock.tsx +2 -1
- package/src/elements/prompt-input.tsx +8 -8
- package/src/elements/register-impl.ts +46 -0
- package/src/elements/register.ts +28 -0
- package/src/elements/resizable.tsx +52 -25
- package/src/elements/scroll-button.tsx +5 -0
- package/src/elements/slots.ts +107 -12
- package/src/elements/styles.css +30 -6
- package/src/elements/thinking-bar.tsx +16 -7
- package/src/elements/toast.tsx +3 -0
- package/src/elements/tool.tsx +26 -5
- package/src/elements/voice-input.tsx +11 -2
- package/src/elements/voice-output.tsx +16 -3
- package/src/index.ts +2 -0
- package/src/primitives/use-resize-observer.ts +33 -0
- package/src/primitives/use-speech-recognition.ts +12 -1
- package/src/primitives/use-stick-to-bottom.ts +34 -2
- package/src/primitives/use-text-stream.ts +33 -2
- package/src/remote/provider-runtime.ts +6 -3
- package/src/schemas/index.ts +1 -0
- package/src/schemas/tool-defs.ts +297 -6
- package/src/solid.ts +5 -0
- package/src/state/index.ts +12 -0
- package/src/state/persistence.ts +180 -0
- package/src/state/stream.ts +71 -4
- package/src/state/threads.ts +142 -0
- package/src/types.ts +4 -2
- package/src/ui/dialog.tsx +6 -0
- package/src/ui/dock.tsx +445 -0
- package/src/ui/dropdown.tsx +67 -23
- package/src/ui/hover-card.tsx +156 -6
- package/src/ui/input.tsx +29 -10
- package/src/ui/resizable.tsx +11 -0
- package/src/wire/chunk.ts +47 -0
- package/src/wire/consume.ts +185 -26
- package/src/wire/diagnostics.ts +727 -0
- package/src/wire/encode-probe.ts +214 -0
- package/src/wire/encode.ts +267 -14
- package/src/wire/formats/anthropic.ts +8 -1
- package/src/wire/formats/openai.ts +5 -0
- package/src/wire/index.ts +22 -0
- package/src/wire/read.ts +250 -6
- package/src/wire/sse.ts +16 -3
- package/dist/elements/chunks/action-icons-DW9muWrY.js +0 -1
- package/dist/elements/chunks/arrow-left-iJVnQmxA.js +0 -1
- package/dist/elements/chunks/attachments-CL6TaqIb.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BuUqQmaO.js +0 -1
- package/dist/elements/chunks/chat-thread-DxoKaStk.js +0 -1
- package/dist/elements/chunks/check-MdLzbxrm.js +0 -1
- package/dist/elements/chunks/chevron-down-MK7IzDqe.js +0 -1
- package/dist/elements/chunks/chevron-right-C5jXhmtV.js +0 -1
- package/dist/elements/chunks/circle-BG7VkPep.js +0 -1
- package/dist/elements/chunks/circle-check-GqvO2UBs.js +0 -1
- package/dist/elements/chunks/code-block-ClhQO9RW.js +0 -1
- package/dist/elements/chunks/collapsible-DBcBkFPh.js +0 -1
- package/dist/elements/chunks/context-hKjNqiyQ.js +0 -1
- package/dist/elements/chunks/conversation-list-CsGJjSKG.js +0 -1
- package/dist/elements/chunks/default-input-B1Mem5wu.js +0 -1
- package/dist/elements/chunks/define-B_tXMYRm.js +0 -1
- package/dist/elements/chunks/disclosure-DAoYOKew.js +0 -1
- package/dist/elements/chunks/dropdown-CmNna5lT.js +0 -1
- package/dist/elements/chunks/embed-CjAD2jSi.js +0 -1
- package/dist/elements/chunks/form-Cp8Y00Wn.js +0 -1
- package/dist/elements/chunks/hover-card-6KtXpLwT.js +0 -1
- package/dist/elements/chunks/icon-97R8SR2p.js +0 -1
- package/dist/elements/chunks/input-DrseEjhp.js +0 -1
- package/dist/elements/chunks/message-CE4k-qaj.js +0 -1
- package/dist/elements/chunks/message-square-C9ovmtOo.js +0 -1
- package/dist/elements/chunks/reasoning-BrxQfpfI.js +0 -1
- package/dist/elements/chunks/scroll-button-CrTo7wm4.js +0 -1
- package/dist/elements/chunks/share-DgNbkJKY.js +0 -1
- package/dist/elements/chunks/slots-CIw9RlAe.js +0 -1
- package/dist/elements/chunks/store-HIPGhNz9.js +0 -1
- package/dist/elements/chunks/textarea-DPfuhswM.js +0 -1
- package/dist/elements/chunks/variant-custom-D5ZlmziF.js +0 -1
- package/dist/elements/chunks/video-Bb86fVYI.js +0 -1
- package/dist/elements/chunks/x-BOhjBeOd.js +0 -1
- package/dist/primitives/card-validate-generator.testlib.d.ts +0 -20
- package/dist/register-impl-DGmGzrEM.js +0 -145
- package/dist/variant-custom-MkTNTycd.js +0 -1
- package/src/primitives/card-validate-generator.testlib.ts +0 -38
|
@@ -25,10 +25,19 @@ defineWebComponent<Props, Events>('kai-thinking-bar', {
|
|
|
25
25
|
text: 'Thinking',
|
|
26
26
|
stoppable: false,
|
|
27
27
|
stopLabel: 'Answer now',
|
|
28
|
-
}, (props, { dispatch, flag }) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
28
|
+
}, (props, { dispatch, flag, reflectFlag }) => {
|
|
29
|
+
// `stoppable` reflects, following kai-tool's `disabled` (its FIX1). Without it the
|
|
30
|
+
// remove direction is dead: `el.removeAttribute('stoppable')` parses to `undefined`,
|
|
31
|
+
// the prop was already `undefined` after a bare-attribute add, so no prop change
|
|
32
|
+
// fires and `flag()`'s non-reactive hasAttribute fallback is never re-read — the
|
|
33
|
+
// stop affordance stays rendered forever. reflectFlag's coercing read-back resolves
|
|
34
|
+
// every write through the same `flag()` policy, making both directions reactive.
|
|
35
|
+
reflectFlag('stoppable');
|
|
36
|
+
return (
|
|
37
|
+
<ThinkingBar
|
|
38
|
+
text={props.text}
|
|
39
|
+
stopLabel={props.stopLabel}
|
|
40
|
+
onStop={flag('stoppable') ? () => dispatch('kai-stop') : undefined}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
});
|
package/src/elements/toast.tsx
CHANGED
|
@@ -47,6 +47,9 @@ interface Events {
|
|
|
47
47
|
* Stack-level defaults are also declarative: `<kai-toast-region appearance="card"
|
|
48
48
|
* inverse>` makes every toast that doesn't set its own `appearance`/`inverse`
|
|
49
49
|
* render as an inverted card. A per-toast value always wins.
|
|
50
|
+
*
|
|
51
|
+
* Your app chrome must stay below the toast layer; set `--kai-toast-z`
|
|
52
|
+
* (default 100) on the host to move the layer.
|
|
50
53
|
*/
|
|
51
54
|
defineWebComponent<Props, Events>('kai-toast-region', {
|
|
52
55
|
toasts: [],
|
package/src/elements/tool.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Show } from 'solid-js';
|
|
1
|
+
import { createSignal, Show } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
3
|
import { Tool, type ToolPart } from '../components/tool';
|
|
4
4
|
import { wireDisclosure } from './disclosure';
|
|
@@ -36,13 +36,34 @@ defineWebComponent<Props, Events>('kai-tool', {
|
|
|
36
36
|
defaultOpen: undefined,
|
|
37
37
|
disabled: undefined,
|
|
38
38
|
}, (props, ctx) => {
|
|
39
|
-
const { flag } = ctx;
|
|
40
|
-
|
|
39
|
+
const { flag, reflectFlag } = ctx;
|
|
40
|
+
|
|
41
|
+
// A SIGNAL, not a `let`. This facade gates its whole subtree on `<Show when={props.tool}>`,
|
|
42
|
+
// and `tool` is an object prop, so the only sequence a consumer of the HTML spelling
|
|
43
|
+
// has is markup-then-assign: the element connects with no tool, renders nothing, and
|
|
44
|
+
// the Collapsible — and therefore the controller — arrives a tick later.
|
|
45
|
+
//
|
|
46
|
+
// With a plain `let`, wireDisclosure's effects ran once against `undefined` and never
|
|
47
|
+
// again, because the getter they were handed was not reactive and a bare `open`
|
|
48
|
+
// attribute never changes `props.open` to re-trigger them. Net result: `<kai-tool open>`
|
|
49
|
+
// silently stayed shut while `el.open` read back `true` — the property and the
|
|
50
|
+
// rendering disagreed. Making the controller reactive is the whole fix: the effects
|
|
51
|
+
// re-run the moment it lands. `Tool` already tracks its own copy this way internally.
|
|
52
|
+
// Pinned by the ordering rows in tests/elements/tool.test.tsx.
|
|
53
|
+
const [api, setApi] = createSignal<CollapsibleController>();
|
|
41
54
|
|
|
42
55
|
// The standard disclosure surface: settable+reflecting `open`, kai-open-change,
|
|
43
56
|
// show/hide/toggle, disabled-gating. See ./disclosure. This is the SOLE emitter
|
|
44
57
|
// of kai-open-change — the Tool/Collapsible no longer wires its own.
|
|
45
|
-
wireDisclosure(ctx,
|
|
58
|
+
wireDisclosure(ctx, api, () => props.open);
|
|
59
|
+
|
|
60
|
+
// `disabled` reflects too, following kai-dock. Without it the prop is write-only in
|
|
61
|
+
// the read direction AND deaf in the write one: `el.setAttribute('disabled', '')`
|
|
62
|
+
// after mount is parsed by component-register to `undefined`, so the prop never
|
|
63
|
+
// changes and nothing re-renders. reflectFlag's coercing setter resolves that
|
|
64
|
+
// `undefined` back through the same `flag()` policy, which is what makes the plain
|
|
65
|
+
// HTML gesture work at runtime and not only at parse time (findings G-05).
|
|
66
|
+
reflectFlag('disabled');
|
|
46
67
|
|
|
47
68
|
return (
|
|
48
69
|
<Show when={props.tool}>
|
|
@@ -50,7 +71,7 @@ defineWebComponent<Props, Events>('kai-tool', {
|
|
|
50
71
|
toolPart={props.tool!}
|
|
51
72
|
defaultOpen={flag('defaultOpen')}
|
|
52
73
|
disabled={flag('disabled')}
|
|
53
|
-
controllerRef={(a) => (
|
|
74
|
+
controllerRef={(a) => setApi(a)}
|
|
54
75
|
/>
|
|
55
76
|
</Show>
|
|
56
77
|
);
|
|
@@ -39,6 +39,13 @@ interface Events {
|
|
|
39
39
|
* push-to-talk indicator) in sync with the mic. Fires on real transitions
|
|
40
40
|
* only (manual click and programmatic start()/stop()), never on mount. */
|
|
41
41
|
'kai-recording-change': { recording: boolean };
|
|
42
|
+
/** A voice session failed, so no failure is ever silent. `detail.source` names
|
|
43
|
+
* the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on
|
|
44
|
+
* `<kai-voice-output>`), `detail.error` carries the platform error code, the
|
|
45
|
+
* thrown exception's name, or `no-result` when recognition ended with no error
|
|
46
|
+
* and no text (the user said nothing), and `detail.message` is human-readable.
|
|
47
|
+
* Deliberate cancellation does not fire. */
|
|
48
|
+
'kai-voice-error': { source: 'recognition'; error: string; message: string };
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
/**
|
|
@@ -47,8 +54,9 @@ interface Events {
|
|
|
47
54
|
* `SpeechRecognition` (Chrome/Safari; no Firefox — and cloud-based in Chrome).
|
|
48
55
|
* Set `el.transcribe` to route audio through your own async transcriber instead.
|
|
49
56
|
* Where neither is available it records the blob and emits `kai-audio-captured`
|
|
50
|
-
* with no text. Also emits `kai-transcription` (final text)
|
|
51
|
-
* `kai-transcript-interim`
|
|
57
|
+
* with no text. Also emits `kai-transcription` (final text), `kai-voice-error`
|
|
58
|
+
* (a failed or empty session) and, with `interim`, `kai-transcript-interim`
|
|
59
|
+
* (live partials).
|
|
52
60
|
*/
|
|
53
61
|
defineWebComponent<Props, Events>('kai-voice-input', {
|
|
54
62
|
transcribe: undefined,
|
|
@@ -85,6 +93,7 @@ defineWebComponent<Props, Events>('kai-voice-input', {
|
|
|
85
93
|
onTranscription={(text) => dispatch('kai-transcription', { text })}
|
|
86
94
|
onInterim={(text) => dispatch('kai-transcript-interim', { text })}
|
|
87
95
|
onRecordingChange={(recording) => dispatch('kai-recording-change', { recording })}
|
|
96
|
+
onError={(detail) => dispatch('kai-voice-error', detail)}
|
|
88
97
|
controllerRef={(c) => (controller = c)}
|
|
89
98
|
/>
|
|
90
99
|
);
|
|
@@ -20,18 +20,30 @@ interface Props extends Record<string, unknown> {
|
|
|
20
20
|
|
|
21
21
|
/** Events fired by `<kai-voice-output>`. */
|
|
22
22
|
interface Events {
|
|
23
|
-
/** Playback started or stopped. Drive your own UI in sync.
|
|
24
|
-
*
|
|
23
|
+
/** Playback started or stopped. Drive your own UI in sync. `speaking: true`
|
|
24
|
+
* fires when audio actually starts (utterance.onstart natively; audio playback
|
|
25
|
+
* beginning on the `synthesize` path), not when speak() is called; earlier
|
|
26
|
+
* releases fired it optimistically inside speak() itself. Fires on real
|
|
27
|
+
* transitions only (manual click and programmatic speak()/stop()), never on
|
|
28
|
+
* mount. */
|
|
25
29
|
'kai-speaking-change': { speaking: boolean };
|
|
26
30
|
/** The model path (`synthesize`) resolved audio: the raw `Blob` before playback. */
|
|
27
31
|
'kai-synthesized': { blob: Blob };
|
|
32
|
+
/** A voice session failed, so no failure is ever silent. `detail.source` names
|
|
33
|
+
* the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on
|
|
34
|
+
* `<kai-voice-output>`), `detail.error` carries the platform error code, the
|
|
35
|
+
* thrown exception's name, or `no-result` when recognition ended with no error
|
|
36
|
+
* and no text (the user said nothing), and `detail.message` is human-readable.
|
|
37
|
+
* Deliberate cancellation does not fire. */
|
|
38
|
+
'kai-voice-error': { source: 'synthesis'; error: string; message: string };
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
/**
|
|
31
42
|
* `<kai-voice-output>` — a speaker button that reads `text` aloud. Native by
|
|
32
43
|
* default (`speechSynthesis`); set `el.synthesize` to route through your TTS
|
|
33
44
|
* model instead. The output sibling of `<kai-voice-input>`. Emits
|
|
34
|
-
* `kai-speaking-change` and (model
|
|
45
|
+
* `kai-speaking-change`, `kai-voice-error` (a failed synthesis) and (model
|
|
46
|
+
* path) `kai-synthesized`.
|
|
35
47
|
*/
|
|
36
48
|
defineWebComponent<Props, Events>('kai-voice-output', {
|
|
37
49
|
text: '',
|
|
@@ -63,6 +75,7 @@ defineWebComponent<Props, Events>('kai-voice-output', {
|
|
|
63
75
|
onSynthesize={props.synthesize ? (text) => props.synthesize!(text) : undefined}
|
|
64
76
|
onSpeakingChange={(speaking) => dispatch('kai-speaking-change', { speaking })}
|
|
65
77
|
onSynthesized={(blob) => dispatch('kai-synthesized', { blob })}
|
|
78
|
+
onError={(detail) => dispatch('kai-voice-error', detail)}
|
|
66
79
|
controllerRef={(c) => (controller = c)}
|
|
67
80
|
/>
|
|
68
81
|
);
|
package/src/index.ts
CHANGED
|
@@ -339,6 +339,8 @@ export type { VoiceInputProps, VoiceInputController } from './components/voice-i
|
|
|
339
339
|
export { ConversationList } from './components/conversation-list';
|
|
340
340
|
export type { ConversationListProps, ConversationListController } from './components/conversation-list';
|
|
341
341
|
export { ConversationItem } from './components/conversation-item';
|
|
342
|
+
export { SlottedConversationItem } from './components/conversation-item';
|
|
343
|
+
export type { SlottedConversationItemProps } from './components/conversation-item';
|
|
342
344
|
export type { ConversationItemProps } from './components/conversation-item';
|
|
343
345
|
export { ModelSwitcher } from './components/model-switcher';
|
|
344
346
|
export type { ModelSwitcherProps } from './components/model-switcher';
|
|
@@ -10,3 +10,36 @@ export function observeContentHeight(el: Element, onHeight: (height: number) =>
|
|
|
10
10
|
ro.observe(el);
|
|
11
11
|
return () => ro.disconnect();
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
/** Observe an element's resizes but report the FULL rendered document height (not the
|
|
15
|
+
* observed element's own content-box) — `document.body.scrollHeight`.
|
|
16
|
+
*
|
|
17
|
+
* Used by the remote-card provider runtime to size the host iframe (D1, rung 5 IVP
|
|
18
|
+
* task-10-report.md): `observeContentHeight` reports the ResizeObserver content-box of
|
|
19
|
+
* the observed root, which drops that root's OWN padding/border and any ancestor
|
|
20
|
+
* (e.g. `<body>`) padding above it — the host then clips the bottom of the card by
|
|
21
|
+
* exactly those lost pixels. `scrollHeight` is the full padding-box height as actually
|
|
22
|
+
* rendered, so it stays correct no matter which element in the ancestor chain carries
|
|
23
|
+
* the padding/border, including if the provider page's own styles change later —
|
|
24
|
+
* reading contentRect off one fixed element, or hand-summing computed padding/border
|
|
25
|
+
* off a fixed list of ancestors, would both need updating every time that chain does.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately `document.body.scrollHeight`, NOT `document.documentElement.scrollHeight`
|
|
28
|
+
* (N1, task-10-report.md "Fix-wave re-review"): the CSSOM View spec special-cases the
|
|
29
|
+
* scrollHeight of the ROOT element to be `max(viewport scrolling area, viewport
|
|
30
|
+
* height)` — and the host sets the iframe's viewport FROM this very measurement
|
|
31
|
+
* (`host-embed.ts` `sizeIframe`), so `documentElement.scrollHeight` can only grow for
|
|
32
|
+
* the life of the frame: once the iframe is tall, the root's own scrollHeight is
|
|
33
|
+
* floored at that height even after the card's content shrinks. `<body>` carries no
|
|
34
|
+
* such floor — its scrollHeight is a plain padding-box measurement of body's own
|
|
35
|
+
* content, so it shrinks along with the card. */
|
|
36
|
+
export function observeDocumentHeight(el: Element, onHeight: (height: number) => void): () => void {
|
|
37
|
+
let last = -1;
|
|
38
|
+
const ro = new ResizeObserver(() => {
|
|
39
|
+
const doc = el.ownerDocument;
|
|
40
|
+
const h = doc?.body?.scrollHeight ?? doc?.documentElement?.scrollHeight ?? el.getBoundingClientRect().height;
|
|
41
|
+
if (last < 0 || Math.abs(h - last) > THRESHOLD) { last = h; onHeight(h); }
|
|
42
|
+
});
|
|
43
|
+
ro.observe(el);
|
|
44
|
+
return () => ro.disconnect();
|
|
45
|
+
}
|
|
@@ -51,6 +51,14 @@ export interface SpeechRecognitionStartOptions {
|
|
|
51
51
|
lang?: string;
|
|
52
52
|
/** Called with each interim (non-final) transcript when `interim` is enabled. */
|
|
53
53
|
onInterim?: (text: string) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Called when the recognition session hits a runtime error (`recognition.onerror`),
|
|
56
|
+
* with the platform's error code (`network`, `not-allowed`, `no-speech`, ...) and a
|
|
57
|
+
* human-readable message. The session still ends through `onend`, so `start()` still
|
|
58
|
+
* resolves (with whatever text was captured before the error). Without this callback
|
|
59
|
+
* a runtime failure is invisible: the `error` signal is state, not a notification.
|
|
60
|
+
*/
|
|
61
|
+
onError?: (error: string, message: string) => void;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -102,7 +110,10 @@ export function useSpeechRecognition(options: UseSpeechRecognitionOptions = {})
|
|
|
102
110
|
};
|
|
103
111
|
|
|
104
112
|
recognition.onerror = (event) => {
|
|
105
|
-
|
|
113
|
+
const code = event.error ?? 'unknown';
|
|
114
|
+
const message = `Speech recognition error: ${code}`;
|
|
115
|
+
setError(message);
|
|
116
|
+
opts.onError?.(code, message);
|
|
106
117
|
};
|
|
107
118
|
|
|
108
119
|
recognition.onend = () => {
|
|
@@ -17,14 +17,42 @@ export function useStickToBottom() {
|
|
|
17
17
|
|
|
18
18
|
function scrollToBottom(behavior: ScrollBehavior = 'smooth') {
|
|
19
19
|
if (!containerEl) return;
|
|
20
|
-
|
|
20
|
+
if (typeof containerEl.scrollTo === 'function') {
|
|
21
|
+
containerEl.scrollTo({ top: containerEl.scrollHeight, behavior });
|
|
22
|
+
} else {
|
|
23
|
+
containerEl.scrollTop = containerEl.scrollHeight;
|
|
24
|
+
}
|
|
21
25
|
shouldStick = true;
|
|
22
26
|
setIsAtBottom(true);
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
let pendingFrame: number | undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `cancelAnimationFrame`, captured at SETUP -- not called bare at cleanup.
|
|
33
|
+
*
|
|
34
|
+
* Cleanup is not guaranteed to run while the page that mounted this
|
|
35
|
+
* primitive is still standing: a host can tear its DOM globals down first
|
|
36
|
+
* (`component-register`'s `disconnectedCallback` defers a microtask; a
|
|
37
|
+
* test environment deletes the globals synchronously right after
|
|
38
|
+
* detaching). A bare `cancelAnimationFrame` there throws, surfacing as an
|
|
39
|
+
* unhandled rejection that fails a run in which every test passed --
|
|
40
|
+
* see tests/components/teardown-without-dom-globals.test.tsx, and the
|
|
41
|
+
* same pattern in create-tween.ts.
|
|
42
|
+
*
|
|
43
|
+
* Guarded because "setup" here is the component body, and a server render
|
|
44
|
+
* executes component bodies too; Node has neither global.
|
|
45
|
+
*/
|
|
46
|
+
const cancelFrame = typeof cancelAnimationFrame === 'function'
|
|
47
|
+
? cancelAnimationFrame.bind(globalThis)
|
|
48
|
+
: () => {};
|
|
49
|
+
|
|
25
50
|
function onNewContent() {
|
|
26
51
|
if (shouldStick) {
|
|
27
|
-
requestAnimationFrame(() =>
|
|
52
|
+
pendingFrame = requestAnimationFrame(() => {
|
|
53
|
+
pendingFrame = undefined;
|
|
54
|
+
scrollToBottom('instant');
|
|
55
|
+
});
|
|
28
56
|
}
|
|
29
57
|
}
|
|
30
58
|
|
|
@@ -36,6 +64,10 @@ export function useStickToBottom() {
|
|
|
36
64
|
onCleanup(() => {
|
|
37
65
|
el.removeEventListener('scroll', checkIfAtBottom);
|
|
38
66
|
observer.disconnect();
|
|
67
|
+
if (pendingFrame !== undefined) {
|
|
68
|
+
cancelFrame(pendingFrame);
|
|
69
|
+
pendingFrame = undefined;
|
|
70
|
+
}
|
|
39
71
|
});
|
|
40
72
|
}
|
|
41
73
|
|
|
@@ -5,6 +5,19 @@ export interface UseTextStreamOptions {
|
|
|
5
5
|
speed?: number;
|
|
6
6
|
characterChunkSize?: number;
|
|
7
7
|
fadeDuration?: number;
|
|
8
|
+
segmentDelay?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Default fade-in duration for a given speed (ms) — shared with ResponseStream. */
|
|
12
|
+
export function defaultFadeDuration(speed: number): number {
|
|
13
|
+
const s = Math.min(100, Math.max(1, speed));
|
|
14
|
+
return Math.round(1000 / Math.sqrt(s));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Default per-segment stagger for a given speed (ms) — shared with ResponseStream. */
|
|
18
|
+
export function defaultSegmentDelay(speed: number): number {
|
|
19
|
+
const s = Math.min(100, Math.max(1, speed));
|
|
20
|
+
return Math.max(1, Math.round(100 / Math.sqrt(s)));
|
|
8
21
|
}
|
|
9
22
|
|
|
10
23
|
export interface TextStreamSegment {
|
|
@@ -23,6 +36,7 @@ export function useTextStream(options: UseTextStreamOptions) {
|
|
|
23
36
|
let fullText = '';
|
|
24
37
|
let charIndex = 0;
|
|
25
38
|
let intervalId: ReturnType<typeof setInterval> | undefined;
|
|
39
|
+
let completeTimeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
26
40
|
let isPaused = false;
|
|
27
41
|
let asyncIterator: AsyncIterator<string> | undefined;
|
|
28
42
|
|
|
@@ -31,6 +45,10 @@ export function useTextStream(options: UseTextStreamOptions) {
|
|
|
31
45
|
clearInterval(intervalId);
|
|
32
46
|
intervalId = undefined;
|
|
33
47
|
}
|
|
48
|
+
if (completeTimeoutId !== undefined) {
|
|
49
|
+
clearTimeout(completeTimeoutId);
|
|
50
|
+
completeTimeoutId = undefined;
|
|
51
|
+
}
|
|
34
52
|
}
|
|
35
53
|
|
|
36
54
|
function typewriterTick() {
|
|
@@ -76,8 +94,21 @@ export function useTextStream(options: UseTextStreamOptions) {
|
|
|
76
94
|
const words = source.split(/(\s+)/).filter(Boolean);
|
|
77
95
|
setSegments(words.map((text, index) => ({ text, index })));
|
|
78
96
|
setDisplayedText(source);
|
|
79
|
-
//
|
|
80
|
-
//
|
|
97
|
+
// Completion announces after the staggered animation has had time to
|
|
98
|
+
// play: segments * per-segment delay + one fade duration — the promise
|
|
99
|
+
// the comment here used to make with no code behind it (nothing on this
|
|
100
|
+
// path ever called setIsComplete(true), so kai-complete never fired for
|
|
101
|
+
// a fade-mode string). A timer, not a synchronous write: the consumer
|
|
102
|
+
// attaches its kai-complete listener a beat after mount, and a
|
|
103
|
+
// same-tick fire races past it.
|
|
104
|
+
const segDelay = typeof options.segmentDelay === 'number'
|
|
105
|
+
? Math.max(0, options.segmentDelay)
|
|
106
|
+
: defaultSegmentDelay(speed);
|
|
107
|
+
const fadeDur = options.fadeDuration ?? defaultFadeDuration(speed);
|
|
108
|
+
completeTimeoutId = setTimeout(() => {
|
|
109
|
+
completeTimeoutId = undefined;
|
|
110
|
+
setIsComplete(true);
|
|
111
|
+
}, words.length * segDelay + fadeDur);
|
|
81
112
|
}
|
|
82
113
|
} else {
|
|
83
114
|
if (options.mode === 'typewriter') {
|
|
@@ -14,7 +14,7 @@ import { createPacker, isCardWireFrame, type WireMessage } from './wire';
|
|
|
14
14
|
import { assertOrigin, redactFrame } from './origin';
|
|
15
15
|
import { negotiateVersion } from './version';
|
|
16
16
|
import { hasPollutionKey } from './validate';
|
|
17
|
-
import {
|
|
17
|
+
import { observeDocumentHeight } from '../primitives/use-resize-observer';
|
|
18
18
|
import { validateAgainstSchema, type JsonSchema } from '../primitives/card-validate';
|
|
19
19
|
|
|
20
20
|
/** A provider-side renderer for one card `type`. Renamed (was CardRenderer) per H-K
|
|
@@ -105,10 +105,13 @@ export function createCardBridge(options: CreateCardBridgeOptions): CardBridge {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function startObserver(): void {
|
|
108
|
-
// Tear down any existing observer so
|
|
108
|
+
// Tear down any existing observer so observeDocumentHeight's internal `last` baseline
|
|
109
109
|
// re-initializes to -1 and the newly-mounted card always emits its initial height.
|
|
110
|
+
// observeDocumentHeight (not observeContentHeight) so the reported height covers
|
|
111
|
+
// the FULL rendered document — root's own padding/border AND the provider page's
|
|
112
|
+
// body padding above it — not just root's ResizeObserver content-box (D1).
|
|
110
113
|
stopObserver?.(); stopObserver = null;
|
|
111
|
-
stopObserver =
|
|
114
|
+
stopObserver = observeDocumentHeight(root, (height) => {
|
|
112
115
|
if (!currentId) return;
|
|
113
116
|
cardHost.emit({ kind: 'resize', cardId: currentId, height });
|
|
114
117
|
});
|