@kitn.ai/ui 0.26.0 → 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 +16 -5
- package/bin/mcp.js +16 -3
- package/bin/route.js +23 -0
- package/bin/route.test.js +58 -0
- package/dist/{elements/chunks/Icon--Y8vsFal.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/{elements/chunks/audio-visualizer-D7lB6mvR.js → audio-visualizer-B-79y1Tj.js} +1 -1
- 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-flUbeufF.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/{elements/chunks/code-block-BdLiTitd.js → code-block-CUQ5mtv0.js} +1 -1
- package/dist/{elements/chunks/collapsible-BzbXpPzr.js → collapsible-CPJbf6FM.js} +1 -1
- package/dist/components/attachment-types.d.ts +7 -0
- package/dist/components/audio-visualizer/fit-scale.d.ts +1 -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 +46 -1
- package/dist/components/conversation-item.d.ts +19 -7
- package/dist/components/conversation-list.d.ts +17 -5
- package/dist/components/form-widgets.d.ts +67 -2
- package/dist/components/form.d.ts +48 -1
- package/dist/components/message.d.ts +25 -3
- 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/tool-types.d.ts +9 -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/{elements/chunks/context-VLIL3sJ-.js → context-BY8V-Nlp.js} +1 -1
- 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-CQED4T0g.js → create-tween-BPzaefTp.js} +1 -1
- package/dist/{create-tween-BFT6c-Y8.js → create-tween-CnMHviKB.js} +1 -1
- package/dist/{create-tween-CJNlzoaO.js → create-tween-D1aiGZZh.js} +1 -1
- package/dist/{elements/chunks/create-tween-c4Z8TDYz.js → create-tween-DUSQUKpr.js} +2 -2
- package/dist/css-M7EaDHN_.js +1 -6
- package/dist/custom-elements.json +1400 -218
- 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/{elements/chunks/disclosure-CcNbyLy0.js → disclosure-CbLtajUQ.js} +1 -1
- package/dist/{elements/chunks/dropdown-BgWTthUx.js → dropdown-BwhViJFd.js} +1 -1
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/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.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/define-entry.d.ts +12 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.js +101 -7
- package/dist/elements/dropdown.js +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +37 -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/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +2 -2
- 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 +1 -1
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +362 -24
- package/dist/{elements/chunks/ellipsis-7gU33mL2.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-CSOEsNlx.js → external-link-u9d85ORQ.js} +1 -1
- package/dist/file-text-CX7_x42o.js +1 -0
- package/dist/{elements/chunks/file-tree-zvB2i7P9.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 +1 -1
- package/dist/index.js +7330 -5852
- package/dist/index.server.js +5823 -4759
- 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.es.js +1 -1
- package/dist/kbd-961zMPFB.js +1 -0
- package/dist/link-DlZZBGaR.js +1 -0
- package/dist/{elements/chunks/link-preview-OQ9IEq0f.js → link-preview-DIIbV2Sd.js} +1 -1
- package/dist/loader-YQszHFaW.js +1 -0
- package/dist/{elements/chunks/markdown-DgBFaGAz.js → markdown-CVk1MPsj.js} +1 -1
- package/dist/mcp.es.js +1285 -79
- 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-DPIUKTrT.js → minimize-2-UEZmP2QT.js} +1 -1
- package/dist/{elements/chunks/model-switcher-DsT8tFB0.js → model-switcher-Kk1jEQ5t.js} +1 -1
- package/dist/{elements/chunks/overlay-DuiwdXjm.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 +2 -2
- 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 +193 -19
- package/dist/react.js +216 -180
- package/dist/reasoning-Cackq4Rh.js +1 -0
- package/dist/register-impl-C7rENvPK.js +424 -0
- package/dist/{elements/chunks/resizable-D181b4fM.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/tool-defs.d.ts +11 -1
- package/dist/schemas.js +81 -81
- 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-CeJHQqLW.js → separator-CE6vly6z.js} +1 -1
- package/dist/{elements/chunks/settings-CqaHgJF9.js → settings-CE-78SvZ.js} +1 -1
- package/dist/{elements/chunks/settings-group-CjqjLCOn.js → settings-group-ZFWNxFQR.js} +1 -1
- package/dist/{elements/chunks/skeleton-D8akBnKS.js → skeleton-BebdP4mf.js} +1 -1
- package/dist/slider-BAKRYUlz.js +1 -0
- package/dist/{solid-BtdqNZI7.js → solid-BE5ui6sy.js} +8727 -7212
- package/dist/{solid-CnavwBye.js → solid-DFhsce3O.js} +7015 -5886
- package/dist/solid.d.ts +10 -0
- package/dist/solid.js +240 -234
- package/dist/solid.server.js +240 -234
- package/dist/source-B0FlguSx.js +1 -0
- package/dist/star-CBMZvLuN.js +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/state/mock.d.ts +32 -2
- package/dist/state.js +133 -108
- package/dist/{elements/chunks/store-Cjq0qwYN.js → store-7eoadydQ.js} +1 -1
- 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-DX2Ijk3H.js → thumbs-up-DQcu2HMO.js} +1 -1
- package/dist/toast-store-C6yKOhbk.js +1 -0
- package/dist/{elements/chunks/tool-DKQ2D1DP.js → tool-BCYNlfKy.js} +1 -1
- package/dist/{elements/chunks/tooltip-B0G99y8w.js → tooltip-05zI4hjs.js} +1 -1
- package/dist/trash-2-BR1RxGky.js +1 -0
- package/dist/{elements/chunks/triangle-alert-F9cyUEyy.js → triangle-alert-DHohDOCy.js} +1 -1
- package/dist/tsx-B8rCNbgL.js +1 -6
- 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 +22 -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-B8II3-I1.js → variant-aurora-BUOVgPOB.js} +2 -2
- package/dist/{variant-aurora-CMNWOSJR.js → variant-aurora-CUsUJvFI.js} +2 -2
- package/dist/{variant-aurora-CcuDMWwQ.js → variant-aurora-CW2i4bfr.js} +1 -1
- package/dist/{elements/chunks/variant-aurora-qt6Zct8M.js → variant-aurora-xiMPty8f.js} +1 -1
- package/dist/{variant-custom-L16JLLZy.js → variant-custom-BQtOnmeO.js} +1 -1
- package/dist/{variant-custom-C714mqKl.js → variant-custom-CAm9L-E5.js} +2 -2
- package/dist/{variant-custom-BdvYC7af.js → variant-custom-CAnzzppW.js} +2 -2
- package/dist/{elements/chunks/variant-custom-tJp22_BQ.js → variant-custom-D91HjAKz.js} +1 -1
- package/dist/{variant-wave-ecwykeyL.js → variant-wave-Ca1Ls4_y.js} +2 -2
- package/dist/{variant-wave-D7ruiA1W.js → variant-wave-CxX39DKd.js} +2 -2
- package/dist/{elements/chunks/variant-wave-CaQ5ti39.js → variant-wave-DYyzIIZv.js} +1 -1
- package/dist/{variant-wave-2S4La2Ka.js → variant-wave-uY5crU_K.js} +1 -1
- package/dist/vue-BmIZj4XD.js +1 -33
- package/dist/x-C5m1JFgi.js +1 -0
- package/frameworks/react/index.tsx +198 -20
- package/llms-full.txt +1178 -21
- package/llms.txt +6 -3
- package/package.json +17 -4
- package/src/agent-tooling/catalog/invariants.ts +1 -1
- package/src/agent-tooling/catalog/surfaces.ts +72 -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/mcp/server.ts +2 -1
- 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 +104 -3
- 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 +5 -0
- package/src/components/attachment-types.ts +7 -0
- package/src/components/audio-visualizer/fit-scale.ts +1 -1
- package/src/components/card-renderer.tsx +39 -8
- package/src/components/card.tsx +10 -2
- package/src/components/chat-scope-picker.tsx +2 -2
- package/src/components/chat-thread.tsx +72 -9
- package/src/components/choice-card.tsx +102 -37
- package/src/components/coachmark.tsx +1 -1
- package/src/components/code-block.tsx +2 -2
- package/src/components/composer.tsx +89 -15
- package/src/components/confirm-card.tsx +20 -4
- package/src/components/conversation-item.tsx +33 -9
- package/src/components/conversation-list.tsx +25 -10
- 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 +297 -9
- package/src/components/loader.tsx +12 -5
- package/src/components/message-skills.tsx +1 -1
- package/src/components/message.tsx +71 -11
- 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/scroll-button.tsx +56 -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 +1 -1
- package/src/components/tool-types.ts +9 -0
- package/src/elements/attachments.tsx +3 -1
- package/src/elements/chat-workspace.tsx +1 -1
- package/src/elements/chat.tsx +22 -4
- package/src/elements/checkbox-group.tsx +164 -0
- package/src/elements/checkbox.tsx +134 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +12 -1
- package/src/elements/conversation-item.tsx +62 -22
- package/src/elements/conversation-list.tsx +2 -2
- package/src/elements/define-entry.ts +12 -0
- package/src/elements/dock.tsx +11 -0
- package/src/elements/element-data-types.ts +40 -0
- package/src/elements/element-manifest.json +24 -0
- package/src/elements/element-meta.json +736 -46
- package/src/elements/element-nonscalar.json +15 -0
- package/src/elements/element-types.d.ts +362 -24
- 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/message.tsx +2 -0
- package/src/elements/pane-grid.tsx +111 -0
- package/src/elements/prompt-input.tsx +8 -2
- package/src/elements/radio-group.tsx +129 -0
- package/src/elements/register-impl.ts +6 -0
- package/src/elements/scroll-button.tsx +54 -6
- package/src/elements/select.tsx +165 -0
- package/src/elements/slider.tsx +171 -0
- package/src/elements/slots.ts +1 -1
- package/src/elements/styles.css +89 -3
- package/src/elements/thread.tsx +2 -0
- package/src/elements/toast.tsx +14 -1
- package/src/index.ts +2 -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 +2 -2
- package/src/schemas/tool-defs.ts +12 -2
- package/src/solid.ts +10 -0
- package/src/state/index.ts +1 -1
- package/src/state/mock.ts +92 -6
- 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/dock.tsx +145 -6
- package/src/ui/icon.tsx +53 -0
- package/src/ui/input.tsx +249 -9
- 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/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/theme.css +84 -13
- package/dist/elements/chunks/action-icons-D9u3OzYW.js +0 -1
- package/dist/elements/chunks/arrow-left-CVh1TeN7.js +0 -1
- package/dist/elements/chunks/artifact-BkYcfIlZ.js +0 -1
- package/dist/elements/chunks/attachments-DwfNlubq.js +0 -1
- package/dist/elements/chunks/badge-Q0-Cmwzz.js +0 -1
- package/dist/elements/chunks/bash-InADTalH.js +0 -1
- package/dist/elements/chunks/card-renderer-3Dyl-FpN.js +0 -1
- package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
- package/dist/elements/chunks/check-B5kBPKeo.js +0 -1
- package/dist/elements/chunks/chevron-down-DZ1GS39h.js +0 -1
- package/dist/elements/chunks/chevron-right-CvP7OUd2.js +0 -1
- package/dist/elements/chunks/choice-card-D4QUIOWZ.js +0 -1
- package/dist/elements/chunks/circle-CDf9g6MQ.js +0 -1
- package/dist/elements/chunks/circle-check-CA47Nqbz.js +0 -1
- package/dist/elements/chunks/circle-x-CJ_HVbC8.js +0 -1
- package/dist/elements/chunks/composer-Byve-n8K.js +0 -69
- package/dist/elements/chunks/confirm-card-B0flE3MN.js +0 -1
- package/dist/elements/chunks/controllable-DTwTIlwp.js +0 -1
- package/dist/elements/chunks/conversation-item-BDztezOG.js +0 -1
- package/dist/elements/chunks/copy-Nf-kqxXH.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-C2iLFq0b.js +0 -1
- package/dist/elements/chunks/define-wjHR1MkU.js +0 -1
- package/dist/elements/chunks/download-C4V7tBdb.js +0 -1
- package/dist/elements/chunks/embed-D3KewsIJ.js +0 -1
- package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
- package/dist/elements/chunks/file-text-D1G8khle.js +0 -1
- package/dist/elements/chunks/folder-WW2LGLid.js +0 -1
- package/dist/elements/chunks/form-CQirdC4W.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-CJJkfHTK.js +0 -1
- package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
- package/dist/elements/chunks/icon-Cfgmf4fa.js +0 -1
- package/dist/elements/chunks/info-DX3YMOt6.js +0 -1
- package/dist/elements/chunks/input-BtW9U6Sq.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-LGXwuT_V.js +0 -1
- package/dist/elements/chunks/link-2My69BqT.js +0 -1
- package/dist/elements/chunks/loader-iOxc_Tu-.js +0 -1
- package/dist/elements/chunks/message-VMZohrXx.js +0 -1
- package/dist/elements/chunks/message-circle-CpXMM-_n.js +0 -1
- package/dist/elements/chunks/message-square-DxcWtETQ.js +0 -1
- package/dist/elements/chunks/message-tZmV2A3p.js +0 -1
- package/dist/elements/chunks/paperclip-CRZVp4z_.js +0 -1
- package/dist/elements/chunks/progress-bar-DNy66e_E.js +0 -1
- package/dist/elements/chunks/prompt-suggestion-Bn64Nl7L.js +0 -1
- package/dist/elements/chunks/reasoning-Emn9N4-T.js +0 -1
- package/dist/elements/chunks/rotate-cw-CPWe37D9.js +0 -1
- package/dist/elements/chunks/scroll-area-ClZkZxIk.js +0 -1
- package/dist/elements/chunks/scroll-button-DPE-t3x_.js +0 -1
- package/dist/elements/chunks/share-CyfnNEqp.js +0 -1
- package/dist/elements/chunks/source-UWCvmVak.js +0 -1
- package/dist/elements/chunks/star-DoHFAikQ.js +0 -1
- package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
- package/dist/elements/chunks/tasks-card-CmZ5xh6v.js +0 -1
- package/dist/elements/chunks/text-shimmer-DYn09zrz.js +0 -1
- package/dist/elements/chunks/textarea-skiGHURM.js +0 -1
- package/dist/elements/chunks/toast-store-CFnQpThX.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-DoA2f_EU.js +0 -1
- package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
- package/dist/elements/chunks/x-B6UnOiLw.js +0 -1
- package/dist/llms/llms-full.txt +0 -2949
- package/dist/llms/llms.txt +0 -156
- package/dist/register-impl-DpE7icIb.js +0 -293
- package/dist/ui/stat.d.ts +0 -16
- 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/dist/{elements/chunks/slots-DaNjX0rc.js → slots-DaNjX0rc.js} +0 -0
package/dist/llms/llms-full.txt
DELETED
|
@@ -1,2949 +0,0 @@
|
|
|
1
|
-
<!-- AUTO-GENERATED by scripts/gen-llms.mjs — do not edit by hand. Run `npm run build`. -->
|
|
2
|
-
# @kitn.ai/ui — Full Reference
|
|
3
|
-
|
|
4
|
-
# @kitn.ai/ui
|
|
5
|
-
|
|
6
|
-
> Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. 83 custom elements, every one prefixed `kai-` (e.g. `<kai-chat>`, `<kai-artifact>`): streaming responses, markdown + code rendering, reasoning/tool panels, attachments, conversation sidebar, voice input. Zero framework dependency for consumers; the SolidJS runtime it is authored in is bundled in, so the host needs nothing.
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @kitn.ai/ui
|
|
12
|
-
# SolidJS consumers also need the peer dep:
|
|
13
|
-
npm install solid-js
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## #1 rule: array/object data goes on JS PROPERTIES, not HTML attributes
|
|
17
|
-
|
|
18
|
-
This is the single most common mistake. Arrays and objects (`messages`, `models`, `context`, `suggestions`, `triggers`, …) MUST be assigned as JavaScript properties on the element. They CANNOT be passed as HTML attributes — an HTML attribute is always a string and will be ignored or mis-parsed.
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
const chat = document.querySelector('kai-chat');
|
|
22
|
-
chat.messages = [{ id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hi!' }] }]; // ✅ property
|
|
23
|
-
```
|
|
24
|
-
```html
|
|
25
|
-
<kai-chat messages="[...]"></kai-chat> <!-- ❌ never works -->
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Only scalar values (string/number/boolean) work as attributes (e.g. `placeholder`, `loading`, `theme`).
|
|
29
|
-
|
|
30
|
-
## Two layers
|
|
31
|
-
|
|
32
|
-
**Layer 1 — batteries-included web components** (`import '@kitn.ai/ui/elements'`):
|
|
33
|
-
Drop an element into any framework (React, Vue, plain HTML). Data in via JS properties; interactions out via non-bubbling CustomEvents.
|
|
34
|
-
|
|
35
|
-
- `<kai-chat>` — full chat UI (message list + prompt input). The primary starting point.
|
|
36
|
-
- `<kai-conversations>` — sidebar conversation browser with group support.
|
|
37
|
-
- `<kai-prompt-input>` — standalone composer with send button.
|
|
38
|
-
|
|
39
|
-
**Layer 2 — composable primitives** (`import { … } from '@kitn.ai/ui'`):
|
|
40
|
-
All 83 elements are also exported individually. Use them for custom layouts or features `<kai-chat>` does not expose (ChainOfThought, FeedbackBar, ThinkingBar, VoiceInput, …). Your bundler tree-shakes the rest.
|
|
41
|
-
|
|
42
|
-
## Key rules for the web components
|
|
43
|
-
|
|
44
|
-
1. **Array/object data = JS properties** (see above). Scalars may be attributes.
|
|
45
|
-
2. **Events are non-bubbling `CustomEvent`s** — listen directly on the element:
|
|
46
|
-
`chat.addEventListener('kai-submit', (e) => console.log(e.detail.value))`
|
|
47
|
-
3. **`theme` attribute** (`'light' | 'dark' | 'auto'`) works on every element. Default `auto` follows `prefers-color-scheme`.
|
|
48
|
-
4. **Theming via CSS custom properties** — override `--kai-color-*` tokens on `:root`; they pierce Shadow DOM.
|
|
49
|
-
|
|
50
|
-
## ChatMessage schema (required for `<kai-chat>`)
|
|
51
|
-
|
|
52
|
-
A message's content is an **ordered `parts` array**. There is no `content` string: it was removed in 0.20.0. Text, reasoning, tool calls, generative-UI cards, citations and file attachments all live in `parts`, in the order the model produced them, so a post-tool answer renders below its tool panel instead of being glued onto the pre-tool text.
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
interface ChatMessage {
|
|
56
|
-
id: string;
|
|
57
|
-
role: 'user' | 'assistant';
|
|
58
|
-
/** The ONLY content channel. Ordered. */
|
|
59
|
-
parts: MessagePart[];
|
|
60
|
-
/** Action buttons under the message. Chrome, not content. */
|
|
61
|
-
actions?: ('copy' | 'like' | 'dislike' | 'regenerate' | 'edit')[];
|
|
62
|
-
avatar?: { src?: string; fallback?: string; alt?: string };
|
|
63
|
-
feedback?: 'like' | 'dislike';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Six variants, one per kind of content. Every variant may also carry `raw`
|
|
67
|
-
* (`{ source, payload }`), the untranslated provider block the part was
|
|
68
|
-
* normalized from, for echoing a turn back to the model verbatim. */
|
|
69
|
-
type MessagePart =
|
|
70
|
-
| { type: 'text'; text: string; raw?: RawOrigin }
|
|
71
|
-
| { type: 'reasoning'; text: string; label?: string; index?: number; signature?: string; raw?: RawOrigin }
|
|
72
|
-
| { type: 'tool'; tool: ToolPart; raw?: RawOrigin }
|
|
73
|
-
| { type: 'card'; envelope: CardEnvelope; raw?: RawOrigin }
|
|
74
|
-
| { type: 'source'; source: MessageSource; raw?: RawOrigin }
|
|
75
|
-
| { type: 'file'; attachment: AttachmentData; raw?: RawOrigin };
|
|
76
|
-
|
|
77
|
-
interface ToolPart {
|
|
78
|
-
type: string;
|
|
79
|
-
/** Rendering classification. Derived from `type` when you omit it; an explicit
|
|
80
|
-
* value you set is preserved across later patches. */
|
|
81
|
-
kind?: 'command' | 'file-change' | 'search' | 'fetch' | 'mcp' | 'image' | 'generic';
|
|
82
|
-
state: 'input-streaming' | 'input-available' | 'output-available' | 'output-error';
|
|
83
|
-
input?: Record<string, unknown>;
|
|
84
|
-
/** Raw accumulated argument fragments, for character-level streaming. */
|
|
85
|
-
rawInput?: string;
|
|
86
|
-
output?: Record<string, unknown>;
|
|
87
|
-
toolCallId?: string;
|
|
88
|
-
errorText?: string;
|
|
89
|
-
raw?: RawOrigin;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** A citation. Exported as `MessageSource` (the bare `Source` name belongs to
|
|
93
|
-
* the citation-chip component). */
|
|
94
|
-
interface MessageSource { id?: string; url?: string; title?: string; snippet?: string; index?: number }
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
The simplest possible message, and one with reasoning + a tool call before its answer:
|
|
98
|
-
|
|
99
|
-
```js
|
|
100
|
-
{ id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hi!' }] }
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
id: '2',
|
|
104
|
-
role: 'assistant',
|
|
105
|
-
parts: [
|
|
106
|
-
{ type: 'reasoning', text: 'I should search for current pricing.' },
|
|
107
|
-
{ type: 'tool', tool: { type: 'search', state: 'output-available', toolCallId: 'tc_1',
|
|
108
|
-
input: { query: 'current pricing' }, output: { results: ['A', 'B'] } } },
|
|
109
|
-
{ type: 'text', text: 'Here is what I found.' },
|
|
110
|
-
],
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Types are importable: `import type { ChatMessage, MessagePart, MessageSource } from '@kitn.ai/ui'` (also from `'@kitn.ai/ui/react'` and `'@kitn.ai/ui/state'`).
|
|
115
|
-
|
|
116
|
-
## Framework wiring
|
|
117
|
-
|
|
118
|
-
**Plain HTML / CDN**
|
|
119
|
-
```html
|
|
120
|
-
<script type="module" src="https://unpkg.com/@kitn.ai/ui/elements"></script>
|
|
121
|
-
<kai-chat style="display:block;height:100vh"></kai-chat>
|
|
122
|
-
<script type="module">
|
|
123
|
-
const chat = document.querySelector('kai-chat');
|
|
124
|
-
chat.messages = [];
|
|
125
|
-
</script>
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
**React** — typed wrappers auto-set properties and expose `on<Event>` props:
|
|
129
|
-
```tsx
|
|
130
|
-
import { Chat } from '@kitn.ai/ui/react';
|
|
131
|
-
<Chat messages={messages} onSubmit={(e) => send(e.detail.value)} />
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**Vue** — use the element directly; pass arrays via `.prop`:
|
|
135
|
-
```vue
|
|
136
|
-
<kai-chat :messages.prop="messages" @kai-submit="send" />
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Theming
|
|
140
|
-
|
|
141
|
-
```css
|
|
142
|
-
:root {
|
|
143
|
-
--kai-color-background: #0f0f0f;
|
|
144
|
-
--kai-color-primary: #7c3aed;
|
|
145
|
-
--kai-color-muted: #1e1e1e;
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
For plain HTML/CDN: `<link rel="stylesheet" href="…/@kitn.ai/ui/theme.tokens.css">`.
|
|
150
|
-
For Tailwind builds: `@import "@kitn.ai/ui/theme.css"` in your CSS.
|
|
151
|
-
|
|
152
|
-
## Docs
|
|
153
|
-
|
|
154
|
-
- Full element reference (all 83 elements, every prop/event): ./llms-full.txt — https://kitn.dev/llms-full.txt
|
|
155
|
-
- Machine-readable Custom Elements Manifest: https://unpkg.com/@kitn.ai/ui/dist/custom-elements.json
|
|
156
|
-
- Working examples: https://github.com/kitn-ai/ui/tree/main/examples
|
|
157
|
-
- Storybook: https://storybook.kitn.dev
|
|
158
|
-
- Repository: https://github.com/kitn-ai/ui
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## How to build a chat app in 5 steps
|
|
163
|
-
|
|
164
|
-
### 1 — Install
|
|
165
|
-
```bash
|
|
166
|
-
npm install @kitn.ai/ui
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### 2 — Pick your layer
|
|
170
|
-
Drop-in: use `<kai-chat>` for a full chat UI in one tag (`import '@kitn.ai/ui/elements'`).
|
|
171
|
-
Composable: combine `<kai-message>`, `<kai-prompt-input>`, `<kai-reasoning>`, … in your own markup.
|
|
172
|
-
|
|
173
|
-
### 3 — Handle `submit` and stream
|
|
174
|
-
```js
|
|
175
|
-
import '@kitn.ai/ui/elements';
|
|
176
|
-
// The streaming fold. It is 5 lines if you would rather inline it: see the
|
|
177
|
-
// Streaming recipe below.
|
|
178
|
-
import { appendTextPart } from '@kitn.ai/ui/state';
|
|
179
|
-
|
|
180
|
-
const chat = document.querySelector('kai-chat');
|
|
181
|
-
chat.messages = [];
|
|
182
|
-
|
|
183
|
-
chat.addEventListener('kai-submit', async (e) => {
|
|
184
|
-
const userText = e.detail.value;
|
|
185
|
-
|
|
186
|
-
// Append the user message (new array, see the streaming note)
|
|
187
|
-
const history = [...chat.messages, { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text: userText }] }];
|
|
188
|
-
chat.messages = history;
|
|
189
|
-
chat.loading = true;
|
|
190
|
-
|
|
191
|
-
// Add an empty assistant placeholder to stream into
|
|
192
|
-
const aid = crypto.randomUUID();
|
|
193
|
-
chat.messages = [...history, { id: aid, role: 'assistant', parts: [] }];
|
|
194
|
-
|
|
195
|
-
for await (const token of streamFromYourAPI(history)) {
|
|
196
|
-
// Fold each delta onto the message's TRAILING text part. Do NOT replace
|
|
197
|
-
// `parts` wholesale: that drops reasoning/tool/card parts already on it.
|
|
198
|
-
chat.messages = chat.messages.map((m) =>
|
|
199
|
-
m.id === aid ? { ...m, parts: appendTextPart(m.parts, token) } : m);
|
|
200
|
-
}
|
|
201
|
-
chat.loading = false;
|
|
202
|
-
});
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 4 — Wire optional features
|
|
206
|
-
- Reasoning: push `{ type: 'reasoning', text: '…' }` onto the message's `parts`.
|
|
207
|
-
- Tool calls: push `{ type: 'tool', tool: { type: 'search', state: 'output-available', input: {…}, output: {…} } }`.
|
|
208
|
-
- Model switcher: `chat.models = [{ id: 'gpt-4o', name: 'GPT-4o' }]; chat.currentModel = 'gpt-4o';` — listen for `modelchange`.
|
|
209
|
-
- Token meter: `chat.context = { usedTokens: 1200, maxTokens: 128000 };`.
|
|
210
|
-
- History sidebar: add `<kai-conversations>`; listen for `select` and `newchat`.
|
|
211
|
-
|
|
212
|
-
### 5 — Theme
|
|
213
|
-
Override `--kai-color-*` tokens on `:root` (they pierce Shadow DOM).
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## Streaming recipe (critical)
|
|
218
|
-
|
|
219
|
-
Two rules, and both bite:
|
|
220
|
-
|
|
221
|
-
1. **Reassign a NEW array containing a NEW message object on every chunk.** Mutating an existing message object in place will NOT trigger a re-render.
|
|
222
|
-
2. **Fold the delta onto the message's TRAILING text part.** Replacing `parts` with a fresh single-text array re-renders fine but silently deletes any reasoning / tool / card parts the turn already produced.
|
|
223
|
-
|
|
224
|
-
```js
|
|
225
|
-
// The fold. `@kitn.ai/ui/state` exports exactly this as `appendTextPart`.
|
|
226
|
-
const appendText = (parts, delta) => {
|
|
227
|
-
const last = parts[parts.length - 1];
|
|
228
|
-
return last?.type === 'text'
|
|
229
|
-
? [...parts.slice(0, -1), { ...last, text: last.text + delta }]
|
|
230
|
-
: [...parts, { type: 'text', text: delta }];
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
// ✅ re-renders, and keeps every part already on the message
|
|
234
|
-
chat.messages = chat.messages.map((m) =>
|
|
235
|
-
m.id === id ? { ...m, parts: appendText(m.parts, delta) } : m);
|
|
236
|
-
|
|
237
|
-
// ❌ does NOT re-render (same array, same object)
|
|
238
|
-
chat.messages[i].parts = appendText(chat.messages[i].parts, delta);
|
|
239
|
-
|
|
240
|
-
// ❌ re-renders, but drops the message's reasoning/tool/card parts
|
|
241
|
-
chat.messages = chat.messages.map((m) =>
|
|
242
|
-
m.id === id ? { ...m, parts: [{ type: 'text', text: answer }] } : m);
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Opening a new text part when the last part is not text is what stops a post-tool answer being glued onto the pre-tool text.
|
|
246
|
-
|
|
247
|
-
The same reassign rule applies to every array/object property (`models`, `context`, `suggestions`, …): replace, don't mutate.
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Element reference (83 elements, generated from custom-elements.json)
|
|
252
|
-
|
|
253
|
-
Every element also accepts the `theme` attribute. Array/object properties are marked with a `—` attribute: they must be set as JS properties.
|
|
254
|
-
|
|
255
|
-
### `kai-agent-card` / `AgentCard`
|
|
256
|
-
|
|
257
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
258
|
-
|
|
259
|
-
| Property | Attribute | Type | Description |
|
|
260
|
-
|---|---|---|---|
|
|
261
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
262
|
-
| `name` | `name` | `undefined \| string` | The agent's name, the primary label. Attribute: `name`. |
|
|
263
|
-
| `active` | `active` | `undefined \| false \| true` | Selected / focused state: highlighted border + surface. Attribute: `active`. |
|
|
264
|
-
| `needsAttention` | `needs-attention` | `undefined \| false \| true` | Raise a prominent "Needs you" pill plus a glowing amber edge. This is the attention-routing signal that pulls focus to this agent. Attribute: `needs-attention`. |
|
|
265
|
-
| `status` | — | `undefined \| { tone: "working" \| "idle" \| "done" \| "error" \| "blocked"; label?: undefined \| string; pulse?: undefined \| false \| true }` | Run status. A JS PROPERTY (object), not an attribute. Shape: `{ tone, label?, pulse? }`, where `tone` is one of `working` \| `idle` \| `done` \| `error` \| `blocked` (maps to the kit's tool hues), `label` is an optional short string beside the dot, and `pulse` animates the dot. Set it with `el.status = { tone: 'working', label: 'Working', pulse: true }`. |
|
|
266
|
-
|
|
267
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
268
|
-
|
|
269
|
-
| Event | `detail` type | Description |
|
|
270
|
-
|---|---|---|
|
|
271
|
-
| `kai-activate` | `CustomEvent` | The card was activated by a click, or by Enter / Space while focused. Promote this agent back to focus. |
|
|
272
|
-
| `kai-menu` | `CustomEvent` | The trailing "..." kebab was clicked. The consumer opens its own menu; the card only surfaces the affordance (the click does not also activate the card). |
|
|
273
|
-
|
|
274
|
-
**Styleable parts** (restyle from outside via `kai-agent-card::part(name)`):
|
|
275
|
-
|
|
276
|
-
| Part | Description |
|
|
277
|
-
|---|---|
|
|
278
|
-
| `::part(status)` | The leading tone-colored status dot. — `kai-agent-card::part(status) { width: 0.625rem; height: 0.625rem }` |
|
|
279
|
-
| `::part(menu)` | The trailing overflow ("...") menu button. — `kai-agent-card::part(menu) { opacity: 1 }` |
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
### `kai-artifact` / `Artifact`
|
|
284
|
-
|
|
285
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
286
|
-
|
|
287
|
-
| Property | Attribute | Type | Description |
|
|
288
|
-
|---|---|---|---|
|
|
289
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
290
|
-
| `src` | `src` | `undefined \| string` | URL the preview iframe frames. Consumer-controlled. |
|
|
291
|
-
| `files` | — | `undefined \| { path: string; url?: undefined \| string; code?: undefined \| string; language?: undefined \| string; type?: undefined \| "html" \| "pdf" \| "image" \| "other"; additions?: undefined \| number; deletions?: undefined \| number; status?: undefined \| "added" \| "modified" \| "deleted" \| "renamed" \| "untracked" }[]` | Files for the Code tab tree + each file's preview `url`. Omit for a preview-only artifact (the Code tab then has nothing to show; pair it with `no-tabs` to hide the toggle). Set as a JS property (array). |
|
|
292
|
-
| `tab` | `tab` | `undefined \| "preview" \| "code"` | Controlled active tab: `preview` or `code`. When set, the artifact follows it (re-asserted on change). Leave unset for an uncontrolled tab (see `defaultTab`). |
|
|
293
|
-
| `defaultTab` | `default-tab` | `undefined \| "preview" \| "code"` | Uncontrolled INITIAL tab (used only when `tab` is unset). Default `preview`. Seeds the starting tab; the user can then switch freely without the consumer re-asserting a controlled `tab`. |
|
|
294
|
-
| `activeFile` | `active-file` | `undefined \| string` | Selected file path. Syncs the tree highlight, Code source, and preview. |
|
|
295
|
-
| `sandbox` | `sandbox` | `undefined \| string` | iframe `sandbox` override. Secure default `allow-scripts allow-forms` (NOT `allow-same-origin`). |
|
|
296
|
-
| `iframeTitle` | `iframe-title` | `undefined \| string` | Accessible title for the preview iframe. |
|
|
297
|
-
| `maximized` | `maximized` | `undefined \| false \| true` | Reflects the artifact's own maximized view-state (usually driven by the protocol). |
|
|
298
|
-
| `expandable` | `expandable` | `undefined \| false \| true` | Show the expand-to-fill button (OPT-IN). |
|
|
299
|
-
| `openInTab` | `open-in-tab` | `undefined \| false \| true` | Show the open-in-new-tab button (OPT-IN). |
|
|
300
|
-
| `noNav` | `no-nav` | `undefined \| false \| true` | Hide back/forward. |
|
|
301
|
-
| `noReload` | `no-reload` | `undefined \| false \| true` | Hide reload. |
|
|
302
|
-
| `noHome` | `no-home` | `undefined \| false \| true` | Hide home. |
|
|
303
|
-
| `noPathField` | `no-path-field` | `undefined \| false \| true` | Hide the address field. |
|
|
304
|
-
| `noTabs` | `no-tabs` | `undefined \| false \| true` | Hide the Preview\|Code toggle. |
|
|
305
|
-
| `standalone` | `standalone` | `undefined \| false \| true` | Standalone chrome: rounded corners + border (else square, borderless in-panel). |
|
|
306
|
-
| `readonlyPath` | `readonly-path` | `undefined \| false \| true` | Show the address but make it read-only (visible, nav-tracking, non-editable). |
|
|
307
|
-
| `displayUrl` | `display-url` | `undefined \| string` | Friendly address shown in the path field instead of the real current url (read-only, non-navigable). Use when the framed url is not consumer-facing (e.g. a `data:` blob) so a clean address shows instead of leaking it. Scalar string: set as the `display-url` attribute or the `displayUrl` property. |
|
|
308
|
-
|
|
309
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
310
|
-
|
|
311
|
-
| Event | `detail` type | Description |
|
|
312
|
-
|---|---|---|
|
|
313
|
-
| `kai-file-select` | `CustomEvent<{ path: string }>` | Fired when a file is selected. `detail.path`. |
|
|
314
|
-
| `kai-maximize-change` | `CustomEvent<{ maximized: false \| true }>` | Artifact's own maximize button toggled (consumer-observable; non-bubbling). |
|
|
315
|
-
| `kai-maximize-intent` | `CustomEvent<{ requested: false \| true }>` | The maximize PROTOCOL intent, raised as a raw bubbling + composed CustomEvent (not through `dispatch`) so an enclosing `<kai-resizable>` can catch it and maximize the containing panel. Declared here so it is typed and reaches the generated API. Listen for it to drive maximize from your own chrome, or re-emit it to trigger one. |
|
|
316
|
-
| `kai-navigate` | `CustomEvent<{ url: string }>` | Fired when the preview navigates. `detail.url` = the new location. |
|
|
317
|
-
| `kai-tab-change` | `CustomEvent<{ tab: "preview" \| "code" }>` | Fired when the Preview\|Code tab changes. `detail.tab`. |
|
|
318
|
-
|
|
319
|
-
**Methods** (call on the element instance: `document.querySelector('kai-artifact').back()`):
|
|
320
|
-
|
|
321
|
-
| Method | Signature | Description |
|
|
322
|
-
|---|---|---|
|
|
323
|
-
| `back` | `(): void` | Go back in the artifact's own history stack (no-op when there's no prior entry). |
|
|
324
|
-
| `forward` | `(): void` | Go forward in the history stack (no-op when there's no forward entry). |
|
|
325
|
-
| `reload` | `(): void` | Force-reload the current preview url (also re-renders an inline PDF). |
|
|
326
|
-
| `home` | `(): void` | Navigate to the `src` home url (no-op when there's no `src`). |
|
|
327
|
-
| `navigate` | `(url: string): void` | Push + load a url in the preview, the path-field submit path (fires kai-navigate). |
|
|
328
|
-
| `selectFile` | `(path: string): void` | Select a file by path: highlights the tree, shows its source, navigates the preview (fires kai-file-select + kai-navigate). Named selectFile to avoid the `activeFile` prop. |
|
|
329
|
-
| `openExternal` | `(): void` | Open the current url in a new browser tab (no-op when there's no concrete url). Named openExternal, NOT openInTab, which is a prop (toolbar button visibility). |
|
|
330
|
-
| `maximize` | `(): void` | Enter the maximized view-state (fires kai-maximize-change{maximized:true}). Named maximize, NOT maximized, which is a prop. |
|
|
331
|
-
| `restore` | `(): void` | Exit the maximized view-state (fires kai-maximize-change{maximized:false}). |
|
|
332
|
-
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
### `kai-attachments` / `Attachments`
|
|
336
|
-
|
|
337
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
338
|
-
|
|
339
|
-
| Property | Attribute | Type | Description |
|
|
340
|
-
|---|---|---|---|
|
|
341
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
342
|
-
| `items` | — | `undefined \| { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[]` | The attachments to render. Omit (or pass an empty array) for the empty state, which shows `emptyText` if set and nothing otherwise. Set as a JS property (array). |
|
|
343
|
-
| `variant` | `variant` | `undefined \| "grid" \| "inline" \| "list"` | Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. |
|
|
344
|
-
| `hoverCard` | `hover-card` | `undefined \| false \| true` | Wrap each item in a hover card that previews its details. |
|
|
345
|
-
| `removable` | `removable` | `undefined \| false \| true` | Show a remove button per item; clicking it fires a `kai-remove` event. |
|
|
346
|
-
| `showMediaType` | `show-media-type` | `undefined \| false \| true` | Also show the media type beneath the filename (non-grid variants). |
|
|
347
|
-
| `emptyText` | `empty-text` | `undefined \| string` | Text shown when `items` is empty. |
|
|
348
|
-
|
|
349
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
350
|
-
|
|
351
|
-
| Event | `detail` type | Description |
|
|
352
|
-
|---|---|---|
|
|
353
|
-
| `kai-remove` | `CustomEvent<{ id: string }>` | A remove button was clicked. |
|
|
354
|
-
|
|
355
|
-
**Styleable parts** (restyle from outside via `kai-attachments::part(name)`):
|
|
356
|
-
|
|
357
|
-
| Part | Description |
|
|
358
|
-
|---|---|
|
|
359
|
-
| `::part(preview)` | The image shown in an attachment’s hover-card preview. Bounded by default (max ~320×256, aspect preserved) so a large image never blows up the card. Raise or lower the cap from outside. — `kai-attachments::part(preview) { max-width: 32rem; max-height: 24rem }` |
|
|
360
|
-
| `::part(attachment)` | One attachment item: the chip, row or tile, whichever variant is rendering. Restyle its background, radius or border from outside without caring which layout it is. — `kai-chat::part(attachment) { border-radius: 0.25rem }` |
|
|
361
|
-
| `::part(attachment-name)` | The attachment’s filename label. Present in every variant that shows one (a grid tile omits it for an image, which is its own label). Retune its type or hide it entirely. — `kai-chat::part(attachment-name) { font-size: 0.75rem }` |
|
|
362
|
-
|
|
363
|
-
---
|
|
364
|
-
|
|
365
|
-
### `kai-audio-visualizer` / `AudioVisualizer`
|
|
366
|
-
|
|
367
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
368
|
-
|
|
369
|
-
| Property | Attribute | Type | Description |
|
|
370
|
-
|---|---|---|---|
|
|
371
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
372
|
-
| `variant` | `variant` | `undefined \| string` | Look to render: `bar` (default), `grid`, `radial`, `wave`, `aurora`, `custom`. `aura` is accepted as a LiveKit-markup alias for `aurora`. Attribute: `variant`. |
|
|
373
|
-
| `state` | `state` | `undefined \| string` | `idle` (default), `connecting`, `listening`, `thinking`, `speaking`, `disconnected` (connection down: the dead, flat look). LiveKit's room-lifecycle state names are accepted as aliases. Attribute: `state`. |
|
|
374
|
-
| `size` | `size` | `undefined \| string` | `icon` \| `sm` \| `md` (default) \| `lg` \| `xl`. Attribute: `size`. |
|
|
375
|
-
| `barCount` | `bar-count` | `undefined \| number` | Bars to draw. Bar and radial only. Attribute: `bar-count`. |
|
|
376
|
-
| `count` | `count` | `undefined \| number` | Grid only: rows and columns of the (always square) grid. Attribute: `count`. |
|
|
377
|
-
| `radius` | `radius` | `undefined \| number` | Radial only: ring distance from center, in px. Attribute: `radius`. |
|
|
378
|
-
| `spread` | `spread` | `undefined \| number` | Grid only: ring distance for the connecting animation, in cells. Attribute: `spread`. |
|
|
379
|
-
| `interval` | `interval` | `undefined \| number` | Grid only: ms between scripted frames. Attribute: `interval`. |
|
|
380
|
-
| `color` | `color` | `undefined \| string` | CSS color for the geometry, overriding the inherited `currentColor`. Attribute: `color`. |
|
|
381
|
-
| `complexity` | `complexity` | `undefined \| number` | Shader variants only: pattern density, 0..1. Attribute: `complexity`. |
|
|
382
|
-
| `label` | `label` | `undefined \| string` | Setting this makes the element an announced image (`role="img"`) instead of decorative (`aria-hidden`). Attribute: `label`. |
|
|
383
|
-
| `stream` | — | `undefined \| MediaStream` | Live microphone or WebRTC audio to analyze. JS property only. NOTE: amplitude renders only while state is "speaking" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio. |
|
|
384
|
-
| `audioElement` | — | `undefined \| HTMLMediaElement` | An `<audio>` or `<video>` element to tap for its audio. JS property only. NOTE: amplitude renders only while state is "speaking" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio. |
|
|
385
|
-
| `bands` | — | `undefined \| number[]` | Pre-computed levels, 0..1. Set this and no AudioContext is ever built, which is what keeps headless/SSR rendering and browser-speech-synthesis playback (which exposes no audio node) free of Web Audio entirely. JS property only. A new array reference is required for each update; mutating the existing array in place will not re-render. NOTE: amplitude renders only while state is "speaking" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio. |
|
|
386
|
-
| `listeningAmplitude` | `listening-amplitude` | `undefined \| false \| true` | Render live amplitude during the listening state as well, using the same presentation as speaking. Off by default, which keeps LiveKit parity: amplitude from stream, audio-element or bands renders only while state is "speaking". Set it to show a real mic-level picture while the user is the one talking. Boolean. Attribute: `listening-amplitude` (a bare attribute means true; reflected, so the property reads back what the attribute set). |
|
|
387
|
-
| `shader` | — | `undefined \| { fragment: string; uniforms?: undefined \| Record<string, { type: "1f" \| "1i" \| "1fv" \| "2f" \| "3f" \| "3fv" \| "4f" \| "4fv" \| "Matrix2fv" \| "Matrix3fv" \| "Matrix4fv"; value: number \| number[] }> }` | Custom fragment shader for `variant="custom"`. JS property only. |
|
|
388
|
-
| `animateWhenNotVisible` | `animate-when-not-visible` | `undefined \| false \| true` | Shader variants only: keep animating while scrolled off screen. Off by default, which stops drawing and releases the WebGL context until the element comes back (browsers ration contexts to roughly 16 a page). Does not override `prefers-reduced-motion`. Attribute: `animate-when-not-visible`. |
|
|
389
|
-
|
|
390
|
-
_No events._
|
|
391
|
-
|
|
392
|
-
**Styleable parts** (restyle from outside via `kai-audio-visualizer::part(name)`):
|
|
393
|
-
|
|
394
|
-
| Part | Description |
|
|
395
|
-
|---|---|
|
|
396
|
-
| `::part(bar)` | A single bar in the `bar` variant, or a single spoke in the `radial` variant. Also carries `data-kai-index` and `data-kai-highlighted` ("true"/"false") for use inside the shadow root; to style the lit state from OUTSIDE, combine with the `highlighted` part below rather than an attribute selector. — `kai-audio-visualizer::part(bar) { border-radius: 2px } kai-audio-visualizer::part(bar highlighted) { background: var(--brand) }` |
|
|
397
|
-
| `::part(cell)` | A single dot in the `grid` variant. Also carries `data-kai-index` and `data-kai-highlighted` ("true"/"false") for use inside the shadow root; to style the lit state from OUTSIDE, combine with the `highlighted` part below rather than an attribute selector. — `kai-audio-visualizer::part(cell) { border-radius: 9999px } kai-audio-visualizer::part(cell highlighted) { background: var(--brand) }` |
|
|
398
|
-
| `::part(highlighted)` | A second part TOKEN present on a `bar` or `cell` exactly when the sequencer or live audio has it lit, not a standalone styleable element. Combine it in the same `::part()` argument: `::part(bar highlighted)` or `::part(cell highlighted)`. This is the external equivalent of the internal `data-kai-highlighted="true"` attribute, which a `::part()` selector cannot reach (an attribute selector cannot follow a pseudo-element). — `kai-audio-visualizer::part(bar highlighted) { background: var(--brand) } kai-audio-visualizer::part(cell highlighted) { background: var(--brand) }` |
|
|
399
|
-
| `::part(canvas)` | The WebGL canvas backing the `wave` and `aurora` variants. Restyle its size or radius, or layer a mask/filter, from outside. — `kai-audio-visualizer::part(canvas) { border-radius: 0.75rem }` |
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
### `kai-avatar` / `Avatar`
|
|
404
|
-
|
|
405
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
406
|
-
|
|
407
|
-
| Property | Attribute | Type | Description |
|
|
408
|
-
|---|---|---|---|
|
|
409
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
410
|
-
| `src` | `src` | `undefined \| string` | Image URL/data-URI. When absent, the `fallback` initials show instead. |
|
|
411
|
-
| `alt` | `alt` | `undefined \| string` | Alt text for the image. Defaults to `fallback`. |
|
|
412
|
-
| `fallback` | `fallback` | `undefined \| string` | Short text shown when there's no image, usually initials (e.g. "JD", "AI"). |
|
|
413
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg"` | Size token: `sm` \| `md` (default) \| `lg`. |
|
|
414
|
-
|
|
415
|
-
_No events._
|
|
416
|
-
|
|
417
|
-
---
|
|
418
|
-
|
|
419
|
-
### `kai-badge` / `Badge`
|
|
420
|
-
|
|
421
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
422
|
-
|
|
423
|
-
| Property | Attribute | Type | Description |
|
|
424
|
-
|---|---|---|---|
|
|
425
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
426
|
-
| `variant` | `variant` | `undefined \| "default" \| "count" \| "citation"` | `default` (muted pill) · `count` (compact number badge) · `citation` (filled primary, for inline citation markers). Defaults to `default`. |
|
|
427
|
-
|
|
428
|
-
_No events._
|
|
429
|
-
|
|
430
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
431
|
-
|
|
432
|
-
| Slot | Mode | Description |
|
|
433
|
-
|---|---|---|
|
|
434
|
-
| _(default)_ | inject | The badge's label: text, or a small inline icon plus text. |
|
|
435
|
-
|
|
436
|
-
**Styleable parts** (restyle from outside via `kai-badge::part(name)`):
|
|
437
|
-
|
|
438
|
-
| Part | Description |
|
|
439
|
-
|---|---|
|
|
440
|
-
| `::part(badge)` | The badge pill. Restyle its background, color, or shape; the `variant` prop (default/count/citation) sets the defaults. — `kai-badge::part(badge) { background: var(--color-primary); color: var(--color-primary-foreground) }` |
|
|
441
|
-
|
|
442
|
-
---
|
|
443
|
-
|
|
444
|
-
### `kai-button` / `Button`
|
|
445
|
-
|
|
446
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
447
|
-
|
|
448
|
-
| Property | Attribute | Type | Description |
|
|
449
|
-
|---|---|---|---|
|
|
450
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
451
|
-
| `variant` | `variant` | `undefined \| "default" \| "subtle" \| "ghost" \| "outline" \| "destructive"` | Visual style. `default` (filled), `subtle` (muted text, hover tint, the toolbar icon look), `ghost` (transparent, hover fill), `outline`, or `destructive`. Defaults to `default`. |
|
|
452
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg" \| "icon" \| "icon-sm"` | Size token. `icon` / `icon-sm` are square (for icon-only buttons); `sm` / `md` / `lg` size text buttons. Defaults to `md`. |
|
|
453
|
-
| `icon` | `icon` | `undefined \| string` | Leading icon: a named icon (e.g. `"mic"`, `"plus"`), an image URL/data-URI, or plain text. Renders before any slotted label. |
|
|
454
|
-
| `iconTrailing` | `icon-trailing` | `undefined \| string` | Trailing icon, after the label (e.g. `"chevron-down"` for a menu affordance). |
|
|
455
|
-
| `label` | `label` | `undefined \| string` | Accessible name. REQUIRED for icon-only buttons (no visible text); ignored when you slot visible text, which already names the button. An `aria-label` on top of visible text REPLACES that name rather than adding to it, so a button reading "Save" that answers to "Submit" is unusable by speech input (WCAG 2.5.3, Label in Name). The visible text wins. An `icon` / `icon-sm` size hides the slot, which makes the button icon-only whatever you slotted, so `label` is what names it there. |
|
|
456
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the button (non-interactive, dimmed). |
|
|
457
|
-
| `full` | `full` | `undefined \| false \| true` | Stretch the button to the full width of its container (a block button), e.g. a card CTA or a stacked action. Attribute: `full`. |
|
|
458
|
-
| `align` | `align` | `undefined \| "start" \| "center" \| "end"` | Justify the button's content: `start`, `center` (default), or `end`. Combine with `full` for a full-width, left-aligned button. |
|
|
459
|
-
| `type` | `type` | `undefined \| "button" \| "submit" \| "reset"` | Native button `type`. Defaults to `button` (so it never submits a form). |
|
|
460
|
-
|
|
461
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
462
|
-
|
|
463
|
-
| Event | `detail` type | Description |
|
|
464
|
-
|---|---|---|
|
|
465
|
-
| `kai-click` | `CustomEvent` | The button was activated (pointer or keyboard). Carries no detail. The native `click` also bubbles (composed) for consumers who prefer it. |
|
|
466
|
-
|
|
467
|
-
**Methods** (call on the element instance: `document.querySelector('kai-button').focus(…)`):
|
|
468
|
-
|
|
469
|
-
| Method | Signature | Description |
|
|
470
|
-
|---|---|---|
|
|
471
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the inner `<button>` (host.focus() would focus the wrapper). |
|
|
472
|
-
| `blur` | `(): void` | Blur the inner `<button>`. |
|
|
473
|
-
| `click` | `(): void` | Programmatically activate the button. Runs the same path as a user click and fires kai-click. Forwarding to the inner button means `disabled` is respected automatically. |
|
|
474
|
-
|
|
475
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
476
|
-
|
|
477
|
-
| Slot | Mode | Description |
|
|
478
|
-
|---|---|---|
|
|
479
|
-
| _(default)_ | inject | The button's label. Omit it for an icon-only button (pair with `aria-label`). |
|
|
480
|
-
| `icon` | replace | A custom leading icon (any inline SVG, inherits `currentColor`). Wins over the `icon` prop. |
|
|
481
|
-
|
|
482
|
-
**Styleable parts** (restyle from outside via `kai-button::part(name)`):
|
|
483
|
-
|
|
484
|
-
| Part | Description |
|
|
485
|
-
|---|---|
|
|
486
|
-
| `::part(button)` | The button element. Restyle radius, padding, colors, or weight from outside; the `variant`/`size` props set the defaults. — `kai-button::part(button) { border-radius: 9999px; font-weight: 600 }` |
|
|
487
|
-
|
|
488
|
-
---
|
|
489
|
-
|
|
490
|
-
### `kai-card` / `Card`
|
|
491
|
-
|
|
492
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
493
|
-
|
|
494
|
-
| Property | Attribute | Type | Description |
|
|
495
|
-
|---|---|---|---|
|
|
496
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
497
|
-
| `appearance` | `appearance` | `undefined \| "outlined" \| "filled" \| "plain" \| "accent"` | Surface treatment: `outlined` (default) \| `filled` \| `plain` \| `accent`. Attribute: `appearance`. |
|
|
498
|
-
| `orientation` | `orientation` | `undefined \| "vertical" \| "horizontal" \| "responsive"` | `vertical` (default, media on top) \| `horizontal` (media at the start) \| `responsive` (horizontal when the card's container is wide enough, else vertical, via a container query on the card's own width). Attribute: `orientation`. |
|
|
499
|
-
| `collapse` | `collapse` | `undefined \| string` | The card width below which a `responsive` card collapses to vertical and the footer actions stack. A CSS length; default `28rem`. Attribute: `collapse`. |
|
|
500
|
-
| `dense` | `dense` | `undefined \| false \| true` | Tighter spacing for dense lists. Attribute: `dense`. |
|
|
501
|
-
| `dismissible` | `dismissible` | `undefined \| false \| true` | Show a close (×) that hides the card and emits `kai-dismiss`. Attribute: `dismissible`. Off by default. |
|
|
502
|
-
| `href` | `href` | `undefined \| string` | Render the whole card as a link. Attribute: `href`. Wins over `clickable`. |
|
|
503
|
-
| `target` | `target` | `undefined \| string` | `target` for the `href` anchor. Attribute: `target`. |
|
|
504
|
-
| `rel` | `rel` | `undefined \| string` | `rel` for the `href` anchor. Attribute: `rel`. |
|
|
505
|
-
| `clickable` | `clickable` | `undefined \| false \| true` | Make the whole card a button (`role="button"`, Enter/Space, hover affordance) that emits `kai-card-click`. Attribute: `clickable`. Ignored when `href` is set. |
|
|
506
|
-
|
|
507
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
508
|
-
|
|
509
|
-
| Event | `detail` type | Description |
|
|
510
|
-
|---|---|---|
|
|
511
|
-
| `kai-card-click` | `CustomEvent` | A `clickable`/`href` card was activated (click, or Enter/Space). |
|
|
512
|
-
| `kai-dismiss` | `CustomEvent` | The card was dismissed via its × (it also hides itself). |
|
|
513
|
-
|
|
514
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
515
|
-
|
|
516
|
-
| Slot | Mode | Description |
|
|
517
|
-
|---|---|---|
|
|
518
|
-
| _(default)_ | inject | The card body, below the header/media regions. |
|
|
519
|
-
| `media` | inject | Full-bleed media (image/video/illustration) at the top (vertical) or start (horizontal). Clipped to the card corners. |
|
|
520
|
-
| `header` | inject | Header content, e.g. a title. Rendered above the body. |
|
|
521
|
-
| `header-actions` | inject | An actions cluster pinned to the end of the header row. |
|
|
522
|
-
| `footer` | inject | Footer content rendered below the body. |
|
|
523
|
-
| `footer-actions` | inject | Action buttons pinned to the end of the footer. Do NOT combine with a clickable/href card (nested interactive). |
|
|
524
|
-
|
|
525
|
-
**Styleable parts** (restyle from outside via `kai-card::part(name)`):
|
|
526
|
-
|
|
527
|
-
| Part | Description |
|
|
528
|
-
|---|---|
|
|
529
|
-
| `::part(card)` | The card root (a div, or an a when href is set). Restyle its radius, border, or background; set --kai-card-spacing for padding/gaps (the dense prop sets the compact default). — `kai-card::part(card) { border-radius: 1rem; --kai-card-spacing: 1.5rem }` |
|
|
530
|
-
| `::part(media)` | The full-bleed media region. Cap or crop it from outside (e.g. a fixed height with object-fit). — `kai-card::part(media) { max-height: 12rem }` |
|
|
531
|
-
| `::part(header)` | The header row (header content + header-actions). Add a divider or adjust its alignment. — `kai-card::part(header) { border-bottom: 1px solid var(--color-border) }` |
|
|
532
|
-
| `::part(body)` | The default-slot body region. — `kai-card::part(body) { font-size: 0.9375rem }` |
|
|
533
|
-
| `::part(footer)` | The footer row (footer content + footer-actions). — `kai-card::part(footer) { border-top: 1px solid var(--color-border) }` |
|
|
534
|
-
| `::part(dismiss)` | The dismiss (×) button shown when dismissible. Recolor or reposition it from outside. — `kai-card::part(dismiss) { color: var(--color-muted-foreground) }` |
|
|
535
|
-
|
|
536
|
-
---
|
|
537
|
-
|
|
538
|
-
### `kai-cards` / `Cards`
|
|
539
|
-
|
|
540
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
541
|
-
|
|
542
|
-
| Property | Attribute | Type | Description |
|
|
543
|
-
|---|---|---|---|
|
|
544
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
545
|
-
| `cards` | — | `undefined \| { type: string; id: string; data: unknown; title?: undefined \| string; resolution?: undefined \| { kind: "action"; action: string; payload?: unknown; at?: undefined \| string } \| { kind: "submit"; data: unknown; at?: undefined \| string } \| { kind: "dismissed"; at?: undefined \| string } \| { kind: "expired"; reason?: undefined \| string; at?: undefined \| string } }[]` | The stream of card envelopes to render. Set as a JS PROPERTY: `el.cards = [...]`. |
|
|
546
|
-
| `types` | — | `undefined \| Record<string, string>` | Optional type→tag overrides/additions (merged over the built-ins). Property: `el.types`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type. |
|
|
547
|
-
| `schemas` | — | `undefined \| Record<string, object>` | JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `types`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.schemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name, matching `mergeCardTags`, where your entry is spread over ours. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. See `CardSchemaMap` in components/card-renderer.tsx. |
|
|
548
|
-
| `policy` | — | `undefined \| { onSubmit?: undefined \| (cardId: string, data: unknown) => void; onAction?: undefined \| (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: undefined \| (text: string, opts: { mode: "compose" \| "send"; context?: unknown; }) => void; onOpen?: undefined \| (url: string, target: "tab" \| "artifact") => void; onState?: undefined \| (cardId: string, patch: unknown) => void; onDismiss?: undefined \| (cardId: string) => void; onReopen?: undefined \| (cardId: string) => void; onError?: undefined \| (cardId: string, message: string) => void; maxSendPromptMode?: undefined \| "compose" \| "send" }` | Optional CardPolicy handling child events. Property: `el.policy`. |
|
|
549
|
-
| `validateCards` | `validate-cards` | `undefined \| false \| true` | Validate each envelope's `data` against the schema for its type before rendering it, using a built-in's own schema or yours from `schemas`. Default `true`; set `validate-cards="false"` (or `el.validateCards = false`) to opt out. A hard failure (wrong type, a missing required field) renders a diagnostic naming the field instead of the card; a soft failure (bounds) renders the card unchanged. Both emit a contract `error` event. On in production too: a model emitting a bad shape is a production failure mode, so stripping the check there would hide it from exactly the person who needs to see it. |
|
|
550
|
-
|
|
551
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
552
|
-
|
|
553
|
-
| Event | `detail` type | Description |
|
|
554
|
-
|---|---|---|
|
|
555
|
-
| `kai-card-resolved` | `CustomEvent<{ cardId: string; resolution: { kind: "action"; action: string; payload?: unknown; at?: undefined \| string } \| { kind: "submit"; data: unknown; at?: undefined \| string } \| { kind: "dismissed"; at?: undefined \| string } \| { kind: "expired"; reason?: undefined \| string; at?: undefined \| string } }>` | A child card transitioned to a resolved/deferred state (an action was chosen, a form/tasks submission landed, or it was dismissed). Re-emitted off the host as a non-bubbling convenience event so a consumer can observe resolution centrally without diffing the cards array. `detail` = `{ cardId, resolution }`. (A `reopen` un-resolves a card and has no `CardResolution`, so it does NOT fire this; observe reopen via the underlying bubbling `kai-card` event.) |
|
|
556
|
-
|
|
557
|
-
**Methods** (call on the element instance: `document.querySelector('kai-cards').resolve(…)`):
|
|
558
|
-
|
|
559
|
-
| Method | Signature | Description |
|
|
560
|
-
|---|---|---|
|
|
561
|
-
| `resolve` | `(cardId: string, resolution: CardResolution): void` | Programmatically resolve a child card by id: set that envelope's `resolution` so the child re-renders into its read-only/resolved view. The imperative twin of the consumer mutating the cards array. No-op for an unknown id. |
|
|
562
|
-
| `dismiss` | `(cardId: string): void` | Collapse a card to its re-openable stub from the host side. Convenience for `resolve(cardId, { kind: 'dismissed' })`. |
|
|
563
|
-
| `getCard` | `(cardId: string): HTMLElement \| null` | Return the live child element node for a card id (or null) so consumers can call that card's own methods (focus/expand/…) without a shadow-DOM query. |
|
|
564
|
-
|
|
565
|
-
---
|
|
566
|
-
|
|
567
|
-
### `kai-chain-of-thought` / `ChainOfThought`
|
|
568
|
-
|
|
569
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
570
|
-
|
|
571
|
-
| Property | Attribute | Type | Description |
|
|
572
|
-
|---|---|---|---|
|
|
573
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
574
|
-
| `steps` | — | `undefined \| { label: string; content?: undefined \| string; id?: undefined \| string }[]` | The reasoning steps. Set as a JS property. Compound sub-parts collapse to this one data model (Route 1). Each `{ label, content?, id? }`. Omit to supply the steps as `<kai-step>` light-DOM children instead; when both are present the property's steps come first. |
|
|
575
|
-
| `type` | `type` | `undefined \| "single" \| "multiple"` | Open mode: `'multiple'` (default, any number of steps open at once) or `'single'` (at most one open; opening a step closes the others). |
|
|
576
|
-
| `value` | — | `undefined \| string \| string[]` | Controlled open step key(s). When set, it WINS over user interaction (the consumer owns the open set). String in `single` mode, string[] in `multiple` mode. Set as a JS property. |
|
|
577
|
-
| `defaultValue` | — | `undefined \| string \| string[]` | Uncontrolled INITIAL open step key(s), seeding which steps render expanded. Ignored once `value` is provided. Set as a JS property. |
|
|
578
|
-
|
|
579
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
580
|
-
|
|
581
|
-
| Event | `detail` type | Description |
|
|
582
|
-
|---|---|---|
|
|
583
|
-
| `kai-value-change` | `CustomEvent<{ value: string \| string[] }>` | The open set changed, by user click OR an expand()/collapse()/toggle() call. `value` is a string in `single` mode, a string[] in `multiple` mode. (Maps Radix Accordion's onValueChange.) |
|
|
584
|
-
|
|
585
|
-
**Methods** (call on the element instance: `document.querySelector('kai-chain-of-thought').expand(…)`):
|
|
586
|
-
|
|
587
|
-
| Method | Signature | Description |
|
|
588
|
-
|---|---|---|
|
|
589
|
-
| `expand` | `(index?: number): void` | Open one step's detail by index, or ALL steps when called with no arg. In `single` mode opening one step closes the others (expand-all keeps the last). |
|
|
590
|
-
| `collapse` | `(index?: number): void` | Close one step's detail by index, or ALL steps when called with no arg. |
|
|
591
|
-
| `toggle` | `(index?: number): void` | Flip one step's open state by index. |
|
|
592
|
-
|
|
593
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
594
|
-
|
|
595
|
-
| Child element | Attributes | Text content | Notes |
|
|
596
|
-
|---|---|---|---|
|
|
597
|
-
| `<kai-step>` | `label`, `step-id` | yes | Parse a single light-DOM `<kai-step>` element into a `Step` descriptor. Attribute mapping: - `label` → Step.label (the always-visible heading) - `step-id` → Step.id (optional stable open-set key) - textContent → Step.content (optional expandable detail) |
|
|
598
|
-
|
|
599
|
-
---
|
|
600
|
-
|
|
601
|
-
### `kai-chat` / `Chat`
|
|
602
|
-
|
|
603
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
604
|
-
|
|
605
|
-
| Property | Attribute | Type | Description |
|
|
606
|
-
|---|---|---|---|
|
|
607
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
608
|
-
| `value` | — | `undefined \| string \| ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]` | Value of the input. A **string** is controlled (the host owns the text and updates it on `kai-value-change`). A **ComposerDoc** is a one-time seed that pre-populates pills; the user then edits freely. Leave unset for uncontrolled. |
|
|
609
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder text shown in the empty input. |
|
|
610
|
-
| `loading` | `loading` | `undefined \| false \| true` | When true, shows the loading/streaming state and disables submit (use while awaiting the assistant's reply). |
|
|
611
|
-
| `suggestions` | — | `undefined \| string[]` | Starter prompts shown above the input when the thread is empty. Clicking one follows `suggestionMode`. Set as a JS property. |
|
|
612
|
-
| `suggestionMode` | `suggestion-mode` | `undefined \| "submit" \| "fill"` | What clicking a suggestion does: `'submit'` (default) sends it immediately as if typed and submitted; `'fill'` just places it in the input. |
|
|
613
|
-
| `persistSuggestions` | `persist-suggestions` | `undefined \| false \| true` | Keep suggestions visible after the conversation starts. By default suggestions are conversation starters and hide once `messages` is non-empty; set this to keep them always shown. Default false. |
|
|
614
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Body/prose font scale for rendered markdown (`'xs' \| 'sm' \| 'base' \| 'lg'`). Defaults to `'sm'`. |
|
|
615
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme name for syntax-highlighted code blocks (e.g. `'github-dark-dimmed'`). |
|
|
616
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. |
|
|
617
|
-
| `chatTitle` | `chat-title` | `undefined \| string` | Optional header title shown on the left of the header. |
|
|
618
|
-
| `models` | — | `undefined \| { id: string; name: string; provider?: undefined \| string; description?: undefined \| string; group?: undefined \| string }[]` | Optional model list. When set (>1 model) a ModelSwitcher is shown in the header and a `kai-model-change` event fires on selection. |
|
|
619
|
-
| `currentModel` | `current-model` | `undefined \| string` | The currently selected model id (pairs with `models`). |
|
|
620
|
-
| `context` | — | `undefined \| { usedTokens: number; maxTokens: number; inputTokens?: undefined \| number; outputTokens?: undefined \| number; estimatedCost?: undefined \| number }` | Optional context-window token usage. When set, a Context token meter is shown in the header. |
|
|
621
|
-
| `scrollButton` | `scroll-button` | `undefined \| false \| true` | Show the scroll-to-bottom button inside the scroll area. Default true. |
|
|
622
|
-
| `headerStart` | `header-start` | `undefined \| false \| true` | Whether the host has `slot="header-start"` content (left of the title). Set by the `<kai-chat>` facade so a custom control forces the header open. |
|
|
623
|
-
| `headerEnd` | `header-end` | `undefined \| false \| true` | Whether the host has `slot="header-end"` content (right of the controls). |
|
|
624
|
-
| `headerFull` | `header-full` | `undefined \| false \| true` | REPLACE: full custom header in place of the built-in title/model/context bar. |
|
|
625
|
-
| `sidebar` | `sidebar` | `undefined \| false \| true` | INJECT: left sidebar column (e.g. a conversation list / your own nav). |
|
|
626
|
-
| `empty` | `empty` | `undefined \| false \| true` | REPLACE: custom zero-state rendered in the message area while the thread is empty (replaces the empty message list only; the composer and its suggestions still render). |
|
|
627
|
-
| `composer` | `composer` | `undefined \| false \| true` | REPLACE: full custom composer in place of the built-in prompt input. The projected content wires its own submit (the data-flow boundary). |
|
|
628
|
-
| `composerActions` | `composer-actions` | `undefined \| false \| true` | INJECT: accessory row just above the composer (e.g. extra actions). |
|
|
629
|
-
| `footer` | `footer` | `undefined \| false \| true` | INJECT: footer row below the composer (disclaimers, token meter, …). |
|
|
630
|
-
| `webSearch` | `web-search` | `undefined \| false \| true` | Show a web-search (Globe) button in the input toolbar; calls `onWebSearch`. |
|
|
631
|
-
| `voice` | `voice` | `undefined \| false \| true` | Show a Voice (Mic) button in the input toolbar; fires a `voice` event. |
|
|
632
|
-
| `triggers` | — | `undefined \| { char: string; kind: string; items?: undefined \| { id: string; label: string; icon?: undefined \| string; description?: undefined \| string; group?: undefined \| string; kind?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }[]` | Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu that inserts an atomic pill (`/` skills, `@` agents/plugins). Set as a JS property; forwarded to the input. |
|
|
633
|
-
| `kindIcons` | — | `undefined \| Record<string, string>` | Default icon per entity kind (kind → image src) for pills/menu items. |
|
|
634
|
-
| `actionsReveal` | `actions-reveal` | `undefined \| "always" \| "hover"` | Whether each message's action bar is always visible (`'always'`, default) or only revealed on hover of that message row (`'hover'`). |
|
|
635
|
-
| `accept` | `accept` | `undefined \| string` | Which attachment media types the user may stage, in HTML `accept` syntax: `<kai-chat accept="image/*,application/pdf">`. A plain string, so unlike `messages` it DOES work as an attribute. Omitted means no filter. MEDIA TYPES ONLY -- exact (`image/png`) or subtype wildcard (`text/*`). HTML allows a file extension here and this does not: `accept=".py"` THROWS with the entry named, rather than silently resolving to a picker that accepts nothing. It can only NARROW what the kit can already encode: `accept="image/*"` resolves to the four image formats both APIs take, not to every image type the OS offers. Pass the SAME string to `toOpenAIMessages(msgs, { accept })` and the picker and the wire cannot disagree -- both resolve it through `resolveMediaPolicy` against one declaration. That declaration is readable as `encodableMediaTypes()` from `@kitn.ai/ui/wire`, if you would rather build your own picker than use this prop. |
|
|
636
|
-
| `messages` | — | `undefined \| { id: string; role: "user" \| "assistant"; parts: ({ type: "text"; text: string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "reasoning"; text: string; label?: undefined \| string; index?: undefined \| number; streamId?: undefined \| string; signature?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "tool"; tool: { type: string; kind?: undefined \| "command" \| "file-change" \| "search" \| "fetch" \| "mcp" \| "image" \| "generic"; state: "input-streaming" \| "input-available" \| "output-available" \| "output-error"; input?: undefined \| Record<string, unknown>; rawInput?: undefined \| string; output?: undefined \| Record<string, unknown>; toolCallId?: undefined \| string; errorText?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "card"; envelope: { type: string; id: string; data: unknown; title?: undefined \| string; resolution?: undefined \| { kind: "action"; action: string; payload?: unknown; at?: undefined \| string } \| { kind: "submit"; data: unknown; at?: undefined \| string } \| { kind: "dismissed"; at?: undefined \| string } \| { kind: "expired"; reason?: undefined \| string; at?: undefined \| string } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "source"; source: { id?: undefined \| string; url?: undefined \| string; title?: undefined \| string; snippet?: undefined \| string; index?: undefined \| number }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "file"; attachment: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }; raw?: undefined \| { source: string; payload: unknown } })[]; actions?: undefined \| ("copy" \| "like" \| "dislike" \| "regenerate" \| "edit" \| { id: string; label: string; icon?: undefined \| string; tooltip?: undefined \| string })[]; avatar?: undefined \| { src?: undefined \| string; fallback?: undefined \| string; alt?: undefined \| string }; feedback?: undefined \| "like" \| "dislike" }[]` | The full message thread to render, newest last. Each entry carries its role, ordered `parts`, and optional actions/avatar/feedback. Set as a JS property (`el.messages = [...]`); a NEW array reference per streaming chunk re-renders (mutating in place does not). Omit for an empty thread. Re-declared here (rather than inherited from `ChatThreadProps`) because the ELEMENT registers a `[]` default and renders the empty state without it, while the SolidJS `<ChatThread>` component still requires it. The facade hands it a validated array either way. Matches `<kai-thread>`. |
|
|
637
|
-
| `cardTypes` | — | `undefined \| Record<string, string>` | Optional card type -> custom-element tag overrides/additions for `card` parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type. |
|
|
638
|
-
| `cardSchemas` | — | `undefined \| Record<string, object>` | JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `cardTypes`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. |
|
|
639
|
-
|
|
640
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
641
|
-
|
|
642
|
-
| Event | `detail` type | Description |
|
|
643
|
-
|---|---|---|
|
|
644
|
-
| `kai-attachments-change` | `CustomEvent<{ attachments: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[] }>` | The staged attachments changed (file added or removed). Carries the full current list so a consumer can react in real time. |
|
|
645
|
-
| `kai-attachments-rejected` | `CustomEvent<{ rejected: { filename: string; mediaType: string; reason: "filtered" \| "unsupported" }[] }>` | One or more picked files were refused because `accept` excluded them. The element renders NO message of its own: it reports the facts (name, media type, whether the kit could have sent it) and what the user should see is the application's call. Only ever fires when `accept` is set. |
|
|
646
|
-
| `kai-message-action` | `CustomEvent<{ messageId: string; action: string; state?: undefined \| "on" \| "off" }>` | An action button on a message was clicked. `action` is the built-in name or custom id. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. |
|
|
647
|
-
| `kai-model-change` | `CustomEvent<{ modelId: string }>` | The header model switcher changed. |
|
|
648
|
-
| `kai-submit` | `CustomEvent<{ value: string; attachments: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[] }>` | User submitted a message. |
|
|
649
|
-
| `kai-suggestion-click` | `CustomEvent<{ value: string }>` | A suggestion chip was clicked (only in `suggestion-mode="fill"`). |
|
|
650
|
-
| `kai-value-change` | `CustomEvent<{ value: string }>` | Fired on every input change. |
|
|
651
|
-
| `kai-voice` | `CustomEvent<Record<string, never>>` | The Mic / voice button was clicked. |
|
|
652
|
-
| `kai-web-search` | `CustomEvent<Record<string, never>>` | The web-search (Globe) toolbar button was clicked. |
|
|
653
|
-
|
|
654
|
-
**Methods** (call on the element instance: `document.querySelector('kai-chat').focus(…)`):
|
|
655
|
-
|
|
656
|
-
| Method | Signature | Description |
|
|
657
|
-
|---|---|---|
|
|
658
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the composer, meaning the contenteditable (or textarea) inside the shadow root. A native `focus()` on the host lands on the host itself and never reaches it, so this is the only way to focus the input programmatically. |
|
|
659
|
-
| `blur` | `(): void` | Blur whatever currently holds focus inside the shadow root. The companion to `focus()`, for the same reason: a native `blur()` on the host misses the real focus target. |
|
|
660
|
-
| `clear` | `(): void` | Empty the COMPOSER: drops the draft text and every staged attachment, then fires `kai-value-change` with `''`. It does NOT touch the thread. `messages` is the consumer's own state, so clearing history stays the consumer's call. |
|
|
661
|
-
| `send` | `(): void` | Submit whatever the composer currently holds, on the same path as Enter or the send button: fires `kai-submit` with that value plus the staged attachments, then drops the attachments. It takes no argument, so to send text the user never typed, set `el.value` first. There is no empty-check, so an empty composer still fires. The draft is cleared afterwards only when `value` is uncontrolled; a controlled host owns its value and clears it itself. Named `send`, not `submit`, to match the shared vocabulary. |
|
|
662
|
-
| `scrollToBottom` | `(behavior?: ScrollBehavior): void` | Scroll the message viewport to the newest message. Defaults to `'smooth'`; pass `'instant'` to jump without animating. |
|
|
663
|
-
|
|
664
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
665
|
-
|
|
666
|
-
| Slot | Mode | Description |
|
|
667
|
-
|---|---|---|
|
|
668
|
-
| `header-start` | inject | Leading header controls, left of the title. |
|
|
669
|
-
| `header-end` | inject | Trailing header controls. |
|
|
670
|
-
| `header` | replace | Full custom header; replaces the built-in title/model/context bar. |
|
|
671
|
-
| `sidebar` | inject | Left column (your nav / conversation list). Fixed width; use compose-your-own for resizable. |
|
|
672
|
-
| `empty` | replace | Custom zero-state rendered in the message area while the thread is empty. Replaces the empty message list only; the composer and any suggestions still render. |
|
|
673
|
-
| `composer` | replace | Full custom composer; you own submit + loading, drive the thread via messages. |
|
|
674
|
-
| `composer-actions` | inject | Accessory row above the composer. |
|
|
675
|
-
| `footer` | inject | Row below the composer (disclaimers, token meter). |
|
|
676
|
-
|
|
677
|
-
**Styleable parts** (restyle from outside via `kai-chat::part(name)`):
|
|
678
|
-
|
|
679
|
-
| Part | Description |
|
|
680
|
-
|---|---|
|
|
681
|
-
| `::part(header-bar)` | The built-in header bar (the title / model-switcher / context row that hosts the header-start/header-end inject slots). Restyle its height, padding, or gap from outside without replacing the whole header via the `header` slot. — `kai-chat::part(header-bar) { height: 3.5rem; padding-inline: 1rem; gap: 0.5rem }` |
|
|
682
|
-
| `::part(header)` | Full custom header; replaces the built-in title/model/context bar. |
|
|
683
|
-
| `::part(sidebar)` | Left column (your nav / conversation list). Fixed width; use compose-your-own for resizable. |
|
|
684
|
-
| `::part(footer)` | Row below the composer (disclaimers, token meter). |
|
|
685
|
-
|
|
686
|
-
---
|
|
687
|
-
|
|
688
|
-
### `kai-checkpoint` / `Checkpoint`
|
|
689
|
-
|
|
690
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
691
|
-
|
|
692
|
-
| Property | Attribute | Type | Description |
|
|
693
|
-
|---|---|---|---|
|
|
694
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
695
|
-
| `label` | `label` | `undefined \| string` | Optional text beside the icon. |
|
|
696
|
-
| `tooltip` | `tooltip` | `undefined \| string` | Tooltip on hover. |
|
|
697
|
-
| `variant` | `variant` | `undefined \| "ghost" \| "default" \| "outline"` | Visual button style. |
|
|
698
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg" \| "icon" \| "icon-sm"` | Button size (use an `icon*` size for an icon-only checkpoint). |
|
|
699
|
-
|
|
700
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
701
|
-
|
|
702
|
-
| Event | `detail` type | Description |
|
|
703
|
-
|---|---|---|
|
|
704
|
-
| `kai-select` | `CustomEvent` | The checkpoint was clicked. |
|
|
705
|
-
|
|
706
|
-
---
|
|
707
|
-
|
|
708
|
-
### `kai-choice` / `Choice`
|
|
709
|
-
|
|
710
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
711
|
-
|
|
712
|
-
| Property | Attribute | Type | Description |
|
|
713
|
-
|---|---|---|---|
|
|
714
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
715
|
-
| `data` | — | `undefined \| { prompt?: undefined \| string; options: { id: string; label: string; description?: undefined \| string; media?: undefined \| { image?: undefined \| string; imageAlt?: undefined \| string; icon?: undefined \| string }; meta?: undefined \| string; recommended?: undefined \| false \| true; disabled?: undefined \| false \| true; payload?: unknown }[]; allowOther?: undefined \| false \| true \| { label?: undefined \| string; placeholder?: undefined \| string }; submitLabel?: undefined \| string; dismissible?: undefined \| false \| true }` | The choice definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { prompt, options:[…], allowOther?, submitLabel? }`. Import `ChoiceCardData` from `@kitn.ai/ui` for the full shape. |
|
|
716
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted CardEvent. Attribute: `card-id`. |
|
|
717
|
-
| `heading` | `heading` | `undefined \| string` | Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. |
|
|
718
|
-
| `resolution` | — | `undefined \| Record<string, unknown>` | Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'action', action:'…' }`. |
|
|
719
|
-
| `value` | `value` | `undefined \| string` | Controlled selection: the selected option id. When set, the consumer owns the current pick (RadioGroup `value`). Attribute: `value`. |
|
|
720
|
-
| `defaultValue` | `default-value` | `undefined \| string` | Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. |
|
|
721
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the whole radiogroup + Submit (e.g. while the agent is busy). Attribute: `disabled`. |
|
|
722
|
-
|
|
723
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
724
|
-
|
|
725
|
-
| Event | `detail` type | Description |
|
|
726
|
-
|---|---|---|
|
|
727
|
-
| `kai-value-change` | `CustomEvent<{ value: string }>` | The selection changed BEFORE submit (a row click or the `select()` method). Distinct from the terminal `action` verb on the `kai-card` contract event. |
|
|
728
|
-
|
|
729
|
-
**Methods** (call on the element instance: `document.querySelector('kai-choice').focus(…)`):
|
|
730
|
-
|
|
731
|
-
| Method | Signature | Description |
|
|
732
|
-
|---|---|---|
|
|
733
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the radiogroup roving tab stop (or the Other input when selected). |
|
|
734
|
-
| `select` | `(optionId: string): void` | Select an option by id locally: no emit, fires kai-value-change (same as a row click). Lets a consumer pre-highlight or drive selection externally. |
|
|
735
|
-
| `send` | `(): void` | Submit the current selection: emits the `action` verb on kai-card and resolves the card (single-shot). Named `send`, not `submit`, per the shared vocabulary. |
|
|
736
|
-
| `dismiss` | `(): void` | Trigger the dismiss path: emits `dismiss` on kai-card and optimistically collapses the card to its re-openable stub. |
|
|
737
|
-
| `reopen` | `(): void` | Re-open a dismissed card from its stub: emits `reopen` on kai-card. |
|
|
738
|
-
|
|
739
|
-
---
|
|
740
|
-
|
|
741
|
-
### `kai-coachmark` / `Coachmark`
|
|
742
|
-
|
|
743
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
744
|
-
|
|
745
|
-
| Property | Attribute | Type | Description |
|
|
746
|
-
|---|---|---|---|
|
|
747
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
748
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages). Set `el.open = true`, or `<kai-coachmark open>`; listen for `kai-open-change`. |
|
|
749
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
750
|
-
| `headline` | `headline` | `undefined \| string` | The bold title. Named `headline` because `title` collides with the global `HTMLElement.title` attribute (it throws at registration). |
|
|
751
|
-
| `badge` | `badge` | `undefined \| string` | A small badge pill beside the headline (e.g. "New"). |
|
|
752
|
-
| `placement` | `placement` | `undefined \| string` | Floating placement relative to the anchor (default `bottom`). |
|
|
753
|
-
| `tone` | `tone` | `undefined \| "primary" \| "info" \| "success" \| "warning" \| "error"` | Color tone: `primary` (default, theme accent), `info` (blue), `success` (green), `warning` (amber), or `error` (red), reusing the kit's tool hues. |
|
|
754
|
-
| `arrow` | `arrow` | `undefined \| false \| true` | Render the arrow that points at the anchor (default `true`). Set `arrow="false"` for a plain bubble with no pointer. |
|
|
755
|
-
|
|
756
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
757
|
-
|
|
758
|
-
| Event | `detail` type | Description |
|
|
759
|
-
|---|---|---|
|
|
760
|
-
| `kai-dismiss` | `CustomEvent<Record<string, never>>` | The × dismiss button was pressed. The consumer records that this hint was seen so it won't show again. |
|
|
761
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The coachmark opened or closed (a method, the ×, or a driven `open`). |
|
|
762
|
-
|
|
763
|
-
**Methods** (call on the element instance: `document.querySelector('kai-coachmark').show()`):
|
|
764
|
-
|
|
765
|
-
| Method | Signature | Description |
|
|
766
|
-
|---|---|---|
|
|
767
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
768
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
769
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
770
|
-
|
|
771
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
772
|
-
|
|
773
|
-
| Slot | Mode | Description |
|
|
774
|
-
|---|---|---|
|
|
775
|
-
| _(default)_ | inject | The ANCHOR the coachmark points at: the element it attaches to and positions against. The bubble body is the `content` slot. |
|
|
776
|
-
| `content` | replace | The bubble body text shown under the headline. |
|
|
777
|
-
|
|
778
|
-
**Styleable parts** (restyle from outside via `kai-coachmark::part(name)`):
|
|
779
|
-
|
|
780
|
-
| Part | Description |
|
|
781
|
-
|---|---|
|
|
782
|
-
| `::part(bubble)` | The hint bubble panel. Restyle its background, radius, or padding from outside; the default is bg-primary. — `kai-coachmark::part(bubble) { border-radius: 1rem }` |
|
|
783
|
-
| `::part(arrow)` | The arrow pointing at the anchor. Inherits the bubble color; recolor it alongside the bubble. — `kai-coachmark::part(arrow) { background: var(--color-accent) }` |
|
|
784
|
-
| `::part(badge)` | The small badge pill beside the headline (e.g. "New"). — `kai-coachmark::part(badge) { text-transform: none }` |
|
|
785
|
-
| `::part(title)` | The bold headline text. — `kai-coachmark::part(title) { font-size: 0.9375rem }` |
|
|
786
|
-
| `::part(dismiss)` | The dismiss button. Recolor or reposition it from outside. — `kai-coachmark::part(dismiss) { color: var(--color-primary-foreground) }` |
|
|
787
|
-
|
|
788
|
-
---
|
|
789
|
-
|
|
790
|
-
### `kai-code-block` / `CodeBlock`
|
|
791
|
-
|
|
792
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
793
|
-
|
|
794
|
-
| Property | Attribute | Type | Description |
|
|
795
|
-
|---|---|---|---|
|
|
796
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
797
|
-
| `code` | `code` | `string` | The source code to render. |
|
|
798
|
-
| `language` | `language` | `undefined \| string` | Language grammar (e.g. `js`, `python`). Defaults to `tsx`. |
|
|
799
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme name. |
|
|
800
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Disable syntax highlighting (renders plain text, no Shiki). |
|
|
801
|
-
| `copy` | `copy` | `undefined \| false \| true` | Show the copy button. **Defaults to ON**, because this element is documented as shipping one. Opt out with `copy="false"` or `el.copy = false`. |
|
|
802
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Code text sizing. |
|
|
803
|
-
|
|
804
|
-
_No events._
|
|
805
|
-
|
|
806
|
-
**Styleable parts** (restyle from outside via `kai-code-block::part(name)`):
|
|
807
|
-
|
|
808
|
-
| Part | Description |
|
|
809
|
-
|---|---|
|
|
810
|
-
| `::part(copy)` | The copy-to-clipboard button in the header row. Hide it with `copy="false"` rather than CSS. — `kai-code-block::part(copy) { color: var(--color-primary) }` |
|
|
811
|
-
|
|
812
|
-
---
|
|
813
|
-
|
|
814
|
-
### `kai-command` / `Command`
|
|
815
|
-
|
|
816
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
817
|
-
|
|
818
|
-
| Property | Attribute | Type | Description |
|
|
819
|
-
|---|---|---|---|
|
|
820
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
821
|
-
| `items` | — | `undefined \| { id: string; label: string; icon?: undefined \| string; description?: undefined \| string; shortcut?: undefined \| string; group?: undefined \| string }[]` | Flat list of items. Set as a JS property, not an HTML attribute. |
|
|
822
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder text for the search input. |
|
|
823
|
-
| `emptyLabel` | `empty-label` | `undefined \| string` | Label shown when no items match the current query. |
|
|
824
|
-
|
|
825
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
826
|
-
|
|
827
|
-
| Event | `detail` type | Description |
|
|
828
|
-
|---|---|---|
|
|
829
|
-
| `kai-active-change` | `CustomEvent<{ id: string \| undefined }>` | Fired when the highlighted/active item changes, via Arrow keys or when filtering re-clamps the active row. `id` is the newly active item's id, or `undefined` when no item is active (e.g. the filtered list is empty). Lets a host preview the active item without committing a selection. |
|
|
830
|
-
| `kai-query-change` | `CustomEvent<{ value: string }>` | Fired on every keystroke in the search input. |
|
|
831
|
-
| `kai-select` | `CustomEvent<{ id: string }>` | Fired when the user selects an item (click or Enter). |
|
|
832
|
-
|
|
833
|
-
**Methods** (call on the element instance: `document.querySelector('kai-command').focus(…)`):
|
|
834
|
-
|
|
835
|
-
| Method | Signature | Description |
|
|
836
|
-
|---|---|---|
|
|
837
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the search combobox input inside the shadow root so the palette is type-ready on demand (Shadow-DOM autofocus is unreliable, so hosts call this after opening the palette). |
|
|
838
|
-
| `blur` | `(): void` | Blur the focused search input. |
|
|
839
|
-
| `clear` | `(): void` | Reset the search query to empty, re-showing all items, and fire `kai-query-change` with `''`. Mirrors the Escape-key behavior. |
|
|
840
|
-
|
|
841
|
-
**Styleable parts** (restyle from outside via `kai-command::part(name)`):
|
|
842
|
-
|
|
843
|
-
| Part | Description |
|
|
844
|
-
|---|---|
|
|
845
|
-
| `::part(shortcut)` | The right-aligned per-row keyboard shortcut, rendered as kai-kbd key caps. Shown only when a row carries a `shortcut`. — `kai-command::part(shortcut) { opacity: 0.8 }` |
|
|
846
|
-
|
|
847
|
-
---
|
|
848
|
-
|
|
849
|
-
### `kai-compare` / `Compare`
|
|
850
|
-
|
|
851
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
852
|
-
|
|
853
|
-
| Property | Attribute | Type | Description |
|
|
854
|
-
|---|---|---|---|
|
|
855
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
856
|
-
| `data` | — | `undefined \| Record<string, unknown>` | The compare definition (prompt + the two candidates). Set as a JS PROPERTY: `el.data = { prompt, candidates: [A, B], collapse? }`. Import `ResponseCompareData` from `@kitn.ai/ui` for the full shape. |
|
|
857
|
-
| `compareId` | `compare-id` | `undefined \| string` | Stable id correlating every emitted event. Attribute: `compare-id`. |
|
|
858
|
-
| `selection` | — | `undefined \| Record<string, unknown>` | Re-hydrate / control the user's pick. Set as a JS PROPERTY: `el.selection = { chosenId, rejectedIds }`. Renders the collapsed winner. |
|
|
859
|
-
| `layout` | `layout` | `undefined \| "auto" \| "columns" \| "tabs"` | Layout: `'auto'` (default, columns when wide, tabs when narrow, by CONTAINER width) \| `'columns'` (side-by-side) \| `'tabs'` (pills to switch). Attribute: `layout`. |
|
|
860
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Prose/text size for the rendered candidates. Attribute: `prose-size`. |
|
|
861
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme for code blocks in the candidates. Attribute: `code-theme`. |
|
|
862
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Whether code blocks are syntax-highlighted. Attribute: `code-highlight`. |
|
|
863
|
-
|
|
864
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
865
|
-
|
|
866
|
-
| Event | `detail` type | Description |
|
|
867
|
-
|---|---|---|
|
|
868
|
-
| `kai-compare-select` | `CustomEvent<{ chosenId: string; rejectedIds: string[]; at?: undefined \| number }>` | The user committed a pick. `detail` = `{ chosenId, rejectedIds, at }`. |
|
|
869
|
-
| `kai-error` | `CustomEvent<{ compareId: string; message: string }>` | The definition was unusable. |
|
|
870
|
-
| `kai-ready` | `CustomEvent<{ compareId: string }>` | Both candidates have settled and the pick is live. |
|
|
871
|
-
|
|
872
|
-
**Methods** (call on the element instance: `document.querySelector('kai-compare').select(…)`):
|
|
873
|
-
|
|
874
|
-
| Method | Signature | Description |
|
|
875
|
-
|---|---|---|
|
|
876
|
-
| `select` | `(candidateId: string): void` | Programmatically commit a pick by candidate id, on the same path as the "Pick this" button: fires kai-compare-select and optimistically collapses (single-shot; inert while streaming or already resolved). `select` does NOT collide with the `selection` prop (distinct identifier). |
|
|
877
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the current roving tab stop (the focused candidate's "Pick this" radio) so a consumer can move keyboard focus into the radiogroup. |
|
|
878
|
-
|
|
879
|
-
---
|
|
880
|
-
|
|
881
|
-
### `kai-composer` / `Composer`
|
|
882
|
-
|
|
883
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
884
|
-
|
|
885
|
-
| Property | Attribute | Type | Description |
|
|
886
|
-
|---|---|---|---|
|
|
887
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
888
|
-
| `value` | — | `undefined \| string \| ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]` | Controlled value: a string or a full ComposerDoc (set as JS property). |
|
|
889
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder text shown when the composer is empty. |
|
|
890
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the composer entirely (non-interactive). |
|
|
891
|
-
| `loading` | `loading` | `undefined \| false \| true` | Show a loading/streaming state and block submit. |
|
|
892
|
-
| `maxHeight` | `max-height` | `undefined \| number \| string` | Maximum height in px before the content scrolls. Default 240. |
|
|
893
|
-
| `submitOnEnter` | `submit-on-enter` | `undefined \| false \| true` | Whether pressing Enter (without Shift) submits. Default true. |
|
|
894
|
-
| `triggers` | — | `undefined \| { char: string; kind: string; items?: undefined \| { id: string; label: string; icon?: undefined \| string; description?: undefined \| string; group?: undefined \| string; kind?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }[]` | Trigger definitions. Set as a JS property. |
|
|
895
|
-
| `highlights` | — | `undefined \| (string \| { pattern: string; flags?: undefined \| string; class?: undefined \| string })[]` | Keyword highlight rules. Set as a JS property. |
|
|
896
|
-
| `kindIcons` | — | `undefined \| Record<string, string>` | Default icon per entity kind (kind → image URL/data-URI) for items without their own `icon`. Overrides the built-in agent/plugin glyphs. JS property. |
|
|
897
|
-
|
|
898
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
899
|
-
|
|
900
|
-
| Event | `detail` type | Description |
|
|
901
|
-
|---|---|---|
|
|
902
|
-
| `kai-blur` | `CustomEvent<{ originalEvent: FocusEvent }>` | The composer lost focus. |
|
|
903
|
-
| `kai-entity-add` | `CustomEvent<{ entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } }>` | An entity pill was inserted into the composer. |
|
|
904
|
-
| `kai-entity-remove` | `CustomEvent<{ entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } }>` | An entity pill was deleted from the composer. |
|
|
905
|
-
| `kai-focus` | `CustomEvent<{ originalEvent: FocusEvent }>` | The composer gained focus. `focus`/`blur` are NOT composed natively, so they don't escape the shadow root; these re-expose them on the host. (For `keydown`/`paste`/`focusin`/`focusout`, listen NATIVELY on `<kai-composer>`: they're composed and already cross the shadow boundary.) |
|
|
906
|
-
| `kai-submit` | `CustomEvent<{ doc: ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]; text: string; entities: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }>` | The user submitted the composer (Enter or programmatic submit). |
|
|
907
|
-
| `kai-trigger` | `CustomEvent<{ char: string; query: string; rect: DOMRect }>` | A trigger character was detected at the caret (e.g. `/` or `@`). |
|
|
908
|
-
| `kai-trigger-close` | `CustomEvent<Record<string, never>>` | The active trigger was dismissed (Escape, space, or outside click). |
|
|
909
|
-
| `kai-value-change` | `CustomEvent<{ doc: ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]; text: string; entities: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }>` | The content changed (fires on every input event). |
|
|
910
|
-
|
|
911
|
-
**Methods** (call on the element instance: `document.querySelector('kai-composer').focus(…)`):
|
|
912
|
-
|
|
913
|
-
| Method | Signature | Description |
|
|
914
|
-
|---|---|---|
|
|
915
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the editable element. `focus`/`blur` are NOT composed natively, so a host-level focus() can't reach the editable inside the shadow root. This is the only way to focus the composer programmatically. |
|
|
916
|
-
| `blur` | `(): void` | Blur the editable element. |
|
|
917
|
-
| `clear` | `(): void` | Empty the composer to a blank doc (resets the internal value + history baseline; fires kai-value-change). |
|
|
918
|
-
| `send` | `(): void` | Submit the current content programmatically, on the same path as Enter (fires kai-submit). Named `send`, not `submit`, to match the shared vocabulary and avoid any submit collision. |
|
|
919
|
-
| `insertEntity` | `(entity: EntityRef): void` | Insert an atomic entity pill (skill/agent/plugin) at the caret without typing a trigger (fires kai-entity-add). |
|
|
920
|
-
|
|
921
|
-
---
|
|
922
|
-
|
|
923
|
-
### `kai-confirm` / `Confirm`
|
|
924
|
-
|
|
925
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
926
|
-
|
|
927
|
-
| Property | Attribute | Type | Description |
|
|
928
|
-
|---|---|---|---|
|
|
929
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
930
|
-
| `data` | — | `undefined \| { heading?: undefined \| string; body?: undefined \| string; tone?: undefined \| "default" \| "warning" \| "danger"; actions: { id: string; label: string; style?: undefined \| "primary" \| "default" \| "destructive"; payload?: unknown; default?: undefined \| false \| true }[]; dismissible?: undefined \| false \| true }` | The confirm definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { body, tone, actions:[…] }`. Import `ConfirmCardData` from `@kitn.ai/ui` for the full shape. |
|
|
931
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted CardEvent. Attribute: `card-id`. |
|
|
932
|
-
| `heading` | `heading` | `undefined \| string` | Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. |
|
|
933
|
-
| `autofocus` | `autofocus` | `undefined \| false \| true` | Focus the default action on mount (off by default, so nothing steals focus). Attribute: `autofocus`. |
|
|
934
|
-
| `resolution` | — | `undefined \| Record<string, unknown>` | Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'action', action:'…' }`. |
|
|
935
|
-
|
|
936
|
-
_No events._
|
|
937
|
-
|
|
938
|
-
**Methods** (call on the element instance: `document.querySelector('kai-confirm').focus(…)`):
|
|
939
|
-
|
|
940
|
-
| Method | Signature | Description |
|
|
941
|
-
|---|---|---|
|
|
942
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the default action button (or the first action if none is default). The same target `autofocus` focuses on mount, but on demand. |
|
|
943
|
-
| `confirm` | `(actionId?: string): void` | Activate an action by id: emits the `action` verb on kai-card and resolves the card (single-shot). With no id, invokes the default action. |
|
|
944
|
-
| `dismiss` | `(): void` | Trigger the dismiss path: emits `dismiss` on kai-card and optimistically collapses the card to its re-openable stub. |
|
|
945
|
-
| `reopen` | `(): void` | Re-open a dismissed card from its stub: emits `reopen` on kai-card. |
|
|
946
|
-
|
|
947
|
-
---
|
|
948
|
-
|
|
949
|
-
### `kai-context` / `Context`
|
|
950
|
-
|
|
951
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
952
|
-
|
|
953
|
-
| Property | Attribute | Type | Description |
|
|
954
|
-
|---|---|---|---|
|
|
955
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
956
|
-
| `context` | — | `undefined \| { usedTokens: number; maxTokens: number; inputTokens?: undefined \| number; outputTokens?: undefined \| number; reasoningTokens?: undefined \| number; cacheTokens?: undefined \| number; estimatedCost?: undefined \| number }` | Token-usage data. Set as a JS property. |
|
|
957
|
-
| `warnThreshold` | `warn-threshold` | `undefined \| number` | Fraction (0–1) above which the meter turns yellow. Defaults to `0.7` (70%). |
|
|
958
|
-
| `dangerThreshold` | `danger-threshold` | `undefined \| number` | Fraction (0–1) above which the meter turns red. Defaults to `0.9` (90%). |
|
|
959
|
-
|
|
960
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
961
|
-
|
|
962
|
-
| Event | `detail` type | Description |
|
|
963
|
-
|---|---|---|
|
|
964
|
-
| `kai-threshold-change` | `CustomEvent<{ level: "ok" \| "warn" \| "danger" }>` | Fires when the computed severity level changes (ok → warn → danger or back). `detail.level` is `'ok'`, `'warn'`, or `'danger'`. |
|
|
965
|
-
|
|
966
|
-
**Styleable parts** (restyle from outside via `kai-context::part(name)`):
|
|
967
|
-
|
|
968
|
-
| Part | Description |
|
|
969
|
-
|---|---|
|
|
970
|
-
| `::part(track)` | The usage meter track inside the hover-card breakdown. Carries `role="progressbar"` and is in the DOM only while the card is open. Restyle its height, radius, or background from outside. — `kai-context::part(track) { height: 0.5rem }` |
|
|
971
|
-
| `::part(fill)` | The used-tokens portion of that meter. Its width follows `usedTokens / maxTokens`; its default color is the severity hue picked by `warnThreshold` / `dangerThreshold`, so recoloring it from outside replaces that signal. — `kai-context::part(fill) { background: var(--color-tool-blue) }` |
|
|
972
|
-
|
|
973
|
-
---
|
|
974
|
-
|
|
975
|
-
### `kai-conversation-item` / `ConversationItem`
|
|
976
|
-
|
|
977
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
978
|
-
|
|
979
|
-
| Property | Attribute | Type | Description |
|
|
980
|
-
|---|---|---|---|
|
|
981
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
982
|
-
| `conversationId` | `conversation-id` | `undefined \| string` | The row's identity, handed to the container's selection contract. In the element this is the `conversation-id` attribute (host `id` is the fallback). |
|
|
983
|
-
| `active` | `active` | `undefined \| false \| true` | Selected state. Reflected as `aria-current` on the row body and a `data-active` styling hook on the row; the container drives it from its `activeId`. |
|
|
984
|
-
| `compact` | `compact` | `undefined \| false \| true` | Dense single-line row padding. |
|
|
985
|
-
|
|
986
|
-
_No events._
|
|
987
|
-
|
|
988
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
989
|
-
|
|
990
|
-
| Slot | Mode | Description |
|
|
991
|
-
|---|---|---|
|
|
992
|
-
| _(default)_ | inject | The row title. `leading`, `meta` and `menu` are the named regions around it. |
|
|
993
|
-
| `leading` | inject | Leading region before the title (an icon or avatar). |
|
|
994
|
-
| `meta` | inject | Meta region under the title (a timestamp or status line). |
|
|
995
|
-
| `menu` | inject | Your own row menu (a popover trigger). Never selects the row. |
|
|
996
|
-
|
|
997
|
-
**Styleable parts** (restyle from outside via `kai-conversation-item::part(name)`):
|
|
998
|
-
|
|
999
|
-
| Part | Description |
|
|
1000
|
-
|---|---|
|
|
1001
|
-
| `::part(body)` | The activation surface inside the row (button role; carries aria-current and the roving tabindex). The focus ring paints here. — `kai-conversation-item::part(body) { outline-offset: 2px }` |
|
|
1002
|
-
| `::part(row)` | The whole row surface. Carries `data-active` while selected. — `kai-conversation-item::part(row) { border-radius: 0.5rem }` |
|
|
1003
|
-
| `::part(title)` | The title line (the default slot renders inside it). — `kai-conversation-item::part(title) { font-weight: 600 }` |
|
|
1004
|
-
| `::part(leading)` | Leading region before the title (an icon or avatar). |
|
|
1005
|
-
| `::part(meta)` | Meta region under the title (a timestamp or status line). |
|
|
1006
|
-
| `::part(menu)` | Your own row menu (a popover trigger). Never selects the row. |
|
|
1007
|
-
|
|
1008
|
-
---
|
|
1009
|
-
|
|
1010
|
-
### `kai-conversations` / `Conversations`
|
|
1011
|
-
|
|
1012
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1013
|
-
|
|
1014
|
-
| Property | Attribute | Type | Description |
|
|
1015
|
-
|---|---|---|---|
|
|
1016
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1017
|
-
| `groups` | — | `undefined \| { id: string; userId?: undefined \| string; teamId?: undefined \| string; name: string; sortOrder: number; createdAt: string }[]` | The list's section headers (`{ id, name, sortOrder, createdAt }`), rendered in array order. A group carries no conversations of its own; it is matched against `conversations` by id, so the two props are complementary rather than alternatives. Omit for an ungrouped list. Set as a JS property. |
|
|
1018
|
-
| `conversations` | — | `undefined \| { id: string; title: string; groupId?: undefined \| string; scope?: undefined \| { type: "document" \| "collection"; documentId?: undefined \| string; filters?: undefined \| { tags?: undefined \| string[]; authors?: undefined \| string[]; contentType?: undefined \| "transcript" \| "markdown"; dateRange?: undefined \| { from: string; to: string } } }; messageCount: number; lastMessageAt?: undefined \| string; updatedAt: string; trailing?: undefined \| string }[]` | Every conversation the list renders, flat. Each one is filed under the group whose `id` equals its `groupId`; one with no `groupId`, or with a `groupId` matching no entry in `groups`, falls into a trailing "Ungrouped" section, so nothing you pass in is ever dropped. There is no recency bucketing. Set as a JS property. Omit to supply them as `<kai-conversation>` light-DOM children instead, or for the empty state. A search query that matches nothing shows a visible "No conversations match your search" state, distinct from the zero-conversations empty state. Slotted `<kai-conversation-item>` children switch the list into item mode instead: your own rows win and this array is not rendered. |
|
|
1019
|
-
| `activeId` | `active-id` | `undefined \| string` | The id of the currently-open conversation, highlighted in the list. |
|
|
1020
|
-
| `collapsed` | `collapsed` | `undefined \| false \| true` | Controlled collapsed state. Set as a JS property (`el.collapsed = true`) to drive the rail from your app, updating it in response to `kai-collapse-toggle`. Omit for uncontrolled (the element manages it). Collapsed shrinks the rail to a floating reopen button. |
|
|
1021
|
-
| `defaultCollapsed` | `default-collapsed` | `undefined \| false \| true` | Initial collapsed state when uncontrolled (default false). Use the `default-collapsed` attribute to start collapsed in plain HTML. |
|
|
1022
|
-
| `compact` | `compact` | `undefined \| false \| true` | Dense single-line rows (a leading dot + title, no message count). |
|
|
1023
|
-
|
|
1024
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1025
|
-
|
|
1026
|
-
| Event | `detail` type | Description |
|
|
1027
|
-
|---|---|---|
|
|
1028
|
-
| `kai-collapse-toggle` | `CustomEvent<{ collapsed: false \| true }>` | The rail was collapsed or expanded (via the toggle, the reopen button, or a `collapse()`/`expand()`/`toggle()` call). |
|
|
1029
|
-
| `kai-conversation-select` | `CustomEvent<{ id: string }>` | A conversation was selected. The selection event in BOTH modes: a batteries data row, or an activated `<kai-conversation-item>` child (click, Enter or Space). |
|
|
1030
|
-
| `kai-new-chat` | `CustomEvent<Record<string, never>>` | The "New chat" button was clicked. |
|
|
1031
|
-
| `kai-search` | `CustomEvent<{ query: string }>` | The built-in search box query changed (typing, or a programmatic `clear()` which fires it with `''`). Lets a consumer mirror or server-side the filter. |
|
|
1032
|
-
| `kai-toggle-sidebar` | `CustomEvent<Record<string, never>>` | The sidebar toggle was clicked. |
|
|
1033
|
-
|
|
1034
|
-
**Methods** (call on the element instance: `document.querySelector('kai-conversations').focus(…)`):
|
|
1035
|
-
|
|
1036
|
-
| Method | Signature | Description |
|
|
1037
|
-
|---|---|---|
|
|
1038
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the built-in search input inside the shadow root. |
|
|
1039
|
-
| `clear` | `(): void` | Clear the internal search query (resets the list filter) and fire kai-search with an empty string. |
|
|
1040
|
-
| `select` | `(id: string): void` | Programmatically select a conversation by id. The mirror of the kai-conversation-select event (a convenience over driving `activeId`). |
|
|
1041
|
-
| `collapse` | `(): void` | Collapse the rail to its floating reopen button (fires `kai-collapse-toggle`). |
|
|
1042
|
-
| `expand` | `(): void` | Expand the rail back to the full list (fires `kai-collapse-toggle`). |
|
|
1043
|
-
| `toggle` | `(): void` | Toggle the rail collapsed/expanded (fires `kai-collapse-toggle`). |
|
|
1044
|
-
|
|
1045
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1046
|
-
|
|
1047
|
-
| Slot | Mode | Description |
|
|
1048
|
-
|---|---|---|
|
|
1049
|
-
| _(default)_ | inject | Your own `<kai-conversation-item>` rows (item mode: the consumer-owned loop). Data rows do not render while any are present. |
|
|
1050
|
-
| `header` | replace | Full custom title bar; replaces the built-in toggle / "Chats" / New-chat row. |
|
|
1051
|
-
| `empty` | replace | Custom zero-state shown when there are no conversations; replaces the built-in "No conversations yet". |
|
|
1052
|
-
| `footer` | inject | A row below the list: account, settings, or usage. |
|
|
1053
|
-
|
|
1054
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
1055
|
-
|
|
1056
|
-
| Child element | Attributes | Text content | Notes |
|
|
1057
|
-
|---|---|---|---|
|
|
1058
|
-
| `<kai-conversation>` | `group-id`, `id` | yes | Parse a single light-DOM `<kai-conversation>` element into a `ConversationSummary`. Attribute mapping: - `id` → ConversationSummary.id - `group-id` → ConversationSummary.groupId (optional) - textContent → ConversationSummary.title Fields not expressible as HTML attributes are NOT fabricated (F-10): the optional `scope` and `lastMessageAt` stay absent, and the required `messageCount`/`updatedAt` get honest defaults — zero messages, and an empty `updatedAt` from which no trailing relative time is derived (the epoch it used to fabricate rendered a bogus "many days ago" on every declarative row). |
|
|
1059
|
-
|
|
1060
|
-
**Styleable parts** (restyle from outside via `kai-conversations::part(name)`):
|
|
1061
|
-
|
|
1062
|
-
| Part | Description |
|
|
1063
|
-
|---|---|
|
|
1064
|
-
| `::part(trailing)` | The right-aligned trailing text on each conversation row (a count, status, or relative time). Set it per item via the `trailing` field; otherwise a short auto relative time is derived from `updatedAt`. Recolor or resize it from outside. — `kai-conversations::part(trailing) { color: var(--color-primary); font-variant-numeric: tabular-nums }` |
|
|
1065
|
-
| `::part(items)` | The item-mode listbox region wrapping your slotted `<kai-conversation-item>` children. — `kai-conversations::part(items) { gap: 2px }` |
|
|
1066
|
-
|
|
1067
|
-
---
|
|
1068
|
-
|
|
1069
|
-
### `kai-dialog` / `Dialog`
|
|
1070
|
-
|
|
1071
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1072
|
-
|
|
1073
|
-
| Property | Attribute | Type | Description |
|
|
1074
|
-
|---|---|---|---|
|
|
1075
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1076
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on Escape/backdrop). Set `el.open = true`, or `<kai-dialog open>`; listen for `kai-open-change`. |
|
|
1077
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1078
|
-
| `label` | `label` | `undefined \| string` | Accessible name for the modal, used when no `header` slot is projected: `<kai-dialog label="Delete workspace">`. A projected `header` WINS over this (it becomes `aria-labelledby`), because ARIA resolves `aria-labelledby` ahead of `aria-label` and the visible heading is the name both a sighted and a screen-reader user can be talked through. Defaults to `Dialog` so a modal is never nameless. |
|
|
1079
|
-
|
|
1080
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1081
|
-
|
|
1082
|
-
| Event | `detail` type | Description |
|
|
1083
|
-
|---|---|---|
|
|
1084
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The dialog opened or closed (Escape, backdrop click, a driven `open`, or a method). |
|
|
1085
|
-
|
|
1086
|
-
**Methods** (call on the element instance: `document.querySelector('kai-dialog').show()`):
|
|
1087
|
-
|
|
1088
|
-
| Method | Signature | Description |
|
|
1089
|
-
|---|---|---|
|
|
1090
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1091
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1092
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1093
|
-
| `focus` | `(options?: FocusOptions): void` | Move focus to the dialog panel (no-op while closed). |
|
|
1094
|
-
|
|
1095
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1096
|
-
|
|
1097
|
-
| Slot | Mode | Description |
|
|
1098
|
-
|---|---|---|
|
|
1099
|
-
| _(default)_ | inject | The dialog body, between the `header` and `footer` slots. |
|
|
1100
|
-
| `header` | inject | Optional title region at the top of the panel. |
|
|
1101
|
-
| `footer` | inject | Optional actions region at the bottom of the panel. |
|
|
1102
|
-
|
|
1103
|
-
**Styleable parts** (restyle from outside via `kai-dialog::part(name)`):
|
|
1104
|
-
|
|
1105
|
-
| Part | Description |
|
|
1106
|
-
|---|---|
|
|
1107
|
-
| `::part(backdrop)` | The full-area scrim behind the panel. Restyle its color/blur. — `kai-dialog::part(backdrop) { background: rgb(0 0 0 / 0.6) }` |
|
|
1108
|
-
| `::part(panel)` | The centered modal panel. Restyle width, radius, padding. — `kai-dialog::part(panel) { max-width: 32rem }` |
|
|
1109
|
-
| `::part(body)` | The scrolling content region (the default slot). — `kai-dialog::part(body) { padding: 1.25rem }` |
|
|
1110
|
-
| `::part(header)` | Optional title region at the top of the panel. |
|
|
1111
|
-
| `::part(footer)` | Optional actions region at the bottom of the panel. |
|
|
1112
|
-
|
|
1113
|
-
---
|
|
1114
|
-
|
|
1115
|
-
### `kai-dock` / `Dock`
|
|
1116
|
-
|
|
1117
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1118
|
-
|
|
1119
|
-
| Property | Attribute | Type | Description |
|
|
1120
|
-
|---|---|---|---|
|
|
1121
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1122
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on the launcher and Escape). Set `el.open = true`, or `<kai-dock open>`; listen for `kai-open-change`. |
|
|
1123
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1124
|
-
| `position` | `position` | `undefined \| "bottom-end" \| "bottom-start" \| "top-end" \| "top-start"` | Which corner the dock sits in. Logical, so `-end` follows the writing direction and an RTL page docks on the left. Attribute: `position`. |
|
|
1125
|
-
| `label` | `label` | `undefined \| string` | The widget's NAME. Derives the panel's accessible name and both launcher names (`Open ${label}` / `Close ${label}`). Defaults to `Chat`. |
|
|
1126
|
-
| `openLabel` | `open-label` | `undefined \| string` | i18n override for the launcher's name while closed (default `Open ${label}`). |
|
|
1127
|
-
| `closeLabel` | `close-label` | `undefined \| string` | i18n override for the launcher's name while open (default `Close ${label}`). |
|
|
1128
|
-
| `unread` | `unread` | `undefined \| false \| true` | Show the unread dot. YOURS: it renders only while closed, and the dock never writes it back. Clear it in your `kai-open-change` handler. |
|
|
1129
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the launcher; `show()` and `toggle()` are gated on it. |
|
|
1130
|
-
| `focusOnOpen` | `focus-on-open` | `undefined \| "content" \| "panel" \| "none"` | Where focus lands on open: `content` (default, the first element you slotted), `panel`, or `none`. Attribute: `focus-on-open`. |
|
|
1131
|
-
|
|
1132
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1133
|
-
|
|
1134
|
-
| Event | `detail` type | Description |
|
|
1135
|
-
|---|---|---|
|
|
1136
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The dock opened or closed (the launcher, Escape, a driven `open`, or a method). |
|
|
1137
|
-
|
|
1138
|
-
**Methods** (call on the element instance: `document.querySelector('kai-dock').show()`):
|
|
1139
|
-
|
|
1140
|
-
| Method | Signature | Description |
|
|
1141
|
-
|---|---|---|
|
|
1142
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1143
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1144
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1145
|
-
| `focus` | `(options?: FocusOptions): void` | Move focus to the panel while open, or to the launcher while closed. |
|
|
1146
|
-
|
|
1147
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1148
|
-
|
|
1149
|
-
| Slot | Mode | Description |
|
|
1150
|
-
|---|---|---|
|
|
1151
|
-
| _(default)_ | inject | The panel body, the same region as `slot="panel"`. |
|
|
1152
|
-
| `panel` | replace | The panel body. ANY element: a `<kai-chat>`, a form, your own component. The dock never reads or types it, and the default slot is the same region. |
|
|
1153
|
-
| `launcher` | inject | Content inside the built-in button while CLOSED; defaults to a chat glyph. Text works as well as an icon: the button keeps its height and grows sideways into a pill, so a label like "Support" is not clipped. The BUTTON is never slotted away, because it owns aria-expanded, aria-controls, the toggle wiring and the focus return. |
|
|
1154
|
-
| `launcher-open` | inject | Content inside the button while OPEN; defaults to a ✕. Fill only `launcher` and that glyph stays while open rather than morphing into a built-in that clashes with it. |
|
|
1155
|
-
|
|
1156
|
-
**Styleable parts** (restyle from outside via `kai-dock::part(name)`):
|
|
1157
|
-
|
|
1158
|
-
| Part | Description |
|
|
1159
|
-
|---|---|
|
|
1160
|
-
| `::part(launcher)` | The launcher button pinned to the corner: a disc by default, a pill once you slot a text label. Restyle its surface or shadow; --kai-dock-launcher-size sets its height and its minimum width. — `kai-dock::part(launcher) { background: var(--color-info) }` |
|
|
1161
|
-
| `::part(badge)` | The unread dot on the launcher, rendered only while closed and only when `unread` is set. Restyle its color or size. — `kai-dock::part(badge) { background: var(--color-success) }` |
|
|
1162
|
-
| `::part(panel)` | The panel body. ANY element: a `<kai-chat>`, a form, your own component. The dock never reads or types it, and the default slot is the same region. |
|
|
1163
|
-
|
|
1164
|
-
---
|
|
1165
|
-
|
|
1166
|
-
### `kai-dropdown` / `Dropdown`
|
|
1167
|
-
|
|
1168
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1169
|
-
|
|
1170
|
-
| Property | Attribute | Type | Description |
|
|
1171
|
-
|---|---|---|---|
|
|
1172
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1173
|
-
| `triggerIcon` | `trigger-icon` | `undefined \| string` | Built-in trigger: leading icon (a named icon like `"plus"`, an image URL/data-URI, or text). A slotted `slot="trigger"` overrides it. |
|
|
1174
|
-
| `triggerLabel` | `trigger-label` | `undefined \| string` | Built-in trigger: a text label. This is the trigger's VISIBLE text, so it is also its accessible name, and `label` does not override it: an accessible name that does not contain the visible text is unreachable by speech input (WCAG 2.5.3, Label in Name). Same rule `kai-menu` follows. |
|
|
1175
|
-
| `triggerIconTrailing` | `trigger-icon-trailing` | `undefined \| string` | Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). |
|
|
1176
|
-
| `label` | `label` | `undefined \| string` | Accessible name for a trigger with no visible label. Ignored when `triggerLabel` is set, which is already the visible name. It DOES name a slotted `slot="trigger"`, which is VISUAL content with the name supplied separately: the same two-slot distinction `kai-menu` documents. |
|
|
1177
|
-
| `full` | `full` | `undefined \| false \| true` | Stretch the trigger to the full width of its container (a block row). Attribute: `full`. |
|
|
1178
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the menu still self-manages on click/keyboard). Set `el.open = true`, or `<kai-dropdown open>`; listen for `kai-open-change`. |
|
|
1179
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1180
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the trigger: click/keyboard and `show()` no longer open the menu. |
|
|
1181
|
-
|
|
1182
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1183
|
-
|
|
1184
|
-
| Event | `detail` type | Description |
|
|
1185
|
-
|---|---|---|
|
|
1186
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The menu opened or closed (click, keyboard, Escape, outside-click, or a method). |
|
|
1187
|
-
|
|
1188
|
-
**Methods** (call on the element instance: `document.querySelector('kai-dropdown').show()`):
|
|
1189
|
-
|
|
1190
|
-
| Method | Signature | Description |
|
|
1191
|
-
|---|---|---|
|
|
1192
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1193
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1194
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1195
|
-
|
|
1196
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1197
|
-
|
|
1198
|
-
| Slot | Mode | Description |
|
|
1199
|
-
|---|---|---|
|
|
1200
|
-
| _(default)_ | inject | The menu body: your own rows. Give each `role="menuitem"`. The control that opens it is the `trigger` slot. |
|
|
1201
|
-
| `trigger` | replace | Visual content of the trigger button (an icon, text, an `<svg>`). Replaces the built-in trigger* content; name it with `label`. |
|
|
1202
|
-
|
|
1203
|
-
---
|
|
1204
|
-
|
|
1205
|
-
### `kai-editable-label` / `EditableLabel`
|
|
1206
|
-
|
|
1207
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1208
|
-
|
|
1209
|
-
| Property | Attribute | Type | Description |
|
|
1210
|
-
|---|---|---|---|
|
|
1211
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1212
|
-
| `value` | `value` | `undefined \| string` | The label text. Settable and reflected to the `value` attribute. Read `el.value` for live state. |
|
|
1213
|
-
| `editing` | `editing` | `undefined \| false \| true` | Controlled edit state. `el.editing = true` opens the field; reflected to the `editing` attribute. |
|
|
1214
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder shown while editing / when the value is empty. |
|
|
1215
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable entering edit mode. |
|
|
1216
|
-
|
|
1217
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1218
|
-
|
|
1219
|
-
| Event | `detail` type | Description |
|
|
1220
|
-
|---|---|---|
|
|
1221
|
-
| `kai-cancel` | `CustomEvent<Record<string, never>>` | Edit was cancelled (Esc); the text is restored. |
|
|
1222
|
-
| `kai-rename` | `CustomEvent<{ value: string }>` | Committed a changed value (Enter / blur). |
|
|
1223
|
-
|
|
1224
|
-
**Methods** (call on the element instance: `document.querySelector('kai-editable-label').edit()`):
|
|
1225
|
-
|
|
1226
|
-
| Method | Signature | Description |
|
|
1227
|
-
|---|---|---|
|
|
1228
|
-
| `edit` | `(): void` | Switch the label into its editing field, which autofocuses and selects the current text. Same entry point as a user double-click, and a no-op while `disabled`. Commit with `commit()` or by blurring, abandon with `cancel()` or Escape. |
|
|
1229
|
-
| `commit` | `(): void` | Close the field and keep what was typed, exactly as blurring it does. `kai-rename` fires only when the text actually changed, so committing an untouched field is silent. A no-op while the field is closed. |
|
|
1230
|
-
| `cancel` | `(): void` | Abandon the edit, exactly as Escape does: the original text is restored, the field closes and `kai-cancel` fires. `kai-rename` never fires, even if the field was edited. Also works when `editing` was set programmatically and the field has not rendered yet. |
|
|
1231
|
-
|
|
1232
|
-
**Styleable parts** (restyle from outside via `kai-editable-label::part(name)`):
|
|
1233
|
-
|
|
1234
|
-
| Part | Description |
|
|
1235
|
-
|---|---|
|
|
1236
|
-
| `::part(text)` | The read-mode label text. Restyle its typography; it swaps to the input on edit. — `kai-editable-label::part(text) { font-weight: 600 }` |
|
|
1237
|
-
| `::part(input)` | The edit-mode input (the composed kai-input field). — `kai-editable-label::part(input) { font: inherit }` |
|
|
1238
|
-
|
|
1239
|
-
---
|
|
1240
|
-
|
|
1241
|
-
### `kai-embed` / `Embed`
|
|
1242
|
-
|
|
1243
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1244
|
-
|
|
1245
|
-
| Property | Attribute | Type | Description |
|
|
1246
|
-
|---|---|---|---|
|
|
1247
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1248
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted event. Set as an attribute or property. |
|
|
1249
|
-
| `data` | — | `undefined \| { provider: "youtube" \| "vimeo" \| "generic"; id?: undefined \| string; url?: undefined \| string; title?: undefined \| string; poster?: undefined \| string; start?: undefined \| number; aspectRatio?: undefined \| "16:9" \| "4:3" \| "1:1" \| "9:16" }` | The embed payload (provider + id/url + options). Set as a JS **property** (object). |
|
|
1250
|
-
|
|
1251
|
-
_No events._
|
|
1252
|
-
|
|
1253
|
-
---
|
|
1254
|
-
|
|
1255
|
-
### `kai-empty` / `Empty`
|
|
1256
|
-
|
|
1257
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1258
|
-
|
|
1259
|
-
| Property | Attribute | Type | Description |
|
|
1260
|
-
|---|---|---|---|
|
|
1261
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1262
|
-
| `emptyTitle` | `empty-title` | `undefined \| string` | Title text. Attribute: `empty-title` (`title` is a global HTML attribute). |
|
|
1263
|
-
| `description` | `description` | `undefined \| string` | Description text. |
|
|
1264
|
-
|
|
1265
|
-
_No events._
|
|
1266
|
-
|
|
1267
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1268
|
-
|
|
1269
|
-
| Slot | Mode | Description |
|
|
1270
|
-
|---|---|---|
|
|
1271
|
-
| _(default)_ | inject | The empty-state body below the title/description, usually the call to action. |
|
|
1272
|
-
| `media` | replace | The leading illustration or icon above the title (any inline SVG or <img>). Replaces the built-in media box. |
|
|
1273
|
-
|
|
1274
|
-
---
|
|
1275
|
-
|
|
1276
|
-
### `kai-feedback-bar` / `FeedbackBar`
|
|
1277
|
-
|
|
1278
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1279
|
-
|
|
1280
|
-
| Property | Attribute | Type | Description |
|
|
1281
|
-
|---|---|---|---|
|
|
1282
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1283
|
-
| `barTitle` | `bar-title` | `undefined \| string` | The banner label (e.g. "Was this helpful?"). Attribute: `bar-title` (`title` is avoided because it is a global HTML attribute). |
|
|
1284
|
-
| `collectDetail` | `collect-detail` | `undefined \| false \| true` | When set, a not-helpful vote opens an optional detail form before the thank-you confirmation. Attribute: `collect-detail`. |
|
|
1285
|
-
| `categories` | — | `undefined \| string[]` | Optional category chips for the detail form. Set as a JS property (array). |
|
|
1286
|
-
| `detailTitle` | `detail-title` | `undefined \| string` | Heading for the detail form. Attribute: `detail-title`. |
|
|
1287
|
-
| `detailPlaceholder` | `detail-placeholder` | `undefined \| string` | Placeholder for the detail comment box. Attribute: `detail-placeholder`. |
|
|
1288
|
-
| `submitLabel` | `submit-label` | `undefined \| string` | Submit button label in the detail form. Attribute: `submit-label`. |
|
|
1289
|
-
| `thanksMessage` | `thanks-message` | `undefined \| string` | Confirmation copy shown after a vote/submit. Attribute: `thanks-message`. |
|
|
1290
|
-
|
|
1291
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1292
|
-
|
|
1293
|
-
| Event | `detail` type | Description |
|
|
1294
|
-
|---|---|---|
|
|
1295
|
-
| `kai-close` | `CustomEvent` | The user dismissed the banner. |
|
|
1296
|
-
| `kai-feedback` | `CustomEvent<{ value: "helpful" \| "not-helpful" }>` | The user rated the response. `value` is `'helpful'` or `'not-helpful'`. |
|
|
1297
|
-
| `kai-feedback-detail` | `CustomEvent<{ value: "helpful" \| "not-helpful"; category?: undefined \| string; comment?: undefined \| string }>` | The user submitted the optional detail form (`collect-detail`). |
|
|
1298
|
-
|
|
1299
|
-
---
|
|
1300
|
-
|
|
1301
|
-
### `kai-file-tree` / `FileTree`
|
|
1302
|
-
|
|
1303
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1304
|
-
|
|
1305
|
-
| Property | Attribute | Type | Description |
|
|
1306
|
-
|---|---|---|---|
|
|
1307
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1308
|
-
| `files` | — | `{ path: string; url?: undefined \| string; code?: undefined \| string; language?: undefined \| string; type?: undefined \| "html" \| "pdf" \| "image" \| "other"; additions?: undefined \| number; deletions?: undefined \| number; status?: undefined \| "added" \| "modified" \| "deleted" \| "renamed" \| "untracked" }[]` | The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type?, additions?, deletions?, status? }`). |
|
|
1309
|
-
| `activeFile` | `active-file` | `undefined \| string` | Selected file path, highlighted in the tree. |
|
|
1310
|
-
| `defaultExpanded` | — | `undefined \| string[]` | Folder paths expanded initially. Omit to start with all folders open. |
|
|
1311
|
-
| `summary` | `summary` | `undefined \| false \| true` | Show a changed-files summary header (file count + summed `+/-` + Collapse-all). Attribute: `summary`. Off by default. |
|
|
1312
|
-
|
|
1313
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1314
|
-
|
|
1315
|
-
| Event | `detail` type | Description |
|
|
1316
|
-
|---|---|---|
|
|
1317
|
-
| `kai-select` | `CustomEvent<{ path: string }>` | Fired when a file is selected. `detail.path` = the file's path. |
|
|
1318
|
-
|
|
1319
|
-
**Styleable parts** (restyle from outside via `kai-file-tree::part(name)`):
|
|
1320
|
-
|
|
1321
|
-
| Part | Description |
|
|
1322
|
-
|---|---|
|
|
1323
|
-
| `::part(summary)` | The changed-files summary header (the file count, the summed +additions/-deletions, and the Collapse-all/Expand-all toggle). Rendered only when the `summary` attribute is set; restyle or hide it from outside. — `kai-file-tree::part(summary) { border-bottom: none; padding-block: 0.5rem }` |
|
|
1324
|
-
| `::part(status)` | The per-row change-status letter (A/M/D/R/U), shown when a file carries a `status`. Colored with the conventional VCS tool hues; restyle from outside. — `kai-file-tree::part(status) { font-weight: 700 }` |
|
|
1325
|
-
| `::part(stat-additions)` | The trailing `+N` additions stat on a file row (success/green tool hue, tabular-nums). Shown only when a file carries `additions`. — `kai-file-tree::part(stat-additions) { color: var(--color-tool-green) }` |
|
|
1326
|
-
| `::part(stat-deletions)` | The trailing `-N` deletions stat on a file row (error/red tool hue, tabular-nums). Shown only when a file carries `deletions`. — `kai-file-tree::part(stat-deletions) { color: var(--color-tool-red) }` |
|
|
1327
|
-
|
|
1328
|
-
---
|
|
1329
|
-
|
|
1330
|
-
### `kai-file-upload` / `FileUpload`
|
|
1331
|
-
|
|
1332
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1333
|
-
|
|
1334
|
-
| Property | Attribute | Type | Description |
|
|
1335
|
-
|---|---|---|---|
|
|
1336
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1337
|
-
| `multiple` | `multiple` | `undefined \| false \| true` | Allow selecting multiple files (default true). |
|
|
1338
|
-
| `accept` | `accept` | `undefined \| string` | `accept` attribute for the file picker (e.g. `image/*`). |
|
|
1339
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the dropzone: no clicking, no drag-and-drop. |
|
|
1340
|
-
| `label` | `label` | `undefined \| string` | Default dropzone label (overridable via the default slot). |
|
|
1341
|
-
|
|
1342
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1343
|
-
|
|
1344
|
-
| Event | `detail` type | Description |
|
|
1345
|
-
|---|---|---|
|
|
1346
|
-
| `kai-files-added` | `CustomEvent<{ files: File[] }>` | Files were picked or dropped. |
|
|
1347
|
-
|
|
1348
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1349
|
-
|
|
1350
|
-
| Slot | Mode | Description |
|
|
1351
|
-
|---|---|---|
|
|
1352
|
-
| _(default)_ | inject | Custom dropzone content, replacing the default label (the `label` prop is the fallback). |
|
|
1353
|
-
|
|
1354
|
-
---
|
|
1355
|
-
|
|
1356
|
-
### `kai-form` / `Form`
|
|
1357
|
-
|
|
1358
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1359
|
-
|
|
1360
|
-
| Property | Attribute | Type | Description |
|
|
1361
|
-
|---|---|---|---|
|
|
1362
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1363
|
-
| `data` | — | `undefined \| { type: "object"; title?: undefined \| string; description?: undefined \| string; required?: undefined \| string[]; properties: Record<string, { type: "string" \| "number" \| "integer" \| "boolean" \| "array" \| "object"; title?: undefined \| string; description?: undefined \| string; default?: unknown; enum?: undefined \| unknown[]; format?: undefined \| "email" \| "uri" \| "url" \| "date" \| "date-time" \| "time"; minimum?: undefined \| number; maximum?: undefined \| number; minLength?: undefined \| number; maxLength?: undefined \| number; pattern?: undefined \| string; minItems?: undefined \| number; maxItems?: undefined \| number; items?: undefined \| Record<string, unknown> \| { enum: unknown[] }; properties?: undefined \| Record<string, Record<string, unknown>>; required?: undefined \| string[]; readOnly?: undefined \| false \| true; "x-kai-widget"?: undefined \| "textarea" \| "slider" \| "rating" \| "radio" \| "select" \| "checkbox" \| "password" \| "switch"; "x-kai-placeholder"?: undefined \| string; "x-kai-step"?: undefined \| number }>; "x-kai-order"?: undefined \| string[]; "x-kai-inlineMax"?: undefined \| number; "x-kai-submitLabel"?: undefined \| string; "x-kai-dismissible"?: undefined \| false \| true; "x-kai-actions"?: undefined \| { id: string; label: string; variant?: undefined \| "default" \| "ghost" \| "outline" }[] }` | The form definition: a JSON Schema (`type:'object'`) + `x-kai-*` UI hints (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object', properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for the full shape. It IS self-referential (`FormField.properties` is another `FormField` map), and the generated `element-types.d.ts` inlines every named type, so the shipped declaration bottoms out in a `Record<string, unknown>` placeholder one level down rather than carrying the recursion. That is why `FormDefinition` is a `type` alias: an interface gets no implicit index signature, so it would not be assignable to that placeholder. |
|
|
1364
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted CardEvent. Attribute: `card-id`. |
|
|
1365
|
-
| `heading` | `heading` | `undefined \| string` | Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. |
|
|
1366
|
-
| `resolution` | — | `undefined \| Record<string, unknown>` | Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'submit', data:{…} }`. |
|
|
1367
|
-
| `values` | — | `undefined \| Record<string, unknown>` | Controlled field values (JS property). When set, it wins over local edits. |
|
|
1368
|
-
| `defaultValues` | — | `undefined \| Record<string, unknown>` | Initial values overlaying the schema defaults (uncontrolled seed; JS property). |
|
|
1369
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable all fields + submit. Attribute: `disabled`. |
|
|
1370
|
-
|
|
1371
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1372
|
-
|
|
1373
|
-
| Event | `detail` type | Description |
|
|
1374
|
-
|---|---|---|
|
|
1375
|
-
| `kai-values-change` | `CustomEvent<{ values: Record<string, unknown>; valid: false \| true }>` | The form's values changed on input. Carries the current coerced values + validity. |
|
|
1376
|
-
|
|
1377
|
-
**Methods** (call on the element instance: `document.querySelector('kai-form').focus(…)`):
|
|
1378
|
-
|
|
1379
|
-
| Method | Signature | Description |
|
|
1380
|
-
|---|---|---|
|
|
1381
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the first control, or the first INVALID control after a failed validation. |
|
|
1382
|
-
| `send` | `(): void` | Validate + submit programmatically: focus the first invalid field on failure, else emit the `submit` CardEvent and resolve. Named `send`, not `submit`. |
|
|
1383
|
-
| `validate` | `(): void` | Run client-side validation now and return `{ valid, errors? }` WITHOUT submitting. |
|
|
1384
|
-
| `reset` | `(): void` | Re-seed the form from each field's `default` and clear errors. |
|
|
1385
|
-
| `dismiss` | `(): void` | Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). |
|
|
1386
|
-
| `reopen` | `(): void` | Re-open a dismissed card from its stub (emit `reopen`). |
|
|
1387
|
-
|
|
1388
|
-
---
|
|
1389
|
-
|
|
1390
|
-
### `kai-hover-card` / `HoverCard`
|
|
1391
|
-
|
|
1392
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1393
|
-
|
|
1394
|
-
| Property | Attribute | Type | Description |
|
|
1395
|
-
|---|---|---|---|
|
|
1396
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1397
|
-
| `openDelay` | `open-delay` | `undefined \| number` | Delay (ms) before the card opens on hover. Defaults to 0 (focus opens it immediately too). |
|
|
1398
|
-
| `closeDelay` | `close-delay` | `undefined \| number` | Delay (ms) before it closes after the pointer leaves. Defaults to 300. |
|
|
1399
|
-
| `placement` | `placement` | `undefined \| string` | Preferred placement: `'top' \| 'bottom' \| 'left' \| 'right'` (+ optional `-start`/`-end`). Defaults to `'bottom'`; flips to stay in view. |
|
|
1400
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the element still self-manages on hover). Set `el.open = true`, or `<kai-hover-card open>`; listen for `kai-open-change`. |
|
|
1401
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1402
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Suppress the hover behavior entirely without unmounting. |
|
|
1403
|
-
|
|
1404
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1405
|
-
|
|
1406
|
-
| Event | `detail` type | Description |
|
|
1407
|
-
|---|---|---|
|
|
1408
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The card opened or closed (by hover/focus, outside-click, or a method). |
|
|
1409
|
-
|
|
1410
|
-
**Methods** (call on the element instance: `document.querySelector('kai-hover-card').show()`):
|
|
1411
|
-
|
|
1412
|
-
| Method | Signature | Description |
|
|
1413
|
-
|---|---|---|
|
|
1414
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1415
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1416
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1417
|
-
|
|
1418
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1419
|
-
|
|
1420
|
-
| Slot | Mode | Description |
|
|
1421
|
-
|---|---|---|
|
|
1422
|
-
| _(default)_ | inject | The TRIGGER the card hovers off. The card body is the `card` slot. |
|
|
1423
|
-
| `card` | inject | The rich content shown in the floating hover card. |
|
|
1424
|
-
|
|
1425
|
-
---
|
|
1426
|
-
|
|
1427
|
-
### `kai-icon` / `Icon`
|
|
1428
|
-
|
|
1429
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1430
|
-
|
|
1431
|
-
| Property | Attribute | Type | Description |
|
|
1432
|
-
|---|---|---|---|
|
|
1433
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1434
|
-
| `name` | `name` | `undefined \| string` | A curated icon name (e.g. `"mic"`, `"globe"`), an image URL/data-URI, or plain text. |
|
|
1435
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg"` | Size token: `sm` \| `md` (default) \| `lg`. |
|
|
1436
|
-
|
|
1437
|
-
_No events._
|
|
1438
|
-
|
|
1439
|
-
**Styleable parts** (restyle from outside via `kai-icon::part(name)`):
|
|
1440
|
-
|
|
1441
|
-
| Part | Description |
|
|
1442
|
-
|---|---|
|
|
1443
|
-
| `::part(icon)` | The icon wrapper. Inherits `currentColor` and the `size` prop by default; recolor or resize it from outside. — `kai-icon::part(icon) { color: var(--color-primary) }` |
|
|
1444
|
-
|
|
1445
|
-
---
|
|
1446
|
-
|
|
1447
|
-
### `kai-image` / `Image`
|
|
1448
|
-
|
|
1449
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1450
|
-
|
|
1451
|
-
| Property | Attribute | Type | Description |
|
|
1452
|
-
|---|---|---|---|
|
|
1453
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1454
|
-
| `base64` | `base64` | `undefined \| string` | Base64-encoded image data (pair with `media-type`). |
|
|
1455
|
-
| `bytes` | — | `undefined \| Uint8Array<ArrayBufferLike>` | Raw image bytes (set as a JS property). |
|
|
1456
|
-
| `alt` | `alt` | `undefined \| string` | Alt text. |
|
|
1457
|
-
| `mediaType` | `media-type` | `undefined \| string` | MIME type (default `image/png`). |
|
|
1458
|
-
|
|
1459
|
-
_No events._
|
|
1460
|
-
|
|
1461
|
-
---
|
|
1462
|
-
|
|
1463
|
-
### `kai-input` / `Input`
|
|
1464
|
-
|
|
1465
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1466
|
-
|
|
1467
|
-
| Property | Attribute | Type | Description |
|
|
1468
|
-
|---|---|---|---|
|
|
1469
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1470
|
-
| `type` | `type` | `undefined \| string` | Native input type: `text` (default) · `email` · `url` · `search` · `tel` · `password` · `number`. Single-line only. |
|
|
1471
|
-
| `value` | `value` | `undefined \| string` | Controlled value. Settable and reflected to the `value` attribute. `el.value = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read `el.value` for live state. |
|
|
1472
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder shown when empty. |
|
|
1473
|
-
| `label` | `label` | `undefined \| string` | Field label, linked to the input. |
|
|
1474
|
-
| `hint` | `hint` | `undefined \| string` | Helper text below the control. |
|
|
1475
|
-
| `error` | `error` | `undefined \| string` | Error text; flips the field invalid (`aria-invalid` + destructive border). |
|
|
1476
|
-
| `size` | `size` | `undefined \| "sm" \| "md"` | Control density: `sm` or `md`. Defaults to `md`. |
|
|
1477
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable interaction. |
|
|
1478
|
-
| `readonly` | `readonly` | `undefined \| false \| true` | Make the input read-only. |
|
|
1479
|
-
| `required` | `required` | `undefined \| false \| true` | Mark the input required. |
|
|
1480
|
-
| `invalid` | `invalid` | `undefined \| false \| true` | Force the invalid state without an `error` string. |
|
|
1481
|
-
| `name` | `name` | `undefined \| string` | Form-control name. |
|
|
1482
|
-
| `autocomplete` | `autocomplete` | `undefined \| string` | Autofill hint forwarded to the inner input (e.g. `email`, `current-password`). |
|
|
1483
|
-
| `inputmode` | `inputmode` | `undefined \| string` | Virtual-keyboard hint forwarded to the inner input (e.g. `numeric`, `email`). |
|
|
1484
|
-
|
|
1485
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1486
|
-
|
|
1487
|
-
| Event | `detail` type | Description |
|
|
1488
|
-
|---|---|---|
|
|
1489
|
-
| `kai-change` | `CustomEvent<{ value: string }>` | The value was committed (blur). |
|
|
1490
|
-
| `kai-input` | `CustomEvent<{ value: string }>` | The value changed per keystroke. |
|
|
1491
|
-
|
|
1492
|
-
**Methods** (call on the element instance: `document.querySelector('kai-input').focus(…)`):
|
|
1493
|
-
|
|
1494
|
-
| Method | Signature | Description |
|
|
1495
|
-
|---|---|---|
|
|
1496
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the inner input (the host can't reach into the shadow root). |
|
|
1497
|
-
| `select` | `(): void` | Select the inner input's text. |
|
|
1498
|
-
| `clear` | `(): void` | Empty the value and fire `kai-change` with `''`. |
|
|
1499
|
-
|
|
1500
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1501
|
-
|
|
1502
|
-
| Slot | Mode | Description |
|
|
1503
|
-
|---|---|---|
|
|
1504
|
-
| `leading` | inject | A glyph, prefix, or affix at the start of the field, inside the border. |
|
|
1505
|
-
| `trailing` | inject | A button, unit, or affix at the end of the field, inside the border. |
|
|
1506
|
-
|
|
1507
|
-
**Styleable parts** (restyle from outside via `kai-input::part(name)`):
|
|
1508
|
-
|
|
1509
|
-
| Part | Description |
|
|
1510
|
-
|---|---|
|
|
1511
|
-
| `::part(field)` | The bordered control box (the row wrapping any affixes plus the input). Restyle its border, radius, surface, or focus ring. — `kai-input::part(field) { border-radius: 0.75rem }` |
|
|
1512
|
-
| `::part(input)` | The inner input element. Restyle its text, padding, or placeholder. — `kai-input::part(input) { font-variant-numeric: tabular-nums }` |
|
|
1513
|
-
| `::part(label)` | The field label above the control. Restyle its typography or spacing. — `kai-input::part(label) { font-weight: 600 }` |
|
|
1514
|
-
| `::part(hint)` | The hint or error line below the control. Restyle its typography. — `kai-input::part(hint) { font-style: italic }` |
|
|
1515
|
-
|
|
1516
|
-
---
|
|
1517
|
-
|
|
1518
|
-
### `kai-kbd` / `Kbd`
|
|
1519
|
-
|
|
1520
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1521
|
-
|
|
1522
|
-
| Property | Attribute | Type | Description |
|
|
1523
|
-
|---|---|---|---|
|
|
1524
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1525
|
-
| `keys` | `keys` | `undefined \| string` | Shortcut spec: tokens joined by `+` (e.g. `Mod+Shift+K`). Omit it to show default-slot content instead. Display only; the element does not bind keys. |
|
|
1526
|
-
| `platform` | `platform` | `undefined \| "auto" \| "mac" \| "other"` | `mac` uses ⌘/⌥, `other` uses Ctrl. `auto` (default) sniffs the OS. |
|
|
1527
|
-
| `size` | `size` | `undefined \| "sm" \| "md"` | Cap size: `sm` or `md`. Defaults to `md`. |
|
|
1528
|
-
|
|
1529
|
-
_No events._
|
|
1530
|
-
|
|
1531
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1532
|
-
|
|
1533
|
-
| Slot | Mode | Description |
|
|
1534
|
-
|---|---|---|
|
|
1535
|
-
| _(default)_ | inject | Literal key text, when you are not using the `keys` prop to render key caps. |
|
|
1536
|
-
|
|
1537
|
-
**Styleable parts** (restyle from outside via `kai-kbd::part(name)`):
|
|
1538
|
-
|
|
1539
|
-
| Part | Description |
|
|
1540
|
-
|---|---|
|
|
1541
|
-
| `::part(key)` | Each key cap. Restyle its surface, border, radius, or font. — `kai-kbd::part(key) { border-radius: 0.375rem }` |
|
|
1542
|
-
| `::part(separator)` | The gap between key caps. Inject a literal joiner (e.g. a plus sign) from outside. — `kai-kbd::part(separator)::after { content: "+" }` |
|
|
1543
|
-
|
|
1544
|
-
---
|
|
1545
|
-
|
|
1546
|
-
### `kai-link-preview` / `LinkPreview`
|
|
1547
|
-
|
|
1548
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1549
|
-
|
|
1550
|
-
| Property | Attribute | Type | Description |
|
|
1551
|
-
|---|---|---|---|
|
|
1552
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1553
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted event. Set as an attribute or property. |
|
|
1554
|
-
| `data` | — | `undefined \| { url: string; title?: undefined \| string; description?: undefined \| string; image?: undefined \| string; imageAlt?: undefined \| string; favicon?: undefined \| string; domain?: undefined \| string; siteName?: undefined \| string }` | The link payload (OG metadata). Set as a JS **property** (object). |
|
|
1555
|
-
|
|
1556
|
-
_No events._
|
|
1557
|
-
|
|
1558
|
-
---
|
|
1559
|
-
|
|
1560
|
-
### `kai-loader` / `Loader`
|
|
1561
|
-
|
|
1562
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1563
|
-
|
|
1564
|
-
| Property | Attribute | Type | Description |
|
|
1565
|
-
|---|---|---|---|
|
|
1566
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1567
|
-
| `variant` | `variant` | `undefined \| "circular" \| "classic" \| "pulse" \| "pulse-dot" \| "dots" \| "typing" \| "wave" \| "bars" \| "terminal" \| "text-blink" \| "text-shimmer" \| "loading-dots"` | The animation style: `'circular' \| 'classic' \| 'pulse' \| 'pulse-dot' \| 'dots' \| 'typing' \| 'wave' \| 'bars' \| 'terminal' \| 'text-blink' \| 'text-shimmer' \| 'loading-dots'`. Defaults to `'circular'`. |
|
|
1568
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg"` | Loader size: `'sm' \| 'md' \| 'lg'`. Defaults to `'md'`. |
|
|
1569
|
-
| `text` | `text` | `undefined \| string` | Label for the text-based variants. |
|
|
1570
|
-
|
|
1571
|
-
_No events._
|
|
1572
|
-
|
|
1573
|
-
---
|
|
1574
|
-
|
|
1575
|
-
### `kai-markdown` / `Markdown`
|
|
1576
|
-
|
|
1577
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1578
|
-
|
|
1579
|
-
| Property | Attribute | Type | Description |
|
|
1580
|
-
|---|---|---|---|
|
|
1581
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1582
|
-
| `content` | `content` | `string` | The markdown source to render. |
|
|
1583
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Text/markdown sizing. |
|
|
1584
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme for fenced code blocks. |
|
|
1585
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Disable syntax highlighting (no Shiki loads). |
|
|
1586
|
-
|
|
1587
|
-
_No events._
|
|
1588
|
-
|
|
1589
|
-
---
|
|
1590
|
-
|
|
1591
|
-
### `kai-menu` / `Menu`
|
|
1592
|
-
|
|
1593
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1594
|
-
|
|
1595
|
-
| Property | Attribute | Type | Description |
|
|
1596
|
-
|---|---|---|---|
|
|
1597
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1598
|
-
| `items` | — | `undefined \| { id?: undefined \| string; label?: undefined \| string; icon?: undefined \| string; shortcut?: undefined \| string; checked?: undefined \| false \| true; radioGroup?: undefined \| string; disabled?: undefined \| false \| true; separator?: undefined \| false \| true; heading?: undefined \| false \| true; items?: undefined \| Record<string, unknown>[] }[]` | Tree of menu items. Set as a JS property, not an HTML attribute. |
|
|
1599
|
-
| `placement` | `placement` | `undefined \| string` | Optional placement hint (unused by the underlying Dropdown which always positions bottom-start, kept for future extension). |
|
|
1600
|
-
| `triggerIcon` | `trigger-icon` | `undefined \| string` | Built-in trigger: leading icon (a named icon like `"plus"`, an image URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for the common case; a slotted trigger overrides it. |
|
|
1601
|
-
| `triggerLabel` | `trigger-label` | `undefined \| string` | Built-in trigger: a text label (e.g. `"High"`). This is the trigger's VISIBLE text, so it is also its accessible name, and `label` does not override it: an accessible name that does not contain the visible text is unreachable by speech input, which is what WCAG 2.5.3 (Label in Name) exists for. A slotted `slot="trigger"` replaces this built-in trigger entirely and is named differently; see `label`. |
|
|
1602
|
-
| `triggerIconTrailing` | `trigger-icon-trailing` | `undefined \| string` | Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). |
|
|
1603
|
-
| `label` | `label` | `undefined \| string` | Accessible name for a trigger with no visible label. Ignored when `triggerLabel` is set, which is already the visible name. It DOES name a slotted `slot="trigger"`, and that is a difference in what the two slots MEAN, not a limitation. `<kai-button>`'s slot IS the button's label, so text slotted there is the name and `label` steps aside. This slot is VISUAL content, a `+` or an `<svg>`, with the name supplied separately: decoration beside a name, never a second name competing with one. So `label` names the trigger here by design. Slotting a real WORD rather than a glyph makes that word a visible label, and an accessible name has to contain the visible text. Then either drop `label` or make it contain the word you slotted. |
|
|
1604
|
-
| `full` | `full` | `undefined \| false \| true` | Stretch the trigger to the full width of the menu's container (a block row), e.g. a sidebar-footer account row. Same affordance as `<kai-button full>`. Attribute: `full`. |
|
|
1605
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the menu still self-manages on click/keyboard). Set `el.open = true`, or `<kai-menu open>`; listen for `kai-open-change`. |
|
|
1606
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1607
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the trigger: click/keyboard and `show()` no longer open the menu. |
|
|
1608
|
-
|
|
1609
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1610
|
-
|
|
1611
|
-
| Event | `detail` type | Description |
|
|
1612
|
-
|---|---|---|
|
|
1613
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). |
|
|
1614
|
-
| `kai-select` | `CustomEvent<{ id: string; checked?: undefined \| false \| true; radioGroup?: undefined \| string }>` | Fired when the user selects a leaf item. - Plain items: `{ id }`. - Checkbox items: `{ id, checked }` where `checked` is the NEW state. - Radio items: `{ id, radioGroup }`, where the consumer marks `id` as the selected one in `radioGroup` and clears the others. |
|
|
1615
|
-
|
|
1616
|
-
**Methods** (call on the element instance: `document.querySelector('kai-menu').show()`):
|
|
1617
|
-
|
|
1618
|
-
| Method | Signature | Description |
|
|
1619
|
-
|---|---|---|
|
|
1620
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1621
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1622
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1623
|
-
|
|
1624
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1625
|
-
|
|
1626
|
-
| Slot | Mode | Description |
|
|
1627
|
-
|---|---|---|
|
|
1628
|
-
| `trigger` | replace | Your own trigger element; replaces the built-in button driven by the `trigger-icon` / `trigger-label` props. |
|
|
1629
|
-
|
|
1630
|
-
**Styleable parts** (restyle from outside via `kai-menu::part(name)`):
|
|
1631
|
-
|
|
1632
|
-
| Part | Description |
|
|
1633
|
-
|---|---|
|
|
1634
|
-
| `::part(shortcut)` | The right-aligned per-item keyboard shortcut, rendered as kai-kbd key caps. Shown only when an item carries a `shortcut`. — `kai-menu::part(shortcut) { opacity: 0.8 }` |
|
|
1635
|
-
|
|
1636
|
-
---
|
|
1637
|
-
|
|
1638
|
-
### `kai-message` / `Message`
|
|
1639
|
-
|
|
1640
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1641
|
-
|
|
1642
|
-
| Property | Attribute | Type | Description |
|
|
1643
|
-
|---|---|---|---|
|
|
1644
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1645
|
-
| `message` | — | `undefined \| { id: string; role: "user" \| "assistant"; parts: ({ type: "text"; text: string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "reasoning"; text: string; label?: undefined \| string; index?: undefined \| number; streamId?: undefined \| string; signature?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "tool"; tool: { type: string; kind?: undefined \| "command" \| "file-change" \| "search" \| "fetch" \| "mcp" \| "image" \| "generic"; state: "input-streaming" \| "input-available" \| "output-available" \| "output-error"; input?: undefined \| Record<string, unknown>; rawInput?: undefined \| string; output?: undefined \| Record<string, unknown>; toolCallId?: undefined \| string; errorText?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "card"; envelope: { type: string; id: string; data: unknown; title?: undefined \| string; resolution?: undefined \| { kind: "action"; action: string; payload?: unknown; at?: undefined \| string } \| { kind: "submit"; data: unknown; at?: undefined \| string } \| { kind: "dismissed"; at?: undefined \| string } \| { kind: "expired"; reason?: undefined \| string; at?: undefined \| string } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "source"; source: { id?: undefined \| string; url?: undefined \| string; title?: undefined \| string; snippet?: undefined \| string; index?: undefined \| number }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "file"; attachment: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }; raw?: undefined \| { source: string; payload: unknown } })[]; actions?: undefined \| ("copy" \| "like" \| "dislike" \| "regenerate" \| "edit" \| { id: string; label: string; icon?: undefined \| string; tooltip?: undefined \| string })[]; avatar?: undefined \| { src?: undefined \| string; fallback?: undefined \| string; alt?: undefined \| string }; feedback?: undefined \| "like" \| "dislike" }` | The full message object. Set as a JS property. |
|
|
1646
|
-
| `role` | `role` | `undefined \| "user" \| "assistant"` | Who is speaking: `'user'` or `'assistant'`. Convenience for simple cases when not passing a `message` object. This is the SEMANTIC role of the message, not an ARIA role. The name collides with the global ARIA `role` attribute, which is why the facade lifts it off the host (see `liftRoleOffHost`). Neither speaker is a valid ARIA role, so a `role="user"` left on `<kai-message>` is a CRITICAL axe `aria-roles` violation. The accessible role lives on the row inside the shadow root instead: `role="article"` plus an `aria-label` naming the speaker, matching the SolidJS `<Message>` component. |
|
|
1647
|
-
| `markdown` | `markdown` | `undefined \| false \| true` | Force markdown on/off. Defaults to on for assistant, off for user. |
|
|
1648
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Text/markdown sizing for the message body. |
|
|
1649
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme name used for fenced code blocks in the content. |
|
|
1650
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Disable syntax highlighting for code blocks (no Shiki loads). |
|
|
1651
|
-
| `actionsReveal` | `actions-reveal` | `undefined \| "always" \| "hover"` | Whether the action bar is always visible (`'always'`, default) or only revealed on hover of the message row (`'hover'`). |
|
|
1652
|
-
| `avatarSrc` | `avatar-src` | `undefined \| string` | Convenience avatar image URL (used when `message.avatar` is not set). |
|
|
1653
|
-
| `avatarFallback` | `avatar-fallback` | `undefined \| string` | Convenience avatar fallback text (used when `message.avatar` is not set). |
|
|
1654
|
-
| `avatar` | `avatar` | `undefined \| string` | Avatar rail mode. `'none'` omits the avatar rail entirely so the body spans the full row (predictable layout when you never show avatars). Any other value keeps the default behaviour: the built-in avatar when one resolves, or your `slot="avatar"` content when projected (which REPLACES the built-in). |
|
|
1655
|
-
| `cardTypes` | — | `undefined \| Record<string, string>` | Optional card type -> custom-element tag overrides/additions for `card` parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type. |
|
|
1656
|
-
| `cardSchemas` | — | `undefined \| Record<string, object>` | JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `cardTypes`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. |
|
|
1657
|
-
|
|
1658
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1659
|
-
|
|
1660
|
-
| Event | `detail` type | Description |
|
|
1661
|
-
|---|---|---|
|
|
1662
|
-
| `kai-message-action` | `CustomEvent<{ messageId: string; action: string; state?: undefined \| "on" \| "off" }>` | An action button was clicked. `action` is the built-in name or custom id. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. |
|
|
1663
|
-
|
|
1664
|
-
**Methods** (call on the element instance: `document.querySelector('kai-message').copy()`):
|
|
1665
|
-
|
|
1666
|
-
| Method | Signature | Description |
|
|
1667
|
-
|---|---|---|
|
|
1668
|
-
| `copy` | `(): void` | Copy the message content to the clipboard and show the copied check. |
|
|
1669
|
-
|
|
1670
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1671
|
-
|
|
1672
|
-
| Slot | Mode | Description |
|
|
1673
|
-
|---|---|---|
|
|
1674
|
-
| `before-body` | inject | A per-message header at the TOP of the body, above reasoning/tools/content: a model-name label, a role + timestamp line. |
|
|
1675
|
-
| `after-body` | inject | A row at the BOTTOM of the body, below the action bar: a citation/sources row, a token-cost/latency line. |
|
|
1676
|
-
| `avatar` | replace | Replaces the built-in avatar rail with your own node. Use `avatar="none"` to omit the rail and let the body span the full row. |
|
|
1677
|
-
|
|
1678
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
1679
|
-
|
|
1680
|
-
| Child element | Attributes | Text content | Notes |
|
|
1681
|
-
|---|---|---|---|
|
|
1682
|
-
| `<kai-action>` | `action`, `icon`, `id`, `label`, `tooltip` | yes | |
|
|
1683
|
-
|
|
1684
|
-
**Styleable parts** (restyle from outside via `kai-message::part(name)`):
|
|
1685
|
-
|
|
1686
|
-
| Part | Description |
|
|
1687
|
-
|---|---|
|
|
1688
|
-
| `::part(row)` | The message row wrapper (avatar rail + body column). Restyle its gap or alignment from outside. — `kai-message::part(row) { gap: 0.75rem }` |
|
|
1689
|
-
| `::part(bubble)` | The content bubble wrapper. Restyle its background, radius, or padding; for a user message this is the rounded chat bubble. — `kai-message::part(bubble) { background: var(--color-primary); color: var(--color-primary-foreground) }` |
|
|
1690
|
-
| `::part(content)` | The rendered message text/markdown region (same node as `bubble`). Target it to tune typography from outside. — `kai-message::part(content) { font-size: 0.9375rem }` |
|
|
1691
|
-
| `::part(actions)` | The action-bar row (copy / like / regenerate …). Restyle its spacing or hide it entirely from outside. — `kai-message::part(actions) { gap: 0.25rem }` |
|
|
1692
|
-
| `::part(citations)` | The citation row rendered from the message’s `source` parts: a wrapped row of chips below the bubble, never inside it. Restyle its spacing or hide it entirely from outside. — `kai-message::part(citations) { gap: 0.5rem }` |
|
|
1693
|
-
| `::part(attachment)` | One attachment item: the chip, row or tile, whichever variant is rendering. Restyle its background, radius or border from outside without caring which layout it is. — `kai-chat::part(attachment) { border-radius: 0.25rem }` |
|
|
1694
|
-
| `::part(attachment-name)` | The attachment’s filename label. Present in every variant that shows one (a grid tile omits it for an image, which is its own label). Retune its type or hide it entirely. — `kai-chat::part(attachment-name) { font-size: 0.75rem }` |
|
|
1695
|
-
| `::part(avatar)` | Replaces the built-in avatar rail with your own node. Use `avatar="none"` to omit the rail and let the body span the full row. |
|
|
1696
|
-
|
|
1697
|
-
---
|
|
1698
|
-
|
|
1699
|
-
### `kai-model-switcher` / `ModelSwitcher`
|
|
1700
|
-
|
|
1701
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1702
|
-
|
|
1703
|
-
| Property | Attribute | Type | Description |
|
|
1704
|
-
|---|---|---|---|
|
|
1705
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1706
|
-
| `models` | — | `undefined \| { id: string; name: string; provider?: undefined \| string; description?: undefined \| string; group?: undefined \| string }[]` | The selectable models. Set as a JS property (array). Omit to supply them as `<kai-model>` light-DOM children instead; when both are present the property's models come first. |
|
|
1707
|
-
| `currentModel` | `current-model` | `undefined \| string` | The currently-selected model id. Defaults to the first model. |
|
|
1708
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe the dropdown's open state (Shoelace-style: settable + reflected to the `open` attribute, the dropdown still self-manages on click/keyboard). Set `el.open = true`, or `<kai-model-switcher open>`; listen for `kai-open-change`. |
|
|
1709
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1710
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the trigger: click/keyboard and `show()` no longer open the dropdown. |
|
|
1711
|
-
|
|
1712
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1713
|
-
|
|
1714
|
-
| Event | `detail` type | Description |
|
|
1715
|
-
|---|---|---|
|
|
1716
|
-
| `kai-model-change` | `CustomEvent<{ modelId: string }>` | A model was selected. |
|
|
1717
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The model dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). |
|
|
1718
|
-
|
|
1719
|
-
**Methods** (call on the element instance: `document.querySelector('kai-model-switcher').show()`):
|
|
1720
|
-
|
|
1721
|
-
| Method | Signature | Description |
|
|
1722
|
-
|---|---|---|
|
|
1723
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1724
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1725
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1726
|
-
|
|
1727
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
1728
|
-
|
|
1729
|
-
| Child element | Attributes | Text content | Notes |
|
|
1730
|
-
|---|---|---|---|
|
|
1731
|
-
| `<kai-model>` | `description`, `group`, `id`, `provider` | yes | Parse a single light-DOM `<kai-model>` element into a `ModelOption` descriptor. Attribute mapping: - `id` → ModelOption.id - textContent → ModelOption.name - `provider` → ModelOption.provider (optional) - `description` → ModelOption.description (optional subtitle) - `group` → ModelOption.group (optional collapsible section) |
|
|
1732
|
-
|
|
1733
|
-
---
|
|
1734
|
-
|
|
1735
|
-
### `kai-nav` / `Nav`
|
|
1736
|
-
|
|
1737
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1738
|
-
|
|
1739
|
-
| Property | Attribute | Type | Description |
|
|
1740
|
-
|---|---|---|---|
|
|
1741
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1742
|
-
| `items` | — | `undefined \| { id: string; label?: undefined \| string; icon?: undefined \| string; badge?: undefined \| string; trailing?: undefined \| string; disabled?: undefined \| false \| true; children?: undefined \| Record<string, unknown>[]; status?: undefined \| { tone: "primary" \| "info" \| "success" \| "warning" \| "error" \| "neutral"; label?: undefined \| string; pulse?: undefined \| false \| true }; meta?: undefined \| string; action?: undefined \| { icon: string; label: string }; closable?: undefined \| false \| true }[]` | The nav items. Set as a JS property (array, not an attribute). Each item may carry `children` (a collapsible group), a `status` dot, and trailing `meta` text. |
|
|
1743
|
-
| `value` | `value` | `undefined \| string` | Active item id (controlled). |
|
|
1744
|
-
| `defaultValue` | `default-value` | `undefined \| string` | Initial active id when uncontrolled. |
|
|
1745
|
-
| `defaultCollapsed` | — | `undefined \| string[]` | Ids of group items collapsed on first render (groups default to expanded). Set as a JS property (array). |
|
|
1746
|
-
|
|
1747
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1748
|
-
|
|
1749
|
-
| Event | `detail` type | Description |
|
|
1750
|
-
|---|---|---|
|
|
1751
|
-
| `kai-nav-item-action` | `CustomEvent<{ value: string; action?: undefined \| { icon: string; label: string } }>` | A row's trailing `action` button was activated (not a select). `value` is the item id; `action` echoes the item's `{ icon, label }`. |
|
|
1752
|
-
| `kai-nav-item-close` | `CustomEvent<{ value: string }>` | A `closable` row's trailing close button was activated (not a select). `value` is the item id. |
|
|
1753
|
-
| `kai-nav-select` | `CustomEvent<{ id: string }>` | A nav item was activated. |
|
|
1754
|
-
|
|
1755
|
-
**Methods** (call on the element instance: `document.querySelector('kai-nav').select(…)`):
|
|
1756
|
-
|
|
1757
|
-
| Method | Signature | Description |
|
|
1758
|
-
|---|---|---|
|
|
1759
|
-
| `select` | `(id: string): void` | Activate an item by id (fires kai-nav-select). |
|
|
1760
|
-
|
|
1761
|
-
**Styleable parts** (restyle from outside via `kai-nav::part(name)`):
|
|
1762
|
-
|
|
1763
|
-
| Part | Description |
|
|
1764
|
-
|---|---|
|
|
1765
|
-
| `::part(nav)` | The nav list container. Restyle its gap or padding from outside. — `kai-nav::part(nav) { gap: 0.25rem }` |
|
|
1766
|
-
| `::part(item)` | A nav item button (leaf or group parent). The active leaf carries aria-current="page" and a group parent carries aria-expanded; target `::part(item)[aria-current]` for the selected look or `::part(item)[aria-expanded]` for a group row. — `kai-nav::part(item)[aria-current] { background: var(--color-accent) }` |
|
|
1767
|
-
| `::part(group)` | The nested child list rendered under an expanded group item. Add a left guide line or tune its indent from outside. — `kai-nav::part(group) { border-left: 1px solid var(--color-border); margin-left: 1.1rem }` |
|
|
1768
|
-
| `::part(chevron)` | The disclosure chevron on a group row (rotates when expanded). Recolor or resize it from outside. — `kai-nav::part(chevron) { opacity: 1; color: var(--color-primary) }` |
|
|
1769
|
-
| `::part(status)` | The per-item status cluster (a colored dot in the tone hue + an optional label). Shown only when an item carries a `status`; the `pulse` flag animates the dot. Restyle from outside. — `kai-nav::part(status) { gap: 0.5rem }` |
|
|
1770
|
-
| `::part(meta)` | The right-aligned muted trailing text on a row (e.g. a relative time). Shown only when an item carries `meta`; restyle from outside. — `kai-nav::part(meta) { color: var(--color-foreground); font-variant-numeric: tabular-nums }` |
|
|
1771
|
-
| `::part(item-action)` | The trailing per-item action / close button, a sibling of the item button. Shown only when an item carries `action` or `closable`; reveal it on hover or pin it visible from outside. — `kai-nav::part(item-action) { opacity: 1 }` |
|
|
1772
|
-
|
|
1773
|
-
---
|
|
1774
|
-
|
|
1775
|
-
### `kai-notice` / `Notice`
|
|
1776
|
-
|
|
1777
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1778
|
-
|
|
1779
|
-
| Property | Attribute | Type | Description |
|
|
1780
|
-
|---|---|---|---|
|
|
1781
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1782
|
-
| `severity` | `severity` | `undefined \| "neutral" \| "info" \| "warning" \| "error" \| "success"` | `neutral` (default) · `info` · `warning` · `error` · `success`. Drives the leading icon's color and the a11y role (`alert` for errors, else `status`). |
|
|
1783
|
-
| `icon` | `icon` | `undefined \| string` | Leading icon: omit for the severity default, `"none"` to hide it, or a named icon to override. |
|
|
1784
|
-
| `dismissible` | `dismissible` | `undefined \| false \| true` | Show a dismiss (×) that hides the notice and emits `kai-dismiss`. |
|
|
1785
|
-
|
|
1786
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1787
|
-
|
|
1788
|
-
| Event | `detail` type | Description |
|
|
1789
|
-
|---|---|---|
|
|
1790
|
-
| `kai-dismiss` | `CustomEvent` | The notice was dismissed via its × (it also hides itself). |
|
|
1791
|
-
|
|
1792
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1793
|
-
|
|
1794
|
-
| Slot | Mode | Description |
|
|
1795
|
-
|---|---|---|
|
|
1796
|
-
| _(default)_ | inject | The notice message. `icon` and `action` are the named seams around it. |
|
|
1797
|
-
| `action` | inject | A trailing action beside the message: a link or button. |
|
|
1798
|
-
| `icon` | replace | A custom leading icon (any inline SVG, inherits `currentColor`). Overrides the severity default and the `icon` prop, the same escape hatch as `kai-button`. |
|
|
1799
|
-
|
|
1800
|
-
---
|
|
1801
|
-
|
|
1802
|
-
### `kai-pane` / `Pane`
|
|
1803
|
-
|
|
1804
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1805
|
-
|
|
1806
|
-
| Property | Attribute | Type | Description |
|
|
1807
|
-
|---|---|---|---|
|
|
1808
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1809
|
-
| `headline` | `headline` | `undefined \| string` | The pane title (the agent / window name). Named `headline` because `title` collides with the global `HTMLElement.title` attribute (it throws at registration). Attribute: `headline`. |
|
|
1810
|
-
| `subtitle` | `subtitle` | `undefined \| string` | A role / label shown under the title (e.g. "Reviewer", "claude-sonnet"). Attribute: `subtitle`. |
|
|
1811
|
-
| `maximized` | `maximized` | `undefined \| false \| true` | Show the restore glyph instead of maximize, and signal the maximized view-state. Drive it yourself in response to `kai-maximize`. Attribute: `maximized`. |
|
|
1812
|
-
| `focused` | `focused` | `undefined \| false \| true` | Highlight the frame with a ring/border to mark the ACTIVE pane. Attribute: `focused`. |
|
|
1813
|
-
| `showSplit` | `show-split` | `undefined \| false \| true` | Show a split-pane window control that fires `kai-split`. Off by default. Attribute: `show-split`. |
|
|
1814
|
-
| `showDock` | `show-dock` | `undefined \| false \| true` | Show a dock-to-side window control that fires `kai-dock`. Off by default. Attribute: `show-dock`. |
|
|
1815
|
-
| `status` | — | `undefined \| { tone: "working" \| "idle" \| "done" \| "error" \| "blocked"; label?: undefined \| string; pulse?: undefined \| false \| true }` | A tone-colored status dot (+ optional label) in the header. An object `{ tone, label?, pulse? }` set as a JS PROPERTY (not an attribute). |
|
|
1816
|
-
|
|
1817
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1818
|
-
|
|
1819
|
-
| Event | `detail` type | Description |
|
|
1820
|
-
|---|---|---|
|
|
1821
|
-
| `kai-close` | `CustomEvent` | The close (×) control was clicked. |
|
|
1822
|
-
| `kai-dock` | `CustomEvent` | The dock control was clicked (only present when `show-dock`). |
|
|
1823
|
-
| `kai-maximize` | `CustomEvent<{ maximized: false \| true }>` | The maximize/restore control was clicked. `detail.maximized` is the intended NEXT state. Drive the `maximized` prop yourself from it. |
|
|
1824
|
-
| `kai-split` | `CustomEvent` | The split control was clicked (only present when `show-split`). |
|
|
1825
|
-
|
|
1826
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1827
|
-
|
|
1828
|
-
| Slot | Mode | Description |
|
|
1829
|
-
|---|---|---|
|
|
1830
|
-
| _(default)_ | inject | The pane body, below the header row. |
|
|
1831
|
-
| `leading` | inject | A glyph or avatar at the start of the pane header. |
|
|
1832
|
-
| `actions` | inject | Extra header controls, before the built-in window controls. |
|
|
1833
|
-
| `footer` | inject | A pinned row below the body (e.g. a composer). |
|
|
1834
|
-
|
|
1835
|
-
**Styleable parts** (restyle from outside via `kai-pane::part(name)`):
|
|
1836
|
-
|
|
1837
|
-
| Part | Description |
|
|
1838
|
-
|---|---|
|
|
1839
|
-
| `::part(header)` | The pane header bar (leading + title/status + actions + window controls). — `kai-pane::part(header) { padding-inline: 0.75rem }` |
|
|
1840
|
-
| `::part(body)` | The scrolling body region (the default slot). — `kai-pane::part(body) { padding: 1rem }` |
|
|
1841
|
-
| `::part(controls)` | The window-control cluster (maximize/close, and split/dock when enabled). — `kai-pane::part(controls) { gap: 0.25rem }` |
|
|
1842
|
-
| `::part(footer)` | A pinned row below the body (e.g. a composer). |
|
|
1843
|
-
|
|
1844
|
-
---
|
|
1845
|
-
|
|
1846
|
-
### `kai-pane-group` / `PaneGroup`
|
|
1847
|
-
|
|
1848
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1849
|
-
|
|
1850
|
-
| Property | Attribute | Type | Description |
|
|
1851
|
-
|---|---|---|---|
|
|
1852
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1853
|
-
| `tabs` | — | `undefined \| { id: string; name: string; status?: undefined \| { tone: "working" \| "idle" \| "done" \| "error" \| "blocked"; label?: undefined \| string; pulse?: undefined \| false \| true }; needsAttention?: undefined \| false \| true; number?: undefined \| number }[]` | The tabs to render. An array of `{ id, name, status?, needsAttention?, number? }` set as a JS PROPERTY (not an HTML attribute). |
|
|
1854
|
-
| `active` | `active` | `undefined \| string` | The active tab id (controlled, and reflected to the `active` ATTRIBUTE so `::part`/`[active]` selectors and the per-tab named slot follow it). Set it as the `active` attribute or drive it from `kai-tab-change`; omit for uncontrolled (the first tab). |
|
|
1855
|
-
| `focused` | `focused` | `undefined \| false \| true` | Highlight the frame as the ACTIVE group in a multi-group layout. Attribute: `focused`. |
|
|
1856
|
-
|
|
1857
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1858
|
-
|
|
1859
|
-
| Event | `detail` type | Description |
|
|
1860
|
-
|---|---|---|
|
|
1861
|
-
| `kai-tab-change` | `CustomEvent<{ id: string }>` | A tab was selected (click, Enter/Space, or arrow-key move). `detail.id` is the tab's id. |
|
|
1862
|
-
| `kai-tab-close` | `CustomEvent<{ id: string }>` | A tab's close (×) was clicked. Drop the tab from `tabs` yourself. |
|
|
1863
|
-
| `kai-tab-menu` | `CustomEvent<{ id: string }>` | A tab's "…" overflow was clicked. Open your own menu from `detail.id`. |
|
|
1864
|
-
|
|
1865
|
-
**Methods** (call on the element instance: `document.querySelector('kai-pane-group').select(…)`):
|
|
1866
|
-
|
|
1867
|
-
| Method | Signature | Description |
|
|
1868
|
-
|---|---|---|
|
|
1869
|
-
| `select` | `(id: string): void` | Select a tab by id (fires `kai-tab-change`). Ignores unknown ids. |
|
|
1870
|
-
| `focus` | `(): void` | Focus the active tab in the strip. |
|
|
1871
|
-
|
|
1872
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1873
|
-
|
|
1874
|
-
| Slot | Mode | Description |
|
|
1875
|
-
|---|---|---|
|
|
1876
|
-
| _(default)_ | inject | Content shown for every tab. Use it INSTEAD of the per-tab `slot="<tab id>"` seams when you swap the content yourself. |
|
|
1877
|
-
|
|
1878
|
-
**Styleable parts** (restyle from outside via `kai-pane-group::part(name)`):
|
|
1879
|
-
|
|
1880
|
-
| Part | Description |
|
|
1881
|
-
|---|---|
|
|
1882
|
-
| `::part(tabs)` | The tab strip (role="tablist"). Restyle its background, height, padding, or gap from outside. — `kai-pane-group::part(tabs) { background: var(--color-card); gap: 0.25rem }` |
|
|
1883
|
-
| `::part(tab)` | A single tab button. The active tab carries `[aria-selected="true"]`; target `::part(tab)[aria-selected="true"]` for the selected look. — `kai-pane-group::part(tab)[aria-selected="true"] { background: var(--color-accent) }` |
|
|
1884
|
-
| `::part(body)` | The active tab's content region (the named/default slot host). — `kai-pane-group::part(body) { padding: 0.75rem }` |
|
|
1885
|
-
| `::part(menu)` | The per-tab "…" overflow button. Reveal it on hover or pin it visible from outside. — `kai-pane-group::part(menu) { opacity: 1 }` |
|
|
1886
|
-
| `::part(close)` | The per-tab close ("×") button. Recolor, resize, or hide it from outside. — `kai-pane-group::part(close) { color: var(--color-muted-foreground) }` |
|
|
1887
|
-
|
|
1888
|
-
---
|
|
1889
|
-
|
|
1890
|
-
### `kai-popover` / `Popover`
|
|
1891
|
-
|
|
1892
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1893
|
-
|
|
1894
|
-
| Property | Attribute | Type | Description |
|
|
1895
|
-
|---|---|---|---|
|
|
1896
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1897
|
-
| `placement` | `placement` | `undefined \| "top" \| "right" \| "bottom" \| "left" \| "bottom-end" \| "bottom-start" \| "left-end" \| "left-start" \| "right-end" \| "right-start" \| "top-end" \| "top-start"` | Floating placement relative to the trigger (floating-ui placement). |
|
|
1898
|
-
| `gutter` | `gutter` | `undefined \| number` | Gap in px between the trigger and the panel. |
|
|
1899
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the element still self-manages on click). Set `el.open = true`, or `<kai-popover open>`; listen for `kai-open-change`. |
|
|
1900
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
1901
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Turn the popover off while keeping the trigger mounted (clicks and `show()` no longer open it). |
|
|
1902
|
-
|
|
1903
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
1904
|
-
|
|
1905
|
-
| Event | `detail` type | Description |
|
|
1906
|
-
|---|---|---|
|
|
1907
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The popover opened or closed (click, Escape, outside-click, or a method). |
|
|
1908
|
-
|
|
1909
|
-
**Methods** (call on the element instance: `document.querySelector('kai-popover').show()`):
|
|
1910
|
-
|
|
1911
|
-
| Method | Signature | Description |
|
|
1912
|
-
|---|---|---|
|
|
1913
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
1914
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
1915
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
1916
|
-
|
|
1917
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1918
|
-
|
|
1919
|
-
| Slot | Mode | Description |
|
|
1920
|
-
|---|---|---|
|
|
1921
|
-
| _(default)_ | inject | The popover panel body. The control that opens it is the `trigger` slot. |
|
|
1922
|
-
| `trigger` | replace | The control that opens the popover (a button, an avatar, …). The panel anchors to it. |
|
|
1923
|
-
|
|
1924
|
-
---
|
|
1925
|
-
|
|
1926
|
-
### `kai-progress-bar` / `ProgressBar`
|
|
1927
|
-
|
|
1928
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1929
|
-
|
|
1930
|
-
| Property | Attribute | Type | Description |
|
|
1931
|
-
|---|---|---|---|
|
|
1932
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1933
|
-
| `value` | `value` | `undefined \| number` | Current progress value (0..max). Attribute: `value`. |
|
|
1934
|
-
| `max` | `max` | `undefined \| number` | The value `value` runs to (default 100). Attribute: `max`. |
|
|
1935
|
-
| `label` | `label` | `undefined \| string` | Optional caption above the track. Attribute: `label`. |
|
|
1936
|
-
| `tone` | `tone` | `undefined \| string` | Fill color: `primary` (default), `success`, `warning`, `error`, `info`. Attribute: `tone`. |
|
|
1937
|
-
|
|
1938
|
-
_No events._
|
|
1939
|
-
|
|
1940
|
-
**Styleable parts** (restyle from outside via `kai-progress-bar::part(name)`):
|
|
1941
|
-
|
|
1942
|
-
| Part | Description |
|
|
1943
|
-
|---|---|
|
|
1944
|
-
| `::part(track)` | The progress track (the background bar). Restyle its height, radius, or background from outside. — `kai-progress-bar::part(track) { height: 0.5rem }` |
|
|
1945
|
-
| `::part(fill)` | The filled portion; its width follows value/max. Recolor it from outside. — `kai-progress-bar::part(fill) { background: var(--color-tool-green) }` |
|
|
1946
|
-
|
|
1947
|
-
---
|
|
1948
|
-
|
|
1949
|
-
### `kai-prompt-dock` / `PromptDock`
|
|
1950
|
-
|
|
1951
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1952
|
-
|
|
1953
|
-
| Property | Attribute | Type | Description |
|
|
1954
|
-
|---|---|---|---|
|
|
1955
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1956
|
-
| `frame` | `frame` | `undefined \| "inset" \| "edge" \| "none"` | How the tray frames the input, the SPATIAL inset axis: `inset` (default, the classic recessed frame on every side) \| `edge` (top/bottom inset only; the input sits flush left/right so the lips span the full width) \| `none` (no inset; the lips attach directly as a plain stack). Attribute: `frame`. |
|
|
1957
|
-
| `appearance` | `appearance` | `undefined \| "soft" \| "outlined" \| "filled" \| "plain"` | How the tray surface looks, the VISUAL axis orthogonal to `frame`: `soft` (default, sunken surface + border + radius) \| `outlined` (transparent + border + radius) \| `filled` (sunken, no border, + radius) \| `plain` (bare). Attribute: `appearance`. |
|
|
1958
|
-
|
|
1959
|
-
_No events._
|
|
1960
|
-
|
|
1961
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
1962
|
-
|
|
1963
|
-
| Slot | Mode | Description |
|
|
1964
|
-
|---|---|---|
|
|
1965
|
-
| _(default)_ | inject | The input the dock wraps, typically a `<kai-prompt-input>`. The `top`/`bottom` slots are the lips around it. |
|
|
1966
|
-
| `top` | inject | The top lip: a notice or banner above the input. Rendered only when filled. |
|
|
1967
|
-
| `bottom` | inject | The bottom lip: a mode or controls row below the input. Rendered only when filled. |
|
|
1968
|
-
|
|
1969
|
-
**Styleable parts** (restyle from outside via `kai-prompt-dock::part(name)`):
|
|
1970
|
-
|
|
1971
|
-
| Part | Description |
|
|
1972
|
-
|---|---|
|
|
1973
|
-
| `::part(tray)` | The recessed tray that frames the input. The `appearance`/`frame` props set the defaults; the --kai-prompt-dock-* tokens fine-tune surface/border/radius/inset. — `kai-prompt-dock::part(tray) { --kai-prompt-dock-radius: 1rem }` |
|
|
1974
|
-
| `::part(top)` | The top lip: a notice or banner above the input. Rendered only when filled. |
|
|
1975
|
-
| `::part(bottom)` | The bottom lip: a mode or controls row below the input. Rendered only when filled. |
|
|
1976
|
-
|
|
1977
|
-
---
|
|
1978
|
-
|
|
1979
|
-
### `kai-prompt-input` / `PromptInput`
|
|
1980
|
-
|
|
1981
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
1982
|
-
|
|
1983
|
-
| Property | Attribute | Type | Description |
|
|
1984
|
-
|---|---|---|---|
|
|
1985
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
1986
|
-
| `value` | — | `undefined \| string \| ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]` | Value of the input, as a JS property. A **string** is the controlled text mirror (the host owns it and updates on `kai-value-change`). A **ComposerDoc** (array of text/entity segments) is a one-time **seed** that pre-populates pills (skills/agents/plugins); the user then edits freely. Leave unset for uncontrolled behavior. `kai-submit`/`kai-value-change` always emit `value` as the flattened string (back-compat) plus the structured `doc` + `entities`. |
|
|
1987
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder text shown in the empty input. |
|
|
1988
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the input and submit button entirely (non-interactive). |
|
|
1989
|
-
| `loading` | `loading` | `undefined \| false \| true` | Show the loading/streaming state and block submit (use while awaiting a reply). |
|
|
1990
|
-
| `suggestions` | — | `undefined \| string[]` | Starter prompts shown above the input. Clicking one follows `suggestionMode`. Set as a JS property. |
|
|
1991
|
-
| `suggestionMode` | `suggestion-mode` | `undefined \| "submit" \| "fill"` | What clicking a suggestion does: `'submit'` (default) sends it immediately as if typed and submitted; `'fill'` just places it in the input. |
|
|
1992
|
-
| `webSearch` | `web-search` | `undefined \| false \| true` | Show a web-search (Globe) button in the left toolbar; clicking it fires a `kai-web-search` event. Attribute: `web-search`. |
|
|
1993
|
-
| `voice` | `voice` | `undefined \| false \| true` | Show a Voice (Mic) button in the left toolbar; clicking it fires a `voice` event. |
|
|
1994
|
-
| `stoppable` | `stoppable` | `undefined \| false \| true` | When set and `loading` is true, the send button is replaced by a Stop button (square icon, "Stop" aria-label). Clicking it fires `kai-stop`. |
|
|
1995
|
-
| `submit` | `submit` | `undefined \| "always" \| "auto"` | Send-button visibility. `'always'` (default) always shows it; `'auto'` shows it only when there's text/attachments (an empty composer hides it, though Enter still submits). To hide it entirely (Enter-only), it's pure CSS: `::part(send){display:none}`, no prop needed. Restyle via `::part(send)`. The Stop button (`stoppable` + `loading`) is unaffected. |
|
|
1996
|
-
| `attach` | `attach` | `undefined \| false \| true` | When `false`, hides the built-in paperclip attach button even though the element otherwise supports attachments. Use this when a `+` menu in `toolbar-start` already exposes "Add files", to avoid a duplicate control. Defaults to `true`. |
|
|
1997
|
-
| `attachments` | — | `undefined \| { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[]` | Attachments to seed the input with (so a consumer can pre-populate staged files without an upload). Set as a JS property; the element then manages its own attachment state from there (add via the paperclip, remove per chip). |
|
|
1998
|
-
| `triggers` | — | `undefined \| { char: string; kind: string; items?: undefined \| { id: string; label: string; icon?: undefined \| string; description?: undefined \| string; group?: undefined \| string; kind?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }[]` | Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu that inserts an atomic pill. Convention: `/` → skills, `@` → agents (plugins are the grouping/provenance of those items). Set as a JS property. |
|
|
1999
|
-
| `kindIcons` | — | `undefined \| Record<string, string>` | Default icon per entity kind (kind → image URL/data-URI) for pills/menu items without their own `icon`. Overrides the built-in agent/plugin glyphs. JS property. |
|
|
2000
|
-
|
|
2001
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2002
|
-
|
|
2003
|
-
| Event | `detail` type | Description |
|
|
2004
|
-
|---|---|---|
|
|
2005
|
-
| `kai-attachments-change` | `CustomEvent<{ attachments: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[] }>` | The staged attachments changed: a file was added (via the paperclip) or removed (per-chip ×). Carries the full current list so a consumer can react in real time (validate, show upload progress, toggle the send button). |
|
|
2006
|
-
| `kai-stop` | `CustomEvent<Record<string, never>>` | The Stop button was clicked while `stoppable` and `loading` are both true. |
|
|
2007
|
-
| `kai-submit` | `CustomEvent<{ value: string; doc: ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]; entities: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[]; attachments: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }[] }>` | The user submitted the prompt (Enter or send button). `value` is the flattened text (back-compat); `doc` is the structured document and `entities` the inserted pills (skills/agents) for downstream expansion. |
|
|
2008
|
-
| `kai-suggestion-click` | `CustomEvent<{ value: string }>` | A suggestion was clicked while `suggestion-mode="fill"`. |
|
|
2009
|
-
| `kai-toolbar-action` | `CustomEvent<{ action: string }>` | A custom `<kai-action>` toolbar button was clicked. `action` is the `id` of the `<kai-action>` element that was clicked. |
|
|
2010
|
-
| `kai-value-change` | `CustomEvent<{ value: string; doc: ({ type: "text"; text: string } \| { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> } })[]; entities: { kind: string; id: string; label: string; icon?: undefined \| string; promptText?: undefined \| string; data?: undefined \| Record<string, unknown> }[] }>` | The input changed (fires on every edit). Carries the flattened `value` plus the structured `doc` + `entities`. |
|
|
2011
|
-
| `kai-voice` | `CustomEvent<Record<string, never>>` | The Voice (Mic) toolbar button was clicked. |
|
|
2012
|
-
| `kai-web-search` | `CustomEvent<Record<string, never>>` | The web-search (Globe) toolbar button was clicked. |
|
|
2013
|
-
|
|
2014
|
-
**Methods** (call on the element instance: `document.querySelector('kai-prompt-input').focus(…)`):
|
|
2015
|
-
|
|
2016
|
-
| Method | Signature | Description |
|
|
2017
|
-
|---|---|---|
|
|
2018
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the text editor inside the shadow root (not the hidden file input). |
|
|
2019
|
-
| `blur` | `(): void` | Blur the focused input control. |
|
|
2020
|
-
| `clear` | `(): void` | Clear the text and any staged attachments (fires kai-value-change / kai-attachments-change so a controlled consumer can react). |
|
|
2021
|
-
| `send` | `(): void` | Send the current value programmatically, on the same path as Enter / the send button (fires kai-submit, then clears staged attachments). Named `send`, not `submit`, to avoid colliding with the `submit` prop. |
|
|
2022
|
-
|
|
2023
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2024
|
-
|
|
2025
|
-
| Slot | Mode | Description |
|
|
2026
|
-
|---|---|---|
|
|
2027
|
-
| `input-top` | inject | Inside the card, above the textarea (e.g. an inline status strip). For content above/below the whole card, use your own layout; that is light DOM you control. |
|
|
2028
|
-
| `toolbar-start` | inject | Leading controls in the input toolbar, where a + menu goes. |
|
|
2029
|
-
| `toolbar-end` | inject | Trailing controls in the toolbar, before the Send button. |
|
|
2030
|
-
|
|
2031
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
2032
|
-
|
|
2033
|
-
| Child element | Attributes | Text content | Notes |
|
|
2034
|
-
|---|---|---|---|
|
|
2035
|
-
| `<kai-action>` | `action`, `icon`, `id`, `label`, `tooltip` | yes | |
|
|
2036
|
-
|
|
2037
|
-
**Styleable parts** (restyle from outside via `kai-prompt-input::part(name)`):
|
|
2038
|
-
|
|
2039
|
-
| Part | Description |
|
|
2040
|
-
|---|---|
|
|
2041
|
-
| `::part(send)` | The send button. Restyle from outside, or hide it entirely (Enter-only). Hiding is pure CSS, which is why there is no `submit="never"`. — `kai-prompt-input::part(send) { display: none } /* Enter-only; or restyle: background, border-radius, … */` |
|
|
2042
|
-
|
|
2043
|
-
---
|
|
2044
|
-
|
|
2045
|
-
### `kai-reasoning` / `Reasoning`
|
|
2046
|
-
|
|
2047
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2048
|
-
|
|
2049
|
-
| Property | Attribute | Type | Description |
|
|
2050
|
-
|---|---|---|---|
|
|
2051
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2052
|
-
| `text` | `text` | `string` | The reasoning text to display. |
|
|
2053
|
-
| `label` | `label` | `undefined \| string` | Trigger label. |
|
|
2054
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on trigger click + while streaming). Set `el.open = true`; listen for `kai-open-change`. |
|
|
2055
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
2056
|
-
| `streaming` | `streaming` | `undefined \| false \| true` | While true, auto-expands (and re-collapses when it flips false). |
|
|
2057
|
-
| `markdown` | `markdown` | `undefined \| false \| true` | Render `text` as markdown. |
|
|
2058
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Gate the disclosure trigger: programmatic `show()/hide()/toggle()` still work, but the trigger click no longer toggles. |
|
|
2059
|
-
|
|
2060
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2061
|
-
|
|
2062
|
-
| Event | `detail` type | Description |
|
|
2063
|
-
|---|---|---|
|
|
2064
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The reasoning block expanded or collapsed (via the trigger, streaming auto-open, or a method). |
|
|
2065
|
-
|
|
2066
|
-
**Methods** (call on the element instance: `document.querySelector('kai-reasoning').show()`):
|
|
2067
|
-
|
|
2068
|
-
| Method | Signature | Description |
|
|
2069
|
-
|---|---|---|
|
|
2070
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
2071
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
2072
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
2073
|
-
|
|
2074
|
-
---
|
|
2075
|
-
|
|
2076
|
-
### `kai-remote` / `Remote`
|
|
2077
|
-
|
|
2078
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2079
|
-
|
|
2080
|
-
| Property | Attribute | Type | Description |
|
|
2081
|
-
|---|---|---|---|
|
|
2082
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2083
|
-
| `src` | `src` | `undefined \| string` | The remote card URL. Attribute: `src`. |
|
|
2084
|
-
| `providerOrigin` | `provider-origin` | `undefined \| string` | Exact provider origin (https: or http://localhost for dev). Attribute: `provider-origin`. |
|
|
2085
|
-
| `envelope` | — | `undefined \| Record<string, unknown>` | The card envelope to render. JS property only. |
|
|
2086
|
-
| `policy` | — | `undefined \| Record<string, unknown>` | Optional routing policy. JS property only. |
|
|
2087
|
-
|
|
2088
|
-
_No events._
|
|
2089
|
-
|
|
2090
|
-
---
|
|
2091
|
-
|
|
2092
|
-
### `kai-resizable` / `Resizable`
|
|
2093
|
-
|
|
2094
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2095
|
-
|
|
2096
|
-
| Property | Attribute | Type | Description |
|
|
2097
|
-
|---|---|---|---|
|
|
2098
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2099
|
-
| `orientation` | `orientation` | `undefined \| "horizontal" \| "vertical"` | Layout axis: `horizontal` (row, default) or `vertical` (column). |
|
|
2100
|
-
| `maximizedIndex` | — | `undefined \| number \| null` | Which item index is maximized (null = none). Declarative source of truth. |
|
|
2101
|
-
| `handle` | `handle` | `undefined \| "line" \| "grip" \| "none"` | Divider affordance drawn inside each draggable handle's 8px grab zone: - `line` (default): a 1px hairline, transparent at rest, tinting on hover/drag. - `grip`: a dotted grip handle. - `none`: no visible divider, just the invisible hit-area. The full grab zone and keyboard/ARIA behavior are identical for all three. |
|
|
2102
|
-
|
|
2103
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2104
|
-
|
|
2105
|
-
| Event | `detail` type | Description |
|
|
2106
|
-
|---|---|---|
|
|
2107
|
-
| `kai-change` | `CustomEvent<{ sizes: number[] }>` | Fired on drag-end / keyboard resize / visibility change. `detail.sizes` = panel sizes in percent. |
|
|
2108
|
-
| `kai-maximize-change` | `CustomEvent<{ maximized: false \| true; index: number \| null }>` | Observe layout maximize state. |
|
|
2109
|
-
| `kai-maximize-state` | `CustomEvent<{ maximized: false \| true }>` | Authoritative maximize state, dispatched as a raw composed CustomEvent (not through `dispatch`) onto the affected `<kai-resizable-item>` and, on restore, onto the group host. A nested element (e.g. `<kai-artifact>`) listens for it to reconcile its own toggle. |
|
|
2110
|
-
|
|
2111
|
-
**Methods** (call on the element instance: `document.querySelector('kai-resizable').maximize(…)`):
|
|
2112
|
-
|
|
2113
|
-
| Method | Signature | Description |
|
|
2114
|
-
|---|---|---|
|
|
2115
|
-
| `maximize` | `(index: number): void` | Imperatively maximize the item at `index` (thin wrapper over `maximizedIndex`). |
|
|
2116
|
-
| `restore` | `(): void` | Imperatively restore from the maximized layout. |
|
|
2117
|
-
|
|
2118
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2119
|
-
|
|
2120
|
-
| Slot | Mode | Description |
|
|
2121
|
-
|---|---|---|
|
|
2122
|
-
| _(default)_ | inject | The `<kai-resizable-item>` panels, in order. Dividers are inserted between them. |
|
|
2123
|
-
|
|
2124
|
-
---
|
|
2125
|
-
|
|
2126
|
-
### `kai-resizable-item` / `ResizableItem`
|
|
2127
|
-
|
|
2128
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2129
|
-
|
|
2130
|
-
| Property | Attribute | Type | Description |
|
|
2131
|
-
|---|---|---|---|
|
|
2132
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2133
|
-
| `size` | `size` | `undefined \| string` | Initial main-axis size: `"280px"` (fixed) or `"25%"`/`25` (percent). Omitted → flexible. |
|
|
2134
|
-
| `min` | `min` | `undefined \| string` | Minimum size during resize (px or %). |
|
|
2135
|
-
| `max` | `max` | `undefined \| string` | Maximum size during resize (px or %). |
|
|
2136
|
-
| `locked` | `locked` | `undefined \| false \| true` | Fix this panel's size; adjacent dividers become non-draggable. |
|
|
2137
|
-
| `hidden` | `hidden` | `undefined \| false \| true` | Hide this panel; its divider is dropped and the rest reflow. |
|
|
2138
|
-
| `collapsed` | `collapsed` | `undefined \| false \| true` | Collapse this panel. Same layout effect as `hidden` (divider dropped, the rest reflow), but it WORKS as a bare boolean from framework JSX. A plain `<kai-resizable-item collapsed>` in React/Solid/Vue/Svelte collapses the panel at the first render; `hidden` does not, because a JSX boolean sets neither the `hidden` attribute nor the IDL property on a custom element, so the parent never sees it. The facade reflects `collapsed` to a `collapsed` attribute the parent reads. Prefer this over `hidden` for declarative collapse. |
|
|
2139
|
-
|
|
2140
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2141
|
-
|
|
2142
|
-
| Event | `detail` type | Description |
|
|
2143
|
-
|---|---|---|
|
|
2144
|
-
| `kai-change` | `CustomEvent<unknown>` | |
|
|
2145
|
-
| `kai-maximize-change` | `CustomEvent<unknown>` | |
|
|
2146
|
-
| `kai-maximize-state` | `CustomEvent<unknown>` | |
|
|
2147
|
-
|
|
2148
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2149
|
-
|
|
2150
|
-
| Slot | Mode | Description |
|
|
2151
|
-
|---|---|---|
|
|
2152
|
-
| _(default)_ | inject | This panel's content. |
|
|
2153
|
-
|
|
2154
|
-
---
|
|
2155
|
-
|
|
2156
|
-
### `kai-response-stream` / `ResponseStream`
|
|
2157
|
-
|
|
2158
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2159
|
-
|
|
2160
|
-
| Property | Attribute | Type | Description |
|
|
2161
|
-
|---|---|---|---|
|
|
2162
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2163
|
-
| `text` | — | `undefined \| string \| AsyncIterable<string>` | Text to stream. A string, or an `AsyncIterable<string>` (set as a JS property, since async iterables can't be HTML attributes). |
|
|
2164
|
-
| `mode` | `mode` | `undefined \| "typewriter" \| "fade"` | Reveal animation. |
|
|
2165
|
-
| `speed` | `speed` | `undefined \| number` | Characters/segments per tick. |
|
|
2166
|
-
| `as` | `as` | `undefined \| string` | Element tag to render as. |
|
|
2167
|
-
|
|
2168
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2169
|
-
|
|
2170
|
-
| Event | `detail` type | Description |
|
|
2171
|
-
|---|---|---|
|
|
2172
|
-
| `kai-complete` | `CustomEvent` | Streaming finished. |
|
|
2173
|
-
|
|
2174
|
-
---
|
|
2175
|
-
|
|
2176
|
-
### `kai-scope-picker` / `ScopePicker`
|
|
2177
|
-
|
|
2178
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2179
|
-
|
|
2180
|
-
| Property | Attribute | Type | Description |
|
|
2181
|
-
|---|---|---|---|
|
|
2182
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2183
|
-
| `availableAuthors` | — | `undefined \| string[]` | Authors to offer as scope filters. Omit to drop the Authors section (for a tag-only picker). Set as a JS property. |
|
|
2184
|
-
| `availableTags` | — | `undefined \| string[]` | Tags to offer as scope filters. Omit to drop the Tags section (for an author-only picker). Set as a JS property. |
|
|
2185
|
-
| `currentLabel` | `current-label` | `undefined \| string` | The label shown on the trigger for the active scope. |
|
|
2186
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe the dropdown's open state (Shoelace-style: settable + reflected to the `open` attribute, the dropdown still self-manages on click/keyboard). Set `el.open = true`, or `<kai-scope-picker open>`; listen for `kai-open-change`. |
|
|
2187
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
2188
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the trigger: click/keyboard and `show()` no longer open the dropdown. |
|
|
2189
|
-
|
|
2190
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2191
|
-
|
|
2192
|
-
| Event | `detail` type | Description |
|
|
2193
|
-
|---|---|---|
|
|
2194
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The scope dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). |
|
|
2195
|
-
| `kai-scope-change` | `CustomEvent<{ filters: { tags?: undefined \| string[]; authors?: undefined \| string[]; contentType?: undefined \| "transcript" \| "markdown"; dateRange?: undefined \| { from: string; to: string } } \| undefined }>` | A scope was chosen (`undefined` filters = "All Content"). |
|
|
2196
|
-
|
|
2197
|
-
**Methods** (call on the element instance: `document.querySelector('kai-scope-picker').show()`):
|
|
2198
|
-
|
|
2199
|
-
| Method | Signature | Description |
|
|
2200
|
-
|---|---|---|
|
|
2201
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
2202
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
2203
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
2204
|
-
|
|
2205
|
-
---
|
|
2206
|
-
|
|
2207
|
-
### `kai-screen` / `Screen`
|
|
2208
|
-
|
|
2209
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2210
|
-
|
|
2211
|
-
| Property | Attribute | Type | Description |
|
|
2212
|
-
|---|---|---|---|
|
|
2213
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2214
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages). Set `el.open = true`, or `<kai-screen open>`; listen for `kai-open-change`. |
|
|
2215
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
2216
|
-
| `headline` | `headline` | `undefined \| string` | Header title text. A projected `title` slot overrides it. (Named `headline` because `title` collides with the global `HTMLElement.title` attribute.) |
|
|
2217
|
-
| `back` | `back` | `undefined \| false \| true` | Show the back button (default true). |
|
|
2218
|
-
| `noInert` | `no-inert` | `undefined \| false \| true` | Opt out of marking sibling elements inert/aria-hidden while open (for unusual layouts). |
|
|
2219
|
-
|
|
2220
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2221
|
-
|
|
2222
|
-
| Event | `detail` type | Description |
|
|
2223
|
-
|---|---|---|
|
|
2224
|
-
| `kai-back` | `CustomEvent<Record<string, never>>` | Back navigation intent: the back button or Escape. The consumer flips their own routing in response (the screen knows nothing about the trigger). |
|
|
2225
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The screen opened or closed (a method, `Escape` close, or driven `open`). |
|
|
2226
|
-
|
|
2227
|
-
**Methods** (call on the element instance: `document.querySelector('kai-screen').show()`):
|
|
2228
|
-
|
|
2229
|
-
| Method | Signature | Description |
|
|
2230
|
-
|---|---|---|
|
|
2231
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
2232
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
2233
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
2234
|
-
| `focus` | `(options?: FocusOptions): void` | Move focus to the screen surface (no-op while closed). |
|
|
2235
|
-
|
|
2236
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2237
|
-
|
|
2238
|
-
| Slot | Mode | Description |
|
|
2239
|
-
|---|---|---|
|
|
2240
|
-
| _(default)_ | inject | The screen body, below the title bar. |
|
|
2241
|
-
| `title` | replace | Rich header title; overrides the `headline` prop. |
|
|
2242
|
-
| `actions` | inject | Header trailing cluster (e.g. an avatar or overflow menu). |
|
|
2243
|
-
|
|
2244
|
-
**Styleable parts** (restyle from outside via `kai-screen::part(name)`):
|
|
2245
|
-
|
|
2246
|
-
| Part | Description |
|
|
2247
|
-
|---|---|
|
|
2248
|
-
| `::part(header)` | The back-header bar (back button + title + actions). Restyle its height, padding, or border from outside. — `kai-screen::part(header) { height: 3.25rem; padding-inline: 1rem }` |
|
|
2249
|
-
| `::part(back)` | The back button. Restyle or hide it from outside; `back="false"` removes it entirely. — `kai-screen::part(back) { border-radius: 9999px }` |
|
|
2250
|
-
| `::part(body)` | The full-bleed surface that fills the mount point and scrolls its content. Tune padding or background from outside. — `kai-screen::part(body) { background: var(--color-card) }` |
|
|
2251
|
-
| `::part(title)` | Rich header title; overrides the `headline` prop. |
|
|
2252
|
-
|
|
2253
|
-
---
|
|
2254
|
-
|
|
2255
|
-
### `kai-scroll-area` / `ScrollArea`
|
|
2256
|
-
|
|
2257
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2258
|
-
|
|
2259
|
-
| Property | Attribute | Type | Description |
|
|
2260
|
-
|---|---|---|---|
|
|
2261
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2262
|
-
| `orientation` | `orientation` | `undefined \| "vertical" \| "horizontal" \| "both"` | Which axis scrolls. `vertical` (default) · `horizontal` · `both`. The cross axis is clamped so content can't overflow it. |
|
|
2263
|
-
|
|
2264
|
-
_No events._
|
|
2265
|
-
|
|
2266
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2267
|
-
|
|
2268
|
-
| Slot | Mode | Description |
|
|
2269
|
-
|---|---|---|
|
|
2270
|
-
| _(default)_ | inject | The scrollable content. |
|
|
2271
|
-
|
|
2272
|
-
**Styleable parts** (restyle from outside via `kai-scroll-area::part(name)`):
|
|
2273
|
-
|
|
2274
|
-
| Part | Description |
|
|
2275
|
-
|---|---|
|
|
2276
|
-
| `::part(viewport)` | The scrolling container. Add padding or a max-height from outside; the thin scrollbar follows `--color-scrollbar-thumb`. — `kai-scroll-area::part(viewport) { padding-right: 0.5rem }` |
|
|
2277
|
-
|
|
2278
|
-
---
|
|
2279
|
-
|
|
2280
|
-
### `kai-scroll-button` / `ScrollButton`
|
|
2281
|
-
|
|
2282
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2283
|
-
|
|
2284
|
-
| Property | Attribute | Type | Description |
|
|
2285
|
-
|---|---|---|---|
|
|
2286
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2287
|
-
| `for` | `for` | `undefined \| string` | CSS id of the scroll container to control. When omitted the element walks up the DOM (outside its own shadow root) to find the nearest scrollable ancestor. Mirrors the `for` convention of `<label for="...">`. |
|
|
2288
|
-
| `variant` | `variant` | `undefined \| "outline" \| "ghost" \| "default"` | Button visual variant: `'outline' \| 'ghost' \| 'default'`. Defaults to `'outline'`. |
|
|
2289
|
-
| `size` | `size` | `undefined \| "sm" \| "md" \| "lg" \| "icon" \| "icon-sm"` | Button size token. Defaults to `'icon'` (square). |
|
|
2290
|
-
|
|
2291
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2292
|
-
|
|
2293
|
-
| Event | `detail` type | Description |
|
|
2294
|
-
|---|---|---|
|
|
2295
|
-
| `kai-scroll` | `CustomEvent` | Emitted when the user clicks the button and `scrollToBottom()` is called. Carries no detail; consumers use it to know a manual scroll occurred. |
|
|
2296
|
-
|
|
2297
|
-
---
|
|
2298
|
-
|
|
2299
|
-
### `kai-search` / `Search`
|
|
2300
|
-
|
|
2301
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2302
|
-
|
|
2303
|
-
| Property | Attribute | Type | Description |
|
|
2304
|
-
|---|---|---|---|
|
|
2305
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2306
|
-
| `value` | `value` | `undefined \| string` | Controlled query. Settable and reflected to the `value` attribute. Read `el.value` for live state. |
|
|
2307
|
-
| `placeholder` | `placeholder` | `undefined \| string` | Placeholder. Defaults to `Search…`. |
|
|
2308
|
-
| `icon` | `icon` | `undefined \| string` | Leading icon-NAME string (a curated name, URL, or text), resolved to a glyph the same way `kai-button`'s `icon` is. Defaults to `search`. |
|
|
2309
|
-
| `debounce` | `debounce` | `undefined \| number` | Debounce window for `kai-search`, in ms. Defaults to `200`. |
|
|
2310
|
-
| `loading` | `loading` | `undefined \| false \| true` | Show a spinner in place of the leading icon while results load. |
|
|
2311
|
-
| `shortcut` | `shortcut` | `undefined \| string` | Optional shortcut hint shown (as a `kai-kbd`) while the field is empty, e.g. `Mod+K`. Display only; it does not bind the key. |
|
|
2312
|
-
|
|
2313
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2314
|
-
|
|
2315
|
-
| Event | `detail` type | Description |
|
|
2316
|
-
|---|---|---|
|
|
2317
|
-
| `kai-change` | `CustomEvent<{ value: string }>` | The field committed (blur). |
|
|
2318
|
-
| `kai-search` | `CustomEvent<{ value: string }>` | The query changed (debounced live, and on clear). |
|
|
2319
|
-
| `kai-submit` | `CustomEvent<{ value: string }>` | Enter was pressed. |
|
|
2320
|
-
|
|
2321
|
-
**Methods** (call on the element instance: `document.querySelector('kai-search').focus()`):
|
|
2322
|
-
|
|
2323
|
-
| Method | Signature | Description |
|
|
2324
|
-
|---|---|---|
|
|
2325
|
-
| `focus` | `(): void` | Focus the search input inside the shadow root. A native `focus()` on the host lands on the host itself and never reaches it. |
|
|
2326
|
-
| `clear` | `(): void` | Empty the field and fire `kai-search` with an empty value immediately, cancelling any debounced search still in flight, then return focus to the input. Same path as the trailing clear button. |
|
|
2327
|
-
|
|
2328
|
-
**Styleable parts** (restyle from outside via `kai-search::part(name)`):
|
|
2329
|
-
|
|
2330
|
-
| Part | Description |
|
|
2331
|
-
|---|---|
|
|
2332
|
-
| `::part(field)` | The bordered control box (the row wrapping the search icon, input, and clear button). — `kai-search::part(field) { border-radius: 9999px }` |
|
|
2333
|
-
| `::part(input)` | The inner search input element. — `kai-search::part(input) { font-size: 0.875rem }` |
|
|
2334
|
-
| `::part(clear)` | The trailing clear ("x") button, shown when the field is non-empty. — `kai-search::part(clear) { opacity: 1 }` |
|
|
2335
|
-
|
|
2336
|
-
---
|
|
2337
|
-
|
|
2338
|
-
### `kai-segmented` / `Segmented`
|
|
2339
|
-
|
|
2340
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2341
|
-
|
|
2342
|
-
| Property | Attribute | Type | Description |
|
|
2343
|
-
|---|---|---|---|
|
|
2344
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2345
|
-
| `options` | — | `{ value: string; label: string; icon?: undefined \| string }[]` | The selectable segments, left to right. Set as a JS property (array). |
|
|
2346
|
-
| `value` | `value` | `undefined \| string` | Controlled selected `value`. Settable and reflected to the `value` attribute. `el.value = 'preview'` drives it; choosing a segment updates it and fires `kai-change`. Read `el.value` for live state. |
|
|
2347
|
-
| `size` | `size` | `undefined \| "sm" \| "md"` | Control density: `sm` or `md`. Defaults to `md`. |
|
|
2348
|
-
|
|
2349
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2350
|
-
|
|
2351
|
-
| Event | `detail` type | Description |
|
|
2352
|
-
|---|---|---|
|
|
2353
|
-
| `kai-change` | `CustomEvent<{ value: string }>` | A segment was chosen. |
|
|
2354
|
-
|
|
2355
|
-
**Styleable parts** (restyle from outside via `kai-segmented::part(name)`):
|
|
2356
|
-
|
|
2357
|
-
| Part | Description |
|
|
2358
|
-
|---|---|
|
|
2359
|
-
| `::part(track)` | The segmented track (the pill container holding the segments). Restyle its background, radius, or padding. — `kai-segmented::part(track) { border-radius: 9999px }` |
|
|
2360
|
-
| `::part(segment)` | Each segment button. Restyle padding, font weight, or the selected look. — `kai-segmented::part(segment) { font-weight: 600 }` |
|
|
2361
|
-
|
|
2362
|
-
---
|
|
2363
|
-
|
|
2364
|
-
### `kai-separator` / `Separator`
|
|
2365
|
-
|
|
2366
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2367
|
-
|
|
2368
|
-
| Property | Attribute | Type | Description |
|
|
2369
|
-
|---|---|---|---|
|
|
2370
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2371
|
-
| `orientation` | `orientation` | `undefined \| "horizontal" \| "vertical"` | `horizontal` (default, block + full-width) or `vertical` (a rule inside a flex/grid row, stretching to the row height). |
|
|
2372
|
-
|
|
2373
|
-
_No events._
|
|
2374
|
-
|
|
2375
|
-
**Styleable parts** (restyle from outside via `kai-separator::part(name)`):
|
|
2376
|
-
|
|
2377
|
-
| Part | Description |
|
|
2378
|
-
|---|---|
|
|
2379
|
-
| `::part(separator)` | The divider line. Restyle its color, thickness, or inset from outside. — `kai-separator::part(separator) { background: var(--color-border) }` |
|
|
2380
|
-
|
|
2381
|
-
---
|
|
2382
|
-
|
|
2383
|
-
### `kai-setting-item` / `SettingItem`
|
|
2384
|
-
|
|
2385
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2386
|
-
|
|
2387
|
-
| Property | Attribute | Type | Description |
|
|
2388
|
-
|---|---|---|---|
|
|
2389
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2390
|
-
| `label` | `label` | `undefined \| string` | Row label (primary text). Attribute: `label`. |
|
|
2391
|
-
| `description` | `description` | `undefined \| string` | Optional secondary description under the label. Attribute: `description`. |
|
|
2392
|
-
|
|
2393
|
-
_No events._
|
|
2394
|
-
|
|
2395
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2396
|
-
|
|
2397
|
-
| Slot | Mode | Description |
|
|
2398
|
-
|---|---|---|
|
|
2399
|
-
| `control` | inject | The row control (a switch, segmented, select, etc.), right-aligned. Omit it for a label-only row. |
|
|
2400
|
-
|
|
2401
|
-
**Styleable parts** (restyle from outside via `kai-setting-item::part(name)`):
|
|
2402
|
-
|
|
2403
|
-
| Part | Description |
|
|
2404
|
-
|---|---|
|
|
2405
|
-
| `::part(label)` | The label + description block on the left of the row. Restyle its typography or spacing. — `kai-setting-item::part(label) { gap: 0.125rem }` |
|
|
2406
|
-
| `::part(control)` | The row control (a switch, segmented, select, etc.), right-aligned. Omit it for a label-only row. |
|
|
2407
|
-
|
|
2408
|
-
---
|
|
2409
|
-
|
|
2410
|
-
### `kai-settings-group` / `SettingsGroup`
|
|
2411
|
-
|
|
2412
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2413
|
-
|
|
2414
|
-
| Property | Attribute | Type | Description |
|
|
2415
|
-
|---|---|---|---|
|
|
2416
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2417
|
-
| `heading` | `heading` | `undefined \| string` | Small section heading shown above the card. Attribute: `heading`. |
|
|
2418
|
-
| `description` | `description` | `undefined \| string` | Optional muted description under the heading. Attribute: `description`. |
|
|
2419
|
-
|
|
2420
|
-
_No events._
|
|
2421
|
-
|
|
2422
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2423
|
-
|
|
2424
|
-
| Slot | Mode | Description |
|
|
2425
|
-
|---|---|---|
|
|
2426
|
-
| _(default)_ | inject | The `<kai-setting-item>` rows in this group. |
|
|
2427
|
-
|
|
2428
|
-
**Styleable parts** (restyle from outside via `kai-settings-group::part(name)`):
|
|
2429
|
-
|
|
2430
|
-
| Part | Description |
|
|
2431
|
-
|---|---|
|
|
2432
|
-
| `::part(header)` | The group heading + description block. Restyle its spacing or typography. — `kai-settings-group::part(header) { margin-bottom: 0.75rem }` |
|
|
2433
|
-
| `::part(body)` | The bordered card holding the setting rows. Restyle its surface, border, or radius. — `kai-settings-group::part(body) { border-radius: 1rem }` |
|
|
2434
|
-
|
|
2435
|
-
---
|
|
2436
|
-
|
|
2437
|
-
### `kai-skeleton` / `Skeleton`
|
|
2438
|
-
|
|
2439
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2440
|
-
|
|
2441
|
-
| Property | Attribute | Type | Description |
|
|
2442
|
-
|---|---|---|---|
|
|
2443
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2444
|
-
| `variant` | `variant` | `undefined \| "text" \| "rect" \| "circle"` | `text` (one or more lines), `rect` (a block), or `circle` (round). Defaults to `text`. |
|
|
2445
|
-
| `width` | `width` | `undefined \| string` | CSS width (e.g. `'12rem'`, `'60%'`). Defaults to full width (responsive); for `circle` it is the diameter. |
|
|
2446
|
-
| `height` | `height` | `undefined \| string` | CSS height. Defaults per variant (a text line height; circle = width). |
|
|
2447
|
-
| `lines` | `lines` | `undefined \| number` | `text` only: number of lines; the last is shorter. Defaults to 1. |
|
|
2448
|
-
|
|
2449
|
-
_No events._
|
|
2450
|
-
|
|
2451
|
-
**Styleable parts** (restyle from outside via `kai-skeleton::part(name)`):
|
|
2452
|
-
|
|
2453
|
-
| Part | Description |
|
|
2454
|
-
|---|---|
|
|
2455
|
-
| `::part(skeleton)` | The shimmer block(s). Recolor or change the opacity from outside; the default is a low-contrast foreground tint that reads in both light and dark. — `kai-skeleton::part(skeleton) { background: var(--color-primary); opacity: 0.15 }` |
|
|
2456
|
-
|
|
2457
|
-
---
|
|
2458
|
-
|
|
2459
|
-
### `kai-skills` / `Skills`
|
|
2460
|
-
|
|
2461
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2462
|
-
|
|
2463
|
-
| Property | Attribute | Type | Description |
|
|
2464
|
-
|---|---|---|---|
|
|
2465
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2466
|
-
| `skills` | — | `undefined \| { id: string; name: string }[]` | The active skills to badge. Set as a JS property. Omit to supply them as `<kai-skill>` light-DOM children instead; when both are present the property's skills come first. Nothing renders when there are none. |
|
|
2467
|
-
|
|
2468
|
-
_No events._
|
|
2469
|
-
|
|
2470
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
2471
|
-
|
|
2472
|
-
| Child element | Attributes | Text content | Notes |
|
|
2473
|
-
|---|---|---|---|
|
|
2474
|
-
| `<kai-skill>` | `id` | yes | Parse a single light-DOM `<kai-skill>` element into a `Skill` descriptor. Attribute / content mapping: - `id` → Skill.id (falls back to `name` when absent) - `textContent` → Skill.name (the human-readable badge label) Example: `<kai-skill id="web-search">Web Search</kai-skill>` |
|
|
2475
|
-
|
|
2476
|
-
---
|
|
2477
|
-
|
|
2478
|
-
### `kai-source` / `Source`
|
|
2479
|
-
|
|
2480
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2481
|
-
|
|
2482
|
-
| Property | Attribute | Type | Description |
|
|
2483
|
-
|---|---|---|---|
|
|
2484
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2485
|
-
| `href` | `href` | `undefined \| string` | The URL this citation links to (the domain also seeds the default label/favicon). |
|
|
2486
|
-
| `label` | `label` | `undefined \| string` | Trigger label (defaults to the domain). |
|
|
2487
|
-
| `headline` | `headline` | `undefined \| string` | Hover-card headline. Attribute: `headline` (`title` is avoided because it is a global HTML attribute that reflects in a CE constructor and breaks it). |
|
|
2488
|
-
| `description` | `description` | `undefined \| string` | Hover-card body text describing the source. |
|
|
2489
|
-
| `showFavicon` | `show-favicon` | `undefined \| false \| true` | Show the source's favicon next to the trigger label. |
|
|
2490
|
-
|
|
2491
|
-
_No events._
|
|
2492
|
-
|
|
2493
|
-
---
|
|
2494
|
-
|
|
2495
|
-
### `kai-sources` / `Sources`
|
|
2496
|
-
|
|
2497
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2498
|
-
|
|
2499
|
-
| Property | Attribute | Type | Description |
|
|
2500
|
-
|---|---|---|---|
|
|
2501
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2502
|
-
| `sources` | — | `undefined \| { href: string; title?: undefined \| string; description?: undefined \| string; label?: undefined \| string; showFavicon?: undefined \| false \| true }[]` | The sources to render. Set as a JS property. Omit to supply them as `<kai-source>` light-DOM children instead; when both are present the property's sources come first. |
|
|
2503
|
-
| `showFavicon` | `show-favicon` | `undefined \| false \| true` | Show favicons on all items (per-item `showFavicon` overrides). |
|
|
2504
|
-
| `numbered` | `numbered` | `undefined \| false \| true` | When true, each citation chip is labelled with its 1-based index in the merged (prop + declarative-children) list (`[1]`, `[2]`, …) instead of the per-item `label` or domain fallback. HTML attribute: `numbered` (boolean: a bare attribute or `numbered="true"`). JS property: `el.numbered = true`. |
|
|
2505
|
-
|
|
2506
|
-
_No events._
|
|
2507
|
-
|
|
2508
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
2509
|
-
|
|
2510
|
-
| Child element | Attributes | Text content | Notes |
|
|
2511
|
-
|---|---|---|---|
|
|
2512
|
-
| `<kai-source>` | `description`, `headline`, `href`, `label`, `show-favicon` | — | Parse a single light-DOM `<kai-source>` element into a `KaiSourceItem` descriptor. Attribute mapping: - `href` → KaiSourceItem.href - `label` → KaiSourceItem.label - `headline` → KaiSourceItem.title (matches kai-source's prop name; "title" is a reserved HTMLElement attribute so kai-source uses "headline") - `description` → KaiSourceItem.description - `show-favicon`→ KaiSourceItem.showFavicon (bare boolean attribute) |
|
|
2513
|
-
|
|
2514
|
-
---
|
|
2515
|
-
|
|
2516
|
-
### `kai-status` / `Status`
|
|
2517
|
-
|
|
2518
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2519
|
-
|
|
2520
|
-
| Property | Attribute | Type | Description |
|
|
2521
|
-
|---|---|---|---|
|
|
2522
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2523
|
-
| `status` | `status` | `undefined \| "new" \| "online" \| "busy" \| "away" \| "offline"` | Presence/notification state → color. `new` (default) maps to the blue hue. |
|
|
2524
|
-
| `pulse` | `pulse` | `undefined \| false \| true` | Animated ping ring (off by default; respects prefers-reduced-motion). |
|
|
2525
|
-
| `label` | `label` | `undefined \| string` | Accessible name. Without it the dot is decorative. |
|
|
2526
|
-
| `size` | `size` | `undefined \| "sm" \| "md"` | `sm` (default) or `md`. |
|
|
2527
|
-
|
|
2528
|
-
_No events._
|
|
2529
|
-
|
|
2530
|
-
**Styleable parts** (restyle from outside via `kai-status::part(name)`):
|
|
2531
|
-
|
|
2532
|
-
| Part | Description |
|
|
2533
|
-
|---|---|
|
|
2534
|
-
| `::part(dot)` | The status dot. Recolor or resize it from outside; the `status` prop sets the default hue. — `kai-status::part(dot) { background: var(--color-tool-green) }` |
|
|
2535
|
-
|
|
2536
|
-
---
|
|
2537
|
-
|
|
2538
|
-
### `kai-suggestions` / `Suggestions`
|
|
2539
|
-
|
|
2540
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2541
|
-
|
|
2542
|
-
| Property | Attribute | Type | Description |
|
|
2543
|
-
|---|---|---|---|
|
|
2544
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2545
|
-
| `suggestions` | — | `undefined \| (string \| { label: string; value?: undefined \| string; icon?: undefined \| string })[]` | The suggestions. Strings, or `{ label, value }` when the displayed text and the emitted value differ. Set as a JS property. Omit to supply them as `<kai-suggestion>` light-DOM children instead; when both are present the property's suggestions come first. |
|
|
2546
|
-
| `variant` | `variant` | `undefined \| "outline" \| "ghost" \| "default"` | Chip style: `'outline'` (default), `'ghost'`, or `'default'` (filled). |
|
|
2547
|
-
| `size` | `size` | `undefined \| "md" \| "lg"` | Row height for `layout="list"`: `'md'` (default) or `'lg'` for taller rows. Chips are unaffected. |
|
|
2548
|
-
| `layout` | `layout` | `undefined \| "chips" \| "list"` | Layout: `'chips'` (default) renders a wrapping row of rounded pills; `'list'` renders a vertical, full-width "Ideas for you" list where each row is left-aligned with a leading `icon`, a label, and a hover background. |
|
|
2549
|
-
| `block` | `block` | `undefined \| false \| true` | Full-width left-aligned rows instead of pills. |
|
|
2550
|
-
| `highlight` | `highlight` | `undefined \| string` | Substring to highlight within each suggestion. |
|
|
2551
|
-
|
|
2552
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2553
|
-
|
|
2554
|
-
| Event | `detail` type | Description |
|
|
2555
|
-
|---|---|---|
|
|
2556
|
-
| `kai-select` | `CustomEvent<{ value: string }>` | A suggestion was clicked. |
|
|
2557
|
-
|
|
2558
|
-
**Declarative children** (compose these in light DOM instead of setting the JS property):
|
|
2559
|
-
|
|
2560
|
-
| Child element | Attributes | Text content | Notes |
|
|
2561
|
-
|---|---|---|---|
|
|
2562
|
-
| `<kai-suggestion>` | `icon`, `value` | yes | Parse a single `<kai-suggestion>` node into an `Item` descriptor. |
|
|
2563
|
-
|
|
2564
|
-
---
|
|
2565
|
-
|
|
2566
|
-
### `kai-switch` / `Switch`
|
|
2567
|
-
|
|
2568
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2569
|
-
|
|
2570
|
-
| Property | Attribute | Type | Description |
|
|
2571
|
-
|---|---|---|---|
|
|
2572
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2573
|
-
| `checked` | `checked` | `undefined \| false \| true` | Controlled checked state. Settable and reflected to the `checked` attribute. `el.checked = true` (or `<kai-switch checked>`) drives it; the toggle UI updates it and fires `kai-change`. Read `el.checked` for live state. |
|
|
2574
|
-
| `defaultChecked` | `default-checked` | `undefined \| false \| true` | Initial checked state on mount (uncontrolled seed). Bare attribute (`<kai-switch default-checked>`) turns it on. |
|
|
2575
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable interaction. |
|
|
2576
|
-
| `label` | `label` | `undefined \| string` | Accessible label. |
|
|
2577
|
-
| `name` | `name` | `undefined \| string` | Form-control name (paired with `value`). |
|
|
2578
|
-
| `value` | `value` | `undefined \| string` | Submitted value when checked (paired with `name`). Defaults to `'on'`. |
|
|
2579
|
-
|
|
2580
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2581
|
-
|
|
2582
|
-
| Event | `detail` type | Description |
|
|
2583
|
-
|---|---|---|
|
|
2584
|
-
| `kai-change` | `CustomEvent<{ checked: false \| true }>` | The toggle changed. |
|
|
2585
|
-
|
|
2586
|
-
**Methods** (call on the element instance: `document.querySelector('kai-switch').toggle()`):
|
|
2587
|
-
|
|
2588
|
-
| Method | Signature | Description |
|
|
2589
|
-
|---|---|---|
|
|
2590
|
-
| `toggle` | `(): void` | Flip the switch and fire `kai-change` (no-op while disabled). |
|
|
2591
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the inner `role="switch"` button (the host element can't reach it). |
|
|
2592
|
-
|
|
2593
|
-
---
|
|
2594
|
-
|
|
2595
|
-
### `kai-tabs` / `Tabs`
|
|
2596
|
-
|
|
2597
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2598
|
-
|
|
2599
|
-
| Property | Attribute | Type | Description |
|
|
2600
|
-
|---|---|---|---|
|
|
2601
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2602
|
-
| `items` | — | `undefined \| { id: string; label?: undefined \| string; icon?: undefined \| string; disabled?: undefined \| false \| true }[]` | Tabs to render. Set as a JS property, not an HTML attribute. |
|
|
2603
|
-
| `value` | `value` | `undefined \| string` | Controlled selected id. Set as a JS property (or the `value` attribute); drive it from your app in response to `kai-tab-change`. Omit for uncontrolled. |
|
|
2604
|
-
| `defaultValue` | `default-value` | `undefined \| string` | Initial selected id when uncontrolled (use the `default-value` attribute in plain HTML). |
|
|
2605
|
-
| `variant` | `variant` | `undefined \| "segmented" \| "underline"` | `segmented` (default, a pill group) or `underline` (an underlined row). |
|
|
2606
|
-
| `block` | `block` | `undefined \| false \| true` | Stretch the strip to full width, each tab sharing the space equally. |
|
|
2607
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the whole strip. |
|
|
2608
|
-
|
|
2609
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2610
|
-
|
|
2611
|
-
| Event | `detail` type | Description |
|
|
2612
|
-
|---|---|---|
|
|
2613
|
-
| `kai-tab-change` | `CustomEvent<{ value: string }>` | A tab was selected (click, Enter/Space, or arrow-key move). `value` is the item's id. |
|
|
2614
|
-
|
|
2615
|
-
**Methods** (call on the element instance: `document.querySelector('kai-tabs').select(…)`):
|
|
2616
|
-
|
|
2617
|
-
| Method | Signature | Description |
|
|
2618
|
-
|---|---|---|
|
|
2619
|
-
| `select` | `(id: string): void` | Select a tab by id (fires `kai-tab-change`). Ignores unknown/disabled ids. |
|
|
2620
|
-
| `focus` | `(): void` | Focus the active tab (or the first focusable tab). |
|
|
2621
|
-
|
|
2622
|
-
**Styleable parts** (restyle from outside via `kai-tabs::part(name)`):
|
|
2623
|
-
|
|
2624
|
-
| Part | Description |
|
|
2625
|
-
|---|---|
|
|
2626
|
-
| `::part(tablist)` | The tab strip container (role="tablist"). Restyle its gap, padding, background, or radius from outside; the `variant` prop sets the segmented/underline defaults. — `kai-tabs::part(tablist) { gap: 0.5rem; background: var(--color-card) }` |
|
|
2627
|
-
| `::part(tab)` | A single tab button. Restyle from outside; the active tab carries a `[data-active]` attribute, so target `::part(tab)[data-active]` for the selected look. — `kai-tabs::part(tab)[data-active] { color: var(--color-primary); font-weight: 600 }` |
|
|
2628
|
-
|
|
2629
|
-
---
|
|
2630
|
-
|
|
2631
|
-
### `kai-tasks` / `Tasks`
|
|
2632
|
-
|
|
2633
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2634
|
-
|
|
2635
|
-
| Property | Attribute | Type | Description |
|
|
2636
|
-
|---|---|---|---|
|
|
2637
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2638
|
-
| `data` | — | `undefined \| { mode?: undefined \| "select" \| "progress"; heading?: undefined \| string; tasks: { id: string; label: string; description?: undefined \| string; checked?: undefined \| false \| true; disabled?: undefined \| false \| true }[]; selectAll?: undefined \| false \| true; confirmLabel?: undefined \| string; allowEmpty?: undefined \| false \| true; min?: undefined \| number; max?: undefined \| number; dismissible?: undefined \| false \| true }` | The tasks definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { tasks:[…], selectAll, confirmLabel, … }`. Import `TasksCardData` from `@kitn.ai/ui` for the full shape. |
|
|
2639
|
-
| `cardId` | `card-id` | `undefined \| string` | Stable card id correlating every emitted CardEvent. Attribute: `card-id`. |
|
|
2640
|
-
| `heading` | `heading` | `undefined \| string` | Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. |
|
|
2641
|
-
| `resolution` | — | `undefined \| Record<string, unknown>` | Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'submit', data:{ selected:[…] } }`. |
|
|
2642
|
-
| `value` | — | `undefined \| string[]` | Controlled selection (task ids; JS property). When set, it wins over local state. |
|
|
2643
|
-
| `defaultValue` | — | `undefined \| string[]` | Uncontrolled initial selection (task ids; JS property), overlaying per-task `checked`. |
|
|
2644
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Freeze the whole list + Confirm. Attribute: `disabled`. |
|
|
2645
|
-
| `readonly` | `readonly` | `undefined \| false \| true` | Display-only: rows can't be toggled and show the default cursor (no pointer, hover, or focus affordances). Keeps the look as-is. Attribute: `readonly`. |
|
|
2646
|
-
|
|
2647
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2648
|
-
|
|
2649
|
-
| Event | `detail` type | Description |
|
|
2650
|
-
|---|---|---|
|
|
2651
|
-
| `kai-value-change` | `CustomEvent<{ value: string[] }>` | The selection changed on a toggle. Carries the selected ids in input order. |
|
|
2652
|
-
|
|
2653
|
-
**Methods** (call on the element instance: `document.querySelector('kai-tasks').select(…)`):
|
|
2654
|
-
|
|
2655
|
-
| Method | Signature | Description |
|
|
2656
|
-
|---|---|---|
|
|
2657
|
-
| `select` | `(taskIds?: string[]): void` | Set the checked task ids (local-only, no emit), respecting disabled/max. With no arg, select all toggleable rows. |
|
|
2658
|
-
| `toggle` | `(taskId: string, checked?: boolean): void` | Toggle one task by id, honoring the max gate (no `checked` = flip). |
|
|
2659
|
-
| `send` | `(): void` | Confirm the current selection: emits the `submit` CardEvent + resolves (only when the min/max gate passes). Named `send`, not `submit`. |
|
|
2660
|
-
| `focus` | `(options?: FocusOptions): void` | Focus the task group (select-all checkbox if shown, else the first row). |
|
|
2661
|
-
| `dismiss` | `(): void` | Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). |
|
|
2662
|
-
| `reopen` | `(): void` | Re-open a dismissed card from its stub (emit `reopen`). |
|
|
2663
|
-
|
|
2664
|
-
---
|
|
2665
|
-
|
|
2666
|
-
### `kai-text-shimmer` / `TextShimmer`
|
|
2667
|
-
|
|
2668
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2669
|
-
|
|
2670
|
-
| Property | Attribute | Type | Description |
|
|
2671
|
-
|---|---|---|---|
|
|
2672
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2673
|
-
| `text` | `text` | `undefined \| string` | The text to shimmer. |
|
|
2674
|
-
| `as` | `as` | `undefined \| string` | Element tag to render as (default `span`). |
|
|
2675
|
-
| `duration` | `duration` | `undefined \| number` | Animation duration in seconds. |
|
|
2676
|
-
| `spread` | `spread` | `undefined \| number` | Gradient spread (5–45). |
|
|
2677
|
-
|
|
2678
|
-
_No events._
|
|
2679
|
-
|
|
2680
|
-
---
|
|
2681
|
-
|
|
2682
|
-
### `kai-thinking-bar` / `ThinkingBar`
|
|
2683
|
-
|
|
2684
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2685
|
-
|
|
2686
|
-
| Property | Attribute | Type | Description |
|
|
2687
|
-
|---|---|---|---|
|
|
2688
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2689
|
-
| `text` | `text` | `undefined \| string` | The shimmering label, e.g. "Thinking…". |
|
|
2690
|
-
| `stoppable` | `stoppable` | `undefined \| false \| true` | When true, show a "stop" affordance that fires a `stop` event. |
|
|
2691
|
-
| `stopLabel` | `stop-label` | `undefined \| string` | Label for the stop affordance. |
|
|
2692
|
-
|
|
2693
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2694
|
-
|
|
2695
|
-
| Event | `detail` type | Description |
|
|
2696
|
-
|---|---|---|
|
|
2697
|
-
| `kai-stop` | `CustomEvent` | The "stop / answer now" affordance was clicked. |
|
|
2698
|
-
|
|
2699
|
-
---
|
|
2700
|
-
|
|
2701
|
-
### `kai-thread` / `Thread`
|
|
2702
|
-
|
|
2703
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2704
|
-
|
|
2705
|
-
| Property | Attribute | Type | Description |
|
|
2706
|
-
|---|---|---|---|
|
|
2707
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2708
|
-
| `messages` | — | `undefined \| { id: string; role: "user" \| "assistant"; parts: ({ type: "text"; text: string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "reasoning"; text: string; label?: undefined \| string; index?: undefined \| number; streamId?: undefined \| string; signature?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } } \| { type: "tool"; tool: { type: string; kind?: undefined \| "command" \| "file-change" \| "search" \| "fetch" \| "mcp" \| "image" \| "generic"; state: "input-streaming" \| "input-available" \| "output-available" \| "output-error"; input?: undefined \| Record<string, unknown>; rawInput?: undefined \| string; output?: undefined \| Record<string, unknown>; toolCallId?: undefined \| string; errorText?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "card"; envelope: { type: string; id: string; data: unknown; title?: undefined \| string; resolution?: undefined \| { kind: "action"; action: string; payload?: unknown; at?: undefined \| string } \| { kind: "submit"; data: unknown; at?: undefined \| string } \| { kind: "dismissed"; at?: undefined \| string } \| { kind: "expired"; reason?: undefined \| string; at?: undefined \| string } }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "source"; source: { id?: undefined \| string; url?: undefined \| string; title?: undefined \| string; snippet?: undefined \| string; index?: undefined \| number }; raw?: undefined \| { source: string; payload: unknown } } \| { type: "file"; attachment: { id: string; type: "file" \| "source-document"; filename?: undefined \| string; mediaType?: undefined \| string; url?: undefined \| string; title?: undefined \| string }; raw?: undefined \| { source: string; payload: unknown } })[]; actions?: undefined \| ("copy" \| "like" \| "dislike" \| "regenerate" \| "edit" \| { id: string; label: string; icon?: undefined \| string; tooltip?: undefined \| string })[]; avatar?: undefined \| { src?: undefined \| string; fallback?: undefined \| string; alt?: undefined \| string }; feedback?: undefined \| "like" \| "dislike" }[]` | The full message thread to render, newest last. Each entry carries its role, ordered `parts`, and optional actions/avatar/feedback. Set as a JS property (`el.messages = [...]`); a NEW array reference per streaming chunk re-renders (mutating in place does not). |
|
|
2709
|
-
| `loading` | `loading` | `undefined \| false \| true` | Show a typing indicator on the pending assistant turn. Set it while awaiting the assistant's reply. |
|
|
2710
|
-
| `proseSize` | `prose-size` | `undefined \| "xs" \| "sm" \| "base" \| "lg"` | Body/prose font scale for rendered markdown (`'xs' \| 'sm' \| 'base' \| 'lg'`). Defaults to `'sm'`. |
|
|
2711
|
-
| `codeTheme` | `code-theme` | `undefined \| string` | Shiki theme name for syntax-highlighted code blocks (e.g. `'github-dark-dimmed'`). |
|
|
2712
|
-
| `codeHighlight` | `code-highlight` | `undefined \| false \| true` | Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. |
|
|
2713
|
-
| `actionsReveal` | `actions-reveal` | `undefined \| "always" \| "hover"` | Whether each message's action bar is always visible (`'always'`, default) or only revealed on hover of that message row (`'hover'`). |
|
|
2714
|
-
| `scrollButton` | `scroll-button` | `undefined \| false \| true` | Show the scroll-to-bottom button inside the scroll area. Default true. |
|
|
2715
|
-
| `class` | `class` | `undefined \| string` | Extra classes applied to the thread's inner root. |
|
|
2716
|
-
| `cardTypes` | — | `undefined \| Record<string, string>` | Optional card type -> custom-element tag overrides/additions for `card` parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type. |
|
|
2717
|
-
| `cardSchemas` | — | `undefined \| Record<string, object>` | JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `cardTypes`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. |
|
|
2718
|
-
|
|
2719
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2720
|
-
|
|
2721
|
-
| Event | `detail` type | Description |
|
|
2722
|
-
|---|---|---|
|
|
2723
|
-
| `kai-message-action` | `CustomEvent<{ messageId: string; action: string; state?: undefined \| "on" \| "off" }>` | A message's action button was clicked. `action` is the built-in name (`copy` / `like` / `dislike` / `regenerate` / `edit`) or a custom id. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. |
|
|
2724
|
-
|
|
2725
|
-
**Methods** (call on the element instance: `document.querySelector('kai-thread').scrollToBottom(…)`):
|
|
2726
|
-
|
|
2727
|
-
| Method | Signature | Description |
|
|
2728
|
-
|---|---|---|
|
|
2729
|
-
| `scrollToBottom` | `(behavior?: ScrollBehavior): void` | Scroll the message list to the bottom (default `'smooth'`). |
|
|
2730
|
-
|
|
2731
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2732
|
-
|
|
2733
|
-
| Slot | Mode | Description |
|
|
2734
|
-
|---|---|---|
|
|
2735
|
-
| `empty` | replace | Custom zero-state rendered in the message area while the thread is empty; replaces the built-in default. |
|
|
2736
|
-
|
|
2737
|
-
---
|
|
2738
|
-
|
|
2739
|
-
### `kai-toast-region` / `ToastRegion`
|
|
2740
|
-
|
|
2741
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2742
|
-
|
|
2743
|
-
| Property | Attribute | Type | Description |
|
|
2744
|
-
|---|---|---|---|
|
|
2745
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2746
|
-
| `toasts` | — | `undefined \| { id: string; message: string; variant?: undefined \| "neutral" \| "success" \| "warning" \| "error" \| "info"; appearance?: undefined \| "pill" \| "card"; inverse?: undefined \| false \| true; description?: undefined \| string; action?: undefined \| { label: string; onAction: () => void \| false }; duration?: undefined \| number; dismissible?: undefined \| false \| true; target?: undefined \| HTMLElement }[]` | The toasts to render. Newest is shown on top. Set as a JS property (array); pass a new array reference to update. Omit for an empty region, which is the normal resting state and how the imperative `toast()` API starts. |
|
|
2747
|
-
| `position` | `position` | `undefined \| "top-center" \| "top-right" \| "top-left" \| "bottom-center" \| "bottom-right" \| "bottom-left"` | Stack anchor: `'top-center'` (default), `'top-right'`, `'bottom-center'`, … |
|
|
2748
|
-
| `max` | `max` | `undefined \| number` | Max simultaneously-visible toasts; the rest queue. Defaults to `3`. |
|
|
2749
|
-
| `stack` | `stack` | `undefined \| "expanded" \| "collapsed"` | Stacking: 'expanded' (default, full column) \| 'collapsed' (Sonner-style pile that expands on hover/focus). Attribute: stack. |
|
|
2750
|
-
| `appearance` | `appearance` | `undefined \| "pill" \| "card"` | Default appearance for this region's toasts: `'pill'` (default, compact) \| `'card'` (richer, with a description line). A per-toast `appearance` wins. Attribute: `appearance`. |
|
|
2751
|
-
| `inverse` | `inverse` | `undefined \| false \| true` | Default high-contrast inverse treatment for this region's toasts. A per-toast `inverse` wins. Off by default. Attribute: `inverse`. |
|
|
2752
|
-
| `target` | — | `undefined \| HTMLElement` | Container element to anchor this region to (JS property). Set by the store for a scoped region; unset = the global viewport region. |
|
|
2753
|
-
|
|
2754
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2755
|
-
|
|
2756
|
-
| Event | `detail` type | Description |
|
|
2757
|
-
|---|---|---|
|
|
2758
|
-
| `kai-action` | `CustomEvent<{ id: string; label: string }>` | A toast's action button was pressed. |
|
|
2759
|
-
| `kai-dismiss` | `CustomEvent<{ id: string; reason: "timeout" \| "close" \| "action" }>` | A toast left the stack. `reason` is `'timeout' \| 'close' \| 'action'`. |
|
|
2760
|
-
|
|
2761
|
-
---
|
|
2762
|
-
|
|
2763
|
-
### `kai-tool` / `Tool`
|
|
2764
|
-
|
|
2765
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2766
|
-
|
|
2767
|
-
| Property | Attribute | Type | Description |
|
|
2768
|
-
|---|---|---|---|
|
|
2769
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2770
|
-
| `tool` | — | `undefined \| { type: string; kind?: undefined \| "command" \| "file-change" \| "search" \| "fetch" \| "mcp" \| "image" \| "generic"; state: "input-streaming" \| "input-available" \| "output-available" \| "output-error"; input?: undefined \| Record<string, unknown>; rawInput?: undefined \| string; output?: undefined \| Record<string, unknown>; toolCallId?: undefined \| string; errorText?: undefined \| string; raw?: undefined \| { source: string; payload: unknown } }` | The tool-call to display. Set as a JS property. |
|
|
2771
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on trigger click). Set `el.open = true`, or `<kai-tool open>`; listen for `kai-open-change`. |
|
|
2772
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
2773
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Gate the disclosure trigger: programmatic `show()/hide()/toggle()` still work, but the trigger click no longer toggles. |
|
|
2774
|
-
|
|
2775
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2776
|
-
|
|
2777
|
-
| Event | `detail` type | Description |
|
|
2778
|
-
|---|---|---|
|
|
2779
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The panel expanded or collapsed (by trigger click or a method). |
|
|
2780
|
-
|
|
2781
|
-
**Methods** (call on the element instance: `document.querySelector('kai-tool').show()`):
|
|
2782
|
-
|
|
2783
|
-
| Method | Signature | Description |
|
|
2784
|
-
|---|---|---|
|
|
2785
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
2786
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
2787
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
2788
|
-
|
|
2789
|
-
---
|
|
2790
|
-
|
|
2791
|
-
### `kai-tooltip` / `Tooltip`
|
|
2792
|
-
|
|
2793
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2794
|
-
|
|
2795
|
-
| Property | Attribute | Type | Description |
|
|
2796
|
-
|---|---|---|---|
|
|
2797
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2798
|
-
| `content` | `content` | `undefined \| string` | The hint text shown on hover/focus of the slotted trigger. |
|
|
2799
|
-
| `openDelay` | `open-delay` | `undefined \| number` | Delay (ms) before the tooltip appears on hover. Defaults to 600. Focus shows it immediately regardless. |
|
|
2800
|
-
| `closeDelay` | `close-delay` | `undefined \| number` | Delay (ms) before it hides after the pointer leaves. Defaults to 0 (hides immediately). |
|
|
2801
|
-
| `placement` | `placement` | `undefined \| string` | Preferred placement: `'top' \| 'bottom' \| 'left' \| 'right'` (+ optional `-start`/`-end`). Defaults to `'top'`; flips to stay in view. |
|
|
2802
|
-
| `open` | `open` | `undefined \| false \| true` | Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the element still self-manages on hover/focus). Set `el.open = true`, or `<kai-tooltip open>`; listen for `kai-open-change`. |
|
|
2803
|
-
| `defaultOpen` | `default-open` | `undefined \| false \| true` | Initial open state on mount (uncontrolled seed). |
|
|
2804
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Turn the tooltip off while keeping the trigger mounted (hover/focus and `show()` no longer open it). |
|
|
2805
|
-
|
|
2806
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2807
|
-
|
|
2808
|
-
| Event | `detail` type | Description |
|
|
2809
|
-
|---|---|---|
|
|
2810
|
-
| `kai-open-change` | `CustomEvent<{ open: false \| true }>` | The tooltip opened or closed (by hover/focus, outside-click, or a method). |
|
|
2811
|
-
|
|
2812
|
-
**Methods** (call on the element instance: `document.querySelector('kai-tooltip').show()`):
|
|
2813
|
-
|
|
2814
|
-
| Method | Signature | Description |
|
|
2815
|
-
|---|---|---|
|
|
2816
|
-
| `show` | `(): void` | Open it programmatically (no-op while disabled). |
|
|
2817
|
-
| `hide` | `(): void` | Close it programmatically. |
|
|
2818
|
-
| `toggle` | `(): void` | Flip the open state (closes while disabled). |
|
|
2819
|
-
|
|
2820
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2821
|
-
|
|
2822
|
-
| Slot | Mode | Description |
|
|
2823
|
-
|---|---|---|
|
|
2824
|
-
| _(default)_ | inject | The TRIGGER the tooltip describes. The tip text is the `text` prop. |
|
|
2825
|
-
|
|
2826
|
-
---
|
|
2827
|
-
|
|
2828
|
-
### `kai-voice-input` / `VoiceInput`
|
|
2829
|
-
|
|
2830
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2831
|
-
|
|
2832
|
-
| Property | Attribute | Type | Description |
|
|
2833
|
-
|---|---|---|---|
|
|
2834
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2835
|
-
| `transcribe` | — | `undefined \| (audio: Blob) => Promise<string>` | Transcriber the host supplies: records audio, returns the text. This is a **function-valued property** (`el.transcribe = async blob => '...'`) because a value-returning callback can't be modelled as a fire-and-forget event. |
|
|
2836
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the mic button (non-interactive). |
|
|
2837
|
-
| `recognitionLang` | `recognition-lang` | `undefined \| string` | BCP-47 language tag for the native `SpeechRecognition` path (e.g. `en-US`). Attribute: `recognition-lang` (the plain `lang` attribute is reserved by `HTMLElement` and can't be a custom-element property). No effect when `transcribe` is set or the browser lacks SpeechRecognition. |
|
|
2838
|
-
| `interim` | `interim` | `undefined \| false \| true` | Emit live partial transcripts (`kai-transcript-interim`) during native recognition. Attribute: `interim`. No-op on the transcribe/fallback paths. |
|
|
2839
|
-
|
|
2840
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2841
|
-
|
|
2842
|
-
| Event | `detail` type | Description |
|
|
2843
|
-
|---|---|---|
|
|
2844
|
-
| `kai-audio-captured` | `CustomEvent<{ blob: Blob }>` | Raw audio captured (before transcription), for hosts that prefer to handle transcription themselves instead of via the `transcribe` property. Also the unsupported-fallback signal: no `transcribe`, no SpeechRecognition, so only the blob is produced (no text). |
|
|
2845
|
-
| `kai-recording-change` | `CustomEvent<{ recording: false \| true }>` | Recording started or stopped. Lets the host drive its own UI (waveform, push-to-talk indicator) in sync with the mic. Fires on real transitions only (manual click and programmatic start()/stop()), never on mount. |
|
|
2846
|
-
| `kai-transcript-interim` | `CustomEvent<{ text: string }>` | Live partial transcript during native recognition (only when `interim` is set). Fires repeatedly before the final `kai-transcription`. |
|
|
2847
|
-
| `kai-transcription` | `CustomEvent<{ text: string }>` | Final transcript: the `transcribe` property resolved, OR native `SpeechRecognition` produced final text (no `transcribe` set). |
|
|
2848
|
-
| `kai-voice-error` | `CustomEvent<{ source: "recognition"; error: string; message: string }>` | A voice session failed, so no failure is ever silent. `detail.source` names the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on `<kai-voice-output>`), `detail.error` carries the platform error code, the thrown exception's name, or `no-result` when recognition ended with no error and no text (the user said nothing), and `detail.message` is human-readable. Deliberate cancellation does not fire. |
|
|
2849
|
-
|
|
2850
|
-
**Methods** (call on the element instance: `document.querySelector('kai-voice-input').start()`):
|
|
2851
|
-
|
|
2852
|
-
| Method | Signature | Description |
|
|
2853
|
-
|---|---|---|
|
|
2854
|
-
| `start` | `(): void` | Begin recording programmatically (e.g. push-to-talk bound to a global key). Runs the same getUserMedia path as clicking the mic; no-ops if already recording. |
|
|
2855
|
-
| `stop` | `(): void` | Stop the in-progress recording, producing the blob (→ kai-audio-captured) and running transcription. Pairs with start() for push-to-talk. |
|
|
2856
|
-
|
|
2857
|
-
---
|
|
2858
|
-
|
|
2859
|
-
### `kai-voice-output` / `VoiceOutput`
|
|
2860
|
-
|
|
2861
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2862
|
-
|
|
2863
|
-
| Property | Attribute | Type | Description |
|
|
2864
|
-
|---|---|---|---|
|
|
2865
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2866
|
-
| `text` | `text` | `undefined \| string` | The utterance to read aloud. |
|
|
2867
|
-
| `autoplay` | `autoplay` | `undefined \| false \| true` | Speak automatically when `text` is set/changed. |
|
|
2868
|
-
| `synthesize` | — | `undefined \| (text: string) => Promise<Blob>` | TTS model seam the host supplies: given text, returns an audio `Blob` to play. This is a **function-valued property** (`el.synthesize = async text => blob`); when set, the native `speechSynthesis` path is bypassed. Mirrors `<kai-voice-input>`'s `transcribe`. A value-returning callback can't be modelled as a fire-and-forget event, hence a property. |
|
|
2869
|
-
| `disabled` | `disabled` | `undefined \| false \| true` | Disable the button (non-interactive). |
|
|
2870
|
-
|
|
2871
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2872
|
-
|
|
2873
|
-
| Event | `detail` type | Description |
|
|
2874
|
-
|---|---|---|
|
|
2875
|
-
| `kai-speaking-change` | `CustomEvent<{ speaking: false \| true }>` | Playback started or stopped. Drive your own UI in sync. `speaking: true` fires when audio actually starts (utterance.onstart natively; audio playback beginning on the `synthesize` path), not when speak() is called; earlier releases fired it optimistically inside speak() itself. Fires on real transitions only (manual click and programmatic speak()/stop()), never on mount. |
|
|
2876
|
-
| `kai-synthesized` | `CustomEvent<{ blob: Blob }>` | The model path (`synthesize`) resolved audio: the raw `Blob` before playback. |
|
|
2877
|
-
| `kai-voice-error` | `CustomEvent<{ source: "synthesis"; error: string; message: string }>` | A voice session failed, so no failure is ever silent. `detail.source` names the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on `<kai-voice-output>`), `detail.error` carries the platform error code, the thrown exception's name, or `no-result` when recognition ended with no error and no text (the user said nothing), and `detail.message` is human-readable. Deliberate cancellation does not fire. |
|
|
2878
|
-
|
|
2879
|
-
**Methods** (call on the element instance: `document.querySelector('kai-voice-output').speak()`):
|
|
2880
|
-
|
|
2881
|
-
| Method | Signature | Description |
|
|
2882
|
-
|---|---|---|
|
|
2883
|
-
| `speak` | `(): void` | Speak the current `text` (native, or via `synthesize` if set). |
|
|
2884
|
-
| `pause` | `(): void` | Pause playback (resumable). |
|
|
2885
|
-
| `resume` | `(): void` | Resume paused playback. |
|
|
2886
|
-
| `stop` | `(): void` | Stop playback and reset. |
|
|
2887
|
-
|
|
2888
|
-
**Styleable parts** (restyle from outside via `kai-voice-output::part(name)`):
|
|
2889
|
-
|
|
2890
|
-
| Part | Description |
|
|
2891
|
-
|---|---|
|
|
2892
|
-
| `::part(button)` | The speaker/play button. Restyle radius, size, padding, or colors from outside; it is a ghost icon button by default. — `kai-voice-output::part(button) { border-radius: 9999px; color: var(--color-primary) }` |
|
|
2893
|
-
|
|
2894
|
-
---
|
|
2895
|
-
|
|
2896
|
-
### `kai-workspace` / `Workspace`
|
|
2897
|
-
|
|
2898
|
-
**Properties** (every element also accepts `theme="light|dark|auto"`; only scalar props work as HTML attributes):
|
|
2899
|
-
|
|
2900
|
-
| Property | Attribute | Type | Description |
|
|
2901
|
-
|---|---|---|---|
|
|
2902
|
-
| `theme` | `theme` | `"light" \| "dark" \| "auto"` | Color mode (`auto` follows prefers-color-scheme). |
|
|
2903
|
-
| `startCollapsed` | `start-collapsed` | `undefined \| false \| true` | Controlled collapsed state of the start aside. Set this as a JS property (`el.startCollapsed = true`) to drive the aside from your app, updating it in response to the `kai-aside-toggle` event. Omit for uncontrolled (the element manages it). |
|
|
2904
|
-
| `defaultStartCollapsed` | `default-start-collapsed` | `undefined \| false \| true` | Initial collapsed state of the start aside when uncontrolled (default false). Use the `default-start-collapsed` attribute to start collapsed in plain HTML. |
|
|
2905
|
-
| `endCollapsed` | `end-collapsed` | `undefined \| false \| true` | Controlled collapsed state of the end aside. Set this as a JS property (`el.endCollapsed = true`) to drive the aside from your app, updating it in response to the `kai-aside-toggle` event. Omit for uncontrolled (the element manages it). |
|
|
2906
|
-
| `defaultEndCollapsed` | `default-end-collapsed` | `undefined \| false \| true` | Initial collapsed state of the end aside when uncontrolled (default false). Use the `default-end-collapsed` attribute to start collapsed in plain HTML. |
|
|
2907
|
-
| `collapseBelow` | `collapse-below` | `undefined \| number` | Auto-collapse both asides when the shell's own width drops below this many px, and re-expand when it grows back above. Applies to uncontrolled asides only (it never fights an app-driven collapsed prop); omit to disable. Fires `kai-aside-toggle`. Attribute: `collapse-below`. |
|
|
2908
|
-
| `drawerBelow` | `drawer-below` | `undefined \| number` | Below this shell width in px, an expanded aside renders as an overlay drawer over the main region instead of a column beside it. Escape inside the drawer closes it and returns focus to the element focused before it opened. Omit to disable. Attribute: `drawer-below`. |
|
|
2909
|
-
| `compact` | `compact` | `undefined \| false \| true` | Density hint. Reflected as a `data-compact` hook on the root (and as the `compact` attribute on the element) for your CSS and slotted content; the shell itself keeps no other opinion about density. |
|
|
2910
|
-
|
|
2911
|
-
**Events** (non-bubbling `CustomEvent`s — listen directly on the element):
|
|
2912
|
-
|
|
2913
|
-
| Event | `detail` type | Description |
|
|
2914
|
-
|---|---|---|
|
|
2915
|
-
| `kai-aside-resize` | `CustomEvent<{ side: "start" \| "end"; width: number }>` | The aside was resized (fires per drag step, keyboard nudge, or a handle double-click reset), width in px. |
|
|
2916
|
-
| `kai-aside-toggle` | `CustomEvent<{ side: "start" \| "end"; collapsed: false \| true }>` | An aside collapsed or expanded (a method, the breakpoint, the drawer's Escape). |
|
|
2917
|
-
|
|
2918
|
-
**Methods** (call on the element instance: `document.querySelector('kai-workspace').toggleAside(…)`):
|
|
2919
|
-
|
|
2920
|
-
| Method | Signature | Description |
|
|
2921
|
-
|---|---|---|
|
|
2922
|
-
| `toggleAside` | `(side: WorkspaceAsideSide): void` | Collapse/expand one aside (fires `kai-aside-toggle`). |
|
|
2923
|
-
| `collapseAside` | `(side: WorkspaceAsideSide): void` | Force one aside collapsed (fires `kai-aside-toggle`). |
|
|
2924
|
-
| `expandAside` | `(side: WorkspaceAsideSide): void` | Force one aside expanded (fires `kai-aside-toggle`). |
|
|
2925
|
-
|
|
2926
|
-
**Slots** (project your own markup via `slot="name"` on a light-DOM child):
|
|
2927
|
-
|
|
2928
|
-
| Slot | Mode | Description |
|
|
2929
|
-
|---|---|---|
|
|
2930
|
-
| _(default)_ | inject | The main region content (same region as the `main` slot): your `<kai-chat>`, or any app view. |
|
|
2931
|
-
| `header` | inject | The top band across the full shell width (app bar, tabs, breadcrumbs). |
|
|
2932
|
-
| `start` | inject | The inline-start aside column (a conversation rail, a nav, a file tree). Resizable and collapsible. |
|
|
2933
|
-
| `main` | inject | The main region. Unnamed children project here too, via the default slot. |
|
|
2934
|
-
| `end` | inject | The inline-end aside column (inspector, notes, preview). Resizable and collapsible. |
|
|
2935
|
-
| `footer` | inject | The bottom band across the full shell width (status bar, disclaimers). |
|
|
2936
|
-
|
|
2937
|
-
**Styleable parts** (restyle from outside via `kai-workspace::part(name)`):
|
|
2938
|
-
|
|
2939
|
-
| Part | Description |
|
|
2940
|
-
|---|---|
|
|
2941
|
-
| `::part(aside)` | Both aside columns match this part (each also matches its own start/end part). Restyle the shared aside surface or border from outside; the --kai-workspace-start-* and --kai-workspace-end-* custom properties set the widths. — `kai-workspace::part(aside) { background: var(--color-card) }` |
|
|
2942
|
-
| `::part(header)` | The top band across the full shell width (app bar, tabs, breadcrumbs). |
|
|
2943
|
-
| `::part(start)` | The inline-start aside column (a conversation rail, a nav, a file tree). Resizable and collapsible. |
|
|
2944
|
-
| `::part(main)` | The main region. Unnamed children project here too, via the default slot. |
|
|
2945
|
-
| `::part(end)` | The inline-end aside column (inspector, notes, preview). Resizable and collapsible. |
|
|
2946
|
-
| `::part(footer)` | The bottom band across the full shell width (status bar, disclaimers). |
|
|
2947
|
-
|
|
2948
|
-
---
|
|
2949
|
-
|