@kitn.ai/ui 0.28.0 → 0.30.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 +11 -7
- package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
- package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
- package/dist/agent-tooling/construct/public.d.ts +15 -0
- package/dist/agent-tooling/construct/schema.d.ts +111 -0
- package/dist/arrow-down-D783iMJj.js +1 -0
- package/dist/arrow-left-0VLM5kyg.js +1 -0
- package/dist/artifact-DGjzHYUT.js +1 -0
- package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
- package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
- package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
- package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
- package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
- package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
- package/dist/check-CiEOVnEN.js +1 -0
- package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
- package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
- package/dist/chevron-down-CSobuZRG.js +1 -0
- package/dist/chevron-right-DR9ZAP-2.js +1 -0
- package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
- package/dist/circle-BC66EYF7.js +1 -0
- package/dist/circle-check-BqmahW0O.js +1 -0
- package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
- package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
- package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
- package/dist/components/builder-composer-triggers.d.ts +62 -0
- package/dist/components/builder-layout.d.ts +54 -0
- package/dist/components/builder-message-actions.d.ts +72 -0
- package/dist/components/builder-panel.d.ts +189 -0
- package/dist/components/builder-preview.d.ts +11 -0
- package/dist/components/builder-shell-controls.d.ts +69 -0
- package/dist/components/builder-skeleton.d.ts +58 -0
- package/dist/components/builder-start.d.ts +75 -0
- package/dist/components/builder-workspace-variants.d.ts +23 -0
- package/dist/components/captions.d.ts +66 -0
- package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
- package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
- package/dist/construct-cli.es.js +3 -3
- package/dist/construct.d.ts +5 -0
- package/dist/construct.js +327 -0
- package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
- package/dist/controllable-BagRpyHv.js +1 -0
- package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
- package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
- package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
- package/dist/core-C8fzo39E.js +1 -12
- package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
- package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
- package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
- package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
- package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
- package/dist/define-CI0y3eE4.js +1 -0
- package/dist/define.js +40 -40
- package/dist/define.server.js +45 -45
- package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
- package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
- 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-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkbox-group.js +1 -1
- package/dist/elements/checkbox.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- 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.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.js +1 -1
- package/dist/elements/dropdown.js +1 -1
- package/dist/elements/editable-label.js +1 -1
- 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-grid.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/radio-group.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- 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/select.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/slider.js +1 -1
- 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/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
- package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
- package/dist/engine-javascript-C1x7zo1_.js +1 -141
- package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
- package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
- package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
- package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
- package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
- package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
- package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
- package/dist/index.js +1741 -1725
- package/dist/index.server.js +1582 -1566
- package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
- package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
- package/dist/kai.es.js +1 -1
- package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
- package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
- package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
- package/dist/loader-KvJB6NrT.js +1 -0
- package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
- package/dist/mcp.es.js +9 -5
- package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
- package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
- package/dist/message-circle-BPpp5QKv.js +1 -0
- package/dist/message-square-BLbsd9BJ.js +1 -0
- package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
- package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
- package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
- package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
- package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
- package/dist/play-BXy1u7rW.js +1 -0
- package/dist/primitives/use-auto-resize.d.ts +11 -0
- package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
- package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
- package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
- package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
- package/dist/register-impl-DvEnhIxx.js +424 -0
- package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
- package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
- package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
- package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
- package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
- package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
- package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
- package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
- package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
- package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
- package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
- package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
- package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
- package/dist/solid.d.ts +6 -0
- package/dist/solid.js +259 -254
- package/dist/solid.server.js +259 -254
- package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
- package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
- package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
- package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
- package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
- package/dist/text-shimmer-BSzgEnDH.js +1 -0
- package/dist/textarea-DrYNt_0z.js +1 -0
- package/dist/theme.tokens.css +22 -21
- package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
- package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
- package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
- package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
- package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
- package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
- package/dist/ui/color-field.d.ts +48 -0
- package/dist/ui/textarea.d.ts +4 -0
- package/dist/ui/toggle-chip.d.ts +40 -0
- package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
- package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
- package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
- package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
- package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
- package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
- package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
- package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
- package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
- package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
- package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
- package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
- package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
- package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
- package/dist/x-eiO9V6J6.js +1 -0
- package/{src/elements/styles.css → kit-base.css} +27 -44
- package/package.json +32 -17
- package/solid.css +33 -0
- package/theme.css +39 -23
- package/bin/route.test.js +0 -58
- package/dist/arrow-down-CjRU3JgV.js +0 -1
- package/dist/arrow-left-Bnpb1UEW.js +0 -1
- package/dist/artifact-Bwt7OgcR.js +0 -1
- package/dist/check-njkVdZu2.js +0 -1
- package/dist/chevron-down-B72s6PXR.js +0 -1
- package/dist/chevron-right-BatuHzUm.js +0 -1
- package/dist/circle-check-B62pODB3.js +0 -1
- package/dist/circle-zx0ByzY9.js +0 -1
- package/dist/controllable-CnGpMF6r.js +0 -1
- package/dist/define-By-uL588.js +0 -1
- package/dist/loader-BM4CEz4G.js +0 -1
- package/dist/message-circle-DruwObfX.js +0 -1
- package/dist/message-square-BG6q6mlm.js +0 -1
- package/dist/play-BvKKq3fX.js +0 -1
- package/dist/register-impl-B1hLkrI8.js +0 -424
- package/dist/text-shimmer-Dcj1MHuq.js +0 -1
- package/dist/textarea-Dpvbngbg.js +0 -1
- package/dist/x-Z5UntkIJ.js +0 -1
- package/src/agent-tooling/README.md +0 -192
- package/src/agent-tooling/archetypes.ts +0 -205
- package/src/agent-tooling/catalog/README.md +0 -676
- package/src/agent-tooling/catalog/catalog-types.ts +0 -231
- package/src/agent-tooling/catalog/fabrications.ts +0 -96
- package/src/agent-tooling/catalog/invariants.ts +0 -284
- package/src/agent-tooling/catalog/labs-titles.ts +0 -114
- package/src/agent-tooling/catalog/scenarios.ts +0 -87
- package/src/agent-tooling/catalog/surfaces.ts +0 -347
- package/src/agent-tooling/construct/cli-entry.ts +0 -8
- package/src/agent-tooling/construct/cli.ts +0 -147
- package/src/agent-tooling/construct/codegen.ts +0 -1635
- package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
- package/src/agent-tooling/construct/dev.ts +0 -148
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
- package/src/agent-tooling/construct/schema.ts +0 -452
- package/src/agent-tooling/integrations/anthropic.ts +0 -442
- package/src/agent-tooling/integrations/cloudflare.ts +0 -218
- package/src/agent-tooling/integrations/langgraph.ts +0 -133
- package/src/agent-tooling/integrations/mastra.ts +0 -182
- package/src/agent-tooling/integrations/mock.ts +0 -148
- package/src/agent-tooling/integrations/ollama.ts +0 -97
- package/src/agent-tooling/integrations/openai.ts +0 -95
- package/src/agent-tooling/integrations/openrouter.ts +0 -82
- package/src/agent-tooling/integrations/pi.ts +0 -176
- package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
- package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
- package/src/agent-tooling/mcp/manifest.ts +0 -422
- package/src/agent-tooling/mcp/server.ts +0 -116
- package/src/agent-tooling/mcp/stdio.ts +0 -18
- package/src/agent-tooling/mcp/tools/construct.ts +0 -130
- package/src/agent-tooling/mcp/tools/debug.ts +0 -621
- package/src/agent-tooling/mcp/tools/reference.ts +0 -980
- package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
- package/src/agent-tooling/mcp/tools/theme.ts +0 -456
- package/src/agent-tooling/mcp/tools/types.ts +0 -14
- package/src/agent-tooling/mcp/validate-args.ts +0 -141
- package/src/agent-tooling/recipes/composed-thread.ts +0 -714
- package/src/agent-tooling/recipes/index.ts +0 -22
- package/src/agent-tooling/recipes/types.ts +0 -32
- package/src/agent-tooling/registry.ts +0 -132
- package/src/agent-tooling/route-emit.ts +0 -305
- package/src/agent-tooling/types.ts +0 -390
- package/src/components/artifact-card.tsx +0 -120
- package/src/components/artifact.tsx +0 -914
- package/src/components/attachment-types.ts +0 -66
- package/src/components/attachments.tsx +0 -536
- package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
- package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
- package/src/components/audio-visualizer/fit-scale.ts +0 -112
- package/src/components/audio-visualizer/index.tsx +0 -528
- package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
- package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
- package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
- package/src/components/audio-visualizer/sizes.ts +0 -54
- package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
- package/src/components/audio-visualizer/variant-bar.tsx +0 -175
- package/src/components/audio-visualizer/variant-custom.tsx +0 -344
- package/src/components/audio-visualizer/variant-grid.tsx +0 -175
- package/src/components/audio-visualizer/variant-radial.tsx +0 -163
- package/src/components/audio-visualizer/variant-wave.tsx +0 -130
- package/src/components/audio-visualizer/wave.glsl.ts +0 -130
- package/src/components/card-fallback.tsx +0 -60
- package/src/components/card-renderer.tsx +0 -220
- package/src/components/card.tsx +0 -212
- package/src/components/chain-of-thought.tsx +0 -348
- package/src/components/chat-container.tsx +0 -89
- package/src/components/chat-scope-picker.tsx +0 -57
- package/src/components/chat-thread.tsx +0 -1014
- package/src/components/checkpoint.tsx +0 -88
- package/src/components/choice-card.tsx +0 -743
- package/src/components/coachmark.tsx +0 -249
- package/src/components/code-block.tsx +0 -181
- package/src/components/composer-dom.ts +0 -159
- package/src/components/composer-highlight.ts +0 -242
- package/src/components/composer-history.ts +0 -82
- package/src/components/composer.tsx +0 -1075
- package/src/components/confirm-card.tsx +0 -402
- package/src/components/context.tsx +0 -377
- package/src/components/conversation-item.tsx +0 -241
- package/src/components/conversation-list.tsx +0 -429
- package/src/components/conversation-panel.tsx +0 -118
- package/src/components/dismissed-stub.tsx +0 -80
- package/src/components/embed.tsx +0 -200
- package/src/components/empty.tsx +0 -177
- package/src/components/feedback-bar.tsx +0 -166
- package/src/components/file-tree.tsx +0 -530
- package/src/components/file-upload.tsx +0 -167
- package/src/components/form-widgets.tsx +0 -525
- package/src/components/form.tsx +0 -1296
- package/src/components/home-panel.tsx +0 -159
- package/src/components/image.tsx +0 -65
- package/src/components/link-preview.tsx +0 -195
- package/src/components/loader.tsx +0 -367
- package/src/components/markdown.tsx +0 -162
- package/src/components/message-skills.tsx +0 -40
- package/src/components/message.tsx +0 -765
- package/src/components/model-switcher.tsx +0 -132
- package/src/components/prompt-input.tsx +0 -188
- package/src/components/prompt-suggestion.tsx +0 -150
- package/src/components/reasoning.tsx +0 -293
- package/src/components/response-compare-types.ts +0 -152
- package/src/components/response-compare.tsx +0 -455
- package/src/components/response-stream.tsx +0 -109
- package/src/components/screen.tsx +0 -181
- package/src/components/scroll-button.tsx +0 -93
- package/src/components/source.tsx +0 -192
- package/src/components/tasks-card.tsx +0 -801
- package/src/components/text-shimmer.tsx +0 -37
- package/src/components/thinking-bar.tsx +0 -50
- package/src/components/thread.tsx +0 -228
- package/src/components/toast.tsx +0 -503
- package/src/components/tool-classify.ts +0 -26
- package/src/components/tool-types.ts +0 -49
- package/src/components/tool.tsx +0 -190
- package/src/components/use-card-resolution.ts +0 -44
- package/src/components/voice-input.tsx +0 -222
- package/src/components/voice-output.tsx +0 -242
- package/src/components/widget-tab-bar.tsx +0 -73
- package/src/components/workspace-shell.tsx +0 -285
- package/src/diagnostics/hook.ts +0 -352
- package/src/diagnostics/index.ts +0 -82
- package/src/diagnostics/report-request.ts +0 -296
- package/src/elements/agent-card.tsx +0 -67
- package/src/elements/artifact.tsx +0 -194
- package/src/elements/attachments.tsx +0 -140
- package/src/elements/audio-visualizer.tsx +0 -227
- package/src/elements/autoloader.ts +0 -89
- package/src/elements/avatar.tsx +0 -33
- package/src/elements/badge.tsx +0 -32
- package/src/elements/button.tsx +0 -149
- package/src/elements/card.tsx +0 -133
- package/src/elements/cards.tsx +0 -266
- package/src/elements/chain-of-thought.tsx +0 -141
- package/src/elements/chat-scope-picker.tsx +0 -65
- package/src/elements/chat-types.ts +0 -102
- package/src/elements/chat-workspace.tsx +0 -188
- package/src/elements/chat.tsx +0 -304
- package/src/elements/checkbox-group.tsx +0 -164
- package/src/elements/checkbox.tsx +0 -134
- package/src/elements/checkpoint.tsx +0 -47
- package/src/elements/choice.tsx +0 -100
- package/src/elements/coachmark.tsx +0 -90
- package/src/elements/code-block.tsx +0 -60
- package/src/elements/command.tsx +0 -197
- package/src/elements/compare.tsx +0 -111
- package/src/elements/compiled.css +0 -2
- package/src/elements/composer.tsx +0 -162
- package/src/elements/confirm-card.tsx +0 -76
- package/src/elements/context-meter.tsx +0 -107
- package/src/elements/conversation-item.tsx +0 -120
- package/src/elements/conversation-list.tsx +0 -203
- package/src/elements/css.ts +0 -5
- package/src/elements/default-input.tsx +0 -392
- package/src/elements/define-entry.ts +0 -12
- package/src/elements/define.tsx +0 -563
- package/src/elements/diagnostic-events.ts +0 -114
- package/src/elements/dialog.tsx +0 -145
- package/src/elements/disclosure.ts +0 -95
- package/src/elements/dock.tsx +0 -215
- package/src/elements/dropdown.tsx +0 -123
- package/src/elements/editable-label.tsx +0 -140
- package/src/elements/element-data-types.ts +0 -152
- package/src/elements/element-diagnostics.ts +0 -392
- package/src/elements/element-manifest.json +0 -354
- package/src/elements/element-nonscalar.json +0 -187
- package/src/elements/element-types.d.ts +0 -4353
- package/src/elements/embed.tsx +0 -35
- package/src/elements/empty.tsx +0 -29
- package/src/elements/feedback-bar.tsx +0 -66
- package/src/elements/file-tree.tsx +0 -62
- package/src/elements/file-upload.tsx +0 -44
- package/src/elements/form.tsx +0 -94
- package/src/elements/hover-card.tsx +0 -80
- package/src/elements/icon.tsx +0 -41
- package/src/elements/image.tsx +0 -32
- package/src/elements/input.tsx +0 -492
- package/src/elements/kbd.tsx +0 -45
- package/src/elements/link-preview.tsx +0 -34
- package/src/elements/loader.tsx +0 -25
- package/src/elements/markdown.tsx +0 -38
- package/src/elements/menu.tsx +0 -241
- package/src/elements/message-skills.tsx +0 -83
- package/src/elements/message.tsx +0 -361
- package/src/elements/model-switcher.tsx +0 -121
- package/src/elements/nav.tsx +0 -87
- package/src/elements/notice.tsx +0 -53
- package/src/elements/pane-grid.tsx +0 -111
- package/src/elements/pane-group.tsx +0 -119
- package/src/elements/pane.tsx +0 -129
- package/src/elements/popover.tsx +0 -81
- package/src/elements/progress-bar.tsx +0 -39
- package/src/elements/prompt-dock.tsx +0 -82
- package/src/elements/prompt-input.tsx +0 -240
- package/src/elements/prompt-suggestions.tsx +0 -113
- package/src/elements/radio-group.tsx +0 -129
- package/src/elements/reasoning.tsx +0 -71
- package/src/elements/register-impl.ts +0 -148
- package/src/elements/register.ts +0 -76
- package/src/elements/remote.tsx +0 -225
- package/src/elements/resizable.globals.d.ts +0 -36
- package/src/elements/resizable.tsx +0 -704
- package/src/elements/response-stream.tsx +0 -40
- package/src/elements/screen.tsx +0 -90
- package/src/elements/scroll-area.tsx +0 -33
- package/src/elements/scroll-button.tsx +0 -179
- package/src/elements/search.tsx +0 -185
- package/src/elements/segmented.tsx +0 -129
- package/src/elements/select.tsx +0 -165
- package/src/elements/separator.tsx +0 -36
- package/src/elements/setting-item.tsx +0 -50
- package/src/elements/settings-group.tsx +0 -37
- package/src/elements/skeleton.tsx +0 -45
- package/src/elements/slider.tsx +0 -171
- package/src/elements/slot-text.ts +0 -73
- package/src/elements/slots.ts +0 -787
- package/src/elements/source.tsx +0 -126
- package/src/elements/status.tsx +0 -42
- package/src/elements/switch.tsx +0 -118
- package/src/elements/tabs.tsx +0 -95
- package/src/elements/tasks.tsx +0 -103
- package/src/elements/text-shimmer.tsx +0 -28
- package/src/elements/thinking-bar.tsx +0 -43
- package/src/elements/thread.tsx +0 -139
- package/src/elements/toast.tsx +0 -106
- package/src/elements/tool.tsx +0 -78
- package/src/elements/tooltip.tsx +0 -85
- package/src/elements/validate-messages.ts +0 -76
- package/src/elements/voice-input.tsx +0 -100
- package/src/elements/voice-output.tsx +0 -82
- package/src/index.ts +0 -430
- package/src/primitives/audio-bands.ts +0 -174
- package/src/primitives/card-component-types.ts +0 -63
- package/src/primitives/card-contract.ts +0 -80
- package/src/primitives/card-data-types.ts +0 -361
- package/src/primitives/card-host.tsx +0 -37
- package/src/primitives/card-recovery.ts +0 -160
- package/src/primitives/card-registry.tsx +0 -78
- package/src/primitives/card-resolution.ts +0 -36
- package/src/primitives/card-routing.ts +0 -85
- package/src/primitives/card-schemas/artifact.schema.json +0 -92
- package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
- package/src/primitives/card-schemas/card-event.schema.json +0 -12
- package/src/primitives/card-schemas/choice.schema.json +0 -75
- package/src/primitives/card-schemas/confirm.schema.json +0 -65
- package/src/primitives/card-schemas/embed.schema.json +0 -63
- package/src/primitives/card-schemas/form.result.schema.json +0 -7
- package/src/primitives/card-schemas/form.schema.json +0 -53
- package/src/primitives/card-schemas/link.schema.json +0 -54
- package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
- package/src/primitives/card-schemas/tasks.schema.json +0 -83
- package/src/primitives/card-tags.ts +0 -61
- package/src/primitives/card-validate-cards.ts +0 -255
- package/src/primitives/card-validate-schemas.ts +0 -58
- package/src/primitives/card-validate.ts +0 -131
- package/src/primitives/chat-config.tsx +0 -103
- package/src/primitives/composer-model.ts +0 -49
- package/src/primitives/composer-triggers.ts +0 -35
- package/src/primitives/controllable.ts +0 -21
- package/src/primitives/conversation-store.ts +0 -248
- package/src/primitives/create-kai-chat.ts +0 -66
- package/src/primitives/create-tween.ts +0 -266
- package/src/primitives/embed-providers.ts +0 -254
- package/src/primitives/field-mask.ts +0 -256
- package/src/primitives/field-semantics.ts +0 -115
- package/src/primitives/highlighter.ts +0 -157
- package/src/primitives/input-mask.ts +0 -853
- package/src/primitives/link-preview.ts +0 -87
- package/src/primitives/message-feedback.ts +0 -124
- package/src/primitives/pdf-preview.ts +0 -121
- package/src/primitives/toast-store.ts +0 -338
- package/src/primitives/url-scheme-policy.ts +0 -70
- package/src/primitives/use-audio-analysis.ts +0 -340
- package/src/primitives/use-auto-resize.ts +0 -31
- package/src/primitives/use-resize-observer.ts +0 -45
- package/src/primitives/use-sequencer.ts +0 -72
- package/src/primitives/use-speech-recognition.ts +0 -146
- package/src/primitives/use-stick-to-bottom.ts +0 -75
- package/src/primitives/use-text-stream.ts +0 -143
- package/src/primitives/use-voice-recorder.ts +0 -62
- package/src/primitives/visualizer-sequences.ts +0 -350
- package/src/remote/host-embed.ts +0 -345
- package/src/remote/index.ts +0 -2
- package/src/remote/origin.ts +0 -30
- package/src/remote/provider-runtime.ts +0 -262
- package/src/remote/provider.ts +0 -2
- package/src/remote/validate.ts +0 -22
- package/src/remote/version.ts +0 -12
- package/src/remote/wire.ts +0 -48
- package/src/schemas/from-tool-call.ts +0 -151
- package/src/schemas/index.ts +0 -341
- package/src/schemas/provider-subsets.ts +0 -538
- package/src/schemas/registry.ts +0 -355
- package/src/schemas/tool-defs.ts +0 -793
- package/src/solid.ts +0 -173
- package/src/state/index.ts +0 -44
- package/src/state/messages.ts +0 -53
- package/src/state/mock.ts +0 -297
- package/src/state/parts.ts +0 -295
- package/src/state/persistence.ts +0 -180
- package/src/state/stream.ts +0 -246
- package/src/state/suggestions.ts +0 -9
- package/src/state/threads.ts +0 -142
- package/src/test-utils/fake-clock.ts +0 -88
- package/src/types.ts +0 -95
- package/src/ui/action-icons.ts +0 -53
- package/src/ui/agent-card.tsx +0 -218
- package/src/ui/avatar.tsx +0 -23
- package/src/ui/badge.tsx +0 -21
- package/src/ui/button.tsx +0 -49
- package/src/ui/card.tsx +0 -245
- package/src/ui/checkbox-group.tsx +0 -153
- package/src/ui/checkbox.tsx +0 -63
- package/src/ui/collapsible.tsx +0 -163
- package/src/ui/command.tsx +0 -103
- package/src/ui/dialog.tsx +0 -223
- package/src/ui/dock.tsx +0 -630
- package/src/ui/dropdown.tsx +0 -636
- package/src/ui/editable-label.tsx +0 -112
- package/src/ui/hover-card.tsx +0 -345
- package/src/ui/icon.tsx +0 -167
- package/src/ui/input.tsx +0 -391
- package/src/ui/kbd.tsx +0 -118
- package/src/ui/nav.tsx +0 -282
- package/src/ui/notice.tsx +0 -84
- package/src/ui/overlay.tsx +0 -277
- package/src/ui/pane-grid.tsx +0 -117
- package/src/ui/pane-group.tsx +0 -291
- package/src/ui/pane.tsx +0 -193
- package/src/ui/popover.tsx +0 -106
- package/src/ui/progress-bar.tsx +0 -83
- package/src/ui/prompt-dock.tsx +0 -145
- package/src/ui/radio.tsx +0 -150
- package/src/ui/resizable.tsx +0 -693
- package/src/ui/scroll-area.tsx +0 -26
- package/src/ui/segmented.tsx +0 -109
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -10
- package/src/ui/settings-group.tsx +0 -67
- package/src/ui/skeleton.tsx +0 -73
- package/src/ui/slider.tsx +0 -178
- package/src/ui/status.tsx +0 -48
- package/src/ui/switch.tsx +0 -119
- package/src/ui/tabs.tsx +0 -168
- package/src/ui/textarea.tsx +0 -21
- package/src/ui/tooltip.tsx +0 -118
- package/src/utils/cn.ts +0 -30
- package/src/wire/chunk.ts +0 -248
- package/src/wire/consume.ts +0 -599
- package/src/wire/diagnostics.ts +0 -727
- package/src/wire/encode-probe.ts +0 -214
- package/src/wire/encode.ts +0 -947
- package/src/wire/files.ts +0 -342
- package/src/wire/formats/anthropic.ts +0 -274
- package/src/wire/formats/openai.ts +0 -228
- package/src/wire/index.ts +0 -95
- package/src/wire/media-types.ts +0 -344
- package/src/wire/read.ts +0 -396
- package/src/wire/sink-helpers.ts +0 -50
- package/src/wire/sse.ts +0 -153
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { splitProps, Show, createSignal, createEffect, on, onCleanup } from 'solid-js';
|
|
2
|
-
import { cn } from '../utils/cn';
|
|
3
|
-
import { Button } from '../ui/button';
|
|
4
|
-
import { Tooltip } from '../ui/tooltip';
|
|
5
|
-
|
|
6
|
-
/** Imperative handle exposed via `controllerRef` — surfaces the playback controls
|
|
7
|
-
* so the `<kai-voice-output>` facade can forward them as instance methods. Both
|
|
8
|
-
* the native (speechSynthesis) and model (synthesize → Audio) paths run through
|
|
9
|
-
* these, so manual clicks and programmatic calls behave identically. */
|
|
10
|
-
export interface VoiceOutputController {
|
|
11
|
-
/** Speak the current `text` (native by default, model if `synthesize` is set). */
|
|
12
|
-
speak(): void;
|
|
13
|
-
/** Pause playback (resumable). */
|
|
14
|
-
pause(): void;
|
|
15
|
-
/** Resume paused playback. */
|
|
16
|
-
resume(): void;
|
|
17
|
-
/** Stop playback and reset. */
|
|
18
|
-
stop(): void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface VoiceOutputProps {
|
|
22
|
-
/** The utterance to read aloud. */
|
|
23
|
-
text: string;
|
|
24
|
-
/** Speak automatically when `text` is set/changed. */
|
|
25
|
-
autoplay?: boolean;
|
|
26
|
-
/** TTS model seam: given text, return an audio Blob to play. When set, the
|
|
27
|
-
* native speechSynthesis path is bypassed. Mirrors VoiceInput's `onTranscribe`. */
|
|
28
|
-
onSynthesize?: (text: string) => Promise<Blob>;
|
|
29
|
-
/** Fires whenever playback starts or stops. `speaking: true` means audio has
|
|
30
|
-
* actually started (utterance.onstart on the native path; audio.play()
|
|
31
|
-
* resolving on the model path), not that speak() was called. */
|
|
32
|
-
onSpeakingChange?: (speaking: boolean) => void;
|
|
33
|
-
/** Synthesis failed: a native utterance error, a rejecting `onSynthesize`, or
|
|
34
|
-
* audio playback failing to start. `error` is the platform error code or the
|
|
35
|
-
* exception's name. Deliberate cancellation (stop(), a new speak()) is not a
|
|
36
|
-
* failure and does not fire. The facade maps this to kai-voice-error. */
|
|
37
|
-
onError?: (detail: { source: 'synthesis'; error: string; message: string }) => void;
|
|
38
|
-
/** Fires once the model path resolves audio (model path only). */
|
|
39
|
-
onSynthesized?: (blob: Blob) => void;
|
|
40
|
-
disabled?: boolean;
|
|
41
|
-
class?: string;
|
|
42
|
-
/** Receive the imperative controller once mounted. The `<kai-voice-output>`
|
|
43
|
-
* facade forwards these as element methods (speak/pause/resume/stop). */
|
|
44
|
-
controllerRef?: (controller: VoiceOutputController) => void;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** True when the browser exposes the Web Speech synthesis API. */
|
|
48
|
-
function hasSpeechSynthesis(): boolean {
|
|
49
|
-
return typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function VoiceOutput(props: VoiceOutputProps) {
|
|
53
|
-
const [local] = splitProps(props, ['text', 'disabled', 'class']);
|
|
54
|
-
const [isSpeaking, setIsSpeaking] = createSignal(false);
|
|
55
|
-
const [isLoading, setIsLoading] = createSignal(false);
|
|
56
|
-
|
|
57
|
-
// The model path plays through one reused <Audio>; the native path drives
|
|
58
|
-
// speechSynthesis. Only one is live at a time (branch on onSynthesize).
|
|
59
|
-
let audio: HTMLAudioElement | undefined;
|
|
60
|
-
let objectUrl: string | undefined;
|
|
61
|
-
let utterance: SpeechSynthesisUtterance | undefined;
|
|
62
|
-
|
|
63
|
-
// No way to speak at all → render disabled. A model seam OR native synthesis
|
|
64
|
-
// is enough; absent both, the control is inert (see the facade/spec).
|
|
65
|
-
const capable = () => !!props.onSynthesize || hasSpeechSynthesis();
|
|
66
|
-
|
|
67
|
-
const label = () =>
|
|
68
|
-
isLoading() ? 'Synthesizing...' : isSpeaking() ? 'Stop' : 'Read aloud';
|
|
69
|
-
|
|
70
|
-
function revokeUrl() {
|
|
71
|
-
if (objectUrl) {
|
|
72
|
-
URL.revokeObjectURL(objectUrl);
|
|
73
|
-
objectUrl = undefined;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Native path: speechSynthesis.speak(new SpeechSynthesisUtterance(text)).
|
|
78
|
-
// isSpeaking waits for utterance.onstart, so onSpeakingChange(true) means the
|
|
79
|
-
// audio actually began. It used to flip optimistically before speak(), which
|
|
80
|
-
// made "speaking" mean "speak() was called" and raced consumers watching for
|
|
81
|
-
// playback to start (W4 symptom 3).
|
|
82
|
-
function speakNative() {
|
|
83
|
-
if (!hasSpeechSynthesis() || !local.text) return;
|
|
84
|
-
window.speechSynthesis.cancel();
|
|
85
|
-
utterance = new SpeechSynthesisUtterance(local.text);
|
|
86
|
-
utterance.onstart = () => setIsSpeaking(true);
|
|
87
|
-
utterance.onend = () => setIsSpeaking(false);
|
|
88
|
-
utterance.onerror = (event) => {
|
|
89
|
-
setIsSpeaking(false);
|
|
90
|
-
const code = event?.error ?? 'unknown';
|
|
91
|
-
// `canceled`/`interrupted` are what the platform reports when the app
|
|
92
|
-
// itself cancels (stop(), or a new speak() pre-empting): deliberate, not
|
|
93
|
-
// a failure. Everything else surfaces (W4 traced a `not-allowed` here
|
|
94
|
-
// that vanished without a word).
|
|
95
|
-
if (code === 'canceled' || code === 'interrupted') return;
|
|
96
|
-
props.onError?.({
|
|
97
|
-
source: 'synthesis',
|
|
98
|
-
error: code,
|
|
99
|
-
message: `Speech synthesis error: ${code}`,
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
window.speechSynthesis.speak(utterance);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Model path: await onSynthesize(text) → play the Blob via an <Audio>.
|
|
106
|
-
async function speakModel() {
|
|
107
|
-
if (!props.onSynthesize || !local.text) return;
|
|
108
|
-
setIsLoading(true);
|
|
109
|
-
try {
|
|
110
|
-
const blob = await props.onSynthesize(local.text);
|
|
111
|
-
props.onSynthesized?.(blob);
|
|
112
|
-
revokeUrl();
|
|
113
|
-
objectUrl = URL.createObjectURL(blob);
|
|
114
|
-
audio ??= new Audio();
|
|
115
|
-
audio.src = objectUrl;
|
|
116
|
-
audio.onended = () => setIsSpeaking(false);
|
|
117
|
-
audio.onerror = () => {
|
|
118
|
-
setIsSpeaking(false);
|
|
119
|
-
props.onError?.({
|
|
120
|
-
source: 'synthesis',
|
|
121
|
-
error: 'playback-failed',
|
|
122
|
-
message: 'The synthesized audio failed to play',
|
|
123
|
-
});
|
|
124
|
-
};
|
|
125
|
-
await audio.play();
|
|
126
|
-
// play() resolving is this path's "audio actually started" (the model
|
|
127
|
-
// path's counterpart of utterance.onstart), so isSpeaking flips only now.
|
|
128
|
-
setIsSpeaking(true);
|
|
129
|
-
} catch (err) {
|
|
130
|
-
// onSynthesize rejected, or play() did (e.g. NotAllowedError under an
|
|
131
|
-
// autoplay policy). Either way the reply is silent: say so.
|
|
132
|
-
setIsSpeaking(false);
|
|
133
|
-
props.onError?.({
|
|
134
|
-
source: 'synthesis',
|
|
135
|
-
error: err instanceof Error ? err.name : 'unknown',
|
|
136
|
-
message: err instanceof Error ? err.message : String(err),
|
|
137
|
-
});
|
|
138
|
-
} finally {
|
|
139
|
-
setIsLoading(false);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function speak() {
|
|
144
|
-
if (props.onSynthesize) void speakModel();
|
|
145
|
-
else speakNative();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function stop() {
|
|
149
|
-
if (props.onSynthesize) {
|
|
150
|
-
if (audio) {
|
|
151
|
-
audio.pause();
|
|
152
|
-
audio.currentTime = 0;
|
|
153
|
-
}
|
|
154
|
-
} else if (hasSpeechSynthesis()) {
|
|
155
|
-
window.speechSynthesis.cancel();
|
|
156
|
-
}
|
|
157
|
-
setIsSpeaking(false);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function pause() {
|
|
161
|
-
if (props.onSynthesize) audio?.pause();
|
|
162
|
-
else if (hasSpeechSynthesis()) window.speechSynthesis.pause();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function resume() {
|
|
166
|
-
if (props.onSynthesize) void audio?.play();
|
|
167
|
-
else if (hasSpeechSynthesis()) window.speechSynthesis.resume();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function handleClick() {
|
|
171
|
-
if (isSpeaking()) stop();
|
|
172
|
-
else speak();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Emit speaking transitions to the host. `defer: true` skips the spurious
|
|
176
|
-
// initial `false` — only real start/stop transitions fire.
|
|
177
|
-
createEffect(on(isSpeaking, (speaking) => {
|
|
178
|
-
props.onSpeakingChange?.(speaking);
|
|
179
|
-
}, { defer: true }));
|
|
180
|
-
|
|
181
|
-
// Autoplay: speak when text first arrives / changes (defer skips the mount
|
|
182
|
-
// value so an empty seed doesn't speak).
|
|
183
|
-
createEffect(on(() => local.text, (text) => {
|
|
184
|
-
if (props.autoplay && text) speak();
|
|
185
|
-
}, { defer: true }));
|
|
186
|
-
|
|
187
|
-
props.controllerRef?.({ speak, pause, resume, stop });
|
|
188
|
-
|
|
189
|
-
onCleanup(() => {
|
|
190
|
-
stop();
|
|
191
|
-
revokeUrl();
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// Speaker icon (idle)
|
|
195
|
-
const SpeakerIcon = () => (
|
|
196
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
197
|
-
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
|
|
198
|
-
<path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07" />
|
|
199
|
-
</svg>
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
// Square stop icon (speaking)
|
|
203
|
-
const StopIcon = () => (
|
|
204
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
|
|
205
|
-
<rect x="4" y="4" width="16" height="16" rx="2" />
|
|
206
|
-
</svg>
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Spinner (model synthesis in flight)
|
|
210
|
-
const Spinner = () => (
|
|
211
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="animate-spin">
|
|
212
|
-
<path d="M21 12a9 9 0 11-6.219-8.56" />
|
|
213
|
-
</svg>
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
return (
|
|
217
|
-
<div class={cn('relative inline-flex items-center justify-center', local.class)}>
|
|
218
|
-
<Tooltip content={label()}>
|
|
219
|
-
<Button
|
|
220
|
-
part="button"
|
|
221
|
-
variant="ghost"
|
|
222
|
-
size="icon-sm"
|
|
223
|
-
aria-label={label()}
|
|
224
|
-
aria-pressed={isSpeaking()}
|
|
225
|
-
onClick={handleClick}
|
|
226
|
-
disabled={local.disabled || !capable() || isLoading()}
|
|
227
|
-
class={cn('relative z-10 rounded-full transition-all duration-300')}
|
|
228
|
-
>
|
|
229
|
-
<Show when={isLoading()}>
|
|
230
|
-
<Spinner />
|
|
231
|
-
</Show>
|
|
232
|
-
<Show when={!isLoading() && isSpeaking()}>
|
|
233
|
-
<StopIcon />
|
|
234
|
-
</Show>
|
|
235
|
-
<Show when={!isLoading() && !isSpeaking()}>
|
|
236
|
-
<SpeakerIcon />
|
|
237
|
-
</Show>
|
|
238
|
-
</Button>
|
|
239
|
-
</Tooltip>
|
|
240
|
-
</div>
|
|
241
|
-
);
|
|
242
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { Show } from 'solid-js';
|
|
2
|
-
import { cn } from '../utils/cn';
|
|
3
|
-
import { renderIcon } from '../ui/icon';
|
|
4
|
-
|
|
5
|
-
export interface WidgetTabBarProps {
|
|
6
|
-
active: 'home' | 'messages';
|
|
7
|
-
onChange: (tab: 'home' | 'messages') => void;
|
|
8
|
-
/** Whether the Messages tab has unread activity. Reaches BOTH the visible
|
|
9
|
-
* dot and the tab's accessible name (`aria-label`) — a dot alone is
|
|
10
|
-
* invisible to assistive tech, the #336 lesson this test pins. */
|
|
11
|
-
unread?: boolean;
|
|
12
|
-
homeLabel?: string;
|
|
13
|
-
messagesLabel?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The widget's Home/Messages tab bar (Intercom-pattern chrome, H-2/H-6). Real
|
|
18
|
-
* `tablist`/`tab` semantics — this is a persistent view switch within the
|
|
19
|
-
* widget, not page navigation, so it is not `<Nav>`'s `role="page"` dialect.
|
|
20
|
-
*/
|
|
21
|
-
export function WidgetTabBar(props: WidgetTabBarProps) {
|
|
22
|
-
const home = () => props.homeLabel ?? 'Home';
|
|
23
|
-
const messages = () => props.messagesLabel ?? 'Messages';
|
|
24
|
-
const messagesLabel = () => (props.unread ? `${messages()} (unread)` : messages());
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<nav
|
|
28
|
-
role="tablist"
|
|
29
|
-
aria-label="Widget navigation"
|
|
30
|
-
class="flex h-14 shrink-0 items-stretch border-t border-border bg-background"
|
|
31
|
-
>
|
|
32
|
-
<button
|
|
33
|
-
type="button"
|
|
34
|
-
role="tab"
|
|
35
|
-
data-kai-tab-home
|
|
36
|
-
aria-selected={props.active === 'home'}
|
|
37
|
-
aria-label={home()}
|
|
38
|
-
onClick={() => props.onChange('home')}
|
|
39
|
-
class={cn(
|
|
40
|
-
'flex flex-1 flex-col items-center justify-center gap-0.5 text-xs transition-colors',
|
|
41
|
-
props.active === 'home' ? 'text-primary' : 'text-muted-foreground hover:text-foreground',
|
|
42
|
-
)}
|
|
43
|
-
>
|
|
44
|
-
{renderIcon('home', { class: 'size-5' })}
|
|
45
|
-
<span>{home()}</span>
|
|
46
|
-
</button>
|
|
47
|
-
<button
|
|
48
|
-
type="button"
|
|
49
|
-
role="tab"
|
|
50
|
-
data-kai-tab-messages
|
|
51
|
-
aria-selected={props.active === 'messages'}
|
|
52
|
-
aria-label={messagesLabel()}
|
|
53
|
-
onClick={() => props.onChange('messages')}
|
|
54
|
-
class={cn(
|
|
55
|
-
'flex flex-1 flex-col items-center justify-center gap-0.5 text-xs transition-colors',
|
|
56
|
-
props.active === 'messages' ? 'text-primary' : 'text-muted-foreground hover:text-foreground',
|
|
57
|
-
)}
|
|
58
|
-
>
|
|
59
|
-
<span class="relative">
|
|
60
|
-
{renderIcon('message-square', { class: 'size-5' })}
|
|
61
|
-
<Show when={props.unread}>
|
|
62
|
-
<span
|
|
63
|
-
data-kai-tab-unread
|
|
64
|
-
aria-hidden="true"
|
|
65
|
-
class="absolute -right-0.5 -top-0.5 size-1.5 rounded-full bg-unread"
|
|
66
|
-
/>
|
|
67
|
-
</Show>
|
|
68
|
-
</span>
|
|
69
|
-
<span>{messages()}</span>
|
|
70
|
-
</button>
|
|
71
|
-
</nav>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import { Show, createSignal, createMemo, onMount, onCleanup, type JSX } from 'solid-js';
|
|
2
|
-
import { createControllableSignal } from '../primitives/controllable';
|
|
3
|
-
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '../ui/resizable';
|
|
4
|
-
import { cn } from '../utils/cn';
|
|
5
|
-
|
|
6
|
-
/** The two aside columns of the shell, named logically (`start` follows the
|
|
7
|
-
* writing direction; on an RTL page it is the right column). */
|
|
8
|
-
export type WorkspaceAsideSide = 'start' | 'end';
|
|
9
|
-
|
|
10
|
-
/** Detail of an aside collapse/expand, however it happened (a method, the
|
|
11
|
-
* breakpoint, the drawer's Escape). */
|
|
12
|
-
export interface WorkspaceAsideToggleDetail {
|
|
13
|
-
side: WorkspaceAsideSide;
|
|
14
|
-
collapsed: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Detail of an aside resize (fires per drag step, keyboard nudge, or a handle double-click reset), width in px. */
|
|
18
|
-
export interface WorkspaceAsideResizeDetail {
|
|
19
|
-
side: WorkspaceAsideSide;
|
|
20
|
-
width: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Imperative surface exposed through `controllerRef` (the facade forwards it
|
|
24
|
-
* as element methods). */
|
|
25
|
-
export interface WorkspaceShellController {
|
|
26
|
-
/** Collapse/expand one aside (reports through onAsideToggle). */
|
|
27
|
-
toggleAside(side: WorkspaceAsideSide): void;
|
|
28
|
-
/** Force one aside collapsed (reports through onAsideToggle). */
|
|
29
|
-
collapseAside(side: WorkspaceAsideSide): void;
|
|
30
|
-
/** Force one aside expanded (reports through onAsideToggle). */
|
|
31
|
-
expandAside(side: WorkspaceAsideSide): void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface WorkspaceShellProps {
|
|
35
|
-
/** Header band content. The region renders only when this is provided. */
|
|
36
|
-
header?: JSX.Element;
|
|
37
|
-
/** Start aside content (the inline-start column: a rail, a nav, a file tree).
|
|
38
|
-
* The region renders only when this is provided. */
|
|
39
|
-
start?: JSX.Element;
|
|
40
|
-
/** End aside content (the inline-end column: inspector, notes, preview).
|
|
41
|
-
* The region renders only when this is provided. */
|
|
42
|
-
end?: JSX.Element;
|
|
43
|
-
/** Footer band content. The region renders only when this is provided. */
|
|
44
|
-
footer?: JSX.Element;
|
|
45
|
-
/** Main region content. Always rendered. */
|
|
46
|
-
children?: JSX.Element;
|
|
47
|
-
|
|
48
|
-
/** Controlled collapsed state of the start aside. Omit for uncontrolled. */
|
|
49
|
-
startCollapsed?: boolean;
|
|
50
|
-
/** Initial collapsed state of the start aside when uncontrolled (default false). */
|
|
51
|
-
defaultStartCollapsed?: boolean;
|
|
52
|
-
/** Controlled collapsed state of the end aside. Omit for uncontrolled. */
|
|
53
|
-
endCollapsed?: boolean;
|
|
54
|
-
/** Initial collapsed state of the end aside when uncontrolled (default false). */
|
|
55
|
-
defaultEndCollapsed?: boolean;
|
|
56
|
-
|
|
57
|
-
/** Start aside default width in px (default 280). */
|
|
58
|
-
startWidth?: number;
|
|
59
|
-
/** Start aside minimum width in px during resize (default 200). */
|
|
60
|
-
startMinWidth?: number;
|
|
61
|
-
/** Start aside maximum width in px during resize (default 480). */
|
|
62
|
-
startMaxWidth?: number;
|
|
63
|
-
/** End aside default width in px (default 320). */
|
|
64
|
-
endWidth?: number;
|
|
65
|
-
/** End aside minimum width in px during resize (default 200). */
|
|
66
|
-
endMinWidth?: number;
|
|
67
|
-
/** End aside maximum width in px during resize (default 480). */
|
|
68
|
-
endMaxWidth?: number;
|
|
69
|
-
|
|
70
|
-
/** Auto-collapse both asides when the shell's own width drops below this many
|
|
71
|
-
* px, and re-expand when it grows back above. Applies to uncontrolled asides
|
|
72
|
-
* only (it never fights an app-driven collapsed prop); omit to disable. */
|
|
73
|
-
collapseBelow?: number;
|
|
74
|
-
/** Below this shell width in px, an expanded aside renders as an overlay
|
|
75
|
-
* drawer over the main region instead of a column beside it. Escape inside
|
|
76
|
-
* the drawer closes it and returns focus to the element focused before it
|
|
77
|
-
* opened. Omit to disable. */
|
|
78
|
-
drawerBelow?: number;
|
|
79
|
-
/** Density hint. Reflected as a `data-compact` hook on the root (and as the
|
|
80
|
-
* `compact` attribute on the element) for your CSS and slotted content; the
|
|
81
|
-
* shell itself keeps no other opinion about density. */
|
|
82
|
-
compact?: boolean;
|
|
83
|
-
|
|
84
|
-
/** An aside collapsed or expanded (any path: method, breakpoint, drawer Escape). */
|
|
85
|
-
onAsideToggle?: (detail: WorkspaceAsideToggleDetail) => void;
|
|
86
|
-
/** The aside was resized (fires per drag step, keyboard nudge, or a handle double-click reset), width in px. */
|
|
87
|
-
onAsideResize?: (detail: WorkspaceAsideResizeDetail) => void;
|
|
88
|
-
|
|
89
|
-
/** Receives the imperative controller once on mount. */
|
|
90
|
-
controllerRef?: (controller: WorkspaceShellController) => void;
|
|
91
|
-
class?: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The chat-agnostic workspace layout shell: five regions (header · start aside ·
|
|
96
|
-
* main · end aside · footer) with resize handles between the columns, per-aside
|
|
97
|
-
* controlled/uncontrolled collapse, collapse-below-breakpoint, and a mobile
|
|
98
|
-
* drawer mode for the asides. It knows nothing about chat: a file tree in
|
|
99
|
-
* `start` is as valid as a conversation rail.
|
|
100
|
-
*/
|
|
101
|
-
export function WorkspaceShell(props: WorkspaceShellProps) {
|
|
102
|
-
let rootEl!: HTMLDivElement;
|
|
103
|
-
|
|
104
|
-
// --- host width (drives collapseBelow + drawerBelow) ---
|
|
105
|
-
const [hostWidth, setHostWidth] = createSignal<number | undefined>(undefined);
|
|
106
|
-
|
|
107
|
-
// --- per-aside collapse: controlled wins, otherwise internal state ---
|
|
108
|
-
const [startCollapsed, setStartCollapsed] = createControllableSignal(
|
|
109
|
-
() => props.startCollapsed,
|
|
110
|
-
props.defaultStartCollapsed ?? false,
|
|
111
|
-
);
|
|
112
|
-
const [endCollapsed, setEndCollapsed] = createControllableSignal(
|
|
113
|
-
() => props.endCollapsed,
|
|
114
|
-
props.defaultEndCollapsed ?? false,
|
|
115
|
-
);
|
|
116
|
-
const collapsed = (side: WorkspaceAsideSide) => (side === 'start' ? startCollapsed() : endCollapsed());
|
|
117
|
-
const isControlled = (side: WorkspaceAsideSide) =>
|
|
118
|
-
(side === 'start' ? props.startCollapsed : props.endCollapsed) !== undefined;
|
|
119
|
-
|
|
120
|
-
const setCollapsedTo = (side: WorkspaceAsideSide, next: boolean) => {
|
|
121
|
-
if (side === 'start') setStartCollapsed(next); else setEndCollapsed(next);
|
|
122
|
-
if (next) restoreDrawerFocus(side);
|
|
123
|
-
props.onAsideToggle?.({ side, collapsed: next });
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// --- drawer mode + focus return ---
|
|
127
|
-
const drawerMode = createMemo(() => {
|
|
128
|
-
const below = props.drawerBelow;
|
|
129
|
-
const width = hostWidth();
|
|
130
|
-
return below != null && width != null && width < below;
|
|
131
|
-
});
|
|
132
|
-
// The element focused when a drawer opened, restored on close. Per side, so a
|
|
133
|
-
// start drawer closing never steals focus a later end drawer captured.
|
|
134
|
-
const drawerOpeners: Partial<Record<WorkspaceAsideSide, HTMLElement>> = {};
|
|
135
|
-
const captureDrawerFocus = (side: WorkspaceAsideSide) => {
|
|
136
|
-
if (!drawerMode()) return;
|
|
137
|
-
const active = document.activeElement;
|
|
138
|
-
if (active instanceof HTMLElement) drawerOpeners[side] = active;
|
|
139
|
-
};
|
|
140
|
-
const restoreDrawerFocus = (side: WorkspaceAsideSide) => {
|
|
141
|
-
const opener = drawerOpeners[side];
|
|
142
|
-
delete drawerOpeners[side];
|
|
143
|
-
if (drawerMode() && opener && opener.isConnected) opener.focus();
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const expand = (side: WorkspaceAsideSide) => {
|
|
147
|
-
captureDrawerFocus(side);
|
|
148
|
-
setCollapsedTo(side, false);
|
|
149
|
-
};
|
|
150
|
-
const controller: WorkspaceShellController = {
|
|
151
|
-
toggleAside: (side) => (collapsed(side) ? expand(side) : setCollapsedTo(side, true)),
|
|
152
|
-
collapseAside: (side) => setCollapsedTo(side, true),
|
|
153
|
-
expandAside: (side) => expand(side),
|
|
154
|
-
};
|
|
155
|
-
props.controllerRef?.(controller);
|
|
156
|
-
|
|
157
|
-
// --- collapse-below-breakpoint (uncontrolled asides only) ---
|
|
158
|
-
// `autoCollapsed` tracks whether WE collapsed a side, so crossing back above
|
|
159
|
-
// the breakpoint never expands an aside the user collapsed themselves.
|
|
160
|
-
const autoCollapsed: Record<WorkspaceAsideSide, boolean> = { start: false, end: false };
|
|
161
|
-
const applyBreakpoint = (width: number) => {
|
|
162
|
-
const below = props.collapseBelow;
|
|
163
|
-
if (below == null) return;
|
|
164
|
-
const isBelow = width < below;
|
|
165
|
-
for (const side of ['start', 'end'] as const) {
|
|
166
|
-
// A side with no content has nothing to collapse; reporting a toggle for
|
|
167
|
-
// a region that does not exist would be noise, not loudness.
|
|
168
|
-
if (!asideContent(side)) continue;
|
|
169
|
-
if (isControlled(side)) continue;
|
|
170
|
-
if (isBelow && !collapsed(side)) {
|
|
171
|
-
autoCollapsed[side] = true;
|
|
172
|
-
setCollapsedTo(side, true);
|
|
173
|
-
} else if (!isBelow && collapsed(side) && autoCollapsed[side]) {
|
|
174
|
-
autoCollapsed[side] = false;
|
|
175
|
-
setCollapsedTo(side, false);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
onMount(() => {
|
|
181
|
-
if (typeof ResizeObserver === 'undefined') return;
|
|
182
|
-
const ro = new ResizeObserver((entries) => {
|
|
183
|
-
const width = entries[0]?.contentRect.width ?? rootEl.clientWidth;
|
|
184
|
-
setHostWidth(width);
|
|
185
|
-
applyBreakpoint(width);
|
|
186
|
-
});
|
|
187
|
-
ro.observe(rootEl);
|
|
188
|
-
onCleanup(() => ro.disconnect());
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// --- widths ---
|
|
192
|
-
const widths = (side: WorkspaceAsideSide) =>
|
|
193
|
-
side === 'start'
|
|
194
|
-
? {
|
|
195
|
-
size: props.startWidth ?? 280,
|
|
196
|
-
min: props.startMinWidth ?? 200,
|
|
197
|
-
max: props.startMaxWidth ?? 480,
|
|
198
|
-
}
|
|
199
|
-
: {
|
|
200
|
-
size: props.endWidth ?? 320,
|
|
201
|
-
min: props.endMinWidth ?? 200,
|
|
202
|
-
max: props.endMaxWidth ?? 480,
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// --- drawer Escape: scoped to the drawer (never a document listener, never
|
|
206
|
-
// swallowed — the kai-dock rule at page scale) ---
|
|
207
|
-
const onDrawerKeyDown = (side: WorkspaceAsideSide) => (event: KeyboardEvent) => {
|
|
208
|
-
if (event.key !== 'Escape') return;
|
|
209
|
-
setCollapsedTo(side, true);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const asideRefs: Partial<Record<WorkspaceAsideSide, HTMLElement>> = {};
|
|
213
|
-
const emitResize = (side: WorkspaceAsideSide) => {
|
|
214
|
-
const el = asideRefs[side];
|
|
215
|
-
if (!el) return;
|
|
216
|
-
props.onAsideResize?.({ side, width: el.getBoundingClientRect().width });
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const asideContent = (side: WorkspaceAsideSide) => (side === 'start' ? props.start : props.end);
|
|
220
|
-
|
|
221
|
-
/** An aside as a resizable column (desktop mode). */
|
|
222
|
-
const asideColumn = (side: WorkspaceAsideSide) => {
|
|
223
|
-
const w = widths(side);
|
|
224
|
-
return (
|
|
225
|
-
<ResizablePanel
|
|
226
|
-
defaultSize={`${w.size}px`}
|
|
227
|
-
minSize={`${w.min}px`}
|
|
228
|
-
maxSize={`${w.max}px`}
|
|
229
|
-
part={side === 'start' ? 'aside start' : 'aside end'}
|
|
230
|
-
ref={(el: HTMLElement) => (asideRefs[side] = el)}
|
|
231
|
-
class="bg-surface"
|
|
232
|
-
>
|
|
233
|
-
{asideContent(side)}
|
|
234
|
-
</ResizablePanel>
|
|
235
|
-
);
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
/** An aside as an overlay drawer (mobile mode). */
|
|
239
|
-
const asideDrawer = (side: WorkspaceAsideSide) => (
|
|
240
|
-
<div
|
|
241
|
-
part={side === 'start' ? 'aside start' : 'aside end'}
|
|
242
|
-
data-drawer=""
|
|
243
|
-
class={cn(
|
|
244
|
-
'absolute inset-y-0 z-20 max-w-[85%] overflow-auto border-border bg-surface shadow-lg',
|
|
245
|
-
side === 'start' ? 'start-0 border-e' : 'end-0 border-s',
|
|
246
|
-
)}
|
|
247
|
-
style={{ width: `${widths(side).size}px` }}
|
|
248
|
-
onKeyDown={onDrawerKeyDown(side)}
|
|
249
|
-
>
|
|
250
|
-
{asideContent(side)}
|
|
251
|
-
</div>
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
const showAside = (side: WorkspaceAsideSide) => !!asideContent(side) && !collapsed(side);
|
|
255
|
-
|
|
256
|
-
return (
|
|
257
|
-
<div
|
|
258
|
-
ref={rootEl}
|
|
259
|
-
class={cn('flex h-full w-full flex-col overflow-hidden bg-background', props.class)}
|
|
260
|
-
data-compact={props.compact ? '' : undefined}
|
|
261
|
-
>
|
|
262
|
-
<Show when={props.header}>
|
|
263
|
-
<div part="header" class="shrink-0 border-b border-border">{props.header}</div>
|
|
264
|
-
</Show>
|
|
265
|
-
<div class="relative min-h-0 flex-1">
|
|
266
|
-
<ResizablePanelGroup orientation="horizontal">
|
|
267
|
-
<Show when={showAside('start') && !drawerMode()}>
|
|
268
|
-
{asideColumn('start')}
|
|
269
|
-
<ResizableHandle onPanelResize={() => emitResize('start')} />
|
|
270
|
-
</Show>
|
|
271
|
-
<ResizablePanel part="main">{props.children}</ResizablePanel>
|
|
272
|
-
<Show when={showAside('end') && !drawerMode()}>
|
|
273
|
-
<ResizableHandle onPanelResize={() => emitResize('end')} />
|
|
274
|
-
{asideColumn('end')}
|
|
275
|
-
</Show>
|
|
276
|
-
</ResizablePanelGroup>
|
|
277
|
-
<Show when={showAside('start') && drawerMode()}>{asideDrawer('start')}</Show>
|
|
278
|
-
<Show when={showAside('end') && drawerMode()}>{asideDrawer('end')}</Show>
|
|
279
|
-
</div>
|
|
280
|
-
<Show when={props.footer}>
|
|
281
|
-
<div part="footer" class="shrink-0 border-t border-border">{props.footer}</div>
|
|
282
|
-
</Show>
|
|
283
|
-
</div>
|
|
284
|
-
);
|
|
285
|
-
}
|