@kitn.ai/ui 0.25.2 → 0.27.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 +17 -6
- package/bin/mcp.js +16 -3
- package/bin/route.js +23 -0
- package/bin/route.test.js +58 -0
- package/dist/{elements/chunks/Icon-b5A8hlHs.js → Icon-BnFKqqtY.js} +1 -1
- package/dist/action-icons-CBskfBMz.js +1 -0
- package/dist/arrow-down-Br0qtpsz.js +1 -0
- package/dist/arrow-left-Dj7xgE12.js +1 -0
- package/dist/artifact-CvXEm1lS.js +1 -0
- package/dist/assets/dev-5XzXYR21.js +91 -0
- package/dist/attachments-C43ZegEq.js +1 -0
- package/dist/audio-visualizer-B-79y1Tj.js +1 -0
- package/dist/badge-BpUbq8c0.js +1 -0
- package/dist/bash-InADTalH.js +1 -6
- package/dist/bell-sn17Ip9v.js +1 -0
- package/dist/{elements/chunks/button-B9okqG73.js → button-BH6rN0U-.js} +1 -1
- package/dist/card-renderer-Cb1gQmth.js +1 -0
- package/dist/card-routing-DifQgS7n.js +1 -0
- package/dist/check-DPeeMUYx.js +1 -0
- package/dist/checkbox-Dc9Yov_B.js +1 -0
- package/dist/checkbox-group-B1kDLLYk.js +1 -0
- package/dist/chevron-down-CHSWk7ZT.js +1 -0
- package/dist/chevron-right-B7l_fMgx.js +1 -0
- package/dist/choice-card-BT3c1S8g.js +1 -0
- package/dist/circle-Bb0yOpqM.js +1 -0
- package/dist/circle-check-BGZpCiz7.js +1 -0
- package/dist/circle-x-wobWkoSx.js +1 -0
- package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
- package/dist/code-block-CUQ5mtv0.js +1 -0
- package/dist/collapsible-CPJbf6FM.js +1 -0
- package/dist/components/attachment-types.d.ts +53 -1
- package/dist/components/attachments.d.ts +31 -0
- package/dist/components/audio-visualizer/fit-scale.d.ts +50 -0
- package/dist/components/audio-visualizer/index.d.ts +15 -1
- package/dist/components/audio-visualizer/variant-bar.d.ts +24 -1
- package/dist/components/card-renderer.d.ts +13 -0
- package/dist/components/card.d.ts +4 -0
- package/dist/components/chat-thread.d.ts +49 -42
- package/dist/components/code-block.d.ts +22 -0
- package/dist/components/conversation-item.d.ts +66 -1
- package/dist/components/conversation-list.d.ts +77 -0
- package/dist/components/form-widgets.d.ts +67 -2
- package/dist/components/form.d.ts +89 -0
- package/dist/components/message.d.ts +29 -0
- package/dist/components/reasoning.d.ts +6 -0
- package/dist/components/scroll-button.d.ts +11 -0
- package/dist/components/thread.d.ts +5 -0
- package/dist/components/toast.d.ts +2 -1
- package/dist/components/tool-types.d.ts +9 -0
- package/dist/components/voice-input.d.ts +8 -0
- package/dist/components/voice-output.d.ts +12 -1
- package/dist/components/workspace-shell.d.ts +87 -0
- package/dist/composer-CjngLzal.js +106 -0
- package/dist/confirm-card-DCx_A4bU.js +1 -0
- package/dist/construct-cli.es.js +1169 -0
- package/dist/context-BY8V-Nlp.js +1 -0
- package/dist/controllable-D43BKmtX.js +1 -0
- package/dist/conversation-list-D4lLU_yS.js +1 -0
- package/dist/copy-B6DO4PqB.js +1 -0
- package/dist/core-AYMC6_lb.js +12 -5874
- package/dist/{create-tween-CUzOlaMS.js → create-tween-BPzaefTp.js} +1 -1
- package/dist/{create-tween-B5Y4Im8G.js → create-tween-CnMHviKB.js} +1 -1
- package/dist/{create-tween-4z1XYLkR.js → create-tween-D1aiGZZh.js} +1 -1
- package/dist/{elements/chunks/create-tween-CUrM6D_o.js → create-tween-DUSQUKpr.js} +2 -2
- package/dist/css-M7EaDHN_.js +1 -6
- package/dist/custom-elements.json +3468 -1927
- package/dist/default-input-CucQEOqH.js +1 -0
- package/dist/define-CGGX-7Vg.js +1 -0
- package/dist/define.d.ts +4 -0
- package/dist/define.js +510 -0
- package/dist/define.server.d.ts +5 -0
- package/dist/define.server.js +506 -0
- package/dist/diagnostics/hook.d.ts +81 -0
- package/dist/diagnostics/index.d.ts +7 -0
- package/dist/diagnostics/report-request.d.ts +61 -0
- package/dist/diagnostics.d.ts +5 -0
- package/dist/diagnostics.js +209 -0
- package/dist/disclosure-CbLtajUQ.js +1 -0
- package/dist/dropdown-BwhViJFd.js +1 -0
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/autoloader.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- package/dist/elements/card.js +1 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkbox-group.d.ts +1 -0
- package/dist/elements/checkbox-group.js +1 -0
- package/dist/elements/checkbox.d.ts +1 -0
- package/dist/elements/checkbox.js +1 -0
- 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.d.ts +1 -0
- package/dist/elements/conversation-item.js +1 -0
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/default-input.d.ts +3 -3
- package/dist/elements/define-entry.d.ts +12 -0
- package/dist/elements/define.d.ts +27 -0
- package/dist/elements/diagnostic-events.d.ts +74 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.d.ts +1 -0
- package/dist/elements/dock.js +243 -0
- package/dist/elements/dropdown.d.ts +1 -0
- package/dist/elements/dropdown.js +1 -0
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +37 -0
- package/dist/elements/element-diagnostics.d.ts +81 -0
- package/dist/elements/embed.js +1 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- package/dist/elements/hover-card.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- package/dist/elements/link-preview.js +1 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.js +1 -1
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- package/dist/elements/nav.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-grid.d.ts +1 -0
- package/dist/elements/pane-grid.js +1 -0
- 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.d.ts +1 -0
- package/dist/elements/radio-group.js +1 -0
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/register.d.ts +2 -0
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +3 -3
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/select.d.ts +1 -0
- package/dist/elements/select.js +1 -0
- 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.d.ts +1 -0
- package/dist/elements/slider.js +1 -0
- package/dist/elements/slots.d.ts +36 -4
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +589 -167
- package/dist/{elements/chunks/ellipsis-CVxqfsDZ.js → ellipsis-DFr4Vqr3.js} +1 -1
- package/dist/embed-5s_vU4J0.js +1 -0
- package/dist/engine-javascript-vq0WuIJl.js +14 -2516
- package/dist/{elements/chunks/external-link-DG2sRdQL.js → external-link-u9d85ORQ.js} +1 -1
- package/dist/file-text-CX7_x42o.js +1 -0
- package/dist/{elements/chunks/file-tree-yGWNK0Js.js → file-tree-D3kBjXI5.js} +1 -1
- package/dist/folder-V-YdIL8f.js +1 -0
- package/dist/form-BRNUMCN2.js +1 -0
- package/dist/github-dark-dimmed-DUshB20C.js +1 -4
- package/dist/github-light-JYsPkUQd.js +1 -4
- package/dist/hover-card-DaeiYrTA.js +1 -0
- package/dist/html-CPZ3oZQ7.js +1 -10
- package/dist/icon-BpixdZNq.js +1 -0
- package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8473 -6470
- package/dist/index.server.js +6495 -4958
- package/dist/info-8mFsIjS3.js +1 -0
- package/dist/input-d1Yuu-hz.js +1 -0
- package/dist/javascript-C25yR2R2.js +1 -6
- package/dist/json-DxJze_jm.js +1 -6
- package/dist/kai-provider.es.js +40 -40
- package/dist/kai.es.js +1 -1
- package/dist/kbd-961zMPFB.js +1 -0
- package/dist/link-DlZZBGaR.js +1 -0
- package/dist/{elements/chunks/link-preview-Cf5KOP-i.js → link-preview-DIIbV2Sd.js} +1 -1
- package/dist/loader-YQszHFaW.js +1 -0
- package/dist/{elements/chunks/markdown-DbozyYqa.js → markdown-CVk1MPsj.js} +1 -1
- package/dist/mcp.es.js +3873 -544
- package/dist/message-CwKVEdZg.js +1 -0
- package/dist/message-DS8lzHc1.js +1 -0
- package/dist/message-circle-Xf8Q-vZp.js +1 -0
- package/dist/message-square-Cxnwgkns.js +1 -0
- package/dist/{elements/chunks/minimize-2-SegJ_oku.js → minimize-2-UEZmP2QT.js} +1 -1
- package/dist/{elements/chunks/model-switcher-D7JrFFHp.js → model-switcher-Kk1jEQ5t.js} +1 -1
- package/dist/{elements/chunks/overlay-CV7z2YuX.js → overlay-C1od6LOz.js} +1 -1
- package/dist/panel-right-ryET0yyn.js +1 -0
- package/dist/paperclip-BDNoZFJP.js +1 -0
- package/dist/play-OFIvYXUQ.js +1 -0
- package/dist/primitives/card-data-types.d.ts +49 -0
- package/dist/primitives/card-routing.d.ts +1 -33
- package/dist/primitives/card-validate.d.ts +2 -2
- package/dist/primitives/chat-config.d.ts +29 -2
- package/dist/primitives/field-mask.d.ts +96 -0
- package/dist/primitives/field-semantics.d.ts +36 -0
- package/dist/primitives/input-mask.d.ts +46 -0
- package/dist/primitives/url-scheme-policy.d.ts +34 -0
- package/dist/primitives/use-resize-observer.d.ts +23 -0
- package/dist/primitives/use-speech-recognition.d.ts +8 -0
- package/dist/primitives/use-text-stream.d.ts +5 -0
- package/dist/progress-bar-BvYX0aoy.js +1 -0
- package/dist/prompt-suggestion-BRFu2lcu.js +1 -0
- package/dist/radio-DcL23cNJ.js +1 -0
- package/dist/react/index.d.ts +306 -283
- package/dist/react.js +309 -247
- package/dist/reasoning-Cackq4Rh.js +1 -0
- package/dist/register-impl-C7rENvPK.js +424 -0
- package/dist/{elements/chunks/resizable-Dpzjlvp4.js → resizable-Cp9HUYih.js} +1 -1
- package/dist/rotate-ccw-0DLRDHH5.js +1 -0
- package/dist/rotate-cw-DOB9IGcU.js +1 -0
- package/dist/schemas/form.schema.json +21 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/tool-defs.d.ts +45 -0
- package/dist/schemas.js +398 -305
- package/dist/scroll-area-emVmWP4K.js +1 -0
- package/dist/scroll-button-CeP_gv1x.js +1 -0
- package/dist/select-CWmu00tS.js +1 -0
- package/dist/{elements/chunks/separator-DH2r_ZSZ.js → separator-CE6vly6z.js} +1 -1
- package/dist/{elements/chunks/settings-BFMOd6yB.js → settings-CE-78SvZ.js} +1 -1
- package/dist/{elements/chunks/settings-group-B3VZKIcz.js → settings-group-ZFWNxFQR.js} +1 -1
- package/dist/{elements/chunks/skeleton-N8BuWYmf.js → skeleton-BebdP4mf.js} +1 -1
- package/dist/slider-BAKRYUlz.js +1 -0
- package/dist/slots-DaNjX0rc.js +1 -0
- package/dist/{solid-BMuDmFo_.js → solid-BE5ui6sy.js} +10672 -8116
- package/dist/{solid-CGYNdLRR.js → solid-DFhsce3O.js} +8137 -6056
- package/dist/solid.d.ts +15 -0
- package/dist/solid.js +248 -235
- package/dist/solid.server.js +248 -235
- package/dist/source-B0FlguSx.js +1 -0
- package/dist/star-CBMZvLuN.js +1 -0
- package/dist/state/index.d.ts +5 -1
- package/dist/state/mock.d.ts +32 -2
- package/dist/state/persistence.d.ts +51 -0
- package/dist/state/stream.d.ts +50 -0
- package/dist/state/threads.d.ts +71 -0
- package/dist/state.js +297 -172
- package/dist/store-7eoadydQ.js +1 -0
- package/dist/svelte--5p79yCD.js +1 -15
- package/dist/switch-CViARZCy.js +1 -0
- package/dist/tasks-card-MjCcOhR_.js +1 -0
- package/dist/text-shimmer-DKlwRF2G.js +1 -0
- package/dist/textarea-3ay2Me2-.js +1 -0
- package/dist/theme.tokens.css +82 -13
- package/dist/{elements/chunks/thumbs-up-DQe0hvkZ.js → thumbs-up-DQcu2HMO.js} +1 -1
- package/dist/toast-store-C6yKOhbk.js +1 -0
- package/dist/{elements/chunks/tool-C1YtxwPu.js → tool-BCYNlfKy.js} +1 -1
- package/dist/{elements/chunks/tooltip-BqwnFWhn.js → tooltip-05zI4hjs.js} +1 -1
- package/dist/trash-2-BR1RxGky.js +1 -0
- package/dist/{elements/chunks/triangle-alert-B6or7F5u.js → triangle-alert-DHohDOCy.js} +1 -1
- package/dist/tsx-B8rCNbgL.js +1 -6
- package/dist/types.d.ts +4 -2
- package/dist/typescript-RycA9KXf.js +1 -6
- package/dist/ui/checkbox-group.d.ts +83 -0
- package/dist/ui/checkbox.d.ts +40 -0
- package/dist/ui/dock.d.ts +131 -0
- package/dist/ui/hover-card.d.ts +44 -0
- package/dist/ui/icon.d.ts +3 -0
- package/dist/ui/input.d.ts +48 -2
- package/dist/ui/radio.d.ts +85 -0
- package/dist/ui/select.d.ts +71 -0
- package/dist/ui/slider.d.ts +65 -0
- package/dist/ui/switch.d.ts +9 -2
- package/dist/upload-BbGW6A_u.js +1 -0
- package/dist/url-scheme-policy-DHpoTJwB.js +1 -0
- package/dist/use-card-resolution-CJW4grFa.js +1 -0
- package/dist/{variant-aurora-DwSOfraQ.js → variant-aurora-BUOVgPOB.js} +27 -27
- package/dist/{variant-aurora-wKvAQ5wp.js → variant-aurora-CUsUJvFI.js} +28 -28
- package/dist/{variant-aurora-XEkPT0_z.js → variant-aurora-CW2i4bfr.js} +2 -2
- package/dist/{elements/chunks/variant-aurora-QXTZPyST.js → variant-aurora-xiMPty8f.js} +2 -2
- package/dist/variant-custom-BQtOnmeO.js +1 -0
- package/dist/{variant-custom-BhS9wIpU.js → variant-custom-CAm9L-E5.js} +65 -65
- package/dist/{variant-custom-eFIg2XWQ.js → variant-custom-CAnzzppW.js} +40 -40
- package/dist/variant-custom-D91HjAKz.js +1 -0
- package/dist/{variant-wave-CUWGx9Bn.js → variant-wave-Ca1Ls4_y.js} +21 -21
- package/dist/{variant-wave-CbVsmgwT.js → variant-wave-CxX39DKd.js} +25 -25
- package/dist/{variant-wave-BwzrHD1s.js → variant-wave-DYyzIIZv.js} +2 -2
- package/dist/{elements/chunks/variant-wave-DDCwhLas.js → variant-wave-uY5crU_K.js} +2 -2
- package/dist/vue-BmIZj4XD.js +1 -33
- package/dist/wire/chunk.d.ts +47 -0
- package/dist/wire/diagnostics.d.ts +575 -0
- package/dist/wire/encode-probe.d.ts +70 -0
- package/dist/wire/encode.d.ts +24 -0
- package/dist/wire/index.d.ts +2 -0
- package/dist/wire/sse.d.ts +10 -2
- package/dist/wire.js +917 -480
- package/dist/x-C5m1JFgi.js +1 -0
- package/frameworks/react/index.tsx +325 -108
- package/llms-full.txt +1354 -82
- package/llms.txt +6 -3
- package/package.json +39 -6
- package/src/agent-tooling/archetypes.ts +41 -9
- package/src/agent-tooling/catalog/README.md +676 -0
- package/src/agent-tooling/catalog/catalog-types.ts +231 -0
- package/src/agent-tooling/catalog/fabrications.ts +96 -0
- package/src/agent-tooling/catalog/invariants.ts +284 -0
- package/src/agent-tooling/catalog/labs-titles.ts +114 -0
- package/src/agent-tooling/catalog/scenarios.ts +87 -0
- package/src/agent-tooling/catalog/surfaces.ts +347 -0
- package/src/agent-tooling/construct/cli-entry.ts +8 -0
- package/src/agent-tooling/construct/cli.ts +131 -0
- package/src/agent-tooling/construct/codegen.ts +1353 -0
- package/src/agent-tooling/construct/construct.v1.schema.json +250 -0
- package/src/agent-tooling/construct/dev.ts +148 -0
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +23 -0
- package/src/agent-tooling/construct/schema.ts +371 -0
- package/src/agent-tooling/integrations/anthropic.ts +7 -1
- package/src/agent-tooling/integrations/cloudflare.ts +43 -2
- package/src/agent-tooling/integrations/langgraph.ts +7 -1
- package/src/agent-tooling/integrations/mastra.ts +7 -1
- package/src/agent-tooling/integrations/mock.ts +92 -17
- package/src/agent-tooling/integrations/ollama.ts +7 -1
- package/src/agent-tooling/integrations/openai.ts +7 -1
- package/src/agent-tooling/integrations/openrouter.ts +7 -1
- package/src/agent-tooling/integrations/pi.ts +56 -1
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +7 -1
- package/src/agent-tooling/mcp/css-raw.d.ts +12 -0
- package/src/agent-tooling/mcp/manifest.ts +100 -1
- package/src/agent-tooling/mcp/server.ts +63 -6
- package/src/agent-tooling/mcp/tools/construct.ts +130 -0
- package/src/agent-tooling/mcp/tools/debug.ts +126 -4
- package/src/agent-tooling/mcp/tools/reference.ts +542 -5
- package/src/agent-tooling/mcp/tools/scaffold.ts +1834 -307
- package/src/agent-tooling/mcp/tools/theme.ts +146 -30
- package/src/agent-tooling/mcp/validate-args.ts +141 -0
- package/src/agent-tooling/recipes/composed-thread.ts +714 -0
- package/src/agent-tooling/recipes/index.ts +22 -0
- package/src/agent-tooling/recipes/types.ts +32 -0
- package/src/agent-tooling/registry.ts +24 -7
- package/src/agent-tooling/route-emit.ts +26 -2
- package/src/components/attachment-types.ts +54 -1
- package/src/components/attachments.tsx +169 -22
- package/src/components/audio-visualizer/fit-scale.ts +112 -0
- package/src/components/audio-visualizer/index.tsx +80 -3
- package/src/components/audio-visualizer/variant-aurora.tsx +10 -4
- package/src/components/audio-visualizer/variant-bar.tsx +38 -6
- package/src/components/audio-visualizer/variant-custom.tsx +8 -2
- package/src/components/audio-visualizer/variant-grid.tsx +16 -11
- package/src/components/audio-visualizer/variant-radial.tsx +15 -10
- package/src/components/audio-visualizer/variant-wave.tsx +7 -2
- package/src/components/card-renderer.tsx +39 -8
- package/src/components/card.tsx +10 -2
- package/src/components/chat-container.tsx +4 -1
- package/src/components/chat-scope-picker.tsx +2 -2
- package/src/components/chat-thread.tsx +105 -13
- package/src/components/choice-card.tsx +102 -37
- package/src/components/coachmark.tsx +1 -1
- package/src/components/code-block.tsx +81 -5
- package/src/components/composer.tsx +89 -8
- package/src/components/confirm-card.tsx +20 -4
- package/src/components/conversation-item.tsx +138 -4
- package/src/components/conversation-list.tsx +230 -15
- package/src/components/embed.tsx +4 -0
- package/src/components/empty.tsx +14 -3
- package/src/components/file-tree.tsx +5 -1
- package/src/components/form-widgets.tsx +257 -195
- package/src/components/form.tsx +336 -21
- package/src/components/loader.tsx +12 -5
- package/src/components/message-skills.tsx +1 -1
- package/src/components/message.tsx +142 -12
- package/src/components/prompt-input.tsx +7 -1
- package/src/components/prompt-suggestion.tsx +4 -1
- package/src/components/reasoning.tsx +30 -3
- package/src/components/response-compare.tsx +2 -2
- package/src/components/response-stream.tsx +13 -7
- package/src/components/screen.tsx +5 -0
- package/src/components/scroll-button.tsx +63 -4
- package/src/components/source.tsx +6 -1
- package/src/components/tasks-card.tsx +58 -16
- package/src/components/thread.tsx +10 -1
- package/src/components/toast.tsx +11 -5
- package/src/components/tool-types.ts +9 -0
- package/src/components/voice-input.tsx +35 -3
- package/src/components/voice-output.tsx +46 -6
- package/src/components/workspace-shell.tsx +285 -0
- package/src/diagnostics/hook.ts +352 -0
- package/src/diagnostics/index.ts +82 -0
- package/src/diagnostics/report-request.ts +296 -0
- package/src/elements/attachments.tsx +9 -8
- package/src/elements/audio-visualizer.tsx +48 -4
- package/src/elements/chat-workspace.tsx +159 -287
- package/src/elements/chat.tsx +31 -10
- package/src/elements/checkbox-group.tsx +164 -0
- package/src/elements/checkbox.tsx +134 -0
- package/src/elements/code-block.tsx +19 -1
- package/src/elements/command.tsx +4 -1
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +12 -1
- package/src/elements/conversation-item.tsx +120 -0
- package/src/elements/conversation-list.tsx +60 -11
- package/src/elements/default-input.tsx +5 -5
- package/src/elements/define-entry.ts +12 -0
- package/src/elements/define.tsx +168 -8
- package/src/elements/diagnostic-events.ts +114 -0
- package/src/elements/dialog.tsx +47 -0
- package/src/elements/disclosure.ts +34 -12
- package/src/elements/dock.tsx +215 -0
- package/src/elements/dropdown.tsx +123 -0
- package/src/elements/element-data-types.ts +40 -0
- package/src/elements/element-diagnostics.ts +392 -0
- package/src/elements/element-manifest.json +36 -0
- package/src/elements/element-meta.json +1483 -560
- package/src/elements/element-nonscalar.json +185 -0
- package/src/elements/element-types.d.ts +589 -167
- package/src/elements/feedback-bar.tsx +5 -0
- package/src/elements/icon-names.json +29 -0
- package/src/elements/input.tsx +312 -23
- package/src/elements/menu.tsx +13 -0
- package/src/elements/message.tsx +2 -0
- package/src/elements/pane-grid.tsx +111 -0
- package/src/elements/prompt-dock.tsx +2 -1
- package/src/elements/prompt-input.tsx +16 -10
- package/src/elements/radio-group.tsx +129 -0
- package/src/elements/register-impl.ts +52 -0
- package/src/elements/register.ts +28 -0
- package/src/elements/resizable.tsx +52 -25
- package/src/elements/scroll-button.tsx +59 -6
- package/src/elements/select.tsx +165 -0
- package/src/elements/slider.tsx +171 -0
- package/src/elements/slots.ts +108 -13
- package/src/elements/styles.css +119 -9
- package/src/elements/thinking-bar.tsx +16 -7
- package/src/elements/thread.tsx +2 -0
- package/src/elements/toast.tsx +17 -1
- package/src/elements/tool.tsx +26 -5
- package/src/elements/voice-input.tsx +11 -2
- package/src/elements/voice-output.tsx +16 -3
- package/src/index.ts +4 -1
- package/src/primitives/card-data-types.ts +49 -0
- package/src/primitives/card-host.tsx +4 -2
- package/src/primitives/card-routing.ts +7 -56
- package/src/primitives/card-schemas/form.schema.json +21 -1
- package/src/primitives/card-validate.ts +10 -2
- package/src/primitives/chat-config.tsx +33 -6
- package/src/primitives/field-mask.ts +256 -0
- package/src/primitives/field-semantics.ts +115 -0
- package/src/primitives/input-mask.ts +853 -0
- package/src/primitives/toast-store.ts +66 -4
- package/src/primitives/url-scheme-policy.ts +70 -0
- package/src/primitives/use-resize-observer.ts +33 -0
- package/src/primitives/use-speech-recognition.ts +12 -1
- package/src/primitives/use-stick-to-bottom.ts +34 -2
- package/src/primitives/use-text-stream.ts +33 -2
- package/src/remote/provider-runtime.ts +6 -3
- package/src/schemas/index.ts +1 -0
- package/src/schemas/tool-defs.ts +307 -6
- package/src/solid.ts +15 -0
- package/src/state/index.ts +13 -1
- package/src/state/mock.ts +92 -6
- package/src/state/persistence.ts +180 -0
- package/src/state/stream.ts +71 -4
- package/src/state/threads.ts +142 -0
- package/src/types.ts +4 -2
- package/src/ui/agent-card.tsx +2 -2
- package/src/ui/avatar.tsx +1 -1
- package/src/ui/checkbox-group.tsx +153 -0
- package/src/ui/checkbox.tsx +63 -0
- package/src/ui/dialog.tsx +6 -0
- package/src/ui/dock.tsx +584 -0
- package/src/ui/dropdown.tsx +67 -23
- package/src/ui/hover-card.tsx +156 -6
- package/src/ui/icon.tsx +53 -0
- package/src/ui/input.tsx +275 -16
- package/src/ui/kbd.tsx +1 -1
- package/src/ui/nav.tsx +1 -1
- package/src/ui/pane-group.tsx +2 -2
- package/src/ui/radio.tsx +150 -0
- package/src/ui/resizable.tsx +11 -0
- package/src/ui/select.tsx +168 -0
- package/src/ui/slider.tsx +178 -0
- package/src/ui/switch.tsx +49 -18
- package/src/utils/cn.ts +11 -5
- package/src/wire/chunk.ts +47 -0
- package/src/wire/consume.ts +185 -26
- package/src/wire/diagnostics.ts +727 -0
- package/src/wire/encode-probe.ts +214 -0
- package/src/wire/encode.ts +267 -14
- package/src/wire/formats/anthropic.ts +8 -1
- package/src/wire/formats/openai.ts +5 -0
- package/src/wire/index.ts +22 -0
- package/src/wire/read.ts +250 -6
- package/src/wire/sse.ts +16 -3
- package/theme.css +84 -13
- package/dist/elements/chunks/action-icons-DW9muWrY.js +0 -1
- package/dist/elements/chunks/arrow-left-iJVnQmxA.js +0 -1
- package/dist/elements/chunks/artifact-BSuPYFHY.js +0 -1
- package/dist/elements/chunks/attachments-CL6TaqIb.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BuUqQmaO.js +0 -1
- package/dist/elements/chunks/badge-TIMiJFKc.js +0 -1
- package/dist/elements/chunks/bash-InADTalH.js +0 -1
- package/dist/elements/chunks/card-renderer-CSoTL_e1.js +0 -1
- package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
- package/dist/elements/chunks/chat-thread-DxoKaStk.js +0 -1
- package/dist/elements/chunks/check-MdLzbxrm.js +0 -1
- package/dist/elements/chunks/chevron-down-MK7IzDqe.js +0 -1
- package/dist/elements/chunks/chevron-right-C5jXhmtV.js +0 -1
- package/dist/elements/chunks/choice-card-CGMc3kek.js +0 -1
- package/dist/elements/chunks/circle-BG7VkPep.js +0 -1
- package/dist/elements/chunks/circle-check-GqvO2UBs.js +0 -1
- package/dist/elements/chunks/circle-x-mhH7pOK2.js +0 -1
- package/dist/elements/chunks/code-block-ClhQO9RW.js +0 -1
- package/dist/elements/chunks/collapsible-DBcBkFPh.js +0 -1
- package/dist/elements/chunks/composer-CZZmtYOT.js +0 -69
- package/dist/elements/chunks/confirm-card-BWjf2-xo.js +0 -1
- package/dist/elements/chunks/context-hKjNqiyQ.js +0 -1
- package/dist/elements/chunks/conversation-list-CsGJjSKG.js +0 -1
- package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
- package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
- package/dist/elements/chunks/default-input-B1Mem5wu.js +0 -1
- package/dist/elements/chunks/define-B_tXMYRm.js +0 -1
- package/dist/elements/chunks/disclosure-DAoYOKew.js +0 -1
- package/dist/elements/chunks/download-DnCyWFJE.js +0 -1
- package/dist/elements/chunks/dropdown-CmNna5lT.js +0 -1
- package/dist/elements/chunks/embed-CjAD2jSi.js +0 -1
- package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
- package/dist/elements/chunks/file-text-D0J9F6M7.js +0 -1
- package/dist/elements/chunks/folder-NV1pi_ud.js +0 -1
- package/dist/elements/chunks/form-Cp8Y00Wn.js +0 -1
- package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
- package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
- package/dist/elements/chunks/hover-card-6KtXpLwT.js +0 -1
- package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
- package/dist/elements/chunks/icon-97R8SR2p.js +0 -1
- package/dist/elements/chunks/info-C8r5Q6cc.js +0 -1
- package/dist/elements/chunks/input-DrseEjhp.js +0 -1
- package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
- package/dist/elements/chunks/json-DxJze_jm.js +0 -1
- package/dist/elements/chunks/kbd-OGJDUT-O.js +0 -1
- package/dist/elements/chunks/link-BdsfLB7b.js +0 -1
- package/dist/elements/chunks/loader-B5QzK_8_.js +0 -1
- package/dist/elements/chunks/message-CE4k-qaj.js +0 -1
- package/dist/elements/chunks/message-DtXKPqiR.js +0 -1
- package/dist/elements/chunks/message-square-C9ovmtOo.js +0 -1
- package/dist/elements/chunks/paperclip-Bg0ITU3b.js +0 -1
- package/dist/elements/chunks/progress-bar-D1_rzt6N.js +0 -1
- package/dist/elements/chunks/prompt-suggestion-D5Sm8xF1.js +0 -1
- package/dist/elements/chunks/reasoning-BrxQfpfI.js +0 -1
- package/dist/elements/chunks/rotate-cw-DzVDJOA1.js +0 -1
- package/dist/elements/chunks/scroll-area-93A1bbeG.js +0 -1
- package/dist/elements/chunks/scroll-button-CrTo7wm4.js +0 -1
- package/dist/elements/chunks/share-DgNbkJKY.js +0 -1
- package/dist/elements/chunks/slots-CIw9RlAe.js +0 -1
- package/dist/elements/chunks/source-w9V0NnBn.js +0 -1
- package/dist/elements/chunks/star-DHvACxtm.js +0 -1
- package/dist/elements/chunks/store-HIPGhNz9.js +0 -1
- package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
- package/dist/elements/chunks/tasks-card-lPxoodlA.js +0 -1
- package/dist/elements/chunks/text-shimmer-BY_rI3s5.js +0 -1
- package/dist/elements/chunks/textarea-DPfuhswM.js +0 -1
- package/dist/elements/chunks/toast-store-VUZZBhzH.js +0 -1
- package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
- package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
- package/dist/elements/chunks/use-card-resolution-DJg32jGH.js +0 -1
- package/dist/elements/chunks/variant-custom-D5ZlmziF.js +0 -1
- package/dist/elements/chunks/video-Bb86fVYI.js +0 -1
- package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
- package/dist/elements/chunks/x-BOhjBeOd.js +0 -1
- package/dist/llms/llms-full.txt +0 -2834
- package/dist/llms/llms.txt +0 -156
- package/dist/primitives/card-validate-generator.testlib.d.ts +0 -20
- package/dist/register-impl-DGmGzrEM.js +0 -145
- package/dist/ui/stat.d.ts +0 -16
- package/dist/variant-custom-MkTNTycd.js +0 -1
- package/src/primitives/card-validate-generator.testlib.ts +0 -38
- package/src/ui/stat.tsx +0 -41
- /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
- /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
package/src/ui/dropdown.tsx
CHANGED
|
@@ -37,6 +37,63 @@ const useDropdown = () => {
|
|
|
37
37
|
// a parent's querySelectorAll scoped to its own menu never reaches sub items.
|
|
38
38
|
const ITEM_SELECTOR = '[role="menuitem"]:not([aria-disabled="true"]), [role="menuitemcheckbox"]:not([aria-disabled="true"]), [role="menuitemradio"]:not([aria-disabled="true"])';
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* The roving-focus set, in FLAT-TREE order.
|
|
42
|
+
*
|
|
43
|
+
* ★ NOT `querySelectorAll`, and the difference is the whole point: a `<slot>` in the
|
|
44
|
+
* shadow tree contains NONE of the light-DOM nodes it projects, so a plain query
|
|
45
|
+
* returns zero items for any facade whose rows are SLOTTED (`<kai-dropdown>`) and
|
|
46
|
+
* ArrowUp/Down, Home/End and typeahead all reach nothing. The items-tree facades
|
|
47
|
+
* (`kai-menu`, `kai-model-switcher`, `kai-scope-picker`) render their rows INTO the
|
|
48
|
+
* shadow tree, so both spellings agree for them — which is exactly why this went
|
|
49
|
+
* unnoticed until a slotted menu body existed.
|
|
50
|
+
*
|
|
51
|
+
* Same class as `hasFocusableChild` in ./hover-card.tsx, which asks the boolean
|
|
52
|
+
* version of this question. This one needs the ORDER as well, so it walks the tree
|
|
53
|
+
* and splices each slot's assigned elements in AT THE SLOT'S POSITION rather than
|
|
54
|
+
* appending them; a menu may mix rendered and slotted rows. `flatten: true` follows
|
|
55
|
+
* a slot assigned to another slot.
|
|
56
|
+
*
|
|
57
|
+
* Scope is unchanged: submenu content is portaled to a SIBLING node, so a parent's
|
|
58
|
+
* walk still never reaches sub items.
|
|
59
|
+
*/
|
|
60
|
+
function menuItems(root: HTMLElement | undefined): HTMLElement[] {
|
|
61
|
+
if (!root) return [];
|
|
62
|
+
const out: HTMLElement[] = [];
|
|
63
|
+
const collect = (el: Element): void => {
|
|
64
|
+
if (el.matches(ITEM_SELECTOR)) out.push(el as HTMLElement);
|
|
65
|
+
for (const child of Array.from(el.children)) visit(child);
|
|
66
|
+
};
|
|
67
|
+
const visit = (el: Element): void => {
|
|
68
|
+
if (el.localName === 'slot') {
|
|
69
|
+
for (const assigned of (el as HTMLSlotElement).assignedElements({ flatten: true })) collect(assigned);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
collect(el);
|
|
73
|
+
};
|
|
74
|
+
for (const child of Array.from(root.children)) visit(child);
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The first roving-focus item, in flat-tree order. Replaces
|
|
79
|
+
* `querySelector(ITEM_SELECTOR)` for the reason `menuItems` replaces the `All`. */
|
|
80
|
+
const firstMenuItem = (root: HTMLElement | undefined): HTMLElement | undefined => menuItems(root)[0];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The focused item, resolved across BOTH trees.
|
|
84
|
+
*
|
|
85
|
+
* Inside a Shadow DOM `document.activeElement` returns the HOST rather than the
|
|
86
|
+
* focused menu item, so the menu's own root node is asked first. But a SLOTTED row
|
|
87
|
+
* lives in the LIGHT DOM: focus is then outside the shadow tree, that root reports
|
|
88
|
+
* null, and the document's answer is the real one. Asking only the shadow root would
|
|
89
|
+
* leave `currentIndex()` at -1 for every slotted row, so ArrowDown would restart at
|
|
90
|
+
* the top instead of advancing.
|
|
91
|
+
*/
|
|
92
|
+
function activeMenuItem(root: HTMLElement | undefined): Element | null {
|
|
93
|
+
const tree = root?.getRootNode() as Document | ShadowRoot | undefined;
|
|
94
|
+
return (tree?.activeElement ?? document.activeElement) as Element | null;
|
|
95
|
+
}
|
|
96
|
+
|
|
40
97
|
/** Imperative open controller, handed to a parent (e.g. the kai-menu facade) via
|
|
41
98
|
* `controllerRef` so it can drive/observe the Dropdown's open state. */
|
|
42
99
|
export interface DropdownController { open: Accessor<boolean>; setOpen: (v: boolean) => void; }
|
|
@@ -103,8 +160,8 @@ export function Dropdown(props: DropdownProps) {
|
|
|
103
160
|
// attempt focus now and re-assert in the menu ref's microtask so it lands
|
|
104
161
|
// once the node exists. Skip disabled items (roving-focus contract).
|
|
105
162
|
if (opts?.viaKeyboard) {
|
|
106
|
-
queueMicrotask(() => menu()
|
|
107
|
-
menu()
|
|
163
|
+
queueMicrotask(() => firstMenuItem(menu())?.focus());
|
|
164
|
+
firstMenuItem(menu())?.focus();
|
|
108
165
|
}
|
|
109
166
|
} else if (opts?.returnFocus !== false) {
|
|
110
167
|
// Closing via keyboard/select: return focus to the trigger. The menu
|
|
@@ -179,23 +236,14 @@ export function DropdownContent(props: DropdownContentProps) {
|
|
|
179
236
|
refs: () => [ctx.trigger(), ctx.menu(), ...ctx.subMenus()],
|
|
180
237
|
});
|
|
181
238
|
|
|
182
|
-
const items = () =>
|
|
239
|
+
const items = () => menuItems(ctx.menu());
|
|
183
240
|
const focusIndex = (i: number) => {
|
|
184
241
|
const list = items();
|
|
185
242
|
if (!list.length) return;
|
|
186
243
|
const idx = ((i % list.length) + list.length) % list.length;
|
|
187
244
|
list[idx].focus();
|
|
188
245
|
};
|
|
189
|
-
|
|
190
|
-
// (every kitn-* element), `document.activeElement` returns the host element,
|
|
191
|
-
// not the focused menu item, which would break ArrowUp/Down roving focus.
|
|
192
|
-
// `getRootNode().activeElement` correctly returns the active node within the
|
|
193
|
-
// same tree (ShadowRoot or Document).
|
|
194
|
-
const activeItem = () => {
|
|
195
|
-
const root = ctx.menu()?.getRootNode() as Document | ShadowRoot | undefined;
|
|
196
|
-
return (root?.activeElement ?? document.activeElement) as Element | null;
|
|
197
|
-
};
|
|
198
|
-
const currentIndex = () => items().findIndex((el) => el === activeItem());
|
|
246
|
+
const currentIndex = () => items().findIndex((el) => el === activeMenuItem(ctx.menu()));
|
|
199
247
|
|
|
200
248
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
201
249
|
const list = items();
|
|
@@ -226,7 +274,7 @@ export function DropdownContent(props: DropdownContentProps) {
|
|
|
226
274
|
// synchronously; this ref-time microtask re-asserts focus once the
|
|
227
275
|
// menu node exists. Skip disabled items.
|
|
228
276
|
if (ctx.openedViaKeyboard()) {
|
|
229
|
-
queueMicrotask(() => el
|
|
277
|
+
queueMicrotask(() => firstMenuItem(el)?.focus());
|
|
230
278
|
}
|
|
231
279
|
}}
|
|
232
280
|
id={ctx.menuId}
|
|
@@ -424,8 +472,8 @@ export function DropdownSub(props: DropdownSubProps) {
|
|
|
424
472
|
setOpenSig(v);
|
|
425
473
|
if (v) {
|
|
426
474
|
if (opts?.viaKeyboard) {
|
|
427
|
-
queueMicrotask(() => menu()
|
|
428
|
-
menu()
|
|
475
|
+
queueMicrotask(() => firstMenuItem(menu())?.focus());
|
|
476
|
+
firstMenuItem(menu())?.focus();
|
|
429
477
|
}
|
|
430
478
|
} else if (opts?.returnFocus !== false) {
|
|
431
479
|
const el = trigger();
|
|
@@ -516,18 +564,14 @@ export function DropdownSubContent(props: DropdownSubContentProps) {
|
|
|
516
564
|
// useDismiss here would double-fire Escape because document listeners run
|
|
517
565
|
// after stopPropagation on the element, not on the document.
|
|
518
566
|
|
|
519
|
-
const items = () =>
|
|
567
|
+
const items = () => menuItems(sub.menu());
|
|
520
568
|
const focusIndex = (i: number) => {
|
|
521
569
|
const list = items();
|
|
522
570
|
if (!list.length) return;
|
|
523
571
|
const idx = ((i % list.length) + list.length) % list.length;
|
|
524
572
|
list[idx].focus();
|
|
525
573
|
};
|
|
526
|
-
const
|
|
527
|
-
const root = sub.menu()?.getRootNode() as Document | ShadowRoot | undefined;
|
|
528
|
-
return (root?.activeElement ?? document.activeElement) as Element | null;
|
|
529
|
-
};
|
|
530
|
-
const currentIndex = () => items().findIndex((el) => el === activeItem());
|
|
574
|
+
const currentIndex = () => items().findIndex((el) => el === activeMenuItem(sub.menu()));
|
|
531
575
|
|
|
532
576
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
533
577
|
const list = items();
|
|
@@ -559,7 +603,7 @@ export function DropdownSubContent(props: DropdownSubContentProps) {
|
|
|
559
603
|
const unregister = parent.registerSubMenu(el);
|
|
560
604
|
onCleanup(unregister);
|
|
561
605
|
if (sub.openedViaKeyboard()) {
|
|
562
|
-
queueMicrotask(() => el
|
|
606
|
+
queueMicrotask(() => firstMenuItem(el)?.focus());
|
|
563
607
|
}
|
|
564
608
|
}}
|
|
565
609
|
id={sub.menuId}
|
package/src/ui/hover-card.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createContext, useContext, createSignal, Show, splitProps, onCleanup,
|
|
2
|
+
createContext, useContext, createSignal, createUniqueId, Show, splitProps, onCleanup,
|
|
3
3
|
type JSX, type Accessor,
|
|
4
4
|
} from 'solid-js';
|
|
5
5
|
import { Portal } from 'solid-js/web';
|
|
@@ -17,6 +17,12 @@ interface HoverCardCtx {
|
|
|
17
17
|
setContent: (el: HTMLElement) => void;
|
|
18
18
|
trigger: Accessor<HTMLElement | undefined>;
|
|
19
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>;
|
|
20
26
|
}
|
|
21
27
|
const Ctx = createContext<HoverCardCtx>();
|
|
22
28
|
const useHoverCard = () => {
|
|
@@ -45,6 +51,7 @@ export function HoverCardRoot(props: HoverCardRootProps) {
|
|
|
45
51
|
const [open, setOpen] = createSignal(props.defaultOpen ?? false);
|
|
46
52
|
const [trigger, setTrigger] = createSignal<HTMLElement>();
|
|
47
53
|
const [content, setContent] = createSignal<HTMLElement>();
|
|
54
|
+
const contentId = createUniqueId();
|
|
48
55
|
let timer: number | undefined;
|
|
49
56
|
props.controllerRef?.({ open, setOpen });
|
|
50
57
|
|
|
@@ -73,25 +80,167 @@ export function HoverCardRoot(props: HoverCardRootProps) {
|
|
|
73
80
|
open, enter, leave, close,
|
|
74
81
|
setTrigger, setContent,
|
|
75
82
|
trigger, content,
|
|
83
|
+
contentId,
|
|
84
|
+
disabled: () => props.disabled ?? false,
|
|
76
85
|
}}>
|
|
77
86
|
{props.children}
|
|
78
87
|
</Ctx.Provider>
|
|
79
88
|
);
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
export interface HoverCardTriggerProps {
|
|
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
|
+
};
|
|
83
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
|
+
*/
|
|
84
170
|
export function HoverCardTrigger(props: HoverCardTriggerProps) {
|
|
85
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
|
+
|
|
86
180
|
return (
|
|
87
181
|
<As
|
|
88
182
|
as="span"
|
|
89
|
-
class={cn(
|
|
90
|
-
|
|
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}
|
|
91
242
|
onPointerEnter={ctx.enter}
|
|
92
243
|
onPointerLeave={ctx.leave}
|
|
93
|
-
onFocusIn={ctx.enter}
|
|
94
|
-
onFocusOut={ctx.leave}
|
|
95
244
|
>
|
|
96
245
|
{props.children}
|
|
97
246
|
</As>
|
|
@@ -166,6 +315,7 @@ export function HoverCardContent(props: HoverCardContentProps) {
|
|
|
166
315
|
>
|
|
167
316
|
{/* Inner card: all visual + animation classes and the presence state. */}
|
|
168
317
|
<div
|
|
318
|
+
id={ctx.contentId}
|
|
169
319
|
data-expanded={presence.state() === 'open' ? '' : undefined}
|
|
170
320
|
data-closed={presence.state() === 'closed' ? '' : undefined}
|
|
171
321
|
class={cn(
|
package/src/ui/icon.tsx
CHANGED
|
@@ -9,6 +9,16 @@ import {
|
|
|
9
9
|
Archive, ArrowUp, Bookmark, Copy, Ellipsis, ExternalLink, Flag,
|
|
10
10
|
GitBranch, GitPullRequest, ListFilter, RotateCw,
|
|
11
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,
|
|
12
22
|
} from 'lucide-solid';
|
|
13
23
|
|
|
14
24
|
type IconComponent = Component<{ class?: string }>;
|
|
@@ -68,8 +78,51 @@ const NAMED_ICONS: Record<string, IconComponent> = {
|
|
|
68
78
|
// Theme / appearance glyphs.
|
|
69
79
|
moon: Moon,
|
|
70
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,
|
|
71
120
|
};
|
|
72
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
|
+
|
|
73
126
|
/** Render an item icon.
|
|
74
127
|
*
|
|
75
128
|
* Resolution order:
|