@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
|
@@ -54,7 +54,10 @@ interface Props extends Record<string, unknown> {
|
|
|
54
54
|
|
|
55
55
|
/** Events fired by `<kai-composer>`. */
|
|
56
56
|
interface Events {
|
|
57
|
-
/** The user submitted the composer (Enter or programmatic submit).
|
|
57
|
+
/** The user submitted the composer (Enter or programmatic submit). Note the
|
|
58
|
+
* detail carries no `attachments`; `<kai-composer>` is the bare editing
|
|
59
|
+
* surface: no send button, toolbar, or attachments. For a drop-in composer
|
|
60
|
+
* row with all three, reach for `<kai-prompt-input>`, which is built on this. */
|
|
58
61
|
'kai-submit': { doc: ComposerDoc; text: string; entities: EntityRef[] };
|
|
59
62
|
/** The content changed (fires on every input event). */
|
|
60
63
|
'kai-value-change': { doc: ComposerDoc; text: string; entities: EntityRef[] };
|
|
@@ -75,6 +78,14 @@ interface Events {
|
|
|
75
78
|
'kai-blur': { originalEvent: FocusEvent };
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
/**
|
|
82
|
+
* `<kai-composer>` — the bare editing surface: rich text, entity pills,
|
|
83
|
+
* trigger menus, Enter-to-submit, and nothing else. No send button, no
|
|
84
|
+
* toolbar, no attachments — that division is deliberate. For a drop-in chat
|
|
85
|
+
* composer with a send button, toolbar, and attachment staging, reach for
|
|
86
|
+
* `<kai-prompt-input>`, which is built on this element. Keep `<kai-composer>`
|
|
87
|
+
* when you are composing the input row yourself and want to own those pieces.
|
|
88
|
+
*/
|
|
78
89
|
defineWebComponent<Props, Events>('kai-composer', {
|
|
79
90
|
value: undefined,
|
|
80
91
|
placeholder: undefined,
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { readSlots, CONVERSATION_ITEM_SLOTS } from './slots';
|
|
4
|
+
import { SlottedConversationItem } from '../components/conversation-item';
|
|
5
|
+
import { isStandaloneConversationItem, readConversationItemId } from '../components/conversation-list';
|
|
6
|
+
|
|
7
|
+
interface Props extends Record<string, unknown> {
|
|
8
|
+
/** The row's identity: the `conversation-id` attribute (host `id` is the
|
|
9
|
+
* fallback). Inside `<kai-conversations>` it is handed to the container's
|
|
10
|
+
* selection contract (`kai-conversation-select`); standalone it is the `id`
|
|
11
|
+
* in this element's own `kai-select` detail. */
|
|
12
|
+
conversationId?: string;
|
|
13
|
+
/** Selected state. Reflected as `aria-current` on the row body and a
|
|
14
|
+
* `data-active` styling hook on the row; inside a container the container
|
|
15
|
+
* drives it from its `activeId`, standalone you set it yourself. */
|
|
16
|
+
active?: boolean;
|
|
17
|
+
/** Dense single-line row padding. */
|
|
18
|
+
compact?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Events {
|
|
22
|
+
/** STANDALONE activation only: the row was activated (click, Enter or Space on its body) while the item is NOT a
|
|
23
|
+
* direct child of `<kai-conversations>`. `id` is the row's identity: the
|
|
24
|
+
* `conversation-id` attribute, else the host `id`. Inside a container this
|
|
25
|
+
* never fires: activation surfaces once, as `kai-conversation-select` on the
|
|
26
|
+
* container. */
|
|
27
|
+
'kai-select': { id: string };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `<kai-conversation-item>` — one composed row of a consumer-owned conversation
|
|
32
|
+
* loop. Two placements, one activation event each:
|
|
33
|
+
*
|
|
34
|
+
* SLOTTED into `<kai-conversations>`' light DOM (a direct child): the consumer
|
|
35
|
+
* owns the loop (framework-native `map`, `<For>`, `v-for`); the container
|
|
36
|
+
* detects these children, skips its data rendering, and runs the parent-item
|
|
37
|
+
* contract over them — selection state flowing container to item, roving
|
|
38
|
+
* tabindex, arrow-key traversal, and the accessible list/row relationship
|
|
39
|
+
* (list rows with button bodies and `aria-current` marking the active one;
|
|
40
|
+
* axe's nested-interactive and aria-required-children
|
|
41
|
+
* rules are why this is not listbox/option). Activation (click, Enter, Space)
|
|
42
|
+
* surfaces as `kai-conversation-select` on the container, and the item itself
|
|
43
|
+
* fires nothing — no double event.
|
|
44
|
+
*
|
|
45
|
+
* STANDALONE (anywhere else — a hand-composed rail, or wrapped in another
|
|
46
|
+
* element even inside a container, since the container manages only direct
|
|
47
|
+
* children): the row activates ITSELF.
|
|
48
|
+
* Its shadow body is a tabbable `role="button"`, and click / Enter / Space
|
|
49
|
+
* fire `kai-select` on this element with `{ id }` — non-bubbling, like every
|
|
50
|
+
* `kai-*` event, so listen on the item itself. What a standalone row does NOT
|
|
51
|
+
* have is the container's LIST story: roving tabindex across rows, arrow-key
|
|
52
|
+
* traversal, and the shared `role="list"` relationship — each standalone row
|
|
53
|
+
* is an ordinary tab stop, and a hand-composed rail brings its own list
|
|
54
|
+
* semantics (or slots the rows into `<kai-conversations>` and gets them for
|
|
55
|
+
* free).
|
|
56
|
+
*
|
|
57
|
+
* Slots: the default slot is the title; `leading`, `meta` and `menu` are the
|
|
58
|
+
* named regions. The `menu` slot takes your OWN popover (rename, fork, archive
|
|
59
|
+
* live there); the element provides only the region plus focus and ARIA
|
|
60
|
+
* plumbing, never a declarative actions prop, and a click inside it never
|
|
61
|
+
* selects the row — in either placement.
|
|
62
|
+
*/
|
|
63
|
+
defineWebComponent<Props, Events>('kai-conversation-item', {
|
|
64
|
+
conversationId: undefined,
|
|
65
|
+
active: undefined,
|
|
66
|
+
compact: undefined,
|
|
67
|
+
}, (props, { element, flag, reflectFlag, dispatch }) => {
|
|
68
|
+
// Which named regions the consumer has filled; drives the conditional
|
|
69
|
+
// wrappers so an empty region leaves no stray box behind.
|
|
70
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
71
|
+
// Standalone vs container-managed, decided at mount (an item is not
|
|
72
|
+
// reparented in practice; the activation handler re-checks at event time so
|
|
73
|
+
// a row moved INTO a container can never double-fire).
|
|
74
|
+
const [standalone, setStandalone] = createSignal(false);
|
|
75
|
+
onMount(() => {
|
|
76
|
+
const read = () => setSlots(readSlots(element, CONVERSATION_ITEM_SLOTS));
|
|
77
|
+
read();
|
|
78
|
+
const observer = new MutationObserver(read);
|
|
79
|
+
observer.observe(element, { childList: true, attributes: true, subtree: true });
|
|
80
|
+
onCleanup(() => observer.disconnect());
|
|
81
|
+
|
|
82
|
+
// The HOST is the row LISTITEM:
|
|
83
|
+
// it wraps the activation body AND the consumer's tabbable menu, so it must
|
|
84
|
+
// never be the activation control itself — axe nested-interactive bans
|
|
85
|
+
// focusable descendants of a control. The button role, aria-current and the
|
|
86
|
+
// tabindex live on the shadow BODY (`data-kai-item-body`): inside a
|
|
87
|
+
// container its controller stamps them; standalone the component renders
|
|
88
|
+
// them itself. An authored role wins.
|
|
89
|
+
if (!element.hasAttribute('role')) element.setAttribute('role', 'listitem');
|
|
90
|
+
|
|
91
|
+
setStandalone(isStandaloneConversationItem(element));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Standalone activation → the per-item `kai-select` event. The re-check at
|
|
95
|
+
// event time keeps this dead the moment the item becomes a container's direct
|
|
96
|
+
// child, so the container's `kai-conversation-select` stays the only event.
|
|
97
|
+
const activate = () => {
|
|
98
|
+
if (!isStandaloneConversationItem(element)) return;
|
|
99
|
+
dispatch('kai-select', { id: readConversationItemId(element) });
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Property and attribute stay in agreement for `active`; the body's
|
|
103
|
+
// aria-current follows it reactively (nothing is written to the host).
|
|
104
|
+
reflectFlag('active');
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<SlottedConversationItem
|
|
108
|
+
conversationId={props.conversationId as string | undefined}
|
|
109
|
+
active={flag('active')}
|
|
110
|
+
compact={flag('compact')}
|
|
111
|
+
hostSemantics
|
|
112
|
+
onActivate={standalone() ? activate : undefined}
|
|
113
|
+
leading={slots().leading ? <slot name="leading" /> : undefined}
|
|
114
|
+
meta={slots().meta ? <slot name="meta" /> : undefined}
|
|
115
|
+
menu={slots().menu ? <slot name="menu" /> : undefined}
|
|
116
|
+
>
|
|
117
|
+
<slot />
|
|
118
|
+
</SlottedConversationItem>
|
|
119
|
+
);
|
|
120
|
+
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { createSignal, onMount, onCleanup, Show } from 'solid-js';
|
|
1
|
+
import { createSignal, createEffect, onMount, onCleanup, Show } from 'solid-js';
|
|
2
2
|
import { defineWebComponent } from './define';
|
|
3
3
|
import { createControllableSignal } from '../primitives/controllable';
|
|
4
4
|
import { readSlots, CONVERSATIONS_SLOTS } from './slots';
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
ConversationList, CollapsedRail, createConversationItemsController,
|
|
7
|
+
type ConversationListController,
|
|
8
|
+
} from '../components/conversation-list';
|
|
9
|
+
import type { ConversationGroup, ConversationSummary } from '../types';
|
|
7
10
|
|
|
8
11
|
interface Props extends Record<string, unknown> {
|
|
9
12
|
/** The list's section headers (`{ id, name, sortOrder, createdAt }`), rendered
|
|
@@ -16,7 +19,11 @@ interface Props extends Record<string, unknown> {
|
|
|
16
19
|
* matching no entry in `groups`, falls into a trailing "Ungrouped" section, so
|
|
17
20
|
* nothing you pass in is ever dropped. There is no recency bucketing. Set as a
|
|
18
21
|
* JS property. Omit to supply them as `<kai-conversation>` light-DOM children
|
|
19
|
-
* instead, or for the empty state.
|
|
22
|
+
* instead, or for the empty state. A search query that matches nothing shows a
|
|
23
|
+
* visible "No conversations match your search" state, distinct from the
|
|
24
|
+
* zero-conversations empty state. Slotted `<kai-conversation-item>` children
|
|
25
|
+
* switch the list into item mode instead: your own rows win and this array is
|
|
26
|
+
* not rendered. */
|
|
20
27
|
conversations?: ConversationSummary[];
|
|
21
28
|
/** The id of the currently-open conversation, highlighted in the list. */
|
|
22
29
|
activeId?: string;
|
|
@@ -28,10 +35,14 @@ interface Props extends Record<string, unknown> {
|
|
|
28
35
|
/** Initial collapsed state when uncontrolled (default false). Use the
|
|
29
36
|
* `default-collapsed` attribute to start collapsed in plain HTML. */
|
|
30
37
|
defaultCollapsed?: boolean;
|
|
38
|
+
/** Dense single-line rows (a leading dot + title, no message count). */
|
|
39
|
+
compact?: boolean;
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
interface Events {
|
|
34
|
-
/** A conversation was selected.
|
|
43
|
+
/** A conversation was selected. The selection event in BOTH modes: a
|
|
44
|
+
* batteries data row, or an activated `<kai-conversation-item>` child
|
|
45
|
+
* (click, Enter or Space). */
|
|
35
46
|
'kai-conversation-select': { id: string };
|
|
36
47
|
/** The "New chat" button was clicked. */
|
|
37
48
|
'kai-new-chat': Record<string, never>;
|
|
@@ -50,19 +61,19 @@ interface Events {
|
|
|
50
61
|
* - `id` → ConversationSummary.id
|
|
51
62
|
* - `group-id` → ConversationSummary.groupId (optional)
|
|
52
63
|
* - textContent → ConversationSummary.title
|
|
53
|
-
*
|
|
54
|
-
* `
|
|
55
|
-
*
|
|
64
|
+
* Fields not expressible as HTML attributes are NOT fabricated: the
|
|
65
|
+
* optional `scope` and `lastMessageAt` stay absent, and the required
|
|
66
|
+
* `messageCount`/`updatedAt` get honest defaults — zero messages, and an empty
|
|
67
|
+
* `updatedAt` from which no trailing relative time is derived (the epoch it
|
|
68
|
+
* used to fabricate rendered a bogus "many days ago" on every declarative row).
|
|
56
69
|
*/
|
|
57
70
|
export function parseKaiConversationElement(n: Element): ConversationSummary {
|
|
58
71
|
return {
|
|
59
72
|
id: n.getAttribute('id') ?? '',
|
|
60
73
|
title: n.textContent?.trim() ?? '',
|
|
61
74
|
groupId: n.getAttribute('group-id') ?? undefined,
|
|
62
|
-
scope: { type: 'collection' } as ConversationScope,
|
|
63
75
|
messageCount: 0,
|
|
64
|
-
|
|
65
|
-
updatedAt: new Date(0).toISOString(),
|
|
76
|
+
updatedAt: '',
|
|
66
77
|
};
|
|
67
78
|
}
|
|
68
79
|
|
|
@@ -72,17 +83,34 @@ defineWebComponent<Props, Events>('kai-conversations', {
|
|
|
72
83
|
activeId: undefined,
|
|
73
84
|
collapsed: undefined,
|
|
74
85
|
defaultCollapsed: undefined,
|
|
86
|
+
compact: undefined,
|
|
75
87
|
}, (props, { dispatch, element, expose, flag }) => {
|
|
76
88
|
// Read declarative <kai-conversation> children from light DOM.
|
|
77
89
|
// Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
|
|
78
90
|
const [slottedConversations, setSlottedConversations] = createSignal<ConversationSummary[]>([]);
|
|
91
|
+
// Item mode: light-DOM <kai-conversation-item> children
|
|
92
|
+
// mean the CONSUMER owns the loop — the container skips its data rendering and
|
|
93
|
+
// runs the parent-item contract over the hosts instead.
|
|
94
|
+
const [itemHosts, setItemHosts] = createSignal<HTMLElement[]>([]);
|
|
79
95
|
// Which composition slots (header/empty/footer) the consumer has filled.
|
|
80
96
|
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
81
97
|
onMount(() => {
|
|
82
98
|
const read = () => {
|
|
83
99
|
const nodes = [...element.querySelectorAll('kai-conversation')];
|
|
84
100
|
setSlottedConversations(nodes.map(parseKaiConversationElement));
|
|
101
|
+
// Reference-stable: a fresh array every observer tick would re-run the
|
|
102
|
+
// sync effect (whose writes the observer sees) in a feedback loop.
|
|
103
|
+
const hosts = [...element.querySelectorAll<HTMLElement>(':scope > kai-conversation-item')];
|
|
104
|
+
setItemHosts((prev) =>
|
|
105
|
+
prev.length === hosts.length && hosts.every((h, i) => h === prev[i]) ? prev : hosts,
|
|
106
|
+
);
|
|
85
107
|
setSlots(readSlots(element, CONVERSATIONS_SLOTS));
|
|
108
|
+
// Re-sync on EVERY mutation, not only membership changes: an item host
|
|
109
|
+
// that upgrades after the first sync mutates its own attributes (the
|
|
110
|
+
// facade's mount), which lands here — and its shadow body needs stamping
|
|
111
|
+
// even though the hosts array is reference-stable. sync() writes
|
|
112
|
+
// on-change only, so this cannot feed the observer a loop.
|
|
113
|
+
if (hosts.length) itemsController.sync();
|
|
86
114
|
};
|
|
87
115
|
read();
|
|
88
116
|
const observer = new MutationObserver(read);
|
|
@@ -90,9 +118,26 @@ defineWebComponent<Props, Events>('kai-conversations', {
|
|
|
90
118
|
onCleanup(() => observer.disconnect());
|
|
91
119
|
});
|
|
92
120
|
|
|
121
|
+
const itemMode = () => itemHosts().length > 0;
|
|
122
|
+
|
|
93
123
|
// Prop conversations take precedence; slotted children are appended after.
|
|
94
124
|
const allConversations = () => [...(props.conversations ?? []), ...slottedConversations()];
|
|
95
125
|
|
|
126
|
+
// The parent-item contract: selection flowing container→item, roving tabindex,
|
|
127
|
+
// ARIA list-row bookkeeping — pure DOM, host-agnostic (see the controller's JSDoc in
|
|
128
|
+
// components/conversation-list.tsx). Solid context cannot cross the element
|
|
129
|
+
// boundary, so the channel is DOM traversal by construction.
|
|
130
|
+
const itemsController = createConversationItemsController({
|
|
131
|
+
getItems: itemHosts,
|
|
132
|
+
getActiveId: () => props.activeId as string | undefined,
|
|
133
|
+
onSelect: (id) => dispatch('kai-conversation-select', { id }),
|
|
134
|
+
});
|
|
135
|
+
// Re-derive the bookkeeping whenever the children change (the MutationObserver
|
|
136
|
+
// and the shadow slot's slotchange both funnel into itemHosts) or activeId moves.
|
|
137
|
+
createEffect(() => {
|
|
138
|
+
if (itemMode()) itemsController.sync();
|
|
139
|
+
});
|
|
140
|
+
|
|
96
141
|
// ── Rail collapse (controlled/uncontrolled, same pattern as kai-workspace) ──
|
|
97
142
|
// `collapsed` (when set) wins; otherwise the element manages its own state,
|
|
98
143
|
// seeded from `defaultCollapsed`. `setCollapsedTo` always writes the internal
|
|
@@ -143,8 +188,12 @@ defineWebComponent<Props, Events>('kai-conversations', {
|
|
|
143
188
|
onSelect={(id) => dispatch('kai-conversation-select', { id })}
|
|
144
189
|
onNewChat={() => dispatch('kai-new-chat')}
|
|
145
190
|
onToggleSidebar={() => { dispatch('kai-toggle-sidebar'); setCollapsedTo(true); }}
|
|
191
|
+
compact={flag('compact')}
|
|
146
192
|
onSearchChange={(query) => dispatch('kai-search', { query })}
|
|
147
193
|
controllerRef={(c) => (controller = c)}
|
|
194
|
+
items={itemMode() ? <slot /> : undefined}
|
|
195
|
+
itemsKeyDown={itemsController.handleKeyDown}
|
|
196
|
+
itemsClick={itemsController.handleClick}
|
|
148
197
|
header={slots().header ? <slot name="header" /> : undefined}
|
|
149
198
|
footer={slots().footer ? <slot name="footer" /> : undefined}
|
|
150
199
|
empty={slots().empty ? <slot name="empty" /> : undefined}
|
|
@@ -70,8 +70,8 @@ export interface DefaultPromptInputProps {
|
|
|
70
70
|
* (name, media type, reason) and renders nothing itself: what the user should
|
|
71
71
|
* see is the application's call, not the kit's. */
|
|
72
72
|
onAttachmentsRejected?: (rejected: RejectedAttachment[]) => void;
|
|
73
|
-
/** Show a
|
|
74
|
-
|
|
73
|
+
/** Show a web-search (Globe) button in the left toolbar; calls `onWebSearch`. */
|
|
74
|
+
webSearch?: boolean;
|
|
75
75
|
/** Show a Voice (Mic) button in the left toolbar; calls `onVoice`. */
|
|
76
76
|
voice?: boolean;
|
|
77
77
|
/** Send-button visibility. `'always'` (default) always shows it; `'auto'` shows
|
|
@@ -84,7 +84,7 @@ export interface DefaultPromptInputProps {
|
|
|
84
84
|
onSubmit: () => void;
|
|
85
85
|
onSuggestionClick: (v: string) => void;
|
|
86
86
|
onAttachmentsChange?: (attachments: AttachmentData[]) => void;
|
|
87
|
-
|
|
87
|
+
onWebSearch?: () => void;
|
|
88
88
|
onVoice?: () => void;
|
|
89
89
|
/** When `true` and `loading` is also `true`, the send button is replaced by
|
|
90
90
|
* a Stop button that calls `onStop`. */
|
|
@@ -296,7 +296,7 @@ export function DefaultPromptInput(props: DefaultPromptInputProps) {
|
|
|
296
296
|
<Paperclip class="size-4" />
|
|
297
297
|
</Button>
|
|
298
298
|
</Show>
|
|
299
|
-
<Show when={props.
|
|
299
|
+
<Show when={props.webSearch}>
|
|
300
300
|
<Button
|
|
301
301
|
type="button"
|
|
302
302
|
variant="outline"
|
|
@@ -304,7 +304,7 @@ export function DefaultPromptInput(props: DefaultPromptInputProps) {
|
|
|
304
304
|
class="rounded-full gap-1"
|
|
305
305
|
aria-label="Search the web"
|
|
306
306
|
disabled={props.disabled}
|
|
307
|
-
onClick={() => props.
|
|
307
|
+
onClick={() => props.onWebSearch?.()}
|
|
308
308
|
>
|
|
309
309
|
<Globe class="size-4" />
|
|
310
310
|
Search
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @kitn.ai/ui/define — the facade seam, public.
|
|
3
|
+
*
|
|
4
|
+
* The construct engine's GENERATED projects (and any consumer who wants to wrap
|
|
5
|
+
* a pure-Solid interior as one self-registering element) import from here. Its
|
|
6
|
+
* own subpath rather than ./solid because define.tsx carries ELEMENT_CSS (the
|
|
7
|
+
* full compiled kit CSS) and solid-element — weight ./solid consumers must not
|
|
8
|
+
* pay. SSR-safe by construction: defineWebComponent no-ops without
|
|
9
|
+
* customElements (see define.tsx).
|
|
10
|
+
*/
|
|
11
|
+
export { defineWebComponent } from './define';
|
|
12
|
+
export type { WebComponentContext } from './define';
|
package/src/elements/define.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { customElement } from 'solid-element';
|
|
2
2
|
import { ChatConfig } from '../primitives/chat-config';
|
|
3
3
|
import { ELEMENT_CSS } from './css';
|
|
4
|
-
import {
|
|
4
|
+
import { elementDiagnosticsWanted, installElementDiagnostics } from './element-diagnostics';
|
|
5
|
+
import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Shared constructable stylesheet, built once and adopted by every element's
|
|
@@ -78,6 +79,33 @@ export interface WebComponentContext<E = Record<string, unknown>> {
|
|
|
78
79
|
* convention). Methods are attached when the facade renders (on element upgrade).
|
|
79
80
|
*/
|
|
80
81
|
expose: (methods: Record<string, (...args: never[]) => unknown>) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Reflect a boolean prop to its host attribute AND make that prop read back what
|
|
84
|
+
* was set. Use this instead of hand-rolling
|
|
85
|
+
* `createEffect(() => element.toggleAttribute('x', flag('x')))`.
|
|
86
|
+
*
|
|
87
|
+
* WHY IT IS ONE CALL AND NOT TWO. The reflection is what BREAKS the read-back, so
|
|
88
|
+
* the fix has to be attached to it or it gets forgotten — and it was, three times.
|
|
89
|
+
* `toggleAttribute(name, true)` sets the attribute to the EMPTY STRING;
|
|
90
|
+
* component-register's `attributeChangedCallback` then writes the prop back as
|
|
91
|
+
* `this[name] = parseAttributeValue("")`, and `parseAttributeValue` returns
|
|
92
|
+
* `undefined` for the empty string. So a reflected flag became write-only:
|
|
93
|
+
* `el.loading = true` left `el.loading === undefined` while `[loading]` was on the
|
|
94
|
+
* host. The element kept BEHAVING correctly, because `flag()` reads the attribute —
|
|
95
|
+
* which is precisely why nobody noticed until a consumer tried to read the property
|
|
96
|
+
* back (findings G-05).
|
|
97
|
+
*
|
|
98
|
+
* What this installs is an instance-level wrapper around the accessor
|
|
99
|
+
* component-register already created, coercing every incoming value through the
|
|
100
|
+
* same `flag()` policy (`resolveFlag`) — so the `undefined` write-back resolves to
|
|
101
|
+
* the attribute that caused it, and the property and the attribute can no longer
|
|
102
|
+
* disagree. It delegates to the underlying setter, so reactivity is untouched.
|
|
103
|
+
*
|
|
104
|
+
* `source` overrides where the ON/OFF value comes from, for an element whose truth
|
|
105
|
+
* is an internal controller rather than the prop (see `wireDisclosure`). Returning
|
|
106
|
+
* `undefined` from it means "not ready, leave the attribute alone".
|
|
107
|
+
*/
|
|
108
|
+
reflectFlag: (name: string, source?: () => boolean | undefined) => void;
|
|
81
109
|
/**
|
|
82
110
|
* Whether the element should currently render its dark-mode look --
|
|
83
111
|
* exactly the SAME resolved value that already drives the `.dark` class
|
|
@@ -197,10 +225,22 @@ function defineWithNonReflectingProps<T>(
|
|
|
197
225
|
tag: string,
|
|
198
226
|
keys: readonly string[],
|
|
199
227
|
define: () => T,
|
|
228
|
+
/**
|
|
229
|
+
* Anything else that must be on the prototype BEFORE the registry sees the
|
|
230
|
+
* class. Today that is the element-layer diagnostics, and it needs this seam
|
|
231
|
+
* for a reason that is adjacent to the one above but not the same: `define()`
|
|
232
|
+
* SNAPSHOTS the lifecycle callbacks (`connectedCallback`,
|
|
233
|
+
* `attributeChangedCallback`, …) off the prototype into the custom-element
|
|
234
|
+
* definition, and the browser invokes the snapshot. A wrapper installed
|
|
235
|
+
* afterwards is present on the prototype, passes `hasOwnProperty`, and is
|
|
236
|
+
* never called. See `installElementDiagnostics`.
|
|
237
|
+
*/
|
|
238
|
+
alsoPatch?: (proto: object) => void,
|
|
200
239
|
): { result: T; handled: boolean } {
|
|
201
|
-
// `handled` = nothing more for the caller to do. With no colliding props
|
|
202
|
-
// nothing to install at all, so that case is
|
|
203
|
-
|
|
240
|
+
// `handled` = nothing more for the caller to do. With no colliding props and
|
|
241
|
+
// nothing else to patch there is nothing to install at all, so that case is
|
|
242
|
+
// trivially handled.
|
|
243
|
+
if (keys.length === 0 && !alsoPatch) return { result: define(), handled: true };
|
|
204
244
|
const registry = customElements;
|
|
205
245
|
const hadOwnDefine = Object.prototype.hasOwnProperty.call(registry, 'define');
|
|
206
246
|
const inner = registry.define;
|
|
@@ -214,7 +254,8 @@ function defineWithNonReflectingProps<T>(
|
|
|
214
254
|
options?: ElementDefinitionOptions,
|
|
215
255
|
) {
|
|
216
256
|
if (name === tag) {
|
|
217
|
-
installNonReflectingProps(constructor.prototype, keys);
|
|
257
|
+
if (keys.length) installNonReflectingProps(constructor.prototype, keys);
|
|
258
|
+
alsoPatch?.(constructor.prototype);
|
|
218
259
|
handled = true;
|
|
219
260
|
}
|
|
220
261
|
return inner.call(this, name, constructor, options);
|
|
@@ -237,6 +278,76 @@ function defineWithNonReflectingProps<T>(
|
|
|
237
278
|
}
|
|
238
279
|
}
|
|
239
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Marks a setter as one of ours, so the wrap is idempotent WITHOUT being permanent.
|
|
283
|
+
*
|
|
284
|
+
* The mark goes on the setter function rather than on the element, and that is the
|
|
285
|
+
* whole subtlety: component-register installs a FRESH instance accessor from
|
|
286
|
+
* `initializeProps` on every (re)connect after a release, which throws our wrapper
|
|
287
|
+
* away. An element-level "already done" flag would then skip re-wrapping and the
|
|
288
|
+
* property would quietly go write-only again on the second mount. An unmarked setter
|
|
289
|
+
* is by definition a new one, so it gets wrapped again.
|
|
290
|
+
*/
|
|
291
|
+
const FLAG_READ_BACK = Symbol('kai-flag-read-back');
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Wrap the instance accessor component-register created for `name` so every value
|
|
295
|
+
* written to it — a consumer's assignment, or the `undefined` write-back that
|
|
296
|
+
* `attributeChangedCallback` performs after a `toggleAttribute` — is resolved through
|
|
297
|
+
* the same policy `flag()` uses.
|
|
298
|
+
*
|
|
299
|
+
* TIMING. This must run from the facade body, i.e. during `connectedCallback` AFTER
|
|
300
|
+
* `initializeProps`, and that is not a detail: `initializeProps` harvests any value
|
|
301
|
+
* set on the element BEFORE upgrade (`value = element[key]`) and only then installs
|
|
302
|
+
* the accessor. Wrapping earlier (on the prototype, the way `installNonReflectingProps`
|
|
303
|
+
* does) would be shadowed by that accessor and would also sit in front of the harvest —
|
|
304
|
+
* the same class of defect `define-upgrade-ordering.test.tsx` pins for attributes.
|
|
305
|
+
*/
|
|
306
|
+
function installFlagReadBack(element: HTMLElement, name: string, attribute: string): void {
|
|
307
|
+
const inner = Object.getOwnPropertyDescriptor(element, name);
|
|
308
|
+
if (!inner?.get || !inner.set) {
|
|
309
|
+
// Reached only if `name` is not a declared prop of this element — a typo, or a
|
|
310
|
+
// facade reflecting something it never declared. Warn rather than no-op silently;
|
|
311
|
+
// a silent skip here would look exactly like a working read-back.
|
|
312
|
+
console.warn(
|
|
313
|
+
`reflectFlag("${name}"): no such declared prop on <${element.localName}> — ` +
|
|
314
|
+
`the attribute will still reflect, but the property will not read back.`,
|
|
315
|
+
);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const { get, set } = inner;
|
|
319
|
+
if ((set as { [FLAG_READ_BACK]?: true })[FLAG_READ_BACK]) return;
|
|
320
|
+
|
|
321
|
+
const wrapped = function (this: HTMLElement, value: unknown) {
|
|
322
|
+
set.call(this, resolveFlag(this, value, attribute));
|
|
323
|
+
} as ((value: unknown) => void) & { [FLAG_READ_BACK]?: true };
|
|
324
|
+
wrapped[FLAG_READ_BACK] = true;
|
|
325
|
+
|
|
326
|
+
Object.defineProperty(element, name, {
|
|
327
|
+
get,
|
|
328
|
+
set: wrapped,
|
|
329
|
+
enumerable: inner.enumerable ?? true,
|
|
330
|
+
configurable: true,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Seed, but ONLY upwards. The value sitting in the prop store right now may already
|
|
334
|
+
// be the broken one: `<el loading>` parses to `undefined` in `initializeProps`
|
|
335
|
+
// exactly as it does in the write-back, so without this the bare-attribute case
|
|
336
|
+
// would still read back `undefined` until something else wrote to the prop.
|
|
337
|
+
//
|
|
338
|
+
// WHY NOT SEED `false` TOO. Writing `false` over an `undefined` would look tidier
|
|
339
|
+
// and is wrong: for props declared with an `undefined` default, `undefined` MEANS
|
|
340
|
+
// "the consumer has not set this", and at least one caller depends on telling that
|
|
341
|
+
// apart from an explicit `false` — `wireDisclosure` seeds from `defaultOpen` only
|
|
342
|
+
// while `open` is unset, so a blanket `false` seed would clobber
|
|
343
|
+
// `<el default-open>` on every mount. Promoting only a present attribute to `true`
|
|
344
|
+
// fixes the read-back without inventing an opinion the author never expressed.
|
|
345
|
+
const current = get.call(element);
|
|
346
|
+
if (typeof current !== 'boolean' && resolveFlag(element, current, attribute)) {
|
|
347
|
+
wrapped.call(element, true);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
240
351
|
/** Underlying flag resolution; see `WebComponentContext.flag`. */
|
|
241
352
|
function resolveFlag(element: HTMLElement, value: unknown, attribute: string): boolean {
|
|
242
353
|
if (value === true) return true;
|
|
@@ -329,6 +440,21 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
|
|
|
329
440
|
const flag = (name: string) =>
|
|
330
441
|
resolveFlag(element, (props as Record<string, unknown>)[name], toAttr(name));
|
|
331
442
|
|
|
443
|
+
// Reflect a boolean prop to its attribute and keep the property readable. See
|
|
444
|
+
// WebComponentContext.reflectFlag for the defect this exists to close.
|
|
445
|
+
const reflectFlag: WebComponentContext<E>['reflectFlag'] = (name, source) => {
|
|
446
|
+
const attribute = toAttr(name);
|
|
447
|
+
installFlagReadBack(element, name, attribute);
|
|
448
|
+
createEffect(() => {
|
|
449
|
+
const on = source ? source() : flag(name);
|
|
450
|
+
// `undefined` means the caller's source is not ready yet (a controller a
|
|
451
|
+
// primitive has not handed up). Leave the author's attribute alone rather
|
|
452
|
+
// than writing a guessed OFF over it.
|
|
453
|
+
if (on === undefined) return;
|
|
454
|
+
element.toggleAttribute(attribute, on);
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
|
|
332
458
|
// Attach imperative methods onto the host instance. See WebComponentContext.expose.
|
|
333
459
|
// Uses defineProperty so a method can shadow an inherited getter-only accessor
|
|
334
460
|
// (e.g. `focus`/`blur`) which a plain assignment would throw on. A method name
|
|
@@ -381,15 +507,39 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
|
|
|
381
507
|
<div classList={{ dark: isDark() }} style={{ display: 'contents', color: 'var(--color-foreground)' }}>
|
|
382
508
|
<div ref={portalNode} />
|
|
383
509
|
<ChatConfig portalMount={portalNode}>
|
|
384
|
-
{Facade(props as unknown as P, {
|
|
510
|
+
{Facade(props as unknown as P, {
|
|
511
|
+
element,
|
|
512
|
+
dispatch,
|
|
513
|
+
flag,
|
|
514
|
+
reflectFlag,
|
|
515
|
+
expose,
|
|
516
|
+
dark: isDark,
|
|
517
|
+
})}
|
|
385
518
|
</ChatConfig>
|
|
386
519
|
</div>
|
|
387
520
|
</>
|
|
388
521
|
);
|
|
389
522
|
};
|
|
390
523
|
|
|
391
|
-
|
|
392
|
-
|
|
524
|
+
// Element-layer diagnostics: report the three `kai-` contract violations that
|
|
525
|
+
// are otherwise silent (an array or object prop set as an HTML attribute, the
|
|
526
|
+
// same array reference handed back, a new array of the same item objects).
|
|
527
|
+
//
|
|
528
|
+
// HERE because this function is the single choke point — every kai-* element
|
|
529
|
+
// registers through it, which `elements/slots.test.ts` already enforces — so
|
|
530
|
+
// one call covers every element with no per-element work and no second list.
|
|
531
|
+
//
|
|
532
|
+
// Through the pre-define seam, not after the fact, because the registry
|
|
533
|
+
// snapshots lifecycle callbacks at definition time; see `alsoPatch` above.
|
|
534
|
+
// `elementDiagnosticsWanted` is asked first so a tag with no non-scalar prop
|
|
535
|
+
// (37 of the 80) does not even pay for the registry interception.
|
|
536
|
+
const wantsDiagnostics = elementDiagnosticsWanted(tag);
|
|
537
|
+
|
|
538
|
+
const { result: Ctor, handled } = defineWithNonReflectingProps(
|
|
539
|
+
tag,
|
|
540
|
+
shadowedProps,
|
|
541
|
+
() => customElement(tag, defaults, renderFacade),
|
|
542
|
+
wantsDiagnostics ? (proto) => installElementDiagnostics(tag, proto) : undefined,
|
|
393
543
|
);
|
|
394
544
|
|
|
395
545
|
// Belt and braces for the one path the wrap cannot see: if `customElements.define`
|
|
@@ -400,4 +550,14 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
|
|
|
400
550
|
// in the normal case, where the accessors are already on this same prototype.
|
|
401
551
|
const proto = (Ctor as unknown as { prototype?: object } | undefined)?.prototype;
|
|
402
552
|
if (!handled && proto) installNonReflectingProps(proto, shadowedProps);
|
|
553
|
+
|
|
554
|
+
// NOTE the diagnostics have no equivalent late fallback, and must not get one.
|
|
555
|
+
// The non-reflecting props still work when installed late (they only have to
|
|
556
|
+
// beat the NEXT constructor); the diagnostics do not, because the registry has
|
|
557
|
+
// already snapshotted the lifecycle callbacks it will invoke. Installing them
|
|
558
|
+
// here would produce a wrapper that is visibly present and never called —
|
|
559
|
+
// which is worse than not installing it, since it would read as coverage. So
|
|
560
|
+
// in the one environment the pre-define seam cannot reach (a frozen registry:
|
|
561
|
+
// SES lockdown, a sealed polyfill), element diagnostics are simply absent, and
|
|
562
|
+
// every other element behaviour is unaffected.
|
|
403
563
|
}
|