@signalflare-ai/ui 1.1.0 → 1.3.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 +102 -5
- package/README.md +1 -1
- package/ai/component-registry.json +531 -79
- package/ai/component-registry.md +4067 -6
- package/ai/schemas.ts +6 -1
- 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-CBfz5XEf.js} +4 -4
- package/dist/{ai-actions-DSVeQn4e.js.map → ai-actions-CBfz5XEf.js.map} +1 -1
- package/dist/{ai-agent-card-BXHwhWAU.js → ai-agent-card-CByAUe0q.js} +3 -3
- package/dist/ai-agent-card-CByAUe0q.js.map +1 -0
- package/dist/{ai-approval-aa0qvjFN.js → ai-approval-Ci8N70a7.js} +4 -3
- package/dist/{ai-approval-aa0qvjFN.js.map → ai-approval-Ci8N70a7.js.map} +1 -1
- package/dist/{ai-code-block-BgtIxtZZ.js → ai-code-block-P9TJHvaC.js} +37 -39
- package/dist/ai-code-block-P9TJHvaC.js.map +1 -0
- package/dist/ai-conversation-Qslfdi1t.js +228 -0
- package/dist/ai-conversation-Qslfdi1t.js.map +1 -0
- package/dist/{ai-info-banner-uFxHHwBA.js → ai-info-banner-B_9vtGK3.js} +8 -4
- package/dist/ai-info-banner-B_9vtGK3.js.map +1 -0
- package/dist/{ai-message-BjnFznXy.js → ai-message-Ci3gwM7G.js} +29 -10
- package/dist/ai-message-Ci3gwM7G.js.map +1 -0
- package/dist/{ai-mission-header-08__gULL.js → ai-mission-header-CaBc19-t.js} +2 -2
- package/dist/{ai-mission-header-08__gULL.js.map → ai-mission-header-CaBc19-t.js.map} +1 -1
- package/dist/{ai-part-group-DBtgTgAn.js → ai-part-group-Dx1Mr92B.js} +5 -4
- package/dist/ai-part-group-Dx1Mr92B.js.map +1 -0
- package/dist/{ai-prompt-input-CuluUzpf.js → ai-prompt-input-Bm4XoSj2.js} +44 -55
- package/dist/ai-prompt-input-Bm4XoSj2.js.map +1 -0
- package/dist/{ai-question-CHHoDJMg.js → ai-question-OyJovxGe.js} +4 -3
- package/dist/{ai-question-CHHoDJMg.js.map → ai-question-OyJovxGe.js.map} +1 -1
- package/dist/{ai-reasoning-CnL6ZSr5.js → ai-reasoning-BLfBXx3F.js} +9 -5
- package/dist/ai-reasoning-BLfBXx3F.js.map +1 -0
- package/dist/{ai-response-BEUg3xvd.js → ai-response-hbVCZJmo.js} +9 -4
- package/dist/ai-response-hbVCZJmo.js.map +1 -0
- package/dist/{ai-shimmer-By5_L05p.js → ai-shimmer-BamNMNK3.js} +2 -2
- package/dist/{ai-shimmer-By5_L05p.js.map → ai-shimmer-BamNMNK3.js.map} +1 -1
- package/dist/{ai-status-badge-BGYGWYF6.js → ai-status-badge-BZLczdkI.js} +2 -2
- package/dist/{ai-status-badge-BGYGWYF6.js.map → ai-status-badge-BZLczdkI.js.map} +1 -1
- package/dist/{ai-streaming-text-CMfoThV0.js → ai-streaming-text-DgYu64UH.js} +44 -16
- package/dist/ai-streaming-text-DgYu64UH.js.map +1 -0
- package/dist/{ai-subagent-DcPRqkAA.js → ai-subagent-p97AI1h9.js} +14 -6
- package/dist/ai-subagent-p97AI1h9.js.map +1 -0
- package/dist/{ai-suggestion-MgeCg5Ar.js → ai-suggestion-Bj6vF7CT.js} +3 -3
- package/dist/{ai-suggestion-MgeCg5Ar.js.map → ai-suggestion-Bj6vF7CT.js.map} +1 -1
- package/dist/{ai-task-list-Da9zIm00.js → ai-task-list-C_UQYpk9.js} +15 -6
- package/dist/ai-task-list-C_UQYpk9.js.map +1 -0
- package/dist/{ai-timeline-Cwu045IR.js → ai-timeline-CePL1LOU.js} +3 -3
- package/dist/ai-timeline-CePL1LOU.js.map +1 -0
- package/dist/{ai-tool-Cn1O4xjP.js → ai-tool-CfRcwmHT.js} +35 -16
- package/dist/ai-tool-CfRcwmHT.js.map +1 -0
- package/dist/{ai-usage-bar-DjS12DMp.js → ai-usage-bar-45pVRCGA.js} +2 -2
- package/dist/{ai-usage-bar-DjS12DMp.js.map → ai-usage-bar-45pVRCGA.js.map} +1 -1
- package/dist/{badge-D_eaA6wv.js → badge-Beb-6uut.js} +5 -5
- package/dist/{badge-D_eaA6wv.js.map → badge-Beb-6uut.js.map} +1 -1
- package/dist/{banner-B_6oBrsu.js → banner-CCEksxPg.js} +8 -3
- package/dist/banner-CCEksxPg.js.map +1 -0
- package/dist/{breadcrumbs-BlmeYfgq.js → breadcrumbs-HiTmgaZ4.js} +5 -5
- package/dist/{breadcrumbs-BlmeYfgq.js.map → breadcrumbs-HiTmgaZ4.js.map} +1 -1
- package/dist/{button-De0267YU.js → button-BHOgXJRU.js} +4 -4
- package/dist/{button-De0267YU.js.map → button-BHOgXJRU.js.map} +1 -1
- package/dist/catalog.js +1 -1
- package/dist/catalog.js.map +1 -1
- package/dist/{chart-BK3sVPnD.js → chart-B9FfZdKs.js} +7 -7
- package/dist/chart-B9FfZdKs.js.map +1 -0
- package/dist/{checkbox-DYhUmZNw.js → checkbox-Cy_OCyay.js} +3 -3
- package/dist/{checkbox-DYhUmZNw.js.map → checkbox-Cy_OCyay.js.map} +1 -1
- package/dist/{clipboard-text-ssybngLw.js → clipboard-text-CKSvNp9L.js} +6 -5
- package/dist/clipboard-text-CKSvNp9L.js.map +1 -0
- package/dist/{cn-YROP2_ox.js → cn-CmAOpn49.js} +2 -2
- package/dist/{cn-YROP2_ox.js.map → cn-CmAOpn49.js.map} +1 -1
- package/dist/{code-Cx-QSoOT.js → code-JsQz-0G_.js} +4 -4
- package/dist/{code-Cx-QSoOT.js.map → code-JsQz-0G_.js.map} +1 -1
- package/dist/{collapsible-DWsXeXmS.js → collapsible-1kOZ-89L.js} +2 -2
- package/dist/{collapsible-DWsXeXmS.js.map → collapsible-1kOZ-89L.js.map} +1 -1
- package/dist/{combobox-C0iW6a0r.js → combobox-CQwDmqgA.js} +4 -4
- package/dist/{combobox-C0iW6a0r.js.map → combobox-CQwDmqgA.js.map} +1 -1
- package/dist/command-line/cli.js +3 -3
- package/dist/{command-palette-DGzioeki.js → command-palette-Bkuv3e6o.js} +20 -5
- package/dist/command-palette-Bkuv3e6o.js.map +1 -0
- 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/link.js +3 -3
- package/dist/components/link.js.map +1 -1
- package/dist/components/loader.js +2 -2
- 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-DDSFMHud.js} +136 -53
- package/dist/data-grid-DDSFMHud.js.map +1 -0
- package/dist/{date-picker-Dqg9L4xu.js → date-picker-O34AqG3f.js} +2 -2
- package/dist/{date-picker-Dqg9L4xu.js.map → date-picker-O34AqG3f.js.map} +1 -1
- package/dist/{date-range-picker-D75LLINc.js → date-range-picker-YKYvum_r.js} +29 -39
- package/dist/{date-range-picker-D75LLINc.js.map → date-range-picker-YKYvum_r.js.map} +1 -1
- package/dist/{dialog-CyHEQXEY.js → dialog-DYqu4aDO.js} +3 -3
- package/dist/{dialog-CyHEQXEY.js.map → dialog-DYqu4aDO.js.map} +1 -1
- package/dist/{dist-1-gcEL2L.js → dist-6AtBsaJE.js} +153 -47
- package/dist/dist-6AtBsaJE.js.map +1 -0
- package/dist/{dropdown-qnEYRFXZ.js → dropdown-XzbnRLYR.js} +15 -5
- package/dist/dropdown-XzbnRLYR.js.map +1 -0
- package/dist/{echart-DURZEyai.js → echart-DGBIVAv1.js} +23 -57
- package/dist/{echart-DURZEyai.js.map → echart-DGBIVAv1.js.map} +1 -1
- package/dist/{empty-D2TypIId.js → empty-C1tAkawe.js} +12 -7
- package/dist/empty-C1tAkawe.js.map +1 -0
- package/dist/{field-Y_UK1_Cg.js → field-DBpFzzBS.js} +3 -3
- package/dist/{field-Y_UK1_Cg.js.map → field-DBpFzzBS.js.map} +1 -1
- package/dist/{filters-Bw_U6ZTx.js → filters-SmEl93za.js} +10 -10
- package/dist/filters-SmEl93za.js.map +1 -0
- package/dist/{flow-BRsYUCJa.js → flow-BLzgbq1T.js} +6 -6
- package/dist/flow-BLzgbq1T.js.map +1 -0
- package/dist/genui.js +2 -2
- package/dist/genui.js.map +1 -1
- package/dist/{grid-qUAN9hFx.js → grid-CifjQL-5.js} +2 -2
- package/dist/{grid-qUAN9hFx.js.map → grid-CifjQL-5.js.map} +1 -1
- package/dist/{highlight-to-react-ClEfL81q.js → highlight-to-react-DN9dUCS2.js} +9 -15
- package/dist/highlight-to-react-DN9dUCS2.js.map +1 -0
- package/dist/index.js +72 -72
- package/dist/index.js.map +1 -1
- package/dist/{input-DddtBN-g.js → input-COmx2M_R.js} +5 -5
- package/dist/{input-DddtBN-g.js.map → input-COmx2M_R.js.map} +1 -1
- package/dist/{input-DXYUjGgD.js → input-GkfMQZC_.js} +3 -3
- package/dist/{input-DXYUjGgD.js.map → input-GkfMQZC_.js.map} +1 -1
- package/dist/{label-QtJxtJ4u.js → label-CiGZ464N.js} +3 -3
- package/dist/{label-QtJxtJ4u.js.map → label-CiGZ464N.js.map} +1 -1
- package/dist/{layer-card-BME0eljh.js → layer-card-8l8GuLQr.js} +2 -2
- package/dist/{layer-card-BME0eljh.js.map → layer-card-8l8GuLQr.js.map} +1 -1
- package/dist/layout-CWBE0qwx.js +6207 -0
- package/dist/layout-CWBE0qwx.js.map +1 -0
- package/dist/{link-provider-BUZKXaNE.js → link-provider-BSn8YJon.js} +2 -2
- package/dist/link-provider-BSn8YJon.js.map +1 -0
- package/dist/{loader-DAcc-Uag.js → loader-BEMz8pJO.js} +1 -1
- package/dist/{loader-DAcc-Uag.js.map → loader-BEMz8pJO.js.map} +1 -1
- package/dist/measured-text-CXkdw9Yr.js +305 -0
- package/dist/measured-text-CXkdw9Yr.js.map +1 -0
- package/dist/{menubar-C8NzAjfd.js → menubar-CoOr4ocj.js} +3 -3
- package/dist/{menubar-C8NzAjfd.js.map → menubar-CoOr4ocj.js.map} +1 -1
- package/dist/{meter-CpmTenEr.js → meter-Pf_VOl59.js} +2 -2
- package/dist/{meter-CpmTenEr.js.map → meter-Pf_VOl59.js.map} +1 -1
- package/dist/{pagination-BVqdlONY.js → pagination-DSY279Ta.js} +2 -2
- package/dist/{pagination-BVqdlONY.js.map → pagination-DSY279Ta.js.map} +1 -1
- package/dist/{popover-BRQZ2b6z.js → popover-BY-e9co1.js} +2 -2
- package/dist/{popover-BRQZ2b6z.js.map → popover-BY-e9co1.js.map} +1 -1
- package/dist/{radio-BNSwOt3B.js → radio-DZwL13j0.js} +2 -2
- package/dist/{radio-BNSwOt3B.js.map → radio-DZwL13j0.js.map} +1 -1
- package/dist/{select-1w2aebGQ.js → select-BFifYqHA.js} +6 -6
- package/dist/{select-1w2aebGQ.js.map → select-BFifYqHA.js.map} +1 -1
- package/dist/{sensitive-input-82Cez3vj.js → sensitive-input-DHLZcM73.js} +4 -4
- package/dist/{sensitive-input-82Cez3vj.js.map → sensitive-input-DHLZcM73.js.map} +1 -1
- package/dist/{sidebar-CAsCmSpM.js → sidebar-odGsdvG4.js} +6 -7
- package/dist/sidebar-odGsdvG4.js.map +1 -0
- package/dist/{signalflare-ai-logo-DDhxMJD6.js → signalflare-ai-logo-CNaDT_w8.js} +2 -2
- package/dist/{signalflare-ai-logo-DDhxMJD6.js.map → signalflare-ai-logo-CNaDT_w8.js.map} +1 -1
- package/dist/{skeleton-line-Do3UmGk9.js → skeleton-line-CxxYVTO2.js} +2 -2
- package/dist/{skeleton-line-Do3UmGk9.js.map → skeleton-line-CxxYVTO2.js.map} +1 -1
- package/dist/{sparkline-DdbeM4Ai.js → sparkline-BQ-4j2W2.js} +2 -2
- package/dist/{sparkline-DdbeM4Ai.js.map → sparkline-BQ-4j2W2.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 +40 -16
- package/dist/src/blocks/commander/commander.tsx +15 -15
- package/dist/src/blocks/map-block/map-block.d.ts.map +1 -1
- package/dist/src/blocks/map-block/map-block.tsx +11 -7
- package/dist/src/components/ai-approval/ai-approval.d.ts.map +1 -1
- package/dist/src/components/ai-code-block/ai-code-block.d.ts +14 -13
- package/dist/src/components/ai-code-block/ai-code-block.d.ts.map +1 -1
- 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-part-group/ai-part-group.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/controller.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-prompt-input/types.d.ts.map +1 -1
- package/dist/src/components/ai-question/ai-question.d.ts.map +1 -1
- package/dist/src/components/ai-reasoning/ai-reasoning.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/chart/echart.d.ts.map +1 -1
- package/dist/src/components/clipboard-text/clipboard-text.d.ts.map +1 -1
- package/dist/src/components/data-grid/data-grid.d.ts +2 -1
- package/dist/src/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/src/components/data-grid/features.d.ts +20 -0
- package/dist/src/components/data-grid/features.d.ts.map +1 -0
- package/dist/src/components/data-grid/types.d.ts +38 -7
- package/dist/src/components/data-grid/types.d.ts.map +1 -1
- package/dist/src/components/empty/empty.d.ts.map +1 -1
- package/dist/src/components/filters/filters.d.ts.map +1 -1
- package/dist/src/components/flow/use-children.d.ts +1 -1
- package/dist/src/components/link/link.d.ts.map +1 -1
- package/dist/src/components/sidebar/sidebar.d.ts +1 -1
- package/dist/src/components/signalflare-ai-logo/signalflare-ai-logo.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 +36 -1
- package/dist/src/components/text/text.d.ts.map +1 -1
- package/dist/src/components/text-roll/text-roll.d.ts.map +1 -1
- package/dist/src/components/theme-toggle/theme-toggle.d.ts.map +1 -1
- package/dist/src/components/toast/toast.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/highlight-to-react.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-Bspk4XFr.js} +30 -12
- package/dist/stat-card-Bspk4XFr.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-minimal.css +9 -9
- package/dist/styles/theme-sf.css +14 -20
- package/dist/styles/theme-vesper.css +91 -0
- package/dist/{surface-BduI7Ehl.js → surface-CWdSFVUx.js} +3 -3
- package/dist/{surface-BduI7Ehl.js.map → surface-CWdSFVUx.js.map} +1 -1
- package/dist/{switch-CzZBRBL7.js → switch-TA4cByCJ.js} +5 -5
- package/dist/switch-TA4cByCJ.js.map +1 -0
- package/dist/{table-Rv4JMy0B.js → table-BM8JBGBs.js} +3 -3
- package/dist/{table-Rv4JMy0B.js.map → table-BM8JBGBs.js.map} +1 -1
- package/dist/{tabs-1cHrYoel.js → tabs-bnH2vGLv.js} +2 -2
- package/dist/{tabs-1cHrYoel.js.map → tabs-bnH2vGLv.js.map} +1 -1
- package/dist/{text-KJmGkwnf.js → text-iQ0YUFNg.js} +27 -6
- package/dist/text-iQ0YUFNg.js.map +1 -0
- package/dist/{text-roll-BZ3I1umc.js → text-roll-C3U2jd2u.js} +5 -2
- package/dist/text-roll-C3U2jd2u.js.map +1 -0
- package/dist/{theme-toggle-Bhu681D7.js → theme-toggle-BTVxD-fD.js} +10 -9
- package/dist/theme-toggle-BTVxD-fD.js.map +1 -0
- package/dist/{toast-Nw28a5Cx.js → toast-CgZVaAkw.js} +3 -3
- package/dist/{toast-Nw28a5Cx.js.map → toast-CgZVaAkw.js.map} +1 -1
- package/dist/{tooltip-Cb7QW-7H.js → tooltip-uobk6Oh-.js} +9 -3
- package/dist/tooltip-uobk6Oh-.js.map +1 -0
- package/dist/{use-agent-harness-BMyF8pTq.js → use-agent-harness-Dl8w6X5O.js} +3 -3
- package/dist/{use-agent-harness-BMyF8pTq.js.map → use-agent-harness-Dl8w6X5O.js.map} +1 -1
- package/dist/utils.js +4 -3
- package/package.json +27 -24
- package/scripts/component-registry/discovery.ts +11 -10
- package/scripts/component-registry/example-cleanup.ts +8 -8
- package/scripts/component-registry/index.ts +6 -6
- package/scripts/component-registry/schema-generator.ts +1 -1
- package/scripts/component-registry/sub-components.ts +35 -23
- package/scripts/component-registry/utils.ts +11 -11
- package/scripts/component-registry/variant-parser.ts +17 -15
- package/scripts/convert-demos-to-stories.ts +5 -5
- package/scripts/css-build.ts +1 -1
- package/scripts/theme-generator/config.ts +28 -146
- package/scripts/theme-generator/generate-css.ts +1 -2
- package/scripts/theme-generator/index.ts +0 -1
- package/scripts/theme-generator/migrate.ts +3 -3
- package/dist/ai-agent-card-BXHwhWAU.js.map +0 -1
- package/dist/ai-code-block-BgtIxtZZ.js.map +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-part-group-DBtgTgAn.js.map +0 -1
- package/dist/ai-prompt-input-CuluUzpf.js.map +0 -1
- package/dist/ai-reasoning-CnL6ZSr5.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-timeline-Cwu045IR.js.map +0 -1
- package/dist/ai-tool-Cn1O4xjP.js.map +0 -1
- package/dist/banner-B_6oBrsu.js.map +0 -1
- package/dist/chart-BK3sVPnD.js.map +0 -1
- package/dist/clipboard-text-ssybngLw.js.map +0 -1
- package/dist/command-palette-DGzioeki.js.map +0 -1
- package/dist/data-grid-CG76N_hK.js.map +0 -1
- package/dist/dist-1-gcEL2L.js.map +0 -1
- package/dist/dropdown-qnEYRFXZ.js.map +0 -1
- package/dist/empty-D2TypIId.js.map +0 -1
- package/dist/filters-Bw_U6ZTx.js.map +0 -1
- package/dist/flow-BRsYUCJa.js.map +0 -1
- package/dist/highlight-to-react-ClEfL81q.js.map +0 -1
- package/dist/link-provider-BUZKXaNE.js.map +0 -1
- package/dist/sidebar-CAsCmSpM.js.map +0 -1
- package/dist/stat-card-CEZscNh8.js.map +0 -1
- package/dist/styles/theme-blue-tint.css +0 -98
- package/dist/switch-CzZBRBL7.js.map +0 -1
- package/dist/text-KJmGkwnf.js.map +0 -1
- package/dist/text-roll-BZ3I1umc.js.map +0 -1
- package/dist/theme-toggle-Bhu681D7.js.map +0 -1
- package/dist/tooltip-Cb7QW-7H.js.map +0 -1
package/ai/component-registry.md
CHANGED
|
@@ -26,6 +26,25 @@ 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
|
+
|
|
29
48
|
---
|
|
30
49
|
|
|
31
50
|
### AiAgentCard
|
|
@@ -75,6 +94,105 @@ Container for a row of AI message action buttons.
|
|
|
75
94
|
|
|
76
95
|
`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
96
|
|
|
97
|
+
**Examples:**
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<div className="flex flex-wrap gap-3">
|
|
101
|
+
<AiAgentCard
|
|
102
|
+
name="Explore"
|
|
103
|
+
agentType="explore"
|
|
104
|
+
status="running"
|
|
105
|
+
modelId="claude-haiku-3.5"
|
|
106
|
+
currentTask="Scanning auth files for deprecated patterns..."
|
|
107
|
+
duration={4200}
|
|
108
|
+
toolCallCount={3}
|
|
109
|
+
/>
|
|
110
|
+
<AiAgentCard
|
|
111
|
+
name="Execute"
|
|
112
|
+
agentType="execute"
|
|
113
|
+
status="running"
|
|
114
|
+
modelId="claude-sonnet-4"
|
|
115
|
+
currentTask="Rewriting jwt.ts using jose library..."
|
|
116
|
+
duration={8700}
|
|
117
|
+
toolCallCount={1}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<div className="flex flex-wrap gap-3">
|
|
124
|
+
<AiAgentCard
|
|
125
|
+
name="Explore"
|
|
126
|
+
agentType="explore"
|
|
127
|
+
status="idle"
|
|
128
|
+
modelId="claude-haiku-3.5"
|
|
129
|
+
/>
|
|
130
|
+
<AiAgentCard
|
|
131
|
+
name="Plan"
|
|
132
|
+
agentType="plan"
|
|
133
|
+
status="running"
|
|
134
|
+
modelId="claude-sonnet-4"
|
|
135
|
+
currentTask="Drafting migration steps..."
|
|
136
|
+
duration={2100}
|
|
137
|
+
toolCallCount={0}
|
|
138
|
+
/>
|
|
139
|
+
<AiAgentCard
|
|
140
|
+
name="Execute"
|
|
141
|
+
agentType="execute"
|
|
142
|
+
status="completed"
|
|
143
|
+
modelId="claude-sonnet-4"
|
|
144
|
+
currentTask="Rewrote 4 files successfully."
|
|
145
|
+
duration={12_400}
|
|
146
|
+
toolCallCount={7}
|
|
147
|
+
/>
|
|
148
|
+
<AiAgentCard
|
|
149
|
+
name="Test"
|
|
150
|
+
agentType="test"
|
|
151
|
+
status="error"
|
|
152
|
+
modelId="claude-haiku-3.5"
|
|
153
|
+
currentTask="3 tests failed: auth.spec.ts"
|
|
154
|
+
duration={3200}
|
|
155
|
+
toolCallCount={2}
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
<div className="flex flex-wrap gap-3">
|
|
162
|
+
<AiAgentCard
|
|
163
|
+
name="Explore"
|
|
164
|
+
agentType="explore"
|
|
165
|
+
status="completed"
|
|
166
|
+
modelId="claude-haiku-3.5"
|
|
167
|
+
duration={4200}
|
|
168
|
+
toolCallCount={5}
|
|
169
|
+
/>
|
|
170
|
+
<AiAgentCard
|
|
171
|
+
name="Execute"
|
|
172
|
+
agentType="execute"
|
|
173
|
+
status="running"
|
|
174
|
+
modelId="claude-sonnet-4"
|
|
175
|
+
currentTask="Patching consumers..."
|
|
176
|
+
duration={6100}
|
|
177
|
+
toolCallCount={3}
|
|
178
|
+
selected
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
<div className="flex flex-wrap gap-2">
|
|
185
|
+
{[
|
|
186
|
+
{ name: "Explore", agentType: "explore", status: "completed" as const },
|
|
187
|
+
{ name: "Plan", agentType: "plan", status: "completed" as const },
|
|
188
|
+
{ name: "Execute", agentType: "execute", status: "running" as const },
|
|
189
|
+
{ name: "Review", agentType: "review", status: "idle" as const },
|
|
190
|
+
].map((agent) => (
|
|
191
|
+
<AiAgentCard key={agent.name} size="sm" {...agent} />
|
|
192
|
+
))}
|
|
193
|
+
</div>
|
|
194
|
+
```
|
|
195
|
+
|
|
78
196
|
---
|
|
79
197
|
|
|
80
198
|
### AiApproval
|
|
@@ -119,11 +237,47 @@ Approval card for tool calls and plan submissions. Maps to harness events: `tool
|
|
|
119
237
|
|
|
120
238
|
`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
239
|
|
|
240
|
+
**Examples:**
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<div className="w-full max-w-md">
|
|
244
|
+
<AiApproval
|
|
245
|
+
kind="tool"
|
|
246
|
+
status={status}
|
|
247
|
+
title="Execute shell command"
|
|
248
|
+
description="rm -rf /tmp/cache"
|
|
249
|
+
onApprove={() => setStatus("approved")}
|
|
250
|
+
onReject={() => setStatus("rejected")}
|
|
251
|
+
/>
|
|
252
|
+
</div>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
<div className="w-full max-w-md">
|
|
257
|
+
<AiApproval
|
|
258
|
+
kind="plan"
|
|
259
|
+
status={status}
|
|
260
|
+
title="Deployment plan"
|
|
261
|
+
description="The agent proposes the following steps:"
|
|
262
|
+
items={[
|
|
263
|
+
{ id: "1", label: "Run test suite", description: "All 142 tests" },
|
|
264
|
+
{ id: "2", label: "Build production bundle" },
|
|
265
|
+
{ id: "3", label: "Deploy to staging", description: "us-east-1" },
|
|
266
|
+
{ id: "4", label: "Run smoke tests" },
|
|
267
|
+
{ id: "5", label: "Promote to production" },
|
|
268
|
+
]}
|
|
269
|
+
showFeedback
|
|
270
|
+
onApprove={() => setStatus("approved")}
|
|
271
|
+
onReject={() => setStatus("rejected")}
|
|
272
|
+
/>
|
|
273
|
+
</div>
|
|
274
|
+
```
|
|
275
|
+
|
|
122
276
|
---
|
|
123
277
|
|
|
124
278
|
### AiCodeBlock
|
|
125
279
|
|
|
126
|
-
|
|
280
|
+
AiCodeBlock component
|
|
127
281
|
|
|
128
282
|
**Type:** component
|
|
129
283
|
|
|
@@ -149,6 +303,32 @@ Displays a code block with monospace formatting and an optional copy button. Doe
|
|
|
149
303
|
|
|
150
304
|
`bg-sf-recessed`, `border-sf-line`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`
|
|
151
305
|
|
|
306
|
+
**Sub-Components:**
|
|
307
|
+
|
|
308
|
+
This is a compound component. Use these sub-components:
|
|
309
|
+
|
|
310
|
+
#### AiCodeBlock.CopyButton
|
|
311
|
+
|
|
312
|
+
CopyButton sub-component
|
|
313
|
+
|
|
314
|
+
Props:
|
|
315
|
+
|
|
316
|
+
- `timeout`: number
|
|
317
|
+
|
|
318
|
+
**Examples:**
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
<AiCodeBlock code={CODE} language="tsx">
|
|
322
|
+
<AiCodeBlockCopyButton />
|
|
323
|
+
</AiCodeBlock>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
<AiCodeBlock code="npm install @signalflare-ai/ui">
|
|
328
|
+
<AiCodeBlockCopyButton />
|
|
329
|
+
</AiCodeBlock>
|
|
330
|
+
```
|
|
331
|
+
|
|
152
332
|
---
|
|
153
333
|
|
|
154
334
|
### AiConversation
|
|
@@ -169,6 +349,24 @@ Outer scroll container for a conversation. Sticks to the bottom as new messages
|
|
|
169
349
|
- `lang`: string
|
|
170
350
|
- `title`: string
|
|
171
351
|
|
|
352
|
+
**Examples:**
|
|
353
|
+
|
|
354
|
+
```tsx
|
|
355
|
+
<div className="h-80 w-full overflow-hidden rounded-lg border border-sf-line">
|
|
356
|
+
<AiConversation>
|
|
357
|
+
<AiConversationContent>
|
|
358
|
+
{MESSAGES.map((m) => (
|
|
359
|
+
<AiMessage key={m.id} from={m.from}>
|
|
360
|
+
<AiMessageContent>
|
|
361
|
+
<AiResponse>{m.text}</AiResponse>
|
|
362
|
+
</AiMessageContent>
|
|
363
|
+
</AiMessage>
|
|
364
|
+
))}
|
|
365
|
+
</AiConversationContent>
|
|
366
|
+
</AiConversation>
|
|
367
|
+
</div>
|
|
368
|
+
```
|
|
369
|
+
|
|
172
370
|
---
|
|
173
371
|
|
|
174
372
|
### AiInfoBanner
|
|
@@ -199,6 +397,18 @@ Inline conversation banner for system notices. Renders as a compact, horizontall
|
|
|
199
397
|
|
|
200
398
|
`border-sf-danger`, `border-sf-info`, `border-sf-line`, `text-sf-danger`, `text-sf-info`, `text-sf-subtle`
|
|
201
399
|
|
|
400
|
+
**Examples:**
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
<div className="flex w-full flex-col gap-3">
|
|
404
|
+
<AiInfoBanner level="info">
|
|
405
|
+
Follow-up message queued — will send after current response completes
|
|
406
|
+
</AiInfoBanner>
|
|
407
|
+
<AiInfoBanner level="change">Switched to claude-opus-4-6</AiInfoBanner>
|
|
408
|
+
<AiInfoBanner level="error">Connection lost. Retrying in 3s…</AiInfoBanner>
|
|
409
|
+
</div>
|
|
410
|
+
```
|
|
411
|
+
|
|
202
412
|
---
|
|
203
413
|
|
|
204
414
|
### AiMessage
|
|
@@ -227,6 +437,37 @@ Root message container. Sets layout, group class, and role context.
|
|
|
227
437
|
|
|
228
438
|
`bg-sf-control`, `bg-sf-overlay`, `bg-sf-tint`, `text-sf-default`, `text-sf-subtle`
|
|
229
439
|
|
|
440
|
+
**Examples:**
|
|
441
|
+
|
|
442
|
+
```tsx
|
|
443
|
+
<div className="flex w-full flex-col gap-2 p-4">
|
|
444
|
+
<AiMessage from="user">
|
|
445
|
+
<AiMessageContent>What is the capital of France?</AiMessageContent>
|
|
446
|
+
</AiMessage>
|
|
447
|
+
<AiMessage from="assistant">
|
|
448
|
+
<AiMessageContent>
|
|
449
|
+
<AiResponse>{"The capital of France is **Paris**."}</AiResponse>
|
|
450
|
+
</AiMessageContent>
|
|
451
|
+
<AiMessageToolbar>
|
|
452
|
+
<AiMessageActions>
|
|
453
|
+
<AiMessageAction tooltip="Copy">
|
|
454
|
+
<CopyIcon className="size-4" />
|
|
455
|
+
</AiMessageAction>
|
|
456
|
+
<AiMessageAction tooltip="Retry">
|
|
457
|
+
<ArrowCounterClockwiseIcon className="size-4" />
|
|
458
|
+
</AiMessageAction>
|
|
459
|
+
</AiMessageActions>
|
|
460
|
+
</AiMessageToolbar>
|
|
461
|
+
</AiMessage>
|
|
462
|
+
</div>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
<AiMessage from="user">
|
|
467
|
+
<AiMessageContent>Can you summarise this document?</AiMessageContent>
|
|
468
|
+
</AiMessage>
|
|
469
|
+
```
|
|
470
|
+
|
|
230
471
|
---
|
|
231
472
|
|
|
232
473
|
### AiMissionHeader
|
|
@@ -269,6 +510,116 @@ Root message container. Sets layout, group class, and role context.
|
|
|
269
510
|
|
|
270
511
|
`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
512
|
|
|
513
|
+
**Examples:**
|
|
514
|
+
|
|
515
|
+
```tsx
|
|
516
|
+
<AiMissionHeader
|
|
517
|
+
title="Refactor auth module"
|
|
518
|
+
taskList={{
|
|
519
|
+
title: "Refactor auth module",
|
|
520
|
+
tasks: [
|
|
521
|
+
{
|
|
522
|
+
id: "t1",
|
|
523
|
+
content: "Explore authentication codebase",
|
|
524
|
+
status: "completed",
|
|
525
|
+
priority: "high",
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
id: "t2",
|
|
529
|
+
content: "Identify deprecated patterns",
|
|
530
|
+
status: "completed",
|
|
531
|
+
priority: "high",
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
id: "t3",
|
|
535
|
+
content: "Write updated auth helpers",
|
|
536
|
+
status: "in_progress",
|
|
537
|
+
priority: "medium",
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
id: "t4",
|
|
541
|
+
content: "Update all consumers",
|
|
542
|
+
status: "pending",
|
|
543
|
+
priority: "medium",
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
id: "t5",
|
|
547
|
+
content: "Update tests",
|
|
548
|
+
status: "pending",
|
|
549
|
+
priority: "low",
|
|
550
|
+
},
|
|
551
|
+
],
|
|
552
|
+
}}
|
|
553
|
+
usage={{
|
|
554
|
+
inputTokens: 12_480,
|
|
555
|
+
outputTokens: 3256,
|
|
556
|
+
totalTokens: 15_736,
|
|
557
|
+
cost: 0.04,
|
|
558
|
+
}}
|
|
559
|
+
activeAgentCount={2}
|
|
560
|
+
totalAgentCount={4}
|
|
561
|
+
startedAt={startedAt}
|
|
562
|
+
isRunning
|
|
563
|
+
/>
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
```tsx
|
|
567
|
+
<AiMissionHeader
|
|
568
|
+
title="Deploy to production"
|
|
569
|
+
taskList={{
|
|
570
|
+
tasks: [
|
|
571
|
+
{
|
|
572
|
+
id: "t1",
|
|
573
|
+
content: "Run tests",
|
|
574
|
+
status: "completed",
|
|
575
|
+
priority: "high",
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
id: "t2",
|
|
579
|
+
content: "Build artifacts",
|
|
580
|
+
status: "completed",
|
|
581
|
+
priority: "high",
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
id: "t3",
|
|
585
|
+
content: "Deploy to staging",
|
|
586
|
+
status: "completed",
|
|
587
|
+
priority: "medium",
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
id: "t4",
|
|
591
|
+
content: "Smoke test",
|
|
592
|
+
status: "completed",
|
|
593
|
+
priority: "medium",
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
id: "t5",
|
|
597
|
+
content: "Deploy to production",
|
|
598
|
+
status: "completed",
|
|
599
|
+
priority: "high",
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
}}
|
|
603
|
+
usage={{ totalTokens: 28_400, cost: 0.12 }}
|
|
604
|
+
activeAgentCount={0}
|
|
605
|
+
totalAgentCount={3}
|
|
606
|
+
startedAt={startedAt}
|
|
607
|
+
endedAt={endedAt}
|
|
608
|
+
isRunning={false}
|
|
609
|
+
/>
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
```tsx
|
|
613
|
+
<AiMissionHeader
|
|
614
|
+
title="Analyze codebase"
|
|
615
|
+
activeAgentCount={1}
|
|
616
|
+
totalAgentCount={2}
|
|
617
|
+
startedAt={startedAt}
|
|
618
|
+
isRunning
|
|
619
|
+
variant="compact"
|
|
620
|
+
/>
|
|
621
|
+
```
|
|
622
|
+
|
|
272
623
|
---
|
|
273
624
|
|
|
274
625
|
### AiPartGroup
|
|
@@ -298,6 +649,49 @@ Groups streaming ephemeral activity (tool calls + reasoning) into a single rolli
|
|
|
298
649
|
|
|
299
650
|
`bg-sf-tint`, `border-sf-line`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
|
|
300
651
|
|
|
652
|
+
**Examples:**
|
|
653
|
+
|
|
654
|
+
```tsx
|
|
655
|
+
<div className="flex flex-col gap-3">
|
|
656
|
+
<div className="flex items-center justify-between gap-3">
|
|
657
|
+
<Text variant="secondary" size="sm">
|
|
658
|
+
Rolling window of 3 rows while streaming. Collapses to a single frozen
|
|
659
|
+
line when complete.
|
|
660
|
+
</Text>
|
|
661
|
+
<Button onClick={() => setRunId((n) => n + 1)} size="sm" variant="ghost">
|
|
662
|
+
Run again
|
|
663
|
+
</Button>
|
|
664
|
+
</div>
|
|
665
|
+
<div className="min-h-[6rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3">
|
|
666
|
+
<AiPartGroup
|
|
667
|
+
complete={complete}
|
|
668
|
+
groupKey={`activity-demo-${runId}`}
|
|
669
|
+
max={3}
|
|
670
|
+
title="Investigating failing auth tests"
|
|
671
|
+
>
|
|
672
|
+
{steps.map((s) =>
|
|
673
|
+
s.kind === "tool" ? (
|
|
674
|
+
<AiToolCall
|
|
675
|
+
duration={s.duration}
|
|
676
|
+
key={s.part.toolCallId}
|
|
677
|
+
part={s.part}
|
|
678
|
+
variant="ephemeral"
|
|
679
|
+
/>
|
|
680
|
+
) : (
|
|
681
|
+
<AiReasoning
|
|
682
|
+
duration={s.duration}
|
|
683
|
+
isStreaming={s.isStreaming}
|
|
684
|
+
key={s.id}
|
|
685
|
+
part={{ text: s.text }}
|
|
686
|
+
variant="ephemeral"
|
|
687
|
+
/>
|
|
688
|
+
)
|
|
689
|
+
)}
|
|
690
|
+
</AiPartGroup>
|
|
691
|
+
</div>
|
|
692
|
+
</div>
|
|
693
|
+
```
|
|
694
|
+
|
|
301
695
|
---
|
|
302
696
|
|
|
303
697
|
### AiQuestion
|
|
@@ -338,6 +732,55 @@ Agent question card. Renders when the agent uses the `ask_user` built-in tool an
|
|
|
338
732
|
|
|
339
733
|
`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
734
|
|
|
735
|
+
**Examples:**
|
|
736
|
+
|
|
737
|
+
```tsx
|
|
738
|
+
<div className="w-full max-w-md">
|
|
739
|
+
<AiQuestion
|
|
740
|
+
questionId="q-demo-1"
|
|
741
|
+
question="How should I handle the failing tests?"
|
|
742
|
+
header="Decision needed"
|
|
743
|
+
status={status}
|
|
744
|
+
answeredWith={answer}
|
|
745
|
+
options={[
|
|
746
|
+
{
|
|
747
|
+
label: "Fix them",
|
|
748
|
+
description: "Update the test expectations to match new behavior",
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
label: "Skip them",
|
|
752
|
+
description: "Mark as skipped for now and create a ticket",
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
label: "Delete them",
|
|
756
|
+
description: "Remove outdated tests entirely",
|
|
757
|
+
},
|
|
758
|
+
]}
|
|
759
|
+
allowCustom
|
|
760
|
+
onAnswer={(_id, ans) => {
|
|
761
|
+
setAnswer(ans);
|
|
762
|
+
setStatus("answered");
|
|
763
|
+
}}
|
|
764
|
+
/>
|
|
765
|
+
</div>
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
```tsx
|
|
769
|
+
<div className="w-full max-w-md">
|
|
770
|
+
<AiQuestion
|
|
771
|
+
questionId="q-demo-2"
|
|
772
|
+
question="What should the commit message be for these changes?"
|
|
773
|
+
status={status}
|
|
774
|
+
answeredWith={answer}
|
|
775
|
+
allowCustom
|
|
776
|
+
onAnswer={(_id, ans) => {
|
|
777
|
+
setAnswer(ans);
|
|
778
|
+
setStatus("answered");
|
|
779
|
+
}}
|
|
780
|
+
/>
|
|
781
|
+
</div>
|
|
782
|
+
```
|
|
783
|
+
|
|
341
784
|
---
|
|
342
785
|
|
|
343
786
|
### AiReasoning
|
|
@@ -387,6 +830,73 @@ Collapsible reasoning block. Supports three display variants: - `"default"` —
|
|
|
387
830
|
|
|
388
831
|
`bg-sf-tint`, `border-sf-line`, `text-sf-subtle`, `text-sf-success`
|
|
389
832
|
|
|
833
|
+
**Examples:**
|
|
834
|
+
|
|
835
|
+
```tsx
|
|
836
|
+
<AiReasoning
|
|
837
|
+
part={{ text: SAMPLE_REASONING }}
|
|
838
|
+
isStreaming={false}
|
|
839
|
+
duration={3}
|
|
840
|
+
defaultExpanded
|
|
841
|
+
/>
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
```tsx
|
|
845
|
+
<AiReasoning
|
|
846
|
+
part={{ text: "Analysing context and forming a response..." }}
|
|
847
|
+
isStreaming
|
|
848
|
+
/>
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
```tsx
|
|
852
|
+
<AiReasoning
|
|
853
|
+
variant="inline"
|
|
854
|
+
part={{ text: SAMPLE_REASONING }}
|
|
855
|
+
isStreaming={false}
|
|
856
|
+
/>
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
```tsx
|
|
860
|
+
<div className="flex flex-col gap-3">
|
|
861
|
+
<div className="flex items-center justify-between gap-3">
|
|
862
|
+
<Text variant="secondary" size="sm">
|
|
863
|
+
Reasoning row evaporates 800ms after streaming ends.
|
|
864
|
+
</Text>
|
|
865
|
+
<Button onClick={() => setRunId((n) => n + 1)} size="sm" variant="ghost">
|
|
866
|
+
Think again
|
|
867
|
+
</Button>
|
|
868
|
+
</div>
|
|
869
|
+
<div
|
|
870
|
+
className={
|
|
871
|
+
"min-h-[3.5rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3"
|
|
872
|
+
}
|
|
873
|
+
>
|
|
874
|
+
<AiReasoning
|
|
875
|
+
// `key` ensures each replay re-mounts to reset the dismiss state.
|
|
876
|
+
key={runId}
|
|
877
|
+
variant="ephemeral"
|
|
878
|
+
part={{
|
|
879
|
+
text: "**Reviewing diff** — checking for breaking changes in the migration.",
|
|
880
|
+
}}
|
|
881
|
+
isStreaming={isStreaming}
|
|
882
|
+
/>
|
|
883
|
+
</div>
|
|
884
|
+
</div>
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
```tsx
|
|
888
|
+
<AiReasoningGroup
|
|
889
|
+
parts={[
|
|
890
|
+
{ text: "**Step 1** — Understood the user intent and context." },
|
|
891
|
+
{ text: "**Step 2** — Reviewed relevant data and constraints." },
|
|
892
|
+
{ text: "**Step 3** — Formulated the final response structure." },
|
|
893
|
+
]}
|
|
894
|
+
isStreaming={false}
|
|
895
|
+
totalDuration={7}
|
|
896
|
+
defaultExpanded
|
|
897
|
+
/>
|
|
898
|
+
```
|
|
899
|
+
|
|
390
900
|
---
|
|
391
901
|
|
|
392
902
|
### AiResponse
|
|
@@ -410,6 +920,39 @@ Renders AI-generated markdown using Streamdown. Supports streaming animation, sy
|
|
|
410
920
|
|
|
411
921
|
`text-sf-default`
|
|
412
922
|
|
|
923
|
+
**Examples:**
|
|
924
|
+
|
|
925
|
+
```tsx
|
|
926
|
+
<AiResponse>{MARKDOWN_LIKE}</AiResponse>
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
```tsx
|
|
930
|
+
<AiResponse isAnimating={isAnimating}>{text}</AiResponse>
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
```tsx
|
|
934
|
+
<div className="flex w-full flex-col gap-4">
|
|
935
|
+
<AiResponse
|
|
936
|
+
components={{ a: LinkComponent } as Components}
|
|
937
|
+
linkSafety={{ enabled: false }}
|
|
938
|
+
>
|
|
939
|
+
{DEEP_LINK_MARKDOWN}
|
|
940
|
+
</AiResponse>
|
|
941
|
+
{activeFile && (
|
|
942
|
+
<div className="rounded-lg border border-sf-brand/30 bg-sf-brand/10 px-3 py-2 text-sm text-sf-default">
|
|
943
|
+
<span className="text-sf-subtle">Opened file:</span>{" "}
|
|
944
|
+
<code className="font-mono text-sf-brand">{activeFile}</code>
|
|
945
|
+
<button
|
|
946
|
+
onClick={() => setActiveFile(null)}
|
|
947
|
+
className="ml-3 text-xs text-sf-subtle hover:text-sf-default"
|
|
948
|
+
>
|
|
949
|
+
Dismiss
|
|
950
|
+
</button>
|
|
951
|
+
</div>
|
|
952
|
+
)}
|
|
953
|
+
</div>
|
|
954
|
+
```
|
|
955
|
+
|
|
413
956
|
---
|
|
414
957
|
|
|
415
958
|
### AiShimmer
|
|
@@ -435,6 +978,26 @@ AiShimmer component
|
|
|
435
978
|
- `spread`: number
|
|
436
979
|
Shimmer width multiplier relative to text length.
|
|
437
980
|
|
|
981
|
+
**Examples:**
|
|
982
|
+
|
|
983
|
+
```tsx
|
|
984
|
+
<AiShimmer>Thinking...</AiShimmer>
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
```tsx
|
|
988
|
+
<p className="text-sf-default text-sm">
|
|
989
|
+
The AI is{" "}
|
|
990
|
+
<AiShimmer as="span" duration={1.5}>
|
|
991
|
+
generating a response
|
|
992
|
+
</AiShimmer>
|
|
993
|
+
.
|
|
994
|
+
</p>
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
```tsx
|
|
998
|
+
<AiShimmer duration={4}>Analysing your request...</AiShimmer>
|
|
999
|
+
```
|
|
1000
|
+
|
|
438
1001
|
---
|
|
439
1002
|
|
|
440
1003
|
### AiStatusBadge
|
|
@@ -470,6 +1033,45 @@ Compact pill-shaped badge showing an icon, label, and a status indicator. Used b
|
|
|
470
1033
|
|
|
471
1034
|
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
|
|
472
1035
|
|
|
1036
|
+
**Examples:**
|
|
1037
|
+
|
|
1038
|
+
```tsx
|
|
1039
|
+
<AiStatusBadge icon={MagnifyingGlassIcon} label="web_search" status="idle" />
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
```tsx
|
|
1043
|
+
<div className="flex flex-wrap gap-2">
|
|
1044
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="idle" />
|
|
1045
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="running" />
|
|
1046
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="success" />
|
|
1047
|
+
<AiStatusBadge icon={GlobeIcon} label="search_web" status="error" />
|
|
1048
|
+
</div>
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
```tsx
|
|
1052
|
+
<div className="flex flex-wrap gap-2">
|
|
1053
|
+
<AiStatusBadge
|
|
1054
|
+
icon={DatabaseIcon}
|
|
1055
|
+
label="query_db"
|
|
1056
|
+
info="3/5"
|
|
1057
|
+
status="running"
|
|
1058
|
+
/>
|
|
1059
|
+
<AiStatusBadge
|
|
1060
|
+
icon={BrainIcon}
|
|
1061
|
+
label="analyse"
|
|
1062
|
+
info="done"
|
|
1063
|
+
status="success"
|
|
1064
|
+
/>
|
|
1065
|
+
</div>
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
```tsx
|
|
1069
|
+
<div className="flex flex-wrap gap-2">
|
|
1070
|
+
<AiStatusBadge label="processing" status="running" />
|
|
1071
|
+
<AiStatusBadge label="complete" status="success" />
|
|
1072
|
+
</div>
|
|
1073
|
+
```
|
|
1074
|
+
|
|
473
1075
|
---
|
|
474
1076
|
|
|
475
1077
|
### AiStreamingText
|
|
@@ -489,6 +1091,17 @@ AiStreamingText component
|
|
|
489
1091
|
- `children`: ReactNode
|
|
490
1092
|
Child elements
|
|
491
1093
|
|
|
1094
|
+
**Examples:**
|
|
1095
|
+
|
|
1096
|
+
```tsx
|
|
1097
|
+
<p className="max-w-sm text-sf-default text-sm">
|
|
1098
|
+
{displayed}
|
|
1099
|
+
{streaming && (
|
|
1100
|
+
<span className="ml-0.5 inline-block h-4 w-0.5 animate-pulse bg-sf-brand" />
|
|
1101
|
+
)}
|
|
1102
|
+
</p>
|
|
1103
|
+
```
|
|
1104
|
+
|
|
492
1105
|
---
|
|
493
1106
|
|
|
494
1107
|
### AiSubagent
|
|
@@ -529,7 +1142,92 @@ Collapsible wrapper for nested subagent activity. Shows the subagent name, statu
|
|
|
529
1142
|
|
|
530
1143
|
**Colors (sf tokens used):**
|
|
531
1144
|
|
|
532
|
-
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-
|
|
1145
|
+
`bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
|
|
1146
|
+
|
|
1147
|
+
**Examples:**
|
|
1148
|
+
|
|
1149
|
+
```tsx
|
|
1150
|
+
<div className="w-full max-w-lg">
|
|
1151
|
+
<AiSubagent
|
|
1152
|
+
name="Explore"
|
|
1153
|
+
agentType="explore"
|
|
1154
|
+
status="running"
|
|
1155
|
+
modelId="claude-haiku-3.5"
|
|
1156
|
+
defaultExpanded
|
|
1157
|
+
>
|
|
1158
|
+
<div className="flex flex-col gap-1.5 text-sm text-sf-subtle">
|
|
1159
|
+
<p>Searching codebase for authentication patterns...</p>
|
|
1160
|
+
<div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
|
|
1161
|
+
<span className="text-sf-brand">Glob</span>
|
|
1162
|
+
<span className="text-sf-subtle">src/**/*auth*</span>
|
|
1163
|
+
</div>
|
|
1164
|
+
<div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
|
|
1165
|
+
<span className="text-sf-brand">Read</span>
|
|
1166
|
+
<span className="text-sf-subtle">src/middleware/auth.ts</span>
|
|
1167
|
+
</div>
|
|
1168
|
+
</div>
|
|
1169
|
+
</AiSubagent>
|
|
1170
|
+
</div>
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
```tsx
|
|
1174
|
+
<div className="w-full max-w-lg">
|
|
1175
|
+
<AiSubagent
|
|
1176
|
+
name="Execute"
|
|
1177
|
+
agentType="execute"
|
|
1178
|
+
status="completed"
|
|
1179
|
+
modelId="claude-sonnet-4"
|
|
1180
|
+
duration={12400}
|
|
1181
|
+
defaultExpanded={false}
|
|
1182
|
+
>
|
|
1183
|
+
<div className="text-sm text-sf-subtle">
|
|
1184
|
+
<p>Refactored 3 files, added 2 new tests. All tests passing.</p>
|
|
1185
|
+
</div>
|
|
1186
|
+
</AiSubagent>
|
|
1187
|
+
</div>
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
```tsx
|
|
1191
|
+
<div className="w-full max-w-lg">
|
|
1192
|
+
<AiSubagent
|
|
1193
|
+
name="Plan"
|
|
1194
|
+
agentType="plan"
|
|
1195
|
+
status="completed"
|
|
1196
|
+
modelId="claude-sonnet-4"
|
|
1197
|
+
duration={28000}
|
|
1198
|
+
defaultExpanded
|
|
1199
|
+
>
|
|
1200
|
+
<div className="flex flex-col gap-2">
|
|
1201
|
+
<p className="text-sm text-sf-subtle">
|
|
1202
|
+
Breaking down the migration into subtasks...
|
|
1203
|
+
</p>
|
|
1204
|
+
<AiSubagent
|
|
1205
|
+
name="Explore"
|
|
1206
|
+
agentType="explore"
|
|
1207
|
+
status="completed"
|
|
1208
|
+
modelId="claude-haiku-3.5"
|
|
1209
|
+
duration={4200}
|
|
1210
|
+
defaultExpanded={false}
|
|
1211
|
+
>
|
|
1212
|
+
<p className="text-sm text-sf-subtle">
|
|
1213
|
+
Found 12 files using deprecated API.
|
|
1214
|
+
</p>
|
|
1215
|
+
</AiSubagent>
|
|
1216
|
+
<AiSubagent
|
|
1217
|
+
name="Execute"
|
|
1218
|
+
agentType="execute"
|
|
1219
|
+
status="running"
|
|
1220
|
+
modelId="claude-sonnet-4"
|
|
1221
|
+
defaultExpanded
|
|
1222
|
+
>
|
|
1223
|
+
<p className="text-sm text-sf-subtle">
|
|
1224
|
+
Updating import paths in batch 1/3...
|
|
1225
|
+
</p>
|
|
1226
|
+
</AiSubagent>
|
|
1227
|
+
</div>
|
|
1228
|
+
</AiSubagent>
|
|
1229
|
+
</div>
|
|
1230
|
+
```
|
|
533
1231
|
|
|
534
1232
|
---
|
|
535
1233
|
|
|
@@ -582,6 +1280,14 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
|
|
|
582
1280
|
|
|
583
1281
|
`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
1282
|
|
|
1283
|
+
**Examples:**
|
|
1284
|
+
|
|
1285
|
+
```tsx
|
|
1286
|
+
<div className="w-full max-w-sm">
|
|
1287
|
+
<AiTaskList title="Agent tasks" tasks={tasks} />
|
|
1288
|
+
</div>
|
|
1289
|
+
```
|
|
1290
|
+
|
|
585
1291
|
---
|
|
586
1292
|
|
|
587
1293
|
### AiTimeline
|
|
@@ -618,6 +1324,95 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
|
|
|
618
1324
|
|
|
619
1325
|
`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
1326
|
|
|
1327
|
+
**Examples:**
|
|
1328
|
+
|
|
1329
|
+
```tsx
|
|
1330
|
+
<AiTimeline timeOrigin={T0} pixelsPerSecond={25} showNowMarker nowMs={nowMs}>
|
|
1331
|
+
<AiTimelineLane
|
|
1332
|
+
label="Main"
|
|
1333
|
+
agentType="main"
|
|
1334
|
+
status="running"
|
|
1335
|
+
modelId="claude-sonnet-4"
|
|
1336
|
+
blocks={mainBlocks}
|
|
1337
|
+
timeOrigin={T0}
|
|
1338
|
+
nowMs={nowMs}
|
|
1339
|
+
pxPerMs={pxPerMs}
|
|
1340
|
+
/>
|
|
1341
|
+
<AiTimelineLane
|
|
1342
|
+
label="Explore"
|
|
1343
|
+
agentType="explore"
|
|
1344
|
+
status="completed"
|
|
1345
|
+
modelId="claude-haiku-3.5"
|
|
1346
|
+
blocks={exploreBlocks}
|
|
1347
|
+
timeOrigin={T0}
|
|
1348
|
+
nowMs={nowMs}
|
|
1349
|
+
pxPerMs={pxPerMs}
|
|
1350
|
+
/>
|
|
1351
|
+
<AiTimelineLane
|
|
1352
|
+
label="Plan"
|
|
1353
|
+
agentType="plan"
|
|
1354
|
+
status="completed"
|
|
1355
|
+
modelId="claude-sonnet-4"
|
|
1356
|
+
blocks={planBlocks}
|
|
1357
|
+
timeOrigin={T0}
|
|
1358
|
+
nowMs={nowMs}
|
|
1359
|
+
pxPerMs={pxPerMs}
|
|
1360
|
+
/>
|
|
1361
|
+
<AiTimelineLane
|
|
1362
|
+
label="Execute"
|
|
1363
|
+
agentType="execute"
|
|
1364
|
+
status="running"
|
|
1365
|
+
modelId="claude-sonnet-4"
|
|
1366
|
+
blocks={executeBlocks}
|
|
1367
|
+
timeOrigin={T0}
|
|
1368
|
+
nowMs={nowMs}
|
|
1369
|
+
pxPerMs={pxPerMs}
|
|
1370
|
+
/>
|
|
1371
|
+
</AiTimeline>
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
```tsx
|
|
1375
|
+
<AiTimeline timeOrigin={T0} pixelsPerSecond={25} showNowMarker nowMs={nowMs}>
|
|
1376
|
+
<AiTimelineLane
|
|
1377
|
+
label="Explore"
|
|
1378
|
+
agentType="explore"
|
|
1379
|
+
status="completed"
|
|
1380
|
+
blocks={exploreBlocks}
|
|
1381
|
+
timeOrigin={T0}
|
|
1382
|
+
nowMs={nowMs}
|
|
1383
|
+
pxPerMs={pxPerMs}
|
|
1384
|
+
density="compact"
|
|
1385
|
+
/>
|
|
1386
|
+
<AiTimelineLane
|
|
1387
|
+
label="Execute"
|
|
1388
|
+
agentType="execute"
|
|
1389
|
+
status="running"
|
|
1390
|
+
blocks={executeBlocks}
|
|
1391
|
+
timeOrigin={T0}
|
|
1392
|
+
nowMs={nowMs}
|
|
1393
|
+
pxPerMs={pxPerMs}
|
|
1394
|
+
density="compact"
|
|
1395
|
+
/>
|
|
1396
|
+
</AiTimeline>
|
|
1397
|
+
```
|
|
1398
|
+
|
|
1399
|
+
```tsx
|
|
1400
|
+
<AiTimeline
|
|
1401
|
+
timeOrigin={t}
|
|
1402
|
+
pixelsPerSecond={30}
|
|
1403
|
+
showNowMarker={false}
|
|
1404
|
+
nowMs={nowMs}
|
|
1405
|
+
>
|
|
1406
|
+
<AiTimelineLane
|
|
1407
|
+
label="Agent"
|
|
1408
|
+
blocks={allTypeBlocks}
|
|
1409
|
+
timeOrigin={t}
|
|
1410
|
+
nowMs={nowMs}
|
|
1411
|
+
pxPerMs={pxPerMs}
|
|
1412
|
+
/>
|
|
1413
|
+
</AiTimeline>
|
|
1414
|
+
```
|
|
1415
|
+
|
|
621
1416
|
---
|
|
622
1417
|
|
|
623
1418
|
### AiToolCall
|
|
@@ -697,6 +1492,25 @@ Compact token usage display bar. Shows input/output token counts, total, optiona
|
|
|
697
1492
|
|
|
698
1493
|
`text-sf-inactive`, `text-sf-subtle`
|
|
699
1494
|
|
|
1495
|
+
**Examples:**
|
|
1496
|
+
|
|
1497
|
+
```tsx
|
|
1498
|
+
<div className="w-full max-w-md rounded-lg border border-sf-line">
|
|
1499
|
+
<AiUsageBar
|
|
1500
|
+
inputTokens={12480}
|
|
1501
|
+
outputTokens={3256}
|
|
1502
|
+
cost={0.04}
|
|
1503
|
+
modelId="claude-sonnet-4"
|
|
1504
|
+
/>
|
|
1505
|
+
</div>
|
|
1506
|
+
```
|
|
1507
|
+
|
|
1508
|
+
```tsx
|
|
1509
|
+
<div className="w-full max-w-sm rounded-lg border border-sf-line">
|
|
1510
|
+
<AiUsageBar inputTokens={850} outputTokens={124} />
|
|
1511
|
+
</div>
|
|
1512
|
+
```
|
|
1513
|
+
|
|
700
1514
|
---
|
|
701
1515
|
|
|
702
1516
|
### Badge
|
|
@@ -741,6 +1555,116 @@ Small status label for categorizing or highlighting content. Supports icons, loa
|
|
|
741
1555
|
|
|
742
1556
|
`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
1557
|
|
|
1558
|
+
**Examples:**
|
|
1559
|
+
|
|
1560
|
+
```tsx
|
|
1561
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1562
|
+
<Badge variant="primary">Primary</Badge>
|
|
1563
|
+
<Badge variant="secondary">Secondary</Badge>
|
|
1564
|
+
<Badge variant="destructive">Destructive</Badge>
|
|
1565
|
+
<Badge variant="outline">Outline</Badge>
|
|
1566
|
+
<Badge variant="beta">Beta</Badge>
|
|
1567
|
+
<Badge variant="success">Success</Badge>
|
|
1568
|
+
<Badge variant="warning">Warning</Badge>
|
|
1569
|
+
<Badge variant="info">Info</Badge>
|
|
1570
|
+
<Badge variant="ghost">Ghost</Badge>
|
|
1571
|
+
</div>
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
```tsx
|
|
1575
|
+
<Badge variant="primary">Primary</Badge>
|
|
1576
|
+
```
|
|
1577
|
+
|
|
1578
|
+
```tsx
|
|
1579
|
+
<p className="flex items-center gap-2">
|
|
1580
|
+
Workers
|
|
1581
|
+
<Badge variant="beta">Beta</Badge>
|
|
1582
|
+
</p>
|
|
1583
|
+
```
|
|
1584
|
+
|
|
1585
|
+
```tsx
|
|
1586
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1587
|
+
<Badge variant="success" icon={CheckCircleIcon}>
|
|
1588
|
+
Verified
|
|
1589
|
+
</Badge>
|
|
1590
|
+
<Badge variant="secondary" icon={LightningIcon}>
|
|
1591
|
+
Boosted
|
|
1592
|
+
</Badge>
|
|
1593
|
+
<Badge variant="outline" icon={TagIcon} iconPosition="right">
|
|
1594
|
+
Tagged
|
|
1595
|
+
</Badge>
|
|
1596
|
+
</div>
|
|
1597
|
+
```
|
|
1598
|
+
|
|
1599
|
+
```tsx
|
|
1600
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1601
|
+
{tags.map((tag) => (
|
|
1602
|
+
<Badge
|
|
1603
|
+
key={tag}
|
|
1604
|
+
variant="secondary"
|
|
1605
|
+
onDismiss={() => setTags((t) => t.filter((v) => v !== tag))}
|
|
1606
|
+
>
|
|
1607
|
+
{tag}
|
|
1608
|
+
</Badge>
|
|
1609
|
+
))}
|
|
1610
|
+
{tags.length === 0 && (
|
|
1611
|
+
<span className="text-sm text-sf-subtle">All tags removed</span>
|
|
1612
|
+
)}
|
|
1613
|
+
</div>
|
|
1614
|
+
```
|
|
1615
|
+
|
|
1616
|
+
```tsx
|
|
1617
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1618
|
+
<Badge variant="secondary" loading>
|
|
1619
|
+
Syncing
|
|
1620
|
+
</Badge>
|
|
1621
|
+
<Badge variant="info" loading>
|
|
1622
|
+
Deploying
|
|
1623
|
+
</Badge>
|
|
1624
|
+
</div>
|
|
1625
|
+
```
|
|
1626
|
+
|
|
1627
|
+
```tsx
|
|
1628
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1629
|
+
<Badge variant="outline" dot="green">
|
|
1630
|
+
Online
|
|
1631
|
+
</Badge>
|
|
1632
|
+
<Badge variant="outline" dot="red">
|
|
1633
|
+
Offline
|
|
1634
|
+
</Badge>
|
|
1635
|
+
<Badge variant="outline" dot="yellow">
|
|
1636
|
+
Degraded
|
|
1637
|
+
</Badge>
|
|
1638
|
+
<Badge variant="outline" dot="blue">
|
|
1639
|
+
Deploying
|
|
1640
|
+
</Badge>
|
|
1641
|
+
</div>
|
|
1642
|
+
```
|
|
1643
|
+
|
|
1644
|
+
```tsx
|
|
1645
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1646
|
+
<Badge variant="secondary" onClick={handleBadgeClick}>
|
|
1647
|
+
Clickable
|
|
1648
|
+
</Badge>
|
|
1649
|
+
<Badge variant="info" href="https://example.com">
|
|
1650
|
+
Link badge
|
|
1651
|
+
</Badge>
|
|
1652
|
+
</div>
|
|
1653
|
+
```
|
|
1654
|
+
|
|
1655
|
+
```tsx
|
|
1656
|
+
<TooltipProvider>
|
|
1657
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1658
|
+
<Badge variant="success" tooltip="Deployed 2 hours ago" dot="green">
|
|
1659
|
+
Production
|
|
1660
|
+
</Badge>
|
|
1661
|
+
<Badge variant="outline" tooltip="3 of 5 tasks complete">
|
|
1662
|
+
3/5
|
|
1663
|
+
</Badge>
|
|
1664
|
+
</div>
|
|
1665
|
+
</TooltipProvider>
|
|
1666
|
+
```
|
|
1667
|
+
|
|
744
1668
|
---
|
|
745
1669
|
|
|
746
1670
|
### Banner
|
|
@@ -771,6 +1695,38 @@ Full-width message bar for informational, warning, or error notices.
|
|
|
771
1695
|
|
|
772
1696
|
`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
1697
|
|
|
1698
|
+
**Examples:**
|
|
1699
|
+
|
|
1700
|
+
```tsx
|
|
1701
|
+
<div className="space-y-3">
|
|
1702
|
+
<Banner>This is an informational banner.</Banner>
|
|
1703
|
+
<Banner variant="alert">This is an alert banner.</Banner>
|
|
1704
|
+
<Banner variant="error">This is an error banner.</Banner>
|
|
1705
|
+
</div>
|
|
1706
|
+
```
|
|
1707
|
+
|
|
1708
|
+
```tsx
|
|
1709
|
+
<Banner>This is an informational banner.</Banner>
|
|
1710
|
+
```
|
|
1711
|
+
|
|
1712
|
+
```tsx
|
|
1713
|
+
<Banner variant="alert">Your session will expire soon.</Banner>
|
|
1714
|
+
```
|
|
1715
|
+
|
|
1716
|
+
```tsx
|
|
1717
|
+
<Banner icon={<WarningCircleIcon />} variant="alert">
|
|
1718
|
+
Review your billing information.
|
|
1719
|
+
</Banner>
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1722
|
+
```tsx
|
|
1723
|
+
<Banner icon={<InfoIcon />}>
|
|
1724
|
+
<Text DANGEROUS_className="text-inherit">
|
|
1725
|
+
This banner supports <strong>custom content</strong> with Text.
|
|
1726
|
+
</Text>
|
|
1727
|
+
</Banner>
|
|
1728
|
+
```
|
|
1729
|
+
|
|
774
1730
|
---
|
|
775
1731
|
|
|
776
1732
|
### Breadcrumbs
|
|
@@ -830,6 +1786,47 @@ Props:
|
|
|
830
1786
|
|
|
831
1787
|
- `text`: string (required)
|
|
832
1788
|
|
|
1789
|
+
**Examples:**
|
|
1790
|
+
|
|
1791
|
+
```tsx
|
|
1792
|
+
<Breadcrumbs>
|
|
1793
|
+
<Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
|
|
1794
|
+
<Breadcrumbs.Separator />
|
|
1795
|
+
<Breadcrumbs.Link href="#">Docs</Breadcrumbs.Link>
|
|
1796
|
+
<Breadcrumbs.Separator />
|
|
1797
|
+
<Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
|
|
1798
|
+
</Breadcrumbs>
|
|
1799
|
+
```
|
|
1800
|
+
|
|
1801
|
+
```tsx
|
|
1802
|
+
<Breadcrumbs>
|
|
1803
|
+
<Breadcrumbs.Link href="#" icon={<HouseIcon size={16} />}>
|
|
1804
|
+
Home
|
|
1805
|
+
</Breadcrumbs.Link>
|
|
1806
|
+
<Breadcrumbs.Separator />
|
|
1807
|
+
<Breadcrumbs.Link href="#">Projects</Breadcrumbs.Link>
|
|
1808
|
+
<Breadcrumbs.Separator />
|
|
1809
|
+
<Breadcrumbs.Current>Current Project</Breadcrumbs.Current>
|
|
1810
|
+
</Breadcrumbs>
|
|
1811
|
+
```
|
|
1812
|
+
|
|
1813
|
+
```tsx
|
|
1814
|
+
<Breadcrumbs>
|
|
1815
|
+
<Breadcrumbs.Current icon={<HouseIcon size={16} />}>
|
|
1816
|
+
Worker Analytics
|
|
1817
|
+
</Breadcrumbs.Current>
|
|
1818
|
+
</Breadcrumbs>
|
|
1819
|
+
```
|
|
1820
|
+
|
|
1821
|
+
```tsx
|
|
1822
|
+
<Breadcrumbs>
|
|
1823
|
+
<Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
|
|
1824
|
+
<Breadcrumbs.Separator />
|
|
1825
|
+
<Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
|
|
1826
|
+
<Breadcrumbs.Clipboard text="#" />
|
|
1827
|
+
</Breadcrumbs>
|
|
1828
|
+
```
|
|
1829
|
+
|
|
833
1830
|
---
|
|
834
1831
|
|
|
835
1832
|
### Button
|
|
@@ -897,6 +1894,59 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
|
|
|
897
1894
|
|
|
898
1895
|
`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
1896
|
|
|
1897
|
+
**Examples:**
|
|
1898
|
+
|
|
1899
|
+
```tsx
|
|
1900
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1901
|
+
<Button variant="secondary">Button</Button>
|
|
1902
|
+
<Button variant="secondary" shape="square" icon={PlusIcon} aria-label="Add" />
|
|
1903
|
+
</div>
|
|
1904
|
+
```
|
|
1905
|
+
|
|
1906
|
+
```tsx
|
|
1907
|
+
<Button variant="primary">Primary</Button>
|
|
1908
|
+
```
|
|
1909
|
+
|
|
1910
|
+
```tsx
|
|
1911
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
1912
|
+
<Button size="xs" variant="secondary">
|
|
1913
|
+
Extra Small
|
|
1914
|
+
</Button>
|
|
1915
|
+
<Button size="sm" variant="secondary">
|
|
1916
|
+
Small
|
|
1917
|
+
</Button>
|
|
1918
|
+
<Button size="base" variant="secondary">
|
|
1919
|
+
Base
|
|
1920
|
+
</Button>
|
|
1921
|
+
<Button size="lg" variant="secondary">
|
|
1922
|
+
Large
|
|
1923
|
+
</Button>
|
|
1924
|
+
</div>
|
|
1925
|
+
```
|
|
1926
|
+
|
|
1927
|
+
```tsx
|
|
1928
|
+
<Button variant="secondary" icon={PlusIcon}>
|
|
1929
|
+
Create Worker
|
|
1930
|
+
</Button>
|
|
1931
|
+
```
|
|
1932
|
+
|
|
1933
|
+
```tsx
|
|
1934
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
1935
|
+
<Button
|
|
1936
|
+
variant="secondary"
|
|
1937
|
+
shape="square"
|
|
1938
|
+
icon={PlusIcon}
|
|
1939
|
+
aria-label="Add item"
|
|
1940
|
+
/>
|
|
1941
|
+
<Button
|
|
1942
|
+
variant="secondary"
|
|
1943
|
+
shape="circle"
|
|
1944
|
+
icon={PlusIcon}
|
|
1945
|
+
aria-label="Add item"
|
|
1946
|
+
/>
|
|
1947
|
+
</div>
|
|
1948
|
+
```
|
|
1949
|
+
|
|
900
1950
|
---
|
|
901
1951
|
|
|
902
1952
|
### Checkbox
|
|
@@ -985,6 +2035,66 @@ Props:
|
|
|
985
2035
|
- `controlFirst`: boolean
|
|
986
2036
|
- `className`: string
|
|
987
2037
|
|
|
2038
|
+
**Examples:**
|
|
2039
|
+
|
|
2040
|
+
```tsx
|
|
2041
|
+
<Checkbox
|
|
2042
|
+
label="Accept terms and conditions"
|
|
2043
|
+
checked={checked}
|
|
2044
|
+
onCheckedChange={setChecked}
|
|
2045
|
+
/>
|
|
2046
|
+
```
|
|
2047
|
+
|
|
2048
|
+
```tsx
|
|
2049
|
+
<Checkbox
|
|
2050
|
+
label="Select all"
|
|
2051
|
+
indeterminate={indeterminate}
|
|
2052
|
+
onCheckedChange={setIndeterminate}
|
|
2053
|
+
/>
|
|
2054
|
+
```
|
|
2055
|
+
|
|
2056
|
+
```tsx
|
|
2057
|
+
<Checkbox
|
|
2058
|
+
label="Remember me"
|
|
2059
|
+
controlFirst={false}
|
|
2060
|
+
checked={checked}
|
|
2061
|
+
onCheckedChange={setChecked}
|
|
2062
|
+
/>
|
|
2063
|
+
```
|
|
2064
|
+
|
|
2065
|
+
```tsx
|
|
2066
|
+
<Checkbox label="Disabled option" disabled />
|
|
2067
|
+
```
|
|
2068
|
+
|
|
2069
|
+
```tsx
|
|
2070
|
+
<Checkbox label="Invalid option" variant="error" />
|
|
2071
|
+
```
|
|
2072
|
+
|
|
2073
|
+
```tsx
|
|
2074
|
+
<Checkbox.Group
|
|
2075
|
+
legend="Email preferences"
|
|
2076
|
+
description="Choose how you'd like to receive updates"
|
|
2077
|
+
value={preferences}
|
|
2078
|
+
onValueChange={setPreferences}
|
|
2079
|
+
>
|
|
2080
|
+
<Checkbox.Item value="email" label="Email notifications" />
|
|
2081
|
+
<Checkbox.Item value="sms" label="SMS notifications" />
|
|
2082
|
+
<Checkbox.Item value="push" label="Push notifications" />
|
|
2083
|
+
</Checkbox.Group>
|
|
2084
|
+
```
|
|
2085
|
+
|
|
2086
|
+
```tsx
|
|
2087
|
+
<Checkbox.Group
|
|
2088
|
+
legend="Required preferences"
|
|
2089
|
+
error="Please select at least one notification method"
|
|
2090
|
+
value={[]}
|
|
2091
|
+
onValueChange={() => {}}
|
|
2092
|
+
>
|
|
2093
|
+
<Checkbox.Item value="email" label="Email" variant="error" />
|
|
2094
|
+
<Checkbox.Item value="sms" label="SMS" variant="error" />
|
|
2095
|
+
</Checkbox.Group>
|
|
2096
|
+
```
|
|
2097
|
+
|
|
988
2098
|
---
|
|
989
2099
|
|
|
990
2100
|
### ClipboardText
|
|
@@ -1062,6 +2172,19 @@ Read-only text field with a one-click copy-to-clipboard button.
|
|
|
1062
2172
|
- borderRadius: 8
|
|
1063
2173
|
- fontSize: 14
|
|
1064
2174
|
|
|
2175
|
+
**Examples:**
|
|
2176
|
+
|
|
2177
|
+
```tsx
|
|
2178
|
+
<ClipboardText text="0c239dd2" />
|
|
2179
|
+
```
|
|
2180
|
+
|
|
2181
|
+
```tsx
|
|
2182
|
+
<ClipboardText
|
|
2183
|
+
text="npx sf add button"
|
|
2184
|
+
tooltip={{ copiedText: "Copied!", side: "top", text: "Copy" }}
|
|
2185
|
+
/>
|
|
2186
|
+
```
|
|
2187
|
+
|
|
1065
2188
|
---
|
|
1066
2189
|
|
|
1067
2190
|
### Code
|
|
@@ -1108,6 +2231,26 @@ Props:
|
|
|
1108
2231
|
- `code`: string (required)
|
|
1109
2232
|
- `lang`: CodeLang
|
|
1110
2233
|
|
|
2234
|
+
**Examples:**
|
|
2235
|
+
|
|
2236
|
+
```tsx
|
|
2237
|
+
<CodeBlock
|
|
2238
|
+
lang="tsx"
|
|
2239
|
+
code={`const greeting = "Hello, World!";
|
|
2240
|
+
console.log(greeting);`}
|
|
2241
|
+
/>
|
|
2242
|
+
```
|
|
2243
|
+
|
|
2244
|
+
```tsx
|
|
2245
|
+
<Code
|
|
2246
|
+
lang="bash"
|
|
2247
|
+
code="export API_KEY={{apiKey}}"
|
|
2248
|
+
values={{
|
|
2249
|
+
apiKey: { highlight: true, value: "sk_live_123" },
|
|
2250
|
+
}}
|
|
2251
|
+
/>
|
|
2252
|
+
```
|
|
2253
|
+
|
|
1111
2254
|
---
|
|
1112
2255
|
|
|
1113
2256
|
### Collapsible
|
|
@@ -1136,6 +2279,30 @@ Collapsible component for showing/hiding content. Features: - Animated chevron i
|
|
|
1136
2279
|
|
|
1137
2280
|
`border-sf-fill`, `text-sf-link`
|
|
1138
2281
|
|
|
2282
|
+
**Examples:**
|
|
2283
|
+
|
|
2284
|
+
```tsx
|
|
2285
|
+
<div className="w-full">
|
|
2286
|
+
<Collapsible label="What is SF?" open={isOpen} onOpenChange={setIsOpen}>
|
|
2287
|
+
A minimal, composable component library for building modern interfaces.
|
|
2288
|
+
</Collapsible>
|
|
2289
|
+
</div>
|
|
2290
|
+
```
|
|
2291
|
+
|
|
2292
|
+
```tsx
|
|
2293
|
+
<div className="w-full space-y-2">
|
|
2294
|
+
<Collapsible label="What is SF?" open={open1} onOpenChange={setOpen1}>
|
|
2295
|
+
A minimal, composable component library for building modern interfaces.
|
|
2296
|
+
</Collapsible>
|
|
2297
|
+
<Collapsible label="How do I use it?" open={open2} onOpenChange={setOpen2}>
|
|
2298
|
+
Install the components and import them into your project.
|
|
2299
|
+
</Collapsible>
|
|
2300
|
+
<Collapsible label="Is it open source?" open={open3} onOpenChange={setOpen3}>
|
|
2301
|
+
Check the repository for license information.
|
|
2302
|
+
</Collapsible>
|
|
2303
|
+
</div>
|
|
2304
|
+
```
|
|
2305
|
+
|
|
1139
2306
|
---
|
|
1140
2307
|
|
|
1141
2308
|
### Combobox
|
|
@@ -1258,6 +2425,161 @@ Usage:
|
|
|
1258
2425
|
</Combobox.Collection>
|
|
1259
2426
|
```
|
|
1260
2427
|
|
|
2428
|
+
**Examples:**
|
|
2429
|
+
|
|
2430
|
+
```tsx
|
|
2431
|
+
<Combobox
|
|
2432
|
+
value={value}
|
|
2433
|
+
onValueChange={(v) => setValue(v as string | null)}
|
|
2434
|
+
items={fruits}
|
|
2435
|
+
>
|
|
2436
|
+
<Combobox.TriggerInput placeholder="Please select" />
|
|
2437
|
+
<Combobox.Content>
|
|
2438
|
+
<Combobox.Empty />
|
|
2439
|
+
<Combobox.List>
|
|
2440
|
+
{(item: string) => (
|
|
2441
|
+
<Combobox.Item key={item} value={item}>
|
|
2442
|
+
{item}
|
|
2443
|
+
</Combobox.Item>
|
|
2444
|
+
)}
|
|
2445
|
+
</Combobox.List>
|
|
2446
|
+
</Combobox.Content>
|
|
2447
|
+
</Combobox>
|
|
2448
|
+
```
|
|
2449
|
+
|
|
2450
|
+
```tsx
|
|
2451
|
+
<Combobox
|
|
2452
|
+
value={value}
|
|
2453
|
+
onValueChange={(v) => setValue(v as Language)}
|
|
2454
|
+
items={languages}
|
|
2455
|
+
>
|
|
2456
|
+
<Combobox.TriggerValue className="w-[200px]" />
|
|
2457
|
+
<Combobox.Content>
|
|
2458
|
+
<Combobox.Input placeholder="Search languages" />
|
|
2459
|
+
<Combobox.Empty />
|
|
2460
|
+
<Combobox.List>
|
|
2461
|
+
{(item: Language) => (
|
|
2462
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2463
|
+
{item.emoji} {item.label}
|
|
2464
|
+
</Combobox.Item>
|
|
2465
|
+
)}
|
|
2466
|
+
</Combobox.List>
|
|
2467
|
+
</Combobox.Content>
|
|
2468
|
+
</Combobox>
|
|
2469
|
+
```
|
|
2470
|
+
|
|
2471
|
+
```tsx
|
|
2472
|
+
<Combobox
|
|
2473
|
+
value={value}
|
|
2474
|
+
onValueChange={(v) => setValue(v as ServerLocation | null)}
|
|
2475
|
+
items={servers}
|
|
2476
|
+
>
|
|
2477
|
+
<Combobox.TriggerInput className="w-[200px]" placeholder="Select server" />
|
|
2478
|
+
<Combobox.Content>
|
|
2479
|
+
<Combobox.Empty />
|
|
2480
|
+
<Combobox.List>
|
|
2481
|
+
{(group: ServerLocationGroup) => (
|
|
2482
|
+
<Combobox.Group key={group.value} items={group.items}>
|
|
2483
|
+
<Combobox.GroupLabel>{group.value}</Combobox.GroupLabel>
|
|
2484
|
+
<Combobox.Collection>
|
|
2485
|
+
{(item: ServerLocation) => (
|
|
2486
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2487
|
+
{item.label}
|
|
2488
|
+
</Combobox.Item>
|
|
2489
|
+
)}
|
|
2490
|
+
</Combobox.Collection>
|
|
2491
|
+
</Combobox.Group>
|
|
2492
|
+
)}
|
|
2493
|
+
</Combobox.List>
|
|
2494
|
+
</Combobox.Content>
|
|
2495
|
+
</Combobox>
|
|
2496
|
+
```
|
|
2497
|
+
|
|
2498
|
+
```tsx
|
|
2499
|
+
<div className="flex gap-2">
|
|
2500
|
+
<Combobox
|
|
2501
|
+
value={value}
|
|
2502
|
+
onValueChange={setValue}
|
|
2503
|
+
items={bots}
|
|
2504
|
+
isItemEqualToValue={(bot: BotItem, selected: BotItem) =>
|
|
2505
|
+
bot.value === selected.value
|
|
2506
|
+
}
|
|
2507
|
+
multiple
|
|
2508
|
+
>
|
|
2509
|
+
<Combobox.TriggerMultipleWithInput
|
|
2510
|
+
className="w-[400px]"
|
|
2511
|
+
placeholder="Select bots"
|
|
2512
|
+
renderItem={(selected: BotItem) => (
|
|
2513
|
+
<Combobox.Chip key={selected.value}>{selected.label}</Combobox.Chip>
|
|
2514
|
+
)}
|
|
2515
|
+
inputSide="right"
|
|
2516
|
+
/>
|
|
2517
|
+
<Combobox.Content className="max-h-[200px] min-w-auto overflow-y-auto">
|
|
2518
|
+
<Combobox.Empty />
|
|
2519
|
+
<Combobox.List>
|
|
2520
|
+
{(item: BotItem) => (
|
|
2521
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2522
|
+
<div className="flex gap-2">
|
|
2523
|
+
<Text>{item.label}</Text>
|
|
2524
|
+
<Text variant="secondary">{item.author}</Text>
|
|
2525
|
+
</div>
|
|
2526
|
+
</Combobox.Item>
|
|
2527
|
+
)}
|
|
2528
|
+
</Combobox.List>
|
|
2529
|
+
</Combobox.Content>
|
|
2530
|
+
</Combobox>
|
|
2531
|
+
<Button variant="primary">Submit</Button>
|
|
2532
|
+
</div>
|
|
2533
|
+
```
|
|
2534
|
+
|
|
2535
|
+
```tsx
|
|
2536
|
+
<div className="w-80">
|
|
2537
|
+
<Combobox
|
|
2538
|
+
items={databases}
|
|
2539
|
+
value={value}
|
|
2540
|
+
onValueChange={setValue}
|
|
2541
|
+
label="Database"
|
|
2542
|
+
description="Select your preferred database"
|
|
2543
|
+
>
|
|
2544
|
+
<Combobox.TriggerInput placeholder="Select database" />
|
|
2545
|
+
<Combobox.Content>
|
|
2546
|
+
<Combobox.Empty />
|
|
2547
|
+
<Combobox.List>
|
|
2548
|
+
{(item: DatabaseItem) => (
|
|
2549
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2550
|
+
{item.label}
|
|
2551
|
+
</Combobox.Item>
|
|
2552
|
+
)}
|
|
2553
|
+
</Combobox.List>
|
|
2554
|
+
</Combobox.Content>
|
|
2555
|
+
</Combobox>
|
|
2556
|
+
</div>
|
|
2557
|
+
```
|
|
2558
|
+
|
|
2559
|
+
```tsx
|
|
2560
|
+
<div className="w-80">
|
|
2561
|
+
<Combobox
|
|
2562
|
+
items={databases}
|
|
2563
|
+
value={value}
|
|
2564
|
+
onValueChange={setValue}
|
|
2565
|
+
label="Database"
|
|
2566
|
+
error={{ match: true, message: "Please select a database" }}
|
|
2567
|
+
>
|
|
2568
|
+
<Combobox.TriggerInput placeholder="Select database" />
|
|
2569
|
+
<Combobox.Content>
|
|
2570
|
+
<Combobox.Empty />
|
|
2571
|
+
<Combobox.List>
|
|
2572
|
+
{(item: DatabaseItem) => (
|
|
2573
|
+
<Combobox.Item key={item.value} value={item}>
|
|
2574
|
+
{item.label}
|
|
2575
|
+
</Combobox.Item>
|
|
2576
|
+
)}
|
|
2577
|
+
</Combobox.List>
|
|
2578
|
+
</Combobox.Content>
|
|
2579
|
+
</Combobox>
|
|
2580
|
+
</div>
|
|
2581
|
+
```
|
|
2582
|
+
|
|
1261
2583
|
---
|
|
1262
2584
|
|
|
1263
2585
|
### CommandPalette
|
|
@@ -1281,6 +2603,216 @@ CommandPalette — accessible command palette / spotlight search overlay. Compou
|
|
|
1281
2603
|
|
|
1282
2604
|
`bg-sf-elevated`, `bg-sf-overlay`, `bg-sf-warning`, `ring-sf-line`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
|
|
1283
2605
|
|
|
2606
|
+
**Examples:**
|
|
2607
|
+
|
|
2608
|
+
```tsx
|
|
2609
|
+
<div className="flex flex-col items-start gap-4">
|
|
2610
|
+
<Button onClick={() => setOpen(true)}>Open Command Palette</Button>
|
|
2611
|
+
{selectedItem && (
|
|
2612
|
+
<p className="text-sm text-sf-subtle">
|
|
2613
|
+
Last selected: <span className="text-sf-default">{selectedItem}</span>
|
|
2614
|
+
</p>
|
|
2615
|
+
)}
|
|
2616
|
+
|
|
2617
|
+
<CommandPalette.Root
|
|
2618
|
+
open={open}
|
|
2619
|
+
onOpenChange={setOpen}
|
|
2620
|
+
items={sampleGroups}
|
|
2621
|
+
value={search}
|
|
2622
|
+
onValueChange={setSearch}
|
|
2623
|
+
itemToStringValue={(group) => group.label}
|
|
2624
|
+
onSelect={(item, { newTab }) => {
|
|
2625
|
+
console.log("Selected:", item.title, newTab ? "(new tab)" : "");
|
|
2626
|
+
handleSelect(item);
|
|
2627
|
+
}}
|
|
2628
|
+
getSelectableItems={getSelectableItems}
|
|
2629
|
+
>
|
|
2630
|
+
<CommandPalette.Input placeholder="Type a command or search..." />
|
|
2631
|
+
<CommandPalette.List>
|
|
2632
|
+
<CommandPalette.Results>
|
|
2633
|
+
{(group: CommandGroup) => (
|
|
2634
|
+
<CommandPalette.Group key={group.id}>
|
|
2635
|
+
<CommandPalette.GroupLabel>{group.label}</CommandPalette.GroupLabel>
|
|
2636
|
+
<CommandPalette.Items>
|
|
2637
|
+
{(item: CommandItem) => (
|
|
2638
|
+
<CommandPalette.Item
|
|
2639
|
+
key={item.id}
|
|
2640
|
+
value={item}
|
|
2641
|
+
onClick={() => handleSelect(item)}
|
|
2642
|
+
>
|
|
2643
|
+
<span className="flex items-center gap-3">
|
|
2644
|
+
{item.icon && (
|
|
2645
|
+
<span className="text-sf-subtle">{item.icon}</span>
|
|
2646
|
+
)}
|
|
2647
|
+
<span>{item.title}</span>
|
|
2648
|
+
</span>
|
|
2649
|
+
</CommandPalette.Item>
|
|
2650
|
+
)}
|
|
2651
|
+
</CommandPalette.Items>
|
|
2652
|
+
</CommandPalette.Group>
|
|
2653
|
+
)}
|
|
2654
|
+
</CommandPalette.Results>
|
|
2655
|
+
<CommandPalette.Empty>No commands found</CommandPalette.Empty>
|
|
2656
|
+
</CommandPalette.List>
|
|
2657
|
+
<CommandPalette.Footer>
|
|
2658
|
+
<span className="flex items-center gap-2">
|
|
2659
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2660
|
+
↑↓
|
|
2661
|
+
</kbd>
|
|
2662
|
+
<span>Navigate</span>
|
|
2663
|
+
</span>
|
|
2664
|
+
<span className="flex items-center gap-2">
|
|
2665
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2666
|
+
↵
|
|
2667
|
+
</kbd>
|
|
2668
|
+
<span>Select</span>
|
|
2669
|
+
</span>
|
|
2670
|
+
</CommandPalette.Footer>
|
|
2671
|
+
</CommandPalette.Root>
|
|
2672
|
+
</div>
|
|
2673
|
+
```
|
|
2674
|
+
|
|
2675
|
+
```tsx
|
|
2676
|
+
<div>
|
|
2677
|
+
<Button onClick={() => setOpen(true)}>Open Simple Palette</Button>
|
|
2678
|
+
|
|
2679
|
+
<CommandPalette.Root
|
|
2680
|
+
open={open}
|
|
2681
|
+
onOpenChange={setOpen}
|
|
2682
|
+
items={simpleItems}
|
|
2683
|
+
value={search}
|
|
2684
|
+
onValueChange={setSearch}
|
|
2685
|
+
itemToStringValue={(item) => item.title}
|
|
2686
|
+
onSelect={(item) => {
|
|
2687
|
+
console.log("Selected:", item.title);
|
|
2688
|
+
setOpen(false);
|
|
2689
|
+
}}
|
|
2690
|
+
getSelectableItems={(items) => items}
|
|
2691
|
+
>
|
|
2692
|
+
<CommandPalette.Input placeholder="Search actions..." />
|
|
2693
|
+
<CommandPalette.List>
|
|
2694
|
+
<CommandPalette.Results>
|
|
2695
|
+
{(item: SimpleItem) => (
|
|
2696
|
+
<CommandPalette.Item
|
|
2697
|
+
key={item.id}
|
|
2698
|
+
value={item}
|
|
2699
|
+
onClick={() => {
|
|
2700
|
+
console.log("Clicked:", item.title);
|
|
2701
|
+
setOpen(false);
|
|
2702
|
+
}}
|
|
2703
|
+
>
|
|
2704
|
+
{item.title}
|
|
2705
|
+
</CommandPalette.Item>
|
|
2706
|
+
)}
|
|
2707
|
+
</CommandPalette.Results>
|
|
2708
|
+
<CommandPalette.Empty>No actions found</CommandPalette.Empty>
|
|
2709
|
+
</CommandPalette.List>
|
|
2710
|
+
</CommandPalette.Root>
|
|
2711
|
+
</div>
|
|
2712
|
+
```
|
|
2713
|
+
|
|
2714
|
+
```tsx
|
|
2715
|
+
<div>
|
|
2716
|
+
<Button onClick={handleOpen}>Open with Loading</Button>
|
|
2717
|
+
|
|
2718
|
+
<CommandPalette.Root
|
|
2719
|
+
open={open}
|
|
2720
|
+
onOpenChange={setOpen}
|
|
2721
|
+
items={loading ? [] : sampleGroups}
|
|
2722
|
+
value={search}
|
|
2723
|
+
onValueChange={setSearch}
|
|
2724
|
+
itemToStringValue={(group) => group.label}
|
|
2725
|
+
getSelectableItems={getSelectableItems}
|
|
2726
|
+
>
|
|
2727
|
+
<CommandPalette.Input placeholder="Search..." />
|
|
2728
|
+
<CommandPalette.List>
|
|
2729
|
+
{loading ? (
|
|
2730
|
+
<CommandPalette.Loading />
|
|
2731
|
+
) : (
|
|
2732
|
+
<>
|
|
2733
|
+
<CommandPalette.Results>
|
|
2734
|
+
{(group: CommandGroup) => (
|
|
2735
|
+
<CommandPalette.Group key={group.id}>
|
|
2736
|
+
<CommandPalette.GroupLabel>
|
|
2737
|
+
{group.label}
|
|
2738
|
+
</CommandPalette.GroupLabel>
|
|
2739
|
+
<CommandPalette.Items>
|
|
2740
|
+
{(item: CommandItem) => (
|
|
2741
|
+
<CommandPalette.Item
|
|
2742
|
+
key={item.id}
|
|
2743
|
+
value={item}
|
|
2744
|
+
onClick={() => setOpen(false)}
|
|
2745
|
+
>
|
|
2746
|
+
<span className="flex items-center gap-3">
|
|
2747
|
+
{item.icon && (
|
|
2748
|
+
<span className="text-sf-subtle">{item.icon}</span>
|
|
2749
|
+
)}
|
|
2750
|
+
<span>{item.title}</span>
|
|
2751
|
+
</span>
|
|
2752
|
+
</CommandPalette.Item>
|
|
2753
|
+
)}
|
|
2754
|
+
</CommandPalette.Items>
|
|
2755
|
+
</CommandPalette.Group>
|
|
2756
|
+
)}
|
|
2757
|
+
</CommandPalette.Results>
|
|
2758
|
+
<CommandPalette.Empty>No results found</CommandPalette.Empty>
|
|
2759
|
+
</>
|
|
2760
|
+
)}
|
|
2761
|
+
</CommandPalette.List>
|
|
2762
|
+
</CommandPalette.Root>
|
|
2763
|
+
</div>
|
|
2764
|
+
```
|
|
2765
|
+
|
|
2766
|
+
```tsx
|
|
2767
|
+
<div>
|
|
2768
|
+
<Button onClick={() => setOpen(true)}>Open with ResultItem</Button>
|
|
2769
|
+
|
|
2770
|
+
<CommandPalette.Root
|
|
2771
|
+
open={open}
|
|
2772
|
+
onOpenChange={setOpen}
|
|
2773
|
+
items={searchResults}
|
|
2774
|
+
value={search}
|
|
2775
|
+
onValueChange={setSearch}
|
|
2776
|
+
itemToStringValue={(item) => item.title}
|
|
2777
|
+
getSelectableItems={(items) => items}
|
|
2778
|
+
>
|
|
2779
|
+
<CommandPalette.Input placeholder="Search documentation..." />
|
|
2780
|
+
<CommandPalette.List>
|
|
2781
|
+
<CommandPalette.Results>
|
|
2782
|
+
{(item: SearchResult) => (
|
|
2783
|
+
<CommandPalette.ResultItem
|
|
2784
|
+
key={item.id}
|
|
2785
|
+
value={item}
|
|
2786
|
+
title={item.title}
|
|
2787
|
+
breadcrumbs={item.breadcrumbs}
|
|
2788
|
+
icon={item.icon}
|
|
2789
|
+
onClick={() => {
|
|
2790
|
+
console.log("Navigate to:", item.title);
|
|
2791
|
+
setOpen(false);
|
|
2792
|
+
}}
|
|
2793
|
+
/>
|
|
2794
|
+
)}
|
|
2795
|
+
</CommandPalette.Results>
|
|
2796
|
+
<CommandPalette.Empty>No pages found</CommandPalette.Empty>
|
|
2797
|
+
</CommandPalette.List>
|
|
2798
|
+
<CommandPalette.Footer>
|
|
2799
|
+
<span className="flex items-center gap-2">
|
|
2800
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2801
|
+
↑↓
|
|
2802
|
+
</kbd>
|
|
2803
|
+
<span>Navigate</span>
|
|
2804
|
+
</span>
|
|
2805
|
+
<span className="flex items-center gap-2">
|
|
2806
|
+
<kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
|
|
2807
|
+
⌘↵
|
|
2808
|
+
</kbd>
|
|
2809
|
+
<span>Open in new tab</span>
|
|
2810
|
+
</span>
|
|
2811
|
+
</CommandPalette.Footer>
|
|
2812
|
+
</CommandPalette.Root>
|
|
2813
|
+
</div>
|
|
2814
|
+
```
|
|
2815
|
+
|
|
1284
2816
|
---
|
|
1285
2817
|
|
|
1286
2818
|
### DataGrid
|
|
@@ -1331,6 +2863,137 @@ ColumnToggle sub-component
|
|
|
1331
2863
|
|
|
1332
2864
|
Empty sub-component
|
|
1333
2865
|
|
|
2866
|
+
**Examples:**
|
|
2867
|
+
|
|
2868
|
+
```tsx
|
|
2869
|
+
<LayerCard>
|
|
2870
|
+
<LayerCard.Primary className="p-0">
|
|
2871
|
+
<DataGrid data={sampleUsers} columns={columns} enableSorting>
|
|
2872
|
+
<DataGrid.Content />
|
|
2873
|
+
</DataGrid>
|
|
2874
|
+
</LayerCard.Primary>
|
|
2875
|
+
</LayerCard>
|
|
2876
|
+
```
|
|
2877
|
+
|
|
2878
|
+
```tsx
|
|
2879
|
+
<LayerCard>
|
|
2880
|
+
<LayerCard.Primary className="p-0">
|
|
2881
|
+
<DataGrid
|
|
2882
|
+
data={paginatedData}
|
|
2883
|
+
columns={columns.slice(0, 3)}
|
|
2884
|
+
pageSize={pageSize}
|
|
2885
|
+
pageIndex={pageIndex}
|
|
2886
|
+
onPaginationChange={({ pageIndex: newPage }) => setPageIndex(newPage)}
|
|
2887
|
+
totalCount={totalCount}
|
|
2888
|
+
manualPagination
|
|
2889
|
+
>
|
|
2890
|
+
<DataGrid.Content />
|
|
2891
|
+
<DataGrid.Pagination />
|
|
2892
|
+
</DataGrid>
|
|
2893
|
+
</LayerCard.Primary>
|
|
2894
|
+
</LayerCard>
|
|
2895
|
+
```
|
|
2896
|
+
|
|
2897
|
+
```tsx
|
|
2898
|
+
<LayerCard>
|
|
2899
|
+
<LayerCard.Primary className="p-0">
|
|
2900
|
+
<DataGrid
|
|
2901
|
+
data={sampleUsers.slice(0, 4)}
|
|
2902
|
+
columns={columns}
|
|
2903
|
+
enableRowSelection
|
|
2904
|
+
rowSelection={rowSelection}
|
|
2905
|
+
onRowSelectionChange={setRowSelection}
|
|
2906
|
+
>
|
|
2907
|
+
<DataGrid.Content />
|
|
2908
|
+
</DataGrid>
|
|
2909
|
+
<div className="border-t border-sf-line p-3 text-sm">
|
|
2910
|
+
<p className="text-sf-subtle">
|
|
2911
|
+
Selected: {Object.keys(rowSelection).length} rows
|
|
2912
|
+
</p>
|
|
2913
|
+
</div>
|
|
2914
|
+
</LayerCard.Primary>
|
|
2915
|
+
</LayerCard>
|
|
2916
|
+
```
|
|
2917
|
+
|
|
2918
|
+
```tsx
|
|
2919
|
+
<LayerCard>
|
|
2920
|
+
<LayerCard.Primary className="p-0">
|
|
2921
|
+
<DataGrid
|
|
2922
|
+
data={sampleUsers.slice(0, 4)}
|
|
2923
|
+
columns={columns}
|
|
2924
|
+
columnVisibility={columnVisibility}
|
|
2925
|
+
onColumnVisibilityChange={setColumnVisibility}
|
|
2926
|
+
>
|
|
2927
|
+
<DataGrid.Toolbar className="p-3">
|
|
2928
|
+
<DataGrid.ColumnToggle />
|
|
2929
|
+
</DataGrid.Toolbar>
|
|
2930
|
+
<DataGrid.Content />
|
|
2931
|
+
</DataGrid>
|
|
2932
|
+
</LayerCard.Primary>
|
|
2933
|
+
</LayerCard>
|
|
2934
|
+
```
|
|
2935
|
+
|
|
2936
|
+
```tsx
|
|
2937
|
+
<LayerCard>
|
|
2938
|
+
<LayerCard.Primary className="p-0">
|
|
2939
|
+
<DataGrid data={sampleUsers} columns={columns} enableSorting>
|
|
2940
|
+
<DataGrid.Toolbar className="flex items-center justify-between p-3">
|
|
2941
|
+
<span className="text-sm font-medium">Users</span>
|
|
2942
|
+
<DataGrid.ColumnToggle />
|
|
2943
|
+
</DataGrid.Toolbar>
|
|
2944
|
+
<DataGrid.Content />
|
|
2945
|
+
</DataGrid>
|
|
2946
|
+
</LayerCard.Primary>
|
|
2947
|
+
</LayerCard>
|
|
2948
|
+
```
|
|
2949
|
+
|
|
2950
|
+
```tsx
|
|
2951
|
+
<LayerCard>
|
|
2952
|
+
<LayerCard.Primary className="p-0">
|
|
2953
|
+
<DataGrid
|
|
2954
|
+
data={[]}
|
|
2955
|
+
columns={columns.slice(0, 3)}
|
|
2956
|
+
emptyState={
|
|
2957
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
2958
|
+
<p className="text-sf-strong font-medium">No users found</p>
|
|
2959
|
+
<p className="text-sf-subtle mt-1 text-sm">
|
|
2960
|
+
Try adjusting your filters or add new users
|
|
2961
|
+
</p>
|
|
2962
|
+
</div>
|
|
2963
|
+
}
|
|
2964
|
+
>
|
|
2965
|
+
<DataGrid.Content />
|
|
2966
|
+
</DataGrid>
|
|
2967
|
+
</LayerCard.Primary>
|
|
2968
|
+
</LayerCard>
|
|
2969
|
+
```
|
|
2970
|
+
|
|
2971
|
+
```tsx
|
|
2972
|
+
<LayerCard>
|
|
2973
|
+
<LayerCard.Primary className="p-0">
|
|
2974
|
+
<DataGrid data={[]} columns={columns.slice(0, 3)} loading loadingRows={3}>
|
|
2975
|
+
<DataGrid.Content />
|
|
2976
|
+
</DataGrid>
|
|
2977
|
+
</LayerCard.Primary>
|
|
2978
|
+
</LayerCard>
|
|
2979
|
+
```
|
|
2980
|
+
|
|
2981
|
+
```tsx
|
|
2982
|
+
<LayerCard>
|
|
2983
|
+
<LayerCard.Primary className="p-0">
|
|
2984
|
+
<DataGrid
|
|
2985
|
+
data={sampleUsers}
|
|
2986
|
+
columns={resizableColumns}
|
|
2987
|
+
enableSorting
|
|
2988
|
+
enableColumnResizing
|
|
2989
|
+
columnResizeMode="onEnd"
|
|
2990
|
+
>
|
|
2991
|
+
<DataGrid.Content />
|
|
2992
|
+
</DataGrid>
|
|
2993
|
+
</LayerCard.Primary>
|
|
2994
|
+
</LayerCard>
|
|
2995
|
+
```
|
|
2996
|
+
|
|
1334
2997
|
---
|
|
1335
2998
|
|
|
1336
2999
|
### DatePicker
|
|
@@ -1354,6 +3017,154 @@ DatePicker — a date selection calendar. Built on [react-day-picker](https://da
|
|
|
1354
3017
|
|
|
1355
3018
|
`bg-sf-base`
|
|
1356
3019
|
|
|
3020
|
+
**Examples:**
|
|
3021
|
+
|
|
3022
|
+
```tsx
|
|
3023
|
+
<div className="flex flex-col gap-4">
|
|
3024
|
+
<DatePicker
|
|
3025
|
+
mode="single"
|
|
3026
|
+
selected={date}
|
|
3027
|
+
onChange={(d) => {
|
|
3028
|
+
if (d) {
|
|
3029
|
+
setDate(d);
|
|
3030
|
+
}
|
|
3031
|
+
}}
|
|
3032
|
+
/>
|
|
3033
|
+
<p className="text-sm text-sf-subtle">
|
|
3034
|
+
Selected: {date ? date.toLocaleDateString() : "None"}
|
|
3035
|
+
</p>
|
|
3036
|
+
</div>
|
|
3037
|
+
```
|
|
3038
|
+
|
|
3039
|
+
```tsx
|
|
3040
|
+
<div className="flex flex-col gap-4">
|
|
3041
|
+
<DatePicker mode="multiple" selected={dates} onChange={setDates} max={5} />
|
|
3042
|
+
<p className="text-sm text-sf-subtle">
|
|
3043
|
+
Selected: {dates?.length ?? 0} date(s)
|
|
3044
|
+
</p>
|
|
3045
|
+
</div>
|
|
3046
|
+
```
|
|
3047
|
+
|
|
3048
|
+
```tsx
|
|
3049
|
+
<div className="flex flex-col gap-4">
|
|
3050
|
+
<DatePicker
|
|
3051
|
+
mode="range"
|
|
3052
|
+
selected={range}
|
|
3053
|
+
onChange={setRange}
|
|
3054
|
+
numberOfMonths={2}
|
|
3055
|
+
/>
|
|
3056
|
+
<p className="text-sm text-sf-subtle">
|
|
3057
|
+
Range:{" "}
|
|
3058
|
+
{range?.from
|
|
3059
|
+
? `${range.from.toLocaleDateString()} - ${range.to?.toLocaleDateString() ?? "..."}`
|
|
3060
|
+
: "None"}
|
|
3061
|
+
</p>
|
|
3062
|
+
</div>
|
|
3063
|
+
```
|
|
3064
|
+
|
|
3065
|
+
```tsx
|
|
3066
|
+
<div className="flex flex-col gap-4">
|
|
3067
|
+
<DatePicker
|
|
3068
|
+
mode="range"
|
|
3069
|
+
selected={range}
|
|
3070
|
+
onChange={setRange}
|
|
3071
|
+
min={3}
|
|
3072
|
+
max={7}
|
|
3073
|
+
footer={<span className="text-xs text-sf-subtle">Select 3-7 nights</span>}
|
|
3074
|
+
/>
|
|
3075
|
+
</div>
|
|
3076
|
+
```
|
|
3077
|
+
|
|
3078
|
+
```tsx
|
|
3079
|
+
<Popover>
|
|
3080
|
+
<Popover.Trigger asChild>
|
|
3081
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3082
|
+
{date ? date.toLocaleDateString() : "Pick a date"}
|
|
3083
|
+
</Button>
|
|
3084
|
+
</Popover.Trigger>
|
|
3085
|
+
<Popover.Content className="p-3">
|
|
3086
|
+
<DatePicker mode="single" selected={date} onChange={setDate} />
|
|
3087
|
+
</Popover.Content>
|
|
3088
|
+
</Popover>
|
|
3089
|
+
```
|
|
3090
|
+
|
|
3091
|
+
```tsx
|
|
3092
|
+
<Popover>
|
|
3093
|
+
<Popover.Trigger asChild>
|
|
3094
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3095
|
+
{formatRange()}
|
|
3096
|
+
</Button>
|
|
3097
|
+
</Popover.Trigger>
|
|
3098
|
+
<Popover.Content className="p-3">
|
|
3099
|
+
<DatePicker
|
|
3100
|
+
mode="range"
|
|
3101
|
+
selected={range}
|
|
3102
|
+
onChange={setRange}
|
|
3103
|
+
numberOfMonths={2}
|
|
3104
|
+
/>
|
|
3105
|
+
</Popover.Content>
|
|
3106
|
+
</Popover>
|
|
3107
|
+
```
|
|
3108
|
+
|
|
3109
|
+
```tsx
|
|
3110
|
+
<Popover>
|
|
3111
|
+
<Popover.Trigger asChild>
|
|
3112
|
+
<Button variant="outline" icon={CalendarDotsIcon}>
|
|
3113
|
+
{formatRange()}
|
|
3114
|
+
</Button>
|
|
3115
|
+
</Popover.Trigger>
|
|
3116
|
+
<Popover.Content className="p-0">
|
|
3117
|
+
<div className="flex">
|
|
3118
|
+
<div className="flex flex-col gap-1 border-r border-sf-line p-2 text-sm">
|
|
3119
|
+
{presets.map((preset) => {
|
|
3120
|
+
const isActive = isPresetActive(preset);
|
|
3121
|
+
return (
|
|
3122
|
+
<button
|
|
3123
|
+
key={preset.label}
|
|
3124
|
+
type="button"
|
|
3125
|
+
onClick={() => handlePresetClick(preset)}
|
|
3126
|
+
className={`rounded-md px-3 py-1.5 text-left whitespace-nowrap ${
|
|
3127
|
+
isActive
|
|
3128
|
+
? "bg-sf-bg-inverse text-sf-text-inverse"
|
|
3129
|
+
: "text-sf-strong hover:bg-sf-control"
|
|
3130
|
+
}`}
|
|
3131
|
+
>
|
|
3132
|
+
{preset.label}
|
|
3133
|
+
</button>
|
|
3134
|
+
);
|
|
3135
|
+
})}
|
|
3136
|
+
</div>
|
|
3137
|
+
<div className="p-3">
|
|
3138
|
+
<DatePicker
|
|
3139
|
+
mode="range"
|
|
3140
|
+
selected={range}
|
|
3141
|
+
onChange={setRange}
|
|
3142
|
+
month={month}
|
|
3143
|
+
onMonthChange={setMonth}
|
|
3144
|
+
numberOfMonths={2}
|
|
3145
|
+
/>
|
|
3146
|
+
</div>
|
|
3147
|
+
</div>
|
|
3148
|
+
</Popover.Content>
|
|
3149
|
+
</Popover>
|
|
3150
|
+
```
|
|
3151
|
+
|
|
3152
|
+
```tsx
|
|
3153
|
+
<DatePicker
|
|
3154
|
+
mode="multiple"
|
|
3155
|
+
selected={dates}
|
|
3156
|
+
onChange={setDates}
|
|
3157
|
+
max={maxDays}
|
|
3158
|
+
disabled={unavailableDates}
|
|
3159
|
+
fixedWeeks
|
|
3160
|
+
footer={
|
|
3161
|
+
<p className="text-xs text-sf-subtle pt-2 w-full">
|
|
3162
|
+
{selectedCount}/{maxDays} days selected. Grayed dates are unavailable.
|
|
3163
|
+
</p>
|
|
3164
|
+
}
|
|
3165
|
+
/>
|
|
3166
|
+
```
|
|
3167
|
+
|
|
1357
3168
|
---
|
|
1358
3169
|
|
|
1359
3170
|
### DateRangePicker
|
|
@@ -1478,6 +3289,228 @@ Description sub-component
|
|
|
1478
3289
|
|
|
1479
3290
|
Close sub-component
|
|
1480
3291
|
|
|
3292
|
+
**Examples:**
|
|
3293
|
+
|
|
3294
|
+
```tsx
|
|
3295
|
+
<Dialog.Root>
|
|
3296
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />
|
|
3297
|
+
<Dialog className="p-8">
|
|
3298
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3299
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3300
|
+
Modal Title
|
|
3301
|
+
</Dialog.Title>
|
|
3302
|
+
<Dialog.Close
|
|
3303
|
+
aria-label="Close"
|
|
3304
|
+
render={(props) => (
|
|
3305
|
+
<Button
|
|
3306
|
+
{...props}
|
|
3307
|
+
variant="secondary"
|
|
3308
|
+
shape="square"
|
|
3309
|
+
icon={<XIcon />}
|
|
3310
|
+
aria-label="Close"
|
|
3311
|
+
/>
|
|
3312
|
+
)}
|
|
3313
|
+
/>
|
|
3314
|
+
</div>
|
|
3315
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3316
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
3317
|
+
tempor incididunt ut labore et dolore magna aliqua.
|
|
3318
|
+
</Dialog.Description>
|
|
3319
|
+
</Dialog>
|
|
3320
|
+
</Dialog.Root>
|
|
3321
|
+
```
|
|
3322
|
+
|
|
3323
|
+
```tsx
|
|
3324
|
+
<Dialog.Root>
|
|
3325
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />
|
|
3326
|
+
<Dialog className="p-8">
|
|
3327
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3328
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3329
|
+
Modal Title
|
|
3330
|
+
</Dialog.Title>
|
|
3331
|
+
<Dialog.Close
|
|
3332
|
+
aria-label="Close"
|
|
3333
|
+
render={(props) => (
|
|
3334
|
+
<Button
|
|
3335
|
+
{...props}
|
|
3336
|
+
variant="secondary"
|
|
3337
|
+
shape="square"
|
|
3338
|
+
icon={<XIcon />}
|
|
3339
|
+
aria-label="Close"
|
|
3340
|
+
/>
|
|
3341
|
+
)}
|
|
3342
|
+
/>
|
|
3343
|
+
</div>
|
|
3344
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3345
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
3346
|
+
tempor incididunt ut labore et dolore magna aliqua.
|
|
3347
|
+
</Dialog.Description>
|
|
3348
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3349
|
+
<Dialog.Close
|
|
3350
|
+
render={(props) => (
|
|
3351
|
+
<Button variant="secondary" {...props}>
|
|
3352
|
+
Cancel
|
|
3353
|
+
</Button>
|
|
3354
|
+
)}
|
|
3355
|
+
/>
|
|
3356
|
+
<Dialog.Close
|
|
3357
|
+
render={(props) => (
|
|
3358
|
+
<Button variant="destructive" {...props}>
|
|
3359
|
+
Delete
|
|
3360
|
+
</Button>
|
|
3361
|
+
)}
|
|
3362
|
+
/>
|
|
3363
|
+
</div>
|
|
3364
|
+
</Dialog>
|
|
3365
|
+
</Dialog.Root>
|
|
3366
|
+
```
|
|
3367
|
+
|
|
3368
|
+
```tsx
|
|
3369
|
+
<Dialog.Root disablePointerDismissal>
|
|
3370
|
+
<Dialog.Trigger
|
|
3371
|
+
render={(p) => (
|
|
3372
|
+
<Button {...p} variant="destructive">
|
|
3373
|
+
Delete Project
|
|
3374
|
+
</Button>
|
|
3375
|
+
)}
|
|
3376
|
+
/>
|
|
3377
|
+
<Dialog className="p-8">
|
|
3378
|
+
<div className="mb-4 flex items-center gap-3">
|
|
3379
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-sf-danger/20">
|
|
3380
|
+
<WarningIcon size={20} className="text-sf-danger" />
|
|
3381
|
+
</div>
|
|
3382
|
+
<Dialog.Title className="text-xl font-semibold">
|
|
3383
|
+
Delete Project?
|
|
3384
|
+
</Dialog.Title>
|
|
3385
|
+
</div>
|
|
3386
|
+
<Dialog.Description className="text-sf-subtle">
|
|
3387
|
+
This action cannot be undone. This will permanently delete the project and
|
|
3388
|
+
all associated data.
|
|
3389
|
+
</Dialog.Description>
|
|
3390
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3391
|
+
<Dialog.Close
|
|
3392
|
+
render={(props) => (
|
|
3393
|
+
<Button variant="secondary" {...props}>
|
|
3394
|
+
Cancel
|
|
3395
|
+
</Button>
|
|
3396
|
+
)}
|
|
3397
|
+
/>
|
|
3398
|
+
<Dialog.Close
|
|
3399
|
+
render={(props) => (
|
|
3400
|
+
<Button variant="destructive" {...props}>
|
|
3401
|
+
Delete
|
|
3402
|
+
</Button>
|
|
3403
|
+
)}
|
|
3404
|
+
/>
|
|
3405
|
+
</div>
|
|
3406
|
+
</Dialog>
|
|
3407
|
+
</Dialog.Root>
|
|
3408
|
+
```
|
|
3409
|
+
|
|
3410
|
+
```tsx
|
|
3411
|
+
<Dialog.Root>
|
|
3412
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
|
|
3413
|
+
<Dialog className="p-8">
|
|
3414
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3415
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3416
|
+
Create Resource
|
|
3417
|
+
</Dialog.Title>
|
|
3418
|
+
<Dialog.Close
|
|
3419
|
+
aria-label="Close"
|
|
3420
|
+
render={(props) => (
|
|
3421
|
+
<Button
|
|
3422
|
+
{...props}
|
|
3423
|
+
variant="secondary"
|
|
3424
|
+
shape="square"
|
|
3425
|
+
icon={<XIcon />}
|
|
3426
|
+
aria-label="Close"
|
|
3427
|
+
/>
|
|
3428
|
+
)}
|
|
3429
|
+
/>
|
|
3430
|
+
</div>
|
|
3431
|
+
<Dialog.Description className="mb-4 text-sf-subtle">
|
|
3432
|
+
Select a region for your new resource.
|
|
3433
|
+
</Dialog.Description>
|
|
3434
|
+
<Select
|
|
3435
|
+
className="w-full"
|
|
3436
|
+
renderValue={(v) =>
|
|
3437
|
+
regions.find((r) => r.value === v)?.label ?? "Select region..."
|
|
3438
|
+
}
|
|
3439
|
+
>
|
|
3440
|
+
{regions.map((region) => (
|
|
3441
|
+
<Select.Option key={region.value} value={region.value}>
|
|
3442
|
+
{region.label}
|
|
3443
|
+
</Select.Option>
|
|
3444
|
+
))}
|
|
3445
|
+
</Select>
|
|
3446
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3447
|
+
<Dialog.Close
|
|
3448
|
+
render={(props) => (
|
|
3449
|
+
<Button variant="secondary" {...props}>
|
|
3450
|
+
Cancel
|
|
3451
|
+
</Button>
|
|
3452
|
+
)}
|
|
3453
|
+
/>
|
|
3454
|
+
<Button variant="primary">Create</Button>
|
|
3455
|
+
</div>
|
|
3456
|
+
</Dialog>
|
|
3457
|
+
</Dialog.Root>
|
|
3458
|
+
```
|
|
3459
|
+
|
|
3460
|
+
```tsx
|
|
3461
|
+
<Dialog.Root>
|
|
3462
|
+
<Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
|
|
3463
|
+
<Dialog className="p-8">
|
|
3464
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
3465
|
+
<Dialog.Title className="text-2xl font-semibold">
|
|
3466
|
+
Create Resource
|
|
3467
|
+
</Dialog.Title>
|
|
3468
|
+
<Dialog.Close
|
|
3469
|
+
aria-label="Close"
|
|
3470
|
+
render={(props) => (
|
|
3471
|
+
<Button
|
|
3472
|
+
{...props}
|
|
3473
|
+
variant="secondary"
|
|
3474
|
+
shape="square"
|
|
3475
|
+
icon={<XIcon />}
|
|
3476
|
+
aria-label="Close"
|
|
3477
|
+
/>
|
|
3478
|
+
)}
|
|
3479
|
+
/>
|
|
3480
|
+
</div>
|
|
3481
|
+
<Dialog.Description className="mb-4 text-sf-subtle">
|
|
3482
|
+
Search and select a region for your new resource.
|
|
3483
|
+
</Dialog.Description>
|
|
3484
|
+
<Combobox value={value} onValueChange={setValue} items={regions}>
|
|
3485
|
+
<Combobox.TriggerInput
|
|
3486
|
+
className="w-full"
|
|
3487
|
+
placeholder="Search regions..."
|
|
3488
|
+
/>
|
|
3489
|
+
<Combobox.Content>
|
|
3490
|
+
<Combobox.Empty>No regions found</Combobox.Empty>
|
|
3491
|
+
<Combobox.List>
|
|
3492
|
+
{(item: { value: string; label: string }) => (
|
|
3493
|
+
<Combobox.Item key={item.value} value={item}>
|
|
3494
|
+
{item.label}
|
|
3495
|
+
</Combobox.Item>
|
|
3496
|
+
)}
|
|
3497
|
+
</Combobox.List>
|
|
3498
|
+
</Combobox.Content>
|
|
3499
|
+
</Combobox>
|
|
3500
|
+
<div className="mt-8 flex justify-end gap-2">
|
|
3501
|
+
<Dialog.Close
|
|
3502
|
+
render={(props) => (
|
|
3503
|
+
<Button variant="secondary" {...props}>
|
|
3504
|
+
Cancel
|
|
3505
|
+
</Button>
|
|
3506
|
+
)}
|
|
3507
|
+
/>
|
|
3508
|
+
<Button variant="primary">Create</Button>
|
|
3509
|
+
</div>
|
|
3510
|
+
</Dialog>
|
|
3511
|
+
</Dialog.Root>
|
|
3512
|
+
```
|
|
3513
|
+
|
|
1481
3514
|
---
|
|
1482
3515
|
|
|
1483
3516
|
### DropdownMenu
|
|
@@ -1599,6 +3632,91 @@ Placeholder shown when a list, table, or page has no content to display.
|
|
|
1599
3632
|
|
|
1600
3633
|
`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
3634
|
|
|
3635
|
+
**Examples:**
|
|
3636
|
+
|
|
3637
|
+
```tsx
|
|
3638
|
+
<Empty
|
|
3639
|
+
icon={<PackageIcon size={48} />}
|
|
3640
|
+
title="No packages found"
|
|
3641
|
+
description="Get started by installing your first package."
|
|
3642
|
+
commandLine="npm install @signalflare-ai/ui"
|
|
3643
|
+
contents={
|
|
3644
|
+
<div className="flex items-center gap-2">
|
|
3645
|
+
<Button icon={<CodeIcon />}>See examples</Button>
|
|
3646
|
+
<Button icon={<GlobeIcon />} variant="primary">
|
|
3647
|
+
View documentation
|
|
3648
|
+
</Button>
|
|
3649
|
+
</div>
|
|
3650
|
+
}
|
|
3651
|
+
/>
|
|
3652
|
+
```
|
|
3653
|
+
|
|
3654
|
+
```tsx
|
|
3655
|
+
<div className="flex flex-col gap-8">
|
|
3656
|
+
<div>
|
|
3657
|
+
<p className="mb-2 text-sm text-sf-subtle">Small</p>
|
|
3658
|
+
<Empty
|
|
3659
|
+
size="sm"
|
|
3660
|
+
icon={<DatabaseIcon size={32} className="text-sf-inactive" />}
|
|
3661
|
+
title="No data available"
|
|
3662
|
+
description="There is no data to display."
|
|
3663
|
+
/>
|
|
3664
|
+
</div>
|
|
3665
|
+
<div>
|
|
3666
|
+
<p className="mb-2 text-sm text-sf-subtle">Base</p>
|
|
3667
|
+
<Empty
|
|
3668
|
+
size="base"
|
|
3669
|
+
icon={<DatabaseIcon size={48} className="text-sf-inactive" />}
|
|
3670
|
+
title="No data available"
|
|
3671
|
+
description="There is no data to display."
|
|
3672
|
+
/>
|
|
3673
|
+
</div>
|
|
3674
|
+
<div>
|
|
3675
|
+
<p className="mb-2 text-sm text-sf-subtle">Large</p>
|
|
3676
|
+
<Empty
|
|
3677
|
+
size="lg"
|
|
3678
|
+
icon={<DatabaseIcon size={64} className="text-sf-inactive" />}
|
|
3679
|
+
title="No data available"
|
|
3680
|
+
description="There is no data to display."
|
|
3681
|
+
/>
|
|
3682
|
+
</div>
|
|
3683
|
+
</div>
|
|
3684
|
+
```
|
|
3685
|
+
|
|
3686
|
+
```tsx
|
|
3687
|
+
<Empty
|
|
3688
|
+
icon={<FolderOpenIcon size={48} className="text-sf-inactive" />}
|
|
3689
|
+
title="No projects found"
|
|
3690
|
+
description="Get started by creating your first project using the command below."
|
|
3691
|
+
commandLine="npm create sf-project"
|
|
3692
|
+
/>
|
|
3693
|
+
```
|
|
3694
|
+
|
|
3695
|
+
```tsx
|
|
3696
|
+
<Empty
|
|
3697
|
+
icon={<CloudSlashIcon size={48} className="text-sf-inactive" />}
|
|
3698
|
+
title="No connection"
|
|
3699
|
+
description="Unable to connect to the server. Please check your connection and try again."
|
|
3700
|
+
contents={
|
|
3701
|
+
<div className="flex gap-2">
|
|
3702
|
+
<Button variant="primary">Retry</Button>
|
|
3703
|
+
<Button variant="secondary">Go Back</Button>
|
|
3704
|
+
</div>
|
|
3705
|
+
}
|
|
3706
|
+
/>
|
|
3707
|
+
```
|
|
3708
|
+
|
|
3709
|
+
```tsx
|
|
3710
|
+
<Empty title="Nothing here" />
|
|
3711
|
+
```
|
|
3712
|
+
|
|
3713
|
+
```tsx
|
|
3714
|
+
<Empty
|
|
3715
|
+
title="No results found"
|
|
3716
|
+
description="Try adjusting your search or filter to find what you're looking for."
|
|
3717
|
+
/>
|
|
3718
|
+
```
|
|
3719
|
+
|
|
1602
3720
|
---
|
|
1603
3721
|
|
|
1604
3722
|
### Field
|
|
@@ -1677,6 +3795,61 @@ Filters component for building and managing active filter conditions. Supports m
|
|
|
1677
3795
|
|
|
1678
3796
|
`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
3797
|
|
|
3798
|
+
**Examples:**
|
|
3799
|
+
|
|
3800
|
+
```tsx
|
|
3801
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3802
|
+
<Filters filters={filters} fields={filterFields} onChange={setFilters} />
|
|
3803
|
+
<div className="mt-4 rounded bg-sf-elevated p-3 font-mono text-xs">
|
|
3804
|
+
<p className="text-sf-subtle mb-1">Active filters:</p>
|
|
3805
|
+
<pre className="text-sf-strong overflow-x-auto">
|
|
3806
|
+
{JSON.stringify(filters, null, 2)}
|
|
3807
|
+
</pre>
|
|
3808
|
+
</div>
|
|
3809
|
+
</div>
|
|
3810
|
+
```
|
|
3811
|
+
|
|
3812
|
+
```tsx
|
|
3813
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3814
|
+
<Filters
|
|
3815
|
+
filters={filters}
|
|
3816
|
+
fields={filterFields.slice(0, 3)}
|
|
3817
|
+
onChange={setFilters}
|
|
3818
|
+
size="sm"
|
|
3819
|
+
/>
|
|
3820
|
+
</div>
|
|
3821
|
+
```
|
|
3822
|
+
|
|
3823
|
+
```tsx
|
|
3824
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3825
|
+
<Filters
|
|
3826
|
+
filters={filters}
|
|
3827
|
+
fields={filterFields}
|
|
3828
|
+
onChange={setFilters}
|
|
3829
|
+
showSearchInput
|
|
3830
|
+
/>
|
|
3831
|
+
<p className="text-sf-subtle mt-3 text-xs">
|
|
3832
|
+
Open the "Add Filter" menu to see grouped fields (General, User Details)
|
|
3833
|
+
</p>
|
|
3834
|
+
</div>
|
|
3835
|
+
```
|
|
3836
|
+
|
|
3837
|
+
```tsx
|
|
3838
|
+
<div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
|
|
3839
|
+
<Filters
|
|
3840
|
+
filters={filters}
|
|
3841
|
+
fields={filterFields.slice(0, 3)}
|
|
3842
|
+
onChange={setFilters}
|
|
3843
|
+
enableShortcut
|
|
3844
|
+
shortcutKey="k"
|
|
3845
|
+
shortcutLabel="Cmd+K"
|
|
3846
|
+
/>
|
|
3847
|
+
<p className="text-sf-subtle mt-3 text-xs">
|
|
3848
|
+
Press Cmd+K (or Ctrl+K) to quickly open the add filter menu
|
|
3849
|
+
</p>
|
|
3850
|
+
</div>
|
|
3851
|
+
```
|
|
3852
|
+
|
|
1680
3853
|
---
|
|
1681
3854
|
|
|
1682
3855
|
### Grid
|
|
@@ -1720,6 +3893,229 @@ Responsive CSS grid layout container with preset column configurations.
|
|
|
1720
3893
|
|
|
1721
3894
|
`border-sf-line`
|
|
1722
3895
|
|
|
3896
|
+
**Examples:**
|
|
3897
|
+
|
|
3898
|
+
```tsx
|
|
3899
|
+
<Grid variant="2up" gap="base">
|
|
3900
|
+
<GridItem>
|
|
3901
|
+
<Tile>
|
|
3902
|
+
<div>Item 1</div>
|
|
3903
|
+
<div className="mt-1">First grid item</div>
|
|
3904
|
+
</Tile>
|
|
3905
|
+
</GridItem>
|
|
3906
|
+
<GridItem>
|
|
3907
|
+
<Tile>
|
|
3908
|
+
<div>Item 2</div>
|
|
3909
|
+
<div className="mt-1">Second grid item</div>
|
|
3910
|
+
</Tile>
|
|
3911
|
+
</GridItem>
|
|
3912
|
+
</Grid>
|
|
3913
|
+
```
|
|
3914
|
+
|
|
3915
|
+
```tsx
|
|
3916
|
+
<div className="flex flex-col gap-8">
|
|
3917
|
+
<div>
|
|
3918
|
+
<p className="mb-2 text-sf-subtle">variant="2up"</p>
|
|
3919
|
+
<Grid variant="2up" gap="sm">
|
|
3920
|
+
<GridItem>
|
|
3921
|
+
<Tile>
|
|
3922
|
+
<span className="block text-center">1</span>
|
|
3923
|
+
</Tile>
|
|
3924
|
+
</GridItem>
|
|
3925
|
+
<GridItem>
|
|
3926
|
+
<Tile>
|
|
3927
|
+
<span className="block text-center">2</span>
|
|
3928
|
+
</Tile>
|
|
3929
|
+
</GridItem>
|
|
3930
|
+
</Grid>
|
|
3931
|
+
</div>
|
|
3932
|
+
|
|
3933
|
+
<div>
|
|
3934
|
+
<p className="mb-2 text-sf-subtle">variant="3up"</p>
|
|
3935
|
+
<Grid variant="3up" gap="sm">
|
|
3936
|
+
<GridItem>
|
|
3937
|
+
<Tile>
|
|
3938
|
+
<span className="block text-center">1</span>
|
|
3939
|
+
</Tile>
|
|
3940
|
+
</GridItem>
|
|
3941
|
+
<GridItem>
|
|
3942
|
+
<Tile>
|
|
3943
|
+
<span className="block text-center">2</span>
|
|
3944
|
+
</Tile>
|
|
3945
|
+
</GridItem>
|
|
3946
|
+
<GridItem>
|
|
3947
|
+
<Tile>
|
|
3948
|
+
<span className="block text-center">3</span>
|
|
3949
|
+
</Tile>
|
|
3950
|
+
</GridItem>
|
|
3951
|
+
</Grid>
|
|
3952
|
+
</div>
|
|
3953
|
+
|
|
3954
|
+
<div>
|
|
3955
|
+
<p className="mb-2 text-sf-subtle">variant="4up"</p>
|
|
3956
|
+
<Grid variant="4up" gap="sm">
|
|
3957
|
+
<GridItem>
|
|
3958
|
+
<Tile>
|
|
3959
|
+
<span className="block text-center">1</span>
|
|
3960
|
+
</Tile>
|
|
3961
|
+
</GridItem>
|
|
3962
|
+
<GridItem>
|
|
3963
|
+
<Tile>
|
|
3964
|
+
<span className="block text-center">2</span>
|
|
3965
|
+
</Tile>
|
|
3966
|
+
</GridItem>
|
|
3967
|
+
<GridItem>
|
|
3968
|
+
<Tile>
|
|
3969
|
+
<span className="block text-center">3</span>
|
|
3970
|
+
</Tile>
|
|
3971
|
+
</GridItem>
|
|
3972
|
+
<GridItem>
|
|
3973
|
+
<Tile>
|
|
3974
|
+
<span className="block text-center">4</span>
|
|
3975
|
+
</Tile>
|
|
3976
|
+
</GridItem>
|
|
3977
|
+
</Grid>
|
|
3978
|
+
</div>
|
|
3979
|
+
</div>
|
|
3980
|
+
```
|
|
3981
|
+
|
|
3982
|
+
```tsx
|
|
3983
|
+
<div className="flex flex-col gap-8">
|
|
3984
|
+
<div>
|
|
3985
|
+
<p className="mb-2 text-sf-subtle">variant="2-1" (66% / 33%)</p>
|
|
3986
|
+
<Grid variant="2-1" gap="sm">
|
|
3987
|
+
<GridItem>
|
|
3988
|
+
<Tile>
|
|
3989
|
+
<div>Main Content</div>
|
|
3990
|
+
<div className="mt-1">Two-thirds width</div>
|
|
3991
|
+
</Tile>
|
|
3992
|
+
</GridItem>
|
|
3993
|
+
<GridItem>
|
|
3994
|
+
<Tile>
|
|
3995
|
+
<div>Sidebar</div>
|
|
3996
|
+
<div className="mt-1">One-third width</div>
|
|
3997
|
+
</Tile>
|
|
3998
|
+
</GridItem>
|
|
3999
|
+
</Grid>
|
|
4000
|
+
</div>
|
|
4001
|
+
|
|
4002
|
+
<div>
|
|
4003
|
+
<p className="mb-2 text-sf-subtle">variant="1-2" (33% / 66%)</p>
|
|
4004
|
+
<Grid variant="1-2" gap="sm">
|
|
4005
|
+
<GridItem>
|
|
4006
|
+
<Tile>
|
|
4007
|
+
<div>Sidebar</div>
|
|
4008
|
+
<div className="mt-1">One-third width</div>
|
|
4009
|
+
</Tile>
|
|
4010
|
+
</GridItem>
|
|
4011
|
+
<GridItem>
|
|
4012
|
+
<Tile>
|
|
4013
|
+
<div>Main Content</div>
|
|
4014
|
+
<div className="mt-1">Two-thirds width</div>
|
|
4015
|
+
</Tile>
|
|
4016
|
+
</GridItem>
|
|
4017
|
+
</Grid>
|
|
4018
|
+
</div>
|
|
4019
|
+
</div>
|
|
4020
|
+
```
|
|
4021
|
+
|
|
4022
|
+
```tsx
|
|
4023
|
+
<div className="flex flex-col gap-8">
|
|
4024
|
+
<div>
|
|
4025
|
+
<p className="mb-2 text-sf-subtle">gap="none"</p>
|
|
4026
|
+
<Grid variant="side-by-side" gap="none">
|
|
4027
|
+
<GridItem>
|
|
4028
|
+
<Tile>
|
|
4029
|
+
<span className="block text-center">1</span>
|
|
4030
|
+
</Tile>
|
|
4031
|
+
</GridItem>
|
|
4032
|
+
<GridItem>
|
|
4033
|
+
<Tile>
|
|
4034
|
+
<span className="block text-center">2</span>
|
|
4035
|
+
</Tile>
|
|
4036
|
+
</GridItem>
|
|
4037
|
+
</Grid>
|
|
4038
|
+
</div>
|
|
4039
|
+
|
|
4040
|
+
<div>
|
|
4041
|
+
<p className="mb-2 text-sf-subtle">gap="sm"</p>
|
|
4042
|
+
<Grid variant="side-by-side" gap="sm">
|
|
4043
|
+
<GridItem>
|
|
4044
|
+
<Tile>
|
|
4045
|
+
<span className="block text-center">1</span>
|
|
4046
|
+
</Tile>
|
|
4047
|
+
</GridItem>
|
|
4048
|
+
<GridItem>
|
|
4049
|
+
<Tile>
|
|
4050
|
+
<span className="block text-center">2</span>
|
|
4051
|
+
</Tile>
|
|
4052
|
+
</GridItem>
|
|
4053
|
+
</Grid>
|
|
4054
|
+
</div>
|
|
4055
|
+
|
|
4056
|
+
<div>
|
|
4057
|
+
<p className="mb-2 text-sf-subtle">gap="base" (default, responsive)</p>
|
|
4058
|
+
<Grid variant="side-by-side" gap="base">
|
|
4059
|
+
<GridItem>
|
|
4060
|
+
<Tile>
|
|
4061
|
+
<span className="block text-center">1</span>
|
|
4062
|
+
</Tile>
|
|
4063
|
+
</GridItem>
|
|
4064
|
+
<GridItem>
|
|
4065
|
+
<Tile>
|
|
4066
|
+
<span className="block text-center">2</span>
|
|
4067
|
+
</Tile>
|
|
4068
|
+
</GridItem>
|
|
4069
|
+
</Grid>
|
|
4070
|
+
</div>
|
|
4071
|
+
|
|
4072
|
+
<div>
|
|
4073
|
+
<p className="mb-2 text-sf-subtle">gap="lg"</p>
|
|
4074
|
+
<Grid variant="side-by-side" gap="lg">
|
|
4075
|
+
<GridItem>
|
|
4076
|
+
<Tile>
|
|
4077
|
+
<span className="block text-center">1</span>
|
|
4078
|
+
</Tile>
|
|
4079
|
+
</GridItem>
|
|
4080
|
+
<GridItem>
|
|
4081
|
+
<Tile>
|
|
4082
|
+
<span className="block text-center">2</span>
|
|
4083
|
+
</Tile>
|
|
4084
|
+
</GridItem>
|
|
4085
|
+
</Grid>
|
|
4086
|
+
</div>
|
|
4087
|
+
</div>
|
|
4088
|
+
```
|
|
4089
|
+
|
|
4090
|
+
```tsx
|
|
4091
|
+
<Grid variant="4up" gap="base" mobileDivider>
|
|
4092
|
+
<GridItem>
|
|
4093
|
+
<Tile>
|
|
4094
|
+
<div>Item 1</div>
|
|
4095
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4096
|
+
</Tile>
|
|
4097
|
+
</GridItem>
|
|
4098
|
+
<GridItem>
|
|
4099
|
+
<Tile>
|
|
4100
|
+
<div>Item 2</div>
|
|
4101
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4102
|
+
</Tile>
|
|
4103
|
+
</GridItem>
|
|
4104
|
+
<GridItem>
|
|
4105
|
+
<Tile>
|
|
4106
|
+
<div>Item 3</div>
|
|
4107
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4108
|
+
</Tile>
|
|
4109
|
+
</GridItem>
|
|
4110
|
+
<GridItem>
|
|
4111
|
+
<Tile>
|
|
4112
|
+
<div>Item 4</div>
|
|
4113
|
+
<div className="mt-1">Has divider on mobile</div>
|
|
4114
|
+
</Tile>
|
|
4115
|
+
</GridItem>
|
|
4116
|
+
</Grid>
|
|
4117
|
+
```
|
|
4118
|
+
|
|
1723
4119
|
---
|
|
1724
4120
|
|
|
1725
4121
|
### Input
|
|
@@ -1765,6 +4161,87 @@ Input component
|
|
|
1765
4161
|
|
|
1766
4162
|
- **Dimensions:** `[object Object]`
|
|
1767
4163
|
|
|
4164
|
+
**Examples:**
|
|
4165
|
+
|
|
4166
|
+
```tsx
|
|
4167
|
+
<Input
|
|
4168
|
+
label="Email"
|
|
4169
|
+
placeholder="you@example.com"
|
|
4170
|
+
description="We'll never share your email"
|
|
4171
|
+
/>
|
|
4172
|
+
```
|
|
4173
|
+
|
|
4174
|
+
```tsx
|
|
4175
|
+
<Input
|
|
4176
|
+
label="Email"
|
|
4177
|
+
placeholder="you@example.com"
|
|
4178
|
+
value="invalid-email"
|
|
4179
|
+
variant="error"
|
|
4180
|
+
error="Please enter a valid email address"
|
|
4181
|
+
/>
|
|
4182
|
+
```
|
|
4183
|
+
|
|
4184
|
+
```tsx
|
|
4185
|
+
<Input
|
|
4186
|
+
label="Password"
|
|
4187
|
+
type="password"
|
|
4188
|
+
value="short"
|
|
4189
|
+
variant="error"
|
|
4190
|
+
error={{
|
|
4191
|
+
match: "tooShort",
|
|
4192
|
+
message: "Password must be at least 8 characters",
|
|
4193
|
+
}}
|
|
4194
|
+
minLength={8}
|
|
4195
|
+
/>
|
|
4196
|
+
```
|
|
4197
|
+
|
|
4198
|
+
```tsx
|
|
4199
|
+
<div className="flex flex-col gap-4">
|
|
4200
|
+
<Input size="xs" label="Extra Small" placeholder="Extra small input" />
|
|
4201
|
+
<Input size="sm" label="Small" placeholder="Small input" />
|
|
4202
|
+
<Input label="Base" placeholder="Base input (default)" />
|
|
4203
|
+
<Input size="lg" label="Large" placeholder="Large input" />
|
|
4204
|
+
</div>
|
|
4205
|
+
```
|
|
4206
|
+
|
|
4207
|
+
```tsx
|
|
4208
|
+
<Input label="Disabled field" placeholder="Cannot edit" disabled />
|
|
4209
|
+
```
|
|
4210
|
+
|
|
4211
|
+
```tsx
|
|
4212
|
+
<div className="flex flex-col gap-4">
|
|
4213
|
+
<Input type="email" label="Email" placeholder="you@example.com" />
|
|
4214
|
+
<Input type="password" label="Password" placeholder="••••••••" />
|
|
4215
|
+
<Input type="number" label="Age" placeholder="18" />
|
|
4216
|
+
<Input type="tel" label="Phone" placeholder="+1 (555) 000-0000" />
|
|
4217
|
+
</div>
|
|
4218
|
+
```
|
|
4219
|
+
|
|
4220
|
+
```tsx
|
|
4221
|
+
<Input label="Phone Number" required={false} placeholder="+1 (555) 000-0000" />
|
|
4222
|
+
```
|
|
4223
|
+
|
|
4224
|
+
```tsx
|
|
4225
|
+
<Input
|
|
4226
|
+
label="API Key"
|
|
4227
|
+
labelTooltip="Find this in your dashboard under Settings > API Keys"
|
|
4228
|
+
placeholder="sk_live_..."
|
|
4229
|
+
/>
|
|
4230
|
+
```
|
|
4231
|
+
|
|
4232
|
+
```tsx
|
|
4233
|
+
<Input
|
|
4234
|
+
label={
|
|
4235
|
+
<span>
|
|
4236
|
+
Email for <strong>billing</strong>
|
|
4237
|
+
</span>
|
|
4238
|
+
}
|
|
4239
|
+
required
|
|
4240
|
+
placeholder="billing@company.com"
|
|
4241
|
+
type="email"
|
|
4242
|
+
/>
|
|
4243
|
+
```
|
|
4244
|
+
|
|
1768
4245
|
---
|
|
1769
4246
|
|
|
1770
4247
|
### Label
|
|
@@ -1796,6 +4273,56 @@ Label component for form fields. Provides a standardized way to display labels w
|
|
|
1796
4273
|
|
|
1797
4274
|
`text-sf-default`, `text-sf-strong`
|
|
1798
4275
|
|
|
4276
|
+
**Examples:**
|
|
4277
|
+
|
|
4278
|
+
```tsx
|
|
4279
|
+
<div className="flex flex-col gap-4">
|
|
4280
|
+
<Label>Default Label</Label>
|
|
4281
|
+
<Label showOptional>Optional Label</Label>
|
|
4282
|
+
<Label tooltip="More information about this field">Label with Tooltip</Label>
|
|
4283
|
+
</div>
|
|
4284
|
+
```
|
|
4285
|
+
|
|
4286
|
+
```tsx
|
|
4287
|
+
<Input label="Phone Number" required={false} placeholder="+1 555-0000" />
|
|
4288
|
+
```
|
|
4289
|
+
|
|
4290
|
+
```tsx
|
|
4291
|
+
<Input
|
|
4292
|
+
label="API Key"
|
|
4293
|
+
labelTooltip="Find this in your dashboard settings under API > Keys"
|
|
4294
|
+
placeholder="sk_live_..."
|
|
4295
|
+
/>
|
|
4296
|
+
```
|
|
4297
|
+
|
|
4298
|
+
```tsx
|
|
4299
|
+
<Checkbox
|
|
4300
|
+
label={
|
|
4301
|
+
<span>
|
|
4302
|
+
I agree to the <strong>Terms of Service</strong>
|
|
4303
|
+
</span>
|
|
4304
|
+
}
|
|
4305
|
+
/>
|
|
4306
|
+
```
|
|
4307
|
+
|
|
4308
|
+
```tsx
|
|
4309
|
+
<div className="flex max-w-md flex-col gap-4">
|
|
4310
|
+
<Input label="Full Name" placeholder="John Doe" />
|
|
4311
|
+
<Input
|
|
4312
|
+
label="Email"
|
|
4313
|
+
labelTooltip="We'll send your receipt here"
|
|
4314
|
+
placeholder="john@example.com"
|
|
4315
|
+
type="email"
|
|
4316
|
+
/>
|
|
4317
|
+
<Input label="Company" required={false} placeholder="Acme Inc." />
|
|
4318
|
+
<Select label="Country" hideLabel={false} placeholder="Select a country">
|
|
4319
|
+
<Select.Option value="us">United States</Select.Option>
|
|
4320
|
+
<Select.Option value="uk">United Kingdom</Select.Option>
|
|
4321
|
+
<Select.Option value="ca">Canada</Select.Option>
|
|
4322
|
+
</Select>
|
|
4323
|
+
</div>
|
|
4324
|
+
```
|
|
4325
|
+
|
|
1799
4326
|
---
|
|
1800
4327
|
|
|
1801
4328
|
### LayerCard
|
|
@@ -1828,10 +4355,64 @@ This is a compound component. Use these sub-components:
|
|
|
1828
4355
|
|
|
1829
4356
|
Primary sub-component
|
|
1830
4357
|
|
|
4358
|
+
Props:
|
|
4359
|
+
|
|
4360
|
+
- `className`: string
|
|
4361
|
+
|
|
1831
4362
|
#### LayerCard.Secondary
|
|
1832
4363
|
|
|
1833
4364
|
Secondary sub-component
|
|
1834
4365
|
|
|
4366
|
+
Props:
|
|
4367
|
+
|
|
4368
|
+
- `className`: string
|
|
4369
|
+
|
|
4370
|
+
**Examples:**
|
|
4371
|
+
|
|
4372
|
+
```tsx
|
|
4373
|
+
<LayerCard>
|
|
4374
|
+
<LayerCard.Secondary className="flex items-center justify-between">
|
|
4375
|
+
<div>Next Steps</div>
|
|
4376
|
+
<Button
|
|
4377
|
+
variant="ghost"
|
|
4378
|
+
size="sm"
|
|
4379
|
+
shape="square"
|
|
4380
|
+
aria-label="Go to next steps"
|
|
4381
|
+
>
|
|
4382
|
+
<ArrowRightIcon size={16} />
|
|
4383
|
+
</Button>
|
|
4384
|
+
</LayerCard.Secondary>
|
|
4385
|
+
|
|
4386
|
+
<LayerCard.Primary>Get started with SF</LayerCard.Primary>
|
|
4387
|
+
</LayerCard>
|
|
4388
|
+
```
|
|
4389
|
+
|
|
4390
|
+
```tsx
|
|
4391
|
+
<LayerCard className="w-[250px]">
|
|
4392
|
+
<LayerCard.Secondary>Getting Started</LayerCard.Secondary>
|
|
4393
|
+
<LayerCard.Primary>
|
|
4394
|
+
<p className="text-sm text-sf-subtle">Quick start guide for new users</p>
|
|
4395
|
+
</LayerCard.Primary>
|
|
4396
|
+
</LayerCard>
|
|
4397
|
+
```
|
|
4398
|
+
|
|
4399
|
+
```tsx
|
|
4400
|
+
<div className="flex gap-4">
|
|
4401
|
+
<LayerCard className="w-[200px]">
|
|
4402
|
+
<LayerCard.Secondary>Components</LayerCard.Secondary>
|
|
4403
|
+
<LayerCard.Primary>
|
|
4404
|
+
<p className="text-sm">Browse all components</p>
|
|
4405
|
+
</LayerCard.Primary>
|
|
4406
|
+
</LayerCard>
|
|
4407
|
+
<LayerCard className="w-[200px]">
|
|
4408
|
+
<LayerCard.Secondary>Examples</LayerCard.Secondary>
|
|
4409
|
+
<LayerCard.Primary>
|
|
4410
|
+
<p className="text-sm">View code examples</p>
|
|
4411
|
+
</LayerCard.Primary>
|
|
4412
|
+
</LayerCard>
|
|
4413
|
+
</div>
|
|
4414
|
+
```
|
|
4415
|
+
|
|
1835
4416
|
---
|
|
1836
4417
|
|
|
1837
4418
|
### Link
|
|
@@ -1882,6 +4463,69 @@ This is a compound component. Use these sub-components:
|
|
|
1882
4463
|
|
|
1883
4464
|
ExternalIcon sub-component
|
|
1884
4465
|
|
|
4466
|
+
**Examples:**
|
|
4467
|
+
|
|
4468
|
+
```tsx
|
|
4469
|
+
<div className="grid gap-x-6 gap-y-4 text-base md:grid-cols-3">
|
|
4470
|
+
<Link href="#">Default inline link</Link>
|
|
4471
|
+
<Link href="#" variant="current">
|
|
4472
|
+
Current color link
|
|
4473
|
+
</Link>
|
|
4474
|
+
<Link href="#" variant="plain">
|
|
4475
|
+
Plain inline link
|
|
4476
|
+
</Link>
|
|
4477
|
+
</div>
|
|
4478
|
+
```
|
|
4479
|
+
|
|
4480
|
+
```tsx
|
|
4481
|
+
<p className="mx-auto max-w-md text-base leading-relaxed text-sf-default">
|
|
4482
|
+
This is a paragraph with an <Link href="#">inline link</Link> that flows
|
|
4483
|
+
naturally with the surrounding text. Links maintain proper underline offset
|
|
4484
|
+
for readability.
|
|
4485
|
+
</p>
|
|
4486
|
+
```
|
|
4487
|
+
|
|
4488
|
+
```tsx
|
|
4489
|
+
<Link
|
|
4490
|
+
href="https://cloudflare.com"
|
|
4491
|
+
target="_blank"
|
|
4492
|
+
rel="noopener noreferrer"
|
|
4493
|
+
className="text-base"
|
|
4494
|
+
>
|
|
4495
|
+
Visit Cloudflare <Link.ExternalIcon />
|
|
4496
|
+
</Link>
|
|
4497
|
+
```
|
|
4498
|
+
|
|
4499
|
+
```tsx
|
|
4500
|
+
<p className="text-base text-sf-danger">
|
|
4501
|
+
This error message contains a{" "}
|
|
4502
|
+
<Link href="#" variant="current">
|
|
4503
|
+
link
|
|
4504
|
+
</Link>{" "}
|
|
4505
|
+
that inherits the red color from its parent.
|
|
4506
|
+
</p>
|
|
4507
|
+
```
|
|
4508
|
+
|
|
4509
|
+
```tsx
|
|
4510
|
+
<div className="flex flex-col gap-x-6 gap-y-4 text-base md:flex-row">
|
|
4511
|
+
<Link render={<CustomRouterLink href="/dashboard" />} variant="inline">
|
|
4512
|
+
Dashboard (via render)
|
|
4513
|
+
</Link>
|
|
4514
|
+
<Link
|
|
4515
|
+
render={
|
|
4516
|
+
<CustomRouterLink
|
|
4517
|
+
href="https://developers.cloudflare.com"
|
|
4518
|
+
target="_blank"
|
|
4519
|
+
rel="noopener noreferrer"
|
|
4520
|
+
/>
|
|
4521
|
+
}
|
|
4522
|
+
variant="inline"
|
|
4523
|
+
>
|
|
4524
|
+
Cloudflare Docs <Link.ExternalIcon />
|
|
4525
|
+
</Link>
|
|
4526
|
+
</div>
|
|
4527
|
+
```
|
|
4528
|
+
|
|
1885
4529
|
---
|
|
1886
4530
|
|
|
1887
4531
|
### Loader
|
|
@@ -1903,6 +4547,20 @@ Animated circular spinner for indicating loading states. Uses CSS keyframe anima
|
|
|
1903
4547
|
- `"base"`: Default loader size
|
|
1904
4548
|
- `"lg"`: Large loader for prominent loading states
|
|
1905
4549
|
|
|
4550
|
+
**Examples:**
|
|
4551
|
+
|
|
4552
|
+
```tsx
|
|
4553
|
+
<div className="flex items-center gap-4">
|
|
4554
|
+
<Loader size="sm" />
|
|
4555
|
+
<Loader size="base" />
|
|
4556
|
+
<Loader size="lg" />
|
|
4557
|
+
</div>
|
|
4558
|
+
```
|
|
4559
|
+
|
|
4560
|
+
```tsx
|
|
4561
|
+
<Loader size={24} />
|
|
4562
|
+
```
|
|
4563
|
+
|
|
1906
4564
|
---
|
|
1907
4565
|
|
|
1908
4566
|
### MenuBar
|
|
@@ -1932,6 +4590,29 @@ MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. E
|
|
|
1932
4590
|
|
|
1933
4591
|
**Styling:**
|
|
1934
4592
|
|
|
4593
|
+
**Examples:**
|
|
4594
|
+
|
|
4595
|
+
```tsx
|
|
4596
|
+
<MenuBar
|
|
4597
|
+
isActive="bold"
|
|
4598
|
+
optionIds
|
|
4599
|
+
options={[
|
|
4600
|
+
{
|
|
4601
|
+
icon: <TextBolderIcon />,
|
|
4602
|
+
id: "bold",
|
|
4603
|
+
onClick: () => {},
|
|
4604
|
+
tooltip: "Bold",
|
|
4605
|
+
},
|
|
4606
|
+
{
|
|
4607
|
+
icon: <TextItalicIcon />,
|
|
4608
|
+
id: "italic",
|
|
4609
|
+
onClick: () => {},
|
|
4610
|
+
tooltip: "Italic",
|
|
4611
|
+
},
|
|
4612
|
+
]}
|
|
4613
|
+
/>
|
|
4614
|
+
```
|
|
4615
|
+
|
|
1935
4616
|
---
|
|
1936
4617
|
|
|
1937
4618
|
### Meter
|
|
@@ -1967,6 +4648,28 @@ Progress bar showing a measured value within a known range (e.g. quota usage).
|
|
|
1967
4648
|
|
|
1968
4649
|
`bg-sf-fill`, `text-sf-default`, `text-sf-strong`
|
|
1969
4650
|
|
|
4651
|
+
**Examples:**
|
|
4652
|
+
|
|
4653
|
+
```tsx
|
|
4654
|
+
<Meter label="Storage used" value={65} />
|
|
4655
|
+
```
|
|
4656
|
+
|
|
4657
|
+
```tsx
|
|
4658
|
+
<Meter label="API requests" value={75} customValue="750 / 1,000" />
|
|
4659
|
+
```
|
|
4660
|
+
|
|
4661
|
+
```tsx
|
|
4662
|
+
<Meter label="Progress" value={40} showValue={false} />
|
|
4663
|
+
```
|
|
4664
|
+
|
|
4665
|
+
```tsx
|
|
4666
|
+
<Meter
|
|
4667
|
+
label="Upload progress"
|
|
4668
|
+
value={80}
|
|
4669
|
+
indicatorClassName="from-green-500 via-green-500 to-green-500"
|
|
4670
|
+
/>
|
|
4671
|
+
```
|
|
4672
|
+
|
|
1970
4673
|
---
|
|
1971
4674
|
|
|
1972
4675
|
### Pagination
|
|
@@ -2001,6 +4704,32 @@ Page navigation controls with page count display.
|
|
|
2001
4704
|
|
|
2002
4705
|
**Styling:**
|
|
2003
4706
|
|
|
4707
|
+
**Examples:**
|
|
4708
|
+
|
|
4709
|
+
```tsx
|
|
4710
|
+
<Pagination page={page} setPage={setPage} perPage={10} totalCount={100} />
|
|
4711
|
+
```
|
|
4712
|
+
|
|
4713
|
+
```tsx
|
|
4714
|
+
<Pagination
|
|
4715
|
+
page={page}
|
|
4716
|
+
setPage={setPage}
|
|
4717
|
+
perPage={10}
|
|
4718
|
+
totalCount={100}
|
|
4719
|
+
controls="simple"
|
|
4720
|
+
/>
|
|
4721
|
+
```
|
|
4722
|
+
|
|
4723
|
+
```tsx
|
|
4724
|
+
<Pagination
|
|
4725
|
+
text={({ perPage }) => `Page ${page} - showing ${perPage} per page`}
|
|
4726
|
+
page={page}
|
|
4727
|
+
setPage={setPage}
|
|
4728
|
+
perPage={25}
|
|
4729
|
+
totalCount={100}
|
|
4730
|
+
/>
|
|
4731
|
+
```
|
|
4732
|
+
|
|
2004
4733
|
---
|
|
2005
4734
|
|
|
2006
4735
|
### Popover
|
|
@@ -2033,10 +4762,22 @@ This is a compound component. Use these sub-components:
|
|
|
2033
4762
|
|
|
2034
4763
|
Trigger sub-component
|
|
2035
4764
|
|
|
4765
|
+
Props:
|
|
4766
|
+
|
|
4767
|
+
- `asChild`: boolean
|
|
4768
|
+
|
|
2036
4769
|
#### Popover.Content
|
|
2037
4770
|
|
|
2038
4771
|
Content sub-component
|
|
2039
4772
|
|
|
4773
|
+
Props:
|
|
4774
|
+
|
|
4775
|
+
- `align`: PopoverAlign
|
|
4776
|
+
- `sideOffset`: number
|
|
4777
|
+
- `alignOffset`: number
|
|
4778
|
+
- `className`: string
|
|
4779
|
+
- `children`: ReactNode
|
|
4780
|
+
|
|
2040
4781
|
#### Popover.Title
|
|
2041
4782
|
|
|
2042
4783
|
Title sub-component
|
|
@@ -2049,6 +4790,150 @@ Description sub-component
|
|
|
2049
4790
|
|
|
2050
4791
|
Close sub-component
|
|
2051
4792
|
|
|
4793
|
+
Props:
|
|
4794
|
+
|
|
4795
|
+
- `asChild`: boolean
|
|
4796
|
+
|
|
4797
|
+
**Examples:**
|
|
4798
|
+
|
|
4799
|
+
```tsx
|
|
4800
|
+
<Popover>
|
|
4801
|
+
<Popover.Trigger asChild>
|
|
4802
|
+
<Button shape="square" icon={BellIcon} aria-label="Notifications" />
|
|
4803
|
+
</Popover.Trigger>
|
|
4804
|
+
<Popover.Content>
|
|
4805
|
+
<Popover.Title>Notifications</Popover.Title>
|
|
4806
|
+
<Popover.Description>You are all caught up. Good job!</Popover.Description>
|
|
4807
|
+
</Popover.Content>
|
|
4808
|
+
</Popover>
|
|
4809
|
+
```
|
|
4810
|
+
|
|
4811
|
+
```tsx
|
|
4812
|
+
<Popover>
|
|
4813
|
+
<Popover.Trigger asChild>
|
|
4814
|
+
<Button>Open Popover</Button>
|
|
4815
|
+
</Popover.Trigger>
|
|
4816
|
+
<Popover.Content>
|
|
4817
|
+
<Popover.Title>Popover Title</Popover.Title>
|
|
4818
|
+
<Popover.Description>
|
|
4819
|
+
This is a basic popover with a title and description.
|
|
4820
|
+
</Popover.Description>
|
|
4821
|
+
</Popover.Content>
|
|
4822
|
+
</Popover>
|
|
4823
|
+
```
|
|
4824
|
+
|
|
4825
|
+
```tsx
|
|
4826
|
+
<Popover>
|
|
4827
|
+
<Popover.Trigger asChild>
|
|
4828
|
+
<Button>Open Settings</Button>
|
|
4829
|
+
</Popover.Trigger>
|
|
4830
|
+
<Popover.Content>
|
|
4831
|
+
<Popover.Title>Settings</Popover.Title>
|
|
4832
|
+
<Popover.Description>Configure your preferences below.</Popover.Description>
|
|
4833
|
+
<div className="mt-3">
|
|
4834
|
+
<Popover.Close asChild>
|
|
4835
|
+
<Button variant="secondary" size="sm">
|
|
4836
|
+
Close
|
|
4837
|
+
</Button>
|
|
4838
|
+
</Popover.Close>
|
|
4839
|
+
</div>
|
|
4840
|
+
</Popover.Content>
|
|
4841
|
+
</Popover>
|
|
4842
|
+
```
|
|
4843
|
+
|
|
4844
|
+
```tsx
|
|
4845
|
+
<div className="flex flex-wrap gap-4">
|
|
4846
|
+
<Popover>
|
|
4847
|
+
<Popover.Trigger asChild>
|
|
4848
|
+
<Button variant="secondary">Bottom</Button>
|
|
4849
|
+
</Popover.Trigger>
|
|
4850
|
+
<Popover.Content side="bottom">
|
|
4851
|
+
<Popover.Title>Bottom</Popover.Title>
|
|
4852
|
+
<Popover.Description>Popover on bottom (default).</Popover.Description>
|
|
4853
|
+
</Popover.Content>
|
|
4854
|
+
</Popover>
|
|
4855
|
+
|
|
4856
|
+
<Popover>
|
|
4857
|
+
<Popover.Trigger asChild>
|
|
4858
|
+
<Button variant="secondary">Top</Button>
|
|
4859
|
+
</Popover.Trigger>
|
|
4860
|
+
<Popover.Content side="top">
|
|
4861
|
+
<Popover.Title>Top</Popover.Title>
|
|
4862
|
+
<Popover.Description>Popover on top.</Popover.Description>
|
|
4863
|
+
</Popover.Content>
|
|
4864
|
+
</Popover>
|
|
4865
|
+
|
|
4866
|
+
<Popover>
|
|
4867
|
+
<Popover.Trigger asChild>
|
|
4868
|
+
<Button variant="secondary">Left</Button>
|
|
4869
|
+
</Popover.Trigger>
|
|
4870
|
+
<Popover.Content side="left">
|
|
4871
|
+
<Popover.Title>Left</Popover.Title>
|
|
4872
|
+
<Popover.Description>Popover on left.</Popover.Description>
|
|
4873
|
+
</Popover.Content>
|
|
4874
|
+
</Popover>
|
|
4875
|
+
|
|
4876
|
+
<Popover>
|
|
4877
|
+
<Popover.Trigger asChild>
|
|
4878
|
+
<Button variant="secondary">Right</Button>
|
|
4879
|
+
</Popover.Trigger>
|
|
4880
|
+
<Popover.Content side="right">
|
|
4881
|
+
<Popover.Title>Right</Popover.Title>
|
|
4882
|
+
<Popover.Description>Popover on right.</Popover.Description>
|
|
4883
|
+
</Popover.Content>
|
|
4884
|
+
</Popover>
|
|
4885
|
+
</div>
|
|
4886
|
+
```
|
|
4887
|
+
|
|
4888
|
+
```tsx
|
|
4889
|
+
<Popover>
|
|
4890
|
+
<Popover.Trigger asChild>
|
|
4891
|
+
<Button>User Profile</Button>
|
|
4892
|
+
</Popover.Trigger>
|
|
4893
|
+
<Popover.Content className="w-64">
|
|
4894
|
+
<div className="flex items-center gap-3">
|
|
4895
|
+
<div className="size-10 rounded-full bg-sf-recessed" />
|
|
4896
|
+
<div>
|
|
4897
|
+
<Popover.Title>Jane Doe</Popover.Title>
|
|
4898
|
+
<p className="text-sm text-sf-subtle">jane@example.com</p>
|
|
4899
|
+
</div>
|
|
4900
|
+
</div>
|
|
4901
|
+
<div className="mt-3 flex gap-2 border-t border-sf-line pt-3">
|
|
4902
|
+
<Button variant="secondary" size="sm" className="flex-1">
|
|
4903
|
+
Profile
|
|
4904
|
+
</Button>
|
|
4905
|
+
<Popover.Close asChild>
|
|
4906
|
+
<Button variant="ghost" size="sm" className="flex-1">
|
|
4907
|
+
Sign Out
|
|
4908
|
+
</Button>
|
|
4909
|
+
</Popover.Close>
|
|
4910
|
+
</div>
|
|
4911
|
+
</Popover.Content>
|
|
4912
|
+
</Popover>
|
|
4913
|
+
```
|
|
4914
|
+
|
|
4915
|
+
```tsx
|
|
4916
|
+
<Popover>
|
|
4917
|
+
<Popover.Trigger openOnHover delay={200} asChild>
|
|
4918
|
+
<Button variant="secondary">Hover Me</Button>
|
|
4919
|
+
</Popover.Trigger>
|
|
4920
|
+
<Popover.Content>
|
|
4921
|
+
<Popover.Title>Hover Triggered</Popover.Title>
|
|
4922
|
+
<Popover.Description>
|
|
4923
|
+
This popover opens on hover with a 200ms delay. It can still contain
|
|
4924
|
+
interactive content like buttons and links.
|
|
4925
|
+
</Popover.Description>
|
|
4926
|
+
<div className="mt-3">
|
|
4927
|
+
<Popover.Close asChild>
|
|
4928
|
+
<Button variant="secondary" size="sm">
|
|
4929
|
+
Got it
|
|
4930
|
+
</Button>
|
|
4931
|
+
</Popover.Close>
|
|
4932
|
+
</div>
|
|
4933
|
+
</Popover.Content>
|
|
4934
|
+
</Popover>
|
|
4935
|
+
```
|
|
4936
|
+
|
|
2052
4937
|
---
|
|
2053
4938
|
|
|
2054
4939
|
### PromptInput
|
|
@@ -2071,8 +4956,10 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
|
|
|
2071
4956
|
Maximum file size in bytes.
|
|
2072
4957
|
- `backLayer`: ReactNode
|
|
2073
4958
|
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
|
-
|
|
4959
|
+
- `backLayerTitle`: ReactNode
|
|
4960
|
+
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"`.
|
|
4961
|
+
- `backLayerStatus`: enum
|
|
4962
|
+
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
4963
|
- `backLayerOpen`: boolean
|
|
2077
4964
|
Controls whether the back layer is visible. Pair with `onBackLayerOpenChange` for a controlled pattern.
|
|
2078
4965
|
- `autoOpenBackLayerWhen`: boolean
|
|
@@ -2085,7 +4972,7 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
|
|
|
2085
4972
|
|
|
2086
4973
|
**Colors (sf tokens used):**
|
|
2087
4974
|
|
|
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`
|
|
4975
|
+
`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
4976
|
|
|
2090
4977
|
**Sub-Components:**
|
|
2091
4978
|
|
|
@@ -2095,6 +4982,10 @@ This is a compound component. Use these sub-components:
|
|
|
2095
4982
|
|
|
2096
4983
|
BackLayer sub-component
|
|
2097
4984
|
|
|
4985
|
+
Props:
|
|
4986
|
+
|
|
4987
|
+
- `className`: string
|
|
4988
|
+
|
|
2098
4989
|
#### PromptInput.Textarea
|
|
2099
4990
|
|
|
2100
4991
|
Textarea sub-component
|
|
@@ -2127,10 +5018,18 @@ AddTagButton sub-component
|
|
|
2127
5018
|
|
|
2128
5019
|
Tags sub-component
|
|
2129
5020
|
|
|
5021
|
+
Props:
|
|
5022
|
+
|
|
5023
|
+
- `children`: (tag: PromptInputTagData) => ReactNode (required)
|
|
5024
|
+
|
|
2130
5025
|
#### PromptInput.Tag
|
|
2131
5026
|
|
|
2132
5027
|
Tag sub-component
|
|
2133
5028
|
|
|
5029
|
+
Props:
|
|
5030
|
+
|
|
5031
|
+
- `data`: PromptInputTagData (required)
|
|
5032
|
+
|
|
2134
5033
|
#### PromptInput.AttachButton
|
|
2135
5034
|
|
|
2136
5035
|
AttachButton sub-component
|
|
@@ -2139,10 +5038,17 @@ AttachButton sub-component
|
|
|
2139
5038
|
|
|
2140
5039
|
Attachments sub-component
|
|
2141
5040
|
|
|
5041
|
+
Props:
|
|
5042
|
+
|
|
5043
|
+
- `children`: (attachment: AttachmentFile) => ReactNode (required)
|
|
5044
|
+
|
|
2142
5045
|
#### PromptInput.Attachment
|
|
2143
5046
|
|
|
2144
5047
|
Attachment sub-component
|
|
2145
5048
|
|
|
5049
|
+
Props:
|
|
5050
|
+
|
|
5051
|
+
- `data`: AttachmentFile (required)
|
|
2146
5052
|
|
|
2147
5053
|
---
|
|
2148
5054
|
|
|
@@ -2183,6 +5089,77 @@ Radio — radio button group for single-select choices. Compound component: `Rad
|
|
|
2183
5089
|
|
|
2184
5090
|
`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
5091
|
|
|
5092
|
+
**Examples:**
|
|
5093
|
+
|
|
5094
|
+
```tsx
|
|
5095
|
+
<Radio.Group
|
|
5096
|
+
legend="Notification preference"
|
|
5097
|
+
value={value}
|
|
5098
|
+
onValueChange={setValue}
|
|
5099
|
+
>
|
|
5100
|
+
<Radio.Item label="Email" value="email" />
|
|
5101
|
+
<Radio.Item label="SMS" value="sms" />
|
|
5102
|
+
<Radio.Item label="Push notification" value="push" />
|
|
5103
|
+
</Radio.Group>
|
|
5104
|
+
```
|
|
5105
|
+
|
|
5106
|
+
```tsx
|
|
5107
|
+
<Radio.Group
|
|
5108
|
+
legend="Size"
|
|
5109
|
+
orientation="horizontal"
|
|
5110
|
+
value={value}
|
|
5111
|
+
onValueChange={setValue}
|
|
5112
|
+
>
|
|
5113
|
+
<Radio.Item label="Small" value="sm" />
|
|
5114
|
+
<Radio.Item label="Medium" value="md" />
|
|
5115
|
+
<Radio.Item label="Large" value="lg" />
|
|
5116
|
+
</Radio.Group>
|
|
5117
|
+
```
|
|
5118
|
+
|
|
5119
|
+
```tsx
|
|
5120
|
+
<Radio.Group
|
|
5121
|
+
legend="Shipping method"
|
|
5122
|
+
description="Choose how you'd like to receive your order"
|
|
5123
|
+
value={value}
|
|
5124
|
+
onValueChange={setValue}
|
|
5125
|
+
>
|
|
5126
|
+
<Radio.Item label="Standard (5-7 days)" value="standard" />
|
|
5127
|
+
<Radio.Item label="Express (2-3 days)" value="express" />
|
|
5128
|
+
<Radio.Item label="Overnight" value="overnight" />
|
|
5129
|
+
</Radio.Group>
|
|
5130
|
+
```
|
|
5131
|
+
|
|
5132
|
+
```tsx
|
|
5133
|
+
<Radio.Group
|
|
5134
|
+
legend="Payment method"
|
|
5135
|
+
error="Please select a payment method to continue"
|
|
5136
|
+
>
|
|
5137
|
+
<Radio.Item label="Credit Card" value="card" variant="error" />
|
|
5138
|
+
<Radio.Item label="PayPal" value="paypal" variant="error" />
|
|
5139
|
+
<Radio.Item label="Bank Transfer" value="bank" variant="error" />
|
|
5140
|
+
</Radio.Group>
|
|
5141
|
+
```
|
|
5142
|
+
|
|
5143
|
+
```tsx
|
|
5144
|
+
<div className="flex flex-col gap-6">
|
|
5145
|
+
<Radio.Group legend="Disabled group" disabled defaultValue="a">
|
|
5146
|
+
<Radio.Item label="Option A" value="a" />
|
|
5147
|
+
<Radio.Item label="Option B" value="b" />
|
|
5148
|
+
</Radio.Group>
|
|
5149
|
+
<Radio.Group legend="Individual disabled" defaultValue="available">
|
|
5150
|
+
<Radio.Item label="Available" value="available" />
|
|
5151
|
+
<Radio.Item label="Unavailable" value="unavailable" disabled />
|
|
5152
|
+
</Radio.Group>
|
|
5153
|
+
</div>
|
|
5154
|
+
```
|
|
5155
|
+
|
|
5156
|
+
```tsx
|
|
5157
|
+
<Radio.Group legend="Preferences" controlPosition="end" defaultValue="a">
|
|
5158
|
+
<Radio.Item label="Label before radio" value="a" />
|
|
5159
|
+
<Radio.Item label="Another option" value="b" />
|
|
5160
|
+
</Radio.Group>
|
|
5161
|
+
```
|
|
5162
|
+
|
|
2186
5163
|
---
|
|
2187
5164
|
|
|
2188
5165
|
### Select
|
|
@@ -2240,6 +5217,105 @@ This is a compound component. Use these sub-components:
|
|
|
2240
5217
|
|
|
2241
5218
|
Option sub-component
|
|
2242
5219
|
|
|
5220
|
+
**Examples:**
|
|
5221
|
+
|
|
5222
|
+
```tsx
|
|
5223
|
+
<Select
|
|
5224
|
+
className="w-[200px]"
|
|
5225
|
+
value={value}
|
|
5226
|
+
onValueChange={(v) => setValue(v ?? "apple")}
|
|
5227
|
+
items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
|
|
5228
|
+
>
|
|
5229
|
+
<Select.Option value="apple">Apple</Select.Option>
|
|
5230
|
+
<Select.Option value="banana">Banana</Select.Option>
|
|
5231
|
+
<Select.Option value="cherry">Cherry</Select.Option>
|
|
5232
|
+
</Select>
|
|
5233
|
+
```
|
|
5234
|
+
|
|
5235
|
+
```tsx
|
|
5236
|
+
<Select
|
|
5237
|
+
className="w-[200px]"
|
|
5238
|
+
renderValue={(v) => (
|
|
5239
|
+
<span>
|
|
5240
|
+
{v.emoji} {v.label}
|
|
5241
|
+
</span>
|
|
5242
|
+
)}
|
|
5243
|
+
value={value}
|
|
5244
|
+
onValueChange={(v) => setValue(v as (typeof languages)[0])}
|
|
5245
|
+
>
|
|
5246
|
+
{languages.map((language) => (
|
|
5247
|
+
<Select.Option key={language.value} value={language}>
|
|
5248
|
+
{language.emoji} {language.label}
|
|
5249
|
+
</Select.Option>
|
|
5250
|
+
))}
|
|
5251
|
+
</Select>
|
|
5252
|
+
```
|
|
5253
|
+
|
|
5254
|
+
```tsx
|
|
5255
|
+
<Select className="w-[200px]" loading />
|
|
5256
|
+
```
|
|
5257
|
+
|
|
5258
|
+
```tsx
|
|
5259
|
+
<Select
|
|
5260
|
+
className="w-[200px]"
|
|
5261
|
+
loading={loading}
|
|
5262
|
+
value={value}
|
|
5263
|
+
onValueChange={(v) => setValue(v as string | null)}
|
|
5264
|
+
placeholder="Please select"
|
|
5265
|
+
>
|
|
5266
|
+
{data?.map((item) => (
|
|
5267
|
+
<Select.Option key={item} value={item}>
|
|
5268
|
+
{item}
|
|
5269
|
+
</Select.Option>
|
|
5270
|
+
))}
|
|
5271
|
+
</Select>
|
|
5272
|
+
```
|
|
5273
|
+
|
|
5274
|
+
```tsx
|
|
5275
|
+
<Select
|
|
5276
|
+
className="w-[250px]"
|
|
5277
|
+
multiple
|
|
5278
|
+
renderValue={(value) => {
|
|
5279
|
+
if (value.length > 3) {
|
|
5280
|
+
return (
|
|
5281
|
+
<span className="line-clamp-1">
|
|
5282
|
+
{value.slice(2).join(", ") + ` and ${value.length - 2} more`}
|
|
5283
|
+
</span>
|
|
5284
|
+
);
|
|
5285
|
+
}
|
|
5286
|
+
return <span>{value.join(", ")}</span>;
|
|
5287
|
+
}}
|
|
5288
|
+
value={value}
|
|
5289
|
+
onValueChange={(v) => setValue(v as string[])}
|
|
5290
|
+
>
|
|
5291
|
+
<Select.Option value="Name">Name</Select.Option>
|
|
5292
|
+
<Select.Option value="Location">Location</Select.Option>
|
|
5293
|
+
<Select.Option value="Size">Size</Select.Option>
|
|
5294
|
+
<Select.Option value="Read">Read</Select.Option>
|
|
5295
|
+
<Select.Option value="Write">Write</Select.Option>
|
|
5296
|
+
<Select.Option value="CreatedAt">Created At</Select.Option>
|
|
5297
|
+
</Select>
|
|
5298
|
+
```
|
|
5299
|
+
|
|
5300
|
+
```tsx
|
|
5301
|
+
<Select
|
|
5302
|
+
className="w-[200px]"
|
|
5303
|
+
onValueChange={(v) => setValue(v as (typeof authors)[0] | null)}
|
|
5304
|
+
value={value}
|
|
5305
|
+
isItemEqualToValue={(item, value) => item?.id === value?.id}
|
|
5306
|
+
renderValue={(author) => author?.name ?? "Please select author"}
|
|
5307
|
+
>
|
|
5308
|
+
{authors.map((author) => (
|
|
5309
|
+
<Select.Option key={author.id} value={author}>
|
|
5310
|
+
<div className="flex w-[300px] items-center justify-between gap-2">
|
|
5311
|
+
<Text>{author.name}</Text>
|
|
5312
|
+
<Text variant="secondary">{author.title}</Text>
|
|
5313
|
+
</div>
|
|
5314
|
+
</Select.Option>
|
|
5315
|
+
))}
|
|
5316
|
+
</Select>
|
|
5317
|
+
```
|
|
5318
|
+
|
|
2243
5319
|
---
|
|
2244
5320
|
|
|
2245
5321
|
### SensitiveInput
|
|
@@ -2295,6 +5371,76 @@ Password/secret input that masks its value by default and reveals on click. Incl
|
|
|
2295
5371
|
|
|
2296
5372
|
`bg-sf-brand`, `bg-sf-control`, `outline-sf-ring`, `text-sf-default`, `text-sf-subtle`
|
|
2297
5373
|
|
|
5374
|
+
**Examples:**
|
|
5375
|
+
|
|
5376
|
+
```tsx
|
|
5377
|
+
<div className="w-80">
|
|
5378
|
+
<SensitiveInput label="API Key" defaultValue="sk_live_abc123xyz789" />
|
|
5379
|
+
</div>
|
|
5380
|
+
```
|
|
5381
|
+
|
|
5382
|
+
```tsx
|
|
5383
|
+
<div className="flex flex-col gap-4">
|
|
5384
|
+
{sizes.map((size) => (
|
|
5385
|
+
<div key={size} className="flex items-center gap-2">
|
|
5386
|
+
<span className="w-12 text-sm text-sf-subtle">{size}</span>
|
|
5387
|
+
<SensitiveInput
|
|
5388
|
+
label={`${size} size`}
|
|
5389
|
+
size={size}
|
|
5390
|
+
defaultValue="secret-api-key-123"
|
|
5391
|
+
/>
|
|
5392
|
+
</div>
|
|
5393
|
+
))}
|
|
5394
|
+
</div>
|
|
5395
|
+
```
|
|
5396
|
+
|
|
5397
|
+
```tsx
|
|
5398
|
+
<div className="flex w-80 flex-col gap-4">
|
|
5399
|
+
<SensitiveInput
|
|
5400
|
+
label="Controlled Secret"
|
|
5401
|
+
value={value}
|
|
5402
|
+
onValueChange={setValue}
|
|
5403
|
+
/>
|
|
5404
|
+
<div className="text-sm text-sf-subtle">
|
|
5405
|
+
Current value: <code className="text-sf-default">{value}</code>
|
|
5406
|
+
</div>
|
|
5407
|
+
<div className="flex gap-2">
|
|
5408
|
+
<Button
|
|
5409
|
+
onClick={() => setValue("new-secret-" + Date.now())}
|
|
5410
|
+
variant="primary"
|
|
5411
|
+
size="sm"
|
|
5412
|
+
>
|
|
5413
|
+
Change value
|
|
5414
|
+
</Button>
|
|
5415
|
+
<Button onClick={() => setValue("")} variant="secondary" size="sm">
|
|
5416
|
+
Clear
|
|
5417
|
+
</Button>
|
|
5418
|
+
</div>
|
|
5419
|
+
</div>
|
|
5420
|
+
```
|
|
5421
|
+
|
|
5422
|
+
```tsx
|
|
5423
|
+
<div className="flex w-80 flex-col gap-4">
|
|
5424
|
+
<SensitiveInput
|
|
5425
|
+
label="Error State"
|
|
5426
|
+
variant="error"
|
|
5427
|
+
defaultValue="invalid-key"
|
|
5428
|
+
error="This API key is not valid"
|
|
5429
|
+
/>
|
|
5430
|
+
<SensitiveInput label="Disabled" defaultValue="cannot-edit" disabled />
|
|
5431
|
+
<SensitiveInput
|
|
5432
|
+
label="Read-only"
|
|
5433
|
+
defaultValue="view-only-secret-key"
|
|
5434
|
+
readOnly
|
|
5435
|
+
/>
|
|
5436
|
+
<SensitiveInput
|
|
5437
|
+
label="With Description"
|
|
5438
|
+
defaultValue="my-secret-value"
|
|
5439
|
+
description="Keep this value secure and don't share it"
|
|
5440
|
+
/>
|
|
5441
|
+
</div>
|
|
5442
|
+
```
|
|
5443
|
+
|
|
2298
5444
|
---
|
|
2299
5445
|
|
|
2300
5446
|
### Sidebar
|
|
@@ -2457,6 +5603,283 @@ CollapsibleTrigger sub-component
|
|
|
2457
5603
|
|
|
2458
5604
|
CollapsibleContent sub-component
|
|
2459
5605
|
|
|
5606
|
+
**Examples:**
|
|
5607
|
+
|
|
5608
|
+
```tsx
|
|
5609
|
+
<DemoContainer>
|
|
5610
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5611
|
+
<Sidebar>
|
|
5612
|
+
<Sidebar.Content>
|
|
5613
|
+
<Sidebar.Group>
|
|
5614
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5615
|
+
<Sidebar.Menu>
|
|
5616
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5617
|
+
Home
|
|
5618
|
+
</Sidebar.MenuButton>
|
|
5619
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5620
|
+
Analytics
|
|
5621
|
+
</Sidebar.MenuButton>
|
|
5622
|
+
<Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
|
|
5623
|
+
</Sidebar.Menu>
|
|
5624
|
+
</Sidebar.Group>
|
|
5625
|
+
|
|
5626
|
+
<Sidebar.Group>
|
|
5627
|
+
<Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
|
|
5628
|
+
<Sidebar.Menu>
|
|
5629
|
+
<Sidebar.MenuItem>
|
|
5630
|
+
<Sidebar.Collapsible defaultOpen>
|
|
5631
|
+
<Sidebar.CollapsibleTrigger
|
|
5632
|
+
render={
|
|
5633
|
+
<Sidebar.MenuButton icon={CodeIcon}>
|
|
5634
|
+
Compute
|
|
5635
|
+
<Sidebar.MenuChevron />
|
|
5636
|
+
</Sidebar.MenuButton>
|
|
5637
|
+
}
|
|
5638
|
+
/>
|
|
5639
|
+
<Sidebar.CollapsibleContent>
|
|
5640
|
+
<Sidebar.MenuSub>
|
|
5641
|
+
<Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
|
|
5642
|
+
<Sidebar.MenuSubButton>
|
|
5643
|
+
Durable Objects
|
|
5644
|
+
</Sidebar.MenuSubButton>
|
|
5645
|
+
</Sidebar.MenuSub>
|
|
5646
|
+
</Sidebar.CollapsibleContent>
|
|
5647
|
+
</Sidebar.Collapsible>
|
|
5648
|
+
</Sidebar.MenuItem>
|
|
5649
|
+
<Sidebar.MenuButton icon={DatabaseIcon}>Storage</Sidebar.MenuButton>
|
|
5650
|
+
</Sidebar.Menu>
|
|
5651
|
+
</Sidebar.Group>
|
|
5652
|
+
</Sidebar.Content>
|
|
5653
|
+
</Sidebar>
|
|
5654
|
+
<DemoMain />
|
|
5655
|
+
</Sidebar.Provider>
|
|
5656
|
+
</DemoContainer>
|
|
5657
|
+
```
|
|
5658
|
+
|
|
5659
|
+
```tsx
|
|
5660
|
+
<DemoContainer>
|
|
5661
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5662
|
+
<Sidebar>
|
|
5663
|
+
<Sidebar.Content>
|
|
5664
|
+
<Sidebar.Group collapsible defaultOpen>
|
|
5665
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5666
|
+
<Sidebar.GroupContent>
|
|
5667
|
+
<Sidebar.Menu>
|
|
5668
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5669
|
+
Home
|
|
5670
|
+
</Sidebar.MenuButton>
|
|
5671
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5672
|
+
Analytics
|
|
5673
|
+
</Sidebar.MenuButton>
|
|
5674
|
+
<Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
|
|
5675
|
+
</Sidebar.Menu>
|
|
5676
|
+
</Sidebar.GroupContent>
|
|
5677
|
+
</Sidebar.Group>
|
|
5678
|
+
|
|
5679
|
+
<Sidebar.Group collapsible defaultOpen={false}>
|
|
5680
|
+
<Sidebar.GroupLabel>Settings</Sidebar.GroupLabel>
|
|
5681
|
+
<Sidebar.GroupContent>
|
|
5682
|
+
<Sidebar.Menu>
|
|
5683
|
+
<Sidebar.MenuButton icon={ShieldCheckIcon}>
|
|
5684
|
+
Security
|
|
5685
|
+
</Sidebar.MenuButton>
|
|
5686
|
+
<Sidebar.MenuButton icon={LockIcon}>
|
|
5687
|
+
Access Control
|
|
5688
|
+
</Sidebar.MenuButton>
|
|
5689
|
+
</Sidebar.Menu>
|
|
5690
|
+
</Sidebar.GroupContent>
|
|
5691
|
+
</Sidebar.Group>
|
|
5692
|
+
</Sidebar.Content>
|
|
5693
|
+
</Sidebar>
|
|
5694
|
+
<DemoMain />
|
|
5695
|
+
</Sidebar.Provider>
|
|
5696
|
+
</DemoContainer>
|
|
5697
|
+
```
|
|
5698
|
+
|
|
5699
|
+
```tsx
|
|
5700
|
+
<DemoContainer>
|
|
5701
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5702
|
+
<Sidebar>
|
|
5703
|
+
<Sidebar.Header>
|
|
5704
|
+
<BrandLogo />
|
|
5705
|
+
</Sidebar.Header>
|
|
5706
|
+
<Sidebar.Content>
|
|
5707
|
+
<Sidebar.Group>
|
|
5708
|
+
<Sidebar.Menu>
|
|
5709
|
+
<Sidebar.MenuButton icon={HouseIcon} tooltip="Home" active>
|
|
5710
|
+
Home
|
|
5711
|
+
</Sidebar.MenuButton>
|
|
5712
|
+
<Sidebar.MenuButton icon={ChartBarIcon} tooltip="Analytics">
|
|
5713
|
+
Analytics
|
|
5714
|
+
</Sidebar.MenuButton>
|
|
5715
|
+
<Sidebar.MenuButton icon={CodeIcon} tooltip="Compute">
|
|
5716
|
+
Compute
|
|
5717
|
+
</Sidebar.MenuButton>
|
|
5718
|
+
<Sidebar.MenuButton icon={DatabaseIcon} tooltip="Storage">
|
|
5719
|
+
Storage
|
|
5720
|
+
</Sidebar.MenuButton>
|
|
5721
|
+
</Sidebar.Menu>
|
|
5722
|
+
</Sidebar.Group>
|
|
5723
|
+
</Sidebar.Content>
|
|
5724
|
+
<Sidebar.Footer>
|
|
5725
|
+
<Sidebar.Trigger />
|
|
5726
|
+
</Sidebar.Footer>
|
|
5727
|
+
</Sidebar>
|
|
5728
|
+
<DemoMain>
|
|
5729
|
+
<ToggleButton />
|
|
5730
|
+
<p className="text-sm">
|
|
5731
|
+
Click the button or the sidebar trigger to toggle
|
|
5732
|
+
</p>
|
|
5733
|
+
</DemoMain>
|
|
5734
|
+
</Sidebar.Provider>
|
|
5735
|
+
</DemoContainer>
|
|
5736
|
+
```
|
|
5737
|
+
|
|
5738
|
+
```tsx
|
|
5739
|
+
<DemoContainer>
|
|
5740
|
+
<Sidebar.Provider defaultOpen className="min-h-0! h-full">
|
|
5741
|
+
<Sidebar>
|
|
5742
|
+
<Sidebar.Header>
|
|
5743
|
+
<BrandLogo />
|
|
5744
|
+
</Sidebar.Header>
|
|
5745
|
+
|
|
5746
|
+
<Sidebar.Content>
|
|
5747
|
+
<div className="px-1 pb-2">
|
|
5748
|
+
<Sidebar.Input placeholder="Quick search..." shortcut="⌘K" />
|
|
5749
|
+
</div>
|
|
5750
|
+
|
|
5751
|
+
<Sidebar.Group>
|
|
5752
|
+
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
|
|
5753
|
+
<Sidebar.Menu>
|
|
5754
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5755
|
+
Home
|
|
5756
|
+
</Sidebar.MenuButton>
|
|
5757
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5758
|
+
Analytics
|
|
5759
|
+
</Sidebar.MenuButton>
|
|
5760
|
+
<Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
|
|
5761
|
+
</Sidebar.Menu>
|
|
5762
|
+
</Sidebar.Group>
|
|
5763
|
+
|
|
5764
|
+
<Sidebar.Separator />
|
|
5765
|
+
|
|
5766
|
+
<Sidebar.Group>
|
|
5767
|
+
<Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
|
|
5768
|
+
<Sidebar.Menu>
|
|
5769
|
+
<Sidebar.MenuItem>
|
|
5770
|
+
<Sidebar.Collapsible defaultOpen>
|
|
5771
|
+
<Sidebar.CollapsibleTrigger
|
|
5772
|
+
render={
|
|
5773
|
+
<Sidebar.MenuButton icon={CodeIcon}>
|
|
5774
|
+
Compute
|
|
5775
|
+
<Sidebar.MenuChevron />
|
|
5776
|
+
</Sidebar.MenuButton>
|
|
5777
|
+
}
|
|
5778
|
+
/>
|
|
5779
|
+
<Sidebar.CollapsibleContent>
|
|
5780
|
+
<Sidebar.MenuSub>
|
|
5781
|
+
<Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
|
|
5782
|
+
<Sidebar.MenuSubButton>
|
|
5783
|
+
Durable Objects
|
|
5784
|
+
</Sidebar.MenuSubButton>
|
|
5785
|
+
<Sidebar.MenuSubButton>
|
|
5786
|
+
Containers
|
|
5787
|
+
<Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
|
|
5788
|
+
</Sidebar.MenuSubButton>
|
|
5789
|
+
</Sidebar.MenuSub>
|
|
5790
|
+
</Sidebar.CollapsibleContent>
|
|
5791
|
+
</Sidebar.Collapsible>
|
|
5792
|
+
</Sidebar.MenuItem>
|
|
5793
|
+
<Sidebar.MenuButton icon={DatabaseIcon}>Storage</Sidebar.MenuButton>
|
|
5794
|
+
</Sidebar.Menu>
|
|
5795
|
+
</Sidebar.Group>
|
|
5796
|
+
|
|
5797
|
+
<Sidebar.Group>
|
|
5798
|
+
<Sidebar.GroupLabel>Security</Sidebar.GroupLabel>
|
|
5799
|
+
<Sidebar.Menu>
|
|
5800
|
+
<Sidebar.MenuButton icon={ShieldCheckIcon}>
|
|
5801
|
+
Firewall
|
|
5802
|
+
</Sidebar.MenuButton>
|
|
5803
|
+
<Sidebar.MenuButton icon={LockIcon}>
|
|
5804
|
+
Access
|
|
5805
|
+
<Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
|
|
5806
|
+
</Sidebar.MenuButton>
|
|
5807
|
+
<Sidebar.MenuButton icon={BellIcon}>
|
|
5808
|
+
Notifications
|
|
5809
|
+
</Sidebar.MenuButton>
|
|
5810
|
+
</Sidebar.Menu>
|
|
5811
|
+
</Sidebar.Group>
|
|
5812
|
+
</Sidebar.Content>
|
|
5813
|
+
|
|
5814
|
+
<Sidebar.Footer>
|
|
5815
|
+
<Sidebar.MenuButton icon={GearIcon}>Settings</Sidebar.MenuButton>
|
|
5816
|
+
</Sidebar.Footer>
|
|
5817
|
+
</Sidebar>
|
|
5818
|
+
<DemoMain />
|
|
5819
|
+
</Sidebar.Provider>
|
|
5820
|
+
</DemoContainer>
|
|
5821
|
+
```
|
|
5822
|
+
|
|
5823
|
+
```tsx
|
|
5824
|
+
<DemoContainer>
|
|
5825
|
+
<Sidebar.Provider
|
|
5826
|
+
defaultOpen
|
|
5827
|
+
resizable
|
|
5828
|
+
defaultWidth={240}
|
|
5829
|
+
minWidth={180}
|
|
5830
|
+
maxWidth={400}
|
|
5831
|
+
className="min-h-0! h-full"
|
|
5832
|
+
>
|
|
5833
|
+
<Sidebar>
|
|
5834
|
+
<Sidebar.Header>
|
|
5835
|
+
<BrandLogo />
|
|
5836
|
+
</Sidebar.Header>
|
|
5837
|
+
<Sidebar.Content>
|
|
5838
|
+
<Sidebar.Group>
|
|
5839
|
+
<Sidebar.Menu>
|
|
5840
|
+
<Sidebar.MenuButton icon={HouseIcon} active>
|
|
5841
|
+
Home
|
|
5842
|
+
</Sidebar.MenuButton>
|
|
5843
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>
|
|
5844
|
+
Analytics
|
|
5845
|
+
</Sidebar.MenuButton>
|
|
5846
|
+
<Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
|
|
5847
|
+
</Sidebar.Menu>
|
|
5848
|
+
</Sidebar.Group>
|
|
5849
|
+
</Sidebar.Content>
|
|
5850
|
+
<Sidebar.ResizeHandle />
|
|
5851
|
+
</Sidebar>
|
|
5852
|
+
<DemoMain>
|
|
5853
|
+
<p className="text-sm">Drag the sidebar edge to resize</p>
|
|
5854
|
+
</DemoMain>
|
|
5855
|
+
</Sidebar.Provider>
|
|
5856
|
+
</DemoContainer>
|
|
5857
|
+
```
|
|
5858
|
+
|
|
5859
|
+
```tsx
|
|
5860
|
+
<DemoContainer>
|
|
5861
|
+
<Sidebar.Provider defaultOpen side="right" className="min-h-0! h-full">
|
|
5862
|
+
<DemoMain>
|
|
5863
|
+
<p className="text-sm">Sidebar on the right</p>
|
|
5864
|
+
</DemoMain>
|
|
5865
|
+
<Sidebar>
|
|
5866
|
+
<Sidebar.Content>
|
|
5867
|
+
<Sidebar.Group>
|
|
5868
|
+
<Sidebar.GroupLabel>Details</Sidebar.GroupLabel>
|
|
5869
|
+
<Sidebar.Menu>
|
|
5870
|
+
<Sidebar.MenuButton icon={GearIcon} active>
|
|
5871
|
+
Properties
|
|
5872
|
+
</Sidebar.MenuButton>
|
|
5873
|
+
<Sidebar.MenuButton icon={ChartBarIcon}>Metrics</Sidebar.MenuButton>
|
|
5874
|
+
<Sidebar.MenuButton icon={BellIcon}>Alerts</Sidebar.MenuButton>
|
|
5875
|
+
</Sidebar.Menu>
|
|
5876
|
+
</Sidebar.Group>
|
|
5877
|
+
</Sidebar.Content>
|
|
5878
|
+
</Sidebar>
|
|
5879
|
+
</Sidebar.Provider>
|
|
5880
|
+
</DemoContainer>
|
|
5881
|
+
```
|
|
5882
|
+
|
|
2460
5883
|
---
|
|
2461
5884
|
|
|
2462
5885
|
### SignalFlareAILogo
|
|
@@ -2732,6 +6155,127 @@ SignalFlare AI logo component.
|
|
|
2732
6155
|
|
|
2733
6156
|
`bg-sf-base`, `ring-sf-line`, `text-sf-default`
|
|
2734
6157
|
|
|
6158
|
+
**Examples:**
|
|
6159
|
+
|
|
6160
|
+
```tsx
|
|
6161
|
+
<SignalFlareAILogo className="w-72" />
|
|
6162
|
+
```
|
|
6163
|
+
|
|
6164
|
+
```tsx
|
|
6165
|
+
<SignalFlareAILogo variant="glyph" className="w-16" />
|
|
6166
|
+
```
|
|
6167
|
+
|
|
6168
|
+
```tsx
|
|
6169
|
+
<div className="flex flex-wrap items-center gap-8">
|
|
6170
|
+
<SignalFlareAILogo className="w-32" color="brand" />
|
|
6171
|
+
<SignalFlareAILogo className="w-32" color="mono" />
|
|
6172
|
+
<div className="rounded-lg bg-white p-4">
|
|
6173
|
+
<SignalFlareAILogo className="w-32" color="black" />
|
|
6174
|
+
</div>
|
|
6175
|
+
<div className="rounded-lg bg-black p-4">
|
|
6176
|
+
<SignalFlareAILogo className="w-32" color="white" />
|
|
6177
|
+
</div>
|
|
6178
|
+
</div>
|
|
6179
|
+
```
|
|
6180
|
+
|
|
6181
|
+
```tsx
|
|
6182
|
+
<div className="flex flex-wrap items-center gap-8">
|
|
6183
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="brand" />
|
|
6184
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="mono" />
|
|
6185
|
+
<div className="rounded-lg bg-white p-4">
|
|
6186
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="black" />
|
|
6187
|
+
</div>
|
|
6188
|
+
<div className="rounded-lg bg-black p-4">
|
|
6189
|
+
<SignalFlareAILogo variant="glyph" className="w-10" color="white" />
|
|
6190
|
+
</div>
|
|
6191
|
+
</div>
|
|
6192
|
+
```
|
|
6193
|
+
|
|
6194
|
+
```tsx
|
|
6195
|
+
<div className="flex flex-wrap items-end gap-6">
|
|
6196
|
+
<SignalFlareAILogo className="w-24" />
|
|
6197
|
+
<SignalFlareAILogo className="w-36" />
|
|
6198
|
+
<SignalFlareAILogo className="w-52" />
|
|
6199
|
+
</div>
|
|
6200
|
+
```
|
|
6201
|
+
|
|
6202
|
+
```tsx
|
|
6203
|
+
<div className="flex items-center gap-4">
|
|
6204
|
+
<DropdownMenu>
|
|
6205
|
+
<DropdownMenu.Trigger>
|
|
6206
|
+
<button
|
|
6207
|
+
type="button"
|
|
6208
|
+
className="flex items-center gap-2 rounded-lg bg-[#4188ff] px-4 py-3 text-white transition-opacity hover:opacity-80"
|
|
6209
|
+
>
|
|
6210
|
+
<SignalFlareAILogo variant="glyph" color="white" className="w-6" />
|
|
6211
|
+
<span className="font-medium">Logo</span>
|
|
6212
|
+
</button>
|
|
6213
|
+
</DropdownMenu.Trigger>
|
|
6214
|
+
<DropdownMenu.Content>
|
|
6215
|
+
<DropdownMenu.Item
|
|
6216
|
+
icon={MapPinIcon}
|
|
6217
|
+
onSelect={() =>
|
|
6218
|
+
copyToClipboard(
|
|
6219
|
+
generateSignalFlareAILogoSvg({ variant: "glyph" }),
|
|
6220
|
+
"glyph"
|
|
6221
|
+
)
|
|
6222
|
+
}
|
|
6223
|
+
>
|
|
6224
|
+
{copied === "glyph" ? "Copied!" : "Copy icon as SVG"}
|
|
6225
|
+
</DropdownMenu.Item>
|
|
6226
|
+
<DropdownMenu.Item
|
|
6227
|
+
icon={CodeIcon}
|
|
6228
|
+
onSelect={() =>
|
|
6229
|
+
copyToClipboard(
|
|
6230
|
+
generateSignalFlareAILogoSvg({ variant: "full" }),
|
|
6231
|
+
"full"
|
|
6232
|
+
)
|
|
6233
|
+
}
|
|
6234
|
+
>
|
|
6235
|
+
{copied === "full" ? "Copied!" : "Copy full logo as SVG"}
|
|
6236
|
+
</DropdownMenu.Item>
|
|
6237
|
+
<DropdownMenu.Separator />
|
|
6238
|
+
<DropdownMenu.Item
|
|
6239
|
+
icon={ArrowSquareOutIcon}
|
|
6240
|
+
onSelect={() =>
|
|
6241
|
+
window.open("https://signalflare.ai", "_blank", "noopener")
|
|
6242
|
+
}
|
|
6243
|
+
>
|
|
6244
|
+
Visit SignalFlare AI
|
|
6245
|
+
</DropdownMenu.Item>
|
|
6246
|
+
</DropdownMenu.Content>
|
|
6247
|
+
</DropdownMenu>
|
|
6248
|
+
|
|
6249
|
+
<span className="text-sm text-sf-subtle">
|
|
6250
|
+
Click to open the brand assets menu
|
|
6251
|
+
</span>
|
|
6252
|
+
</div>
|
|
6253
|
+
```
|
|
6254
|
+
|
|
6255
|
+
```tsx
|
|
6256
|
+
<PoweredBySignalFlareAI />
|
|
6257
|
+
```
|
|
6258
|
+
|
|
6259
|
+
```tsx
|
|
6260
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
6261
|
+
<PoweredBySignalFlareAI color="brand" />
|
|
6262
|
+
<PoweredBySignalFlareAI color="mono" />
|
|
6263
|
+
<PoweredBySignalFlareAI color="black" />
|
|
6264
|
+
<div className="rounded-lg bg-black p-3">
|
|
6265
|
+
<PoweredBySignalFlareAI color="white" />
|
|
6266
|
+
</div>
|
|
6267
|
+
</div>
|
|
6268
|
+
```
|
|
6269
|
+
|
|
6270
|
+
```tsx
|
|
6271
|
+
<footer className="flex w-full items-center justify-between rounded-lg border border-sf-line bg-sf-elevated px-6 py-4">
|
|
6272
|
+
<span className="text-sm text-sf-subtle">
|
|
6273
|
+
© 2026 Your Company. All rights reserved.
|
|
6274
|
+
</span>
|
|
6275
|
+
<PoweredBySignalFlareAI />
|
|
6276
|
+
</footer>
|
|
6277
|
+
```
|
|
6278
|
+
|
|
2735
6279
|
---
|
|
2736
6280
|
|
|
2737
6281
|
### Sparkline
|
|
@@ -2751,11 +6295,26 @@ Sparkline — a tiny inline chart intended for embedding in cards, tables, or ro
|
|
|
2751
6295
|
- `children`: ReactNode
|
|
2752
6296
|
Child elements
|
|
2753
6297
|
|
|
6298
|
+
**Examples:**
|
|
6299
|
+
|
|
6300
|
+
```tsx
|
|
6301
|
+
<Sparkline echarts={echarts} data={sample} isDarkMode={isDarkMode} />
|
|
6302
|
+
```
|
|
6303
|
+
|
|
6304
|
+
```tsx
|
|
6305
|
+
<Sparkline
|
|
6306
|
+
echarts={echarts}
|
|
6307
|
+
data={sample}
|
|
6308
|
+
variant="area"
|
|
6309
|
+
isDarkMode={isDarkMode}
|
|
6310
|
+
/>
|
|
6311
|
+
```
|
|
6312
|
+
|
|
2754
6313
|
---
|
|
2755
6314
|
|
|
2756
6315
|
### StatCard
|
|
2757
6316
|
|
|
2758
|
-
StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline.
|
|
6317
|
+
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
6318
|
|
|
2760
6319
|
**Type:** component
|
|
2761
6320
|
|
|
@@ -2786,6 +6345,24 @@ StatCard — compact KPI tile displaying a label, a primary value, and an option
|
|
|
2786
6345
|
|
|
2787
6346
|
`bg-sf-elevated`, `bg-sf-fill`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
|
|
2788
6347
|
|
|
6348
|
+
**Examples:**
|
|
6349
|
+
|
|
6350
|
+
```tsx
|
|
6351
|
+
<StatCard
|
|
6352
|
+
label="Active users"
|
|
6353
|
+
value="12,384"
|
|
6354
|
+
delta={{ value: 0.12, label: "vs last week" }}
|
|
6355
|
+
/>
|
|
6356
|
+
```
|
|
6357
|
+
|
|
6358
|
+
```tsx
|
|
6359
|
+
<StatCard size="sm" label="MRR" value="$128,420" hint="30-day avg" />
|
|
6360
|
+
```
|
|
6361
|
+
|
|
6362
|
+
```tsx
|
|
6363
|
+
<StatCard label="Signups" value="—" loading />
|
|
6364
|
+
```
|
|
6365
|
+
|
|
2789
6366
|
---
|
|
2790
6367
|
|
|
2791
6368
|
### Surface
|
|
@@ -2811,6 +6388,44 @@ Surface component
|
|
|
2811
6388
|
|
|
2812
6389
|
`bg-sf-base`, `ring-sf-line`
|
|
2813
6390
|
|
|
6391
|
+
**Examples:**
|
|
6392
|
+
|
|
6393
|
+
```tsx
|
|
6394
|
+
<Surface className="rounded-lg p-6">
|
|
6395
|
+
<Text size="lg" bold>
|
|
6396
|
+
Surface Component
|
|
6397
|
+
</Text>
|
|
6398
|
+
<div className="mt-2">
|
|
6399
|
+
<Text variant="secondary">
|
|
6400
|
+
A container with consistent elevation and border styling.
|
|
6401
|
+
</Text>
|
|
6402
|
+
</div>
|
|
6403
|
+
</Surface>
|
|
6404
|
+
```
|
|
6405
|
+
|
|
6406
|
+
```tsx
|
|
6407
|
+
<div className="flex flex-col gap-4">
|
|
6408
|
+
<Surface as="section" className="rounded-lg p-4">
|
|
6409
|
+
<Text bold>As section element</Text>
|
|
6410
|
+
</Surface>
|
|
6411
|
+
<Surface as="article" className="rounded-lg p-4">
|
|
6412
|
+
<Text bold>As article element</Text>
|
|
6413
|
+
</Surface>
|
|
6414
|
+
<Surface as="aside" className="rounded-lg p-4">
|
|
6415
|
+
<Text bold>As aside element</Text>
|
|
6416
|
+
</Surface>
|
|
6417
|
+
</div>
|
|
6418
|
+
```
|
|
6419
|
+
|
|
6420
|
+
```tsx
|
|
6421
|
+
<Surface className="rounded-lg p-6">
|
|
6422
|
+
<Text bold>Outer Surface</Text>
|
|
6423
|
+
<Surface className="mt-4 rounded-md bg-sf-elevated p-4">
|
|
6424
|
+
<Text variant="secondary">Nested Surface</Text>
|
|
6425
|
+
</Surface>
|
|
6426
|
+
</Surface>
|
|
6427
|
+
```
|
|
6428
|
+
|
|
2814
6429
|
---
|
|
2815
6430
|
|
|
2816
6431
|
### Switch
|
|
@@ -2879,6 +6494,16 @@ Props:
|
|
|
2879
6494
|
- `controlFirst`: boolean
|
|
2880
6495
|
- `className`: string
|
|
2881
6496
|
|
|
6497
|
+
**Examples:**
|
|
6498
|
+
|
|
6499
|
+
```tsx
|
|
6500
|
+
<Switch label="Switch" checked={checked} onCheckedChange={setChecked} />
|
|
6501
|
+
```
|
|
6502
|
+
|
|
6503
|
+
```tsx
|
|
6504
|
+
<Switch label="Disabled" checked={false} disabled />
|
|
6505
|
+
```
|
|
6506
|
+
|
|
2882
6507
|
---
|
|
2883
6508
|
|
|
2884
6509
|
### Table
|
|
@@ -2948,6 +6573,234 @@ Footer sub-component
|
|
|
2948
6573
|
|
|
2949
6574
|
ResizeHandle sub-component
|
|
2950
6575
|
|
|
6576
|
+
**Examples:**
|
|
6577
|
+
|
|
6578
|
+
```tsx
|
|
6579
|
+
<LayerCard>
|
|
6580
|
+
<LayerCard.Primary className="p-0">
|
|
6581
|
+
<Table>
|
|
6582
|
+
<Table.Header>
|
|
6583
|
+
<Table.Row>
|
|
6584
|
+
<Table.Head>Subject</Table.Head>
|
|
6585
|
+
<Table.Head>From</Table.Head>
|
|
6586
|
+
<Table.Head>Date</Table.Head>
|
|
6587
|
+
</Table.Row>
|
|
6588
|
+
</Table.Header>
|
|
6589
|
+
<Table.Body>
|
|
6590
|
+
{emailData.slice(0, 3).map((row) => (
|
|
6591
|
+
<Table.Row key={row.id}>
|
|
6592
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6593
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6594
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6595
|
+
</Table.Row>
|
|
6596
|
+
))}
|
|
6597
|
+
</Table.Body>
|
|
6598
|
+
</Table>
|
|
6599
|
+
</LayerCard.Primary>
|
|
6600
|
+
</LayerCard>
|
|
6601
|
+
```
|
|
6602
|
+
|
|
6603
|
+
```tsx
|
|
6604
|
+
<LayerCard>
|
|
6605
|
+
<LayerCard.Primary className="p-0">
|
|
6606
|
+
<Table>
|
|
6607
|
+
<Table.Header>
|
|
6608
|
+
<Table.Row>
|
|
6609
|
+
<Table.CheckHead
|
|
6610
|
+
checked={selectedIds.size === rows.length}
|
|
6611
|
+
indeterminate={
|
|
6612
|
+
selectedIds.size > 0 && selectedIds.size < rows.length
|
|
6613
|
+
}
|
|
6614
|
+
onValueChange={toggleAll}
|
|
6615
|
+
aria-label="Select all rows"
|
|
6616
|
+
/>
|
|
6617
|
+
<Table.Head>Subject</Table.Head>
|
|
6618
|
+
<Table.Head>From</Table.Head>
|
|
6619
|
+
<Table.Head>Date</Table.Head>
|
|
6620
|
+
</Table.Row>
|
|
6621
|
+
</Table.Header>
|
|
6622
|
+
<Table.Body>
|
|
6623
|
+
{rows.map((row) => (
|
|
6624
|
+
<Table.Row key={row.id}>
|
|
6625
|
+
<Table.CheckCell
|
|
6626
|
+
checked={selectedIds.has(row.id)}
|
|
6627
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6628
|
+
aria-label={`Select ${row.subject}`}
|
|
6629
|
+
/>
|
|
6630
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6631
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6632
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6633
|
+
</Table.Row>
|
|
6634
|
+
))}
|
|
6635
|
+
</Table.Body>
|
|
6636
|
+
</Table>
|
|
6637
|
+
</LayerCard.Primary>
|
|
6638
|
+
</LayerCard>
|
|
6639
|
+
```
|
|
6640
|
+
|
|
6641
|
+
```tsx
|
|
6642
|
+
<LayerCard>
|
|
6643
|
+
<LayerCard.Primary className="p-0">
|
|
6644
|
+
<Table>
|
|
6645
|
+
<Table.Header>
|
|
6646
|
+
<Table.Row>
|
|
6647
|
+
<Table.CheckHead
|
|
6648
|
+
checked={selectedIds.size === rows.length}
|
|
6649
|
+
indeterminate={
|
|
6650
|
+
selectedIds.size > 0 && selectedIds.size < rows.length
|
|
6651
|
+
}
|
|
6652
|
+
onValueChange={toggleAll}
|
|
6653
|
+
aria-label="Select all rows"
|
|
6654
|
+
/>
|
|
6655
|
+
<Table.Head>Subject</Table.Head>
|
|
6656
|
+
<Table.Head>From</Table.Head>
|
|
6657
|
+
<Table.Head>Date</Table.Head>
|
|
6658
|
+
</Table.Row>
|
|
6659
|
+
</Table.Header>
|
|
6660
|
+
<Table.Body>
|
|
6661
|
+
{rows.map((row) => (
|
|
6662
|
+
<Table.Row
|
|
6663
|
+
key={row.id}
|
|
6664
|
+
variant={selectedIds.has(row.id) ? "selected" : "default"}
|
|
6665
|
+
>
|
|
6666
|
+
<Table.CheckCell
|
|
6667
|
+
checked={selectedIds.has(row.id)}
|
|
6668
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6669
|
+
aria-label={`Select ${row.subject}`}
|
|
6670
|
+
/>
|
|
6671
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6672
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6673
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6674
|
+
</Table.Row>
|
|
6675
|
+
))}
|
|
6676
|
+
</Table.Body>
|
|
6677
|
+
</Table>
|
|
6678
|
+
</LayerCard.Primary>
|
|
6679
|
+
</LayerCard>
|
|
6680
|
+
```
|
|
6681
|
+
|
|
6682
|
+
```tsx
|
|
6683
|
+
<LayerCard>
|
|
6684
|
+
<LayerCard.Primary className="p-0">
|
|
6685
|
+
<Table layout="fixed">
|
|
6686
|
+
<colgroup>
|
|
6687
|
+
<col />
|
|
6688
|
+
<col className="w-[150px]" />
|
|
6689
|
+
<col className="w-[150px]" />
|
|
6690
|
+
</colgroup>
|
|
6691
|
+
<Table.Header>
|
|
6692
|
+
<Table.Row>
|
|
6693
|
+
<Table.Head>Subject</Table.Head>
|
|
6694
|
+
<Table.Head>From</Table.Head>
|
|
6695
|
+
<Table.Head>Date</Table.Head>
|
|
6696
|
+
</Table.Row>
|
|
6697
|
+
</Table.Header>
|
|
6698
|
+
<Table.Body>
|
|
6699
|
+
{emailData.map((row) => (
|
|
6700
|
+
<Table.Row key={row.id}>
|
|
6701
|
+
<Table.Cell>{row.subject}</Table.Cell>
|
|
6702
|
+
<Table.Cell>{row.from}</Table.Cell>
|
|
6703
|
+
<Table.Cell>{row.date}</Table.Cell>
|
|
6704
|
+
</Table.Row>
|
|
6705
|
+
))}
|
|
6706
|
+
</Table.Body>
|
|
6707
|
+
</Table>
|
|
6708
|
+
</LayerCard.Primary>
|
|
6709
|
+
</LayerCard>
|
|
6710
|
+
```
|
|
6711
|
+
|
|
6712
|
+
```tsx
|
|
6713
|
+
<LayerCard>
|
|
6714
|
+
<LayerCard.Primary className="w-full overflow-x-auto p-0">
|
|
6715
|
+
<Table layout="fixed">
|
|
6716
|
+
<colgroup>
|
|
6717
|
+
<col />{" "}
|
|
6718
|
+
{/* Checkbox column - width handled by Table.CheckHead/CheckCell */}
|
|
6719
|
+
<col />
|
|
6720
|
+
<col style={{ width: "150px" }} />
|
|
6721
|
+
<col style={{ width: "120px" }} />
|
|
6722
|
+
<col style={{ width: "50px" }} />
|
|
6723
|
+
</colgroup>
|
|
6724
|
+
<Table.Header>
|
|
6725
|
+
<Table.Row>
|
|
6726
|
+
<Table.CheckHead
|
|
6727
|
+
checked={selectedIds.size === emailData.length}
|
|
6728
|
+
indeterminate={
|
|
6729
|
+
selectedIds.size > 0 && selectedIds.size < emailData.length
|
|
6730
|
+
}
|
|
6731
|
+
onValueChange={toggleAll}
|
|
6732
|
+
aria-label="Select all rows"
|
|
6733
|
+
/>
|
|
6734
|
+
<Table.Head>Subject</Table.Head>
|
|
6735
|
+
<Table.Head>From</Table.Head>
|
|
6736
|
+
<Table.Head>Date</Table.Head>
|
|
6737
|
+
<Table.Head />
|
|
6738
|
+
</Table.Row>
|
|
6739
|
+
</Table.Header>
|
|
6740
|
+
<Table.Body>
|
|
6741
|
+
{emailData.map((row) => (
|
|
6742
|
+
<Table.Row
|
|
6743
|
+
key={row.id}
|
|
6744
|
+
variant={selectedIds.has(row.id) ? "selected" : "default"}
|
|
6745
|
+
>
|
|
6746
|
+
<Table.CheckCell
|
|
6747
|
+
checked={selectedIds.has(row.id)}
|
|
6748
|
+
onValueChange={() => toggleRow(row.id)}
|
|
6749
|
+
aria-label={`Select ${row.subject}`}
|
|
6750
|
+
/>
|
|
6751
|
+
<Table.Cell>
|
|
6752
|
+
<div className="flex items-center gap-2">
|
|
6753
|
+
<EnvelopeSimpleIcon size={16} />
|
|
6754
|
+
<span className="truncate">{row.subject}</span>
|
|
6755
|
+
{row.tags && (
|
|
6756
|
+
<div className="ml-2 inline-flex gap-1">
|
|
6757
|
+
{row.tags.map((tag) => (
|
|
6758
|
+
<Badge key={tag}>{tag}</Badge>
|
|
6759
|
+
))}
|
|
6760
|
+
</div>
|
|
6761
|
+
)}
|
|
6762
|
+
</div>
|
|
6763
|
+
</Table.Cell>
|
|
6764
|
+
<Table.Cell>
|
|
6765
|
+
<span className="truncate">{row.from}</span>
|
|
6766
|
+
</Table.Cell>
|
|
6767
|
+
<Table.Cell>
|
|
6768
|
+
<span className="truncate">{row.date}</span>
|
|
6769
|
+
</Table.Cell>
|
|
6770
|
+
<Table.Cell className="text-right">
|
|
6771
|
+
<DropdownMenu>
|
|
6772
|
+
<DropdownMenu.Trigger
|
|
6773
|
+
render={
|
|
6774
|
+
<Button
|
|
6775
|
+
variant="ghost"
|
|
6776
|
+
size="sm"
|
|
6777
|
+
shape="square"
|
|
6778
|
+
aria-label="More options"
|
|
6779
|
+
>
|
|
6780
|
+
<DotsThreeIcon weight="bold" size={16} />
|
|
6781
|
+
</Button>
|
|
6782
|
+
}
|
|
6783
|
+
/>
|
|
6784
|
+
<DropdownMenu.Content>
|
|
6785
|
+
<DropdownMenu.Item icon={EyeIcon}>View</DropdownMenu.Item>
|
|
6786
|
+
<DropdownMenu.Item icon={PencilSimpleIcon}>
|
|
6787
|
+
Edit
|
|
6788
|
+
</DropdownMenu.Item>
|
|
6789
|
+
<DropdownMenu.Separator />
|
|
6790
|
+
<DropdownMenu.Item icon={TrashIcon} variant="danger">
|
|
6791
|
+
Delete
|
|
6792
|
+
</DropdownMenu.Item>
|
|
6793
|
+
</DropdownMenu.Content>
|
|
6794
|
+
</DropdownMenu>
|
|
6795
|
+
</Table.Cell>
|
|
6796
|
+
</Table.Row>
|
|
6797
|
+
))}
|
|
6798
|
+
</Table.Body>
|
|
6799
|
+
</Table>
|
|
6800
|
+
</LayerCard.Primary>
|
|
6801
|
+
</LayerCard>
|
|
6802
|
+
```
|
|
6803
|
+
|
|
2951
6804
|
---
|
|
2952
6805
|
|
|
2953
6806
|
### Tabs
|
|
@@ -2990,6 +6843,114 @@ Tab navigation component with segmented, underline, or pill style. Built on Base
|
|
|
2990
6843
|
|
|
2991
6844
|
**Styling:**
|
|
2992
6845
|
|
|
6846
|
+
**Examples:**
|
|
6847
|
+
|
|
6848
|
+
```tsx
|
|
6849
|
+
<div className="flex flex-col gap-6">
|
|
6850
|
+
<div>
|
|
6851
|
+
<p className="mb-2 text-sm text-sf-subtle">Segmented (default)</p>
|
|
6852
|
+
<Tabs
|
|
6853
|
+
variant="segmented"
|
|
6854
|
+
tabs={[
|
|
6855
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6856
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6857
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6858
|
+
]}
|
|
6859
|
+
selectedValue="tab1"
|
|
6860
|
+
/>
|
|
6861
|
+
</div>
|
|
6862
|
+
<div>
|
|
6863
|
+
<p className="mb-2 text-sm text-sf-subtle">Underline</p>
|
|
6864
|
+
<Tabs
|
|
6865
|
+
variant="underline"
|
|
6866
|
+
tabs={[
|
|
6867
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6868
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6869
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6870
|
+
]}
|
|
6871
|
+
selectedValue="tab1"
|
|
6872
|
+
/>
|
|
6873
|
+
</div>
|
|
6874
|
+
<div>
|
|
6875
|
+
<p className="mb-2 text-sm text-sf-subtle">Pill</p>
|
|
6876
|
+
<Tabs
|
|
6877
|
+
variant="pill"
|
|
6878
|
+
tabs={[
|
|
6879
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6880
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6881
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6882
|
+
]}
|
|
6883
|
+
selectedValue="tab1"
|
|
6884
|
+
/>
|
|
6885
|
+
</div>
|
|
6886
|
+
</div>
|
|
6887
|
+
```
|
|
6888
|
+
|
|
6889
|
+
```tsx
|
|
6890
|
+
<Tabs
|
|
6891
|
+
variant="segmented"
|
|
6892
|
+
tabs={[
|
|
6893
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6894
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6895
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6896
|
+
]}
|
|
6897
|
+
selectedValue="tab1"
|
|
6898
|
+
/>
|
|
6899
|
+
```
|
|
6900
|
+
|
|
6901
|
+
```tsx
|
|
6902
|
+
<div className="space-y-4">
|
|
6903
|
+
<Tabs
|
|
6904
|
+
tabs={[
|
|
6905
|
+
{ label: "Tab 1", value: "tab1" },
|
|
6906
|
+
{ label: "Tab 2", value: "tab2" },
|
|
6907
|
+
{ label: "Tab 3", value: "tab3" },
|
|
6908
|
+
]}
|
|
6909
|
+
value={activeTab}
|
|
6910
|
+
onValueChange={setActiveTab}
|
|
6911
|
+
/>
|
|
6912
|
+
<p className="text-sm text-sf-subtle">
|
|
6913
|
+
Active tab: <code className="text-sm">{activeTab}</code>
|
|
6914
|
+
</p>
|
|
6915
|
+
</div>
|
|
6916
|
+
```
|
|
6917
|
+
|
|
6918
|
+
```tsx
|
|
6919
|
+
<Tabs
|
|
6920
|
+
tabs={[
|
|
6921
|
+
{ label: "Overview", value: "overview" },
|
|
6922
|
+
{ label: "Analytics", value: "analytics" },
|
|
6923
|
+
{ label: "Reports", value: "reports" },
|
|
6924
|
+
{ label: "Notifications", value: "notifications" },
|
|
6925
|
+
{ label: "Settings", value: "settings" },
|
|
6926
|
+
{ label: "Billing", value: "billing" },
|
|
6927
|
+
]}
|
|
6928
|
+
selectedValue="overview"
|
|
6929
|
+
/>
|
|
6930
|
+
```
|
|
6931
|
+
|
|
6932
|
+
```tsx
|
|
6933
|
+
<Tabs
|
|
6934
|
+
tabs={[
|
|
6935
|
+
{
|
|
6936
|
+
label: "Regular Tab",
|
|
6937
|
+
value: "tab1",
|
|
6938
|
+
},
|
|
6939
|
+
{
|
|
6940
|
+
label: "Link Tab",
|
|
6941
|
+
render: (props) => <a {...props} href="#tab2" />,
|
|
6942
|
+
value: "tab2",
|
|
6943
|
+
},
|
|
6944
|
+
{
|
|
6945
|
+
label: "Another Link",
|
|
6946
|
+
render: (props) => <a {...props} href="#tab3" />,
|
|
6947
|
+
value: "tab3",
|
|
6948
|
+
},
|
|
6949
|
+
]}
|
|
6950
|
+
selectedValue="tab1"
|
|
6951
|
+
/>
|
|
6952
|
+
```
|
|
6953
|
+
|
|
2993
6954
|
---
|
|
2994
6955
|
|
|
2995
6956
|
### Text
|
|
@@ -3025,6 +6986,14 @@ Text component
|
|
|
3025
6986
|
The HTML element type to render as (e.g. `"span"`, `"p"`, `"h1"`). Auto-selected based on variant if omitted.
|
|
3026
6987
|
- `children`: ReactNode
|
|
3027
6988
|
Text content.
|
|
6989
|
+
- `wrap`: MeasuredTextMode | boolean
|
|
6990
|
+
Text layout strategy using pretext-driven measurement.
|
|
6991
|
+
- `"natural"` — No measurement, normal browser wrapping (default for body).
|
|
6992
|
+
- `"balance"` — Even wrapping, smallest maxWidth without adding lines (default for headings).
|
|
6993
|
+
- `"shrink"` — Hug widest natural line (maxWidth = line width). Good for chat bubbles.
|
|
6994
|
+
- `"reserve"` — Reserve height based on line count. Good for streaming text.
|
|
6995
|
+
- `reserveLines`: number
|
|
6996
|
+
For `wrap="reserve"`: reserve this many lines of height. If omitted, measures current content to determine line count.
|
|
3028
6997
|
|
|
3029
6998
|
**Colors (sf tokens used):**
|
|
3030
6999
|
|
|
@@ -3032,6 +7001,71 @@ Text component
|
|
|
3032
7001
|
|
|
3033
7002
|
**Styling:**
|
|
3034
7003
|
|
|
7004
|
+
**Examples:**
|
|
7005
|
+
|
|
7006
|
+
```tsx
|
|
7007
|
+
<div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
7008
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7009
|
+
<Text variant="heading1">Heading 1</Text>
|
|
7010
|
+
<p className="font-mono text-xs text-sf-subtle">text-3xl (30px)</p>
|
|
7011
|
+
</div>
|
|
7012
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7013
|
+
<Text variant="heading2">Heading 2</Text>
|
|
7014
|
+
<p className="font-mono text-xs text-sf-subtle">text-2xl (24px)</p>
|
|
7015
|
+
</div>
|
|
7016
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7017
|
+
<Text variant="heading3">Heading 3</Text>
|
|
7018
|
+
<p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
|
|
7019
|
+
</div>
|
|
7020
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7021
|
+
<Text>Body</Text>
|
|
7022
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7023
|
+
</div>
|
|
7024
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7025
|
+
<Text bold>Body bold</Text>
|
|
7026
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7027
|
+
</div>
|
|
7028
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7029
|
+
<Text size="lg">Body lg</Text>
|
|
7030
|
+
<p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
|
|
7031
|
+
</div>
|
|
7032
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7033
|
+
<Text size="sm">Body sm</Text>
|
|
7034
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7035
|
+
</div>
|
|
7036
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7037
|
+
<Text size="xs">Body xs</Text>
|
|
7038
|
+
<p className="font-mono text-xs text-sf-subtle">text-xs (12px)</p>
|
|
7039
|
+
</div>
|
|
7040
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7041
|
+
<Text variant="secondary">Body secondary</Text>
|
|
7042
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7043
|
+
</div>
|
|
7044
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7045
|
+
<Text variant="mono">Monospace</Text>
|
|
7046
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7047
|
+
</div>
|
|
7048
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7049
|
+
<Text variant="mono" size="lg">
|
|
7050
|
+
Monospace lg
|
|
7051
|
+
</Text>
|
|
7052
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7053
|
+
</div>
|
|
7054
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7055
|
+
<Text variant="mono-secondary">Monospace secondary</Text>
|
|
7056
|
+
<p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
|
|
7057
|
+
</div>
|
|
7058
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7059
|
+
<Text variant="success">Success</Text>
|
|
7060
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7061
|
+
</div>
|
|
7062
|
+
<div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
|
|
7063
|
+
<Text variant="error">Error</Text>
|
|
7064
|
+
<p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
|
|
7065
|
+
</div>
|
|
7066
|
+
</div>
|
|
7067
|
+
```
|
|
7068
|
+
|
|
3035
7069
|
---
|
|
3036
7070
|
|
|
3037
7071
|
### TextRoll
|
|
@@ -3149,6 +7183,33 @@ Accessible popup that shows additional information on hover/focus. Wrap your app
|
|
|
3149
7183
|
|
|
3150
7184
|
`bg-sf-elevated`, `fill-sf-elevated`, `fill-sf-tip-shadow`, `fill-sf-tip-stroke`, `outline-sf-fill`, `text-sf-default`
|
|
3151
7185
|
|
|
7186
|
+
**Examples:**
|
|
7187
|
+
|
|
7188
|
+
```tsx
|
|
7189
|
+
<TooltipProvider>
|
|
7190
|
+
<Tooltip content="Add new item">
|
|
7191
|
+
<Button shape="square" icon={PlusIcon} aria-label="Add new item" />
|
|
7192
|
+
</Tooltip>
|
|
7193
|
+
</TooltipProvider>
|
|
7194
|
+
```
|
|
7195
|
+
|
|
7196
|
+
```tsx
|
|
7197
|
+
<TooltipProvider>
|
|
7198
|
+
<div className="flex gap-2">
|
|
7199
|
+
<Tooltip content="Add">
|
|
7200
|
+
<Button shape="square" icon={PlusIcon} aria-label="Add" />
|
|
7201
|
+
</Tooltip>
|
|
7202
|
+
<Tooltip content="Change language">
|
|
7203
|
+
<Button
|
|
7204
|
+
shape="square"
|
|
7205
|
+
icon={TranslateIcon}
|
|
7206
|
+
aria-label="Change language"
|
|
7207
|
+
/>
|
|
7208
|
+
</Tooltip>
|
|
7209
|
+
</div>
|
|
7210
|
+
</TooltipProvider>
|
|
7211
|
+
```
|
|
7212
|
+
|
|
3152
7213
|
---
|
|
3153
7214
|
|
|
3154
7215
|
### InputArea
|