@adea-ai/ui 0.140.0 → 0.142.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/dist/components/composites/appearance-editor/appearance-editor.js +2 -2
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/catalog-browser/catalog-browser-group.js +1 -1
- package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts +56 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts.map +1 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.js +117 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.js.map +1 -0
- package/dist/components/composites/chain-of-thought/index.d.ts +2 -0
- package/dist/components/composites/chain-of-thought/index.d.ts.map +1 -0
- package/dist/components/composites/chain-of-thought/index.js +2 -0
- package/dist/components/composites/chat/chat.d.ts +67 -0
- package/dist/components/composites/chat/chat.d.ts.map +1 -0
- package/dist/components/composites/chat/chat.js +179 -0
- package/dist/components/composites/chat/chat.js.map +1 -0
- package/dist/components/composites/chat/index.d.ts +2 -0
- package/dist/components/composites/chat/index.d.ts.map +1 -0
- package/dist/components/composites/chat/index.js +2 -0
- package/dist/components/composites/checkpoint/checkpoint-model.d.ts +34 -0
- package/dist/components/composites/checkpoint/checkpoint-model.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint-model.js +48 -0
- package/dist/components/composites/checkpoint/checkpoint-model.js.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint.d.ts +48 -0
- package/dist/components/composites/checkpoint/checkpoint.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint.js +160 -0
- package/dist/components/composites/checkpoint/checkpoint.js.map +1 -0
- package/dist/components/composites/checkpoint/index.d.ts +3 -0
- package/dist/components/composites/checkpoint/index.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/index.js +3 -0
- package/dist/components/composites/confirmation/confirmation-model.d.ts +45 -0
- package/dist/components/composites/confirmation/confirmation-model.d.ts.map +1 -0
- package/dist/components/composites/confirmation/confirmation-model.js +51 -0
- package/dist/components/composites/confirmation/confirmation-model.js.map +1 -0
- package/dist/components/composites/confirmation/confirmation.d.ts +72 -0
- package/dist/components/composites/confirmation/confirmation.d.ts.map +1 -0
- package/dist/components/composites/confirmation/confirmation.js +300 -0
- package/dist/components/composites/confirmation/confirmation.js.map +1 -0
- package/dist/components/composites/confirmation/index.d.ts +3 -0
- package/dist/components/composites/confirmation/index.d.ts.map +1 -0
- package/dist/components/composites/confirmation/index.js +3 -0
- package/dist/components/composites/context/context-model.d.ts +69 -0
- package/dist/components/composites/context/context-model.d.ts.map +1 -0
- package/dist/components/composites/context/context-model.js +122 -0
- package/dist/components/composites/context/context-model.js.map +1 -0
- package/dist/components/composites/context/context.d.ts +38 -0
- package/dist/components/composites/context/context.d.ts.map +1 -0
- package/dist/components/composites/context/context.js +234 -0
- package/dist/components/composites/context/context.js.map +1 -0
- package/dist/components/composites/context/index.d.ts +3 -0
- package/dist/components/composites/context/index.d.ts.map +1 -0
- package/dist/components/composites/context/index.js +3 -0
- package/dist/components/composites/file-tree/build-file-tree.d.ts +138 -0
- package/dist/components/composites/file-tree/build-file-tree.d.ts.map +1 -0
- package/dist/components/composites/file-tree/build-file-tree.js +325 -0
- package/dist/components/composites/file-tree/build-file-tree.js.map +1 -0
- package/dist/components/composites/file-tree/file-tree.d.ts +74 -0
- package/dist/components/composites/file-tree/file-tree.d.ts.map +1 -0
- package/dist/components/composites/file-tree/file-tree.js +389 -0
- package/dist/components/composites/file-tree/file-tree.js.map +1 -0
- package/dist/components/composites/file-tree/index.d.ts +3 -0
- package/dist/components/composites/file-tree/index.d.ts.map +1 -0
- package/dist/components/composites/file-tree/index.js +3 -0
- package/dist/components/composites/inline-citation/citation.d.ts +37 -0
- package/dist/components/composites/inline-citation/citation.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/citation.js +52 -0
- package/dist/components/composites/inline-citation/citation.js.map +1 -0
- package/dist/components/composites/inline-citation/index.d.ts +3 -0
- package/dist/components/composites/inline-citation/index.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/index.js +3 -0
- package/dist/components/composites/inline-citation/inline-citation.d.ts +64 -0
- package/dist/components/composites/inline-citation/inline-citation.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/inline-citation.js +272 -0
- package/dist/components/composites/inline-citation/inline-citation.js.map +1 -0
- package/dist/components/composites/message-scroller/index.d.ts +3 -0
- package/dist/components/composites/message-scroller/index.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/index.js +3 -0
- package/dist/components/composites/message-scroller/message-scroller.d.ts +55 -0
- package/dist/components/composites/message-scroller/message-scroller.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/message-scroller.js +201 -0
- package/dist/components/composites/message-scroller/message-scroller.js.map +1 -0
- package/dist/components/composites/message-scroller/scroll-anchor.d.ts +66 -0
- package/dist/components/composites/message-scroller/scroll-anchor.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/scroll-anchor.js +122 -0
- package/dist/components/composites/message-scroller/scroll-anchor.js.map +1 -0
- package/dist/components/composites/model-selector/index.d.ts +3 -0
- package/dist/components/composites/model-selector/index.d.ts.map +1 -0
- package/dist/components/composites/model-selector/index.js +3 -0
- package/dist/components/composites/model-selector/model-selector.d.ts +55 -0
- package/dist/components/composites/model-selector/model-selector.d.ts.map +1 -0
- package/dist/components/composites/model-selector/model-selector.js +490 -0
- package/dist/components/composites/model-selector/model-selector.js.map +1 -0
- package/dist/components/composites/model-selector/models.d.ts +51 -0
- package/dist/components/composites/model-selector/models.d.ts.map +1 -0
- package/dist/components/composites/model-selector/models.js +71 -0
- package/dist/components/composites/model-selector/models.js.map +1 -0
- package/dist/components/composites/plan/index.d.ts +2 -0
- package/dist/components/composites/plan/index.d.ts.map +1 -0
- package/dist/components/composites/plan/index.js +2 -0
- package/dist/components/composites/plan/plan.d.ts +61 -0
- package/dist/components/composites/plan/plan.d.ts.map +1 -0
- package/dist/components/composites/plan/plan.js +130 -0
- package/dist/components/composites/plan/plan.js.map +1 -0
- package/dist/components/composites/queue/index.d.ts +2 -0
- package/dist/components/composites/queue/index.d.ts.map +1 -0
- package/dist/components/composites/queue/index.js +2 -0
- package/dist/components/composites/queue/queue.d.ts +77 -0
- package/dist/components/composites/queue/queue.d.ts.map +1 -0
- package/dist/components/composites/queue/queue.js +271 -0
- package/dist/components/composites/queue/queue.js.map +1 -0
- package/dist/components/composites/reasoning/index.d.ts +2 -0
- package/dist/components/composites/reasoning/index.d.ts.map +1 -0
- package/dist/components/composites/reasoning/index.js +2 -0
- package/dist/components/composites/reasoning/reasoning.d.ts +62 -0
- package/dist/components/composites/reasoning/reasoning.d.ts.map +1 -0
- package/dist/components/composites/reasoning/reasoning.js +156 -0
- package/dist/components/composites/reasoning/reasoning.js.map +1 -0
- package/dist/components/composites/sources/index.d.ts +3 -0
- package/dist/components/composites/sources/index.d.ts.map +1 -0
- package/dist/components/composites/sources/index.js +3 -0
- package/dist/components/composites/sources/source.d.ts +46 -0
- package/dist/components/composites/sources/source.d.ts.map +1 -0
- package/dist/components/composites/sources/source.js +74 -0
- package/dist/components/composites/sources/source.js.map +1 -0
- package/dist/components/composites/sources/sources.d.ts +45 -0
- package/dist/components/composites/sources/sources.d.ts.map +1 -0
- package/dist/components/composites/sources/sources.js +175 -0
- package/dist/components/composites/sources/sources.js.map +1 -0
- package/dist/components/composites/stack-trace/index.d.ts +3 -0
- package/dist/components/composites/stack-trace/index.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/index.js +3 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.d.ts +118 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.js +376 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.js.map +1 -0
- package/dist/components/composites/stack-trace/stack-trace.d.ts +63 -0
- package/dist/components/composites/stack-trace/stack-trace.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/stack-trace.js +491 -0
- package/dist/components/composites/stack-trace/stack-trace.js.map +1 -0
- package/dist/components/composites/subagent/index.d.ts +2 -0
- package/dist/components/composites/subagent/index.d.ts.map +1 -0
- package/dist/components/composites/subagent/index.js +2 -0
- package/dist/components/composites/subagent/subagent.d.ts +55 -0
- package/dist/components/composites/subagent/subagent.d.ts.map +1 -0
- package/dist/components/composites/subagent/subagent.js +138 -0
- package/dist/components/composites/subagent/subagent.js.map +1 -0
- package/dist/components/composites/suggestion/index.d.ts +2 -0
- package/dist/components/composites/suggestion/index.d.ts.map +1 -0
- package/dist/components/composites/suggestion/index.js +2 -0
- package/dist/components/composites/suggestion/suggestion.d.ts +37 -0
- package/dist/components/composites/suggestion/suggestion.d.ts.map +1 -0
- package/dist/components/composites/suggestion/suggestion.js +100 -0
- package/dist/components/composites/suggestion/suggestion.js.map +1 -0
- package/dist/components/composites/task/index.d.ts +2 -0
- package/dist/components/composites/task/index.d.ts.map +1 -0
- package/dist/components/composites/task/index.js +2 -0
- package/dist/components/composites/task/task.d.ts +96 -0
- package/dist/components/composites/task/task.d.ts.map +1 -0
- package/dist/components/composites/task/task.js +311 -0
- package/dist/components/composites/task/task.js.map +1 -0
- package/dist/components/composites/terminal/ansi.d.ts +101 -0
- package/dist/components/composites/terminal/ansi.d.ts.map +1 -0
- package/dist/components/composites/terminal/ansi.js +544 -0
- package/dist/components/composites/terminal/ansi.js.map +1 -0
- package/dist/components/composites/terminal/index.d.ts +4 -0
- package/dist/components/composites/terminal/index.d.ts.map +1 -0
- package/dist/components/composites/terminal/index.js +4 -0
- package/dist/components/composites/terminal/terminal-model.d.ts +63 -0
- package/dist/components/composites/terminal/terminal-model.d.ts.map +1 -0
- package/dist/components/composites/terminal/terminal-model.js +69 -0
- package/dist/components/composites/terminal/terminal-model.js.map +1 -0
- package/dist/components/composites/terminal/terminal.d.ts +88 -0
- package/dist/components/composites/terminal/terminal.d.ts.map +1 -0
- package/dist/components/composites/terminal/terminal.js +500 -0
- package/dist/components/composites/terminal/terminal.js.map +1 -0
- package/dist/components/composites/test-results/index.d.ts +3 -0
- package/dist/components/composites/test-results/index.d.ts.map +1 -0
- package/dist/components/composites/test-results/index.js +3 -0
- package/dist/components/composites/test-results/test-results-model.d.ts +154 -0
- package/dist/components/composites/test-results/test-results-model.d.ts.map +1 -0
- package/dist/components/composites/test-results/test-results-model.js +252 -0
- package/dist/components/composites/test-results/test-results-model.js.map +1 -0
- package/dist/components/composites/test-results/test-results.d.ts +60 -0
- package/dist/components/composites/test-results/test-results.d.ts.map +1 -0
- package/dist/components/composites/test-results/test-results.js +631 -0
- package/dist/components/composites/test-results/test-results.js.map +1 -0
- package/dist/components/composites/tool/format-tool-value.d.ts +37 -0
- package/dist/components/composites/tool/format-tool-value.d.ts.map +1 -0
- package/dist/components/composites/tool/format-tool-value.js +135 -0
- package/dist/components/composites/tool/format-tool-value.js.map +1 -0
- package/dist/components/composites/tool/index.d.ts +3 -0
- package/dist/components/composites/tool/index.d.ts.map +1 -0
- package/dist/components/composites/tool/index.js +3 -0
- package/dist/components/composites/tool/tool.d.ts +69 -0
- package/dist/components/composites/tool/tool.d.ts.map +1 -0
- package/dist/components/composites/tool/tool.js +214 -0
- package/dist/components/composites/tool/tool.js.map +1 -0
- package/dist/components/composites/update-dialog/update-dialog.js +1 -1
- package/dist/components/conversation/conversation-surface.d.ts +7 -0
- package/dist/components/conversation/conversation-surface.d.ts.map +1 -1
- package/dist/components/conversation/conversation-surface.js +2 -0
- package/dist/components/conversation/conversation-surface.js.map +1 -1
- package/dist/components/conversation/scroll-follow-core.d.ts +24 -0
- package/dist/components/conversation/scroll-follow-core.d.ts.map +1 -1
- package/dist/components/conversation/scroll-follow-core.js +23 -1
- package/dist/components/conversation/scroll-follow-core.js.map +1 -1
- package/dist/components/conversation/scroll-follow.d.ts +3 -0
- package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
- package/dist/components/conversation/scroll-follow.js +80 -1
- package/dist/components/conversation/scroll-follow.js.map +1 -1
- package/dist/components/ui/attachment/attachment.d.ts +58 -0
- package/dist/components/ui/attachment/attachment.d.ts.map +1 -0
- package/dist/components/ui/attachment/attachment.js +279 -0
- package/dist/components/ui/attachment/attachment.js.map +1 -0
- package/dist/components/ui/attachment/index.d.ts +2 -0
- package/dist/components/ui/attachment/index.d.ts.map +1 -0
- package/dist/components/ui/attachment/index.js +2 -0
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/bubble/bubble.d.ts +33 -0
- package/dist/components/ui/bubble/bubble.d.ts.map +1 -0
- package/dist/components/ui/bubble/bubble.js +95 -0
- package/dist/components/ui/bubble/bubble.js.map +1 -0
- package/dist/components/ui/bubble/index.d.ts +2 -0
- package/dist/components/ui/bubble/index.d.ts.map +1 -0
- package/dist/components/ui/bubble/index.js +2 -0
- package/dist/components/ui/button/button.d.ts +1 -1
- package/dist/components/ui/code-block/code-block.d.ts +56 -3
- package/dist/components/ui/code-block/code-block.d.ts.map +1 -1
- package/dist/components/ui/code-block/code-block.js +231 -50
- package/dist/components/ui/code-block/code-block.js.map +1 -1
- package/dist/components/ui/code-block/index.d.ts +1 -1
- package/dist/components/ui/code-block/index.d.ts.map +1 -1
- package/dist/components/ui/code-block/index.js +2 -2
- package/dist/components/ui/field/number-field.d.ts +21 -4
- package/dist/components/ui/field/number-field.d.ts.map +1 -1
- package/dist/components/ui/field/number-field.js +22 -11
- package/dist/components/ui/field/number-field.js.map +1 -1
- package/dist/components/ui/marker/index.d.ts +2 -0
- package/dist/components/ui/marker/index.d.ts.map +1 -0
- package/dist/components/ui/marker/index.js +2 -0
- package/dist/components/ui/marker/marker.d.ts +35 -0
- package/dist/components/ui/marker/marker.d.ts.map +1 -0
- package/dist/components/ui/marker/marker.js +123 -0
- package/dist/components/ui/marker/marker.js.map +1 -0
- package/dist/components/ui/message/cite-ranges.d.ts +42 -0
- package/dist/components/ui/message/cite-ranges.d.ts.map +1 -0
- package/dist/components/ui/message/cite-ranges.js +105 -0
- package/dist/components/ui/message/cite-ranges.js.map +1 -0
- package/dist/components/ui/message/index.d.ts +4 -0
- package/dist/components/ui/message/index.d.ts.map +1 -0
- package/dist/components/ui/message/index.js +4 -0
- package/dist/components/ui/message/message.d.ts +95 -0
- package/dist/components/ui/message/message.d.ts.map +1 -0
- package/dist/components/ui/message/message.js +443 -0
- package/dist/components/ui/message/message.js.map +1 -0
- package/dist/components/ui/message/parse-message-text.d.ts +93 -0
- package/dist/components/ui/message/parse-message-text.d.ts.map +1 -0
- package/dist/components/ui/message/parse-message-text.js +365 -0
- package/dist/components/ui/message/parse-message-text.js.map +1 -0
- package/dist/components/ui/questionnaire/index.d.ts +2 -0
- package/dist/components/ui/questionnaire/index.d.ts.map +1 -0
- package/dist/components/ui/questionnaire/index.js +2 -0
- package/dist/components/ui/questionnaire/questionnaire.d.ts +83 -0
- package/dist/components/ui/questionnaire/questionnaire.d.ts.map +1 -0
- package/dist/components/ui/questionnaire/questionnaire.js +470 -0
- package/dist/components/ui/questionnaire/questionnaire.js.map +1 -0
- package/dist/components/ui/status-chip/status-chip.d.ts +1 -1
- package/dist/components/ui/switch/switch.js +11 -11
- package/dist/components/ui/switch/switch.js.map +1 -1
- package/dist/components/ui/trace/index.d.ts +2 -0
- package/dist/components/ui/trace/index.d.ts.map +1 -0
- package/dist/components/ui/trace/index.js +2 -0
- package/dist/components/ui/trace/trace.d.ts +72 -0
- package/dist/components/ui/trace/trace.d.ts.map +1 -0
- package/dist/components/ui/trace/trace.js +340 -0
- package/dist/components/ui/trace/trace.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -5
- package/dist/r/attachment.json +25 -0
- package/dist/r/bubble.json +22 -0
- package/dist/r/chain-of-thought.json +26 -0
- package/dist/r/chat.json +24 -0
- package/dist/r/checkpoint.json +35 -0
- package/dist/r/confirmation.json +34 -0
- package/dist/r/context.json +33 -0
- package/dist/r/file-tree.json +32 -0
- package/dist/r/inline-citation.json +35 -0
- package/dist/r/marker.json +22 -0
- package/dist/r/message-scroller.json +31 -0
- package/dist/r/message.json +33 -0
- package/dist/r/model-selector.json +34 -0
- package/dist/r/plan.json +26 -0
- package/dist/r/questionnaire.json +28 -0
- package/dist/r/queue.json +26 -0
- package/dist/r/reasoning.json +26 -0
- package/dist/r/registry.json +811 -52
- package/dist/r/sources.json +32 -0
- package/dist/r/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
- package/dist/r/src/components/composites/chain-of-thought/index.ts +11 -0
- package/dist/r/src/components/composites/chat/chat.tsx +190 -0
- package/dist/r/src/components/composites/chat/index.ts +11 -0
- package/dist/r/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
- package/dist/r/src/components/composites/checkpoint/checkpoint.tsx +214 -0
- package/dist/r/src/components/composites/checkpoint/index.ts +8 -0
- package/dist/r/src/components/composites/confirmation/confirmation-model.ts +83 -0
- package/dist/r/src/components/composites/confirmation/confirmation.tsx +311 -0
- package/dist/r/src/components/composites/confirmation/index.ts +9 -0
- package/dist/r/src/components/composites/context/context-model.ts +168 -0
- package/dist/r/src/components/composites/context/context.tsx +187 -0
- package/dist/r/src/components/composites/context/index.ts +18 -0
- package/dist/r/src/components/composites/file-tree/build-file-tree.ts +456 -0
- package/dist/r/src/components/composites/file-tree/file-tree.tsx +405 -0
- package/dist/r/src/components/composites/file-tree/index.ts +25 -0
- package/dist/r/src/components/composites/inline-citation/citation.ts +78 -0
- package/dist/r/src/components/composites/inline-citation/index.ts +9 -0
- package/dist/r/src/components/composites/inline-citation/inline-citation.tsx +285 -0
- package/dist/r/src/components/composites/message-scroller/index.ts +2 -0
- package/dist/r/src/components/composites/message-scroller/message-scroller.tsx +301 -0
- package/dist/r/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
- package/dist/r/src/components/composites/model-selector/index.ts +14 -0
- package/dist/r/src/components/composites/model-selector/model-selector.tsx +420 -0
- package/dist/r/src/components/composites/model-selector/models.ts +103 -0
- package/dist/r/src/components/composites/plan/index.ts +1 -0
- package/dist/r/src/components/composites/plan/plan.tsx +155 -0
- package/dist/r/src/components/composites/queue/index.ts +10 -0
- package/dist/r/src/components/composites/queue/queue.tsx +264 -0
- package/dist/r/src/components/composites/reasoning/index.ts +1 -0
- package/dist/r/src/components/composites/reasoning/reasoning.tsx +176 -0
- package/dist/r/src/components/composites/sources/index.ts +11 -0
- package/dist/r/src/components/composites/sources/source.ts +116 -0
- package/dist/r/src/components/composites/sources/sources.tsx +163 -0
- package/dist/r/src/components/composites/stack-trace/index.ts +19 -0
- package/dist/r/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
- package/dist/r/src/components/composites/stack-trace/stack-trace.tsx +395 -0
- package/dist/r/src/components/composites/subagent/index.ts +1 -0
- package/dist/r/src/components/composites/subagent/subagent.tsx +159 -0
- package/dist/r/src/components/composites/suggestion/index.ts +1 -0
- package/dist/r/src/components/composites/suggestion/suggestion.tsx +140 -0
- package/dist/r/src/components/composites/task/index.ts +14 -0
- package/dist/r/src/components/composites/task/task.tsx +317 -0
- package/dist/r/src/components/composites/terminal/ansi.ts +674 -0
- package/dist/r/src/components/composites/terminal/index.ts +20 -0
- package/dist/r/src/components/composites/terminal/terminal-model.ts +111 -0
- package/dist/r/src/components/composites/terminal/terminal.tsx +574 -0
- package/dist/r/src/components/composites/test-results/index.ts +20 -0
- package/dist/r/src/components/composites/test-results/test-results-model.ts +368 -0
- package/dist/r/src/components/composites/test-results/test-results.tsx +586 -0
- package/dist/r/src/components/composites/tool/format-tool-value.ts +221 -0
- package/dist/r/src/components/composites/tool/index.ts +2 -0
- package/dist/r/src/components/composites/tool/tool.tsx +228 -0
- package/dist/r/src/components/conversation/conversation-surface.tsx +9 -0
- package/dist/r/src/components/conversation/scroll-follow-core.ts +31 -0
- package/dist/r/src/components/conversation/scroll-follow.ts +92 -0
- package/dist/r/src/components/ui/attachment/attachment.tsx +282 -0
- package/dist/r/src/components/ui/attachment/index.ts +10 -0
- package/dist/r/src/components/ui/bubble/bubble.tsx +86 -0
- package/dist/r/src/components/ui/bubble/index.ts +1 -0
- package/dist/r/src/components/ui/code-block/code-block.tsx +256 -26
- package/dist/r/src/components/ui/code-block/index.ts +9 -1
- package/dist/r/src/components/ui/field/number-field.tsx +51 -14
- package/dist/r/src/components/ui/marker/index.ts +1 -0
- package/dist/r/src/components/ui/marker/marker.tsx +90 -0
- package/dist/r/src/components/ui/message/cite-ranges.ts +144 -0
- package/dist/r/src/components/ui/message/index.ts +23 -0
- package/dist/r/src/components/ui/message/message.tsx +434 -0
- package/dist/r/src/components/ui/message/parse-message-text.ts +450 -0
- package/dist/r/src/components/ui/questionnaire/index.ts +10 -0
- package/dist/r/src/components/ui/questionnaire/questionnaire.tsx +446 -0
- package/dist/r/src/components/ui/trace/index.ts +9 -0
- package/dist/r/src/components/ui/trace/trace.tsx +334 -0
- package/dist/r/src/styles/base.css +34 -0
- package/dist/r/stack-trace.json +32 -0
- package/dist/r/subagent.json +27 -0
- package/dist/r/suggestion.json +24 -0
- package/dist/r/task.json +28 -0
- package/dist/r/terminal.json +35 -0
- package/dist/r/test-results.json +33 -0
- package/dist/r/tool.json +31 -0
- package/dist/r/trace.json +25 -0
- package/package.json +6 -3
- package/registry.json +811 -52
- package/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
- package/src/components/composites/chain-of-thought/index.ts +11 -0
- package/src/components/composites/chat/chat.tsx +190 -0
- package/src/components/composites/chat/index.ts +11 -0
- package/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
- package/src/components/composites/checkpoint/checkpoint.tsx +214 -0
- package/src/components/composites/checkpoint/index.ts +8 -0
- package/src/components/composites/confirmation/confirmation-model.ts +83 -0
- package/src/components/composites/confirmation/confirmation.tsx +311 -0
- package/src/components/composites/confirmation/index.ts +9 -0
- package/src/components/composites/context/context-model.ts +168 -0
- package/src/components/composites/context/context.tsx +187 -0
- package/src/components/composites/context/index.ts +18 -0
- package/src/components/composites/file-tree/build-file-tree.ts +456 -0
- package/src/components/composites/file-tree/file-tree.tsx +405 -0
- package/src/components/composites/file-tree/index.ts +25 -0
- package/src/components/composites/inline-citation/citation.ts +78 -0
- package/src/components/composites/inline-citation/index.ts +9 -0
- package/src/components/composites/inline-citation/inline-citation.tsx +285 -0
- package/src/components/composites/message-scroller/index.ts +2 -0
- package/src/components/composites/message-scroller/message-scroller.tsx +301 -0
- package/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
- package/src/components/composites/model-selector/index.ts +14 -0
- package/src/components/composites/model-selector/model-selector.tsx +420 -0
- package/src/components/composites/model-selector/models.ts +103 -0
- package/src/components/composites/plan/index.ts +1 -0
- package/src/components/composites/plan/plan.tsx +155 -0
- package/src/components/composites/queue/index.ts +10 -0
- package/src/components/composites/queue/queue.tsx +264 -0
- package/src/components/composites/reasoning/index.ts +1 -0
- package/src/components/composites/reasoning/reasoning.tsx +176 -0
- package/src/components/composites/sources/index.ts +11 -0
- package/src/components/composites/sources/source.ts +116 -0
- package/src/components/composites/sources/sources.tsx +163 -0
- package/src/components/composites/stack-trace/index.ts +19 -0
- package/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
- package/src/components/composites/stack-trace/stack-trace.tsx +395 -0
- package/src/components/composites/subagent/index.ts +1 -0
- package/src/components/composites/subagent/subagent.tsx +159 -0
- package/src/components/composites/suggestion/index.ts +1 -0
- package/src/components/composites/suggestion/suggestion.tsx +140 -0
- package/src/components/composites/task/index.ts +14 -0
- package/src/components/composites/task/task.tsx +317 -0
- package/src/components/composites/terminal/ansi.ts +674 -0
- package/src/components/composites/terminal/index.ts +20 -0
- package/src/components/composites/terminal/terminal-model.ts +111 -0
- package/src/components/composites/terminal/terminal.tsx +574 -0
- package/src/components/composites/test-results/index.ts +20 -0
- package/src/components/composites/test-results/test-results-model.ts +368 -0
- package/src/components/composites/test-results/test-results.tsx +586 -0
- package/src/components/composites/tool/format-tool-value.ts +221 -0
- package/src/components/composites/tool/index.ts +2 -0
- package/src/components/composites/tool/tool.tsx +228 -0
- package/src/components/conversation/conversation-surface.tsx +9 -0
- package/src/components/conversation/scroll-follow-core.ts +31 -0
- package/src/components/conversation/scroll-follow.ts +92 -0
- package/src/components/ui/attachment/attachment.tsx +282 -0
- package/src/components/ui/attachment/index.ts +10 -0
- package/src/components/ui/bubble/bubble.tsx +86 -0
- package/src/components/ui/bubble/index.ts +1 -0
- package/src/components/ui/code-block/code-block.tsx +256 -26
- package/src/components/ui/code-block/index.ts +9 -1
- package/src/components/ui/field/number-field.tsx +51 -14
- package/src/components/ui/marker/index.ts +1 -0
- package/src/components/ui/marker/marker.tsx +90 -0
- package/src/components/ui/message/cite-ranges.ts +144 -0
- package/src/components/ui/message/index.ts +23 -0
- package/src/components/ui/message/message.tsx +434 -0
- package/src/components/ui/message/parse-message-text.ts +450 -0
- package/src/components/ui/questionnaire/index.ts +10 -0
- package/src/components/ui/questionnaire/questionnaire.tsx +446 -0
- package/src/components/ui/trace/index.ts +9 -0
- package/src/components/ui/trace/trace.tsx +334 -0
- package/src/index.ts +26 -0
- package/src/styles/base.css +34 -0
|
@@ -2,16 +2,23 @@ import { cn } from "../../../lib/utils.js";
|
|
|
2
2
|
import { Button } from "../button/button.js";
|
|
3
3
|
import { className, createComponent, effect, insert, memo, mergeProps, setAttribute, setStyleProperty, spread, style, template, use } from "solid-js/web";
|
|
4
4
|
import { Check, Copy } from "lucide-solid";
|
|
5
|
-
import { For, Show, createMemo, createSignal, splitProps } from "solid-js";
|
|
5
|
+
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount, splitProps } from "solid-js";
|
|
6
6
|
//#region src/components/ui/code-block/code-block.tsx
|
|
7
|
-
var _tmpl$ = /*#__PURE__*/ template(`<div class="flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100">`);
|
|
8
|
-
var _tmpl$2 = /*#__PURE__*/ template(`<
|
|
9
|
-
var _tmpl$3 = /*#__PURE__*/ template(`<
|
|
10
|
-
var _tmpl$4 = /*#__PURE__*/ template(`<div
|
|
11
|
-
var _tmpl$5 = /*#__PURE__*/ template(`<
|
|
12
|
-
var _tmpl$6 = /*#__PURE__*/ template(`<
|
|
13
|
-
var _tmpl$7 = /*#__PURE__*/ template(`<div
|
|
14
|
-
var _tmpl$8 = /*#__PURE__*/ template(`<
|
|
7
|
+
var _tmpl$ = /*#__PURE__*/ template(`<div class="flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100 [@media(hover:none)]:opacity-100">`);
|
|
8
|
+
var _tmpl$2 = /*#__PURE__*/ template(`<div class="flex items-center gap-2 border-t border-border px-3 py-1 text-xs text-muted-foreground"><span>Showing the first <!> of <!> lines.`);
|
|
9
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<p class="px-3 pb-2 text-xs text-muted-foreground italic">Generating…`);
|
|
10
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<div data-code-block-footer class="flex items-center justify-end border-t border-transparent px-3 py-1 transition-colors group-focus-within/code:border-border group-hover/code:border-border">`);
|
|
11
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<div data-slot=code-block><div><span class="truncate font-code text-code text-muted-foreground"></span></div><div data-slot=code-block-body tabindex=0 role=group>`);
|
|
12
|
+
var _tmpl$6 = /*#__PURE__*/ template(`<pre><code class="font-code text-code">`);
|
|
13
|
+
var _tmpl$7 = /*#__PURE__*/ template(`<div>`);
|
|
14
|
+
var _tmpl$8 = /*#__PURE__*/ template(`<span class="text-right text-muted-foreground select-none"aria-hidden=true>`);
|
|
15
|
+
var _tmpl$9 = /*#__PURE__*/ template(`<span class="w-[1ch] text-center text-muted-foreground select-none"aria-hidden=true data-slot=code-line-mark>`);
|
|
16
|
+
var _tmpl$0 = /*#__PURE__*/ template(`<span>`);
|
|
17
|
+
var _tmpl$1 = /*#__PURE__*/ template(`<ins data-mark=add>`);
|
|
18
|
+
var _tmpl$10 = /*#__PURE__*/ template(`<del data-mark=remove>`);
|
|
19
|
+
var _tmpl$11 = /*#__PURE__*/ template(`<code>`);
|
|
20
|
+
/** Lines the per-line renderer shows before it offers the rest. */
|
|
21
|
+
var CODE_BLOCK_LINE_LIMIT = 2e3;
|
|
15
22
|
/** The height a block must exceed before its actions are repeated. */
|
|
16
23
|
var TALL_CODE_BLOCK_PX = 480;
|
|
17
24
|
/**
|
|
@@ -44,20 +51,50 @@ function CodeBlock(props) {
|
|
|
44
51
|
"tallThreshold",
|
|
45
52
|
"maxHeight",
|
|
46
53
|
"wrap",
|
|
54
|
+
"size",
|
|
55
|
+
"lineMarks",
|
|
56
|
+
"loadHighlight",
|
|
57
|
+
"lineLimit",
|
|
58
|
+
"onCopy",
|
|
47
59
|
"class",
|
|
48
60
|
"ref"
|
|
49
61
|
]);
|
|
50
62
|
const [copied, setCopied] = createSignal(false);
|
|
51
63
|
const [failed, setFailed] = createSignal(false);
|
|
52
64
|
const [tall, setTall] = createSignal(false);
|
|
53
|
-
const
|
|
54
|
-
const
|
|
65
|
+
const [loaded, setLoaded] = createSignal();
|
|
66
|
+
const [showAll, setShowAll] = createSignal(false);
|
|
67
|
+
let bodyElement;
|
|
68
|
+
const language = () => local.language?.trim().slice(0, 40) || void 0;
|
|
69
|
+
const label = () => local.title ?? language() ?? "code";
|
|
70
|
+
const groupLabel = () => language() ? `${language()} code` : "code";
|
|
71
|
+
const small = () => local.size === "sm";
|
|
55
72
|
const lines = createMemo(() => local.code.replace(/\n$/, "").split("\n"));
|
|
73
|
+
const lineLimit = () => local.lineLimit ?? 2e3;
|
|
74
|
+
const visibleLines = createMemo(() => showAll() ? lines() : lines().slice(0, lineLimit()));
|
|
75
|
+
const hiddenLines = () => lines().length - visibleLines().length;
|
|
76
|
+
createEffect(on(() => [
|
|
77
|
+
local.complete,
|
|
78
|
+
language(),
|
|
79
|
+
local.loadHighlight
|
|
80
|
+
], ([complete, lang, load]) => {
|
|
81
|
+
setLoaded(void 0);
|
|
82
|
+
if (!complete || !load || local.highlight) return;
|
|
83
|
+
let current = true;
|
|
84
|
+
onCleanup(() => current = false);
|
|
85
|
+
new Promise((resolve) => resolve(load(lang))).then((highlighter) => {
|
|
86
|
+
if (current && highlighter) setLoaded(() => highlighter);
|
|
87
|
+
}, () => void 0);
|
|
88
|
+
}));
|
|
89
|
+
const highlighter = () => local.highlight ?? loaded();
|
|
90
|
+
const perLine = () => highlighter() === void 0 && (local.showLineNumbers === true || local.lineMarks !== void 0);
|
|
91
|
+
const truncated = () => hiddenLines() > 0 && (highlighter() !== void 0 || perLine());
|
|
56
92
|
const maxHeight = () => typeof local.maxHeight === "number" ? `${local.maxHeight}px` : local.maxHeight;
|
|
57
93
|
const copy = async () => {
|
|
58
94
|
const ok = await copyText(local.code);
|
|
59
95
|
setCopied(ok);
|
|
60
96
|
setFailed(!ok);
|
|
97
|
+
local.onCopy?.(ok);
|
|
61
98
|
if (ok) setTimeout(() => setCopied(false), 1500);
|
|
62
99
|
};
|
|
63
100
|
const Actions = () => (() => {
|
|
@@ -66,6 +103,7 @@ function CodeBlock(props) {
|
|
|
66
103
|
insert(_el$, createComponent(Button, {
|
|
67
104
|
variant: "ghost",
|
|
68
105
|
size: "icon-2xs",
|
|
106
|
+
touchTarget: "comfortable",
|
|
69
107
|
get ["aria-label"]() {
|
|
70
108
|
return memo(() => !!copied())() ? local.copiedLabel ?? "Copied" : local.copyLabel ?? "Copy code";
|
|
71
109
|
},
|
|
@@ -90,29 +128,40 @@ function CodeBlock(props) {
|
|
|
90
128
|
return _el$;
|
|
91
129
|
})();
|
|
92
130
|
return (() => {
|
|
93
|
-
var _el$2 = _tmpl$
|
|
131
|
+
var _el$2 = _tmpl$5(), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$3.nextSibling;
|
|
94
132
|
use((element) => {
|
|
95
133
|
if (typeof local.ref === "function") local.ref(element);
|
|
96
134
|
else if (local.ref) local.ref = element;
|
|
97
|
-
new ResizeObserver(() => {
|
|
98
|
-
|
|
99
|
-
|
|
135
|
+
const observer = new ResizeObserver(() => {
|
|
136
|
+
const footer = element.querySelector("[data-code-block-footer]");
|
|
137
|
+
setTall(element.offsetHeight - (footer?.offsetHeight ?? 0) > (local.tallThreshold ?? 480));
|
|
138
|
+
});
|
|
139
|
+
onMount(() => {
|
|
140
|
+
if (bodyElement) observer.observe(bodyElement);
|
|
141
|
+
});
|
|
142
|
+
onCleanup(() => observer.disconnect());
|
|
100
143
|
}, _el$2);
|
|
101
|
-
spread(_el$2, mergeProps({
|
|
102
|
-
|
|
103
|
-
|
|
144
|
+
spread(_el$2, mergeProps({
|
|
145
|
+
get ["data-size"]() {
|
|
146
|
+
return local.size ?? "default";
|
|
147
|
+
},
|
|
148
|
+
get ["class"]() {
|
|
149
|
+
return cn("group/code overflow-hidden border border-border bg-card", small() ? "rounded-lg" : "rounded-xl", local.class);
|
|
150
|
+
}
|
|
151
|
+
}, rest), false, true);
|
|
104
152
|
insert(_el$4, label);
|
|
105
153
|
insert(_el$3, createComponent(Actions, {}), null);
|
|
154
|
+
use((element) => bodyElement = element, _el$5);
|
|
106
155
|
insert(_el$5, createComponent(Show, {
|
|
107
156
|
get when() {
|
|
108
|
-
return
|
|
157
|
+
return highlighter();
|
|
109
158
|
},
|
|
110
159
|
get fallback() {
|
|
111
160
|
return (() => {
|
|
112
|
-
var _el$
|
|
113
|
-
insert(_el$
|
|
161
|
+
var _el$14 = _tmpl$6(), _el$15 = _el$14.firstChild;
|
|
162
|
+
insert(_el$15, createComponent(Show, {
|
|
114
163
|
get when() {
|
|
115
|
-
return
|
|
164
|
+
return perLine();
|
|
116
165
|
},
|
|
117
166
|
get fallback() {
|
|
118
167
|
return local.code.replace(/\n$/, "");
|
|
@@ -120,34 +169,78 @@ function CodeBlock(props) {
|
|
|
120
169
|
get children() {
|
|
121
170
|
return createComponent(For, {
|
|
122
171
|
get each() {
|
|
123
|
-
return
|
|
172
|
+
return visibleLines();
|
|
124
173
|
},
|
|
125
|
-
children: (line, index) => (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
174
|
+
children: (line, index) => createComponent(CodeLine, {
|
|
175
|
+
line,
|
|
176
|
+
get number() {
|
|
177
|
+
return index() + 1;
|
|
178
|
+
},
|
|
179
|
+
get numbered() {
|
|
180
|
+
return local.showLineNumbers === true;
|
|
181
|
+
},
|
|
182
|
+
get mark() {
|
|
183
|
+
return local.lineMarks?.[index() + 1];
|
|
184
|
+
},
|
|
185
|
+
get wrap() {
|
|
186
|
+
return local.wrap === true;
|
|
187
|
+
}
|
|
188
|
+
})
|
|
132
189
|
});
|
|
133
190
|
}
|
|
134
191
|
}));
|
|
135
|
-
effect((
|
|
136
|
-
|
|
192
|
+
effect((_p$) => {
|
|
193
|
+
var _v$6 = cn("m-0", small() ? "px-2 py-1.5" : "px-3 py-2"), _v$7 = local.lineHeight ?? "1.5";
|
|
194
|
+
_v$6 !== _p$.e && className(_el$14, _p$.e = _v$6);
|
|
195
|
+
_v$7 !== _p$.t && setStyleProperty(_el$14, "line-height", _p$.t = _v$7);
|
|
196
|
+
return _p$;
|
|
197
|
+
}, {
|
|
198
|
+
e: void 0,
|
|
199
|
+
t: void 0
|
|
200
|
+
});
|
|
201
|
+
return _el$14;
|
|
137
202
|
})();
|
|
138
203
|
},
|
|
139
204
|
children: (highlight) => (() => {
|
|
140
|
-
var _el$
|
|
141
|
-
insert(_el$
|
|
142
|
-
|
|
205
|
+
var _el$16 = _tmpl$7();
|
|
206
|
+
insert(_el$16, () => highlight()(hiddenLines() > 0 ? visibleLines().join("\n") : local.code));
|
|
207
|
+
effect(() => className(_el$16, small() ? "px-2 py-1.5" : "px-3 py-2"));
|
|
208
|
+
return _el$16;
|
|
143
209
|
})()
|
|
144
210
|
}), null);
|
|
211
|
+
insert(_el$5, createComponent(Show, {
|
|
212
|
+
get when() {
|
|
213
|
+
return truncated();
|
|
214
|
+
},
|
|
215
|
+
get children() {
|
|
216
|
+
var _el$6 = _tmpl$2(), _el$7 = _el$6.firstChild, _el$10 = _el$7.firstChild.nextSibling, _el$11 = _el$10.nextSibling.nextSibling;
|
|
217
|
+
_el$11.nextSibling;
|
|
218
|
+
insert(_el$7, () => visibleLines().length.toLocaleString(), _el$10);
|
|
219
|
+
insert(_el$7, () => lines().length.toLocaleString(), _el$11);
|
|
220
|
+
insert(_el$6, createComponent(Button, {
|
|
221
|
+
variant: "ghost",
|
|
222
|
+
size: "2xs",
|
|
223
|
+
onClick: () => {
|
|
224
|
+
setShowAll(true);
|
|
225
|
+
bodyElement?.focus({ preventScroll: true });
|
|
226
|
+
},
|
|
227
|
+
get children() {
|
|
228
|
+
return [
|
|
229
|
+
"Show all ",
|
|
230
|
+
memo(() => lines().length.toLocaleString()),
|
|
231
|
+
" lines"
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
}), null);
|
|
235
|
+
return _el$6;
|
|
236
|
+
}
|
|
237
|
+
}), null);
|
|
145
238
|
insert(_el$5, createComponent(Show, {
|
|
146
239
|
get when() {
|
|
147
240
|
return !local.complete;
|
|
148
241
|
},
|
|
149
242
|
get children() {
|
|
150
|
-
return _tmpl$
|
|
243
|
+
return _tmpl$3();
|
|
151
244
|
}
|
|
152
245
|
}), null);
|
|
153
246
|
insert(_el$2, createComponent(Show, {
|
|
@@ -155,30 +248,118 @@ function CodeBlock(props) {
|
|
|
155
248
|
return tall();
|
|
156
249
|
},
|
|
157
250
|
get children() {
|
|
158
|
-
var _el$
|
|
159
|
-
insert(_el$
|
|
160
|
-
return _el$
|
|
251
|
+
var _el$13 = _tmpl$4();
|
|
252
|
+
insert(_el$13, createComponent(Actions, {}));
|
|
253
|
+
return _el$13;
|
|
161
254
|
}
|
|
162
255
|
}), null);
|
|
163
256
|
effect((_p$) => {
|
|
164
|
-
var _v$ = local.wrap ? "" : void 0, _v$
|
|
257
|
+
var _v$ = cn("flex items-center justify-between gap-2", small() ? "px-2 py-0.5" : "px-3 py-1"), _v$2 = local.wrap ? "" : void 0, _v$3 = cn("scroll-fade overflow-x-auto", {
|
|
165
258
|
"overflow-y-auto": local.maxHeight !== void 0,
|
|
166
259
|
"[&_pre]:whitespace-pre-wrap [&_pre]:[overflow-wrap:anywhere]": local.wrap
|
|
167
|
-
}), _v$
|
|
168
|
-
_v$ !== _p$.e &&
|
|
169
|
-
_v$2 !== _p$.t &&
|
|
170
|
-
_p$.a
|
|
171
|
-
|
|
260
|
+
}), _v$4 = maxHeight() === void 0 ? void 0 : { "max-height": maxHeight() }, _v$5 = groupLabel();
|
|
261
|
+
_v$ !== _p$.e && className(_el$3, _p$.e = _v$);
|
|
262
|
+
_v$2 !== _p$.t && setAttribute(_el$5, "data-wrap", _p$.t = _v$2);
|
|
263
|
+
_v$3 !== _p$.a && className(_el$5, _p$.a = _v$3);
|
|
264
|
+
_p$.o = style(_el$5, _v$4, _p$.o);
|
|
265
|
+
_v$5 !== _p$.i && setAttribute(_el$5, "aria-label", _p$.i = _v$5);
|
|
172
266
|
return _p$;
|
|
173
267
|
}, {
|
|
174
268
|
e: void 0,
|
|
175
269
|
t: void 0,
|
|
176
270
|
a: void 0,
|
|
177
|
-
o: void 0
|
|
271
|
+
o: void 0,
|
|
272
|
+
i: void 0
|
|
178
273
|
});
|
|
179
274
|
return _el$2;
|
|
180
275
|
})();
|
|
181
276
|
}
|
|
277
|
+
var MARK_GLYPH = {
|
|
278
|
+
add: "+",
|
|
279
|
+
remove: "−",
|
|
280
|
+
highlight: "",
|
|
281
|
+
error: "!"
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* One rendered line. The gutter glyph and the element (`ins`/`del`) carry what a
|
|
285
|
+
* mark means so it survives greyscale and a screen reader; both gutters are
|
|
286
|
+
* unselectable so dragging across the block and copying yields only source.
|
|
287
|
+
*/
|
|
288
|
+
function CodeLine(props) {
|
|
289
|
+
const content = () => [
|
|
290
|
+
createComponent(Show, {
|
|
291
|
+
get when() {
|
|
292
|
+
return props.numbered;
|
|
293
|
+
},
|
|
294
|
+
get children() {
|
|
295
|
+
var _el$17 = _tmpl$8();
|
|
296
|
+
insert(_el$17, () => props.number);
|
|
297
|
+
return _el$17;
|
|
298
|
+
}
|
|
299
|
+
}),
|
|
300
|
+
(() => {
|
|
301
|
+
var _el$18 = _tmpl$9();
|
|
302
|
+
insert(_el$18, (() => {
|
|
303
|
+
var _c$ = memo(() => !!props.mark);
|
|
304
|
+
return () => _c$() ? MARK_GLYPH[props.mark] : "";
|
|
305
|
+
})());
|
|
306
|
+
return _el$18;
|
|
307
|
+
})(),
|
|
308
|
+
(() => {
|
|
309
|
+
var _el$19 = _tmpl$0();
|
|
310
|
+
insert(_el$19, () => props.line || " ");
|
|
311
|
+
effect(() => className(_el$19, cn({ "min-w-0": props.wrap })));
|
|
312
|
+
return _el$19;
|
|
313
|
+
})()
|
|
314
|
+
];
|
|
315
|
+
const rowClass = () => cn("grid gap-3 no-underline", props.numbered ? "grid-cols-[3ch_1ch_1fr]" : "grid-cols-[1ch_1fr]", {
|
|
316
|
+
"bg-success-subtle": props.mark === "add",
|
|
317
|
+
"bg-destructive-subtle": props.mark === "remove" || props.mark === "error",
|
|
318
|
+
"bg-primary-subtle": props.mark === "highlight"
|
|
319
|
+
});
|
|
320
|
+
return createComponent(Show, {
|
|
321
|
+
get when() {
|
|
322
|
+
return props.mark === "add" || props.mark === "remove";
|
|
323
|
+
},
|
|
324
|
+
get fallback() {
|
|
325
|
+
return (() => {
|
|
326
|
+
var _el$21 = _tmpl$0();
|
|
327
|
+
insert(_el$21, content);
|
|
328
|
+
effect((_p$) => {
|
|
329
|
+
var _v$8 = props.mark, _v$9 = rowClass();
|
|
330
|
+
_v$8 !== _p$.e && setAttribute(_el$21, "data-mark", _p$.e = _v$8);
|
|
331
|
+
_v$9 !== _p$.t && className(_el$21, _p$.t = _v$9);
|
|
332
|
+
return _p$;
|
|
333
|
+
}, {
|
|
334
|
+
e: void 0,
|
|
335
|
+
t: void 0
|
|
336
|
+
});
|
|
337
|
+
return _el$21;
|
|
338
|
+
})();
|
|
339
|
+
},
|
|
340
|
+
get children() {
|
|
341
|
+
return createComponent(Show, {
|
|
342
|
+
get when() {
|
|
343
|
+
return props.mark === "add";
|
|
344
|
+
},
|
|
345
|
+
get fallback() {
|
|
346
|
+
return (() => {
|
|
347
|
+
var _el$22 = _tmpl$10();
|
|
348
|
+
insert(_el$22, content);
|
|
349
|
+
effect(() => className(_el$22, rowClass()));
|
|
350
|
+
return _el$22;
|
|
351
|
+
})();
|
|
352
|
+
},
|
|
353
|
+
get children() {
|
|
354
|
+
var _el$20 = _tmpl$1();
|
|
355
|
+
insert(_el$20, content);
|
|
356
|
+
effect(() => className(_el$20, rowClass()));
|
|
357
|
+
return _el$20;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
182
363
|
/**
|
|
183
364
|
* InlineCode.
|
|
184
365
|
*
|
|
@@ -192,14 +373,14 @@ function CodeBlock(props) {
|
|
|
192
373
|
function InlineCode(props) {
|
|
193
374
|
const [local, rest] = splitProps(props, ["class"]);
|
|
194
375
|
return (() => {
|
|
195
|
-
var _el$
|
|
196
|
-
spread(_el$
|
|
376
|
+
var _el$23 = _tmpl$11();
|
|
377
|
+
spread(_el$23, mergeProps({ get ["class"]() {
|
|
197
378
|
return cn("rounded-sm bg-muted px-[0.4em] py-[0.15em] font-code text-code text-foreground [overflow-wrap:anywhere]", local.class);
|
|
198
379
|
} }, rest), false, false);
|
|
199
|
-
return _el$
|
|
380
|
+
return _el$23;
|
|
200
381
|
})();
|
|
201
382
|
}
|
|
202
383
|
//#endregion
|
|
203
|
-
export { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX };
|
|
384
|
+
export { CODE_BLOCK_LINE_LIMIT, CodeBlock, InlineCode, TALL_CODE_BLOCK_PX };
|
|
204
385
|
|
|
205
386
|
//# sourceMappingURL=code-block.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-block.js","names":["createMemo","createSignal","For","Show","splitProps","ComponentProps","JSX","Check","Copy","Button","cn","CodeBlockProps","Omit","code","language","highlight","Element","complete","title","actions","copyLabel","copiedLabel","lineHeight","showLineNumbers","tallThreshold","maxHeight","wrap","TALL_CODE_BLOCK_PX","copyText","text","Promise","navigator","clipboard","writeText","CodeBlock","props","local","rest","copied","setCopied","failed","setFailed","tall","setTall","label","regionLabel","lines","replace","split","copy","ok","setTimeout","Actions","_el$","_tmpl$","_$insert","_$createComponent","variant","size","aria-label","_$memo","undefined","onClick","children","when","fallback","_el$2","_tmpl$4","_el$3","firstChild","_el$4","_el$5","nextSibling","_$use","element","ref","observer","ResizeObserver","offsetHeight","observe","_$spread","_$mergeProps","class","_el$8","_tmpl$5","_el$9","each","line","index","_el$0","_tmpl$6","_el$1","_el$10","_$effect","_$className","_$p","_$setStyleProperty","_el$11","_tmpl$7","_tmpl$2","_el$7","_tmpl$3","_p$","_v$","_v$2","_v$3","_v$4","e","_$setAttribute","t","a","_$style","o","InlineCode","_el$12","_tmpl$8","_$createComponent","_$memo","_$mergeProps","_$className","_$setStyleProperty","_$setAttribute","_$style"],"sources":["../../../../src/components/ui/code-block/code-block.tsx"],"sourcesContent":["import {\n createMemo,\n createSignal,\n For,\n Show,\n splitProps,\n type ComponentProps,\n type JSX,\n} from 'solid-js'\nimport { Check, Copy } from 'lucide-solid'\nimport { Button } from '../button'\nimport { cn } from '#lib/utils'\n\n/**\n * CodeBlock.\n *\n * A fenced block, rendered as a surface. The library ships no highlighter —\n * syntax colouring is a large dependency with its own theme format, and a\n * component that bundled one would force every consumer to pay for it. This\n * renders the block, its chrome, and its behaviour; a caller that wants\n * highlighting passes the result through `highlight`, which is the seam a\n * Shiki/Pierre/Prism integration plugs into.\n *\n * Four details are the reason this exists rather than a styled `<pre>`:\n *\n * **Copy confirms only on success.** `navigator.clipboard.writeText` rejects\n * outside a secure context, in a sandboxed frame, and when the document is not\n * focused. Flipping to a tick unconditionally confirms a copy that did not\n * happen, and the reader pastes something stale and does not know why. The\n * rejection is caught and the button reports the failure instead.\n *\n * **A tall block repeats its action row at the bottom.** Copying from a block\n * that is taller than the viewport otherwise costs a scroll back to the top and\n * another scroll down to where you were. The threshold is a fixed 480px rather\n * than viewport-relative so the behaviour does not change when the window is\n * resized.\n *\n * **The scroller is focusable and named.** A horizontally scrollable region has\n * to be reachable by keyboard — this is axe's `scrollable-region-focusable`, and\n * a region that scrolls but cannot be focused is a WCAG 2.1.1 failure. It is a\n * `region` with a label rather than a bare `tabindex`, so the tab stop announces\n * what it is.\n *\n * **Resolving a streaming block must not move the reader.** When `complete` is\n * false the block shows the code it has plus a generating indicator; the\n * indicator is inside the scroller's own box and does not add a line, because a\n * block that grows the moment its content resolves shifts everything below it.\n * If a caller's `highlight` changes the line box, that is the caller's height to\n * hold — `lineHeight` is a prop for exactly that reason.\n */\nexport type CodeBlockProps = Omit<ComponentProps<'div'>, 'children'> & {\n code: string\n /** The language, shown in the header and used as the region's label. */\n language?: string\n /** The code, transformed — highlighted HTML or a component. Omit for plain text. */\n highlight?: (code: string) => JSX.Element\n /** False while the block is still streaming. Adds a generating indicator. */\n complete?: boolean\n /** A filename or title, shown instead of the language. */\n title?: string\n /** Extra header controls, before the copy button. */\n actions?: JSX.Element\n /** Copy label. Override for a non-English application. */\n copyLabel?: string\n copiedLabel?: string\n /** Line height of the rendered code. Set it when `highlight` changes the box. */\n lineHeight?: string\n /** A line-number gutter. Off by default; a short snippet rarely needs one. */\n showLineNumbers?: boolean\n /** The height above which the action row is repeated below the block. */\n tallThreshold?: number\n /**\n * Cap the code body's height and scroll it vertically past that. A number is\n * pixels; a string is any CSS length (`'20rem'`, `'50vh'`). Unset, the block\n * grows with its content.\n */\n maxHeight?: number | string\n /**\n * Soft-wrap long lines inside the block instead of scrolling sideways. Off by\n * default: wrapped code loses its column alignment, so it is for prose-like\n * output (logs, long commands) in a narrow column. Wraps the plain renderer and\n * any `pre` inside `highlight` output; line numbers stay on the first visual line.\n */\n wrap?: boolean\n}\n\n/** The height a block must exceed before its actions are repeated. */\nexport const TALL_CODE_BLOCK_PX = 480\n\n/**\n * Copy, reporting whether it worked. `navigator.clipboard` is absent in an\n * insecure context, and `writeText` rejects when the document is not focused —\n * both are normal in an embedded or iframed application, and neither should\n * silently look like success.\n */\nasync function copyText(text: string): Promise<boolean> {\n try {\n if (!navigator.clipboard) return false\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n\nexport function CodeBlock(props: CodeBlockProps) {\n const [local, rest] = splitProps(props, [\n 'code',\n 'language',\n 'highlight',\n 'complete',\n 'title',\n 'actions',\n 'copyLabel',\n 'copiedLabel',\n 'lineHeight',\n 'showLineNumbers',\n 'tallThreshold',\n 'maxHeight',\n 'wrap',\n 'class',\n 'ref',\n ])\n\n const [copied, setCopied] = createSignal(false)\n const [failed, setFailed] = createSignal(false)\n const [tall, setTall] = createSignal(false)\n\n const label = () => local.title ?? local.language ?? 'code'\n const regionLabel = () => (local.language ? `${local.language} code` : 'code')\n const lines = createMemo(() => local.code.replace(/\\n$/, '').split('\\n'))\n const maxHeight = () =>\n typeof local.maxHeight === 'number' ? `${local.maxHeight}px` : local.maxHeight\n\n const copy = async () => {\n const ok = await copyText(local.code)\n setCopied(ok)\n setFailed(!ok)\n if (ok) setTimeout(() => setCopied(false), 1500)\n }\n\n const Actions = () => (\n <div class=\"flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100\">\n {local.actions}\n <Button\n variant=\"ghost\"\n size=\"icon-2xs\"\n aria-label={copied() ? (local.copiedLabel ?? 'Copied') : (local.copyLabel ?? 'Copy code')}\n title={failed() ? 'Copying is unavailable in this context' : undefined}\n onClick={() => void copy()}\n >\n <Show when={copied()} fallback={<Copy aria-hidden=\"true\" />}>\n <Check aria-hidden=\"true\" />\n </Show>\n </Button>\n </div>\n )\n\n return (\n <div\n class={cn('group/code overflow-hidden rounded-xl border border-border bg-card', local.class)}\n {...rest}\n ref={(element) => {\n // Composed rather than replaced: a caller's ref must survive.\n if (typeof local.ref === 'function') local.ref(element)\n else if (local.ref) local.ref = element\n // Measured rather than assumed: the caller controls the content, so only\n // the rendered box can say whether the action row has scrolled away.\n const observer = new ResizeObserver(() => {\n setTall(element.offsetHeight > (local.tallThreshold ?? TALL_CODE_BLOCK_PX))\n })\n observer.observe(element)\n }}\n >\n <div class=\"flex items-center justify-between gap-2 px-3 py-1\">\n <span class=\"truncate font-code text-code text-muted-foreground\">{label()}</span>\n <Actions />\n </div>\n <div\n data-slot=\"code-block-body\"\n data-wrap={local.wrap ? '' : undefined}\n class={cn('scroll-fade overflow-x-auto', {\n // A capped body scrolls on both axes; the region is already a tab stop,\n // so the keyboard reaches the vertical overflow the same way.\n 'overflow-y-auto': local.maxHeight !== undefined,\n '[&_pre]:whitespace-pre-wrap [&_pre]:[overflow-wrap:anywhere]': local.wrap,\n })}\n style={maxHeight() === undefined ? undefined : { 'max-height': maxHeight() }}\n // A region that scrolls must be focusable, and a tab stop needs a name.\n tabindex=\"0\"\n role=\"region\"\n aria-label={regionLabel()}\n >\n <Show\n when={local.highlight}\n fallback={\n <pre class=\"m-0 px-3 py-2\" style={{ 'line-height': local.lineHeight ?? '1.5' }}>\n <code class=\"font-code text-code\">\n <Show when={local.showLineNumbers} fallback={local.code.replace(/\\n$/, '')}>\n <For each={lines()}>\n {(line, index) => (\n <span class=\"grid grid-cols-[3ch_1fr] gap-3\">\n <span\n class=\"text-right text-muted-foreground select-none\"\n aria-hidden=\"true\"\n >\n {index() + 1}\n </span>\n <span class={cn({ 'min-w-0': local.wrap })}>{line || ' '}</span>\n </span>\n )}\n </For>\n </Show>\n </code>\n </pre>\n }\n >\n {(highlight) => <div class=\"px-3 py-2\">{highlight()(local.code)}</div>}\n </Show>\n {/*\n In the scroller's box, and a single line: the indicator must not add\n height when it disappears, or a streaming block shifts everything below\n it as it resolves.\n */}\n <Show when={!local.complete}>\n <p class=\"px-3 pb-2 text-xs text-muted-foreground italic\">Generating…</p>\n </Show>\n </div>\n <Show when={tall()}>\n <div\n data-code-block-footer=\"\"\n class=\"flex items-center justify-end border-t border-transparent px-3 py-1 transition-colors group-focus-within/code:border-border group-hover/code:border-border\"\n >\n <Actions />\n </div>\n </Show>\n </div>\n )\n}\n\n/**\n * InlineCode.\n *\n * The `code` inside a sentence. It is a component rather than a class because it\n * has to hold three properties at once: it uses the shared code family and size\n * preference, and it wraps rather than overflows a narrow column\n * (`overflow-wrap: anywhere` — an identifier with\n * no spaces is one long token), and it must be legible against whatever surface\n * it lands on, which is why the fill is a token and not a fixed grey.\n */\nexport function InlineCode(props: ComponentProps<'code'>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <code\n class={cn(\n 'rounded-sm bg-muted px-[0.4em] py-[0.15em] font-code text-code text-foreground [overflow-wrap:anywhere]',\n local.class\n )}\n {...rest}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuFA,IAAa2B,qBAAqB;;;;;;;AAQlC,eAAeC,SAASC,MAAgC;CACtD,IAAI;EACF,IAAI,CAACE,UAAUC,WAAW,OAAO;EACjC,MAAMD,UAAUC,UAAUC,UAAUJ,IAAI;EACxC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgBK,UAAUC,OAAuB;CAC/C,MAAM,CAACC,OAAOC,QAAQjC,WAAW+B,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAK,CACN;CAED,MAAM,CAACG,QAAQC,aAAatC,aAAa,KAAK;CAC9C,MAAM,CAACuC,QAAQC,aAAaxC,aAAa,KAAK;CAC9C,MAAM,CAACyC,MAAMC,WAAW1C,aAAa,KAAK;CAE1C,MAAM2C,cAAcR,MAAMlB,SAASkB,MAAMtB,YAAY;CACrD,MAAM+B,oBAAqBT,MAAMtB,WAAW,GAAGsB,MAAMtB,SAAQ,SAAU;CACvE,MAAMgC,QAAQ9C,iBAAiBoC,MAAMvB,KAAKkC,QAAQ,OAAO,EAAE,CAAC,CAACC,MAAM,IAAI,CAAC;CACxE,MAAMvB,kBACJ,OAAOW,MAAMX,cAAc,WAAW,GAAGW,MAAMX,UAAS,MAAOW,MAAMX;CAEvE,MAAMwB,OAAO,YAAY;EACvB,MAAMC,KAAK,MAAMtB,SAASQ,MAAMvB,IAAI;EACpC0B,UAAUW,EAAE;EACZT,UAAU,CAACS,EAAE;EACb,IAAIA,IAAIC,iBAAiBZ,UAAU,KAAK,GAAG,IAAI;CACjD;CAEA,MAAMa,uBAAU;EAAA,IAAAC,OAAAC,OAAA;EAAAC,OAAAF,YAEXjB,MAAMjB,SAAO,IAAA;EAAAoC,OAAAF,MAAAG,gBACb/C,QAAM;GACLgD,SAAO;GACPC,MAAI;GAAA,KAAA,gBAAA;IAAA,OACQE,WAAA,CAAA,CAAAtB,OAAO,CAAC,CAAA,CAAA,IAAIF,MAAMf,eAAe,WAAae,MAAMhB,aAAa;GAAY;GAAA,IACzFF,QAAK;IAAA,OAAEsB,OAAO,IAAI,2CAA2CqB,KAAAA;GAAS;GACtEC,eAAe,KAAKb,KAAK;GAAC,IAAAc,WAAA;IAAA,OAAAP,gBAEzBrD,MAAI;KAAA,IAAC6D,OAAI;MAAA,OAAE1B,OAAO;KAAC;KAAA,IAAE2B,WAAQ;MAAA,OAAAT,gBAAGhD,MAAI,EAAA,eAAA,OAAA,CAAA;KAAA;KAAA,IAAAuD,WAAA;MAAA,OAAAP,gBAClCjD,OAAK,EAAA,eAAA,OAAA,CAAA;KAAA;IAAA,CAAA;GAAA;EAAA,CAAA,GAAA,IAAA;EAAA,OAAA8C;CAAA,EAAA,CAAA;CAMd,cAAA;EAAA,IAAAa,QAAAC,QAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC,YAAAE,QAAAH,MAAAI;EAAAC,KAIUC,YAAY;GAEhB,IAAI,OAAOtC,MAAMuC,QAAQ,YAAYvC,MAAMuC,IAAID,OAAO;QACjD,IAAItC,MAAMuC,KAAKvC,MAAMuC,MAAMD;GAMhCE,IAHqBC,qBAAqB;IACxClC,QAAQ+B,QAAQI,gBAAgB1C,MAAMZ,iBAAAA,IAAoC;GAC5E,CACAoD,CAAAA,CAASG,QAAQL,OAAO;EAC1B,GAACR,KAAA;EAAAc,OAAAd,OAAAe,WAAA,EAAA,KAAA,WAAA;GAAA,OAZMvE,GAAG,sEAAsE0B,MAAM8C,KAAK;EAAC,EAAA,GACxF7C,IAAI,GAAA,OAAA,IAAA;EAAAkB,OAAAe,OAc4D1B,KAAK;EAAAW,OAAAa,OAAAZ,gBACtEJ,SAAO,CAAA,CAAA,GAAA,IAAA;EAAAG,OAAAgB,OAAAf,gBAiBPrD,MAAI;GAAA,IACH6D,OAAI;IAAA,OAAE5B,MAAMrB;GAAS;GAAA,IACrBkD,WAAQ;IAAA,cAAA;KAAA,IAAAkB,QAAAC,QAAA,GAAAC,QAAAF,MAAAd;KAAAd,OAAA8B,OAAA7B,gBAGDrD,MAAI;MAAA,IAAC6D,OAAI;OAAA,OAAE5B,MAAMb;MAAe;MAAA,IAAE0C,WAAQ;OAAA,OAAE7B,MAAMvB,KAAKkC,QAAQ,OAAO,EAAE;MAAC;MAAA,IAAAgB,WAAA;OAAA,OAAAP,gBACvEtD,KAAG;QAAA,IAACoF,OAAI;SAAA,OAAExC,MAAM;QAAC;QAAAiB,WACdwB,MAAMC,iBAAK;SAAA,IAAAC,QAAAC,QAAA,GAAAC,QAAAF,MAAApB,YAAAuB,SAAAD,MAAAnB;SAAAjB,OAAAoC,aAMNH,MAAM,IAAI,CAAC;SAAAjC,OAAAqC,QAE+BL,QAAQ,GAAG;SAAAM,aAAAC,UAAAF,QAA3ClF,GAAG,EAAE,WAAW0B,MAAMV,KAAK,CAAC,CAAC,CAAA;SAAA,OAAA+D;QAAA,EAAA,CAAA;OAE7C,CAAA;MAAA;KAAA,CAAA,CAAA;KAAAI,QAAAE,QAAAC,iBAAAb,OAAA,eAd0C/C,MAAMd,cAAc,KAAK,CAAA;KAAA,OAAA6D;IAAA,EAAA,CAAA;GAAA;GAAApB,WAqB5EhD,qBAAS;IAAA,IAAAkF,SAAAC,QAAA;IAAA3C,OAAA0C,cAA6BlF,UAAU,CAAC,CAACqB,MAAMvB,IAAI,CAAC;IAAA,OAAAoF;GAAA,EAAA,CAAA;EAAO,CAAA,GAAA,IAAA;EAAA1C,OAAAgB,OAAAf,gBAOvErD,MAAI;GAAA,IAAC6D,OAAI;IAAA,OAAE,CAAC5B,MAAMnB;GAAQ;GAAA,IAAA8C,WAAA;IAAA,OAAAoC,QAAA;GAAA;EAAA,CAAA,GAAA,IAAA;EAAA5C,OAAAW,OAAAV,gBAI5BrD,MAAI;GAAA,IAAC6D,OAAI;IAAA,OAAEtB,KAAK;GAAC;GAAA,IAAAqB,WAAA;IAAA,IAAAqC,QAAAC,QAAA;IAAA9C,OAAA6C,OAAA5C,gBAKbJ,SAAO,CAAA,CAAA,CAAA;IAAA,OAAAgD;GAAA;EAAA,CAAA,GAAA,IAAA;EAAAP,QAAAS,QAAA;GAAA,IAAAC,MArDCnE,MAAMV,OAAO,KAAKmC,KAAAA,GAAS2C,OAC/B9F,GAAG,+BAA+B;IAGvC,mBAAmB0B,MAAMX,cAAcoC,KAAAA;IACvC,gEAAgEzB,MAAMV;GACxE,CAAC,GAAC+E,OACKhF,UAAU,MAAMoC,KAAAA,IAAYA,KAAAA,IAAY,EAAE,cAAcpC,UAAU,EAAE,GAACiF,OAIhE7D,YAAY;GAAC0D,QAAAD,IAAAK,KAAAC,aAAArC,OAAA,aAAA+B,IAAAK,IAAAJ,GAAA;GAAAC,SAAAF,IAAAO,KAAAf,UAAAvB,OAAA+B,IAAAO,IAAAL,IAAA;GAAAF,IAAAQ,IAAAC,MAAAxC,OAAAkC,MAAAH,IAAAQ,CAAA;GAAAJ,SAAAJ,IAAAU,KAAAJ,aAAArC,OAAA,cAAA+B,IAAAU,IAAAN,IAAA;GAAA,OAAAJ;EAAA,GAAA;GAAAK,GAAA9C,KAAAA;GAAAgD,GAAAhD,KAAAA;GAAAiD,GAAAjD,KAAAA;GAAAmD,GAAAnD,KAAAA;EAAA,CAAA;EAAA,OAAAK;CAAA,EAAA,CAAA;AA+CjC;;;;;;;;;;;AAYA,SAAgB+C,WAAW9E,OAA+B;CACxD,MAAM,CAACC,OAAOC,QAAQjC,WAAW+B,OAAO,CAAC,OAAO,CAAC;CAEjD,cAAA;EAAA,IAAA+E,SAAAC,QAAA;EAAAnC,OAAAkC,QAAAjC,WAAA,EAAA,KAAA,WAAA;GAAA,OAEWvE,GACL,2GACA0B,MAAM8C,KACR;EAAC,EAAA,GACG7C,IAAI,GAAA,OAAA,KAAA;EAAA,OAAA6E;CAAA,EAAA,CAAA;AAGd"}
|
|
1
|
+
{"version":3,"file":"code-block.js","names":["createEffect","createMemo","createSignal","For","on","onCleanup","onMount","Show","splitProps","ComponentProps","JSX","Check","Copy","Button","cn","CodeBlockProps","Omit","code","language","highlight","Element","complete","title","actions","copyLabel","copiedLabel","lineHeight","showLineNumbers","tallThreshold","maxHeight","wrap","size","lineMarks","Readonly","Record","CodeLineMark","loadHighlight","Promise","CodeHighlighter","lineLimit","onCopy","ok","CODE_BLOCK_LINE_LIMIT","TALL_CODE_BLOCK_PX","copyText","text","navigator","clipboard","writeText","CodeBlock","props","local","rest","copied","setCopied","failed","setFailed","tall","setTall","loaded","setLoaded","showAll","setShowAll","bodyElement","HTMLDivElement","trim","slice","undefined","label","groupLabel","small","lines","replace","split","visibleLines","hiddenLines","length","const","lang","load","current","resolve","then","highlighter","perLine","truncated","copy","setTimeout","Actions","_el$","_tmpl$","_$insert","_$createComponent","variant","touchTarget","aria-label","_$memo","onClick","children","when","fallback","_el$2","_tmpl$5","_el$3","firstChild","_el$4","_el$5","nextSibling","_$use","element","ref","observer","ResizeObserver","footer","querySelector","HTMLElement","offsetHeight","observe","disconnect","_$spread","_$mergeProps","data-size","class","_el$14","_tmpl$6","_el$15","each","line","index","CodeLine","number","numbered","mark","_$effect","_p$","_v$6","_v$7","e","_$className","t","_$setStyleProperty","_el$16","_tmpl$7","join","_el$6","_tmpl$2","_el$7","_el$8","_el$10","_el$9","_el$11","_el$1","toLocaleString","focus","preventScroll","_tmpl$3","_el$13","_tmpl$4","_v$","_v$2","_v$3","_v$4","_v$5","_$setAttribute","a","o","_$style","i","MARK_GLYPH","add","remove","error","content","_el$17","_tmpl$8","_el$18","_tmpl$9","_c$","_el$19","_tmpl$0","rowClass","_el$21","_v$8","_v$9","_el$22","_tmpl$10","_el$20","_tmpl$1","InlineCode","_el$23","_tmpl$11","_$createComponent","_$memo","_$mergeProps","_$className","_$setStyleProperty","_$setAttribute","_$style"],"sources":["../../../../src/components/ui/code-block/code-block.tsx"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n For,\n on,\n onCleanup,\n onMount,\n Show,\n splitProps,\n type ComponentProps,\n type JSX,\n} from 'solid-js'\nimport { Check, Copy } from 'lucide-solid'\nimport { Button } from '../button'\nimport { cn } from '#lib/utils'\n\n/**\n * CodeBlock.\n *\n * A fenced block, rendered as a surface. The library ships no highlighter —\n * syntax colouring is a large dependency with its own theme format, and a\n * component that bundled one would force every consumer to pay for it. This\n * renders the block, its chrome, and its behaviour; a caller that wants\n * highlighting passes the result through `highlight`, which is the seam a\n * Shiki/Pierre/Prism integration plugs into.\n *\n * Four details are the reason this exists rather than a styled `<pre>`:\n *\n * **Copy confirms only on success.** `navigator.clipboard.writeText` rejects\n * outside a secure context, in a sandboxed frame, and when the document is not\n * focused. Flipping to a tick unconditionally confirms a copy that did not\n * happen, and the reader pastes something stale and does not know why. The\n * rejection is caught and the button reports the failure instead.\n *\n * **A tall block repeats its action row at the bottom.** Copying from a block\n * that is taller than the viewport otherwise costs a scroll back to the top and\n * another scroll down to where you were. The threshold is a fixed 480px rather\n * than viewport-relative so the behaviour does not change when the window is\n * resized.\n *\n * **The scroller is focusable and named.** A horizontally scrollable region has\n * to be reachable by keyboard — this is axe's `scrollable-region-focusable`, and\n * a region that scrolls but cannot be focused is a WCAG 2.1.1 failure. It is a\n * labelled `group` rather than a bare `tabindex`, so the tab stop announces what\n * it is. It is deliberately not a `region` landmark: a transcript holds many\n * blocks, often in one language, and repeated landmarks of one name are noise.\n *\n * **Resolving a streaming block must not move the reader.** When `complete` is\n * false the block shows the code it has plus a generating indicator; the\n * indicator is inside the scroller's own box and does not add a line, because a\n * block that grows the moment its content resolves shifts everything below it.\n * If a caller's `highlight` changes the line box, that is the caller's height to\n * hold — `lineHeight` is a prop for exactly that reason.\n *\n * ## Output, not only source\n *\n * The same surface carries terminal output, logs and diffs inside an agent's\n * activity, so it also:\n *\n * - **loads its highlighter lazily** (`loadHighlight`). The grammar is fetched\n * only for a block that is complete and has a language, the block renders plain\n * until it arrives, and a loader that returns nothing — an unknown language, a\n * failed fetch — leaves the plain text in place without an error. Highlighting\n * a block on every streamed delta would re-tokenise the whole thing per token,\n * so a streaming block stays plain until `complete`.\n * - **marks lines** (`lineMarks`) as added, removed, highlighted or failed. A mark\n * is carried by a gutter glyph and by `<ins>`/`<del>` for the two that change\n * text, never by colour alone, and the glyph is not selectable so a copied\n * selection stays the source.\n * - **copies the source exactly.** The copy button writes `code` as given: no\n * trailing-newline trimming, no line numbers, no gutter glyphs, and the whole\n * block even when only part of it is rendered (`lineLimit`).\n * - **bounds a large render.** Past `lineLimit` lines the per-line renderer and a\n * highlighted render show the first lines and a control to show the rest,\n * because tens of thousands of row elements, or a tokenizer run over all of\n * them, are a freeze, not a transcript. Which renderer is in use is decided\n * at the time, so a highlighter that loads late takes over the bound from the\n * per-line rows and the note below the block always describes what is drawn.\n * The plain renderer is a single text node and needs no limit.\n * - **comes in a small size** (`size=\"sm\"`) for tool output inside a Trace line.\n */\nexport type CodeBlockProps = Omit<ComponentProps<'div'>, 'children' | 'onCopy'> & {\n code: string\n /** The language, shown in the header and used as the region's label. */\n language?: string\n /** The code, transformed — highlighted HTML or a component. Omit for plain text. */\n highlight?: (code: string) => JSX.Element\n /** False while the block is still streaming. Adds a generating indicator. */\n complete?: boolean\n /** A filename or title, shown instead of the language. */\n title?: string\n /** Extra header controls, before the copy button. */\n actions?: JSX.Element\n /** Copy label. Override for a non-English application. */\n copyLabel?: string\n copiedLabel?: string\n /** Line height of the rendered code. Set it when `highlight` changes the box. */\n lineHeight?: string\n /** A line-number gutter. Off by default; a short snippet rarely needs one. */\n showLineNumbers?: boolean\n /** The height above which the action row is repeated below the block. */\n tallThreshold?: number\n /**\n * Cap the code body's height and scroll it vertically past that. A number is\n * pixels; a string is any CSS length (`'20rem'`, `'50vh'`). Unset, the block\n * grows with its content.\n */\n maxHeight?: number | string\n /**\n * Soft-wrap long lines inside the block instead of scrolling sideways. Off by\n * default: wrapped code loses its column alignment, so it is for prose-like\n * output (logs, long commands) in a narrow column. Wraps the plain renderer and\n * any `pre` inside `highlight` output; line numbers stay on the first visual line.\n */\n wrap?: boolean\n /** `sm` is the compact chrome for output nested inside a Trace line. */\n size?: 'default' | 'sm'\n /**\n * Marks on 1-based line numbers. Applies to the per-line renderer, which is\n * used whenever marks or line numbers are present and no highlighter is in use,\n * given as `highlight` or loaded by `loadHighlight`: a highlighter replaces the\n * rows, so the marks and the gutter go with them.\n */\n lineMarks?: Readonly<Record<number, CodeLineMark>>\n /**\n * Resolve a highlighter for the block's language. Called once the block is\n * complete; resolving to `undefined` (or rejecting) keeps the plain rendering.\n */\n loadHighlight?: (language: string | undefined) => Promise<CodeHighlighter | undefined>\n /**\n * Lines the per-line and the highlighted renderer show before offering the\n * rest. Default 2000. The plain renderer is one text node and is not limited.\n */\n lineLimit?: number\n /** Called after each copy attempt with whether the clipboard accepted it. */\n onCopy?: (ok: boolean) => void\n}\n\nexport type CodeLineMark = 'add' | 'remove' | 'highlight' | 'error'\nexport type CodeHighlighter = (code: string) => JSX.Element\n\n/** Lines the per-line renderer shows before it offers the rest. */\nexport const CODE_BLOCK_LINE_LIMIT = 2_000\n\n/** The height a block must exceed before its actions are repeated. */\nexport const TALL_CODE_BLOCK_PX = 480\n\n/**\n * Copy, reporting whether it worked. `navigator.clipboard` is absent in an\n * insecure context, and `writeText` rejects when the document is not focused —\n * both are normal in an embedded or iframed application, and neither should\n * silently look like success.\n */\nasync function copyText(text: string): Promise<boolean> {\n try {\n if (!navigator.clipboard) return false\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n\nexport function CodeBlock(props: CodeBlockProps) {\n const [local, rest] = splitProps(props, [\n 'code',\n 'language',\n 'highlight',\n 'complete',\n 'title',\n 'actions',\n 'copyLabel',\n 'copiedLabel',\n 'lineHeight',\n 'showLineNumbers',\n 'tallThreshold',\n 'maxHeight',\n 'wrap',\n 'size',\n 'lineMarks',\n 'loadHighlight',\n 'lineLimit',\n 'onCopy',\n 'class',\n 'ref',\n ])\n\n const [copied, setCopied] = createSignal(false)\n const [failed, setFailed] = createSignal(false)\n const [tall, setTall] = createSignal(false)\n\n const [loaded, setLoaded] = createSignal<CodeHighlighter>()\n const [showAll, setShowAll] = createSignal(false)\n let bodyElement: HTMLDivElement | undefined\n\n // A language string can come from untrusted model output. It is rendered as\n // text, so it cannot inject markup; the cap keeps a pathological one from\n // swallowing the header.\n const language = () => local.language?.trim().slice(0, 40) || undefined\n const label = () => local.title ?? language() ?? 'code'\n const groupLabel = () => (language() ? `${language()} code` : 'code')\n const small = () => local.size === 'sm'\n const lines = createMemo(() => local.code.replace(/\\n$/, '').split('\\n'))\n const lineLimit = () => local.lineLimit ?? CODE_BLOCK_LINE_LIMIT\n const visibleLines = createMemo(() => (showAll() ? lines() : lines().slice(0, lineLimit())))\n const hiddenLines = () => lines().length - visibleLines().length\n\n // Load once the block has stopped changing. `on` keys the effect to the\n // language and completion, not to every streamed character, and a stale\n // resolution (the language changed while the grammar was in flight) is dropped.\n createEffect(\n on(\n () => [local.complete, language(), local.loadHighlight] as const,\n ([complete, lang, load]) => {\n setLoaded(undefined)\n if (!complete || !load || local.highlight) return\n let current = true\n onCleanup(() => (current = false))\n // Wrapped, not called bare: a loader that throws before it returns a promise\n // (a bad import path, a missing grammar table) must degrade to plain text\n // like one that rejects, not tear down the tree from inside this effect.\n new Promise<CodeHighlighter | undefined>((resolve) => resolve(load(lang))).then(\n (highlighter) => {\n if (current && highlighter) setLoaded(() => highlighter)\n },\n () => undefined\n )\n }\n )\n )\n const highlighter = (): CodeHighlighter | undefined => local.highlight ?? loaded()\n // The renderer in use decides everything about the limit, not the props alone:\n // a highlighter that has loaded since the first render replaces the per-line\n // rows, so what is drawn, and what the footer may say, follows `highlighter()`.\n const perLine = () =>\n highlighter() === undefined && (local.showLineNumbers === true || local.lineMarks !== undefined)\n const truncated = () => hiddenLines() > 0 && (highlighter() !== undefined || perLine())\n const maxHeight = () =>\n typeof local.maxHeight === 'number' ? `${local.maxHeight}px` : local.maxHeight\n\n const copy = async () => {\n const ok = await copyText(local.code)\n setCopied(ok)\n setFailed(!ok)\n local.onCopy?.(ok)\n if (ok) setTimeout(() => setCopied(false), 1500)\n }\n\n const Actions = () => (\n <div class=\"flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100 [@media(hover:none)]:opacity-100\">\n {local.actions}\n <Button\n variant=\"ghost\"\n size=\"icon-2xs\"\n touchTarget=\"comfortable\"\n aria-label={copied() ? (local.copiedLabel ?? 'Copied') : (local.copyLabel ?? 'Copy code')}\n title={failed() ? 'Copying is unavailable in this context' : undefined}\n onClick={() => void copy()}\n >\n <Show when={copied()} fallback={<Copy aria-hidden=\"true\" />}>\n <Check aria-hidden=\"true\" />\n </Show>\n </Button>\n </div>\n )\n\n return (\n <div\n data-slot=\"code-block\"\n data-size={local.size ?? 'default'}\n class={cn(\n 'group/code overflow-hidden border border-border bg-card',\n small() ? 'rounded-lg' : 'rounded-xl',\n local.class\n )}\n {...rest}\n ref={(element) => {\n // Composed rather than replaced: a caller's ref must survive.\n if (typeof local.ref === 'function') local.ref(element)\n else if (local.ref) local.ref = element\n // Measured rather than assumed: the caller controls the content, so only\n // the rendered box can say whether the action row has scrolled away.\n // The body is what is watched, not the block: the repeated action row is\n // added to the block, so watching the block made this callback resize the\n // very element it observes, which is a ResizeObserver loop (WebKit reports\n // it as an uncaught \"loop completed with undelivered notifications\" error).\n // The footer's own height is left out of the measure for the same reason: a\n // block is tall by its content, not by the row that tallness adds.\n const observer = new ResizeObserver(() => {\n const footer = element.querySelector<HTMLElement>('[data-code-block-footer]')\n setTall(\n element.offsetHeight - (footer?.offsetHeight ?? 0) >\n (local.tallThreshold ?? TALL_CODE_BLOCK_PX)\n )\n })\n onMount(() => {\n if (bodyElement) observer.observe(bodyElement)\n })\n onCleanup(() => observer.disconnect())\n }}\n >\n <div\n class={cn('flex items-center justify-between gap-2', small() ? 'px-2 py-0.5' : 'px-3 py-1')}\n >\n <span class=\"truncate font-code text-code text-muted-foreground\">{label()}</span>\n <Actions />\n </div>\n <div\n ref={(element) => (bodyElement = element)}\n data-slot=\"code-block-body\"\n data-wrap={local.wrap ? '' : undefined}\n class={cn('scroll-fade overflow-x-auto', {\n // A capped body scrolls on both axes; the region is already a tab stop,\n // so the keyboard reaches the vertical overflow the same way.\n 'overflow-y-auto': local.maxHeight !== undefined,\n '[&_pre]:whitespace-pre-wrap [&_pre]:[overflow-wrap:anywhere]': local.wrap,\n })}\n style={maxHeight() === undefined ? undefined : { 'max-height': maxHeight() }}\n // A region that scrolls must be focusable, and a tab stop needs a name.\n // A `group`, not a `region`: a landmark with the same role and name as the\n // next block's (\"ts code\" twice) is a duplicate in the screen reader's\n // landmark list, and a long answer would fill that list with code blocks.\n tabindex=\"0\"\n role=\"group\"\n aria-label={groupLabel()}\n >\n <Show\n when={highlighter()}\n fallback={\n <pre\n class={cn('m-0', small() ? 'px-2 py-1.5' : 'px-3 py-2')}\n style={{ 'line-height': local.lineHeight ?? '1.5' }}\n >\n <code class=\"font-code text-code\">\n <Show when={perLine()} fallback={local.code.replace(/\\n$/, '')}>\n <For each={visibleLines()}>\n {(line, index) => (\n <CodeLine\n line={line}\n number={index() + 1}\n numbered={local.showLineNumbers === true}\n mark={local.lineMarks?.[index() + 1]}\n wrap={local.wrap === true}\n />\n )}\n </For>\n </Show>\n </code>\n </pre>\n }\n >\n {(highlight) => (\n <div class={small() ? 'px-2 py-1.5' : 'px-3 py-2'}>\n {highlight()(hiddenLines() > 0 ? visibleLines().join('\\n') : local.code)}\n </div>\n )}\n </Show>\n <Show when={truncated()}>\n <div class=\"flex items-center gap-2 border-t border-border px-3 py-1 text-xs text-muted-foreground\">\n <span>\n Showing the first {visibleLines().length.toLocaleString()} of{' '}\n {lines().length.toLocaleString()} lines.\n </span>\n <Button\n variant=\"ghost\"\n size=\"2xs\"\n onClick={() => {\n setShowAll(true)\n // This button leaves the document with the click; the scroller\n // is the nearest place focus can stay, so a keyboard user keeps their place.\n bodyElement?.focus({ preventScroll: true })\n }}\n >\n Show all {lines().length.toLocaleString()} lines\n </Button>\n </div>\n </Show>\n {/*\n In the scroller's box, and a single line: the indicator must not add\n height when it disappears, or a streaming block shifts everything below\n it as it resolves.\n */}\n <Show when={!local.complete}>\n <p class=\"px-3 pb-2 text-xs text-muted-foreground italic\">Generating…</p>\n </Show>\n </div>\n <Show when={tall()}>\n <div\n data-code-block-footer=\"\"\n class=\"flex items-center justify-end border-t border-transparent px-3 py-1 transition-colors group-focus-within/code:border-border group-hover/code:border-border\"\n >\n <Actions />\n </div>\n </Show>\n </div>\n )\n}\n\nconst MARK_GLYPH: Readonly<Record<CodeLineMark, string>> = {\n add: '+',\n remove: '−',\n highlight: '',\n error: '!',\n}\n\n/**\n * One rendered line. The gutter glyph and the element (`ins`/`del`) carry what a\n * mark means so it survives greyscale and a screen reader; both gutters are\n * unselectable so dragging across the block and copying yields only source.\n */\nfunction CodeLine(props: {\n line: string\n number: number\n numbered: boolean\n mark?: CodeLineMark\n wrap: boolean\n}) {\n const content = () => (\n <>\n <Show when={props.numbered}>\n <span class=\"text-right text-muted-foreground select-none\" aria-hidden=\"true\">\n {props.number}\n </span>\n </Show>\n <span\n class=\"w-[1ch] text-center text-muted-foreground select-none\"\n aria-hidden=\"true\"\n data-slot=\"code-line-mark\"\n >\n {props.mark ? MARK_GLYPH[props.mark] : ''}\n </span>\n <span class={cn({ 'min-w-0': props.wrap })}>{props.line || ' '}</span>\n </>\n )\n const rowClass = () =>\n cn(\n 'grid gap-3 no-underline',\n props.numbered ? 'grid-cols-[3ch_1ch_1fr]' : 'grid-cols-[1ch_1fr]',\n {\n 'bg-success-subtle': props.mark === 'add',\n 'bg-destructive-subtle': props.mark === 'remove' || props.mark === 'error',\n 'bg-primary-subtle': props.mark === 'highlight',\n }\n )\n return (\n <Show\n when={props.mark === 'add' || props.mark === 'remove'}\n fallback={\n <span data-mark={props.mark} class={rowClass()}>\n {content()}\n </span>\n }\n >\n <Show\n when={props.mark === 'add'}\n fallback={\n <del data-mark=\"remove\" class={rowClass()}>\n {content()}\n </del>\n }\n >\n <ins data-mark=\"add\" class={rowClass()}>\n {content()}\n </ins>\n </Show>\n </Show>\n )\n}\n\n/**\n * InlineCode.\n *\n * The `code` inside a sentence. It is a component rather than a class because it\n * has to hold three properties at once: it uses the shared code family and size\n * preference, and it wraps rather than overflows a narrow column\n * (`overflow-wrap: anywhere` — an identifier with\n * no spaces is one long token), and it must be legible against whatever surface\n * it lands on, which is why the fill is a token and not a fixed grey.\n */\nexport function InlineCode(props: ComponentProps<'code'>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <code\n class={cn(\n 'rounded-sm bg-muted px-[0.4em] py-[0.15em] font-code text-code text-foreground [overflow-wrap:anywhere]',\n local.class\n )}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX, type CodeBlockProps } from './code-block';
|
|
1
|
+
export { CODE_BLOCK_LINE_LIMIT, CodeBlock, InlineCode, TALL_CODE_BLOCK_PX, type CodeBlockProps, type CodeHighlighter, type CodeLineMark, } from './code-block';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/code-block/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/code-block/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX } from "./code-block.js";
|
|
2
|
-
export { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX };
|
|
1
|
+
import { CODE_BLOCK_LINE_LIMIT, CodeBlock, InlineCode, TALL_CODE_BLOCK_PX } from "./code-block.js";
|
|
2
|
+
export { CODE_BLOCK_LINE_LIMIT, CodeBlock, InlineCode, TALL_CODE_BLOCK_PX };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type JSX } from 'solid-js';
|
|
2
|
-
|
|
2
|
+
type NumberFieldBaseProps = {
|
|
3
3
|
label: string;
|
|
4
4
|
hint?: string;
|
|
5
|
-
value: number;
|
|
6
5
|
min: number;
|
|
7
6
|
max: number;
|
|
8
7
|
/**
|
|
@@ -20,16 +19,34 @@ export type NumberFieldProps = {
|
|
|
20
19
|
* `integer={false}`, and `min={0.5} step={1}` accepts 0.5, 1.5, 2.5.
|
|
21
20
|
*/
|
|
22
21
|
integer?: boolean;
|
|
23
|
-
|
|
22
|
+
/** Locks the input; a locked field keeps its value and reports nothing. */
|
|
23
|
+
disabled?: boolean;
|
|
24
24
|
class?: string;
|
|
25
25
|
onBlur?: JSX.EventHandler<HTMLInputElement, FocusEvent>;
|
|
26
26
|
};
|
|
27
|
+
export type NumberFieldProps = NumberFieldBaseProps & ({
|
|
28
|
+
optional?: false;
|
|
29
|
+
value: number;
|
|
30
|
+
onChange: (value: number) => void;
|
|
31
|
+
} | {
|
|
32
|
+
/**
|
|
33
|
+
* Lets the field be left blank: a blank field is valid and reports `null`,
|
|
34
|
+
* and a `null` value shows a blank field. Use it for a limit that falls
|
|
35
|
+
* back to a default when unset, so a caller never maps `''` to
|
|
36
|
+
* `undefined` of its own.
|
|
37
|
+
*/
|
|
38
|
+
optional: true;
|
|
39
|
+
value: number | null;
|
|
40
|
+
onChange: (value: number | null) => void;
|
|
41
|
+
});
|
|
27
42
|
/**
|
|
28
43
|
* A controlled numeric field that keeps an editable draft while validating
|
|
29
44
|
* range, integer and step constraints. Invalid drafts are announced and restored
|
|
30
45
|
* to the latest controlled value when focus leaves the input, so `onChange`
|
|
31
46
|
* only ever receives a value the field accepts — a caller never needs a
|
|
32
|
-
* `Number(value) || fallback` of its own.
|
|
47
|
+
* `Number(value) || fallback` of its own. With `optional`, blank is accepted and
|
|
48
|
+
* reported as `null`.
|
|
33
49
|
*/
|
|
34
50
|
export declare function NumberField(props: NumberFieldProps): JSX.Element;
|
|
51
|
+
export {};
|
|
35
52
|
//# sourceMappingURL=number-field.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/number-field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAI/D,
|
|
1
|
+
{"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/number-field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAI/D,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAA;CACxD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GACjD,CACI;IACE,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAClC,GACD;IACE;;;;;OAKG;IACH,QAAQ,EAAE,IAAI,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CACzC,CACJ,CAAA;AAIH;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eA8ElD"}
|
|
@@ -3,22 +3,25 @@ import { Input } from "../input/input.js";
|
|
|
3
3
|
import { createComponent } from "solid-js/web";
|
|
4
4
|
import { createEffect, createSignal } from "solid-js";
|
|
5
5
|
//#region src/components/ui/field/number-field.tsx
|
|
6
|
+
var text = (value) => value === null ? "" : String(value);
|
|
6
7
|
/**
|
|
7
8
|
* A controlled numeric field that keeps an editable draft while validating
|
|
8
9
|
* range, integer and step constraints. Invalid drafts are announced and restored
|
|
9
10
|
* to the latest controlled value when focus leaves the input, so `onChange`
|
|
10
11
|
* only ever receives a value the field accepts — a caller never needs a
|
|
11
|
-
* `Number(value) || fallback` of its own.
|
|
12
|
+
* `Number(value) || fallback` of its own. With `optional`, blank is accepted and
|
|
13
|
+
* reported as `null`.
|
|
12
14
|
*/
|
|
13
15
|
function NumberField(props) {
|
|
14
|
-
const [draft, setDraft] = createSignal(
|
|
16
|
+
const [draft, setDraft] = createSignal(text(props.value));
|
|
15
17
|
const [error, setError] = createSignal("");
|
|
16
18
|
const integer = () => props.integer ?? (props.step === void 0 || Number.isInteger(props.step) && Number.isInteger(props.min));
|
|
17
19
|
createEffect(() => {
|
|
18
|
-
setDraft(
|
|
20
|
+
setDraft(text(props.value));
|
|
19
21
|
});
|
|
20
|
-
const validate = (raw) => {
|
|
21
|
-
if (
|
|
22
|
+
const validate = (raw, badInput) => {
|
|
23
|
+
if (badInput) return `${props.label} must be a valid number.`;
|
|
24
|
+
if (!raw) return props.optional ? "" : `${props.label} is required.`;
|
|
22
25
|
const next = Number(raw);
|
|
23
26
|
if (!Number.isFinite(next)) return `${props.label} must be a valid number.`;
|
|
24
27
|
if (integer() && !Number.isInteger(next)) return `${props.label} must be a whole number.`;
|
|
@@ -57,18 +60,26 @@ function NumberField(props) {
|
|
|
57
60
|
get step() {
|
|
58
61
|
return props.step ?? (integer() ? 1 : "any");
|
|
59
62
|
},
|
|
60
|
-
required
|
|
63
|
+
get required() {
|
|
64
|
+
return !props.optional;
|
|
65
|
+
},
|
|
66
|
+
get disabled() {
|
|
67
|
+
return props.disabled;
|
|
68
|
+
},
|
|
61
69
|
onInput: (event) => {
|
|
62
70
|
const raw = event.currentTarget.value;
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
const badInput = event.currentTarget.validity.badInput;
|
|
72
|
+
if (!badInput) setDraft(raw);
|
|
73
|
+
const nextError = validate(raw, badInput);
|
|
65
74
|
setError(nextError);
|
|
66
|
-
if (
|
|
75
|
+
if (nextError) return;
|
|
76
|
+
props.onChange(raw ? Number(raw) : null);
|
|
67
77
|
},
|
|
68
78
|
onBlur: (event) => {
|
|
69
|
-
if (validate(draft())) {
|
|
70
|
-
setDraft(
|
|
79
|
+
if (validate(draft(), event.currentTarget.validity.badInput)) {
|
|
80
|
+
setDraft(text(props.value));
|
|
71
81
|
setError("");
|
|
82
|
+
event.currentTarget.value = text(props.value);
|
|
72
83
|
}
|
|
73
84
|
props.onBlur?.(event);
|
|
74
85
|
}
|