@signalflare-ai/ui 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -4
- package/README.md +1 -1
- package/ai/component-registry.json +976 -182
- package/ai/component-registry.md +4183 -49
- package/ai/schemas.ts +99 -502
- package/dist/.build-complete +1 -1
- package/dist/ai/schemas.d.ts +76 -58
- package/dist/ai/schemas.d.ts.map +1 -1
- package/dist/{ai-actions-DSVeQn4e.js → ai-actions-BdUZI3Gk.js} +3 -3
- package/dist/{ai-actions-DSVeQn4e.js.map → ai-actions-BdUZI3Gk.js.map} +1 -1
- package/dist/{ai-agent-card-BXHwhWAU.js → ai-agent-card-BR2NIYhi.js} +1 -1
- package/dist/{ai-agent-card-BXHwhWAU.js.map → ai-agent-card-BR2NIYhi.js.map} +1 -1
- package/dist/{ai-approval-aa0qvjFN.js → ai-approval-Ba7mrKba.js} +2 -2
- package/dist/{ai-approval-aa0qvjFN.js.map → ai-approval-Ba7mrKba.js.map} +1 -1
- package/dist/{ai-code-block-BgtIxtZZ.js → ai-code-block-CZtoL73R.js} +3 -3
- package/dist/{ai-code-block-BgtIxtZZ.js.map → ai-code-block-CZtoL73R.js.map} +1 -1
- package/dist/ai-conversation-Cc7WlaBg.js +242 -0
- package/dist/ai-conversation-Cc7WlaBg.js.map +1 -0
- package/dist/{ai-info-banner-uFxHHwBA.js → ai-info-banner-C7EWPBj7.js} +7 -3
- package/dist/ai-info-banner-C7EWPBj7.js.map +1 -0
- package/dist/{ai-message-BjnFznXy.js → ai-message-Bp7L68U_.js} +27 -8
- package/dist/ai-message-Bp7L68U_.js.map +1 -0
- package/dist/{ai-mission-header-08__gULL.js → ai-mission-header-TiCJfTNt.js} +1 -1
- package/dist/{ai-mission-header-08__gULL.js.map → ai-mission-header-TiCJfTNt.js.map} +1 -1
- package/dist/{ai-part-group-DBtgTgAn.js → ai-part-group-DNb9I446.js} +3 -3
- package/dist/{ai-part-group-DBtgTgAn.js.map → ai-part-group-DNb9I446.js.map} +1 -1
- package/dist/{ai-prompt-input-CuluUzpf.js → ai-prompt-input-BVvov_KF.js} +29 -42
- package/dist/ai-prompt-input-BVvov_KF.js.map +1 -0
- package/dist/{ai-question-CHHoDJMg.js → ai-question-GPPMk7YM.js} +2 -2
- package/dist/{ai-question-CHHoDJMg.js.map → ai-question-GPPMk7YM.js.map} +1 -1
- package/dist/{ai-reasoning-CnL6ZSr5.js → ai-reasoning-_feFjk56.js} +2 -2
- package/dist/{ai-reasoning-CnL6ZSr5.js.map → ai-reasoning-_feFjk56.js.map} +1 -1
- package/dist/{ai-response-BEUg3xvd.js → ai-response-CvjV3WhV.js} +8 -3
- package/dist/ai-response-CvjV3WhV.js.map +1 -0
- package/dist/{ai-shimmer-By5_L05p.js → ai-shimmer-j6lKIrjj.js} +1 -1
- package/dist/{ai-shimmer-By5_L05p.js.map → ai-shimmer-j6lKIrjj.js.map} +1 -1
- package/dist/{ai-status-badge-BGYGWYF6.js → ai-status-badge-CSU_QOdz.js} +1 -1
- package/dist/{ai-status-badge-BGYGWYF6.js.map → ai-status-badge-CSU_QOdz.js.map} +1 -1
- package/dist/{ai-streaming-text-CMfoThV0.js → ai-streaming-text-IWW1BhvZ.js} +44 -16
- package/dist/ai-streaming-text-IWW1BhvZ.js.map +1 -0
- package/dist/{ai-subagent-DcPRqkAA.js → ai-subagent-JA4iIMW3.js} +13 -5
- package/dist/ai-subagent-JA4iIMW3.js.map +1 -0
- package/dist/{ai-suggestion-MgeCg5Ar.js → ai-suggestion-BdO6MBuH.js} +2 -2
- package/dist/{ai-suggestion-MgeCg5Ar.js.map → ai-suggestion-BdO6MBuH.js.map} +1 -1
- package/dist/{ai-task-list-Da9zIm00.js → ai-task-list-DYw4R1FA.js} +12 -5
- package/dist/ai-task-list-DYw4R1FA.js.map +1 -0
- package/dist/{ai-timeline-Cwu045IR.js → ai-timeline-C42tOUT8.js} +1 -1
- package/dist/{ai-timeline-Cwu045IR.js.map → ai-timeline-C42tOUT8.js.map} +1 -1
- package/dist/{ai-tool-Cn1O4xjP.js → ai-tool-03jOTwUI.js} +23 -10
- package/dist/ai-tool-03jOTwUI.js.map +1 -0
- package/dist/{ai-usage-bar-DjS12DMp.js → ai-usage-bar-BRf5LC_b.js} +1 -1
- package/dist/{ai-usage-bar-DjS12DMp.js.map → ai-usage-bar-BRf5LC_b.js.map} +1 -1
- package/dist/{badge-D_eaA6wv.js → badge-BheXjMc8.js} +2 -2
- package/dist/{badge-D_eaA6wv.js.map → badge-BheXjMc8.js.map} +1 -1
- package/dist/{banner-B_6oBrsu.js → banner-CcsjunJg.js} +7 -2
- package/dist/banner-CcsjunJg.js.map +1 -0
- package/dist/{breadcrumbs-BlmeYfgq.js → breadcrumbs-CouSyy3H.js} +3 -3
- package/dist/{breadcrumbs-BlmeYfgq.js.map → breadcrumbs-CouSyy3H.js.map} +1 -1
- package/dist/{button-De0267YU.js → button-CO6-qPax.js} +1 -1
- package/dist/{button-De0267YU.js.map → button-CO6-qPax.js.map} +1 -1
- package/dist/catalog.js +1 -1
- package/dist/{chart-BK3sVPnD.js → chart-Dg0qUeSc.js} +2 -2
- package/dist/{chart-BK3sVPnD.js.map → chart-Dg0qUeSc.js.map} +1 -1
- package/dist/{checkbox-DYhUmZNw.js → checkbox-D7p4QKsC.js} +2 -2
- package/dist/{checkbox-DYhUmZNw.js.map → checkbox-D7p4QKsC.js.map} +1 -1
- package/dist/{clipboard-text-ssybngLw.js → clipboard-text-kLaMogs3.js} +3 -3
- package/dist/{clipboard-text-ssybngLw.js.map → clipboard-text-kLaMogs3.js.map} +1 -1
- package/dist/{code-Cx-QSoOT.js → code-BN8InC0G.js} +2 -2
- package/dist/{code-Cx-QSoOT.js.map → code-BN8InC0G.js.map} +1 -1
- package/dist/{collapsible-DWsXeXmS.js → collapsible-D_ueZ0jz.js} +1 -1
- package/dist/{collapsible-DWsXeXmS.js.map → collapsible-D_ueZ0jz.js.map} +1 -1
- package/dist/{combobox-C0iW6a0r.js → combobox-B7TOK0U2.js} +3 -3
- package/dist/{combobox-C0iW6a0r.js.map → combobox-B7TOK0U2.js.map} +1 -1
- package/dist/{command-palette-DGzioeki.js → command-palette-CuNUyJca.js} +2 -2
- package/dist/{command-palette-DGzioeki.js.map → command-palette-CuNUyJca.js.map} +1 -1
- package/dist/components/ai-actions.js +1 -1
- package/dist/components/ai-agent-card.js +1 -1
- package/dist/components/ai-approval.js +1 -1
- package/dist/components/ai-code-block.js +1 -1
- package/dist/components/ai-conversation.js +2 -2
- package/dist/components/ai-info-banner.js +1 -1
- package/dist/components/ai-message.js +1 -1
- package/dist/components/ai-mission-header.js +1 -1
- package/dist/components/ai-part-group.js +1 -1
- package/dist/components/ai-prompt-input.js +1 -1
- package/dist/components/ai-question.js +1 -1
- package/dist/components/ai-reasoning.js +1 -1
- package/dist/components/ai-response.js +1 -1
- package/dist/components/ai-shimmer.js +1 -1
- package/dist/components/ai-status-badge.js +1 -1
- package/dist/components/ai-streaming-text.js +2 -2
- package/dist/components/ai-subagent.js +1 -1
- package/dist/components/ai-suggestion.js +1 -1
- package/dist/components/ai-task-list.js +1 -1
- package/dist/components/ai-timeline.js +1 -1
- package/dist/components/ai-tool.js +1 -1
- package/dist/components/ai-usage-bar.js +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/banner.js +1 -1
- package/dist/components/breadcrumbs.js +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/chart.js +2 -2
- package/dist/components/checkbox.js +1 -1
- package/dist/components/clipboard-text.js +1 -1
- package/dist/components/code.js +1 -1
- package/dist/components/collapsible.js +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/command-palette.js +1 -1
- package/dist/components/data-grid.js +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/date-range-picker.js +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dropdown.js +1 -1
- package/dist/components/empty.js +1 -1
- package/dist/components/field.js +1 -1
- package/dist/components/filters.js +1 -1
- package/dist/components/flow.js +1 -1
- package/dist/components/grid.js +1 -1
- package/dist/components/input.js +2 -2
- package/dist/components/label.js +1 -1
- package/dist/components/layer-card.js +1 -1
- package/dist/components/loader.js +1 -1
- package/dist/components/menubar.js +1 -1
- package/dist/components/meter.js +1 -1
- package/dist/components/pagination.js +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/radio.js +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/sensitive-input.js +1 -1
- package/dist/components/sidebar.js +1 -1
- package/dist/components/signalflare-ai-logo.js +1 -1
- package/dist/components/sparkline.js +1 -1
- package/dist/components/stat-card.js +1 -1
- package/dist/components/surface.js +1 -1
- package/dist/components/switch.js +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/tabs.js +1 -1
- package/dist/components/text-roll.js +1 -1
- package/dist/components/text.js +1 -1
- package/dist/components/theme-toggle.js +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/use-agent-harness.js +1 -1
- package/dist/{data-grid-CG76N_hK.js → data-grid-DGHmU0w3.js} +8 -8
- package/dist/{data-grid-CG76N_hK.js.map → data-grid-DGHmU0w3.js.map} +1 -1
- package/dist/{date-picker-Dqg9L4xu.js → date-picker--ox89RBy.js} +1 -1
- package/dist/{date-picker-Dqg9L4xu.js.map → date-picker--ox89RBy.js.map} +1 -1
- package/dist/{date-range-picker-D75LLINc.js → date-range-picker-DVa7QBqE.js} +1 -1
- package/dist/{date-range-picker-D75LLINc.js.map → date-range-picker-DVa7QBqE.js.map} +1 -1
- package/dist/{dialog-CyHEQXEY.js → dialog-Bv1oSFOd.js} +2 -2
- package/dist/{dialog-CyHEQXEY.js.map → dialog-Bv1oSFOd.js.map} +1 -1
- package/dist/{dist-1-gcEL2L.js → dist-B6iWiWwp.js} +25 -25
- package/dist/{dist-1-gcEL2L.js.map → dist-B6iWiWwp.js.map} +1 -1
- package/dist/{dropdown-qnEYRFXZ.js → dropdown-B_nrGXjV.js} +2 -2
- package/dist/{dropdown-qnEYRFXZ.js.map → dropdown-B_nrGXjV.js.map} +1 -1
- package/dist/{echart-DURZEyai.js → echart-CdOUaT-r.js} +1 -1
- package/dist/{echart-DURZEyai.js.map → echart-CdOUaT-r.js.map} +1 -1
- package/dist/{empty-D2TypIId.js → empty-DZnN0zKX.js} +11 -6
- package/dist/empty-DZnN0zKX.js.map +1 -0
- package/dist/{field-Y_UK1_Cg.js → field-B_yVof52.js} +2 -2
- package/dist/{field-Y_UK1_Cg.js.map → field-B_yVof52.js.map} +1 -1
- package/dist/{filters-Bw_U6ZTx.js → filters-cpJCY21R.js} +7 -7
- package/dist/{filters-Bw_U6ZTx.js.map → filters-cpJCY21R.js.map} +1 -1
- package/dist/{flow-BRsYUCJa.js → flow-B4v198ot.js} +1 -1
- package/dist/{flow-BRsYUCJa.js.map → flow-B4v198ot.js.map} +1 -1
- package/dist/genui.js +1 -1
- package/dist/{grid-qUAN9hFx.js → grid-CEd64Lnh.js} +1 -1
- package/dist/{grid-qUAN9hFx.js.map → grid-CEd64Lnh.js.map} +1 -1
- package/dist/{highlight-to-react-ClEfL81q.js → highlight-to-react-D0Yav4jk.js} +1 -1
- package/dist/{highlight-to-react-ClEfL81q.js.map → highlight-to-react-D0Yav4jk.js.map} +1 -1
- package/dist/index.js +69 -69
- package/dist/{input-DXYUjGgD.js → input-B2bbijRh.js} +2 -2
- package/dist/{input-DXYUjGgD.js.map → input-B2bbijRh.js.map} +1 -1
- package/dist/{input-DddtBN-g.js → input-ClB_E4Lb.js} +4 -4
- package/dist/{input-DddtBN-g.js.map → input-ClB_E4Lb.js.map} +1 -1
- package/dist/{label-QtJxtJ4u.js → label-DUv_urO1.js} +2 -2
- package/dist/{label-QtJxtJ4u.js.map → label-DUv_urO1.js.map} +1 -1
- package/dist/{layer-card-BME0eljh.js → layer-card-BK7eYfwn.js} +1 -1
- package/dist/{layer-card-BME0eljh.js.map → layer-card-BK7eYfwn.js.map} +1 -1
- package/dist/layout-DJHMMap2.js +6103 -0
- package/dist/layout-DJHMMap2.js.map +1 -0
- package/dist/measured-text-BI3dTJmH.js +290 -0
- package/dist/measured-text-BI3dTJmH.js.map +1 -0
- package/dist/{menubar-C8NzAjfd.js → menubar-Cxf3xeAt.js} +2 -2
- package/dist/{menubar-C8NzAjfd.js.map → menubar-Cxf3xeAt.js.map} +1 -1
- package/dist/{meter-CpmTenEr.js → meter-BFFe9l5b.js} +1 -1
- package/dist/{meter-CpmTenEr.js.map → meter-BFFe9l5b.js.map} +1 -1
- package/dist/{pagination-BVqdlONY.js → pagination-yS372Tr4.js} +2 -2
- package/dist/{pagination-BVqdlONY.js.map → pagination-yS372Tr4.js.map} +1 -1
- package/dist/{popover-BRQZ2b6z.js → popover-SRoJaCZr.js} +1 -1
- package/dist/{popover-BRQZ2b6z.js.map → popover-SRoJaCZr.js.map} +1 -1
- package/dist/{radio-BNSwOt3B.js → radio-BcwhwYNB.js} +1 -1
- package/dist/{radio-BNSwOt3B.js.map → radio-BcwhwYNB.js.map} +1 -1
- package/dist/{select-1w2aebGQ.js → select-DMhdoHMa.js} +4 -4
- package/dist/{select-1w2aebGQ.js.map → select-DMhdoHMa.js.map} +1 -1
- package/dist/{sensitive-input-82Cez3vj.js → sensitive-input-CJUpIRal.js} +3 -3
- package/dist/{sensitive-input-82Cez3vj.js.map → sensitive-input-CJUpIRal.js.map} +1 -1
- package/dist/{sidebar-CAsCmSpM.js → sidebar-D4zrlYpn.js} +2 -2
- package/dist/{sidebar-CAsCmSpM.js.map → sidebar-D4zrlYpn.js.map} +1 -1
- package/dist/{signalflare-ai-logo-DDhxMJD6.js → signalflare-ai-logo-Bipogceq.js} +1 -1
- package/dist/{signalflare-ai-logo-DDhxMJD6.js.map → signalflare-ai-logo-Bipogceq.js.map} +1 -1
- package/dist/{skeleton-line-Do3UmGk9.js → skeleton-line-CH1-h6e2.js} +1 -1
- package/dist/{skeleton-line-Do3UmGk9.js.map → skeleton-line-CH1-h6e2.js.map} +1 -1
- package/dist/{sparkline-DdbeM4Ai.js → sparkline-DHmgj1d0.js} +2 -2
- package/dist/{sparkline-DdbeM4Ai.js.map → sparkline-DHmgj1d0.js.map} +1 -1
- package/dist/src/blocks/agent-harness/agent-harness.d.ts.map +1 -1
- package/dist/src/blocks/agent-harness/agent-harness.tsx +29 -5
- package/dist/src/components/ai-conversation/ai-conversation.d.ts +69 -37
- package/dist/src/components/ai-conversation/ai-conversation.d.ts.map +1 -1
- package/dist/src/components/ai-conversation/index.d.ts +2 -1
- package/dist/src/components/ai-conversation/index.d.ts.map +1 -1
- package/dist/src/components/ai-conversation/measurement-constants.d.ts +30 -0
- package/dist/src/components/ai-conversation/measurement-constants.d.ts.map +1 -0
- package/dist/src/components/ai-info-banner/ai-info-banner.d.ts.map +1 -1
- package/dist/src/components/ai-message/ai-message.d.ts +3 -0
- package/dist/src/components/ai-message/ai-message.d.ts.map +1 -1
- package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts +13 -3
- package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
- package/dist/src/components/ai-prompt-input/index.d.ts +1 -1
- package/dist/src/components/ai-prompt-input/index.d.ts.map +1 -1
- package/dist/src/components/ai-response/ai-response.d.ts +12 -1
- package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
- package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts +27 -0
- package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts.map +1 -1
- package/dist/src/components/ai-streaming-text/index.d.ts +1 -1
- package/dist/src/components/ai-streaming-text/index.d.ts.map +1 -1
- package/dist/src/components/ai-subagent/ai-subagent.d.ts.map +1 -1
- package/dist/src/components/ai-task-list/ai-task-list.d.ts.map +1 -1
- package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
- package/dist/src/components/banner/banner.d.ts.map +1 -1
- package/dist/src/components/empty/empty.d.ts.map +1 -1
- package/dist/src/components/stat-card/stat-card.d.ts +5 -0
- package/dist/src/components/stat-card/stat-card.d.ts.map +1 -1
- package/dist/src/components/text/text.d.ts +35 -1
- package/dist/src/components/text/text.d.ts.map +1 -1
- package/dist/src/components/tooltip/tooltip.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts +2 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/measured-text.d.ts +40 -0
- package/dist/src/utils/measured-text.d.ts.map +1 -0
- package/dist/src/utils/use-measured-text.d.ts +59 -0
- package/dist/src/utils/use-measured-text.d.ts.map +1 -0
- package/dist/{stat-card-CEZscNh8.js → stat-card-Ew-ofzEm.js} +28 -10
- package/dist/stat-card-Ew-ofzEm.js.map +1 -0
- package/dist/styles/sf-binding.css +1 -1
- package/dist/styles/sf-standalone.css +2 -2
- package/dist/styles/shadcn.css +1 -1
- package/dist/styles/theme-fedramp.css +12 -3
- package/dist/styles/theme-minimal.css +104 -26
- package/dist/styles/theme-sf.css +138 -39
- package/dist/styles/theme-vesper.css +91 -0
- package/dist/{surface-BduI7Ehl.js → surface-DGwRlC0o.js} +1 -1
- package/dist/{surface-BduI7Ehl.js.map → surface-DGwRlC0o.js.map} +1 -1
- package/dist/{switch-CzZBRBL7.js → switch-BxAMfHdt.js} +2 -2
- package/dist/{switch-CzZBRBL7.js.map → switch-BxAMfHdt.js.map} +1 -1
- package/dist/{table-Rv4JMy0B.js → table-BBeAtYVZ.js} +2 -2
- package/dist/{table-Rv4JMy0B.js.map → table-BBeAtYVZ.js.map} +1 -1
- package/dist/{tabs-1cHrYoel.js → tabs-CeHu7Scn.js} +1 -1
- package/dist/{tabs-1cHrYoel.js.map → tabs-CeHu7Scn.js.map} +1 -1
- package/dist/{text-KJmGkwnf.js → text-Cqryz7rk.js} +27 -5
- package/dist/text-Cqryz7rk.js.map +1 -0
- package/dist/{text-roll-BZ3I1umc.js → text-roll-Ch52hcQj.js} +1 -1
- package/dist/{text-roll-BZ3I1umc.js.map → text-roll-Ch52hcQj.js.map} +1 -1
- package/dist/{theme-toggle-Bhu681D7.js → theme-toggle-LDfIKEqx.js} +3 -3
- package/dist/{theme-toggle-Bhu681D7.js.map → theme-toggle-LDfIKEqx.js.map} +1 -1
- package/dist/{toast-Nw28a5Cx.js → toast-CaFQNYng.js} +2 -2
- package/dist/{toast-Nw28a5Cx.js.map → toast-CaFQNYng.js.map} +1 -1
- package/dist/{tooltip-Cb7QW-7H.js → tooltip-g9lFsvcT.js} +8 -2
- package/dist/tooltip-g9lFsvcT.js.map +1 -0
- package/dist/{use-agent-harness-BMyF8pTq.js → use-agent-harness-BTcNJdw4.js} +1 -1
- package/dist/{use-agent-harness-BMyF8pTq.js.map → use-agent-harness-BTcNJdw4.js.map} +1 -1
- package/dist/utils.js +2 -1
- package/package.json +2 -1
- package/scripts/css-build.ts +1 -1
- package/scripts/theme-generator/config.ts +27 -141
- package/scripts/theme-generator/generate-css.ts +0 -1
- package/scripts/theme-generator/index.ts +0 -1
- package/dist/ai-conversation-CArP7C8K.js +0 -184
- package/dist/ai-conversation-CArP7C8K.js.map +0 -1
- package/dist/ai-info-banner-uFxHHwBA.js.map +0 -1
- package/dist/ai-message-BjnFznXy.js.map +0 -1
- package/dist/ai-prompt-input-CuluUzpf.js.map +0 -1
- package/dist/ai-response-BEUg3xvd.js.map +0 -1
- package/dist/ai-streaming-text-CMfoThV0.js.map +0 -1
- package/dist/ai-subagent-DcPRqkAA.js.map +0 -1
- package/dist/ai-task-list-Da9zIm00.js.map +0 -1
- package/dist/ai-tool-Cn1O4xjP.js.map +0 -1
- package/dist/banner-B_6oBrsu.js.map +0 -1
- package/dist/empty-D2TypIId.js.map +0 -1
- package/dist/stat-card-CEZscNh8.js.map +0 -1
- package/dist/styles/theme-blue-tint.css +0 -98
- package/dist/text-KJmGkwnf.js.map +0 -1
- package/dist/tooltip-Cb7QW-7H.js.map +0 -1
package/ai/component-registry.md
CHANGED
|
@@ -26,11 +26,31 @@ Container for a row of AI message action buttons.
|
|
|
26
26
|
|
|
27
27
|
`text-sf-default`, `text-sf-subtle`
|
|
28
28
|
|
|
29
|
+
**Examples:**
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<AiActions>
|
|
33
|
+
<AiAction tooltip="Copy">
|
|
34
|
+
<CopyIcon className="size-4" />
|
|
35
|
+
</AiAction>
|
|
36
|
+
<AiAction tooltip="Retry">
|
|
37
|
+
<ArrowCounterClockwiseIcon className="size-4" />
|
|
38
|
+
</AiAction>
|
|
39
|
+
<AiAction tooltip="Thumbs up">
|
|
40
|
+
<ThumbsUpIcon className="size-4" />
|
|
41
|
+
</AiAction>
|
|
42
|
+
<AiAction tooltip="Thumbs down">
|
|
43
|
+
<ThumbsDownIcon className="size-4" />
|
|
44
|
+
</AiAction>
|
|
45
|
+
</AiActions>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
29
49
|
---
|
|
30
50
|
|
|
31
51
|
### AiAgentCard
|
|
32
52
|
|
|
33
|
-
`AiAgentCard` — compact card showing one agent's status in a commander dashboard.
|
|
53
|
+
`AiAgentCard` — compact card showing one agent's status in a commander dashboard. Displays: agent icon, name, status indicator, current task, model, duration, and tool call count. Clickable for selection.
|
|
34
54
|
|
|
35
55
|
**Type:** component
|
|
36
56
|
|
|
@@ -75,11 +95,111 @@ Container for a row of AI message action buttons.
|
|
|
75
95
|
|
|
76
96
|
`bg-sf-brand`, `bg-sf-danger`, `bg-sf-elevated`, `bg-sf-fill`, `bg-sf-recessed`, `bg-sf-success`, `bg-sf-tint`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`, `text-sf-success`
|
|
77
97
|
|
|
98
|
+
**Examples:**
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
<div className="flex flex-wrap gap-3">
|
|
102
|
+
<AiAgentCard
|
|
103
|
+
name="Explore"
|
|
104
|
+
agentType="explore"
|
|
105
|
+
status="running"
|
|
106
|
+
modelId="claude-haiku-3.5"
|
|
107
|
+
currentTask="Scanning auth files for deprecated patterns..."
|
|
108
|
+
duration={4200}
|
|
109
|
+
toolCallCount={3}
|
|
110
|
+
/>
|
|
111
|
+
<AiAgentCard
|
|
112
|
+
name="Execute"
|
|
113
|
+
agentType="execute"
|
|
114
|
+
status="running"
|
|
115
|
+
modelId="claude-sonnet-4"
|
|
116
|
+
currentTask="Rewriting jwt.ts using jose library..."
|
|
117
|
+
duration={8700}
|
|
118
|
+
toolCallCount={1}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<div className="flex flex-wrap gap-3">
|
|
125
|
+
<AiAgentCard
|
|
126
|
+
name="Explore"
|
|
127
|
+
agentType="explore"
|
|
128
|
+
status="idle"
|
|
129
|
+
modelId="claude-haiku-3.5"
|
|
130
|
+
/>
|
|
131
|
+
<AiAgentCard
|
|
132
|
+
name="Plan"
|
|
133
|
+
agentType="plan"
|
|
134
|
+
status="running"
|
|
135
|
+
modelId="claude-sonnet-4"
|
|
136
|
+
currentTask="Drafting migration steps..."
|
|
137
|
+
duration={2100}
|
|
138
|
+
toolCallCount={0}
|
|
139
|
+
/>
|
|
140
|
+
<AiAgentCard
|
|
141
|
+
name="Execute"
|
|
142
|
+
agentType="execute"
|
|
143
|
+
status="completed"
|
|
144
|
+
modelId="claude-sonnet-4"
|
|
145
|
+
currentTask="Rewrote 4 files successfully."
|
|
146
|
+
duration={12_400}
|
|
147
|
+
toolCallCount={7}
|
|
148
|
+
/>
|
|
149
|
+
<AiAgentCard
|
|
150
|
+
name="Test"
|
|
151
|
+
agentType="test"
|
|
152
|
+
status="error"
|
|
153
|
+
modelId="claude-haiku-3.5"
|
|
154
|
+
currentTask="3 tests failed: auth.spec.ts"
|
|
155
|
+
duration={3200}
|
|
156
|
+
toolCallCount={2}
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
<div className="flex flex-wrap gap-3">
|
|
163
|
+
<AiAgentCard
|
|
164
|
+
name="Explore"
|
|
165
|
+
agentType="explore"
|
|
166
|
+
status="completed"
|
|
167
|
+
modelId="claude-haiku-3.5"
|
|
168
|
+
duration={4200}
|
|
169
|
+
toolCallCount={5}
|
|
170
|
+
/>
|
|
171
|
+
<AiAgentCard
|
|
172
|
+
name="Execute"
|
|
173
|
+
agentType="execute"
|
|
174
|
+
status="running"
|
|
175
|
+
modelId="claude-sonnet-4"
|
|
176
|
+
currentTask="Patching consumers..."
|
|
177
|
+
duration={6100}
|
|
178
|
+
toolCallCount={3}
|
|
179
|
+
selected
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<div className="flex flex-wrap gap-2">
|
|
186
|
+
{[
|
|
187
|
+
{ name: "Explore", agentType: "explore", status: "completed" as const },
|
|
188
|
+
{ name: "Plan", agentType: "plan", status: "completed" as const },
|
|
189
|
+
{ name: "Execute", agentType: "execute", status: "running" as const },
|
|
190
|
+
{ name: "Review", agentType: "review", status: "idle" as const },
|
|
191
|
+
].map((agent) => (
|
|
192
|
+
<AiAgentCard key={agent.name} size="sm" {...agent} />
|
|
193
|
+
))}
|
|
194
|
+
</div>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
|
|
78
198
|
---
|
|
79
199
|
|
|
80
200
|
### AiApproval
|
|
81
201
|
|
|
82
|
-
Approval card for tool calls and plan submissions.
|
|
202
|
+
Approval card for tool calls and plan submissions. Maps to harness events: `tool_approval_required`, `plan_approval_required`, `plan_approved`.
|
|
83
203
|
|
|
84
204
|
**Type:** component
|
|
85
205
|
|
|
@@ -119,6 +239,43 @@ Approval card for tool calls and plan submissions. Maps to harness events: `tool
|
|
|
119
239
|
|
|
120
240
|
`bg-sf-base`, `bg-sf-brand`, `bg-sf-elevated`, `border-sf-line`, `border-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`, `text-sf-success`
|
|
121
241
|
|
|
242
|
+
**Examples:**
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
<div className="w-full max-w-md">
|
|
246
|
+
<AiApproval
|
|
247
|
+
kind="tool"
|
|
248
|
+
status={status}
|
|
249
|
+
title="Execute shell command"
|
|
250
|
+
description="rm -rf /tmp/cache"
|
|
251
|
+
onApprove={() => setStatus("approved")}
|
|
252
|
+
onReject={() => setStatus("rejected")}
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
<div className="w-full max-w-md">
|
|
259
|
+
<AiApproval
|
|
260
|
+
kind="plan"
|
|
261
|
+
status={status}
|
|
262
|
+
title="Deployment plan"
|
|
263
|
+
description="The agent proposes the following steps:"
|
|
264
|
+
items={[
|
|
265
|
+
{ id: "1", label: "Run test suite", description: "All 142 tests" },
|
|
266
|
+
{ id: "2", label: "Build production bundle" },
|
|
267
|
+
{ id: "3", label: "Deploy to staging", description: "us-east-1" },
|
|
268
|
+
{ id: "4", label: "Run smoke tests" },
|
|
269
|
+
{ id: "5", label: "Promote to production" },
|
|
270
|
+
]}
|
|
271
|
+
showFeedback
|
|
272
|
+
onApprove={() => setStatus("approved")}
|
|
273
|
+
onReject={() => setStatus("rejected")}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
|
|
122
279
|
---
|
|
123
280
|
|
|
124
281
|
### AiCodeBlock
|
|
@@ -149,6 +306,21 @@ Displays a code block with monospace formatting and an optional copy button. Doe
|
|
|
149
306
|
|
|
150
307
|
`bg-sf-recessed`, `border-sf-line`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`
|
|
151
308
|
|
|
309
|
+
**Examples:**
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
<AiCodeBlock code={CODE} language="tsx">
|
|
313
|
+
<AiCodeBlockCopyButton />
|
|
314
|
+
</AiCodeBlock>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
<AiCodeBlock code="npm install @signalflare-ai/ui">
|
|
319
|
+
<AiCodeBlockCopyButton />
|
|
320
|
+
</AiCodeBlock>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
|
|
152
324
|
---
|
|
153
325
|
|
|
154
326
|
### AiConversation
|
|
@@ -169,11 +341,30 @@ Outer scroll container for a conversation. Sticks to the bottom as new messages
|
|
|
169
341
|
- `lang`: string
|
|
170
342
|
- `title`: string
|
|
171
343
|
|
|
344
|
+
**Examples:**
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
<div className="h-80 w-full overflow-hidden rounded-lg border border-sf-line">
|
|
348
|
+
<AiConversation>
|
|
349
|
+
<AiConversationContent>
|
|
350
|
+
{MESSAGES.map((m) => (
|
|
351
|
+
<AiMessage key={m.id} from={m.from}>
|
|
352
|
+
<AiMessageContent>
|
|
353
|
+
<AiResponse>{m.text}</AiResponse>
|
|
354
|
+
</AiMessageContent>
|
|
355
|
+
</AiMessage>
|
|
356
|
+
))}
|
|
357
|
+
</AiConversationContent>
|
|
358
|
+
</AiConversation>
|
|
359
|
+
</div>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
|
|
172
363
|
---
|
|
173
364
|
|
|
174
365
|
### AiInfoBanner
|
|
175
366
|
|
|
176
|
-
Inline conversation banner for system notices. Renders as a compact, horizontally centered divider-like notice rather than a chat bubble.
|
|
367
|
+
Inline conversation banner for system notices. Renders as a compact, horizontally centered divider-like notice rather than a chat bubble. Maps to harness events: `error`, `info`, `mode_changed`, `model_changed`.
|
|
177
368
|
|
|
178
369
|
**Type:** component
|
|
179
370
|
|
|
@@ -199,6 +390,21 @@ Inline conversation banner for system notices. Renders as a compact, horizontall
|
|
|
199
390
|
|
|
200
391
|
`border-sf-danger`, `border-sf-info`, `border-sf-line`, `text-sf-danger`, `text-sf-info`, `text-sf-subtle`
|
|
201
392
|
|
|
393
|
+
**Examples:**
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
<div className="flex w-full flex-col gap-3">
|
|
397
|
+
<AiInfoBanner level="info">
|
|
398
|
+
Follow-up message queued — will send after current response completes
|
|
399
|
+
</AiInfoBanner>
|
|
400
|
+
<AiInfoBanner level="change">Switched to claude-opus-4-6</AiInfoBanner>
|
|
401
|
+
<AiInfoBanner level="error">
|
|
402
|
+
Connection lost. Retrying in 3s…
|
|
403
|
+
</AiInfoBanner>
|
|
404
|
+
</div>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
|
|
202
408
|
---
|
|
203
409
|
|
|
204
410
|
### AiMessage
|
|
@@ -227,11 +433,43 @@ Root message container. Sets layout, group class, and role context.
|
|
|
227
433
|
|
|
228
434
|
`bg-sf-control`, `bg-sf-overlay`, `bg-sf-tint`, `text-sf-default`, `text-sf-subtle`
|
|
229
435
|
|
|
436
|
+
**Examples:**
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
<div className="flex w-full flex-col gap-2 p-4">
|
|
440
|
+
<AiMessage from="user">
|
|
441
|
+
<AiMessageContent>What is the capital of France?</AiMessageContent>
|
|
442
|
+
</AiMessage>
|
|
443
|
+
<AiMessage from="assistant">
|
|
444
|
+
<AiMessageContent>
|
|
445
|
+
<AiResponse>{"The capital of France is **Paris**."}</AiResponse>
|
|
446
|
+
</AiMessageContent>
|
|
447
|
+
<AiMessageToolbar>
|
|
448
|
+
<AiMessageActions>
|
|
449
|
+
<AiMessageAction tooltip="Copy">
|
|
450
|
+
<CopyIcon className="size-4" />
|
|
451
|
+
</AiMessageAction>
|
|
452
|
+
<AiMessageAction tooltip="Retry">
|
|
453
|
+
<ArrowCounterClockwiseIcon className="size-4" />
|
|
454
|
+
</AiMessageAction>
|
|
455
|
+
</AiMessageActions>
|
|
456
|
+
</AiMessageToolbar>
|
|
457
|
+
</AiMessage>
|
|
458
|
+
</div>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
<AiMessage from="user">
|
|
463
|
+
<AiMessageContent>Can you summarise this document?</AiMessageContent>
|
|
464
|
+
</AiMessage>
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
|
|
230
468
|
---
|
|
231
469
|
|
|
232
470
|
### AiMissionHeader
|
|
233
471
|
|
|
234
|
-
`AiMissionHeader` — top bar for the Commander dashboard.
|
|
472
|
+
`AiMissionHeader` — top bar for the Commander dashboard. Shows: mission title, progress bar (from task list), agent count, live elapsed time, token usage, and an abort button while running.
|
|
235
473
|
|
|
236
474
|
**Type:** component
|
|
237
475
|
|
|
@@ -269,11 +507,122 @@ Root message container. Sets layout, group class, and role context.
|
|
|
269
507
|
|
|
270
508
|
`bg-sf-base`, `bg-sf-brand`, `bg-sf-danger`, `bg-sf-fill`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
|
|
271
509
|
|
|
510
|
+
**Examples:**
|
|
511
|
+
|
|
512
|
+
```tsx
|
|
513
|
+
<AiMissionHeader
|
|
514
|
+
title="Refactor auth module"
|
|
515
|
+
taskList={{
|
|
516
|
+
title: "Refactor auth module",
|
|
517
|
+
tasks: [
|
|
518
|
+
{
|
|
519
|
+
id: "t1",
|
|
520
|
+
content: "Explore authentication codebase",
|
|
521
|
+
status: "completed",
|
|
522
|
+
priority: "high",
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
id: "t2",
|
|
526
|
+
content: "Identify deprecated patterns",
|
|
527
|
+
status: "completed",
|
|
528
|
+
priority: "high",
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: "t3",
|
|
532
|
+
content: "Write updated auth helpers",
|
|
533
|
+
status: "in_progress",
|
|
534
|
+
priority: "medium",
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
id: "t4",
|
|
538
|
+
content: "Update all consumers",
|
|
539
|
+
status: "pending",
|
|
540
|
+
priority: "medium",
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
id: "t5",
|
|
544
|
+
content: "Update tests",
|
|
545
|
+
status: "pending",
|
|
546
|
+
priority: "low",
|
|
547
|
+
},
|
|
548
|
+
],
|
|
549
|
+
}}
|
|
550
|
+
usage={{
|
|
551
|
+
inputTokens: 12_480,
|
|
552
|
+
outputTokens: 3256,
|
|
553
|
+
totalTokens: 15_736,
|
|
554
|
+
cost: 0.04,
|
|
555
|
+
}}
|
|
556
|
+
activeAgentCount={2}
|
|
557
|
+
totalAgentCount={4}
|
|
558
|
+
startedAt={startedAt}
|
|
559
|
+
isRunning
|
|
560
|
+
/>
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
```tsx
|
|
564
|
+
<AiMissionHeader
|
|
565
|
+
title="Deploy to production"
|
|
566
|
+
taskList={{
|
|
567
|
+
tasks: [
|
|
568
|
+
{
|
|
569
|
+
id: "t1",
|
|
570
|
+
content: "Run tests",
|
|
571
|
+
status: "completed",
|
|
572
|
+
priority: "high",
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
id: "t2",
|
|
576
|
+
content: "Build artifacts",
|
|
577
|
+
status: "completed",
|
|
578
|
+
priority: "high",
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
id: "t3",
|
|
582
|
+
content: "Deploy to staging",
|
|
583
|
+
status: "completed",
|
|
584
|
+
priority: "medium",
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
id: "t4",
|
|
588
|
+
content: "Smoke test",
|
|
589
|
+
status: "completed",
|
|
590
|
+
priority: "medium",
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
id: "t5",
|
|
594
|
+
content: "Deploy to production",
|
|
595
|
+
status: "completed",
|
|
596
|
+
priority: "high",
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
}}
|
|
600
|
+
usage={{ totalTokens: 28_400, cost: 0.12 }}
|
|
601
|
+
activeAgentCount={0}
|
|
602
|
+
totalAgentCount={3}
|
|
603
|
+
startedAt={startedAt}
|
|
604
|
+
endedAt={endedAt}
|
|
605
|
+
isRunning={false}
|
|
606
|
+
/>
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
```tsx
|
|
610
|
+
<AiMissionHeader
|
|
611
|
+
title="Analyze codebase"
|
|
612
|
+
activeAgentCount={1}
|
|
613
|
+
totalAgentCount={2}
|
|
614
|
+
startedAt={startedAt}
|
|
615
|
+
isRunning
|
|
616
|
+
variant="compact"
|
|
617
|
+
/>
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
|
|
272
621
|
---
|
|
273
622
|
|
|
274
623
|
### AiPartGroup
|
|
275
624
|
|
|
276
|
-
Groups streaming ephemeral activity (tool calls + reasoning) into a single rolling window during streaming, then collapses to a frozen summary line once the parent message completes.
|
|
625
|
+
Groups streaming ephemeral activity (tool calls + reasoning) into a single rolling window during streaming, then collapses to a frozen summary line once the parent message completes. Behavior: - **Streaming:** shows the most recent `max` (default 3) ephemeral children. Pinned rows (errors / user-expanded) sit above the live window. - **Completed:** writes a snapshot keyed by `groupKey`, unmounts ephemeral children entirely, and renders a static `▸ {title} · N steps` line. - **Re-mount after completion:** always renders the cached snapshot — no animations, no `useEffect` re-runs, no tool re-execution risk.
|
|
277
626
|
|
|
278
627
|
**Type:** component
|
|
279
628
|
|
|
@@ -298,11 +647,59 @@ Groups streaming ephemeral activity (tool calls + reasoning) into a single rolli
|
|
|
298
647
|
|
|
299
648
|
`bg-sf-tint`, `border-sf-line`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
|
|
300
649
|
|
|
650
|
+
**Examples:**
|
|
651
|
+
|
|
652
|
+
```tsx
|
|
653
|
+
<div className="flex flex-col gap-3">
|
|
654
|
+
<div className="flex items-center justify-between gap-3">
|
|
655
|
+
<Text variant="secondary" size="sm">
|
|
656
|
+
Rolling window of 3 rows while streaming. Collapses to a single frozen
|
|
657
|
+
line when complete.
|
|
658
|
+
</Text>
|
|
659
|
+
<Button
|
|
660
|
+
onClick={() => setRunId((n) => n + 1)}
|
|
661
|
+
size="sm"
|
|
662
|
+
variant="ghost"
|
|
663
|
+
>
|
|
664
|
+
Run again
|
|
665
|
+
</Button>
|
|
666
|
+
</div>
|
|
667
|
+
<div className="min-h-[6rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3">
|
|
668
|
+
<AiPartGroup
|
|
669
|
+
complete={complete}
|
|
670
|
+
groupKey={`activity-demo-${runId}`}
|
|
671
|
+
max={3}
|
|
672
|
+
title="Investigating failing auth tests"
|
|
673
|
+
>
|
|
674
|
+
{steps.map((s) =>
|
|
675
|
+
s.kind === "tool" ? (
|
|
676
|
+
<AiToolCall
|
|
677
|
+
duration={s.duration}
|
|
678
|
+
key={s.part.toolCallId}
|
|
679
|
+
part={s.part}
|
|
680
|
+
variant="ephemeral"
|
|
681
|
+
/>
|
|
682
|
+
) : (
|
|
683
|
+
<AiReasoning
|
|
684
|
+
duration={s.duration}
|
|
685
|
+
isStreaming={s.isStreaming}
|
|
686
|
+
key={s.id}
|
|
687
|
+
part={{ text: s.text }}
|
|
688
|
+
variant="ephemeral"
|
|
689
|
+
/>
|
|
690
|
+
)
|
|
691
|
+
)}
|
|
692
|
+
</AiPartGroup>
|
|
693
|
+
</div>
|
|
694
|
+
</div>
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
|
|
301
698
|
---
|
|
302
699
|
|
|
303
700
|
### AiQuestion
|
|
304
701
|
|
|
305
|
-
Agent question card. Renders when the agent uses the `ask_user` built-in tool and needs a response before continuing.
|
|
702
|
+
Agent question card. Renders when the agent uses the `ask_user` built-in tool and needs a response before continuing. Maps to harness event: `ask_question`.
|
|
306
703
|
|
|
307
704
|
**Type:** component
|
|
308
705
|
|
|
@@ -338,6 +735,56 @@ Agent question card. Renders when the agent uses the `ask_user` built-in tool an
|
|
|
338
735
|
|
|
339
736
|
`bg-sf-base`, `bg-sf-brand`, `bg-sf-tint`, `border-sf-brand`, `border-sf-line`, `border-sf-ring`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-inverse`, `text-sf-subtle`, `text-sf-success`
|
|
340
737
|
|
|
738
|
+
**Examples:**
|
|
739
|
+
|
|
740
|
+
```tsx
|
|
741
|
+
<div className="w-full max-w-md">
|
|
742
|
+
<AiQuestion
|
|
743
|
+
questionId="q-demo-1"
|
|
744
|
+
question="How should I handle the failing tests?"
|
|
745
|
+
header="Decision needed"
|
|
746
|
+
status={status}
|
|
747
|
+
answeredWith={answer}
|
|
748
|
+
options={[
|
|
749
|
+
{
|
|
750
|
+
label: "Fix them",
|
|
751
|
+
description: "Update the test expectations to match new behavior",
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
label: "Skip them",
|
|
755
|
+
description: "Mark as skipped for now and create a ticket",
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
label: "Delete them",
|
|
759
|
+
description: "Remove outdated tests entirely",
|
|
760
|
+
},
|
|
761
|
+
]}
|
|
762
|
+
allowCustom
|
|
763
|
+
onAnswer={(_id, ans) => {
|
|
764
|
+
setAnswer(ans);
|
|
765
|
+
setStatus("answered");
|
|
766
|
+
}}
|
|
767
|
+
/>
|
|
768
|
+
</div>
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
```tsx
|
|
772
|
+
<div className="w-full max-w-md">
|
|
773
|
+
<AiQuestion
|
|
774
|
+
questionId="q-demo-2"
|
|
775
|
+
question="What should the commit message be for these changes?"
|
|
776
|
+
status={status}
|
|
777
|
+
answeredWith={answer}
|
|
778
|
+
allowCustom
|
|
779
|
+
onAnswer={(_id, ans) => {
|
|
780
|
+
setAnswer(ans);
|
|
781
|
+
setStatus("answered");
|
|
782
|
+
}}
|
|
783
|
+
/>
|
|
784
|
+
</div>
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
|
|
341
788
|
---
|
|
342
789
|
|
|
343
790
|
### AiReasoning
|
|
@@ -387,11 +834,83 @@ Collapsible reasoning block. Supports three display variants: - `"default"` —
|
|
|
387
834
|
|
|
388
835
|
`bg-sf-tint`, `border-sf-line`, `text-sf-subtle`, `text-sf-success`
|
|
389
836
|
|
|
837
|
+
**Examples:**
|
|
838
|
+
|
|
839
|
+
```tsx
|
|
840
|
+
<AiReasoning
|
|
841
|
+
part={{ text: SAMPLE_REASONING }}
|
|
842
|
+
isStreaming={false}
|
|
843
|
+
duration={3}
|
|
844
|
+
defaultExpanded
|
|
845
|
+
/>
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
```tsx
|
|
849
|
+
<AiReasoning
|
|
850
|
+
part={{ text: "Analysing context and forming a response..." }}
|
|
851
|
+
isStreaming
|
|
852
|
+
/>
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
```tsx
|
|
856
|
+
<AiReasoning
|
|
857
|
+
variant="inline"
|
|
858
|
+
part={{ text: SAMPLE_REASONING }}
|
|
859
|
+
isStreaming={false}
|
|
860
|
+
/>
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
```tsx
|
|
864
|
+
<div className="flex flex-col gap-3">
|
|
865
|
+
<div className="flex items-center justify-between gap-3">
|
|
866
|
+
<Text variant="secondary" size="sm">
|
|
867
|
+
Reasoning row evaporates 800ms after streaming ends.
|
|
868
|
+
</Text>
|
|
869
|
+
<Button
|
|
870
|
+
onClick={() => setRunId((n) => n + 1)}
|
|
871
|
+
size="sm"
|
|
872
|
+
variant="ghost"
|
|
873
|
+
>
|
|
874
|
+
Think again
|
|
875
|
+
</Button>
|
|
876
|
+
</div>
|
|
877
|
+
<div
|
|
878
|
+
className={
|
|
879
|
+
"min-h-[3.5rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3"
|
|
880
|
+
}
|
|
881
|
+
>
|
|
882
|
+
<AiReasoning
|
|
883
|
+
// `key` ensures each replay re-mounts to reset the dismiss state.
|
|
884
|
+
key={runId}
|
|
885
|
+
variant="ephemeral"
|
|
886
|
+
part={{
|
|
887
|
+
text: "**Reviewing diff** — checking for breaking changes in the migration.",
|
|
888
|
+
}}
|
|
889
|
+
isStreaming={isStreaming}
|
|
890
|
+
/>
|
|
891
|
+
</div>
|
|
892
|
+
</div>
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
```tsx
|
|
896
|
+
<AiReasoningGroup
|
|
897
|
+
parts={[
|
|
898
|
+
{ text: "**Step 1** — Understood the user intent and context." },
|
|
899
|
+
{ text: "**Step 2** — Reviewed relevant data and constraints." },
|
|
900
|
+
{ text: "**Step 3** — Formulated the final response structure." },
|
|
901
|
+
]}
|
|
902
|
+
isStreaming={false}
|
|
903
|
+
totalDuration={7}
|
|
904
|
+
defaultExpanded
|
|
905
|
+
/>
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
|
|
390
909
|
---
|
|
391
910
|
|
|
392
911
|
### AiResponse
|
|
393
912
|
|
|
394
|
-
Renders AI-generated markdown using Streamdown. Supports streaming animation, syntax-highlighted code, tables, and more.
|
|
913
|
+
Renders AI-generated markdown using Streamdown. Supports streaming animation, syntax-highlighted code, tables, and more. Pass `isAnimating={true}` while streaming and `false` once complete to get character-by-character reveal animation.
|
|
395
914
|
|
|
396
915
|
**Type:** component
|
|
397
916
|
|
|
@@ -410,6 +929,17 @@ Renders AI-generated markdown using Streamdown. Supports streaming animation, sy
|
|
|
410
929
|
|
|
411
930
|
`text-sf-default`
|
|
412
931
|
|
|
932
|
+
**Examples:**
|
|
933
|
+
|
|
934
|
+
```tsx
|
|
935
|
+
<AiResponse>{MARKDOWN_LIKE}</AiResponse>
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
```tsx
|
|
939
|
+
<AiResponse isAnimating={isAnimating}>{text}</AiResponse>
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
|
|
413
943
|
---
|
|
414
944
|
|
|
415
945
|
### AiShimmer
|
|
@@ -435,6 +965,27 @@ AiShimmer component
|
|
|
435
965
|
- `spread`: number
|
|
436
966
|
Shimmer width multiplier relative to text length.
|
|
437
967
|
|
|
968
|
+
**Examples:**
|
|
969
|
+
|
|
970
|
+
```tsx
|
|
971
|
+
<AiShimmer>Thinking...</AiShimmer>
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
```tsx
|
|
975
|
+
<p className="text-sf-default text-sm">
|
|
976
|
+
The AI is{" "}
|
|
977
|
+
<AiShimmer as="span" duration={1.5}>
|
|
978
|
+
generating a response
|
|
979
|
+
</AiShimmer>
|
|
980
|
+
.
|
|
981
|
+
</p>
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
```tsx
|
|
985
|
+
<AiShimmer duration={4}>Analysing your request...</AiShimmer>
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
|
|
438
989
|
---
|
|
439
990
|
|
|
440
991
|
### AiStatusBadge
|
|
@@ -470,6 +1021,50 @@ Compact pill-shaped badge showing an icon, label, and a status indicator. Used b
|
|
|
470
1021
|
|
|
471
1022
|
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
|
|
472
1023
|
|
|
1024
|
+
**Examples:**
|
|
1025
|
+
|
|
1026
|
+
```tsx
|
|
1027
|
+
<AiStatusBadge
|
|
1028
|
+
icon={MagnifyingGlassIcon}
|
|
1029
|
+
label="web_search"
|
|
1030
|
+
status="idle"
|
|
1031
|
+
/>
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
```tsx
|
|
1035
|
+
<div className="flex flex-wrap gap-2">
|
|
1036
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="idle" />
|
|
1037
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="running" />
|
|
1038
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="success" />
|
|
1039
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="error" />
|
|
1040
|
+
</div>
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
```tsx
|
|
1044
|
+
<div className="flex flex-wrap gap-2">
|
|
1045
|
+
<AiStatusBadge
|
|
1046
|
+
icon={DatabaseIcon}
|
|
1047
|
+
label="query_db"
|
|
1048
|
+
info="3/5"
|
|
1049
|
+
status="running"
|
|
1050
|
+
/>
|
|
1051
|
+
<AiStatusBadge
|
|
1052
|
+
icon={BrainIcon}
|
|
1053
|
+
label="analyse"
|
|
1054
|
+
info="done"
|
|
1055
|
+
status="success"
|
|
1056
|
+
/>
|
|
1057
|
+
</div>
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
```tsx
|
|
1061
|
+
<div className="flex flex-wrap gap-2">
|
|
1062
|
+
<AiStatusBadge label="processing" status="running" />
|
|
1063
|
+
<AiStatusBadge label="complete" status="success" />
|
|
1064
|
+
</div>
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
|
|
473
1068
|
---
|
|
474
1069
|
|
|
475
1070
|
### AiStreamingText
|
|
@@ -489,11 +1084,23 @@ AiStreamingText component
|
|
|
489
1084
|
- `children`: ReactNode
|
|
490
1085
|
Child elements
|
|
491
1086
|
|
|
1087
|
+
**Examples:**
|
|
1088
|
+
|
|
1089
|
+
```tsx
|
|
1090
|
+
<p className="max-w-sm text-sf-default text-sm">
|
|
1091
|
+
{displayed}
|
|
1092
|
+
{streaming && (
|
|
1093
|
+
<span className="ml-0.5 inline-block h-4 w-0.5 animate-pulse bg-sf-brand" />
|
|
1094
|
+
)}
|
|
1095
|
+
</p>
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
|
|
492
1099
|
---
|
|
493
1100
|
|
|
494
1101
|
### AiSubagent
|
|
495
1102
|
|
|
496
|
-
Collapsible wrapper for nested subagent activity. Shows the subagent name, status, model, and duration in a header, with all subagent output (text, tool calls, etc.) in a collapsible body.
|
|
1103
|
+
Collapsible wrapper for nested subagent activity. Shows the subagent name, status, model, and duration in a header, with all subagent output (text, tool calls, etc.) in a collapsible body. Maps to harness events: `subagent_start`, `subagent_text_delta`, `subagent_tool_start`, `subagent_tool_end`, `subagent_end`, `subagent_model_changed`.
|
|
497
1104
|
|
|
498
1105
|
**Type:** component
|
|
499
1106
|
|
|
@@ -529,7 +1136,93 @@ Collapsible wrapper for nested subagent activity. Shows the subagent name, statu
|
|
|
529
1136
|
|
|
530
1137
|
**Colors (sf tokens used):**
|
|
531
1138
|
|
|
532
|
-
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-
|
|
1139
|
+
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
|
|
1140
|
+
|
|
1141
|
+
**Examples:**
|
|
1142
|
+
|
|
1143
|
+
```tsx
|
|
1144
|
+
<div className="w-full max-w-lg">
|
|
1145
|
+
<AiSubagent
|
|
1146
|
+
name="Explore"
|
|
1147
|
+
agentType="explore"
|
|
1148
|
+
status="running"
|
|
1149
|
+
modelId="claude-haiku-3.5"
|
|
1150
|
+
defaultExpanded
|
|
1151
|
+
>
|
|
1152
|
+
<div className="flex flex-col gap-1.5 text-sm text-sf-subtle">
|
|
1153
|
+
<p>Searching codebase for authentication patterns...</p>
|
|
1154
|
+
<div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
|
|
1155
|
+
<span className="text-sf-brand">Glob</span>
|
|
1156
|
+
<span className="text-sf-subtle">src/**/*auth*</span>
|
|
1157
|
+
</div>
|
|
1158
|
+
<div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
|
|
1159
|
+
<span className="text-sf-brand">Read</span>
|
|
1160
|
+
<span className="text-sf-subtle">src/middleware/auth.ts</span>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
</AiSubagent>
|
|
1164
|
+
</div>
|
|
1165
|
+
```
|
|
1166
|
+
|
|
1167
|
+
```tsx
|
|
1168
|
+
<div className="w-full max-w-lg">
|
|
1169
|
+
<AiSubagent
|
|
1170
|
+
name="Execute"
|
|
1171
|
+
agentType="execute"
|
|
1172
|
+
status="completed"
|
|
1173
|
+
modelId="claude-sonnet-4"
|
|
1174
|
+
duration={12400}
|
|
1175
|
+
defaultExpanded={false}
|
|
1176
|
+
>
|
|
1177
|
+
<div className="text-sm text-sf-subtle">
|
|
1178
|
+
<p>Refactored 3 files, added 2 new tests. All tests passing.</p>
|
|
1179
|
+
</div>
|
|
1180
|
+
</AiSubagent>
|
|
1181
|
+
</div>
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
```tsx
|
|
1185
|
+
<div className="w-full max-w-lg">
|
|
1186
|
+
<AiSubagent
|
|
1187
|
+
name="Plan"
|
|
1188
|
+
agentType="plan"
|
|
1189
|
+
status="completed"
|
|
1190
|
+
modelId="claude-sonnet-4"
|
|
1191
|
+
duration={28000}
|
|
1192
|
+
defaultExpanded
|
|
1193
|
+
>
|
|
1194
|
+
<div className="flex flex-col gap-2">
|
|
1195
|
+
<p className="text-sm text-sf-subtle">
|
|
1196
|
+
Breaking down the migration into subtasks...
|
|
1197
|
+
</p>
|
|
1198
|
+
<AiSubagent
|
|
1199
|
+
name="Explore"
|
|
1200
|
+
agentType="explore"
|
|
1201
|
+
status="completed"
|
|
1202
|
+
modelId="claude-haiku-3.5"
|
|
1203
|
+
duration={4200}
|
|
1204
|
+
defaultExpanded={false}
|
|
1205
|
+
>
|
|
1206
|
+
<p className="text-sm text-sf-subtle">
|
|
1207
|
+
Found 12 files using deprecated API.
|
|
1208
|
+
</p>
|
|
1209
|
+
</AiSubagent>
|
|
1210
|
+
<AiSubagent
|
|
1211
|
+
name="Execute"
|
|
1212
|
+
agentType="execute"
|
|
1213
|
+
status="running"
|
|
1214
|
+
modelId="claude-sonnet-4"
|
|
1215
|
+
defaultExpanded
|
|
1216
|
+
>
|
|
1217
|
+
<p className="text-sm text-sf-subtle">
|
|
1218
|
+
Updating import paths in batch 1/3...
|
|
1219
|
+
</p>
|
|
1220
|
+
</AiSubagent>
|
|
1221
|
+
</div>
|
|
1222
|
+
</AiSubagent>
|
|
1223
|
+
</div>
|
|
1224
|
+
```
|
|
1225
|
+
|
|
533
1226
|
|
|
534
1227
|
---
|
|
535
1228
|
|
|
@@ -555,7 +1248,7 @@ Horizontally scrollable container for suggestion pills. Position it relative to
|
|
|
555
1248
|
|
|
556
1249
|
### AiTaskList
|
|
557
1250
|
|
|
558
|
-
Task progress list. Renders structured tasks from the harness `task_write` tool. Typically rendered inside the `PromptInputBackLayer` or inline in conversation.
|
|
1251
|
+
Task progress list. Renders structured tasks from the harness `task_write` tool. Typically rendered inside the `PromptInputBackLayer` or inline in conversation. Maps to harness event: `task_updated`.
|
|
559
1252
|
|
|
560
1253
|
**Type:** component
|
|
561
1254
|
|
|
@@ -582,11 +1275,20 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
|
|
|
582
1275
|
|
|
583
1276
|
`bg-sf-brand`, `bg-sf-danger`, `bg-sf-subtle`, `bg-sf-success`, `bg-sf-tint`, `bg-sf-warning`, `text-sf-default`, `text-sf-subtle`
|
|
584
1277
|
|
|
1278
|
+
**Examples:**
|
|
1279
|
+
|
|
1280
|
+
```tsx
|
|
1281
|
+
<div className="w-full max-w-sm">
|
|
1282
|
+
<AiTaskList title="Agent tasks" tasks={tasks} />
|
|
1283
|
+
</div>
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
|
|
585
1287
|
---
|
|
586
1288
|
|
|
587
1289
|
### AiTimeline
|
|
588
1290
|
|
|
589
|
-
`AiTimeline` — horizontal swim-lane timeline for commander-level orchestration.
|
|
1291
|
+
`AiTimeline` — horizontal swim-lane timeline for commander-level orchestration. Displays multiple `AiTimelineLane` children on a shared time axis. Supports live updating (a "now" marker follows the live edge), panning, and zoom via `pixelsPerSecond`.
|
|
590
1292
|
|
|
591
1293
|
**Type:** component
|
|
592
1294
|
|
|
@@ -618,6 +1320,106 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
|
|
|
618
1320
|
|
|
619
1321
|
`bg-sf-base`, `bg-sf-brand`, `bg-sf-danger`, `bg-sf-elevated`, `bg-sf-fill`, `bg-sf-info`, `bg-sf-line`, `bg-sf-recessed`, `bg-sf-warning`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-inverse`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
|
|
620
1322
|
|
|
1323
|
+
**Examples:**
|
|
1324
|
+
|
|
1325
|
+
```tsx
|
|
1326
|
+
<AiTimeline
|
|
1327
|
+
timeOrigin={T0}
|
|
1328
|
+
pixelsPerSecond={25}
|
|
1329
|
+
showNowMarker
|
|
1330
|
+
nowMs={nowMs}
|
|
1331
|
+
>
|
|
1332
|
+
<AiTimelineLane
|
|
1333
|
+
label="Main"
|
|
1334
|
+
agentType="main"
|
|
1335
|
+
status="running"
|
|
1336
|
+
modelId="claude-sonnet-4"
|
|
1337
|
+
blocks={mainBlocks}
|
|
1338
|
+
timeOrigin={T0}
|
|
1339
|
+
nowMs={nowMs}
|
|
1340
|
+
pxPerMs={pxPerMs}
|
|
1341
|
+
/>
|
|
1342
|
+
<AiTimelineLane
|
|
1343
|
+
label="Explore"
|
|
1344
|
+
agentType="explore"
|
|
1345
|
+
status="completed"
|
|
1346
|
+
modelId="claude-haiku-3.5"
|
|
1347
|
+
blocks={exploreBlocks}
|
|
1348
|
+
timeOrigin={T0}
|
|
1349
|
+
nowMs={nowMs}
|
|
1350
|
+
pxPerMs={pxPerMs}
|
|
1351
|
+
/>
|
|
1352
|
+
<AiTimelineLane
|
|
1353
|
+
label="Plan"
|
|
1354
|
+
agentType="plan"
|
|
1355
|
+
status="completed"
|
|
1356
|
+
modelId="claude-sonnet-4"
|
|
1357
|
+
blocks={planBlocks}
|
|
1358
|
+
timeOrigin={T0}
|
|
1359
|
+
nowMs={nowMs}
|
|
1360
|
+
pxPerMs={pxPerMs}
|
|
1361
|
+
/>
|
|
1362
|
+
<AiTimelineLane
|
|
1363
|
+
label="Execute"
|
|
1364
|
+
agentType="execute"
|
|
1365
|
+
status="running"
|
|
1366
|
+
modelId="claude-sonnet-4"
|
|
1367
|
+
blocks={executeBlocks}
|
|
1368
|
+
timeOrigin={T0}
|
|
1369
|
+
nowMs={nowMs}
|
|
1370
|
+
pxPerMs={pxPerMs}
|
|
1371
|
+
/>
|
|
1372
|
+
</AiTimeline>
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
```tsx
|
|
1376
|
+
<AiTimeline
|
|
1377
|
+
timeOrigin={T0}
|
|
1378
|
+
pixelsPerSecond={25}
|
|
1379
|
+
showNowMarker
|
|
1380
|
+
nowMs={nowMs}
|
|
1381
|
+
>
|
|
1382
|
+
<AiTimelineLane
|
|
1383
|
+
label="Explore"
|
|
1384
|
+
agentType="explore"
|
|
1385
|
+
status="completed"
|
|
1386
|
+
blocks={exploreBlocks}
|
|
1387
|
+
timeOrigin={T0}
|
|
1388
|
+
nowMs={nowMs}
|
|
1389
|
+
pxPerMs={pxPerMs}
|
|
1390
|
+
density="compact"
|
|
1391
|
+
/>
|
|
1392
|
+
<AiTimelineLane
|
|
1393
|
+
label="Execute"
|
|
1394
|
+
agentType="execute"
|
|
1395
|
+
status="running"
|
|
1396
|
+
blocks={executeBlocks}
|
|
1397
|
+
timeOrigin={T0}
|
|
1398
|
+
nowMs={nowMs}
|
|
1399
|
+
pxPerMs={pxPerMs}
|
|
1400
|
+
density="compact"
|
|
1401
|
+
/>
|
|
1402
|
+
</AiTimeline>
|
|
1403
|
+
```
|
|
1404
|
+
|
|
1405
|
+
```tsx
|
|
1406
|
+
<AiTimeline
|
|
1407
|
+
timeOrigin={t}
|
|
1408
|
+
pixelsPerSecond={30}
|
|
1409
|
+
showNowMarker={false}
|
|
1410
|
+
nowMs={nowMs}
|
|
1411
|
+
>
|
|
1412
|
+
<AiTimelineLane
|
|
1413
|
+
label="Agent"
|
|
1414
|
+
blocks={allTypeBlocks}
|
|
1415
|
+
timeOrigin={t}
|
|
1416
|
+
nowMs={nowMs}
|
|
1417
|
+
pxPerMs={pxPerMs}
|
|
1418
|
+
/>
|
|
1419
|
+
</AiTimeline>
|
|
1420
|
+
```
|
|
1421
|
+
|
|
1422
|
+
|
|
621
1423
|
---
|
|
622
1424
|
|
|
623
1425
|
### AiToolCall
|
|
@@ -665,7 +1467,7 @@ Renders a single tool call. Supports three display variants: - `"default"` — e
|
|
|
665
1467
|
|
|
666
1468
|
### AiUsageBar
|
|
667
1469
|
|
|
668
|
-
Compact token usage display bar. Shows input/output token counts, total, optional cost, and model identifier.
|
|
1470
|
+
Compact token usage display bar. Shows input/output token counts, total, optional cost, and model identifier. Maps to harness event: `usage_update`.
|
|
669
1471
|
|
|
670
1472
|
**Type:** component
|
|
671
1473
|
|
|
@@ -697,6 +1499,26 @@ Compact token usage display bar. Shows input/output token counts, total, optiona
|
|
|
697
1499
|
|
|
698
1500
|
`text-sf-inactive`, `text-sf-subtle`
|
|
699
1501
|
|
|
1502
|
+
**Examples:**
|
|
1503
|
+
|
|
1504
|
+
```tsx
|
|
1505
|
+
<div className="w-full max-w-md rounded-lg border border-sf-line">
|
|
1506
|
+
<AiUsageBar
|
|
1507
|
+
inputTokens={12480}
|
|
1508
|
+
outputTokens={3256}
|
|
1509
|
+
cost={0.04}
|
|
1510
|
+
modelId="claude-sonnet-4"
|
|
1511
|
+
/>
|
|
1512
|
+
</div>
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
```tsx
|
|
1516
|
+
<div className="w-full max-w-sm rounded-lg border border-sf-line">
|
|
1517
|
+
<AiUsageBar inputTokens={850} outputTokens={124} />
|
|
1518
|
+
</div>
|
|
1519
|
+
```
|
|
1520
|
+
|
|
1521
|
+
|
|
700
1522
|
---
|
|
701
1523
|
|
|
702
1524
|
### Badge
|
|
@@ -741,6 +1563,117 @@ Small status label for categorizing or highlighting content. Supports icons, loa
|
|
|
741
1563
|
|
|
742
1564
|
`bg-sf-brand`, `bg-sf-contrast`, `bg-sf-danger`, `bg-sf-fill`, `bg-sf-info`, `bg-sf-subtle`, `bg-sf-success`, `bg-sf-warning`, `border-sf-brand`, `border-sf-fill`, `text-sf-default`, `text-sf-inverse`, `text-sf-link`, `text-sf-strong`, `text-sf-success`, `text-sf-warning`
|
|
743
1565
|
|
|
1566
|
+
**Examples:**
|
|
1567
|
+
|
|
1568
|
+
```tsx
|
|
1569
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1570
|
+
<Badge variant="primary">Primary</Badge>
|
|
1571
|
+
<Badge variant="secondary">Secondary</Badge>
|
|
1572
|
+
<Badge variant="destructive">Destructive</Badge>
|
|
1573
|
+
<Badge variant="outline">Outline</Badge>
|
|
1574
|
+
<Badge variant="beta">Beta</Badge>
|
|
1575
|
+
<Badge variant="success">Success</Badge>
|
|
1576
|
+
<Badge variant="warning">Warning</Badge>
|
|
1577
|
+
<Badge variant="info">Info</Badge>
|
|
1578
|
+
<Badge variant="ghost">Ghost</Badge>
|
|
1579
|
+
</div>
|
|
1580
|
+
```
|
|
1581
|
+
|
|
1582
|
+
```tsx
|
|
1583
|
+
<Badge variant="primary">Primary</Badge>
|
|
1584
|
+
```
|
|
1585
|
+
|
|
1586
|
+
```tsx
|
|
1587
|
+
<p className="flex items-center gap-2">
|
|
1588
|
+
Workers
|
|
1589
|
+
<Badge variant="beta">Beta</Badge>
|
|
1590
|
+
</p>
|
|
1591
|
+
```
|
|
1592
|
+
|
|
1593
|
+
```tsx
|
|
1594
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1595
|
+
<Badge variant="success" icon={CheckCircleIcon}>
|
|
1596
|
+
Verified
|
|
1597
|
+
</Badge>
|
|
1598
|
+
<Badge variant="secondary" icon={LightningIcon}>
|
|
1599
|
+
Boosted
|
|
1600
|
+
</Badge>
|
|
1601
|
+
<Badge variant="outline" icon={TagIcon} iconPosition="right">
|
|
1602
|
+
Tagged
|
|
1603
|
+
</Badge>
|
|
1604
|
+
</div>
|
|
1605
|
+
```
|
|
1606
|
+
|
|
1607
|
+
```tsx
|
|
1608
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1609
|
+
{tags.map((tag) => (
|
|
1610
|
+
<Badge
|
|
1611
|
+
key={tag}
|
|
1612
|
+
variant="secondary"
|
|
1613
|
+
onDismiss={() => setTags((t) => t.filter((v) => v !== tag))}
|
|
1614
|
+
>
|
|
1615
|
+
{tag}
|
|
1616
|
+
</Badge>
|
|
1617
|
+
))}
|
|
1618
|
+
{tags.length === 0 && (
|
|
1619
|
+
<span className="text-sm text-sf-subtle">All tags removed</span>
|
|
1620
|
+
)}
|
|
1621
|
+
</div>
|
|
1622
|
+
```
|
|
1623
|
+
|
|
1624
|
+
```tsx
|
|
1625
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1626
|
+
<Badge variant="secondary" loading>
|
|
1627
|
+
Syncing
|
|
1628
|
+
</Badge>
|
|
1629
|
+
<Badge variant="info" loading>
|
|
1630
|
+
Deploying
|
|
1631
|
+
</Badge>
|
|
1632
|
+
</div>
|
|
1633
|
+
```
|
|
1634
|
+
|
|
1635
|
+
```tsx
|
|
1636
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1637
|
+
<Badge variant="outline" dot="green">
|
|
1638
|
+
Online
|
|
1639
|
+
</Badge>
|
|
1640
|
+
<Badge variant="outline" dot="red">
|
|
1641
|
+
Offline
|
|
1642
|
+
</Badge>
|
|
1643
|
+
<Badge variant="outline" dot="yellow">
|
|
1644
|
+
Degraded
|
|
1645
|
+
</Badge>
|
|
1646
|
+
<Badge variant="outline" dot="blue">
|
|
1647
|
+
Deploying
|
|
1648
|
+
</Badge>
|
|
1649
|
+
</div>
|
|
1650
|
+
```
|
|
1651
|
+
|
|
1652
|
+
```tsx
|
|
1653
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1654
|
+
<Badge variant="secondary" onClick={handleBadgeClick}>
|
|
1655
|
+
Clickable
|
|
1656
|
+
</Badge>
|
|
1657
|
+
<Badge variant="info" href="https://example.com">
|
|
1658
|
+
Link badge
|
|
1659
|
+
</Badge>
|
|
1660
|
+
</div>
|
|
1661
|
+
```
|
|
1662
|
+
|
|
1663
|
+
```tsx
|
|
1664
|
+
<TooltipProvider>
|
|
1665
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1666
|
+
<Badge variant="success" tooltip="Deployed 2 hours ago" dot="green">
|
|
1667
|
+
Production
|
|
1668
|
+
</Badge>
|
|
1669
|
+
<Badge variant="outline" tooltip="3 of 5 tasks complete">
|
|
1670
|
+
3/5
|
|
1671
|
+
</Badge>
|
|
1672
|
+
</div>
|
|
1673
|
+
</TooltipProvider>
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1676
|
+
|
|
744
1677
|
---
|
|
745
1678
|
|
|
746
1679
|
### Banner
|
|
@@ -771,6 +1704,39 @@ Full-width message bar for informational, warning, or error notices.
|
|
|
771
1704
|
|
|
772
1705
|
`bg-sf-danger`, `bg-sf-danger-tint`, `bg-sf-info`, `bg-sf-info-tint`, `bg-sf-warning`, `bg-sf-warning-tint`, `border-sf-danger`, `border-sf-info`, `border-sf-warning`, `text-sf-danger`, `text-sf-link`, `text-sf-warning`
|
|
773
1706
|
|
|
1707
|
+
**Examples:**
|
|
1708
|
+
|
|
1709
|
+
```tsx
|
|
1710
|
+
<div className="space-y-3">
|
|
1711
|
+
<Banner>This is an informational banner.</Banner>
|
|
1712
|
+
<Banner variant="alert">This is an alert banner.</Banner>
|
|
1713
|
+
<Banner variant="error">This is an error banner.</Banner>
|
|
1714
|
+
</div>
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
```tsx
|
|
1718
|
+
<Banner>This is an informational banner.</Banner>
|
|
1719
|
+
```
|
|
1720
|
+
|
|
1721
|
+
```tsx
|
|
1722
|
+
<Banner variant="alert">Your session will expire soon.</Banner>
|
|
1723
|
+
```
|
|
1724
|
+
|
|
1725
|
+
```tsx
|
|
1726
|
+
<Banner icon={<WarningCircleIcon />} variant="alert">
|
|
1727
|
+
Review your billing information.
|
|
1728
|
+
</Banner>
|
|
1729
|
+
```
|
|
1730
|
+
|
|
1731
|
+
```tsx
|
|
1732
|
+
<Banner icon={<InfoIcon />}>
|
|
1733
|
+
<Text DANGEROUS_className="text-inherit">
|
|
1734
|
+
This banner supports <strong>custom content</strong> with Text.
|
|
1735
|
+
</Text>
|
|
1736
|
+
</Banner>
|
|
1737
|
+
```
|
|
1738
|
+
|
|
1739
|
+
|
|
774
1740
|
---
|
|
775
1741
|
|
|
776
1742
|
### Breadcrumbs
|
|
@@ -805,7 +1771,6 @@ This is a compound component. Use these sub-components:
|
|
|
805
1771
|
Link sub-component
|
|
806
1772
|
|
|
807
1773
|
Props:
|
|
808
|
-
|
|
809
1774
|
- `href`: string (required)
|
|
810
1775
|
- `icon`: React.ReactNode
|
|
811
1776
|
|
|
@@ -814,7 +1779,6 @@ Props:
|
|
|
814
1779
|
Current sub-component
|
|
815
1780
|
|
|
816
1781
|
Props:
|
|
817
|
-
|
|
818
1782
|
- `loading`: boolean
|
|
819
1783
|
- `icon`: React.ReactNode
|
|
820
1784
|
|
|
@@ -827,9 +1791,51 @@ Separator sub-component
|
|
|
827
1791
|
Clipboard sub-component
|
|
828
1792
|
|
|
829
1793
|
Props:
|
|
830
|
-
|
|
831
1794
|
- `text`: string (required)
|
|
832
1795
|
|
|
1796
|
+
|
|
1797
|
+
**Examples:**
|
|
1798
|
+
|
|
1799
|
+
```tsx
|
|
1800
|
+
<Breadcrumbs>
|
|
1801
|
+
<Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
|
|
1802
|
+
<Breadcrumbs.Separator />
|
|
1803
|
+
<Breadcrumbs.Link href="#">Docs</Breadcrumbs.Link>
|
|
1804
|
+
<Breadcrumbs.Separator />
|
|
1805
|
+
<Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
|
|
1806
|
+
</Breadcrumbs>
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
```tsx
|
|
1810
|
+
<Breadcrumbs>
|
|
1811
|
+
<Breadcrumbs.Link href="#" icon={<HouseIcon size={16} />}>
|
|
1812
|
+
Home
|
|
1813
|
+
</Breadcrumbs.Link>
|
|
1814
|
+
<Breadcrumbs.Separator />
|
|
1815
|
+
<Breadcrumbs.Link href="#">Projects</Breadcrumbs.Link>
|
|
1816
|
+
<Breadcrumbs.Separator />
|
|
1817
|
+
<Breadcrumbs.Current>Current Project</Breadcrumbs.Current>
|
|
1818
|
+
</Breadcrumbs>
|
|
1819
|
+
```
|
|
1820
|
+
|
|
1821
|
+
```tsx
|
|
1822
|
+
<Breadcrumbs>
|
|
1823
|
+
<Breadcrumbs.Current icon={<HouseIcon size={16} />}>
|
|
1824
|
+
Worker Analytics
|
|
1825
|
+
</Breadcrumbs.Current>
|
|
1826
|
+
</Breadcrumbs>
|
|
1827
|
+
```
|
|
1828
|
+
|
|
1829
|
+
```tsx
|
|
1830
|
+
<Breadcrumbs>
|
|
1831
|
+
<Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
|
|
1832
|
+
<Breadcrumbs.Separator />
|
|
1833
|
+
<Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
|
|
1834
|
+
<Breadcrumbs.Clipboard text="#" />
|
|
1835
|
+
</Breadcrumbs>
|
|
1836
|
+
```
|
|
1837
|
+
|
|
1838
|
+
|
|
833
1839
|
---
|
|
834
1840
|
|
|
835
1841
|
### Button
|
|
@@ -878,7 +1884,6 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
|
|
|
878
1884
|
- `not-disabled`: `not-disabled:hover:border-secondary! not-disabled:hover:bg-sf-control`
|
|
879
1885
|
- `disabled`: `disabled:bg-sf-control/50 disabled:!text-sf-danger/70`
|
|
880
1886
|
- `data-state`: `data-[state=open]:bg-sf-control`
|
|
881
|
-
|
|
882
1887
|
- `children`: ReactNode
|
|
883
1888
|
- `className`: string
|
|
884
1889
|
- `icon`: ReactNode
|
|
@@ -897,6 +1902,65 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
|
|
|
897
1902
|
|
|
898
1903
|
`bg-sf-base`, `bg-sf-brand`, `bg-sf-brand-hover`, `bg-sf-control`, `bg-sf-danger`, `bg-sf-tint`, `ring-sf-line`, `ring-sf-ring`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`
|
|
899
1904
|
|
|
1905
|
+
**Examples:**
|
|
1906
|
+
|
|
1907
|
+
```tsx
|
|
1908
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1909
|
+
<Button variant="secondary">Button</Button>
|
|
1910
|
+
<Button
|
|
1911
|
+
variant="secondary"
|
|
1912
|
+
shape="square"
|
|
1913
|
+
icon={PlusIcon}
|
|
1914
|
+
aria-label="Add"
|
|
1915
|
+
/>
|
|
1916
|
+
</div>
|
|
1917
|
+
```
|
|
1918
|
+
|
|
1919
|
+
```tsx
|
|
1920
|
+
<Button variant="primary">Primary</Button>
|
|
1921
|
+
```
|
|
1922
|
+
|
|
1923
|
+
```tsx
|
|
1924
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
1925
|
+
<Button size="xs" variant="secondary">
|
|
1926
|
+
Extra Small
|
|
1927
|
+
</Button>
|
|
1928
|
+
<Button size="sm" variant="secondary">
|
|
1929
|
+
Small
|
|
1930
|
+
</Button>
|
|
1931
|
+
<Button size="base" variant="secondary">
|
|
1932
|
+
Base
|
|
1933
|
+
</Button>
|
|
1934
|
+
<Button size="lg" variant="secondary">
|
|
1935
|
+
Large
|
|
1936
|
+
</Button>
|
|
1937
|
+
</div>
|
|
1938
|
+
```
|
|
1939
|
+
|
|
1940
|
+
```tsx
|
|
1941
|
+
<Button variant="secondary" icon={PlusIcon}>
|
|
1942
|
+
Create Worker
|
|
1943
|
+
</Button>
|
|
1944
|
+
```
|
|
1945
|
+
|
|
1946
|
+
```tsx
|
|
1947
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
1948
|
+
<Button
|
|
1949
|
+
variant="secondary"
|
|
1950
|
+
shape="square"
|
|
1951
|
+
icon={PlusIcon}
|
|
1952
|
+
aria-label="Add item"
|
|
1953
|
+
/>
|
|
1954
|
+
<Button
|
|
1955
|
+
variant="secondary"
|
|
1956
|
+
shape="circle"
|
|
1957
|
+
icon={PlusIcon}
|
|
1958
|
+
aria-label="Add item"
|
|
1959
|
+
/>
|
|
1960
|
+
</div>
|
|
1961
|
+
```
|
|
1962
|
+
|
|
1963
|
+
|
|
900
1964
|
---
|
|
901
1965
|
|
|
902
1966
|
### Checkbox
|
|
@@ -919,7 +1983,6 @@ Checkbox component
|
|
|
919
1983
|
- `"default"`:
|
|
920
1984
|
- `focus`: `[&:focus-within>span]:ring-sf-ring`
|
|
921
1985
|
- `hover`: `[&:hover>span]:ring-sf-ring`
|
|
922
|
-
|
|
923
1986
|
- `label`: ReactNode
|
|
924
1987
|
Label content for the checkbox (enables built-in Field wrapper) - can be a string or any React node
|
|
925
1988
|
- `labelTooltip`: ReactNode
|
|
@@ -974,7 +2037,6 @@ Item sub-component
|
|
|
974
2037
|
Group sub-component
|
|
975
2038
|
|
|
976
2039
|
Props:
|
|
977
|
-
|
|
978
2040
|
- `legend`: string (required)
|
|
979
2041
|
- `children`: ReactNode (required)
|
|
980
2042
|
- `error`: string
|
|
@@ -985,11 +2047,73 @@ Props:
|
|
|
985
2047
|
- `controlFirst`: boolean
|
|
986
2048
|
- `className`: string
|
|
987
2049
|
|
|
988
|
-
---
|
|
989
|
-
|
|
990
|
-
### ClipboardText
|
|
991
2050
|
|
|
992
|
-
|
|
2051
|
+
**Examples:**
|
|
2052
|
+
|
|
2053
|
+
```tsx
|
|
2054
|
+
<Checkbox
|
|
2055
|
+
label="Accept terms and conditions"
|
|
2056
|
+
checked={checked}
|
|
2057
|
+
onCheckedChange={setChecked}
|
|
2058
|
+
/>
|
|
2059
|
+
```
|
|
2060
|
+
|
|
2061
|
+
```tsx
|
|
2062
|
+
<Checkbox
|
|
2063
|
+
label="Select all"
|
|
2064
|
+
indeterminate={indeterminate}
|
|
2065
|
+
onCheckedChange={setIndeterminate}
|
|
2066
|
+
/>
|
|
2067
|
+
```
|
|
2068
|
+
|
|
2069
|
+
```tsx
|
|
2070
|
+
<Checkbox
|
|
2071
|
+
label="Remember me"
|
|
2072
|
+
controlFirst={false}
|
|
2073
|
+
checked={checked}
|
|
2074
|
+
onCheckedChange={setChecked}
|
|
2075
|
+
/>
|
|
2076
|
+
```
|
|
2077
|
+
|
|
2078
|
+
```tsx
|
|
2079
|
+
<Checkbox label="Disabled option" disabled />
|
|
2080
|
+
```
|
|
2081
|
+
|
|
2082
|
+
```tsx
|
|
2083
|
+
<Checkbox label="Invalid option" variant="error" />
|
|
2084
|
+
```
|
|
2085
|
+
|
|
2086
|
+
```tsx
|
|
2087
|
+
<Checkbox.Group
|
|
2088
|
+
legend="Email preferences"
|
|
2089
|
+
description="Choose how you'd like to receive updates"
|
|
2090
|
+
value={preferences}
|
|
2091
|
+
onValueChange={setPreferences}
|
|
2092
|
+
>
|
|
2093
|
+
<Checkbox.Item value="email" label="Email notifications" />
|
|
2094
|
+
<Checkbox.Item value="sms" label="SMS notifications" />
|
|
2095
|
+
<Checkbox.Item value="push" label="Push notifications" />
|
|
2096
|
+
</Checkbox.Group>
|
|
2097
|
+
```
|
|
2098
|
+
|
|
2099
|
+
```tsx
|
|
2100
|
+
<Checkbox.Group
|
|
2101
|
+
legend="Required preferences"
|
|
2102
|
+
error="Please select at least one notification method"
|
|
2103
|
+
value={[]}
|
|
2104
|
+
onValueChange={() => {}}
|
|
2105
|
+
>
|
|
2106
|
+
<Checkbox.Item value="email" label="Email" variant="error" />
|
|
2107
|
+
<Checkbox.Item value="sms" label="SMS" variant="error" />
|
|
2108
|
+
</Checkbox.Group>
|
|
2109
|
+
```
|
|
2110
|
+
|
|
2111
|
+
|
|
2112
|
+
---
|
|
2113
|
+
|
|
2114
|
+
### ClipboardText
|
|
2115
|
+
|
|
2116
|
+
Read-only text field with a one-click copy-to-clipboard button.
|
|
993
2117
|
|
|
994
2118
|
**Type:** component
|
|
995
2119
|
|
|
@@ -1062,6 +2186,20 @@ Read-only text field with a one-click copy-to-clipboard button.
|
|
|
1062
2186
|
- borderRadius: 8
|
|
1063
2187
|
- fontSize: 14
|
|
1064
2188
|
|
|
2189
|
+
**Examples:**
|
|
2190
|
+
|
|
2191
|
+
```tsx
|
|
2192
|
+
<ClipboardText text="0c239dd2" />
|
|
2193
|
+
```
|
|
2194
|
+
|
|
2195
|
+
```tsx
|
|
2196
|
+
<ClipboardText
|
|
2197
|
+
text="npx sf add button"
|
|
2198
|
+
tooltip={{ copiedText: "Copied!", side: "top", text: "Copy" }}
|
|
2199
|
+
/>
|
|
2200
|
+
```
|
|
2201
|
+
|
|
2202
|
+
|
|
1065
2203
|
---
|
|
1066
2204
|
|
|
1067
2205
|
### Code
|
|
@@ -1095,6 +2233,7 @@ Code component
|
|
|
1095
2233
|
|
|
1096
2234
|
**Styling:**
|
|
1097
2235
|
|
|
2236
|
+
|
|
1098
2237
|
**Sub-Components:**
|
|
1099
2238
|
|
|
1100
2239
|
This is a compound component. Use these sub-components:
|
|
@@ -1104,15 +2243,36 @@ This is a compound component. Use these sub-components:
|
|
|
1104
2243
|
Block sub-component
|
|
1105
2244
|
|
|
1106
2245
|
Props:
|
|
1107
|
-
|
|
1108
2246
|
- `code`: string (required)
|
|
1109
2247
|
- `lang`: CodeLang
|
|
1110
2248
|
|
|
2249
|
+
|
|
2250
|
+
**Examples:**
|
|
2251
|
+
|
|
2252
|
+
```tsx
|
|
2253
|
+
<CodeBlock
|
|
2254
|
+
lang="tsx"
|
|
2255
|
+
code={`const greeting = "Hello, World!";
|
|
2256
|
+
console.log(greeting);`}
|
|
2257
|
+
/>
|
|
2258
|
+
```
|
|
2259
|
+
|
|
2260
|
+
```tsx
|
|
2261
|
+
<Code
|
|
2262
|
+
lang="bash"
|
|
2263
|
+
code="export API_KEY={{apiKey}}"
|
|
2264
|
+
values={{
|
|
2265
|
+
apiKey: { highlight: true, value: "sk_live_123" },
|
|
2266
|
+
}}
|
|
2267
|
+
/>
|
|
2268
|
+
```
|
|
2269
|
+
|
|
2270
|
+
|
|
1111
2271
|
---
|
|
1112
2272
|
|
|
1113
2273
|
### Collapsible
|
|
1114
2274
|
|
|
1115
|
-
Collapsible component for showing/hiding content.
|
|
2275
|
+
Collapsible component for showing/hiding content. Features: - Animated chevron indicator (rotates 180° when open) - Accessible with aria-expanded and aria-controls - Content panel with left border accent
|
|
1116
2276
|
|
|
1117
2277
|
**Type:** component
|
|
1118
2278
|
|
|
@@ -1136,11 +2296,44 @@ Collapsible component for showing/hiding content. Features: - Animated chevron i
|
|
|
1136
2296
|
|
|
1137
2297
|
`border-sf-fill`, `text-sf-link`
|
|
1138
2298
|
|
|
2299
|
+
**Examples:**
|
|
2300
|
+
|
|
2301
|
+
```tsx
|
|
2302
|
+
<div className="w-full">
|
|
2303
|
+
<Collapsible label="What is SF?" open={isOpen} onOpenChange={setIsOpen}>
|
|
2304
|
+
A minimal, composable component library for building modern interfaces.
|
|
2305
|
+
</Collapsible>
|
|
2306
|
+
</div>
|
|
2307
|
+
```
|
|
2308
|
+
|
|
2309
|
+
```tsx
|
|
2310
|
+
<div className="w-full space-y-2">
|
|
2311
|
+
<Collapsible label="What is SF?" open={open1} onOpenChange={setOpen1}>
|
|
2312
|
+
A minimal, composable component library for building modern interfaces.
|
|
2313
|
+
</Collapsible>
|
|
2314
|
+
<Collapsible
|
|
2315
|
+
label="How do I use it?"
|
|
2316
|
+
open={open2}
|
|
2317
|
+
onOpenChange={setOpen2}
|
|
2318
|
+
>
|
|
2319
|
+
Install the components and import them into your project.
|
|
2320
|
+
</Collapsible>
|
|
2321
|
+
<Collapsible
|
|
2322
|
+
label="Is it open source?"
|
|
2323
|
+
open={open3}
|
|
2324
|
+
onOpenChange={setOpen3}
|
|
2325
|
+
>
|
|
2326
|
+
Check the repository for license information.
|
|
2327
|
+
</Collapsible>
|
|
2328
|
+
</div>
|
|
2329
|
+
```
|
|
2330
|
+
|
|
2331
|
+
|
|
1139
2332
|
---
|
|
1140
2333
|
|
|
1141
2334
|
### Combobox
|
|
1142
2335
|
|
|
1143
|
-
Combobox — autocomplete input with filterable dropdown list.
|
|
2336
|
+
Combobox — autocomplete input with filterable dropdown list. Compound component: `Combobox` (Root), `.TriggerInput`, `.TriggerValue`, `.TriggerMultipleWithInput`, `.Content`, `.Item`, `.Chip`, `.Input`, `.Empty`, `.GroupLabel`, `.Group`, `.List`, `.Collection`.
|
|
1144
2337
|
|
|
1145
2338
|
**Type:** component
|
|
1146
2339
|
|
|
@@ -1191,7 +2384,6 @@ This is a compound component. Use these sub-components:
|
|
|
1191
2384
|
Content sub-component
|
|
1192
2385
|
|
|
1193
2386
|
Props:
|
|
1194
|
-
|
|
1195
2387
|
- `className`: string
|
|
1196
2388
|
- `align`: ComboboxBase.Positioner.Props["align"]
|
|
1197
2389
|
- `alignOffset`: ComboboxBase.Positioner.Props["alignOffset"]
|
|
@@ -1243,11 +2435,9 @@ List sub-component
|
|
|
1243
2435
|
Renders filtered list items. Use when you need more control over item rendering.
|
|
1244
2436
|
|
|
1245
2437
|
Props:
|
|
1246
|
-
|
|
1247
2438
|
- `children`: (item: T, index: number) => ReactNode (required) - Function that receives each filtered item and returns a node
|
|
1248
2439
|
|
|
1249
2440
|
Usage:
|
|
1250
|
-
|
|
1251
2441
|
```tsx
|
|
1252
2442
|
<Combobox.Collection>
|
|
1253
2443
|
{(item, index) => (
|
|
@@ -1258,11 +2448,171 @@ Usage:
|
|
|
1258
2448
|
</Combobox.Collection>
|
|
1259
2449
|
```
|
|
1260
2450
|
|
|
2451
|
+
|
|
2452
|
+
**Examples:**
|
|
2453
|
+
|
|
2454
|
+
```tsx
|
|
2455
|
+
<Combobox
|
|
2456
|
+
value={value}
|
|
2457
|
+
onValueChange={(v) => setValue(v as string | null)}
|
|
2458
|
+
items={fruits}
|
|
2459
|
+
>
|
|
2460
|
+
<Combobox.TriggerInput placeholder="Please select" />
|
|
2461
|
+
<Combobox.Content>
|
|
2462
|
+
<Combobox.Empty />
|
|
2463
|
+
<Combobox.List>
|
|
2464
|
+
{(item: string) => (
|
|
2465
|
+
<Combobox.Item key={item} value={item}>
|
|
2466
|
+
{item}
|
|
2467
|
+
</Combobox.Item>
|
|
2468
|
+
)}
|
|
2469
|
+
</Combobox.List>
|
|
2470
|
+
</Combobox.Content>
|
|
2471
|
+
</Combobox>
|
|
2472
|
+
```
|
|
2473
|
+
|
|
2474
|
+
```tsx
|
|
2475
|
+
<Combobox
|
|
2476
|
+
value={value}
|
|
2477
|
+
onValueChange={(v) => setValue(v as Language)}
|
|
2478
|
+
items={languages}
|
|
2479
|
+
>
|
|
2480
|
+
<Combobox.TriggerValue className="w-[200px]" />
|
|
2481
|
+
<Combobox.Content>
|
|
2482
|
+
<Combobox.Input placeholder="Search languages" />
|
|
2483
|
+
<Combobox.Empty />
|
|
2484
|
+
<Combobox.List>
|
|
2485
|
+
{(item: Language) => (
|
|
2486
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2487
|
+
{item.emoji} {item.label}
|
|
2488
|
+
</Combobox.Item>
|
|
2489
|
+
)}
|
|
2490
|
+
</Combobox.List>
|
|
2491
|
+
</Combobox.Content>
|
|
2492
|
+
</Combobox>
|
|
2493
|
+
```
|
|
2494
|
+
|
|
2495
|
+
```tsx
|
|
2496
|
+
<Combobox
|
|
2497
|
+
value={value}
|
|
2498
|
+
onValueChange={(v) => setValue(v as ServerLocation | null)}
|
|
2499
|
+
items={servers}
|
|
2500
|
+
>
|
|
2501
|
+
<Combobox.TriggerInput
|
|
2502
|
+
className="w-[200px]"
|
|
2503
|
+
placeholder="Select server"
|
|
2504
|
+
/>
|
|
2505
|
+
<Combobox.Content>
|
|
2506
|
+
<Combobox.Empty />
|
|
2507
|
+
<Combobox.List>
|
|
2508
|
+
{(group: ServerLocationGroup) => (
|
|
2509
|
+
<Combobox.Group key={group.value} items={group.items}>
|
|
2510
|
+
<Combobox.GroupLabel>{group.value}</Combobox.GroupLabel>
|
|
2511
|
+
<Combobox.Collection>
|
|
2512
|
+
{(item: ServerLocation) => (
|
|
2513
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2514
|
+
{item.label}
|
|
2515
|
+
</Combobox.Item>
|
|
2516
|
+
)}
|
|
2517
|
+
</Combobox.Collection>
|
|
2518
|
+
</Combobox.Group>
|
|
2519
|
+
)}
|
|
2520
|
+
</Combobox.List>
|
|
2521
|
+
</Combobox.Content>
|
|
2522
|
+
</Combobox>
|
|
2523
|
+
```
|
|
2524
|
+
|
|
2525
|
+
```tsx
|
|
2526
|
+
<div className="flex gap-2">
|
|
2527
|
+
<Combobox
|
|
2528
|
+
value={value}
|
|
2529
|
+
onValueChange={setValue}
|
|
2530
|
+
items={bots}
|
|
2531
|
+
isItemEqualToValue={(bot: BotItem, selected: BotItem) =>
|
|
2532
|
+
bot.value === selected.value
|
|
2533
|
+
}
|
|
2534
|
+
multiple
|
|
2535
|
+
>
|
|
2536
|
+
<Combobox.TriggerMultipleWithInput
|
|
2537
|
+
className="w-[400px]"
|
|
2538
|
+
placeholder="Select bots"
|
|
2539
|
+
renderItem={(selected: BotItem) => (
|
|
2540
|
+
<Combobox.Chip key={selected.value}>{selected.label}</Combobox.Chip>
|
|
2541
|
+
)}
|
|
2542
|
+
inputSide="right"
|
|
2543
|
+
/>
|
|
2544
|
+
<Combobox.Content className="max-h-[200px] min-w-auto overflow-y-auto">
|
|
2545
|
+
<Combobox.Empty />
|
|
2546
|
+
<Combobox.List>
|
|
2547
|
+
{(item: BotItem) => (
|
|
2548
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2549
|
+
<div className="flex gap-2">
|
|
2550
|
+
<Text>{item.label}</Text>
|
|
2551
|
+
<Text variant="secondary">{item.author}</Text>
|
|
2552
|
+
</div>
|
|
2553
|
+
</Combobox.Item>
|
|
2554
|
+
)}
|
|
2555
|
+
</Combobox.List>
|
|
2556
|
+
</Combobox.Content>
|
|
2557
|
+
</Combobox>
|
|
2558
|
+
<Button variant="primary">Submit</Button>
|
|
2559
|
+
</div>
|
|
2560
|
+
```
|
|
2561
|
+
|
|
2562
|
+
```tsx
|
|
2563
|
+
<div className="w-80">
|
|
2564
|
+
<Combobox
|
|
2565
|
+
items={databases}
|
|
2566
|
+
value={value}
|
|
2567
|
+
onValueChange={setValue}
|
|
2568
|
+
label="Database"
|
|
2569
|
+
description="Select your preferred database"
|
|
2570
|
+
>
|
|
2571
|
+
<Combobox.TriggerInput placeholder="Select database" />
|
|
2572
|
+
<Combobox.Content>
|
|
2573
|
+
<Combobox.Empty />
|
|
2574
|
+
<Combobox.List>
|
|
2575
|
+
{(item: DatabaseItem) => (
|
|
2576
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2577
|
+
{item.label}
|
|
2578
|
+
</Combobox.Item>
|
|
2579
|
+
)}
|
|
2580
|
+
</Combobox.List>
|
|
2581
|
+
</Combobox.Content>
|
|
2582
|
+
</Combobox>
|
|
2583
|
+
</div>
|
|
2584
|
+
```
|
|
2585
|
+
|
|
2586
|
+
```tsx
|
|
2587
|
+
<div className="w-80">
|
|
2588
|
+
<Combobox
|
|
2589
|
+
items={databases}
|
|
2590
|
+
value={value}
|
|
2591
|
+
onValueChange={setValue}
|
|
2592
|
+
label="Database"
|
|
2593
|
+
error={{ match: true, message: "Please select a database" }}
|
|
2594
|
+
>
|
|
2595
|
+
<Combobox.TriggerInput placeholder="Select database" />
|
|
2596
|
+
<Combobox.Content>
|
|
2597
|
+
<Combobox.Empty />
|
|
2598
|
+
<Combobox.List>
|
|
2599
|
+
{(item: DatabaseItem) => (
|
|
2600
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2601
|
+
{item.label}
|
|
2602
|
+
</Combobox.Item>
|
|
2603
|
+
)}
|
|
2604
|
+
</Combobox.List>
|
|
2605
|
+
</Combobox.Content>
|
|
2606
|
+
</Combobox>
|
|
2607
|
+
</div>
|
|
2608
|
+
```
|
|
2609
|
+
|
|
2610
|
+
|
|
1261
2611
|
---
|
|
1262
2612
|
|
|
1263
2613
|
### CommandPalette
|
|
1264
2614
|
|
|
1265
|
-
CommandPalette — accessible command palette / spotlight search overlay.
|
|
2615
|
+
CommandPalette — accessible command palette / spotlight search overlay. Compound component: `CommandPalette.Root` (or `.Dialog` + `.Panel`), `.Input`, `.List`, `.Results`, `.Items`, `.Group`, `.GroupLabel`, `.Item`, `.ResultItem`, `.HighlightedText`, `.Empty`, `.Loading`, `.Footer`. Built on `@base-ui/react/autocomplete` + `@base-ui/react/dialog`.
|
|
1266
2616
|
|
|
1267
2617
|
**Type:** component
|
|
1268
2618
|
|
|
@@ -1281,6 +2631,221 @@ CommandPalette — accessible command palette / spotlight search overlay. Compou
|
|
|
1281
2631
|
|
|
1282
2632
|
`bg-sf-elevated`, `bg-sf-overlay`, `bg-sf-warning`, `ring-sf-line`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
|
|
1283
2633
|
|
|
2634
|
+
**Examples:**
|
|
2635
|
+
|
|
2636
|
+
```tsx
|
|
2637
|
+
<div className="flex flex-col items-start gap-4">
|
|
2638
|
+
<Button onClick={() => setOpen(true)}>Open Command Palette</Button>
|
|
2639
|
+
{selectedItem && (
|
|
2640
|
+
<p className="text-sm text-sf-subtle">
|
|
2641
|
+
Last selected: <span className="text-sf-default">{selectedItem}</span>
|
|
2642
|
+
</p>
|
|
2643
|
+
)}
|
|
2644
|
+
|
|
2645
|
+
<CommandPalette.Root
|
|
2646
|
+
open={open}
|
|
2647
|
+
onOpenChange={setOpen}
|
|
2648
|
+
items={sampleGroups}
|
|
2649
|
+
value={search}
|
|
2650
|
+
onValueChange={setSearch}
|
|
2651
|
+
itemToStringValue={(group) => group.label}
|
|
2652
|
+
onSelect={(item, { newTab }) => {
|
|
2653
|
+
console.log("Selected:", item.title, newTab ? "(new tab)" : "");
|
|
2654
|
+
handleSelect(item);
|
|
2655
|
+
}}
|
|
2656
|
+
getSelectableItems={getSelectableItems}
|
|
2657
|
+
>
|
|
2658
|
+
<CommandPalette.Input placeholder="Type a command or search..." />
|
|
2659
|
+
<CommandPalette.List>
|
|
2660
|
+
<CommandPalette.Results>
|
|
2661
|
+
{(group: CommandGroup) => (
|
|
2662
|
+
<CommandPalette.Group key={group.id}>
|
|
2663
|
+
<CommandPalette.GroupLabel>
|
|
2664
|
+
{group.label}
|
|
2665
|
+
</CommandPalette.GroupLabel>
|
|
2666
|
+
<CommandPalette.Items>
|
|
2667
|
+
{(item: CommandItem) => (
|
|
2668
|
+
<CommandPalette.Item
|
|
2669
|
+
key={item.id}
|
|
2670
|
+
value={item}
|
|
2671
|
+
onClick={() => handleSelect(item)}
|
|
2672
|
+
>
|
|
2673
|
+
<span className="flex items-center gap-3">
|
|
2674
|
+
{item.icon && (
|
|
2675
|
+
<span className="text-sf-subtle">{item.icon}</span>
|
|
2676
|
+
)}
|
|
2677
|
+
<span>{item.title}</span>
|
|
2678
|
+
</span>
|
|
2679
|
+
</CommandPalette.Item>
|
|
2680
|
+
)}
|
|
2681
|
+
</CommandPalette.Items>
|
|
2682
|
+
</CommandPalette.Group>
|
|
2683
|
+
)}
|
|
2684
|
+
</CommandPalette.Results>
|
|
2685
|
+
<CommandPalette.Empty>No commands found</CommandPalette.Empty>
|
|
2686
|
+
</CommandPalette.List>
|
|
2687
|
+
<CommandPalette.Footer>
|
|
2688
|
+
<span className="flex items-center gap-2">
|
|
2689
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2690
|
+
↑↓
|
|
2691
|
+
</kbd>
|
|
2692
|
+
<span>Navigate</span>
|
|
2693
|
+
</span>
|
|
2694
|
+
<span className="flex items-center gap-2">
|
|
2695
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2696
|
+
↵
|
|
2697
|
+
</kbd>
|
|
2698
|
+
<span>Select</span>
|
|
2699
|
+
</span>
|
|
2700
|
+
</CommandPalette.Footer>
|
|
2701
|
+
</CommandPalette.Root>
|
|
2702
|
+
</div>
|
|
2703
|
+
```
|
|
2704
|
+
|
|
2705
|
+
```tsx
|
|
2706
|
+
<div>
|
|
2707
|
+
<Button onClick={() => setOpen(true)}>Open Simple Palette</Button>
|
|
2708
|
+
|
|
2709
|
+
<CommandPalette.Root
|
|
2710
|
+
open={open}
|
|
2711
|
+
onOpenChange={setOpen}
|
|
2712
|
+
items={simpleItems}
|
|
2713
|
+
value={search}
|
|
2714
|
+
onValueChange={setSearch}
|
|
2715
|
+
itemToStringValue={(item) => item.title}
|
|
2716
|
+
onSelect={(item) => {
|
|
2717
|
+
console.log("Selected:", item.title);
|
|
2718
|
+
setOpen(false);
|
|
2719
|
+
}}
|
|
2720
|
+
getSelectableItems={(items) => items}
|
|
2721
|
+
>
|
|
2722
|
+
<CommandPalette.Input placeholder="Search actions..." />
|
|
2723
|
+
<CommandPalette.List>
|
|
2724
|
+
<CommandPalette.Results>
|
|
2725
|
+
{(item: SimpleItem) => (
|
|
2726
|
+
<CommandPalette.Item
|
|
2727
|
+
key={item.id}
|
|
2728
|
+
value={item}
|
|
2729
|
+
onClick={() => {
|
|
2730
|
+
console.log("Clicked:", item.title);
|
|
2731
|
+
setOpen(false);
|
|
2732
|
+
}}
|
|
2733
|
+
>
|
|
2734
|
+
{item.title}
|
|
2735
|
+
</CommandPalette.Item>
|
|
2736
|
+
)}
|
|
2737
|
+
</CommandPalette.Results>
|
|
2738
|
+
<CommandPalette.Empty>No actions found</CommandPalette.Empty>
|
|
2739
|
+
</CommandPalette.List>
|
|
2740
|
+
</CommandPalette.Root>
|
|
2741
|
+
</div>
|
|
2742
|
+
```
|
|
2743
|
+
|
|
2744
|
+
```tsx
|
|
2745
|
+
<div>
|
|
2746
|
+
<Button onClick={handleOpen}>Open with Loading</Button>
|
|
2747
|
+
|
|
2748
|
+
<CommandPalette.Root
|
|
2749
|
+
open={open}
|
|
2750
|
+
onOpenChange={setOpen}
|
|
2751
|
+
items={loading ? [] : sampleGroups}
|
|
2752
|
+
value={search}
|
|
2753
|
+
onValueChange={setSearch}
|
|
2754
|
+
itemToStringValue={(group) => group.label}
|
|
2755
|
+
getSelectableItems={getSelectableItems}
|
|
2756
|
+
>
|
|
2757
|
+
<CommandPalette.Input placeholder="Search..." />
|
|
2758
|
+
<CommandPalette.List>
|
|
2759
|
+
{loading ? (
|
|
2760
|
+
<CommandPalette.Loading />
|
|
2761
|
+
) : (
|
|
2762
|
+
<>
|
|
2763
|
+
<CommandPalette.Results>
|
|
2764
|
+
{(group: CommandGroup) => (
|
|
2765
|
+
<CommandPalette.Group key={group.id}>
|
|
2766
|
+
<CommandPalette.GroupLabel>
|
|
2767
|
+
{group.label}
|
|
2768
|
+
</CommandPalette.GroupLabel>
|
|
2769
|
+
<CommandPalette.Items>
|
|
2770
|
+
{(item: CommandItem) => (
|
|
2771
|
+
<CommandPalette.Item
|
|
2772
|
+
key={item.id}
|
|
2773
|
+
value={item}
|
|
2774
|
+
onClick={() => setOpen(false)}
|
|
2775
|
+
>
|
|
2776
|
+
<span className="flex items-center gap-3">
|
|
2777
|
+
{item.icon && (
|
|
2778
|
+
<span className="text-sf-subtle">
|
|
2779
|
+
{item.icon}
|
|
2780
|
+
</span>
|
|
2781
|
+
)}
|
|
2782
|
+
<span>{item.title}</span>
|
|
2783
|
+
</span>
|
|
2784
|
+
</CommandPalette.Item>
|
|
2785
|
+
)}
|
|
2786
|
+
</CommandPalette.Items>
|
|
2787
|
+
</CommandPalette.Group>
|
|
2788
|
+
)}
|
|
2789
|
+
</CommandPalette.Results>
|
|
2790
|
+
<CommandPalette.Empty>No results found</CommandPalette.Empty>
|
|
2791
|
+
</>
|
|
2792
|
+
)}
|
|
2793
|
+
</CommandPalette.List>
|
|
2794
|
+
</CommandPalette.Root>
|
|
2795
|
+
</div>
|
|
2796
|
+
```
|
|
2797
|
+
|
|
2798
|
+
```tsx
|
|
2799
|
+
<div>
|
|
2800
|
+
<Button onClick={() => setOpen(true)}>Open with ResultItem</Button>
|
|
2801
|
+
|
|
2802
|
+
<CommandPalette.Root
|
|
2803
|
+
open={open}
|
|
2804
|
+
onOpenChange={setOpen}
|
|
2805
|
+
items={searchResults}
|
|
2806
|
+
value={search}
|
|
2807
|
+
onValueChange={setSearch}
|
|
2808
|
+
itemToStringValue={(item) => item.title}
|
|
2809
|
+
getSelectableItems={(items) => items}
|
|
2810
|
+
>
|
|
2811
|
+
<CommandPalette.Input placeholder="Search documentation..." />
|
|
2812
|
+
<CommandPalette.List>
|
|
2813
|
+
<CommandPalette.Results>
|
|
2814
|
+
{(item: SearchResult) => (
|
|
2815
|
+
<CommandPalette.ResultItem
|
|
2816
|
+
key={item.id}
|
|
2817
|
+
value={item}
|
|
2818
|
+
title={item.title}
|
|
2819
|
+
breadcrumbs={item.breadcrumbs}
|
|
2820
|
+
icon={item.icon}
|
|
2821
|
+
onClick={() => {
|
|
2822
|
+
console.log("Navigate to:", item.title);
|
|
2823
|
+
setOpen(false);
|
|
2824
|
+
}}
|
|
2825
|
+
/>
|
|
2826
|
+
)}
|
|
2827
|
+
</CommandPalette.Results>
|
|
2828
|
+
<CommandPalette.Empty>No pages found</CommandPalette.Empty>
|
|
2829
|
+
</CommandPalette.List>
|
|
2830
|
+
<CommandPalette.Footer>
|
|
2831
|
+
<span className="flex items-center gap-2">
|
|
2832
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2833
|
+
↑↓
|
|
2834
|
+
</kbd>
|
|
2835
|
+
<span>Navigate</span>
|
|
2836
|
+
</span>
|
|
2837
|
+
<span className="flex items-center gap-2">
|
|
2838
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2839
|
+
⌘↵
|
|
2840
|
+
</kbd>
|
|
2841
|
+
<span>Open in new tab</span>
|
|
2842
|
+
</span>
|
|
2843
|
+
</CommandPalette.Footer>
|
|
2844
|
+
</CommandPalette.Root>
|
|
2845
|
+
</div>
|
|
2846
|
+
```
|
|
2847
|
+
|
|
2848
|
+
|
|
1284
2849
|
---
|
|
1285
2850
|
|
|
1286
2851
|
### DataGrid
|
|
@@ -1331,11 +2896,149 @@ ColumnToggle sub-component
|
|
|
1331
2896
|
|
|
1332
2897
|
Empty sub-component
|
|
1333
2898
|
|
|
2899
|
+
|
|
2900
|
+
**Examples:**
|
|
2901
|
+
|
|
2902
|
+
```tsx
|
|
2903
|
+
<LayerCard>
|
|
2904
|
+
<LayerCard.Primary className="p-0">
|
|
2905
|
+
<DataGrid data={sampleUsers} columns={columns} enableSorting>
|
|
2906
|
+
<DataGrid.Content />
|
|
2907
|
+
</DataGrid>
|
|
2908
|
+
</LayerCard.Primary>
|
|
2909
|
+
</LayerCard>
|
|
2910
|
+
```
|
|
2911
|
+
|
|
2912
|
+
```tsx
|
|
2913
|
+
<LayerCard>
|
|
2914
|
+
<LayerCard.Primary className="p-0">
|
|
2915
|
+
<DataGrid
|
|
2916
|
+
data={paginatedData}
|
|
2917
|
+
columns={columns.slice(0, 3)}
|
|
2918
|
+
pageSize={pageSize}
|
|
2919
|
+
pageIndex={pageIndex}
|
|
2920
|
+
onPaginationChange={({ pageIndex: newPage }) => setPageIndex(newPage)}
|
|
2921
|
+
totalCount={totalCount}
|
|
2922
|
+
manualPagination
|
|
2923
|
+
>
|
|
2924
|
+
<DataGrid.Content />
|
|
2925
|
+
<DataGrid.Pagination />
|
|
2926
|
+
</DataGrid>
|
|
2927
|
+
</LayerCard.Primary>
|
|
2928
|
+
</LayerCard>
|
|
2929
|
+
```
|
|
2930
|
+
|
|
2931
|
+
```tsx
|
|
2932
|
+
<LayerCard>
|
|
2933
|
+
<LayerCard.Primary className="p-0">
|
|
2934
|
+
<DataGrid
|
|
2935
|
+
data={sampleUsers.slice(0, 4)}
|
|
2936
|
+
columns={columns}
|
|
2937
|
+
enableRowSelection
|
|
2938
|
+
rowSelection={rowSelection}
|
|
2939
|
+
onRowSelectionChange={setRowSelection}
|
|
2940
|
+
>
|
|
2941
|
+
<DataGrid.Content />
|
|
2942
|
+
</DataGrid>
|
|
2943
|
+
<div className="border-t border-sf-line p-3 text-sm">
|
|
2944
|
+
<p className="text-sf-subtle">
|
|
2945
|
+
Selected: {Object.keys(rowSelection).length} rows
|
|
2946
|
+
</p>
|
|
2947
|
+
</div>
|
|
2948
|
+
</LayerCard.Primary>
|
|
2949
|
+
</LayerCard>
|
|
2950
|
+
```
|
|
2951
|
+
|
|
2952
|
+
```tsx
|
|
2953
|
+
<LayerCard>
|
|
2954
|
+
<LayerCard.Primary className="p-0">
|
|
2955
|
+
<DataGrid
|
|
2956
|
+
data={sampleUsers.slice(0, 4)}
|
|
2957
|
+
columns={columns}
|
|
2958
|
+
columnVisibility={columnVisibility}
|
|
2959
|
+
onColumnVisibilityChange={setColumnVisibility}
|
|
2960
|
+
>
|
|
2961
|
+
<DataGrid.Toolbar className="p-3">
|
|
2962
|
+
<DataGrid.ColumnToggle />
|
|
2963
|
+
</DataGrid.Toolbar>
|
|
2964
|
+
<DataGrid.Content />
|
|
2965
|
+
</DataGrid>
|
|
2966
|
+
</LayerCard.Primary>
|
|
2967
|
+
</LayerCard>
|
|
2968
|
+
```
|
|
2969
|
+
|
|
2970
|
+
```tsx
|
|
2971
|
+
<LayerCard>
|
|
2972
|
+
<LayerCard.Primary className="p-0">
|
|
2973
|
+
<DataGrid data={sampleUsers} columns={columns} enableSorting>
|
|
2974
|
+
<DataGrid.Toolbar className="flex items-center justify-between p-3">
|
|
2975
|
+
<span className="text-sm font-medium">Users</span>
|
|
2976
|
+
<DataGrid.ColumnToggle />
|
|
2977
|
+
</DataGrid.Toolbar>
|
|
2978
|
+
<DataGrid.Content />
|
|
2979
|
+
</DataGrid>
|
|
2980
|
+
</LayerCard.Primary>
|
|
2981
|
+
</LayerCard>
|
|
2982
|
+
```
|
|
2983
|
+
|
|
2984
|
+
```tsx
|
|
2985
|
+
<LayerCard>
|
|
2986
|
+
<LayerCard.Primary className="p-0">
|
|
2987
|
+
<DataGrid
|
|
2988
|
+
data={[]}
|
|
2989
|
+
columns={columns.slice(0, 3)}
|
|
2990
|
+
emptyState={
|
|
2991
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
2992
|
+
<p className="text-sf-strong font-medium">No users found</p>
|
|
2993
|
+
<p className="text-sf-subtle mt-1 text-sm">
|
|
2994
|
+
Try adjusting your filters or add new users
|
|
2995
|
+
</p>
|
|
2996
|
+
</div>
|
|
2997
|
+
}
|
|
2998
|
+
>
|
|
2999
|
+
<DataGrid.Content />
|
|
3000
|
+
</DataGrid>
|
|
3001
|
+
</LayerCard.Primary>
|
|
3002
|
+
</LayerCard>
|
|
3003
|
+
```
|
|
3004
|
+
|
|
3005
|
+
```tsx
|
|
3006
|
+
<LayerCard>
|
|
3007
|
+
<LayerCard.Primary className="p-0">
|
|
3008
|
+
<DataGrid
|
|
3009
|
+
data={[]}
|
|
3010
|
+
columns={columns.slice(0, 3)}
|
|
3011
|
+
loading
|
|
3012
|
+
loadingRows={3}
|
|
3013
|
+
>
|
|
3014
|
+
<DataGrid.Content />
|
|
3015
|
+
</DataGrid>
|
|
3016
|
+
</LayerCard.Primary>
|
|
3017
|
+
</LayerCard>
|
|
3018
|
+
```
|
|
3019
|
+
|
|
3020
|
+
```tsx
|
|
3021
|
+
<LayerCard>
|
|
3022
|
+
<LayerCard.Primary className="p-0">
|
|
3023
|
+
<DataGrid
|
|
3024
|
+
data={sampleUsers}
|
|
3025
|
+
columns={resizableColumns}
|
|
3026
|
+
enableSorting
|
|
3027
|
+
enableColumnResizing
|
|
3028
|
+
columnResizeMode="onEnd"
|
|
3029
|
+
>
|
|
3030
|
+
<DataGrid.Content />
|
|
3031
|
+
</DataGrid>
|
|
3032
|
+
</LayerCard.Primary>
|
|
3033
|
+
</LayerCard>
|
|
3034
|
+
```
|
|
3035
|
+
|
|
3036
|
+
|
|
1334
3037
|
---
|
|
1335
3038
|
|
|
1336
3039
|
### DatePicker
|
|
1337
3040
|
|
|
1338
|
-
DatePicker — a date selection calendar.
|
|
3041
|
+
DatePicker — a date selection calendar. Built on [react-day-picker](https://daypicker.dev) with SignalFlare styling. Supports three selection modes: single, multiple, and range.
|
|
1339
3042
|
|
|
1340
3043
|
**Type:** component
|
|
1341
3044
|
|
|
@@ -1354,11 +3057,167 @@ DatePicker — a date selection calendar. Built on [react-day-picker](https://da
|
|
|
1354
3057
|
|
|
1355
3058
|
`bg-sf-base`
|
|
1356
3059
|
|
|
3060
|
+
**Examples:**
|
|
3061
|
+
|
|
3062
|
+
```tsx
|
|
3063
|
+
<div className="flex flex-col gap-4">
|
|
3064
|
+
<DatePicker
|
|
3065
|
+
mode="single"
|
|
3066
|
+
selected={date}
|
|
3067
|
+
onChange={(d) => {
|
|
3068
|
+
if (d) {
|
|
3069
|
+
setDate(d);
|
|
3070
|
+
}
|
|
3071
|
+
}}
|
|
3072
|
+
/>
|
|
3073
|
+
<p className="text-sm text-sf-subtle">
|
|
3074
|
+
Selected: {date ? date.toLocaleDateString() : "None"}
|
|
3075
|
+
</p>
|
|
3076
|
+
</div>
|
|
3077
|
+
```
|
|
3078
|
+
|
|
3079
|
+
```tsx
|
|
3080
|
+
<div className="flex flex-col gap-4">
|
|
3081
|
+
<DatePicker
|
|
3082
|
+
mode="multiple"
|
|
3083
|
+
selected={dates}
|
|
3084
|
+
onChange={setDates}
|
|
3085
|
+
max={5}
|
|
3086
|
+
/>
|
|
3087
|
+
<p className="text-sm text-sf-subtle">
|
|
3088
|
+
Selected: {dates?.length ?? 0} date(s)
|
|
3089
|
+
</p>
|
|
3090
|
+
</div>
|
|
3091
|
+
```
|
|
3092
|
+
|
|
3093
|
+
```tsx
|
|
3094
|
+
<div className="flex flex-col gap-4">
|
|
3095
|
+
<DatePicker
|
|
3096
|
+
mode="range"
|
|
3097
|
+
selected={range}
|
|
3098
|
+
onChange={setRange}
|
|
3099
|
+
numberOfMonths={2}
|
|
3100
|
+
/>
|
|
3101
|
+
<p className="text-sm text-sf-subtle">
|
|
3102
|
+
Range:{" "}
|
|
3103
|
+
{range?.from
|
|
3104
|
+
? `${range.from.toLocaleDateString()} - ${range.to?.toLocaleDateString() ?? "..."}`
|
|
3105
|
+
: "None"}
|
|
3106
|
+
</p>
|
|
3107
|
+
</div>
|
|
3108
|
+
```
|
|
3109
|
+
|
|
3110
|
+
```tsx
|
|
3111
|
+
<div className="flex flex-col gap-4">
|
|
3112
|
+
<DatePicker
|
|
3113
|
+
mode="range"
|
|
3114
|
+
selected={range}
|
|
3115
|
+
onChange={setRange}
|
|
3116
|
+
min={3}
|
|
3117
|
+
max={7}
|
|
3118
|
+
footer={
|
|
3119
|
+
<span className="text-xs text-sf-subtle">Select 3-7 nights</span>
|
|
3120
|
+
}
|
|
3121
|
+
/>
|
|
3122
|
+
</div>
|
|
3123
|
+
```
|
|
3124
|
+
|
|
3125
|
+
```tsx
|
|
3126
|
+
<Popover>
|
|
3127
|
+
<Popover.Trigger asChild>
|
|
3128
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3129
|
+
{date ? date.toLocaleDateString() : "Pick a date"}
|
|
3130
|
+
</Button>
|
|
3131
|
+
</Popover.Trigger>
|
|
3132
|
+
<Popover.Content className="p-3">
|
|
3133
|
+
<DatePicker mode="single" selected={date} onChange={setDate} />
|
|
3134
|
+
</Popover.Content>
|
|
3135
|
+
</Popover>
|
|
3136
|
+
```
|
|
3137
|
+
|
|
3138
|
+
```tsx
|
|
3139
|
+
<Popover>
|
|
3140
|
+
<Popover.Trigger asChild>
|
|
3141
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3142
|
+
{formatRange()}
|
|
3143
|
+
</Button>
|
|
3144
|
+
</Popover.Trigger>
|
|
3145
|
+
<Popover.Content className="p-3">
|
|
3146
|
+
<DatePicker
|
|
3147
|
+
mode="range"
|
|
3148
|
+
selected={range}
|
|
3149
|
+
onChange={setRange}
|
|
3150
|
+
numberOfMonths={2}
|
|
3151
|
+
/>
|
|
3152
|
+
</Popover.Content>
|
|
3153
|
+
</Popover>
|
|
3154
|
+
```
|
|
3155
|
+
|
|
3156
|
+
```tsx
|
|
3157
|
+
<Popover>
|
|
3158
|
+
<Popover.Trigger asChild>
|
|
3159
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3160
|
+
{formatRange()}
|
|
3161
|
+
</Button>
|
|
3162
|
+
</Popover.Trigger>
|
|
3163
|
+
<Popover.Content className="p-0">
|
|
3164
|
+
<div className="flex">
|
|
3165
|
+
<div className="flex flex-col gap-1 border-r border-sf-line p-2 text-sm">
|
|
3166
|
+
{presets.map((preset) => {
|
|
3167
|
+
const isActive = isPresetActive(preset);
|
|
3168
|
+
return (
|
|
3169
|
+
<button
|
|
3170
|
+
key={preset.label}
|
|
3171
|
+
type="button"
|
|
3172
|
+
onClick={() => handlePresetClick(preset)}
|
|
3173
|
+
className={`rounded-md px-3 py-1.5 text-left whitespace-nowrap ${
|
|
3174
|
+
isActive
|
|
3175
|
+
? "bg-sf-bg-inverse text-sf-text-inverse"
|
|
3176
|
+
: "text-sf-strong hover:bg-sf-control"
|
|
3177
|
+
}`}
|
|
3178
|
+
>
|
|
3179
|
+
{preset.label}
|
|
3180
|
+
</button>
|
|
3181
|
+
);
|
|
3182
|
+
})}
|
|
3183
|
+
</div>
|
|
3184
|
+
<div className="p-3">
|
|
3185
|
+
<DatePicker
|
|
3186
|
+
mode="range"
|
|
3187
|
+
selected={range}
|
|
3188
|
+
onChange={setRange}
|
|
3189
|
+
month={month}
|
|
3190
|
+
onMonthChange={setMonth}
|
|
3191
|
+
numberOfMonths={2}
|
|
3192
|
+
/>
|
|
3193
|
+
</div>
|
|
3194
|
+
</div>
|
|
3195
|
+
</Popover.Content>
|
|
3196
|
+
</Popover>
|
|
3197
|
+
```
|
|
3198
|
+
|
|
3199
|
+
```tsx
|
|
3200
|
+
<DatePicker
|
|
3201
|
+
mode="multiple"
|
|
3202
|
+
selected={dates}
|
|
3203
|
+
onChange={setDates}
|
|
3204
|
+
max={maxDays}
|
|
3205
|
+
disabled={unavailableDates}
|
|
3206
|
+
fixedWeeks
|
|
3207
|
+
footer={
|
|
3208
|
+
<p className="text-xs text-sf-subtle pt-2 w-full">
|
|
3209
|
+
{selectedCount}/{maxDays} days selected. Grayed dates are unavailable.
|
|
3210
|
+
</p>
|
|
3211
|
+
}
|
|
3212
|
+
/>
|
|
3213
|
+
```
|
|
3214
|
+
|
|
3215
|
+
|
|
1357
3216
|
---
|
|
1358
3217
|
|
|
1359
3218
|
### DateRangePicker
|
|
1360
3219
|
|
|
1361
|
-
DateRangePicker — dual-calendar date range selector.
|
|
3220
|
+
DateRangePicker — dual-calendar date range selector. Renders two side-by-side month calendars with click-to-select start/end dates, hover preview of the range, a timezone footer, and a reset button.
|
|
1362
3221
|
|
|
1363
3222
|
**Type:** component
|
|
1364
3223
|
|
|
@@ -1478,11 +3337,235 @@ Description sub-component
|
|
|
1478
3337
|
|
|
1479
3338
|
Close sub-component
|
|
1480
3339
|
|
|
3340
|
+
|
|
3341
|
+
**Examples:**
|
|
3342
|
+
|
|
3343
|
+
```tsx
|
|
3344
|
+
<Dialog.Root>
|
|
3345
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />
|
|
3346
|
+
<Dialog className="p-8">
|
|
3347
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3348
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3349
|
+
Modal Title
|
|
3350
|
+
</Dialog.Title>
|
|
3351
|
+
<Dialog.Close
|
|
3352
|
+
aria-label="Close"
|
|
3353
|
+
render={(props) => (
|
|
3354
|
+
<Button
|
|
3355
|
+
{...props}
|
|
3356
|
+
variant="secondary"
|
|
3357
|
+
shape="square"
|
|
3358
|
+
icon={<XIcon />}
|
|
3359
|
+
aria-label="Close"
|
|
3360
|
+
/>
|
|
3361
|
+
)}
|
|
3362
|
+
/>
|
|
3363
|
+
</div>
|
|
3364
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3365
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
3366
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
3367
|
+
</Dialog.Description>
|
|
3368
|
+
</Dialog>
|
|
3369
|
+
</Dialog.Root>
|
|
3370
|
+
```
|
|
3371
|
+
|
|
3372
|
+
```tsx
|
|
3373
|
+
<Dialog.Root>
|
|
3374
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />
|
|
3375
|
+
<Dialog className="p-8">
|
|
3376
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3377
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3378
|
+
Modal Title
|
|
3379
|
+
</Dialog.Title>
|
|
3380
|
+
<Dialog.Close
|
|
3381
|
+
aria-label="Close"
|
|
3382
|
+
render={(props) => (
|
|
3383
|
+
<Button
|
|
3384
|
+
{...props}
|
|
3385
|
+
variant="secondary"
|
|
3386
|
+
shape="square"
|
|
3387
|
+
icon={<XIcon />}
|
|
3388
|
+
aria-label="Close"
|
|
3389
|
+
/>
|
|
3390
|
+
)}
|
|
3391
|
+
/>
|
|
3392
|
+
</div>
|
|
3393
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3394
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
3395
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
3396
|
+
</Dialog.Description>
|
|
3397
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3398
|
+
<Dialog.Close
|
|
3399
|
+
render={(props) => (
|
|
3400
|
+
<Button variant="secondary" {...props}>
|
|
3401
|
+
Cancel
|
|
3402
|
+
</Button>
|
|
3403
|
+
)}
|
|
3404
|
+
/>
|
|
3405
|
+
<Dialog.Close
|
|
3406
|
+
render={(props) => (
|
|
3407
|
+
<Button variant="destructive" {...props}>
|
|
3408
|
+
Delete
|
|
3409
|
+
</Button>
|
|
3410
|
+
)}
|
|
3411
|
+
/>
|
|
3412
|
+
</div>
|
|
3413
|
+
</Dialog>
|
|
3414
|
+
</Dialog.Root>
|
|
3415
|
+
```
|
|
3416
|
+
|
|
3417
|
+
```tsx
|
|
3418
|
+
<Dialog.Root disablePointerDismissal>
|
|
3419
|
+
<Dialog.Trigger
|
|
3420
|
+
render={(p) => (
|
|
3421
|
+
<Button {...p} variant="destructive">
|
|
3422
|
+
Delete Project
|
|
3423
|
+
</Button>
|
|
3424
|
+
)}
|
|
3425
|
+
/>
|
|
3426
|
+
<Dialog className="p-8">
|
|
3427
|
+
<div className="mb-4 flex items-center gap-3">
|
|
3428
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-sf-danger/20">
|
|
3429
|
+
<WarningIcon size={20} className="text-sf-danger" />
|
|
3430
|
+
</div>
|
|
3431
|
+
<Dialog.Title className="text-xl font-semibold">
|
|
3432
|
+
Delete Project?
|
|
3433
|
+
</Dialog.Title>
|
|
3434
|
+
</div>
|
|
3435
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3436
|
+
This action cannot be undone. This will permanently delete the project
|
|
3437
|
+
and all associated data.
|
|
3438
|
+
</Dialog.Description>
|
|
3439
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3440
|
+
<Dialog.Close
|
|
3441
|
+
render={(props) => (
|
|
3442
|
+
<Button variant="secondary" {...props}>
|
|
3443
|
+
Cancel
|
|
3444
|
+
</Button>
|
|
3445
|
+
)}
|
|
3446
|
+
/>
|
|
3447
|
+
<Dialog.Close
|
|
3448
|
+
render={(props) => (
|
|
3449
|
+
<Button variant="destructive" {...props}>
|
|
3450
|
+
Delete
|
|
3451
|
+
</Button>
|
|
3452
|
+
)}
|
|
3453
|
+
/>
|
|
3454
|
+
</div>
|
|
3455
|
+
</Dialog>
|
|
3456
|
+
</Dialog.Root>
|
|
3457
|
+
```
|
|
3458
|
+
|
|
3459
|
+
```tsx
|
|
3460
|
+
<Dialog.Root>
|
|
3461
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
|
|
3462
|
+
<Dialog className="p-8">
|
|
3463
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3464
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3465
|
+
Create Resource
|
|
3466
|
+
</Dialog.Title>
|
|
3467
|
+
<Dialog.Close
|
|
3468
|
+
aria-label="Close"
|
|
3469
|
+
render={(props) => (
|
|
3470
|
+
<Button
|
|
3471
|
+
{...props}
|
|
3472
|
+
variant="secondary"
|
|
3473
|
+
shape="square"
|
|
3474
|
+
icon={<XIcon />}
|
|
3475
|
+
aria-label="Close"
|
|
3476
|
+
/>
|
|
3477
|
+
)}
|
|
3478
|
+
/>
|
|
3479
|
+
</div>
|
|
3480
|
+
<Dialog.Description className="mb-4 text-sf-subtle">
|
|
3481
|
+
Select a region for your new resource.
|
|
3482
|
+
</Dialog.Description>
|
|
3483
|
+
<Select
|
|
3484
|
+
className="w-full"
|
|
3485
|
+
renderValue={(v) =>
|
|
3486
|
+
regions.find((r) => r.value === v)?.label ?? "Select region..."
|
|
3487
|
+
}
|
|
3488
|
+
>
|
|
3489
|
+
{regions.map((region) => (
|
|
3490
|
+
<Select.Option key={region.value} value={region.value}>
|
|
3491
|
+
{region.label}
|
|
3492
|
+
</Select.Option>
|
|
3493
|
+
))}
|
|
3494
|
+
</Select>
|
|
3495
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3496
|
+
<Dialog.Close
|
|
3497
|
+
render={(props) => (
|
|
3498
|
+
<Button variant="secondary" {...props}>
|
|
3499
|
+
Cancel
|
|
3500
|
+
</Button>
|
|
3501
|
+
)}
|
|
3502
|
+
/>
|
|
3503
|
+
<Button variant="primary">Create</Button>
|
|
3504
|
+
</div>
|
|
3505
|
+
</Dialog>
|
|
3506
|
+
</Dialog.Root>
|
|
3507
|
+
```
|
|
3508
|
+
|
|
3509
|
+
```tsx
|
|
3510
|
+
<Dialog.Root>
|
|
3511
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
|
|
3512
|
+
<Dialog className="p-8">
|
|
3513
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3514
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3515
|
+
Create Resource
|
|
3516
|
+
</Dialog.Title>
|
|
3517
|
+
<Dialog.Close
|
|
3518
|
+
aria-label="Close"
|
|
3519
|
+
render={(props) => (
|
|
3520
|
+
<Button
|
|
3521
|
+
{...props}
|
|
3522
|
+
variant="secondary"
|
|
3523
|
+
shape="square"
|
|
3524
|
+
icon={<XIcon />}
|
|
3525
|
+
aria-label="Close"
|
|
3526
|
+
/>
|
|
3527
|
+
)}
|
|
3528
|
+
/>
|
|
3529
|
+
</div>
|
|
3530
|
+
<Dialog.Description className="mb-4 text-sf-subtle">
|
|
3531
|
+
Search and select a region for your new resource.
|
|
3532
|
+
</Dialog.Description>
|
|
3533
|
+
<Combobox value={value} onValueChange={setValue} items={regions}>
|
|
3534
|
+
<Combobox.TriggerInput
|
|
3535
|
+
className="w-full"
|
|
3536
|
+
placeholder="Search regions..."
|
|
3537
|
+
/>
|
|
3538
|
+
<Combobox.Content>
|
|
3539
|
+
<Combobox.Empty>No regions found</Combobox.Empty>
|
|
3540
|
+
<Combobox.List>
|
|
3541
|
+
{(item: { value: string; label: string }) => (
|
|
3542
|
+
<Combobox.Item key={item.value} value={item}>
|
|
3543
|
+
{item.label}
|
|
3544
|
+
</Combobox.Item>
|
|
3545
|
+
)}
|
|
3546
|
+
</Combobox.List>
|
|
3547
|
+
</Combobox.Content>
|
|
3548
|
+
</Combobox>
|
|
3549
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3550
|
+
<Dialog.Close
|
|
3551
|
+
render={(props) => (
|
|
3552
|
+
<Button variant="secondary" {...props}>
|
|
3553
|
+
Cancel
|
|
3554
|
+
</Button>
|
|
3555
|
+
)}
|
|
3556
|
+
/>
|
|
3557
|
+
<Button variant="primary">Create</Button>
|
|
3558
|
+
</div>
|
|
3559
|
+
</Dialog>
|
|
3560
|
+
</Dialog.Root>
|
|
3561
|
+
```
|
|
3562
|
+
|
|
3563
|
+
|
|
1481
3564
|
---
|
|
1482
3565
|
|
|
1483
3566
|
### DropdownMenu
|
|
1484
3567
|
|
|
1485
|
-
DropdownMenu — accessible dropdown menu anchored to a trigger.
|
|
3568
|
+
DropdownMenu — accessible dropdown menu anchored to a trigger. Compound component: `DropdownMenu` (Root), `.Trigger`, `.Content`, `.Item`, `.CheckboxItem`, `.RadioGroup`, `.RadioItem`, `.RadioItemIndicator`, `.Sub`, `.SubTrigger`, `.SubContent`, `.Label`, `.Separator`, `.Shortcut`, `.Group`. Built on `@base-ui/react/menu`.
|
|
1486
3569
|
|
|
1487
3570
|
**Type:** component
|
|
1488
3571
|
|
|
@@ -1564,6 +3647,7 @@ Shortcut sub-component
|
|
|
1564
3647
|
|
|
1565
3648
|
Group sub-component (wraps DropdownMenuPrimitive)
|
|
1566
3649
|
|
|
3650
|
+
|
|
1567
3651
|
---
|
|
1568
3652
|
|
|
1569
3653
|
### Empty
|
|
@@ -1599,6 +3683,92 @@ Placeholder shown when a list, table, or page has no content to display.
|
|
|
1599
3683
|
|
|
1600
3684
|
`bg-sf-control`, `bg-sf-overlay`, `border-sf-fill`, `border-sf-interact`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-success`
|
|
1601
3685
|
|
|
3686
|
+
**Examples:**
|
|
3687
|
+
|
|
3688
|
+
```tsx
|
|
3689
|
+
<Empty
|
|
3690
|
+
icon={<PackageIcon size={48} />}
|
|
3691
|
+
title="No packages found"
|
|
3692
|
+
description="Get started by installing your first package."
|
|
3693
|
+
commandLine="npm install @signalflare-ai/ui"
|
|
3694
|
+
contents={
|
|
3695
|
+
<div className="flex items-center gap-2">
|
|
3696
|
+
<Button icon={<CodeIcon />}>See examples</Button>
|
|
3697
|
+
<Button icon={<GlobeIcon />} variant="primary">
|
|
3698
|
+
View documentation
|
|
3699
|
+
</Button>
|
|
3700
|
+
</div>
|
|
3701
|
+
}
|
|
3702
|
+
/>
|
|
3703
|
+
```
|
|
3704
|
+
|
|
3705
|
+
```tsx
|
|
3706
|
+
<div className="flex flex-col gap-8">
|
|
3707
|
+
<div>
|
|
3708
|
+
<p className="mb-2 text-sm text-sf-subtle">Small</p>
|
|
3709
|
+
<Empty
|
|
3710
|
+
size="sm"
|
|
3711
|
+
icon={<DatabaseIcon size={32} className="text-sf-inactive" />}
|
|
3712
|
+
title="No data available"
|
|
3713
|
+
description="There is no data to display."
|
|
3714
|
+
/>
|
|
3715
|
+
</div>
|
|
3716
|
+
<div>
|
|
3717
|
+
<p className="mb-2 text-sm text-sf-subtle">Base</p>
|
|
3718
|
+
<Empty
|
|
3719
|
+
size="base"
|
|
3720
|
+
icon={<DatabaseIcon size={48} className="text-sf-inactive" />}
|
|
3721
|
+
title="No data available"
|
|
3722
|
+
description="There is no data to display."
|
|
3723
|
+
/>
|
|
3724
|
+
</div>
|
|
3725
|
+
<div>
|
|
3726
|
+
<p className="mb-2 text-sm text-sf-subtle">Large</p>
|
|
3727
|
+
<Empty
|
|
3728
|
+
size="lg"
|
|
3729
|
+
icon={<DatabaseIcon size={64} className="text-sf-inactive" />}
|
|
3730
|
+
title="No data available"
|
|
3731
|
+
description="There is no data to display."
|
|
3732
|
+
/>
|
|
3733
|
+
</div>
|
|
3734
|
+
</div>
|
|
3735
|
+
```
|
|
3736
|
+
|
|
3737
|
+
```tsx
|
|
3738
|
+
<Empty
|
|
3739
|
+
icon={<FolderOpenIcon size={48} className="text-sf-inactive" />}
|
|
3740
|
+
title="No projects found"
|
|
3741
|
+
description="Get started by creating your first project using the command below."
|
|
3742
|
+
commandLine="npm create sf-project"
|
|
3743
|
+
/>
|
|
3744
|
+
```
|
|
3745
|
+
|
|
3746
|
+
```tsx
|
|
3747
|
+
<Empty
|
|
3748
|
+
icon={<CloudSlashIcon size={48} className="text-sf-inactive" />}
|
|
3749
|
+
title="No connection"
|
|
3750
|
+
description="Unable to connect to the server. Please check your connection and try again."
|
|
3751
|
+
contents={
|
|
3752
|
+
<div className="flex gap-2">
|
|
3753
|
+
<Button variant="primary">Retry</Button>
|
|
3754
|
+
<Button variant="secondary">Go Back</Button>
|
|
3755
|
+
</div>
|
|
3756
|
+
}
|
|
3757
|
+
/>
|
|
3758
|
+
```
|
|
3759
|
+
|
|
3760
|
+
```tsx
|
|
3761
|
+
<Empty title="Nothing here" />
|
|
3762
|
+
```
|
|
3763
|
+
|
|
3764
|
+
```tsx
|
|
3765
|
+
<Empty
|
|
3766
|
+
title="No results found"
|
|
3767
|
+
description="Try adjusting your search or filter to find what you're looking for."
|
|
3768
|
+
/>
|
|
3769
|
+
```
|
|
3770
|
+
|
|
3771
|
+
|
|
1602
3772
|
---
|
|
1603
3773
|
|
|
1604
3774
|
### Field
|
|
@@ -1636,7 +3806,7 @@ Form field wrapper that provides a label, optional description, and error displa
|
|
|
1636
3806
|
|
|
1637
3807
|
### Filters
|
|
1638
3808
|
|
|
1639
|
-
Filters component for building and managing active filter conditions.
|
|
3809
|
+
Filters component for building and managing active filter conditions. Supports multiple filter types (text, select, multiselect, custom), operators, and an "Add Filter" popover interface. Designed to work standalone or with DataGrid for advanced data filtering.
|
|
1640
3810
|
|
|
1641
3811
|
**Type:** component
|
|
1642
3812
|
|
|
@@ -1677,6 +3847,62 @@ Filters component for building and managing active filter conditions. Supports m
|
|
|
1677
3847
|
|
|
1678
3848
|
`bg-sf-fill`, `bg-sf-line`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-line`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
|
|
1679
3849
|
|
|
3850
|
+
**Examples:**
|
|
3851
|
+
|
|
3852
|
+
```tsx
|
|
3853
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3854
|
+
<Filters filters={filters} fields={filterFields} onChange={setFilters} />
|
|
3855
|
+
<div className="mt-4 rounded bg-sf-elevated p-3 font-mono text-xs">
|
|
3856
|
+
<p className="text-sf-subtle mb-1">Active filters:</p>
|
|
3857
|
+
<pre className="text-sf-strong overflow-x-auto">
|
|
3858
|
+
{JSON.stringify(filters, null, 2)}
|
|
3859
|
+
</pre>
|
|
3860
|
+
</div>
|
|
3861
|
+
</div>
|
|
3862
|
+
```
|
|
3863
|
+
|
|
3864
|
+
```tsx
|
|
3865
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3866
|
+
<Filters
|
|
3867
|
+
filters={filters}
|
|
3868
|
+
fields={filterFields.slice(0, 3)}
|
|
3869
|
+
onChange={setFilters}
|
|
3870
|
+
size="sm"
|
|
3871
|
+
/>
|
|
3872
|
+
</div>
|
|
3873
|
+
```
|
|
3874
|
+
|
|
3875
|
+
```tsx
|
|
3876
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3877
|
+
<Filters
|
|
3878
|
+
filters={filters}
|
|
3879
|
+
fields={filterFields}
|
|
3880
|
+
onChange={setFilters}
|
|
3881
|
+
showSearchInput
|
|
3882
|
+
/>
|
|
3883
|
+
<p className="text-sf-subtle mt-3 text-xs">
|
|
3884
|
+
Open the "Add Filter" menu to see grouped fields (General, User Details)
|
|
3885
|
+
</p>
|
|
3886
|
+
</div>
|
|
3887
|
+
```
|
|
3888
|
+
|
|
3889
|
+
```tsx
|
|
3890
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3891
|
+
<Filters
|
|
3892
|
+
filters={filters}
|
|
3893
|
+
fields={filterFields.slice(0, 3)}
|
|
3894
|
+
onChange={setFilters}
|
|
3895
|
+
enableShortcut
|
|
3896
|
+
shortcutKey="k"
|
|
3897
|
+
shortcutLabel="Cmd+K"
|
|
3898
|
+
/>
|
|
3899
|
+
<p className="text-sf-subtle mt-3 text-xs">
|
|
3900
|
+
Press Cmd+K (or Ctrl+K) to quickly open the add filter menu
|
|
3901
|
+
</p>
|
|
3902
|
+
</div>
|
|
3903
|
+
```
|
|
3904
|
+
|
|
3905
|
+
|
|
1680
3906
|
---
|
|
1681
3907
|
|
|
1682
3908
|
### Grid
|
|
@@ -1720,6 +3946,230 @@ Responsive CSS grid layout container with preset column configurations.
|
|
|
1720
3946
|
|
|
1721
3947
|
`border-sf-line`
|
|
1722
3948
|
|
|
3949
|
+
**Examples:**
|
|
3950
|
+
|
|
3951
|
+
```tsx
|
|
3952
|
+
<Grid variant="2up" gap="base">
|
|
3953
|
+
<GridItem>
|
|
3954
|
+
<Tile>
|
|
3955
|
+
<div>Item 1</div>
|
|
3956
|
+
<div className="mt-1">First grid item</div>
|
|
3957
|
+
</Tile>
|
|
3958
|
+
</GridItem>
|
|
3959
|
+
<GridItem>
|
|
3960
|
+
<Tile>
|
|
3961
|
+
<div>Item 2</div>
|
|
3962
|
+
<div className="mt-1">Second grid item</div>
|
|
3963
|
+
</Tile>
|
|
3964
|
+
</GridItem>
|
|
3965
|
+
</Grid>
|
|
3966
|
+
```
|
|
3967
|
+
|
|
3968
|
+
```tsx
|
|
3969
|
+
<div className="flex flex-col gap-8">
|
|
3970
|
+
<div>
|
|
3971
|
+
<p className="mb-2 text-sf-subtle">variant="2up"</p>
|
|
3972
|
+
<Grid variant="2up" gap="sm">
|
|
3973
|
+
<GridItem>
|
|
3974
|
+
<Tile>
|
|
3975
|
+
<span className="block text-center">1</span>
|
|
3976
|
+
</Tile>
|
|
3977
|
+
</GridItem>
|
|
3978
|
+
<GridItem>
|
|
3979
|
+
<Tile>
|
|
3980
|
+
<span className="block text-center">2</span>
|
|
3981
|
+
</Tile>
|
|
3982
|
+
</GridItem>
|
|
3983
|
+
</Grid>
|
|
3984
|
+
</div>
|
|
3985
|
+
|
|
3986
|
+
<div>
|
|
3987
|
+
<p className="mb-2 text-sf-subtle">variant="3up"</p>
|
|
3988
|
+
<Grid variant="3up" gap="sm">
|
|
3989
|
+
<GridItem>
|
|
3990
|
+
<Tile>
|
|
3991
|
+
<span className="block text-center">1</span>
|
|
3992
|
+
</Tile>
|
|
3993
|
+
</GridItem>
|
|
3994
|
+
<GridItem>
|
|
3995
|
+
<Tile>
|
|
3996
|
+
<span className="block text-center">2</span>
|
|
3997
|
+
</Tile>
|
|
3998
|
+
</GridItem>
|
|
3999
|
+
<GridItem>
|
|
4000
|
+
<Tile>
|
|
4001
|
+
<span className="block text-center">3</span>
|
|
4002
|
+
</Tile>
|
|
4003
|
+
</GridItem>
|
|
4004
|
+
</Grid>
|
|
4005
|
+
</div>
|
|
4006
|
+
|
|
4007
|
+
<div>
|
|
4008
|
+
<p className="mb-2 text-sf-subtle">variant="4up"</p>
|
|
4009
|
+
<Grid variant="4up" gap="sm">
|
|
4010
|
+
<GridItem>
|
|
4011
|
+
<Tile>
|
|
4012
|
+
<span className="block text-center">1</span>
|
|
4013
|
+
</Tile>
|
|
4014
|
+
</GridItem>
|
|
4015
|
+
<GridItem>
|
|
4016
|
+
<Tile>
|
|
4017
|
+
<span className="block text-center">2</span>
|
|
4018
|
+
</Tile>
|
|
4019
|
+
</GridItem>
|
|
4020
|
+
<GridItem>
|
|
4021
|
+
<Tile>
|
|
4022
|
+
<span className="block text-center">3</span>
|
|
4023
|
+
</Tile>
|
|
4024
|
+
</GridItem>
|
|
4025
|
+
<GridItem>
|
|
4026
|
+
<Tile>
|
|
4027
|
+
<span className="block text-center">4</span>
|
|
4028
|
+
</Tile>
|
|
4029
|
+
</GridItem>
|
|
4030
|
+
</Grid>
|
|
4031
|
+
</div>
|
|
4032
|
+
</div>
|
|
4033
|
+
```
|
|
4034
|
+
|
|
4035
|
+
```tsx
|
|
4036
|
+
<div className="flex flex-col gap-8">
|
|
4037
|
+
<div>
|
|
4038
|
+
<p className="mb-2 text-sf-subtle">variant="2-1" (66% / 33%)</p>
|
|
4039
|
+
<Grid variant="2-1" gap="sm">
|
|
4040
|
+
<GridItem>
|
|
4041
|
+
<Tile>
|
|
4042
|
+
<div>Main Content</div>
|
|
4043
|
+
<div className="mt-1">Two-thirds width</div>
|
|
4044
|
+
</Tile>
|
|
4045
|
+
</GridItem>
|
|
4046
|
+
<GridItem>
|
|
4047
|
+
<Tile>
|
|
4048
|
+
<div>Sidebar</div>
|
|
4049
|
+
<div className="mt-1">One-third width</div>
|
|
4050
|
+
</Tile>
|
|
4051
|
+
</GridItem>
|
|
4052
|
+
</Grid>
|
|
4053
|
+
</div>
|
|
4054
|
+
|
|
4055
|
+
<div>
|
|
4056
|
+
<p className="mb-2 text-sf-subtle">variant="1-2" (33% / 66%)</p>
|
|
4057
|
+
<Grid variant="1-2" gap="sm">
|
|
4058
|
+
<GridItem>
|
|
4059
|
+
<Tile>
|
|
4060
|
+
<div>Sidebar</div>
|
|
4061
|
+
<div className="mt-1">One-third width</div>
|
|
4062
|
+
</Tile>
|
|
4063
|
+
</GridItem>
|
|
4064
|
+
<GridItem>
|
|
4065
|
+
<Tile>
|
|
4066
|
+
<div>Main Content</div>
|
|
4067
|
+
<div className="mt-1">Two-thirds width</div>
|
|
4068
|
+
</Tile>
|
|
4069
|
+
</GridItem>
|
|
4070
|
+
</Grid>
|
|
4071
|
+
</div>
|
|
4072
|
+
</div>
|
|
4073
|
+
```
|
|
4074
|
+
|
|
4075
|
+
```tsx
|
|
4076
|
+
<div className="flex flex-col gap-8">
|
|
4077
|
+
<div>
|
|
4078
|
+
<p className="mb-2 text-sf-subtle">gap="none"</p>
|
|
4079
|
+
<Grid variant="side-by-side" gap="none">
|
|
4080
|
+
<GridItem>
|
|
4081
|
+
<Tile>
|
|
4082
|
+
<span className="block text-center">1</span>
|
|
4083
|
+
</Tile>
|
|
4084
|
+
</GridItem>
|
|
4085
|
+
<GridItem>
|
|
4086
|
+
<Tile>
|
|
4087
|
+
<span className="block text-center">2</span>
|
|
4088
|
+
</Tile>
|
|
4089
|
+
</GridItem>
|
|
4090
|
+
</Grid>
|
|
4091
|
+
</div>
|
|
4092
|
+
|
|
4093
|
+
<div>
|
|
4094
|
+
<p className="mb-2 text-sf-subtle">gap="sm"</p>
|
|
4095
|
+
<Grid variant="side-by-side" gap="sm">
|
|
4096
|
+
<GridItem>
|
|
4097
|
+
<Tile>
|
|
4098
|
+
<span className="block text-center">1</span>
|
|
4099
|
+
</Tile>
|
|
4100
|
+
</GridItem>
|
|
4101
|
+
<GridItem>
|
|
4102
|
+
<Tile>
|
|
4103
|
+
<span className="block text-center">2</span>
|
|
4104
|
+
</Tile>
|
|
4105
|
+
</GridItem>
|
|
4106
|
+
</Grid>
|
|
4107
|
+
</div>
|
|
4108
|
+
|
|
4109
|
+
<div>
|
|
4110
|
+
<p className="mb-2 text-sf-subtle">gap="base" (default, responsive)</p>
|
|
4111
|
+
<Grid variant="side-by-side" gap="base">
|
|
4112
|
+
<GridItem>
|
|
4113
|
+
<Tile>
|
|
4114
|
+
<span className="block text-center">1</span>
|
|
4115
|
+
</Tile>
|
|
4116
|
+
</GridItem>
|
|
4117
|
+
<GridItem>
|
|
4118
|
+
<Tile>
|
|
4119
|
+
<span className="block text-center">2</span>
|
|
4120
|
+
</Tile>
|
|
4121
|
+
</GridItem>
|
|
4122
|
+
</Grid>
|
|
4123
|
+
</div>
|
|
4124
|
+
|
|
4125
|
+
<div>
|
|
4126
|
+
<p className="mb-2 text-sf-subtle">gap="lg"</p>
|
|
4127
|
+
<Grid variant="side-by-side" gap="lg">
|
|
4128
|
+
<GridItem>
|
|
4129
|
+
<Tile>
|
|
4130
|
+
<span className="block text-center">1</span>
|
|
4131
|
+
</Tile>
|
|
4132
|
+
</GridItem>
|
|
4133
|
+
<GridItem>
|
|
4134
|
+
<Tile>
|
|
4135
|
+
<span className="block text-center">2</span>
|
|
4136
|
+
</Tile>
|
|
4137
|
+
</GridItem>
|
|
4138
|
+
</Grid>
|
|
4139
|
+
</div>
|
|
4140
|
+
</div>
|
|
4141
|
+
```
|
|
4142
|
+
|
|
4143
|
+
```tsx
|
|
4144
|
+
<Grid variant="4up" gap="base" mobileDivider>
|
|
4145
|
+
<GridItem>
|
|
4146
|
+
<Tile>
|
|
4147
|
+
<div>Item 1</div>
|
|
4148
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4149
|
+
</Tile>
|
|
4150
|
+
</GridItem>
|
|
4151
|
+
<GridItem>
|
|
4152
|
+
<Tile>
|
|
4153
|
+
<div>Item 2</div>
|
|
4154
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4155
|
+
</Tile>
|
|
4156
|
+
</GridItem>
|
|
4157
|
+
<GridItem>
|
|
4158
|
+
<Tile>
|
|
4159
|
+
<div>Item 3</div>
|
|
4160
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4161
|
+
</Tile>
|
|
4162
|
+
</GridItem>
|
|
4163
|
+
<GridItem>
|
|
4164
|
+
<Tile>
|
|
4165
|
+
<div>Item 4</div>
|
|
4166
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4167
|
+
</Tile>
|
|
4168
|
+
</GridItem>
|
|
4169
|
+
</Grid>
|
|
4170
|
+
```
|
|
4171
|
+
|
|
4172
|
+
|
|
1723
4173
|
---
|
|
1724
4174
|
|
|
1725
4175
|
### Input
|
|
@@ -1765,11 +4215,97 @@ Input component
|
|
|
1765
4215
|
|
|
1766
4216
|
- **Dimensions:** `[object Object]`
|
|
1767
4217
|
|
|
4218
|
+
**Examples:**
|
|
4219
|
+
|
|
4220
|
+
```tsx
|
|
4221
|
+
<Input
|
|
4222
|
+
label="Email"
|
|
4223
|
+
placeholder="you@example.com"
|
|
4224
|
+
description="We'll never share your email"
|
|
4225
|
+
/>
|
|
4226
|
+
```
|
|
4227
|
+
|
|
4228
|
+
```tsx
|
|
4229
|
+
<Input
|
|
4230
|
+
label="Email"
|
|
4231
|
+
placeholder="you@example.com"
|
|
4232
|
+
value="invalid-email"
|
|
4233
|
+
variant="error"
|
|
4234
|
+
error="Please enter a valid email address"
|
|
4235
|
+
/>
|
|
4236
|
+
```
|
|
4237
|
+
|
|
4238
|
+
```tsx
|
|
4239
|
+
<Input
|
|
4240
|
+
label="Password"
|
|
4241
|
+
type="password"
|
|
4242
|
+
value="short"
|
|
4243
|
+
variant="error"
|
|
4244
|
+
error={{
|
|
4245
|
+
match: "tooShort",
|
|
4246
|
+
message: "Password must be at least 8 characters",
|
|
4247
|
+
}}
|
|
4248
|
+
minLength={8}
|
|
4249
|
+
/>
|
|
4250
|
+
```
|
|
4251
|
+
|
|
4252
|
+
```tsx
|
|
4253
|
+
<div className="flex flex-col gap-4">
|
|
4254
|
+
<Input size="xs" label="Extra Small" placeholder="Extra small input" />
|
|
4255
|
+
<Input size="sm" label="Small" placeholder="Small input" />
|
|
4256
|
+
<Input label="Base" placeholder="Base input (default)" />
|
|
4257
|
+
<Input size="lg" label="Large" placeholder="Large input" />
|
|
4258
|
+
</div>
|
|
4259
|
+
```
|
|
4260
|
+
|
|
4261
|
+
```tsx
|
|
4262
|
+
<Input label="Disabled field" placeholder="Cannot edit" disabled />
|
|
4263
|
+
```
|
|
4264
|
+
|
|
4265
|
+
```tsx
|
|
4266
|
+
<div className="flex flex-col gap-4">
|
|
4267
|
+
<Input type="email" label="Email" placeholder="you@example.com" />
|
|
4268
|
+
<Input type="password" label="Password" placeholder="••••••••" />
|
|
4269
|
+
<Input type="number" label="Age" placeholder="18" />
|
|
4270
|
+
<Input type="tel" label="Phone" placeholder="+1 (555) 000-0000" />
|
|
4271
|
+
</div>
|
|
4272
|
+
```
|
|
4273
|
+
|
|
4274
|
+
```tsx
|
|
4275
|
+
<Input
|
|
4276
|
+
label="Phone Number"
|
|
4277
|
+
required={false}
|
|
4278
|
+
placeholder="+1 (555) 000-0000"
|
|
4279
|
+
/>
|
|
4280
|
+
```
|
|
4281
|
+
|
|
4282
|
+
```tsx
|
|
4283
|
+
<Input
|
|
4284
|
+
label="API Key"
|
|
4285
|
+
labelTooltip="Find this in your dashboard under Settings > API Keys"
|
|
4286
|
+
placeholder="sk_live_..."
|
|
4287
|
+
/>
|
|
4288
|
+
```
|
|
4289
|
+
|
|
4290
|
+
```tsx
|
|
4291
|
+
<Input
|
|
4292
|
+
label={
|
|
4293
|
+
<span>
|
|
4294
|
+
Email for <strong>billing</strong>
|
|
4295
|
+
</span>
|
|
4296
|
+
}
|
|
4297
|
+
required
|
|
4298
|
+
placeholder="billing@company.com"
|
|
4299
|
+
type="email"
|
|
4300
|
+
/>
|
|
4301
|
+
```
|
|
4302
|
+
|
|
4303
|
+
|
|
1768
4304
|
---
|
|
1769
4305
|
|
|
1770
4306
|
### Label
|
|
1771
4307
|
|
|
1772
|
-
Label component for form fields.
|
|
4308
|
+
Label component for form fields. Provides a standardized way to display labels with optional indicators: - Optional indicator: gray "(optional)" text when `showOptional={true}` - Tooltip: info icon with hover tooltip for additional context
|
|
1773
4309
|
|
|
1774
4310
|
**Type:** component
|
|
1775
4311
|
|
|
@@ -1796,6 +4332,59 @@ Label component for form fields. Provides a standardized way to display labels w
|
|
|
1796
4332
|
|
|
1797
4333
|
`text-sf-default`, `text-sf-strong`
|
|
1798
4334
|
|
|
4335
|
+
**Examples:**
|
|
4336
|
+
|
|
4337
|
+
```tsx
|
|
4338
|
+
<div className="flex flex-col gap-4">
|
|
4339
|
+
<Label>Default Label</Label>
|
|
4340
|
+
<Label showOptional>Optional Label</Label>
|
|
4341
|
+
<Label tooltip="More information about this field">
|
|
4342
|
+
Label with Tooltip
|
|
4343
|
+
</Label>
|
|
4344
|
+
</div>
|
|
4345
|
+
```
|
|
4346
|
+
|
|
4347
|
+
```tsx
|
|
4348
|
+
<Input label="Phone Number" required={false} placeholder="+1 555-0000" />
|
|
4349
|
+
```
|
|
4350
|
+
|
|
4351
|
+
```tsx
|
|
4352
|
+
<Input
|
|
4353
|
+
label="API Key"
|
|
4354
|
+
labelTooltip="Find this in your dashboard settings under API > Keys"
|
|
4355
|
+
placeholder="sk_live_..."
|
|
4356
|
+
/>
|
|
4357
|
+
```
|
|
4358
|
+
|
|
4359
|
+
```tsx
|
|
4360
|
+
<Checkbox
|
|
4361
|
+
label={
|
|
4362
|
+
<span>
|
|
4363
|
+
I agree to the <strong>Terms of Service</strong>
|
|
4364
|
+
</span>
|
|
4365
|
+
}
|
|
4366
|
+
/>
|
|
4367
|
+
```
|
|
4368
|
+
|
|
4369
|
+
```tsx
|
|
4370
|
+
<div className="flex max-w-md flex-col gap-4">
|
|
4371
|
+
<Input label="Full Name" placeholder="John Doe" />
|
|
4372
|
+
<Input
|
|
4373
|
+
label="Email"
|
|
4374
|
+
labelTooltip="We'll send your receipt here"
|
|
4375
|
+
placeholder="john@example.com"
|
|
4376
|
+
type="email"
|
|
4377
|
+
/>
|
|
4378
|
+
<Input label="Company" required={false} placeholder="Acme Inc." />
|
|
4379
|
+
<Select label="Country" hideLabel={false} placeholder="Select a country">
|
|
4380
|
+
<Select.Option value="us">United States</Select.Option>
|
|
4381
|
+
<Select.Option value="uk">United Kingdom</Select.Option>
|
|
4382
|
+
<Select.Option value="ca">Canada</Select.Option>
|
|
4383
|
+
</Select>
|
|
4384
|
+
</div>
|
|
4385
|
+
```
|
|
4386
|
+
|
|
4387
|
+
|
|
1799
4388
|
---
|
|
1800
4389
|
|
|
1801
4390
|
### LayerCard
|
|
@@ -1820,6 +4409,7 @@ LayerCard component
|
|
|
1820
4409
|
|
|
1821
4410
|
**Styling:**
|
|
1822
4411
|
|
|
4412
|
+
|
|
1823
4413
|
**Sub-Components:**
|
|
1824
4414
|
|
|
1825
4415
|
This is a compound component. Use these sub-components:
|
|
@@ -1832,6 +4422,56 @@ Primary sub-component
|
|
|
1832
4422
|
|
|
1833
4423
|
Secondary sub-component
|
|
1834
4424
|
|
|
4425
|
+
|
|
4426
|
+
**Examples:**
|
|
4427
|
+
|
|
4428
|
+
```tsx
|
|
4429
|
+
<LayerCard>
|
|
4430
|
+
<LayerCard.Secondary className="flex items-center justify-between">
|
|
4431
|
+
<div>Next Steps</div>
|
|
4432
|
+
<Button
|
|
4433
|
+
variant="ghost"
|
|
4434
|
+
size="sm"
|
|
4435
|
+
shape="square"
|
|
4436
|
+
aria-label="Go to next steps"
|
|
4437
|
+
>
|
|
4438
|
+
<ArrowRightIcon size={16} />
|
|
4439
|
+
</Button>
|
|
4440
|
+
</LayerCard.Secondary>
|
|
4441
|
+
|
|
4442
|
+
<LayerCard.Primary>Get started with SF</LayerCard.Primary>
|
|
4443
|
+
</LayerCard>
|
|
4444
|
+
```
|
|
4445
|
+
|
|
4446
|
+
```tsx
|
|
4447
|
+
<LayerCard className="w-[250px]">
|
|
4448
|
+
<LayerCard.Secondary>Getting Started</LayerCard.Secondary>
|
|
4449
|
+
<LayerCard.Primary>
|
|
4450
|
+
<p className="text-sm text-sf-subtle">
|
|
4451
|
+
Quick start guide for new users
|
|
4452
|
+
</p>
|
|
4453
|
+
</LayerCard.Primary>
|
|
4454
|
+
</LayerCard>
|
|
4455
|
+
```
|
|
4456
|
+
|
|
4457
|
+
```tsx
|
|
4458
|
+
<div className="flex gap-4">
|
|
4459
|
+
<LayerCard className="w-[200px]">
|
|
4460
|
+
<LayerCard.Secondary>Components</LayerCard.Secondary>
|
|
4461
|
+
<LayerCard.Primary>
|
|
4462
|
+
<p className="text-sm">Browse all components</p>
|
|
4463
|
+
</LayerCard.Primary>
|
|
4464
|
+
</LayerCard>
|
|
4465
|
+
<LayerCard className="w-[200px]">
|
|
4466
|
+
<LayerCard.Secondary>Examples</LayerCard.Secondary>
|
|
4467
|
+
<LayerCard.Primary>
|
|
4468
|
+
<p className="text-sm">View code examples</p>
|
|
4469
|
+
</LayerCard.Primary>
|
|
4470
|
+
</LayerCard>
|
|
4471
|
+
</div>
|
|
4472
|
+
```
|
|
4473
|
+
|
|
4474
|
+
|
|
1835
4475
|
---
|
|
1836
4476
|
|
|
1837
4477
|
### Link
|
|
@@ -1854,7 +4494,6 @@ Link component
|
|
|
1854
4494
|
**State Classes:**
|
|
1855
4495
|
- `"plain"`:
|
|
1856
4496
|
- `hover`: `hover:text-primary/70`
|
|
1857
|
-
|
|
1858
4497
|
- `to`: string
|
|
1859
4498
|
- `children`: ReactNode
|
|
1860
4499
|
- `className`: string
|
|
@@ -1882,6 +4521,71 @@ This is a compound component. Use these sub-components:
|
|
|
1882
4521
|
|
|
1883
4522
|
ExternalIcon sub-component
|
|
1884
4523
|
|
|
4524
|
+
|
|
4525
|
+
**Examples:**
|
|
4526
|
+
|
|
4527
|
+
```tsx
|
|
4528
|
+
<div className="grid gap-x-6 gap-y-4 text-base md:grid-cols-3">
|
|
4529
|
+
<Link href="#">Default inline link</Link>
|
|
4530
|
+
<Link href="#" variant="current">
|
|
4531
|
+
Current color link
|
|
4532
|
+
</Link>
|
|
4533
|
+
<Link href="#" variant="plain">
|
|
4534
|
+
Plain inline link
|
|
4535
|
+
</Link>
|
|
4536
|
+
</div>
|
|
4537
|
+
```
|
|
4538
|
+
|
|
4539
|
+
```tsx
|
|
4540
|
+
<p className="mx-auto max-w-md text-base leading-relaxed text-sf-default">
|
|
4541
|
+
This is a paragraph with an <Link href="#">inline link</Link> that flows
|
|
4542
|
+
naturally with the surrounding text. Links maintain proper underline
|
|
4543
|
+
offset for readability.
|
|
4544
|
+
</p>
|
|
4545
|
+
```
|
|
4546
|
+
|
|
4547
|
+
```tsx
|
|
4548
|
+
<Link
|
|
4549
|
+
href="https://cloudflare.com"
|
|
4550
|
+
target="_blank"
|
|
4551
|
+
rel="noopener noreferrer"
|
|
4552
|
+
className="text-base"
|
|
4553
|
+
>
|
|
4554
|
+
Visit Cloudflare <Link.ExternalIcon />
|
|
4555
|
+
</Link>
|
|
4556
|
+
```
|
|
4557
|
+
|
|
4558
|
+
```tsx
|
|
4559
|
+
<p className="text-base text-sf-danger">
|
|
4560
|
+
This error message contains a{" "}
|
|
4561
|
+
<Link href="#" variant="current">
|
|
4562
|
+
link
|
|
4563
|
+
</Link>{" "}
|
|
4564
|
+
that inherits the red color from its parent.
|
|
4565
|
+
</p>
|
|
4566
|
+
```
|
|
4567
|
+
|
|
4568
|
+
```tsx
|
|
4569
|
+
<div className="flex flex-col gap-x-6 gap-y-4 text-base md:flex-row">
|
|
4570
|
+
<Link render={<CustomRouterLink href="/dashboard" />} variant="inline">
|
|
4571
|
+
Dashboard (via render)
|
|
4572
|
+
</Link>
|
|
4573
|
+
<Link
|
|
4574
|
+
render={
|
|
4575
|
+
<CustomRouterLink
|
|
4576
|
+
href="https://developers.cloudflare.com"
|
|
4577
|
+
target="_blank"
|
|
4578
|
+
rel="noopener noreferrer"
|
|
4579
|
+
/>
|
|
4580
|
+
}
|
|
4581
|
+
variant="inline"
|
|
4582
|
+
>
|
|
4583
|
+
Cloudflare Docs <Link.ExternalIcon />
|
|
4584
|
+
</Link>
|
|
4585
|
+
</div>
|
|
4586
|
+
```
|
|
4587
|
+
|
|
4588
|
+
|
|
1885
4589
|
---
|
|
1886
4590
|
|
|
1887
4591
|
### Loader
|
|
@@ -1903,11 +4607,26 @@ Animated circular spinner for indicating loading states. Uses CSS keyframe anima
|
|
|
1903
4607
|
- `"base"`: Default loader size
|
|
1904
4608
|
- `"lg"`: Large loader for prominent loading states
|
|
1905
4609
|
|
|
4610
|
+
**Examples:**
|
|
4611
|
+
|
|
4612
|
+
```tsx
|
|
4613
|
+
<div className="flex items-center gap-4">
|
|
4614
|
+
<Loader size="sm" />
|
|
4615
|
+
<Loader size="base" />
|
|
4616
|
+
<Loader size="lg" />
|
|
4617
|
+
</div>
|
|
4618
|
+
```
|
|
4619
|
+
|
|
4620
|
+
```tsx
|
|
4621
|
+
<Loader size={24} />
|
|
4622
|
+
```
|
|
4623
|
+
|
|
4624
|
+
|
|
1906
4625
|
---
|
|
1907
4626
|
|
|
1908
4627
|
### MenuBar
|
|
1909
4628
|
|
|
1910
|
-
MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation.
|
|
4629
|
+
MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. Each option renders as a `<button>` with a Tooltip. The active option is visually highlighted with an elevated background.
|
|
1911
4630
|
|
|
1912
4631
|
**Type:** component
|
|
1913
4632
|
|
|
@@ -1932,6 +4651,31 @@ MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. E
|
|
|
1932
4651
|
|
|
1933
4652
|
**Styling:**
|
|
1934
4653
|
|
|
4654
|
+
|
|
4655
|
+
**Examples:**
|
|
4656
|
+
|
|
4657
|
+
```tsx
|
|
4658
|
+
<MenuBar
|
|
4659
|
+
isActive="bold"
|
|
4660
|
+
optionIds
|
|
4661
|
+
options={[
|
|
4662
|
+
{
|
|
4663
|
+
icon: <TextBolderIcon />,
|
|
4664
|
+
id: "bold",
|
|
4665
|
+
onClick: () => {},
|
|
4666
|
+
tooltip: "Bold",
|
|
4667
|
+
},
|
|
4668
|
+
{
|
|
4669
|
+
icon: <TextItalicIcon />,
|
|
4670
|
+
id: "italic",
|
|
4671
|
+
onClick: () => {},
|
|
4672
|
+
tooltip: "Italic",
|
|
4673
|
+
},
|
|
4674
|
+
]}
|
|
4675
|
+
/>
|
|
4676
|
+
```
|
|
4677
|
+
|
|
4678
|
+
|
|
1935
4679
|
---
|
|
1936
4680
|
|
|
1937
4681
|
### Meter
|
|
@@ -1967,6 +4711,29 @@ Progress bar showing a measured value within a known range (e.g. quota usage).
|
|
|
1967
4711
|
|
|
1968
4712
|
`bg-sf-fill`, `text-sf-default`, `text-sf-strong`
|
|
1969
4713
|
|
|
4714
|
+
**Examples:**
|
|
4715
|
+
|
|
4716
|
+
```tsx
|
|
4717
|
+
<Meter label="Storage used" value={65} />
|
|
4718
|
+
```
|
|
4719
|
+
|
|
4720
|
+
```tsx
|
|
4721
|
+
<Meter label="API requests" value={75} customValue="750 / 1,000" />
|
|
4722
|
+
```
|
|
4723
|
+
|
|
4724
|
+
```tsx
|
|
4725
|
+
<Meter label="Progress" value={40} showValue={false} />
|
|
4726
|
+
```
|
|
4727
|
+
|
|
4728
|
+
```tsx
|
|
4729
|
+
<Meter
|
|
4730
|
+
label="Upload progress"
|
|
4731
|
+
value={80}
|
|
4732
|
+
indicatorClassName="from-green-500 via-green-500 to-green-500"
|
|
4733
|
+
/>
|
|
4734
|
+
```
|
|
4735
|
+
|
|
4736
|
+
|
|
1970
4737
|
---
|
|
1971
4738
|
|
|
1972
4739
|
### Pagination
|
|
@@ -2001,6 +4768,34 @@ Page navigation controls with page count display.
|
|
|
2001
4768
|
|
|
2002
4769
|
**Styling:**
|
|
2003
4770
|
|
|
4771
|
+
|
|
4772
|
+
**Examples:**
|
|
4773
|
+
|
|
4774
|
+
```tsx
|
|
4775
|
+
<Pagination page={page} setPage={setPage} perPage={10} totalCount={100} />
|
|
4776
|
+
```
|
|
4777
|
+
|
|
4778
|
+
```tsx
|
|
4779
|
+
<Pagination
|
|
4780
|
+
page={page}
|
|
4781
|
+
setPage={setPage}
|
|
4782
|
+
perPage={10}
|
|
4783
|
+
totalCount={100}
|
|
4784
|
+
controls="simple"
|
|
4785
|
+
/>
|
|
4786
|
+
```
|
|
4787
|
+
|
|
4788
|
+
```tsx
|
|
4789
|
+
<Pagination
|
|
4790
|
+
text={({ perPage }) => `Page ${page} - showing ${perPage} per page`}
|
|
4791
|
+
page={page}
|
|
4792
|
+
setPage={setPage}
|
|
4793
|
+
perPage={25}
|
|
4794
|
+
totalCount={100}
|
|
4795
|
+
/>
|
|
4796
|
+
```
|
|
4797
|
+
|
|
4798
|
+
|
|
2004
4799
|
---
|
|
2005
4800
|
|
|
2006
4801
|
### Popover
|
|
@@ -2049,6 +4844,154 @@ Description sub-component
|
|
|
2049
4844
|
|
|
2050
4845
|
Close sub-component
|
|
2051
4846
|
|
|
4847
|
+
|
|
4848
|
+
**Examples:**
|
|
4849
|
+
|
|
4850
|
+
```tsx
|
|
4851
|
+
<Popover>
|
|
4852
|
+
<Popover.Trigger asChild>
|
|
4853
|
+
<Button shape="square" icon={BellIcon} aria-label="Notifications" />
|
|
4854
|
+
</Popover.Trigger>
|
|
4855
|
+
<Popover.Content>
|
|
4856
|
+
<Popover.Title>Notifications</Popover.Title>
|
|
4857
|
+
<Popover.Description>
|
|
4858
|
+
You are all caught up. Good job!
|
|
4859
|
+
</Popover.Description>
|
|
4860
|
+
</Popover.Content>
|
|
4861
|
+
</Popover>
|
|
4862
|
+
```
|
|
4863
|
+
|
|
4864
|
+
```tsx
|
|
4865
|
+
<Popover>
|
|
4866
|
+
<Popover.Trigger asChild>
|
|
4867
|
+
<Button>Open Popover</Button>
|
|
4868
|
+
</Popover.Trigger>
|
|
4869
|
+
<Popover.Content>
|
|
4870
|
+
<Popover.Title>Popover Title</Popover.Title>
|
|
4871
|
+
<Popover.Description>
|
|
4872
|
+
This is a basic popover with a title and description.
|
|
4873
|
+
</Popover.Description>
|
|
4874
|
+
</Popover.Content>
|
|
4875
|
+
</Popover>
|
|
4876
|
+
```
|
|
4877
|
+
|
|
4878
|
+
```tsx
|
|
4879
|
+
<Popover>
|
|
4880
|
+
<Popover.Trigger asChild>
|
|
4881
|
+
<Button>Open Settings</Button>
|
|
4882
|
+
</Popover.Trigger>
|
|
4883
|
+
<Popover.Content>
|
|
4884
|
+
<Popover.Title>Settings</Popover.Title>
|
|
4885
|
+
<Popover.Description>
|
|
4886
|
+
Configure your preferences below.
|
|
4887
|
+
</Popover.Description>
|
|
4888
|
+
<div className="mt-3">
|
|
4889
|
+
<Popover.Close asChild>
|
|
4890
|
+
<Button variant="secondary" size="sm">
|
|
4891
|
+
Close
|
|
4892
|
+
</Button>
|
|
4893
|
+
</Popover.Close>
|
|
4894
|
+
</div>
|
|
4895
|
+
</Popover.Content>
|
|
4896
|
+
</Popover>
|
|
4897
|
+
```
|
|
4898
|
+
|
|
4899
|
+
```tsx
|
|
4900
|
+
<div className="flex flex-wrap gap-4">
|
|
4901
|
+
<Popover>
|
|
4902
|
+
<Popover.Trigger asChild>
|
|
4903
|
+
<Button variant="secondary">Bottom</Button>
|
|
4904
|
+
</Popover.Trigger>
|
|
4905
|
+
<Popover.Content side="bottom">
|
|
4906
|
+
<Popover.Title>Bottom</Popover.Title>
|
|
4907
|
+
<Popover.Description>
|
|
4908
|
+
Popover on bottom (default).
|
|
4909
|
+
</Popover.Description>
|
|
4910
|
+
</Popover.Content>
|
|
4911
|
+
</Popover>
|
|
4912
|
+
|
|
4913
|
+
<Popover>
|
|
4914
|
+
<Popover.Trigger asChild>
|
|
4915
|
+
<Button variant="secondary">Top</Button>
|
|
4916
|
+
</Popover.Trigger>
|
|
4917
|
+
<Popover.Content side="top">
|
|
4918
|
+
<Popover.Title>Top</Popover.Title>
|
|
4919
|
+
<Popover.Description>Popover on top.</Popover.Description>
|
|
4920
|
+
</Popover.Content>
|
|
4921
|
+
</Popover>
|
|
4922
|
+
|
|
4923
|
+
<Popover>
|
|
4924
|
+
<Popover.Trigger asChild>
|
|
4925
|
+
<Button variant="secondary">Left</Button>
|
|
4926
|
+
</Popover.Trigger>
|
|
4927
|
+
<Popover.Content side="left">
|
|
4928
|
+
<Popover.Title>Left</Popover.Title>
|
|
4929
|
+
<Popover.Description>Popover on left.</Popover.Description>
|
|
4930
|
+
</Popover.Content>
|
|
4931
|
+
</Popover>
|
|
4932
|
+
|
|
4933
|
+
<Popover>
|
|
4934
|
+
<Popover.Trigger asChild>
|
|
4935
|
+
<Button variant="secondary">Right</Button>
|
|
4936
|
+
</Popover.Trigger>
|
|
4937
|
+
<Popover.Content side="right">
|
|
4938
|
+
<Popover.Title>Right</Popover.Title>
|
|
4939
|
+
<Popover.Description>Popover on right.</Popover.Description>
|
|
4940
|
+
</Popover.Content>
|
|
4941
|
+
</Popover>
|
|
4942
|
+
</div>
|
|
4943
|
+
```
|
|
4944
|
+
|
|
4945
|
+
```tsx
|
|
4946
|
+
<Popover>
|
|
4947
|
+
<Popover.Trigger asChild>
|
|
4948
|
+
<Button>User Profile</Button>
|
|
4949
|
+
</Popover.Trigger>
|
|
4950
|
+
<Popover.Content className="w-64">
|
|
4951
|
+
<div className="flex items-center gap-3">
|
|
4952
|
+
<div className="size-10 rounded-full bg-sf-recessed" />
|
|
4953
|
+
<div>
|
|
4954
|
+
<Popover.Title>Jane Doe</Popover.Title>
|
|
4955
|
+
<p className="text-sm text-sf-subtle">jane@example.com</p>
|
|
4956
|
+
</div>
|
|
4957
|
+
</div>
|
|
4958
|
+
<div className="mt-3 flex gap-2 border-t border-sf-line pt-3">
|
|
4959
|
+
<Button variant="secondary" size="sm" className="flex-1">
|
|
4960
|
+
Profile
|
|
4961
|
+
</Button>
|
|
4962
|
+
<Popover.Close asChild>
|
|
4963
|
+
<Button variant="ghost" size="sm" className="flex-1">
|
|
4964
|
+
Sign Out
|
|
4965
|
+
</Button>
|
|
4966
|
+
</Popover.Close>
|
|
4967
|
+
</div>
|
|
4968
|
+
</Popover.Content>
|
|
4969
|
+
</Popover>
|
|
4970
|
+
```
|
|
4971
|
+
|
|
4972
|
+
```tsx
|
|
4973
|
+
<Popover>
|
|
4974
|
+
<Popover.Trigger openOnHover delay={200} asChild>
|
|
4975
|
+
<Button variant="secondary">Hover Me</Button>
|
|
4976
|
+
</Popover.Trigger>
|
|
4977
|
+
<Popover.Content>
|
|
4978
|
+
<Popover.Title>Hover Triggered</Popover.Title>
|
|
4979
|
+
<Popover.Description>
|
|
4980
|
+
This popover opens on hover with a 200ms delay. It can still contain
|
|
4981
|
+
interactive content like buttons and links.
|
|
4982
|
+
</Popover.Description>
|
|
4983
|
+
<div className="mt-3">
|
|
4984
|
+
<Popover.Close asChild>
|
|
4985
|
+
<Button variant="secondary" size="sm">
|
|
4986
|
+
Got it
|
|
4987
|
+
</Button>
|
|
4988
|
+
</Popover.Close>
|
|
4989
|
+
</div>
|
|
4990
|
+
</Popover.Content>
|
|
4991
|
+
</Popover>
|
|
4992
|
+
```
|
|
4993
|
+
|
|
4994
|
+
|
|
2052
4995
|
---
|
|
2053
4996
|
|
|
2054
4997
|
### PromptInput
|
|
@@ -2071,8 +5014,10 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
|
|
|
2071
5014
|
Maximum file size in bytes.
|
|
2072
5015
|
- `backLayer`: ReactNode
|
|
2073
5016
|
Content rendered in the collapsible back layer (e.g. HITL approvals, task lists). When provided the prompt input is wrapped in a LayerCard shell with a header row containing a chevron toggle. Use `PromptInputBackLayer` to compose structured content for this slot.
|
|
2074
|
-
- `backLayerTitle`:
|
|
2075
|
-
|
|
5017
|
+
- `backLayerTitle`: ReactNode
|
|
5018
|
+
Header content shown in the back layer header row. Strings render as plain text; pass JSX to compose with icons/spinners/badges. Defaults to `"Context"`.
|
|
5019
|
+
- `backLayerStatus`: enum
|
|
5020
|
+
Optional status indicator rendered next to the title. `"running"` shows a small spinner; `"error"` shows an inline error icon. Use this instead of composing JSX into `backLayerTitle` for the common case of an agent doing work.
|
|
2076
5021
|
- `backLayerOpen`: boolean
|
|
2077
5022
|
Controls whether the back layer is visible. Pair with `onBackLayerOpenChange` for a controlled pattern.
|
|
2078
5023
|
- `autoOpenBackLayerWhen`: boolean
|
|
@@ -2085,7 +5030,7 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
|
|
|
2085
5030
|
|
|
2086
5031
|
**Colors (sf tokens used):**
|
|
2087
5032
|
|
|
2088
|
-
`bg-sf-base`, `bg-sf-control`, `bg-sf-elevated`, `bg-sf-info-tint`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-info`, `ring-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-subtle`
|
|
5033
|
+
`bg-sf-base`, `bg-sf-control`, `bg-sf-elevated`, `bg-sf-info-tint`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-info`, `ring-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-subtle`
|
|
2089
5034
|
|
|
2090
5035
|
**Sub-Components:**
|
|
2091
5036
|
|
|
@@ -2148,7 +5093,7 @@ Attachment sub-component
|
|
|
2148
5093
|
|
|
2149
5094
|
### Radio
|
|
2150
5095
|
|
|
2151
|
-
Radio — radio button group for single-select choices.
|
|
5096
|
+
Radio — radio button group for single-select choices. Compound component: `Radio.Group` (with built-in Fieldset) and `Radio.Item`. Built on `@base-ui/react/radio-group` + `@base-ui/react/radio`.
|
|
2152
5097
|
|
|
2153
5098
|
**Type:** component
|
|
2154
5099
|
|
|
@@ -2183,6 +5128,78 @@ Radio — radio button group for single-select choices. Compound component: `Rad
|
|
|
2183
5128
|
|
|
2184
5129
|
`bg-sf-base`, `bg-sf-contrast`, `border-sf-line`, `ring-sf-danger`, `ring-sf-interact`, `ring-sf-ring`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`
|
|
2185
5130
|
|
|
5131
|
+
**Examples:**
|
|
5132
|
+
|
|
5133
|
+
```tsx
|
|
5134
|
+
<Radio.Group
|
|
5135
|
+
legend="Notification preference"
|
|
5136
|
+
value={value}
|
|
5137
|
+
onValueChange={setValue}
|
|
5138
|
+
>
|
|
5139
|
+
<Radio.Item label="Email" value="email" />
|
|
5140
|
+
<Radio.Item label="SMS" value="sms" />
|
|
5141
|
+
<Radio.Item label="Push notification" value="push" />
|
|
5142
|
+
</Radio.Group>
|
|
5143
|
+
```
|
|
5144
|
+
|
|
5145
|
+
```tsx
|
|
5146
|
+
<Radio.Group
|
|
5147
|
+
legend="Size"
|
|
5148
|
+
orientation="horizontal"
|
|
5149
|
+
value={value}
|
|
5150
|
+
onValueChange={setValue}
|
|
5151
|
+
>
|
|
5152
|
+
<Radio.Item label="Small" value="sm" />
|
|
5153
|
+
<Radio.Item label="Medium" value="md" />
|
|
5154
|
+
<Radio.Item label="Large" value="lg" />
|
|
5155
|
+
</Radio.Group>
|
|
5156
|
+
```
|
|
5157
|
+
|
|
5158
|
+
```tsx
|
|
5159
|
+
<Radio.Group
|
|
5160
|
+
legend="Shipping method"
|
|
5161
|
+
description="Choose how you'd like to receive your order"
|
|
5162
|
+
value={value}
|
|
5163
|
+
onValueChange={setValue}
|
|
5164
|
+
>
|
|
5165
|
+
<Radio.Item label="Standard (5-7 days)" value="standard" />
|
|
5166
|
+
<Radio.Item label="Express (2-3 days)" value="express" />
|
|
5167
|
+
<Radio.Item label="Overnight" value="overnight" />
|
|
5168
|
+
</Radio.Group>
|
|
5169
|
+
```
|
|
5170
|
+
|
|
5171
|
+
```tsx
|
|
5172
|
+
<Radio.Group
|
|
5173
|
+
legend="Payment method"
|
|
5174
|
+
error="Please select a payment method to continue"
|
|
5175
|
+
>
|
|
5176
|
+
<Radio.Item label="Credit Card" value="card" variant="error" />
|
|
5177
|
+
<Radio.Item label="PayPal" value="paypal" variant="error" />
|
|
5178
|
+
<Radio.Item label="Bank Transfer" value="bank" variant="error" />
|
|
5179
|
+
</Radio.Group>
|
|
5180
|
+
```
|
|
5181
|
+
|
|
5182
|
+
```tsx
|
|
5183
|
+
<div className="flex flex-col gap-6">
|
|
5184
|
+
<Radio.Group legend="Disabled group" disabled defaultValue="a">
|
|
5185
|
+
<Radio.Item label="Option A" value="a" />
|
|
5186
|
+
<Radio.Item label="Option B" value="b" />
|
|
5187
|
+
</Radio.Group>
|
|
5188
|
+
<Radio.Group legend="Individual disabled" defaultValue="available">
|
|
5189
|
+
<Radio.Item label="Available" value="available" />
|
|
5190
|
+
<Radio.Item label="Unavailable" value="unavailable" disabled />
|
|
5191
|
+
</Radio.Group>
|
|
5192
|
+
</div>
|
|
5193
|
+
```
|
|
5194
|
+
|
|
5195
|
+
```tsx
|
|
5196
|
+
<Radio.Group legend="Preferences" controlPosition="end" defaultValue="a">
|
|
5197
|
+
<Radio.Item label="Label before radio" value="a" />
|
|
5198
|
+
<Radio.Item label="Another option" value="b" />
|
|
5199
|
+
</Radio.Group>
|
|
5200
|
+
```
|
|
5201
|
+
|
|
5202
|
+
|
|
2186
5203
|
---
|
|
2187
5204
|
|
|
2188
5205
|
### Select
|
|
@@ -2232,6 +5249,7 @@ Select component
|
|
|
2232
5249
|
|
|
2233
5250
|
**Styling:**
|
|
2234
5251
|
|
|
5252
|
+
|
|
2235
5253
|
**Sub-Components:**
|
|
2236
5254
|
|
|
2237
5255
|
This is a compound component. Use these sub-components:
|
|
@@ -2240,6 +5258,107 @@ This is a compound component. Use these sub-components:
|
|
|
2240
5258
|
|
|
2241
5259
|
Option sub-component
|
|
2242
5260
|
|
|
5261
|
+
|
|
5262
|
+
**Examples:**
|
|
5263
|
+
|
|
5264
|
+
```tsx
|
|
5265
|
+
<Select
|
|
5266
|
+
className="w-[200px]"
|
|
5267
|
+
value={value}
|
|
5268
|
+
onValueChange={(v) => setValue(v ?? "apple")}
|
|
5269
|
+
items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
|
|
5270
|
+
>
|
|
5271
|
+
<Select.Option value="apple">Apple</Select.Option>
|
|
5272
|
+
<Select.Option value="banana">Banana</Select.Option>
|
|
5273
|
+
<Select.Option value="cherry">Cherry</Select.Option>
|
|
5274
|
+
</Select>
|
|
5275
|
+
```
|
|
5276
|
+
|
|
5277
|
+
```tsx
|
|
5278
|
+
<Select
|
|
5279
|
+
className="w-[200px]"
|
|
5280
|
+
renderValue={(v) => (
|
|
5281
|
+
<span>
|
|
5282
|
+
{v.emoji} {v.label}
|
|
5283
|
+
</span>
|
|
5284
|
+
)}
|
|
5285
|
+
value={value}
|
|
5286
|
+
onValueChange={(v) => setValue(v as (typeof languages)[0])}
|
|
5287
|
+
>
|
|
5288
|
+
{languages.map((language) => (
|
|
5289
|
+
<Select.Option key={language.value} value={language}>
|
|
5290
|
+
{language.emoji} {language.label}
|
|
5291
|
+
</Select.Option>
|
|
5292
|
+
))}
|
|
5293
|
+
</Select>
|
|
5294
|
+
```
|
|
5295
|
+
|
|
5296
|
+
```tsx
|
|
5297
|
+
<Select className="w-[200px]" loading />
|
|
5298
|
+
```
|
|
5299
|
+
|
|
5300
|
+
```tsx
|
|
5301
|
+
<Select
|
|
5302
|
+
className="w-[200px]"
|
|
5303
|
+
loading={loading}
|
|
5304
|
+
value={value}
|
|
5305
|
+
onValueChange={(v) => setValue(v as string | null)}
|
|
5306
|
+
placeholder="Please select"
|
|
5307
|
+
>
|
|
5308
|
+
{data?.map((item) => (
|
|
5309
|
+
<Select.Option key={item} value={item}>
|
|
5310
|
+
{item}
|
|
5311
|
+
</Select.Option>
|
|
5312
|
+
))}
|
|
5313
|
+
</Select>
|
|
5314
|
+
```
|
|
5315
|
+
|
|
5316
|
+
```tsx
|
|
5317
|
+
<Select
|
|
5318
|
+
className="w-[250px]"
|
|
5319
|
+
multiple
|
|
5320
|
+
renderValue={(value) => {
|
|
5321
|
+
if (value.length > 3) {
|
|
5322
|
+
return (
|
|
5323
|
+
<span className="line-clamp-1">
|
|
5324
|
+
{value.slice(2).join(", ") + ` and ${value.length - 2} more`}
|
|
5325
|
+
</span>
|
|
5326
|
+
);
|
|
5327
|
+
}
|
|
5328
|
+
return <span>{value.join(", ")}</span>;
|
|
5329
|
+
}}
|
|
5330
|
+
value={value}
|
|
5331
|
+
onValueChange={(v) => setValue(v as string[])}
|
|
5332
|
+
>
|
|
5333
|
+
<Select.Option value="Name">Name</Select.Option>
|
|
5334
|
+
<Select.Option value="Location">Location</Select.Option>
|
|
5335
|
+
<Select.Option value="Size">Size</Select.Option>
|
|
5336
|
+
<Select.Option value="Read">Read</Select.Option>
|
|
5337
|
+
<Select.Option value="Write">Write</Select.Option>
|
|
5338
|
+
<Select.Option value="CreatedAt">Created At</Select.Option>
|
|
5339
|
+
</Select>
|
|
5340
|
+
```
|
|
5341
|
+
|
|
5342
|
+
```tsx
|
|
5343
|
+
<Select
|
|
5344
|
+
className="w-[200px]"
|
|
5345
|
+
onValueChange={(v) => setValue(v as (typeof authors)[0] | null)}
|
|
5346
|
+
value={value}
|
|
5347
|
+
isItemEqualToValue={(item, value) => item?.id === value?.id}
|
|
5348
|
+
renderValue={(author) => author?.name ?? "Please select author"}
|
|
5349
|
+
>
|
|
5350
|
+
{authors.map((author) => (
|
|
5351
|
+
<Select.Option key={author.id} value={author}>
|
|
5352
|
+
<div className="flex w-[300px] items-center justify-between gap-2">
|
|
5353
|
+
<Text>{author.name}</Text>
|
|
5354
|
+
<Text variant="secondary">{author.title}</Text>
|
|
5355
|
+
</div>
|
|
5356
|
+
</Select.Option>
|
|
5357
|
+
))}
|
|
5358
|
+
</Select>
|
|
5359
|
+
```
|
|
5360
|
+
|
|
5361
|
+
|
|
2243
5362
|
---
|
|
2244
5363
|
|
|
2245
5364
|
### SensitiveInput
|
|
@@ -2295,11 +5414,82 @@ Password/secret input that masks its value by default and reveals on click. Incl
|
|
|
2295
5414
|
|
|
2296
5415
|
`bg-sf-brand`, `bg-sf-control`, `outline-sf-ring`, `text-sf-default`, `text-sf-subtle`
|
|
2297
5416
|
|
|
5417
|
+
**Examples:**
|
|
5418
|
+
|
|
5419
|
+
```tsx
|
|
5420
|
+
<div className="w-80">
|
|
5421
|
+
<SensitiveInput label="API Key" defaultValue="sk_live_abc123xyz789" />
|
|
5422
|
+
</div>
|
|
5423
|
+
```
|
|
5424
|
+
|
|
5425
|
+
```tsx
|
|
5426
|
+
<div className="flex flex-col gap-4">
|
|
5427
|
+
{sizes.map((size) => (
|
|
5428
|
+
<div key={size} className="flex items-center gap-2">
|
|
5429
|
+
<span className="w-12 text-sm text-sf-subtle">{size}</span>
|
|
5430
|
+
<SensitiveInput
|
|
5431
|
+
label={`${size} size`}
|
|
5432
|
+
size={size}
|
|
5433
|
+
defaultValue="secret-api-key-123"
|
|
5434
|
+
/>
|
|
5435
|
+
</div>
|
|
5436
|
+
))}
|
|
5437
|
+
</div>
|
|
5438
|
+
```
|
|
5439
|
+
|
|
5440
|
+
```tsx
|
|
5441
|
+
<div className="flex w-80 flex-col gap-4">
|
|
5442
|
+
<SensitiveInput
|
|
5443
|
+
label="Controlled Secret"
|
|
5444
|
+
value={value}
|
|
5445
|
+
onValueChange={setValue}
|
|
5446
|
+
/>
|
|
5447
|
+
<div className="text-sm text-sf-subtle">
|
|
5448
|
+
Current value: <code className="text-sf-default">{value}</code>
|
|
5449
|
+
</div>
|
|
5450
|
+
<div className="flex gap-2">
|
|
5451
|
+
<Button
|
|
5452
|
+
onClick={() => setValue("new-secret-" + Date.now())}
|
|
5453
|
+
variant="primary"
|
|
5454
|
+
size="sm"
|
|
5455
|
+
>
|
|
5456
|
+
Change value
|
|
5457
|
+
</Button>
|
|
5458
|
+
<Button onClick={() => setValue("")} variant="secondary" size="sm">
|
|
5459
|
+
Clear
|
|
5460
|
+
</Button>
|
|
5461
|
+
</div>
|
|
5462
|
+
</div>
|
|
5463
|
+
```
|
|
5464
|
+
|
|
5465
|
+
```tsx
|
|
5466
|
+
<div className="flex w-80 flex-col gap-4">
|
|
5467
|
+
<SensitiveInput
|
|
5468
|
+
label="Error State"
|
|
5469
|
+
variant="error"
|
|
5470
|
+
defaultValue="invalid-key"
|
|
5471
|
+
error="This API key is not valid"
|
|
5472
|
+
/>
|
|
5473
|
+
<SensitiveInput label="Disabled" defaultValue="cannot-edit" disabled />
|
|
5474
|
+
<SensitiveInput
|
|
5475
|
+
label="Read-only"
|
|
5476
|
+
defaultValue="view-only-secret-key"
|
|
5477
|
+
readOnly
|
|
5478
|
+
/>
|
|
5479
|
+
<SensitiveInput
|
|
5480
|
+
label="With Description"
|
|
5481
|
+
defaultValue="my-secret-value"
|
|
5482
|
+
description="Keep this value secure and don't share it"
|
|
5483
|
+
/>
|
|
5484
|
+
</div>
|
|
5485
|
+
```
|
|
5486
|
+
|
|
5487
|
+
|
|
2298
5488
|
---
|
|
2299
5489
|
|
|
2300
5490
|
### Sidebar
|
|
2301
5491
|
|
|
2302
|
-
Sidebar — responsive navigation panel with expand/collapse support.
|
|
5492
|
+
Sidebar — responsive navigation panel with expand/collapse support. Compound component: `Sidebar` (root `<aside>`), `.Provider`, `.Header`, `.Content`, `.Footer`, `.Group`, `.GroupLabel`, `.GroupContent`, `.Menu`, `.MenuItem`, `.MenuButton`, `.MenuAction`, `.MenuBadge`, `.MenuSub`, `.MenuSubItem`, `.MenuSubButton`, `.Separator`, `.Input`, `.Trigger`, `.Rail`, `.MenuChevron`, `.Collapsible`, `.CollapsibleTrigger`, `.CollapsibleContent`. Built on `@base-ui/react/collapsible` + `@base-ui/react/dialog`.
|
|
2303
5493
|
|
|
2304
5494
|
**Type:** component
|
|
2305
5495
|
|
|
@@ -2343,6 +5533,7 @@ Sidebar — responsive navigation panel with expand/collapse support. Compound c
|
|
|
2343
5533
|
|
|
2344
5534
|
**Styling:**
|
|
2345
5535
|
|
|
5536
|
+
|
|
2346
5537
|
**Sub-Components:**
|
|
2347
5538
|
|
|
2348
5539
|
This is a compound component. Use these sub-components:
|
|
@@ -2352,7 +5543,6 @@ This is a compound component. Use these sub-components:
|
|
|
2352
5543
|
Provider sub-component
|
|
2353
5544
|
|
|
2354
5545
|
Props:
|
|
2355
|
-
|
|
2356
5546
|
- `defaultOpen`: boolean
|
|
2357
5547
|
- `open`: boolean
|
|
2358
5548
|
- `variant`: SidebarVariant
|
|
@@ -2457,6 +5647,299 @@ CollapsibleTrigger sub-component
|
|
|
2457
5647
|
|
|
2458
5648
|
CollapsibleContent sub-component
|
|
2459
5649
|
|
|
5650
|
+
|
|
5651
|
+
**Examples:**
|
|
5652
|
+
|
|
5653
|
+
```tsx
|
|
5654
|
+
<DemoContainer>
|
|
5655
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5656
|
+
<Sidebar>
|
|
5657
|
+
<Sidebar.Content>
|
|
5658
|
+
<Sidebar.Group>
|
|
5659
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5660
|
+
<Sidebar.Menu>
|
|
5661
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5662
|
+
Home
|
|
5663
|
+
</Sidebar.MenuButton>
|
|
5664
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5665
|
+
Analytics
|
|
5666
|
+
</Sidebar.MenuButton>
|
|
5667
|
+
<Sidebar.MenuButton icon={GlobeIcon}>
|
|
5668
|
+
Domains
|
|
5669
|
+
</Sidebar.MenuButton>
|
|
5670
|
+
</Sidebar.Menu>
|
|
5671
|
+
</Sidebar.Group>
|
|
5672
|
+
|
|
5673
|
+
<Sidebar.Group>
|
|
5674
|
+
<Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
|
|
5675
|
+
<Sidebar.Menu>
|
|
5676
|
+
<Sidebar.MenuItem>
|
|
5677
|
+
<Sidebar.Collapsible defaultOpen>
|
|
5678
|
+
<Sidebar.CollapsibleTrigger
|
|
5679
|
+
render={
|
|
5680
|
+
<Sidebar.MenuButton icon={CodeIcon}>
|
|
5681
|
+
Compute
|
|
5682
|
+
<Sidebar.MenuChevron />
|
|
5683
|
+
</Sidebar.MenuButton>
|
|
5684
|
+
}
|
|
5685
|
+
/>
|
|
5686
|
+
<Sidebar.CollapsibleContent>
|
|
5687
|
+
<Sidebar.MenuSub>
|
|
5688
|
+
<Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
|
|
5689
|
+
<Sidebar.MenuSubButton>
|
|
5690
|
+
Durable Objects
|
|
5691
|
+
</Sidebar.MenuSubButton>
|
|
5692
|
+
</Sidebar.MenuSub>
|
|
5693
|
+
</Sidebar.CollapsibleContent>
|
|
5694
|
+
</Sidebar.Collapsible>
|
|
5695
|
+
</Sidebar.MenuItem>
|
|
5696
|
+
<Sidebar.MenuButton icon={DatabaseIcon}>
|
|
5697
|
+
Storage
|
|
5698
|
+
</Sidebar.MenuButton>
|
|
5699
|
+
</Sidebar.Menu>
|
|
5700
|
+
</Sidebar.Group>
|
|
5701
|
+
</Sidebar.Content>
|
|
5702
|
+
</Sidebar>
|
|
5703
|
+
<DemoMain />
|
|
5704
|
+
</Sidebar.Provider>
|
|
5705
|
+
</DemoContainer>
|
|
5706
|
+
```
|
|
5707
|
+
|
|
5708
|
+
```tsx
|
|
5709
|
+
<DemoContainer>
|
|
5710
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5711
|
+
<Sidebar>
|
|
5712
|
+
<Sidebar.Content>
|
|
5713
|
+
<Sidebar.Group collapsible defaultOpen>
|
|
5714
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5715
|
+
<Sidebar.GroupContent>
|
|
5716
|
+
<Sidebar.Menu>
|
|
5717
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5718
|
+
Home
|
|
5719
|
+
</Sidebar.MenuButton>
|
|
5720
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5721
|
+
Analytics
|
|
5722
|
+
</Sidebar.MenuButton>
|
|
5723
|
+
<Sidebar.MenuButton icon={GlobeIcon}>
|
|
5724
|
+
Domains
|
|
5725
|
+
</Sidebar.MenuButton>
|
|
5726
|
+
</Sidebar.Menu>
|
|
5727
|
+
</Sidebar.GroupContent>
|
|
5728
|
+
</Sidebar.Group>
|
|
5729
|
+
|
|
5730
|
+
<Sidebar.Group collapsible defaultOpen={false}>
|
|
5731
|
+
<Sidebar.GroupLabel>Settings</Sidebar.GroupLabel>
|
|
5732
|
+
<Sidebar.GroupContent>
|
|
5733
|
+
<Sidebar.Menu>
|
|
5734
|
+
<Sidebar.MenuButton icon={ShieldCheckIcon}>
|
|
5735
|
+
Security
|
|
5736
|
+
</Sidebar.MenuButton>
|
|
5737
|
+
<Sidebar.MenuButton icon={LockIcon}>
|
|
5738
|
+
Access Control
|
|
5739
|
+
</Sidebar.MenuButton>
|
|
5740
|
+
</Sidebar.Menu>
|
|
5741
|
+
</Sidebar.GroupContent>
|
|
5742
|
+
</Sidebar.Group>
|
|
5743
|
+
</Sidebar.Content>
|
|
5744
|
+
</Sidebar>
|
|
5745
|
+
<DemoMain />
|
|
5746
|
+
</Sidebar.Provider>
|
|
5747
|
+
</DemoContainer>
|
|
5748
|
+
```
|
|
5749
|
+
|
|
5750
|
+
```tsx
|
|
5751
|
+
<DemoContainer>
|
|
5752
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5753
|
+
<Sidebar>
|
|
5754
|
+
<Sidebar.Header>
|
|
5755
|
+
<BrandLogo />
|
|
5756
|
+
</Sidebar.Header>
|
|
5757
|
+
<Sidebar.Content>
|
|
5758
|
+
<Sidebar.Group>
|
|
5759
|
+
<Sidebar.Menu>
|
|
5760
|
+
<Sidebar.MenuButton icon={HouseIcon} tooltip="Home" active>
|
|
5761
|
+
Home
|
|
5762
|
+
</Sidebar.MenuButton>
|
|
5763
|
+
<Sidebar.MenuButton icon={ChartBarIcon} tooltip="Analytics">
|
|
5764
|
+
Analytics
|
|
5765
|
+
</Sidebar.MenuButton>
|
|
5766
|
+
<Sidebar.MenuButton icon={CodeIcon} tooltip="Compute">
|
|
5767
|
+
Compute
|
|
5768
|
+
</Sidebar.MenuButton>
|
|
5769
|
+
<Sidebar.MenuButton icon={DatabaseIcon} tooltip="Storage">
|
|
5770
|
+
Storage
|
|
5771
|
+
</Sidebar.MenuButton>
|
|
5772
|
+
</Sidebar.Menu>
|
|
5773
|
+
</Sidebar.Group>
|
|
5774
|
+
</Sidebar.Content>
|
|
5775
|
+
<Sidebar.Footer>
|
|
5776
|
+
<Sidebar.Trigger />
|
|
5777
|
+
</Sidebar.Footer>
|
|
5778
|
+
</Sidebar>
|
|
5779
|
+
<DemoMain>
|
|
5780
|
+
<ToggleButton />
|
|
5781
|
+
<p className="text-sm">
|
|
5782
|
+
Click the button or the sidebar trigger to toggle
|
|
5783
|
+
</p>
|
|
5784
|
+
</DemoMain>
|
|
5785
|
+
</Sidebar.Provider>
|
|
5786
|
+
</DemoContainer>
|
|
5787
|
+
```
|
|
5788
|
+
|
|
5789
|
+
```tsx
|
|
5790
|
+
<DemoContainer>
|
|
5791
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5792
|
+
<Sidebar>
|
|
5793
|
+
<Sidebar.Header>
|
|
5794
|
+
<BrandLogo />
|
|
5795
|
+
</Sidebar.Header>
|
|
5796
|
+
|
|
5797
|
+
<Sidebar.Content>
|
|
5798
|
+
<div className="px-1 pb-2">
|
|
5799
|
+
<Sidebar.Input placeholder="Quick search..." shortcut="⌘K" />
|
|
5800
|
+
</div>
|
|
5801
|
+
|
|
5802
|
+
<Sidebar.Group>
|
|
5803
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5804
|
+
<Sidebar.Menu>
|
|
5805
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5806
|
+
Home
|
|
5807
|
+
</Sidebar.MenuButton>
|
|
5808
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5809
|
+
Analytics
|
|
5810
|
+
</Sidebar.MenuButton>
|
|
5811
|
+
<Sidebar.MenuButton icon={GlobeIcon}>
|
|
5812
|
+
Domains
|
|
5813
|
+
</Sidebar.MenuButton>
|
|
5814
|
+
</Sidebar.Menu>
|
|
5815
|
+
</Sidebar.Group>
|
|
5816
|
+
|
|
5817
|
+
<Sidebar.Separator />
|
|
5818
|
+
|
|
5819
|
+
<Sidebar.Group>
|
|
5820
|
+
<Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
|
|
5821
|
+
<Sidebar.Menu>
|
|
5822
|
+
<Sidebar.MenuItem>
|
|
5823
|
+
<Sidebar.Collapsible defaultOpen>
|
|
5824
|
+
<Sidebar.CollapsibleTrigger
|
|
5825
|
+
render={
|
|
5826
|
+
<Sidebar.MenuButton icon={CodeIcon}>
|
|
5827
|
+
Compute
|
|
5828
|
+
<Sidebar.MenuChevron />
|
|
5829
|
+
</Sidebar.MenuButton>
|
|
5830
|
+
}
|
|
5831
|
+
/>
|
|
5832
|
+
<Sidebar.CollapsibleContent>
|
|
5833
|
+
<Sidebar.MenuSub>
|
|
5834
|
+
<Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
|
|
5835
|
+
<Sidebar.MenuSubButton>
|
|
5836
|
+
Durable Objects
|
|
5837
|
+
</Sidebar.MenuSubButton>
|
|
5838
|
+
<Sidebar.MenuSubButton>
|
|
5839
|
+
Containers
|
|
5840
|
+
<Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
|
|
5841
|
+
</Sidebar.MenuSubButton>
|
|
5842
|
+
</Sidebar.MenuSub>
|
|
5843
|
+
</Sidebar.CollapsibleContent>
|
|
5844
|
+
</Sidebar.Collapsible>
|
|
5845
|
+
</Sidebar.MenuItem>
|
|
5846
|
+
<Sidebar.MenuButton icon={DatabaseIcon}>
|
|
5847
|
+
Storage
|
|
5848
|
+
</Sidebar.MenuButton>
|
|
5849
|
+
</Sidebar.Menu>
|
|
5850
|
+
</Sidebar.Group>
|
|
5851
|
+
|
|
5852
|
+
<Sidebar.Group>
|
|
5853
|
+
<Sidebar.GroupLabel>Security</Sidebar.GroupLabel>
|
|
5854
|
+
<Sidebar.Menu>
|
|
5855
|
+
<Sidebar.MenuButton icon={ShieldCheckIcon}>
|
|
5856
|
+
Firewall
|
|
5857
|
+
</Sidebar.MenuButton>
|
|
5858
|
+
<Sidebar.MenuButton icon={LockIcon}>
|
|
5859
|
+
Access
|
|
5860
|
+
<Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
|
|
5861
|
+
</Sidebar.MenuButton>
|
|
5862
|
+
<Sidebar.MenuButton icon={BellIcon}>
|
|
5863
|
+
Notifications
|
|
5864
|
+
</Sidebar.MenuButton>
|
|
5865
|
+
</Sidebar.Menu>
|
|
5866
|
+
</Sidebar.Group>
|
|
5867
|
+
</Sidebar.Content>
|
|
5868
|
+
|
|
5869
|
+
<Sidebar.Footer>
|
|
5870
|
+
<Sidebar.MenuButton icon={GearIcon}>Settings</Sidebar.MenuButton>
|
|
5871
|
+
</Sidebar.Footer>
|
|
5872
|
+
</Sidebar>
|
|
5873
|
+
<DemoMain />
|
|
5874
|
+
</Sidebar.Provider>
|
|
5875
|
+
</DemoContainer>
|
|
5876
|
+
```
|
|
5877
|
+
|
|
5878
|
+
```tsx
|
|
5879
|
+
<DemoContainer>
|
|
5880
|
+
<Sidebar.Provider
|
|
5881
|
+
defaultOpen
|
|
5882
|
+
resizable
|
|
5883
|
+
defaultWidth={240}
|
|
5884
|
+
minWidth={180}
|
|
5885
|
+
maxWidth={400}
|
|
5886
|
+
className="min-h-0! h-full"
|
|
5887
|
+
>
|
|
5888
|
+
<Sidebar>
|
|
5889
|
+
<Sidebar.Header>
|
|
5890
|
+
<BrandLogo />
|
|
5891
|
+
</Sidebar.Header>
|
|
5892
|
+
<Sidebar.Content>
|
|
5893
|
+
<Sidebar.Group>
|
|
5894
|
+
<Sidebar.Menu>
|
|
5895
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5896
|
+
Home
|
|
5897
|
+
</Sidebar.MenuButton>
|
|
5898
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5899
|
+
Analytics
|
|
5900
|
+
</Sidebar.MenuButton>
|
|
5901
|
+
<Sidebar.MenuButton icon={GlobeIcon}>
|
|
5902
|
+
Domains
|
|
5903
|
+
</Sidebar.MenuButton>
|
|
5904
|
+
</Sidebar.Menu>
|
|
5905
|
+
</Sidebar.Group>
|
|
5906
|
+
</Sidebar.Content>
|
|
5907
|
+
<Sidebar.ResizeHandle />
|
|
5908
|
+
</Sidebar>
|
|
5909
|
+
<DemoMain>
|
|
5910
|
+
<p className="text-sm">Drag the sidebar edge to resize</p>
|
|
5911
|
+
</DemoMain>
|
|
5912
|
+
</Sidebar.Provider>
|
|
5913
|
+
</DemoContainer>
|
|
5914
|
+
```
|
|
5915
|
+
|
|
5916
|
+
```tsx
|
|
5917
|
+
<DemoContainer>
|
|
5918
|
+
<Sidebar.Provider defaultOpen side="right" className="min-h-0! h-full">
|
|
5919
|
+
<DemoMain>
|
|
5920
|
+
<p className="text-sm">Sidebar on the right</p>
|
|
5921
|
+
</DemoMain>
|
|
5922
|
+
<Sidebar>
|
|
5923
|
+
<Sidebar.Content>
|
|
5924
|
+
<Sidebar.Group>
|
|
5925
|
+
<Sidebar.GroupLabel>Details</Sidebar.GroupLabel>
|
|
5926
|
+
<Sidebar.Menu>
|
|
5927
|
+
<Sidebar.MenuButton icon={GearIcon} active>
|
|
5928
|
+
Properties
|
|
5929
|
+
</Sidebar.MenuButton>
|
|
5930
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5931
|
+
Metrics
|
|
5932
|
+
</Sidebar.MenuButton>
|
|
5933
|
+
<Sidebar.MenuButton icon={BellIcon}>Alerts</Sidebar.MenuButton>
|
|
5934
|
+
</Sidebar.Menu>
|
|
5935
|
+
</Sidebar.Group>
|
|
5936
|
+
</Sidebar.Content>
|
|
5937
|
+
</Sidebar>
|
|
5938
|
+
</Sidebar.Provider>
|
|
5939
|
+
</DemoContainer>
|
|
5940
|
+
```
|
|
5941
|
+
|
|
5942
|
+
|
|
2460
5943
|
---
|
|
2461
5944
|
|
|
2462
5945
|
### SignalFlareAILogo
|
|
@@ -2732,6 +6215,128 @@ SignalFlare AI logo component.
|
|
|
2732
6215
|
|
|
2733
6216
|
`bg-sf-base`, `ring-sf-line`, `text-sf-default`
|
|
2734
6217
|
|
|
6218
|
+
**Examples:**
|
|
6219
|
+
|
|
6220
|
+
```tsx
|
|
6221
|
+
<SignalFlareAILogo className="w-72" />
|
|
6222
|
+
```
|
|
6223
|
+
|
|
6224
|
+
```tsx
|
|
6225
|
+
<SignalFlareAILogo variant="glyph" className="w-16" />
|
|
6226
|
+
```
|
|
6227
|
+
|
|
6228
|
+
```tsx
|
|
6229
|
+
<div className="flex flex-wrap items-center gap-8">
|
|
6230
|
+
<SignalFlareAILogo className="w-32" color="brand" />
|
|
6231
|
+
<SignalFlareAILogo className="w-32" color="mono" />
|
|
6232
|
+
<div className="rounded-lg bg-white p-4">
|
|
6233
|
+
<SignalFlareAILogo className="w-32" color="black" />
|
|
6234
|
+
</div>
|
|
6235
|
+
<div className="rounded-lg bg-black p-4">
|
|
6236
|
+
<SignalFlareAILogo className="w-32" color="white" />
|
|
6237
|
+
</div>
|
|
6238
|
+
</div>
|
|
6239
|
+
```
|
|
6240
|
+
|
|
6241
|
+
```tsx
|
|
6242
|
+
<div className="flex flex-wrap items-center gap-8">
|
|
6243
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="brand" />
|
|
6244
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="mono" />
|
|
6245
|
+
<div className="rounded-lg bg-white p-4">
|
|
6246
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="black" />
|
|
6247
|
+
</div>
|
|
6248
|
+
<div className="rounded-lg bg-black p-4">
|
|
6249
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="white" />
|
|
6250
|
+
</div>
|
|
6251
|
+
</div>
|
|
6252
|
+
```
|
|
6253
|
+
|
|
6254
|
+
```tsx
|
|
6255
|
+
<div className="flex flex-wrap items-end gap-6">
|
|
6256
|
+
<SignalFlareAILogo className="w-24" />
|
|
6257
|
+
<SignalFlareAILogo className="w-36" />
|
|
6258
|
+
<SignalFlareAILogo className="w-52" />
|
|
6259
|
+
</div>
|
|
6260
|
+
```
|
|
6261
|
+
|
|
6262
|
+
```tsx
|
|
6263
|
+
<div className="flex items-center gap-4">
|
|
6264
|
+
<DropdownMenu>
|
|
6265
|
+
<DropdownMenu.Trigger>
|
|
6266
|
+
<button
|
|
6267
|
+
type="button"
|
|
6268
|
+
className="flex items-center gap-2 rounded-lg bg-[#4188ff] px-4 py-3 text-white transition-opacity hover:opacity-80"
|
|
6269
|
+
>
|
|
6270
|
+
<SignalFlareAILogo variant="glyph" color="white" className="w-6" />
|
|
6271
|
+
<span className="font-medium">Logo</span>
|
|
6272
|
+
</button>
|
|
6273
|
+
</DropdownMenu.Trigger>
|
|
6274
|
+
<DropdownMenu.Content>
|
|
6275
|
+
<DropdownMenu.Item
|
|
6276
|
+
icon={MapPinIcon}
|
|
6277
|
+
onSelect={() =>
|
|
6278
|
+
copyToClipboard(
|
|
6279
|
+
generateSignalFlareAILogoSvg({ variant: "glyph" }),
|
|
6280
|
+
"glyph"
|
|
6281
|
+
)
|
|
6282
|
+
}
|
|
6283
|
+
>
|
|
6284
|
+
{copied === "glyph" ? "Copied!" : "Copy icon as SVG"}
|
|
6285
|
+
</DropdownMenu.Item>
|
|
6286
|
+
<DropdownMenu.Item
|
|
6287
|
+
icon={CodeIcon}
|
|
6288
|
+
onSelect={() =>
|
|
6289
|
+
copyToClipboard(
|
|
6290
|
+
generateSignalFlareAILogoSvg({ variant: "full" }),
|
|
6291
|
+
"full"
|
|
6292
|
+
)
|
|
6293
|
+
}
|
|
6294
|
+
>
|
|
6295
|
+
{copied === "full" ? "Copied!" : "Copy full logo as SVG"}
|
|
6296
|
+
</DropdownMenu.Item>
|
|
6297
|
+
<DropdownMenu.Separator />
|
|
6298
|
+
<DropdownMenu.Item
|
|
6299
|
+
icon={ArrowSquareOutIcon}
|
|
6300
|
+
onSelect={() =>
|
|
6301
|
+
window.open("https://signalflare.ai", "_blank", "noopener")
|
|
6302
|
+
}
|
|
6303
|
+
>
|
|
6304
|
+
Visit SignalFlare AI
|
|
6305
|
+
</DropdownMenu.Item>
|
|
6306
|
+
</DropdownMenu.Content>
|
|
6307
|
+
</DropdownMenu>
|
|
6308
|
+
|
|
6309
|
+
<span className="text-sm text-sf-subtle">
|
|
6310
|
+
Click to open the brand assets menu
|
|
6311
|
+
</span>
|
|
6312
|
+
</div>
|
|
6313
|
+
```
|
|
6314
|
+
|
|
6315
|
+
```tsx
|
|
6316
|
+
<PoweredBySignalFlareAI />
|
|
6317
|
+
```
|
|
6318
|
+
|
|
6319
|
+
```tsx
|
|
6320
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
6321
|
+
<PoweredBySignalFlareAI color="brand" />
|
|
6322
|
+
<PoweredBySignalFlareAI color="mono" />
|
|
6323
|
+
<PoweredBySignalFlareAI color="black" />
|
|
6324
|
+
<div className="rounded-lg bg-black p-3">
|
|
6325
|
+
<PoweredBySignalFlareAI color="white" />
|
|
6326
|
+
</div>
|
|
6327
|
+
</div>
|
|
6328
|
+
```
|
|
6329
|
+
|
|
6330
|
+
```tsx
|
|
6331
|
+
<footer className="flex w-full items-center justify-between rounded-lg border border-sf-line bg-sf-elevated px-6 py-4">
|
|
6332
|
+
<span className="text-sm text-sf-subtle">
|
|
6333
|
+
© 2026 Your Company. All rights reserved.
|
|
6334
|
+
</span>
|
|
6335
|
+
<PoweredBySignalFlareAI />
|
|
6336
|
+
</footer>
|
|
6337
|
+
```
|
|
6338
|
+
|
|
6339
|
+
|
|
2735
6340
|
---
|
|
2736
6341
|
|
|
2737
6342
|
### Sparkline
|
|
@@ -2751,11 +6356,27 @@ Sparkline — a tiny inline chart intended for embedding in cards, tables, or ro
|
|
|
2751
6356
|
- `children`: ReactNode
|
|
2752
6357
|
Child elements
|
|
2753
6358
|
|
|
6359
|
+
**Examples:**
|
|
6360
|
+
|
|
6361
|
+
```tsx
|
|
6362
|
+
<Sparkline echarts={echarts} data={sample} isDarkMode={isDarkMode} />
|
|
6363
|
+
```
|
|
6364
|
+
|
|
6365
|
+
```tsx
|
|
6366
|
+
<Sparkline
|
|
6367
|
+
echarts={echarts}
|
|
6368
|
+
data={sample}
|
|
6369
|
+
variant="area"
|
|
6370
|
+
isDarkMode={isDarkMode}
|
|
6371
|
+
/>
|
|
6372
|
+
```
|
|
6373
|
+
|
|
6374
|
+
|
|
2754
6375
|
---
|
|
2755
6376
|
|
|
2756
6377
|
### StatCard
|
|
2757
6378
|
|
|
2758
|
-
StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline.
|
|
6379
|
+
StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline. Uses pretext-driven `Text` for consistent spacing and wrapping: - Labels use `wrap="balance"` for even multiline breaks - Values use `wrap="shrink"` so sparklines tuck tight against numbers - Hints use `wrap="natural"` (numeric content rarely wraps)
|
|
2759
6380
|
|
|
2760
6381
|
**Type:** component
|
|
2761
6382
|
|
|
@@ -2786,6 +6407,25 @@ StatCard — compact KPI tile displaying a label, a primary value, and an option
|
|
|
2786
6407
|
|
|
2787
6408
|
`bg-sf-elevated`, `bg-sf-fill`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
|
|
2788
6409
|
|
|
6410
|
+
**Examples:**
|
|
6411
|
+
|
|
6412
|
+
```tsx
|
|
6413
|
+
<StatCard
|
|
6414
|
+
label="Active users"
|
|
6415
|
+
value="12,384"
|
|
6416
|
+
delta={{ value: 0.12, label: "vs last week" }}
|
|
6417
|
+
/>
|
|
6418
|
+
```
|
|
6419
|
+
|
|
6420
|
+
```tsx
|
|
6421
|
+
<StatCard size="sm" label="MRR" value="$128,420" hint="30-day avg" />
|
|
6422
|
+
```
|
|
6423
|
+
|
|
6424
|
+
```tsx
|
|
6425
|
+
<StatCard label="Signups" value="—" loading />
|
|
6426
|
+
```
|
|
6427
|
+
|
|
6428
|
+
|
|
2789
6429
|
---
|
|
2790
6430
|
|
|
2791
6431
|
### Surface
|
|
@@ -2811,6 +6451,45 @@ Surface component
|
|
|
2811
6451
|
|
|
2812
6452
|
`bg-sf-base`, `ring-sf-line`
|
|
2813
6453
|
|
|
6454
|
+
**Examples:**
|
|
6455
|
+
|
|
6456
|
+
```tsx
|
|
6457
|
+
<Surface className="rounded-lg p-6">
|
|
6458
|
+
<Text size="lg" bold>
|
|
6459
|
+
Surface Component
|
|
6460
|
+
</Text>
|
|
6461
|
+
<div className="mt-2">
|
|
6462
|
+
<Text variant="secondary">
|
|
6463
|
+
A container with consistent elevation and border styling.
|
|
6464
|
+
</Text>
|
|
6465
|
+
</div>
|
|
6466
|
+
</Surface>
|
|
6467
|
+
```
|
|
6468
|
+
|
|
6469
|
+
```tsx
|
|
6470
|
+
<div className="flex flex-col gap-4">
|
|
6471
|
+
<Surface as="section" className="rounded-lg p-4">
|
|
6472
|
+
<Text bold>As section element</Text>
|
|
6473
|
+
</Surface>
|
|
6474
|
+
<Surface as="article" className="rounded-lg p-4">
|
|
6475
|
+
<Text bold>As article element</Text>
|
|
6476
|
+
</Surface>
|
|
6477
|
+
<Surface as="aside" className="rounded-lg p-4">
|
|
6478
|
+
<Text bold>As aside element</Text>
|
|
6479
|
+
</Surface>
|
|
6480
|
+
</div>
|
|
6481
|
+
```
|
|
6482
|
+
|
|
6483
|
+
```tsx
|
|
6484
|
+
<Surface className="rounded-lg p-6">
|
|
6485
|
+
<Text bold>Outer Surface</Text>
|
|
6486
|
+
<Surface className="mt-4 rounded-md bg-sf-elevated p-4">
|
|
6487
|
+
<Text variant="secondary">Nested Surface</Text>
|
|
6488
|
+
</Surface>
|
|
6489
|
+
</Surface>
|
|
6490
|
+
```
|
|
6491
|
+
|
|
6492
|
+
|
|
2814
6493
|
---
|
|
2815
6494
|
|
|
2816
6495
|
### Switch
|
|
@@ -2870,7 +6549,6 @@ Item sub-component
|
|
|
2870
6549
|
Group sub-component
|
|
2871
6550
|
|
|
2872
6551
|
Props:
|
|
2873
|
-
|
|
2874
6552
|
- `legend`: string (required)
|
|
2875
6553
|
- `children`: ReactNode (required)
|
|
2876
6554
|
- `error`: string
|
|
@@ -2879,11 +6557,23 @@ Props:
|
|
|
2879
6557
|
- `controlFirst`: boolean
|
|
2880
6558
|
- `className`: string
|
|
2881
6559
|
|
|
6560
|
+
|
|
6561
|
+
**Examples:**
|
|
6562
|
+
|
|
6563
|
+
```tsx
|
|
6564
|
+
<Switch label="Switch" checked={checked} onCheckedChange={setChecked} />
|
|
6565
|
+
```
|
|
6566
|
+
|
|
6567
|
+
```tsx
|
|
6568
|
+
<Switch label="Disabled" checked={false} disabled />
|
|
6569
|
+
```
|
|
6570
|
+
|
|
6571
|
+
|
|
2882
6572
|
---
|
|
2883
6573
|
|
|
2884
6574
|
### Table
|
|
2885
6575
|
|
|
2886
|
-
Table — semantic HTML table with styled rows, cells, and selection support.
|
|
6576
|
+
Table — semantic HTML table with styled rows, cells, and selection support. Compound component: `Table` (Root), `.Header`, `.Head`, `.Body`, `.Row`, `.Cell`, `.Footer`, `.CheckCell`, `.CheckHead`, `.ResizeHandle`.
|
|
2887
6577
|
|
|
2888
6578
|
**Type:** component
|
|
2889
6579
|
|
|
@@ -2948,6 +6638,236 @@ Footer sub-component
|
|
|
2948
6638
|
|
|
2949
6639
|
ResizeHandle sub-component
|
|
2950
6640
|
|
|
6641
|
+
|
|
6642
|
+
**Examples:**
|
|
6643
|
+
|
|
6644
|
+
```tsx
|
|
6645
|
+
<LayerCard>
|
|
6646
|
+
<LayerCard.Primary className="p-0">
|
|
6647
|
+
<Table>
|
|
6648
|
+
<Table.Header>
|
|
6649
|
+
<Table.Row>
|
|
6650
|
+
<Table.Head>Subject</Table.Head>
|
|
6651
|
+
<Table.Head>From</Table.Head>
|
|
6652
|
+
<Table.Head>Date</Table.Head>
|
|
6653
|
+
</Table.Row>
|
|
6654
|
+
</Table.Header>
|
|
6655
|
+
<Table.Body>
|
|
6656
|
+
{emailData.slice(0, 3).map((row) => (
|
|
6657
|
+
<Table.Row key={row.id}>
|
|
6658
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6659
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6660
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6661
|
+
</Table.Row>
|
|
6662
|
+
))}
|
|
6663
|
+
</Table.Body>
|
|
6664
|
+
</Table>
|
|
6665
|
+
</LayerCard.Primary>
|
|
6666
|
+
</LayerCard>
|
|
6667
|
+
```
|
|
6668
|
+
|
|
6669
|
+
```tsx
|
|
6670
|
+
<LayerCard>
|
|
6671
|
+
<LayerCard.Primary className="p-0">
|
|
6672
|
+
<Table>
|
|
6673
|
+
<Table.Header>
|
|
6674
|
+
<Table.Row>
|
|
6675
|
+
<Table.CheckHead
|
|
6676
|
+
checked={selectedIds.size === rows.length}
|
|
6677
|
+
indeterminate={
|
|
6678
|
+
selectedIds.size > 0 && selectedIds.size < rows.length
|
|
6679
|
+
}
|
|
6680
|
+
onValueChange={toggleAll}
|
|
6681
|
+
aria-label="Select all rows"
|
|
6682
|
+
/>
|
|
6683
|
+
<Table.Head>Subject</Table.Head>
|
|
6684
|
+
<Table.Head>From</Table.Head>
|
|
6685
|
+
<Table.Head>Date</Table.Head>
|
|
6686
|
+
</Table.Row>
|
|
6687
|
+
</Table.Header>
|
|
6688
|
+
<Table.Body>
|
|
6689
|
+
{rows.map((row) => (
|
|
6690
|
+
<Table.Row key={row.id}>
|
|
6691
|
+
<Table.CheckCell
|
|
6692
|
+
checked={selectedIds.has(row.id)}
|
|
6693
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6694
|
+
aria-label={`Select ${row.subject}`}
|
|
6695
|
+
/>
|
|
6696
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6697
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6698
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6699
|
+
</Table.Row>
|
|
6700
|
+
))}
|
|
6701
|
+
</Table.Body>
|
|
6702
|
+
</Table>
|
|
6703
|
+
</LayerCard.Primary>
|
|
6704
|
+
</LayerCard>
|
|
6705
|
+
```
|
|
6706
|
+
|
|
6707
|
+
```tsx
|
|
6708
|
+
<LayerCard>
|
|
6709
|
+
<LayerCard.Primary className="p-0">
|
|
6710
|
+
<Table>
|
|
6711
|
+
<Table.Header>
|
|
6712
|
+
<Table.Row>
|
|
6713
|
+
<Table.CheckHead
|
|
6714
|
+
checked={selectedIds.size === rows.length}
|
|
6715
|
+
indeterminate={
|
|
6716
|
+
selectedIds.size > 0 && selectedIds.size < rows.length
|
|
6717
|
+
}
|
|
6718
|
+
onValueChange={toggleAll}
|
|
6719
|
+
aria-label="Select all rows"
|
|
6720
|
+
/>
|
|
6721
|
+
<Table.Head>Subject</Table.Head>
|
|
6722
|
+
<Table.Head>From</Table.Head>
|
|
6723
|
+
<Table.Head>Date</Table.Head>
|
|
6724
|
+
</Table.Row>
|
|
6725
|
+
</Table.Header>
|
|
6726
|
+
<Table.Body>
|
|
6727
|
+
{rows.map((row) => (
|
|
6728
|
+
<Table.Row
|
|
6729
|
+
key={row.id}
|
|
6730
|
+
variant={selectedIds.has(row.id) ? "selected" : "default"}
|
|
6731
|
+
>
|
|
6732
|
+
<Table.CheckCell
|
|
6733
|
+
checked={selectedIds.has(row.id)}
|
|
6734
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6735
|
+
aria-label={`Select ${row.subject}`}
|
|
6736
|
+
/>
|
|
6737
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6738
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6739
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6740
|
+
</Table.Row>
|
|
6741
|
+
))}
|
|
6742
|
+
</Table.Body>
|
|
6743
|
+
</Table>
|
|
6744
|
+
</LayerCard.Primary>
|
|
6745
|
+
</LayerCard>
|
|
6746
|
+
```
|
|
6747
|
+
|
|
6748
|
+
```tsx
|
|
6749
|
+
<LayerCard>
|
|
6750
|
+
<LayerCard.Primary className="p-0">
|
|
6751
|
+
<Table layout="fixed">
|
|
6752
|
+
<colgroup>
|
|
6753
|
+
<col />
|
|
6754
|
+
<col className="w-[150px]" />
|
|
6755
|
+
<col className="w-[150px]" />
|
|
6756
|
+
</colgroup>
|
|
6757
|
+
<Table.Header>
|
|
6758
|
+
<Table.Row>
|
|
6759
|
+
<Table.Head>Subject</Table.Head>
|
|
6760
|
+
<Table.Head>From</Table.Head>
|
|
6761
|
+
<Table.Head>Date</Table.Head>
|
|
6762
|
+
</Table.Row>
|
|
6763
|
+
</Table.Header>
|
|
6764
|
+
<Table.Body>
|
|
6765
|
+
{emailData.map((row) => (
|
|
6766
|
+
<Table.Row key={row.id}>
|
|
6767
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6768
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6769
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6770
|
+
</Table.Row>
|
|
6771
|
+
))}
|
|
6772
|
+
</Table.Body>
|
|
6773
|
+
</Table>
|
|
6774
|
+
</LayerCard.Primary>
|
|
6775
|
+
</LayerCard>
|
|
6776
|
+
```
|
|
6777
|
+
|
|
6778
|
+
```tsx
|
|
6779
|
+
<LayerCard>
|
|
6780
|
+
<LayerCard.Primary className="w-full overflow-x-auto p-0">
|
|
6781
|
+
<Table layout="fixed">
|
|
6782
|
+
<colgroup>
|
|
6783
|
+
<col />{" "}
|
|
6784
|
+
{/* Checkbox column - width handled by Table.CheckHead/CheckCell */}
|
|
6785
|
+
<col />
|
|
6786
|
+
<col style={{ width: "150px" }} />
|
|
6787
|
+
<col style={{ width: "120px" }} />
|
|
6788
|
+
<col style={{ width: "50px" }} />
|
|
6789
|
+
</colgroup>
|
|
6790
|
+
<Table.Header>
|
|
6791
|
+
<Table.Row>
|
|
6792
|
+
<Table.CheckHead
|
|
6793
|
+
checked={selectedIds.size === emailData.length}
|
|
6794
|
+
indeterminate={
|
|
6795
|
+
selectedIds.size > 0 && selectedIds.size < emailData.length
|
|
6796
|
+
}
|
|
6797
|
+
onValueChange={toggleAll}
|
|
6798
|
+
aria-label="Select all rows"
|
|
6799
|
+
/>
|
|
6800
|
+
<Table.Head>Subject</Table.Head>
|
|
6801
|
+
<Table.Head>From</Table.Head>
|
|
6802
|
+
<Table.Head>Date</Table.Head>
|
|
6803
|
+
<Table.Head />
|
|
6804
|
+
</Table.Row>
|
|
6805
|
+
</Table.Header>
|
|
6806
|
+
<Table.Body>
|
|
6807
|
+
{emailData.map((row) => (
|
|
6808
|
+
<Table.Row
|
|
6809
|
+
key={row.id}
|
|
6810
|
+
variant={selectedIds.has(row.id) ? "selected" : "default"}
|
|
6811
|
+
>
|
|
6812
|
+
<Table.CheckCell
|
|
6813
|
+
checked={selectedIds.has(row.id)}
|
|
6814
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6815
|
+
aria-label={`Select ${row.subject}`}
|
|
6816
|
+
/>
|
|
6817
|
+
<Table.Cell>
|
|
6818
|
+
<div className="flex items-center gap-2">
|
|
6819
|
+
<EnvelopeSimpleIcon size={16} />
|
|
6820
|
+
<span className="truncate">{row.subject}</span>
|
|
6821
|
+
{row.tags && (
|
|
6822
|
+
<div className="ml-2 inline-flex gap-1">
|
|
6823
|
+
{row.tags.map((tag) => (
|
|
6824
|
+
<Badge key={tag}>{tag}</Badge>
|
|
6825
|
+
))}
|
|
6826
|
+
</div>
|
|
6827
|
+
)}
|
|
6828
|
+
</div>
|
|
6829
|
+
</Table.Cell>
|
|
6830
|
+
<Table.Cell>
|
|
6831
|
+
<span className="truncate">{row.from}</span>
|
|
6832
|
+
</Table.Cell>
|
|
6833
|
+
<Table.Cell>
|
|
6834
|
+
<span className="truncate">{row.date}</span>
|
|
6835
|
+
</Table.Cell>
|
|
6836
|
+
<Table.Cell className="text-right">
|
|
6837
|
+
<DropdownMenu>
|
|
6838
|
+
<DropdownMenu.Trigger
|
|
6839
|
+
render={
|
|
6840
|
+
<Button
|
|
6841
|
+
variant="ghost"
|
|
6842
|
+
size="sm"
|
|
6843
|
+
shape="square"
|
|
6844
|
+
aria-label="More options"
|
|
6845
|
+
>
|
|
6846
|
+
<DotsThreeIcon weight="bold" size={16} />
|
|
6847
|
+
</Button>
|
|
6848
|
+
}
|
|
6849
|
+
/>
|
|
6850
|
+
<DropdownMenu.Content>
|
|
6851
|
+
<DropdownMenu.Item icon={EyeIcon}>View</DropdownMenu.Item>
|
|
6852
|
+
<DropdownMenu.Item icon={PencilSimpleIcon}>
|
|
6853
|
+
Edit
|
|
6854
|
+
</DropdownMenu.Item>
|
|
6855
|
+
<DropdownMenu.Separator />
|
|
6856
|
+
<DropdownMenu.Item icon={TrashIcon} variant="danger">
|
|
6857
|
+
Delete
|
|
6858
|
+
</DropdownMenu.Item>
|
|
6859
|
+
</DropdownMenu.Content>
|
|
6860
|
+
</DropdownMenu>
|
|
6861
|
+
</Table.Cell>
|
|
6862
|
+
</Table.Row>
|
|
6863
|
+
))}
|
|
6864
|
+
</Table.Body>
|
|
6865
|
+
</Table>
|
|
6866
|
+
</LayerCard.Primary>
|
|
6867
|
+
</LayerCard>
|
|
6868
|
+
```
|
|
6869
|
+
|
|
6870
|
+
|
|
2951
6871
|
---
|
|
2952
6872
|
|
|
2953
6873
|
### Tabs
|
|
@@ -2990,6 +6910,116 @@ Tab navigation component with segmented, underline, or pill style. Built on Base
|
|
|
2990
6910
|
|
|
2991
6911
|
**Styling:**
|
|
2992
6912
|
|
|
6913
|
+
|
|
6914
|
+
**Examples:**
|
|
6915
|
+
|
|
6916
|
+
```tsx
|
|
6917
|
+
<div className="flex flex-col gap-6">
|
|
6918
|
+
<div>
|
|
6919
|
+
<p className="mb-2 text-sm text-sf-subtle">Segmented (default)</p>
|
|
6920
|
+
<Tabs
|
|
6921
|
+
variant="segmented"
|
|
6922
|
+
tabs={[
|
|
6923
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6924
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6925
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6926
|
+
]}
|
|
6927
|
+
selectedValue="tab1"
|
|
6928
|
+
/>
|
|
6929
|
+
</div>
|
|
6930
|
+
<div>
|
|
6931
|
+
<p className="mb-2 text-sm text-sf-subtle">Underline</p>
|
|
6932
|
+
<Tabs
|
|
6933
|
+
variant="underline"
|
|
6934
|
+
tabs={[
|
|
6935
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6936
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6937
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6938
|
+
]}
|
|
6939
|
+
selectedValue="tab1"
|
|
6940
|
+
/>
|
|
6941
|
+
</div>
|
|
6942
|
+
<div>
|
|
6943
|
+
<p className="mb-2 text-sm text-sf-subtle">Pill</p>
|
|
6944
|
+
<Tabs
|
|
6945
|
+
variant="pill"
|
|
6946
|
+
tabs={[
|
|
6947
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6948
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6949
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6950
|
+
]}
|
|
6951
|
+
selectedValue="tab1"
|
|
6952
|
+
/>
|
|
6953
|
+
</div>
|
|
6954
|
+
</div>
|
|
6955
|
+
```
|
|
6956
|
+
|
|
6957
|
+
```tsx
|
|
6958
|
+
<Tabs
|
|
6959
|
+
variant="segmented"
|
|
6960
|
+
tabs={[
|
|
6961
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6962
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6963
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6964
|
+
]}
|
|
6965
|
+
selectedValue="tab1"
|
|
6966
|
+
/>
|
|
6967
|
+
```
|
|
6968
|
+
|
|
6969
|
+
```tsx
|
|
6970
|
+
<div className="space-y-4">
|
|
6971
|
+
<Tabs
|
|
6972
|
+
tabs={[
|
|
6973
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6974
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6975
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6976
|
+
]}
|
|
6977
|
+
value={activeTab}
|
|
6978
|
+
onValueChange={setActiveTab}
|
|
6979
|
+
/>
|
|
6980
|
+
<p className="text-sm text-sf-subtle">
|
|
6981
|
+
Active tab: <code className="text-sm">{activeTab}</code>
|
|
6982
|
+
</p>
|
|
6983
|
+
</div>
|
|
6984
|
+
```
|
|
6985
|
+
|
|
6986
|
+
```tsx
|
|
6987
|
+
<Tabs
|
|
6988
|
+
tabs={[
|
|
6989
|
+
{ label: "Overview", value: "overview" },
|
|
6990
|
+
{ label: "Analytics", value: "analytics" },
|
|
6991
|
+
{ label: "Reports", value: "reports" },
|
|
6992
|
+
{ label: "Notifications", value: "notifications" },
|
|
6993
|
+
{ label: "Settings", value: "settings" },
|
|
6994
|
+
{ label: "Billing", value: "billing" },
|
|
6995
|
+
]}
|
|
6996
|
+
selectedValue="overview"
|
|
6997
|
+
/>
|
|
6998
|
+
```
|
|
6999
|
+
|
|
7000
|
+
```tsx
|
|
7001
|
+
<Tabs
|
|
7002
|
+
tabs={[
|
|
7003
|
+
{
|
|
7004
|
+
label: "Regular Tab",
|
|
7005
|
+
value: "tab1",
|
|
7006
|
+
},
|
|
7007
|
+
{
|
|
7008
|
+
label: "Link Tab",
|
|
7009
|
+
render: (props) => <a {...props} href="#tab2" />,
|
|
7010
|
+
value: "tab2",
|
|
7011
|
+
},
|
|
7012
|
+
{
|
|
7013
|
+
label: "Another Link",
|
|
7014
|
+
render: (props) => <a {...props} href="#tab3" />,
|
|
7015
|
+
value: "tab3",
|
|
7016
|
+
},
|
|
7017
|
+
]}
|
|
7018
|
+
selectedValue="tab1"
|
|
7019
|
+
/>
|
|
7020
|
+
```
|
|
7021
|
+
|
|
7022
|
+
|
|
2993
7023
|
---
|
|
2994
7024
|
|
|
2995
7025
|
### Text
|
|
@@ -3025,6 +7055,14 @@ Text component
|
|
|
3025
7055
|
The HTML element type to render as (e.g. `"span"`, `"p"`, `"h1"`). Auto-selected based on variant if omitted.
|
|
3026
7056
|
- `children`: ReactNode
|
|
3027
7057
|
Text content.
|
|
7058
|
+
- `wrap`: MeasuredTextMode | boolean
|
|
7059
|
+
Text layout strategy using pretext-driven measurement.
|
|
7060
|
+
- `"natural"` — No measurement, normal browser wrapping (default for body).
|
|
7061
|
+
- `"balance"` — Even wrapping, smallest maxWidth without adding lines (default for headings).
|
|
7062
|
+
- `"shrink"` — Hug widest natural line (maxWidth = line width). Good for chat bubbles.
|
|
7063
|
+
- `"reserve"` — Reserve height based on line count. Good for streaming text.
|
|
7064
|
+
- `reserveLines`: number
|
|
7065
|
+
For `wrap="reserve"`: reserve this many lines of height. If omitted, measures current content to determine line count.
|
|
3028
7066
|
|
|
3029
7067
|
**Colors (sf tokens used):**
|
|
3030
7068
|
|
|
@@ -3032,11 +7070,78 @@ Text component
|
|
|
3032
7070
|
|
|
3033
7071
|
**Styling:**
|
|
3034
7072
|
|
|
7073
|
+
|
|
7074
|
+
**Examples:**
|
|
7075
|
+
|
|
7076
|
+
```tsx
|
|
7077
|
+
<div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
7078
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7079
|
+
<Text variant="heading1">Heading 1</Text>
|
|
7080
|
+
<p className="font-mono text-xs text-sf-subtle">text-3xl (30px)</p>
|
|
7081
|
+
</div>
|
|
7082
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7083
|
+
<Text variant="heading2">Heading 2</Text>
|
|
7084
|
+
<p className="font-mono text-xs text-sf-subtle">text-2xl (24px)</p>
|
|
7085
|
+
</div>
|
|
7086
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7087
|
+
<Text variant="heading3">Heading 3</Text>
|
|
7088
|
+
<p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
|
|
7089
|
+
</div>
|
|
7090
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7091
|
+
<Text>Body</Text>
|
|
7092
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7093
|
+
</div>
|
|
7094
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7095
|
+
<Text bold>Body bold</Text>
|
|
7096
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7097
|
+
</div>
|
|
7098
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7099
|
+
<Text size="lg">Body lg</Text>
|
|
7100
|
+
<p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
|
|
7101
|
+
</div>
|
|
7102
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7103
|
+
<Text size="sm">Body sm</Text>
|
|
7104
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7105
|
+
</div>
|
|
7106
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7107
|
+
<Text size="xs">Body xs</Text>
|
|
7108
|
+
<p className="font-mono text-xs text-sf-subtle">text-xs (12px)</p>
|
|
7109
|
+
</div>
|
|
7110
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7111
|
+
<Text variant="secondary">Body secondary</Text>
|
|
7112
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7113
|
+
</div>
|
|
7114
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7115
|
+
<Text variant="mono">Monospace</Text>
|
|
7116
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7117
|
+
</div>
|
|
7118
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7119
|
+
<Text variant="mono" size="lg">
|
|
7120
|
+
Monospace lg
|
|
7121
|
+
</Text>
|
|
7122
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7123
|
+
</div>
|
|
7124
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7125
|
+
<Text variant="mono-secondary">Monospace secondary</Text>
|
|
7126
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7127
|
+
</div>
|
|
7128
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7129
|
+
<Text variant="success">Success</Text>
|
|
7130
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7131
|
+
</div>
|
|
7132
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7133
|
+
<Text variant="error">Error</Text>
|
|
7134
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7135
|
+
</div>
|
|
7136
|
+
</div>
|
|
7137
|
+
```
|
|
7138
|
+
|
|
7139
|
+
|
|
3035
7140
|
---
|
|
3036
7141
|
|
|
3037
7142
|
### TextRoll
|
|
3038
7143
|
|
|
3039
|
-
Letter-by-letter roll animation. Each character flips on the X axis: the current letter rolls up and out, the new letter rolls in from below. Good for title changes (e.g. a streaming activity group swapping its current-step label) where the text content is short and the change should register visually.
|
|
7144
|
+
Letter-by-letter roll animation. Each character flips on the X axis: the current letter rolls up and out, the new letter rolls in from below. Good for title changes (e.g. a streaming activity group swapping its current-step label) where the text content is short and the change should register visually. Wraps the string in an `aria-hidden` visual stack with a screen-reader-only copy of the full text so a11y tools always read the real content.
|
|
3040
7145
|
|
|
3041
7146
|
**Type:** component
|
|
3042
7147
|
|
|
@@ -3065,7 +7170,7 @@ Letter-by-letter roll animation. Each character flips on the X axis: the current
|
|
|
3065
7170
|
|
|
3066
7171
|
### ThemeToggle
|
|
3067
7172
|
|
|
3068
|
-
Theme toggle button. Cycles through light → dark → system (follows OS) modes.
|
|
7173
|
+
Theme toggle button. Cycles through light → dark → system (follows OS) modes. Reads from and writes to `localStorage` under the key `"theme"`. When set to `"system"` the key is removed so the OS preference takes over automatically. Applies the resolved mode to `document.documentElement.dataset.mode`.
|
|
3069
7174
|
|
|
3070
7175
|
**Type:** component
|
|
3071
7176
|
|
|
@@ -3094,7 +7199,7 @@ Theme toggle button. Cycles through light → dark → system (follows OS) modes
|
|
|
3094
7199
|
|
|
3095
7200
|
### Toasty
|
|
3096
7201
|
|
|
3097
|
-
Toasty — toast notification provider and viewport.
|
|
7202
|
+
Toasty — toast notification provider and viewport. Renders a `Toast.Provider` with a fixed-position viewport in the bottom-right corner. Toasts stack with smooth enter/exit animations, swipe-to-dismiss, and expand-on-hover. Built on `@base-ui/react/toast`.
|
|
3098
7203
|
|
|
3099
7204
|
**Type:** component
|
|
3100
7205
|
|
|
@@ -3119,6 +7224,7 @@ Toasty — toast notification provider and viewport. Renders a `Toast.Provider`
|
|
|
3119
7224
|
|
|
3120
7225
|
**Styling:**
|
|
3121
7226
|
|
|
7227
|
+
|
|
3122
7228
|
---
|
|
3123
7229
|
|
|
3124
7230
|
### Tooltip
|
|
@@ -3149,6 +7255,34 @@ Accessible popup that shows additional information on hover/focus. Wrap your app
|
|
|
3149
7255
|
|
|
3150
7256
|
`bg-sf-elevated`, `fill-sf-elevated`, `fill-sf-tip-shadow`, `fill-sf-tip-stroke`, `outline-sf-fill`, `text-sf-default`
|
|
3151
7257
|
|
|
7258
|
+
**Examples:**
|
|
7259
|
+
|
|
7260
|
+
```tsx
|
|
7261
|
+
<TooltipProvider>
|
|
7262
|
+
<Tooltip content="Add new item">
|
|
7263
|
+
<Button shape="square" icon={PlusIcon} aria-label="Add new item" />
|
|
7264
|
+
</Tooltip>
|
|
7265
|
+
</TooltipProvider>
|
|
7266
|
+
```
|
|
7267
|
+
|
|
7268
|
+
```tsx
|
|
7269
|
+
<TooltipProvider>
|
|
7270
|
+
<div className="flex gap-2">
|
|
7271
|
+
<Tooltip content="Add">
|
|
7272
|
+
<Button shape="square" icon={PlusIcon} aria-label="Add" />
|
|
7273
|
+
</Tooltip>
|
|
7274
|
+
<Tooltip content="Change language">
|
|
7275
|
+
<Button
|
|
7276
|
+
shape="square"
|
|
7277
|
+
icon={TranslateIcon}
|
|
7278
|
+
aria-label="Change language"
|
|
7279
|
+
/>
|
|
7280
|
+
</Tooltip>
|
|
7281
|
+
</div>
|
|
7282
|
+
</TooltipProvider>
|
|
7283
|
+
```
|
|
7284
|
+
|
|
7285
|
+
|
|
3152
7286
|
---
|
|
3153
7287
|
|
|
3154
7288
|
### InputArea
|
|
@@ -3163,6 +7297,7 @@ Multi-line textarea input with Input variants and InputArea-specific dimensions
|
|
|
3163
7297
|
|
|
3164
7298
|
**Props:**
|
|
3165
7299
|
|
|
7300
|
+
|
|
3166
7301
|
**Styling:**
|
|
3167
7302
|
|
|
3168
7303
|
- **Size Variants:**
|
|
@@ -3174,7 +7309,6 @@ Multi-line textarea input with Input variants and InputArea-specific dimensions
|
|
|
3174
7309
|
## Quick Reference
|
|
3175
7310
|
|
|
3176
7311
|
**Components by Category:**
|
|
3177
|
-
|
|
3178
7312
|
- **Other:** AiActions, AiAgentCard, AiApproval, AiCodeBlock, AiConversation, AiInfoBanner, AiMessage, AiMissionHeader, AiPartGroup, AiQuestion, AiReasoning, AiResponse, AiShimmer, AiStatusBadge, AiStreamingText, AiSubagent, AiSuggestions, AiTaskList, AiTimeline, AiToolCall, AiUsageBar, DataGrid, DatePicker, Filters, Label, Link, PromptInput, SensitiveInput, Sidebar, SignalFlareAILogo, Sparkline, StatCard, Table, TextRoll, ThemeToggle, AgentHarness, Commander, DashboardGrid, DeleteResource, Map, MetricsOverview
|
|
3179
7313
|
- **Display:** Badge, Breadcrumbs, Code, Collapsible, Empty, LayerCard, Meter, Text
|
|
3180
7314
|
- **Feedback:** Banner, Loader, Toasty
|