@elabs-ai/components-ai 4.2.0 → 5.0.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 +1 -1
- package/dist/{_audio-player-media-chrome-T3XVXWRZ.js → _audio-player-media-chrome.js} +1 -1
- package/dist/_code-block-theme.js +12 -0
- package/dist/_code-block-theme.js.map +1 -0
- package/dist/{_flow-boundary-SHNWLQG5.js → _flow-boundary.js} +1 -1
- package/dist/_flow-boundary.js.map +1 -0
- package/dist/_flow-lazy.js +8 -0
- package/dist/_flow-lazy.js.map +1 -0
- package/dist/_lazy-boundary-conformance.js +2 -0
- package/dist/_lazy-boundary-conformance.js.map +1 -0
- package/dist/_lazy-cjk.js +13 -0
- package/dist/_lazy-cjk.js.map +1 -0
- package/dist/_lazy-engine-boundary.js +9 -0
- package/dist/_lazy-engine-boundary.js.map +1 -0
- package/dist/_lazy-math.js +13 -0
- package/dist/_lazy-math.js.map +1 -0
- package/dist/_lazy-mermaid.js +12 -0
- package/dist/_lazy-mermaid.js.map +1 -0
- package/dist/_mermaid-error-panel.js +9 -0
- package/dist/_mermaid-error-panel.js.map +1 -0
- package/dist/{_persona-rive-JEG44YHX.js → _persona-rive.js} +19 -24
- package/dist/_persona-rive.js.map +1 -0
- package/dist/_streamdown-i18n.js +21 -0
- package/dist/_streamdown-i18n.js.map +1 -0
- package/dist/_streamdown-safety.js +10 -0
- package/dist/_streamdown-safety.js.map +1 -0
- package/dist/_theme-scope-store.js +13 -0
- package/dist/_theme-scope-store.js.map +1 -0
- package/dist/a2ui/a2ui-surface.js +17 -0
- package/dist/a2ui/a2ui-surface.js.map +1 -0
- package/dist/a2ui/core/catalog.generated.js +10 -0
- package/dist/a2ui/core/catalog.generated.js.map +1 -0
- package/dist/a2ui/core/complete-json.js +10 -0
- package/dist/a2ui/core/complete-json.js.map +1 -0
- package/dist/a2ui/core/index.js +37 -0
- package/dist/a2ui/core/index.js.map +1 -0
- package/dist/a2ui/core/schema.js +11 -0
- package/dist/a2ui/core/schema.js.map +1 -0
- package/dist/a2ui/core/spec.js +10 -0
- package/dist/a2ui/core/spec.js.map +1 -0
- package/dist/a2ui/core/validate.js +16 -0
- package/dist/a2ui/core/validate.js.map +1 -0
- package/dist/a2ui/index.js +54 -0
- package/dist/a2ui/index.js.map +1 -0
- package/dist/a2ui/ui-catalog.js +18 -0
- package/dist/a2ui/ui-catalog.js.map +1 -0
- package/dist/agent-event.js +10 -0
- package/dist/agent-event.js.map +1 -0
- package/dist/agent-timeline.js +11 -0
- package/dist/agent-timeline.js.map +1 -0
- package/dist/agent.js +25 -0
- package/dist/agent.js.map +1 -0
- package/dist/artifact.js +23 -0
- package/dist/artifact.js.map +1 -0
- package/dist/asset-preview.js +22 -0
- package/dist/asset-preview.js.map +1 -0
- package/dist/attachments.js +33 -0
- package/dist/attachments.js.map +1 -0
- package/dist/audio-player.js +30 -0
- package/dist/audio-player.js.map +1 -0
- package/dist/audio-visualizer.js +9 -0
- package/dist/audio-visualizer.js.map +1 -0
- package/dist/canvas.js +10 -0
- package/dist/canvas.js.map +1 -0
- package/dist/chain-of-thought.js +22 -0
- package/dist/chain-of-thought.js.map +1 -0
- package/dist/chat-greeting.js +8 -0
- package/dist/chat-greeting.js.map +1 -0
- package/dist/chat-shell.js +9 -0
- package/dist/chat-shell.js.map +1 -0
- package/dist/checkpoint.js +13 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/chunk-2XOIG5TG.js +72 -0
- package/dist/chunk-2XOIG5TG.js.map +1 -0
- package/dist/chunk-34CQ2VHM.js +172 -0
- package/dist/chunk-34CQ2VHM.js.map +1 -0
- package/dist/chunk-3TDHPXZZ.js +60 -0
- package/dist/chunk-3TDHPXZZ.js.map +1 -0
- package/dist/chunk-3XNPMDZY.js +478 -0
- package/dist/chunk-3XNPMDZY.js.map +1 -0
- package/dist/chunk-3YPT3V7L.js +56 -0
- package/dist/chunk-3YPT3V7L.js.map +1 -0
- package/dist/chunk-475UEU2Q.js +87 -0
- package/dist/chunk-475UEU2Q.js.map +1 -0
- package/dist/chunk-4CBTII2I.js +95 -0
- package/dist/chunk-4CBTII2I.js.map +1 -0
- package/dist/chunk-4XRNIZMG.js +22 -0
- package/dist/chunk-4XRNIZMG.js.map +1 -0
- package/dist/chunk-5NNWUKK5.js +2 -0
- package/dist/chunk-5NNWUKK5.js.map +1 -0
- package/dist/chunk-5UOMU27Z.js +164 -0
- package/dist/chunk-5UOMU27Z.js.map +1 -0
- package/dist/chunk-5VGYZ62I.js +264 -0
- package/dist/chunk-5VGYZ62I.js.map +1 -0
- package/dist/chunk-6IQPH2OS.js +21 -0
- package/dist/chunk-6IQPH2OS.js.map +1 -0
- package/dist/chunk-6PB2MXCI.js +482 -0
- package/dist/chunk-6PB2MXCI.js.map +1 -0
- package/dist/chunk-7FD5CZEU.js +215 -0
- package/dist/chunk-7FD5CZEU.js.map +1 -0
- package/dist/chunk-7RL6KZDF.js +266 -0
- package/dist/chunk-7RL6KZDF.js.map +1 -0
- package/dist/chunk-ADOYAGGK.js +482 -0
- package/dist/chunk-ADOYAGGK.js.map +1 -0
- package/dist/chunk-AXMNJMMH.js +984 -0
- package/dist/chunk-AXMNJMMH.js.map +1 -0
- package/dist/chunk-BA3AEMOU.js +21 -0
- package/dist/chunk-BA3AEMOU.js.map +1 -0
- package/dist/chunk-BBHFOYML.js +336 -0
- package/dist/chunk-BBHFOYML.js.map +1 -0
- package/dist/chunk-BHUVISIY.js +221 -0
- package/dist/chunk-BHUVISIY.js.map +1 -0
- package/dist/chunk-BM2LWERA.js +100 -0
- package/dist/chunk-BM2LWERA.js.map +1 -0
- package/dist/chunk-CMOYXNPJ.js +211 -0
- package/dist/chunk-CMOYXNPJ.js.map +1 -0
- package/dist/chunk-CZP3RHC4.js +74 -0
- package/dist/chunk-CZP3RHC4.js.map +1 -0
- package/dist/chunk-DDG5JHQT.js +112 -0
- package/dist/chunk-DDG5JHQT.js.map +1 -0
- package/dist/chunk-DJODXO7I.js +38 -0
- package/dist/chunk-DJODXO7I.js.map +1 -0
- package/dist/chunk-DWJDJLPU.js +192 -0
- package/dist/chunk-DWJDJLPU.js.map +1 -0
- package/dist/chunk-DZW6LM22.js +45 -0
- package/dist/chunk-DZW6LM22.js.map +1 -0
- package/dist/chunk-ELGCZLZF.js +305 -0
- package/dist/chunk-ELGCZLZF.js.map +1 -0
- package/dist/chunk-EV3U6ZZB.js +209 -0
- package/dist/chunk-EV3U6ZZB.js.map +1 -0
- package/dist/chunk-EY7LVUKQ.js +87 -0
- package/dist/chunk-EY7LVUKQ.js.map +1 -0
- package/dist/chunk-F4C74F7M.js +230 -0
- package/dist/chunk-F4C74F7M.js.map +1 -0
- package/dist/chunk-FERYDFZA.js +108 -0
- package/dist/chunk-FERYDFZA.js.map +1 -0
- package/dist/chunk-FUIYG2DS.js +166 -0
- package/dist/chunk-FUIYG2DS.js.map +1 -0
- package/dist/chunk-GKYZT3LA.js +136 -0
- package/dist/chunk-GKYZT3LA.js.map +1 -0
- package/dist/chunk-H42LRUQ4.js +102 -0
- package/dist/chunk-H42LRUQ4.js.map +1 -0
- package/dist/chunk-HVXM2G5F.js +222 -0
- package/dist/chunk-HVXM2G5F.js.map +1 -0
- package/dist/chunk-I4RDAGVY.js +53 -0
- package/dist/chunk-I4RDAGVY.js.map +1 -0
- package/dist/chunk-IQJG4IDX.js +208 -0
- package/dist/chunk-IQJG4IDX.js.map +1 -0
- package/dist/chunk-IX2PXG4Y.js +144 -0
- package/dist/chunk-IX2PXG4Y.js.map +1 -0
- package/dist/chunk-IXICSOOP.js +287 -0
- package/dist/chunk-IXICSOOP.js.map +1 -0
- package/dist/chunk-JY5HSN4D.js +84 -0
- package/dist/chunk-JY5HSN4D.js.map +1 -0
- package/dist/chunk-LMNSBOBG.js +19 -0
- package/dist/chunk-LMNSBOBG.js.map +1 -0
- package/dist/chunk-MBI7D6IL.js +42 -0
- package/dist/chunk-MBI7D6IL.js.map +1 -0
- package/dist/chunk-MLFMYCPH.js +192 -0
- package/dist/chunk-MLFMYCPH.js.map +1 -0
- package/dist/chunk-MOK66734.js +33 -0
- package/dist/chunk-MOK66734.js.map +1 -0
- package/dist/chunk-MXTAWPYM.js +196 -0
- package/dist/chunk-MXTAWPYM.js.map +1 -0
- package/dist/chunk-NCL2UZKI.js +96 -0
- package/dist/chunk-NCL2UZKI.js.map +1 -0
- package/dist/chunk-NET4YLRY.js +107 -0
- package/dist/chunk-NET4YLRY.js.map +1 -0
- package/dist/chunk-NIG67CFM.js +329 -0
- package/dist/chunk-NIG67CFM.js.map +1 -0
- package/dist/chunk-NMVNNO3L.js +10 -0
- package/dist/chunk-NMVNNO3L.js.map +1 -0
- package/dist/chunk-NP7VID4K.js +2 -0
- package/dist/chunk-NP7VID4K.js.map +1 -0
- package/dist/chunk-NPUCMAG2.js +382 -0
- package/dist/chunk-NPUCMAG2.js.map +1 -0
- package/dist/chunk-NSCLRHES.js +102 -0
- package/dist/chunk-NSCLRHES.js.map +1 -0
- package/dist/chunk-OEUXHVFW.js +86 -0
- package/dist/chunk-OEUXHVFW.js.map +1 -0
- package/dist/chunk-ONBHFIMZ.js +137 -0
- package/dist/chunk-ONBHFIMZ.js.map +1 -0
- package/dist/chunk-OPH2HHL2.js +228 -0
- package/dist/chunk-OPH2HHL2.js.map +1 -0
- package/dist/chunk-OQERHIQP.js +287 -0
- package/dist/chunk-OQERHIQP.js.map +1 -0
- package/dist/chunk-P6YJAZFG.js +103 -0
- package/dist/chunk-P6YJAZFG.js.map +1 -0
- package/dist/chunk-PG7ERDOD.js +65 -0
- package/dist/chunk-PG7ERDOD.js.map +1 -0
- package/dist/chunk-PIB5JBMA.js +90 -0
- package/dist/chunk-PIB5JBMA.js.map +1 -0
- package/dist/chunk-PQ5BPIWQ.js +22 -0
- package/dist/chunk-PQ5BPIWQ.js.map +1 -0
- package/dist/chunk-PQBF6ZIQ.js +55 -0
- package/dist/chunk-PQBF6ZIQ.js.map +1 -0
- package/dist/chunk-PTWCTSZL.js +173 -0
- package/dist/chunk-PTWCTSZL.js.map +1 -0
- package/dist/chunk-QJUNPVOS.js +101 -0
- package/dist/chunk-QJUNPVOS.js.map +1 -0
- package/dist/chunk-QUDZOTRV.js +43 -0
- package/dist/chunk-QUDZOTRV.js.map +1 -0
- package/dist/chunk-RB7G65JC.js +213 -0
- package/dist/chunk-RB7G65JC.js.map +1 -0
- package/dist/chunk-RPHAOR7P.js +45 -0
- package/dist/chunk-RPHAOR7P.js.map +1 -0
- package/dist/chunk-RTCSH2AN.js +331 -0
- package/dist/chunk-RTCSH2AN.js.map +1 -0
- package/dist/chunk-S3ISPW3A.js +28 -0
- package/dist/chunk-S3ISPW3A.js.map +1 -0
- package/dist/chunk-SEVN656N.js +36 -0
- package/dist/chunk-SEVN656N.js.map +1 -0
- package/dist/chunk-SKVG672B.js +64 -0
- package/dist/chunk-SKVG672B.js.map +1 -0
- package/dist/chunk-SPQIU7GA.js +236 -0
- package/dist/chunk-SPQIU7GA.js.map +1 -0
- package/dist/chunk-SSGJ6MEM.js +1076 -0
- package/dist/chunk-SSGJ6MEM.js.map +1 -0
- package/dist/chunk-SSKZ2AED.js +118 -0
- package/dist/chunk-SSKZ2AED.js.map +1 -0
- package/dist/chunk-T56JFGXI.js +561 -0
- package/dist/chunk-T56JFGXI.js.map +1 -0
- package/dist/chunk-TCB6O74A.js +137 -0
- package/dist/chunk-TCB6O74A.js.map +1 -0
- package/dist/chunk-TTEYPO6X.js +57 -0
- package/dist/chunk-TTEYPO6X.js.map +1 -0
- package/dist/chunk-TWPHAJNM.js +462 -0
- package/dist/chunk-TWPHAJNM.js.map +1 -0
- package/dist/chunk-TXJJLP4O.js +336 -0
- package/dist/chunk-TXJJLP4O.js.map +1 -0
- package/dist/chunk-TZ6TB7VM.js +245 -0
- package/dist/chunk-TZ6TB7VM.js.map +1 -0
- package/dist/chunk-UBLKJJ7K.js +278 -0
- package/dist/chunk-UBLKJJ7K.js.map +1 -0
- package/dist/chunk-UCJ6IUFS.js +52 -0
- package/dist/chunk-UCJ6IUFS.js.map +1 -0
- package/dist/chunk-UCKFJ3QF.js +197 -0
- package/dist/chunk-UCKFJ3QF.js.map +1 -0
- package/dist/chunk-UPXSLILN.js +20 -0
- package/dist/chunk-UPXSLILN.js.map +1 -0
- package/dist/chunk-V4DORGWJ.js +92 -0
- package/dist/chunk-V4DORGWJ.js.map +1 -0
- package/dist/chunk-V6E5DYZD.js +80 -0
- package/dist/chunk-V6E5DYZD.js.map +1 -0
- package/dist/chunk-VLLYKF3P.js +96 -0
- package/dist/chunk-VLLYKF3P.js.map +1 -0
- package/dist/chunk-VLNBTOH6.js +43 -0
- package/dist/chunk-VLNBTOH6.js.map +1 -0
- package/dist/chunk-WMDSMSPL.js +303 -0
- package/dist/chunk-WMDSMSPL.js.map +1 -0
- package/dist/chunk-WU5BLGTF.js +149 -0
- package/dist/chunk-WU5BLGTF.js.map +1 -0
- package/dist/chunk-WYTZVSGK.js +245 -0
- package/dist/chunk-WYTZVSGK.js.map +1 -0
- package/dist/chunk-X47QMM6K.js +187 -0
- package/dist/chunk-X47QMM6K.js.map +1 -0
- package/dist/chunk-XNBKO32Y.js +174 -0
- package/dist/chunk-XNBKO32Y.js.map +1 -0
- package/dist/chunk-YHUSW7D2.js +40 -0
- package/dist/chunk-YHUSW7D2.js.map +1 -0
- package/dist/chunk-YSKD7UXX.js +126 -0
- package/dist/chunk-YSKD7UXX.js.map +1 -0
- package/dist/chunk-YYRDGWOU.js +72 -0
- package/dist/chunk-YYRDGWOU.js.map +1 -0
- package/dist/chunk-ZIGZMWM7.js +19 -0
- package/dist/chunk-ZIGZMWM7.js.map +1 -0
- package/dist/chunk-ZKRTUKNP.js +40 -0
- package/dist/chunk-ZKRTUKNP.js.map +1 -0
- package/dist/code-block.js +38 -0
- package/dist/code-block.js.map +1 -0
- package/dist/commit.js +51 -0
- package/dist/commit.js.map +1 -0
- package/dist/composer.js +15 -0
- package/dist/composer.js.map +1 -0
- package/dist/confirmation.js +53 -0
- package/dist/confirmation.js.map +1 -0
- package/dist/connection.js +8 -0
- package/dist/connection.js.map +1 -0
- package/dist/context-panel.js +25 -0
- package/dist/context-panel.js.map +1 -0
- package/dist/controls.js +10 -0
- package/dist/controls.js.map +1 -0
- package/dist/conversation.js +19 -0
- package/dist/conversation.js.map +1 -0
- package/dist/diff-view.js +15 -0
- package/dist/diff-view.js.map +1 -0
- package/dist/edge.js +10 -0
- package/dist/edge.js.map +1 -0
- package/dist/environment-variables.js +29 -0
- package/dist/environment-variables.js.map +1 -0
- package/dist/file-tree.js +23 -0
- package/dist/file-tree.js.map +1 -0
- package/dist/gallery.js +9 -0
- package/dist/gallery.js.map +1 -0
- package/dist/grouped-parts.js +21 -0
- package/dist/grouped-parts.js.map +1 -0
- package/dist/image.js +9 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +366 -98
- package/dist/index.js +672 -13577
- package/dist/index.js.map +1 -1
- package/dist/inline-citation.js +39 -0
- package/dist/inline-citation.js.map +1 -0
- package/dist/jsx-preview.js +17 -0
- package/dist/jsx-preview.js.map +1 -0
- package/dist/markdown-view.js +17 -0
- package/dist/markdown-view.js.map +1 -0
- package/dist/message-compare.js +12 -0
- package/dist/message-compare.js.map +1 -0
- package/dist/message-edit.js +19 -0
- package/dist/message-edit.js.map +1 -0
- package/dist/message-feedback.js +11 -0
- package/dist/message-feedback.js.map +1 -0
- package/dist/message-form-spec.js +38 -0
- package/dist/message-form-spec.js.map +1 -0
- package/dist/message-form.js +26 -0
- package/dist/message-form.js.map +1 -0
- package/dist/message-table-spec.js +26 -0
- package/dist/message-table-spec.js.map +1 -0
- package/dist/message-table.js +12 -0
- package/dist/message-table.js.map +1 -0
- package/dist/message.js +51 -0
- package/dist/message.js.map +1 -0
- package/dist/mic-selector.js +27 -0
- package/dist/mic-selector.js.map +1 -0
- package/dist/model-provider-logo.js +13 -0
- package/dist/model-provider-logo.js.map +1 -0
- package/dist/motion-config.js +9 -0
- package/dist/motion-config.js.map +1 -0
- package/dist/node.js +22 -0
- package/dist/node.js.map +1 -0
- package/dist/open-in-chat.js +31 -0
- package/dist/open-in-chat.js.map +1 -0
- package/dist/package-info.js +25 -0
- package/dist/package-info.js.map +1 -0
- package/dist/panel.js +10 -0
- package/dist/panel.js.map +1 -0
- package/dist/part-groups.js +18 -0
- package/dist/part-groups.js.map +1 -0
- package/dist/permission-mode-select.js +9 -0
- package/dist/permission-mode-select.js.map +1 -0
- package/dist/persona-sources.js +8 -0
- package/dist/persona-sources.js.map +1 -0
- package/dist/persona.js +14 -0
- package/dist/persona.js.map +1 -0
- package/dist/plan.js +32 -0
- package/dist/plan.js.map +1 -0
- package/dist/prompt-input-effort.js +9 -0
- package/dist/prompt-input-effort.js.map +1 -0
- package/dist/prompt-input-mode.js +10 -0
- package/dist/prompt-input-mode.js.map +1 -0
- package/dist/prompt-input-slash.js +12 -0
- package/dist/prompt-input-slash.js.map +1 -0
- package/dist/prompt-input.js +89 -0
- package/dist/prompt-input.js.map +1 -0
- package/dist/queue.js +37 -0
- package/dist/queue.js.map +1 -0
- package/dist/reasoning.js +23 -0
- package/dist/reasoning.js.map +1 -0
- package/dist/sandbox.js +28 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/schema-display.js +33 -0
- package/dist/schema-display.js.map +1 -0
- package/dist/selection-toolbar.js +11 -0
- package/dist/selection-toolbar.js.map +1 -0
- package/dist/session-header.js +9 -0
- package/dist/session-header.js.map +1 -0
- package/dist/session-status-bar.js +9 -0
- package/dist/session-status-bar.js.map +1 -0
- package/dist/shimmer.js +9 -0
- package/dist/shimmer.js.map +1 -0
- package/dist/snippet.js +17 -0
- package/dist/snippet.js.map +1 -0
- package/dist/sources.js +17 -0
- package/dist/sources.js.map +1 -0
- package/dist/speech-input.js +9 -0
- package/dist/speech-input.js.map +1 -0
- package/dist/stack-trace.js +27 -0
- package/dist/stack-trace.js.map +1 -0
- package/dist/suggestion.js +16 -0
- package/dist/suggestion.js.map +1 -0
- package/dist/task.js +18 -0
- package/dist/task.js.map +1 -0
- package/dist/test-results.js +43 -0
- package/dist/test-results.js.map +1 -0
- package/dist/token-usage.js +27 -0
- package/dist/token-usage.js.map +1 -0
- package/dist/tool-result-card.js +9 -0
- package/dist/tool-result-card.js.map +1 -0
- package/dist/tool.js +27 -0
- package/dist/tool.js.map +1 -0
- package/dist/toolbar.js +10 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/transcription.js +11 -0
- package/dist/transcription.js.map +1 -0
- package/dist/turn-status.js +9 -0
- package/dist/turn-status.js.map +1 -0
- package/dist/use-audio-level.js +9 -0
- package/dist/use-audio-level.js.map +1 -0
- package/dist/voice-selector.js +47 -0
- package/dist/voice-selector.js.map +1 -0
- package/dist/web-preview.js +19 -0
- package/dist/web-preview.js.map +1 -0
- package/package.json +11 -9
- package/schemas/a2ui-surface.v1.schema.json +5425 -0
- package/src/_chat-shell-rail.tsx +3 -1
- package/src/_flow-boundary.tsx +2 -2
- package/src/_persona-rive.tsx +27 -41
- package/src/a2ui/a2ui-surface.stories.tsx +662 -0
- package/src/a2ui/a2ui-surface.test.tsx +201 -0
- package/src/a2ui/a2ui-surface.tsx +354 -0
- package/src/a2ui/catalog.source.json +772 -0
- package/src/a2ui/core/a2ui-core.test.ts +178 -0
- package/src/a2ui/core/catalog.generated.ts +1006 -0
- package/src/a2ui/core/complete-json.ts +81 -0
- package/src/a2ui/core/index.ts +10 -0
- package/src/a2ui/core/schema.ts +111 -0
- package/src/a2ui/core/spec.ts +148 -0
- package/src/a2ui/core/validate.ts +266 -0
- package/src/a2ui/index.ts +7 -0
- package/src/a2ui/ui-catalog.tsx +225 -0
- package/src/a2ui/wave1-chart-spec.test.ts +87 -0
- package/src/a2ui/wave2-chart-spec.test.ts +108 -0
- package/src/agentic-workspace.stories.tsx +6 -45
- package/src/chat-shell.test.tsx +40 -10
- package/src/chat-shell.tsx +90 -44
- package/src/chat.stories.tsx +47 -42
- package/src/composer.stories.tsx +4 -5
- package/src/composer.test.tsx +45 -0
- package/src/composer.tsx +104 -21
- package/src/context-panel.stories.tsx +1 -1
- package/src/context-panel.tsx +1 -1
- package/src/conversation.stories.tsx +1 -0
- package/src/conversation.test.tsx +16 -0
- package/src/conversation.tsx +16 -2
- package/src/diff-view.stories.tsx +79 -0
- package/src/diff-view.tsx +3 -2
- package/src/file-tree.tsx +24 -17
- package/src/gallery.stories.tsx +42 -0
- package/src/gallery.tsx +2 -2
- package/src/grouped-parts.stories.tsx +23 -0
- package/src/grouped-parts.tsx +1 -1
- package/src/index.ts +1 -0
- package/src/message-compare.stories.tsx +40 -0
- package/src/message-compare.tsx +2 -1
- package/src/message-form.tsx +1 -1
- package/src/message-table.stories.tsx +24 -0
- package/src/message-table.tsx +1 -1
- package/src/package-info.tsx +12 -9
- package/src/reasoning.stories.tsx +27 -0
- package/src/reasoning.tsx +1 -1
- package/src/session-header.stories.tsx +35 -1
- package/src/session-header.tsx +1 -1
- package/src/sources.stories.tsx +30 -0
- package/src/sources.tsx +4 -1
- package/src/templates-ai-assistant.stories.tsx +151 -87
- package/src/tool.stories.tsx +39 -0
- package/src/tool.tsx +3 -3
- package/src/toolbar.tsx +0 -10
- package/dist/_flow-boundary-SHNWLQG5.js.map +0 -1
- package/dist/_persona-rive-JEG44YHX.js.map +0 -1
- /package/dist/{_audio-player-media-chrome-T3XVXWRZ.js.map → _audio-player-media-chrome.js.map} +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/turn-status.tsx
|
|
4
|
+
import { Button, cn, formatElapsed, useLocale } from "@elabs-ai/components-ui";
|
|
5
|
+
import { ArrowDownIcon, SquareIcon } from "lucide-react";
|
|
6
|
+
import { forwardRef } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var TurnStatus = forwardRef(function TurnStatus2({
|
|
9
|
+
label,
|
|
10
|
+
elapsedMs,
|
|
11
|
+
tokens,
|
|
12
|
+
turn,
|
|
13
|
+
turnTotal,
|
|
14
|
+
status = "working",
|
|
15
|
+
onStop,
|
|
16
|
+
showScrollToBottom,
|
|
17
|
+
onScrollToBottom,
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}, ref) {
|
|
21
|
+
const { t, formatNumber } = useLocale();
|
|
22
|
+
const isSettled = status === "settled";
|
|
23
|
+
const formattedElapsed = elapsedMs === void 0 ? void 0 : formatElapsed(elapsedMs);
|
|
24
|
+
const settledText = isSettled ? label ?? (formattedElapsed ? t("ai.turnStatus.completedIn", { elapsed: formattedElapsed }) : t("ai.turnStatus.completed")) : void 0;
|
|
25
|
+
const announced = isSettled ? settledText ?? "" : label ?? "";
|
|
26
|
+
const hasTokens = tokens?.input !== void 0 || tokens?.output !== void 0;
|
|
27
|
+
const hasTurn = turn !== void 0;
|
|
28
|
+
const visibleLabel = isSettled ? settledText : label;
|
|
29
|
+
const hasMeta = !isSettled && (formattedElapsed !== void 0 || hasTokens || hasTurn);
|
|
30
|
+
const showStop = !isSettled && Boolean(onStop);
|
|
31
|
+
const hasTrailing = hasMeta || showScrollToBottom || showStop;
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
className: cn("flex w-full items-center gap-3 text-body text-foreground", className),
|
|
37
|
+
"data-slot": "turn-status",
|
|
38
|
+
...props,
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
"span",
|
|
42
|
+
{
|
|
43
|
+
"aria-hidden": "true",
|
|
44
|
+
className: cn(
|
|
45
|
+
"size-2 shrink-0 rounded-full",
|
|
46
|
+
isSettled ? "bg-success" : "animate-pulse bg-primary motion-reduce:animate-none"
|
|
47
|
+
),
|
|
48
|
+
"data-slot": "turn-status-indicator"
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
visibleLabel ? /* @__PURE__ */ jsx("span", { className: "truncate", "data-slot": "turn-status-label", children: visibleLabel }) : null,
|
|
52
|
+
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", "data-slot": "turn-status-live", role: "status", children: announced }),
|
|
53
|
+
hasTrailing ? /* @__PURE__ */ jsxs("div", { className: "ms-auto flex shrink-0 items-center gap-3", "data-slot": "turn-status-trailing", children: [
|
|
54
|
+
hasMeta ? /* @__PURE__ */ jsxs(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
className: "flex items-center gap-3 text-meta text-muted-foreground tabular-nums",
|
|
58
|
+
"data-slot": "turn-status-meta",
|
|
59
|
+
children: [
|
|
60
|
+
formattedElapsed ? /* @__PURE__ */ jsx("span", { "data-slot": "turn-status-elapsed", children: formattedElapsed }) : null,
|
|
61
|
+
hasTokens ? /* @__PURE__ */ jsxs("span", { "data-slot": "turn-status-tokens", children: [
|
|
62
|
+
formatNumber(tokens?.input ?? 0, { notation: "compact" }),
|
|
63
|
+
"\u2191 ",
|
|
64
|
+
formatNumber(tokens?.output ?? 0, { notation: "compact" }),
|
|
65
|
+
"\u2193"
|
|
66
|
+
] }) : null,
|
|
67
|
+
hasTurn ? /* @__PURE__ */ jsxs("span", { "data-slot": "turn-status-turn", children: [
|
|
68
|
+
turn,
|
|
69
|
+
turnTotal === void 0 ? "" : `/${turnTotal}`
|
|
70
|
+
] }) : null
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
) : null,
|
|
74
|
+
showScrollToBottom ? /* @__PURE__ */ jsx(
|
|
75
|
+
Button,
|
|
76
|
+
{
|
|
77
|
+
"aria-label": t("ai.turnStatus.scrollToBottom"),
|
|
78
|
+
"data-slot": "turn-status-scroll-to-bottom",
|
|
79
|
+
onClick: onScrollToBottom,
|
|
80
|
+
size: "icon-sm",
|
|
81
|
+
type: "button",
|
|
82
|
+
variant: "ghost",
|
|
83
|
+
children: /* @__PURE__ */ jsx(ArrowDownIcon, { className: "size-4" })
|
|
84
|
+
}
|
|
85
|
+
) : null,
|
|
86
|
+
showStop ? /* @__PURE__ */ jsx(
|
|
87
|
+
Button,
|
|
88
|
+
{
|
|
89
|
+
"aria-label": t("ai.promptInput.stop"),
|
|
90
|
+
"data-slot": "turn-status-stop",
|
|
91
|
+
onClick: onStop,
|
|
92
|
+
size: "icon-sm",
|
|
93
|
+
type: "button",
|
|
94
|
+
variant: "outline",
|
|
95
|
+
children: /* @__PURE__ */ jsx(SquareIcon, { className: "size-4" })
|
|
96
|
+
}
|
|
97
|
+
) : null
|
|
98
|
+
] }) : null
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export {
|
|
105
|
+
TurnStatus
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=chunk-NET4YLRY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/turn-status.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button, cn, formatElapsed, useLocale } from \"@elabs-ai/components-ui\";\nimport { ArrowDownIcon, SquareIcon } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nexport interface TurnStatusTokens {\n input?: number;\n output?: number;\n}\n\nexport interface TurnStatusProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n /**\n * What the turn is doing right now, e.g. `\"Working…\"`, `\"Editing files…\"`.\n * Caller-supplied and rendered verbatim — `TurnStatus` never invents this\n * text, so it carries no default and needs no translation key of its own.\n */\n label?: string;\n /** Elapsed time in the current turn, in milliseconds. Rendered via `formatElapsed`. */\n elapsedMs?: number;\n /** Token counts for the turn so far. */\n tokens?: TurnStatusTokens;\n /** 1-based index of the current turn. */\n turn?: number;\n /** Total number of turns, when known. */\n turnTotal?: number;\n /**\n * `\"working\"` (default) renders the live stats + stop control and keeps\n * announcing `label` changes. `\"settled\"` renders the completed-turn line\n * instead and stops announcing (the elapsed/tokens/turn stats and the stop\n * control are hidden — the turn is over).\n */\n status?: \"working\" | \"settled\";\n /** Renders a focusable stop button, reachable by keyboard, while `status=\"working\"`. */\n onStop?: () => void;\n /** Renders a \"scroll to bottom\" affordance. */\n showScrollToBottom?: boolean;\n onScrollToBottom?: () => void;\n}\n\n/**\n * TurnStatus — the in-turn footer: a working/settled label, elapsed time,\n * token counts, turn progress, and a stop affordance, all in one place (#105).\n *\n * Exactly ONE `role=\"status\" aria-live=\"polite\"` region is rendered — a\n * visually-hidden node that announces `label` while working and the\n * completed-turn line once `status=\"settled\"`. The ticking elapsed time and\n * token/turn counts are plain (non-live) visible text: they update every\n * render without re-announcing on every tick, which would flood assistive\n * tech (see `.claude/rules/loading-states.md`). This mirrors `Persona`'s\n * visible-content/`sr-only`-announcement split.\n */\nexport const TurnStatus = forwardRef<HTMLDivElement, TurnStatusProps>(function TurnStatus(\n {\n label,\n elapsedMs,\n tokens,\n turn,\n turnTotal,\n status = \"working\",\n onStop,\n showScrollToBottom,\n onScrollToBottom,\n className,\n ...props\n },\n ref,\n) {\n const { t, formatNumber } = useLocale();\n const isSettled = status === \"settled\";\n const formattedElapsed = elapsedMs === undefined ? undefined : formatElapsed(elapsedMs);\n\n const settledText = isSettled\n ? (label ??\n (formattedElapsed\n ? t(\"ai.turnStatus.completedIn\", { elapsed: formattedElapsed })\n : t(\"ai.turnStatus.completed\")))\n : undefined;\n\n /** The one thing this component ever announces: `label`, or the settled line. */\n const announced = isSettled ? (settledText ?? \"\") : (label ?? \"\");\n\n const hasTokens = tokens?.input !== undefined || tokens?.output !== undefined;\n const hasTurn = turn !== undefined;\n const visibleLabel = isSettled ? settledText : label;\n const hasMeta = !isSettled && (formattedElapsed !== undefined || hasTokens || hasTurn);\n const showStop = !isSettled && Boolean(onStop);\n const hasTrailing = hasMeta || showScrollToBottom || showStop;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex w-full items-center gap-3 text-body text-foreground\", className)}\n data-slot=\"turn-status\"\n {...props}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n isSettled ? \"bg-success\" : \"animate-pulse bg-primary motion-reduce:animate-none\",\n )}\n data-slot=\"turn-status-indicator\"\n />\n\n {visibleLabel ? (\n <span className=\"truncate\" data-slot=\"turn-status-label\">\n {visibleLabel}\n </span>\n ) : null}\n\n {/* The single live region — see the component doc comment above. */}\n <span aria-live=\"polite\" className=\"sr-only\" data-slot=\"turn-status-live\" role=\"status\">\n {announced}\n </span>\n\n {hasTrailing ? (\n <div className=\"ms-auto flex shrink-0 items-center gap-3\" data-slot=\"turn-status-trailing\">\n {hasMeta ? (\n <div\n className=\"flex items-center gap-3 text-meta text-muted-foreground tabular-nums\"\n data-slot=\"turn-status-meta\"\n >\n {formattedElapsed ? (\n <span data-slot=\"turn-status-elapsed\">{formattedElapsed}</span>\n ) : null}\n {hasTokens ? (\n <span data-slot=\"turn-status-tokens\">\n {formatNumber(tokens?.input ?? 0, { notation: \"compact\" })}\n {\"↑ \"}\n {formatNumber(tokens?.output ?? 0, { notation: \"compact\" })}\n {\"↓\"}\n </span>\n ) : null}\n {hasTurn ? (\n <span data-slot=\"turn-status-turn\">\n {turn}\n {turnTotal === undefined ? \"\" : `/${turnTotal}`}\n </span>\n ) : null}\n </div>\n ) : null}\n\n {showScrollToBottom ? (\n <Button\n aria-label={t(\"ai.turnStatus.scrollToBottom\")}\n data-slot=\"turn-status-scroll-to-bottom\"\n onClick={onScrollToBottom}\n size=\"icon-sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n <ArrowDownIcon className=\"size-4\" />\n </Button>\n ) : null}\n\n {showStop ? (\n <Button\n aria-label={t(\"ai.promptInput.stop\")}\n data-slot=\"turn-status-stop\"\n onClick={onStop}\n size=\"icon-sm\"\n type=\"button\"\n variant=\"outline\"\n >\n <SquareIcon className=\"size-4\" />\n </Button>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n});\n"],"mappings":";;;AAEA,SAAS,QAAQ,IAAI,eAAe,iBAAiB;AACrD,SAAS,eAAe,kBAAkB;AAE1C,SAAS,kBAAkB;AA4FrB,cA+BU,YA/BV;AA5CC,IAAM,aAAa,WAA4C,SAASA,YAC7E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,EAAE,GAAG,aAAa,IAAI,UAAU;AACtC,QAAM,YAAY,WAAW;AAC7B,QAAM,mBAAmB,cAAc,SAAY,SAAY,cAAc,SAAS;AAEtF,QAAM,cAAc,YACf,UACA,mBACG,EAAE,6BAA6B,EAAE,SAAS,iBAAiB,CAAC,IAC5D,EAAE,yBAAyB,KAC/B;AAGJ,QAAM,YAAY,YAAa,eAAe,KAAO,SAAS;AAE9D,QAAM,YAAY,QAAQ,UAAU,UAAa,QAAQ,WAAW;AACpE,QAAM,UAAU,SAAS;AACzB,QAAM,eAAe,YAAY,cAAc;AAC/C,QAAM,UAAU,CAAC,cAAc,qBAAqB,UAAa,aAAa;AAC9E,QAAM,WAAW,CAAC,aAAa,QAAQ,MAAM;AAC7C,QAAM,cAAc,WAAW,sBAAsB;AAErD,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,4DAA4D,SAAS;AAAA,MACnF,aAAU;AAAA,MACT,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAW;AAAA,cACT;AAAA,cACA,YAAY,eAAe;AAAA,YAC7B;AAAA,YACA,aAAU;AAAA;AAAA,QACZ;AAAA,QAEC,eACC,oBAAC,UAAK,WAAU,YAAW,aAAU,qBAClC,wBACH,IACE;AAAA,QAGJ,oBAAC,UAAK,aAAU,UAAS,WAAU,WAAU,aAAU,oBAAmB,MAAK,UAC5E,qBACH;AAAA,QAEC,cACC,qBAAC,SAAI,WAAU,4CAA2C,aAAU,wBACjE;AAAA,oBACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,aAAU;AAAA,cAET;AAAA,mCACC,oBAAC,UAAK,aAAU,uBAAuB,4BAAiB,IACtD;AAAA,gBACH,YACC,qBAAC,UAAK,aAAU,sBACb;AAAA,+BAAa,QAAQ,SAAS,GAAG,EAAE,UAAU,UAAU,CAAC;AAAA,kBACxD;AAAA,kBACA,aAAa,QAAQ,UAAU,GAAG,EAAE,UAAU,UAAU,CAAC;AAAA,kBACzD;AAAA,mBACH,IACE;AAAA,gBACH,UACC,qBAAC,UAAK,aAAU,oBACb;AAAA;AAAA,kBACA,cAAc,SAAY,KAAK,IAAI,SAAS;AAAA,mBAC/C,IACE;AAAA;AAAA;AAAA,UACN,IACE;AAAA,UAEH,qBACC;AAAA,YAAC;AAAA;AAAA,cACC,cAAY,EAAE,8BAA8B;AAAA,cAC5C,aAAU;AAAA,cACV,SAAS;AAAA,cACT,MAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAQ;AAAA,cAER,8BAAC,iBAAc,WAAU,UAAS;AAAA;AAAA,UACpC,IACE;AAAA,UAEH,WACC;AAAA,YAAC;AAAA;AAAA,cACC,cAAY,EAAE,qBAAqB;AAAA,cACnC,aAAU;AAAA,cACV,SAAS;AAAA,cACT,MAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAQ;AAAA,cAER,8BAAC,cAAW,WAAU,UAAS;AAAA;AAAA,UACjC,IACE;AAAA,WACN,IACE;AAAA;AAAA;AAAA,EACN;AAEJ,CAAC;","names":["TurnStatus"]}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/jsx-preview.tsx
|
|
4
|
+
import { Skeleton } from "@elabs-ai/components-ui";
|
|
5
|
+
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
6
|
+
import { AlertCircle } from "lucide-react";
|
|
7
|
+
import {
|
|
8
|
+
createContext,
|
|
9
|
+
memo,
|
|
10
|
+
useCallback,
|
|
11
|
+
useContext,
|
|
12
|
+
useEffect,
|
|
13
|
+
useMemo,
|
|
14
|
+
useRef,
|
|
15
|
+
useState
|
|
16
|
+
} from "react";
|
|
17
|
+
import JsxParser from "react-jsx-parser";
|
|
18
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
var JSXPreviewContext = createContext(null);
|
|
20
|
+
var JSX_PREVIEW_BLACKLISTED_TAGS = [
|
|
21
|
+
"script",
|
|
22
|
+
"style",
|
|
23
|
+
"iframe",
|
|
24
|
+
"form",
|
|
25
|
+
"object",
|
|
26
|
+
"embed",
|
|
27
|
+
"link",
|
|
28
|
+
"meta",
|
|
29
|
+
"base"
|
|
30
|
+
];
|
|
31
|
+
var useJSXPreview = () => {
|
|
32
|
+
const context = useContext(JSXPreviewContext);
|
|
33
|
+
if (!context) {
|
|
34
|
+
throw new Error("JSXPreview components must be used within JSXPreview");
|
|
35
|
+
}
|
|
36
|
+
return context;
|
|
37
|
+
};
|
|
38
|
+
var TAG_NAME_START = /[a-zA-Z]/;
|
|
39
|
+
var TAG_NAME_CHAR = /[a-zA-Z0-9]/;
|
|
40
|
+
function findNextJsxTag(code, fromIndex) {
|
|
41
|
+
const len = code.length;
|
|
42
|
+
let i = fromIndex;
|
|
43
|
+
while (i < len) {
|
|
44
|
+
if (code[i] !== "<") {
|
|
45
|
+
i++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
let j = i + 1;
|
|
49
|
+
const closing = code[j] === "/";
|
|
50
|
+
if (closing) j++;
|
|
51
|
+
const nameStart = j;
|
|
52
|
+
if (!TAG_NAME_START.test(code[nameStart] ?? "")) {
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
j++;
|
|
57
|
+
while (j < len && TAG_NAME_CHAR.test(code[j] ?? "")) {
|
|
58
|
+
j++;
|
|
59
|
+
}
|
|
60
|
+
const tagName = code.slice(nameStart, j);
|
|
61
|
+
let depth = 0;
|
|
62
|
+
let quote = null;
|
|
63
|
+
let k = j;
|
|
64
|
+
let closedAt = -1;
|
|
65
|
+
let selfClosing = false;
|
|
66
|
+
while (k < len) {
|
|
67
|
+
const ch = code[k];
|
|
68
|
+
if (quote) {
|
|
69
|
+
if (ch === quote) quote = null;
|
|
70
|
+
k++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (ch === '"' || ch === "'") {
|
|
74
|
+
quote = ch;
|
|
75
|
+
k++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (ch === "{") {
|
|
79
|
+
depth++;
|
|
80
|
+
k++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (ch === "}") {
|
|
84
|
+
depth = Math.max(0, depth - 1);
|
|
85
|
+
k++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (depth === 0 && ch === ">") {
|
|
89
|
+
let p = k - 1;
|
|
90
|
+
while (p > j && code[p] === " ") p--;
|
|
91
|
+
selfClosing = code[p] === "/";
|
|
92
|
+
closedAt = k + 1;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
k++;
|
|
96
|
+
}
|
|
97
|
+
if (closedAt === -1) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
endIndex: closedAt,
|
|
102
|
+
tagName,
|
|
103
|
+
type: closing ? "closing" : selfClosing ? "self-closing" : "opening"
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
var stripIncompleteTag = (text) => {
|
|
109
|
+
const lastOpen = text.lastIndexOf("<");
|
|
110
|
+
if (lastOpen === -1) {
|
|
111
|
+
return text;
|
|
112
|
+
}
|
|
113
|
+
const afterOpen = text.slice(lastOpen);
|
|
114
|
+
if (!afterOpen.includes(">")) {
|
|
115
|
+
return text.slice(0, lastOpen);
|
|
116
|
+
}
|
|
117
|
+
return text;
|
|
118
|
+
};
|
|
119
|
+
var completeJsxTag = (code) => {
|
|
120
|
+
const stack = [];
|
|
121
|
+
let position = 0;
|
|
122
|
+
while (position < code.length) {
|
|
123
|
+
const match = findNextJsxTag(code, position);
|
|
124
|
+
if (!match) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (match.type === "opening") {
|
|
128
|
+
stack.push(match.tagName);
|
|
129
|
+
} else if (match.type === "closing") {
|
|
130
|
+
stack.pop();
|
|
131
|
+
}
|
|
132
|
+
position = match.endIndex;
|
|
133
|
+
}
|
|
134
|
+
return code.slice(0, position) + stripIncompleteTag(code.slice(position)) + [...stack].reverse().map((tag) => `</${tag}>`).join("");
|
|
135
|
+
};
|
|
136
|
+
var STREAM_RECOMPUTE_THROTTLE_MS = 80;
|
|
137
|
+
function useCompletedJsx(jsx2, isStreaming) {
|
|
138
|
+
const cacheRef = useRef({ jsx: jsx2, result: completeJsxTag(jsx2), time: 0 });
|
|
139
|
+
return useMemo(() => {
|
|
140
|
+
const cache = cacheRef.current;
|
|
141
|
+
if (jsx2 === cache.jsx) return cache.result;
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
if (isStreaming && now - cache.time < STREAM_RECOMPUTE_THROTTLE_MS) {
|
|
144
|
+
return cache.result;
|
|
145
|
+
}
|
|
146
|
+
const result = completeJsxTag(jsx2);
|
|
147
|
+
cacheRef.current = { jsx: jsx2, result, time: now };
|
|
148
|
+
return result;
|
|
149
|
+
}, [jsx2, isStreaming]);
|
|
150
|
+
}
|
|
151
|
+
var JSXPreview = memo(
|
|
152
|
+
({
|
|
153
|
+
jsx: jsx2,
|
|
154
|
+
isStreaming = false,
|
|
155
|
+
loading = false,
|
|
156
|
+
components,
|
|
157
|
+
bindings,
|
|
158
|
+
onError,
|
|
159
|
+
className,
|
|
160
|
+
children,
|
|
161
|
+
...props
|
|
162
|
+
}) => {
|
|
163
|
+
const [prevJsx, setPrevJsx] = useState(jsx2);
|
|
164
|
+
const [error, setError] = useState(null);
|
|
165
|
+
const [hasRendered, setHasRendered] = useState(false);
|
|
166
|
+
if (jsx2 !== prevJsx) {
|
|
167
|
+
setPrevJsx(jsx2);
|
|
168
|
+
setError(null);
|
|
169
|
+
}
|
|
170
|
+
const completed = useCompletedJsx(jsx2, isStreaming);
|
|
171
|
+
const isIncomplete = jsx2.trim() !== "" && completed !== jsx2;
|
|
172
|
+
const processedJsx = useMemo(() => {
|
|
173
|
+
if (loading) return "";
|
|
174
|
+
return isStreaming || isIncomplete ? completed : jsx2;
|
|
175
|
+
}, [jsx2, isStreaming, loading, isIncomplete, completed]);
|
|
176
|
+
const status = useMemo(() => {
|
|
177
|
+
if (loading) return "pending";
|
|
178
|
+
if (jsx2.trim() === "") return hasRendered ? "ready" : "idle";
|
|
179
|
+
if (isStreaming || isIncomplete) return "pending";
|
|
180
|
+
return error != null ? "error" : "ready";
|
|
181
|
+
}, [jsx2, isStreaming, loading, isIncomplete, error, hasRendered]);
|
|
182
|
+
const contextValue = useMemo(
|
|
183
|
+
() => ({
|
|
184
|
+
bindings,
|
|
185
|
+
components,
|
|
186
|
+
error,
|
|
187
|
+
hasRendered,
|
|
188
|
+
isStreaming,
|
|
189
|
+
jsx: jsx2,
|
|
190
|
+
loading,
|
|
191
|
+
onErrorProp: onError,
|
|
192
|
+
processedJsx,
|
|
193
|
+
setError,
|
|
194
|
+
setHasRendered,
|
|
195
|
+
status
|
|
196
|
+
}),
|
|
197
|
+
[
|
|
198
|
+
bindings,
|
|
199
|
+
components,
|
|
200
|
+
error,
|
|
201
|
+
hasRendered,
|
|
202
|
+
isStreaming,
|
|
203
|
+
jsx2,
|
|
204
|
+
loading,
|
|
205
|
+
onError,
|
|
206
|
+
processedJsx,
|
|
207
|
+
status
|
|
208
|
+
]
|
|
209
|
+
);
|
|
210
|
+
return /* @__PURE__ */ jsx(JSXPreviewContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { className: cn("relative", className), ...props, children }) });
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
JSXPreview.displayName = "JSXPreview";
|
|
214
|
+
var JSXPreviewContent = memo(({ className, ...props }) => {
|
|
215
|
+
const { processedJsx, status, components, bindings, setError, setHasRendered, onErrorProp } = useJSXPreview();
|
|
216
|
+
const lastGoodJsxRef = useRef("");
|
|
217
|
+
const [erroredJsx, setErroredJsx] = useState(null);
|
|
218
|
+
const pendingErrorRef = useRef(null);
|
|
219
|
+
const prevProcessedRef = useRef(processedJsx);
|
|
220
|
+
if (prevProcessedRef.current !== processedJsx) {
|
|
221
|
+
prevProcessedRef.current = processedJsx;
|
|
222
|
+
if (erroredJsx !== null) setErroredJsx(null);
|
|
223
|
+
}
|
|
224
|
+
const hadError = erroredJsx === processedJsx;
|
|
225
|
+
const handleError = useCallback(
|
|
226
|
+
(error) => {
|
|
227
|
+
pendingErrorRef.current = { error, jsx: processedJsx };
|
|
228
|
+
},
|
|
229
|
+
[processedJsx]
|
|
230
|
+
);
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
const failed = pendingErrorRef.current?.jsx === processedJsx;
|
|
233
|
+
if (failed) {
|
|
234
|
+
const { error } = pendingErrorRef.current;
|
|
235
|
+
pendingErrorRef.current = null;
|
|
236
|
+
if (erroredJsx !== processedJsx) setErroredJsx(processedJsx);
|
|
237
|
+
if (status !== "pending") {
|
|
238
|
+
setError(error);
|
|
239
|
+
onErrorProp?.(error);
|
|
240
|
+
}
|
|
241
|
+
} else if (erroredJsx !== processedJsx && processedJsx.trim() !== "") {
|
|
242
|
+
lastGoodJsxRef.current = processedJsx;
|
|
243
|
+
setHasRendered(true);
|
|
244
|
+
}
|
|
245
|
+
}, [processedJsx, status, erroredJsx, setError, setHasRendered, onErrorProp]);
|
|
246
|
+
if (status !== "ready" && status !== "pending") {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const displayJsx = hadError ? lastGoodJsxRef.current : processedJsx;
|
|
250
|
+
return /* @__PURE__ */ jsx("div", { className: cn("jsx-preview-content", className), ...props, children: /* @__PURE__ */ jsx(
|
|
251
|
+
JsxParser,
|
|
252
|
+
{
|
|
253
|
+
allowUnknownElements: false,
|
|
254
|
+
bindings,
|
|
255
|
+
blacklistedTags: JSX_PREVIEW_BLACKLISTED_TAGS,
|
|
256
|
+
components,
|
|
257
|
+
jsx: displayJsx,
|
|
258
|
+
onError: handleError,
|
|
259
|
+
renderInWrapper: false
|
|
260
|
+
}
|
|
261
|
+
) });
|
|
262
|
+
});
|
|
263
|
+
JSXPreviewContent.displayName = "JSXPreviewContent";
|
|
264
|
+
var JSXPreviewSkeleton = memo(
|
|
265
|
+
({ className, children, ...props }) => {
|
|
266
|
+
const { status, hasRendered } = useJSXPreview();
|
|
267
|
+
const show = !hasRendered && status === "pending";
|
|
268
|
+
const [announce, setAnnounce] = useState(false);
|
|
269
|
+
useEffect(() => setAnnounce(show), [show]);
|
|
270
|
+
return /* @__PURE__ */ jsxs(
|
|
271
|
+
"div",
|
|
272
|
+
{
|
|
273
|
+
className: cn(show ? "space-y-2" : "sr-only", className),
|
|
274
|
+
role: "status",
|
|
275
|
+
"aria-live": "polite",
|
|
276
|
+
...props,
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: announce ? "Loading preview\u2026" : "" }),
|
|
279
|
+
show ? children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
280
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full" }),
|
|
281
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
282
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-16" }),
|
|
283
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-16" }),
|
|
284
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-16" })
|
|
285
|
+
] })
|
|
286
|
+
] }) : null
|
|
287
|
+
]
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
JSXPreviewSkeleton.displayName = "JSXPreviewSkeleton";
|
|
293
|
+
var renderChildren = (children, error) => {
|
|
294
|
+
if (typeof children === "function") {
|
|
295
|
+
return children(error);
|
|
296
|
+
}
|
|
297
|
+
return children;
|
|
298
|
+
};
|
|
299
|
+
var JSXPreviewError = memo(({ className, children, ...props }) => {
|
|
300
|
+
const { status, error } = useJSXPreview();
|
|
301
|
+
if (status !== "error" || !error) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
return /* @__PURE__ */ jsx(
|
|
305
|
+
"div",
|
|
306
|
+
{
|
|
307
|
+
className: cn(
|
|
308
|
+
"flex items-center gap-2 rounded-md bg-destructive/10 p-3 text-body text-destructive-text",
|
|
309
|
+
className
|
|
310
|
+
),
|
|
311
|
+
role: "alert",
|
|
312
|
+
...props,
|
|
313
|
+
children: children ? renderChildren(children, error) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
314
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "size-4 shrink-0" }),
|
|
315
|
+
/* @__PURE__ */ jsx("span", { children: error.message })
|
|
316
|
+
] })
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
});
|
|
320
|
+
JSXPreviewError.displayName = "JSXPreviewError";
|
|
321
|
+
|
|
322
|
+
export {
|
|
323
|
+
useJSXPreview,
|
|
324
|
+
JSXPreview,
|
|
325
|
+
JSXPreviewContent,
|
|
326
|
+
JSXPreviewSkeleton,
|
|
327
|
+
JSXPreviewError
|
|
328
|
+
};
|
|
329
|
+
//# sourceMappingURL=chunk-NIG67CFM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/jsx-preview.tsx"],"sourcesContent":["\"use client\";\n\nimport { Skeleton } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport { AlertCircle } from \"lucide-react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { TProps as JsxParserProps } from \"react-jsx-parser\";\nimport JsxParser from \"react-jsx-parser\";\n\n/**\n * The readiness of the preview, derived from the input (see loading-states.md):\n * - `idle` — nothing requested yet (empty input, never rendered). Renders nothing.\n * - `pending` — not-ready: `loading`, `isStreaming`, OR syntactically incomplete\n * input (a half-arrived tag). Builds up best-effort; the error slot\n * is suppressed; the skeleton shows until the first successful paint.\n * - `ready` — settled, parseable input is rendering.\n * - `error` — settled AND genuinely invalid input (the only state that surfaces\n * `JSXPreviewError`).\n */\nexport type JSXPreviewStatus = \"idle\" | \"pending\" | \"ready\" | \"error\";\n\ninterface JSXPreviewContextValue {\n jsx: string;\n processedJsx: string;\n isStreaming: boolean;\n loading: boolean;\n status: JSXPreviewStatus;\n hasRendered: boolean;\n error: Error | null;\n setError: (error: Error | null) => void;\n setHasRendered: (value: boolean) => void;\n components: JsxParserProps[\"components\"];\n bindings: JsxParserProps[\"bindings\"];\n onErrorProp?: (error: Error) => void;\n}\n\nconst JSXPreviewContext = createContext<JSXPreviewContextValue | null>(null);\n\n/**\n * HTML elements that must never render from agent/model-authored JSX: script\n * execution, style/link/meta/base injection, and embeddable third-party\n * surfaces (iframe/object/embed) or a form that could post data out. Merged\n * with `react-jsx-parser`'s own default (`script`) via `blacklistedTags`.\n */\nconst JSX_PREVIEW_BLACKLISTED_TAGS = [\n \"script\",\n \"style\",\n \"iframe\",\n \"form\",\n \"object\",\n \"embed\",\n \"link\",\n \"meta\",\n \"base\",\n];\n\nexport const useJSXPreview = () => {\n const context = useContext(JSXPreviewContext);\n if (!context) {\n throw new Error(\"JSXPreview components must be used within JSXPreview\");\n }\n return context;\n};\n\nconst TAG_NAME_START = /[a-zA-Z]/;\nconst TAG_NAME_CHAR = /[a-zA-Z0-9]/;\n\ninterface JsxTagMatch {\n tagName: string;\n type: \"opening\" | \"closing\" | \"self-closing\";\n endIndex: number;\n}\n\n/**\n * Finds the next complete JSX tag at or after `fromIndex`, tracking brace\n * depth and quoted strings so a `>` inside an attribute expression (e.g.\n * `onClick={() => foo()}`) is never mistaken for the tag's own closing\n * bracket (the previous plain regex did exactly that). Walks the ORIGINAL\n * string by absolute index — no per-iteration substring slicing — so one\n * pass over the whole input is linear.\n */\nfunction findNextJsxTag(code: string, fromIndex: number): JsxTagMatch | null {\n const len = code.length;\n let i = fromIndex;\n\n while (i < len) {\n if (code[i] !== \"<\") {\n i++;\n continue;\n }\n\n let j = i + 1;\n const closing = code[j] === \"/\";\n if (closing) j++;\n\n const nameStart = j;\n if (!TAG_NAME_START.test(code[nameStart] ?? \"\")) {\n i++;\n continue;\n }\n j++;\n while (j < len && TAG_NAME_CHAR.test(code[j] ?? \"\")) {\n j++;\n }\n const tagName = code.slice(nameStart, j);\n\n let depth = 0;\n let quote: string | null = null;\n let k = j;\n let closedAt = -1;\n let selfClosing = false;\n\n while (k < len) {\n const ch = code[k];\n if (quote) {\n if (ch === quote) quote = null;\n k++;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n k++;\n continue;\n }\n if (ch === \"{\") {\n depth++;\n k++;\n continue;\n }\n if (ch === \"}\") {\n depth = Math.max(0, depth - 1);\n k++;\n continue;\n }\n if (depth === 0 && ch === \">\") {\n let p = k - 1;\n while (p > j && code[p] === \" \") p--;\n selfClosing = code[p] === \"/\";\n closedAt = k + 1;\n break;\n }\n k++;\n }\n\n // No closing '>' yet for this tag at this depth — it is incomplete, not\n // a match; the caller treats everything from here on as trailing text.\n if (closedAt === -1) {\n return null;\n }\n\n return {\n endIndex: closedAt,\n tagName,\n type: closing ? \"closing\" : selfClosing ? \"self-closing\" : \"opening\",\n };\n }\n\n return null;\n}\n\nconst stripIncompleteTag = (text: string) => {\n // Find the last '<' that isn't part of a complete tag\n const lastOpen = text.lastIndexOf(\"<\");\n if (lastOpen === -1) {\n return text;\n }\n\n const afterOpen = text.slice(lastOpen);\n // If there's no closing '>' after the last '<', it's an incomplete tag\n if (!afterOpen.includes(\">\")) {\n return text.slice(0, lastOpen);\n }\n\n return text;\n};\n\nconst completeJsxTag = (code: string) => {\n const stack: string[] = [];\n let position = 0;\n\n while (position < code.length) {\n const match = findNextJsxTag(code, position);\n if (!match) {\n // No more complete tags ahead; everything past `position` is trailing\n // text (possibly a mid-typed tag), handled by stripIncompleteTag below.\n break;\n }\n\n if (match.type === \"opening\") {\n stack.push(match.tagName);\n } else if (match.type === \"closing\") {\n stack.pop();\n }\n\n position = match.endIndex;\n }\n\n return (\n code.slice(0, position) +\n stripIncompleteTag(code.slice(position)) +\n [...stack]\n .reverse()\n .map((tag) => `</${tag}>`)\n .join(\"\")\n );\n};\n\n/** How often `completeJsxTag` may re-run while content is still streaming in. */\nconst STREAM_RECOMPUTE_THROTTLE_MS = 80;\n\n/**\n * Tag-balances `jsx` like `completeJsxTag`, but while `isStreaming` is true it\n * skips a fresh (expensive, whole-string) recompute more often than once per\n * `STREAM_RECOMPUTE_THROTTLE_MS` — otherwise every incoming token re-scans the\n * entire accumulated string from scratch. Settled input (`isStreaming` false)\n * always recomputes immediately so the final render is exact.\n */\nfunction useCompletedJsx(jsx: string, isStreaming: boolean): string {\n const cacheRef = useRef({ jsx, result: completeJsxTag(jsx), time: 0 });\n\n return useMemo(() => {\n const cache = cacheRef.current;\n if (jsx === cache.jsx) return cache.result;\n\n const now = Date.now();\n if (isStreaming && now - cache.time < STREAM_RECOMPUTE_THROTTLE_MS) {\n return cache.result;\n }\n\n const result = completeJsxTag(jsx);\n cacheRef.current = { jsx, result, time: now };\n return result;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- cacheRef is a stable ref, not reactive state\n }, [jsx, isStreaming]);\n}\n\nexport type JSXPreviewProps = ComponentProps<\"div\"> & {\n jsx: string;\n /** Content is arriving incrementally — build up, suppress transient errors. */\n isStreaming?: boolean;\n /**\n * No renderable content yet (fetch-then-show). Forces the `pending` state so\n * `JSXPreviewSkeleton` shows until `jsx` arrives. Orthogonal to `isStreaming`.\n */\n loading?: boolean;\n components?: JsxParserProps[\"components\"];\n bindings?: JsxParserProps[\"bindings\"];\n onError?: (error: Error) => void;\n};\n\nexport const JSXPreview = memo(\n ({\n jsx,\n isStreaming = false,\n loading = false,\n components,\n bindings,\n onError,\n className,\n children,\n ...props\n }: JSXPreviewProps) => {\n const [prevJsx, setPrevJsx] = useState(jsx);\n const [error, setError] = useState<Error | null>(null);\n const [hasRendered, setHasRendered] = useState(false);\n\n // Clear the terminal error when jsx changes (derived state pattern)\n if (jsx !== prevJsx) {\n setPrevJsx(jsx);\n setError(null);\n }\n\n // The tag-balanced best-effort of the current input. When it differs from the\n // raw jsx, the input ends mid-tag → it is INCOMPLETE (still streaming / being\n // typed), not invalid. This is the timer-free \"not-ready\" signal. Throttled\n // while streaming so every incoming token doesn't re-scan the whole string.\n const completed = useCompletedJsx(jsx, isStreaming);\n const isIncomplete = jsx.trim() !== \"\" && completed !== jsx;\n\n const processedJsx = useMemo(() => {\n if (loading) return \"\";\n return isStreaming || isIncomplete ? completed : jsx;\n }, [jsx, isStreaming, loading, isIncomplete, completed]);\n\n const status = useMemo<JSXPreviewStatus>(() => {\n if (loading) return \"pending\";\n if (jsx.trim() === \"\") return hasRendered ? \"ready\" : \"idle\";\n if (isStreaming || isIncomplete) return \"pending\";\n return error != null ? \"error\" : \"ready\";\n }, [jsx, isStreaming, loading, isIncomplete, error, hasRendered]);\n\n const contextValue = useMemo(\n () => ({\n bindings,\n components,\n error,\n hasRendered,\n isStreaming,\n jsx,\n loading,\n onErrorProp: onError,\n processedJsx,\n setError,\n setHasRendered,\n status,\n }),\n [\n bindings,\n components,\n error,\n hasRendered,\n isStreaming,\n jsx,\n loading,\n onError,\n processedJsx,\n status,\n ],\n );\n\n return (\n <JSXPreviewContext.Provider value={contextValue}>\n <div className={cn(\"relative\", className)} {...props}>\n {children}\n </div>\n </JSXPreviewContext.Provider>\n );\n },\n);\n\nJSXPreview.displayName = \"JSXPreview\";\n\nexport type JSXPreviewContentProps = Omit<ComponentProps<\"div\">, \"children\">;\n\nexport const JSXPreviewContent = memo(({ className, ...props }: JSXPreviewContentProps) => {\n const { processedJsx, status, components, bindings, setError, setHasRendered, onErrorProp } =\n useJSXPreview();\n const lastGoodJsxRef = useRef(\"\");\n // `erroredJsx` is committed in an effect (never during render). The parser\n // reports errors synchronously DURING its own render, so `handleError` only\n // stashes a ref — committing state there would be a setState-in-render.\n const [erroredJsx, setErroredJsx] = useState<string | null>(null);\n const pendingErrorRef = useRef<{ jsx: string; error: Error } | null>(null);\n\n // Reset the per-input error flag synchronously when the content changes.\n const prevProcessedRef = useRef(processedJsx);\n if (prevProcessedRef.current !== processedJsx) {\n prevProcessedRef.current = processedJsx;\n if (erroredJsx !== null) setErroredJsx(null);\n }\n const hadError = erroredJsx === processedJsx;\n\n const handleError = useCallback(\n (error: Error) => {\n pendingErrorRef.current = { error, jsx: processedJsx };\n },\n [processedJsx],\n );\n\n // After commit, reconcile the parse outcome. A fresh error becomes terminal\n // (surfaces `JSXPreviewError`) ONLY when settled — for a `pending` input it is\n // held silently (build-up keeps going behind the last good render). A clean\n // render records the last-good JSX and marks the first paint.\n useEffect(() => {\n const failed = pendingErrorRef.current?.jsx === processedJsx;\n if (failed) {\n const { error } = pendingErrorRef.current!;\n pendingErrorRef.current = null;\n if (erroredJsx !== processedJsx) setErroredJsx(processedJsx);\n if (status !== \"pending\") {\n setError(error);\n onErrorProp?.(error);\n }\n } else if (erroredJsx !== processedJsx && processedJsx.trim() !== \"\") {\n lastGoodJsxRef.current = processedJsx;\n setHasRendered(true);\n }\n }, [processedJsx, status, erroredJsx, setError, setHasRendered, onErrorProp]);\n\n // The error slot and the skeleton own the \"error\" / nothing-yet states.\n if (status !== \"ready\" && status !== \"pending\") {\n return null;\n }\n\n // While pending, a failed parse falls back to the last good render (which may\n // be empty on first paint — the skeleton covers that).\n const displayJsx = hadError ? lastGoodJsxRef.current : processedJsx;\n\n return (\n <div className={cn(\"jsx-preview-content\", className)} {...props}>\n <JsxParser\n allowUnknownElements={false}\n bindings={bindings}\n blacklistedTags={JSX_PREVIEW_BLACKLISTED_TAGS}\n components={components}\n jsx={displayJsx}\n onError={handleError}\n renderInWrapper={false}\n />\n </div>\n );\n});\n\nJSXPreviewContent.displayName = \"JSXPreviewContent\";\n\nexport type JSXPreviewSkeletonProps = ComponentProps<\"div\">;\n\n/**\n * The not-ready placeholder (loading-states.md §slot anatomy). Renders a\n * layout-shaped `Skeleton` while the preview is `pending` and nothing has\n * painted yet — so a streaming/incomplete surface BUILDS UP behind a skeleton\n * instead of flashing the error box. Pass `children` to override the shape.\n */\nexport const JSXPreviewSkeleton = memo(\n ({ className, children, ...props }: JSXPreviewSkeletonProps) => {\n const { status, hasRendered } = useJSXPreview();\n\n // Show only before the first successful paint; once content builds up, the\n // partial render is its own affordance (no skeleton-over-content).\n const show = !hasRendered && status === \"pending\";\n\n // The live region must exist in the DOM BEFORE its text appears, or NVDA\n // skips the announcement (ARIA22). So the wrapper is ALWAYS rendered (it\n // collapses to `sr-only` when idle) and the label is set one tick later via\n // an effect — guaranteeing an empty region precedes the \"Loading…\" text.\n const [announce, setAnnounce] = useState(false);\n useEffect(() => setAnnounce(show), [show]);\n\n return (\n <div\n className={cn(show ? \"space-y-2\" : \"sr-only\", className)}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n <span className=\"sr-only\">{announce ? \"Loading preview…\" : \"\"}</span>\n {show\n ? (children ?? (\n <>\n <Skeleton className=\"h-20 w-full\" />\n <div className=\"grid grid-cols-3 gap-2\">\n <Skeleton className=\"h-16\" />\n <Skeleton className=\"h-16\" />\n <Skeleton className=\"h-16\" />\n </div>\n </>\n ))\n : null}\n </div>\n );\n },\n);\n\nJSXPreviewSkeleton.displayName = \"JSXPreviewSkeleton\";\n\nexport type JSXPreviewErrorProps = ComponentProps<\"div\"> & {\n children?: ReactNode | ((error: Error) => ReactNode);\n};\n\nconst renderChildren = (\n children: ReactNode | ((error: Error) => ReactNode),\n error: Error,\n): ReactNode => {\n if (typeof children === \"function\") {\n return children(error);\n }\n return children;\n};\n\nexport const JSXPreviewError = memo(({ className, children, ...props }: JSXPreviewErrorProps) => {\n const { status, error } = useJSXPreview();\n\n // Terminal failures only — never while loading / streaming / incomplete.\n if (status !== \"error\" || !error) {\n return null;\n }\n\n return (\n <div\n // The status wash is the separation gesture (#194, research 08 §B.1):\n // `bg-destructive/10` + the destructive ink/icon already mark the region,\n // and the alpha-wash survives high decoration (token-inequality escape from the\n // drawn-not-filled rule), so the old `border border-destructive/50` was\n // redundant on every theme — dropped. Text + icon use `text-destructive-text`\n // (the on-surface destructive ink ramp) — raw `text-destructive` fails AA on\n // the wash (3.86:1) and goes near-white in dark; the *-text token is\n // AA-guaranteed and keeps the destructive cue in every theme.\n className={cn(\n \"flex items-center gap-2 rounded-md bg-destructive/10 p-3 text-body text-destructive-text\",\n className,\n )}\n role=\"alert\"\n {...props}\n >\n {children ? (\n renderChildren(children, error)\n ) : (\n <>\n <AlertCircle className=\"size-4 shrink-0\" />\n <span>{error.message}</span>\n </>\n )}\n </div>\n );\n});\n\nJSXPreviewError.displayName = \"JSXPreviewError\";\n"],"mappings":"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","names":["jsx"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/_flow-lazy.ts"],"sourcesContent":["/**\n * The one dynamic-import seam every React-Flow-backed component in\n * `@elabs-ai/components-ai` goes through.\n *\n * `@xyflow/react` declares no `sideEffects`, so a static import from any of the\n * six public modules (`canvas`, `controls`, `edge`, `node`, `panel`, `toolbar`)\n * put the whole engine into the entry chunk of every consumer. They all reach it\n * through **one** boundary module — `_flow-boundary.tsx` — rather than six, so\n * the engine lands in exactly one chunk: six boundaries would mean six chunks\n * each pulling the same engine, and a `<Node>` rendered inside an already-loaded\n * `<Canvas>` would fetch a second copy.\n *\n * Because every part resolves from the same specifier, the parts _inside_ a\n * canvas resolve from the module cache the canvas already populated.\n *\n * This module is deliberately NOT itself a lazy boundary (it carries no such\n * docblock tag, and `pnpm heavy-deps:check` would fail the six static imports\n * below if it did): it holds no engine import of its own, only the `import()`\n * call, so the public modules may import it statically. See ADR 0019.\n */\nimport { lazy } from \"react\";\nimport type { ComponentType, LazyExoticComponent } from \"react\";\n\ntype FlowBoundaryModule = typeof import(\"./_flow-boundary\");\n\n/**\n * Wrap one implementation from the React Flow boundary in a `lazy()` component.\n *\n * @param pick Selects the implementation from the boundary module.\n */\nexport const lazyFlowPart = <P>(\n pick: (module: FlowBoundaryModule) => ComponentType<P>,\n): LazyExoticComponent<ComponentType<P>> =>\n lazy(() => import(\"./_flow-boundary\").then((m) => ({ default: pick(m) })));\n"],"mappings":";;;AAoBA,SAAS,YAAY;AAUd,IAAM,eAAe,CAC1B,SAEA,KAAK,MAAM,OAAO,qBAAkB,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,KAAK,CAAC,EAAE,EAAE,CAAC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|