@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,112 +0,0 @@
|
|
|
1
|
-
import { type JSX, Show, createSignal, createEffect, untrack } from 'solid-js';
|
|
2
|
-
import { cn } from '../utils/cn';
|
|
3
|
-
import { Input } from './input';
|
|
4
|
-
|
|
5
|
-
export interface EditableLabelProps {
|
|
6
|
-
/** The label text. */
|
|
7
|
-
value: string;
|
|
8
|
-
/** Controlled edit state. When it flips true the field opens; double-click and
|
|
9
|
-
* the host's `edit()` open it too. */
|
|
10
|
-
editing?: boolean;
|
|
11
|
-
/** Placeholder shown while editing (and as muted text when the value is empty). */
|
|
12
|
-
placeholder?: string;
|
|
13
|
-
/** Disable entering edit mode. */
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
/** Fires on commit (Enter / blur) with the new value — ONLY when it changed. */
|
|
16
|
-
onRename?: (value: string) => void;
|
|
17
|
-
/** Fires on Esc (cancel); the text is restored. */
|
|
18
|
-
onCancel?: () => void;
|
|
19
|
-
class?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* `EditableLabel`: inline rename. Shows `value` as text; double-click (or the
|
|
24
|
-
* `editing` prop, or a host `edit()`) swaps in an autofocused `Input` with the
|
|
25
|
-
* text pre-selected. Enter or blur commits (fires `onRename` only when the value
|
|
26
|
-
* changed); Esc cancels (fires `onCancel`, restores the text). Both exit editing.
|
|
27
|
-
*
|
|
28
|
-
* Parts: `text` (the read view), `input` (the field while editing).
|
|
29
|
-
*/
|
|
30
|
-
export function EditableLabel(props: EditableLabelProps): JSX.Element {
|
|
31
|
-
// `editing` is seeded from the controlled prop and follows it; double-click /
|
|
32
|
-
// commit / cancel toggle it locally without touching the prop (no feedback loop).
|
|
33
|
-
const [editing, setEditing] = createSignal(!!props.editing);
|
|
34
|
-
createEffect(() => setEditing(!!props.editing));
|
|
35
|
-
|
|
36
|
-
// The displayed text. Seeded from `value`, kept in sync with it, and updated
|
|
37
|
-
// optimistically on a successful rename so the read view shows the new label.
|
|
38
|
-
const [text, setText] = createSignal(props.value);
|
|
39
|
-
createEffect(() => setText(props.value));
|
|
40
|
-
|
|
41
|
-
let root: HTMLElement | undefined;
|
|
42
|
-
// Set before an Enter/Esc unmounts the field so its teardown blur does not
|
|
43
|
-
// double-commit (mirrors the AMUX inline-rename guard).
|
|
44
|
-
let suppressBlur = false;
|
|
45
|
-
|
|
46
|
-
const focusSelect = () => {
|
|
47
|
-
const input = root?.querySelector('input');
|
|
48
|
-
if (input) { input.focus(); input.select(); }
|
|
49
|
-
};
|
|
50
|
-
createEffect(() => { if (editing()) queueMicrotask(focusSelect); });
|
|
51
|
-
|
|
52
|
-
const enterEdit = () => { if (!props.disabled) setEditing(true); };
|
|
53
|
-
|
|
54
|
-
const commit = (next: string) => {
|
|
55
|
-
if (!untrack(editing)) return; // idempotent: a teardown blur after Enter is a no-op
|
|
56
|
-
setEditing(false);
|
|
57
|
-
if (next !== untrack(text)) { setText(next); props.onRename?.(next); }
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const cancel = () => {
|
|
61
|
-
if (!untrack(editing)) return;
|
|
62
|
-
setEditing(false);
|
|
63
|
-
props.onCancel?.();
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const onFieldKeyDown = (e: KeyboardEvent) => {
|
|
67
|
-
const el = e.currentTarget as HTMLInputElement;
|
|
68
|
-
if (e.key === 'Enter') { e.preventDefault(); suppressBlur = true; commit(el.value); }
|
|
69
|
-
else if (e.key === 'Escape') { e.preventDefault(); suppressBlur = true; cancel(); }
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const onFieldBlur = (v: string) => {
|
|
73
|
-
if (suppressBlur) { suppressBlur = false; return; }
|
|
74
|
-
commit(v);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<span ref={root} class={cn('inline-flex max-w-full items-center', props.class)}>
|
|
79
|
-
<Show
|
|
80
|
-
when={editing()}
|
|
81
|
-
fallback={
|
|
82
|
-
<span
|
|
83
|
-
part="text"
|
|
84
|
-
tabindex={props.disabled ? undefined : 0}
|
|
85
|
-
class={cn(
|
|
86
|
-
'inline-block max-w-full truncate rounded px-1 py-0.5 text-sm text-foreground',
|
|
87
|
-
props.disabled ? 'cursor-default opacity-60' : 'cursor-text hover:bg-muted',
|
|
88
|
-
!text() && 'text-muted-foreground',
|
|
89
|
-
)}
|
|
90
|
-
onDblClick={enterEdit}
|
|
91
|
-
onKeyDown={(e) => {
|
|
92
|
-
if (!props.disabled && (e.key === 'Enter' || e.key === 'F2')) { e.preventDefault(); enterEdit(); }
|
|
93
|
-
}}
|
|
94
|
-
>
|
|
95
|
-
{text() || props.placeholder || ''}
|
|
96
|
-
</span>
|
|
97
|
-
}
|
|
98
|
-
>
|
|
99
|
-
<Input
|
|
100
|
-
value={text()}
|
|
101
|
-
placeholder={props.placeholder}
|
|
102
|
-
disabled={props.disabled}
|
|
103
|
-
size="sm"
|
|
104
|
-
class="h-7 py-0"
|
|
105
|
-
aria-label={props.placeholder ?? 'Edit label'}
|
|
106
|
-
onKeyDown={onFieldKeyDown}
|
|
107
|
-
onValueChange={onFieldBlur}
|
|
108
|
-
/>
|
|
109
|
-
</Show>
|
|
110
|
-
</span>
|
|
111
|
-
);
|
|
112
|
-
}
|
package/src/ui/hover-card.tsx
DELETED
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext, useContext, createSignal, createUniqueId, Show, splitProps, onCleanup,
|
|
3
|
-
type JSX, type Accessor,
|
|
4
|
-
} from 'solid-js';
|
|
5
|
-
import { Portal } from 'solid-js/web';
|
|
6
|
-
import { type Placement } from '@floating-ui/dom';
|
|
7
|
-
import { cn } from '../utils/cn';
|
|
8
|
-
import { useChatConfig } from '../primitives/chat-config';
|
|
9
|
-
import { createPresence, usePosition, useDismiss, As } from './overlay';
|
|
10
|
-
|
|
11
|
-
interface HoverCardCtx {
|
|
12
|
-
open: Accessor<boolean>;
|
|
13
|
-
enter: () => void;
|
|
14
|
-
leave: () => void;
|
|
15
|
-
close: () => void;
|
|
16
|
-
setTrigger: (el: HTMLElement) => void;
|
|
17
|
-
setContent: (el: HTMLElement) => void;
|
|
18
|
-
trigger: Accessor<HTMLElement | undefined>;
|
|
19
|
-
content: Accessor<HTMLElement | undefined>;
|
|
20
|
-
/** Ties a focused trigger to the card it reveals. Without it a keyboard tab
|
|
21
|
-
* stop announces nothing, which is a focus stop that wastes the user's time. */
|
|
22
|
-
contentId: string;
|
|
23
|
-
/** Whether this card refuses to open. Read by the TRIGGER, not just by
|
|
24
|
-
* `enter()`: a card that cannot open must not be in the tab order either. */
|
|
25
|
-
disabled: Accessor<boolean>;
|
|
26
|
-
}
|
|
27
|
-
const Ctx = createContext<HoverCardCtx>();
|
|
28
|
-
const useHoverCard = () => {
|
|
29
|
-
const c = useContext(Ctx);
|
|
30
|
-
if (!c) throw new Error('HoverCard parts must be used within <HoverCardRoot>');
|
|
31
|
-
return c;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** Imperative open controller, handed to a parent (e.g. the kai-hover-card facade)
|
|
35
|
-
* via `controllerRef` so it can drive/observe open state. */
|
|
36
|
-
export interface HoverCardController { open: Accessor<boolean>; setOpen: (v: boolean) => void; }
|
|
37
|
-
|
|
38
|
-
export interface HoverCardRootProps {
|
|
39
|
-
children: JSX.Element;
|
|
40
|
-
openDelay?: number;
|
|
41
|
-
closeDelay?: number;
|
|
42
|
-
/** Initial open state (uncontrolled seed). */
|
|
43
|
-
defaultOpen?: boolean;
|
|
44
|
-
/** When true, hover/focus never opens the card. */
|
|
45
|
-
disabled?: boolean;
|
|
46
|
-
/** Receive the open controller (open accessor + setOpen) once mounted. */
|
|
47
|
-
controllerRef?: (api: HoverCardController) => void;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function HoverCardRoot(props: HoverCardRootProps) {
|
|
51
|
-
const [open, setOpen] = createSignal(props.defaultOpen ?? false);
|
|
52
|
-
const [trigger, setTrigger] = createSignal<HTMLElement>();
|
|
53
|
-
const [content, setContent] = createSignal<HTMLElement>();
|
|
54
|
-
const contentId = createUniqueId();
|
|
55
|
-
let timer: number | undefined;
|
|
56
|
-
props.controllerRef?.({ open, setOpen });
|
|
57
|
-
|
|
58
|
-
// ONE shared timer drives both trigger and content. Entering either cancels
|
|
59
|
-
// any pending close and schedules an open; leaving either cancels any pending
|
|
60
|
-
// open and schedules a close. Because the pointer transit trigger -> content
|
|
61
|
-
// fires leave() then enter() against the SAME timer, the close is cancelled
|
|
62
|
-
// before it can run, so the card never flickers and there are no stale-timer
|
|
63
|
-
// sporadics (the HC-1 fix).
|
|
64
|
-
const enter = () => {
|
|
65
|
-
if (props.disabled) return;
|
|
66
|
-
clearTimeout(timer);
|
|
67
|
-
timer = window.setTimeout(() => setOpen(true), props.openDelay ?? 0);
|
|
68
|
-
};
|
|
69
|
-
const leave = () => {
|
|
70
|
-
clearTimeout(timer);
|
|
71
|
-
// closeDelay default is 300ms (Radix-style) as a belt-and-suspenders fallback
|
|
72
|
-
// for diagonal pointer escapes that miss the transparent safe bridge.
|
|
73
|
-
timer = window.setTimeout(() => setOpen(false), props.closeDelay ?? 300);
|
|
74
|
-
};
|
|
75
|
-
const close = () => { clearTimeout(timer); setOpen(false); };
|
|
76
|
-
onCleanup(() => clearTimeout(timer));
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<Ctx.Provider value={{
|
|
80
|
-
open, enter, leave, close,
|
|
81
|
-
setTrigger, setContent,
|
|
82
|
-
trigger, content,
|
|
83
|
-
contentId,
|
|
84
|
-
disabled: () => props.disabled ?? false,
|
|
85
|
-
}}>
|
|
86
|
-
{props.children}
|
|
87
|
-
</Ctx.Provider>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface HoverCardTriggerProps {
|
|
92
|
-
children: JSX.Element;
|
|
93
|
-
class?: string;
|
|
94
|
-
/**
|
|
95
|
-
* Whether the trigger is its own tab stop. Omit for the automatic behaviour,
|
|
96
|
-
* which is right for every case in this repo: the trigger takes focus only
|
|
97
|
-
* when nothing inside it already can.
|
|
98
|
-
*
|
|
99
|
-
* Pass `false` to keep a trigger out of the tab order entirely, or `true` to
|
|
100
|
-
* force a stop. Both are escape hatches — reach for them when the automatic
|
|
101
|
-
* answer is wrong, not to restate it.
|
|
102
|
-
*/
|
|
103
|
-
focusable?: boolean;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Anything the platform puts in the tab order by default, plus anything a
|
|
107
|
-
* consumer opted in with `tabindex`. `tabindex="-1"` is deliberately excluded:
|
|
108
|
-
* it is programmatically focusable but the Tab key skips it, so a trigger
|
|
109
|
-
* containing only such an element still needs a stop of its own. */
|
|
110
|
-
const FOCUSABLE_CHILD =
|
|
111
|
-
'a[href],button,input,select,textarea,summary,[contenteditable=""],[contenteditable="true"],[tabindex]:not([tabindex^="-"])';
|
|
112
|
-
|
|
113
|
-
/** Does this subtree already offer the keyboard a way in? Slotted content is
|
|
114
|
-
* checked through `assignedElements()`, because a `<slot>` in the shadow tree
|
|
115
|
-
* contains none of the light-DOM nodes it projects — the `kai-hover-card`
|
|
116
|
-
* facade wraps a bare `<slot />`, so without this branch every use of that
|
|
117
|
-
* element would be told its children are inert.
|
|
118
|
-
*
|
|
119
|
-
* ★ WHEN this runs is as load-bearing as what it asks. At ref time the facade's
|
|
120
|
-
* trigger contains `<slot></slot>` with NOTHING assigned yet, so a single call
|
|
121
|
-
* from the ref answers "inert" for a slot that is about to receive a focusable
|
|
122
|
-
* `<a>` — and the trigger stamps a second tab stop on top of the child's. That
|
|
123
|
-
* is the very regression the `assignedElements()` branch was added to prevent,
|
|
124
|
-
* reintroduced by timing rather than by logic. Measured with a real Tab key:
|
|
125
|
-
* 4 stops across a 3-widget fixture. So the caller re-runs this on
|
|
126
|
-
* `slotchange`; see `HoverCardTrigger`. */
|
|
127
|
-
const hasFocusableChild = (root: HTMLElement): boolean => {
|
|
128
|
-
if (root.querySelector(FOCUSABLE_CHILD)) return true;
|
|
129
|
-
return Array.from(root.querySelectorAll('slot')).some((slot) =>
|
|
130
|
-
(slot as HTMLSlotElement).assignedElements().some(
|
|
131
|
-
(el) => el.matches(FOCUSABLE_CHILD) || el.querySelector(FOCUSABLE_CHILD),
|
|
132
|
-
),
|
|
133
|
-
);
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* ★ THE TRIGGER IS A TAB STOP WHEN, AND ONLY WHEN, ITS CHILDREN ARE NOT.
|
|
138
|
-
*
|
|
139
|
-
* `onFocusIn`/`onFocusOut` were here from the start and the focus-open path was
|
|
140
|
-
* plainly intended, but the span never set `tabindex`, so the Tab key could not
|
|
141
|
-
* land on it and neither handler could fire on a keyboard. It went unnoticed for
|
|
142
|
-
* as long as it did because `focusin` BUBBLES and every consumer at the time put
|
|
143
|
-
* something focusable inside the trigger — `source.tsx` an `<a>`, `context.tsx`
|
|
144
|
-
* a `<Button>` — so the card opened via the child and the span's own inertness
|
|
145
|
-
* never showed. The first trigger with inert children (an attachment tile: a
|
|
146
|
-
* div, an img, an svg) had no tab stop anywhere in it.
|
|
147
|
-
*
|
|
148
|
-
* Hence delegation rather than an unconditional `tabindex`: adding one always
|
|
149
|
-
* would give every existing consumer TWO stops for one card, which is a worse
|
|
150
|
-
* bug than the one being fixed. The check runs in the ref AND again on every
|
|
151
|
-
* `slotchange`, because slot assignment happens after the ref and a one-shot
|
|
152
|
-
* check calls a not-yet-filled `<slot>` inert (see `hasFocusableChild`).
|
|
153
|
-
*
|
|
154
|
-
* ★ THE FOCUS LISTENERS ARE NATIVE, NOT SOLID'S DELEGATED `onFocusIn`. Solid
|
|
155
|
-
* delegates a fixed set of events from the document and retargets them into
|
|
156
|
-
* component trees; inside these shadow roots that path runs for a PROGRAMMATIC
|
|
157
|
-
* `.focus()` and, in the deeper trees, not for a real Tab. Measured: tabbing to
|
|
158
|
-
* an attachment tile in a mounted `<kai-chat>` left the card shut and
|
|
159
|
-
* `aria-describedby` null while `.focus()` on the same element opened it — so
|
|
160
|
-
* every keyboard user got a tab stop that announced nothing and showed nothing,
|
|
161
|
-
* which is worse than no stop at all. `addEventListener` in the ref does not
|
|
162
|
-
* care how focus arrived. Anything in this kit relying on delegated focus
|
|
163
|
-
* events inside a shadow root is suspect for the same reason.
|
|
164
|
-
*
|
|
165
|
-
* `aria-describedby` is what makes the stop worth arriving at: the card is
|
|
166
|
-
* DESCRIPTIVE, not an action, so the trigger gets no `role="button"` — that
|
|
167
|
-
* would promise an activation that does not exist — and instead points at the
|
|
168
|
-
* content it reveals so a screen reader reads it out.
|
|
169
|
-
*/
|
|
170
|
-
export function HoverCardTrigger(props: HoverCardTriggerProps) {
|
|
171
|
-
const ctx = useHoverCard();
|
|
172
|
-
const [detectedInert, setDetectedInert] = createSignal(false);
|
|
173
|
-
// `&& !disabled` last, and it beats an explicit `focusable` — a disabled card
|
|
174
|
-
// early-returns out of `enter()`, so a stop here could never open anything.
|
|
175
|
-
// Landing on it would announce nothing and reveal nothing, which is the dead
|
|
176
|
-
// stop the note above argues against; forcing one is not an escape hatch
|
|
177
|
-
// anybody should get.
|
|
178
|
-
const isFocusable = () => (props.focusable ?? detectedInert()) && !ctx.disabled();
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<As
|
|
182
|
-
as="span"
|
|
183
|
-
class={cn(
|
|
184
|
-
'inline-block',
|
|
185
|
-
// A tab stop nobody can SEE is barely an improvement on no tab stop —
|
|
186
|
-
// WCAG 2.4.7. Only when this element is the stop; a delegating trigger
|
|
187
|
-
// must not draw a ring around its child's own focus state.
|
|
188
|
-
//
|
|
189
|
-
// AN OUTLINE, NOT A RING, and both halves of that were measured rather
|
|
190
|
-
// than assumed:
|
|
191
|
-
//
|
|
192
|
-
// 1. ★ A TAILWIND v4 UTILITY THAT ROUTES THROUGH `@property` IS INERT
|
|
193
|
-
// INSIDE THESE SHADOW ROOTS, and that is a trap far wider than this
|
|
194
|
-
// line. v4 gives `--tw-*` custom properties their defaults with
|
|
195
|
-
// `@property`, and an `@property` rule delivered through a shadow
|
|
196
|
-
// root's `adoptedStyleSheets` never registers — so the var resolves
|
|
197
|
-
// to nothing, the declaration is invalid, and the property falls
|
|
198
|
-
// back to its initial value. Measured in Chrome, twice:
|
|
199
|
-
// `ring-2 ring-offset-1` set `--tw-ring-shadow` correctly and
|
|
200
|
-
// computed `box-shadow: none`; `inset-ring-2` did the same; and
|
|
201
|
-
// `outline-2` alone computed `outline-style: none` while width,
|
|
202
|
-
// colour and offset all landed, because only the style goes
|
|
203
|
-
// through `var(--tw-outline-style)`. Hence the literal
|
|
204
|
-
// `[outline-style:solid]` — the one part that cannot be a var.
|
|
205
|
-
// 2. The offset is NEGATIVE so the outline lands inside the border
|
|
206
|
-
// box. A trigger that fills its container (`block size-full` inside
|
|
207
|
-
// the attachment tile's `overflow-hidden rounded-lg`) would
|
|
208
|
-
// otherwise have its focus indicator painted straight into the
|
|
209
|
-
// clip, and a trigger cannot know whether its container clips.
|
|
210
|
-
isFocusable() &&
|
|
211
|
-
'rounded-sm focus-visible:[outline-style:solid] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring',
|
|
212
|
-
props.class,
|
|
213
|
-
)}
|
|
214
|
-
ref={(el: HTMLElement) => {
|
|
215
|
-
ctx.setTrigger(el);
|
|
216
|
-
|
|
217
|
-
// Native listeners, deliberately — see the note above. `focusin` /
|
|
218
|
-
// `focusout` rather than `focus` / `blur` because these have to fire
|
|
219
|
-
// for a focusable CHILD too, and only the -in/-out pair bubbles.
|
|
220
|
-
const enter = () => ctx.enter();
|
|
221
|
-
const leave = () => ctx.leave();
|
|
222
|
-
el.addEventListener('focusin', enter);
|
|
223
|
-
el.addEventListener('focusout', leave);
|
|
224
|
-
onCleanup(() => {
|
|
225
|
-
el.removeEventListener('focusin', enter);
|
|
226
|
-
el.removeEventListener('focusout', leave);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Ask now for the direct-children case, and again whenever a slot is
|
|
230
|
-
// filled or emptied. Both are needed: `slotchange` never fires for a
|
|
231
|
-
// trigger with no slot in it, and the ref-time answer is wrong for one
|
|
232
|
-
// that has.
|
|
233
|
-
const evaluate = () => setDetectedInert(!hasFocusableChild(el));
|
|
234
|
-
evaluate();
|
|
235
|
-
for (const slot of Array.from(el.querySelectorAll('slot'))) {
|
|
236
|
-
slot.addEventListener('slotchange', evaluate);
|
|
237
|
-
onCleanup(() => slot.removeEventListener('slotchange', evaluate));
|
|
238
|
-
}
|
|
239
|
-
}}
|
|
240
|
-
tabIndex={isFocusable() ? 0 : undefined}
|
|
241
|
-
aria-describedby={isFocusable() && ctx.open() ? ctx.contentId : undefined}
|
|
242
|
-
onPointerEnter={ctx.enter}
|
|
243
|
-
onPointerLeave={ctx.leave}
|
|
244
|
-
>
|
|
245
|
-
{props.children}
|
|
246
|
-
</As>
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export interface HoverCardContentProps { children: JSX.Element; class?: string; placement?: Placement; }
|
|
251
|
-
|
|
252
|
-
// Visual gap between trigger and the visible card. Also the depth of the
|
|
253
|
-
// transparent safe bridge so the pointer never crosses "empty" space.
|
|
254
|
-
const GUTTER = 8;
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Returns the CSS padding property that, set to `gutter`px on the OUTER floating
|
|
258
|
-
* shell, recreates the visual gap as a transparent safe area on the
|
|
259
|
-
* trigger-facing side. The outer shell is placed flush (gutter: 0) so the
|
|
260
|
-
* padding bridges the gap while keeping the inner card the same distance away.
|
|
261
|
-
*
|
|
262
|
-
* Placement strings from @floating-ui/dom (post flip/shift) may carry a
|
|
263
|
-
* '-start'/'-end' alignment suffix; we split on '-' and key on the side.
|
|
264
|
-
* bottom* -> padding-top, top* -> padding-bottom,
|
|
265
|
-
* left* -> padding-right, right* -> padding-left
|
|
266
|
-
*/
|
|
267
|
-
function gapPaddingStyle(placement: string, gutter: number): JSX.CSSProperties {
|
|
268
|
-
const side = placement.split('-')[0];
|
|
269
|
-
const prop: Record<string, keyof JSX.CSSProperties> = {
|
|
270
|
-
bottom: 'padding-top',
|
|
271
|
-
top: 'padding-bottom',
|
|
272
|
-
left: 'padding-right',
|
|
273
|
-
right: 'padding-left',
|
|
274
|
-
};
|
|
275
|
-
return { [prop[side] ?? 'padding-top']: `${gutter}px` };
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export function HoverCardContent(props: HoverCardContentProps) {
|
|
279
|
-
const ctx = useHoverCard();
|
|
280
|
-
const config = useChatConfig();
|
|
281
|
-
const presence = createPresence(ctx.open);
|
|
282
|
-
// gutter: 0 places the outer shell flush with the trigger; the visual gap is
|
|
283
|
-
// recreated by transparent padding (gapPaddingStyle) so the hit area bridges
|
|
284
|
-
// it and a straight trigger->content transit never leaves a hot zone.
|
|
285
|
-
const position = usePosition(ctx.trigger, ctx.content, {
|
|
286
|
-
placement: props.placement ?? 'bottom',
|
|
287
|
-
gutter: 0,
|
|
288
|
-
// Trigger removed from the DOM -> close so the card portal doesn't orphan.
|
|
289
|
-
onDisconnect: () => ctx.close(),
|
|
290
|
-
});
|
|
291
|
-
// Escape OR an outside click closes immediately — an outside click is a
|
|
292
|
-
// deliberate dismiss, not a hover-out (which uses leave()'s grace delay).
|
|
293
|
-
useDismiss({ enabled: ctx.open, onDismiss: () => ctx.close(), refs: () => [ctx.trigger(), ctx.content()] });
|
|
294
|
-
|
|
295
|
-
return (
|
|
296
|
-
<Show when={presence.present()}>
|
|
297
|
-
<Portal mount={config.portalMount()}>
|
|
298
|
-
{/* Outer shell: positioning + the transparent safe bridge + hot zone. */}
|
|
299
|
-
<div
|
|
300
|
-
ref={(el) => { ctx.setContent(el); presence.setRef(el); }}
|
|
301
|
-
data-hovercard-content
|
|
302
|
-
onPointerEnter={ctx.enter}
|
|
303
|
-
onPointerLeave={ctx.leave}
|
|
304
|
-
onFocusIn={ctx.enter}
|
|
305
|
-
onFocusOut={ctx.leave}
|
|
306
|
-
style={{
|
|
307
|
-
position: 'fixed',
|
|
308
|
-
left: `${position.pos().x}px`,
|
|
309
|
-
top: `${position.pos().y}px`,
|
|
310
|
-
background: 'transparent',
|
|
311
|
-
visibility: position.hidden() ? 'hidden' : 'visible',
|
|
312
|
-
...gapPaddingStyle(position.pos().placement, GUTTER),
|
|
313
|
-
}}
|
|
314
|
-
class="z-50"
|
|
315
|
-
>
|
|
316
|
-
{/* Inner card: all visual + animation classes and the presence state. */}
|
|
317
|
-
<div
|
|
318
|
-
id={ctx.contentId}
|
|
319
|
-
data-expanded={presence.state() === 'open' ? '' : undefined}
|
|
320
|
-
data-closed={presence.state() === 'closed' ? '' : undefined}
|
|
321
|
-
class={cn(
|
|
322
|
-
'rounded-lg bg-card kai-elevation',
|
|
323
|
-
'animate-in fade-in-0 zoom-in-95 data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95',
|
|
324
|
-
props.class,
|
|
325
|
-
)}
|
|
326
|
-
>
|
|
327
|
-
{props.children}
|
|
328
|
-
</div>
|
|
329
|
-
</div>
|
|
330
|
-
</Portal>
|
|
331
|
-
</Show>
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
export interface HoverCardProps { trigger: JSX.Element; children: JSX.Element; class?: string; openDelay?: number; closeDelay?: number; placement?: Placement; }
|
|
336
|
-
|
|
337
|
-
export function HoverCard(props: HoverCardProps) {
|
|
338
|
-
const [local] = splitProps(props, ['trigger', 'children', 'class', 'openDelay', 'closeDelay', 'placement']);
|
|
339
|
-
return (
|
|
340
|
-
<HoverCardRoot openDelay={local.openDelay} closeDelay={local.closeDelay}>
|
|
341
|
-
<HoverCardTrigger>{local.trigger}</HoverCardTrigger>
|
|
342
|
-
<HoverCardContent class={cn('w-64 p-4', local.class)} placement={local.placement}>{local.children}</HoverCardContent>
|
|
343
|
-
</HoverCardRoot>
|
|
344
|
-
);
|
|
345
|
-
}
|
package/src/ui/icon.tsx
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type { Component, JSX } from 'solid-js';
|
|
2
|
-
import {
|
|
3
|
-
Plus, Paperclip, Github, Globe, Sparkles, Settings,
|
|
4
|
-
FileText, Folder, Image, Monitor, MessageCircle, MessageSquare, Search,
|
|
5
|
-
Mic, AudioLines, X, ChevronDown, ChevronLeft,
|
|
6
|
-
Pencil, BookOpen, Code, Smile,
|
|
7
|
-
Share, ArrowLeft, MoreHorizontal,
|
|
8
|
-
House, Clock, Lock, Box, Briefcase, PanelLeft, Circle, SlidersHorizontal, Workflow, SquarePen,
|
|
9
|
-
Archive, ArrowUp, Bookmark, Copy, Ellipsis, ExternalLink, Flag,
|
|
10
|
-
GitBranch, GitPullRequest, ListFilter, RotateCw,
|
|
11
|
-
Moon, Sun,
|
|
12
|
-
// Device / viewport glyphs.
|
|
13
|
-
Tablet, Smartphone, Laptop,
|
|
14
|
-
// Direction glyphs completing the chevron + arrow quartets.
|
|
15
|
-
ChevronRight, ChevronUp, ArrowRight, ArrowDown, PanelRight,
|
|
16
|
-
// Status glyphs (kai-notice / kai-toast / kai-tool render these already).
|
|
17
|
-
Check, Info, TriangleAlert, CircleCheck, CircleAlert, CircleX,
|
|
18
|
-
// Action glyphs the kit performs but could not be named.
|
|
19
|
-
Trash2, Download, Upload, Link, RotateCcw,
|
|
20
|
-
// Pane / media chrome.
|
|
21
|
-
Maximize2, Minimize2, Eye, EyeOff, Bell, Square, Minus, Play,
|
|
22
|
-
} from 'lucide-solid';
|
|
23
|
-
|
|
24
|
-
type IconComponent = Component<{ class?: string }>;
|
|
25
|
-
|
|
26
|
-
/** Curated name → lucide-solid component map for item icons in kai-menu /
|
|
27
|
-
* kai-command. Extend here when new named icons are needed. */
|
|
28
|
-
const NAMED_ICONS: Record<string, IconComponent> = {
|
|
29
|
-
plus: Plus,
|
|
30
|
-
paperclip: Paperclip,
|
|
31
|
-
github: Github,
|
|
32
|
-
globe: Globe,
|
|
33
|
-
sparkles: Sparkles,
|
|
34
|
-
settings: Settings,
|
|
35
|
-
'file-text': FileText,
|
|
36
|
-
folder: Folder,
|
|
37
|
-
image: Image,
|
|
38
|
-
monitor: Monitor,
|
|
39
|
-
'message-circle': MessageCircle,
|
|
40
|
-
'message-square': MessageSquare,
|
|
41
|
-
search: Search,
|
|
42
|
-
mic: Mic,
|
|
43
|
-
'audio-lines': AudioLines,
|
|
44
|
-
x: X,
|
|
45
|
-
'chevron-down': ChevronDown,
|
|
46
|
-
pencil: Pencil,
|
|
47
|
-
'book-open': BookOpen,
|
|
48
|
-
code: Code,
|
|
49
|
-
smile: Smile,
|
|
50
|
-
// Header / chrome glyphs.
|
|
51
|
-
share: Share,
|
|
52
|
-
'arrow-left': ArrowLeft,
|
|
53
|
-
'more-horizontal': MoreHorizontal,
|
|
54
|
-
'chevron-left': ChevronLeft,
|
|
55
|
-
// App-shell glyphs (sidebar nav, recents, filters).
|
|
56
|
-
home: House,
|
|
57
|
-
clock: Clock,
|
|
58
|
-
lock: Lock,
|
|
59
|
-
box: Box,
|
|
60
|
-
briefcase: Briefcase,
|
|
61
|
-
'panel-left': PanelLeft,
|
|
62
|
-
circle: Circle,
|
|
63
|
-
'sliders-horizontal': SlidersHorizontal,
|
|
64
|
-
workflow: Workflow,
|
|
65
|
-
'square-pen': SquarePen,
|
|
66
|
-
// Code-app / dev-tool glyphs (git, filters, list actions).
|
|
67
|
-
archive: Archive,
|
|
68
|
-
'arrow-up': ArrowUp,
|
|
69
|
-
bookmark: Bookmark,
|
|
70
|
-
copy: Copy,
|
|
71
|
-
ellipsis: Ellipsis,
|
|
72
|
-
'external-link': ExternalLink,
|
|
73
|
-
flag: Flag,
|
|
74
|
-
'git-branch': GitBranch,
|
|
75
|
-
'git-pull-request': GitPullRequest,
|
|
76
|
-
'list-filter': ListFilter,
|
|
77
|
-
'rotate-cw': RotateCw,
|
|
78
|
-
// Theme / appearance glyphs.
|
|
79
|
-
moon: Moon,
|
|
80
|
-
sun: Sun,
|
|
81
|
-
// Device / viewport glyphs. `desktop` and `mobile` are aliases onto the same
|
|
82
|
-
// components as `monitor`/`smartphone` — lucide's names are not the words a
|
|
83
|
-
// consumer reaches for, and an alias costs nothing in the bundle.
|
|
84
|
-
desktop: Monitor,
|
|
85
|
-
laptop: Laptop,
|
|
86
|
-
tablet: Tablet,
|
|
87
|
-
smartphone: Smartphone,
|
|
88
|
-
mobile: Smartphone,
|
|
89
|
-
// Direction glyphs — chevron-down/left and arrow-left/up were here without
|
|
90
|
-
// their opposites; both quartets are now complete.
|
|
91
|
-
'chevron-right': ChevronRight,
|
|
92
|
-
'chevron-up': ChevronUp,
|
|
93
|
-
'arrow-right': ArrowRight,
|
|
94
|
-
'arrow-down': ArrowDown,
|
|
95
|
-
'panel-right': PanelRight,
|
|
96
|
-
// Status glyphs. kai-notice / kai-toast / kai-tool already paint these, so a
|
|
97
|
-
// host building matching UI needs to be able to name them.
|
|
98
|
-
check: Check,
|
|
99
|
-
info: Info,
|
|
100
|
-
'triangle-alert': TriangleAlert,
|
|
101
|
-
'circle-check': CircleCheck,
|
|
102
|
-
'circle-alert': CircleAlert,
|
|
103
|
-
'circle-x': CircleX,
|
|
104
|
-
// Action glyphs. `trash`/`download`/`link` match the keys action-icons.ts
|
|
105
|
-
// already uses for message actions; `upload` is download's missing sibling.
|
|
106
|
-
trash: Trash2,
|
|
107
|
-
download: Download,
|
|
108
|
-
upload: Upload,
|
|
109
|
-
link: Link,
|
|
110
|
-
'rotate-ccw': RotateCcw,
|
|
111
|
-
// Pane / media chrome (kai-pane, kai-artifact, kai-embed, kai-agent-card).
|
|
112
|
-
'maximize-2': Maximize2,
|
|
113
|
-
'minimize-2': Minimize2,
|
|
114
|
-
eye: Eye,
|
|
115
|
-
'eye-off': EyeOff,
|
|
116
|
-
bell: Bell,
|
|
117
|
-
square: Square,
|
|
118
|
-
minus: Minus,
|
|
119
|
-
play: Play,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
/** Every curated icon name, sorted. Derived from `NAMED_ICONS` so a gallery,
|
|
123
|
-
* a story control or a test can never drift from the map itself. */
|
|
124
|
-
export const ICON_NAMES: readonly string[] = Object.keys(NAMED_ICONS).sort();
|
|
125
|
-
|
|
126
|
-
/** Render an item icon.
|
|
127
|
-
*
|
|
128
|
-
* Resolution order:
|
|
129
|
-
* 1. Known icon name (e.g. `"paperclip"`) → lucide-solid component.
|
|
130
|
-
* 2. URL / absolute path / data-URI → `<img>`.
|
|
131
|
-
* 3. Anything else → `<span>` text fallback.
|
|
132
|
-
* Returns `null` when `icon` is undefined/empty.
|
|
133
|
-
*
|
|
134
|
-
* The img and span branches render different markup, so they accept different
|
|
135
|
-
* class options: `imgClass` for the `<img>`, `spanClass` for the `<span>`.
|
|
136
|
-
* `class` is a shared fallback. Pass `ariaHidden` to mark the span decorative. */
|
|
137
|
-
export function renderIcon(
|
|
138
|
-
icon: string | undefined,
|
|
139
|
-
opts?: { class?: string; imgClass?: string; spanClass?: string; ariaHidden?: boolean },
|
|
140
|
-
): JSX.Element {
|
|
141
|
-
if (!icon) return null;
|
|
142
|
-
const Named = NAMED_ICONS[icon];
|
|
143
|
-
if (Named) {
|
|
144
|
-
return <Named class={opts?.imgClass ?? opts?.class ?? 'mr-2 size-4 shrink-0'} />;
|
|
145
|
-
}
|
|
146
|
-
const isUrl = /^(https?:|\/|data:)/.test(icon);
|
|
147
|
-
// DEV footgun guard: a kebab/identifier-shaped string that isn't a URL and
|
|
148
|
-
// isn't a known name is almost certainly a typo'd/unregistered icon (e.g.
|
|
149
|
-
// `icon="share"` before it was added) — it would silently paint as literal
|
|
150
|
-
// text. Warn in dev only; emoji/arbitrary text passes through untouched.
|
|
151
|
-
if (import.meta.env.DEV && !isUrl && /^[a-z][a-z0-9-]*$/.test(icon)) {
|
|
152
|
-
console.warn(
|
|
153
|
-
`[kai-icon] unknown icon name "${icon}" — rendering as text. ` +
|
|
154
|
-
'Add it to NAMED_ICONS in src/ui/icon.tsx, or pass a URL / an inline SVG via slot="icon".',
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
return isUrl
|
|
158
|
-
? <img src={icon} alt="" class={opts?.imgClass ?? opts?.class ?? 'size-4 shrink-0'} />
|
|
159
|
-
: (
|
|
160
|
-
<span
|
|
161
|
-
class={opts?.spanClass ?? opts?.class ?? 'size-4 shrink-0'}
|
|
162
|
-
aria-hidden={opts?.ariaHidden ? 'true' : undefined}
|
|
163
|
-
>
|
|
164
|
-
{icon}
|
|
165
|
-
</span>
|
|
166
|
-
);
|
|
167
|
-
}
|