@od-oneapp/uni-ui 2026.1.1301
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 +753 -0
- package/dist/actions-C-SEx2GS.mjs +180 -0
- package/dist/actions-C-SEx2GS.mjs.map +1 -0
- package/dist/actions-Ch7h6cYC.d.mts +50 -0
- package/dist/actions-Cnupw96c.d.mts +50 -0
- package/dist/alert-BVUF7Xzb.d.mts +22 -0
- package/dist/alert-BuPyEXF-.mjs +206 -0
- package/dist/alert-BuPyEXF-.mjs.map +1 -0
- package/dist/alert-CfjDnZpm.d.mts +22 -0
- package/dist/animated-size-container-DSKNt1Cn.mjs +106 -0
- package/dist/animated-size-container-DSKNt1Cn.mjs.map +1 -0
- package/dist/areas-CtE8w69A.mjs +144 -0
- package/dist/areas-CtE8w69A.mjs.map +1 -0
- package/dist/areas-DtGnjGuX.d.mts +22 -0
- package/dist/auth-nav-user-CRxDpY_7.d.mts +30 -0
- package/dist/auth-nav-user-DPFv8dTp.mjs +181 -0
- package/dist/auth-nav-user-DPFv8dTp.mjs.map +1 -0
- package/dist/avatar-DjiX7nT8.mjs +202 -0
- package/dist/avatar-DjiX7nT8.mjs.map +1 -0
- package/dist/badge-CGTN2VG0.d.mts +25 -0
- package/dist/badge-CVoIuyYX.mjs +242 -0
- package/dist/badge-CVoIuyYX.mjs.map +1 -0
- package/dist/badge-DH0tY3wJ.d.mts +25 -0
- package/dist/bars-CWTAPKgm.d.mts +20 -0
- package/dist/bars-DOLvecrq.mjs +125 -0
- package/dist/bars-DOLvecrq.mjs.map +1 -0
- package/dist/branch-BEl6eS77.mjs +323 -0
- package/dist/branch-BEl6eS77.mjs.map +1 -0
- package/dist/branch-BtdY_TLE.d.mts +58 -0
- package/dist/branch-Duq6cW0s.d.mts +58 -0
- package/dist/button-BAdq0gBE.d.mts +31 -0
- package/dist/button-DVOrrZLw.mjs +632 -0
- package/dist/button-DVOrrZLw.mjs.map +1 -0
- package/dist/button-DnjeAftr.d.mts +31 -0
- package/dist/carousel-D-J1Zgn1.d.mts +49 -0
- package/dist/carousel-Dx5AOW5k.mjs +345 -0
- package/dist/carousel-Dx5AOW5k.mjs.map +1 -0
- package/dist/carousel-sY0y1-or.d.mts +49 -0
- package/dist/chart-context-CLV35VLJ.mjs +27 -0
- package/dist/chart-context-CLV35VLJ.mjs.map +1 -0
- package/dist/checkbox-wiF-DV6q.mjs +194 -0
- package/dist/checkbox-wiF-DV6q.mjs.map +1 -0
- package/dist/code-block-Cg_XtPH7.mjs +243 -0
- package/dist/code-block-Cg_XtPH7.mjs.map +1 -0
- package/dist/collapsible-CRgTpRfr.d.mts +46 -0
- package/dist/collapsible-CXy4T04n.mjs +239 -0
- package/dist/collapsible-CXy4T04n.mjs.map +1 -0
- package/dist/combobox-DSrxSkSl.d.mts +79 -0
- package/dist/combobox-DYFh2eZf.d.mts +79 -0
- package/dist/combobox-uEKksQFR.mjs +410 -0
- package/dist/combobox-uEKksQFR.mjs.map +1 -0
- package/dist/command-xK3X_A9t.mjs +206 -0
- package/dist/command-xK3X_A9t.mjs.map +1 -0
- package/dist/components-ai-elements/actions/index.d.mts +5 -0
- package/dist/components-ai-elements/actions/index.mjs +4 -0
- package/dist/components-ai-elements/agent-step/index.d.mts +32 -0
- package/dist/components-ai-elements/agent-step/index.mjs +183 -0
- package/dist/components-ai-elements/agent-step/index.mjs.map +1 -0
- package/dist/components-ai-elements/artifact/index.d.mts +81 -0
- package/dist/components-ai-elements/artifact/index.mjs +153 -0
- package/dist/components-ai-elements/artifact/index.mjs.map +1 -0
- package/dist/components-ai-elements/branch/index.d.mts +5 -0
- package/dist/components-ai-elements/branch/index.mjs +4 -0
- package/dist/components-ai-elements/chain-of-thought/index.d.mts +90 -0
- package/dist/components-ai-elements/chain-of-thought/index.mjs +338 -0
- package/dist/components-ai-elements/chain-of-thought/index.mjs.map +1 -0
- package/dist/components-ai-elements/chat-input/index.d.mts +21 -0
- package/dist/components-ai-elements/chat-input/index.mjs +137 -0
- package/dist/components-ai-elements/chat-input/index.mjs.map +1 -0
- package/dist/components-ai-elements/checkpoint/index.d.mts +46 -0
- package/dist/components-ai-elements/checkpoint/index.mjs +161 -0
- package/dist/components-ai-elements/checkpoint/index.mjs.map +1 -0
- package/dist/components-ai-elements/code-block/index.d.mts +39 -0
- package/dist/components-ai-elements/code-block/index.mjs +4 -0
- package/dist/components-ai-elements/confirmation/index.d.mts +96 -0
- package/dist/components-ai-elements/confirmation/index.mjs +295 -0
- package/dist/components-ai-elements/confirmation/index.mjs.map +1 -0
- package/dist/components-ai-elements/context/index.d.mts +83 -0
- package/dist/components-ai-elements/context/index.mjs +456 -0
- package/dist/components-ai-elements/context/index.mjs.map +1 -0
- package/dist/components-ai-elements/conversation/index.d.mts +46 -0
- package/dist/components-ai-elements/conversation/index.mjs +180 -0
- package/dist/components-ai-elements/conversation/index.mjs.map +1 -0
- package/dist/components-ai-elements/custom/index.d.mts +1142 -0
- package/dist/components-ai-elements/custom/index.mjs +5578 -0
- package/dist/components-ai-elements/custom/index.mjs.map +1 -0
- package/dist/components-ai-elements/generative-ui/index.d.mts +4 -0
- package/dist/components-ai-elements/generative-ui/index.mjs +4 -0
- package/dist/components-ai-elements/image/index.d.mts +20 -0
- package/dist/components-ai-elements/image/index.mjs +121 -0
- package/dist/components-ai-elements/image/index.mjs.map +1 -0
- package/dist/components-ai-elements/inline-citation/index.d.mts +94 -0
- package/dist/components-ai-elements/inline-citation/index.mjs +371 -0
- package/dist/components-ai-elements/inline-citation/index.mjs.map +1 -0
- package/dist/components-ai-elements/loader/index.d.mts +24 -0
- package/dist/components-ai-elements/loader/index.mjs +4 -0
- package/dist/components-ai-elements/message/index.d.mts +153 -0
- package/dist/components-ai-elements/message/index.mjs +597 -0
- package/dist/components-ai-elements/message/index.mjs.map +1 -0
- package/dist/components-ai-elements/model-selector/index.d.mts +72 -0
- package/dist/components-ai-elements/model-selector/index.mjs +224 -0
- package/dist/components-ai-elements/model-selector/index.mjs.map +1 -0
- package/dist/components-ai-elements/open-in-chat/index.d.mts +64 -0
- package/dist/components-ai-elements/open-in-chat/index.mjs +502 -0
- package/dist/components-ai-elements/open-in-chat/index.mjs.map +1 -0
- package/dist/components-ai-elements/plan/index.d.mts +71 -0
- package/dist/components-ai-elements/plan/index.mjs +219 -0
- package/dist/components-ai-elements/plan/index.mjs.map +1 -0
- package/dist/components-ai-elements/prompt-char-counter/index.d.mts +19 -0
- package/dist/components-ai-elements/prompt-char-counter/index.mjs +116 -0
- package/dist/components-ai-elements/prompt-char-counter/index.mjs.map +1 -0
- package/dist/components-ai-elements/prompt-input/index.d.mts +386 -0
- package/dist/components-ai-elements/prompt-input/index.mjs +4 -0
- package/dist/components-ai-elements/queue/index.d.mts +121 -0
- package/dist/components-ai-elements/queue/index.mjs +284 -0
- package/dist/components-ai-elements/queue/index.mjs.map +1 -0
- package/dist/components-ai-elements/reasoning/index.d.mts +42 -0
- package/dist/components-ai-elements/reasoning/index.mjs +241 -0
- package/dist/components-ai-elements/reasoning/index.mjs.map +1 -0
- package/dist/components-ai-elements/shimmer/index.d.mts +23 -0
- package/dist/components-ai-elements/shimmer/index.mjs +4 -0
- package/dist/components-ai-elements/sources/index.d.mts +56 -0
- package/dist/components-ai-elements/sources/index.mjs +211 -0
- package/dist/components-ai-elements/sources/index.mjs.map +1 -0
- package/dist/components-ai-elements/suggestion/index.d.mts +40 -0
- package/dist/components-ai-elements/suggestion/index.mjs +145 -0
- package/dist/components-ai-elements/suggestion/index.mjs.map +1 -0
- package/dist/components-ai-elements/task/index.d.mts +70 -0
- package/dist/components-ai-elements/task/index.mjs +218 -0
- package/dist/components-ai-elements/task/index.mjs.map +1 -0
- package/dist/components-ai-elements/tool/index.d.mts +78 -0
- package/dist/components-ai-elements/tool/index.mjs +370 -0
- package/dist/components-ai-elements/tool/index.mjs.map +1 -0
- package/dist/components-ai-elements/tool-approval/index.d.mts +20 -0
- package/dist/components-ai-elements/tool-approval/index.mjs +252 -0
- package/dist/components-ai-elements/tool-approval/index.mjs.map +1 -0
- package/dist/components-ai-elements/web-preview/index.d.mts +136 -0
- package/dist/components-ai-elements/web-preview/index.mjs +773 -0
- package/dist/components-ai-elements/web-preview/index.mjs.map +1 -0
- package/dist/components-ai-elements-constants.d.mts +207 -0
- package/dist/components-ai-elements-constants.mjs +301 -0
- package/dist/components-ai-elements-constants.mjs.map +1 -0
- package/dist/components-ai-workflows/canvas/index.d.mts +22 -0
- package/dist/components-ai-workflows/canvas/index.mjs +135 -0
- package/dist/components-ai-workflows/canvas/index.mjs.map +1 -0
- package/dist/components-ai-workflows/connection/index.d.mts +22 -0
- package/dist/components-ai-workflows/connection/index.mjs +4 -0
- package/dist/components-ai-workflows/controls/index.d.mts +14 -0
- package/dist/components-ai-workflows/controls/index.mjs +89 -0
- package/dist/components-ai-workflows/controls/index.mjs.map +1 -0
- package/dist/components-ai-workflows/edge/index.d.mts +20 -0
- package/dist/components-ai-workflows/edge/index.mjs +102 -0
- package/dist/components-ai-workflows/edge/index.mjs.map +1 -0
- package/dist/components-ai-workflows/node/index.d.mts +3 -0
- package/dist/components-ai-workflows/node/index.mjs +4 -0
- package/dist/components-ai-workflows/panel/index.d.mts +15 -0
- package/dist/components-ai-workflows/panel/index.mjs +89 -0
- package/dist/components-ai-workflows/panel/index.mjs.map +1 -0
- package/dist/components-ai-workflows/resizable-node/index.d.mts +30 -0
- package/dist/components-ai-workflows/resizable-node/index.mjs +164 -0
- package/dist/components-ai-workflows/resizable-node/index.mjs.map +1 -0
- package/dist/components-ai-workflows/toolbar/index.d.mts +19 -0
- package/dist/components-ai-workflows/toolbar/index.mjs +91 -0
- package/dist/components-ai-workflows/toolbar/index.mjs.map +1 -0
- package/dist/components-auth-client-nav-user.d.mts +3 -0
- package/dist/components-auth-client-nav-user.mjs +4 -0
- package/dist/components-auth-client-providers.d.mts +13 -0
- package/dist/components-auth-client-providers.mjs +89 -0
- package/dist/components-auth-client-providers.mjs.map +1 -0
- package/dist/components-auth-client.d.mts +5 -0
- package/dist/components-auth-client.mjs +5 -0
- package/dist/components-auth-server.d.mts +1878 -0
- package/dist/components-auth-server.mjs +32769 -0
- package/dist/components-auth-server.mjs.map +1 -0
- package/dist/components-auth.d.mts +5 -0
- package/dist/components-auth.mjs +5 -0
- package/dist/components-charts/areas/index.d.mts +3 -0
- package/dist/components-charts/areas/index.mjs +4 -0
- package/dist/components-charts/bars/index.d.mts +3 -0
- package/dist/components-charts/bars/index.mjs +4 -0
- package/dist/components-charts/funnel-chart/index.d.mts +3 -0
- package/dist/components-charts/funnel-chart/index.mjs +4 -0
- package/dist/components-charts/mini-area-chart/index.d.mts +3 -0
- package/dist/components-charts/mini-area-chart/index.mjs +4 -0
- package/dist/components-charts/time-series-chart/index.d.mts +3 -0
- package/dist/components-charts/time-series-chart/index.mjs +4 -0
- package/dist/components-charts/tooltip-sync/index.d.mts +3 -0
- package/dist/components-charts/tooltip-sync/index.mjs +4 -0
- package/dist/components-charts/x-axis/index.d.mts +3 -0
- package/dist/components-charts/x-axis/index.mjs +4 -0
- package/dist/components-charts/y-axis/index.d.mts +3 -0
- package/dist/components-charts/y-axis/index.mjs +4 -0
- package/dist/components-elements-accordion.d.mts +59 -0
- package/dist/components-elements-accordion.mjs +275 -0
- package/dist/components-elements-accordion.mjs.map +1 -0
- package/dist/components-elements-alert.d.mts +3 -0
- package/dist/components-elements-alert.mjs +4 -0
- package/dist/components-elements-avatar.d.mts +24 -0
- package/dist/components-elements-avatar.mjs +4 -0
- package/dist/components-elements-badge.d.mts +4 -0
- package/dist/components-elements-badge.mjs +4 -0
- package/dist/components-elements-button.d.mts +4 -0
- package/dist/components-elements-button.mjs +4 -0
- package/dist/components-elements-card.d.mts +3 -0
- package/dist/components-elements-card.mjs +4 -0
- package/dist/components-elements-carousel.d.mts +5 -0
- package/dist/components-elements-carousel.mjs +4 -0
- package/dist/components-elements-chart.d.mts +24 -0
- package/dist/components-elements-chart.mjs +226 -0
- package/dist/components-elements-chart.mjs.map +1 -0
- package/dist/components-elements-collapsible.d.mts +3 -0
- package/dist/components-elements-collapsible.mjs +4 -0
- package/dist/components-elements-dialog.d.mts +3 -0
- package/dist/components-elements-dialog.mjs +4 -0
- package/dist/components-elements-dropdown-menu.d.mts +3 -0
- package/dist/components-elements-dropdown-menu.mjs +4 -0
- package/dist/components-elements-dynamic-breadcrumb.d.mts +16 -0
- package/dist/components-elements-dynamic-breadcrumb.mjs +4 -0
- package/dist/components-elements-empty.d.mts +18 -0
- package/dist/components-elements-empty.mjs +199 -0
- package/dist/components-elements-empty.mjs.map +1 -0
- package/dist/components-elements-hover-card.d.mts +3 -0
- package/dist/components-elements-hover-card.mjs +4 -0
- package/dist/components-elements-loading-dots.d.mts +3 -0
- package/dist/components-elements-loading-dots.mjs +4 -0
- package/dist/components-elements-pagination-controls.d.mts +28 -0
- package/dist/components-elements-pagination-controls.mjs +4 -0
- package/dist/components-elements-progress.d.mts +28 -0
- package/dist/components-elements-progress.mjs +4 -0
- package/dist/components-elements-resizable.d.mts +31 -0
- package/dist/components-elements-resizable.mjs +4 -0
- package/dist/components-elements-scroll-area.d.mts +3 -0
- package/dist/components-elements-scroll-area.mjs +4 -0
- package/dist/components-elements-separator.d.mts +3 -0
- package/dist/components-elements-separator.mjs +4 -0
- package/dist/components-elements-skeleton.d.mts +3 -0
- package/dist/components-elements-skeleton.mjs +4 -0
- package/dist/components-elements-status-badge.d.mts +22 -0
- package/dist/components-elements-status-badge.mjs +174 -0
- package/dist/components-elements-status-badge.mjs.map +1 -0
- package/dist/components-elements-table.d.mts +44 -0
- package/dist/components-elements-table.mjs +4 -0
- package/dist/components-elements-tabs.d.mts +43 -0
- package/dist/components-elements-tabs.mjs +435 -0
- package/dist/components-elements-tabs.mjs.map +1 -0
- package/dist/components-elements-tooltip.d.mts +3 -0
- package/dist/components-elements-tooltip.mjs +4 -0
- package/dist/components-filter/filter-list/index.d.mts +4 -0
- package/dist/components-filter/filter-list/index.mjs +4 -0
- package/dist/components-filter/filter-select/index.d.mts +4 -0
- package/dist/components-filter/filter-select/index.mjs +4 -0
- package/dist/components-forms/checkbox/index.d.mts +27 -0
- package/dist/components-forms/checkbox/index.mjs +4 -0
- package/dist/components-forms/combobox/index.d.mts +5 -0
- package/dist/components-forms/combobox/index.mjs +4 -0
- package/dist/components-forms/date-picker/index.d.mts +3 -0
- package/dist/components-forms/date-picker/index.mjs +4 -0
- package/dist/components-forms/file-upload/index.d.mts +49 -0
- package/dist/components-forms/file-upload/index.mjs +323 -0
- package/dist/components-forms/file-upload/index.mjs.map +1 -0
- package/dist/components-forms/input/index.d.mts +3 -0
- package/dist/components-forms/input/index.mjs +4 -0
- package/dist/components-forms/input-group/index.d.mts +5 -0
- package/dist/components-forms/input-group/index.mjs +4 -0
- package/dist/components-forms/label/index.d.mts +23 -0
- package/dist/components-forms/label/index.mjs +4 -0
- package/dist/components-forms/radio-group/index.d.mts +29 -0
- package/dist/components-forms/radio-group/index.mjs +215 -0
- package/dist/components-forms/radio-group/index.mjs.map +1 -0
- package/dist/components-forms/select/index.d.mts +3 -0
- package/dist/components-forms/select/index.mjs +4 -0
- package/dist/components-forms/switch/index.d.mts +30 -0
- package/dist/components-forms/switch/index.mjs +4 -0
- package/dist/components-forms/textarea/index.d.mts +19 -0
- package/dist/components-forms/textarea/index.mjs +4 -0
- package/dist/components-layout/app-sidebar/index.d.mts +47 -0
- package/dist/components-layout/app-sidebar/index.mjs +340 -0
- package/dist/components-layout/app-sidebar/index.mjs.map +1 -0
- package/dist/components-layout/artifact-panel/index.d.mts +3 -0
- package/dist/components-layout/artifact-panel/index.mjs +4 -0
- package/dist/components-layout/content-sidebar/index.d.mts +89 -0
- package/dist/components-layout/content-sidebar/index.mjs +202 -0
- package/dist/components-layout/content-sidebar/index.mjs.map +1 -0
- package/dist/components-layout/nav-app-switcher/index.d.mts +3 -0
- package/dist/components-layout/nav-app-switcher/index.mjs +4 -0
- package/dist/components-layout/nav-main/index.d.mts +30 -0
- package/dist/components-layout/nav-main/index.mjs +4 -0
- package/dist/components-layout/nav-projects/index.d.mts +18 -0
- package/dist/components-layout/nav-projects/index.mjs +153 -0
- package/dist/components-layout/nav-projects/index.mjs.map +1 -0
- package/dist/components-layout/nav-secondary/index.d.mts +31 -0
- package/dist/components-layout/nav-secondary/index.mjs +4 -0
- package/dist/components-layout/nav-user/index.d.mts +17 -0
- package/dist/components-layout/nav-user/index.mjs +4 -0
- package/dist/components-layout/oneapp/index.mjs +4 -0
- package/dist/components-layout/sidebar/index.d.mts +8 -0
- package/dist/components-layout/sidebar/index.mjs +4 -0
- package/dist/components-layout/sidebar-inset-header-portal/index.d.mts +3 -0
- package/dist/components-layout/sidebar-inset-header-portal/index.mjs +4 -0
- package/dist/components-layout/sidebar-slots/index.d.mts +3 -0
- package/dist/components-layout/sidebar-slots/index.mjs +4 -0
- package/dist/components-layout/theme-provider/index.d.mts +15 -0
- package/dist/components-layout/theme-provider/index.mjs +4 -0
- package/dist/components-layout-app-shell.d.mts +83 -0
- package/dist/components-layout-app-shell.mjs +185 -0
- package/dist/components-layout-app-shell.mjs.map +1 -0
- package/dist/components-layout-oneapp.d.mts +84 -0
- package/dist/components-layout-oneapp.mjs +4 -0
- package/dist/components-overlays-confirm-dialog.d.mts +38 -0
- package/dist/components-overlays-confirm-dialog.mjs +145 -0
- package/dist/components-overlays-confirm-dialog.mjs.map +1 -0
- package/dist/components-overlays-toast.d.mts +16 -0
- package/dist/components-overlays-toast.mjs +127 -0
- package/dist/components-overlays-toast.mjs.map +1 -0
- package/dist/connection-D_kWZtAX.mjs +105 -0
- package/dist/connection-D_kWZtAX.mjs.map +1 -0
- package/dist/dark-mode-B4L-MZr7.mjs +288 -0
- package/dist/dark-mode-B4L-MZr7.mjs.map +1 -0
- package/dist/dark-mode-CYb7lJ6G.d.mts +191 -0
- package/dist/date-range-picker-CdemRFs_.mjs +676 -0
- package/dist/date-range-picker-CdemRFs_.mjs.map +1 -0
- package/dist/dialog-Di5QhIga.d.mts +31 -0
- package/dist/dialog-DuluSpxA.mjs +293 -0
- package/dist/dialog-DuluSpxA.mjs.map +1 -0
- package/dist/dropdown-menu-91g1g_Cl.mjs +379 -0
- package/dist/dropdown-menu-91g1g_Cl.mjs.map +1 -0
- package/dist/dropdown-menu-CwRZCnNs.d.mts +91 -0
- package/dist/dynamic-breadcrumb-33t_hdEI.mjs +385 -0
- package/dist/dynamic-breadcrumb-33t_hdEI.mjs.map +1 -0
- package/dist/error-boundary-Ggc5btkU.mjs +297 -0
- package/dist/error-boundary-Ggc5btkU.mjs.map +1 -0
- package/dist/filter-list-BMT7Nrli.d.mts +27 -0
- package/dist/filter-list-B_9aV5Lp.mjs +279 -0
- package/dist/filter-list-B_9aV5Lp.mjs.map +1 -0
- package/dist/filter-select-COLb1S5z.d.mts +34 -0
- package/dist/filter-select-CYfBhJ_E.mjs +341 -0
- package/dist/filter-select-CYfBhJ_E.mjs.map +1 -0
- package/dist/fonts.d.mts +22 -0
- package/dist/fonts.mjs +104 -0
- package/dist/fonts.mjs.map +1 -0
- package/dist/funnel-chart-CUpUr1pl.d.mts +22 -0
- package/dist/funnel-chart-fdwagDvc.mjs +318 -0
- package/dist/funnel-chart-fdwagDvc.mjs.map +1 -0
- package/dist/generative-ui-renderer-D0ZgNRZF.mjs +484 -0
- package/dist/generative-ui-renderer-D0ZgNRZF.mjs.map +1 -0
- package/dist/generative-ui-renderer-D69qYK0D.d.mts +32 -0
- package/dist/hooks/index.d.mts +5 -0
- package/dist/hooks/index.mjs +6 -0
- package/dist/hooks/use-mobile.d.mts +6 -0
- package/dist/hooks/use-mobile.mjs +45 -0
- package/dist/hooks/use-mobile.mjs.map +1 -0
- package/dist/hooks/use-responsive.d.mts +13 -0
- package/dist/hooks/use-responsive.mjs +50 -0
- package/dist/hooks/use-responsive.mjs.map +1 -0
- package/dist/hooks/use-scroll-progress.d.mts +17 -0
- package/dist/hooks/use-scroll-progress.mjs +62 -0
- package/dist/hooks/use-scroll-progress.mjs.map +1 -0
- package/dist/hooks/use-toast.d.mts +21 -0
- package/dist/hooks/use-toast.mjs +40 -0
- package/dist/hooks/use-toast.mjs.map +1 -0
- package/dist/hover-card-BqEpbXMp.d.mts +31 -0
- package/dist/hover-card-nn4fjJOh.mjs +161 -0
- package/dist/hover-card-nn4fjJOh.mjs.map +1 -0
- package/dist/index-AwyfWaOP.d.mts +60 -0
- package/dist/index.d.mts +503 -0
- package/dist/index.mjs +2158 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input-CT1C9DMs.d.mts +19 -0
- package/dist/input-D0T5jbR6.d.mts +19 -0
- package/dist/input-DhpkXN3J.mjs +176 -0
- package/dist/input-DhpkXN3J.mjs.map +1 -0
- package/dist/input-group-CTBpkGI9.mjs +231 -0
- package/dist/input-group-CTBpkGI9.mjs.map +1 -0
- package/dist/input-group-DcDPUaQ3.d.mts +20 -0
- package/dist/input-group-VSZJM_on.d.mts +20 -0
- package/dist/integrations-COjiOhkd.d.mts +60 -0
- package/dist/integrations-Doz6nfxm.d.mts +60 -0
- package/dist/integrations-lBG309ZD.mjs +471 -0
- package/dist/integrations-lBG309ZD.mjs.map +1 -0
- package/dist/label-DnUThLUR.mjs +148 -0
- package/dist/label-DnUThLUR.mjs.map +1 -0
- package/dist/lib/export-csv.d.mts +12 -0
- package/dist/lib/export-csv.mjs +63 -0
- package/dist/lib/export-csv.mjs.map +1 -0
- package/dist/lib/index.d.mts +6 -0
- package/dist/lib/index.mjs +7 -0
- package/dist/lib/resize-image.d.mts +11 -0
- package/dist/lib/resize-image.mjs +66 -0
- package/dist/lib/resize-image.mjs.map +1 -0
- package/dist/lib/stable-sort.d.mts +6 -0
- package/dist/lib/stable-sort.mjs +33 -0
- package/dist/lib/stable-sort.mjs.map +1 -0
- package/dist/lib/utils.d.mts +8 -0
- package/dist/lib/utils.mjs +4 -0
- package/dist/lib-utils.mjs +4 -0
- package/dist/loader-B2SF0yPJ.mjs +168 -0
- package/dist/loader-B2SF0yPJ.mjs.map +1 -0
- package/dist/loading-dots-DJfxDgv3.mjs +119 -0
- package/dist/loading-dots-DJfxDgv3.mjs.map +1 -0
- package/dist/loading-dots-DvR1lwC-.d.mts +11 -0
- package/dist/mini-area-chart-GIUU-ZLo.d.mts +30 -0
- package/dist/mini-area-chart-s5ItHBk8.mjs +225 -0
- package/dist/mini-area-chart-s5ItHBk8.mjs.map +1 -0
- package/dist/motion-DLlwbMJ0.d.mts +33 -0
- package/dist/motion-zelaDelJ.mjs +47 -0
- package/dist/motion-zelaDelJ.mjs.map +1 -0
- package/dist/nav-app-switcher-B1NTlYrm.d.mts +43 -0
- package/dist/nav-app-switcher-V7aJAC18.mjs +235 -0
- package/dist/nav-app-switcher-V7aJAC18.mjs.map +1 -0
- package/dist/nav-main-BscfzNoi.mjs +105 -0
- package/dist/nav-main-BscfzNoi.mjs.map +1 -0
- package/dist/nav-secondary-t-xeA0I4.mjs +51 -0
- package/dist/nav-secondary-t-xeA0I4.mjs.map +1 -0
- package/dist/nav-user-A4YHm3-O.mjs +193 -0
- package/dist/nav-user-A4YHm3-O.mjs.map +1 -0
- package/dist/node-BKXOPjw9.d.mts +100 -0
- package/dist/node-CdmDD4k-.mjs +116 -0
- package/dist/node-CdmDD4k-.mjs.map +1 -0
- package/dist/oneapp-CfwhNatF.mjs +322 -0
- package/dist/oneapp-CfwhNatF.mjs.map +1 -0
- package/dist/pagination-controls-CE3-eCxI.mjs +135 -0
- package/dist/pagination-controls-CE3-eCxI.mjs.map +1 -0
- package/dist/popover-DmWxl2lW.mjs +198 -0
- package/dist/popover-DmWxl2lW.mjs.map +1 -0
- package/dist/preview.d.mts +6 -0
- package/dist/progress-BWxdthl4.mjs +230 -0
- package/dist/progress-BWxdthl4.mjs.map +1 -0
- package/dist/prompt-input-SFJ9_lNw.mjs +1149 -0
- package/dist/prompt-input-SFJ9_lNw.mjs.map +1 -0
- package/dist/resizable--DaTse0W.mjs +124 -0
- package/dist/resizable--DaTse0W.mjs.map +1 -0
- package/dist/scroll-area-Bxi-Edjc.mjs +139 -0
- package/dist/scroll-area-Bxi-Edjc.mjs.map +1 -0
- package/dist/scroll-area-CDRGG59G.d.mts +19 -0
- package/dist/select-DI6PzHN3.mjs +411 -0
- package/dist/select-DI6PzHN3.mjs.map +1 -0
- package/dist/select-csqviwUw.d.mts +44 -0
- package/dist/separator-BG9BqZqg.d.mts +20 -0
- package/dist/separator-CNQqqwfO.d.mts +20 -0
- package/dist/separator-veJJBul5.mjs +118 -0
- package/dist/separator-veJJBul5.mjs.map +1 -0
- package/dist/shared-BqVcofZN.d.mts +91 -0
- package/dist/shared-auth.d.mts +5 -0
- package/dist/shared-auth.mjs +6 -0
- package/dist/shimmer-BLRAD4VL.mjs +102 -0
- package/dist/shimmer-BLRAD4VL.mjs.map +1 -0
- package/dist/sidebar-CPteoqnB.d.mts +163 -0
- package/dist/sidebar-CdWE7H3R.mjs +814 -0
- package/dist/sidebar-CdWE7H3R.mjs.map +1 -0
- package/dist/sidebar-DYgXCHqQ.d.mts +163 -0
- package/dist/sidebar-inset-header-portal-CIRN-lKw.mjs +153 -0
- package/dist/sidebar-inset-header-portal-CIRN-lKw.mjs.map +1 -0
- package/dist/sidebar-inset-header-portal-DjfK7xCt.d.mts +24 -0
- package/dist/sidebar-slots-DNCEnx5L.mjs +135 -0
- package/dist/sidebar-slots-DNCEnx5L.mjs.map +1 -0
- package/dist/sidebar-slots-OqNmzlIk.d.mts +47 -0
- package/dist/skeleton-ByXUFNDF.d.mts +35 -0
- package/dist/skeleton-aXwA3YID.mjs +211 -0
- package/dist/skeleton-aXwA3YID.mjs.map +1 -0
- package/dist/sources.css +16 -0
- package/dist/storybook-preview.mjs +184 -0
- package/dist/storybook-preview.mjs.map +1 -0
- package/dist/styles/colors.css +166 -0
- package/dist/styles/index.css +2 -0
- package/dist/styles/mantine.css +1024 -0
- package/dist/styles/spacing.css +62 -0
- package/dist/styles/theme.css +1687 -0
- package/dist/styles/typography.css +59 -0
- package/dist/styles/variables.css +998 -0
- package/dist/styles.css +1 -0
- package/dist/switch-BFct1r4a.mjs +223 -0
- package/dist/switch-BFct1r4a.mjs.map +1 -0
- package/dist/table-DNkLM1TB.mjs +261 -0
- package/dist/table-DNkLM1TB.mjs.map +1 -0
- package/dist/textarea-MpLFc9sB.mjs +173 -0
- package/dist/textarea-MpLFc9sB.mjs.map +1 -0
- package/dist/theme-provider-4D34sBmG.mjs +83 -0
- package/dist/theme-provider-4D34sBmG.mjs.map +1 -0
- package/dist/time-series-chart-B66xH88w.d.mts +69 -0
- package/dist/time-series-chart-DxnknDhW.mjs +400 -0
- package/dist/time-series-chart-DxnknDhW.mjs.map +1 -0
- package/dist/tokens/tokens.dtcg.json +4353 -0
- package/dist/tokens/tokens.json +895 -0
- package/dist/tokens-mantine-types.d.mts +3 -0
- package/dist/tokens-mantine-types.mjs +4 -0
- package/dist/tokens.css +2 -0
- package/dist/tokens.d.mts +9398 -0
- package/dist/tokens.mjs +9311 -0
- package/dist/tokens.mjs.map +1 -0
- package/dist/tooltip-B8_zKnHC.mjs +301 -0
- package/dist/tooltip-B8_zKnHC.mjs.map +1 -0
- package/dist/tooltip-BA27ygge.d.mts +44 -0
- package/dist/tooltip-FqB3srL-.d.mts +44 -0
- package/dist/tooltip-sync-Ax1GmpjC.d.mts +17 -0
- package/dist/tooltip-sync-DzJUgiTM.mjs +85 -0
- package/dist/tooltip-sync-DzJUgiTM.mjs.map +1 -0
- package/dist/types-B8z57DW2.d.mts +41 -0
- package/dist/use-artifact-panel-state-CUQTn2Uq.mjs +346 -0
- package/dist/use-artifact-panel-state-CUQTn2Uq.mjs.map +1 -0
- package/dist/use-artifact-panel-state-DPZC--sz.d.mts +150 -0
- package/dist/utils-BJGrUJ6T.mjs +77 -0
- package/dist/utils-BJGrUJ6T.mjs.map +1 -0
- package/dist/utils-D2bGp2p_.mjs +33 -0
- package/dist/utils-D2bGp2p_.mjs.map +1 -0
- package/dist/x-axis-BY00htJY.mjs +137 -0
- package/dist/x-axis-BY00htJY.mjs.map +1 -0
- package/dist/x-axis-Dh66iD8l.d.mts +21 -0
- package/dist/y-axis-DgHlVHRG.mjs +118 -0
- package/dist/y-axis-DgHlVHRG.mjs.map +1 -0
- package/dist/y-axis-DocBbrSp.d.mts +23 -0
- package/dist/z-index-BlBlZL-F.d.mts +10775 -0
- package/package.json +429 -0
- package/src/ai-oneapp/flow-chat/index.ts +3 -0
- package/src/ai-oneapp/flow-chat/node-suggestion-card.tsx +37 -0
- package/src/ai-oneapp/flow-chat/template-suggestion-card.tsx +49 -0
- package/src/ai-oneapp/flow-chat/workflow-action-toast.tsx +55 -0
- package/src/components/.gitkeep +0 -0
- package/src/components/ai-elements/__tests__/test-utils.tsx +12 -0
- package/src/components/ai-elements/actions/actions.stories.tsx +288 -0
- package/src/components/ai-elements/actions/actions.test.tsx +60 -0
- package/src/components/ai-elements/actions/actions.tsx +286 -0
- package/src/components/ai-elements/actions/index.ts +7 -0
- package/src/components/ai-elements/agent-step/agent-step.stories.tsx +167 -0
- package/src/components/ai-elements/agent-step/agent-step.tsx +206 -0
- package/src/components/ai-elements/agent-step/index.ts +7 -0
- package/src/components/ai-elements/ai-elements.constants.ts +516 -0
- package/src/components/ai-elements/artifact/artifact.stories.tsx +199 -0
- package/src/components/ai-elements/artifact/artifact.tsx +277 -0
- package/src/components/ai-elements/artifact/index.ts +7 -0
- package/src/components/ai-elements/branch/branch.stories.tsx +212 -0
- package/src/components/ai-elements/branch/branch.test.tsx +148 -0
- package/src/components/ai-elements/branch/branch.tsx +502 -0
- package/src/components/ai-elements/branch/index.ts +7 -0
- package/src/components/ai-elements/chain-of-thought/chain-of-thought.stories.tsx +172 -0
- package/src/components/ai-elements/chain-of-thought/chain-of-thought.tsx +505 -0
- package/src/components/ai-elements/chain-of-thought/index.ts +7 -0
- package/src/components/ai-elements/chat-input/chat-input.stories.tsx +185 -0
- package/src/components/ai-elements/chat-input/chat-input.tsx +201 -0
- package/src/components/ai-elements/chat-input/index.ts +7 -0
- package/src/components/ai-elements/checkpoint/checkpoint.stories.tsx +171 -0
- package/src/components/ai-elements/checkpoint/checkpoint.tsx +256 -0
- package/src/components/ai-elements/checkpoint/index.ts +7 -0
- package/src/components/ai-elements/code-block/code-block.stories.tsx +317 -0
- package/src/components/ai-elements/code-block/code-block.tsx +366 -0
- package/src/components/ai-elements/code-block/index.ts +7 -0
- package/src/components/ai-elements/confirmation/confirmation.stories.tsx +236 -0
- package/src/components/ai-elements/confirmation/confirmation.tsx +465 -0
- package/src/components/ai-elements/confirmation/index.ts +7 -0
- package/src/components/ai-elements/context/context.stories.tsx +80 -0
- package/src/components/ai-elements/context/context.tsx +585 -0
- package/src/components/ai-elements/context/index.ts +7 -0
- package/src/components/ai-elements/conversation/__tests__/conversation.test.tsx +402 -0
- package/src/components/ai-elements/conversation/conversation.stories.tsx +1019 -0
- package/src/components/ai-elements/conversation/conversation.tsx +260 -0
- package/src/components/ai-elements/conversation/index.ts +7 -0
- package/src/components/ai-elements/custom/__tests__/accessibility.test.tsx +27 -0
- package/src/components/ai-elements/custom/__tests__/chat-container.test.tsx +30 -0
- package/src/components/ai-elements/custom/__tests__/conversation-history.test.tsx +100 -0
- package/src/components/ai-elements/custom/__tests__/export-dropdown.test.tsx +60 -0
- package/src/components/ai-elements/custom/ai-label/ai-label.stories.tsx +86 -0
- package/src/components/ai-elements/custom/ai-label/ai-label.tsx +291 -0
- package/src/components/ai-elements/custom/ai-label/index.ts +7 -0
- package/src/components/ai-elements/custom/artifact-skeleton/artifact-skeleton.stories.tsx +155 -0
- package/src/components/ai-elements/custom/artifact-skeleton/artifact-skeleton.tsx +269 -0
- package/src/components/ai-elements/custom/artifact-skeleton/index.ts +18 -0
- package/src/components/ai-elements/custom/audio-player/audio-player.stories.tsx +50 -0
- package/src/components/ai-elements/custom/audio-player/audio-player.tsx +296 -0
- package/src/components/ai-elements/custom/audio-player/index.ts +1 -0
- package/src/components/ai-elements/custom/button-group/button-group.stories.tsx +108 -0
- package/src/components/ai-elements/custom/button-group/button-group.tsx +142 -0
- package/src/components/ai-elements/custom/button-group/index.ts +15 -0
- package/src/components/ai-elements/custom/chat-container/chat-container.stories.tsx +143 -0
- package/src/components/ai-elements/custom/chat-container/chat-container.tsx +406 -0
- package/src/components/ai-elements/custom/chat-container/index.ts +9 -0
- package/src/components/ai-elements/custom/collapsible/collapsible.stories.tsx +130 -0
- package/src/components/ai-elements/custom/collapsible/index.ts +11 -0
- package/src/components/ai-elements/custom/collapsible/use-collapsible.tsx +240 -0
- package/src/components/ai-elements/custom/collapsible-content/collapsible-content.stories.tsx +113 -0
- package/src/components/ai-elements/custom/collapsible-content/collapsible-content.tsx +141 -0
- package/src/components/ai-elements/custom/collapsible-content/index.ts +7 -0
- package/src/components/ai-elements/custom/content-placeholder/content-placeholder.stories.tsx +82 -0
- package/src/components/ai-elements/custom/content-placeholder/content-placeholder.tsx +319 -0
- package/src/components/ai-elements/custom/content-placeholder/index.ts +10 -0
- package/src/components/ai-elements/custom/conversation-header/conversation-header.stories.tsx +102 -0
- package/src/components/ai-elements/custom/conversation-header/conversation-header.tsx +202 -0
- package/src/components/ai-elements/custom/conversation-header/index.ts +12 -0
- package/src/components/ai-elements/custom/conversation-history/conversation-history.stories.tsx +191 -0
- package/src/components/ai-elements/custom/conversation-history/conversation-history.tsx +515 -0
- package/src/components/ai-elements/custom/conversation-history/index.ts +16 -0
- package/src/components/ai-elements/custom/diff-view/diff-view.stories.tsx +173 -0
- package/src/components/ai-elements/custom/diff-view/diff-view.tsx +261 -0
- package/src/components/ai-elements/custom/diff-view/index.ts +7 -0
- package/src/components/ai-elements/custom/draggable-tabs/draggable-tabs.stories.tsx +157 -0
- package/src/components/ai-elements/custom/draggable-tabs/draggable-tabs.tsx +311 -0
- package/src/components/ai-elements/custom/draggable-tabs/index.ts +7 -0
- package/src/components/ai-elements/custom/export-conversation/export-conversation.stories.tsx +73 -0
- package/src/components/ai-elements/custom/export-conversation/export-conversation.tsx +405 -0
- package/src/components/ai-elements/custom/export-conversation/index.ts +10 -0
- package/src/components/ai-elements/custom/export-dropdown/export-dropdown.stories.tsx +121 -0
- package/src/components/ai-elements/custom/export-dropdown/export-dropdown.tsx +315 -0
- package/src/components/ai-elements/custom/export-dropdown/index.ts +11 -0
- package/src/components/ai-elements/custom/feedback/feedback.stories.tsx +85 -0
- package/src/components/ai-elements/custom/feedback/feedback.tsx +425 -0
- package/src/components/ai-elements/custom/feedback/index.ts +13 -0
- package/src/components/ai-elements/custom/file-card/file-card.stories.tsx +65 -0
- package/src/components/ai-elements/custom/file-card/file-card.tsx +249 -0
- package/src/components/ai-elements/custom/file-card/index.ts +1 -0
- package/src/components/ai-elements/custom/file-tree/file-tree.stories.tsx +96 -0
- package/src/components/ai-elements/custom/file-tree/file-tree.tsx +266 -0
- package/src/components/ai-elements/custom/file-tree/index.ts +7 -0
- package/src/components/ai-elements/custom/index.ts +73 -0
- package/src/components/ai-elements/custom/keyboard-shortcut/index.ts +14 -0
- package/src/components/ai-elements/custom/keyboard-shortcut/keyboard-shortcut.stories.tsx +118 -0
- package/src/components/ai-elements/custom/keyboard-shortcut/keyboard-shortcut.tsx +292 -0
- package/src/components/ai-elements/custom/message-edit/index.ts +1 -0
- package/src/components/ai-elements/custom/message-edit/message-edit.stories.tsx +88 -0
- package/src/components/ai-elements/custom/message-edit/message-edit.tsx +225 -0
- package/src/components/ai-elements/custom/message-error/index.ts +7 -0
- package/src/components/ai-elements/custom/message-error/message-error.stories.tsx +85 -0
- package/src/components/ai-elements/custom/message-error/message-error.tsx +301 -0
- package/src/components/ai-elements/custom/message-group/index.ts +1 -0
- package/src/components/ai-elements/custom/message-group/message-group.stories.tsx +82 -0
- package/src/components/ai-elements/custom/message-group/message-group.tsx +77 -0
- package/src/components/ai-elements/custom/message-separator/index.ts +1 -0
- package/src/components/ai-elements/custom/message-separator/message-separator.stories.tsx +65 -0
- package/src/components/ai-elements/custom/message-separator/message-separator.tsx +132 -0
- package/src/components/ai-elements/custom/scroll-to-bottom/index.ts +11 -0
- package/src/components/ai-elements/custom/scroll-to-bottom/scroll-to-bottom.stories.tsx +116 -0
- package/src/components/ai-elements/custom/scroll-to-bottom/use-scroll-to-bottom.tsx +215 -0
- package/src/components/ai-elements/custom/snippet/index.ts +1 -0
- package/src/components/ai-elements/custom/snippet/snippet.stories.tsx +59 -0
- package/src/components/ai-elements/custom/snippet/snippet.tsx +158 -0
- package/src/components/ai-elements/custom/stack-trace/index.ts +1 -0
- package/src/components/ai-elements/custom/stack-trace/stack-trace.stories.tsx +112 -0
- package/src/components/ai-elements/custom/stack-trace/stack-trace.tsx +368 -0
- package/src/components/ai-elements/custom/terminal/index.ts +9 -0
- package/src/components/ai-elements/custom/terminal/terminal.stories.tsx +92 -0
- package/src/components/ai-elements/custom/terminal/terminal.tsx +233 -0
- package/src/components/ai-elements/custom/test-results/test-results.tsx +438 -0
- package/src/components/ai-elements/custom/thought-chain/index.ts +7 -0
- package/src/components/ai-elements/custom/thought-chain/thought-chain.stories.tsx +123 -0
- package/src/components/ai-elements/custom/thought-chain/thought-chain.tsx +246 -0
- package/src/components/ai-elements/custom/token-usage/index.ts +6 -0
- package/src/components/ai-elements/custom/token-usage/token-usage.stories.tsx +104 -0
- package/src/components/ai-elements/custom/token-usage/token-usage.tsx +236 -0
- package/src/components/ai-elements/custom/transcription/index.ts +1 -0
- package/src/components/ai-elements/custom/transcription/transcription.stories.tsx +80 -0
- package/src/components/ai-elements/custom/transcription/transcription.tsx +163 -0
- package/src/components/ai-elements/custom/typing-indicator/index.ts +1 -0
- package/src/components/ai-elements/custom/typing-indicator/typing-indicator.stories.tsx +71 -0
- package/src/components/ai-elements/custom/typing-indicator/typing-indicator.tsx +126 -0
- package/src/components/ai-elements/custom/undo-redo/index.ts +12 -0
- package/src/components/ai-elements/custom/undo-redo/undo-redo.stories.tsx +145 -0
- package/src/components/ai-elements/custom/undo-redo/use-undo-redo.tsx +324 -0
- package/src/components/ai-elements/custom/voice-selector/index.ts +7 -0
- package/src/components/ai-elements/custom/voice-selector/voice-selector.stories.tsx +67 -0
- package/src/components/ai-elements/custom/voice-selector/voice-selector.tsx +301 -0
- package/src/components/ai-elements/custom/welcome/index.ts +1 -0
- package/src/components/ai-elements/custom/welcome/welcome.stories.tsx +92 -0
- package/src/components/ai-elements/custom/welcome/welcome.tsx +213 -0
- package/src/components/ai-elements/generative-ui/generative-ui-renderer.stories.tsx +451 -0
- package/src/components/ai-elements/generative-ui/generative-ui-renderer.test.tsx +383 -0
- package/src/components/ai-elements/generative-ui/generative-ui-renderer.tsx +668 -0
- package/src/components/ai-elements/generative-ui/index.ts +21 -0
- package/src/components/ai-elements/image/image.stories.tsx +179 -0
- package/src/components/ai-elements/image/image.tsx +178 -0
- package/src/components/ai-elements/image/index.ts +7 -0
- package/src/components/ai-elements/index.ts +195 -0
- package/src/components/ai-elements/inline-citation/index.ts +7 -0
- package/src/components/ai-elements/inline-citation/inline-citation.stories.tsx +331 -0
- package/src/components/ai-elements/inline-citation/inline-citation.tsx +595 -0
- package/src/components/ai-elements/loader/index.ts +7 -0
- package/src/components/ai-elements/loader/loader.stories.tsx +185 -0
- package/src/components/ai-elements/loader/loader.tsx +177 -0
- package/src/components/ai-elements/message/__tests__/message.test.tsx +352 -0
- package/src/components/ai-elements/message/index.ts +7 -0
- package/src/components/ai-elements/message/message-actions.test.tsx +51 -0
- package/src/components/ai-elements/message/message.stories.tsx +609 -0
- package/src/components/ai-elements/message/message.test.tsx +52 -0
- package/src/components/ai-elements/message/message.tsx +1125 -0
- package/src/components/ai-elements/message/response.test.tsx +18 -0
- package/src/components/ai-elements/model-selector/index.ts +7 -0
- package/src/components/ai-elements/model-selector/model-selector.stories.tsx +198 -0
- package/src/components/ai-elements/model-selector/model-selector.tsx +406 -0
- package/src/components/ai-elements/modernization_walkthrough.md +51 -0
- package/src/components/ai-elements/open-in-chat/index.ts +7 -0
- package/src/components/ai-elements/open-in-chat/open-in-chat.stories.tsx +221 -0
- package/src/components/ai-elements/open-in-chat/open-in-chat.tsx +606 -0
- package/src/components/ai-elements/plan/index.ts +7 -0
- package/src/components/ai-elements/plan/plan.stories.tsx +233 -0
- package/src/components/ai-elements/plan/plan.tsx +337 -0
- package/src/components/ai-elements/prompt-char-counter/index.ts +7 -0
- package/src/components/ai-elements/prompt-char-counter/prompt-char-counter.stories.tsx +98 -0
- package/src/components/ai-elements/prompt-char-counter/prompt-char-counter.tsx +159 -0
- package/src/components/ai-elements/prompt-input/index.ts +7 -0
- package/src/components/ai-elements/prompt-input/prompt-input.stories.tsx +548 -0
- package/src/components/ai-elements/prompt-input/prompt-input.test.tsx +22 -0
- package/src/components/ai-elements/prompt-input/prompt-input.tsx +2112 -0
- package/src/components/ai-elements/queue/index.ts +7 -0
- package/src/components/ai-elements/queue/queue.stories.tsx +249 -0
- package/src/components/ai-elements/queue/queue.tsx +456 -0
- package/src/components/ai-elements/reasoning/index.ts +7 -0
- package/src/components/ai-elements/reasoning/reasoning.stories.tsx +147 -0
- package/src/components/ai-elements/reasoning/reasoning.tsx +356 -0
- package/src/components/ai-elements/shimmer/index.ts +7 -0
- package/src/components/ai-elements/shimmer/shimmer.stories.tsx +240 -0
- package/src/components/ai-elements/shimmer/shimmer.tsx +150 -0
- package/src/components/ai-elements/sources/index.ts +7 -0
- package/src/components/ai-elements/sources/sources.stories.tsx +259 -0
- package/src/components/ai-elements/sources/sources.test.tsx +40 -0
- package/src/components/ai-elements/sources/sources.tsx +327 -0
- package/src/components/ai-elements/suggestion/index.ts +7 -0
- package/src/components/ai-elements/suggestion/suggestion.stories.tsx +207 -0
- package/src/components/ai-elements/suggestion/suggestion.tsx +229 -0
- package/src/components/ai-elements/task/index.ts +7 -0
- package/src/components/ai-elements/task/task.stories.tsx +213 -0
- package/src/components/ai-elements/task/task.tsx +356 -0
- package/src/components/ai-elements/test-utils.tsx +28 -0
- package/src/components/ai-elements/tool/index.ts +7 -0
- package/src/components/ai-elements/tool/tool.stories.tsx +195 -0
- package/src/components/ai-elements/tool/tool.test.tsx +160 -0
- package/src/components/ai-elements/tool/tool.tsx +537 -0
- package/src/components/ai-elements/tool-approval/index.ts +7 -0
- package/src/components/ai-elements/tool-approval/tool-approval.stories.tsx +260 -0
- package/src/components/ai-elements/tool-approval/tool-approval.tsx +423 -0
- package/src/components/ai-elements/vitest.config.ts +17 -0
- package/src/components/ai-elements/vitest.setup.ts +6 -0
- package/src/components/ai-elements/web-preview/index.ts +7 -0
- package/src/components/ai-elements/web-preview/web-preview.stories.tsx +202 -0
- package/src/components/ai-elements/web-preview/web-preview.tsx +1166 -0
- package/src/components/ai-workflows/canvas/canvas.stories.tsx +120 -0
- package/src/components/ai-workflows/canvas/canvas.tsx +173 -0
- package/src/components/ai-workflows/canvas/index.ts +7 -0
- package/src/components/ai-workflows/connection/connection.stories.tsx +66 -0
- package/src/components/ai-workflows/connection/connection.tsx +119 -0
- package/src/components/ai-workflows/connection/index.ts +7 -0
- package/src/components/ai-workflows/controls/controls.stories.tsx +72 -0
- package/src/components/ai-workflows/controls/controls.tsx +132 -0
- package/src/components/ai-workflows/controls/index.ts +7 -0
- package/src/components/ai-workflows/edge/edge.stories.tsx +120 -0
- package/src/components/ai-workflows/edge/edge.test.tsx +47 -0
- package/src/components/ai-workflows/edge/edge.tsx +136 -0
- package/src/components/ai-workflows/edge/index.ts +7 -0
- package/src/components/ai-workflows/flow-constants.ts +11 -0
- package/src/components/ai-workflows/node/index.ts +7 -0
- package/src/components/ai-workflows/node/node.stories.tsx +111 -0
- package/src/components/ai-workflows/node/node.tsx +227 -0
- package/src/components/ai-workflows/panel/index.ts +7 -0
- package/src/components/ai-workflows/panel/panel.stories.tsx +102 -0
- package/src/components/ai-workflows/panel/panel.tsx +106 -0
- package/src/components/ai-workflows/resizable-node/index.ts +7 -0
- package/src/components/ai-workflows/resizable-node/resizable-node.stories.tsx +93 -0
- package/src/components/ai-workflows/resizable-node/resizable-node.tsx +228 -0
- package/src/components/ai-workflows/toolbar/index.ts +7 -0
- package/src/components/ai-workflows/toolbar/toolbar.stories.tsx +99 -0
- package/src/components/ai-workflows/toolbar/toolbar.tsx +130 -0
- package/src/components/auth/client/index.ts +12 -0
- package/src/components/auth/client/nav-user/auth-nav-user.tsx +237 -0
- package/src/components/auth/client/nav-user/index.ts +11 -0
- package/src/components/auth/client/providers/ThemeProvider.stories.tsx +59 -0
- package/src/components/auth/client/providers/ThemeProvider.tsx +39 -0
- package/src/components/auth/client/providers/index.ts +7 -0
- package/src/components/auth/client/providers.tsx +129 -0
- package/src/components/auth/index.ts +14 -0
- package/src/components/auth/server/account/ProfileForm.stories.tsx +105 -0
- package/src/components/auth/server/account/ProfileForm.tsx +236 -0
- package/src/components/auth/server/account/index.ts +7 -0
- package/src/components/auth/server/actions/index.ts +11 -0
- package/src/components/auth/server/actions.ts +88 -0
- package/src/components/auth/server/admin/AdminBulkUserActions.stories.tsx +129 -0
- package/src/components/auth/server/admin/AdminBulkUserActions.tsx +649 -0
- package/src/components/auth/server/admin/AdminDashboard.stories.tsx +215 -0
- package/src/components/auth/server/admin/AdminDashboard.tsx +785 -0
- package/src/components/auth/server/admin/AdminDevicesManager.tsx +411 -0
- package/src/components/auth/server/admin/AdminImpersonation.stories.tsx +121 -0
- package/src/components/auth/server/admin/AdminImpersonation.tsx +569 -0
- package/src/components/auth/server/admin/AdminPasskeysManager.tsx +393 -0
- package/src/components/auth/server/admin/AdminSecurityEventsViewer.tsx +395 -0
- package/src/components/auth/server/admin/AdminServiceAccountsManager.tsx +454 -0
- package/src/components/auth/server/admin/AdminSessionsManager.tsx +664 -0
- package/src/components/auth/server/admin/AdminTwoFactorManager.tsx +431 -0
- package/src/components/auth/server/admin/AdminUserCreation.stories.tsx +87 -0
- package/src/components/auth/server/admin/AdminUserCreation.tsx +777 -0
- package/src/components/auth/server/admin/AdminUserDetail.stories.tsx +178 -0
- package/src/components/auth/server/admin/AdminUserDetail.tsx +1044 -0
- package/src/components/auth/server/admin/AdminUsersList.stories.tsx +228 -0
- package/src/components/auth/server/admin/AdminUsersList.tsx +859 -0
- package/src/components/auth/server/admin/index.ts +59 -0
- package/src/components/auth/server/advanced/PasskeySetup.stories.tsx +70 -0
- package/src/components/auth/server/advanced/PasskeySetup.tsx +383 -0
- package/src/components/auth/server/advanced/TwoFactorSetup.stories.tsx +79 -0
- package/src/components/auth/server/advanced/TwoFactorSetup.tsx +459 -0
- package/src/components/auth/server/advanced/TwoFactorVerify.stories.tsx +69 -0
- package/src/components/auth/server/advanced/TwoFactorVerify.tsx +323 -0
- package/src/components/auth/server/advanced/index.ts +10 -0
- package/src/components/auth/server/api-keys/APIKeysList.stories.tsx +95 -0
- package/src/components/auth/server/api-keys/APIKeysList.tsx +470 -0
- package/src/components/auth/server/api-keys/CreateAPIKeyForm.stories.tsx +79 -0
- package/src/components/auth/server/api-keys/CreateAPIKeyForm.tsx +501 -0
- package/src/components/auth/server/api-keys/index.ts +9 -0
- package/src/components/auth/server/enhanced/AccountDeletionFlow.stories.tsx +115 -0
- package/src/components/auth/server/enhanced/AccountDeletionFlow.tsx +733 -0
- package/src/components/auth/server/enhanced/AnonymousSessionCreator.stories.tsx +80 -0
- package/src/components/auth/server/enhanced/AnonymousSessionCreator.tsx +398 -0
- package/src/components/auth/server/enhanced/AnonymousToAccountConverter.stories.tsx +61 -0
- package/src/components/auth/server/enhanced/AnonymousToAccountConverter.tsx +538 -0
- package/src/components/auth/server/enhanced/BackupCodesManager.stories.tsx +108 -0
- package/src/components/auth/server/enhanced/BackupCodesManager.tsx +718 -0
- package/src/components/auth/server/enhanced/BearerTokenGenerator.stories.tsx +85 -0
- package/src/components/auth/server/enhanced/BearerTokenGenerator.tsx +618 -0
- package/src/components/auth/server/enhanced/ChangePasswordForm.stories.tsx +108 -0
- package/src/components/auth/server/enhanced/ChangePasswordForm.tsx +313 -0
- package/src/components/auth/server/enhanced/DataExportRequest.stories.tsx +84 -0
- package/src/components/auth/server/enhanced/DataExportRequest.tsx +734 -0
- package/src/components/auth/server/enhanced/DeviceManagement.stories.tsx +161 -0
- package/src/components/auth/server/enhanced/DeviceManagement.tsx +700 -0
- package/src/components/auth/server/enhanced/EmailChangeVerification.stories.tsx +94 -0
- package/src/components/auth/server/enhanced/EmailChangeVerification.tsx +421 -0
- package/src/components/auth/server/enhanced/EmailOTPSignIn.stories.tsx +68 -0
- package/src/components/auth/server/enhanced/EmailOTPSignIn.tsx +516 -0
- package/src/components/auth/server/enhanced/EmailOTPVerification.stories.tsx +95 -0
- package/src/components/auth/server/enhanced/EmailOTPVerification.tsx +610 -0
- package/src/components/auth/server/enhanced/EmailVerificationRequest.stories.tsx +97 -0
- package/src/components/auth/server/enhanced/EmailVerificationRequest.tsx +461 -0
- package/src/components/auth/server/enhanced/EmailVerificationStatus.stories.tsx +96 -0
- package/src/components/auth/server/enhanced/EmailVerificationStatus.tsx +631 -0
- package/src/components/auth/server/enhanced/MagicLinkRequestForm.stories.tsx +88 -0
- package/src/components/auth/server/enhanced/MagicLinkRequestForm.tsx +439 -0
- package/src/components/auth/server/enhanced/MagicLinkStatusIndicator.stories.tsx +101 -0
- package/src/components/auth/server/enhanced/MagicLinkStatusIndicator.tsx +610 -0
- package/src/components/auth/server/enhanced/MultiSessionDashboard.stories.tsx +101 -0
- package/src/components/auth/server/enhanced/MultiSessionDashboard.tsx +996 -0
- package/src/components/auth/server/enhanced/OrganizationAuditLog.stories.tsx +86 -0
- package/src/components/auth/server/enhanced/OrganizationAuditLog.tsx +1006 -0
- package/src/components/auth/server/enhanced/PasskeyManagement.stories.tsx +102 -0
- package/src/components/auth/server/enhanced/PasskeyManagement.tsx +705 -0
- package/src/components/auth/server/enhanced/PasskeyRegistrationWizard.stories.tsx +83 -0
- package/src/components/auth/server/enhanced/PasskeyRegistrationWizard.tsx +566 -0
- package/src/components/auth/server/enhanced/PasskeySignInInterface.stories.tsx +90 -0
- package/src/components/auth/server/enhanced/PasskeySignInInterface.tsx +792 -0
- package/src/components/auth/server/enhanced/PasswordStrengthIndicator.stories.tsx +129 -0
- package/src/components/auth/server/enhanced/PasswordStrengthIndicator.tsx +539 -0
- package/src/components/auth/server/enhanced/PhoneNumberManagement.stories.tsx +103 -0
- package/src/components/auth/server/enhanced/PhoneNumberManagement.tsx +594 -0
- package/src/components/auth/server/enhanced/PhoneNumberSetupForm.stories.tsx +91 -0
- package/src/components/auth/server/enhanced/PhoneNumberSetupForm.tsx +518 -0
- package/src/components/auth/server/enhanced/PhoneSignInForm.stories.tsx +63 -0
- package/src/components/auth/server/enhanced/PhoneSignInForm.tsx +801 -0
- package/src/components/auth/server/enhanced/PhoneSignInWithSMS.stories.tsx +87 -0
- package/src/components/auth/server/enhanced/PhoneSignInWithSMS.tsx +886 -0
- package/src/components/auth/server/enhanced/PhoneVerificationForm.stories.tsx +81 -0
- package/src/components/auth/server/enhanced/PhoneVerificationForm.tsx +306 -0
- package/src/components/auth/server/enhanced/ResendVerificationEmail.stories.tsx +84 -0
- package/src/components/auth/server/enhanced/ResendVerificationEmail.tsx +407 -0
- package/src/components/auth/server/enhanced/SMSVerificationForm.stories.tsx +92 -0
- package/src/components/auth/server/enhanced/SMSVerificationForm.tsx +521 -0
- package/src/components/auth/server/enhanced/SecurityEventLog.stories.tsx +115 -0
- package/src/components/auth/server/enhanced/SecurityEventLog.tsx +916 -0
- package/src/components/auth/server/enhanced/TeamCreationWizard.stories.tsx +85 -0
- package/src/components/auth/server/enhanced/TeamCreationWizard.tsx +1023 -0
- package/src/components/auth/server/enhanced/__tests__/actions.test.ts +388 -0
- package/src/components/auth/server/enhanced/__tests__/more-actions.test.ts +139 -0
- package/src/components/auth/server/enhanced/actions.ts +1199 -0
- package/src/components/auth/server/enhanced/auth-enhanced-actions.ts +936 -0
- package/src/components/auth/server/enhanced/index.ts +37 -0
- package/src/components/auth/server/forms/ForgotPasswordForm.stories.tsx +82 -0
- package/src/components/auth/server/forms/ForgotPasswordForm.tsx +287 -0
- package/src/components/auth/server/forms/ResetPasswordForm.stories.tsx +79 -0
- package/src/components/auth/server/forms/ResetPasswordForm.tsx +217 -0
- package/src/components/auth/server/forms/SignInForm.stories.tsx +113 -0
- package/src/components/auth/server/forms/SignInForm.tsx +211 -0
- package/src/components/auth/server/forms/SignUpForm.stories.tsx +130 -0
- package/src/components/auth/server/forms/SignUpForm.tsx +243 -0
- package/src/components/auth/server/forms/index.ts +10 -0
- package/src/components/auth/server/index.ts +22 -0
- package/src/components/auth/server/jwt/JWTTokenManager.tsx +315 -0
- package/src/components/auth/server/jwt/index.ts +7 -0
- package/src/components/auth/server/organization/AuditLogViewer.tsx +288 -0
- package/src/components/auth/server/organization/CreateRoleDialog.tsx +540 -0
- package/src/components/auth/server/organization/EditRoleDialog.tsx +487 -0
- package/src/components/auth/server/organization/InviteMembers.stories.tsx +82 -0
- package/src/components/auth/server/organization/InviteMembers.tsx +264 -0
- package/src/components/auth/server/organization/MembersList.stories.tsx +117 -0
- package/src/components/auth/server/organization/MembersList.tsx +425 -0
- package/src/components/auth/server/organization/OrganizationCreation.stories.tsx +99 -0
- package/src/components/auth/server/organization/OrganizationCreation.tsx +293 -0
- package/src/components/auth/server/organization/OrganizationSettings.stories.tsx +99 -0
- package/src/components/auth/server/organization/OrganizationSettings.tsx +494 -0
- package/src/components/auth/server/organization/OrganizationSwitcher.stories.tsx +98 -0
- package/src/components/auth/server/organization/OrganizationSwitcher.tsx +308 -0
- package/src/components/auth/server/organization/PermissionMatrix.tsx +366 -0
- package/src/components/auth/server/organization/RoleManagement.stories.tsx +120 -0
- package/src/components/auth/server/organization/RoleManagement.tsx +318 -0
- package/src/components/auth/server/organization/index.ts +16 -0
- package/src/components/auth/server/session/SessionsList.stories.tsx +81 -0
- package/src/components/auth/server/session/SessionsList.tsx +274 -0
- package/src/components/auth/server/session/index.ts +7 -0
- package/src/components/auth/server/social/SocialLoginButtons.stories.tsx +139 -0
- package/src/components/auth/server/social/SocialLoginButtons.tsx +292 -0
- package/src/components/auth/server/social/index.ts +7 -0
- package/src/components/auth/server/ui/Alert.stories.tsx +97 -0
- package/src/components/auth/server/ui/Alert.tsx +159 -0
- package/src/components/auth/server/ui/Button.stories.tsx +149 -0
- package/src/components/auth/server/ui/Button.tsx +221 -0
- package/src/components/auth/server/ui/Card.stories.tsx +80 -0
- package/src/components/auth/server/ui/Card.tsx +51 -0
- package/src/components/auth/server/ui/Input.stories.tsx +143 -0
- package/src/components/auth/server/ui/Input.tsx +195 -0
- package/src/components/auth/server/ui/index.ts +18 -0
- package/src/components/charts/areas/areas.stories.tsx +113 -0
- package/src/components/charts/areas/areas.tsx +185 -0
- package/src/components/charts/areas/index.ts +11 -0
- package/src/components/charts/bars/bars.stories.tsx +109 -0
- package/src/components/charts/bars/bars.tsx +164 -0
- package/src/components/charts/bars/index.ts +11 -0
- package/src/components/charts/chart-context.ts +35 -0
- package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +111 -0
- package/src/components/charts/funnel-chart/funnel-chart.tsx +392 -0
- package/src/components/charts/funnel-chart/index.ts +11 -0
- package/src/components/charts/index.ts +45 -0
- package/src/components/charts/mini-area-chart/index.ts +11 -0
- package/src/components/charts/mini-area-chart/mini-area-chart.stories.tsx +100 -0
- package/src/components/charts/mini-area-chart/mini-area-chart.tsx +244 -0
- package/src/components/charts/time-series-chart/index.ts +11 -0
- package/src/components/charts/time-series-chart/time-series-chart.stories.tsx +140 -0
- package/src/components/charts/time-series-chart/time-series-chart.tsx +337 -0
- package/src/components/charts/tooltip-sync/index.ts +11 -0
- package/src/components/charts/tooltip-sync/tooltip-sync.stories.tsx +89 -0
- package/src/components/charts/tooltip-sync/tooltip-sync.tsx +91 -0
- package/src/components/charts/types.ts +93 -0
- package/src/components/charts/use-tooltip.ts +230 -0
- package/src/components/charts/utils.ts +69 -0
- package/src/components/charts/x-axis/index.ts +11 -0
- package/src/components/charts/x-axis/x-axis.stories.tsx +94 -0
- package/src/components/charts/x-axis/x-axis.tsx +176 -0
- package/src/components/charts/y-axis/index.ts +7 -0
- package/src/components/charts/y-axis/y-axis.stories.tsx +110 -0
- package/src/components/charts/y-axis/y-axis.tsx +139 -0
- package/src/components/elements/atoms/alert/alert.stories.tsx +234 -0
- package/src/components/elements/atoms/alert/alert.tsx +293 -0
- package/src/components/elements/atoms/alert/index.ts +7 -0
- package/src/components/elements/atoms/avatar/avatar.stories.tsx +174 -0
- package/src/components/elements/atoms/avatar/avatar.tsx +274 -0
- package/src/components/elements/atoms/avatar/index.ts +7 -0
- package/src/components/elements/atoms/badge/badge.stories.tsx +186 -0
- package/src/components/elements/atoms/badge/badge.tsx +333 -0
- package/src/components/elements/atoms/badge/index.ts +7 -0
- package/src/components/elements/atoms/blur-image/blur-image.stories.tsx +140 -0
- package/src/components/elements/atoms/blur-image/blur-image.tsx +102 -0
- package/src/components/elements/atoms/blur-image/index.ts +7 -0
- package/src/components/elements/atoms/button/button.stories.tsx +776 -0
- package/src/components/elements/atoms/button/button.tsx +878 -0
- package/src/components/elements/atoms/button/index.ts +7 -0
- package/src/components/elements/atoms/copy-button/copy-button.stories.tsx +162 -0
- package/src/components/elements/atoms/copy-button/copy-button.tsx +232 -0
- package/src/components/elements/atoms/copy-button/index.ts +7 -0
- package/src/components/elements/atoms/copy-text/copy-text.stories.tsx +128 -0
- package/src/components/elements/atoms/copy-text/copy-text.tsx +201 -0
- package/src/components/elements/atoms/copy-text/index.ts +7 -0
- package/src/components/elements/atoms/empty-state/empty-state.stories.tsx +410 -0
- package/src/components/elements/atoms/empty-state/empty-state.tsx +338 -0
- package/src/components/elements/atoms/empty-state/index.ts +1 -0
- package/src/components/elements/atoms/go-back-button/go-back-button.stories.tsx +83 -0
- package/src/components/elements/atoms/go-back-button/go-back-button.tsx +104 -0
- package/src/components/elements/atoms/go-back-button/index.ts +7 -0
- package/src/components/elements/atoms/inline-snippet/index.ts +7 -0
- package/src/components/elements/atoms/inline-snippet/inline-snippet.stories.tsx +130 -0
- package/src/components/elements/atoms/inline-snippet/inline-snippet.tsx +140 -0
- package/src/components/elements/atoms/loading-dots/index.ts +1 -0
- package/src/components/elements/atoms/loading-dots/loading-dots.stories.tsx +274 -0
- package/src/components/elements/atoms/loading-dots/loading-dots.tsx +138 -0
- package/src/components/elements/atoms/mode-toggle/index.ts +7 -0
- package/src/components/elements/atoms/mode-toggle/mode-toggle.stories.tsx +67 -0
- package/src/components/elements/atoms/mode-toggle/mode-toggle.tsx +163 -0
- package/src/components/elements/atoms/progress/index.ts +7 -0
- package/src/components/elements/atoms/progress/progress.stories.tsx +141 -0
- package/src/components/elements/atoms/progress/progress.tsx +314 -0
- package/src/components/elements/atoms/progress-circle/index.ts +7 -0
- package/src/components/elements/atoms/progress-circle/progress-circle.stories.tsx +185 -0
- package/src/components/elements/atoms/progress-circle/progress-circle.tsx +207 -0
- package/src/components/elements/atoms/separator/index.ts +7 -0
- package/src/components/elements/atoms/separator/separator.stories.tsx +154 -0
- package/src/components/elements/atoms/separator/separator.tsx +169 -0
- package/src/components/elements/atoms/skeleton/index.ts +7 -0
- package/src/components/elements/atoms/skeleton/skeleton.stories.tsx +152 -0
- package/src/components/elements/atoms/skeleton/skeleton.tsx +336 -0
- package/src/components/elements/atoms/slider/index.ts +7 -0
- package/src/components/elements/atoms/slider/slider.stories.tsx +199 -0
- package/src/components/elements/atoms/slider/slider.tsx +487 -0
- package/src/components/elements/atoms/sonner/index.ts +7 -0
- package/src/components/elements/atoms/sonner/sonner.stories.tsx +408 -0
- package/src/components/elements/atoms/sonner/sonner.tsx +131 -0
- package/src/components/elements/atoms/status-badge/index.ts +7 -0
- package/src/components/elements/atoms/status-badge/status-badge.stories.tsx +166 -0
- package/src/components/elements/atoms/status-badge/status-badge.tsx +262 -0
- package/src/components/elements/atoms/timestamp-tooltip/index.ts +7 -0
- package/src/components/elements/atoms/timestamp-tooltip/timestamp-tooltip.stories.tsx +127 -0
- package/src/components/elements/atoms/timestamp-tooltip/timestamp-tooltip.tsx +404 -0
- package/src/components/elements/molecules/animated-size-container/animated-size-container.stories.tsx +165 -0
- package/src/components/elements/molecules/animated-size-container/animated-size-container.tsx +125 -0
- package/src/components/elements/molecules/animated-size-container/index.ts +7 -0
- package/src/components/elements/molecules/avatar-stack/avatar-stack.stories.tsx +179 -0
- package/src/components/elements/molecules/avatar-stack/avatar-stack.tsx +258 -0
- package/src/components/elements/molecules/avatar-stack/index.ts +7 -0
- package/src/components/elements/molecules/breadcrumb/breadcrumb.stories.tsx +273 -0
- package/src/components/elements/molecules/breadcrumb/breadcrumb.tsx +299 -0
- package/src/components/elements/molecules/breadcrumb/index.ts +7 -0
- package/src/components/elements/molecules/button-group/button-group.stories.tsx +267 -0
- package/src/components/elements/molecules/button-group/button-group.tsx +244 -0
- package/src/components/elements/molecules/button-group/index.ts +7 -0
- package/src/components/elements/molecules/collapsible/collapsible.stories.tsx +186 -0
- package/src/components/elements/molecules/collapsible/collapsible.tsx +362 -0
- package/src/components/elements/molecules/collapsible/index.ts +7 -0
- package/src/components/elements/molecules/empty/empty.stories.tsx +182 -0
- package/src/components/elements/molecules/empty/empty.tsx +230 -0
- package/src/components/elements/molecules/empty/index.ts +7 -0
- package/src/components/elements/molecules/pagination-controls/index.ts +8 -0
- package/src/components/elements/molecules/pagination-controls/pagination-controls.stories.tsx +193 -0
- package/src/components/elements/molecules/pagination-controls/pagination-controls.tsx +174 -0
- package/src/components/elements/molecules/tab-select/index.ts +7 -0
- package/src/components/elements/molecules/tab-select/tab-select.stories.tsx +175 -0
- package/src/components/elements/molecules/tab-select/tab-select.tsx +261 -0
- package/src/components/elements/molecules/tabs/index.ts +7 -0
- package/src/components/elements/molecules/tabs/tabs.stories.tsx +198 -0
- package/src/components/elements/molecules/tabs/tabs.tsx +744 -0
- package/src/components/elements/molecules/toggle-group/index.ts +7 -0
- package/src/components/elements/molecules/toggle-group/toggle-group.stories.tsx +201 -0
- package/src/components/elements/molecules/toggle-group/toggle-group.tsx +236 -0
- package/src/components/elements/organisms/accordion/accordion.stories.tsx +217 -0
- package/src/components/elements/organisms/accordion/accordion.tsx +456 -0
- package/src/components/elements/organisms/accordion/index.ts +7 -0
- package/src/components/elements/organisms/card/card.stories.tsx +406 -0
- package/src/components/elements/organisms/card/card.tsx +437 -0
- package/src/components/elements/organisms/card/index.ts +8 -0
- package/src/components/elements/organisms/card/integration-card.stories.tsx +348 -0
- package/src/components/elements/organisms/card/integration-compact.stories.tsx +310 -0
- package/src/components/elements/organisms/card/integrations.tsx +356 -0
- package/src/components/elements/organisms/carousel/carousel.stories.tsx +182 -0
- package/src/components/elements/organisms/carousel/carousel.tsx +537 -0
- package/src/components/elements/organisms/carousel/index.ts +7 -0
- package/src/components/elements/organisms/chart/chart.stories.tsx +147 -0
- package/src/components/elements/organisms/chart/chart.tsx +317 -0
- package/src/components/elements/organisms/chart/index.ts +7 -0
- package/src/components/elements/organisms/command/command.stories.tsx +246 -0
- package/src/components/elements/organisms/command/command.tsx +284 -0
- package/src/components/elements/organisms/command/index.ts +7 -0
- package/src/components/elements/organisms/dialog/dialog.stories.tsx +266 -0
- package/src/components/elements/organisms/dialog/dialog.tsx +366 -0
- package/src/components/elements/organisms/dialog/index.ts +7 -0
- package/src/components/elements/organisms/dropdown-menu/dropdown-menu.stories.tsx +334 -0
- package/src/components/elements/organisms/dropdown-menu/dropdown-menu.tsx +611 -0
- package/src/components/elements/organisms/dropdown-menu/index.ts +7 -0
- package/src/components/elements/organisms/dynamic-breadcrumb/dynamic-breadcrumb.stories.tsx +50 -0
- package/src/components/elements/organisms/dynamic-breadcrumb/dynamic-breadcrumb.tsx +257 -0
- package/src/components/elements/organisms/dynamic-breadcrumb/index.ts +7 -0
- package/src/components/elements/organisms/error-boundary/error-boundary.stories.tsx +142 -0
- package/src/components/elements/organisms/error-boundary/error-boundary.tsx +408 -0
- package/src/components/elements/organisms/error-boundary/index.ts +7 -0
- package/src/components/elements/organisms/hover-card/hover-card.stories.tsx +245 -0
- package/src/components/elements/organisms/hover-card/hover-card.tsx +370 -0
- package/src/components/elements/organisms/hover-card/index.ts +7 -0
- package/src/components/elements/organisms/modal/index.ts +7 -0
- package/src/components/elements/organisms/modal/modal.stories.tsx +189 -0
- package/src/components/elements/organisms/modal/modal.tsx +266 -0
- package/src/components/elements/organisms/popover/index.ts +7 -0
- package/src/components/elements/organisms/popover/popover.stories.tsx +200 -0
- package/src/components/elements/organisms/popover/popover.tsx +302 -0
- package/src/components/elements/organisms/resizable/index.ts +7 -0
- package/src/components/elements/organisms/resizable/resizable.stories.tsx +204 -0
- package/src/components/elements/organisms/resizable/resizable.tsx +178 -0
- package/src/components/elements/organisms/scroll-area/index.ts +7 -0
- package/src/components/elements/organisms/scroll-area/scroll-area.stories.tsx +170 -0
- package/src/components/elements/organisms/scroll-area/scroll-area.tsx +167 -0
- package/src/components/elements/organisms/sheet/index.ts +7 -0
- package/src/components/elements/organisms/sheet/sheet.stories.tsx +235 -0
- package/src/components/elements/organisms/sheet/sheet.tsx +381 -0
- package/src/components/elements/organisms/table/index.ts +7 -0
- package/src/components/elements/organisms/table/table.stories.tsx +238 -0
- package/src/components/elements/organisms/table/table.tsx +392 -0
- package/src/components/elements/organisms/tooltip/index.ts +7 -0
- package/src/components/elements/organisms/tooltip/tooltip.stories.tsx +205 -0
- package/src/components/elements/organisms/tooltip/tooltip.tsx +547 -0
- package/src/components/filter/filter-list/filter-list.stories.tsx +157 -0
- package/src/components/filter/filter-list/filter-list.tsx +435 -0
- package/src/components/filter/filter-list/index.ts +7 -0
- package/src/components/filter/filter-select/filter-select.stories.tsx +124 -0
- package/src/components/filter/filter-select/filter-select.tsx +558 -0
- package/src/components/filter/filter-select/index.ts +7 -0
- package/src/components/filter/index.ts +9 -0
- package/src/components/filter/types.ts +70 -0
- package/src/components/forms/checkbox/checkbox.stories.tsx +177 -0
- package/src/components/forms/checkbox/checkbox.tsx +332 -0
- package/src/components/forms/checkbox/index.ts +11 -0
- package/src/components/forms/combobox/combobox.stories.tsx +224 -0
- package/src/components/forms/combobox/combobox.tsx +679 -0
- package/src/components/forms/combobox/index.ts +7 -0
- package/src/components/forms/date-picker/calendar/calendar.stories.tsx +78 -0
- package/src/components/forms/date-picker/calendar/calendar.tsx +271 -0
- package/src/components/forms/date-picker/calendar/index.ts +7 -0
- package/src/components/forms/date-picker/date-range-picker/date-range-picker.stories.tsx +108 -0
- package/src/components/forms/date-picker/date-range-picker/date-range-picker.tsx +334 -0
- package/src/components/forms/date-picker/date-range-picker/index.ts +7 -0
- package/src/components/forms/date-picker/index.ts +10 -0
- package/src/components/forms/date-picker/presets/index.ts +7 -0
- package/src/components/forms/date-picker/presets/presets.stories.tsx +105 -0
- package/src/components/forms/date-picker/presets/presets.tsx +196 -0
- package/src/components/forms/date-picker/shared.ts +109 -0
- package/src/components/forms/date-picker/trigger/index.ts +7 -0
- package/src/components/forms/date-picker/trigger/trigger.stories.tsx +78 -0
- package/src/components/forms/date-picker/trigger/trigger.tsx +195 -0
- package/src/components/forms/date-picker/types.ts +63 -0
- package/src/components/forms/file-upload/file-upload.stories.tsx +145 -0
- package/src/components/forms/file-upload/file-upload.tsx +504 -0
- package/src/components/forms/file-upload/index.ts +7 -0
- package/src/components/forms/input/index.ts +7 -0
- package/src/components/forms/input/input.stories.tsx +185 -0
- package/src/components/forms/input/input.tsx +228 -0
- package/src/components/forms/input-group/index.ts +11 -0
- package/src/components/forms/input-group/input-group.stories.tsx +146 -0
- package/src/components/forms/input-group/input-group.tsx +344 -0
- package/src/components/forms/label/index.ts +7 -0
- package/src/components/forms/label/label.stories.tsx +140 -0
- package/src/components/forms/label/label.tsx +189 -0
- package/src/components/forms/radio-group/index.ts +7 -0
- package/src/components/forms/radio-group/radio-group.stories.tsx +233 -0
- package/src/components/forms/radio-group/radio-group.tsx +476 -0
- package/src/components/forms/select/index.ts +7 -0
- package/src/components/forms/select/select.stories.tsx +274 -0
- package/src/components/forms/select/select.tsx +654 -0
- package/src/components/forms/switch/index.ts +11 -0
- package/src/components/forms/switch/switch.stories.tsx +166 -0
- package/src/components/forms/switch/switch.tsx +362 -0
- package/src/components/forms/textarea/index.ts +7 -0
- package/src/components/forms/textarea/textarea.stories.tsx +176 -0
- package/src/components/forms/textarea/textarea.tsx +225 -0
- package/src/components/layout/app-shell.tsx +363 -0
- package/src/components/layout/app-sidebar/app-sidebar.stories.tsx +68 -0
- package/src/components/layout/app-sidebar/app-sidebar.tsx +418 -0
- package/src/components/layout/app-sidebar/index.ts +11 -0
- package/src/components/layout/artifact-panel/artifact-panel-header.tsx +89 -0
- package/src/components/layout/artifact-panel/expandable-panel.stories.tsx +484 -0
- package/src/components/layout/artifact-panel/expandable-panel.tsx +289 -0
- package/src/components/layout/artifact-panel/index.ts +23 -0
- package/src/components/layout/artifact-panel/split-panel-layout.tsx +70 -0
- package/src/components/layout/artifact-panel/types.ts +63 -0
- package/src/components/layout/artifact-panel/use-artifact-panel-state.ts +101 -0
- package/src/components/layout/content-sidebar/content-sidebar.stories.tsx +490 -0
- package/src/components/layout/content-sidebar/content-sidebar.tsx +337 -0
- package/src/components/layout/content-sidebar/index.ts +17 -0
- package/src/components/layout/nav-app-switcher/index.ts +7 -0
- package/src/components/layout/nav-app-switcher/nav-app-switcher.stories.tsx +138 -0
- package/src/components/layout/nav-app-switcher/nav-app-switcher.tsx +282 -0
- package/src/components/layout/nav-main/index.ts +11 -0
- package/src/components/layout/nav-main/nav-main.stories.tsx +103 -0
- package/src/components/layout/nav-main/nav-main.tsx +259 -0
- package/src/components/layout/nav-projects/index.ts +11 -0
- package/src/components/layout/nav-projects/nav-projects.stories.tsx +82 -0
- package/src/components/layout/nav-projects/nav-projects.tsx +218 -0
- package/src/components/layout/nav-secondary/index.ts +11 -0
- package/src/components/layout/nav-secondary/nav-secondary.stories.tsx +81 -0
- package/src/components/layout/nav-secondary/nav-secondary.tsx +145 -0
- package/src/components/layout/nav-user/index.ts +11 -0
- package/src/components/layout/nav-user/nav-user.stories.tsx +80 -0
- package/src/components/layout/nav-user/nav-user.tsx +226 -0
- package/src/components/layout/oneapp/auth-context.tsx +74 -0
- package/src/components/layout/oneapp/ensure-anonymous-session.tsx +218 -0
- package/src/components/layout/oneapp/index.ts +37 -0
- package/src/components/layout/oneapp/microfrontend-layout.tsx +191 -0
- package/src/components/layout/oneapp/types.ts +98 -0
- package/src/components/layout/sidebar/index.ts +7 -0
- package/src/components/layout/sidebar/sidebar.stories.tsx +170 -0
- package/src/components/layout/sidebar/sidebar.tsx +945 -0
- package/src/components/layout/sidebar-inset-header-portal/index.ts +8 -0
- package/src/components/layout/sidebar-inset-header-portal/sidebar-inset-header-portal.stories.tsx +355 -0
- package/src/components/layout/sidebar-inset-header-portal/sidebar-inset-header-portal.tsx +179 -0
- package/src/components/layout/sidebar-slots/USAGE.md +163 -0
- package/src/components/layout/sidebar-slots/__tests__/sidebar-slots.test.tsx +239 -0
- package/src/components/layout/sidebar-slots/index.ts +9 -0
- package/src/components/layout/sidebar-slots/sidebar-slots.stories.tsx +525 -0
- package/src/components/layout/sidebar-slots/sidebar-slots.tsx +205 -0
- package/src/components/layout/theme-provider/index.ts +11 -0
- package/src/components/layout/theme-provider/theme-provider.stories.tsx +82 -0
- package/src/components/layout/theme-provider/theme-provider.tsx +101 -0
- package/src/components/overlays/confirm-dialog.stories.tsx +371 -0
- package/src/components/overlays/confirm-dialog.tsx +201 -0
- package/src/components/overlays/toast.stories.tsx +373 -0
- package/src/components/overlays/toast.tsx +115 -0
- package/src/constants/container.ts +183 -0
- package/src/constants/index.ts +38 -0
- package/src/constants/motion.ts +104 -0
- package/src/fonts/Satoshi-Variable.woff2 +0 -0
- package/src/fonts/Satoshi-VariableItalic.woff2 +0 -0
- package/src/fonts/fonts.css +41 -0
- package/src/fonts/index.ts +106 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/ai-chat/context.tsx +294 -0
- package/src/hooks/ai-chat/hooks.ts +297 -0
- package/src/hooks/ai-chat/index.ts +35 -0
- package/src/hooks/ai-chat/utils.ts +65 -0
- package/src/hooks/index.ts +18 -0
- package/src/hooks/use-mobile.ts +45 -0
- package/src/hooks/use-responsive.ts +64 -0
- package/src/hooks/use-scroll-progress.ts +101 -0
- package/src/hooks/use-toast.ts +65 -0
- package/src/index.ts +857 -0
- package/src/lib/export-csv.ts +107 -0
- package/src/lib/index.ts +10 -0
- package/src/lib/resize-image.ts +109 -0
- package/src/lib/stable-sort.ts +29 -0
- package/src/lib/utils.ts +28 -0
- package/src/react-19-compat.d.ts +28 -0
- package/src/shared/auth/index.ts +8 -0
- package/src/shared/auth/types/index.ts +163 -0
- package/src/shared/auth/types.ts +196 -0
- package/src/shared/auth/utils/dark-mode.ts +336 -0
- package/src/shared/index.ts +5 -0
- package/src/styles/_tokens.generated.scss +84 -0
- package/src/styles/ai-elements.scss +9 -0
- package/src/styles/base.scss +44 -0
- package/src/styles/flows.scss +62 -0
- package/src/styles/globals.css +627 -0
- package/src/styles/index.scss +9 -0
- package/src/styles/shadcn.scss +16 -0
- package/src/styles/sources.css +16 -0
- package/src/styles/theme.css +1687 -0
- package/src/styles/theme.template.css +95 -0
- package/src/tokens/accessibility.ts +494 -0
- package/src/tokens/animations.ts +305 -0
- package/src/tokens/aspect-ratio.ts +89 -0
- package/src/tokens/blur.ts +82 -0
- package/src/tokens/border-width.ts +86 -0
- package/src/tokens/breakpoints.ts +150 -0
- package/src/tokens/colors.ts +1199 -0
- package/src/tokens/component.ts +362 -0
- package/src/tokens/container.ts +42 -0
- package/src/tokens/focus.ts +266 -0
- package/src/tokens/form-states.ts +521 -0
- package/src/tokens/grid.ts +258 -0
- package/src/tokens/index.ts +1175 -0
- package/src/tokens/interactions.ts +558 -0
- package/src/tokens/mantine-types.ts +68 -0
- package/src/tokens/opacity.ts +139 -0
- package/src/tokens/palette.ts +854 -0
- package/src/tokens/pseudo-elements.ts +508 -0
- package/src/tokens/radius.ts +57 -0
- package/src/tokens/shadows.ts +313 -0
- package/src/tokens/spacing.ts +95 -0
- package/src/tokens/states.ts +392 -0
- package/src/tokens/structural.ts +589 -0
- package/src/tokens/timing.ts +224 -0
- package/src/tokens/typography.ts +242 -0
- package/src/tokens/z-index.ts +184 -0
- package/storybook/preview.tsx +201 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/ai-elements/custom/ai-label/ai-label.tsx","../../../src/components/ai-elements/custom/feedback/feedback.tsx","../../../src/components/ai-elements/custom/message-error/message-error.tsx","../../../src/components/ai-elements/custom/conversation-history/conversation-history.tsx","../../../src/components/ai-elements/custom/chat-container/chat-container.tsx","../../../src/components/ai-elements/custom/message-edit/message-edit.tsx","../../../src/components/ai-elements/custom/typing-indicator/typing-indicator.tsx","../../../src/components/ai-elements/custom/export-conversation/export-conversation.tsx","../../../src/components/ai-elements/custom/content-placeholder/content-placeholder.tsx","../../../src/components/ai-elements/custom/token-usage/token-usage.tsx","../../../src/components/ai-elements/custom/message-group/message-group.tsx","../../../src/components/ai-elements/custom/message-separator/message-separator.tsx","../../../src/components/ai-elements/custom/conversation-header/conversation-header.tsx","../../../src/components/ai-elements/custom/welcome/welcome.tsx","../../../src/components/ai-elements/custom/file-card/file-card.tsx","../../../src/components/ai-elements/custom/file-tree/file-tree.tsx","../../../src/components/ai-elements/custom/terminal/terminal.tsx","../../../src/components/ai-elements/custom/stack-trace/stack-trace.tsx","../../../src/components/ai-elements/custom/snippet/snippet.tsx","../../../src/components/ai-elements/custom/audio-player/audio-player.tsx","../../../src/components/ai-elements/custom/transcription/transcription.tsx","../../../src/components/ai-elements/custom/voice-selector/voice-selector.tsx","../../../src/components/ai-elements/custom/thought-chain/thought-chain.tsx","../../../src/components/ai-elements/custom/scroll-to-bottom/use-scroll-to-bottom.tsx","../../../src/components/ai-elements/custom/undo-redo/use-undo-redo.tsx","../../../src/components/ai-elements/custom/collapsible/use-collapsible.tsx","../../../src/components/ai-elements/custom/keyboard-shortcut/keyboard-shortcut.tsx","../../../src/components/ai-elements/custom/collapsible-content/collapsible-content.tsx","../../../src/components/ai-elements/custom/diff-view/diff-view.tsx","../../../src/components/ai-elements/custom/artifact-skeleton/artifact-skeleton.tsx","../../../src/components/ai-elements/custom/export-dropdown/export-dropdown.tsx","../../../src/components/ai-elements/custom/draggable-tabs/draggable-tabs.tsx"],"sourcesContent":["/**\n * @fileoverview AILabel Component - Premium Harmony V2\n *\n * A persistent indicator that content is AI-generated, with an optional\n * explainability popover showing model name, confidence, and metadata.\n * Inspired by IBM Carbon for AI's AI Label pattern.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Semantic color tokens\n * - Popover with explainability layer\n * - Variants: inline, floating, attached\n * - Sparkle icon convention (AWS Cloudscape)\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/ai-label\n * @component AILabel, AILabelPopover\n *\n * @useCases\n * - Mark AI-generated messages, artifacts, or code blocks\n * - Provide first-layer explainability (model, timestamp, confidence)\n * - Trust indicator for enterprise AI interfaces\n * - Distinguish AI content from human content (accessibility requirement)\n *\n * @example\n * <AILabel />\n * <AILabel variant=\"floating\" model=\"GPT-4o\" />\n * <AILabel variant=\"inline\" showPopover model=\"Claude\" confidence={0.95} />\n */\n\n'use client';\n\nimport { createContext, useCallback, useId, useMemo } from 'react';\n\nimport { useClickOutside, useDisclosure, useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport { SparklesIcon } from 'lucide-react';\nimport { AnimatePresence, motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_FLUID,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\ntype AILabelContextValue = {\n open: boolean;\n toggle: () => void;\n close: () => void;\n};\n\nconst AILabelContext = createContext<AILabelContextValue | null>(null);\n\nexport type AILabelVariant = 'inline' | 'floating' | 'attached';\n\n/** Positional class names for each AILabel variant (module-level constant). */\nconst VARIANT_STYLES: Record<AILabelVariant, string> = {\n inline: 'inline-flex',\n floating: 'absolute top-2 right-2',\n attached: 'absolute -top-2 -right-2',\n};\n\nexport type AILabelProps = Omit<HTMLMotionProps<'div'>, 'children'> & {\n /** Display variant */\n variant?: AILabelVariant;\n /** AI model name */\n model?: string;\n /** Confidence score (0-1) */\n confidence?: number;\n /** Generation timestamp */\n timestamp?: Date;\n /** Show explainability popover on click */\n showPopover?: boolean;\n /** Custom label text */\n label?: string;\n /** Optional popover content */\n children?: React.ReactNode;\n};\n\nexport const AILabel = ({\n className,\n variant = 'inline',\n model,\n confidence,\n timestamp,\n showPopover = false,\n label = 'AI',\n children,\n ...props\n}: AILabelProps) => {\n const [opened, { toggle, close }] = useDisclosure(false);\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n const ref = useClickOutside(() => close());\n const popoverId = useId();\n const popoverTitleId = useId();\n\n const contextValue = useMemo(() => ({ open: opened, toggle, close }), [opened, toggle, close]);\n\n const entryVariants = useMemo(\n () => ({\n initial: { opacity: reducedMotion ? 1 : 0, scale: reducedMotion ? 1 : 0.9 },\n animate: { opacity: 1, scale: 1 },\n }),\n [reducedMotion],\n );\n\n const handleClick = useCallback(() => {\n if (showPopover) toggle();\n }, [showPopover, toggle]);\n\n return (\n <AILabelContext.Provider value={contextValue}>\n <motion.div\n ref={ref}\n className={cn('relative z-10', VARIANT_STYLES[variant], className)}\n variants={entryVariants}\n initial=\"initial\"\n animate=\"animate\"\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"AILabel\"\n data-variant={variant}\n {...props}\n >\n <motion.button\n type=\"button\"\n onClick={handleClick}\n className={cn(\n 'bg-primary/10 text-primary border-primary/20 inline-flex items-center rounded-full border px-2 py-0.5',\n AI_TEXT.xs,\n AI_SPACING.xs,\n AI_TRANSITION.colors,\n 'duration-150',\n AI_FOCUS.ring,\n showPopover && 'hover:bg-primary/15 cursor-pointer',\n !showPopover && 'cursor-default',\n isTouchDevice && 'min-h-11 min-w-11',\n )}\n whileHover={\n showPopover && !reducedMotion ? { scale: 1.03, transition: SPRING_TACTILE } : undefined\n }\n whileTap={\n showPopover && !reducedMotion ? { scale: 0.97, transition: SPRING_TACTILE } : undefined\n }\n aria-label={`AI generated${model ? ` by ${model}` : ''}`}\n aria-expanded={showPopover ? opened : undefined}\n aria-controls={showPopover ? popoverId : undefined}\n data-state={opened ? 'open' : 'closed'}\n >\n <SparklesIcon className={AI_ICON.sm} aria-hidden />\n <span className=\"font-medium\">{label}</span>\n </motion.button>\n\n {showPopover ? (\n <AnimatePresence mode=\"wait\">\n {opened ? (\n <AILabelPopover\n id={popoverId}\n aria-labelledby={popoverTitleId}\n model={model}\n confidence={confidence}\n timestamp={timestamp}\n titleId={popoverTitleId}\n >\n {children}\n </AILabelPopover>\n ) : null}\n </AnimatePresence>\n ) : null}\n </motion.div>\n </AILabelContext.Provider>\n );\n};\n\nexport type AILabelPopoverProps = Omit<HTMLMotionProps<'div'>, 'children'> & {\n model?: string;\n confidence?: number;\n timestamp?: Date;\n /** ID to apply to the popover title element for aria-labelledby */\n titleId?: string;\n children?: React.ReactNode;\n};\n\nexport const AILabelPopover = ({\n className,\n model,\n confidence,\n timestamp,\n titleId,\n children,\n ...props\n}: AILabelPopoverProps) => {\n const reducedMotion = useReducedMotion();\n\n const popoverVariants = useMemo(\n () => ({\n hidden: { opacity: 0, scale: 0.95, y: -4 },\n visible: {\n opacity: 1,\n scale: 1,\n y: 0,\n transition: reducedMotion ? { duration: 0 } : SPRING_GENTLE,\n },\n exit: {\n opacity: 0,\n scale: 0.95,\n y: -4,\n transition: reducedMotion ? { duration: 0 } : SPRING_FLUID,\n },\n }),\n [reducedMotion],\n );\n\n const formattedConfidence =\n confidence !== undefined && Number.isFinite(confidence)\n ? `${Math.round(Math.min(1, Math.max(0, confidence)) * 100)}%`\n : undefined;\n let formattedTime: string | undefined;\n try {\n formattedTime = timestamp\n ? new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(timestamp)\n : undefined;\n } catch {\n // Invalid Date object -- fallback to undefined so no time is displayed\n formattedTime = undefined;\n }\n\n return (\n <motion.div\n className={cn(\n 'border-border/60 bg-popover/95 absolute top-full right-0 z-20 mt-1 w-64 rounded-xl border p-3 shadow-lg backdrop-blur',\n className,\n )}\n variants={popoverVariants}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n data-component=\"AILabelPopover\"\n role=\"dialog\"\n aria-labelledby={titleId}\n aria-label={titleId ? undefined : 'AI generation details'}\n {...props}\n >\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <SparklesIcon className={cn('text-primary', AI_ICON.md)} aria-hidden />\n <span id={titleId} className=\"text-foreground text-sm font-medium\">\n AI Generated\n </span>\n </div>\n\n {model || formattedConfidence || formattedTime ? (\n <dl className=\"text-muted-foreground space-y-1 text-xs\">\n {model ? (\n <div className=\"flex justify-between\">\n <dt className=\"font-medium\">Model</dt>\n <dd>{model}</dd>\n </div>\n ) : null}\n {formattedConfidence ? (\n <div className=\"flex justify-between\">\n <dt className=\"font-medium\">Confidence</dt>\n <dd>{formattedConfidence}</dd>\n </div>\n ) : null}\n {formattedTime ? (\n <div className=\"flex justify-between\">\n <dt className=\"font-medium\">Generated</dt>\n <dd>{formattedTime}</dd>\n </div>\n ) : null}\n </dl>\n ) : null}\n\n {children ? <div className=\"border-border/50 border-t pt-2\">{children}</div> : null}\n </div>\n </motion.div>\n );\n};\n\nAILabel.displayName = 'AILabel';\nAILabelPopover.displayName = 'AILabelPopover';\n","/**\n * @fileoverview Feedback Component - Premium Harmony V2\n *\n * Components for collecting user feedback on AI-generated content.\n * Provides thumbs up/down with visual persistence, follow-up dialog,\n * and confirmation states. Inspired by AWS Cloudscape GenAI feedback pattern.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Persistent visual state after feedback\n * - Follow-up dialog on negative feedback\n * - Confirmation message after submission\n * - Keyboard accessible\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/feedback\n * @component Feedback, FeedbackButton, FeedbackDialog, FeedbackConfirmation\n *\n * @useCases\n * - Thumbs up/down on AI responses\n * - Collecting detailed negative feedback (irrelevant, incorrect, harmful)\n * - Showing submission confirmation\n * - Enterprise feedback collection for model improvement\n *\n * @example\n * <Feedback\n * onFeedback={handleFeedback}\n * onDetailedFeedback={handleDetailed}\n * />\n */\n\n'use client';\n\nimport type { ComponentProps, KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport { CheckIcon, ThumbsDownIcon, ThumbsUpIcon } from 'lucide-react';\nimport { AnimatePresence, motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_FLUID,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\nexport type FeedbackValue = 'positive' | 'negative' | null;\n\nexport type FeedbackReason =\n | 'irrelevant'\n | 'incorrect'\n | 'incomplete'\n | 'harmful'\n | 'too_verbose'\n | 'other';\n\nexport type DetailedFeedback = {\n value: FeedbackValue;\n reasons?: FeedbackReason[];\n comment?: string;\n};\n\ntype FeedbackContextValue = {\n feedback: FeedbackValue;\n setFeedback: (value: FeedbackValue) => void;\n showDialog: boolean;\n setShowDialog: (show: boolean) => void;\n submitted: boolean;\n setSubmitted: (submitted: boolean) => void;\n};\n\nconst FeedbackContext = createContext<FeedbackContextValue | null>(null);\n\nconst useFeedbackContext = () => {\n const ctx = useContext(FeedbackContext);\n if (!ctx) throw new Error('Feedback subcomponents must be used within Feedback');\n return ctx;\n};\n\nexport type FeedbackProps = Omit<ComponentProps<'div'>, 'defaultValue' | 'value'> & {\n /** Callback when basic feedback is given */\n onFeedback?: (value: FeedbackValue) => void;\n /** Callback when detailed feedback is submitted */\n onDetailedFeedback?: (feedback: DetailedFeedback) => void;\n /** Controlled feedback value */\n value?: FeedbackValue;\n /** Default feedback value */\n defaultValue?: FeedbackValue;\n /** Whether to show detailed feedback dialog on thumbs down */\n showDetailedOnNegative?: boolean;\n};\n\nexport const Feedback = ({\n className,\n onFeedback,\n onDetailedFeedback,\n value: controlledValue,\n defaultValue = null,\n showDetailedOnNegative = true,\n children,\n ...props\n}: FeedbackProps) => {\n const [internalValue, setInternalValue] = useState<FeedbackValue>(defaultValue);\n const [showDialog, setShowDialog] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n\n const feedback = controlledValue !== undefined ? controlledValue : internalValue;\n\n const setFeedback = useCallback(\n (newValue: FeedbackValue) => {\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onFeedback?.(newValue);\n\n if (newValue === 'negative' && showDetailedOnNegative) {\n setShowDialog(true);\n } else if (newValue === 'positive') {\n setSubmitted(true);\n }\n },\n [controlledValue, onFeedback, showDetailedOnNegative],\n );\n\n const handleDialogSubmit = useCallback(\n (reasons: FeedbackReason[], comment?: string) => {\n onDetailedFeedback?.({ value: 'negative', reasons, comment });\n setShowDialog(false);\n setSubmitted(true);\n },\n [onDetailedFeedback],\n );\n\n const handleDialogDismiss = useCallback(() => {\n setShowDialog(false);\n }, []);\n\n const contextValue = useMemo(\n () => ({ feedback, setFeedback, showDialog, setShowDialog, submitted, setSubmitted }),\n [feedback, setFeedback, showDialog, setShowDialog, submitted, setSubmitted],\n );\n\n return (\n <FeedbackContext.Provider value={contextValue}>\n <div\n className={cn('flex items-center', AI_SPACING.xs, className)}\n data-component=\"Feedback\"\n data-state={feedback ?? 'none'}\n role=\"group\"\n aria-label=\"Rate this response\"\n {...props}\n >\n {children ?? (\n <>\n <FeedbackButton feedbackType=\"positive\" />\n <FeedbackButton feedbackType=\"negative\" />\n <AnimatePresence mode=\"wait\">\n {submitted ? <FeedbackConfirmation key=\"confirmation\" /> : null}\n </AnimatePresence>\n </>\n )}\n </div>\n\n <AnimatePresence mode=\"wait\">\n {showDialog ? (\n <FeedbackDialog\n key=\"dialog\"\n onSubmit={handleDialogSubmit}\n onDismiss={handleDialogDismiss}\n />\n ) : null}\n </AnimatePresence>\n </FeedbackContext.Provider>\n );\n};\n\nexport type FeedbackButtonProps = Omit<ComponentProps<typeof Button>, 'type'> & {\n /** Whether this button represents positive or negative feedback */\n feedbackType: 'positive' | 'negative';\n};\n\nexport const FeedbackButton = ({ feedbackType, className, ...props }: FeedbackButtonProps) => {\n const { feedback, setFeedback } = useFeedbackContext();\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n const isActive = feedback === feedbackType;\n const Icon = feedbackType === 'positive' ? ThumbsUpIcon : ThumbsDownIcon;\n\n const handleClick = useCallback(() => {\n setFeedback(isActive ? null : feedbackType);\n }, [isActive, feedbackType, setFeedback]);\n\n return (\n <motion.div\n whileHover={\n !reducedMotion && !isTouchDevice ? { scale: 1.05, transition: SPRING_TACTILE } : undefined\n }\n whileTap={!reducedMotion ? { scale: 0.95, transition: SPRING_TACTILE } : undefined}\n >\n <Button\n {...props}\n className={cn(\n 'min-h-11 min-w-11 p-0',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n isActive &&\n feedbackType === 'positive' &&\n 'text-success bg-success/10 hover:bg-success/15',\n isActive &&\n feedbackType === 'negative' &&\n 'text-destructive bg-destructive/10 hover:bg-destructive/15',\n !isActive && 'text-muted-foreground hover:text-foreground',\n className,\n )}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={handleClick}\n aria-label={feedbackType === 'positive' ? 'Helpful' : 'Not helpful'}\n aria-pressed={isActive}\n data-state={isActive ? 'active' : 'inactive'}\n data-feedback-type={feedbackType}\n >\n <Icon className={cn(AI_ICON.md, isActive && 'fill-current')} />\n </Button>\n </motion.div>\n );\n};\n\nexport type FeedbackConfirmationProps = Omit<HTMLMotionProps<'div'>, 'ref'>;\n\nexport const FeedbackConfirmation = ({ className, ...props }: FeedbackConfirmationProps) => {\n const reducedMotion = useReducedMotion();\n\n return (\n <motion.div\n className={cn('text-muted-foreground flex items-center gap-1', AI_TEXT.xs, className)}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, x: -8 }}\n animate={{ opacity: 1, x: 0 }}\n exit={reducedMotion ? { opacity: 0 } : { opacity: 0, x: -8 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"FeedbackConfirmation\"\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n <CheckIcon className={cn('text-success', AI_ICON.sm)} aria-hidden />\n <span>Thanks for your feedback</span>\n </motion.div>\n );\n};\n\nconst FEEDBACK_REASONS: { value: FeedbackReason; label: string }[] = [\n { value: 'irrelevant', label: \"Doesn't match my question\" },\n { value: 'incorrect', label: 'Contains incorrect information' },\n { value: 'incomplete', label: 'Missing important details' },\n { value: 'harmful', label: 'Contains harmful content' },\n { value: 'too_verbose', label: 'Too long or verbose' },\n { value: 'other', label: 'Other' },\n];\n\nexport type FeedbackDialogProps = Omit<HTMLMotionProps<'div'>, 'ref' | 'onSubmit'> & {\n onSubmit: (reasons: FeedbackReason[], comment?: string) => void;\n onDismiss: () => void;\n};\n\nexport const FeedbackDialog = ({\n className,\n onSubmit,\n onDismiss,\n ...props\n}: FeedbackDialogProps) => {\n const [selectedReasons, setSelectedReasons] = useState<FeedbackReason[]>([]);\n const [comment, setComment] = useState('');\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const toggleReason = useCallback((reason: FeedbackReason) => {\n setSelectedReasons(prev =>\n prev.includes(reason) ? prev.filter(r => r !== reason) : [...prev, reason],\n );\n }, []);\n\n const handleSubmit = useCallback(() => {\n onSubmit(selectedReasons, comment || undefined);\n }, [onSubmit, selectedReasons, comment]);\n\n const handleKeyDown = useCallback(\n (e: ReactKeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onDismiss();\n } else if (e.key === 'Tab') {\n // Basic focus trap: cycle between focusable elements\n const container = containerRef.current;\n if (!container) return;\n\n const focusableElements = container.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), textarea:not([disabled])',\n );\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement?.focus();\n } else if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement?.focus();\n }\n }\n },\n [onDismiss],\n );\n\n // Auto-focus textarea when dialog opens\n useEffect(() => {\n textareaRef.current?.focus();\n }, []);\n\n return (\n <motion.div\n ref={containerRef}\n className={cn(\n 'border-border bg-popover mt-2 w-full max-w-sm rounded-xl border p-4 shadow-lg',\n className,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: -8, scale: 0.98 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={reducedMotion ? { opacity: 0 } : { opacity: 0, y: -8, scale: 0.98 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_FLUID}\n data-component=\"FeedbackDialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Tell us more about this response\"\n onKeyDown={handleKeyDown}\n {...props}\n >\n <div className=\"space-y-3\">\n <p className={cn('text-foreground font-medium', AI_TEXT.sm)}>What went wrong?</p>\n\n <div className=\"flex flex-wrap gap-2\">\n {FEEDBACK_REASONS.map(({ value, label }) => {\n const isSelected = selectedReasons.includes(value);\n return (\n <button\n key={value}\n type=\"button\"\n onClick={() => toggleReason(value)}\n className={cn(\n 'rounded-full border px-3 py-1.5',\n AI_TEXT.xs,\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n isTouchDevice && 'min-h-11',\n isSelected\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border text-muted-foreground hover:border-foreground/30 hover:text-foreground',\n )}\n aria-pressed={isSelected}\n data-state={isSelected ? 'selected' : 'unselected'}\n >\n {label}\n </button>\n );\n })}\n </div>\n\n <textarea\n ref={textareaRef}\n className={cn(\n 'border-border bg-background text-foreground placeholder:text-muted-foreground w-full resize-none rounded-lg border p-2',\n AI_TEXT.sm,\n AI_FOCUS.ring,\n )}\n rows={2}\n maxLength={1000}\n placeholder=\"Additional comments (optional)\"\n aria-label=\"Additional comments\"\n value={comment}\n onChange={e => setComment(e.target.value)}\n />\n\n <div className=\"flex justify-end gap-2\">\n <Button size=\"sm\" variant=\"ghost\" type=\"button\" onClick={onDismiss}>\n Cancel\n </Button>\n <Button\n size=\"sm\"\n variant=\"default\"\n type=\"button\"\n onClick={handleSubmit}\n disabled={selectedReasons.length === 0 && !comment}\n >\n Submit\n </Button>\n </div>\n </div>\n </motion.div>\n );\n};\n\nFeedback.displayName = 'Feedback';\nFeedbackButton.displayName = 'FeedbackButton';\nFeedbackConfirmation.displayName = 'FeedbackConfirmation';\nFeedbackDialog.displayName = 'FeedbackDialog';\n","/**\n * @fileoverview MessageError & ConversationError Components - Premium Harmony V2\n *\n * Error recovery components for AI chat interfaces. Displays inline error\n * alerts with categorized error types and recovery actions.\n * Inspired by AWS Cloudscape GenAI error patterns.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Error categorization (connection, rate-limit, server, content-filtered, timeout)\n * - Recovery actions (retry, refresh, dismiss)\n * - Accessible with aria-live for screen readers\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/message-error\n * @component MessageError, ConversationError\n *\n * @useCases\n * - API failure inline in conversation\n * - Rate limiting with retry countdown\n * - Connection errors with reconnect\n * - Content moderation blocks\n * - Timeout errors with retry\n *\n * @example\n * <MessageError type=\"server-error\" onRetry={handleRetry} />\n * <ConversationError type=\"connection-error\" onRefresh={handleRefresh} />\n */\n\n'use client';\n\nimport type { ElementType } from 'react';\nimport { useMemo } from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport {\n AlertTriangleIcon,\n RefreshCwIcon,\n ShieldAlertIcon,\n TimerIcon,\n WifiOffIcon,\n XCircleIcon,\n} from 'lucide-react';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_COLORS,\n AI_CONTAINER_RADIUS,\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_FLUID,\n SPRING_GENTLE,\n} from '../../ai-elements.constants';\n\nexport type ErrorType =\n | 'connection-error'\n | 'rate-limit'\n | 'server-error'\n | 'content-filtered'\n | 'timeout'\n | 'unknown';\n\ntype ErrorConfig = {\n icon: ElementType;\n title: string;\n description: string;\n actionLabel: string;\n};\n\nconst ERROR_CONFIG: Record<ErrorType, ErrorConfig> = {\n 'connection-error': {\n icon: WifiOffIcon,\n title: 'Connection lost',\n description: 'Unable to reach the server. Check your internet connection and try again.',\n actionLabel: 'Reconnect',\n },\n 'rate-limit': {\n icon: TimerIcon,\n title: 'Rate limit reached',\n description: 'Too many requests. Please wait a moment before trying again.',\n actionLabel: 'Try again',\n },\n 'server-error': {\n icon: XCircleIcon,\n title: 'Something went wrong',\n description: 'The server encountered an error processing your request.',\n actionLabel: 'Try again',\n },\n 'content-filtered': {\n icon: ShieldAlertIcon,\n title: 'Content filtered',\n description: 'The response was blocked by content safety filters. Try rephrasing your request.',\n actionLabel: 'Dismiss',\n },\n timeout: {\n icon: TimerIcon,\n title: 'Request timed out',\n description: 'The request took too long to complete. Please try again.',\n actionLabel: 'Retry',\n },\n unknown: {\n icon: AlertTriangleIcon,\n title: 'An error occurred',\n description: 'Something unexpected happened. Please try again.',\n actionLabel: 'Try again',\n },\n};\n\nexport type MessageErrorProps = HTMLMotionProps<'div'> & {\n /** Error type category */\n type?: ErrorType;\n /** Custom title override */\n title?: string;\n /** Custom description override */\n description?: string;\n /** Custom action label override */\n actionLabel?: string;\n /** Retry callback */\n onRetry?: () => void;\n /** Dismiss callback */\n onDismiss?: () => void;\n /** Whether retry is in progress */\n isRetrying?: boolean;\n};\n\nexport const MessageError = ({\n className,\n type = 'unknown',\n title: titleOverride,\n description: descriptionOverride,\n actionLabel: actionLabelOverride,\n onRetry,\n onDismiss,\n isRetrying = false,\n ...props\n}: MessageErrorProps) => {\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n const config = ERROR_CONFIG[type];\n const Icon = config.icon;\n const title = titleOverride ?? config.title;\n const description = descriptionOverride ?? config.description;\n const actionLabel = actionLabelOverride ?? config.actionLabel;\n\n const entryVariants = useMemo(\n () => ({\n initial: reducedMotion ? { opacity: 1 } : { opacity: 0, y: 8, scale: 0.98 },\n animate: { opacity: 1, y: 0, scale: 1 },\n }),\n [reducedMotion],\n );\n\n return (\n <motion.div\n className={cn(\n 'flex w-full items-start gap-3 border p-4',\n AI_CONTAINER_RADIUS,\n AI_COLORS.error.bg,\n AI_COLORS.error.border,\n className,\n )}\n variants={entryVariants}\n initial=\"initial\"\n animate=\"animate\"\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n role=\"alert\"\n data-component=\"MessageError\"\n data-error-type={type}\n {...props}\n >\n <Icon className={cn('text-destructive mt-0.5 shrink-0', AI_ICON.md)} aria-hidden />\n\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-foreground text-sm font-medium\">{title}</p>\n <p className={cn('text-muted-foreground', AI_TEXT.sm)}>{description}</p>\n </div>\n\n <div className={cn('flex shrink-0 items-center', AI_SPACING.xs)}>\n {onRetry ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n type=\"button\"\n onClick={isRetrying ? undefined : onRetry}\n aria-disabled={isRetrying || undefined}\n className={cn(\n AI_FOCUS.ring,\n AI_TRANSITION.colors,\n 'duration-150',\n isTouchDevice && 'min-h-11',\n isRetrying && 'pointer-events-none opacity-50',\n )}\n data-retrying={isRetrying || undefined}\n >\n <RefreshCwIcon\n className={cn(AI_ICON.sm, isRetrying && !reducedMotion && 'animate-spin')}\n aria-hidden\n />\n {actionLabel}\n </Button>\n ) : null}\n\n {onDismiss ? (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={onDismiss}\n className={cn(AI_FOCUS.ring, 'text-muted-foreground', isTouchDevice && 'min-h-11')}\n aria-label=\"Dismiss error\"\n >\n Dismiss\n </Button>\n ) : null}\n </div>\n </motion.div>\n );\n};\n\nexport type ConversationErrorProps = HTMLMotionProps<'div'> & {\n /** Error type category */\n type?: ErrorType;\n /** Custom title override */\n title?: string;\n /** Custom description override */\n description?: string;\n /** Refresh/reconnect callback */\n onRefresh?: () => void;\n /** Whether refresh is in progress */\n isRefreshing?: boolean;\n};\n\nexport const ConversationError = ({\n className,\n type = 'unknown',\n title: titleOverride,\n description: descriptionOverride,\n onRefresh,\n isRefreshing = false,\n ...props\n}: ConversationErrorProps) => {\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n const config = ERROR_CONFIG[type];\n const Icon = config.icon;\n const title = titleOverride ?? config.title;\n const description = descriptionOverride ?? config.description;\n\n return (\n <motion.div\n className={cn(\n 'flex size-full flex-col items-center justify-center p-8 text-center',\n AI_SPACING.md,\n className,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_FLUID}\n role=\"alert\"\n data-component=\"ConversationError\"\n data-error-type={type}\n {...props}\n >\n <div className={cn('text-destructive/60 rounded-full p-3', AI_COLORS.error.bg)}>\n <Icon className=\"size-8\" aria-hidden />\n </div>\n\n <div className=\"space-y-2\">\n <h3 className=\"text-foreground text-base font-medium\">{title}</h3>\n <p className={cn('text-muted-foreground max-w-sm', AI_TEXT.sm)}>{description}</p>\n </div>\n\n {onRefresh ? (\n <Button\n variant=\"outline\"\n type=\"button\"\n onClick={onRefresh}\n disabled={isRefreshing}\n className={cn(AI_FOCUS.ring, AI_TRANSITION.colors, isTouchDevice && 'min-h-11')}\n >\n <RefreshCwIcon\n className={cn(AI_ICON.sm, isRefreshing && !reducedMotion && 'animate-spin')}\n aria-hidden\n />\n {isRefreshing ? 'Reconnecting...' : 'Try again'}\n </Button>\n ) : null}\n </motion.div>\n );\n};\n\nMessageError.displayName = 'MessageError';\nConversationError.displayName = 'ConversationError';\n","/**\n * @fileoverview ConversationHistory Components - Premium Harmony V2\n *\n * Searchable conversation history drawer/panel for managing past AI sessions.\n * Inspired by PatternFly AI's conversation history and Microsoft Fluent Copilot.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Searchable conversation list\n * - Pin/star conversations\n * - New chat action\n * - Stagger animations for list items\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/conversation-history\n *\n * @useCases\n * - Sidebar conversation list\n * - Searchable history drawer\n * - Pinned/starred conversations\n * - \"New chat\" button\n * - Conversation management (rename, delete)\n *\n * @example\n * <ConversationHistory>\n * <ConversationHistoryHeader>\n * <ConversationHistoryNew onClick={handleNew} />\n * <ConversationHistorySearch value={search} onChange={setSearch} />\n * </ConversationHistoryHeader>\n * <ConversationHistoryList>\n * <ConversationHistoryItem id=\"1\" title=\"Code Review\" date={new Date()} />\n * </ConversationHistoryList>\n * </ConversationHistory>\n */\n\n'use client';\n\nimport type { ComponentProps, ReactElement, ReactNode } from 'react';\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useMemo,\n useState,\n} from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport {\n Loader2,\n MessageSquarePlusIcon,\n PinIcon,\n PinOffIcon,\n SearchIcon,\n Trash2Icon,\n} from 'lucide-react';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport { ScrollArea } from '../../../elements/organisms/scroll-area';\nimport {\n AI_FOCUS,\n AI_HOVER,\n AI_ICON,\n AI_ICON_STYLE,\n AI_PADDING,\n AI_SPACING,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_GENTLE,\n} from '../../ai-elements.constants';\n\ntype ConversationHistoryContextValue = {\n activeId: string | null;\n setActiveId: (id: string | null) => void;\n searchValue: string;\n setSearchValue: (value: string) => void;\n};\n\nconst ConversationHistoryContext = createContext<ConversationHistoryContextValue | null>(null);\n\nconst useConversationHistory = () => {\n const ctx = useContext(ConversationHistoryContext);\n if (!ctx) {\n throw new Error('ConversationHistory subcomponents must be used within ConversationHistory');\n }\n return ctx;\n};\n\nexport type ConversationHistoryProps = ComponentProps<'aside'> & {\n /** Currently active conversation ID */\n activeId?: string | null;\n /** Callback when active conversation changes */\n onActiveChange?: (id: string | null) => void;\n};\n\nexport const ConversationHistory = ({\n className,\n activeId: controlledActiveId,\n onActiveChange,\n children,\n ...props\n}: ConversationHistoryProps) => {\n const [internalActiveId, setInternalActiveId] = useState<string | null>(null);\n const activeId = controlledActiveId !== undefined ? controlledActiveId : internalActiveId;\n const [searchValue, setSearchValue] = useState('');\n\n const setActiveId = useCallback(\n (id: string | null) => {\n if (controlledActiveId === undefined) {\n setInternalActiveId(id);\n }\n onActiveChange?.(id);\n },\n [controlledActiveId, onActiveChange],\n );\n\n const contextValue = useMemo(\n () => ({ activeId, setActiveId, searchValue, setSearchValue }),\n [activeId, setActiveId, searchValue],\n );\n\n return (\n <ConversationHistoryContext.Provider value={contextValue}>\n <aside\n className={cn('bg-background border-border flex h-full w-72 flex-col border-r', className)}\n role=\"navigation\"\n aria-label=\"Conversation history\"\n data-component=\"ConversationHistory\"\n {...props}\n >\n {children}\n </aside>\n </ConversationHistoryContext.Provider>\n );\n};\n\nexport type ConversationHistoryHeaderProps = ComponentProps<'div'>;\n\nexport const ConversationHistoryHeader = ({\n className,\n ...props\n}: ConversationHistoryHeaderProps) => (\n <div\n className={cn(\n 'border-border flex flex-col border-b',\n AI_PADDING.standard,\n AI_SPACING.sm,\n className,\n )}\n {...props}\n />\n);\n\nexport type ConversationHistoryNewProps = ComponentProps<typeof Button> & {\n isLoading?: boolean;\n};\n\nexport const ConversationHistoryNew = ({\n className,\n children,\n isLoading = false,\n disabled,\n ...props\n}: ConversationHistoryNewProps) => {\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n return (\n <Button\n className={cn('w-full justify-start', AI_FOCUS.ring, isTouchDevice && 'min-h-11', className)}\n variant=\"outline\"\n type=\"button\"\n size=\"sm\"\n disabled={disabled || isLoading}\n {...props}\n >\n {isLoading ? (\n <Loader2 className={cn(AI_ICON.md, 'animate-spin')} aria-hidden />\n ) : (\n <MessageSquarePlusIcon className={AI_ICON.md} aria-hidden />\n )}\n {children ?? 'New chat'}\n </Button>\n );\n};\n\nexport type ConversationHistorySearchProps = ComponentProps<'input'> & {\n value?: string;\n onValueChange?: (value: string) => void;\n error?: boolean;\n};\n\nexport const ConversationHistorySearch = ({\n className,\n value,\n onValueChange,\n onChange,\n error = false,\n ...props\n}: ConversationHistorySearchProps) => {\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n const { searchValue, setSearchValue } = useConversationHistory();\n const resolvedValue = value ?? searchValue;\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const nextValue = e.target.value;\n setSearchValue(nextValue);\n onValueChange?.(nextValue);\n onChange?.(e);\n },\n [onValueChange, onChange, setSearchValue],\n );\n\n return (\n <div className=\"relative\">\n <SearchIcon\n className={cn(\n 'absolute top-1/2 left-2.5 -translate-y-1/2',\n AI_ICON_STYLE.muted,\n AI_ICON.sm,\n )}\n aria-hidden\n />\n <input\n className={cn(\n 'border-border bg-background text-foreground placeholder:text-muted-foreground w-full rounded-lg border py-1.5 pr-3 pl-8',\n AI_TEXT.sm,\n AI_FOCUS.ring,\n AI_TRANSITION.colors,\n isTouchDevice && 'min-h-11',\n error && 'border-destructive',\n className,\n )}\n type=\"search\"\n placeholder=\"Search conversations...\"\n value={resolvedValue}\n onChange={handleChange}\n aria-label=\"Search conversations\"\n aria-invalid={error || undefined}\n {...props}\n />\n </div>\n );\n};\n\nexport type ConversationHistoryListProps = ComponentProps<'div'> & {\n maxHeight?: number;\n};\n\nexport const ConversationHistoryList = ({\n className,\n children,\n maxHeight,\n ...props\n}: ConversationHistoryListProps) => {\n const { searchValue } = useConversationHistory();\n const normalizedQuery = searchValue.trim().toLowerCase();\n\n const filterChildren = useCallback(\n (nodes: ReactNode): ReactNode[] => {\n const recurse = (nodeList: ReactNode): ReactNode[] => {\n return Children.toArray(nodeList).flatMap(node => {\n if (!normalizedQuery) {\n return [node];\n }\n\n if (!isValidElement(node)) {\n return [node];\n }\n\n if (node.type === ConversationHistoryItem) {\n const item = node as ReactElement<{ title?: string }>;\n const title = typeof item.props.title === 'string' ? item.props.title : '';\n return title.toLowerCase().includes(normalizedQuery) ? [node] : [];\n }\n\n if (node.type === ConversationHistorySection) {\n const section = node as ReactElement<{ children?: ReactNode }>;\n const filteredSectionChildren = recurse(section.props.children);\n if (filteredSectionChildren.length === 0) {\n return [];\n }\n return [\n cloneElement(section, {\n children: filteredSectionChildren,\n } as any),\n ];\n }\n\n return [node];\n });\n };\n return recurse(nodes);\n },\n [normalizedQuery],\n );\n\n const filteredChildren = useMemo(\n () => (normalizedQuery ? filterChildren(children) : Children.toArray(children)),\n [children, filterChildren, normalizedQuery],\n );\n\n return (\n <ScrollArea className={cn('flex-1', className)} style={maxHeight ? { maxHeight } : undefined}>\n <div\n className={cn('flex flex-col', AI_SPACING.xs, AI_PADDING.compact)}\n role=\"listbox\"\n aria-label=\"Conversations\"\n aria-orientation=\"vertical\"\n {...props}\n >\n {filteredChildren}\n </div>\n </ScrollArea>\n );\n};\n\nexport type ConversationHistoryItemProps = HTMLMotionProps<'div'> & {\n /** Unique conversation ID */\n id: string;\n /** Conversation title */\n title: string;\n /** Last message preview */\n preview?: string;\n /** Conversation date */\n date?: Date;\n /** Whether conversation is pinned */\n pinned?: boolean;\n /** Pin toggle callback */\n onPinToggle?: (id: string) => void;\n /** Delete callback */\n onDelete?: (id: string) => void;\n /** Stagger animation index */\n index?: number;\n};\n\nexport const ConversationHistoryItem = ({\n className,\n id,\n title,\n preview,\n date,\n pinned = false,\n onPinToggle,\n onDelete,\n index = 0,\n ...props\n}: ConversationHistoryItemProps) => {\n const { activeId, setActiveId } = useConversationHistory();\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n const isActive = activeId === id;\n\n let formattedDate: string | undefined;\n if (date) {\n try {\n formattedDate = new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric' }).format(\n date,\n );\n } catch {\n // Invalid Date -- skip display\n formattedDate = undefined;\n }\n }\n\n const handleClick = useCallback(() => {\n setActiveId(id);\n }, [id, setActiveId]);\n\n const handlePin = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onPinToggle?.(id);\n },\n [id, onPinToggle],\n );\n\n const handleDelete = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(id);\n },\n [id, onDelete],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setActiveId(id);\n }\n },\n [id, setActiveId],\n );\n\n return (\n <motion.div\n className={cn(\n 'group flex w-full cursor-pointer items-start gap-2 rounded-lg p-2.5 text-left',\n AI_TRANSITION.colors,\n 'duration-150',\n AI_FOCUS.ring,\n 'outline-offset-2',\n isTouchDevice && 'min-h-11',\n isActive ? 'bg-accent text-accent-foreground' : cn('text-foreground', AI_HOVER.bg),\n className,\n )}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, x: -8 }}\n animate={{ opacity: 1, x: 0 }}\n transition={reducedMotion ? { duration: 0 } : { ...SPRING_GENTLE, delay: index * 0.03 }}\n role=\"option\"\n aria-selected={isActive}\n tabIndex={0}\n data-component=\"ConversationHistoryItem\"\n data-active={isActive || undefined}\n data-pinned={pinned || undefined}\n {...props}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1\">\n {pinned ? (\n <PinIcon className={cn('text-primary shrink-0', AI_ICON.sm)} aria-label=\"Pinned\" />\n ) : null}\n <p className=\"truncate text-sm font-medium\">{title}</p>\n </div>\n {preview ? (\n <p className={cn('text-muted-foreground mt-0.5 truncate', AI_TEXT.xs)}>{preview}</p>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {formattedDate ? (\n <span className={cn('text-muted-foreground', AI_TEXT.xs)}>{formattedDate}</span>\n ) : null}\n\n <div className=\"flex items-center opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100\">\n {onPinToggle ? (\n <button\n type=\"button\"\n onClick={handlePin}\n className={cn(\n 'min-h-8 min-w-8 rounded-md p-1',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n 'text-muted-foreground hover:text-foreground',\n )}\n aria-label={pinned ? 'Unpin conversation' : 'Pin conversation'}\n >\n {pinned ? <PinOffIcon className={AI_ICON.sm} /> : <PinIcon className={AI_ICON.sm} />}\n </button>\n ) : null}\n\n {onDelete ? (\n <button\n type=\"button\"\n onClick={handleDelete}\n className={cn(\n 'min-h-8 min-w-8 rounded-md p-1',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n 'text-muted-foreground hover:text-destructive',\n )}\n aria-label=\"Delete conversation\"\n >\n <Trash2Icon className={AI_ICON.sm} />\n </button>\n ) : null}\n </div>\n </div>\n </motion.div>\n );\n};\n\nexport type ConversationHistorySectionProps = ComponentProps<'div'> & {\n title: string;\n};\n\nexport const ConversationHistorySection = ({\n className,\n title,\n children,\n ...props\n}: ConversationHistorySectionProps) => {\n const labelId = useId();\n\n return (\n <div className={cn('space-y-1', className)} role=\"group\" aria-labelledby={labelId} {...props}>\n <p\n id={labelId}\n className={cn(\n 'text-muted-foreground px-2 pt-2 text-xs font-medium tracking-wide uppercase',\n )}\n >\n {title}\n </p>\n {children}\n </div>\n );\n};\n\nConversationHistory.displayName = 'ConversationHistory';\nConversationHistoryHeader.displayName = 'ConversationHistoryHeader';\nConversationHistoryNew.displayName = 'ConversationHistoryNew';\nConversationHistorySearch.displayName = 'ConversationHistorySearch';\nConversationHistoryList.displayName = 'ConversationHistoryList';\nConversationHistoryItem.displayName = 'ConversationHistoryItem';\nConversationHistorySection.displayName = 'ConversationHistorySection';\n","/**\n * @fileoverview ChatContainer Component - Premium Harmony V2\n *\n * A display mode system for AI chat interfaces. Supports embedded, docked,\n * overlay, and fullscreen modes with responsive behavior.\n * Inspired by PatternFly AI (4 modes) and Microsoft Fluent (3 frameworks).\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - 4 display modes: embedded, docked, overlay, fullscreen\n * - Responsive breakpoint behavior (auto-fullscreen on mobile)\n * - Resize handle for docked mode\n * - Minimize/maximize controls\n * - Backdrop for overlay mode\n * - Reduced motion support\n * - Touch vs desktop adaptive\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/chat-container\n * @component ChatContainer, ChatContainerControls\n *\n * @useCases\n * - Embedded chat within a page layout\n * - Docked side panel assistant\n * - Floating overlay chat widget\n * - Fullscreen chat application\n * - Responsive mode switching\n *\n * @example\n * <ChatContainer mode=\"docked\" position=\"right\">\n * <Conversation>...</Conversation>\n * </ChatContainer>\n */\n\n'use client';\n\nimport type { ComponentProps } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport {\n MaximizeIcon,\n MinimizeIcon,\n PanelRightCloseIcon,\n PanelRightOpenIcon,\n XIcon,\n} from 'lucide-react';\nimport { AnimatePresence, motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TRANSITION,\n SPRING_FLUID,\n} from '../../ai-elements.constants';\n\nexport type ChatDisplayMode = 'embedded' | 'docked' | 'overlay' | 'fullscreen';\nexport type ChatDockPosition = 'left' | 'right' | 'bottom';\n\ntype ChatContainerContextValue = {\n mode: ChatDisplayMode;\n setMode: (mode: ChatDisplayMode) => void;\n isMinimized: boolean;\n setIsMinimized: (minimized: boolean | ((prev: boolean) => boolean)) => void;\n isOpen: boolean;\n setIsOpen: (open: boolean) => void;\n position: ChatDockPosition;\n};\n\nconst ChatContainerContext = createContext<ChatContainerContextValue | null>(null);\n\nexport const useChatContainer = () => {\n const ctx = useContext(ChatContainerContext);\n if (!ctx) throw new Error('ChatContainer subcomponents must be used within ChatContainer');\n return ctx;\n};\n\nexport type ChatContainerProps = HTMLMotionProps<'div'> & {\n /** Display mode */\n mode?: ChatDisplayMode;\n /** Controlled mode change */\n onModeChange?: (mode: ChatDisplayMode) => void;\n /** Dock position (for docked mode) */\n position?: ChatDockPosition;\n /** Width for docked/overlay mode */\n width?: number | string;\n /** Whether the container is open (for overlay/docked) */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Whether to show backdrop in overlay mode */\n showBackdrop?: boolean;\n /** Auto fullscreen on mobile */\n autoFullscreenMobile?: boolean;\n};\n\nexport const ChatContainer = ({\n className,\n mode: modeProp = 'embedded',\n onModeChange,\n position = 'right',\n width = 400,\n open: openProp,\n onOpenChange,\n showBackdrop = true,\n autoFullscreenMobile = true,\n children,\n ...props\n}: ChatContainerProps) => {\n const [internalModeState, setInternalMode] = useState<ChatDisplayMode>(modeProp);\n const [prevModeProp, setPrevModeProp] = useState<ChatDisplayMode>(modeProp);\n const [isMinimized, setIsMinimized] = useState(false);\n const [internalOpen, setInternalOpen] = useState(true);\n const reducedMotion = useReducedMotion();\n const isMobile = useMediaQuery('(max-width: 768px)');\n\n // Sync internalMode when modeProp changes (uncontrolled mode)\n if (modeProp !== prevModeProp) {\n setPrevModeProp(modeProp);\n if (onModeChange === undefined) {\n setInternalMode(modeProp);\n }\n }\n\n const baseMode = onModeChange !== undefined ? modeProp : internalModeState;\n const mode =\n autoFullscreenMobile && isMobile && baseMode !== 'embedded' ? 'fullscreen' : baseMode;\n const isOpen = openProp !== undefined ? openProp : internalOpen;\n\n const setMode = useCallback(\n (newMode: ChatDisplayMode) => {\n if (onModeChange === undefined) {\n setInternalMode(newMode);\n }\n onModeChange?.(newMode);\n },\n [onModeChange],\n );\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (openProp === undefined) {\n setInternalOpen(open);\n }\n onOpenChange?.(open);\n },\n [openProp, onOpenChange],\n );\n\n const contextValue = useMemo(\n () => ({ mode, setMode, isMinimized, setIsMinimized, isOpen, setIsOpen, position }),\n // setIsMinimized is a stable React state setter, excluded from deps\n\n [mode, setMode, isMinimized, isOpen, setIsOpen, position],\n );\n\n const modeStyles = useMemo<Record<ChatDisplayMode, string>>(\n () => ({\n embedded: 'relative flex flex-col h-full w-full',\n docked: cn(\n 'fixed z-40 flex flex-col',\n position === 'right' && 'right-0 top-0 h-full border-l',\n position === 'left' && 'left-0 top-0 h-full border-r',\n position === 'bottom' && 'bottom-0 left-0 w-full border-t',\n ),\n overlay: 'fixed z-50 flex flex-col rounded-xl border shadow-2xl',\n fullscreen: 'fixed inset-0 z-50 flex flex-col',\n }),\n [position],\n );\n\n const positionStyles = useMemo(\n () =>\n mode === 'overlay'\n ? cn(\n position === 'right' && 'right-4 bottom-4',\n position === 'left' && 'left-4 bottom-4',\n position === 'bottom' && 'right-4 bottom-4',\n )\n : '',\n [mode, position],\n );\n\n const sizeStyle = useMemo(\n () =>\n mode === 'docked' || mode === 'overlay'\n ? {\n width: position === 'bottom' ? '100%' : width,\n height: position === 'bottom' ? 400 : (mode === 'overlay' ? '70vh' : '100%'),\n maxHeight: mode === 'overlay' ? '70vh' : undefined,\n }\n : undefined,\n [mode, position, width],\n );\n\n const animationVariants = useMemo(() => {\n if (mode === 'overlay') {\n return {\n initial: { opacity: 0, scale: 0.95, y: 20 },\n animate: { opacity: 1, scale: 1, y: 0 },\n exit: { opacity: 0, scale: 0.95, y: 20 },\n };\n }\n if (mode === 'docked') {\n const slideDir =\n position === 'right' ? { x: 300 } : (position === 'left' ? { x: -300 } : { y: 300 });\n return {\n initial: { opacity: 0, ...slideDir },\n animate: { opacity: 1, x: 0, y: 0 },\n exit: { opacity: 0, ...slideDir },\n };\n }\n return {\n initial: { opacity: reducedMotion ? 1 : 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0 },\n };\n }, [mode, position, reducedMotion]);\n\n const shouldRender = isOpen || mode === 'embedded';\n\n const handleBackdropClick = useCallback(() => setIsOpen(false), [setIsOpen]);\n\n // Close on Escape for overlay and fullscreen modes\n useEffect(() => {\n if (mode !== 'overlay' && mode !== 'fullscreen') return;\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n setIsOpen(false);\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [mode, isOpen, setIsOpen]);\n\n return (\n <ChatContainerContext.Provider value={contextValue}>\n <AnimatePresence>\n {mode === 'overlay' && showBackdrop && shouldRender ? (\n <motion.div\n key=\"chat-backdrop\"\n className=\"fixed inset-0 z-40 bg-black/40\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n onClick={handleBackdropClick}\n role=\"button\"\n aria-label=\"Close panel\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleBackdropClick();\n }\n }}\n />\n ) : null}\n </AnimatePresence>\n\n <AnimatePresence>\n {shouldRender ? (\n <motion.div\n key=\"chat-container\"\n className={cn(\n 'bg-background border-border',\n modeStyles[mode],\n positionStyles,\n isMinimized && mode !== 'embedded' && 'h-12 overflow-hidden',\n className,\n )}\n style={sizeStyle}\n initial={reducedMotion ? undefined : animationVariants.initial}\n animate={animationVariants.animate}\n exit={reducedMotion ? undefined : animationVariants.exit}\n transition={reducedMotion ? { duration: 0 } : SPRING_FLUID}\n data-component=\"ChatContainer\"\n data-testid=\"chat-container\"\n data-mode={mode}\n data-position={position}\n data-minimized={isMinimized || undefined}\n role=\"complementary\"\n aria-label=\"AI Assistant\"\n {...props}\n >\n {children}\n </motion.div>\n ) : null}\n </AnimatePresence>\n </ChatContainerContext.Provider>\n );\n};\n\nexport type ChatContainerControlsProps = ComponentProps<'div'> & {\n /** Show minimize button */\n showMinimize?: boolean;\n /** Show maximize/fullscreen button */\n showMaximize?: boolean;\n /** Show close button */\n showClose?: boolean;\n /** Show dock toggle */\n showDockToggle?: boolean;\n};\n\nexport const ChatContainerControls = ({\n className,\n showMinimize = true,\n showMaximize = true,\n showClose = true,\n showDockToggle = false,\n ...props\n}: ChatContainerControlsProps) => {\n const { mode, setMode, isMinimized, setIsMinimized, setIsOpen } = useChatContainer();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n const buttonClass = cn(\n 'size-8 p-0',\n AI_FOCUS.ring,\n AI_TRANSITION.colors,\n 'text-muted-foreground hover:text-foreground',\n isTouchDevice && 'min-h-11 min-w-11',\n );\n\n if (mode === 'embedded') return null;\n\n return (\n <div\n className={cn('flex items-center', AI_SPACING.xs, className)}\n data-component=\"ChatContainerControls\"\n {...props}\n >\n {showDockToggle && mode === 'docked' ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setMode('overlay')}\n aria-label=\"Undock\"\n >\n <PanelRightOpenIcon className={AI_ICON.md} />\n </Button>\n ) : null}\n\n {showDockToggle && mode === 'overlay' ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setMode('docked')}\n aria-label=\"Dock to side\"\n >\n <PanelRightCloseIcon className={AI_ICON.md} />\n </Button>\n ) : null}\n\n {showMinimize ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setIsMinimized(prev => !prev)}\n aria-label={isMinimized ? 'Restore' : 'Minimize'}\n >\n <MinimizeIcon className={AI_ICON.md} />\n </Button>\n ) : null}\n\n {showMaximize ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setMode(mode === 'fullscreen' ? 'overlay' : 'fullscreen')}\n aria-label={mode === 'fullscreen' ? 'Exit fullscreen' : 'Fullscreen'}\n >\n <MaximizeIcon className={AI_ICON.md} />\n </Button>\n ) : null}\n\n {showClose ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setIsOpen(false)}\n aria-label=\"Close\"\n >\n <XIcon className={AI_ICON.md} />\n </Button>\n ) : null}\n </div>\n );\n};\n\nChatContainer.displayName = 'ChatContainer';\nChatContainerControls.displayName = 'ChatContainerControls';\n","/**\n * @fileoverview MessageEdit Component - Premium Harmony V2\n *\n * Inline message editor that replaces message content with an editable\n * textarea and save/cancel controls. Handles escape to cancel, Cmd/Ctrl+Enter to save.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Keyboard shortcuts (Escape = cancel, Cmd+Enter = save)\n * - Auto-focus and auto-resize textarea\n * - Animated transition between view and edit modes\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/message-edit\n * @component MessageEdit\n *\n * @useCases\n * - Edit and resubmit user messages\n * - Correct typos in sent messages\n * - Refine prompts without creating new messages\n *\n * @example\n * <MessageEdit\n * value={messageText}\n * onSave={handleSave}\n * onCancel={handleCancel}\n * />\n */\n\n'use client';\n\nimport { useCallback, useEffect, useReducer, useRef } from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport { CheckIcon, XIcon } from 'lucide-react';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_CONTAINER_RADIUS,\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_FLUID,\n} from '../../ai-elements.constants';\n\nexport type MessageEditProps = Omit<HTMLMotionProps<'div'>, 'ref' | 'onSubmit'> & {\n /** Current message text */\n value: string;\n /** Save callback with edited text */\n onSave: (value: string) => void;\n /** Cancel callback */\n onCancel: () => void;\n /** Maximum character limit */\n maxLength?: number;\n /** Placeholder text */\n placeholder?: string;\n /** Whether save is in progress */\n isSaving?: boolean;\n};\n\nexport const MessageEdit = ({\n className,\n value,\n onSave,\n onCancel,\n maxLength,\n placeholder = 'Edit your message...',\n isSaving = false,\n ...props\n}: MessageEditProps) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const prevValueRef = useRef<string>(value);\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n // Use reducer for editValue to avoid setState in effect\n // Sync external prop changes to local state only when not focused\n // This preserves user edits in controlled components\n type EditValueAction = { type: 'set'; value: string } | { type: 'update'; value: string };\n const editValueReducer = (state: string, action: EditValueAction): string => {\n if (action.type === 'set') {\n return action.value;\n }\n return action.value;\n };\n const [editValue, dispatchEditValue] = useReducer(editValueReducer, value);\n\n // Sync external prop changes to local state only when not focused\n useEffect(() => {\n const hasChanged = value !== prevValueRef.current;\n const isNotFocused = !textareaRef.current?.matches(':focus');\n\n if (hasChanged && isNotFocused) {\n dispatchEditValue({ type: 'set', value });\n }\n\n prevValueRef.current = value;\n }, [value]);\n\n // Auto-focus and select text on mount\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.focus();\n textarea.setSelectionRange(textarea.value.length, textarea.value.length);\n }\n }, []);\n\n // Auto-resize textarea to fit content\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${textarea.scrollHeight}px`;\n }\n }, [editValue]);\n\n const handleSave = useCallback(() => {\n const trimmed = editValue.trim();\n if (trimmed && trimmed !== value.trim()) {\n onSave(trimmed);\n } else {\n onCancel();\n }\n }, [editValue, value, onSave, onCancel]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onCancel();\n } else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleSave();\n }\n },\n [onCancel, handleSave],\n );\n\n const hasChanges = editValue.trim() !== value.trim();\n const isOverLimit = maxLength !== undefined && editValue.length > maxLength;\n\n return (\n <motion.div\n className={cn('w-full space-y-2', className)}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: -4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={reducedMotion ? { opacity: 0 } : { opacity: 0, y: -4 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_FLUID}\n data-component=\"MessageEdit\"\n {...props}\n >\n <div className={cn('border-border bg-background relative border', AI_CONTAINER_RADIUS)}>\n <textarea\n ref={textareaRef}\n className={cn(\n 'text-foreground placeholder:text-muted-foreground w-full resize-none bg-transparent p-3 outline-none',\n AI_TEXT.sm,\n AI_FOCUS.ring,\n )}\n value={editValue}\n onChange={e => dispatchEditValue({ type: 'update', value: e.target.value })}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n maxLength={maxLength}\n rows={1}\n disabled={isSaving}\n aria-label=\"Edit message\"\n />\n\n {maxLength ? (\n <output\n className={cn(\n 'px-3 pb-2 text-right',\n AI_TEXT.xs,\n isOverLimit ? 'text-destructive' : 'text-muted-foreground',\n )}\n aria-live=\"polite\"\n aria-label={`${editValue.length} of ${maxLength} characters used${isOverLimit ? ', limit exceeded' : ''}`}\n >\n {editValue.length}/{maxLength}\n </output>\n ) : null}\n </div>\n\n <div className={cn('flex items-center justify-between', AI_SPACING.xs)}>\n <p className={cn('text-muted-foreground', AI_TEXT.xs)}>\n {isTouchDevice ? 'Tap Save to submit' : 'Escape to cancel · Cmd+Enter to save'}\n </p>\n\n <div className={cn('flex items-center', AI_SPACING.xs)}>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={onCancel}\n disabled={isSaving}\n className={cn(AI_FOCUS.ring, AI_TRANSITION.colors, isTouchDevice && 'min-h-11')}\n >\n <XIcon className={AI_ICON.sm} aria-hidden />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n variant=\"default\"\n type=\"button\"\n onClick={handleSave}\n disabled={!hasChanges || isOverLimit || isSaving}\n className={cn(AI_FOCUS.ring, AI_TRANSITION.colors, isTouchDevice && 'min-h-11')}\n >\n <CheckIcon className={AI_ICON.sm} aria-hidden />\n {isSaving ? 'Saving...' : 'Save'}\n </Button>\n </div>\n </div>\n </motion.div>\n );\n};\n\nMessageEdit.displayName = 'MessageEdit';\n","/**\n * @fileoverview TypingIndicator Component - Premium Harmony V2\n *\n * Animated indicator showing that the AI is processing a request.\n * Displays contextual text (\"Thinking...\", \"Searching...\", etc.)\n * with animated dots. Sits in the message flow between user input\n * and AI response.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Animated bouncing dots\n * - Contextual status text\n * - Reduced motion support\n * - Auto-dismisses when no longer needed\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/typing-indicator\n * @component TypingIndicator\n *\n * @useCases\n * - Show \"Thinking...\" between send and first token\n * - Show \"Searching the web...\" during tool execution\n * - Show \"Analyzing your code...\" during processing\n * - Show \"Generating image...\" during generation\n *\n * @example\n * <TypingIndicator />\n * <TypingIndicator text=\"Searching the web...\" />\n * <TypingIndicator text=\"Analyzing your code...\" avatar={<BotAvatar />} />\n */\n\n'use client';\n\nimport { useMemo } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_SPACING, AI_TEXT, SPRING_GENTLE } from '../../ai-elements.constants';\n\nexport type TypingIndicatorProps = HTMLMotionProps<'div'> & {\n /** Status text displayed alongside dots */\n text?: string;\n /** Avatar/icon to show before the indicator */\n avatar?: React.ReactNode;\n /** Whether to show the bouncing dots */\n showDots?: boolean;\n};\n\nconst TypingDot = ({\n delay,\n reducedMotion,\n}: {\n delay: number;\n reducedMotion: boolean | undefined;\n}) => {\n if (reducedMotion) {\n return <span className=\"bg-muted-foreground/60 inline-block size-1.5 rounded-full\" />;\n }\n\n return (\n <motion.span\n className=\"bg-muted-foreground/60 inline-block size-1.5 rounded-full\"\n animate={{\n y: [0, -4, 0],\n opacity: [0.4, 1, 0.4],\n }}\n transition={{\n duration: 1,\n repeat: Number.POSITIVE_INFINITY,\n ease: 'easeInOut',\n delay,\n }}\n />\n );\n};\n\nexport const TypingIndicator = ({\n className,\n text = 'Thinking',\n avatar,\n showDots = true,\n ...props\n}: TypingIndicatorProps) => {\n const reducedMotion = useReducedMotion();\n\n const entryVariants = useMemo(\n () => ({\n initial: reducedMotion ? { opacity: 1 } : { opacity: 0, y: 8 },\n animate: { opacity: 1, y: 0 },\n exit: reducedMotion ? { opacity: 0 } : { opacity: 0, y: -8 },\n }),\n [reducedMotion],\n );\n\n return (\n <motion.div\n className={cn('flex items-center', AI_SPACING.sm, className)}\n variants={entryVariants}\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n transition={reducedMotion ? { duration: 0.15 } : SPRING_GENTLE}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={`${text}...`}\n data-component=\"TypingIndicator\"\n {...props}\n >\n {avatar ? <div className=\"shrink-0\">{avatar}</div> : null}\n\n <div className={cn('flex items-center gap-1.5', AI_TEXT.sm, 'text-muted-foreground')}>\n <span>{text}</span>\n {showDots ? (\n <span className=\"inline-flex items-center gap-0.5\" aria-hidden>\n <TypingDot delay={0} reducedMotion={reducedMotion} />\n <TypingDot delay={0.15} reducedMotion={reducedMotion} />\n <TypingDot delay={0.3} reducedMotion={reducedMotion} />\n </span>\n ) : null}\n </div>\n </motion.div>\n );\n};\n\nTypingIndicator.displayName = 'TypingIndicator';\n","/**\n * @fileoverview ExportConversation Utility - Premium Harmony V2\n *\n * Utility functions and components for exporting AI conversations\n * to various formats (Markdown, Plain Text, JSON).\n *\n * Features:\n * - Export to Markdown, Plain Text, JSON\n * - Configurable: include/exclude metadata, timestamps, tool outputs\n * - Download trigger component with format selection\n * - Clipboard copy support\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/export-conversation\n * @component ExportConversationButton\n *\n * @useCases\n * - Save AI conversations for documentation\n * - Share conversations with team members\n * - Export for compliance/audit purposes\n * - Copy conversation to clipboard\n *\n * @example\n * <ExportConversationButton\n * messages={messages}\n * onExport={handleExport}\n * />\n *\n * // Or use utilities directly:\n * const markdown = formatConversationAsMarkdown(messages);\n */\n\n'use client';\n\nimport type { ComponentProps } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useMediaQuery } from '@mantine/hooks';\nimport {\n CheckIcon,\n CopyIcon,\n DownloadIcon,\n FileJsonIcon,\n FileTextIcon,\n XCircleIcon,\n} from 'lucide-react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport { AI_FOCUS, AI_ICON, AI_SPACING, AI_TEXT, AI_TRANSITION } from '../../ai-elements.constants';\n\nexport type ExportMessage = {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp?: Date;\n model?: string;\n};\n\n/** Safely format a Date; returns empty string if the Date is invalid. */\nfunction safeFormatDate(date: Date | undefined, options: Intl.DateTimeFormatOptions): string {\n if (!date) return '';\n try {\n return new Intl.DateTimeFormat(undefined, options).format(date);\n } catch {\n return '';\n }\n}\n\n/** Safely call toISOString; returns empty string for invalid Dates. */\nfunction safeISOString(date: Date | undefined): string | undefined {\n if (!date) return undefined;\n try {\n return date.toISOString();\n } catch {\n return undefined;\n }\n}\n\nexport type ExportFormat = 'markdown' | 'text' | 'json';\n\nexport type ExportOptions = {\n /** Include timestamps in export */\n includeTimestamps?: boolean;\n /** Include model metadata */\n includeMetadata?: boolean;\n /** Include system messages */\n includeSystemMessages?: boolean;\n /** Custom title for the export */\n title?: string;\n};\n\n/**\n * Format conversation as Markdown\n */\nexport const formatConversationAsMarkdown = (\n messages: ExportMessage[],\n options: ExportOptions = {},\n): string => {\n const {\n includeTimestamps = true,\n includeMetadata = false,\n includeSystemMessages = false,\n title,\n } = options;\n\n const lines: string[] = [];\n\n if (title) {\n lines.push(`# ${title}`, '');\n }\n\n const filteredMessages = includeSystemMessages\n ? messages\n : messages.filter(m => m.role !== 'system');\n\n if (filteredMessages.length === 0) {\n return title ? `# ${title}\\n\\n_No messages to export._\\n` : '_No messages to export._\\n';\n }\n\n for (const message of filteredMessages) {\n const roleLabel =\n message.role === 'user'\n ? '**You**'\n : (message.role === 'assistant'\n ? '**Assistant**'\n : '**System**');\n const dateStr = includeTimestamps\n ? safeFormatDate(message.timestamp, { dateStyle: 'short', timeStyle: 'short' })\n : '';\n const timestamp = dateStr ? ` _(${dateStr})_` : '';\n const metadata = includeMetadata && message.model ? ` [${message.model}]` : '';\n\n lines.push(`### ${roleLabel}${metadata}${timestamp}`, '', message.content, '');\n }\n\n return lines.join('\\n');\n};\n\n/**\n * Format conversation as plain text\n */\nexport const formatConversationAsText = (\n messages: ExportMessage[],\n options: ExportOptions = {},\n): string => {\n const { includeTimestamps = true, includeSystemMessages = false, title } = options;\n\n const lines: string[] = [];\n\n if (title) {\n lines.push(title, '='.repeat(title.length), '');\n }\n\n const filteredMessages = includeSystemMessages\n ? messages\n : messages.filter(m => m.role !== 'system');\n\n if (filteredMessages.length === 0) {\n return title\n ? `${title}\\n${'='.repeat(title.length)}\\n\\nNo messages to export.\\n`\n : 'No messages to export.\\n';\n }\n\n for (const message of filteredMessages) {\n const roleLabel =\n message.role === 'user' ? 'You' : (message.role === 'assistant' ? 'Assistant' : 'System');\n const dateStr = includeTimestamps\n ? safeFormatDate(message.timestamp, { dateStyle: 'short', timeStyle: 'short' })\n : '';\n const timestamp = dateStr ? ` (${dateStr})` : '';\n\n lines.push(`${roleLabel}${timestamp}:`, message.content, '');\n }\n\n return lines.join('\\n');\n};\n\n/**\n * Format conversation as JSON\n */\nexport const formatConversationAsJSON = (\n messages: ExportMessage[],\n options: ExportOptions = {},\n): string => {\n const { includeSystemMessages = false, title } = options;\n\n const filteredMessages = includeSystemMessages\n ? messages\n : messages.filter(m => m.role !== 'system');\n\n try {\n return JSON.stringify(\n {\n title: title ?? 'Conversation Export',\n exportedAt: new Date().toISOString(),\n messageCount: filteredMessages.length,\n messages: filteredMessages.map(m => ({\n id: m.id,\n role: m.role,\n content: m.content,\n ...(safeISOString(m.timestamp) ? { timestamp: safeISOString(m.timestamp) } : {}),\n ...(m.model ? { model: m.model } : {}),\n })),\n },\n null,\n 2,\n );\n } catch {\n return '{\"error\": \"Failed to serialize conversation\"}';\n }\n};\n\n/**\n * Trigger a file download in the browser\n */\nconst downloadFile = (content: string, filename: string, mimeType: string) => {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n // Defer revocation to ensure the download starts before the URL is invalidated\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n};\n\nexport type ExportConversationButtonProps = Omit<ComponentProps<'div'>, 'children'> & {\n /** Messages to export */\n messages: ExportMessage[];\n /** Export options */\n options?: ExportOptions;\n /** Custom filename (without extension) */\n filename?: string;\n /** Callback after export */\n onExport?: (format: ExportFormat) => void;\n /** Show copy to clipboard option */\n showCopy?: boolean;\n children?: React.ReactNode;\n};\n\nconst DEFAULT_EXPORT_OPTIONS: ExportOptions = {};\n\nexport const ExportConversationButton = ({\n className,\n messages,\n options = DEFAULT_EXPORT_OPTIONS,\n filename = 'conversation',\n onExport,\n showCopy = true,\n children,\n ...props\n}: ExportConversationButtonProps) => {\n const [copied, setCopied] = useState(false);\n const [copyError, setCopyError] = useState(false);\n const copyTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n useEffect(() => {\n return () => {\n if (copyTimeoutRef.current) {\n clearTimeout(copyTimeoutRef.current);\n }\n };\n }, []);\n\n const buttonClass = cn(\n 'flex items-center gap-1.5',\n AI_TEXT.xs,\n AI_FOCUS.ring,\n AI_TRANSITION.colors,\n 'duration-150',\n isTouchDevice && 'min-h-11',\n );\n\n const handleExport = useCallback(\n (format: ExportFormat) => {\n const formatters: Record<ExportFormat, () => string> = {\n markdown: () => formatConversationAsMarkdown(messages, options),\n text: () => formatConversationAsText(messages, options),\n json: () => formatConversationAsJSON(messages, options),\n };\n\n const extensions: Record<ExportFormat, string> = {\n markdown: '.md',\n text: '.txt',\n json: '.json',\n };\n\n const mimeTypes: Record<ExportFormat, string> = {\n markdown: 'text/markdown',\n text: 'text/plain',\n json: 'application/json',\n };\n\n const content = formatters[format]();\n downloadFile(content, `${filename}${extensions[format]}`, mimeTypes[format]);\n onExport?.(format);\n },\n [messages, options, filename, onExport],\n );\n\n const handleCopy = useCallback(async () => {\n try {\n setCopyError(false);\n const content = formatConversationAsMarkdown(messages, options);\n await navigator.clipboard.writeText(content);\n setCopied(true);\n if (copyTimeoutRef.current) {\n clearTimeout(copyTimeoutRef.current);\n }\n copyTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Clipboard API unavailable (non-HTTPS context or permission denied)\n setCopyError(true);\n if (copyTimeoutRef.current) {\n clearTimeout(copyTimeoutRef.current);\n }\n copyTimeoutRef.current = setTimeout(() => setCopyError(false), 3000);\n }\n }, [messages, options]);\n\n const isEmpty = messages.length === 0;\n\n if (children) {\n return (\n <div className={className} {...props}>\n {children}\n </div>\n );\n }\n\n return (\n <div\n className={cn('flex items-center', AI_SPACING.xs, className)}\n role=\"toolbar\"\n aria-label=\"Export conversation\"\n data-component=\"ExportConversation\"\n {...props}\n >\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => handleExport('markdown')}\n aria-label=\"Export as Markdown\"\n disabled={isEmpty}\n >\n <DownloadIcon className={AI_ICON.sm} aria-hidden />\n Markdown\n </Button>\n\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => handleExport('text')}\n aria-label=\"Export as Plain Text\"\n disabled={isEmpty}\n >\n <FileTextIcon className={AI_ICON.sm} aria-hidden />\n Text\n </Button>\n\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => handleExport('json')}\n aria-label=\"Export as JSON\"\n disabled={isEmpty}\n >\n <FileJsonIcon className={AI_ICON.sm} aria-hidden />\n JSON\n </Button>\n\n {showCopy ? (\n <Button\n className={buttonClass}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => void handleCopy()}\n aria-label={copyError ? 'Copy failed' : (copied ? 'Copied!' : 'Copy to clipboard')}\n disabled={isEmpty}\n >\n {copyError ? (\n <XCircleIcon className={cn(AI_ICON.sm, 'text-destructive')} aria-hidden />\n ) : (copied ? (\n <CheckIcon className={cn(AI_ICON.sm, 'text-success')} aria-hidden />\n ) : (\n <CopyIcon className={AI_ICON.sm} aria-hidden />\n ))}\n {copyError ? 'Failed' : (copied ? 'Copied' : 'Copy')}\n </Button>\n ) : null}\n </div>\n );\n};\n\nExportConversationButton.displayName = 'ExportConversationButton';\n","/**\n * @fileoverview ContentPlaceholder Components - Premium Harmony V2\n *\n * Skeleton loading placeholders for non-text AI content (tables, code blocks,\n * images). Shows visual progress while content is being generated.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Shimmer/pulse animations\n * - Reduced motion support\n * - Variants for table, code, image, and generic content\n * - Configurable dimensions and row counts\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/content-placeholder\n * @component ContentPlaceholder, TablePlaceholder, CodePlaceholder, ImagePlaceholder\n *\n * @useCases\n * - Loading state while AI generates a table\n * - Loading state while AI generates a code block\n * - Loading state while AI generates an image\n * - Generic content loading skeleton\n *\n * @example\n * <TablePlaceholder rows={5} columns={3} />\n * <CodePlaceholder lines={10} language=\"python\" />\n * <ImagePlaceholder aspectRatio=\"16/9\" />\n */\n\n'use client';\n\nimport type { ComponentProps } from 'react';\nimport { useMemo } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_CONTAINER_RADIUS, AI_TEXT } from '../../ai-elements.constants';\n\nconst shimmerClass = (reducedMotion: boolean | undefined) =>\n !reducedMotion ? 'animate-pulse' : '';\n\n/**\n * Deterministic pseudo-random number generator based on seed.\n * Produces a value between 0 and 1 that is identical on SSR and client\n * for the same input, avoiding hydration mismatches from Math.random().\n */\nfunction seededRandom(seed: number): number {\n const x = Math.sin(seed + 1) * 10000;\n return x - Math.floor(x);\n}\n\nexport type ContentPlaceholderProps = ComponentProps<'div'> & {\n /** Number of placeholder lines */\n lines?: number;\n /** Label shown above the placeholder */\n label?: string;\n};\n\nexport const ContentPlaceholder = ({\n className,\n lines: linesProp = 3,\n label,\n ...props\n}: ContentPlaceholderProps) => {\n const reducedMotion = useReducedMotion();\n const lines = Math.max(0, Math.round(linesProp));\n\n return (\n <div\n className={cn('w-full space-y-2', className)}\n role=\"progressbar\"\n aria-label={label ?? 'Loading content'}\n aria-busy\n data-component=\"ContentPlaceholder\"\n {...props}\n >\n {label ? <p className={cn('text-muted-foreground', AI_TEXT.xs)}>{label}</p> : null}\n {Array.from({ length: lines }, (_, i) => (\n <div\n key={`line-${i}`}\n className={cn('bg-muted h-4 rounded', shimmerClass(reducedMotion))}\n style={{ width: `${Math.max(40, 100 - i * 15)}%` }}\n />\n ))}\n </div>\n );\n};\n\nexport type TablePlaceholderProps = ComponentProps<'div'> & {\n /** Number of table rows */\n rows?: number;\n /** Number of table columns */\n columns?: number;\n /** Label shown above the placeholder */\n label?: string;\n};\n\nexport const TablePlaceholder = ({\n className,\n rows: rowsProp = 4,\n columns: columnsProp = 3,\n label,\n ...props\n}: TablePlaceholderProps) => {\n const reducedMotion = useReducedMotion();\n const rows = Math.max(0, Math.round(rowsProp));\n const columns = Math.max(1, Math.round(columnsProp));\n\n const cellWidths = useMemo(\n () =>\n Array.from({ length: rows }, (_, rowIdx) =>\n Array.from(\n { length: columns },\n (_, colIdx) => 60 + seededRandom(rowIdx * columns + colIdx) * 30,\n ),\n ),\n [rows, columns],\n );\n\n return (\n <div\n className={cn('border-border w-full overflow-hidden rounded-lg border', className)}\n role=\"progressbar\"\n aria-label={label ?? 'Loading table'}\n aria-busy\n data-component=\"TablePlaceholder\"\n {...props}\n >\n {label ? (\n <div className=\"border-border border-b px-3 py-2\">\n <p className={cn('text-muted-foreground', AI_TEXT.xs)}>{label}</p>\n </div>\n ) : null}\n\n {/* Header row */}\n <div className=\"bg-muted/30 border-border flex border-b\">\n {Array.from({ length: columns }, (_, i) => (\n <div\n key={`col-header-${i}`}\n className=\"border-border/50 flex-1 border-r p-2 last:border-r-0\"\n >\n <div\n className={cn('bg-muted h-3.5 rounded', shimmerClass(reducedMotion))}\n style={{ width: '70%' }}\n />\n </div>\n ))}\n </div>\n\n {/* Data rows */}\n {cellWidths.map(rowWidths => (\n <div key={rowWidths.join('-')} className=\"border-border flex border-b last:border-b-0\">\n {rowWidths.map(width => (\n <div\n key={`${width.toFixed(2)}`}\n className=\"border-border/50 flex-1 border-r p-2 last:border-r-0\"\n >\n <div\n className={cn('bg-muted h-3 rounded', shimmerClass(reducedMotion))}\n style={{ width: `${width}%` }}\n />\n </div>\n ))}\n </div>\n ))}\n </div>\n );\n};\n\nexport type CodePlaceholderProps = ComponentProps<'div'> & {\n /** Number of code lines */\n lines?: number;\n /** Language label */\n language?: string;\n /** Label shown above the placeholder */\n label?: string;\n};\n\nexport const CodePlaceholder = ({\n className,\n lines: linesProp = 8,\n language,\n label,\n ...props\n}: CodePlaceholderProps) => {\n const reducedMotion = useReducedMotion();\n const lines = Math.max(0, Math.round(linesProp));\n\n // Simulate code indentation patterns (memoized to avoid flicker on re-render)\n const lineWidths = useMemo(\n () =>\n Array.from({ length: lines }, (_, i) => {\n const indent = i % 4 === 0 || i === lines - 1 ? 0 : (i % 3 === 0 ? 1 : 2);\n const width = 30 + seededRandom(i + 100) * 50;\n return { indent, width };\n }),\n [lines],\n );\n\n return (\n <div\n className={cn('bg-muted/50 w-full overflow-hidden', AI_CONTAINER_RADIUS, className)}\n role=\"progressbar\"\n aria-label={label ?? `Loading ${language ? `${language} ` : ''}code`}\n aria-busy\n data-component=\"CodePlaceholder\"\n {...props}\n >\n {/* Header bar with language label */}\n <div className=\"flex items-center justify-between px-4 py-2\">\n <div className={cn('text-muted-foreground', AI_TEXT.xs)}>{language ?? 'code'}</div>\n <div className={cn('bg-muted h-3 w-12 rounded', shimmerClass(reducedMotion))} />\n </div>\n\n {/* Code lines */}\n <div className=\"space-y-1.5 px-4 pb-4\">\n {lineWidths.map(({ indent, width }) => (\n <div\n key={`indent-${indent}-width-${width.toFixed(2)}`}\n style={{ paddingLeft: `${indent * 16}px` }}\n >\n <div\n className={cn('bg-muted h-3 rounded', shimmerClass(reducedMotion))}\n style={{ width: `${width}%` }}\n />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport type ImagePlaceholderProps = ComponentProps<'div'> & {\n /** CSS aspect ratio (e.g., \"16/9\", \"1/1\", \"4/3\") */\n aspectRatio?: string;\n /** Width of the placeholder */\n width?: number | string;\n /** Label shown below the placeholder */\n label?: string;\n /** Show a progress percentage */\n progress?: number;\n};\n\nexport const ImagePlaceholder = ({\n className,\n aspectRatio = '16/9',\n width = '100%',\n label,\n progress: progressProp,\n ...props\n}: ImagePlaceholderProps) => {\n const reducedMotion = useReducedMotion();\n const progress =\n progressProp !== undefined && Number.isFinite(progressProp)\n ? Math.min(100, Math.max(0, progressProp))\n : undefined;\n\n return (\n <div\n className={cn('space-y-2', className)}\n role=\"progressbar\"\n aria-label={label ?? 'Loading image'}\n aria-busy\n {...(progress !== undefined\n ? { 'aria-valuenow': progress, 'aria-valuemin': 0, 'aria-valuemax': 100 }\n : {})}\n data-component=\"ImagePlaceholder\"\n {...props}\n >\n <div\n className={cn(\n 'bg-muted/50 border-border flex items-center justify-center overflow-hidden border',\n AI_CONTAINER_RADIUS,\n shimmerClass(reducedMotion),\n )}\n style={{ aspectRatio, width }}\n >\n <div className=\"text-muted-foreground/40 flex flex-col items-center gap-2\">\n <svg\n className=\"size-8\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n viewBox=\"0 0 24 24\"\n role=\"img\"\n aria-label=\"Image placeholder\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909M3.75 21h16.5a1.5 1.5 0 0 0 1.5-1.5V4.5a1.5 1.5 0 0 0-1.5-1.5H3.75a1.5 1.5 0 0 0-1.5 1.5v15a1.5 1.5 0 0 0 1.5 1.5Z\"\n />\n </svg>\n {progress !== undefined ? (\n <span className={cn('text-muted-foreground', AI_TEXT.xs)}>{Math.round(progress)}%</span>\n ) : null}\n </div>\n </div>\n\n {label ? (\n <p className={cn('text-muted-foreground text-center', AI_TEXT.xs)}>{label}</p>\n ) : null}\n\n {progress !== undefined ? (\n <div className=\"bg-muted h-1 w-full overflow-hidden rounded-full\">\n <div\n className=\"bg-primary h-full rounded-full transition-all duration-300\"\n style={{ width: `${Math.min(100, Math.max(0, progress))}%` }}\n />\n </div>\n ) : null}\n </div>\n );\n};\n\nContentPlaceholder.displayName = 'ContentPlaceholder';\nTablePlaceholder.displayName = 'TablePlaceholder';\nCodePlaceholder.displayName = 'CodePlaceholder';\nImagePlaceholder.displayName = 'ImagePlaceholder';\n","/**\n * @fileoverview TokenUsage Component - Premium Harmony V2\n *\n * Displays AI token consumption, cost estimates, and usage limits.\n * Designed for enterprise AI governance and cost awareness.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Token count display (input/output/total)\n * - Cost estimate with currency formatting\n * - Progress bar toward usage limits\n * - Reduced motion support\n * - Compact and expanded variants\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/token-usage\n * @component TokenUsage, TokenUsageBar\n *\n * @useCases\n * - Display token counts in prompt input footer\n * - Show cost estimates per conversation\n * - Progress toward daily/monthly token limits\n * - Enterprise billing awareness\n *\n * @example\n * <TokenUsage inputTokens={150} outputTokens={420} />\n * <TokenUsage inputTokens={150} outputTokens={420} cost={0.0023} limit={10000} />\n * <TokenUsageBar used={7500} limit={10000} />\n */\n\n'use client';\n\nimport type { ComponentProps } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_SPACING, AI_TEXT, SPRING_GENTLE } from '../../ai-elements.constants';\n\nexport type TokenUsageProps = HTMLMotionProps<'div'> & {\n /** Input token count */\n inputTokens?: number;\n /** Output token count */\n outputTokens?: number;\n /** Total tokens (if different from input + output) */\n totalTokens?: number;\n /** Estimated cost in USD */\n cost?: number;\n /** Token limit for progress display */\n limit?: number;\n /** Currency code for cost formatting */\n currency?: string;\n /** Compact display (single line) */\n compact?: boolean;\n /** Model name for context */\n model?: string;\n};\n\nconst formatNumber = (n: number): string => {\n if (!Number.isFinite(n) || n < 0) return '0';\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;\n return n.toLocaleString();\n};\n\nconst formatCost = (cost: number, currency: string): string => {\n if (!Number.isFinite(cost)) return '$0.0000';\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n minimumFractionDigits: 4,\n maximumFractionDigits: 4,\n }).format(cost);\n } catch {\n // Invalid currency code -- fall back to plain number\n return `${cost.toFixed(4)} ${currency}`;\n }\n};\n\nexport const TokenUsage = ({\n className,\n inputTokens,\n outputTokens,\n totalTokens: totalTokensProp,\n cost,\n limit,\n currency = 'USD',\n compact = false,\n model,\n ...props\n}: TokenUsageProps) => {\n const reducedMotion = useReducedMotion();\n\n const total = totalTokensProp ?? (inputTokens ?? 0) + (outputTokens ?? 0);\n const safeLimit = limit !== undefined && Number.isFinite(limit) && limit > 0 ? limit : undefined;\n const percentage = safeLimit ? Math.min(100, (total / safeLimit) * 100) : undefined;\n const isNearLimit = percentage !== undefined && percentage >= 80;\n const isOverLimit = percentage !== undefined && percentage >= 100;\n\n if (compact) {\n return (\n <motion.div\n className={cn(\n 'text-muted-foreground flex items-center',\n AI_SPACING.xs,\n AI_TEXT.xs,\n className,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"TokenUsage\"\n data-compact\n role=\"status\"\n aria-label={`Token usage: ${formatNumber(total)} tokens${cost ? `, cost: ${formatCost(cost, currency)}` : ''}`}\n {...props}\n >\n <span className=\"tabular-nums\">{formatNumber(total)} tokens</span>\n {cost !== undefined ? (\n <>\n <span className=\"text-border\">·</span>\n <span className=\"tabular-nums\">{formatCost(cost, currency)}</span>\n </>\n ) : null}\n {safeLimit ? (\n <>\n <span className=\"text-border\">·</span>\n <span\n className={cn(\n 'tabular-nums',\n isOverLimit && 'text-destructive',\n isNearLimit && !isOverLimit && 'text-warning',\n )}\n >\n {formatNumber(total)}/{formatNumber(safeLimit)}\n </span>\n </>\n ) : null}\n </motion.div>\n );\n }\n\n return (\n <motion.div\n className={cn('space-y-1.5', className)}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"TokenUsage\"\n role=\"region\"\n aria-label=\"Token usage details\"\n {...props}\n >\n <div\n className={cn(\n 'text-muted-foreground flex flex-wrap items-center justify-between',\n AI_TEXT.xs,\n )}\n >\n <div className={cn('flex items-center', AI_SPACING.sm)}>\n {inputTokens !== undefined ? (\n <span>\n <span className=\"font-medium\">In:</span>{' '}\n <span className=\"tabular-nums\">{formatNumber(inputTokens)}</span>\n </span>\n ) : null}\n {outputTokens !== undefined ? (\n <span>\n <span className=\"font-medium\">Out:</span>{' '}\n <span className=\"tabular-nums\">{formatNumber(outputTokens)}</span>\n </span>\n ) : null}\n <span>\n <span className=\"font-medium\">Total:</span>{' '}\n <span className=\"tabular-nums\">{formatNumber(total)}</span>\n </span>\n </div>\n\n <div className={cn('flex items-center', AI_SPACING.sm)}>\n {model ? <span className=\"text-muted-foreground/70\">{model}</span> : null}\n {cost !== undefined ? (\n <span className=\"font-medium tabular-nums\">{formatCost(cost, currency)}</span>\n ) : null}\n </div>\n </div>\n\n {safeLimit ? <TokenUsageBar used={total} limit={safeLimit} /> : null}\n </motion.div>\n );\n};\n\nexport type TokenUsageBarProps = ComponentProps<'div'> & {\n /** Tokens used */\n used: number;\n /** Token limit */\n limit: number;\n};\n\nexport const TokenUsageBar = ({ className, used, limit, ...props }: TokenUsageBarProps) => {\n const percentage = limit > 0 ? Math.min(100, (used / limit) * 100) : 0;\n const isNearLimit = percentage >= 80;\n const isOverLimit = percentage >= 100;\n\n const barColor = isOverLimit ? 'bg-destructive' : (isNearLimit ? 'bg-warning' : 'bg-primary');\n\n return (\n <div className={cn('space-y-0.5', className)} {...props}>\n <div className=\"bg-muted h-1.5 w-full overflow-hidden rounded-full\">\n <div\n className={cn(barColor, 'h-full rounded-full transition-all duration-500')}\n style={{ width: `${percentage}%` }}\n role=\"progressbar\"\n aria-valuenow={used}\n aria-valuemin={0}\n aria-valuemax={limit}\n aria-label={`${formatNumber(used)} of ${formatNumber(limit)} tokens used`}\n />\n </div>\n <div className={cn('text-muted-foreground flex justify-between', AI_TEXT.xs)}>\n <span\n className={cn(\n isOverLimit && 'text-destructive',\n isNearLimit && !isOverLimit && 'text-warning',\n )}\n >\n {Math.round(percentage)}% used\n </span>\n <span className=\"tabular-nums\">{formatNumber(Math.max(0, limit - used))} remaining</span>\n </div>\n </div>\n );\n};\n\nTokenUsage.displayName = 'TokenUsage';\nTokenUsageBar.displayName = 'TokenUsageBar';\n","/**\n * @fileoverview MessageGroup Component - Premium Harmony V2\n *\n * Groups consecutive messages from the same sender to reduce visual clutter.\n * Shows avatar only on the first message and uses compact spacing between\n * grouped messages for a cleaner conversation thread.\n *\n * Features:\n * - Compact spacing mode for grouped messages\n * - Sender-based styling (user, assistant, system)\n * - Semantic data attributes for styling hooks\n * - Accessible role and labelling\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/message-group\n * @component MessageGroup\n *\n * @useCases\n * - Grouping consecutive messages from the same sender\n * - Reducing visual spacing between related messages\n * - Chat thread organization with sender-aware styling\n * - Multi-turn conversation display optimization\n *\n * @example\n * <MessageGroup from=\"assistant\">\n * <Message>Hello! How can I help?</Message>\n * <Message>I can assist with coding, writing, and more.</Message>\n * </MessageGroup>\n *\n * @example\n * <MessageGroup from=\"user\" compact>\n * <Message>Can you help me with React?</Message>\n * <Message>Specifically with hooks.</Message>\n * </MessageGroup>\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_SPACING } from '../../ai-elements.constants';\n\nexport type MessageGroupProps = HTMLAttributes<HTMLDivElement> & {\n /** The sender of the messages in this group */\n from: 'user' | 'assistant' | 'system';\n /** Compact spacing between grouped messages */\n compact?: boolean;\n};\n\n/**\n * MessageGroup - Groups consecutive messages from the same sender.\n *\n * Reduces visual spacing between grouped messages and provides\n * sender-based data attributes for styling. Show the avatar only\n * on the first child message for a cleaner look.\n */\nexport const MessageGroup = ({\n className,\n from,\n compact = false,\n children,\n ...props\n}: MessageGroupProps) => (\n <div\n className={cn('flex flex-col', compact ? AI_SPACING.xs : AI_SPACING.sm, className)}\n role=\"group\"\n aria-label={`Messages from ${from}`}\n data-component=\"MessageGroup\"\n data-from={from}\n data-compact={compact || undefined}\n {...props}\n >\n {children}\n </div>\n);\n\nMessageGroup.displayName = 'MessageGroup';\n","/**\n * @fileoverview MessageSeparator Component - Premium Harmony V2\n *\n * A date/time divider between message groups. Displays a horizontal rule\n * with a centered label showing a relative or absolute date string.\n * Automatically formats timestamps as \"Today\", \"Yesterday\", or a\n * locale-formatted date.\n *\n * Features:\n * - Auto-formatting of Date objects to relative labels\n * - Manual label override\n * - Semantic separator role for accessibility\n * - AI design token integration\n * - Muted styling that blends into conversation flow\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/message-separator\n * @component MessageSeparator\n *\n * @useCases\n * - Date dividers between chat message groups\n * - Session boundary markers in conversation history\n * - \"New messages\" separator in real-time chat\n * - Temporal context in long conversation threads\n *\n * @example\n * <MessageSeparator label=\"Today\" />\n *\n * @example\n * <MessageSeparator timestamp={new Date()} />\n *\n * @example\n * <MessageSeparator timestamp={new Date('2026-01-15')} />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_BODY, AI_PADDING } from '../../ai-elements.constants';\n\nexport type MessageSeparatorProps = HTMLAttributes<HTMLDivElement> & {\n /** The label to display (e.g., \"Today\", \"Yesterday\", \"Jan 15, 2026\") */\n label?: string;\n /** Timestamp to auto-format as relative date */\n timestamp?: Date;\n};\n\n/**\n * Formats a Date as an absolute string: \"MMM DD, YYYY\".\n * This is deterministic (same input always produces the same output)\n * and safe for SSR since it does not depend on the current time.\n */\nfunction formatAbsoluteDate(date: Date): string {\n return new Intl.DateTimeFormat(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n }).format(date);\n}\n\n/**\n * Formats a Date as a relative label: \"Today\", \"Yesterday\", or \"MMM DD, YYYY\".\n * Uses `new Date()` internally, so must only be called on the client\n * (inside useEffect) to avoid SSR hydration mismatches.\n */\nfunction formatRelativeDate(date: Date): string {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n const diffMs = today.getTime() - target.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n\n return formatAbsoluteDate(date);\n}\n\n/**\n * MessageSeparator - Date/time divider between message groups.\n *\n * Shows a horizontal line with a centered label. If a `timestamp` is\n * provided without a `label`, the component auto-formats it as a\n * relative date string.\n */\nexport const MessageSeparator = ({\n className,\n label,\n timestamp,\n ...props\n}: MessageSeparatorProps) => {\n // Use the deterministic absolute date for SSR; upgrade to relative (\"Today\",\n // \"Yesterday\") after hydration to avoid mismatch from `new Date()` in render.\n const ssrLabel = useMemo(() => {\n if (label) return label;\n if (timestamp) return formatAbsoluteDate(timestamp);\n return;\n }, [label, timestamp]);\n\n const [displayLabel, setDisplayLabel] = useState(ssrLabel);\n\n useEffect(() => {\n if (label) {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setDisplayLabel(label);\n } else if (timestamp) {\n setDisplayLabel(formatRelativeDate(timestamp));\n } else {\n setDisplayLabel(undefined);\n }\n }, [label, timestamp]);\n\n return (\n <div\n className={cn('flex items-center', AI_PADDING.compact, className)}\n role=\"separator\"\n aria-label={displayLabel}\n data-component=\"MessageSeparator\"\n {...props}\n >\n <hr className=\"border-border flex-1 border-t\" aria-hidden=\"true\" />\n {displayLabel ? (\n <span className={cn(AI_BODY.small, 'shrink-0 px-3 select-none')}>{displayLabel}</span>\n ) : null}\n <hr className=\"border-border flex-1 border-t\" aria-hidden=\"true\" />\n </div>\n );\n};\n\nMessageSeparator.displayName = 'MessageSeparator';\n","/**\n * @fileoverview ConversationHeader Component - Premium Harmony V2\n *\n * A header bar for the chat area using a compound component pattern.\n * Provides slots for a back button, title, subtitle, and trailing actions.\n *\n * Features:\n * - Compound component pattern (Title, Subtitle, Back, Actions)\n * - Responsive layout with left/center/right zones\n * - Spring-animated back button with reduced motion support\n * - Touch-friendly 44px targets\n * - AI design token integration\n * - Semantic heading structure\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/conversation-header\n * @component ConversationHeader, ConversationHeaderTitle, ConversationHeaderSubtitle, ConversationHeaderBack, ConversationHeaderActions\n *\n * @useCases\n * - Chat window header with title and back navigation\n * - Conversation thread header with participant info\n * - AI assistant header with model name and actions\n * - Mobile chat header with navigation affordance\n *\n * @example\n * <ConversationHeader>\n * <ConversationHeaderBack onBack={() => router.back()} />\n * <ConversationHeaderTitle>New Conversation</ConversationHeaderTitle>\n * <ConversationHeaderSubtitle>Claude 3.5 Sonnet</ConversationHeaderSubtitle>\n * <ConversationHeaderActions>\n * <Button variant=\"ghost\" size=\"icon\"><SettingsIcon /></Button>\n * </ConversationHeaderActions>\n * </ConversationHeader>\n */\n\n'use client';\n\nimport type { ComponentProps, HTMLAttributes } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { ArrowLeftIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_BODY,\n AI_FOCUS,\n AI_ICON,\n AI_PADDING,\n AI_SPACING,\n AI_TITLE,\n AI_TRANSITION,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\n/* -----------------------------------------------------------------\n * ConversationHeader (root)\n * ----------------------------------------------------------------- */\n\nexport type ConversationHeaderProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * ConversationHeader - Root header bar for the chat area.\n *\n * Layout: Back button on left, title/subtitle center-left, actions on right.\n * Min height 56px with a bottom border.\n */\nexport const ConversationHeader = ({ className, children, ...props }: ConversationHeaderProps) => (\n <header\n className={cn(\n 'border-border flex min-h-14 items-center border-b',\n AI_PADDING.standard,\n AI_SPACING.sm,\n className,\n )}\n data-component=\"ConversationHeader\"\n {...props}\n >\n {children}\n </header>\n);\n\n/* -----------------------------------------------------------------\n * ConversationHeaderTitle\n * ----------------------------------------------------------------- */\n\nexport type ConversationHeaderTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\n/**\n * ConversationHeaderTitle - Heading element for the conversation title.\n */\nexport const ConversationHeaderTitle = ({\n className,\n children,\n ...props\n}: ConversationHeaderTitleProps) => (\n <h2\n className={cn(AI_TITLE.primary, 'truncate', className)}\n data-component=\"ConversationHeaderTitle\"\n {...props}\n >\n {children}\n </h2>\n);\n\n/* -----------------------------------------------------------------\n * ConversationHeaderSubtitle\n * ----------------------------------------------------------------- */\n\nexport type ConversationHeaderSubtitleProps = HTMLAttributes<HTMLParagraphElement>;\n\n/**\n * ConversationHeaderSubtitle - Secondary text below the title (model name, status, etc.).\n */\nexport const ConversationHeaderSubtitle = ({\n className,\n children,\n ...props\n}: ConversationHeaderSubtitleProps) => (\n <p\n className={cn(AI_BODY.small, 'truncate', className)}\n data-component=\"ConversationHeaderSubtitle\"\n {...props}\n >\n {children}\n </p>\n);\n\n/* -----------------------------------------------------------------\n * ConversationHeaderBack\n * ----------------------------------------------------------------- */\n\nexport type ConversationHeaderBackProps = ComponentProps<typeof Button> & {\n /** Callback when the back button is clicked */\n onBack?: () => void;\n};\n\n/**\n * ConversationHeaderBack - Back navigation button with spring animation.\n */\nexport const ConversationHeaderBack = ({\n className,\n onBack,\n onClick,\n ...props\n}: ConversationHeaderBackProps) => {\n const reducedMotion = useReducedMotion();\n\n return (\n <motion.div\n whileHover={reducedMotion ? undefined : { x: -2, transition: SPRING_TACTILE }}\n whileTap={reducedMotion ? undefined : { scale: 0.95, transition: SPRING_TACTILE }}\n >\n <Button\n {...props}\n className={cn('shrink-0', AI_TRANSITION.colors, AI_FOCUS.ring, className)}\n variant=\"ghost\"\n size=\"icon\"\n type=\"button\"\n onClick={onBack ?? onClick}\n aria-label=\"Go back\"\n data-component=\"ConversationHeaderBack\"\n >\n <ArrowLeftIcon className={AI_ICON.md} />\n </Button>\n </motion.div>\n );\n};\n\n/* -----------------------------------------------------------------\n * ConversationHeaderActions\n * ----------------------------------------------------------------- */\n\nexport type ConversationHeaderActionsProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * ConversationHeaderActions - Container for trailing action buttons.\n * Pushes itself to the right via ml-auto.\n */\nexport const ConversationHeaderActions = ({\n className,\n children,\n ...props\n}: ConversationHeaderActionsProps) => (\n <div\n className={cn('ml-auto flex shrink-0 items-center', AI_SPACING.xs, className)}\n data-component=\"ConversationHeaderActions\"\n {...props}\n >\n {children}\n </div>\n);\n\n/* -----------------------------------------------------------------\n * Display names\n * ----------------------------------------------------------------- */\n\nConversationHeader.displayName = 'ConversationHeader';\nConversationHeaderTitle.displayName = 'ConversationHeaderTitle';\nConversationHeaderSubtitle.displayName = 'ConversationHeaderSubtitle';\nConversationHeaderBack.displayName = 'ConversationHeaderBack';\nConversationHeaderActions.displayName = 'ConversationHeaderActions';\n","/**\n * @fileoverview Welcome Component - Premium Harmony V2\n *\n * An onboarding welcome screen shown in empty chat states. Displays an\n * AI persona with avatar, greeting, description, and starter prompt chips.\n * Prompt chips use spring physics animations for delightful interaction.\n *\n * Features:\n * - Premium Harmony V2 spring physics on prompt chips\n * - Touch vs desktop detection (44px touch targets)\n * - Reduced motion support\n * - Centered vertical layout with flexible slots\n * - Stagger animation for prompt chips\n * - Accessible focus management\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/welcome\n * @component Welcome\n *\n * @useCases\n * - Empty chat state onboarding screen\n * - AI assistant introduction with persona\n * - Starter prompt suggestions for first-time users\n * - Capability overview for AI interfaces\n * - Persona-driven conversation starters\n *\n * @example\n * <Welcome\n * name=\"Claude\"\n * greeting=\"Hello! I'm Claude.\"\n * description=\"I can help with coding, writing, analysis, and more.\"\n * icon={<BotIcon className=\"size-10\" />}\n * prompts={[\n * { label: 'Write a poem', value: 'Write me a short poem about nature' },\n * { label: 'Explain React hooks', value: 'Explain React hooks to me' },\n * ]}\n * onPromptClick={(value) => sendMessage(value)}\n * />\n */\n\n'use client';\n\nimport type * as React from 'react';\nimport { useMemo } from 'react';\n\nimport { useMediaQuery, useReducedMotion } from '@mantine/hooks';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_BODY,\n AI_FOCUS,\n AI_SPACING,\n AI_TEXT,\n AI_TITLE,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\nexport type WelcomeProps = Omit<HTMLMotionProps<'div'>, 'ref' | 'children'> & {\n /** AI persona name */\n name?: string;\n /** Greeting message */\n greeting?: string;\n /** Description of the AI's capabilities */\n description?: string;\n /** Avatar/icon for the AI persona */\n icon?: React.ReactNode;\n /** Starter prompt suggestions */\n prompts?: { label: string; value: string }[];\n /** Callback when a prompt is clicked */\n onPromptClick?: (value: string) => void;\n children?: React.ReactNode;\n};\n\n/**\n * Welcome - Onboarding welcome screen shown in empty chat.\n *\n * Vertically centered layout with icon at top, name as heading,\n * greeting below, description as muted text, and prompt chips\n * at the bottom in a flex-wrap grid.\n */\nexport const Welcome = ({\n className,\n name,\n greeting,\n description,\n icon,\n prompts,\n onPromptClick,\n children,\n ...props\n}: WelcomeProps) => {\n const reducedMotion = useReducedMotion();\n const isTouchDevice = useMediaQuery('(pointer: coarse)');\n\n const containerVariants = useMemo(\n () => ({\n hidden: { opacity: reducedMotion ? 1 : 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: reducedMotion ? 0 : 0.06,\n },\n },\n }),\n [reducedMotion],\n );\n\n const itemVariants = useMemo(\n () => ({\n hidden: {\n opacity: reducedMotion ? 1 : 0,\n y: reducedMotion ? 0 : 8,\n },\n visible: {\n opacity: 1,\n y: 0,\n transition: reducedMotion ? { duration: 0 } : SPRING_GENTLE,\n },\n }),\n [reducedMotion],\n );\n\n return (\n <motion.div\n className={cn(\n 'flex size-full flex-col items-center justify-center p-8 text-center',\n AI_SPACING.lg,\n className,\n )}\n variants={containerVariants}\n initial=\"hidden\"\n animate=\"visible\"\n data-component=\"Welcome\"\n role=\"region\"\n aria-label={name ? `Welcome - ${name}` : 'Welcome'}\n {...props}\n >\n {children ?? (\n <>\n {/* Icon / Avatar */}\n {icon ? (\n <motion.div className=\"text-muted-foreground\" variants={itemVariants}>\n {icon}\n </motion.div>\n ) : null}\n\n {/* Name heading */}\n {name ? (\n <motion.h2 className={cn(AI_TITLE.primary, AI_TEXT.lg)} variants={itemVariants}>\n {name}\n </motion.h2>\n ) : null}\n\n {/* Greeting */}\n {greeting ? (\n <motion.p className={cn(AI_BODY.primary, AI_TEXT.base)} variants={itemVariants}>\n {greeting}\n </motion.p>\n ) : null}\n\n {/* Description */}\n {description ? (\n <motion.p\n className={cn(AI_BODY.secondary, AI_TEXT.sm, 'max-w-md')}\n variants={itemVariants}\n >\n {description}\n </motion.p>\n ) : null}\n\n {/* Prompt chips */}\n {prompts && prompts.length > 0 ? (\n <motion.div\n className={cn('flex max-w-lg flex-wrap justify-center', AI_SPACING.xs, 'pt-2')}\n variants={itemVariants}\n role=\"group\"\n aria-label=\"Suggested prompts\"\n >\n {prompts.map((prompt, index) => (\n <motion.button\n key={prompt.value ?? index}\n type=\"button\"\n onClick={() => onPromptClick?.(prompt.value)}\n className={cn(\n 'border-border min-h-11 rounded-full border px-4 py-2',\n AI_TEXT.sm,\n 'text-muted-foreground',\n AI_TRANSITION.colors,\n 'duration-150',\n 'hover:border-foreground/30 hover:text-foreground',\n AI_FOCUS.ring,\n )}\n whileHover={\n reducedMotion || isTouchDevice\n ? undefined\n : { scale: 1.03, transition: SPRING_TACTILE }\n }\n whileTap={reducedMotion ? undefined : { scale: 0.97, transition: SPRING_TACTILE }}\n >\n {prompt.label}\n </motion.button>\n ))}\n </motion.div>\n ) : null}\n </>\n )}\n </motion.div>\n );\n};\n\nWelcome.displayName = 'Welcome';\n","/**\n * @fileoverview FileCard Component - Premium Harmony V2\n *\n * Displays file metadata (name, size, type, icon) for file attachments\n * in AI chat messages. Automatically selects an appropriate icon based on\n * MIME type and formats file size into human-readable units.\n *\n * Features:\n * - MIME-type-aware icon selection (text, image, code, generic)\n * - Auto-formatted file size (bytes, KB, MB, GB)\n * - Loading state with pulse animation\n * - Optional download link via href\n * - Optional remove button with spring animation\n * - Reduced motion support\n * - Touch-friendly interaction targets\n * - AI design token integration\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/file-card\n * @component FileCard\n *\n * @useCases\n * - File attachments in chat messages\n * - Upload previews in the compose area\n * - Document references in AI responses\n * - Download links for generated artifacts\n * - File list in conversation context\n *\n * @example\n * <FileCard name=\"report.pdf\" size={1024000} mimeType=\"application/pdf\" />\n *\n * @example\n * <FileCard\n * name=\"screenshot.png\"\n * size={2048576}\n * mimeType=\"image/png\"\n * href=\"/files/screenshot.png\"\n * onRemove={() => removeFile('screenshot.png')}\n * />\n *\n * @example\n * <FileCard name=\"data.csv\" size={512} isLoading />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useCallback, useMemo } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport {\n FileCodeIcon,\n FileIcon,\n FileImageIcon,\n FileTextIcon,\n Loader2Icon,\n XIcon,\n} from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_BODY,\n AI_CONTAINER,\n AI_FOCUS,\n AI_ICON,\n AI_SPACING,\n AI_TRANSITION,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\nexport type FileCardProps = HTMLAttributes<HTMLDivElement> & {\n /** File name */\n name: string;\n /** File size in bytes (auto-formatted) */\n size?: number;\n /** MIME type */\n mimeType?: string;\n /** Whether the file is downloading/uploading */\n isLoading?: boolean;\n /** Download URL */\n href?: string;\n /** Remove callback */\n onRemove?: () => void;\n};\n\n/** MIME types that should display the code file icon. */\nconst CODE_MIME_TYPES = new Set([\n 'application/json',\n 'application/javascript',\n 'application/typescript',\n 'application/xml',\n 'application/x-python',\n 'application/x-sh',\n 'application/x-yaml',\n 'text/html',\n 'text/css',\n 'text/javascript',\n]);\n\n/**\n * Returns the appropriate lucide icon component based on MIME type.\n */\nfunction getFileIcon(mimeType?: string): typeof FileIcon {\n if (!mimeType) return FileIcon;\n\n if (mimeType.startsWith('image/')) return FileImageIcon;\n\n if (CODE_MIME_TYPES.has(mimeType)) return FileCodeIcon;\n\n if (mimeType.startsWith('text/')) return FileTextIcon;\n\n if (\n mimeType === 'application/pdf' ||\n mimeType === 'application/msword' ||\n mimeType.includes('wordprocessingml') ||\n mimeType.includes('spreadsheetml') ||\n mimeType.includes('presentationml')\n ) {\n return FileTextIcon;\n }\n\n return FileIcon;\n}\n\n/**\n * Formats bytes into a human-readable string (KB, MB, GB).\n */\nfunction formatFileSize(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';\n\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), units.length - 1);\n const value = bytes / k ** i;\n\n return `${value < 10 && i > 0 ? value.toFixed(1) : Math.round(value)} ${units[i]}`;\n}\n\n/**\n * FileCard - Displays file metadata with type-aware icon and auto-formatted size.\n *\n * Shows a file type icon, truncated filename, formatted size, and optional\n * remove button. Supports loading state and download link.\n */\nexport const FileCard = ({\n className,\n name,\n size,\n mimeType,\n isLoading = false,\n href,\n onRemove,\n ...props\n}: FileCardProps) => {\n const reducedMotion = useReducedMotion();\n\n const formattedSize = useMemo(\n () => (size !== undefined ? formatFileSize(size) : undefined),\n [size],\n );\n\n const handleRemove = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemove?.();\n },\n [onRemove],\n );\n\n // Render icon based on mime type - avoids dynamic component creation\n const renderFileIcon = () => {\n const iconClassName = AI_ICON.lg;\n const IconComponent = getFileIcon(mimeType);\n return <IconComponent className={iconClassName} aria-hidden />;\n };\n\n const content = (\n <div\n className={cn(\n AI_CONTAINER.cardCompact,\n 'flex items-center',\n AI_SPACING.sm,\n 'max-w-xs',\n isLoading && !reducedMotion && 'animate-pulse',\n className,\n )}\n data-component=\"FileCard\"\n data-loading={isLoading}\n data-mime={mimeType}\n {...props}\n >\n {/* File icon */}\n <div className=\"text-muted-foreground shrink-0\">\n {isLoading ? (\n <Loader2Icon className={cn(AI_ICON.lg, 'animate-spin')} aria-hidden />\n ) : (\n renderFileIcon()\n )}\n </div>\n\n {/* File info */}\n <div className=\"min-w-0 flex-1\">\n <p className={cn(AI_BODY.primary, 'truncate font-medium')} title={name}>\n {name}\n </p>\n {formattedSize ? <p className={cn(AI_BODY.small)}>{formattedSize}</p> : null}\n </div>\n\n {/* Remove button */}\n {onRemove ? (\n <motion.div\n className=\"shrink-0\"\n whileHover={reducedMotion ? undefined : { scale: 1.1, transition: SPRING_TACTILE }}\n whileTap={reducedMotion ? undefined : { scale: 0.9, transition: SPRING_TACTILE }}\n >\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn('size-7', AI_TRANSITION.colors, AI_FOCUS.ring)}\n onClick={handleRemove}\n type=\"button\"\n aria-label={`Remove ${name}`}\n >\n <XIcon className={AI_ICON.sm} />\n </Button>\n </motion.div>\n ) : null}\n </div>\n );\n\n if (href && !isLoading) {\n return (\n <a\n href={href}\n download={name}\n rel=\"noopener noreferrer\"\n className={cn('block no-underline', AI_TRANSITION.colors, 'hover:opacity-80')}\n aria-label={`Download ${name}`}\n >\n {content}\n </a>\n );\n }\n\n return content;\n};\n\nFileCard.displayName = 'FileCard';\n","/**\n * @fileoverview FileTree Component - Premium Harmony V2\n *\n * A hierarchical file/folder tree navigator for code agent interfaces.\n * Displays project structure with collapsible directories, file type icons,\n * and active-node highlighting. Commonly used by AI coding assistants\n * to show the project structure being operated on.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Collapsible directory nodes with chevron rotation\n * - Active/highlighted node support\n * - Reduced motion support\n * - Semantic design tokens\n * - Keyboard accessible\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/file-tree\n * @component FileTree, FileTreeItem\n *\n * @useCases\n * - Display project file structure in code agent UIs\n * - Navigate to files from an AI-generated change list\n * - Highlight active or modified files in a diff view\n *\n * @example\n * <FileTree\n * nodes={[\n * { name: 'src', type: 'directory', children: [\n * { name: 'index.ts', type: 'file' },\n * { name: 'utils.ts', type: 'file', isActive: true },\n * ]},\n * { name: 'package.json', type: 'file' },\n * ]}\n * onNodeClick={(node, path) => console.log(path)}\n * defaultExpanded={['src']}\n * />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_CONTAINER,\n AI_FOCUS,\n AI_HOVER,\n AI_ICON,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\n// ============================================\n// TYPES\n// ============================================\n\n/**\n * Represents a single node in the file tree (file or directory).\n */\nexport type FileTreeNode = {\n /** Display name of the file or directory */\n name: string;\n /** Whether this is a file or directory */\n type: 'file' | 'directory';\n /** Child nodes (only for directories) */\n children?: FileTreeNode[];\n /** Whether the node is highlighted/active */\n isActive?: boolean;\n /** File language for icon coloring */\n language?: string;\n};\n\n/**\n * Props for the FileTree root component.\n */\nexport type FileTreeProps = HTMLAttributes<HTMLDivElement> & {\n /** Array of top-level file tree nodes */\n nodes: FileTreeNode[];\n /** Callback when a node is clicked, receives node and full path */\n onNodeClick?: (node: FileTreeNode, path: string) => void;\n /** Initially expanded directory paths */\n defaultExpanded?: string[];\n};\n\n/**\n * Props for an individual FileTreeItem.\n */\nexport type FileTreeItemProps = HTMLAttributes<HTMLDivElement> & {\n /** The file tree node to render */\n node: FileTreeNode;\n /** Indentation depth (0-based) */\n depth: number;\n /** Full path from root to this node */\n path: string;\n /** Callback when a node is clicked */\n onNodeClick?: (node: FileTreeNode, path: string) => void;\n /** Array of directory paths that should be expanded by default */\n defaultExpanded?: string[];\n};\n\n// ============================================\n// FILE TREE ITEM\n// ============================================\n\n/**\n * A single item row in the file tree, either a file or a collapsible directory.\n */\nexport const FileTreeItem = ({\n node,\n depth,\n path,\n onNodeClick,\n defaultExpanded = [],\n className,\n ...props\n}: FileTreeItemProps) => {\n const defaultExpandedSet = useMemo(() => new Set(defaultExpanded), [defaultExpanded]);\n const [isExpanded, setIsExpanded] = useState(defaultExpandedSet.has(path));\n const reducedMotion = useReducedMotion();\n\n const isDirectory = node.type === 'directory';\n const hasChildren = isDirectory && node.children && node.children.length > 0;\n\n const handleClick = useCallback(() => {\n if (isDirectory) {\n setIsExpanded(prev => !prev);\n }\n onNodeClick?.(node, path);\n }, [isDirectory, node, path, onNodeClick]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick();\n }\n },\n [handleClick],\n );\n\n const DirectoryIcon = isExpanded ? FolderOpenIcon : FolderIcon;\n\n return (\n <div data-component=\"FileTreeItem\" role=\"none\" {...props}>\n <motion.div\n className={cn(\n 'flex cursor-pointer items-center gap-1.5 rounded-md px-1.5 py-1',\n AI_TEXT.sm,\n AI_TRANSITION.colors,\n AI_HOVER.bg,\n AI_FOCUS.ring,\n node.isActive && 'bg-accent/50 text-foreground',\n !node.isActive && 'text-muted-foreground',\n className,\n )}\n style={{ paddingLeft: `${depth * 16 + 6}px` }}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"treeitem\"\n tabIndex={0}\n aria-expanded={isDirectory ? isExpanded : undefined}\n aria-selected={node.isActive ?? false}\n whileHover={!reducedMotion ? { x: 1, transition: SPRING_TACTILE } : undefined}\n >\n {isDirectory ? (\n <motion.span\n animate={{ rotate: isExpanded ? 90 : 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_TACTILE}\n className=\"flex shrink-0 items-center\"\n >\n <ChevronRightIcon className={cn(AI_ICON.sm, 'text-muted-foreground')} aria-hidden />\n </motion.span>\n ) : (\n <span className=\"flex w-3.5 shrink-0 items-center\" />\n )}\n\n {isDirectory ? (\n <DirectoryIcon className={cn(AI_ICON.md, 'text-warning shrink-0')} aria-hidden />\n ) : (\n <FileIcon className={cn(AI_ICON.md, 'text-muted-foreground shrink-0')} aria-hidden />\n )}\n\n <span className=\"truncate\">{node.name}</span>\n </motion.div>\n\n <AnimatePresence initial={false}>\n {hasChildren && isExpanded ? (\n <motion.div\n key={`${path}-children`}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={reducedMotion ? { opacity: 0 } : { opacity: 0, height: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n role=\"group\"\n style={{ overflow: 'hidden' }}\n >\n {node.children?.map(child => {\n const childPath = `${path}/${child.name}`;\n return (\n <FileTreeItem\n key={childPath}\n node={child}\n depth={depth + 1}\n path={childPath}\n onNodeClick={onNodeClick}\n defaultExpanded={defaultExpanded}\n />\n );\n })}\n </motion.div>\n ) : null}\n </AnimatePresence>\n </div>\n );\n};\n\n// ============================================\n// FILE TREE\n// ============================================\n\n/**\n * Hierarchical file/folder tree navigator component.\n * Renders a recursive tree of files and directories with\n * expand/collapse, active highlighting, and click callbacks.\n */\nexport const FileTree = ({\n nodes,\n onNodeClick,\n defaultExpanded = [],\n className,\n ...props\n}: FileTreeProps) => {\n return (\n <div\n className={cn(AI_CONTAINER.subtle, 'overflow-hidden', className)}\n data-component=\"FileTree\"\n role=\"tree\"\n aria-label=\"File tree\"\n {...props}\n >\n {nodes.map(node => {\n const path = node.name;\n return (\n <FileTreeItem\n key={path}\n node={node}\n depth={0}\n path={path}\n onNodeClick={onNodeClick}\n defaultExpanded={defaultExpanded}\n />\n );\n })}\n </div>\n );\n};\n\nFileTree.displayName = 'FileTree';\nFileTreeItem.displayName = 'FileTreeItem';\n","/**\n * @fileoverview Terminal Component - Premium Harmony V2\n *\n * A terminal/console output display component for showing command output\n * with monospace font and dark background. Supports stdout, stderr,\n * command, and info line types with color differentiation.\n *\n * Features:\n * - macOS-style header with decorative dots\n * - Line-type coloring (stdout, stderr, command, info)\n * - Streaming mode with blinking cursor\n * - Premium Harmony V2 spring animations\n * - Reduced motion support\n * - Auto-scroll to bottom on new content\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/terminal\n * @component Terminal, TerminalHeader, TerminalContent\n *\n * @useCases\n * - Display command output in code agent UIs\n * - Show build/test logs from CI pipelines\n * - Stream real-time process output\n * - Display installation or migration script results\n *\n * @example\n * <Terminal\n * title=\"build output\"\n * lines={[\n * { content: '$ npm run build', type: 'command' },\n * { content: 'Compiling...', type: 'info' },\n * { content: 'Build succeeded', type: 'stdout' },\n * ]}\n * isStreaming={false}\n * />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useEffect, useRef } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { SPRING_GENTLE } from '../../ai-elements.constants';\n\nimport type { HTMLMotionProps } from 'motion/react';\n\n// ============================================\n// TYPES\n// ============================================\n\n/**\n * A single line of terminal output.\n */\nexport type TerminalLine = {\n /** The text content of the line */\n content: string;\n /** Line type for color differentiation */\n type?: 'stdout' | 'stderr' | 'command' | 'info';\n};\n\n/**\n * Props for the Terminal root component.\n */\nexport type TerminalProps = Omit<HTMLMotionProps<'div'>, 'ref'> & {\n /** Array of terminal output lines */\n lines: TerminalLine[];\n /** Title displayed in the terminal header */\n title?: string;\n /** Whether output is still streaming (shows blinking cursor) */\n isStreaming?: boolean;\n};\n\n/**\n * Props for the TerminalHeader sub-component.\n */\nexport type TerminalHeaderProps = HTMLAttributes<HTMLDivElement> & {\n /** Title text to display in the header */\n title?: string;\n};\n\n/**\n * Props for the TerminalContent sub-component.\n */\nexport type TerminalContentProps = HTMLAttributes<HTMLPreElement> & {\n /** Terminal lines to render */\n lines: TerminalLine[];\n /** Whether to show blinking cursor at the end */\n isStreaming?: boolean;\n};\n\n// ============================================\n// LINE TYPE STYLES\n// ============================================\n\nconst LINE_TYPE_STYLES: Record<NonNullable<TerminalLine['type']>, string> = {\n stdout: 'text-zinc-100',\n stderr: 'text-red-400',\n command: 'text-green-400',\n info: 'text-blue-400',\n};\n\n// ============================================\n// TERMINAL HEADER\n// ============================================\n\n/**\n * Terminal header with macOS-style decorative dots and title.\n */\nexport const TerminalHeader = ({ title, className, ...props }: TerminalHeaderProps) => {\n return (\n <div\n className={cn('flex items-center gap-2 border-b border-zinc-800 px-4 py-2.5', className)}\n data-component=\"TerminalHeader\"\n {...props}\n >\n {/* macOS-style decorative dots */}\n <div className=\"flex items-center gap-1.5\" aria-hidden>\n <span className=\"size-3 rounded-full bg-red-500/80\" />\n <span className=\"size-3 rounded-full bg-yellow-500/80\" />\n <span className=\"size-3 rounded-full bg-green-500/80\" />\n </div>\n\n {title ? <span className=\"ml-2 text-xs font-medium text-zinc-400\">{title}</span> : null}\n </div>\n );\n};\n\n// ============================================\n// TERMINAL CONTENT\n// ============================================\n\n/**\n * Terminal content area displaying lines with type-based coloring.\n */\nexport const TerminalContent = ({\n lines,\n isStreaming = false,\n className,\n ...props\n}: TerminalContentProps) => {\n const scrollRef = useRef<HTMLPreElement>(null);\n\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n // Only auto-scroll if user is already near the bottom (within 50px).\n // This prevents hijacking the scroll position when the user is reading\n // earlier output during streaming.\n const isNearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 50;\n if (isNearBottom) {\n el.scrollTop = el.scrollHeight;\n }\n }, [lines]);\n\n return (\n <pre\n ref={scrollRef}\n className={cn('overflow-auto p-4 font-mono text-sm leading-relaxed', className)}\n data-component=\"TerminalContent\"\n {...props}\n >\n {lines.map(line => (\n <div\n key={`${line.type ?? 'stdout'}-${line.content.slice(0, 50)}`}\n className={cn(LINE_TYPE_STYLES[line.type ?? 'stdout'])}\n >\n {line.type === 'command' ? (\n <>\n <span className=\"text-zinc-500\">$ </span>\n {line.content}\n </>\n ) : (\n line.content\n )}\n </div>\n ))}\n {isStreaming ? (\n <span className=\"inline-block animate-pulse text-zinc-100\" aria-hidden=\"true\">\n ▋\n </span>\n ) : null}\n </pre>\n );\n};\n\n// ============================================\n// TERMINAL\n// ============================================\n\n/**\n * Terminal/console output display component with dark background,\n * monospace font, and line-type coloring. Supports streaming mode\n * with a blinking cursor indicator.\n */\nexport const Terminal = ({\n lines,\n title,\n isStreaming = false,\n className,\n ...props\n}: TerminalProps) => {\n const reducedMotion = useReducedMotion();\n\n return (\n <motion.div\n className={cn(\n 'overflow-hidden rounded-lg bg-zinc-950 text-zinc-100',\n 'border border-zinc-800',\n className,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"Terminal\"\n data-streaming={isStreaming ? 'true' : undefined}\n role=\"log\"\n aria-label={title ? `Terminal: ${title}` : 'Terminal output'}\n aria-live={isStreaming ? 'polite' : undefined}\n {...props}\n >\n <TerminalHeader title={title} />\n <TerminalContent lines={lines} isStreaming={isStreaming} />\n </motion.div>\n );\n};\n\nTerminal.displayName = 'Terminal';\nTerminalHeader.displayName = 'TerminalHeader';\nTerminalContent.displayName = 'TerminalContent';\n","/**\n * @fileoverview StackTrace Component - Premium Harmony V2\n *\n * A formatted error stack trace display that parses and highlights\n * file paths, line numbers, and function names. Distinguishes between\n * user code and library frames, with collapsible library frame sections.\n *\n * Features:\n * - Error message display in destructive color\n * - User code vs library code frame differentiation\n * - Collapsible library frames with \"Show N more frames\" toggle\n * - Clickable frames for navigation\n * - Monospace font for code-like appearance\n * - Premium Harmony V2 spring animations\n * - Reduced motion support\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/stack-trace\n * @component StackTrace\n *\n * @useCases\n * - Display runtime errors in AI debugging interfaces\n * - Show stack traces from test failures\n * - Navigate to error locations in code agent UIs\n * - Present formatted error context to users\n *\n * @example\n * <StackTrace\n * error=\"TypeError: Cannot read properties of undefined (reading 'map')\"\n * frames={[\n * { functionName: 'renderList', fileName: 'src/components/List.tsx', lineNumber: 42, columnNumber: 12, isUserCode: true },\n * { functionName: 'React.createElement', fileName: 'node_modules/react/cjs/react.development.js', lineNumber: 1001, isUserCode: false },\n * ]}\n * collapseLibraryFrames\n * onFrameClick={(frame) => openFile(frame.fileName, frame.lineNumber)}\n * />\n */\n\n'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { AlertTriangleIcon, ChevronDownIcon, ChevronRightIcon } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_CONTAINER,\n AI_FOCUS,\n AI_HOVER,\n AI_ICON,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\nimport type { HTMLMotionProps } from 'motion/react';\n\n// ============================================\n// TYPES\n// ============================================\n\n/**\n * A single frame in a stack trace.\n */\nexport type StackFrame = {\n /** Function or method name at this frame */\n functionName?: string;\n /** Source file path */\n fileName: string;\n /** Line number in the source file */\n lineNumber?: number;\n /** Column number in the source file */\n columnNumber?: number;\n /** Whether this frame is from user code (vs library) */\n isUserCode?: boolean;\n};\n\n/**\n * Props for the StackTrace component.\n */\nexport type StackTraceProps = Omit<HTMLMotionProps<'div'>, 'ref'> & {\n /** The error message to display */\n error: string;\n /** Array of stack frames (top frame first) */\n frames: StackFrame[];\n /** Whether to initially collapse library frames */\n collapseLibraryFrames?: boolean;\n /** Callback when a frame row is clicked */\n onFrameClick?: (frame: StackFrame) => void;\n};\n\n// ============================================\n// HELPERS\n// ============================================\n\n/**\n * Formats a stack frame location as \"file:line:col\".\n */\nfunction formatLocation(frame: StackFrame): string {\n let loc = frame.fileName;\n if (frame.lineNumber !== undefined) {\n loc += `:${frame.lineNumber}`;\n if (frame.columnNumber !== undefined) {\n loc += `:${frame.columnNumber}`;\n }\n }\n return loc;\n}\n\n/**\n * Groups consecutive library frames into collapsible sections.\n */\nfunction groupFrames(\n frames: StackFrame[],\n): Array<{ type: 'user'; frame: StackFrame } | { type: 'library'; frames: StackFrame[] }> {\n const groups: Array<\n { type: 'user'; frame: StackFrame } | { type: 'library'; frames: StackFrame[] }\n > = [];\n\n let libraryBuffer: StackFrame[] = [];\n\n for (const frame of frames) {\n if (frame.isUserCode === true) {\n // Flush library buffer\n if (libraryBuffer.length > 0) {\n groups.push({ type: 'library', frames: [...libraryBuffer] });\n libraryBuffer = [];\n }\n groups.push({ type: 'user', frame });\n } else {\n libraryBuffer.push(frame);\n }\n }\n\n // Flush remaining library frames\n if (libraryBuffer.length > 0) {\n groups.push({ type: 'library', frames: libraryBuffer });\n }\n\n return groups;\n}\n\n// ============================================\n// STACK TRACE\n// ============================================\n\n/**\n * Formatted error stack trace display with file path highlighting,\n * user/library frame separation, and clickable frame navigation.\n */\nexport const StackTrace = ({\n error,\n frames,\n collapseLibraryFrames = true,\n onFrameClick,\n className,\n ...props\n}: StackTraceProps) => {\n const reducedMotion = useReducedMotion();\n const grouped = useMemo(() => groupFrames(frames), [frames]);\n\n if (frames.length === 0) {\n return (\n <motion.div\n className={cn(AI_CONTAINER.card, 'overflow-hidden', className)}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"StackTrace\"\n role=\"region\"\n aria-label=\"Error stack trace\"\n {...props}\n >\n <div className=\"flex items-start gap-2\">\n <AlertTriangleIcon\n className={cn(AI_ICON.md, 'text-destructive mt-0.5 shrink-0')}\n aria-hidden\n />\n <div>\n <p className=\"text-destructive font-mono text-sm font-medium\">{error}</p>\n <p className=\"text-muted-foreground mt-2 text-sm\">No stack trace available</p>\n </div>\n </div>\n </motion.div>\n );\n }\n\n return (\n <motion.div\n className={cn(AI_CONTAINER.card, 'overflow-hidden', className)}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"StackTrace\"\n role=\"region\"\n aria-label=\"Error stack trace\"\n {...props}\n >\n {/* Error message */}\n <div className=\"flex items-start gap-2 pb-3\">\n <AlertTriangleIcon\n className={cn(AI_ICON.md, 'text-destructive mt-0.5 shrink-0')}\n aria-hidden\n />\n <p className=\"text-destructive font-mono text-sm font-medium\">{error}</p>\n </div>\n\n {/* Stack frames */}\n <div className=\"space-y-0.5 font-mono\">\n {grouped.map((group, _groupIndex) => {\n if (group.type === 'user') {\n const { frame } = group;\n return (\n <FrameRow\n key={`user-${frame.fileName}:${frame.lineNumber ?? ''}:${frame.columnNumber ?? ''}`}\n frame={frame}\n isUserCode\n onClick={onFrameClick}\n />\n );\n }\n\n return (\n <LibraryFrameGroup\n key={`lib-group-${group.frames[0]?.fileName}:${group.frames[0]?.lineNumber ?? ''}`}\n frames={group.frames}\n defaultCollapsed={collapseLibraryFrames}\n onClick={onFrameClick}\n />\n );\n })}\n </div>\n </motion.div>\n );\n};\n\n// ============================================\n// FRAME ROW\n// ============================================\n\ntype FrameRowProps = {\n frame: StackFrame;\n isUserCode?: boolean;\n onClick?: (frame: StackFrame) => void;\n};\n\nconst FrameRow = ({ frame, isUserCode = false, onClick }: FrameRowProps) => {\n const reducedMotion = useReducedMotion();\n\n const handleClick = useCallback(() => {\n onClick?.(frame);\n }, [frame, onClick]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick();\n }\n },\n [handleClick],\n );\n\n return (\n <motion.div\n className={cn(\n 'flex items-baseline gap-2 rounded-md px-2 py-1',\n AI_TEXT.xs,\n AI_TRANSITION.colors,\n isUserCode && 'bg-muted/50',\n onClick && cn(AI_HOVER.bg, 'cursor-pointer', AI_FOCUS.ring),\n )}\n onClick={onClick ? handleClick : undefined}\n onKeyDown={onClick ? handleKeyDown : undefined}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n aria-label={\n onClick\n ? `Navigate to ${frame.functionName ?? '<anonymous>'} at ${formatLocation(frame)}`\n : undefined\n }\n whileHover={onClick && !reducedMotion ? { x: 2, transition: SPRING_TACTILE } : undefined}\n >\n <span className=\"text-muted-foreground shrink-0\">{frame.functionName ?? '<anonymous>'}</span>\n <span className={cn('truncate', isUserCode ? 'text-foreground' : 'text-muted-foreground/70')}>\n {formatLocation(frame)}\n </span>\n </motion.div>\n );\n};\n\nFrameRow.displayName = 'FrameRow';\n\n// ============================================\n// LIBRARY FRAME GROUP\n// ============================================\n\ntype LibraryFrameGroupProps = {\n frames: StackFrame[];\n defaultCollapsed?: boolean;\n onClick?: (frame: StackFrame) => void;\n};\n\nconst LibraryFrameGroup = ({\n frames,\n defaultCollapsed = true,\n onClick,\n}: LibraryFrameGroupProps) => {\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n const reducedMotion = useReducedMotion();\n\n const toggle = useCallback(() => setCollapsed(prev => !prev), []);\n\n if (frames.length === 0) return null;\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={toggle}\n className={cn(\n 'flex w-full items-center gap-1 rounded-md px-2 py-1',\n AI_TEXT.xs,\n 'text-muted-foreground',\n AI_HOVER.bg,\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n )}\n aria-expanded={!collapsed}\n >\n {collapsed ? (\n <ChevronRightIcon className={AI_ICON.sm} aria-hidden />\n ) : (\n <ChevronDownIcon className={AI_ICON.sm} aria-hidden />\n )}\n <span>\n {collapsed ? 'Show' : 'Hide'} {frames.length} library frame\n {frames.length !== 1 ? 's' : ''}\n </span>\n </button>\n <AnimatePresence initial={false}>\n {!collapsed ? (\n <motion.div\n key=\"library-frames\"\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={reducedMotion ? { opacity: 0 } : { opacity: 0, height: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n >\n {frames.map(frame => (\n <FrameRow\n key={`${frame.fileName}:${frame.lineNumber ?? ''}:${frame.columnNumber ?? ''}`}\n frame={frame}\n onClick={onClick}\n />\n ))}\n </motion.div>\n ) : null}\n </AnimatePresence>\n </div>\n );\n};\n\nLibraryFrameGroup.displayName = 'LibraryFrameGroup';\n\nStackTrace.displayName = 'StackTrace';\n","/**\n * @fileoverview Snippet Component - Premium Harmony V2\n *\n * A compact inline code snippet with optional language tag and copy button.\n * Smaller and more inline than CodeBlock -- designed for single-line or\n * few-line code references within AI conversation flows.\n *\n * Features:\n * - Compact single-row display with muted background\n * - Language badge on the left\n * - Copy-to-clipboard with success feedback (CheckIcon for 2s)\n * - AI-generated content indicator\n * - Premium Harmony V2 spring animations\n * - Reduced motion support\n * - Keyboard accessible\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/snippet\n * @component Snippet\n *\n * @useCases\n * - Display inline code references in AI responses\n * - Show command snippets with copy functionality\n * - Reference file paths, function names, or variables\n * - Highlight AI-generated code fragments\n *\n * @example\n * <Snippet code=\"npm install @od-oneapp/uni-ui\" language=\"bash\" showCopy />\n * <Snippet code=\"const x = await fetch(url)\" language=\"ts\" isGenerated />\n */\n\n'use client';\n\nimport { useCallback } from 'react';\n\nimport { useClipboard, useReducedMotion } from '@mantine/hooks';\nimport { CheckIcon, CopyIcon, SparklesIcon } from 'lucide-react';\nimport { motion, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_FOCUS,\n AI_ICON,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\n// ============================================\n// TYPES\n// ============================================\n\n/**\n * Props for the Snippet component.\n */\nexport type SnippetProps = Omit<HTMLMotionProps<'div'>, 'ref'> & {\n /** The code string to display */\n code: string;\n /** Programming language for the badge label */\n language?: string;\n /** Show copy button on the right */\n showCopy?: boolean;\n /** Whether the snippet is from AI-generated content */\n isGenerated?: boolean;\n};\n\n// ============================================\n// SNIPPET\n// ============================================\n\n/**\n * Compact inline code snippet with language tag and copy button.\n * Designed for single-line or few-line code references that are\n * lighter-weight than a full CodeBlock.\n */\nexport const Snippet = ({\n code,\n language,\n showCopy = true,\n isGenerated = false,\n className,\n ...props\n}: SnippetProps) => {\n const reducedMotion = useReducedMotion();\n const { copy, copied } = useClipboard({ timeout: 2000 });\n\n const handleCopy = useCallback(() => {\n copy(code);\n }, [copy, code]);\n\n return (\n <motion.div\n className={cn(\n 'bg-muted/50 flex items-center gap-2 rounded-md px-3 py-2 font-mono',\n AI_TEXT.sm,\n className,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 2 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n data-component=\"Snippet\"\n data-language={language}\n data-generated={isGenerated ? 'true' : undefined}\n role=\"region\"\n aria-label={language ? `Code snippet (${language})` : 'Code snippet'}\n {...props}\n >\n {/* Language badge */}\n {language ? (\n <span\n className={cn(\n 'shrink-0 rounded px-1.5 py-0.5',\n AI_TEXT.xs,\n 'bg-muted text-muted-foreground font-medium',\n )}\n >\n {language}\n </span>\n ) : null}\n\n {/* AI-generated indicator */}\n {isGenerated ? (\n <SparklesIcon\n className={cn(AI_ICON.sm, 'text-primary shrink-0')}\n aria-label=\"AI generated\"\n />\n ) : null}\n\n {/* Code content */}\n <code className=\"text-foreground min-w-0 flex-1 truncate\">{code}</code>\n\n {/* Copy button */}\n {showCopy ? (\n <motion.button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n 'min-h-8 min-w-8 shrink-0 rounded-md p-1',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n 'text-muted-foreground hover:text-foreground',\n )}\n whileHover={!reducedMotion ? { scale: 1.1, transition: SPRING_TACTILE } : undefined}\n whileTap={!reducedMotion ? { scale: 0.9, transition: SPRING_TACTILE } : undefined}\n aria-label={copied ? 'Copied' : 'Copy to clipboard'}\n >\n {copied ? (\n <CheckIcon className={cn(AI_ICON.sm, 'text-success')} aria-hidden />\n ) : (\n <CopyIcon className={AI_ICON.sm} aria-hidden />\n )}\n </motion.button>\n ) : null}\n </motion.div>\n );\n};\n\nSnippet.displayName = 'Snippet';\n","/**\n * @fileoverview AudioPlayer Component - Premium Harmony V2\n *\n * Audio playback component for AI-generated speech and audio responses.\n * Provides play/pause controls, a clickable progress bar, and time display.\n * Supports compact mode for dense UIs.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch-friendly 44px play/pause target\n * - Reduced motion support\n * - Clickable progress bar with seek\n * - Compact mode (play button + thin progress bar only)\n * - Semantic color tokens from AI design system\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/audio-player\n * @component AudioPlayer\n *\n * @example\n * <AudioPlayer src=\"/audio/response.mp3\" title=\"AI Response\" />\n * <AudioPlayer src=\"/audio/clip.wav\" compact />\n * <AudioPlayer src=\"/audio/long.mp3\" duration={120} autoPlay />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useCallback, useRef, useState } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { PauseIcon, PlayIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_CONTAINER,\n AI_FOCUS,\n AI_ICON,\n AI_TEXT,\n AI_TITLE,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\n/**\n * Format seconds into m:ss display string.\n *\n * @param seconds - Time value in seconds\n * @returns Formatted time string (e.g. \"1:05\")\n */\nfunction formatTime(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\n/** Props for the AudioPlayer component. */\nexport type AudioPlayerProps = HTMLAttributes<HTMLDivElement> & {\n /** Audio source URL */\n src: string;\n /** Optional title displayed above the controls */\n title?: string;\n /** Duration in seconds (if known before metadata loads) */\n duration?: number;\n /** Auto-play on mount */\n autoPlay?: boolean;\n /** Compact mode (just play button + progress) */\n compact?: boolean;\n};\n\n/**\n * Audio playback component for AI-generated speech/audio responses.\n *\n * Renders a play/pause button, a clickable progress bar, and a time\n * display. In compact mode only the button and a thin progress bar\n * are shown.\n */\nexport const AudioPlayer = ({\n className,\n src,\n title,\n duration: durationProp,\n autoPlay = false,\n compact = false,\n ...props\n}: AudioPlayerProps) => {\n const audioRef = useRef<HTMLAudioElement>(null);\n const progressRef = useRef<HTMLDivElement>(null);\n const reducedMotion = useReducedMotion();\n\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n // Track the duration reported by the audio element separately.\n // The effective duration is computed from the prop (if provided) or the audio metadata.\n // This avoids a useEffect-based prop-to-state sync which is a React anti-pattern for derived state.\n const [audioDuration, setAudioDuration] = useState(0);\n const duration = durationProp ?? audioDuration;\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n\n const handleLoadedMetadata = useCallback(() => {\n const audio = audioRef.current;\n if (!audio) return;\n setAudioDuration(audio.duration);\n setIsLoaded(true);\n }, []);\n\n const handleTimeUpdate = useCallback(() => {\n const audio = audioRef.current;\n if (!audio) return;\n setCurrentTime(audio.currentTime);\n }, []);\n\n const handleEnded = useCallback(() => {\n setIsPlaying(false);\n setCurrentTime(0);\n }, []);\n\n const handlePlay = useCallback(() => setIsPlaying(true), []);\n const handlePause = useCallback(() => setIsPlaying(false), []);\n\n const handleError = useCallback(() => {\n setIsPlaying(false);\n setHasError(true);\n }, []);\n\n const togglePlayPause = useCallback(async () => {\n const audio = audioRef.current;\n if (!audio) return;\n\n if (audio.paused) {\n try {\n await audio.play();\n } catch {\n // Browser prevented playback (e.g. autoplay policy).\n // onPlay won't fire, so ensure state stays false.\n setIsPlaying(false);\n }\n } else {\n audio.pause();\n }\n }, []);\n\n const handleProgressClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n const bar = progressRef.current;\n const audio = audioRef.current;\n if (!bar || !audio || !duration) return;\n\n const rect = bar.getBoundingClientRect();\n if (rect.width === 0) return;\n const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));\n const newTime = ratio * duration;\n\n audio.currentTime = newTime;\n setCurrentTime(newTime);\n },\n [duration],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n const audio = audioRef.current;\n if (!audio || !duration) return;\n const step = 5;\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n const newTime = Math.min(duration, audio.currentTime + step);\n audio.currentTime = newTime;\n setCurrentTime(newTime);\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n const newTime = Math.max(0, audio.currentTime - step);\n audio.currentTime = newTime;\n setCurrentTime(newTime);\n } else if (e.key === 'Home') {\n e.preventDefault();\n audio.currentTime = 0;\n setCurrentTime(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n audio.currentTime = duration;\n setCurrentTime(duration);\n }\n },\n [duration],\n );\n\n const progress = duration > 0 ? (currentTime / duration) * 100 : 0;\n\n const Icon = isPlaying ? PauseIcon : PlayIcon;\n\n return (\n <div\n className={cn(\n AI_CONTAINER.card,\n 'flex items-center gap-3',\n !isLoaded && 'animate-pulse opacity-60',\n className,\n )}\n data-component=\"AudioPlayer\"\n data-state={isPlaying ? 'playing' : 'paused'}\n {...props}\n >\n {/* Hidden audio element */}\n <audio\n ref={audioRef}\n src={src}\n preload=\"metadata\"\n autoPlay={autoPlay}\n onLoadedMetadata={handleLoadedMetadata}\n onTimeUpdate={handleTimeUpdate}\n onEnded={handleEnded}\n onPlay={handlePlay}\n onPause={handlePause}\n onError={handleError}\n >\n <track kind=\"captions\" />\n </audio>\n\n {/* Error state */}\n {hasError ? (\n <div className={cn(AI_TEXT.xs, 'text-destructive flex-1 py-1')}>Unable to load audio</div>\n ) : null}\n\n {/* Play / Pause button */}\n {!hasError ? (\n <motion.div\n whileHover={!reducedMotion ? { scale: 1.05, transition: SPRING_TACTILE } : undefined}\n whileTap={!reducedMotion ? { scale: 0.95, transition: SPRING_TACTILE } : undefined}\n >\n <Button\n className={cn('size-11 p-0', AI_TRANSITION.colors, AI_FOCUS.ring)}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={() => void togglePlayPause()}\n aria-label={isPlaying ? 'Pause' : 'Play'}\n disabled={!isLoaded}\n >\n <Icon className={cn(AI_ICON.lg, 'text-foreground')} />\n </Button>\n </motion.div>\n ) : null}\n\n {/* Content area */}\n {!hasError ? (\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n {/* Title (hidden in compact mode) */}\n {title && !compact ? (\n <span className={cn(AI_TITLE.secondary, 'truncate')}>{title}</span>\n ) : null}\n\n {/* Progress bar */}\n <div\n ref={progressRef}\n className={cn(\n 'bg-muted relative h-1.5 w-full cursor-pointer rounded-full',\n AI_TRANSITION.all,\n AI_FOCUS.ring,\n )}\n onClick={handleProgressClick}\n role=\"slider\"\n aria-valuenow={Math.round(currentTime)}\n aria-valuemin={0}\n aria-valuemax={Math.round(duration)}\n aria-valuetext={`${formatTime(currentTime)} of ${formatTime(duration)}`}\n aria-orientation=\"horizontal\"\n aria-label=\"Audio progress\"\n tabIndex={0}\n onKeyDown={handleKeyDown}\n >\n <motion.div\n className=\"bg-primary absolute inset-y-0 left-0 rounded-full\"\n initial={false}\n animate={{ width: `${progress}%` }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n />\n </div>\n\n {/* Time display (hidden in compact mode) */}\n {!compact ? (\n <div className={cn(AI_TEXT.xs, 'text-muted-foreground font-mono')}>\n {formatTime(currentTime)} / {formatTime(duration)}\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n};\n\nAudioPlayer.displayName = 'AudioPlayer';\n","/**\n * @fileoverview Transcription Component - Premium Harmony V2\n *\n * Real-time speech transcription display. Shows words appearing as they\n * are transcribed, distinguishing interim (uncertain) text from final\n * (confirmed) text. Includes a pulsing microphone indicator and an\n * optional language badge.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Reduced motion support\n * - Interim vs final text visual distinction\n * - Pulsing mic indicator when actively listening\n * - Language badge\n * - Inline flowing segments\n * - Semantic color tokens from AI design system\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/transcription\n * @component Transcription\n *\n * @example\n * <Transcription\n * segments={[\n * { text: 'Hello world', isFinal: true },\n * { text: 'this is a test', isFinal: false },\n * ]}\n * isListening\n * language=\"en-US\"\n * />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { MicIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_BODY,\n AI_CONTAINER,\n AI_ICON,\n AI_TEXT,\n AI_TRANSITION,\n SPRING_GENTLE,\n} from '../../ai-elements.constants';\n\n/** A single transcription segment with confidence and finality metadata. */\nexport type TranscriptionSegment = {\n /** Transcribed text content */\n text: string;\n /** Whether the transcription engine considers this final */\n isFinal: boolean;\n /** Timestamp of the segment in milliseconds */\n timestamp?: number;\n /** Confidence score (0-1) from the transcription engine */\n confidence?: number;\n};\n\n/** Props for the Transcription component. */\nexport type TranscriptionProps = HTMLAttributes<HTMLDivElement> & {\n /** Ordered list of transcription segments */\n segments: TranscriptionSegment[];\n /** Whether the microphone is actively transcribing */\n isListening?: boolean;\n /** Language being transcribed (e.g. \"en-US\") */\n language?: string;\n};\n\n/**\n * Real-time speech transcription display.\n *\n * Renders segments as inline flowing text. Final segments use the\n * primary body style while interim segments appear muted and italic\n * to convey uncertainty. A pulsing red microphone icon indicates\n * active listening.\n */\nexport const Transcription = ({\n className,\n segments,\n isListening = false,\n language,\n ...props\n}: TranscriptionProps) => {\n const reducedMotion = useReducedMotion();\n\n return (\n <div\n className={cn(AI_CONTAINER.subtle, 'relative', className)}\n data-component=\"Transcription\"\n data-listening={isListening}\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Transcription\"\n {...props}\n >\n {/* Language badge */}\n {language ? (\n <span\n className={cn(\n 'border-border/50 bg-muted absolute top-2 right-2 inline-flex items-center rounded-full border px-2 py-0.5',\n AI_TEXT.xs,\n 'text-muted-foreground font-medium',\n )}\n >\n {language}\n </span>\n ) : null}\n\n {/* Transcription content */}\n <div className=\"flex flex-wrap items-start gap-x-1\">\n {/* Listening indicator */}\n {isListening ? (\n <motion.span\n className=\"mr-1 inline-flex items-center\"\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n >\n <MicIcon\n className={cn(AI_ICON.md, 'text-destructive animate-pulse')}\n aria-label=\"Listening\"\n />\n </motion.span>\n ) : null}\n\n {/* Segments rendered inline */}\n {segments.map((segment, index) => (\n <motion.span\n key={segment.timestamp != null ? `ts-${segment.timestamp}` : `seg-${index}`}\n className={cn(\n segment.isFinal ? AI_BODY.primary : 'text-muted-foreground italic',\n AI_TRANSITION.colors,\n )}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={\n reducedMotion\n ? { duration: 0 }\n : { delay: Math.min(index * 0.02, 0.5), ...SPRING_GENTLE }\n }\n >\n {segment.text}\n </motion.span>\n ))}\n\n {/* Empty state */}\n {segments.length === 0 && !isListening ? (\n <span className={cn(AI_BODY.secondary, 'italic')}>No transcription yet</span>\n ) : null}\n\n {/* Listening placeholder when no segments */}\n {segments.length === 0 && isListening ? (\n <span className={cn(AI_BODY.secondary, 'italic')}>Listening...</span>\n ) : null}\n </div>\n </div>\n );\n};\n\nTranscription.displayName = 'Transcription';\n","/**\n * @fileoverview VoiceSelector Component - Premium Harmony V2\n *\n * Dropdown/list for selecting a text-to-speech voice. Displays voice name,\n * language badge, optional gender icon, a preview play button, and a\n * selected checkmark. Keyboard navigable with focus ring.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Touch-friendly 44px targets\n * - Reduced motion support\n * - Keyboard navigation with focus ring\n * - Preview play button per voice\n * - Selected state with primary highlight\n * - Semantic color tokens from AI design system\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/voice-selector\n * @component VoiceSelector, VoiceSelectorItem\n *\n * @example\n * <VoiceSelector\n * voices={[\n * { id: 'alloy', name: 'Alloy', language: 'English', gender: 'neutral' },\n * { id: 'echo', name: 'Echo', language: 'English', gender: 'male', previewUrl: '/preview.mp3' },\n * ]}\n * selectedVoiceId=\"alloy\"\n * onVoiceSelect={(id) => console.log(id)}\n * />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { useCallback, useRef } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { CheckIcon, PlayCircleIcon, UserIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { Button } from '../../../elements/atoms/button';\nimport {\n AI_CONTAINER,\n AI_FOCUS,\n AI_ICON,\n AI_STACK,\n AI_TEXT,\n AI_TITLE,\n AI_TRANSITION,\n SPRING_GENTLE,\n SPRING_TACTILE,\n} from '../../ai-elements.constants';\n\n/** Represents a single TTS voice option. */\nexport type Voice = {\n /** Unique identifier */\n id: string;\n /** Display name */\n name: string;\n /** Language label (e.g. \"English\", \"Spanish\") */\n language: string;\n /** Optional gender hint */\n gender?: 'male' | 'female' | 'neutral';\n /** Optional preview audio URL */\n previewUrl?: string;\n};\n\n/** Props for the VoiceSelector component. */\nexport type VoiceSelectorProps = HTMLAttributes<HTMLDivElement> & {\n /** List of available voices */\n voices: Voice[];\n /** Currently selected voice ID */\n selectedVoiceId?: string;\n /** Callback when a voice is selected */\n onVoiceSelect?: (voiceId: string) => void;\n /** Callback when preview is requested */\n onPreview?: (voiceId: string) => void;\n};\n\n/**\n * Voice selection list for choosing a TTS voice.\n *\n * Renders each voice as a row with name, language badge, optional gender\n * icon, preview play button, and a checkmark for the selected voice.\n */\nexport const VoiceSelector = ({\n className,\n voices,\n selectedVoiceId,\n onVoiceSelect,\n onPreview,\n ...props\n}: VoiceSelectorProps) => {\n const listRef = useRef<HTMLDivElement>(null);\n\n const handleListKeyDown = useCallback((e: React.KeyboardEvent<HTMLDivElement>) => {\n const container = listRef.current;\n if (!container) return;\n\n const items = [...container.querySelectorAll<HTMLElement>('[role=\"option\"]')];\n const currentIndex = document.activeElement\n ? items.indexOf(document.activeElement as HTMLElement)\n : -1;\n\n let nextIndex = -1;\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n } else if (e.key === 'Home') {\n e.preventDefault();\n nextIndex = 0;\n } else if (e.key === 'End') {\n e.preventDefault();\n nextIndex = items.length - 1;\n }\n\n const nextItem = nextIndex >= 0 ? items[nextIndex] : undefined;\n if (nextItem) {\n nextItem.focus();\n }\n }, []);\n\n // Compute active descendant ID based on selected voice (ref access avoided in render)\n const activeDescendantId = selectedVoiceId ? `voice-${selectedVoiceId}` : undefined;\n\n return (\n <div\n ref={listRef}\n className={cn(AI_CONTAINER.card, AI_STACK.tight, className)}\n data-component=\"VoiceSelector\"\n role=\"listbox\"\n aria-label=\"Select a voice\"\n aria-activedescendant={activeDescendantId}\n tabIndex={0}\n onKeyDown={handleListKeyDown}\n {...props}\n >\n {voices.length === 0 ? (\n <p className={cn(AI_TEXT.xs, 'text-muted-foreground py-2 text-center italic')}>\n No voices available\n </p>\n ) : (\n voices.map((voice, index) => (\n <VoiceSelectorItem\n key={voice.id}\n voice={voice}\n isSelected={voice.id === selectedVoiceId}\n onSelect={() => onVoiceSelect?.(voice.id)}\n onPreview={onPreview ? () => onPreview(voice.id) : undefined}\n tabIndex={voice.id === selectedVoiceId || (!selectedVoiceId && index === 0) ? 0 : -1}\n />\n ))\n )}\n </div>\n );\n};\n\n/** Props for an individual voice item row. */\nexport type VoiceSelectorItemProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n 'role' | 'aria-selected' | 'onAnimationStart' | 'onDrag' | 'onDragStart' | 'onDragEnd'\n> & {\n /** Voice data */\n voice: Voice;\n /** Whether this voice is currently selected */\n isSelected?: boolean;\n /** Callback when this voice is selected */\n onSelect?: () => void;\n /** Callback when preview is requested */\n onPreview?: () => void;\n /** Tab index (managed by parent VoiceSelector for roving tabindex) */\n tabIndex?: number;\n};\n\n/**\n * Individual voice item within the VoiceSelector list.\n *\n * Renders a single row with voice metadata and interaction controls.\n */\nexport const VoiceSelectorItem = ({\n className,\n voice,\n isSelected = false,\n onSelect,\n onPreview,\n tabIndex = 0,\n ...props\n}: VoiceSelectorItemProps) => {\n const reducedMotion = useReducedMotion();\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect?.();\n }\n },\n [onSelect],\n );\n\n const handlePreviewClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onPreview?.();\n },\n [onPreview],\n );\n\n return (\n <motion.div\n {...props}\n id={`voice-${voice.id}`}\n className={cn(\n 'flex cursor-pointer items-center gap-3 rounded-md px-3 py-2',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n isSelected\n ? 'bg-primary/10 border-primary/30 border'\n : 'hover:bg-accent/50 border border-transparent',\n className,\n )}\n onClick={onSelect}\n onKeyDown={handleKeyDown}\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${voice.name}, ${voice.language}${voice.gender ? `, ${voice.gender}` : ''}${isSelected ? ', selected' : ''}`}\n tabIndex={tabIndex}\n data-component=\"VoiceSelectorItem\"\n data-state={isSelected ? 'selected' : 'unselected'}\n whileHover={!reducedMotion ? { scale: 1.01, transition: SPRING_TACTILE } : undefined}\n whileTap={!reducedMotion ? { scale: 0.99, transition: SPRING_TACTILE } : undefined}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n >\n {/* Gender icon (optional) */}\n {voice.gender ? (\n <UserIcon\n className={cn(AI_ICON.md, 'text-muted-foreground shrink-0')}\n aria-label={voice.gender}\n />\n ) : null}\n\n {/* Voice name */}\n <span className={cn(AI_TITLE.secondary, 'flex-1 truncate')}>{voice.name}</span>\n\n {/* Language badge */}\n <span\n className={cn(\n 'bg-muted inline-flex shrink-0 items-center rounded-full px-2 py-0.5',\n AI_TEXT.xs,\n 'text-muted-foreground',\n )}\n >\n {voice.language}\n </span>\n\n {/* Preview button */}\n {onPreview ? (\n <motion.div\n whileHover={!reducedMotion ? { scale: 1.1, transition: SPRING_TACTILE } : undefined}\n whileTap={!reducedMotion ? { scale: 0.9, transition: SPRING_TACTILE } : undefined}\n >\n <Button\n className={cn(\n 'min-h-11 min-w-11 shrink-0 p-0',\n AI_TRANSITION.colors,\n AI_FOCUS.ring,\n 'text-muted-foreground hover:text-foreground',\n )}\n size=\"sm\"\n variant=\"ghost\"\n type=\"button\"\n onClick={handlePreviewClick}\n aria-label={`Preview ${voice.name}`}\n >\n <PlayCircleIcon className={AI_ICON.lg} />\n </Button>\n </motion.div>\n ) : null}\n\n {/* Selected checkmark */}\n {isSelected ? (\n <motion.span\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={reducedMotion ? { duration: 0 } : SPRING_GENTLE}\n className=\"shrink-0\"\n >\n <CheckIcon className={cn(AI_ICON.md, 'text-primary')} aria-hidden />\n </motion.span>\n ) : null}\n </motion.div>\n );\n};\n\nVoiceSelector.displayName = 'VoiceSelector';\nVoiceSelectorItem.displayName = 'VoiceSelectorItem';\n","/**\n * @fileoverview ThoughtChain Component - Premium Harmony V2\n *\n * Multi-step tool execution chain visualization. Renders a connected\n * vertical timeline of tool calls with status indicators, forming a\n * visual pipeline. Different from chain-of-thought: this component\n * focuses on discrete tool/step execution rather than reasoning text.\n *\n * Features:\n * - Premium Harmony V2 spring physics animations\n * - Reduced motion support\n * - Vertical timeline with connecting lines\n * - Per-step status indicators (pending, running, complete, error)\n * - Stagger animation for step entry\n * - Tool name badges and duration display\n * - Semantic color tokens from AI design system\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/thought-chain\n * @component ThoughtChain, ThoughtChainStep\n *\n * @example\n * <ThoughtChain\n * steps={[\n * { id: '1', title: 'Search documents', status: 'complete', toolName: 'search', duration: 120 },\n * { id: '2', title: 'Analyze results', status: 'running', toolName: 'analyze' },\n * { id: '3', title: 'Generate summary', status: 'pending' },\n * ]}\n * isActive\n * />\n */\n\n'use client';\n\nimport type { HTMLAttributes } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { CheckIcon, Loader2, MinusIcon, XIcon } from 'lucide-react';\nimport { motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n AI_BODY,\n AI_CONTAINER,\n AI_ICON,\n AI_TEXT,\n AI_TITLE,\n AI_TRANSITION,\n SPRING_GENTLE,\n} from '../../ai-elements.constants';\n\nimport type { HTMLMotionProps } from 'motion/react';\n\n/** A single step in a thought chain execution pipeline. */\nexport type ThoughtChainStepData = {\n /** Unique step identifier */\n id: string;\n /** Step title */\n title: string;\n /** Optional description */\n description?: string;\n /** Current execution status */\n status: 'pending' | 'running' | 'complete' | 'error';\n /** Tool name if this step is a tool call */\n toolName?: string;\n /** Duration in milliseconds */\n duration?: number;\n};\n\n/** Props for the ThoughtChain component. */\nexport type ThoughtChainProps = HTMLAttributes<HTMLOListElement> & {\n /** Ordered list of execution steps */\n steps: ThoughtChainStepData[];\n /** Whether the chain is still executing */\n isActive?: boolean;\n};\n\n/**\n * Multi-step tool execution chain visualization.\n *\n * Renders a vertical timeline with status indicators and connecting\n * lines showing the progress of a series of tool calls or processing\n * steps.\n */\nexport const ThoughtChain = ({\n className,\n steps,\n isActive = false,\n ...props\n}: ThoughtChainProps) => {\n return (\n <ol\n className={cn(AI_CONTAINER.card, 'list-none overflow-hidden', className)}\n data-component=\"ThoughtChain\"\n data-active={isActive}\n aria-label=\"Execution steps\"\n {...props}\n >\n {steps.map((step, index) => (\n <ThoughtChainStepItem\n key={step.id}\n step={step}\n isLast={index === steps.length - 1}\n index={index}\n />\n ))}\n\n {steps.length === 0 ? (\n <p className={cn(AI_TEXT.xs, 'text-muted-foreground py-2 text-center italic')}>\n No steps yet\n </p>\n ) : null}\n </ol>\n );\n};\n\n/** Props for an individual step in the ThoughtChain. */\nexport type ThoughtChainStepProps = Omit<HTMLMotionProps<'li'>, 'ref'> & {\n /** Step data */\n step: ThoughtChainStepData;\n /** Whether this is the last step (no connecting line below) */\n isLast: boolean;\n /** Index for stagger animation delay */\n index: number;\n};\n\n/**\n * Format milliseconds into a human-readable duration string.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted string (e.g. \"120ms\", \"1.2s\")\n */\nfunction formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '0ms';\n if (ms < 1000) return `${Math.round(ms)}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\n/**\n * Individual step within the ThoughtChain timeline.\n *\n * Renders a status circle on the left with a connecting line to the\n * next step, and step content (title, description, badges) on the right.\n */\nexport const ThoughtChainStepItem = ({\n className,\n step,\n isLast,\n index,\n ...props\n}: ThoughtChainStepProps) => {\n const reducedMotion = useReducedMotion();\n\n const staggerDelay = reducedMotion ? 0 : index * 0.05;\n\n /** Whether this step has been reached (not pending). */\n const isReached = step.status !== 'pending';\n\n return (\n <motion.li\n className={cn('relative flex gap-3', className)}\n data-component=\"ThoughtChainStep\"\n data-status={step.status}\n initial={reducedMotion ? { opacity: 1 } : { opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reducedMotion ? { duration: 0 } : { delay: staggerDelay, ...SPRING_GENTLE }}\n {...props}\n >\n {/* Timeline column: circle + connecting line */}\n <div className=\"relative flex flex-col items-center\">\n {/* Status circle */}\n <div\n className={cn(\n 'relative z-10 flex size-6 shrink-0 items-center justify-center rounded-full border-2',\n AI_TRANSITION.colors,\n step.status === 'pending' && 'border-muted-foreground bg-background',\n step.status === 'running' && 'border-info bg-background animate-pulse',\n step.status === 'complete' && 'border-success bg-success',\n step.status === 'error' && 'border-destructive bg-destructive',\n )}\n role=\"img\"\n aria-label={`Step status: ${step.status}`}\n >\n {step.status === 'pending' ? (\n <MinusIcon className={cn(AI_ICON.sm, 'text-muted-foreground')} aria-hidden />\n ) : null}\n {step.status === 'running' ? (\n <Loader2 className={cn(AI_ICON.sm, 'text-info animate-spin')} aria-hidden />\n ) : null}\n {step.status === 'complete' ? (\n <CheckIcon className={cn(AI_ICON.sm, 'text-success-foreground')} aria-hidden />\n ) : null}\n {step.status === 'error' ? (\n <XIcon className={cn(AI_ICON.sm, 'text-destructive-foreground')} aria-hidden />\n ) : null}\n </div>\n\n {/* Connecting line */}\n {!isLast ? (\n <div\n className={cn(\n 'min-h-[16px] w-0.5 flex-1',\n AI_TRANSITION.colors,\n isReached ? 'bg-success/50' : 'bg-border',\n )}\n />\n ) : null}\n </div>\n\n {/* Content column */}\n <div className={cn('flex-1 pb-4', isLast && 'pb-0')}>\n {/* Title row */}\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <span className={cn(AI_TITLE.secondary, 'truncate')}>{step.title}</span>\n\n {/* Tool name badge */}\n {step.toolName ? (\n <span\n className={cn(\n 'bg-muted inline-flex items-center rounded-full px-2 py-0.5',\n AI_TEXT.xs,\n 'text-muted-foreground font-mono',\n )}\n >\n {step.toolName}\n </span>\n ) : null}\n\n {/* Duration */}\n {step.duration !== undefined ? (\n <span className={cn(AI_TEXT.xs, 'text-muted-foreground font-mono')}>\n {formatDuration(step.duration)}\n </span>\n ) : null}\n </div>\n\n {/* Description */}\n {step.description ? (\n <p className={cn(AI_BODY.secondary, 'mt-1')}>{step.description}</p>\n ) : null}\n </div>\n </motion.li>\n );\n};\n\nThoughtChain.displayName = 'ThoughtChain';\nThoughtChainStepItem.displayName = 'ThoughtChainStepItem';\n","/**\n * @fileoverview useScrollToBottom - Intelligent auto-scroll hook\n *\n * Extracted from oneapp-onstage canvas for reuse across all chat/streaming UIs.\n * Provides automatic scrolling to the bottom of a container when new content\n * is added, with smart detection of user scrolling intent.\n *\n * Features:\n * - Detects user scrolling intent and preserves manual scroll position\n * - Auto-scrolls only when user is already at bottom (within threshold)\n * - Uses MutationObserver and ResizeObserver for content change detection\n * - Debounced scroll detection to distinguish intentional from programmatic scrolling\n * - Provides viewport enter/leave callbacks for intersection-based scroll management\n * - Smooth or instant scroll behavior options\n * - Passive scroll listeners for optimal performance\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/scroll-to-bottom\n *\n * @example\n * ```tsx\n * function ChatWindow() {\n * const { containerRef, endRef, isAtBottom, scrollToBottom } = useScrollToBottom();\n *\n * return (\n * <div ref={containerRef} className=\"overflow-y-auto h-[400px]\">\n * {messages.map(msg => <Message key={msg.id} {...msg} />)}\n * <div ref={endRef} />\n * {!isAtBottom && (\n * <button onClick={() => scrollToBottom('smooth')}>\n * Scroll to Latest\n * </button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n/** Options for useScrollToBottom */\nexport interface UseScrollToBottomOptions {\n /** Distance from bottom (in px) to consider \"at bottom\". Default: 100 */\n threshold?: number;\n /** Debounce time (in ms) for scroll event detection. Default: 150 */\n scrollDebounce?: number;\n}\n\n/** Return type for useScrollToBottom */\nexport interface UseScrollToBottomReturn {\n /** Ref to attach to the scrollable container element */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Ref to attach to a marker element at the bottom of content */\n endRef: React.RefObject<HTMLDivElement | null>;\n /** Whether the container is currently scrolled to bottom */\n isAtBottom: boolean;\n /** Function to programmatically scroll to bottom */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /** Callback to mark container as at bottom (for intersection observer) */\n onViewportEnter: () => void;\n /** Callback to mark container as not at bottom (for intersection observer) */\n onViewportLeave: () => void;\n}\n\n/**\n * Hook for intelligent auto-scroll behavior in scrollable containers.\n *\n * Observes content and size changes and auto-scrolls to the bottom only\n * when the container is already near the bottom and the user is not\n * actively scrolling.\n */\nexport function useScrollToBottom(options: UseScrollToBottomOptions = {}): UseScrollToBottomReturn {\n const { threshold = 100, scrollDebounce = 150 } = options;\n\n const containerRef = useRef<HTMLDivElement>(null);\n // endRef is exposed for consumers to place at the bottom of their scrollable content\n // (e.g., <div ref={endRef} />) to enable intersection-based scroll detection\n const endRef = useRef<HTMLDivElement>(null);\n const [isAtBottom, setIsAtBottom] = useState(true);\n const isAtBottomRef = useRef(true);\n const isUserScrollingRef = useRef(false);\n\n // Keep ref in sync with state\n useEffect(() => {\n isAtBottomRef.current = isAtBottom;\n }, [isAtBottom]);\n\n const checkIfAtBottom = useCallback(() => {\n if (!containerRef.current) {\n return true;\n }\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n return scrollTop + clientHeight >= scrollHeight - threshold;\n }, [threshold]);\n\n const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth') => {\n if (!containerRef.current) {\n return;\n }\n containerRef.current.scrollTo({\n top: containerRef.current.scrollHeight,\n behavior,\n });\n }, []);\n\n // Handle user scroll events\n useEffect(() => {\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n let scrollTimeout: ReturnType<typeof setTimeout>;\n\n const handleScroll = () => {\n isUserScrollingRef.current = true;\n clearTimeout(scrollTimeout);\n\n const atBottom = checkIfAtBottom();\n setIsAtBottom(atBottom);\n isAtBottomRef.current = atBottom;\n\n scrollTimeout = setTimeout(() => {\n isUserScrollingRef.current = false;\n }, scrollDebounce);\n };\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n return () => {\n container.removeEventListener('scroll', handleScroll);\n clearTimeout(scrollTimeout);\n };\n }, [checkIfAtBottom, scrollDebounce]);\n\n // Auto-scroll when content changes\n useEffect(() => {\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n let rafId: number | null = null;\n\n const scrollIfNeeded = () => {\n if (isAtBottomRef.current && !isUserScrollingRef.current) {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n }\n rafId = requestAnimationFrame(() => {\n rafId = null;\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'instant',\n });\n setIsAtBottom(true);\n isAtBottomRef.current = true;\n });\n }\n };\n\n const resizeObserver = new ResizeObserver(scrollIfNeeded);\n resizeObserver.observe(container);\n\n // Observe initial children for resize events\n for (const child of container.children) {\n resizeObserver.observe(child);\n }\n\n const mutationObserver = new MutationObserver(mutations => {\n // Register newly added children with the ResizeObserver\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node instanceof Element) {\n resizeObserver.observe(node);\n }\n });\n });\n scrollIfNeeded();\n });\n mutationObserver.observe(container, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n\n return () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n }\n mutationObserver.disconnect();\n resizeObserver.disconnect();\n };\n }, []);\n\n const onViewportEnter = useCallback(() => {\n setIsAtBottom(true);\n isAtBottomRef.current = true;\n }, []);\n\n const onViewportLeave = useCallback(() => {\n setIsAtBottom(false);\n isAtBottomRef.current = false;\n }, []);\n\n return {\n containerRef,\n endRef,\n isAtBottom,\n scrollToBottom,\n onViewportEnter,\n onViewportLeave,\n };\n}\n","/**\n * @fileoverview useUndoRedo - History management hook with keyboard shortcuts\n *\n * Extracted from oneapp-onstage canvas for reuse in editors, forms, and tools.\n * Provides undo/redo with configurable history, keyboard shortcuts (Cmd/Ctrl+Z),\n * toast feedback, and labeled history entries.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/undo-redo\n *\n * @example\n * ```tsx\n * function TextEditor() {\n * const { value, setValue, undo, redo, canUndo, canRedo, shortcuts } = useUndoRedo({\n * initialValue: '',\n * valueLabel: 'text',\n * });\n *\n * return (\n * <div>\n * <button onClick={undo} disabled={!canUndo}>Undo ({shortcuts.undo})</button>\n * <button onClick={redo} disabled={!canRedo}>Redo ({shortcuts.redo})</button>\n * <textarea value={value} onChange={(e) => setValue(e.target.value, 'Edit text')} />\n * </div>\n * );\n * }\n * ```\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { logWarn } from '@repo/shared';\n\n/** Options for useUndoRedo */\nexport interface UseUndoRedoOptions<T> {\n /** Initial value */\n initialValue: T;\n /** Maximum history size (default: 50) */\n maxHistory?: number;\n /** Enable keyboard shortcuts (default: true) */\n enableShortcuts?: boolean;\n /** Show toast feedback (default: false) */\n showToasts?: boolean;\n /** Custom equality check */\n isEqual?: (a: T, b: T) => boolean;\n /** Callback when undo is performed */\n onUndo?: (previousValue: T, currentValue: T) => void;\n /** Callback when redo is performed */\n onRedo?: (previousValue: T, currentValue: T) => void;\n /** Label for the value type (used in toasts) */\n valueLabel?: string;\n /** Custom toast function. If not provided and showToasts is true, uses console.log */\n toastFn?: (\n message: string,\n options?: { action?: { label: string; onClick: () => void }; duration?: number },\n ) => void;\n}\n\n/** A single entry in the undo/redo history */\nexport interface UndoRedoHistoryEntry<T> {\n value: T;\n label: string;\n timestamp: number;\n}\n\n/** Return type for useUndoRedo */\nexport interface UseUndoRedoReturn<T> {\n /** Current value */\n value: T;\n /** Set a new value (adds to history) */\n setValue: (newValue: T, label?: string) => void;\n /** Undo to previous value */\n undo: () => void;\n /** Redo to next value */\n redo: () => void;\n /** Whether undo is available */\n canUndo: boolean;\n /** Whether redo is available */\n canRedo: boolean;\n /** Number of undo steps available */\n undoCount: number;\n /** Number of redo steps available */\n redoCount: number;\n /** Clear all history */\n clearHistory: () => void;\n /** Reset to initial value */\n reset: () => void;\n /** Description of what will be undone */\n undoDescription: string | null;\n /** Description of what will be redone */\n redoDescription: string | null;\n /** Full history for debugging */\n history: UndoRedoHistoryEntry<T>[];\n /** Keyboard shortcut hints */\n shortcuts: { undo: string; redo: string };\n}\n\nfunction defaultIsEqual<T>(a: T, b: T): boolean {\n if (a === b) return true;\n try {\n return JSON.stringify(a) === JSON.stringify(b);\n } catch (error) {\n // Circular references or BigInt values -- fall back to reference equality\n logWarn(\n 'useUndoRedo: defaultIsEqual failed to serialize values for comparison',\n error instanceof Error ? error : undefined,\n );\n return false;\n }\n}\n\n/**\n * Hook for undo/redo with history management and optional keyboard shortcuts.\n *\n * This is a self-contained implementation that does not depend on Mantine hooks,\n * making it suitable for use in any React project.\n */\nexport function useUndoRedo<T>(options: UseUndoRedoOptions<T>): UseUndoRedoReturn<T> {\n const {\n initialValue,\n maxHistory = 50,\n enableShortcuts = true,\n showToasts = false,\n isEqual = defaultIsEqual,\n onUndo,\n onRedo,\n valueLabel = 'change',\n toastFn,\n } = options;\n\n type HistoryEntry = UndoRedoHistoryEntry<T>;\n\n const initialHistory: HistoryEntry[] = [{ value: initialValue, label: 'Initial', timestamp: 0 }];\n const [history, setHistory] = useState<HistoryEntry[]>(initialHistory);\n const [historyIndex, setHistoryIndex] = useState(0);\n\n // Refs mirror state for synchronous access in rapid consecutive calls\n const historyRef = useRef<HistoryEntry[]>(initialHistory);\n const historyIndexRef = useRef(0);\n\n const operationsRef = useRef<{ undo: () => void; redo: () => void }>({\n undo: () => {},\n redo: () => {},\n });\n\n const currentValue = history[historyIndex]?.value ?? initialValue;\n const canUndo = historyIndex > 0;\n const canRedo = historyIndex < history.length - 1;\n const undoCount = historyIndex;\n const redoCount = history.length - 1 - historyIndex;\n const undoDescription = canUndo ? (history[historyIndex - 1]?.label ?? null) : null;\n const redoDescription = canRedo ? (history[historyIndex + 1]?.label ?? null) : null;\n\n const notify = useCallback(\n (message: string, action?: { label: string; onClick: () => void }) => {\n if (!showToasts) return;\n if (toastFn) {\n toastFn(message, { action, duration: 4000 });\n }\n },\n [showToasts, toastFn],\n );\n\n const setValue = useCallback(\n (newValue: T, label = 'Change') => {\n // Read from refs to avoid stale closure on rapid consecutive calls\n const currentIdx = historyIndexRef.current;\n const latestHistory = historyRef.current;\n const latestValue = latestHistory[currentIdx]?.value ?? initialValue;\n\n if (isEqual(latestValue, newValue)) return;\n\n const truncated = latestHistory.slice(0, currentIdx + 1);\n const entry: HistoryEntry = { value: newValue, label, timestamp: Date.now() };\n const next = [...truncated, entry];\n const finalHistory = next.length > maxHistory ? next.slice(1) : next;\n const newIdx = next.length > maxHistory ? maxHistory - 1 : currentIdx + 1;\n\n // Update refs synchronously so the next call sees fresh values\n historyRef.current = finalHistory;\n historyIndexRef.current = newIdx;\n\n setHistory(finalHistory);\n setHistoryIndex(newIdx);\n },\n [initialValue, isEqual, maxHistory],\n );\n\n const undo = useCallback(() => {\n const idx = historyIndexRef.current;\n const hist = historyRef.current;\n if (idx <= 0) return;\n\n const previousEntry = hist[idx - 1];\n const currentEntry = hist[idx];\n if (!previousEntry) return;\n\n const newIdx = idx - 1;\n historyIndexRef.current = newIdx;\n setHistoryIndex(newIdx);\n\n onUndo?.(previousEntry.value, currentEntry?.value ?? initialValue);\n notify(`Undid: ${currentEntry?.label ?? valueLabel}`, {\n label: 'Redo',\n onClick: () => operationsRef.current.redo(),\n });\n }, [initialValue, notify, onUndo, valueLabel]);\n\n const redo = useCallback(() => {\n const idx = historyIndexRef.current;\n const hist = historyRef.current;\n if (idx >= hist.length - 1) return;\n\n const nextEntry = hist[idx + 1];\n const currentEntry = hist[idx];\n if (!nextEntry) return;\n\n const newIdx = idx + 1;\n historyIndexRef.current = newIdx;\n setHistoryIndex(newIdx);\n\n onRedo?.(currentEntry?.value ?? initialValue, nextEntry.value);\n notify(`Redid: ${nextEntry.label ?? valueLabel}`, {\n label: 'Undo',\n onClick: () => operationsRef.current.undo(),\n });\n }, [initialValue, notify, onRedo, valueLabel]);\n\n useEffect(() => {\n operationsRef.current = { undo, redo };\n }, [undo, redo]);\n\n const clearHistory = useCallback(() => {\n const latestValue = historyRef.current[historyIndexRef.current]?.value ?? initialValue;\n const cleared: HistoryEntry[] = [\n { value: latestValue, label: 'Current', timestamp: Date.now() },\n ];\n historyRef.current = cleared;\n historyIndexRef.current = 0;\n setHistory(cleared);\n setHistoryIndex(0);\n }, [initialValue]);\n\n const reset = useCallback(() => {\n const resetHistory: HistoryEntry[] = [\n { value: initialValue, label: 'Initial', timestamp: Date.now() },\n ];\n historyRef.current = resetHistory;\n historyIndexRef.current = 0;\n setHistory(resetHistory);\n setHistoryIndex(0);\n }, [initialValue]);\n\n // Keyboard shortcuts\n useEffect(() => {\n if (!enableShortcuts) return;\n\n const handler = (e: KeyboardEvent) => {\n // Only handle shortcuts when the target is the body or within an element\n // that doesn't have its own undo/redo behavior (e.g., text inputs, textareas)\n const target = e.target as HTMLElement;\n if (\n target instanceof HTMLInputElement ||\n target instanceof HTMLTextAreaElement ||\n target.isContentEditable\n ) {\n return;\n }\n\n const mod = e.metaKey || e.ctrlKey;\n if (mod && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n operationsRef.current.undo();\n } else if ((mod && e.key === 'z' && e.shiftKey) || (mod && e.key === 'y')) {\n e.preventDefault();\n operationsRef.current.redo();\n }\n };\n\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [enableShortcuts]);\n\n // Defer navigator access to useEffect to avoid SSR hydration mismatch\n // (navigator is undefined during SSR, producing different shortcut labels)\n const [isMac, setIsMac] = useState(false);\n\n useEffect(() => {\n if (typeof navigator === 'undefined') return;\n // Prefer navigator.platform over deprecated navigator.userAgent for platform detection\n const platform =\n (navigator as { userAgentData?: { platform?: string } }).userAgentData?.platform ??\n navigator.platform ??\n '';\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsMac(/mac/i.test(platform));\n }, []);\n\n const shortcuts = useMemo(\n () => ({\n undo: isMac ? '⌘Z' : 'Ctrl+Z',\n redo: isMac ? '⌘⇧Z' : 'Ctrl+Y',\n }),\n [isMac],\n );\n\n return {\n value: currentValue,\n setValue,\n undo,\n redo,\n canUndo,\n canRedo,\n undoCount,\n redoCount,\n clearHistory,\n reset,\n undoDescription,\n redoDescription,\n history,\n shortcuts,\n };\n}\n","/**\n * @fileoverview useCollapsible - Progressive disclosure hook\n *\n * Extracted from oneapp-onstage canvas for reuse in any expandable/collapsible UI.\n * Manages expand/collapse state with optional localStorage persistence,\n * content threshold detection, and accessibility attributes.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/collapsible\n *\n * @example\n * ```tsx\n * function CollapsibleSection({ content }: { content: string }) {\n * const {\n * isExpanded, toggle, checkContent, containerProps, triggerProps,\n * } = useCollapsible({ contentThreshold: 500, storageKey: 'section-expanded' });\n *\n * const shouldCollapse = checkContent(content);\n *\n * return (\n * <div {...containerProps}>\n * <div className={isExpanded ? '' : 'line-clamp-3'}>{content}</div>\n * {shouldCollapse && (\n * <button {...triggerProps}>{isExpanded ? 'Show less' : 'Show more'}</button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\n\n'use client';\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n type MutableRefObject,\n} from 'react';\n\n/** Configuration for collapsible behavior */\nexport interface UseCollapsibleOptions {\n /** Unique key for localStorage persistence */\n storageKey?: string;\n /** Default expanded state */\n defaultExpanded?: boolean;\n /** Character threshold before showing \"Show more\" */\n contentThreshold?: number;\n /** Line threshold before showing \"Show more\" */\n lineThreshold?: number;\n /** Callback when expanded state changes */\n onToggle?: (expanded: boolean) => void;\n}\n\n/** Return type for useCollapsible */\nexport interface UseCollapsibleReturn {\n /** Whether content is expanded */\n isExpanded: boolean;\n /** Toggle expanded state */\n toggle: () => void;\n /** Expand content */\n expand: () => void;\n /** Collapse content */\n collapse: () => void;\n /** Whether content exceeds threshold and needs collapsing */\n needsCollapsing: boolean;\n /** Check if specific content needs collapsing */\n checkContent: (content: string) => boolean;\n /** Previous expanded state (for animations) */\n wasExpanded: boolean | undefined;\n /** Props to spread on the collapsible container */\n containerProps: {\n 'data-expanded': string;\n };\n /** Props to spread on the trigger button */\n triggerProps: {\n onClick: () => void;\n 'aria-expanded': boolean;\n };\n}\n\n/**\n * Hook for managing collapsible/expandable content sections.\n *\n * Self-contained implementation with optional localStorage persistence.\n * No external hook dependencies beyond React.\n */\nexport function useCollapsible(options: UseCollapsibleOptions = {}): UseCollapsibleReturn {\n const {\n storageKey,\n defaultExpanded = false,\n contentThreshold = 500,\n lineThreshold = 5,\n onToggle,\n } = options;\n\n // Use reducer for expanded state to handle localStorage sync without setState in effect\n type ExpandedAction =\n | { type: 'set'; value: boolean }\n | { type: 'toggle' }\n | { type: 'sync'; value: boolean };\n const expandedReducer = (state: boolean, action: ExpandedAction): boolean => {\n switch (action.type) {\n case 'set':\n return action.value;\n case 'toggle':\n return !state;\n case 'sync':\n return action.value;\n default:\n return state;\n }\n };\n const [isExpanded, dispatchExpanded] = useReducer(expandedReducer, defaultExpanded);\n\n const [wasExpanded, setWasExpanded] = useState(() => defaultExpanded);\n\n useLayoutEffect(() => {\n // Update wasExpanded to track previous state for animations\n // Safe in useLayoutEffect: derived state update for animation tracking, not cascading\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setWasExpanded(isExpanded);\n }, [isExpanded]);\n\n const contentRef = useRef<string>('');\n const [needsCollapsing, setNeedsCollapsing] = useState(false);\n const pendingNeedsCollapsingRef: MutableRefObject<boolean | null> = useRef(null);\n\n // Flush deferred needsCollapsing updates from checkContent\n useEffect(() => {\n if (pendingNeedsCollapsingRef.current !== null) {\n setNeedsCollapsing(pendingNeedsCollapsingRef.current);\n\n pendingNeedsCollapsingRef.current = null;\n }\n });\n\n // Sync from localStorage on mount (client-only to avoid hydration mismatch)\n // Use ref to track if already synced and reducer dispatch instead of setState\n const syncedRef = useRef(false);\n useEffect(() => {\n if (storageKey && !syncedRef.current) {\n try {\n const stored = localStorage.getItem(storageKey);\n if (stored !== null) {\n const parsed: unknown = JSON.parse(stored);\n if (typeof parsed === 'boolean' && parsed !== isExpanded) {\n // Use reducer dispatch instead of setState to avoid linter warning\n dispatchExpanded({ type: 'sync', value: parsed });\n }\n }\n syncedRef.current = true;\n } catch {\n // Ignore parse errors (corrupt data, SecurityError in sandboxed iframes)\n syncedRef.current = true;\n }\n }\n }, [storageKey, isExpanded]);\n\n // Persist to localStorage\n const persistState = useCallback(\n (value: boolean) => {\n if (storageKey && typeof window !== 'undefined') {\n try {\n localStorage.setItem(storageKey, JSON.stringify(value));\n } catch {\n // Ignore quota errors\n }\n }\n },\n [storageKey],\n );\n\n const toggle = useCallback(() => {\n const newState = !isExpanded;\n dispatchExpanded({ type: 'toggle' });\n persistState(newState);\n onToggle?.(newState);\n }, [isExpanded, persistState, onToggle]);\n\n const expand = useCallback(() => {\n if (isExpanded) return; // Already expanded, skip side effects\n dispatchExpanded({ type: 'set', value: true });\n persistState(true);\n onToggle?.(true);\n }, [isExpanded, persistState, onToggle]);\n\n const collapse = useCallback(() => {\n if (!isExpanded) return; // Already collapsed, skip side effects\n dispatchExpanded({ type: 'set', value: false });\n persistState(false);\n onToggle?.(false);\n }, [isExpanded, persistState, onToggle]);\n\n const checkContent = useCallback(\n (content: string): boolean => {\n contentRef.current = content;\n const exceedsCharThreshold = content.length > contentThreshold;\n const lineCount = content.split('\\n').length;\n const exceedsLineThreshold = lineCount > lineThreshold;\n const result = exceedsCharThreshold || exceedsLineThreshold;\n // Defer state update to useEffect to avoid updating state during render\n if (needsCollapsing !== result) {\n pendingNeedsCollapsingRef.current = result;\n }\n return result;\n },\n [contentThreshold, lineThreshold, needsCollapsing],\n );\n\n const containerProps = useMemo(\n () => ({\n 'data-expanded': isExpanded ? 'true' : 'false',\n }),\n [isExpanded],\n );\n\n const triggerProps = useMemo(\n () => ({\n onClick: toggle,\n 'aria-expanded': isExpanded,\n }),\n [toggle, isExpanded],\n );\n\n return {\n isExpanded,\n toggle,\n expand,\n collapse,\n needsCollapsing,\n checkContent,\n wasExpanded,\n containerProps,\n triggerProps,\n };\n}\n","/**\n * @fileoverview KeyboardShortcutIndicator - Platform-aware keyboard shortcut display\n *\n * Extracted from oneapp-onstage canvas for reuse across all UIs that display\n * keyboard shortcuts. Automatically adapts to Mac vs Windows/Linux with\n * appropriate symbols (⌘ vs Ctrl, ⌥ vs Alt, etc.).\n *\n * Includes:\n * - KeyboardShortcutIndicator: Renders individual shortcut keys as styled `<kbd>` elements\n * - ShortcutDisplay: Shows shortcut with a label (e.g. \"Save ⌘S\")\n * - useShortcutSymbols: Hook returning platform-specific modifier symbols\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/keyboard-shortcut\n *\n * @example\n * ```tsx\n * <KeyboardShortcutIndicator keys={['mod', 'z']} />\n * // Mac: ⌘Z, Windows: Ctrl+Z\n *\n * <ShortcutDisplay label=\"Save\" keys={['mod', 's']} />\n *\n * const { mod, shift } = useShortcutSymbols();\n * ```\n */\n\n'use client';\n\nimport type React from 'react';\nimport { useEffect, useMemo, useReducer, useRef, useState } from 'react';\n\nimport { cn } from '../../../../lib/utils';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype ModifierKey = 'mod' | 'ctrl' | 'alt' | 'shift' | 'meta';\ntype SpecialKey =\n | 'enter'\n | 'escape'\n | 'space'\n | 'tab'\n | 'backspace'\n | 'delete'\n | 'up'\n | 'down'\n | 'left'\n | 'right';\n\n/** A shortcut key identifier */\nexport type ShortcutKey = ModifierKey | SpecialKey | string;\n\nexport interface KeyboardShortcutIndicatorProps {\n /** Shortcut keys to display (e.g., ['mod', 'z'] for Cmd+Z) */\n readonly keys: readonly ShortcutKey[];\n /** Size variant */\n readonly size?: 'sm' | 'md' | 'lg';\n /** Additional CSS classes */\n readonly className?: string;\n /** Whether to show in a compact inline format */\n readonly inline?: boolean;\n /** Hide on touch devices (default: true) */\n readonly hideOnTouch?: boolean;\n}\n\n/** Props for the ShortcutDisplay component */\nexport interface ShortcutDisplayProps {\n /** Label describing the action */\n readonly label: string;\n /** Shortcut keys */\n readonly keys: readonly ShortcutKey[];\n /** Additional CSS classes */\n readonly className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Symbol Mappings\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst MAC_SYMBOLS: Record<string, string> = {\n mod: '⌘',\n meta: '⌘',\n ctrl: '⌃',\n alt: '⌥',\n shift: '⇧',\n enter: '↵',\n escape: 'esc',\n space: '␣',\n tab: '⇥',\n backspace: '⌫',\n delete: '⌦',\n up: '↑',\n down: '↓',\n left: '←',\n right: '→',\n};\n\nconst WIN_SYMBOLS: Record<string, string> = {\n mod: 'Ctrl',\n meta: 'Win',\n ctrl: 'Ctrl',\n alt: 'Alt',\n shift: 'Shift',\n enter: 'Enter',\n escape: 'Esc',\n space: 'Space',\n tab: 'Tab',\n backspace: 'Backspace',\n delete: 'Del',\n up: '↑',\n down: '↓',\n left: '←',\n right: '→',\n};\n\nfunction getIsMac(): boolean {\n return typeof navigator !== 'undefined' && /mac/i.test(navigator.userAgent);\n}\n\nfunction getIsTouch(): boolean {\n return typeof window !== 'undefined' && 'ontouchstart' in window;\n}\n\nfunction formatKey(key: ShortcutKey, isMac: boolean): string {\n const symbols: Readonly<Record<string, string>> = isMac ? MAC_SYMBOLS : WIN_SYMBOLS;\n const lowerKey = key.toLowerCase();\n const symbol: string | undefined = symbols[lowerKey];\n\n if (symbol !== undefined) {\n return symbol;\n }\n\n if (key.length === 1) {\n return key.toUpperCase();\n }\n\n if (/^f\\d+$/i.test(key)) {\n return key.toUpperCase();\n }\n\n return key;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Size Classes\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst sizeClasses = {\n sm: 'text-2xs px-1 py-0.5 min-w-[18px]',\n md: 'text-xs px-1.5 py-0.5 min-w-[22px]',\n lg: 'text-sm px-2 py-1 min-w-[26px]',\n} as const;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Components\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Displays keyboard shortcut keys with platform-appropriate symbols.\n */\nexport function KeyboardShortcutIndicator({\n keys,\n size = 'sm',\n className = '',\n inline = false,\n hideOnTouch = true,\n}: KeyboardShortcutIndicatorProps): React.JSX.Element | null {\n // Defer platform detection to useEffect to avoid hydration mismatch\n // (navigator/window are unavailable during SSR)\n const [isMac, setIsMac] = useState(false);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsMac(getIsMac());\n\n setIsTouch(getIsTouch());\n }, []);\n\n const formattedKeys = useMemo(() => keys.map(key => formatKey(key, isMac)), [keys, isMac]);\n\n if (hideOnTouch && isTouch) {\n return null;\n }\n\n const kbdClass = cn(\n 'inline-flex items-center justify-center',\n 'rounded border',\n 'bg-muted border-border',\n 'text-muted-foreground',\n sizeClasses[size],\n );\n\n if (inline) {\n return (\n <span\n className={cn('inline-flex items-center font-mono', className)}\n role=\"group\"\n aria-label={`Keyboard shortcut: ${keys.join(' + ')}`}\n >\n {keys.map((key, index) => (\n <kbd\n key={String(key).toLowerCase()}\n className={cn(kbdClass, index > 0 && !isMac && 'ml-0.5')}\n >\n {formattedKeys[index]}\n </kbd>\n ))}\n </span>\n );\n }\n\n return (\n <div\n className={cn('inline-flex items-center gap-0.5 font-mono', className)}\n role=\"group\"\n aria-label={`Keyboard shortcut: ${keys.join(' + ')}`}\n >\n {keys.map((key, index) => (\n <kbd key={String(key).toLowerCase()} className={kbdClass}>\n {formattedKeys[index]}\n </kbd>\n ))}\n </div>\n );\n}\n\n/**\n * Shortcut with a label — shows \"Label ⌘K\" format.\n */\nexport function ShortcutDisplay({\n label,\n keys,\n className = '',\n}: ShortcutDisplayProps): React.JSX.Element {\n return (\n <div className={cn('flex items-center justify-between gap-4 text-sm', className)}>\n <span className=\"text-muted-foreground\">{label}</span>\n <KeyboardShortcutIndicator keys={keys} />\n </div>\n );\n}\n\n/**\n * Hook returning platform-specific modifier symbols.\n */\n/** Return type for useShortcutSymbols */\nexport interface ShortcutSymbols {\n readonly mod: string;\n readonly alt: string;\n readonly shift: string;\n readonly ctrl: string;\n readonly enter: string;\n readonly escape: string;\n readonly isMac: boolean;\n}\n\nexport function useShortcutSymbols(): ShortcutSymbols {\n // Defer platform detection to useEffect to avoid hydration mismatch\n // Use reducer to avoid setState in effect\n type IsMacAction = { type: 'sync'; value: boolean };\n const isMacReducer = (_state: boolean, action: IsMacAction): boolean => {\n return action.value;\n };\n const [isMac, dispatchIsMac] = useReducer(isMacReducer, getIsMac());\n const syncedRef = useRef(false);\n\n useEffect(() => {\n // On mount/after hydration, update if server and client values differ\n // Use ref to track if already synced and reducer dispatch instead of setState\n if (!syncedRef.current) {\n const clientIsMac = getIsMac();\n if (clientIsMac !== isMac) {\n dispatchIsMac({ type: 'sync', value: clientIsMac });\n }\n syncedRef.current = true;\n }\n }, [isMac]);\n\n return useMemo(\n () => ({\n mod: isMac ? '⌘' : 'Ctrl',\n alt: isMac ? '⌥' : 'Alt',\n shift: isMac ? '⇧' : 'Shift',\n ctrl: isMac ? '⌃' : 'Ctrl',\n enter: isMac ? '↵' : 'Enter',\n escape: 'Esc',\n isMac,\n }),\n [isMac],\n );\n}\n","/**\n * @fileoverview CollapsibleContent - Progressive disclosure for long text\n *\n * Extracted from oneapp-onstage canvas. Automatically detects if content exceeds\n * character/line thresholds and shows a \"Show more/less\" toggle with smooth animations.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/collapsible-content\n *\n * @example\n * ```tsx\n * <CollapsibleContent content={longText} maxChars={300} maxLines={4} />\n * ```\n */\n\n'use client';\n\nimport type React from 'react';\nimport { useId, useMemo } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { ChevronDown, ChevronUp } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_FOCUS, AI_TEXT, SPRING_FLUID } from '../../ai-elements.constants';\nimport { useCollapsible } from '../collapsible';\n\nexport interface CollapsibleContentProps {\n /** Content to display */\n readonly content: string;\n /** Maximum characters before collapsing (default: 500) */\n readonly maxChars?: number;\n /** Maximum lines before collapsing (default: 6) */\n readonly maxLines?: number;\n /** Whether to start expanded (default: false) */\n readonly defaultExpanded?: boolean;\n /** Custom className for the container */\n readonly className?: string;\n /** Label for \"show more\" button */\n readonly showMoreLabel?: string;\n /** Label for \"show less\" button */\n readonly showLessLabel?: string;\n}\n\n/**\n * Progressive disclosure component for long text content.\n *\n * Truncates at character/line threshold and provides an animated\n * \"Show more/less\" toggle.\n */\nexport function CollapsibleContent({\n content,\n maxChars = 500,\n maxLines = 6,\n defaultExpanded = false,\n className = '',\n showMoreLabel = 'Show more',\n showLessLabel = 'Show less',\n}: CollapsibleContentProps): React.JSX.Element {\n const contentId = useId();\n const reducedMotion = useReducedMotion() ?? false;\n const { isExpanded, toggle } = useCollapsible({ defaultExpanded });\n\n const { needsCollapsing, truncatedContent, lineCount } = useMemo(() => {\n const lines = content.split('\\n');\n const charExceeds = content.length > maxChars;\n const lineExceeds = lines.length > maxLines;\n const needs = charExceeds || lineExceeds;\n\n let truncated = content;\n if (needs && !isExpanded) {\n if (lineExceeds) {\n truncated = lines.slice(0, maxLines).join('\\n');\n if (truncated.length < content.length) {\n truncated = `${truncated.trimEnd()}...`;\n }\n } else if (charExceeds) {\n truncated = `${content.slice(0, maxChars).trimEnd()}...`;\n }\n }\n\n return { needsCollapsing: needs, truncatedContent: truncated, lineCount: lines.length };\n }, [content, maxChars, maxLines, isExpanded]);\n\n if (!needsCollapsing) {\n return (\n <div className={className}>\n <p className={cn(AI_TEXT.sm, 'whitespace-pre-wrap')}>{content}</p>\n </div>\n );\n }\n\n const motionProps = reducedMotion\n ? {}\n : {\n initial: { opacity: 0.8 },\n animate: { opacity: 1 },\n transition: SPRING_FLUID,\n };\n\n return (\n <div\n className={className}\n data-expanded={isExpanded ? 'true' : 'false'}\n data-reduced-motion={reducedMotion ? 'true' : 'false'}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div id={contentId} key={isExpanded ? 'expanded' : 'collapsed'} {...motionProps}>\n <p className={cn(AI_TEXT.sm, 'whitespace-pre-wrap')}>\n {isExpanded ? content : truncatedContent}\n </p>\n </motion.div>\n </AnimatePresence>\n\n <button\n type=\"button\"\n onClick={toggle}\n className={cn(\n 'mt-2 flex min-h-8 items-center gap-1',\n AI_TEXT.xs,\n 'text-muted-foreground hover:text-foreground transition-colors',\n AI_FOCUS.ring,\n )}\n aria-expanded={isExpanded}\n aria-controls={contentId}\n >\n {isExpanded ? (\n <>\n <ChevronUp className=\"size-3.5\" aria-hidden=\"true\" />\n {showLessLabel}\n </>\n ) : (\n <>\n <ChevronDown className=\"size-3.5\" aria-hidden=\"true\" />\n {showMoreLabel} ({lineCount} lines)\n </>\n )}\n </button>\n </div>\n );\n}\n","/**\n * @fileoverview GenericDiffView - Side-by-side array diff visualization\n *\n * Extracted from oneapp-onstage canvas. A reusable, accessible diff component\n * for comparing two versions of array-based content. Features color-coded\n * change indicators (added, removed, changed) with WCAG-compliant styling.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/diff-view\n *\n * @example\n * ```tsx\n * <GenericDiffView\n * oldContent={oldJson}\n * newContent={newJson}\n * parseContent={(c) => JSON.parse(c)}\n * renderItem={(item) => <pre>{JSON.stringify(item, null, 2)}</pre>}\n * isEqual={(a, b) => JSON.stringify(a) === JSON.stringify(b)}\n * itemLabel=\"Item\"\n * />\n * ```\n */\n\n'use client';\n\nimport type React from 'react';\nimport { useMemo, type ReactNode } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\n\nimport { cn } from '../../../../lib/utils';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Status of a diff item */\nexport type DiffItemStatus = 'added' | 'removed' | 'changed' | 'unchanged';\n\nexport interface GenericDiffViewProps<T> {\n /** Serialized old content */\n readonly oldContent: string;\n /** Serialized new content */\n readonly newContent: string;\n /** Parse content string into array of items */\n readonly parseContent: (content: string) => T[];\n /** Render a single item */\n readonly renderItem: (item: T, index: number) => ReactNode;\n /** Check if two items are equal */\n readonly isEqual: (oldItem: T | undefined, newItem: T | undefined) => boolean;\n /** Label for items (e.g., \"Slide\", \"Chart\", \"Section\") */\n readonly itemLabel: string;\n /** Optional header content */\n readonly headerContent?: ReactNode;\n /** Previous version label (default: \"Previous Version\") */\n readonly oldLabel?: string;\n /** Current version label (default: \"Current Version\") */\n readonly newLabel?: string;\n /** Additional CSS classes */\n readonly className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Generic side-by-side diff view for comparing array-based content.\n *\n * Provides accessible comparison with:\n * - Color-coded change indicators (added/removed/changed)\n * - Reduced motion support\n * - Semantic color tokens\n */\nexport function GenericDiffView<T>({\n oldContent,\n newContent,\n parseContent,\n renderItem,\n isEqual,\n itemLabel,\n headerContent,\n oldLabel = 'Previous Version',\n newLabel = 'Current Version',\n className,\n}: GenericDiffViewProps<T>): React.JSX.Element {\n const reducedMotion = useReducedMotion();\n\n const { items: oldItems, error: oldError } = useMemo(() => {\n try {\n return { items: parseContent(oldContent), error: null };\n } catch (err) {\n return {\n items: [] as T[],\n error: `Failed to parse old content: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n }, [parseContent, oldContent]);\n const { items: newItems, error: newError } = useMemo(() => {\n try {\n return { items: parseContent(newContent), error: null };\n } catch (err) {\n return {\n items: [] as T[],\n error: `Failed to parse new content: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n }, [parseContent, newContent]);\n\n const parseError = oldError ?? newError;\n const maxItems = Math.max(oldItems.length, newItems.length);\n\n const diffStatuses = useMemo(\n () =>\n Array.from({ length: maxItems }, (_, index) => {\n const oldItem = oldItems[index];\n const newItem = newItems[index];\n const isRemoved = oldItem !== undefined && newItem === undefined;\n const isAdded = oldItem === undefined && newItem !== undefined;\n return {\n id: `diff-item-${index}`,\n oldItem,\n newItem,\n isRemoved,\n isAdded,\n isChanged: !isRemoved && !isAdded && !isEqual(oldItem, newItem),\n };\n }),\n [maxItems, oldItems, newItems, isEqual],\n );\n\n return (\n <div\n className={cn('flex h-full flex-col gap-4 overflow-auto p-4', className)}\n data-reduced-motion={reducedMotion ? 'true' : 'false'}\n >\n {/* Legend */}\n <section className=\"flex items-center gap-4 text-sm\" aria-label=\"Diff legend\">\n <div className=\"flex items-center gap-2\">\n <span className=\"bg-destructive/30 inline-block size-3 rounded\" aria-hidden=\"true\" />\n <span className=\"text-muted-foreground\">Removed</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"bg-success/30 inline-block size-3 rounded\" aria-hidden=\"true\" />\n <span className=\"text-muted-foreground\">Added</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"bg-warning/30 inline-block size-3 rounded\" aria-hidden=\"true\" />\n <span className=\"text-muted-foreground\">Changed</span>\n </div>\n </section>\n\n {parseError ? (\n <div\n className=\"text-destructive bg-destructive/10 border-destructive/30 rounded-md border p-3 text-sm\"\n role=\"alert\"\n >\n {parseError}\n </div>\n ) : null}\n\n {headerContent}\n\n {maxItems === 0 && !parseError ? (\n <div className=\"text-muted-foreground py-8 text-center text-sm\" role=\"status\">\n No differences to display\n </div>\n ) : null}\n\n {/* Two-column comparison */}\n <section className=\"grid grid-cols-2 gap-4\" aria-label=\"Side-by-side comparison\">\n {/* Old Version */}\n <section className=\"space-y-4\" aria-label={oldLabel}>\n <h3 className=\"text-muted-foreground text-sm font-medium\">{oldLabel}</h3>\n {diffStatuses.map(({ id, oldItem, isRemoved, isChanged }, index) => {\n if (oldItem === undefined) {\n return (\n <div\n key={id}\n className=\"bg-background text-muted-foreground min-h-11 rounded-lg border border-dashed p-4\"\n data-state=\"empty\"\n >\n (No {itemLabel.toLowerCase()})\n </div>\n );\n }\n\n const state = isRemoved ? 'removed' : (isChanged ? 'changed' : 'unchanged');\n\n return (\n <div\n key={id}\n className={cn(\n 'bg-card min-h-11 rounded-lg border p-4 transition-colors',\n isRemoved && 'border-destructive/50 bg-destructive/10',\n isChanged && !isRemoved && 'border-warning/50 bg-warning/5',\n )}\n data-state={state}\n >\n <div className=\"text-muted-foreground mb-2 flex items-center gap-2 text-xs\">\n <span>\n {itemLabel} {index + 1}\n </span>\n {isRemoved ? (\n <span className=\"text-destructive font-medium\">(Removed)</span>\n ) : null}\n {isChanged && !isRemoved ? (\n <span className=\"text-warning font-medium\">(Changed)</span>\n ) : null}\n </div>\n {renderItem(oldItem, index)}\n </div>\n );\n })}\n </section>\n\n {/* New Version */}\n <section className=\"space-y-4\" aria-label={newLabel}>\n <h3 className=\"text-muted-foreground text-sm font-medium\">{newLabel}</h3>\n {diffStatuses.map(({ id, newItem, isAdded, isChanged }, index) => {\n if (newItem === undefined) {\n return (\n <div\n key={id}\n className=\"bg-background text-muted-foreground min-h-11 rounded-lg border border-dashed p-4\"\n data-state=\"removed\"\n >\n (Removed)\n </div>\n );\n }\n\n const state = isAdded ? 'added' : (isChanged ? 'changed' : 'unchanged');\n\n return (\n <div\n key={id}\n className={cn(\n 'bg-card min-h-11 rounded-lg border p-4 transition-colors',\n isAdded && 'border-success/50 bg-success/10',\n isChanged && !isAdded && 'border-warning/50 bg-warning/5',\n )}\n data-state={state}\n >\n <div className=\"text-muted-foreground mb-2 flex items-center gap-2 text-xs\">\n <span>\n {itemLabel} {index + 1}\n </span>\n {isAdded ? <span className=\"text-success font-medium\">(Added)</span> : null}\n {isChanged && !isAdded ? (\n <span className=\"text-warning font-medium\">(Changed)</span>\n ) : null}\n </div>\n {renderItem(newItem, index)}\n </div>\n );\n })}\n </section>\n </section>\n </div>\n );\n}\n","/**\n * @fileoverview ArtifactSkeleton - Content-type-specific loading skeletons\n *\n * Extracted from oneapp-onstage canvas. Provides shimmer-animated skeleton\n * loaders for 7 content types: text, code, dashboard, image, sheet, slide, generic.\n * Each skeleton mimics the actual content structure for a polished loading UX.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/artifact-skeleton\n *\n * @example\n * ```tsx\n * <TextSkeleton />\n * <CodeSkeleton />\n * <DashboardSkeleton />\n * <ImageSkeleton />\n * <SheetSkeleton />\n * <SlideSkeleton />\n * <GenericSkeleton />\n *\n * // Or select by content type:\n * const Skel = getContentSkeleton('code');\n * <Skel />\n * ```\n */\n\n'use client';\n\nimport type React from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\n\nimport { cn } from '../../../../lib/utils';\nimport { AI_NESTED_RADIUS } from '../../ai-elements.constants';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Supported content skeleton types */\nexport type SkeletonContentType =\n | 'text'\n | 'code'\n | 'dashboard'\n | 'image'\n | 'sheet'\n | 'slide'\n | 'generic';\n\n/** Props for the SkeletonBar building-block component */\nexport interface SkeletonBarProps {\n /** Additional CSS classes for width/height/spacing */\n readonly className?: string;\n /** Whether to show the pulse animation (default: true) */\n readonly animate?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Base Skeleton Bar\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction SkeletonBar({ className = '', animate = true }: SkeletonBarProps): React.JSX.Element {\n const reducedMotion = useReducedMotion() ?? false;\n const shouldAnimate = animate && !reducedMotion;\n\n return (\n <div\n className={cn('bg-muted', shouldAnimate && 'animate-pulse', AI_NESTED_RADIUS, className)}\n aria-hidden=\"true\"\n />\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Content Type Skeletons\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Text/document skeleton -- title + paragraphs + subheading */\nexport function TextSkeleton(): React.JSX.Element {\n return (\n <div className=\"space-y-4 p-4\" role=\"status\" aria-label=\"Loading document...\">\n <SkeletonBar className=\"h-8 w-3/4\" />\n <div className=\"space-y-2\">\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-5/6\" />\n </div>\n <div className=\"space-y-2\">\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-4/5\" />\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-2/3\" />\n </div>\n <SkeletonBar className=\"mt-6 h-6 w-1/2\" />\n <div className=\"space-y-2\">\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-3/4\" />\n </div>\n <span className=\"sr-only\">Loading document content...</span>\n </div>\n );\n}\n\n/** Code editor skeleton — line numbers + varied-width code lines */\nconst CODE_SKELETON_WIDTHS = [\n 'w-3/4',\n 'w-1/2',\n 'w-full',\n 'w-2/3',\n 'w-5/6',\n 'w-1/3',\n 'w-4/5',\n] as const;\nconst CODE_SKELETON_LINES = Array.from({ length: 12 }, (_, i) => ({\n id: `line-${i}`,\n width: CODE_SKELETON_WIDTHS[i % CODE_SKELETON_WIDTHS.length],\n indent: i === 2 || i === 3 || i === 7 || i === 8 ? 'ml-4' : '',\n}));\n\nexport function CodeSkeleton(): React.JSX.Element {\n return (\n <div className=\"bg-muted/30 p-4 font-mono\" role=\"status\" aria-label=\"Loading code...\">\n <div className=\"space-y-2\">\n {CODE_SKELETON_LINES.map(line => (\n <div key={line.id} className=\"flex items-center gap-4\">\n <SkeletonBar className=\"h-4 w-6 opacity-50\" />\n <SkeletonBar className={cn('h-4', line.width, line.indent)} />\n </div>\n ))}\n </div>\n <span className=\"sr-only\">Loading code content...</span>\n </div>\n );\n}\n\n/** Dashboard/chart skeleton — title + chart area + legend */\nexport function DashboardSkeleton(): React.JSX.Element {\n return (\n <div className=\"space-y-4 p-4\" role=\"status\" aria-label=\"Loading dashboard...\">\n <div className=\"flex items-center justify-between\">\n <SkeletonBar className=\"h-6 w-1/3\" />\n <SkeletonBar className=\"h-8 w-24\" />\n </div>\n <div className=\"relative h-64\">\n <SkeletonBar className=\"absolute inset-0\" />\n <div className=\"absolute top-4 bottom-8 left-2 flex flex-col justify-between\">\n {Array.from({ length: 5 }, (_, i) => (\n <SkeletonBar key={`axis-${i}`} className=\"h-3 w-8\" />\n ))}\n </div>\n <div className=\"absolute right-4 bottom-2 left-12 flex justify-between\">\n {Array.from({ length: 6 }, (_, i) => (\n <SkeletonBar key={`label-${i}`} className=\"h-3 w-10\" />\n ))}\n </div>\n </div>\n <div className=\"flex gap-4\">\n {Array.from({ length: 3 }, (_, i) => (\n <div key={`legend-${i}`} className=\"flex items-center gap-2\">\n <SkeletonBar className=\"size-3 rounded-full\" />\n <SkeletonBar className=\"h-3 w-16\" />\n </div>\n ))}\n </div>\n <span className=\"sr-only\">Loading dashboard content...</span>\n </div>\n );\n}\n\n/** Image placeholder skeleton */\nexport function ImageSkeleton(): React.JSX.Element {\n return (\n <div\n className=\"flex flex-col items-center justify-center p-4\"\n role=\"status\"\n aria-label=\"Loading image...\"\n >\n <SkeletonBar className=\"aspect-video w-full max-w-md\" />\n <SkeletonBar className=\"mt-4 h-4 w-1/2\" />\n <span className=\"sr-only\">Loading image content...</span>\n </div>\n );\n}\n\n/** Spreadsheet/table skeleton — header row + data rows */\nexport function SheetSkeleton(): React.JSX.Element {\n return (\n <div className=\"p-4\" role=\"status\" aria-label=\"Loading spreadsheet...\">\n <div className=\"mb-2 flex gap-2\">\n <SkeletonBar className=\"h-8 w-8\" />\n {Array.from({ length: 5 }, (_, i) => (\n <SkeletonBar key={`header-col-${i}`} className=\"h-8 flex-1\" />\n ))}\n </div>\n {Array.from({ length: 8 }, (_, row) => (\n <div key={`row-${row}`} className=\"flex gap-2 py-1\">\n <SkeletonBar className=\"h-6 w-8 opacity-50\" />\n {Array.from({ length: 5 }, (_, col) => (\n <SkeletonBar key={`cell-${row}-${col}`} className=\"h-6 flex-1\" />\n ))}\n </div>\n ))}\n <span className=\"sr-only\">Loading spreadsheet content...</span>\n </div>\n );\n}\n\n/** Presentation slide skeleton — slide + thumbnail strip */\nexport function SlideSkeleton(): React.JSX.Element {\n return (\n <div className=\"p-4\" role=\"status\" aria-label=\"Loading slide...\">\n <div className=\"border-border aspect-video rounded-lg border p-6\">\n <SkeletonBar className=\"mx-auto mb-8 h-10 w-2/3\" />\n <div className=\"flex gap-8\">\n <div className=\"flex-1 space-y-3\">\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-5/6\" />\n <SkeletonBar className=\"h-4 w-4/5\" />\n <SkeletonBar className=\"mt-4 h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-3/4\" />\n </div>\n <SkeletonBar className=\"h-32 w-40\" />\n </div>\n </div>\n <div className=\"mt-4 flex gap-2\">\n {Array.from({ length: 4 }, (_, i) => (\n <SkeletonBar key={`thumbnail-${i}`} className=\"aspect-video w-20\" />\n ))}\n </div>\n <span className=\"sr-only\">Loading slide content...</span>\n </div>\n );\n}\n\n/** Generic content skeleton — fallback for unknown types */\nexport function GenericSkeleton(): React.JSX.Element {\n return (\n <div className=\"space-y-4 p-4\" role=\"status\" aria-label=\"Loading content...\">\n <SkeletonBar className=\"h-8 w-1/2\" />\n <SkeletonBar className=\"h-4 w-full\" />\n <SkeletonBar className=\"h-4 w-3/4\" />\n <SkeletonBar className=\"h-32 w-full\" />\n <span className=\"sr-only\">Loading content...</span>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Selector\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Map of content type to skeleton component. */\nconst CONTENT_SKELETONS: Record<SkeletonContentType, () => React.JSX.Element> = {\n text: TextSkeleton,\n code: CodeSkeleton,\n dashboard: DashboardSkeleton,\n image: ImageSkeleton,\n sheet: SheetSkeleton,\n slide: SlideSkeleton,\n generic: GenericSkeleton,\n};\n\n/**\n * Returns the appropriate skeleton component for a content type.\n */\nexport function getContentSkeleton(type: SkeletonContentType): () => React.JSX.Element {\n return CONTENT_SKELETONS[type] ?? GenericSkeleton;\n}\n\nexport { SkeletonBar };\n","/**\n * @fileoverview ExportDropdown - Format selection dropdown for document export\n *\n * Extracted from oneapp-onstage canvas. Provides a dropdown menu for selecting\n * export formats with format icons, descriptions, and last-used format preference\n * persistence via localStorage.\n *\n * Decoupled from canvas-specific dependencies. The DOCX export handler is provided\n * via an optional callback prop, making all exports configurable.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/export-dropdown\n *\n * @example\n * ```tsx\n * <ExportDropdown\n * content={editorContent}\n * title=\"My Document\"\n * disabled={isStreaming}\n * />\n * ```\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type React from 'react';\nimport type { ReactNode } from 'react';\n\nimport { Download, FileCode, FileJson, FileText, FileType } from 'lucide-react';\n\nimport { cn } from '../../../../lib/utils';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../../../elements/organisms/dropdown-menu';\nimport { AI_FOCUS } from '../../ai-elements.constants';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Supported document export formats */\nexport type DocumentExportFormat = 'docx' | 'markdown' | 'html' | 'json';\n\n/** Configuration for a single document export format */\nexport interface FormatConfig {\n /** User-facing format name */\n readonly label: string;\n /** Short description of the format */\n readonly description: string;\n /** File extension without the dot */\n readonly extension: string;\n /** MIME type for blob creation */\n readonly mimeType: string;\n /** Icon element rendered next to the label */\n readonly icon: ReactNode;\n}\n\n/** Props for the ExportDropdown component */\nexport interface ExportDropdownProps {\n /** Content to export (HTML, Markdown, or JSON string) */\n readonly content: string;\n /** Document title for filename */\n readonly title?: string;\n /** Whether the dropdown is disabled */\n readonly disabled?: boolean;\n /** Custom trigger element (defaults to download icon button) */\n readonly trigger?: ReactNode;\n /** Additional CSS classes for the trigger */\n readonly className?: string;\n /** Available formats (defaults to all). Useful to restrict options. */\n readonly formats?: readonly DocumentExportFormat[];\n /** Custom export handler. Called with (format, content, filename). Return false to use default. */\n readonly onExport?: (\n format: DocumentExportFormat,\n content: string,\n filename: string,\n ) => Promise<boolean | void>;\n /** Toast/notification function */\n readonly onSuccess?: (message: string) => void;\n /** Error notification function */\n readonly onError?: (message: string) => void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst FORMAT_CONFIGS: Record<DocumentExportFormat, FormatConfig> = {\n docx: {\n label: 'Word Document',\n description: 'Microsoft Word (.docx)',\n extension: 'docx',\n mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n icon: <FileType className=\"size-4\" />,\n },\n markdown: {\n label: 'Markdown',\n description: 'Plain text with formatting (.md)',\n extension: 'md',\n mimeType: 'text/markdown',\n icon: <FileText className=\"size-4\" />,\n },\n html: {\n label: 'HTML',\n description: 'Web page format (.html)',\n extension: 'html',\n mimeType: 'text/html',\n icon: <FileCode className=\"size-4\" />,\n },\n json: {\n label: 'JSON',\n description: 'Editor data format (.json)',\n extension: 'json',\n mimeType: 'application/json',\n icon: <FileJson className=\"size-4\" />,\n },\n};\n\nconst DEFAULT_FORMAT_ORDER: DocumentExportFormat[] = ['docx', 'markdown', 'html', 'json'];\n\nconst STORAGE_KEY = 'export-format-preference';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n setTimeout(() => {\n URL.revokeObjectURL(url);\n }, 100);\n}\n\nfunction isDocumentExportFormat(value: string): value is DocumentExportFormat {\n return (DEFAULT_FORMAT_ORDER as readonly string[]).includes(value);\n}\n\nfunction getStoredFormat(): DocumentExportFormat | null {\n if (typeof window === 'undefined') return null;\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored && isDocumentExportFormat(stored)) {\n return stored;\n }\n } catch {\n // Ignore\n }\n return null;\n}\n\nfunction setStoredFormat(format: DocumentExportFormat): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(STORAGE_KEY, format);\n } catch {\n // Ignore\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Format selection dropdown for document export.\n */\nexport function ExportDropdown({\n content,\n title = 'document',\n disabled = false,\n trigger,\n className,\n formats = DEFAULT_FORMAT_ORDER,\n onExport,\n onSuccess,\n onError,\n}: ExportDropdownProps): React.JSX.Element {\n const [isExporting, setIsExporting] = useState(false);\n // Ref guard prevents race conditions from rapid double-clicks.\n // State updates are async so two clicks can both read isExporting=false\n // before React re-renders. The ref is updated synchronously.\n const isExportingRef = useRef(false);\n // Initialize with a deterministic default to match SSR output.\n // Sync from localStorage in useEffect to avoid hydration mismatch\n // (localStorage is unavailable during SSR and may hold a different format).\n const [lastFormat, setLastFormat] = useState<DocumentExportFormat>(\n formats.length > 0 ? (formats[0] as DocumentExportFormat) : 'markdown',\n );\n\n useEffect(() => {\n const stored = getStoredFormat();\n if (stored && formats.includes(stored)) {\n setLastFormat(stored);\n }\n }, [formats]);\n\n const handleExport = useCallback(\n async (format: DocumentExportFormat) => {\n if (!formats.includes(format)) {\n onError?.('Invalid export format');\n return;\n }\n\n // Use ref for synchronous guard against rapid double-clicks\n if (isExportingRef.current || disabled) return;\n\n if (!content || content.trim().length === 0) {\n onError?.('No content to export');\n return;\n }\n\n isExportingRef.current = true;\n setIsExporting(true);\n setLastFormat(format);\n setStoredFormat(format);\n\n const config = FORMAT_CONFIGS[format];\n const safeTitle = title.replaceAll(/[\"*/:<>?\\\\|]/g, '_').slice(0, 200);\n const filename = `${safeTitle}.${config.extension}`;\n\n try {\n // Allow custom export handler to take over\n if (onExport) {\n const handled = await onExport(format, content, filename);\n if (handled !== false) {\n onSuccess?.(`Exported as ${filename}`);\n return;\n }\n }\n\n // Default: text-based exports (no DOCX without custom handler)\n if (format === 'docx') {\n onError?.('DOCX export requires a custom onExport handler');\n return;\n }\n\n const blob = new Blob([content], { type: config.mimeType });\n downloadBlob(blob, filename);\n onSuccess?.(`Exported as ${filename}`);\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? `Export failed: ${error.message}`\n : `Failed to export as ${config.label}`;\n onError?.(errorMessage);\n } finally {\n isExportingRef.current = false;\n setIsExporting(false);\n }\n },\n [content, title, disabled, formats, onExport, onSuccess, onError],\n );\n\n const sortedFormats = formats.includes(lastFormat)\n ? [lastFormat, ...formats.filter(f => f !== lastFormat)]\n : formats;\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild disabled={disabled || isExporting}>\n {trigger ?? (\n <button\n type=\"button\"\n className={cn(\n 'hover:bg-accent inline-flex items-center justify-center rounded-md p-2 transition-colors',\n 'disabled:pointer-events-none disabled:opacity-50',\n AI_FOCUS.ring,\n className,\n )}\n disabled={disabled || isExporting}\n aria-label={isExporting ? 'Exporting document...' : 'Export document'}\n aria-busy={isExporting}\n aria-haspopup=\"menu\"\n >\n <span className=\"sr-only\">{isExporting ? 'Exporting...' : 'Export options'}</span>\n <Download className=\"size-[18px]\" aria-hidden=\"true\" />\n </button>\n )}\n </DropdownMenuTrigger>\n\n <DropdownMenuContent align=\"end\" className=\"w-56\" aria-label=\"Export format options\">\n {sortedFormats.map(format => {\n const config = FORMAT_CONFIGS[format];\n const isLast = format === lastFormat;\n\n return (\n <DropdownMenuItem\n key={format}\n onClick={() => void handleExport(format)}\n disabled={isExporting}\n className={cn('cursor-pointer gap-3', isLast && 'bg-accent/50')}\n data-format={format}\n aria-label={`Export as ${config.label}`}\n >\n <span aria-hidden=\"true\">{config.icon}</span>\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">{config.label}</span>\n <span className=\"text-muted-foreground text-xs\">{config.description}</span>\n </div>\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","/**\n * @fileoverview DraggableTabs - Reorderable tab bar with kind badges\n *\n * Extracted and generalized from oneapp-onstage ArtifactTabs. Provides a\n * reorderable tab bar with type badges, streaming indicators, and close-on-hover.\n * Uses Framer Motion Reorder for drag-to-reorder support.\n *\n * Generalized from canvas-specific `Artifact` type to accept any item with\n * `{id, title, kind?, status?}`.\n *\n * @module @od-oneapp/uni-ui/components/ai-elements/custom/draggable-tabs\n *\n * @example\n * ```tsx\n * <DraggableTabs\n * items={artifacts}\n * activeIndex={0}\n * onSelect={(i) => setActive(i)}\n * onClose={(i) => removeTab(i)}\n * onReorder={(newOrder) => setItems(newOrder)}\n * kindColors={{ text: 'bg-blue-500/20 text-blue-600', code: 'bg-green-500/20 text-green-600' }}\n * />\n * ```\n */\n\n'use client';\n\nimport type React from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport { useCallback, useState } from 'react';\n\nimport { useReducedMotion } from '@mantine/hooks';\nimport { X } from 'lucide-react';\nimport { AnimatePresence, motion, Reorder } from 'motion/react';\n\nimport { cn } from '../../../../lib/utils';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** A tab item -- only requires `id`. All other fields optional. */\nexport interface TabItem {\n /** Unique identifier */\n readonly id: string;\n /** Display title (falls back to kind or \"Untitled\") */\n readonly title?: string;\n /** Category/type for badge display */\n readonly kind?: string;\n /** Status for streaming indicator */\n readonly status?: 'idle' | 'streaming' | 'complete' | 'error';\n}\n\nexport interface DraggableTabsProps<T extends TabItem> {\n /** Array of tab items */\n readonly items: readonly T[];\n /** Index of currently active tab */\n readonly activeIndex: number;\n /** Callback when a tab is selected */\n readonly onSelect: (index: number) => void;\n /** Callback when a tab is closed */\n readonly onClose: (index: number) => void;\n /** Callback when tabs are reordered */\n readonly onReorder: (newOrder: T[]) => void;\n /** Whether reordering is enabled (default: true) */\n readonly allowReorder?: boolean;\n /** Optional CSS class name */\n readonly className?: string;\n /** Kind badge color map: kind -> tailwind classes */\n readonly kindColors?: Readonly<Record<string, string>>;\n /** Kind display label map: kind -> display name */\n readonly kindLabels?: Readonly<Record<string, string>>;\n /** Whether to show item count (default: true) */\n readonly showCount?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst TAB_SPRING = {\n type: 'spring' as const,\n stiffness: 500,\n damping: 30,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sub-components\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction StreamingIndicator() {\n return (\n <span className=\"relative flex size-2\" role=\"status\" aria-label=\"Streaming\">\n <span className=\"bg-primary absolute inline-flex size-full animate-ping rounded-full opacity-75\" />\n <span className=\"bg-primary relative inline-flex size-2 rounded-full\" />\n <span className=\"sr-only\">Streaming in progress</span>\n </span>\n );\n}\n\nfunction KindBadge({\n kind,\n colorClass,\n label,\n}: {\n kind: string;\n colorClass?: string;\n label?: string;\n}) {\n return (\n <span\n className={cn(\n 'text-2xs rounded px-1.5 py-0.5 font-medium uppercase',\n colorClass ?? 'bg-muted text-muted-foreground',\n )}\n >\n {label ?? kind}\n </span>\n );\n}\n\ninterface SingleTabProps<T extends TabItem> {\n item: T;\n isActive: boolean;\n onSelect: () => void;\n onClose: () => void;\n kindColors?: Record<string, string>;\n kindLabels?: Record<string, string>;\n}\n\nfunction SingleTab<T extends TabItem>({\n item,\n isActive,\n onSelect,\n onClose,\n kindColors,\n kindLabels,\n}: SingleTabProps<T>) {\n const [isHovered, setIsHovered] = useState(false);\n const reducedMotion = useReducedMotion();\n\n const handleKeyDown = useCallback(\n (e: ReactKeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect();\n }\n },\n [onSelect],\n );\n\n return (\n <motion.div\n layout\n initial={{ opacity: 0, scale: 0.9 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.9 }}\n transition={reducedMotion ? { duration: 0 } : TAB_SPRING}\n role=\"tab\"\n tabIndex={isActive ? 0 : -1}\n aria-selected={isActive}\n className={cn(\n 'group relative flex items-center gap-2 rounded-md px-3 py-1.5',\n 'cursor-pointer transition-colors select-none',\n 'hover:bg-accent',\n 'focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none',\n isActive ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground',\n )}\n onClick={onSelect}\n onKeyDown={handleKeyDown}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {item.status === 'streaming' && <StreamingIndicator />}\n\n {item.kind ? (\n <KindBadge\n kind={item.kind}\n colorClass={kindColors?.[item.kind]}\n label={kindLabels?.[item.kind]}\n />\n ) : null}\n\n <span className=\"max-w-[100px] truncate text-sm\">\n {item.title || item.kind || 'Untitled'}\n </span>\n\n <button\n type=\"button\"\n tabIndex={0}\n onClick={e => {\n e.stopPropagation();\n onClose();\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n onClose();\n }\n }}\n className={cn(\n 'ml-1 min-h-6 min-w-6 rounded-full p-0.5 transition-opacity',\n 'hover:bg-muted focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none',\n isHovered || isActive ? 'opacity-100' : 'opacity-0 focus-visible:opacity-100',\n )}\n aria-label={`Close ${item.title || item.kind || 'tab'}`}\n >\n <X className=\"size-3\" aria-hidden=\"true\" />\n </button>\n\n {isActive ? (\n <motion.div\n layoutId=\"activeTabIndicator\"\n className=\"bg-primary absolute right-0 bottom-0 left-0 h-0.5\"\n transition={reducedMotion ? { duration: 0 } : TAB_SPRING}\n />\n ) : null}\n </motion.div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main Component\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Reorderable tab bar with kind badges and streaming indicators.\n *\n * Generalized from canvas ArtifactTabs to work with any item type\n * that has an `id` field.\n */\nexport function DraggableTabs<T extends TabItem>({\n items,\n activeIndex: activeIndexProp,\n onSelect,\n onClose,\n onReorder,\n allowReorder = true,\n className,\n kindColors,\n kindLabels,\n showCount = true,\n}: DraggableTabsProps<T>): React.JSX.Element | null {\n // Clamp activeIndex to valid range to prevent out-of-bounds access\n const activeIndex =\n items.length > 0 ? Math.max(0, Math.min(activeIndexProp, items.length - 1)) : -1;\n\n if (items.length === 0) {\n return null;\n }\n\n const tabProps = { kindColors, kindLabels };\n\n return (\n <div\n className={cn(\n 'border-border bg-muted/30 flex items-center gap-1 overflow-x-auto border-b px-2 py-1',\n className,\n )}\n role=\"tablist\"\n aria-label=\"Tabs\"\n >\n {allowReorder ? (\n <Reorder.Group\n axis=\"x\"\n values={[...items]}\n onReorder={onReorder}\n className=\"flex items-center gap-1\"\n >\n <AnimatePresence mode=\"popLayout\">\n {items.map((item, index) => (\n <Reorder.Item\n key={item.id}\n value={item}\n className=\"cursor-grab active:cursor-grabbing\"\n >\n <SingleTab\n item={item}\n isActive={index === activeIndex}\n onSelect={() => onSelect(index)}\n onClose={() => onClose(index)}\n {...tabProps}\n />\n </Reorder.Item>\n ))}\n </AnimatePresence>\n </Reorder.Group>\n ) : (\n <AnimatePresence mode=\"popLayout\">\n {items.map((item, index) => (\n <SingleTab\n key={item.id}\n item={item}\n isActive={index === activeIndex}\n onSelect={() => onSelect(index)}\n onClose={() => onClose(index)}\n {...tabProps}\n />\n ))}\n </AnimatePresence>\n )}\n\n {showCount ? (\n <div className=\"text-muted-foreground ml-auto flex items-center text-xs\">\n {items.length} tab{items.length !== 1 ? 's' : ''}\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|