@kitn.ai/ui 0.16.0 → 0.18.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 +55 -17
- package/dist/components/artifact.d.ts +39 -1
- package/dist/components/attachment-types.d.ts +12 -0
- package/dist/components/attachments.d.ts +2 -10
- package/dist/components/card.d.ts +27 -0
- package/dist/components/chain-of-thought.d.ts +78 -2
- package/dist/components/chat-scope-picker.d.ts +7 -0
- package/dist/components/chat-thread.d.ts +39 -16
- package/dist/components/choice-card.d.ts +27 -0
- package/dist/components/coachmark.d.ts +49 -0
- package/dist/components/composer-dom.d.ts +35 -0
- package/dist/components/composer-highlight.d.ts +48 -0
- package/dist/components/composer-history.d.ts +34 -0
- package/dist/components/composer.d.ts +86 -0
- package/dist/components/confirm-card.d.ts +17 -0
- package/dist/components/conversation-item.d.ts +9 -0
- package/dist/components/conversation-list.d.ts +36 -1
- package/dist/components/dismissed-stub.d.ts +22 -0
- package/dist/components/file-tree.d.ts +15 -0
- package/dist/components/form.d.ts +34 -0
- package/dist/components/markdown.d.ts +3 -0
- package/dist/components/message.d.ts +71 -2
- package/dist/components/model-switcher.d.ts +7 -0
- package/dist/components/prompt-input.d.ts +13 -4
- package/dist/components/prompt-suggestion.d.ts +9 -1
- package/dist/components/reasoning.d.ts +14 -1
- package/dist/components/response-compare-types.d.ts +66 -0
- package/dist/components/response-compare.d.ts +65 -0
- package/dist/components/screen.d.ts +46 -0
- package/dist/components/tasks-card.d.ts +50 -1
- package/dist/components/toast.d.ts +58 -0
- package/dist/components/tool-types.d.ts +10 -0
- package/dist/components/tool.d.ts +8 -8
- package/dist/components/use-card-resolution.d.ts +10 -6
- package/dist/components/voice-input.d.ts +27 -0
- package/dist/components/voice-output.d.ts +33 -0
- package/dist/core-C8fzo39E.js +12 -0
- package/dist/custom-elements.json +8472 -1691
- package/dist/elements/agent-card.d.ts +1 -0
- package/dist/elements/agent-card.js +1 -0
- package/dist/elements/artifact.js +1 -0
- package/dist/elements/attachments.js +1 -0
- package/dist/elements/autoloader.d.ts +2 -0
- package/dist/elements/autoloader.js +1 -0
- package/dist/elements/avatar.d.ts +1 -0
- package/dist/elements/avatar.js +1 -0
- package/dist/elements/badge.d.ts +1 -0
- package/dist/elements/badge.js +1 -0
- package/dist/elements/button.d.ts +1 -0
- package/dist/elements/button.js +1 -0
- package/dist/elements/card.js +1 -0
- package/dist/elements/cards.d.ts +1 -0
- package/dist/elements/cards.js +1 -0
- package/dist/elements/chain-of-thought.d.ts +0 -12
- package/dist/elements/chain-of-thought.js +1 -0
- package/dist/elements/chat-scope-picker.js +1 -0
- package/dist/elements/chat-types.d.ts +8 -2
- package/dist/elements/chat-workspace.js +1 -0
- package/dist/elements/chat.js +1 -0
- package/dist/elements/checkpoint.js +1 -0
- package/dist/elements/choice.js +1 -0
- package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
- package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
- package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
- package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
- package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
- package/dist/elements/chunks/bash-InADTalH.js +1 -0
- package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
- package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
- package/dist/elements/chunks/card-routing-C986KuUA.js +1 -0
- package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
- package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
- package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
- package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
- package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
- package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
- package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
- package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
- package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
- package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
- package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
- package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
- package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
- package/dist/elements/chunks/core-AYMC6_lb.js +12 -0
- package/dist/elements/chunks/css-M7EaDHN_.js +1 -0
- package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
- package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
- package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
- package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
- package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
- package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
- package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +141 -0
- package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
- package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
- package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
- package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
- package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +1 -0
- package/dist/elements/chunks/github-light-JYsPkUQd.js +1 -0
- package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
- package/dist/elements/chunks/html-CPZ3oZQ7.js +1 -0
- package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
- package/dist/elements/chunks/index-BCRhi84a.js +1 -0
- package/dist/elements/chunks/info-B_toFS0l.js +1 -0
- package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
- package/dist/elements/chunks/javascript-C25yR2R2.js +1 -0
- package/dist/elements/chunks/json-DxJze_jm.js +1 -0
- package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
- package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
- package/dist/elements/chunks/loader-q6MamGus.js +1 -0
- package/dist/elements/chunks/markdown-DBrcqq4S.js +64 -0
- package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
- package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
- package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
- package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
- package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
- package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
- package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
- package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
- package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
- package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
- package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
- package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
- package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
- package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
- package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
- package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
- package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
- package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
- package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
- package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
- package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
- package/dist/elements/chunks/svelte--5p79yCD.js +1 -0
- package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
- package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
- package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
- package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
- package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
- package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
- package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
- package/dist/elements/chunks/tsx-B8rCNbgL.js +1 -0
- package/dist/elements/chunks/typescript-RycA9KXf.js +1 -0
- package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
- package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
- package/dist/elements/chunks/vue-BmIZj4XD.js +1 -0
- package/dist/elements/chunks/x-C1qtndxn.js +1 -0
- package/dist/elements/coachmark.d.ts +1 -0
- package/dist/elements/coachmark.js +1 -0
- package/dist/elements/code-block.js +1 -0
- package/dist/elements/command.d.ts +1 -0
- package/dist/elements/command.js +1 -0
- package/dist/elements/compare.d.ts +1 -0
- package/dist/elements/compare.js +1 -0
- package/dist/elements/composer.d.ts +1 -0
- package/dist/elements/composer.js +1 -0
- package/dist/elements/confirm-card.js +1 -0
- package/dist/elements/context-meter.js +1 -0
- package/dist/elements/conversation-list.d.ts +1 -11
- package/dist/elements/conversation-list.js +1 -0
- package/dist/elements/default-input.d.ts +20 -9
- package/dist/elements/define.d.ts +11 -0
- package/dist/elements/dialog.d.ts +1 -0
- package/dist/elements/dialog.js +1 -0
- package/dist/elements/disclosure.d.ts +37 -0
- package/dist/elements/editable-label.d.ts +1 -0
- package/dist/elements/editable-label.js +1 -0
- package/dist/elements/embed.js +1 -0
- package/dist/elements/empty.js +1 -0
- package/dist/elements/feedback-bar.js +1 -0
- package/dist/elements/file-tree.js +1 -0
- package/dist/elements/file-upload.js +1 -0
- package/dist/elements/form.js +1 -0
- package/dist/elements/hover-card.d.ts +1 -0
- package/dist/elements/hover-card.js +1 -0
- package/dist/elements/icon.d.ts +1 -0
- package/dist/elements/icon.js +1 -0
- package/dist/elements/image.js +1 -0
- package/dist/elements/input.d.ts +1 -0
- package/dist/elements/input.js +1 -0
- package/dist/elements/kbd.d.ts +1 -0
- package/dist/elements/kbd.js +1 -0
- package/dist/elements/link-preview.js +1 -0
- package/dist/elements/loader.js +1 -0
- package/dist/elements/markdown.js +1 -0
- package/dist/elements/menu.d.ts +1 -0
- package/dist/elements/menu.js +1 -0
- package/dist/elements/message-skills.d.ts +0 -16
- package/dist/elements/message-skills.js +1 -0
- package/dist/elements/message.js +1 -0
- package/dist/elements/model-switcher.d.ts +1 -11
- package/dist/elements/model-switcher.js +1 -0
- package/dist/elements/nav.d.ts +1 -0
- package/dist/elements/nav.js +1 -0
- package/dist/elements/notice.d.ts +1 -0
- package/dist/elements/notice.js +1 -0
- package/dist/elements/pane-group.d.ts +1 -0
- package/dist/elements/pane-group.js +1 -0
- package/dist/elements/pane.d.ts +1 -0
- package/dist/elements/pane.js +1 -0
- package/dist/elements/popover.js +1 -0
- package/dist/elements/progress-bar.d.ts +1 -0
- package/dist/elements/progress-bar.js +1 -0
- package/dist/elements/prompt-dock.d.ts +1 -0
- package/dist/elements/prompt-dock.js +1 -0
- package/dist/elements/prompt-input.d.ts +1 -9
- package/dist/elements/prompt-input.js +1 -0
- package/dist/elements/prompt-suggestions.d.ts +0 -6
- package/dist/elements/prompt-suggestions.js +1 -0
- package/dist/elements/reasoning.js +1 -0
- package/dist/elements/register.d.ts +10 -0
- package/dist/elements/remote.js +1 -0
- package/dist/elements/resizable.d.ts +1 -17
- package/dist/elements/resizable.js +1 -0
- package/dist/elements/response-stream.js +14 -0
- package/dist/elements/screen.d.ts +1 -0
- package/dist/elements/screen.js +1 -0
- package/dist/elements/scroll-area.d.ts +1 -0
- package/dist/elements/scroll-area.js +1 -0
- package/dist/elements/scroll-button.js +1 -0
- package/dist/elements/search.d.ts +1 -0
- package/dist/elements/search.js +1 -0
- package/dist/elements/segmented.d.ts +1 -0
- package/dist/elements/segmented.js +1 -0
- package/dist/elements/separator.d.ts +1 -0
- package/dist/elements/separator.js +1 -0
- package/dist/elements/setting-item.d.ts +1 -0
- package/dist/elements/setting-item.js +1 -0
- package/dist/elements/settings-group.d.ts +1 -0
- package/dist/elements/settings-group.js +1 -0
- package/dist/elements/skeleton.d.ts +1 -0
- package/dist/elements/skeleton.js +1 -0
- package/dist/elements/slots.d.ts +176 -0
- package/dist/elements/source.d.ts +0 -17
- package/dist/elements/source.js +1 -0
- package/dist/elements/status.d.ts +1 -0
- package/dist/elements/status.js +1 -0
- package/dist/elements/switch.js +1 -0
- package/dist/elements/tabs.d.ts +1 -0
- package/dist/elements/tabs.js +1 -0
- package/dist/elements/tasks.js +1 -0
- package/dist/elements/text-shimmer.js +1 -0
- package/dist/elements/thinking-bar.js +1 -0
- package/dist/elements/toast.d.ts +1 -0
- package/dist/elements/toast.js +1 -0
- package/dist/elements/tool.js +1 -0
- package/dist/elements/tooltip.d.ts +1 -0
- package/dist/elements/tooltip.js +1 -0
- package/dist/elements/voice-input.js +1 -0
- package/dist/elements/voice-output.d.ts +1 -0
- package/dist/elements/voice-output.js +1 -0
- package/dist/elements.d.ts +772 -61
- package/dist/engine-javascript-C1x7zo1_.js +141 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +14405 -9810
- package/dist/kai.es.js +1 -0
- package/dist/llms/llms-full.txt +1234 -107
- package/dist/llms/llms.txt +4 -4
- package/dist/mcp.es.js +217 -6
- package/dist/primitives/card-contract.d.ts +20 -4
- package/dist/primitives/card-recovery.d.ts +55 -0
- package/dist/primitives/composer-model.d.ts +22 -0
- package/dist/primitives/composer-triggers.d.ts +19 -0
- package/dist/primitives/create-kai-chat.d.ts +38 -0
- package/dist/primitives/message-feedback.d.ts +35 -0
- package/dist/primitives/toast-store.d.ts +118 -0
- package/dist/primitives/use-speech-recognition.d.ts +26 -0
- package/dist/react/index.d.ts +1166 -98
- package/dist/react/runtime.d.ts +9 -2
- package/dist/react/use-kai-chat.d.ts +41 -0
- package/dist/react.js +575 -186
- package/dist/register-impl-CYWGkgbI.js +141 -0
- package/dist/schemas/choice.schema.json +5 -0
- package/dist/schemas/tasks.schema.json +7 -2
- package/dist/state/index.d.ts +4 -0
- package/dist/state/messages.d.ts +11 -0
- package/dist/state/stream.d.ts +22 -0
- package/dist/state/suggestions.d.ts +4 -0
- package/dist/state.js +117 -0
- package/dist/theme.tokens.css +87 -0
- package/dist/types.d.ts +4 -0
- package/dist/ui/agent-card.d.ts +61 -0
- package/dist/ui/button.d.ts +5 -2
- package/dist/ui/card.d.ts +61 -0
- package/dist/ui/collapsible.d.ts +15 -1
- package/dist/ui/command.d.ts +33 -0
- package/dist/ui/dialog.d.ts +42 -0
- package/dist/ui/dropdown.d.ts +95 -1
- package/dist/ui/editable-label.d.ts +26 -0
- package/dist/ui/hover-card.d.ts +13 -1
- package/dist/ui/icon.d.ts +18 -0
- package/dist/ui/input.d.ts +33 -0
- package/dist/ui/kbd.d.ts +21 -0
- package/dist/ui/nav.d.ts +62 -0
- package/dist/ui/notice.d.ts +31 -0
- package/dist/ui/overlay.d.ts +12 -0
- package/dist/ui/pane-grid.d.ts +58 -0
- package/dist/ui/pane-group.d.ts +75 -0
- package/dist/ui/pane.d.ts +78 -0
- package/dist/ui/popover.d.ts +11 -1
- package/dist/ui/progress-bar.d.ts +23 -0
- package/dist/ui/prompt-dock.d.ts +96 -0
- package/dist/ui/resizable.d.ts +12 -0
- package/dist/ui/scroll-area.d.ts +4 -0
- package/dist/ui/segmented.d.ts +28 -0
- package/dist/ui/settings-group.d.ts +32 -0
- package/dist/ui/skeleton.d.ts +12 -0
- package/dist/ui/stat.d.ts +16 -0
- package/dist/ui/status.d.ts +13 -0
- package/dist/ui/switch.d.ts +8 -1
- package/dist/ui/tabs.d.ts +35 -0
- package/dist/ui/tooltip.d.ts +20 -1
- package/frameworks/react/index.tsx +1100 -163
- package/frameworks/react/runtime.tsx +30 -1
- package/frameworks/react/use-kai-chat.tsx +87 -0
- package/llms-full.txt +1234 -107
- package/llms.txt +4 -4
- package/package.json +36 -12
- package/src/agent-tooling/mcp/manifest.ts +14 -0
- package/src/agent-tooling/mcp/tools/debug.ts +194 -6
- package/src/agent-tooling/mcp/tools/reference.ts +32 -0
- package/src/agent-tooling/mcp/tools/scaffold.ts +162 -1
- package/src/components/artifact.tsx +98 -13
- package/src/components/attachment-types.ts +13 -0
- package/src/components/attachments.tsx +4 -14
- package/src/components/card.tsx +109 -15
- package/src/components/chain-of-thought.tsx +210 -1
- package/src/components/chat-scope-picker.tsx +13 -3
- package/src/components/chat-thread.tsx +238 -137
- package/src/components/choice-card.tsx +136 -15
- package/src/components/coachmark.tsx +245 -0
- package/src/components/component-meta.json +921 -108
- package/src/components/composer-dom.ts +159 -0
- package/src/components/composer-highlight.ts +242 -0
- package/src/components/composer-history.ts +82 -0
- package/src/components/composer.tsx +979 -0
- package/src/components/confirm-card.tsx +69 -2
- package/src/components/conversation-item.tsx +69 -7
- package/src/components/conversation-list.tsx +134 -37
- package/src/components/dismissed-stub.tsx +80 -0
- package/src/components/file-tree.tsx +197 -47
- package/src/components/form-widgets.tsx +9 -7
- package/src/components/form.tsx +161 -20
- package/src/components/image.tsx +3 -5
- package/src/components/link-preview.tsx +5 -4
- package/src/components/markdown.tsx +5 -2
- package/src/components/message.tsx +174 -14
- package/src/components/model-switcher.tsx +19 -4
- package/src/components/prompt-input.tsx +46 -75
- package/src/components/prompt-suggestion.tsx +48 -16
- package/src/components/reasoning.tsx +29 -6
- package/src/components/response-compare-types.ts +127 -0
- package/src/components/response-compare.tsx +460 -0
- package/src/components/screen.tsx +176 -0
- package/src/components/tasks-card.tsx +374 -23
- package/src/components/toast.tsx +486 -0
- package/src/components/tool-types.ts +10 -0
- package/src/components/tool.tsx +22 -16
- package/src/components/use-card-resolution.ts +24 -8
- package/src/components/voice-input.tsx +102 -19
- package/src/components/voice-output.tsx +202 -0
- package/src/elements/agent-card.tsx +67 -0
- package/src/elements/artifact.tsx +53 -4
- package/src/elements/attachments.tsx +1 -0
- package/src/elements/autoloader.ts +89 -0
- package/src/elements/avatar.tsx +33 -0
- package/src/elements/badge.tsx +32 -0
- package/src/elements/button.tsx +126 -0
- package/src/elements/card-media.jpg +0 -0
- package/src/elements/card.tsx +124 -31
- package/src/elements/cards.tsx +81 -7
- package/src/elements/chain-of-thought.tsx +77 -32
- package/src/elements/chat-scope-picker.tsx +35 -8
- package/src/elements/chat-types.ts +9 -2
- package/src/elements/chat-workspace.tsx +157 -43
- package/src/elements/chat.tsx +49 -25
- package/src/elements/choice.tsx +71 -19
- package/src/elements/coachmark.tsx +90 -0
- package/src/elements/command.tsx +209 -0
- package/src/elements/compare.tsx +110 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +151 -0
- package/src/elements/confirm-card.tsx +36 -11
- package/src/elements/conversation-list.tsx +80 -11
- package/src/elements/default-input.tsx +75 -53
- package/src/elements/define.tsx +47 -6
- package/src/elements/dialog.tsx +98 -0
- package/src/elements/disclosure.ts +73 -0
- package/src/elements/editable-label.tsx +125 -0
- package/src/elements/element-manifest.json +310 -0
- package/src/elements/element-meta.json +5954 -1605
- package/src/elements/element-types.d.ts +771 -60
- package/src/elements/file-tree.tsx +12 -2
- package/src/elements/file-upload.tsx +1 -1
- package/src/elements/form.tsx +54 -11
- package/src/elements/hover-card.tsx +80 -0
- package/src/elements/icon-names.json +48 -0
- package/src/elements/icon.tsx +41 -0
- package/src/elements/input.tsx +203 -0
- package/src/elements/kbd.tsx +45 -0
- package/src/elements/menu.tsx +217 -0
- package/src/elements/message.tsx +84 -55
- package/src/elements/model-switcher.tsx +27 -1
- package/src/elements/nav.tsx +87 -0
- package/src/elements/notice.tsx +53 -0
- package/src/elements/pane-group.tsx +119 -0
- package/src/elements/pane.tsx +129 -0
- package/src/elements/popover.tsx +39 -17
- package/src/elements/progress-bar.tsx +39 -0
- package/src/elements/prompt-dock.tsx +81 -0
- package/src/elements/prompt-input.tsx +112 -63
- package/src/elements/prompt-suggestions.tsx +25 -9
- package/src/elements/reasoning.tsx +30 -9
- package/src/elements/register-impl.ts +41 -3
- package/src/elements/register.ts +20 -3
- package/src/elements/remote.tsx +4 -0
- package/src/elements/resizable.tsx +48 -11
- package/src/elements/screen.tsx +90 -0
- package/src/elements/scroll-area.tsx +33 -0
- package/src/elements/search.tsx +180 -0
- package/src/elements/segmented.tsx +135 -0
- package/src/elements/separator.tsx +36 -0
- package/src/elements/setting-item.tsx +50 -0
- package/src/elements/settings-group.tsx +37 -0
- package/src/elements/skeleton.tsx +45 -0
- package/src/elements/slots.ts +607 -0
- package/src/elements/source.tsx +13 -6
- package/src/elements/status.tsx +42 -0
- package/src/elements/styles.css +19 -0
- package/src/elements/switch.tsx +89 -14
- package/src/elements/tabs.tsx +95 -0
- package/src/elements/tasks.tsx +70 -14
- package/src/elements/toast.tsx +89 -0
- package/src/elements/tool.tsx +43 -9
- package/src/elements/tooltip.tsx +85 -0
- package/src/elements/video-poster.jpg +0 -0
- package/src/elements/voice-input.tsx +66 -16
- package/src/elements/voice-output.tsx +69 -0
- package/src/index.ts +35 -2
- package/src/primitives/card-contract.ts +14 -5
- package/src/primitives/card-recovery.ts +149 -0
- package/src/primitives/card-routing.ts +3 -0
- package/src/primitives/card-schemas/choice.schema.json +5 -0
- package/src/primitives/card-schemas/tasks.schema.json +7 -2
- package/src/primitives/composer-model.ts +49 -0
- package/src/primitives/composer-triggers.ts +35 -0
- package/src/primitives/create-kai-chat.ts +66 -0
- package/src/primitives/message-feedback.ts +123 -0
- package/src/primitives/toast-store.ts +276 -0
- package/src/primitives/use-speech-recognition.ts +135 -0
- package/src/state/index.ts +6 -0
- package/src/state/messages.ts +36 -0
- package/src/state/stream.ts +92 -0
- package/src/state/suggestions.ts +9 -0
- package/src/types.ts +4 -0
- package/src/ui/agent-card.tsx +212 -0
- package/src/ui/button.tsx +16 -5
- package/src/ui/card.tsx +245 -0
- package/src/ui/collapsible.tsx +30 -4
- package/src/ui/command.tsx +99 -0
- package/src/ui/dialog.tsx +217 -0
- package/src/ui/dropdown.tsx +375 -13
- package/src/ui/editable-label.tsx +112 -0
- package/src/ui/hover-card.tsx +28 -5
- package/src/ui/icon.tsx +110 -0
- package/src/ui/input.tsx +132 -0
- package/src/ui/kbd.tsx +118 -0
- package/src/ui/nav.tsx +282 -0
- package/src/ui/notice.tsx +84 -0
- package/src/ui/overlay.tsx +108 -2
- package/src/ui/pane-grid.tsx +116 -0
- package/src/ui/pane-group.tsx +280 -0
- package/src/ui/pane.tsx +193 -0
- package/src/ui/popover.tsx +16 -2
- package/src/ui/progress-bar.tsx +83 -0
- package/src/ui/prompt-dock.tsx +145 -0
- package/src/ui/resizable.tsx +69 -1
- package/src/ui/scroll-area.tsx +14 -3
- package/src/ui/segmented.tsx +109 -0
- package/src/ui/settings-group.tsx +67 -0
- package/src/ui/skeleton.tsx +62 -5
- package/src/ui/stat.tsx +41 -0
- package/src/ui/status.tsx +48 -0
- package/src/ui/switch.tsx +49 -23
- package/src/ui/tabs.tsx +168 -0
- package/src/ui/tooltip.tsx +57 -7
- package/theme.css +113 -0
- package/dist/components/slash-command.d.ts +0 -15
- package/dist/kitn-chat.es.js +0 -1
- package/dist/register-impl-wCsFPoh9.js +0 -77
- package/dist/register-ujhr1nBS.js +0 -1
- package/src/components/slash-command.tsx +0 -232
- package/src/elements/framework-usage.json +0 -563
- /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
- /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
|
@@ -8,17 +8,20 @@ import {
|
|
|
8
8
|
createMemo,
|
|
9
9
|
createEffect,
|
|
10
10
|
on,
|
|
11
|
+
onMount,
|
|
11
12
|
ErrorBoundary,
|
|
12
13
|
createUniqueId,
|
|
13
14
|
} from 'solid-js';
|
|
14
15
|
import { cn } from '../utils/cn';
|
|
15
16
|
import { Button } from '../ui/button';
|
|
17
|
+
import { ProgressBar } from '../ui/progress-bar';
|
|
16
18
|
import { Card } from './card';
|
|
19
|
+
import { DismissedStub } from './dismissed-stub';
|
|
17
20
|
import type { CardEnvelope, CardEvent, CardHost, CardResolution } from '../primitives/card-contract';
|
|
18
21
|
import { useCardResolution } from './use-card-resolution';
|
|
19
22
|
import { emitCardEvent } from '../primitives/card-routing';
|
|
20
23
|
import { useCardHost } from '../primitives/card-host';
|
|
21
|
-
import { Check } from 'lucide-solid';
|
|
24
|
+
import { Check, Circle, CircleCheck, X } from 'lucide-solid';
|
|
22
25
|
|
|
23
26
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
27
|
// Types (tasks.schema.json) — see src/primitives/card-schemas/tasks.schema.json
|
|
@@ -33,7 +36,15 @@ export interface TasksTask {
|
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export interface TasksCardData {
|
|
36
|
-
|
|
39
|
+
/**
|
|
40
|
+
* `select` (default) = checkbox rows + a confirm button that emits the contract
|
|
41
|
+
* `submit`. `progress` = an onboarding/checklist look: a header `done / total`
|
|
42
|
+
* count, circular indicators, per-item title + muted description, and NO confirm
|
|
43
|
+
* button (checking a row is itself the terminal action). Both share the same
|
|
44
|
+
* selection model (toggle by id, the `max` gate, `kai-value-change`); `progress`
|
|
45
|
+
* is purely a presentational variant.
|
|
46
|
+
*/
|
|
47
|
+
mode?: 'select' | 'progress';
|
|
37
48
|
heading?: string;
|
|
38
49
|
tasks: TasksTask[]; // >=1
|
|
39
50
|
selectAll?: boolean;
|
|
@@ -41,6 +52,7 @@ export interface TasksCardData {
|
|
|
41
52
|
allowEmpty?: boolean;
|
|
42
53
|
min?: number;
|
|
43
54
|
max?: number;
|
|
55
|
+
dismissible?: boolean; // show a close affordance that emits `dismiss`
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
export interface TasksCardResult {
|
|
@@ -121,6 +133,16 @@ export function showSelectAll(data: TasksCardData, tasks: TasksTask[]): boolean
|
|
|
121
133
|
return true;
|
|
122
134
|
}
|
|
123
135
|
|
|
136
|
+
/** Whether the card is in the onboarding-checklist `progress` look (no confirm). */
|
|
137
|
+
export function isProgressMode(data: TasksCardData): boolean {
|
|
138
|
+
return data.mode === 'progress';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** The header progress count (`done` checked / `total` rows) for `progress` mode. */
|
|
142
|
+
export function progressCount(tasks: TasksTask[], selected: Set<string>): { done: number; total: number } {
|
|
143
|
+
return { done: tasks.filter((t) => selected.has(t.id)).length, total: tasks.length };
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
/** Whether confirm is enabled for the current selection count. */
|
|
125
147
|
export function canConfirm(data: TasksCardData, count: number): boolean {
|
|
126
148
|
const min = data.min ?? (data.allowEmpty ? 0 : 1);
|
|
@@ -147,6 +169,24 @@ export function confirmReason(data: TasksCardData, count: number): string | unde
|
|
|
147
169
|
// The <TasksCard> component.
|
|
148
170
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
149
171
|
|
|
172
|
+
/** Imperative handle exposed via `controllerRef` — surfaces the tasks card's latent
|
|
173
|
+
* selection model (set the checked ids, toggle one, confirm, focus the group,
|
|
174
|
+
* dismiss/reopen) so the `<kai-tasks>` facade can forward them as instance methods. */
|
|
175
|
+
export interface TasksCardController {
|
|
176
|
+
/** Set the checked ids (local-only, no emit), respecting disabled/max. No arg = select all toggleable rows. */
|
|
177
|
+
select(taskIds?: string[]): void;
|
|
178
|
+
/** Toggle one task by id, honoring the max gate. */
|
|
179
|
+
toggle(taskId: string, checked?: boolean): void;
|
|
180
|
+
/** Confirm the current selection (only when allowed) — emits `submit` + resolves. */
|
|
181
|
+
send(): void;
|
|
182
|
+
/** Focus the task group (select-all checkbox if shown, else the first row). */
|
|
183
|
+
focus(options?: FocusOptions): void;
|
|
184
|
+
/** Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). */
|
|
185
|
+
dismiss(): void;
|
|
186
|
+
/** Re-open a dismissed card from its stub (emit `reopen`). */
|
|
187
|
+
reopen(): void;
|
|
188
|
+
}
|
|
189
|
+
|
|
150
190
|
export interface TasksCardProps {
|
|
151
191
|
/** The tasks definition (CardEnvelope.data). */
|
|
152
192
|
data?: TasksCardData;
|
|
@@ -162,6 +202,20 @@ export interface TasksCardProps {
|
|
|
162
202
|
class?: string;
|
|
163
203
|
/** When set, render the chromed read-only summary instead of the interactive controls. */
|
|
164
204
|
resolution?: CardResolution;
|
|
205
|
+
/** Controlled selection (task ids) — when set, this wins over internal state. */
|
|
206
|
+
value?: string[];
|
|
207
|
+
/** Uncontrolled initial selection (task ids), overlaying per-task `checked`. */
|
|
208
|
+
defaultValue?: string[];
|
|
209
|
+
/** Freeze the whole list + Confirm. */
|
|
210
|
+
disabled?: boolean;
|
|
211
|
+
/** Display-only: rows can't be toggled and show the default cursor (no pointer,
|
|
212
|
+
* no hover background, no focus ring). Keeps the visual content as-is — this only
|
|
213
|
+
* drops the interactive affordances + a11y exposure. */
|
|
214
|
+
readonly?: boolean;
|
|
215
|
+
/** Fires on every selection change with the selected ids (distinct from submit). */
|
|
216
|
+
onValueChange?: (payload: { value: string[] }) => void;
|
|
217
|
+
/** Receive the imperative controller once mounted. */
|
|
218
|
+
controllerRef?: (controller: TasksCardController) => void;
|
|
165
219
|
}
|
|
166
220
|
|
|
167
221
|
const DEFAULT_DATA: TasksCardData = { tasks: [] };
|
|
@@ -175,7 +229,10 @@ const DEFAULT_DATA: TasksCardData = { tasks: [] };
|
|
|
175
229
|
*/
|
|
176
230
|
export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
177
231
|
const merged = mergeProps({ cardId: 'kai-tasks' }, props);
|
|
178
|
-
const [local] = splitProps(merged, [
|
|
232
|
+
const [local] = splitProps(merged, [
|
|
233
|
+
'data', 'cardId', 'heading', 'host', 'hostElement', 'class', 'resolution',
|
|
234
|
+
'value', 'defaultValue', 'disabled', 'readonly', 'onValueChange', 'controllerRef',
|
|
235
|
+
]);
|
|
179
236
|
|
|
180
237
|
const ctxHost = useCardHost();
|
|
181
238
|
const uid = createUniqueId();
|
|
@@ -196,16 +253,37 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
196
253
|
|
|
197
254
|
const res = useCardResolution({ prop: () => local.resolution, data: () => local.data });
|
|
198
255
|
|
|
199
|
-
//
|
|
256
|
+
// Only ids that exist in the current task list (drop unknown ids defensively).
|
|
257
|
+
const validIds = (ids: string[]): string[] => {
|
|
258
|
+
const known = new Set(tasks().map((t) => t.id));
|
|
259
|
+
return ids.filter((id) => known.has(id));
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Seed selection from `value` (controlled) > `defaultValue` > per-task `checked`,
|
|
263
|
+
// when a NEW definition arrives.
|
|
200
264
|
createEffect(
|
|
201
265
|
on(
|
|
202
266
|
() => local.data,
|
|
203
267
|
() => {
|
|
204
|
-
|
|
268
|
+
const seedIds = local.value ?? local.defaultValue ?? initialSelected(tasks());
|
|
269
|
+
setSelected(new Set(validIds(seedIds)));
|
|
205
270
|
},
|
|
206
271
|
),
|
|
207
272
|
);
|
|
208
273
|
|
|
274
|
+
// Controlled selection: when the consumer drives `value`, mirror it into the set
|
|
275
|
+
// (the controlled prop wins). Deferred so mount's seed runs first.
|
|
276
|
+
createEffect(on(() => local.value, (v) => {
|
|
277
|
+
if (!v) return;
|
|
278
|
+
setSelected(new Set(validIds(v)));
|
|
279
|
+
}, { defer: true }));
|
|
280
|
+
|
|
281
|
+
// Fire the live change signal whenever the selection set changes (distinct from
|
|
282
|
+
// the terminal submit). Deferred so the initial seed doesn't emit.
|
|
283
|
+
createEffect(on(selected, (s) => {
|
|
284
|
+
local.onValueChange?.({ value: selectedInOrder(tasks(), s) });
|
|
285
|
+
}, { defer: true }));
|
|
286
|
+
|
|
209
287
|
// ready / error lifecycle emits.
|
|
210
288
|
createEffect(
|
|
211
289
|
on(valid, (ok) => {
|
|
@@ -214,28 +292,41 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
214
292
|
}),
|
|
215
293
|
);
|
|
216
294
|
|
|
295
|
+
const groupDisabled = (): boolean => local.disabled === true;
|
|
296
|
+
// Display-only: block all toggling/confirm and drop the interactive affordances,
|
|
297
|
+
// without the dimmed/`disabled` look.
|
|
298
|
+
const readOnly = (): boolean => local.readonly === true;
|
|
299
|
+
|
|
217
300
|
const count = createMemo(() => selected().size);
|
|
301
|
+
// `progress` mode = the onboarding-checklist look: a header `done / total`
|
|
302
|
+
// count, circular indicators, no confirm button. Same selection model.
|
|
303
|
+
const progress = createMemo(() => isProgressMode(data()));
|
|
304
|
+
const progressN = createMemo(() => progressCount(tasks(), selected()));
|
|
218
305
|
const confirmLabel = () => data().confirmLabel ?? 'Confirm';
|
|
219
306
|
const masterState = createMemo(() => selectAllState(tasks(), selected()));
|
|
220
307
|
const showMaster = createMemo(() => showSelectAll(data(), tasks()));
|
|
221
308
|
const reason = createMemo(() => confirmReason(data(), count()));
|
|
222
|
-
const confirmEnabled = createMemo(() => canConfirm(data(), count()) && !res.isResolved());
|
|
309
|
+
const confirmEnabled = createMemo(() => canConfirm(data(), count()) && !res.isResolved() && !groupDisabled() && !readOnly());
|
|
223
310
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const next = new Set(selected());
|
|
311
|
+
// Apply one id to a selection set, honoring the max gate (mutates+returns `next`).
|
|
312
|
+
const applyToggle = (next: Set<string>, id: string, on: boolean): Set<string> => {
|
|
227
313
|
if (on) {
|
|
228
314
|
// Respect max: block adding past max.
|
|
229
|
-
if (isMaxReached(data(), next.size) && !next.has(id)) return;
|
|
315
|
+
if (isMaxReached(data(), next.size) && !next.has(id)) return next;
|
|
230
316
|
next.add(id);
|
|
231
317
|
} else {
|
|
232
318
|
next.delete(id);
|
|
233
319
|
}
|
|
234
|
-
|
|
320
|
+
return next;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const toggle = (id: string, on: boolean): void => {
|
|
324
|
+
if (res.isResolved() || groupDisabled() || readOnly()) return;
|
|
325
|
+
setSelected(applyToggle(new Set(selected()), id, on));
|
|
235
326
|
};
|
|
236
327
|
|
|
237
328
|
const toggleAll = (on: boolean): void => {
|
|
238
|
-
if (res.isResolved()) return;
|
|
329
|
+
if (res.isResolved() || groupDisabled() || readOnly()) return;
|
|
239
330
|
const next = new Set(selected());
|
|
240
331
|
for (const id of toggleableIds(tasks())) {
|
|
241
332
|
if (on) next.add(id);
|
|
@@ -251,11 +342,58 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
251
342
|
res.setLocal({ kind: 'submit', data: result });
|
|
252
343
|
};
|
|
253
344
|
|
|
254
|
-
//
|
|
345
|
+
// Dismiss: emit `dismiss` AND optimistically flip to a `dismissed` resolution so
|
|
346
|
+
// the card collapses to its re-openable stub immediately.
|
|
347
|
+
const onDismiss = (): void => {
|
|
348
|
+
if (res.isResolved()) return;
|
|
349
|
+
emit({ kind: 'dismiss', cardId: local.cardId });
|
|
350
|
+
res.setLocal({ kind: 'dismissed' });
|
|
351
|
+
};
|
|
352
|
+
const onReopen = (): void => emit({ kind: 'reopen', cardId: local.cardId });
|
|
353
|
+
|
|
354
|
+
// Imperative controller (Pattern C): hand the facade a handle over the tasks
|
|
355
|
+
// card's latent selection model. select sets the checked ids local-only (no
|
|
356
|
+
// submit); toggle drives one row; send confirms (same path as Confirm); focus
|
|
357
|
+
// targets the group; dismiss/reopen drive the stub.
|
|
358
|
+
onMount(() => {
|
|
359
|
+
local.controllerRef?.({
|
|
360
|
+
select: (taskIds) => {
|
|
361
|
+
if (res.isResolved() || groupDisabled() || readOnly()) return;
|
|
362
|
+
if (taskIds === undefined) { toggleAll(true); return; }
|
|
363
|
+
// Build the set fresh, honoring max + disabled per id (skip disabled rows).
|
|
364
|
+
const next = new Set<string>();
|
|
365
|
+
const toggleable = new Set(toggleableIds(tasks()));
|
|
366
|
+
for (const id of validIds(taskIds)) {
|
|
367
|
+
if (!toggleable.has(id)) continue; // skip per-task-disabled rows
|
|
368
|
+
applyToggle(next, id, true);
|
|
369
|
+
}
|
|
370
|
+
setSelected(next);
|
|
371
|
+
},
|
|
372
|
+
toggle: (taskId, checked) => {
|
|
373
|
+
// No explicit `checked` → flip the current state.
|
|
374
|
+
const on = checked ?? !selected().has(taskId);
|
|
375
|
+
toggle(taskId, on);
|
|
376
|
+
},
|
|
377
|
+
send: () => onConfirm(),
|
|
378
|
+
focus: (options) => {
|
|
379
|
+
const root = local.hostElement?.shadowRoot ?? document;
|
|
380
|
+
const group = root.querySelector<HTMLElement>('[role="group"]');
|
|
381
|
+
// Prefer the select-all checkbox (it's the first labelled input), else the
|
|
382
|
+
// first row's checkbox; fall back to the group container itself.
|
|
383
|
+
const firstInput = group?.querySelector<HTMLElement>('input[type="checkbox"]');
|
|
384
|
+
(firstInput ?? group)?.focus(options);
|
|
385
|
+
},
|
|
386
|
+
dismiss: () => onDismiss(),
|
|
387
|
+
reopen: () => onReopen(),
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Surface the resolved state for host styling. Only a `submit` resolution is the
|
|
392
|
+
// "submitted" state; a deferred `dismissed` (or `expired`) is not.
|
|
255
393
|
createEffect(() => {
|
|
256
394
|
const el = local.hostElement;
|
|
257
395
|
if (!el) return;
|
|
258
|
-
if (res.
|
|
396
|
+
if (res.resolution()?.kind === 'submit') el.setAttribute('data-kai-resolved', 'submitted');
|
|
259
397
|
else el.removeAttribute('data-kai-resolved');
|
|
260
398
|
});
|
|
261
399
|
|
|
@@ -271,6 +409,9 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
271
409
|
|
|
272
410
|
const reasonId = `kai-tl-reason-${uid}`;
|
|
273
411
|
const countId = `kai-tl-count-${uid}`;
|
|
412
|
+
const progressCountId = `kai-tl-progress-${uid}`;
|
|
413
|
+
const progressHeadingId = `kai-tl-heading-${uid}`;
|
|
414
|
+
const headingText = () => local.heading ?? local.data?.heading;
|
|
274
415
|
|
|
275
416
|
return (
|
|
276
417
|
<Show when={valid()} fallback={<Card heading={local.heading} errorMessage={errorMessage()} />}>
|
|
@@ -280,11 +421,33 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
280
421
|
return <Card heading={local.heading} errorMessage="The card failed to render." />;
|
|
281
422
|
}}
|
|
282
423
|
>
|
|
424
|
+
<Show
|
|
425
|
+
when={!res.isDeferred()}
|
|
426
|
+
fallback={
|
|
427
|
+
<DismissedStub type={TASKS_CARD_TYPE} title={local.heading ?? local.data?.heading} onReopen={onReopen} />
|
|
428
|
+
}
|
|
429
|
+
>
|
|
283
430
|
<Card
|
|
284
|
-
heading
|
|
431
|
+
// In `progress` mode the heading + count render as a custom in-body row
|
|
432
|
+
// (so the count can sit right-aligned beside the heading), so the Card
|
|
433
|
+
// chrome's own heading is suppressed.
|
|
434
|
+
heading={progress() ? undefined : headingText()}
|
|
285
435
|
actions={
|
|
286
|
-
|
|
436
|
+
// `progress` mode is confirm-less: checking a row IS the action.
|
|
437
|
+
// `readonly` is display-only, so there's no confirm/dismiss row either.
|
|
438
|
+
progress() || res.isResolved() || readOnly() ? undefined : (
|
|
287
439
|
<div class="flex w-full flex-wrap items-center justify-between gap-2">
|
|
440
|
+
<Show when={local.data?.dismissible === true}>
|
|
441
|
+
<Button
|
|
442
|
+
type="button"
|
|
443
|
+
variant="ghost"
|
|
444
|
+
size="icon-sm"
|
|
445
|
+
aria-label="Dismiss"
|
|
446
|
+
onClick={onDismiss}
|
|
447
|
+
>
|
|
448
|
+
<X size={16} aria-hidden="true" />
|
|
449
|
+
</Button>
|
|
450
|
+
</Show>
|
|
288
451
|
<span id={countId} aria-live="polite" class="text-xs text-muted-foreground">
|
|
289
452
|
{count()} selected
|
|
290
453
|
</span>
|
|
@@ -311,9 +474,31 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
311
474
|
when={!res.isResolved()}
|
|
312
475
|
fallback={<TasksResolved summary={resolvedSummary()!} optimistic={res.isOptimistic()} />}
|
|
313
476
|
>
|
|
477
|
+
<Show when={progress()}>
|
|
478
|
+
<ProgressChecklist
|
|
479
|
+
heading={headingText()}
|
|
480
|
+
headingId={progressHeadingId}
|
|
481
|
+
countId={progressCountId}
|
|
482
|
+
done={progressN().done}
|
|
483
|
+
total={progressN().total}
|
|
484
|
+
tasks={tasks()}
|
|
485
|
+
uid={uid}
|
|
486
|
+
isChecked={(id) => selected().has(id)}
|
|
487
|
+
isBlocked={(task) =>
|
|
488
|
+
groupDisabled() || task.disabled === true ||
|
|
489
|
+
(!selected().has(task.id) && isMaxReached(data(), count()))
|
|
490
|
+
}
|
|
491
|
+
onToggle={(id, on) => toggle(id, on)}
|
|
492
|
+
groupClass={local.class}
|
|
493
|
+
maxNote={data().max !== undefined ? data().max : undefined}
|
|
494
|
+
readonly={readOnly()}
|
|
495
|
+
/>
|
|
496
|
+
</Show>
|
|
497
|
+
<Show when={!progress()}>
|
|
314
498
|
<div
|
|
315
499
|
role="group"
|
|
316
500
|
aria-label={local.heading ?? local.data?.heading ?? 'Tasks'}
|
|
501
|
+
aria-readonly={readOnly() ? 'true' : undefined}
|
|
317
502
|
class={cn('flex flex-col', local.class)}
|
|
318
503
|
onKeyDown={(e) => {
|
|
319
504
|
// Enter anywhere in the card (off a checkbox) confirms when enabled.
|
|
@@ -330,16 +515,20 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
330
515
|
return (
|
|
331
516
|
<label
|
|
332
517
|
class={cn(
|
|
333
|
-
'flex
|
|
518
|
+
'flex items-center gap-3 px-3 py-2.5 text-sm font-medium transition-colors',
|
|
519
|
+
readOnly() ? 'cursor-default' : 'cursor-pointer',
|
|
334
520
|
masterState() === 'checked'
|
|
335
521
|
? 'bg-accent text-accent-foreground'
|
|
336
|
-
:
|
|
522
|
+
: readOnly()
|
|
523
|
+
? 'text-foreground'
|
|
524
|
+
: 'text-foreground hover:bg-muted/50',
|
|
337
525
|
)}
|
|
338
526
|
>
|
|
339
527
|
<input
|
|
340
528
|
type="checkbox"
|
|
341
529
|
class="kai-checkbox"
|
|
342
530
|
checked={masterState() === 'checked'}
|
|
531
|
+
disabled={groupDisabled() || readOnly()}
|
|
343
532
|
aria-checked={indeterminate() ? 'mixed' : masterState() === 'checked'}
|
|
344
533
|
ref={(el) => {
|
|
345
534
|
createEffect(() => {
|
|
@@ -358,15 +547,17 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
358
547
|
{(task) => {
|
|
359
548
|
const checked = () => selected().has(task.id);
|
|
360
549
|
const blocked = () =>
|
|
361
|
-
task.disabled || (!checked() && isMaxReached(data(), count()));
|
|
550
|
+
groupDisabled() || task.disabled || (!checked() && isMaxReached(data(), count()));
|
|
362
551
|
const descId = `kai-tl-desc-${uid}-${task.id}`;
|
|
363
552
|
return (
|
|
364
553
|
<label
|
|
365
554
|
class={cn(
|
|
366
555
|
'flex items-start gap-3 px-3 py-2.5 text-sm transition-colors',
|
|
367
|
-
|
|
368
|
-
? 'cursor-
|
|
369
|
-
:
|
|
556
|
+
readOnly()
|
|
557
|
+
? 'cursor-default'
|
|
558
|
+
: blocked()
|
|
559
|
+
? 'cursor-not-allowed opacity-60'
|
|
560
|
+
: 'cursor-pointer hover:bg-muted/50',
|
|
370
561
|
checked() && !blocked()
|
|
371
562
|
? 'bg-accent font-medium text-accent-foreground'
|
|
372
563
|
: 'text-foreground',
|
|
@@ -377,7 +568,7 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
377
568
|
type="checkbox"
|
|
378
569
|
class="kai-checkbox mt-0.5"
|
|
379
570
|
checked={checked()}
|
|
380
|
-
disabled={blocked()}
|
|
571
|
+
disabled={blocked() || readOnly()}
|
|
381
572
|
aria-disabled={blocked() ? 'true' : undefined}
|
|
382
573
|
aria-describedby={task.description ? descId : undefined}
|
|
383
574
|
onChange={(e) => toggle(task.id, e.currentTarget.checked)}
|
|
@@ -400,13 +591,173 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
|
|
|
400
591
|
<p class="pt-1 text-xs text-muted-foreground">Up to {data().max} selected.</p>
|
|
401
592
|
</Show>
|
|
402
593
|
</div>
|
|
594
|
+
</Show>
|
|
403
595
|
</Show>
|
|
404
596
|
</Card>
|
|
597
|
+
</Show>
|
|
405
598
|
</ErrorBoundary>
|
|
406
599
|
</Show>
|
|
407
600
|
);
|
|
408
601
|
}
|
|
409
602
|
|
|
603
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
604
|
+
// Onboarding-checklist (`mode: 'progress'`) presenter: a header `done / total`
|
|
605
|
+
// count + circular indicators + per-item title/description, no confirm button.
|
|
606
|
+
// Drives the same selection model, where toggling a row IS the action.
|
|
607
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
608
|
+
|
|
609
|
+
function ProgressChecklist(props: {
|
|
610
|
+
heading?: string;
|
|
611
|
+
headingId: string;
|
|
612
|
+
countId: string;
|
|
613
|
+
done: number;
|
|
614
|
+
total: number;
|
|
615
|
+
tasks: TasksTask[];
|
|
616
|
+
uid: string;
|
|
617
|
+
isChecked: (id: string) => boolean;
|
|
618
|
+
isBlocked: (task: TasksTask) => boolean;
|
|
619
|
+
onToggle: (id: string, on: boolean) => void;
|
|
620
|
+
groupClass?: string;
|
|
621
|
+
maxNote?: number;
|
|
622
|
+
/** Display-only: rows aren't focusable/toggleable and show the default cursor. */
|
|
623
|
+
readonly?: boolean;
|
|
624
|
+
}): JSX.Element {
|
|
625
|
+
return (
|
|
626
|
+
<div class={cn('flex flex-col gap-3', props.groupClass)}>
|
|
627
|
+
<Show when={props.heading}>
|
|
628
|
+
<div class="flex items-center justify-between gap-3">
|
|
629
|
+
<span id={props.headingId} class="text-sm font-medium text-foreground">
|
|
630
|
+
{props.heading}
|
|
631
|
+
</span>
|
|
632
|
+
<span
|
|
633
|
+
id={props.countId}
|
|
634
|
+
aria-live="polite"
|
|
635
|
+
class="shrink-0 text-sm font-medium tabular-nums text-muted-foreground"
|
|
636
|
+
>
|
|
637
|
+
{props.done} / {props.total}
|
|
638
|
+
</span>
|
|
639
|
+
</div>
|
|
640
|
+
</Show>
|
|
641
|
+
|
|
642
|
+
{/* Thin progress bar under the heading: filled to done / total. Named off the
|
|
643
|
+
checklist heading (no duplicate caption), or a generic label when headless. */}
|
|
644
|
+
<ProgressBar
|
|
645
|
+
value={props.done}
|
|
646
|
+
max={props.total}
|
|
647
|
+
tone="success"
|
|
648
|
+
aria-labelledby={props.heading ? props.headingId : undefined}
|
|
649
|
+
aria-label={props.heading ? undefined : 'Task progress'}
|
|
650
|
+
/>
|
|
651
|
+
|
|
652
|
+
<ul
|
|
653
|
+
aria-labelledby={props.heading ? props.headingId : undefined}
|
|
654
|
+
aria-label={props.heading ? undefined : 'Checklist'}
|
|
655
|
+
aria-readonly={props.readonly ? 'true' : undefined}
|
|
656
|
+
class="flex flex-col gap-1"
|
|
657
|
+
>
|
|
658
|
+
<For each={props.tasks}>
|
|
659
|
+
{(task) => {
|
|
660
|
+
const checked = () => props.isChecked(task.id);
|
|
661
|
+
const blocked = () => props.isBlocked(task);
|
|
662
|
+
const descId = `kai-tl-pdesc-${props.uid}-${task.id}`;
|
|
663
|
+
return (
|
|
664
|
+
<li>
|
|
665
|
+
<label
|
|
666
|
+
class={cn(
|
|
667
|
+
'group flex items-start gap-3 rounded-lg px-2.5 py-2 text-sm transition-colors',
|
|
668
|
+
// Keyboard focus ring (kit standard, inset so it stays within the
|
|
669
|
+
// row). focus-visible only, so a mouse click that parks focus on the
|
|
670
|
+
// row doesn't leave a noisy persistent outline — and it makes a
|
|
671
|
+
// Tab-focused completed row's open description perceivable. Dropped
|
|
672
|
+
// entirely when readonly (the row isn't focusable then).
|
|
673
|
+
!props.readonly &&
|
|
674
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',
|
|
675
|
+
props.readonly
|
|
676
|
+
? 'cursor-default'
|
|
677
|
+
: blocked()
|
|
678
|
+
? 'cursor-not-allowed opacity-60'
|
|
679
|
+
: 'cursor-pointer hover:bg-muted/50',
|
|
680
|
+
)}
|
|
681
|
+
data-task-id={task.id}
|
|
682
|
+
// Completed rows hide their description until hover/focus, so make the
|
|
683
|
+
// row itself focusable to drive the focus-reveal (group-focus-within).
|
|
684
|
+
// Incomplete rows — and every row when readonly — stay unfocusable.
|
|
685
|
+
// Expose the label + description to AT.
|
|
686
|
+
tabindex={!props.readonly && checked() ? 0 : undefined}
|
|
687
|
+
aria-label={checked() ? task.label : undefined}
|
|
688
|
+
aria-describedby={checked() && task.description ? descId : undefined}
|
|
689
|
+
>
|
|
690
|
+
<input
|
|
691
|
+
type="checkbox"
|
|
692
|
+
class="sr-only"
|
|
693
|
+
checked={checked()}
|
|
694
|
+
disabled={blocked() || props.readonly}
|
|
695
|
+
aria-disabled={blocked() ? 'true' : undefined}
|
|
696
|
+
aria-describedby={task.description ? descId : undefined}
|
|
697
|
+
onChange={(e) => props.onToggle(task.id, e.currentTarget.checked)}
|
|
698
|
+
/>
|
|
699
|
+
<span
|
|
700
|
+
class={cn(
|
|
701
|
+
'mt-0.5 shrink-0 text-muted-foreground',
|
|
702
|
+
// Completed rows: the check gently scales on hover.
|
|
703
|
+
checked() && 'motion-safe:transition-transform motion-safe:group-hover:scale-110',
|
|
704
|
+
)}
|
|
705
|
+
aria-hidden="true"
|
|
706
|
+
>
|
|
707
|
+
<Show
|
|
708
|
+
when={checked()}
|
|
709
|
+
fallback={<Circle size={18} />}
|
|
710
|
+
>
|
|
711
|
+
<CircleCheck size={18} class="text-foreground" />
|
|
712
|
+
</Show>
|
|
713
|
+
</span>
|
|
714
|
+
<span class="flex min-w-0 flex-col gap-0.5">
|
|
715
|
+
<span
|
|
716
|
+
class={cn(
|
|
717
|
+
'font-medium text-foreground',
|
|
718
|
+
// Completed: strike through + muted, brightening on hover.
|
|
719
|
+
checked() && 'line-through opacity-70 motion-safe:transition-opacity motion-safe:group-hover:opacity-100',
|
|
720
|
+
)}
|
|
721
|
+
>
|
|
722
|
+
{task.label}
|
|
723
|
+
</span>
|
|
724
|
+
<Show when={task.description}>
|
|
725
|
+
<Show
|
|
726
|
+
when={checked()}
|
|
727
|
+
fallback={
|
|
728
|
+
<span id={descId} class="text-xs font-normal text-muted-foreground">
|
|
729
|
+
{task.description}
|
|
730
|
+
</span>
|
|
731
|
+
}
|
|
732
|
+
>
|
|
733
|
+
{/* Completed: collapse the description and reveal it on hover or
|
|
734
|
+
keyboard focus via the grid-rows height trick. Height-collapse
|
|
735
|
+
keeps the text in the DOM + a11y tree (unlike display:none). */}
|
|
736
|
+
<div class="grid grid-rows-[0fr] group-hover:grid-rows-[1fr] group-focus-within:grid-rows-[1fr] motion-safe:transition-[grid-template-rows] motion-safe:duration-200">
|
|
737
|
+
<span
|
|
738
|
+
id={descId}
|
|
739
|
+
class="overflow-hidden text-xs font-normal text-muted-foreground opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 motion-safe:transition-opacity"
|
|
740
|
+
>
|
|
741
|
+
{task.description}
|
|
742
|
+
</span>
|
|
743
|
+
</div>
|
|
744
|
+
</Show>
|
|
745
|
+
</Show>
|
|
746
|
+
</span>
|
|
747
|
+
</label>
|
|
748
|
+
</li>
|
|
749
|
+
);
|
|
750
|
+
}}
|
|
751
|
+
</For>
|
|
752
|
+
</ul>
|
|
753
|
+
|
|
754
|
+
<Show when={props.maxNote !== undefined}>
|
|
755
|
+
<p class="text-xs text-muted-foreground">Up to {props.maxNote} selected.</p>
|
|
756
|
+
</Show>
|
|
757
|
+
</div>
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
|
|
410
761
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
411
762
|
// Read-only resolved summary presenter.
|
|
412
763
|
// ─────────────────────────────────────────────────────────────────────────────
|