@k8ordo/ui 1.0.0 → 2.1.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 +206 -171
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/components/_internal/focus-ring.css +37 -0
- package/dist/components/_internal/focus-ring.module.mjs +9 -0
- package/dist/components/_internal/form-value.d.mts +33 -0
- package/dist/components/_internal/form-value.mjs +91 -0
- package/dist/components/_internal/high-contrast.css +18 -0
- package/dist/components/_internal/high-contrast.module.mjs +5 -0
- package/dist/components/_internal/ignore-changes.d.mts +20 -0
- package/dist/components/_internal/ignore-changes.mjs +37 -0
- package/dist/components/_internal/nav-link.css +78 -0
- package/dist/components/_internal/nav-link.d.mts +5 -0
- package/dist/components/_internal/nav-link.mjs +8 -0
- package/dist/components/_internal/nav-link.module.mjs +14 -0
- package/dist/components/_internal/sr-only.css +17 -0
- package/dist/components/_internal/sr-only.module.mjs +5 -0
- package/dist/components/_internal/status-tone.css +37 -0
- package/dist/components/_internal/status-tone.d.mts +20 -0
- package/dist/components/_internal/status-tone.mjs +22 -0
- package/dist/components/_internal/status-tone.module.mjs +14 -0
- package/dist/components/ai/_internal/attachment-preview.css +75 -0
- package/dist/components/ai/_internal/attachment-preview.d.mts +14 -0
- package/dist/components/ai/_internal/attachment-preview.mjs +50 -0
- package/dist/components/ai/_internal/attachment-preview.module.mjs +14 -0
- package/dist/components/ai/_internal/collapsible.css +62 -0
- package/dist/components/ai/_internal/collapsible.d.mts +4 -3
- package/dist/components/ai/_internal/collapsible.mjs +42 -33
- package/dist/components/ai/_internal/collapsible.module.mjs +12 -0
- package/dist/components/ai/_internal/icons.d.mts +7 -0
- package/dist/components/ai/_internal/icons.mjs +14 -0
- package/dist/components/ai/_internal/streaming-cursor.css +28 -0
- package/dist/components/ai/_internal/streaming-cursor.d.mts +2 -3
- package/dist/components/ai/_internal/streaming-cursor.mjs +2 -1
- package/dist/components/ai/_internal/streaming-cursor.module.mjs +8 -0
- package/dist/components/ai/attachment/attachment.css +17 -0
- package/dist/components/ai/attachment/attachment.d.mts +14 -0
- package/dist/components/ai/attachment/attachment.mjs +25 -0
- package/dist/components/ai/attachment/attachment.module.mjs +8 -0
- package/dist/components/ai/attachment/index.d.mts +13 -0
- package/dist/components/ai/attachment/index.mjs +8 -0
- package/dist/components/ai/conversation/conversation.css +71 -0
- package/dist/components/ai/conversation/conversation.d.mts +8 -11
- package/dist/components/ai/conversation/conversation.mjs +39 -40
- package/dist/components/ai/conversation/conversation.module.mjs +11 -0
- package/dist/components/ai/conversation/index.d.mts +15 -2
- package/dist/components/ai/conversation/index.mjs +8 -1
- package/dist/components/ai/index.d.mts +8 -10
- package/dist/components/ai/index.mjs +7 -5
- package/dist/components/ai/message/index.d.mts +39 -2
- package/dist/components/ai/message/index.mjs +12 -1
- package/dist/components/ai/message/message.css +71 -0
- package/dist/components/ai/message/message.d.mts +33 -5
- package/dist/components/ai/message/message.mjs +98 -12
- package/dist/components/ai/message/message.module.mjs +18 -0
- package/dist/components/ai/prompt-input/index.d.mts +31 -2
- package/dist/components/ai/prompt-input/index.mjs +10 -1
- package/dist/components/ai/prompt-input/prompt-input.css +101 -0
- package/dist/components/ai/prompt-input/prompt-input.d.mts +15 -8
- package/dist/components/ai/prompt-input/prompt-input.mjs +152 -42
- package/dist/components/ai/prompt-input/prompt-input.module.mjs +15 -0
- package/dist/components/ai/reasoning/reasoning.css +16 -0
- package/dist/components/ai/reasoning/reasoning.d.mts +2 -3
- package/dist/components/ai/reasoning/reasoning.mjs +5 -5
- package/dist/components/ai/reasoning/reasoning.module.mjs +8 -0
- package/dist/components/ai/response/response.css +453 -0
- package/dist/components/ai/response/response.d.mts +4 -6
- package/dist/components/ai/response/response.mjs +20 -15
- package/dist/components/ai/response/response.module.mjs +8 -0
- package/dist/components/ai/source/index.d.mts +12 -0
- package/dist/components/ai/source/index.mjs +8 -0
- package/dist/components/ai/source/source.css +54 -0
- package/dist/components/ai/source/source.d.mts +13 -0
- package/dist/components/ai/source/source.mjs +51 -0
- package/dist/components/ai/source/source.module.mjs +12 -0
- package/dist/components/ai/suggestion/index.d.mts +13 -2
- package/dist/components/ai/suggestion/index.mjs +7 -1
- package/dist/components/ai/suggestion/suggestion.css +32 -0
- package/dist/components/ai/suggestion/suggestion.d.mts +3 -6
- package/dist/components/ai/suggestion/suggestion.mjs +8 -11
- package/dist/components/ai/suggestion/suggestion.module.mjs +8 -0
- package/dist/components/ai/tool-invocation/approval-bar.css +26 -0
- package/dist/components/ai/tool-invocation/approval-bar.d.mts +11 -0
- package/dist/components/ai/tool-invocation/approval-bar.mjs +59 -0
- package/dist/components/ai/tool-invocation/approval-bar.module.mjs +9 -0
- package/dist/components/ai/tool-invocation/tool-invocation.css +55 -0
- package/dist/components/ai/tool-invocation/tool-invocation.d.mts +5 -5
- package/dist/components/ai/tool-invocation/tool-invocation.mjs +39 -18
- package/dist/components/ai/tool-invocation/tool-invocation.module.mjs +15 -0
- package/dist/components/ai/types.d.mts +21 -4
- package/dist/components/buttons/button/button.css +158 -0
- package/dist/components/buttons/button/button.d.mts +32 -9
- package/dist/components/buttons/button/button.mjs +46 -36
- package/dist/components/buttons/button/button.module.mjs +23 -0
- package/dist/components/buttons/button/index.d.mts +2 -2
- package/dist/components/buttons/copy-button/copy-button.css +15 -0
- package/dist/components/buttons/copy-button/copy-button.d.mts +10 -0
- package/dist/components/buttons/copy-button/copy-button.mjs +70 -0
- package/dist/components/buttons/copy-button/copy-button.module.mjs +8 -0
- package/dist/components/buttons/copy-button/index.d.mts +2 -0
- package/dist/components/buttons/copy-button/index.mjs +2 -0
- package/dist/components/buttons/icon-button/icon-button.css +81 -0
- package/dist/components/buttons/icon-button/icon-button.d.mts +39 -12
- package/dist/components/buttons/icon-button/icon-button.mjs +71 -58
- package/dist/components/buttons/icon-button/icon-button.module.mjs +15 -0
- package/dist/components/buttons/icon-button/index.d.mts +2 -2
- package/dist/components/buttons/toolbar/index.d.mts +14 -0
- package/dist/components/buttons/toolbar/index.mjs +9 -0
- package/dist/components/buttons/toolbar/toolbar.css +30 -0
- package/dist/components/buttons/toolbar/toolbar.d.mts +18 -0
- package/dist/components/buttons/toolbar/toolbar.mjs +111 -0
- package/dist/components/buttons/toolbar/toolbar.module.mjs +9 -0
- package/dist/components/data-display/accordion/accordion-button.css +48 -0
- package/dist/components/data-display/accordion/accordion-button.d.mts +2 -3
- package/dist/components/data-display/accordion/accordion-button.mjs +5 -4
- package/dist/components/data-display/accordion/accordion-button.module.mjs +9 -0
- package/dist/components/data-display/accordion/accordion-item.css +11 -0
- package/dist/components/data-display/accordion/accordion-item.d.mts +2 -3
- package/dist/components/data-display/accordion/accordion-item.mjs +2 -1
- package/dist/components/data-display/accordion/accordion-item.module.mjs +5 -0
- package/dist/components/data-display/accordion/accordion-panel.css +9 -0
- package/dist/components/data-display/accordion/accordion-panel.d.mts +2 -3
- package/dist/components/data-display/accordion/accordion-panel.mjs +2 -2
- package/dist/components/data-display/accordion/accordion-panel.module.mjs +5 -0
- package/dist/components/data-display/accordion/accordion.css +19 -0
- package/dist/components/data-display/accordion/accordion.d.mts +2 -3
- package/dist/components/data-display/accordion/accordion.mjs +2 -1
- package/dist/components/data-display/accordion/accordion.module.mjs +5 -0
- package/dist/components/data-display/accordion/context.d.mts +3 -3
- package/dist/components/data-display/accordion/index.d.mts +2 -3
- package/dist/components/data-display/avatar/avatar.css +95 -0
- package/dist/components/data-display/avatar/avatar.d.mts +2 -3
- package/dist/components/data-display/avatar/avatar.mjs +22 -6
- package/dist/components/data-display/avatar/avatar.module.mjs +18 -0
- package/dist/components/data-display/badge/badge.css +160 -0
- package/dist/components/data-display/badge/badge.d.mts +2 -3
- package/dist/components/data-display/badge/badge.mjs +30 -5
- package/dist/components/data-display/badge/badge.module.mjs +21 -0
- package/dist/components/data-display/card/card.css +44 -0
- package/dist/components/data-display/card/card.d.mts +2 -3
- package/dist/components/data-display/card/card.mjs +12 -2
- package/dist/components/data-display/card/card.module.mjs +12 -0
- package/dist/components/data-display/carousel/carousel.css +83 -0
- package/dist/components/data-display/carousel/carousel.d.mts +11 -0
- package/dist/components/data-display/carousel/carousel.mjs +186 -0
- package/dist/components/data-display/carousel/carousel.module.mjs +18 -0
- package/dist/components/data-display/carousel/index.d.mts +11 -0
- package/dist/components/data-display/carousel/index.mjs +8 -0
- package/dist/components/data-display/code/code.css +37 -0
- package/dist/components/data-display/code/code.d.mts +2 -3
- package/dist/components/data-display/code/code.mjs +7 -6
- package/dist/components/data-display/code/code.module.mjs +9 -0
- package/dist/components/data-display/code/find-all-colors.d.mts +2 -3
- package/dist/components/data-display/code/find-all-colors.mjs +0 -161
- package/dist/components/data-display/code-block/code-block.css +161 -0
- package/dist/components/data-display/code-block/code-block.d.mts +12 -0
- package/dist/components/data-display/code-block/code-block.mjs +44 -0
- package/dist/components/data-display/code-block/code-block.module.mjs +11 -0
- package/dist/components/data-display/code-block/highlight.d.mts +9 -0
- package/dist/components/data-display/code-block/highlight.mjs +54 -0
- package/dist/components/data-display/code-block/index.d.mts +2 -0
- package/dist/components/data-display/code-block/index.mjs +2 -0
- package/dist/components/data-display/data-table/data-table.css +74 -0
- package/dist/components/data-display/data-table/data-table.d.mts +31 -0
- package/dist/components/data-display/data-table/data-table.mjs +155 -0
- package/dist/components/data-display/data-table/data-table.module.mjs +14 -0
- package/dist/components/data-display/data-table/index.d.mts +2 -0
- package/dist/components/data-display/data-table/index.mjs +2 -0
- package/dist/components/data-display/heading/heading.css +99 -0
- package/dist/components/data-display/heading/heading.d.mts +2 -3
- package/dist/components/data-display/heading/heading.mjs +15 -14
- package/dist/components/data-display/heading/heading.module.mjs +20 -0
- package/dist/components/data-display/kbd/index.d.mts +2 -0
- package/dist/components/data-display/kbd/index.mjs +2 -0
- package/dist/components/data-display/kbd/kbd.css +21 -0
- package/dist/components/data-display/kbd/kbd.d.mts +8 -0
- package/dist/components/data-display/kbd/kbd.mjs +17 -0
- package/dist/components/data-display/kbd/kbd.module.mjs +5 -0
- package/dist/components/data-display/prose/index.d.mts +2 -0
- package/dist/components/data-display/prose/index.mjs +2 -0
- package/dist/components/data-display/prose/prose.css +253 -0
- package/dist/components/data-display/prose/prose.d.mts +5 -0
- package/dist/components/data-display/prose/prose.mjs +10 -0
- package/dist/components/data-display/prose/prose.module.mjs +5 -0
- package/dist/components/data-display/table/table.css +107 -0
- package/dist/components/data-display/table/table.d.mts +10 -9
- package/dist/components/data-display/table/table.mjs +26 -15
- package/dist/components/data-display/table/table.module.mjs +22 -0
- package/dist/components/data-display/tree/index.d.mts +2 -0
- package/dist/components/data-display/tree/index.mjs +2 -0
- package/dist/components/data-display/tree/tree.css +84 -0
- package/dist/components/data-display/tree/tree.d.mts +20 -0
- package/dist/components/data-display/tree/tree.mjs +151 -0
- package/dist/components/data-display/tree/tree.module.mjs +15 -0
- package/dist/components/feedback/alert/alert.css +42 -0
- package/dist/components/feedback/alert/alert.d.mts +3 -4
- package/dist/components/feedback/alert/alert.mjs +20 -23
- package/dist/components/feedback/alert/alert.module.mjs +14 -0
- package/dist/components/feedback/callout/callout.css +38 -0
- package/dist/components/feedback/callout/callout.d.mts +10 -0
- package/dist/components/feedback/callout/callout.mjs +38 -0
- package/dist/components/feedback/callout/callout.module.mjs +11 -0
- package/dist/components/feedback/callout/index.d.mts +2 -0
- package/dist/components/feedback/callout/index.mjs +2 -0
- package/dist/components/feedback/empty-state/empty-state.css +36 -0
- package/dist/components/feedback/empty-state/empty-state.d.mts +10 -0
- package/dist/components/feedback/empty-state/empty-state.mjs +27 -0
- package/dist/components/feedback/empty-state/empty-state.module.mjs +11 -0
- package/dist/components/feedback/empty-state/index.d.mts +2 -0
- package/dist/components/feedback/empty-state/index.mjs +2 -0
- package/dist/components/feedback/progress/progress.css +78 -0
- package/dist/components/feedback/progress/progress.d.mts +5 -5
- package/dist/components/feedback/progress/progress.mjs +17 -3
- package/dist/components/feedback/progress/progress.module.mjs +12 -0
- package/dist/components/feedback/skeleton/skeleton.css +64 -0
- package/dist/components/feedback/skeleton/skeleton.d.mts +2 -3
- package/dist/components/feedback/skeleton/skeleton.mjs +19 -2
- package/dist/components/feedback/skeleton/skeleton.module.mjs +17 -0
- package/dist/components/feedback/spinner/spinner.css +40 -0
- package/dist/components/feedback/spinner/spinner.d.mts +2 -3
- package/dist/components/feedback/spinner/spinner.mjs +13 -7
- package/dist/components/feedback/spinner/spinner.module.mjs +12 -0
- package/dist/components/feedback/toast/context.d.mts +8 -9
- package/dist/components/feedback/toast/provider.css +69 -0
- package/dist/components/feedback/toast/provider.d.mts +2 -3
- package/dist/components/feedback/toast/provider.mjs +17 -13
- package/dist/components/feedback/toast/provider.module.mjs +12 -0
- package/dist/components/feedback/toast/toast.d.mts +2 -3
- package/dist/components/form/autocomplete/autocomplete.css +154 -0
- package/dist/components/form/autocomplete/autocomplete.d.mts +2 -3
- package/dist/components/form/autocomplete/autocomplete.mjs +70 -46
- package/dist/components/form/autocomplete/autocomplete.module.mjs +21 -0
- package/dist/components/form/calendar/calendar.css +98 -0
- package/dist/components/form/calendar/calendar.d.mts +14 -0
- package/dist/components/form/calendar/calendar.mjs +182 -0
- package/dist/components/form/calendar/calendar.module.mjs +18 -0
- package/dist/components/form/calendar/index.d.mts +2 -0
- package/dist/components/form/calendar/index.mjs +2 -0
- package/dist/components/form/checkbox/checkbox.css +90 -0
- package/dist/components/form/checkbox/checkbox.d.mts +5 -3
- package/dist/components/form/checkbox/checkbox.mjs +30 -27
- package/dist/components/form/checkbox/checkbox.module.mjs +13 -0
- package/dist/components/form/checkbox-card/checkbox-card.css +138 -0
- package/dist/components/form/checkbox-card/checkbox-card.d.mts +3 -4
- package/dist/components/form/checkbox-card/checkbox-card.mjs +17 -23
- package/dist/components/form/checkbox-card/checkbox-card.module.mjs +17 -0
- package/dist/components/form/checkbox-group/checkbox-group.css +15 -0
- package/dist/components/form/checkbox-group/checkbox-group.d.mts +7 -5
- package/dist/components/form/checkbox-group/checkbox-group.mjs +12 -16
- package/dist/components/form/checkbox-group/checkbox-group.module.mjs +8 -0
- package/dist/components/form/checkbox-group/index.d.mts +5 -3
- package/dist/components/form/color-picker/color-picker.css +172 -0
- package/dist/components/form/color-picker/color-picker.d.mts +28 -0
- package/dist/components/form/color-picker/color-picker.mjs +239 -0
- package/dist/components/form/color-picker/color-picker.module.mjs +20 -0
- package/dist/components/form/color-picker/index.d.mts +2 -0
- package/dist/components/form/color-picker/index.mjs +2 -0
- package/dist/components/form/combobox/combobox.css +143 -0
- package/dist/components/form/combobox/combobox.d.mts +32 -0
- package/dist/components/form/combobox/combobox.mjs +278 -0
- package/dist/components/form/combobox/combobox.module.mjs +19 -0
- package/dist/components/form/combobox/index.d.mts +2 -0
- package/dist/components/form/combobox/index.mjs +2 -0
- package/dist/components/form/date-field/date-field.css +31 -0
- package/dist/components/form/date-field/date-field.d.mts +8 -0
- package/dist/components/form/date-field/date-field.mjs +20 -0
- package/dist/components/form/date-field/date-field.module.mjs +5 -0
- package/dist/components/form/date-field/index.d.mts +2 -0
- package/dist/components/form/date-field/index.mjs +2 -0
- package/dist/components/form/date-picker/date-picker.css +90 -0
- package/dist/components/form/date-picker/date-picker.d.mts +12 -0
- package/dist/components/form/date-picker/date-picker.mjs +77 -0
- package/dist/components/form/date-picker/date-picker.module.mjs +14 -0
- package/dist/components/form/date-picker/index.d.mts +2 -0
- package/dist/components/form/date-picker/index.mjs +2 -0
- package/dist/components/form/file-field/file-field.css +88 -0
- package/dist/components/form/file-field/file-field.d.mts +18 -19
- package/dist/components/form/file-field/file-field.mjs +130 -42
- package/dist/components/form/file-field/file-field.module.mjs +17 -0
- package/dist/components/form/file-field/index.d.mts +20 -2
- package/dist/components/form/file-field/index.mjs +9 -1
- package/dist/components/form/form/form.css +11 -0
- package/dist/components/form/form/form.d.mts +4 -4
- package/dist/components/form/form/form.mjs +2 -1
- package/dist/components/form/form/form.module.mjs +5 -0
- package/dist/components/form/form-control/form-control.css +43 -0
- package/dist/components/form/form-control/form-control.d.mts +2 -3
- package/dist/components/form/form-control/form-control.mjs +11 -10
- package/dist/components/form/form-control/form-control.module.mjs +12 -0
- package/dist/components/form/number-field/cast.d.mts +2 -3
- package/dist/components/form/number-field/cast.mjs +3 -22
- package/dist/components/form/number-field/number-field.css +122 -0
- package/dist/components/form/number-field/number-field.d.mts +10 -10
- package/dist/components/form/number-field/number-field.mjs +126 -54
- package/dist/components/form/number-field/number-field.module.mjs +10 -0
- package/dist/components/form/password-input/password-input.css +88 -0
- package/dist/components/form/password-input/password-input.d.mts +2 -3
- package/dist/components/form/password-input/password-input.mjs +15 -12
- package/dist/components/form/password-input/password-input.module.mjs +12 -0
- package/dist/components/form/radio/radio.css +89 -0
- package/dist/components/form/radio/radio.d.mts +4 -3
- package/dist/components/form/radio/radio.mjs +16 -19
- package/dist/components/form/radio/radio.module.mjs +16 -0
- package/dist/components/form/radio-card/radio-card.css +147 -0
- package/dist/components/form/radio-card/radio-card.d.mts +4 -4
- package/dist/components/form/radio-card/radio-card.mjs +17 -23
- package/dist/components/form/radio-card/radio-card.module.mjs +19 -0
- package/dist/components/form/range-slider/index.d.mts +2 -0
- package/dist/components/form/range-slider/index.mjs +2 -0
- package/dist/components/form/range-slider/range-slider.css +67 -0
- package/dist/components/form/range-slider/range-slider.d.mts +30 -0
- package/dist/components/form/range-slider/range-slider.mjs +135 -0
- package/dist/components/form/range-slider/range-slider.module.mjs +14 -0
- package/dist/components/form/select/select.css +74 -0
- package/dist/components/form/select/select.d.mts +2 -3
- package/dist/components/form/select/select.mjs +25 -8
- package/dist/components/form/select/select.module.mjs +12 -0
- package/dist/components/form/slider/range-input-class.css +97 -0
- package/dist/components/form/slider/range-input-class.d.mts +7 -0
- package/dist/components/form/slider/range-input-class.mjs +10 -0
- package/dist/components/form/slider/range-input-class.module.mjs +8 -0
- package/dist/components/form/slider/slider.css +55 -0
- package/dist/components/form/slider/slider.d.mts +6 -7
- package/dist/components/form/slider/slider.mjs +44 -11
- package/dist/components/form/slider/slider.module.mjs +12 -0
- package/dist/components/form/switch/switch.css +103 -0
- package/dist/components/form/switch/switch.d.mts +2 -3
- package/dist/components/form/switch/switch.mjs +14 -17
- package/dist/components/form/switch/switch.module.mjs +16 -0
- package/dist/components/form/text-field/text-field.css +41 -0
- package/dist/components/form/text-field/text-field.d.mts +4 -5
- package/dist/components/form/text-field/text-field.mjs +2 -3
- package/dist/components/form/text-field/text-field.module.mjs +5 -0
- package/dist/components/form/textarea/textarea.css +50 -0
- package/dist/components/form/textarea/textarea.d.mts +3 -3
- package/dist/components/form/textarea/textarea.mjs +6 -20
- package/dist/components/form/textarea/textarea.module.mjs +9 -0
- package/dist/components/icons/base.css +40 -0
- package/dist/components/icons/base.d.mts +4 -5
- package/dist/components/icons/base.mjs +10 -10
- package/dist/components/icons/base.module.mjs +13 -0
- package/dist/components/icons/browsers.d.mts +5 -6
- package/dist/components/icons/color-scale.d.mts +2 -3
- package/dist/components/icons/github-mark.d.mts +2 -3
- package/dist/components/icons/logo.css +17 -0
- package/dist/components/icons/logo.d.mts +3 -4
- package/dist/components/icons/logo.mjs +4 -3
- package/dist/components/icons/logo.module.mjs +9 -0
- package/dist/components/icons/lucide-deep.d.mts +3 -1
- package/dist/components/icons/lucide-imports.d.mts +3 -1
- package/dist/components/icons/lucide-imports.mjs +3 -1
- package/dist/components/icons/lucide.d.mts +60 -61
- package/dist/components/icons/qiita.d.mts +2 -3
- package/dist/components/icons/twitter.css +9 -0
- package/dist/components/icons/twitter.d.mts +2 -3
- package/dist/components/icons/twitter.mjs +2 -1
- package/dist/components/icons/twitter.module.mjs +5 -0
- package/dist/components/icons/vertical-writing.d.mts +2 -3
- package/dist/components/index.d.mts +62 -29
- package/dist/components/index.mjs +36 -14
- package/dist/components/layout/_shared/gap.css +25 -0
- package/dist/components/layout/_shared/gap.d.mts +8 -9
- package/dist/components/layout/_shared/gap.mjs +6 -5
- package/dist/components/layout/_shared/gap.module.mjs +11 -0
- package/dist/components/layout/_shared/padding.css +25 -0
- package/dist/components/layout/_shared/padding.d.mts +8 -9
- package/dist/components/layout/_shared/padding.mjs +6 -5
- package/dist/components/layout/_shared/padding.module.mjs +11 -0
- package/dist/components/layout/grid/grid.css +93 -0
- package/dist/components/layout/grid/grid.d.mts +5 -6
- package/dist/components/layout/grid/grid.mjs +21 -20
- package/dist/components/layout/grid/grid.module.mjs +25 -0
- package/dist/components/layout/resizable-panels/index.d.mts +18 -0
- package/dist/components/layout/resizable-panels/index.mjs +9 -0
- package/dist/components/layout/resizable-panels/resizable-panels.css +77 -0
- package/dist/components/layout/resizable-panels/resizable-panels.d.mts +21 -0
- package/dist/components/layout/resizable-panels/resizable-panels.mjs +164 -0
- package/dist/components/layout/resizable-panels/resizable-panels.module.mjs +16 -0
- package/dist/components/layout/separator/separator.css +37 -0
- package/dist/components/layout/separator/separator.d.mts +2 -3
- package/dist/components/layout/separator/separator.mjs +12 -9
- package/dist/components/layout/separator/separator.module.mjs +12 -0
- package/dist/components/layout/stack/stack.css +49 -0
- package/dist/components/layout/stack/stack.d.mts +3 -4
- package/dist/components/layout/stack/stack.mjs +11 -10
- package/dist/components/layout/stack/stack.module.mjs +17 -0
- package/dist/components/navigation/anchor/anchor.css +29 -0
- package/dist/components/navigation/anchor/anchor.d.mts +2 -3
- package/dist/components/navigation/anchor/anchor.mjs +5 -2
- package/dist/components/navigation/anchor/anchor.module.mjs +8 -0
- package/dist/components/navigation/breadcrumb/breadcrumb.css +72 -0
- package/dist/components/navigation/breadcrumb/breadcrumb.d.mts +5 -6
- package/dist/components/navigation/breadcrumb/breadcrumb.mjs +15 -9
- package/dist/components/navigation/breadcrumb/breadcrumb.module.mjs +14 -0
- package/dist/components/navigation/breadcrumb/index.d.mts +2 -3
- package/dist/components/navigation/pagination/pagination.css +36 -0
- package/dist/components/navigation/pagination/pagination.d.mts +2 -3
- package/dist/components/navigation/pagination/pagination.mjs +9 -8
- package/dist/components/navigation/pagination/pagination.module.mjs +11 -0
- package/dist/components/navigation/side-nav/index.d.mts +16 -0
- package/dist/components/navigation/side-nav/index.mjs +10 -0
- package/dist/components/navigation/side-nav/side-nav.css +73 -0
- package/dist/components/navigation/side-nav/side-nav.d.mts +31 -0
- package/dist/components/navigation/side-nav/side-nav.mjs +62 -0
- package/dist/components/navigation/side-nav/side-nav.module.mjs +11 -0
- package/dist/components/navigation/stepper/index.d.mts +2 -0
- package/dist/components/navigation/stepper/index.mjs +2 -0
- package/dist/components/navigation/stepper/stepper.css +151 -0
- package/dist/components/navigation/stepper/stepper.d.mts +19 -0
- package/dist/components/navigation/stepper/stepper.mjs +87 -0
- package/dist/components/navigation/stepper/stepper.module.mjs +29 -0
- package/dist/components/navigation/table-of-contents/index.d.mts +2 -0
- package/dist/components/navigation/table-of-contents/index.mjs +2 -0
- package/dist/components/navigation/table-of-contents/table-of-contents.css +17 -0
- package/dist/components/navigation/table-of-contents/table-of-contents.d.mts +12 -0
- package/dist/components/navigation/table-of-contents/table-of-contents.mjs +94 -0
- package/dist/components/navigation/table-of-contents/table-of-contents.module.mjs +8 -0
- package/dist/components/navigation/tabs/index.d.mts +19 -2
- package/dist/components/navigation/tabs/index.mjs +9 -1
- package/dist/components/navigation/tabs/tabs.css +70 -0
- package/dist/components/navigation/tabs/tabs.d.mts +16 -19
- package/dist/components/navigation/tabs/tabs.mjs +52 -49
- package/dist/components/navigation/tabs/tabs.module.mjs +12 -0
- package/dist/components/observers/fragment-instance.d.mts +1 -0
- package/dist/components/observers/in-view/in-view.d.mts +11 -0
- package/dist/components/observers/in-view/in-view.mjs +60 -0
- package/dist/components/observers/in-view/index.d.mts +2 -0
- package/dist/components/observers/in-view/index.mjs +2 -0
- package/dist/components/observers/resize/index.d.mts +2 -0
- package/dist/components/observers/resize/index.mjs +2 -0
- package/dist/components/observers/resize/resize.d.mts +7 -0
- package/dist/components/observers/resize/resize.mjs +25 -0
- package/dist/components/overlays/_internal/modal-dialog-context.d.mts +4 -5
- package/dist/components/overlays/_internal/use-can-hover.d.mts +2 -3
- package/dist/components/overlays/_internal/use-hover-intent.d.mts +3 -4
- package/dist/components/overlays/_internal/use-list-navigation.d.mts +17 -11
- package/dist/components/overlays/_internal/use-list-navigation.mjs +42 -26
- package/dist/components/overlays/command-palette/command-palette.css +91 -0
- package/dist/components/overlays/command-palette/command-palette.d.mts +24 -0
- package/dist/components/overlays/command-palette/command-palette.mjs +139 -0
- package/dist/components/overlays/command-palette/command-palette.module.mjs +14 -0
- package/dist/components/overlays/command-palette/index.d.mts +2 -0
- package/dist/components/overlays/command-palette/index.mjs +2 -0
- package/dist/components/overlays/context-menu/context-menu.d.mts +13 -0
- package/dist/components/overlays/context-menu/context-menu.mjs +79 -0
- package/dist/components/overlays/context-menu/index.d.mts +21 -0
- package/dist/components/overlays/context-menu/index.mjs +13 -0
- package/dist/components/overlays/dialog/dialog.css +31 -0
- package/dist/components/overlays/dialog/dialog.d.mts +12 -17
- package/dist/components/overlays/dialog/dialog.mjs +11 -13
- package/dist/components/overlays/dialog/dialog.module.mjs +10 -0
- package/dist/components/overlays/dialog/index.d.mts +17 -2
- package/dist/components/overlays/dialog/index.mjs +8 -1
- package/dist/components/overlays/drawer/drawer.css +48 -0
- package/dist/components/overlays/drawer/drawer.d.mts +2 -3
- package/dist/components/overlays/drawer/drawer.mjs +11 -10
- package/dist/components/overlays/drawer/drawer.module.mjs +13 -0
- package/dist/components/overlays/dropdown-menu/dropdown-menu.d.mts +19 -26
- package/dist/components/overlays/dropdown-menu/dropdown-menu.mjs +12 -20
- package/dist/components/overlays/dropdown-menu/hooks.d.mts +7 -7
- package/dist/components/overlays/dropdown-menu/hooks.mjs +3 -3
- package/dist/components/overlays/dropdown-menu/index.d.mts +30 -2
- package/dist/components/overlays/dropdown-menu/index.mjs +12 -1
- package/dist/components/overlays/dropdown-menu/shared.css +51 -0
- package/dist/components/overlays/dropdown-menu/shared.d.mts +3 -6
- package/dist/components/overlays/dropdown-menu/shared.mjs +4 -6
- package/dist/components/overlays/dropdown-menu/shared.module.mjs +8 -0
- package/dist/components/overlays/dropdown-menu/sub-menu.css +28 -0
- package/dist/components/overlays/dropdown-menu/sub-menu.d.mts +3 -6
- package/dist/components/overlays/dropdown-menu/sub-menu.mjs +16 -16
- package/dist/components/overlays/dropdown-menu/sub-menu.module.mjs +9 -0
- package/dist/components/overlays/dropdown-menu/use-safe-triangle.d.mts +2 -3
- package/dist/components/overlays/list-box/hooks.d.mts +6 -5
- package/dist/components/overlays/list-box/hooks.mjs +5 -4
- package/dist/components/overlays/list-box/index.d.mts +27 -2
- package/dist/components/overlays/list-box/index.mjs +9 -1
- package/dist/components/overlays/list-box/list-box.css +74 -0
- package/dist/components/overlays/list-box/list-box.d.mts +20 -23
- package/dist/components/overlays/list-box/list-box.mjs +17 -21
- package/dist/components/overlays/list-box/list-box.module.mjs +10 -0
- package/dist/components/overlays/modal/modal.css +119 -0
- package/dist/components/overlays/modal/modal.d.mts +2 -3
- package/dist/components/overlays/modal/modal.mjs +14 -11
- package/dist/components/overlays/modal/modal.module.mjs +11 -0
- package/dist/components/overlays/popover/anchor-positioning.d.mts +4 -5
- package/dist/components/overlays/popover/escape-stack.d.mts +2 -3
- package/dist/components/overlays/popover/hooks.d.mts +7 -8
- package/dist/components/overlays/popover/index.d.mts +25 -2
- package/dist/components/overlays/popover/index.mjs +8 -1
- package/dist/components/overlays/popover/popover.css +51 -0
- package/dist/components/overlays/popover/popover.d.mts +18 -20
- package/dist/components/overlays/popover/popover.mjs +13 -12
- package/dist/components/overlays/popover/popover.module.mjs +11 -0
- package/dist/components/overlays/tooltip/bridge.css +68 -0
- package/dist/components/overlays/tooltip/bridge.d.mts +2 -3
- package/dist/components/overlays/tooltip/bridge.mjs +7 -21
- package/dist/components/overlays/tooltip/bridge.module.mjs +11 -0
- package/dist/components/overlays/tooltip/index.d.mts +22 -2
- package/dist/components/overlays/tooltip/index.mjs +8 -1
- package/dist/components/overlays/tooltip/tooltip.css +15 -0
- package/dist/components/overlays/tooltip/tooltip.d.mts +19 -24
- package/dist/components/overlays/tooltip/tooltip.mjs +5 -9
- package/dist/components/overlays/tooltip/tooltip.module.mjs +5 -0
- package/dist/components/providers/index.d.mts +1 -2
- package/dist/components/providers/portal-root.d.mts +9 -7
- package/dist/components/providers/portal-root.mjs +7 -7
- package/dist/components/providers/ui-provider.d.mts +2 -6
- package/dist/components/providers/ui-provider.mjs +1 -5
- package/dist/helpers/chain.d.mts +2 -3
- package/dist/helpers/chain.mjs +0 -23
- package/dist/helpers/create-safe-context.d.mts +2 -3
- package/dist/helpers/create-safe-context.mjs +0 -17
- package/dist/helpers/index.d.mts +1 -2
- package/dist/helpers/index.mjs +2 -3
- package/dist/helpers/merge-props.d.mts +2 -3
- package/dist/helpers/merge-props.mjs +2 -37
- package/dist/helpers/merge-refs.d.mts +2 -3
- package/dist/helpers/merge-refs.mjs +0 -32
- package/dist/hooks/click-away/index.d.mts +2 -3
- package/dist/hooks/controllable-state/index.d.mts +2 -3
- package/dist/hooks/controllable-state/index.mjs +9 -11
- package/dist/hooks/index.d.mts +2 -23
- package/dist/hooks/index.mjs +2 -22
- package/dist/hooks/writing-mode/index.d.mts +15 -5
- package/dist/hooks/writing-mode/index.mjs +21 -14
- package/dist/i18n/current.d.mts +23 -0
- package/dist/i18n/current.mjs +43 -0
- package/dist/i18n/en.d.mts +2 -3
- package/dist/i18n/en.mjs +46 -0
- package/dist/i18n/index.d.mts +3 -2
- package/dist/i18n/index.mjs +4 -3
- package/dist/i18n/ja.d.mts +2 -3
- package/dist/i18n/ja.mjs +46 -0
- package/dist/i18n/messages.d.mts +81 -3
- package/dist/i18n/usage.d.mts +8 -0
- package/dist/i18n/usage.mjs +131 -0
- package/dist/index.d.mts +40 -47
- package/dist/index.mjs +36 -42
- package/dist/integrations/_shared/openui-defs.d.mts +3 -4
- package/dist/integrations/_shared/openui-defs.mjs +123 -54
- package/dist/integrations/_shared/renderers.css +50 -0
- package/dist/integrations/_shared/renderers.d.mts +71 -52
- package/dist/integrations/_shared/renderers.mjs +292 -34
- package/dist/integrations/_shared/renderers.module.mjs +14 -0
- package/dist/integrations/_shared/schemas.d.mts +388 -104
- package/dist/integrations/_shared/schemas.mjs +165 -27
- package/dist/integrations/ai-sdk/index.d.mts +2 -2
- package/dist/integrations/ai-sdk/map-parts.d.mts +25 -7
- package/dist/integrations/ai-sdk/map-parts.mjs +28 -3
- package/dist/integrations/json-render/catalog.d.mts +336 -18
- package/dist/integrations/json-render/catalog.mjs +120 -57
- package/dist/integrations/json-render/registry.d.mts +3 -4
- package/dist/integrations/json-render/registry.mjs +38 -4
- package/dist/integrations/openui/form-views.d.mts +23 -18
- package/dist/integrations/openui/form-views.mjs +27 -3
- package/dist/integrations/openui/library.d.mts +59 -7
- package/dist/integrations/openui/library.mjs +18 -3
- package/dist/integrations/openui/prompt.d.mts +2 -3
- package/dist/internal/accepts-file.d.mts +8 -0
- package/dist/internal/accepts-file.mjs +19 -0
- package/dist/internal/carries-files.d.mts +3 -0
- package/dist/internal/carries-files.mjs +4 -0
- package/dist/internal/clamp.d.mts +2 -3
- package/dist/internal/clamp.mjs +0 -11
- package/dist/internal/commit-input-value.d.mts +10 -0
- package/dist/internal/commit-input-value.mjs +15 -0
- package/dist/internal/dropped-files.d.mts +3 -0
- package/dist/internal/dropped-files.mjs +8 -0
- package/dist/{hooks/focus-trap/index.d.mts → internal/focus-trap.d.mts} +6 -7
- package/dist/{hooks/focus-trap/index.mjs → internal/focus-trap.mjs} +5 -5
- package/dist/internal/hex-color.d.mts +22 -0
- package/dist/internal/hex-color.mjs +53 -0
- package/dist/internal/iso-date.d.mts +39 -0
- package/dist/internal/iso-date.mjs +98 -0
- package/dist/internal/to-precision.d.mts +2 -3
- package/dist/internal/to-precision.mjs +0 -8
- package/dist/styles/index.css +513 -2534
- package/dist/styles/tailwind.css +217 -17
- package/dist/styles/tokens.d.mts +1 -2
- package/dist/styles/tokens.mjs +1 -2
- package/dist/types/variables.d.mts +7 -9
- package/docs/GUIDE.md +340 -158
- package/docs/llms.txt +18 -10
- package/docs/props.generated.json +2157 -292
- package/docs/references/ai-chat.md +396 -113
- package/docs/references/color.md +258 -113
- package/docs/references/components.md +1891 -461
- package/docs/references/generative-ui.md +163 -34
- package/docs/references/interaction-design.md +103 -73
- package/docs/references/spatial-design.md +112 -90
- package/docs/references/types.md +101 -0
- package/docs/references/typography.md +182 -73
- package/package.json +71 -70
- package/dist/components/_internal/focus-ring.d.mts +0 -8
- package/dist/components/_internal/focus-ring.mjs +0 -8
- package/dist/components/layout/scroll-linked/index.d.mts +0 -2
- package/dist/components/layout/scroll-linked/index.mjs +0 -2
- package/dist/components/layout/scroll-linked/scroll-linked.d.mts +0 -14
- package/dist/components/layout/scroll-linked/scroll-linked.mjs +0 -59
- package/dist/helpers/cn.d.mts +0 -5
- package/dist/helpers/cn.mjs +0 -27
- package/dist/hooks/breakpoint/index.d.mts +0 -5
- package/dist/hooks/breakpoint/index.mjs +0 -24
- package/dist/hooks/client/index.d.mts +0 -4
- package/dist/hooks/client/index.mjs +0 -6
- package/dist/hooks/clipboard/index.d.mts +0 -7
- package/dist/hooks/clipboard/index.mjs +0 -15
- package/dist/hooks/debounced-transition/index.d.mts +0 -5
- package/dist/hooks/debounced-transition/index.mjs +0 -49
- package/dist/hooks/deferred-debounce/index.d.mts +0 -4
- package/dist/hooks/deferred-debounce/index.mjs +0 -9
- package/dist/hooks/disclosure/index.d.mts +0 -10
- package/dist/hooks/disclosure/index.mjs +0 -20
- package/dist/hooks/hash/index.d.mts +0 -4
- package/dist/hooks/hash/index.mjs +0 -25
- package/dist/hooks/hover/index.d.mts +0 -12
- package/dist/hooks/hover/index.mjs +0 -19
- package/dist/hooks/intersection-observer/index.d.mts +0 -3
- package/dist/hooks/intersection-observer/index.mjs +0 -3
- package/dist/hooks/intersection-observer/use-in-view.d.mts +0 -11
- package/dist/hooks/intersection-observer/use-in-view.mjs +0 -18
- package/dist/hooks/intersection-observer/use-intersection-observer.d.mts +0 -11
- package/dist/hooks/intersection-observer/use-intersection-observer.mjs +0 -33
- package/dist/hooks/interval/index.d.mts +0 -4
- package/dist/hooks/interval/index.mjs +0 -19
- package/dist/hooks/local-storage/index.d.mts +0 -4
- package/dist/hooks/local-storage/index.mjs +0 -46
- package/dist/hooks/resize/index.d.mts +0 -8
- package/dist/hooks/resize/index.mjs +0 -24
- package/dist/hooks/scroll-direction/index.d.mts +0 -13
- package/dist/hooks/scroll-direction/index.mjs +0 -67
- package/dist/hooks/scroll-lock/index.d.mts +0 -9
- package/dist/hooks/scroll-lock/index.mjs +0 -59
- package/dist/hooks/session-storage/index.d.mts +0 -4
- package/dist/hooks/session-storage/index.mjs +0 -46
- package/dist/hooks/step/index.d.mts +0 -15
- package/dist/hooks/step/index.mjs +0 -39
- package/dist/hooks/timeout/index.d.mts +0 -4
- package/dist/hooks/timeout/index.mjs +0 -19
- package/dist/hooks/window-resize/index.d.mts +0 -11
- package/dist/hooks/window-resize/index.mjs +0 -21
- package/dist/hooks/window-size/index.d.mts +0 -8
- package/dist/hooks/window-size/index.mjs +0 -31
- package/dist/i18n/context.d.mts +0 -9
- package/dist/i18n/context.mjs +0 -19
- package/dist/styles/base.css +0 -315
- package/dist/styles/tokens.css +0 -380
- package/dist/styles/tokens.generated.d.mts +0 -840
- package/dist/styles/tokens.generated.mjs +0 -813
- package/dist/styles/utilities.css +0 -62
- package/docs/references/helpers.md +0 -120
- package/docs/references/hooks.md +0 -314
|
@@ -1,67 +1,68 @@
|
|
|
1
|
-
# k8ordo
|
|
1
|
+
# @k8ordo/ui AI chat components
|
|
2
2
|
|
|
3
|
-
AI
|
|
3
|
+
Components for building an AI chat UI: the conversation log, messages and their actions, the input box with attachments, reasoning display, tool-invocation display with approval, attachments, and sources. Import them from their dedicated subpaths rather than from the root.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Importing
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
|
-
//
|
|
8
|
+
// Core components (no extra dependencies)
|
|
9
9
|
import {
|
|
10
|
+
Attachment,
|
|
10
11
|
Conversation,
|
|
11
12
|
Message,
|
|
12
13
|
PromptInput,
|
|
13
14
|
Reasoning,
|
|
15
|
+
Source,
|
|
14
16
|
Suggestion,
|
|
15
17
|
ToolInvocation,
|
|
16
18
|
} from '@k8ordo/ui/ai';
|
|
17
|
-
|
|
18
|
-
// ストリーミング対応 Markdown 描画(optional peer: streamdown)
|
|
19
|
-
import { Response } from '@k8ordo/ui/ai/response';
|
|
20
|
-
|
|
21
|
-
// AI SDK 連携(optional peer: ai)
|
|
19
|
+
// AI SDK integration (optional peer: ai)
|
|
22
20
|
import { mapMessageParts } from '@k8ordo/ui/ai-sdk';
|
|
21
|
+
// Streaming-aware Markdown rendering (optional peer: streamdown)
|
|
22
|
+
import { Response } from '@k8ordo/ui/ai/response';
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The types are exported from `@k8ordo/ui/ai` too:
|
|
26
26
|
|
|
27
|
-
- `ChatStatus`: `'ready' | 'submitted' | 'streaming' | 'error'
|
|
28
|
-
- `ToolState`: `'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied'
|
|
27
|
+
- `ChatStatus`: `'ready' | 'submitted' | 'streaming' | 'error'` (compatible with the AI SDK's `status`)
|
|
28
|
+
- `ToolState`: `'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied'` (1:1 with the AI SDK v7 tool states)
|
|
29
|
+
- `ToolApproval`: `{ id: string; approved?: boolean; reason?: string; requestReason?: string; isAutomatic?: boolean }` (the shape of the AI SDK's `part.approval`, so the part's own object can be passed as is)
|
|
30
|
+
- `ToolApprovalResponse`: `{ id: string; approved: boolean }` (what `ToolInvocation` answers with)
|
|
31
|
+
- `MessageFeedback`: `'positive' | 'negative'`
|
|
29
32
|
|
|
30
|
-
### optional
|
|
33
|
+
### Setting up the optional peers
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
Install only what the subpaths you use require. `@k8ordo/ui/ai` itself needs neither.
|
|
33
36
|
|
|
34
37
|
```bash
|
|
35
|
-
# @k8ordo/ui/ai/response
|
|
38
|
+
# If you use @k8ordo/ui/ai/response (Response)
|
|
36
39
|
pnpm add streamdown
|
|
37
|
-
# @k8ordo/ui/ai-sdk
|
|
40
|
+
# If you use @k8ordo/ui/ai-sdk (mapMessageParts)
|
|
38
41
|
pnpm add ai
|
|
39
42
|
```
|
|
40
43
|
|
|
41
|
-
`Response`
|
|
44
|
+
`Response` styles what streamdown renders itself, through the
|
|
45
|
+
`data-streamdown` attribute streamdown puts on every element, so it needs no
|
|
46
|
+
Tailwind. Load streamdown's own stylesheet only when you turn on its `animated`
|
|
47
|
+
option, which keeps its keyframes there:
|
|
42
48
|
|
|
43
49
|
```tsx
|
|
44
50
|
import 'streamdown/styles.css';
|
|
45
51
|
```
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
/* アプリの CSS エントリに追加(パスは CSS ファイルから node_modules への相対) */
|
|
49
|
-
@source '../node_modules/streamdown/dist/*.js';
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
なお本リファレンスの例で使う `useChat` は AI SDK の React バインディング(`pnpm add @ai-sdk/react`)から import する。
|
|
53
|
+
The `useChat` used in the examples below comes from the AI SDK's React bindings (`pnpm add @ai-sdk/react`).
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
The "default" shown for `label`, `sendLabel`, and similar props below is the built-in Japanese dictionary's. The text actually used follows `@k8ordo/i18n`'s current locale (see [i18n](components.md)). Passing the prop directly wins over the dictionary.
|
|
55
56
|
|
|
56
|
-
##
|
|
57
|
+
## The whole picture
|
|
57
58
|
|
|
58
|
-
`Conversation
|
|
59
|
+
`Conversation` (the log), `Message` (a bubble), and `PromptInput` (the input box) form the skeleton. `Response`, `Reasoning`, `ToolInvocation`, `Attachment`, `Source`, and the message actions can be added later — [AI SDK integration](#ai-sdk-integration-mapmessageparts) shows all of them together.
|
|
59
60
|
|
|
60
61
|
```tsx
|
|
61
62
|
'use client';
|
|
63
|
+
import { useChat } from '@ai-sdk/react';
|
|
62
64
|
import { Avatar, AssistantIcon } from '@k8ordo/ui';
|
|
63
65
|
import { Conversation, Message, PromptInput } from '@k8ordo/ui/ai';
|
|
64
|
-
import { useChat } from '@ai-sdk/react';
|
|
65
66
|
import type { UIMessage } from 'ai';
|
|
66
67
|
|
|
67
68
|
const textOf = (m: UIMessage) =>
|
|
@@ -71,22 +72,31 @@ export function Chat() {
|
|
|
71
72
|
const { messages, sendMessage, status, stop } = useChat();
|
|
72
73
|
|
|
73
74
|
return (
|
|
74
|
-
<div
|
|
75
|
+
<div
|
|
76
|
+
style={{
|
|
77
|
+
display: 'flex',
|
|
78
|
+
height: '100%',
|
|
79
|
+
flexDirection: 'column',
|
|
80
|
+
gap: 'calc(var(--spacing) * 3)',
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
75
83
|
<Conversation.Root>
|
|
76
84
|
<Conversation.Messages isStreaming={status === 'streaming'}>
|
|
77
85
|
{messages.map((m) => (
|
|
78
86
|
<Message.Root
|
|
87
|
+
avatar={
|
|
88
|
+
m.role === 'user' ? undefined : (
|
|
89
|
+
<Avatar
|
|
90
|
+
color="primary"
|
|
91
|
+
icon={<AssistantIcon />}
|
|
92
|
+
name="AI"
|
|
93
|
+
size="sm"
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
79
97
|
from={m.role === 'user' ? 'user' : 'assistant'}
|
|
80
98
|
key={m.id}
|
|
81
99
|
>
|
|
82
|
-
{m.role !== 'user' && (
|
|
83
|
-
<Avatar
|
|
84
|
-
color="primary"
|
|
85
|
-
icon={<AssistantIcon />}
|
|
86
|
-
name="AI"
|
|
87
|
-
size="sm"
|
|
88
|
-
/>
|
|
89
|
-
)}
|
|
90
100
|
<Message.Content>{textOf(m)}</Message.Content>
|
|
91
101
|
</Message.Root>
|
|
92
102
|
))}
|
|
@@ -99,7 +109,7 @@ export function Chat() {
|
|
|
99
109
|
onSubmit={(text) => sendMessage({ text })}
|
|
100
110
|
status={status}
|
|
101
111
|
>
|
|
102
|
-
<PromptInput.Textarea placeholder="
|
|
112
|
+
<PromptInput.Textarea placeholder="Type a message" />
|
|
103
113
|
<PromptInput.Submit />
|
|
104
114
|
</PromptInput.Root>
|
|
105
115
|
</div>
|
|
@@ -109,7 +119,7 @@ export function Chat() {
|
|
|
109
119
|
|
|
110
120
|
## Conversation
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
The scrolling region for the conversation log, as a compound component. It sticks to the bottom and auto-scrolls on a new message. Once you scroll away from the bottom, a `ScrollButton` appears.
|
|
113
123
|
|
|
114
124
|
```tsx
|
|
115
125
|
import { Conversation } from '@k8ordo/ui/ai';
|
|
@@ -124,40 +134,94 @@ import { Conversation } from '@k8ordo/ui/ai';
|
|
|
124
134
|
|
|
125
135
|
Props (Conversation.Messages):
|
|
126
136
|
|
|
127
|
-
- `label`: string
|
|
128
|
-
- `isStreaming`: boolean
|
|
137
|
+
- `label`: string (default: `'チャット'`, used as the aria-label)
|
|
138
|
+
- `isStreaming`: boolean (reflected in `aria-busy`)
|
|
129
139
|
|
|
130
140
|
Props (Conversation.ScrollButton):
|
|
131
141
|
|
|
132
|
-
- `label`: string
|
|
142
|
+
- `label`: string (default: `'最新のメッセージへ移動'`)
|
|
133
143
|
|
|
134
144
|
## Message
|
|
135
145
|
|
|
136
|
-
|
|
146
|
+
A single message. `from="user"` renders as a right-aligned bubble; `from="assistant"` renders as running text. `avatar` sits beside the message, and the children stack in a column next to it — attachments, the content, sources, and the actions each get their own row.
|
|
137
147
|
|
|
138
148
|
```tsx
|
|
139
149
|
import { Message } from '@k8ordo/ui/ai';
|
|
140
150
|
|
|
141
151
|
<Message.Root from="user">
|
|
142
|
-
<Message.Content
|
|
152
|
+
<Message.Content>Hello</Message.Content>
|
|
143
153
|
</Message.Root>
|
|
144
154
|
|
|
145
|
-
<Message.Root from="assistant">
|
|
146
|
-
<Message.Content isStreaming
|
|
155
|
+
<Message.Root avatar={<Avatar icon={<AssistantIcon />} name="AI" size="sm" />} from="assistant">
|
|
156
|
+
<Message.Content isStreaming>Text still streaming…</Message.Content>
|
|
147
157
|
</Message.Root>
|
|
148
158
|
```
|
|
149
159
|
|
|
150
160
|
Props (Message.Root):
|
|
151
161
|
|
|
152
|
-
- `from`: `'user'` | `'assistant'
|
|
162
|
+
- `from`: `'user'` | `'assistant'` (required)
|
|
163
|
+
- `avatar`: ReactNode (shown beside the message: left for the assistant, right for the user)
|
|
164
|
+
- plus the other `div` attributes (`className` and `style` excluded)
|
|
153
165
|
|
|
154
166
|
Props (Message.Content):
|
|
155
167
|
|
|
156
|
-
- `isStreaming`: boolean
|
|
168
|
+
- `isStreaming`: boolean (shows the streaming cursor when true)
|
|
169
|
+
- plus the other `div` attributes (`className` and `style` excluded)
|
|
170
|
+
|
|
171
|
+
### Message actions
|
|
172
|
+
|
|
173
|
+
`Message.Actions` is the row of icon buttons under a message. `Copy`, `Regenerate`, and `Feedback` carry their own icons and dictionary labels; `Action` is the generic one for anything else. Each shows its label as a tooltip.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
<Message.Root avatar={avatar} from="assistant">
|
|
177
|
+
<Message.Content>{text}</Message.Content>
|
|
178
|
+
<Message.Actions>
|
|
179
|
+
<Message.Copy value={text} />
|
|
180
|
+
<Message.Regenerate
|
|
181
|
+
disabled={status === 'submitted' || status === 'streaming'}
|
|
182
|
+
onAction={() => regenerate({ messageId: message.id })}
|
|
183
|
+
/>
|
|
184
|
+
<Message.Feedback onChange={(value) => saveFeedback(message.id, value)} />
|
|
185
|
+
<Message.Action label="Share" onAction={() => share(message.id)}>
|
|
186
|
+
<LinkIcon size="sm" />
|
|
187
|
+
</Message.Action>
|
|
188
|
+
</Message.Actions>
|
|
189
|
+
</Message.Root>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- `Copy` is an icon-only, `sm` [`CopyButton`](components.md#copybutton): it writes `value` to the clipboard, shows a check icon — or an error icon when the clipboard refuses — for two seconds, and announces 「コピーしました」 or 「コピーできませんでした」 through a `status` region. Nothing is thrown either way.
|
|
193
|
+
- `Regenerate` and `Action` take `onAction`; a returned promise keeps the button busy (`aria-busy`, `aria-disabled`, presses ignored) until it settles, so `() => regenerate(...)` does not need its own pending state. The button keeps focus meanwhile.
|
|
194
|
+
- `Feedback` is a pair of toggle buttons (`aria-pressed`). Pressing the pressed one again clears it, so `onChange` receives `null`.
|
|
195
|
+
|
|
196
|
+
Props (Message.Actions):
|
|
197
|
+
|
|
198
|
+
- `label`: string (default: `'メッセージの操作'`, used as the group's aria-label)
|
|
199
|
+
|
|
200
|
+
Props (Message.Action):
|
|
201
|
+
|
|
202
|
+
- `label`: string (required; the accessible name and the tooltip)
|
|
203
|
+
- `onAction`: `() => void | Promise<void>`
|
|
204
|
+
- `disabled`: boolean
|
|
205
|
+
- `children`: ReactNode (the icon, `size="sm"`)
|
|
206
|
+
|
|
207
|
+
Props (Message.Copy):
|
|
208
|
+
|
|
209
|
+
- `value`: string (required; the text to copy)
|
|
210
|
+
- `label`: string (default: `'コピー'`)
|
|
211
|
+
|
|
212
|
+
Props (Message.Regenerate):
|
|
213
|
+
|
|
214
|
+
- `onAction`: `() => void | Promise<void>` (required)
|
|
215
|
+
- `label`: string (default: `'再生成'`)
|
|
216
|
+
- `disabled`: boolean
|
|
217
|
+
|
|
218
|
+
Props (Message.Feedback):
|
|
219
|
+
|
|
220
|
+
- `value` / `defaultValue` / `onChange`: `MessageFeedback | null`, controlled or uncontrolled (`onChange` is `(value: MessageFeedback | null) => void`; `null` is no feedback)
|
|
157
221
|
|
|
158
222
|
## PromptInput
|
|
159
223
|
|
|
160
|
-
|
|
224
|
+
The submit form. Enter sends; Shift+Enter inserts a newline; the Enter that commits an IME conversion does not send. While `status` is `'submitted'` or `'streaming'`, `Submit` turns into a stop button. The body is trimmed, and a message with neither text nor attachments is never sent.
|
|
161
225
|
|
|
162
226
|
```tsx
|
|
163
227
|
import { PromptInput } from '@k8ordo/ui/ai';
|
|
@@ -167,30 +231,121 @@ import { PromptInput } from '@k8ordo/ui/ai';
|
|
|
167
231
|
onSubmit={(message) => send(message)}
|
|
168
232
|
onStop={stop}
|
|
169
233
|
>
|
|
170
|
-
<PromptInput.Textarea placeholder="
|
|
234
|
+
<PromptInput.Textarea placeholder="Type a message" />
|
|
171
235
|
<PromptInput.Submit />
|
|
172
236
|
</PromptInput.Root>;
|
|
173
237
|
```
|
|
174
238
|
|
|
239
|
+
### Attachments
|
|
240
|
+
|
|
241
|
+
Pass `accept` to take files. It turns on all three ways in — the `Attach` button's file picker, dropping files onto the input, and pasting them into the textarea — and filters every one of them by the same rule as `<input accept>` (the browser applies it only to the picker). A dropped folder is skipped, as on `FileField.Dropzone`. Without `accept` the input takes text only: `Attach` renders nothing, a pasted file is not taken, and a file dragged over the input shows the not-allowed cursor — the drop is still cancelled, so the browser never opens the file and leaves the chat.
|
|
242
|
+
|
|
243
|
+
`PromptInput.Attachments` lists the files waiting to be sent, image thumbnails included, each with a remove button. `onSubmit` receives them as a `FileList` in its second argument, which the AI SDK's `sendMessage` takes as is. The list empties after each submit, and a message with attachments but no text can be sent — pass `{ files }` alone then, since `sendMessage` turns `text: ''` into an empty text part that some providers reject.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
<PromptInput.Root
|
|
247
|
+
accept="image/*,application/pdf"
|
|
248
|
+
maxFiles={4}
|
|
249
|
+
onStop={stop}
|
|
250
|
+
onSubmit={(text, files) =>
|
|
251
|
+
sendMessage(text === '' ? { files } : { text, files })
|
|
252
|
+
}
|
|
253
|
+
status={status}
|
|
254
|
+
>
|
|
255
|
+
<PromptInput.Attachments />
|
|
256
|
+
<PromptInput.Attach />
|
|
257
|
+
<PromptInput.Textarea placeholder="Type a message" />
|
|
258
|
+
<PromptInput.Submit />
|
|
259
|
+
</PromptInput.Root>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Put `Attachments` first: it takes a row of its own above the textarea. Choose `accept` from what your model reads — the AI SDK turns `image/*` and `text/*` into model input by itself, and other types need handling on your server.
|
|
263
|
+
|
|
175
264
|
Props (PromptInput.Root):
|
|
176
265
|
|
|
177
|
-
- `status`: ChatStatus
|
|
178
|
-
- `value` / `defaultValue` / `onChange`: controlled
|
|
179
|
-
- `onSubmit`: `(message: string) => void
|
|
180
|
-
- `onStop`: `() => void
|
|
266
|
+
- `status`: ChatStatus (default: `'ready'`)
|
|
267
|
+
- `value` / `defaultValue` / `onChange`: supports both controlled and uncontrolled use (`onChange` is `(value: string) => void`)
|
|
268
|
+
- `onSubmit`: `(message: string, files: FileList) => void` (the trimmed body, and the attachments — an empty `FileList` when there are none)
|
|
269
|
+
- `onStop`: `() => void` (when the stop button is pressed mid-send)
|
|
270
|
+
- `accept`: string (the file types to take, in `<input accept>` syntax; omit to take no files)
|
|
271
|
+
- `maxFiles`: number (files beyond it are dropped, first come first kept; `1` also makes the picker single-select)
|
|
272
|
+
|
|
273
|
+
Props (PromptInput.Attachments):
|
|
274
|
+
|
|
275
|
+
- `label`: string (default: `'添付ファイル'`, used as the list's aria-label)
|
|
276
|
+
|
|
277
|
+
Props (PromptInput.Attach):
|
|
278
|
+
|
|
279
|
+
- `label`: string (default: `'ファイルを添付'`)
|
|
181
280
|
|
|
182
281
|
Props (PromptInput.Textarea):
|
|
183
282
|
|
|
184
|
-
- `placeholder`: string
|
|
283
|
+
- `placeholder`: string, plus the other textarea attributes
|
|
185
284
|
|
|
186
285
|
Props (PromptInput.Submit):
|
|
187
286
|
|
|
188
|
-
- `sendLabel`: string
|
|
189
|
-
- `stopLabel`: string
|
|
287
|
+
- `sendLabel`: string (default: `'送信'`)
|
|
288
|
+
- `stopLabel`: string (default: `'停止'`)
|
|
289
|
+
|
|
290
|
+
## Attachment
|
|
291
|
+
|
|
292
|
+
Files attached to a sent message. An image (`image/*`, or the bare `image` the AI SDK allows) shows as a thumbnail with `filename` as its alt text; anything else shows as a chip with its name and media type.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import { Attachment } from '@k8ordo/ui/ai';
|
|
296
|
+
|
|
297
|
+
<Message.Root from="user">
|
|
298
|
+
<Attachment.List>
|
|
299
|
+
{files.map((file) => (
|
|
300
|
+
<Attachment.Item
|
|
301
|
+
filename={file.filename}
|
|
302
|
+
key={file.url}
|
|
303
|
+
mediaType={file.mediaType}
|
|
304
|
+
url={file.url}
|
|
305
|
+
/>
|
|
306
|
+
))}
|
|
307
|
+
</Attachment.List>
|
|
308
|
+
<Message.Content>{text}</Message.Content>
|
|
309
|
+
</Message.Root>;
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Props (Attachment.List):
|
|
313
|
+
|
|
314
|
+
- `label`: string (default: `'添付ファイル'`, used as the list's aria-label)
|
|
315
|
+
|
|
316
|
+
Props (Attachment.Item):
|
|
317
|
+
|
|
318
|
+
- `url`: string (required; a hosted URL or a data URL)
|
|
319
|
+
- `mediaType`: string (required)
|
|
320
|
+
- `filename`: string (without it an image's alt text is 「添付画像」 and a file chip shows the media type)
|
|
321
|
+
|
|
322
|
+
An image `url` is loaded as soon as the item renders, with no click in between. Pass URLs your own server produced or vouches for — a data URL, or your storage — rather than an arbitrary URL a model or tool wrote, which could point anywhere (a tracking pixel, an internal address). The AI SDK already turns files a provider generates into data URLs.
|
|
323
|
+
|
|
324
|
+
## Source
|
|
325
|
+
|
|
326
|
+
The sources a response cites. An item with an `http(s)` `href` is a link that opens in a new tab, labelled by `title` or else the host name; anything else — a document source, or a URL with another scheme — is plain text. The URL comes from the model, so a `javascript:` URL never becomes a link.
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
import { Source } from '@k8ordo/ui/ai';
|
|
330
|
+
|
|
331
|
+
<Source.List>
|
|
332
|
+
<Source.Item href="https://ordo.k8o.me/ui/ai/chat" title="AI chat" />
|
|
333
|
+
<Source.Item title="Internal design doc v3" />
|
|
334
|
+
</Source.List>;
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Props (Source.List):
|
|
338
|
+
|
|
339
|
+
- `label`: string (default: `'出典'`, used as the list's aria-label)
|
|
340
|
+
|
|
341
|
+
Props (Source.Item):
|
|
342
|
+
|
|
343
|
+
- `href`: string (the source's URL)
|
|
344
|
+
- `title`: string (the source's title; falls back to the host name)
|
|
190
345
|
|
|
191
346
|
## Reasoning
|
|
192
347
|
|
|
193
|
-
|
|
348
|
+
A collapsible view of the model's reasoning. While streaming, the label reads 「思考中…」.
|
|
194
349
|
|
|
195
350
|
```tsx
|
|
196
351
|
import { Reasoning } from '@k8ordo/ui/ai';
|
|
@@ -201,15 +356,14 @@ import { Reasoning } from '@k8ordo/ui/ai';
|
|
|
201
356
|
Props:
|
|
202
357
|
|
|
203
358
|
- `isStreaming`: boolean
|
|
204
|
-
- `isOpen` / `defaultOpen` / `onChange`:
|
|
359
|
+
- `isOpen` / `defaultOpen` / `onChange`: open state, controlled or uncontrolled (`onChange` is `(isOpen: boolean) => void`)
|
|
205
360
|
|
|
206
361
|
## Response
|
|
207
362
|
|
|
208
|
-
|
|
363
|
+
A streaming-aware Markdown renderer. It renders half-finished Markdown — an unclosed code block, say — without breaking. Requires the optional peer `streamdown` (see [setup](#setting-up-the-optional-peers)).
|
|
209
364
|
|
|
210
365
|
```tsx
|
|
211
366
|
import { Response } from '@k8ordo/ui/ai/response';
|
|
212
|
-
import 'streamdown/styles.css';
|
|
213
367
|
|
|
214
368
|
<Message.Content>
|
|
215
369
|
<Response isStreaming={isStreaming}>{markdown}</Response>
|
|
@@ -218,47 +372,47 @@ import 'streamdown/styles.css';
|
|
|
218
372
|
|
|
219
373
|
Props:
|
|
220
374
|
|
|
221
|
-
- `children`: string
|
|
375
|
+
- `children`: string (the Markdown, required)
|
|
222
376
|
- `isStreaming`: boolean
|
|
223
|
-
-
|
|
377
|
+
- Every other streamdown prop (`translations`, `controls`, `linkSafety`, `plugins`, `components`, `urlTransform`, `dir`, …) passes straight through. The library owns `className`, `mode` (`mode` is derived from `isStreaming`) and `portal`: the confirmation dialog and a table's full screen open inside the `Response`, where its styles reach them
|
|
224
378
|
|
|
225
|
-
|
|
379
|
+
The wording comes from the i18n dictionary of the current locale, so strings such as `responseCopyCode` and `responseDownloadTable` follow the rest of the components. Pass `translations` to change individual strings (prop > dictionary > streamdown's own default).
|
|
226
380
|
|
|
227
|
-
`linkSafety`
|
|
381
|
+
The library **defaults `linkSafety` to off**. With streamdown's own default (on), links render as `<button>` rather than `<a>`, which loses ⌘-click, middle-click, copying the link address, and the link role for assistive technology. Turn it on explicitly if you want the confirmation dialog:
|
|
228
382
|
|
|
229
383
|
```tsx
|
|
230
384
|
<Response linkSafety={{ enabled: true }}>{markdown}</Response>
|
|
231
385
|
```
|
|
232
386
|
|
|
233
|
-
|
|
387
|
+
Dangerous schemes such as `javascript:` are neutralized by rehype-harden regardless of `linkSafety`, so they never become live links even with the default.
|
|
234
388
|
|
|
235
389
|
## Suggestion
|
|
236
390
|
|
|
237
|
-
|
|
391
|
+
Suggested prompts shown as chips. Clicking one passes its `value` to `onSelect`.
|
|
238
392
|
|
|
239
393
|
```tsx
|
|
240
394
|
import { Suggestion } from '@k8ordo/ui/ai';
|
|
241
395
|
|
|
242
396
|
<Suggestion.List>
|
|
243
|
-
<Suggestion.Item onSelect={send} value="IME
|
|
397
|
+
<Suggestion.Item onSelect={send} value="Tell me about IME support" />
|
|
244
398
|
<Suggestion.Item onSelect={send} value="streaming">
|
|
245
|
-
|
|
399
|
+
How does streaming display work?
|
|
246
400
|
</Suggestion.Item>
|
|
247
401
|
</Suggestion.List>;
|
|
248
402
|
```
|
|
249
403
|
|
|
250
404
|
Props (Suggestion.List):
|
|
251
405
|
|
|
252
|
-
- `label`: string
|
|
406
|
+
- `label`: string (default: `'候補'`, used as the aria-label)
|
|
253
407
|
|
|
254
408
|
Props (Suggestion.Item):
|
|
255
409
|
|
|
256
|
-
- `value`: string
|
|
410
|
+
- `value`: string (required; also serves as the visible text when children is omitted)
|
|
257
411
|
- `onSelect`: `(value: string) => void`
|
|
258
412
|
|
|
259
413
|
## ToolInvocation
|
|
260
414
|
|
|
261
|
-
|
|
415
|
+
A collapsible view of a tool call. The icon switches between spinner, success, error, and denied according to `state` (approval responded and input streaming count as in-progress and show the spinner).
|
|
262
416
|
|
|
263
417
|
```tsx
|
|
264
418
|
import { ToolInvocation } from '@k8ordo/ui/ai';
|
|
@@ -267,23 +421,45 @@ import { ToolInvocation } from '@k8ordo/ui/ai';
|
|
|
267
421
|
name="search_web"
|
|
268
422
|
state="output-available"
|
|
269
423
|
input={{ query: 'k8ordo UI' }}
|
|
270
|
-
output="
|
|
424
|
+
output="Search results…"
|
|
271
425
|
/>;
|
|
272
426
|
```
|
|
273
427
|
|
|
428
|
+
### Approval
|
|
429
|
+
|
|
430
|
+
When `state` is `'approval-requested'`, the tool is waiting for the user. Pass the part's `approval` and an `onApprovalResponse`, and a question with Deny / Allow buttons appears below the header — outside the collapsible panel, so it is visible without expanding the call; the input stays one click away in the panel. Pressing one calls `onApprovalResponse({ id: approval.id, approved })`, which is exactly what the AI SDK's `addToolApprovalResponse` takes. Until a returned promise settles, both buttons are `aria-disabled` and ignore presses; they are not natively `disabled`, so the pressed one keeps focus while the answer is sent. Once the state moves on, the question disappears; if it held focus, focus moves to the tool's header instead of falling to `body`.
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
<ToolInvocation
|
|
434
|
+
name={part.name}
|
|
435
|
+
state={part.state}
|
|
436
|
+
input={part.input}
|
|
437
|
+
approval={part.approval}
|
|
438
|
+
onApprovalResponse={addToolApprovalResponse}
|
|
439
|
+
/>
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
- The question is `approval.requestReason` when the server gave one, 「このツールの実行を許可しますか?」 otherwise.
|
|
443
|
+
- An automatic decision (`approval.isAutomatic`) shows no question and no buttons; there is nothing for the user to answer.
|
|
444
|
+
- Without `onApprovalResponse`, the question shows but the buttons do not.
|
|
445
|
+
- In `'output-denied'`, the panel explains the denial with `approval.reason`, falling back to the default wording.
|
|
446
|
+
|
|
447
|
+
With the AI SDK, send the answer back automatically with `sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses` on `useChat`; otherwise nothing happens after the user answers.
|
|
448
|
+
|
|
274
449
|
Props:
|
|
275
450
|
|
|
276
|
-
- `name`: string
|
|
277
|
-
- `state`: ToolState
|
|
278
|
-
- `input`: unknown
|
|
279
|
-
- `output`: ReactNode
|
|
280
|
-
- `errorText`: string
|
|
281
|
-
- `
|
|
282
|
-
- `
|
|
451
|
+
- `name`: string (required, the tool name)
|
|
452
|
+
- `state`: ToolState (required)
|
|
453
|
+
- `input`: unknown (anything other than a string is shown as JSON)
|
|
454
|
+
- `output`: ReactNode (a string is shown in a `pre`; an element renders as-is)
|
|
455
|
+
- `errorText`: string (shown when `state="output-error"`; falls back to the default wording)
|
|
456
|
+
- `approval`: ToolApproval (the approval being asked for or answered; its `reason` explains an `output-denied` call)
|
|
457
|
+
- `onApprovalResponse`: `(response: ToolApprovalResponse) => void | PromiseLike<void>` (called with the approval `id` and the user's answer)
|
|
458
|
+
- `isOpen` / `defaultOpen` / `onChange`: open state, controlled or uncontrolled
|
|
283
459
|
|
|
284
|
-
## AI SDK
|
|
460
|
+
## AI SDK integration (mapMessageParts)
|
|
285
461
|
|
|
286
|
-
`@k8ordo/ui/ai-sdk`
|
|
462
|
+
`mapMessageParts` from `@k8ordo/ui/ai-sdk` converts the AI SDK's `UIMessage.parts` into a `MappedPart[]` that is easy to render. It has no React dependency and requires the optional peer `ai` (v7).
|
|
287
463
|
|
|
288
464
|
```ts
|
|
289
465
|
type MappedPart =
|
|
@@ -297,49 +473,156 @@ type MappedPart =
|
|
|
297
473
|
input?: unknown;
|
|
298
474
|
output?: unknown;
|
|
299
475
|
errorText?: string;
|
|
300
|
-
|
|
301
|
-
}
|
|
476
|
+
approval?: ToolApproval; // the part's own approval object, id included
|
|
477
|
+
}
|
|
478
|
+
| { kind: 'file'; url: string; mediaType: string; filename?: string }
|
|
479
|
+
| {
|
|
480
|
+
kind: 'source'; // both source-url and source-document
|
|
481
|
+
id: string;
|
|
482
|
+
url?: string; // source-url only
|
|
483
|
+
title?: string;
|
|
484
|
+
mediaType?: string; // source-document only
|
|
485
|
+
filename?: string; // source-document only
|
|
486
|
+
}
|
|
487
|
+
| { kind: 'data'; name: string; id?: string; data: unknown }; // `data-weather` → name 'weather'
|
|
302
488
|
```
|
|
303
489
|
|
|
304
|
-
|
|
490
|
+
Order is preserved. `step-start`, `custom`, and `reasoning-file` parts are skipped.
|
|
491
|
+
|
|
492
|
+
Render each part as its own row under `Message.Root` — the children stack in a column. Files and sources read better as one list each, so pull them out with `filter` and skip them in the loop. A `data` part is yours: pick the ones you know by `name`, and validate what the model put in them before drawing it.
|
|
305
493
|
|
|
306
494
|
```tsx
|
|
495
|
+
'use client';
|
|
496
|
+
import { useChat } from '@ai-sdk/react';
|
|
497
|
+
import { Avatar, AssistantIcon } from '@k8ordo/ui';
|
|
498
|
+
import {
|
|
499
|
+
Attachment,
|
|
500
|
+
Message,
|
|
501
|
+
Reasoning,
|
|
502
|
+
Source,
|
|
503
|
+
ToolInvocation,
|
|
504
|
+
} from '@k8ordo/ui/ai';
|
|
307
505
|
import { mapMessageParts } from '@k8ordo/ui/ai-sdk';
|
|
308
|
-
import { Reasoning, ToolInvocation } from '@k8ordo/ui/ai';
|
|
309
506
|
import { Response } from '@k8ordo/ui/ai/response';
|
|
507
|
+
import { validateGeneratedSpec } from '@k8ordo/ui/json-render';
|
|
508
|
+
import { JsonRenderUI } from '@k8ordo/ui/json-render/registry';
|
|
509
|
+
import { lastAssistantMessageIsCompleteWithApprovalResponses } from 'ai';
|
|
510
|
+
import type { UIMessage } from 'ai';
|
|
310
511
|
|
|
311
|
-
<
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
512
|
+
type Chat = ReturnType<typeof useChat>;
|
|
513
|
+
|
|
514
|
+
function ChatMessage({ message, chat }: { message: UIMessage; chat: Chat }) {
|
|
515
|
+
const parts = mapMessageParts(message);
|
|
516
|
+
const files = parts.filter((part) => part.kind === 'file');
|
|
517
|
+
const sources = parts.filter((part) => part.kind === 'source');
|
|
518
|
+
const text = parts
|
|
519
|
+
.map((part) => (part.kind === 'text' ? part.text : ''))
|
|
520
|
+
.join('');
|
|
521
|
+
const isUser = message.role === 'user';
|
|
522
|
+
|
|
523
|
+
return (
|
|
524
|
+
<Message.Root
|
|
525
|
+
avatar={
|
|
526
|
+
isUser ? undefined : (
|
|
527
|
+
<Avatar icon={<AssistantIcon />} name="AI" size="sm" />
|
|
528
|
+
)
|
|
529
|
+
}
|
|
530
|
+
from={isUser ? 'user' : 'assistant'}
|
|
531
|
+
>
|
|
532
|
+
{files.length > 0 && (
|
|
533
|
+
<Attachment.List>
|
|
534
|
+
{files.map((file) => (
|
|
535
|
+
<Attachment.Item
|
|
536
|
+
filename={file.filename}
|
|
537
|
+
key={file.url}
|
|
538
|
+
mediaType={file.mediaType}
|
|
539
|
+
url={file.url}
|
|
540
|
+
/>
|
|
541
|
+
))}
|
|
542
|
+
</Attachment.List>
|
|
543
|
+
)}
|
|
544
|
+
{parts.map((part, i) => {
|
|
545
|
+
const key = `${message.id}-${i}`;
|
|
546
|
+
if (part.kind === 'text') {
|
|
547
|
+
return (
|
|
548
|
+
<Message.Content key={key}>
|
|
549
|
+
<Response>{part.text}</Response>
|
|
550
|
+
</Message.Content>
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
if (part.kind === 'reasoning') {
|
|
554
|
+
return <Reasoning key={key}>{part.text}</Reasoning>;
|
|
555
|
+
}
|
|
556
|
+
if (part.kind === 'tool') {
|
|
557
|
+
return (
|
|
558
|
+
<ToolInvocation
|
|
559
|
+
approval={part.approval}
|
|
560
|
+
errorText={part.errorText}
|
|
561
|
+
input={part.input}
|
|
562
|
+
key={part.toolCallId}
|
|
563
|
+
name={part.name}
|
|
564
|
+
onApprovalResponse={chat.addToolApprovalResponse}
|
|
565
|
+
// output is unknown, so convert it to a ReactNode first
|
|
566
|
+
output={
|
|
567
|
+
part.output === undefined
|
|
568
|
+
? undefined
|
|
569
|
+
: JSON.stringify(part.output, null, 2)
|
|
570
|
+
}
|
|
571
|
+
state={part.state}
|
|
572
|
+
/>
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
if (part.kind === 'data' && part.name === 'ui') {
|
|
576
|
+
const result = validateGeneratedSpec(part.data);
|
|
577
|
+
return result.ok ? (
|
|
578
|
+
<JsonRenderUI key={key} spec={result.spec} />
|
|
579
|
+
) : null;
|
|
580
|
+
}
|
|
581
|
+
return null;
|
|
582
|
+
})}
|
|
583
|
+
{sources.length > 0 && (
|
|
584
|
+
<Source.List>
|
|
585
|
+
{sources.map((source) => (
|
|
586
|
+
<Source.Item
|
|
587
|
+
href={source.url}
|
|
588
|
+
key={source.id}
|
|
589
|
+
title={source.title}
|
|
590
|
+
/>
|
|
591
|
+
))}
|
|
592
|
+
</Source.List>
|
|
593
|
+
)}
|
|
594
|
+
{!isUser && text !== '' && (
|
|
595
|
+
<Message.Actions>
|
|
596
|
+
<Message.Copy value={text} />
|
|
597
|
+
<Message.Regenerate
|
|
598
|
+
disabled={
|
|
599
|
+
chat.status === 'submitted' || chat.status === 'streaming'
|
|
600
|
+
}
|
|
601
|
+
onAction={() => chat.regenerate({ messageId: message.id })}
|
|
602
|
+
/>
|
|
603
|
+
<Message.Feedback />
|
|
604
|
+
</Message.Actions>
|
|
605
|
+
)}
|
|
606
|
+
</Message.Root>
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export function Chat() {
|
|
611
|
+
const chat = useChat({
|
|
612
|
+
// sends the answers back as soon as every pending approval has one
|
|
613
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
614
|
+
});
|
|
615
|
+
// … Conversation.Root / chat.messages.map((message) => <ChatMessage … />) / PromptInput
|
|
616
|
+
}
|
|
336
617
|
```
|
|
337
618
|
|
|
338
|
-
`
|
|
619
|
+
`examples/ui-integrations` in the repository runs this against the real `useChat`, with a scripted transport in place of a model.
|
|
620
|
+
|
|
621
|
+
`@k8ordo/ui/ai-sdk` exports the `MappedPart` type, and re-exports the `ChatStatus`, `ToolState`, `ToolApproval`, and `ToolApprovalResponse` types as well.
|
|
339
622
|
|
|
340
|
-
##
|
|
623
|
+
## Combining with generative UI
|
|
341
624
|
|
|
342
|
-
|
|
625
|
+
A UI spec returned by an LLM as a tool result can be rendered inside a chat bubble. See the [generative UI reference](generative-ui.md) for details.
|
|
343
626
|
|
|
344
627
|
```tsx
|
|
345
628
|
'use client';
|