@kitn.ai/ui 0.26.0 → 0.28.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 +25 -6
- package/bin/mcp.js +16 -3
- package/bin/route.js +23 -0
- package/bin/route.test.js +58 -0
- package/dist/{elements/chunks/Icon--Y8vsFal.js → Icon-DObhsRtm.js} +1 -1
- package/dist/action-icons-CcgNN2oT.js +1 -0
- package/dist/arrow-down-CjRU3JgV.js +1 -0
- package/dist/arrow-left-Bnpb1UEW.js +1 -0
- package/dist/artifact-Bwt7OgcR.js +1 -0
- package/dist/assets/dev-5XzXYR21.js +91 -0
- package/dist/attachments-Qr4kg-2b.js +1 -0
- package/dist/{elements/chunks/audio-visualizer-D7lB6mvR.js → audio-visualizer-DToYdfSc.js} +1 -1
- package/dist/badge-CdEu_jn2.js +1 -0
- package/dist/bash-InADTalH.js +1 -6
- package/dist/bell-DQAAOpDz.js +1 -0
- package/dist/{elements/chunks/button-flUbeufF.js → button-DkuOnGLy.js} +1 -1
- package/dist/card-renderer-Jx70m6_l.js +1 -0
- package/dist/card-routing-0YidER_3.js +1 -0
- package/dist/check-njkVdZu2.js +1 -0
- package/dist/checkbox-D7iRB3nL.js +1 -0
- package/dist/checkbox-group-B2_rpoPM.js +1 -0
- package/dist/chevron-down-B72s6PXR.js +1 -0
- package/dist/chevron-right-BatuHzUm.js +1 -0
- package/dist/choice-card-m0BYqqOK.js +1 -0
- package/dist/circle-check-B62pODB3.js +1 -0
- package/dist/circle-x-BPG0iPst.js +1 -0
- package/dist/circle-zx0ByzY9.js +1 -0
- package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
- package/dist/code-block-ClMLKb7C.js +1 -0
- package/dist/{elements/chunks/collapsible-BzbXpPzr.js → collapsible-B4DlWicL.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 +135 -2
- package/dist/components/conversation-item.d.ts +35 -7
- package/dist/components/conversation-list.d.ts +17 -5
- package/dist/components/conversation-panel.d.ts +29 -0
- package/dist/components/form-widgets.d.ts +67 -2
- package/dist/components/form.d.ts +48 -1
- package/dist/components/home-panel.d.ts +34 -0
- 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/components/widget-tab-bar.d.ts +16 -0
- package/dist/composer-sQ0HcvyG.js +106 -0
- package/dist/confirm-card-rQWDQsnC.js +1 -0
- package/dist/construct-cli.es.js +1337 -0
- package/dist/{elements/chunks/context-VLIL3sJ-.js → context-0kg4ZX1J.js} +1 -1
- package/dist/controllable-CnGpMF6r.js +1 -0
- package/dist/conversation-item-BxwQLaFJ.js +1 -0
- package/dist/conversation-list-BCfGN1JU.js +1 -0
- package/dist/copy-n9u9rqpi.js +1 -0
- package/dist/core-AYMC6_lb.js +12 -5874
- package/dist/{create-tween-BFT6c-Y8.js → create-tween-C-q-JCM-.js} +1 -1
- package/dist/{create-tween-CJNlzoaO.js → create-tween-CRrJXxBd.js} +1 -1
- package/dist/{create-tween-CQED4T0g.js → create-tween-DZ3RRDHD.js} +1 -1
- package/dist/{elements/chunks/create-tween-c4Z8TDYz.js → create-tween-uPkArjIG.js} +2 -2
- package/dist/css-M7EaDHN_.js +1 -6
- package/dist/custom-elements.json +1433 -202
- package/dist/default-input-CaMrJkgH.js +1 -0
- package/dist/define-By-uL588.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-WUImBbDv.js} +1 -1
- package/dist/{elements/chunks/dropdown-BgWTthUx.js → dropdown-wZVeJOMd.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 +102 -8
- 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 +380 -26
- package/dist/{elements/chunks/ellipsis-7gU33mL2.js → ellipsis-CbOpJnU3.js} +1 -1
- package/dist/embed-CrfjkbUG.js +1 -0
- package/dist/engine-javascript-vq0WuIJl.js +14 -2516
- package/dist/{elements/chunks/external-link-CSOEsNlx.js → external-link-ByXAwBBQ.js} +1 -1
- package/dist/file-text-DMib2qwt.js +1 -0
- package/dist/{elements/chunks/file-tree-zvB2i7P9.js → file-tree-CJqM2aP7.js} +1 -1
- package/dist/folder-_BAb929C.js +1 -0
- package/dist/form-DSZgZQZk.js +1 -0
- package/dist/github-dark-dimmed-DUshB20C.js +1 -4
- package/dist/github-light-JYsPkUQd.js +1 -4
- package/dist/hover-card-BQbul9eq.js +1 -0
- package/dist/html-CPZ3oZQ7.js +1 -10
- package/dist/icon-CdcfRhYI.js +1 -0
- package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +7474 -5857
- package/dist/index.server.js +5965 -4762
- package/dist/info-DsFjGuI_.js +1 -0
- package/dist/input-DKbmkMos.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-PvdGhX4s.js +1 -0
- package/dist/{elements/chunks/link-preview-OQ9IEq0f.js → link-preview-DbM1866N.js} +1 -1
- package/dist/link-zF8PzWfF.js +1 -0
- package/dist/loader-BM4CEz4G.js +1 -0
- package/dist/{elements/chunks/markdown-DgBFaGAz.js → markdown-LMvmAyBk.js} +7 -7
- package/dist/mcp.es.js +1361 -81
- package/dist/message-BSsgvHvf.js +1 -0
- package/dist/message-BYZECyek.js +1 -0
- package/dist/message-circle-DruwObfX.js +1 -0
- package/dist/message-square-BG6q6mlm.js +1 -0
- package/dist/{elements/chunks/minimize-2-DPIUKTrT.js → minimize-2-BQRoBV1V.js} +1 -1
- package/dist/{elements/chunks/model-switcher-DsT8tFB0.js → model-switcher-CMpCOYcB.js} +1 -1
- package/dist/{elements/chunks/overlay-DuiwdXjm.js → overlay-Cb-MkyDa.js} +1 -1
- package/dist/panel-right-i8warFxT.js +1 -0
- package/dist/paperclip-ByY3UVO6.js +1 -0
- package/dist/play-BvKKq3fX.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/conversation-store.d.ts +54 -0
- 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-jVAHvMUf.js +1 -0
- package/dist/prompt-suggestion-CD-qtNgC.js +1 -0
- package/dist/radio-BsoBMhkF.js +1 -0
- package/dist/react/index.d.ts +586 -19
- package/dist/react.js +223 -187
- package/dist/reasoning-4kBPtlTx.js +1 -0
- package/dist/register-impl-B1hLkrI8.js +424 -0
- package/dist/{elements/chunks/resizable-D181b4fM.js → resizable-uPmY9VY-.js} +1 -1
- package/dist/rotate-ccw-B2xn93py.js +1 -0
- package/dist/rotate-cw-CMVLoCyH.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-BqLUo8ZZ.js +1 -0
- package/dist/scroll-button-DslXiJyL.js +1 -0
- package/dist/select-2cLRtPGT.js +1 -0
- package/dist/{elements/chunks/separator-CeJHQqLW.js → separator-BWQtNJcM.js} +1 -1
- package/dist/{elements/chunks/settings-CqaHgJF9.js → settings-BBR63jLg.js} +1 -1
- package/dist/{elements/chunks/settings-group-CjqjLCOn.js → settings-group-B2ciy-Iw.js} +1 -1
- package/dist/{elements/chunks/skeleton-D8akBnKS.js → skeleton-CkHI-HgC.js} +1 -1
- package/dist/slider-DDR9U-i0.js +1 -0
- package/dist/{solid-BtdqNZI7.js → solid-BzCFdL25.js} +9771 -7594
- package/dist/{solid-CnavwBye.js → solid-DruVOXnf.js} +7893 -6183
- package/dist/solid.d.ts +16 -2
- package/dist/solid.js +256 -243
- package/dist/solid.server.js +256 -243
- package/dist/source-GEnFF528.js +1 -0
- package/dist/star-CilHq8GP.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/store-Ciyk6eZG.js +1 -0
- package/dist/svelte--5p79yCD.js +1 -15
- package/dist/switch-KkeQIbuH.js +1 -0
- package/dist/tasks-card-BrN4bggJ.js +1 -0
- package/dist/text-shimmer-Dcj1MHuq.js +1 -0
- package/dist/textarea-Dpvbngbg.js +1 -0
- package/dist/theme.tokens.css +110 -13
- package/dist/{elements/chunks/thumbs-up-DX2Ijk3H.js → thumbs-up-CsT9Wzb9.js} +1 -1
- package/dist/toast-store-tgK6MuMv.js +1 -0
- package/dist/{elements/chunks/tool-DKQ2D1DP.js → tool-DzUjIBT8.js} +1 -1
- package/dist/{elements/chunks/tooltip-B0G99y8w.js → tooltip-Bkkg_4t0.js} +1 -1
- package/dist/trash-2-jBKxjGGQ.js +1 -0
- package/dist/{elements/chunks/triangle-alert-F9cyUEyy.js → triangle-alert-DlQ68ppf.js} +1 -1
- package/dist/tsx-B8rCNbgL.js +1 -6
- package/dist/types.d.ts +48 -3
- 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 +51 -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-TcAHXv9W.js +1 -0
- package/dist/url-scheme-policy-DR5DgvkM.js +1 -0
- package/dist/use-card-resolution-DaZqAdWf.js +1 -0
- package/dist/{elements/chunks/variant-aurora-qt6Zct8M.js → variant-aurora-BhLuYxJR.js} +1 -1
- package/dist/{variant-aurora-B8II3-I1.js → variant-aurora-CNmfHhcx.js} +2 -2
- package/dist/{variant-aurora-CMNWOSJR.js → variant-aurora-D6GsdTPA.js} +2 -2
- package/dist/{variant-aurora-CcuDMWwQ.js → variant-aurora-DbW_OWL2.js} +1 -1
- package/dist/{elements/chunks/variant-custom-tJp22_BQ.js → variant-custom-BRvaNHSi.js} +1 -1
- package/dist/{variant-custom-L16JLLZy.js → variant-custom-BvYHR62b.js} +1 -1
- package/dist/{variant-custom-BdvYC7af.js → variant-custom-DMTrEO5w.js} +2 -2
- package/dist/{variant-custom-C714mqKl.js → variant-custom-DV2x254s.js} +2 -2
- package/dist/{variant-wave-ecwykeyL.js → variant-wave-BNMGrDfj.js} +2 -2
- package/dist/{variant-wave-2S4La2Ka.js → variant-wave-BpDd8t3Z.js} +1 -1
- package/dist/{variant-wave-D7ruiA1W.js → variant-wave-CyBueXj9.js} +2 -2
- package/dist/{elements/chunks/variant-wave-CaQ5ti39.js → variant-wave-sp-qwsdI.js} +1 -1
- package/dist/vue-BmIZj4XD.js +1 -33
- package/dist/x-Z5UntkIJ.js +1 -0
- package/frameworks/react/index.tsx +210 -22
- package/llms-full.txt +1184 -22
- package/llms.txt +6 -3
- package/package.json +17 -4
- package/src/agent-tooling/README.md +192 -0
- package/src/agent-tooling/catalog/invariants.ts +3 -3
- 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 +147 -0
- package/src/agent-tooling/construct/codegen.ts +1635 -0
- package/src/agent-tooling/construct/construct.v1.schema.json +319 -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 +32 -0
- package/src/agent-tooling/construct/schema.ts +452 -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 +602 -43
- 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 +56 -9
- package/src/components/conversation-list.tsx +25 -10
- package/src/components/conversation-panel.tsx +118 -0
- package/src/components/empty.tsx +14 -3
- package/src/components/file-tree.tsx +5 -1
- package/src/components/form-widgets.tsx +257 -195
- package/src/components/form.tsx +297 -9
- package/src/components/home-panel.tsx +159 -0
- 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/components/widget-tab-bar.tsx +73 -0
- package/src/elements/attachments.tsx +3 -1
- package/src/elements/chat-workspace.tsx +1 -1
- package/src/elements/chat.tsx +115 -5
- 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 +767 -34
- package/src/elements/element-nonscalar.json +17 -0
- package/src/elements/element-types.d.ts +380 -26
- 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 +5 -2
- 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/conversation-store.ts +248 -0
- 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 +20 -2
- package/src/state/index.ts +1 -1
- package/src/state/mock.ts +92 -6
- package/src/types.ts +45 -3
- 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 +192 -7
- 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 +112 -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/code-block-BdLiTitd.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/store-Cjq0qwYN.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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createEffect, createSignal, untrack } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { RadioGroup } from '../ui/radio';
|
|
4
|
+
// Public shape of the `options` prop; lives in ./element-data-types so the ROOT
|
|
5
|
+
// entry can re-export it (see that file's header).
|
|
6
|
+
import type { KaiRadioOption } from './element-data-types';
|
|
7
|
+
|
|
8
|
+
interface Props extends Record<string, unknown> {
|
|
9
|
+
/** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute. */
|
|
10
|
+
options: KaiRadioOption[];
|
|
11
|
+
/** Controlled selected `value`. Settable and reflected to the `value` attribute.
|
|
12
|
+
* `el.value = 'degraded'` drives it; choosing a row updates it and fires
|
|
13
|
+
* `kai-change`. Read `el.value` for live state. */
|
|
14
|
+
value?: string;
|
|
15
|
+
/** Shared form-control name for every radio in the group. Defaults to a generated
|
|
16
|
+
* id, so the group is exclusive and keyboard-navigable even when nothing is
|
|
17
|
+
* submitted. */
|
|
18
|
+
name?: string;
|
|
19
|
+
/** Disable every row. Individual rows carry their own `disabled`. */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Accessible name for the group. */
|
|
22
|
+
label?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Events fired by `<kai-radio-group>`. */
|
|
26
|
+
interface Events {
|
|
27
|
+
/** A row was chosen. */
|
|
28
|
+
'kai-change': { value: string };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `<kai-radio-group>` — the kit's "pick exactly one" control: a bordered, divided
|
|
33
|
+
* list over real `<input type="radio">`s that share a `name`, so one tab stop, arrow
|
|
34
|
+
* keys, mutual exclusion and form participation are the browser's and not a
|
|
35
|
+
* reimplementation.
|
|
36
|
+
*
|
|
37
|
+
* Feed it `options` (a JS-property array of `{ value, label, description?, disabled? }`),
|
|
38
|
+
* drive/read the selection with the `value` property (settable + reflected to the
|
|
39
|
+
* `value` attribute, so `:host([value])` and `el.value` see live state), and listen
|
|
40
|
+
* for `kai-change`.
|
|
41
|
+
*
|
|
42
|
+
* Re-rendering follows the kit's reactivity contract: hand it a NEW array reference,
|
|
43
|
+
* and a new object for any option whose content changed — the rows are a
|
|
44
|
+
* reference-keyed list, so mutating an option in place changes nothing on screen.
|
|
45
|
+
*
|
|
46
|
+
* ```html
|
|
47
|
+
* <kai-radio-group value="degraded" label="Severity"></kai-radio-group>
|
|
48
|
+
* <script type="module">
|
|
49
|
+
* import '@kitn.ai/ui/elements';
|
|
50
|
+
* const group = document.querySelector('kai-radio-group');
|
|
51
|
+
* group.options = [
|
|
52
|
+
* { value: 'blocking', label: 'Blocking', description: 'Pages the on-call' },
|
|
53
|
+
* { value: 'degraded', label: 'Degraded' },
|
|
54
|
+
* { value: 'cosmetic', label: 'Cosmetic' },
|
|
55
|
+
* ];
|
|
56
|
+
* group.addEventListener('kai-change', (e) => console.log(e.detail.value));
|
|
57
|
+
* group.value = 'cosmetic'; // drive it (no kai-change — the host already knows)
|
|
58
|
+
* </script>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
defineWebComponent<Props, Events>('kai-radio-group', {
|
|
62
|
+
options: [],
|
|
63
|
+
value: undefined,
|
|
64
|
+
name: undefined,
|
|
65
|
+
disabled: undefined,
|
|
66
|
+
label: undefined,
|
|
67
|
+
}, (props, ctx) => {
|
|
68
|
+
const { element, dispatch, flag, expose } = ctx;
|
|
69
|
+
|
|
70
|
+
// Lift the selection into the facade and drive RadioGroup CONTROLLED so the host can
|
|
71
|
+
// read it (`el.value` / `:host([value])`) and set it after mount. Seed from the
|
|
72
|
+
// `value` property/attribute present on mount; nothing is auto-selected, because
|
|
73
|
+
// `options` normally arrives as a property AFTER upgrade (kai-segmented's structure).
|
|
74
|
+
const [value, setValue] = createSignal(
|
|
75
|
+
(props.value as string | undefined) ?? element.getAttribute('value') ?? '',
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Coerce anything arriving through the `value` setter (a JS assignment, or the
|
|
79
|
+
// attributeChangedCallback write-back) to a string, falling back to the live
|
|
80
|
+
// attribute when nullish so the reflect write-back equals the signal and the guards
|
|
81
|
+
// below absorb it — no attr⇄prop feedback loop.
|
|
82
|
+
const coerce = (v: unknown): string =>
|
|
83
|
+
v == null ? (element.getAttribute('value') ?? '') : String(v);
|
|
84
|
+
|
|
85
|
+
// Apply a new value and fire kai-change once (the user-choice path).
|
|
86
|
+
const apply = (next: string) => {
|
|
87
|
+
if (untrack(value) === next) return;
|
|
88
|
+
setValue(next);
|
|
89
|
+
dispatch('kai-change', { value: next });
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
Object.defineProperty(element, 'value', {
|
|
93
|
+
get: () => value(),
|
|
94
|
+
set: (v: unknown) => { const next = coerce(v); if (untrack(value) !== next) setValue(next); },
|
|
95
|
+
configurable: true,
|
|
96
|
+
enumerable: true,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Reflect internal value → the `[value]` host attribute (for `:host([value])`).
|
|
100
|
+
createEffect(() => {
|
|
101
|
+
const v = value();
|
|
102
|
+
if (v) {
|
|
103
|
+
if (element.getAttribute('value') !== v) element.setAttribute('value', v);
|
|
104
|
+
} else if (element.hasAttribute('value')) {
|
|
105
|
+
element.removeAttribute('value');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expose({
|
|
110
|
+
/** Focus the group's tab stop. That is the selected radio, or the first row when
|
|
111
|
+
* nothing is selected yet. */
|
|
112
|
+
focus: (options?: FocusOptions) => {
|
|
113
|
+
const root = element.shadowRoot;
|
|
114
|
+
const radios = [...(root?.querySelectorAll<HTMLInputElement>('input[type="radio"]') ?? [])];
|
|
115
|
+
(radios.find((r) => r.checked) ?? radios[0])?.focus(options);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<RadioGroup
|
|
121
|
+
options={(props.options ?? []) as KaiRadioOption[]}
|
|
122
|
+
value={value()}
|
|
123
|
+
name={props.name as string | undefined}
|
|
124
|
+
disabled={flag('disabled')}
|
|
125
|
+
label={props.label as string | undefined}
|
|
126
|
+
onChange={(next) => apply(next)}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
});
|
|
@@ -54,6 +54,11 @@ import './artifact';
|
|
|
54
54
|
import './scroll-button';
|
|
55
55
|
import './popover';
|
|
56
56
|
import './switch';
|
|
57
|
+
import './checkbox';
|
|
58
|
+
import './checkbox-group';
|
|
59
|
+
import './radio-group';
|
|
60
|
+
import './slider';
|
|
61
|
+
import './select';
|
|
57
62
|
import './button';
|
|
58
63
|
import './avatar';
|
|
59
64
|
import './badge';
|
|
@@ -94,6 +99,7 @@ import './setting-item';
|
|
|
94
99
|
// Multi-agent workspace primitives (graduated from SolidJS prototypes)
|
|
95
100
|
import './pane';
|
|
96
101
|
import './pane-group';
|
|
102
|
+
import './pane-grid';
|
|
97
103
|
import './agent-card';
|
|
98
104
|
import './dialog';
|
|
99
105
|
import './dock';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createSignal, onCleanup, onMount } from 'solid-js';
|
|
1
|
+
import { Show, createSignal, onCleanup, onMount } from 'solid-js';
|
|
2
2
|
import { cn } from '../utils/cn';
|
|
3
3
|
import { Button } from '../ui/button';
|
|
4
|
-
import {
|
|
4
|
+
import { ArrowDown } from 'lucide-solid';
|
|
5
5
|
import { defineWebComponent } from './define';
|
|
6
6
|
|
|
7
7
|
interface Props extends Record<string, unknown> {
|
|
@@ -14,6 +14,14 @@ interface Props extends Record<string, unknown> {
|
|
|
14
14
|
variant?: 'outline' | 'ghost' | 'default';
|
|
15
15
|
/** Button size token. Defaults to `'icon'` (square). */
|
|
16
16
|
size?: 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm';
|
|
17
|
+
/** The button's accessible name. It is announced whether or not the label is
|
|
18
|
+
* visible, so the text is always localisable. Defaults to
|
|
19
|
+
* `'Scroll to bottom'`. */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Also render `label` visibly beside the icon. Defaults to `false`, which
|
|
22
|
+
* is the icon-only button. When the text is visible it IS the accessible
|
|
23
|
+
* name, so nothing gets announced twice. */
|
|
24
|
+
showLabel?: boolean;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
/** Events fired by `<kai-scroll-button>`. */
|
|
@@ -26,6 +34,27 @@ interface Events {
|
|
|
26
34
|
|
|
27
35
|
const SCROLL_THRESHOLD = 50;
|
|
28
36
|
|
|
37
|
+
/** The accessible name used when the consumer does not supply one. */
|
|
38
|
+
const DEFAULT_LABEL = 'Scroll to bottom';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The floating chip surface. Mirrors `surfaceClasses` in
|
|
42
|
+
* `components/scroll-button.tsx`: the shared `outline` button variant is
|
|
43
|
+
* `bg-muted/50`, half-transparent, so message text showed through a control
|
|
44
|
+
* floating over scrolling content and its edge measured about 1.05:1 against
|
|
45
|
+
* the thread behind it (SC 1.4.11 wants 3:1). `bg-card` is the opaque surface
|
|
46
|
+
* popovers and dropdowns already use, `border-input` is the kit's control edge
|
|
47
|
+
* and clears 3:1 in both themes, and `kai-elevation` is the shared themeable
|
|
48
|
+
* float shadow that keeps an opaque button reading as ABOVE the content.
|
|
49
|
+
* `ghost` and `default` are explicit consumer choices about the fill, so they
|
|
50
|
+
* keep theirs.
|
|
51
|
+
*/
|
|
52
|
+
function surfaceClasses(variant: Props['variant']) {
|
|
53
|
+
return (variant ?? 'outline') === 'outline'
|
|
54
|
+
? 'border border-input bg-card text-card-foreground kai-elevation'
|
|
55
|
+
: 'kai-elevation';
|
|
56
|
+
}
|
|
57
|
+
|
|
29
58
|
/** Walk the composed tree upwards from `startEl` (outside shadow roots) to
|
|
30
59
|
* find the nearest scrollable ancestor. */
|
|
31
60
|
function findScrollableAncestor(startEl: HTMLElement): HTMLElement | null {
|
|
@@ -63,7 +92,9 @@ defineWebComponent<Props, Events>('kai-scroll-button', {
|
|
|
63
92
|
for: undefined,
|
|
64
93
|
variant: 'outline',
|
|
65
94
|
size: 'icon',
|
|
66
|
-
|
|
95
|
+
label: undefined,
|
|
96
|
+
showLabel: undefined,
|
|
97
|
+
}, (props, { element, dispatch, flag }) => {
|
|
67
98
|
const [isAtBottom, setIsAtBottom] = createSignal(true);
|
|
68
99
|
let containerEl: HTMLElement | null = null;
|
|
69
100
|
let cleanupFns: (() => void)[] = [];
|
|
@@ -104,18 +135,25 @@ defineWebComponent<Props, Events>('kai-scroll-button', {
|
|
|
104
135
|
|
|
105
136
|
onCleanup(detach);
|
|
106
137
|
|
|
138
|
+
const label = () => (props.label as string | undefined) ?? DEFAULT_LABEL;
|
|
139
|
+
const showLabel = () => flag('showLabel');
|
|
140
|
+
|
|
107
141
|
return (
|
|
108
142
|
<Button
|
|
109
143
|
variant={props.variant ?? 'outline'}
|
|
110
144
|
size={props.size ?? 'icon'}
|
|
111
|
-
aria-label
|
|
145
|
+
// When the label is visible it IS the accessible name; an aria-label on
|
|
146
|
+
// top of it would override the visible text and the two could disagree.
|
|
147
|
+
aria-label={showLabel() ? undefined : label()}
|
|
112
148
|
// While at the bottom this button is fully transparent and pointer-inert,
|
|
113
149
|
// but it stayed in the tab order — a keyboard user landed on a control
|
|
114
150
|
// they could not see. Mirrors ScrollButton in components/scroll-button.tsx.
|
|
115
151
|
tabindex={isAtBottom() ? -1 : 0}
|
|
116
152
|
aria-hidden={isAtBottom() ? 'true' : undefined}
|
|
117
153
|
class={cn(
|
|
118
|
-
'rounded-
|
|
154
|
+
'rounded-lg transition-all duration-150 ease-out',
|
|
155
|
+
surfaceClasses(props.variant),
|
|
156
|
+
showLabel() ? 'h-9 w-auto gap-1.5 px-3 text-sm' : '',
|
|
119
157
|
!isAtBottom()
|
|
120
158
|
? 'translate-y-0 scale-100 opacity-100'
|
|
121
159
|
: 'pointer-events-none translate-y-4 scale-95 opacity-0',
|
|
@@ -125,7 +163,17 @@ defineWebComponent<Props, Events>('kai-scroll-button', {
|
|
|
125
163
|
dispatch('kai-scroll');
|
|
126
164
|
}}
|
|
127
165
|
>
|
|
128
|
-
|
|
166
|
+
{/* h-4, not the h-5 the chevron used, and the same reasoning as
|
|
167
|
+
components/scroll-button.tsx: a ChevronDown only inks the lower part of
|
|
168
|
+
its 24px viewBox, so at a 20px box its visible mass is small, while
|
|
169
|
+
ArrowDown inks the full height (stem + head) and at 20px crowded the
|
|
170
|
+
padding. Re-checked here because this button box is 36px (size="icon")
|
|
171
|
+
rather than the Solid component's 40px, and 16px balances both. It is
|
|
172
|
+
also the size lucide pairs with text-sm, which the label renders at. */}
|
|
173
|
+
<ArrowDown class="h-4 w-4 shrink-0" aria-hidden="true" />
|
|
174
|
+
<Show when={showLabel()}>
|
|
175
|
+
<span>{label()}</span>
|
|
176
|
+
</Show>
|
|
129
177
|
</Button>
|
|
130
178
|
);
|
|
131
179
|
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { createEffect, createSignal, untrack } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { Select } from '../ui/select';
|
|
4
|
+
// Public shape of the `options` prop; lives in ./element-data-types so the ROOT
|
|
5
|
+
// entry can re-export it (see that file's header).
|
|
6
|
+
import type { KaiSelectOption } from './element-data-types';
|
|
7
|
+
|
|
8
|
+
interface Props extends Record<string, unknown> {
|
|
9
|
+
/** The choices, in display order. Set as a JS PROPERTY (array), never an attribute.
|
|
10
|
+
* Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
|
|
11
|
+
options: KaiSelectOption[];
|
|
12
|
+
/** Controlled selected value. Settable and reflected to the `value` attribute.
|
|
13
|
+
* `el.value = 'high'` drives it; choosing an option updates it and fires
|
|
14
|
+
* `kai-change`. Read `el.value` for live state; for a `multiple` select read
|
|
15
|
+
* `el.values` instead. */
|
|
16
|
+
value?: string;
|
|
17
|
+
/** Text for a leading, disabled, empty option: the "nothing chosen yet" row.
|
|
18
|
+
* Omitted means no such row at all; there is no default wording, because inventing
|
|
19
|
+
* one would put words in your UI. */
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
/** Allow more than one selection. Turns the control into the platform's list box, so
|
|
22
|
+
* the kit's chevron is not drawn. */
|
|
23
|
+
multiple?: boolean;
|
|
24
|
+
/** Force the invalid (destructive-border) state. */
|
|
25
|
+
invalid?: boolean;
|
|
26
|
+
/** Disable interaction. */
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
/** Set the native `required` attribute, and nothing more. Whether an empty select is
|
|
29
|
+
* an error is the application's rule, not the kit's. */
|
|
30
|
+
required?: boolean;
|
|
31
|
+
/** Accessible label for the control. */
|
|
32
|
+
label?: string;
|
|
33
|
+
/** Form-control name, for a native form submit. */
|
|
34
|
+
name?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Events fired by `<kai-select>`. */
|
|
38
|
+
interface Events {
|
|
39
|
+
/** A choice was made. `value` is the first selected option (empty when nothing is
|
|
40
|
+
* selected); `values` is every selected option, which is what a `multiple` select
|
|
41
|
+
* needs. Both are always present, so neither shape silently loses the other. */
|
|
42
|
+
'kai-change': { value: string; values: string[] };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* `<kai-select>` — a select over a REAL native `<select>`, in the kit's field box with
|
|
47
|
+
* the kit's own chevron. Native, not a hand-built listbox: that is what keeps the
|
|
48
|
+
* platform picker on mobile, type-ahead on desktop, form participation and the OS
|
|
49
|
+
* accessibility tree.
|
|
50
|
+
*
|
|
51
|
+
* The dropdown list itself stays OS chrome — it renders outside the page and no
|
|
52
|
+
* stylesheet reaches it. What the element does do is make it follow the kit's
|
|
53
|
+
* light/dark mode rather than the OS's.
|
|
54
|
+
*
|
|
55
|
+
* Feed it `options` (a JS-property array of `{ value, label?, disabled? }`), drive and
|
|
56
|
+
* read the selection with the `value` property (settable + reflected to the `value`
|
|
57
|
+
* attribute, so `:host([value])` and `el.value` see live state), and listen for
|
|
58
|
+
* `kai-change`.
|
|
59
|
+
*
|
|
60
|
+
* Re-rendering follows the kit's reactivity contract: hand it a NEW array reference,
|
|
61
|
+
* and a new object for any option whose content changed — the list is
|
|
62
|
+
* reference-keyed, so mutating an option in place changes nothing on screen.
|
|
63
|
+
*
|
|
64
|
+
* ```html
|
|
65
|
+
* <kai-select value="high" placeholder="Choose a severity…" label="Severity"></kai-select>
|
|
66
|
+
* <script type="module">
|
|
67
|
+
* import '@kitn.ai/ui/elements';
|
|
68
|
+
* const select = document.querySelector('kai-select');
|
|
69
|
+
* // ARRAY prop — a JS property, never an attribute.
|
|
70
|
+
* select.options = [
|
|
71
|
+
* { value: 'low', label: 'Low' },
|
|
72
|
+
* { value: 'high', label: 'High priority' },
|
|
73
|
+
* { value: 'legacy', label: 'Legacy', disabled: true },
|
|
74
|
+
* ];
|
|
75
|
+
* select.addEventListener('kai-change', (e) => console.log(e.detail.value, e.detail.values));
|
|
76
|
+
* select.value = 'low'; // drive it (no kai-change — the host already knows)
|
|
77
|
+
* </script>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
defineWebComponent<Props, Events>('kai-select', {
|
|
81
|
+
options: [],
|
|
82
|
+
value: undefined,
|
|
83
|
+
placeholder: undefined,
|
|
84
|
+
multiple: undefined,
|
|
85
|
+
invalid: undefined,
|
|
86
|
+
disabled: undefined,
|
|
87
|
+
required: undefined,
|
|
88
|
+
label: undefined,
|
|
89
|
+
name: undefined,
|
|
90
|
+
}, (props, ctx) => {
|
|
91
|
+
const { element, dispatch, flag, expose } = ctx;
|
|
92
|
+
|
|
93
|
+
// Lift the selection into the facade and drive Select CONTROLLED so the host can read
|
|
94
|
+
// it (`el.value` / `:host([value])`) and set it after mount. Seed from the `value`
|
|
95
|
+
// property/attribute present on mount; nothing is auto-selected, because `options`
|
|
96
|
+
// normally arrives as a property AFTER upgrade (kai-radio-group's structure).
|
|
97
|
+
const seed = (props.value as string | undefined) ?? element.getAttribute('value') ?? '';
|
|
98
|
+
const [values, setValues] = createSignal<string[]>(seed ? [seed] : []);
|
|
99
|
+
const first = () => values()[0] ?? '';
|
|
100
|
+
|
|
101
|
+
// Coerce anything arriving through the `value` setter (a JS assignment, or the
|
|
102
|
+
// attributeChangedCallback write-back the reflect effect below triggers) to a string,
|
|
103
|
+
// falling back to the live attribute when nullish so the write-back equals the signal
|
|
104
|
+
// and the guards absorb it — no attr⇄prop feedback loop.
|
|
105
|
+
const coerce = (v: unknown): string =>
|
|
106
|
+
v == null ? (element.getAttribute('value') ?? '') : String(v);
|
|
107
|
+
|
|
108
|
+
// Apply a new selection and fire kai-change once (the user-choice path).
|
|
109
|
+
const apply = (next: string[]) => {
|
|
110
|
+
const prev = untrack(values);
|
|
111
|
+
if (prev.length === next.length && prev.every((v, i) => v === next[i])) return;
|
|
112
|
+
setValues(next);
|
|
113
|
+
dispatch('kai-change', { value: next[0] ?? '', values: next });
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
Object.defineProperty(element, 'value', {
|
|
117
|
+
get: () => first(),
|
|
118
|
+
set: (v: unknown) => {
|
|
119
|
+
const next = coerce(v);
|
|
120
|
+
if (untrack(first) !== next) setValues(next ? [next] : []);
|
|
121
|
+
},
|
|
122
|
+
configurable: true,
|
|
123
|
+
enumerable: true,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// The multi-selection read/write side. `value` alone cannot represent it, and
|
|
127
|
+
// returning only the first option from a `multiple` select would be a silent drop.
|
|
128
|
+
Object.defineProperty(element, 'values', {
|
|
129
|
+
get: () => values(),
|
|
130
|
+
set: (v: unknown) => setValues(Array.isArray(v) ? v.map(String) : []),
|
|
131
|
+
configurable: true,
|
|
132
|
+
enumerable: true,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Reflect the primary value → the `[value]` host attribute (for `:host([value])`).
|
|
136
|
+
createEffect(() => {
|
|
137
|
+
const v = first();
|
|
138
|
+
if (v) {
|
|
139
|
+
if (element.getAttribute('value') !== v) element.setAttribute('value', v);
|
|
140
|
+
} else if (element.hasAttribute('value')) {
|
|
141
|
+
element.removeAttribute('value');
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expose({
|
|
146
|
+
/** Focus the inner select (the host element can't reach it). */
|
|
147
|
+
focus: (options?: FocusOptions) =>
|
|
148
|
+
element.shadowRoot?.querySelector<HTMLSelectElement>('select')?.focus(options),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<Select
|
|
153
|
+
options={(props.options ?? []) as KaiSelectOption[]}
|
|
154
|
+
value={values()}
|
|
155
|
+
placeholder={props.placeholder as string | undefined}
|
|
156
|
+
multiple={flag('multiple')}
|
|
157
|
+
invalid={flag('invalid')}
|
|
158
|
+
disabled={flag('disabled')}
|
|
159
|
+
required={flag('required')}
|
|
160
|
+
aria-label={props.label as string | undefined}
|
|
161
|
+
name={props.name as string | undefined}
|
|
162
|
+
onChange={(e) => apply([...e.currentTarget.selectedOptions].map((o) => o.value))}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createEffect, createSignal, untrack } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { Slider } from '../ui/slider';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** Lowest selectable value. Required: a range with no bounds is a guess, and the
|
|
7
|
+
* guess belongs to whoever knows what the number means. */
|
|
8
|
+
min?: number;
|
|
9
|
+
/** Highest selectable value. Required, for the same reason as `min`. */
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Granularity. Omitted means the native default of 1; `any` means continuous. */
|
|
12
|
+
step?: number | 'any';
|
|
13
|
+
/** Controlled value. Settable and reflected to the `value` attribute. `el.value = 40`
|
|
14
|
+
* drives it; dragging updates it and fires `kai-input` per step, `kai-change` on
|
|
15
|
+
* release. Read `el.value` for live state. */
|
|
16
|
+
value?: number;
|
|
17
|
+
/** Disable interaction. */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Accessible label for the slider. */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Form-control name, for a native form submit. */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Show the current value beside the track. Off by default.
|
|
24
|
+
*
|
|
25
|
+
* Two ways in, because one of them is not a scalar. As a bare ATTRIBUTE
|
|
26
|
+
* (`<kai-slider value-label>`) it renders the raw number. As a JS PROPERTY it also
|
|
27
|
+
* accepts a formatter function (`el.valueLabel = (v) => v + '%'`), for a slider that
|
|
28
|
+
* is not counting bare numbers. A function cannot survive an attribute, so that half
|
|
29
|
+
* is property-only.
|
|
30
|
+
*
|
|
31
|
+
* The readout is hidden from assistive tech: the slider already reports the same
|
|
32
|
+
* number, and an exposed copy would be announced twice. */
|
|
33
|
+
valueLabel?: boolean | ((value: number) => string);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Events fired by `<kai-slider>`. */
|
|
37
|
+
interface Events {
|
|
38
|
+
/** The thumb moved. Fires per step during a drag or a key press. */
|
|
39
|
+
'kai-input': { value: number };
|
|
40
|
+
/** The value was committed: pointer released, or a key press finished. */
|
|
41
|
+
'kai-change': { value: number };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `<kai-slider>` — a slider over a real `<input type="range">`, with the kit's filled
|
|
46
|
+
* track and thumb. Arrows, Home, End and PageUp/PageDown all work because the control
|
|
47
|
+
* underneath is the browser's, not a reimplementation.
|
|
48
|
+
*
|
|
49
|
+
* Give it `min` and `max` (there are no defaults on purpose), drive and read the
|
|
50
|
+
* position with the `value` property, and listen for `kai-input` while dragging or
|
|
51
|
+
* `kai-change` on release.
|
|
52
|
+
*
|
|
53
|
+
* ```html
|
|
54
|
+
* <kai-slider min="0" max="100" step="5" value="40" label="Temperature"></kai-slider>
|
|
55
|
+
* <script type="module">
|
|
56
|
+
* import '@kitn.ai/ui/elements';
|
|
57
|
+
* const slider = document.querySelector('kai-slider');
|
|
58
|
+
* slider.addEventListener('kai-input', (e) => console.log(e.detail.value));
|
|
59
|
+
* slider.value = 70; // drive it (no event — the host already knows)
|
|
60
|
+
* </script>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
defineWebComponent<Props, Events>('kai-slider', {
|
|
64
|
+
min: undefined,
|
|
65
|
+
max: undefined,
|
|
66
|
+
step: undefined,
|
|
67
|
+
value: undefined,
|
|
68
|
+
disabled: undefined,
|
|
69
|
+
label: undefined,
|
|
70
|
+
name: undefined,
|
|
71
|
+
valueLabel: undefined,
|
|
72
|
+
}, (props, ctx) => {
|
|
73
|
+
const { element, dispatch, flag, expose } = ctx;
|
|
74
|
+
|
|
75
|
+
// `Number(null)` is 0 and `Number('')` is 0, both FINITE, so a naive
|
|
76
|
+
// `Number.isFinite(Number(v))` treats a missing attribute as a real zero and the
|
|
77
|
+
// fallbacks below never fire. Reject the empty cases before coercing.
|
|
78
|
+
const num = (v: unknown, fallback: number): number => {
|
|
79
|
+
if (v == null || (typeof v === 'string' && v.trim() === '')) return fallback;
|
|
80
|
+
const n = Number(v);
|
|
81
|
+
return Number.isFinite(n) ? n : fallback;
|
|
82
|
+
};
|
|
83
|
+
// No invented bounds: these mirror the native `<input type="range">` defaults, which
|
|
84
|
+
// is what an author who wrote neither attribute is already going to get.
|
|
85
|
+
const min = () => num(props.min, 0);
|
|
86
|
+
const max = () => num(props.max, 100);
|
|
87
|
+
|
|
88
|
+
// Lift the position into the facade and drive Slider CONTROLLED so the host can read
|
|
89
|
+
// it (`el.value` / `:host([value])`) and set it after mount. Seed from the `value`
|
|
90
|
+
// property/attribute present on mount, falling back to the midpoint — HTML's own rule
|
|
91
|
+
// for a range with no value. kai-checkbox / kai-radio-group's structure, deliberately.
|
|
92
|
+
const [value, setValue] = createSignal(
|
|
93
|
+
props.value != null
|
|
94
|
+
? num(props.value, (min() + max()) / 2)
|
|
95
|
+
: num(element.getAttribute('value'), (min() + max()) / 2),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Coerce anything arriving through the `value` setter (a JS assignment, or the
|
|
99
|
+
// write-back `attributeChangedCallback` fires when the reflect effect below writes the
|
|
100
|
+
// attribute) to a number, falling back to the live attribute when nullish so the
|
|
101
|
+
// write-back equals the signal and the guard absorbs it — no attr⇄prop feedback loop.
|
|
102
|
+
const coerce = (v: unknown): number =>
|
|
103
|
+
v == null ? num(element.getAttribute('value'), untrack(value)) : num(v, untrack(value));
|
|
104
|
+
|
|
105
|
+
// Apply a new value and fire once (the user path). No-op while disabled.
|
|
106
|
+
const apply = (next: number, type: 'kai-input' | 'kai-change') => {
|
|
107
|
+
if (flag('disabled')) return;
|
|
108
|
+
// kai-change fires on commit EVEN IF the value equals the last one this element
|
|
109
|
+
// reported, because "you let go here" is information the host cannot derive; the
|
|
110
|
+
// equality guard applies to the per-step stream only.
|
|
111
|
+
if (type === 'kai-input' && untrack(value) === next) return;
|
|
112
|
+
setValue(next);
|
|
113
|
+
dispatch(type, { value: next });
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Reads return LIVE state; host writes drive it WITHOUT firing an event — the host
|
|
117
|
+
// already knows what it set. The equality guard kills the reflect write-back.
|
|
118
|
+
Object.defineProperty(element, 'value', {
|
|
119
|
+
get: () => value(),
|
|
120
|
+
set: (v: unknown) => { const next = coerce(v); if (untrack(value) !== next) setValue(next); },
|
|
121
|
+
configurable: true,
|
|
122
|
+
enumerable: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Reflect internal value → the `[value]` host attribute (for `:host([value])`).
|
|
126
|
+
createEffect(() => {
|
|
127
|
+
const v = String(value());
|
|
128
|
+
if (element.getAttribute('value') !== v) element.setAttribute('value', v);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expose({
|
|
132
|
+
/** Focus the inner range input (the host element can't reach it). */
|
|
133
|
+
focus: (options?: FocusOptions) =>
|
|
134
|
+
element.shadowRoot?.querySelector<HTMLInputElement>('input[type="range"]')?.focus(options),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// `step` arrives as a string when it came from an attribute. Resolve the one literal
|
|
138
|
+
// the spec allows (`any`, continuous) and treat everything else as a number.
|
|
139
|
+
const step = (): number | 'any' | undefined => {
|
|
140
|
+
const raw = props.step;
|
|
141
|
+
if (raw == null) return undefined;
|
|
142
|
+
if (String(raw) === 'any') return 'any';
|
|
143
|
+
const n = Number(raw);
|
|
144
|
+
return Number.isFinite(n) ? n : undefined;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// `valueLabel` arrives either as a bare attribute (the boolean half) or as a property
|
|
148
|
+
// holding a formatter (the half an attribute cannot carry). `flag` handles the first,
|
|
149
|
+
// a typeof check the second.
|
|
150
|
+
const valueLabel = (): boolean | ((v: number) => string) => {
|
|
151
|
+
const raw = props.valueLabel;
|
|
152
|
+
if (typeof raw === 'function') return raw as (v: number) => string;
|
|
153
|
+
return flag('valueLabel');
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Base sets `:host{display:block}`, which is right for a full-width track.
|
|
157
|
+
return (
|
|
158
|
+
<Slider
|
|
159
|
+
min={min()}
|
|
160
|
+
max={max()}
|
|
161
|
+
step={step()}
|
|
162
|
+
value={value()}
|
|
163
|
+
disabled={flag('disabled')}
|
|
164
|
+
aria-label={props.label as string | undefined}
|
|
165
|
+
name={props.name as string | undefined}
|
|
166
|
+
valueLabel={valueLabel()}
|
|
167
|
+
onInput={(e) => apply(e.currentTarget.valueAsNumber, 'kai-input')}
|
|
168
|
+
onChange={(e) => apply(e.currentTarget.valueAsNumber, 'kai-change')}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
});
|
package/src/elements/slots.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Composition slots for `kai-*` elements. A slot is a named region a consumer
|
|
3
3
|
* fills with their own markup. This registry is the SINGLE SOURCE OF TRUTH:
|
|
4
4
|
* the facade derives its detection from it (and, later, docs are generated
|
|
5
|
-
* from it).
|
|
5
|
+
* from it).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/** `inject` = additive (the built-in region still renders, your markup is added
|