@graph8/sdk 0.303.0 → 0.357.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -0
- package/blocks/README.md +32 -0
- package/blocks/_foundation/README.md +78 -0
- package/blocks/_foundation/block.json +79 -0
- package/blocks/_foundation/components/api-error.tsx +62 -0
- package/blocks/_foundation/components/confirm-spend-dialog.tsx +142 -0
- package/blocks/_foundation/components/empty-state.tsx +24 -0
- package/blocks/_foundation/hooks/use-g8-mutation.ts +88 -0
- package/blocks/_foundation/hooks/use-g8-query.ts +87 -0
- package/blocks/_foundation/hooks/use-job-poll.ts +130 -0
- package/blocks/_foundation/hooks/use-paginated.ts +105 -0
- package/blocks/_foundation/lib/g8-client.ts +128 -0
- package/blocks/_foundation/recipes/verify-proxy-key.ts +18 -0
- package/blocks/_foundation/server/proxy.ts +233 -0
- package/blocks/_foundation/server/route.ts +30 -0
- package/blocks/agents/README.md +133 -0
- package/blocks/agents/block.json +223 -0
- package/blocks/agents/components/agent-builder.tsx +199 -0
- package/blocks/agents/components/agent-knowledge-panel.tsx +144 -0
- package/blocks/agents/components/agent-runs.tsx +175 -0
- package/blocks/agents/components/agent-skills-panel.tsx +126 -0
- package/blocks/agents/components/agent-test-console.tsx +175 -0
- package/blocks/agents/lib/agent-types.ts +114 -0
- package/blocks/agents/recipes/create-agent-and-attach-skill.ts +50 -0
- package/blocks/agents/recipes/run-and-follow-agent-run.ts +46 -0
- package/blocks/agents/recipes/test-agent-before-activating.ts +36 -0
- package/blocks/analytics/README.md +73 -0
- package/blocks/analytics/block.json +178 -0
- package/blocks/analytics/components/funnel-chart.tsx +79 -0
- package/blocks/analytics/components/kpi-tiles.tsx +74 -0
- package/blocks/analytics/components/leaderboard.tsx +86 -0
- package/blocks/analytics/components/report-builder.tsx +200 -0
- package/blocks/analytics/hooks/use-report.ts +26 -0
- package/blocks/analytics/lib/analytics-types.ts +108 -0
- package/blocks/analytics/lib/use-debounced.ts +16 -0
- package/blocks/analytics/recipes/01-weekly-outbound-report.ts +32 -0
- package/blocks/analytics/recipes/02-revenue-snapshot.ts +22 -0
- package/blocks/analytics/recipes/03-saved-report.ts +30 -0
- package/blocks/appointments/README.md +80 -0
- package/blocks/appointments/block.json +218 -0
- package/blocks/appointments/components/availability-editor.tsx +192 -0
- package/blocks/appointments/components/booking-page.tsx +154 -0
- package/blocks/appointments/components/event-type-editor.tsx +214 -0
- package/blocks/appointments/components/meeting-detail.tsx +147 -0
- package/blocks/appointments/components/meeting-list.tsx +148 -0
- package/blocks/appointments/hooks/use-available-slots.ts +29 -0
- package/blocks/appointments/hooks/use-schedules.ts +18 -0
- package/blocks/appointments/lib/appointments-types.ts +159 -0
- package/blocks/appointments/lib/idempotency.ts +30 -0
- package/blocks/appointments/recipes/01-create-event-type-and-hours.ts +27 -0
- package/blocks/appointments/recipes/02-find-slots-and-book.ts +34 -0
- package/blocks/appointments/recipes/03-bookings-digest.ts +22 -0
- package/blocks/appointments/recipes/04-calendar-invite.ts +21 -0
- package/blocks/block.schema.json +130 -0
- package/blocks/block.types.ts +109 -0
- package/blocks/campaigns/README.md +118 -0
- package/blocks/campaigns/block.json +361 -0
- package/blocks/campaigns/components/campaign-assets.tsx +180 -0
- package/blocks/campaigns/components/campaign-audience-step.tsx +91 -0
- package/blocks/campaigns/components/campaign-launch-step.tsx +147 -0
- package/blocks/campaigns/components/campaign-list.tsx +120 -0
- package/blocks/campaigns/components/campaign-metrics.tsx +93 -0
- package/blocks/campaigns/components/campaign-select.tsx +52 -0
- package/blocks/campaigns/components/campaign-sequence-step.tsx +158 -0
- package/blocks/campaigns/components/campaign-wizard.tsx +238 -0
- package/blocks/campaigns/components/form-field.tsx +29 -0
- package/blocks/campaigns/components/icp-editor.tsx +230 -0
- package/blocks/campaigns/components/persona-editor.tsx +210 -0
- package/blocks/campaigns/hooks/use-company-profile.ts +34 -0
- package/blocks/campaigns/lib/campaigns-utils.ts +155 -0
- package/blocks/campaigns/recipes/attach-audience-and-launch.ts +33 -0
- package/blocks/campaigns/recipes/campaign-report.ts +22 -0
- package/blocks/campaigns/recipes/generate-ideas-and-create-campaign.ts +51 -0
- package/blocks/campaigns/recipes/set-up-icp-and-personas.ts +37 -0
- package/blocks/coach/README.md +93 -0
- package/blocks/coach/block.json +125 -0
- package/blocks/coach/components/call-scorecard.tsx +126 -0
- package/blocks/coach/components/coaching-feed.tsx +140 -0
- package/blocks/coach/lib/coach-types.ts +116 -0
- package/blocks/coach/recipes/read-a-scorecard.ts +27 -0
- package/blocks/coach/recipes/weekly-coaching-digest.ts +53 -0
- package/blocks/copilot/README.md +99 -0
- package/blocks/copilot/block.json +151 -0
- package/blocks/copilot/components/copilot-memory.tsx +87 -0
- package/blocks/copilot/components/copilot-panel.tsx +189 -0
- package/blocks/copilot/components/copilot-team-chat.tsx +111 -0
- package/blocks/copilot/lib/copilot-types.ts +111 -0
- package/blocks/copilot/recipes/ask-the-copilot.ts +35 -0
- package/blocks/copilot/recipes/post-in-a-work-channel.ts +33 -0
- package/blocks/copilot/recipes/remember-and-recall.ts +19 -0
- package/blocks/crm/README.md +122 -0
- package/blocks/crm/block.json +378 -0
- package/blocks/crm/components/activity-timeline.tsx +99 -0
- package/blocks/crm/components/company-detail.tsx +118 -0
- package/blocks/crm/components/company-table.tsx +173 -0
- package/blocks/crm/components/contact-detail.tsx +135 -0
- package/blocks/crm/components/contact-table.tsx +217 -0
- package/blocks/crm/components/dedupe-review.tsx +164 -0
- package/blocks/crm/components/import-wizard.tsx +193 -0
- package/blocks/crm/components/notes-panel.tsx +112 -0
- package/blocks/crm/components/record-form.tsx +191 -0
- package/blocks/crm/components/task-list.tsx +107 -0
- package/blocks/crm/hooks/use-custom-fields.ts +18 -0
- package/blocks/crm/hooks/use-debounced.ts +13 -0
- package/blocks/crm/hooks/use-page-query.ts +52 -0
- package/blocks/crm/lib/crm-types.ts +136 -0
- package/blocks/crm/recipes/custom-fields-and-values.ts +28 -0
- package/blocks/crm/recipes/dedupe-and-merge.ts +30 -0
- package/blocks/crm/recipes/notes-tasks-and-activity.ts +23 -0
- package/blocks/crm/recipes/upsert-contact-with-company.ts +33 -0
- package/blocks/deals/README.md +78 -0
- package/blocks/deals/block.json +198 -0
- package/blocks/deals/components/deal-detail.tsx +134 -0
- package/blocks/deals/components/forecast-view.tsx +112 -0
- package/blocks/deals/components/pipeline-board.tsx +142 -0
- package/blocks/deals/components/stage-editor.tsx +96 -0
- package/blocks/deals/hooks/use-pipeline-deals.ts +67 -0
- package/blocks/deals/hooks/use-pipelines.ts +19 -0
- package/blocks/deals/lib/deals-types.ts +128 -0
- package/blocks/deals/recipes/01-create-deal-and-advance.ts +32 -0
- package/blocks/deals/recipes/02-pipeline-report.ts +35 -0
- package/blocks/deals/recipes/03-stale-deals-sweep.ts +20 -0
- package/blocks/dialer/README.md +114 -0
- package/blocks/dialer/block.json +260 -0
- package/blocks/dialer/components/call-log.tsx +78 -0
- package/blocks/dialer/components/call-queue.tsx +188 -0
- package/blocks/dialer/components/dialer-workspace.tsx +47 -0
- package/blocks/dialer/components/disposition-panel.tsx +75 -0
- package/blocks/dialer/components/live-calls-table.tsx +107 -0
- package/blocks/dialer/components/session-start-form.tsx +111 -0
- package/blocks/dialer/components/softphone.tsx +122 -0
- package/blocks/dialer/components/transcript-viewer.tsx +82 -0
- package/blocks/dialer/hooks/use-dialer-numbers.ts +19 -0
- package/blocks/dialer/hooks/use-dialer-session.ts +68 -0
- package/blocks/dialer/hooks/use-dispositions.ts +29 -0
- package/blocks/dialer/lib/dialer-types.ts +158 -0
- package/blocks/dialer/lib/softphone-transport.ts +67 -0
- package/blocks/dialer/lib/twilio-transport.ts +74 -0
- package/blocks/dialer/recipes/01-create-session-and-dial.ts +39 -0
- package/blocks/dialer/recipes/02-disposition-calls.ts +26 -0
- package/blocks/dialer/recipes/03-review-a-call.ts +23 -0
- package/blocks/enrichment/README.md +105 -0
- package/blocks/enrichment/block.json +204 -0
- package/blocks/enrichment/components/bulk-enrich-panel.tsx +205 -0
- package/blocks/enrichment/components/email-verify-badge.tsx +82 -0
- package/blocks/enrichment/components/enrich-button.tsx +136 -0
- package/blocks/enrichment/components/waterfall-config.tsx +127 -0
- package/blocks/enrichment/hooks/use-providers.ts +18 -0
- package/blocks/enrichment/lib/enrichment-types.ts +104 -0
- package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +41 -0
- package/blocks/enrichment/recipes/lookup-and-verify.ts +25 -0
- package/blocks/enrichment/recipes/waterfall-pipeline.ts +26 -0
- package/blocks/forms/README.md +112 -0
- package/blocks/forms/block.json +200 -0
- package/blocks/forms/components/form-builder.tsx +150 -0
- package/blocks/forms/components/form-embed.tsx +103 -0
- package/blocks/forms/components/form-mapping-editor.tsx +125 -0
- package/blocks/forms/components/site-audit-panel.tsx +73 -0
- package/blocks/forms/components/submissions-table.tsx +158 -0
- package/blocks/forms/lib/form-types.ts +127 -0
- package/blocks/forms/recipes/install-snippet-and-form.ts +21 -0
- package/blocks/forms/recipes/retry-failed-deliveries.ts +26 -0
- package/blocks/forms/recipes/route-form-to-list.ts +44 -0
- package/blocks/inbox/README.md +72 -0
- package/blocks/inbox/block.json +194 -0
- package/blocks/inbox/components/inbox-list.tsx +156 -0
- package/blocks/inbox/components/inbox-screen.tsx +49 -0
- package/blocks/inbox/components/reply-composer.tsx +183 -0
- package/blocks/inbox/components/tag-and-assign.tsx +189 -0
- package/blocks/inbox/components/thread-badge.tsx +17 -0
- package/blocks/inbox/components/thread-view.tsx +108 -0
- package/blocks/inbox/hooks/use-inbox-thread.ts +24 -0
- package/blocks/inbox/hooks/use-inbox-threads.ts +40 -0
- package/blocks/inbox/lib/idempotency.ts +30 -0
- package/blocks/inbox/lib/inbox-types.ts +100 -0
- package/blocks/inbox/recipes/01-triage-and-reply.ts +43 -0
- package/blocks/inbox/recipes/02-tag-and-assign.ts +31 -0
- package/blocks/inbox/recipes/03-hot-contacts-digest.ts +16 -0
- package/blocks/integrations/README.md +75 -0
- package/blocks/integrations/block.json +172 -0
- package/blocks/integrations/components/integration-list.tsx +165 -0
- package/blocks/integrations/components/sync-status.tsx +223 -0
- package/blocks/integrations/components/webhook-manager.tsx +300 -0
- package/blocks/integrations/lib/integrations-utils.ts +62 -0
- package/blocks/integrations/recipes/crm-sync-health.ts +19 -0
- package/blocks/integrations/recipes/push-contacts-to-crm.ts +20 -0
- package/blocks/integrations/recipes/register-webhook.ts +18 -0
- package/blocks/integrations/recipes/verify-webhook-route.ts +33 -0
- package/blocks/intent/README.md +57 -0
- package/blocks/intent/block.json +138 -0
- package/blocks/intent/components/account-intent-score.tsx +91 -0
- package/blocks/intent/components/intent-feed.tsx +215 -0
- package/blocks/intent/components/intent-keyword-manager.tsx +331 -0
- package/blocks/intent/hooks/use-account-intent.ts +46 -0
- package/blocks/intent/lib/intent-utils.ts +95 -0
- package/blocks/intent/recipes/rank-intent-accounts.ts +36 -0
- package/blocks/intent/recipes/track-competitor-domain.ts +23 -0
- package/blocks/intent/recipes/who-visited-url.ts +18 -0
- package/blocks/lifecycle/README.md +79 -0
- package/blocks/lifecycle/block.json +198 -0
- package/blocks/lifecycle/components/churn-list.tsx +92 -0
- package/blocks/lifecycle/components/customer-table.tsx +119 -0
- package/blocks/lifecycle/components/lead-queue.tsx +127 -0
- package/blocks/lifecycle/components/lifecycle-board.tsx +102 -0
- package/blocks/lifecycle/components/stage-move-dialog.tsx +75 -0
- package/blocks/lifecycle/hooks/use-debounced.ts +13 -0
- package/blocks/lifecycle/hooks/use-lifecycle-stages.ts +27 -0
- package/blocks/lifecycle/lib/lifecycle.ts +99 -0
- package/blocks/lifecycle/recipes/customer-brief.ts +23 -0
- package/blocks/lifecycle/recipes/move-company-stage.ts +17 -0
- package/blocks/lifecycle/recipes/read-lifecycle-board.ts +21 -0
- package/blocks/lifecycle/recipes/unlock-stage-contacts.ts +25 -0
- package/blocks/lists/README.md +96 -0
- package/blocks/lists/block.json +166 -0
- package/blocks/lists/components/add-to-list-button.tsx +111 -0
- package/blocks/lists/components/list-picker.tsx +94 -0
- package/blocks/lists/components/list-table.tsx +160 -0
- package/blocks/lists/components/suppression-manager.tsx +153 -0
- package/blocks/lists/recipes/create-list-and-add-contacts.ts +35 -0
- package/blocks/lists/recipes/refresh-and-check-lists.ts +21 -0
- package/blocks/lists/recipes/suppress-and-reinstate.ts +30 -0
- package/blocks/mailboxes/README.md +71 -0
- package/blocks/mailboxes/block.json +187 -0
- package/blocks/mailboxes/components/connect-mailbox.tsx +284 -0
- package/blocks/mailboxes/components/domain-purchase.tsx +271 -0
- package/blocks/mailboxes/components/mailbox-list.tsx +185 -0
- package/blocks/mailboxes/components/warmup-health.tsx +232 -0
- package/blocks/mailboxes/lib/mailboxes-utils.ts +69 -0
- package/blocks/mailboxes/recipes/buy-domain-and-mailboxes.ts +64 -0
- package/blocks/mailboxes/recipes/connect-imap-mailbox.ts +38 -0
- package/blocks/mailboxes/recipes/is-it-safe-to-send.ts +17 -0
- package/blocks/mailboxes/recipes/warmup-report.ts +31 -0
- package/blocks/newsletter/README.md +122 -0
- package/blocks/newsletter/block.json +224 -0
- package/blocks/newsletter/components/issue-form.tsx +124 -0
- package/blocks/newsletter/components/issue-scheduler.tsx +152 -0
- package/blocks/newsletter/components/newsletter-editor.tsx +131 -0
- package/blocks/newsletter/components/newsletter-stats.tsx +93 -0
- package/blocks/newsletter/components/subscriber-table.tsx +173 -0
- package/blocks/newsletter/lib/newsletter-types.ts +97 -0
- package/blocks/newsletter/recipes/create-newsletter-and-draft-issue.ts +27 -0
- package/blocks/newsletter/recipes/import-audience-and-send.ts +43 -0
- package/blocks/newsletter/recipes/issue-performance-report.ts +26 -0
- package/blocks/nurture/README.md +110 -0
- package/blocks/nurture/block.json +191 -0
- package/blocks/nurture/components/nurture-builder.tsx +114 -0
- package/blocks/nurture/components/nurture-enroll.tsx +107 -0
- package/blocks/nurture/components/nurture-form.tsx +120 -0
- package/blocks/nurture/components/nurture-stats.tsx +81 -0
- package/blocks/nurture/lib/nurture-types.ts +109 -0
- package/blocks/nurture/recipes/create-a-nurture.ts +34 -0
- package/blocks/nurture/recipes/enroll-contacts-and-launch.ts +24 -0
- package/blocks/nurture/recipes/nurture-health-check.ts +28 -0
- package/blocks/objects/README.md +120 -0
- package/blocks/objects/block.json +243 -0
- package/blocks/objects/components/attribute-field-input.tsx +82 -0
- package/blocks/objects/components/attribute-form-dialog.tsx +159 -0
- package/blocks/objects/components/object-not-found.tsx +34 -0
- package/blocks/objects/components/object-record-detail.tsx +143 -0
- package/blocks/objects/components/object-schema-editor.tsx +197 -0
- package/blocks/objects/components/object-table.tsx +130 -0
- package/blocks/objects/components/record-form-dialog.tsx +112 -0
- package/blocks/objects/components/record-roles-panel.tsx +106 -0
- package/blocks/objects/hooks/use-object-schema.ts +36 -0
- package/blocks/objects/lib/object-types.ts +214 -0
- package/blocks/objects/recipes/define-object-and-add-records.ts +24 -0
- package/blocks/objects/recipes/update-audit-and-archive-records.ts +39 -0
- package/blocks/objects/recipes/upsert-records-from-your-system.ts +30 -0
- package/blocks/pages/README.md +104 -0
- package/blocks/pages/block.json +223 -0
- package/blocks/pages/components/brand-kit-editor.tsx +152 -0
- package/blocks/pages/components/content-library.tsx +163 -0
- package/blocks/pages/components/page-editor.tsx +253 -0
- package/blocks/pages/components/page-list.tsx +159 -0
- package/blocks/pages/components/seo-report.tsx +159 -0
- package/blocks/pages/lib/studio.ts +77 -0
- package/blocks/pages/recipes/audit-site-seo.ts +28 -0
- package/blocks/pages/recipes/create-and-publish-page.ts +26 -0
- package/blocks/pages/recipes/edit-page-section.ts +25 -0
- package/blocks/pages/recipes/refresh-brand-kit.ts +22 -0
- package/blocks/quotes/README.md +79 -0
- package/blocks/quotes/block.json +183 -0
- package/blocks/quotes/components/product-picker.tsx +80 -0
- package/blocks/quotes/components/quote-builder.tsx +195 -0
- package/blocks/quotes/components/quote-list.tsx +79 -0
- package/blocks/quotes/components/quote-viewer.tsx +135 -0
- package/blocks/quotes/components/signature-status.tsx +77 -0
- package/blocks/quotes/hooks/use-debounced.ts +13 -0
- package/blocks/quotes/lib/quotes.ts +142 -0
- package/blocks/quotes/recipes/create-and-send-quote.ts +44 -0
- package/blocks/quotes/recipes/revise-sent-quote.ts +18 -0
- package/blocks/quotes/recipes/track-quote-signature.ts +22 -0
- package/blocks/radar/README.md +106 -0
- package/blocks/radar/block.json +189 -0
- package/blocks/radar/components/competitor-battle-card.tsx +53 -0
- package/blocks/radar/components/competitor-tracker.tsx +158 -0
- package/blocks/radar/components/radar-overview.tsx +67 -0
- package/blocks/radar/components/radar-report.tsx +86 -0
- package/blocks/radar/hooks/use-competitors.ts +23 -0
- package/blocks/radar/lib/radar-types.ts +124 -0
- package/blocks/radar/recipes/battle-card.ts +28 -0
- package/blocks/radar/recipes/deep-dive-report.ts +32 -0
- package/blocks/radar/recipes/marketing-snapshot.ts +18 -0
- package/blocks/radar/recipes/track-and-scan.ts +39 -0
- package/blocks/search/README.md +129 -0
- package/blocks/search/block.json +185 -0
- package/blocks/search/components/filter-builder.tsx +149 -0
- package/blocks/search/components/prospect-results.tsx +175 -0
- package/blocks/search/components/save-to-list-dialog.tsx +135 -0
- package/blocks/search/components/saved-searches.tsx +95 -0
- package/blocks/search/hooks/use-filter-options.ts +41 -0
- package/blocks/search/lib/search-types.ts +149 -0
- package/blocks/search/recipes/explore-filter-values.ts +27 -0
- package/blocks/search/recipes/saved-searches.ts +34 -0
- package/blocks/search/recipes/search-and-save-to-list.ts +37 -0
- package/blocks/sequencer/README.md +87 -0
- package/blocks/sequencer/block.json +214 -0
- package/blocks/sequencer/components/enroll-dialog.tsx +93 -0
- package/blocks/sequencer/components/sequence-builder.tsx +306 -0
- package/blocks/sequencer/components/sequence-list.tsx +200 -0
- package/blocks/sequencer/components/sequence-stats.tsx +256 -0
- package/blocks/sequencer/components/step-editor.tsx +213 -0
- package/blocks/sequencer/lib/sequencer-utils.ts +168 -0
- package/blocks/sequencer/recipes/create-multichannel-sequence.ts +51 -0
- package/blocks/sequencer/recipes/launch-and-enroll.ts +44 -0
- package/blocks/sequencer/recipes/pause-when-unsafe.ts +30 -0
- package/blocks/sequencer/recipes/sequence-report.ts +22 -0
- package/blocks/social-ads/README.md +128 -0
- package/blocks/social-ads/block.json +256 -0
- package/blocks/social-ads/components/ad-campaign-list.tsx +136 -0
- package/blocks/social-ads/components/audience-sync.tsx +150 -0
- package/blocks/social-ads/components/creative-gallery.tsx +121 -0
- package/blocks/social-ads/components/post-composer.tsx +122 -0
- package/blocks/social-ads/components/social-post-list.tsx +116 -0
- package/blocks/social-ads/hooks/use-social-accounts.ts +16 -0
- package/blocks/social-ads/lib/social-ads-types.ts +167 -0
- package/blocks/social-ads/recipes/creative-to-gallery.ts +41 -0
- package/blocks/social-ads/recipes/schedule-post.ts +51 -0
- package/blocks/social-ads/recipes/sync-audience-and-launch.ts +41 -0
- package/blocks/visitors/README.md +56 -0
- package/blocks/visitors/block.json +139 -0
- package/blocks/visitors/components/snippet-install.tsx +169 -0
- package/blocks/visitors/components/traffic-chart.tsx +156 -0
- package/blocks/visitors/components/visitor-company-card.tsx +92 -0
- package/blocks/visitors/components/visitor-feed.tsx +157 -0
- package/blocks/visitors/lib/visitors-utils.ts +78 -0
- package/blocks/visitors/recipes/check-snippet-installed.ts +24 -0
- package/blocks/visitors/recipes/recent-company-visits.ts +27 -0
- package/blocks/visitors/recipes/traffic-summary.ts +24 -0
- package/blocks/webchat/README.md +87 -0
- package/blocks/webchat/block.json +134 -0
- package/blocks/webchat/components/chat-widget-config.tsx +160 -0
- package/blocks/webchat/components/conversation-list.tsx +74 -0
- package/blocks/webchat/lib/webchat-types.ts +83 -0
- package/blocks/webchat/recipes/create-bot-and-style-widget.ts +24 -0
- package/blocks/webchat/recipes/list-chat-visitors.ts +24 -0
- package/blocks/workbench/README.md +135 -0
- package/blocks/workbench/block.json +259 -0
- package/blocks/workbench/components/column-recipe-editor.tsx +183 -0
- package/blocks/workbench/components/run-progress.tsx +132 -0
- package/blocks/workbench/components/workbench-add-rows.tsx +100 -0
- package/blocks/workbench/components/workbench-grid.tsx +159 -0
- package/blocks/workbench/components/workbench-row-actions.tsx +102 -0
- package/blocks/workbench/components/workbench-table-list.tsx +105 -0
- package/blocks/workbench/hooks/use-workbench-table.ts +30 -0
- package/blocks/workbench/lib/waterfall-presets.ts +119 -0
- package/blocks/workbench/lib/workbench-types.ts +191 -0
- package/blocks/workbench/recipes/build-enriched-table.ts +65 -0
- package/blocks/workbench/recipes/import-from-search.ts +42 -0
- package/blocks/workbench/recipes/scrape-into-table.ts +36 -0
- package/blocks/workbench/recipes/waterfall-column.ts +55 -0
- package/blocks/workflows/README.md +100 -0
- package/blocks/workflows/block.json +188 -0
- package/blocks/workflows/components/run-history.tsx +136 -0
- package/blocks/workflows/components/trigger-config.tsx +134 -0
- package/blocks/workflows/components/workflow-editor.tsx +142 -0
- package/blocks/workflows/components/workflow-list.tsx +153 -0
- package/blocks/workflows/hooks/use-workflow.ts +51 -0
- package/blocks/workflows/lib/graph.ts +187 -0
- package/blocks/workflows/recipes/create-workflow.ts +35 -0
- package/blocks/workflows/recipes/find-failed-runs.ts +15 -0
- package/blocks/workflows/recipes/run-workflow-and-wait.ts +32 -0
- package/blocks/workflows/recipes/set-trigger.ts +22 -0
- package/dist/cli.js +5330 -29
- package/dist/index.browser.js +7740 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.browser.mjs +7717 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.d.mts +2220 -23
- package/dist/index.d.ts +2220 -23
- package/dist/index.js +64 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -3
- package/dist/index.mjs.map +1 -1
- package/dist/react.browser.js +7598 -0
- package/dist/react.browser.js.map +1 -0
- package/dist/react.browser.mjs +7568 -0
- package/dist/react.browser.mjs.map +1 -0
- package/dist/react.d.mts +2082 -20
- package/dist/react.d.ts +2082 -20
- package/dist/react.js +63 -2
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +63 -2
- package/dist/react.mjs.map +1 -1
- package/dist/types/agentSetup.d.ts +6 -6
- package/dist/types/blocks/add.d.ts +53 -0
- package/dist/types/blocks/create.d.ts +46 -0
- package/dist/types/blocks/doctor.d.ts +26 -0
- package/dist/types/blocks/registry.d.ts +134 -0
- package/dist/types/cli.d.ts +16 -0
- package/dist/types/core.d.ts +1 -1
- package/dist/types/crypto-browser.d.ts +2 -0
- package/dist/types/crypto-node.d.ts +6 -0
- package/dist/types/react.d.ts +1 -1
- package/dist/types/version.d.ts +2 -2
- package/dist/types/webhooks.d.ts +2 -2
- package/dist/ui/index.d.mts +54 -0
- package/dist/ui/index.d.ts +54 -0
- package/dist/ui/index.js +105 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/index.mjs +44 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/ui/lib/compose-refs.d.mts +19 -0
- package/dist/ui/lib/compose-refs.d.ts +19 -0
- package/dist/ui/lib/compose-refs.js +76 -0
- package/dist/ui/lib/compose-refs.js.map +1 -0
- package/dist/ui/lib/compose-refs.mjs +41 -0
- package/dist/ui/lib/compose-refs.mjs.map +1 -0
- package/dist/ui/lib/use-mobile.d.mts +4 -0
- package/dist/ui/lib/use-mobile.d.ts +4 -0
- package/dist/ui/lib/use-mobile.js +57 -0
- package/dist/ui/lib/use-mobile.js.map +1 -0
- package/dist/ui/lib/use-mobile.mjs +22 -0
- package/dist/ui/lib/use-mobile.mjs.map +1 -0
- package/dist/ui/lib/utils.d.mts +10 -0
- package/dist/ui/lib/utils.d.ts +10 -0
- package/dist/ui/lib/utils.js +33 -0
- package/dist/ui/lib/utils.js.map +1 -0
- package/dist/ui/lib/utils.mjs +9 -0
- package/dist/ui/lib/utils.mjs.map +1 -0
- package/dist/ui/primitives/alert-dialog.d.mts +22 -0
- package/dist/ui/primitives/alert-dialog.d.ts +22 -0
- package/dist/ui/primitives/alert-dialog.js +163 -0
- package/dist/ui/primitives/alert-dialog.js.map +1 -0
- package/dist/ui/primitives/alert-dialog.mjs +119 -0
- package/dist/ui/primitives/alert-dialog.mjs.map +1 -0
- package/dist/ui/primitives/avatar.d.mts +8 -0
- package/dist/ui/primitives/avatar.d.ts +8 -0
- package/dist/ui/primitives/avatar.js +91 -0
- package/dist/ui/primitives/avatar.js.map +1 -0
- package/dist/ui/primitives/avatar.mjs +55 -0
- package/dist/ui/primitives/avatar.mjs.map +1 -0
- package/dist/ui/primitives/breadcrumb.d.mts +13 -0
- package/dist/ui/primitives/breadcrumb.d.ts +13 -0
- package/dist/ui/primitives/breadcrumb.js +127 -0
- package/dist/ui/primitives/breadcrumb.js.map +1 -0
- package/dist/ui/primitives/breadcrumb.mjs +97 -0
- package/dist/ui/primitives/breadcrumb.mjs.map +1 -0
- package/dist/ui/primitives/button.d.mts +15 -0
- package/dist/ui/primitives/button.d.ts +15 -0
- package/dist/ui/primitives/button.js +91 -0
- package/dist/ui/primitives/button.js.map +1 -0
- package/dist/ui/primitives/button.mjs +56 -0
- package/dist/ui/primitives/button.mjs.map +1 -0
- package/dist/ui/primitives/card.d.mts +10 -0
- package/dist/ui/primitives/card.d.ts +10 -0
- package/dist/ui/primitives/card.js +101 -0
- package/dist/ui/primitives/card.js.map +1 -0
- package/dist/ui/primitives/card.mjs +62 -0
- package/dist/ui/primitives/card.mjs.map +1 -0
- package/dist/ui/primitives/carousel.d.mts +45 -0
- package/dist/ui/primitives/carousel.d.ts +45 -0
- package/dist/ui/primitives/carousel.js +300 -0
- package/dist/ui/primitives/carousel.js.map +1 -0
- package/dist/ui/primitives/carousel.mjs +261 -0
- package/dist/ui/primitives/carousel.mjs.map +1 -0
- package/dist/ui/primitives/chart.d.mts +68 -0
- package/dist/ui/primitives/chart.d.ts +68 -0
- package/dist/ui/primitives/chart.js +280 -0
- package/dist/ui/primitives/chart.js.map +1 -0
- package/dist/ui/primitives/chart.mjs +241 -0
- package/dist/ui/primitives/chart.mjs.map +1 -0
- package/dist/ui/primitives/collapsible.d.mts +8 -0
- package/dist/ui/primitives/collapsible.d.ts +8 -0
- package/dist/ui/primitives/collapsible.js +72 -0
- package/dist/ui/primitives/collapsible.js.map +1 -0
- package/dist/ui/primitives/collapsible.mjs +36 -0
- package/dist/ui/primitives/collapsible.mjs.map +1 -0
- package/dist/ui/primitives/context-menu.d.mts +29 -0
- package/dist/ui/primitives/context-menu.d.ts +29 -0
- package/dist/ui/primitives/context-menu.js +203 -0
- package/dist/ui/primitives/context-menu.js.map +1 -0
- package/dist/ui/primitives/context-menu.mjs +155 -0
- package/dist/ui/primitives/context-menu.mjs.map +1 -0
- package/dist/ui/primitives/dialog.d.mts +26 -0
- package/dist/ui/primitives/dialog.d.ts +26 -0
- package/dist/ui/primitives/dialog.js +192 -0
- package/dist/ui/primitives/dialog.js.map +1 -0
- package/dist/ui/primitives/dialog.mjs +148 -0
- package/dist/ui/primitives/dialog.mjs.map +1 -0
- package/dist/ui/primitives/drawer.d.mts +26 -0
- package/dist/ui/primitives/drawer.d.ts +26 -0
- package/dist/ui/primitives/drawer.js +146 -0
- package/dist/ui/primitives/drawer.js.map +1 -0
- package/dist/ui/primitives/drawer.mjs +103 -0
- package/dist/ui/primitives/drawer.mjs.map +1 -0
- package/dist/ui/primitives/input.d.mts +5 -0
- package/dist/ui/primitives/input.d.ts +5 -0
- package/dist/ui/primitives/input.js +46 -0
- package/dist/ui/primitives/input.js.map +1 -0
- package/dist/ui/primitives/input.mjs +22 -0
- package/dist/ui/primitives/input.mjs.map +1 -0
- package/dist/ui/primitives/item.d.mts +27 -0
- package/dist/ui/primitives/item.d.ts +27 -0
- package/dist/ui/primitives/item.js +221 -0
- package/dist/ui/primitives/item.js.map +1 -0
- package/dist/ui/primitives/item.mjs +188 -0
- package/dist/ui/primitives/item.mjs.map +1 -0
- package/dist/ui/primitives/kbd.d.mts +15 -0
- package/dist/ui/primitives/kbd.d.ts +15 -0
- package/dist/ui/primitives/kbd.js +45 -0
- package/dist/ui/primitives/kbd.js.map +1 -0
- package/dist/ui/primitives/kbd.mjs +21 -0
- package/dist/ui/primitives/kbd.mjs.map +1 -0
- package/dist/ui/primitives/label.d.mts +6 -0
- package/dist/ui/primitives/label.d.ts +6 -0
- package/dist/ui/primitives/label.js +55 -0
- package/dist/ui/primitives/label.js.map +1 -0
- package/dist/ui/primitives/label.mjs +21 -0
- package/dist/ui/primitives/label.mjs.map +1 -0
- package/dist/ui/primitives/resizable.d.mts +10 -0
- package/dist/ui/primitives/resizable.d.ts +10 -0
- package/dist/ui/primitives/resizable.js +68 -0
- package/dist/ui/primitives/resizable.js.map +1 -0
- package/dist/ui/primitives/resizable.mjs +42 -0
- package/dist/ui/primitives/resizable.mjs.map +1 -0
- package/dist/ui/primitives/save-status.d.mts +31 -0
- package/dist/ui/primitives/save-status.d.ts +31 -0
- package/dist/ui/primitives/save-status.js +150 -0
- package/dist/ui/primitives/save-status.js.map +1 -0
- package/dist/ui/primitives/save-status.mjs +126 -0
- package/dist/ui/primitives/save-status.mjs.map +1 -0
- package/dist/ui/primitives/separator.d.mts +6 -0
- package/dist/ui/primitives/separator.d.ts +6 -0
- package/dist/ui/primitives/separator.js +62 -0
- package/dist/ui/primitives/separator.js.map +1 -0
- package/dist/ui/primitives/separator.mjs +28 -0
- package/dist/ui/primitives/separator.mjs.map +1 -0
- package/dist/ui/primitives/sheet.d.mts +16 -0
- package/dist/ui/primitives/sheet.d.ts +16 -0
- package/dist/ui/primitives/sheet.js +170 -0
- package/dist/ui/primitives/sheet.js.map +1 -0
- package/dist/ui/primitives/sheet.mjs +129 -0
- package/dist/ui/primitives/sheet.mjs.map +1 -0
- package/dist/ui/primitives/sidebar.d.mts +74 -0
- package/dist/ui/primitives/sidebar.d.ts +74 -0
- package/dist/ui/primitives/sidebar.js +697 -0
- package/dist/ui/primitives/sidebar.js.map +1 -0
- package/dist/ui/primitives/sidebar.mjs +651 -0
- package/dist/ui/primitives/sidebar.mjs.map +1 -0
- package/dist/ui/primitives/skeleton.d.mts +5 -0
- package/dist/ui/primitives/skeleton.d.ts +5 -0
- package/dist/ui/primitives/skeleton.js +40 -0
- package/dist/ui/primitives/skeleton.js.map +1 -0
- package/dist/ui/primitives/skeleton.mjs +16 -0
- package/dist/ui/primitives/skeleton.mjs.map +1 -0
- package/dist/ui/primitives/slider.d.mts +20 -0
- package/dist/ui/primitives/slider.d.ts +20 -0
- package/dist/ui/primitives/slider.js +112 -0
- package/dist/ui/primitives/slider.js.map +1 -0
- package/dist/ui/primitives/slider.mjs +78 -0
- package/dist/ui/primitives/slider.mjs.map +1 -0
- package/dist/ui/primitives/sortable.d.mts +50 -0
- package/dist/ui/primitives/sortable.d.ts +50 -0
- package/dist/ui/primitives/sortable.js +456 -0
- package/dist/ui/primitives/sortable.js.map +1 -0
- package/dist/ui/primitives/sortable.mjs +435 -0
- package/dist/ui/primitives/sortable.mjs.map +1 -0
- package/dist/ui/primitives/switch.d.mts +6 -0
- package/dist/ui/primitives/switch.d.ts +6 -0
- package/dist/ui/primitives/switch.js +67 -0
- package/dist/ui/primitives/switch.js.map +1 -0
- package/dist/ui/primitives/switch.mjs +33 -0
- package/dist/ui/primitives/switch.mjs.map +1 -0
- package/dist/ui/primitives/table.d.mts +12 -0
- package/dist/ui/primitives/table.d.ts +12 -0
- package/dist/ui/primitives/table.js +130 -0
- package/dist/ui/primitives/table.js.map +1 -0
- package/dist/ui/primitives/table.mjs +89 -0
- package/dist/ui/primitives/table.mjs.map +1 -0
- package/dist/ui/primitives/tabs.d.mts +9 -0
- package/dist/ui/primitives/tabs.d.ts +9 -0
- package/dist/ui/primitives/tabs.js +86 -0
- package/dist/ui/primitives/tabs.js.map +1 -0
- package/dist/ui/primitives/tabs.mjs +49 -0
- package/dist/ui/primitives/tabs.mjs.map +1 -0
- package/dist/ui/primitives/textarea.d.mts +5 -0
- package/dist/ui/primitives/textarea.d.ts +5 -0
- package/dist/ui/primitives/textarea.js +43 -0
- package/dist/ui/primitives/textarea.js.map +1 -0
- package/dist/ui/primitives/textarea.mjs +19 -0
- package/dist/ui/primitives/textarea.mjs.map +1 -0
- package/dist/ui/primitives/tooltip.d.mts +9 -0
- package/dist/ui/primitives/tooltip.d.ts +9 -0
- package/dist/ui/primitives/tooltip.js +94 -0
- package/dist/ui/primitives/tooltip.js.map +1 -0
- package/dist/ui/primitives/tooltip.mjs +57 -0
- package/dist/ui/primitives/tooltip.mjs.map +1 -0
- package/docs/agents.md +72 -29
- package/docs/api/README.md +7 -3
- package/docs/api/appObjects.d.ts +3 -1
- package/docs/api/appObjects.md +2 -1
- package/docs/api/by-path.md +51 -0
- package/docs/api/dataPipelines.d.ts +149 -0
- package/docs/api/dataPipelines.md +232 -0
- package/docs/api/forms.d.ts +16 -0
- package/docs/api/forms.md +8 -0
- package/docs/api/objects.d.ts +705 -5
- package/docs/api/objects.md +1099 -14
- package/docs/api/ops.d.ts +1 -1
- package/docs/api/ops.md +1 -1
- package/docs/api/processLists.d.ts +247 -0
- package/docs/api/processLists.md +409 -0
- package/docs/api/quotes.d.ts +3 -1
- package/docs/api/quotes.md +7 -2
- package/docs/api/radar.d.ts +4 -0
- package/docs/api/radar.md +1 -0
- package/docs/api/reports.d.ts +476 -0
- package/docs/api/reports.md +539 -0
- package/docs/api/scheduleBuy.d.ts +12 -8
- package/docs/api/scheduleBuy.md +13 -10
- package/docs/api/seo.d.ts +406 -3
- package/docs/api/seo.md +505 -1
- package/docs/api/workspaceBackup.d.ts +324 -0
- package/docs/api/workspaceBackup.md +427 -0
- package/package.json +174 -5
- package/stacks/6sense.json +46 -0
- package/stacks/README.md +20 -0
- package/stacks/apollo.json +128 -0
- package/stacks/clay.json +59 -0
- package/stacks/gong.json +72 -0
- package/stacks/hubspot.json +162 -0
- package/stacks/intercom.json +53 -0
- package/stacks/mailchimp.json +71 -0
- package/stacks/outreach.json +86 -0
- package/stacks/salesforce.json +94 -0
- package/stacks/stack.schema.json +32 -0
- package/stacks/starter.json +22 -0
- package/styles/styles.css +2 -0
- package/styles/theme.css +181 -0
- package/styles/tokens.css +284 -0
- package/templates/next-app/README.md.tmpl +35 -0
- package/templates/next-app/_pages/redirect-page.tsx.tmpl +5 -0
- package/templates/next-app/_pages/route-page.tsx.tmpl +9 -0
- package/templates/next-app/app/globals.css.tmpl +8 -0
- package/templates/next-app/app/layout.tsx.tmpl +19 -0
- package/templates/next-app/components/app-shell.tsx.tmpl +34 -0
- package/templates/next-app/dot-env.local.example.tmpl +6 -0
- package/templates/next-app/dot-gitignore.tmpl +7 -0
- package/templates/next-app/lib/nav.ts.tmpl +2 -0
- package/templates/next-app/next.config.mjs.tmpl +4 -0
- package/templates/next-app/package.json.tmpl +25 -0
- package/templates/next-app/postcss.config.mjs.tmpl +4 -0
- package/templates/next-app/tsconfig.json.tmpl +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
4
|
+
import { cn } from "../lib/utils.mjs";
|
|
5
|
+
function Label({ className, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
LabelPrimitive.Root,
|
|
8
|
+
{
|
|
9
|
+
"data-slot": "label",
|
|
10
|
+
className: cn(
|
|
11
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50 mb-1",
|
|
12
|
+
className
|
|
13
|
+
),
|
|
14
|
+
...props
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
Label
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=label.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/primitives/label.tsx"],"sourcesContent":["/*\n * @graph8/sdk/ui — GENERATED FROM frontend/components/ui/label.tsx. DO NOT EDIT.\n *\n * Edit the app source, then run: npm run generate:ui --prefix sdk/js\n * Hand edits are overwritten and will fail sdk/js/tests/ui/drift.test.ts.\n */\n\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\n\nimport { cn } from \"../lib/utils\";\n\nfunction Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50 mb-1\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n"],"mappings":";AAeI;AANJ,YAAY,oBAAoB;AAEhC,SAAS,UAAU;AAEnB,SAAS,MAAM,EAAE,WAAW,GAAG,MAAM,GAAqD;AACxF,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Separator, Panel, Group } from 'react-resizable-panels';
|
|
3
|
+
|
|
4
|
+
declare const ResizablePanelGroup: ({ className, ...props }: React.ComponentProps<typeof Group>) => React.JSX.Element;
|
|
5
|
+
declare const ResizablePanel: ({ ...props }: React.ComponentProps<typeof Panel>) => React.JSX.Element;
|
|
6
|
+
declare const ResizableHandle: ({ withHandle, className, ...props }: React.ComponentProps<typeof Separator> & {
|
|
7
|
+
withHandle?: boolean;
|
|
8
|
+
}) => React.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Separator, Panel, Group } from 'react-resizable-panels';
|
|
3
|
+
|
|
4
|
+
declare const ResizablePanelGroup: ({ className, ...props }: React.ComponentProps<typeof Group>) => React.JSX.Element;
|
|
5
|
+
declare const ResizablePanel: ({ ...props }: React.ComponentProps<typeof Panel>) => React.JSX.Element;
|
|
6
|
+
declare const ResizableHandle: ({ withHandle, className, ...props }: React.ComponentProps<typeof Separator> & {
|
|
7
|
+
withHandle?: boolean;
|
|
8
|
+
}) => React.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var resizable_exports = {};
|
|
21
|
+
__export(resizable_exports, {
|
|
22
|
+
ResizableHandle: () => ResizableHandle,
|
|
23
|
+
ResizablePanel: () => ResizablePanel,
|
|
24
|
+
ResizablePanelGroup: () => ResizablePanelGroup
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(resizable_exports);
|
|
27
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
28
|
+
var import_lucide_react = require("lucide-react");
|
|
29
|
+
var import_react_resizable_panels = require("react-resizable-panels");
|
|
30
|
+
var import_utils = require("../lib/utils.js");
|
|
31
|
+
const ResizablePanelGroup = ({ className, ...props }) => {
|
|
32
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
33
|
+
import_react_resizable_panels.Group,
|
|
34
|
+
{
|
|
35
|
+
"data-slot": "resizable-panel-group",
|
|
36
|
+
className: (0, import_utils.cn)("flex h-full w-full data-[panel-group-direction=vertical]:flex-col", className),
|
|
37
|
+
...props
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
const ResizablePanel = ({ ...props }) => {
|
|
42
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_resizable_panels.Panel, { "data-slot": "resizable-panel", ...props });
|
|
43
|
+
};
|
|
44
|
+
const ResizableHandle = ({
|
|
45
|
+
withHandle,
|
|
46
|
+
className,
|
|
47
|
+
...props
|
|
48
|
+
}) => {
|
|
49
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
50
|
+
import_react_resizable_panels.Separator,
|
|
51
|
+
{
|
|
52
|
+
"data-slot": "resizable-handle",
|
|
53
|
+
className: (0, import_utils.cn)(
|
|
54
|
+
"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
|
55
|
+
className
|
|
56
|
+
),
|
|
57
|
+
...props,
|
|
58
|
+
children: withHandle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.GripVerticalIcon, { className: "size-2.5" }) })
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
63
|
+
0 && (module.exports = {
|
|
64
|
+
ResizableHandle,
|
|
65
|
+
ResizablePanel,
|
|
66
|
+
ResizablePanelGroup
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=resizable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/primitives/resizable.tsx"],"sourcesContent":["/*\n * @graph8/sdk/ui — GENERATED FROM frontend/components/ui/resizable.tsx. DO NOT EDIT.\n *\n * Edit the app source, then run: npm run generate:ui --prefix sdk/js\n * Hand edits are overwritten and will fail sdk/js/tests/ui/drift.test.ts.\n */\n\"use client\";\n\nimport * as React from \"react\";\nimport { GripVerticalIcon } from \"lucide-react\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\n\nimport { cn } from \"../lib/utils\";\n\nconst ResizablePanelGroup = ({ className, ...props }: React.ComponentProps<typeof Group>) => {\n return (\n <Group\n data-slot=\"resizable-panel-group\"\n className={cn(\"flex h-full w-full data-[panel-group-direction=vertical]:flex-col\", className)}\n {...props}\n />\n );\n};\n\nconst ResizablePanel = ({ ...props }: React.ComponentProps<typeof Panel>) => {\n return <Panel data-slot=\"resizable-panel\" {...props} />;\n};\n\nconst ResizableHandle = ({\n withHandle,\n className,\n ...props\n}: React.ComponentProps<typeof Separator> & {\n withHandle?: boolean;\n}) => {\n return (\n <Separator\n data-slot=\"resizable-handle\"\n className={cn(\n \"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90\",\n className\n )}\n {...props}\n >\n {withHandle && (\n <div className=\"bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border\">\n <GripVerticalIcon className=\"size-2.5\" />\n </div>\n )}\n </Separator>\n );\n};\n\nexport { ResizablePanelGroup, ResizablePanel, ResizableHandle };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBI;AAPJ,0BAAiC;AACjC,oCAAwC;AAExC,mBAAmB;AAEnB,MAAM,sBAAsB,CAAC,EAAE,WAAW,GAAG,MAAM,MAA0C;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,eAAW,iBAAG,qEAAqE,SAAS;AAAA,MAC3F,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,MAAM,iBAAiB,CAAC,EAAE,GAAG,MAAM,MAA0C;AAC3E,SAAO,4CAAC,uCAAM,aAAU,mBAAmB,GAAG,OAAO;AACvD;AAEA,MAAM,kBAAkB,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAEM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,eAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH,wBACC,4CAAC,SAAI,WAAU,6EACb,sDAAC,wCAAiB,WAAU,YAAW,GACzC;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { GripVerticalIcon } from "lucide-react";
|
|
4
|
+
import { Group, Panel, Separator } from "react-resizable-panels";
|
|
5
|
+
import { cn } from "../lib/utils.mjs";
|
|
6
|
+
const ResizablePanelGroup = ({ className, ...props }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
Group,
|
|
9
|
+
{
|
|
10
|
+
"data-slot": "resizable-panel-group",
|
|
11
|
+
className: cn("flex h-full w-full data-[panel-group-direction=vertical]:flex-col", className),
|
|
12
|
+
...props
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
const ResizablePanel = ({ ...props }) => {
|
|
17
|
+
return /* @__PURE__ */ jsx(Panel, { "data-slot": "resizable-panel", ...props });
|
|
18
|
+
};
|
|
19
|
+
const ResizableHandle = ({
|
|
20
|
+
withHandle,
|
|
21
|
+
className,
|
|
22
|
+
...props
|
|
23
|
+
}) => {
|
|
24
|
+
return /* @__PURE__ */ jsx(
|
|
25
|
+
Separator,
|
|
26
|
+
{
|
|
27
|
+
"data-slot": "resizable-handle",
|
|
28
|
+
className: cn(
|
|
29
|
+
"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
|
30
|
+
className
|
|
31
|
+
),
|
|
32
|
+
...props,
|
|
33
|
+
children: withHandle && /* @__PURE__ */ jsx("div", { className: "bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border", children: /* @__PURE__ */ jsx(GripVerticalIcon, { className: "size-2.5" }) })
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
export {
|
|
38
|
+
ResizableHandle,
|
|
39
|
+
ResizablePanel,
|
|
40
|
+
ResizablePanelGroup
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=resizable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/primitives/resizable.tsx"],"sourcesContent":["/*\n * @graph8/sdk/ui — GENERATED FROM frontend/components/ui/resizable.tsx. DO NOT EDIT.\n *\n * Edit the app source, then run: npm run generate:ui --prefix sdk/js\n * Hand edits are overwritten and will fail sdk/js/tests/ui/drift.test.ts.\n */\n\"use client\";\n\nimport * as React from \"react\";\nimport { GripVerticalIcon } from \"lucide-react\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\n\nimport { cn } from \"../lib/utils\";\n\nconst ResizablePanelGroup = ({ className, ...props }: React.ComponentProps<typeof Group>) => {\n return (\n <Group\n data-slot=\"resizable-panel-group\"\n className={cn(\"flex h-full w-full data-[panel-group-direction=vertical]:flex-col\", className)}\n {...props}\n />\n );\n};\n\nconst ResizablePanel = ({ ...props }: React.ComponentProps<typeof Panel>) => {\n return <Panel data-slot=\"resizable-panel\" {...props} />;\n};\n\nconst ResizableHandle = ({\n withHandle,\n className,\n ...props\n}: React.ComponentProps<typeof Separator> & {\n withHandle?: boolean;\n}) => {\n return (\n <Separator\n data-slot=\"resizable-handle\"\n className={cn(\n \"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90\",\n className\n )}\n {...props}\n >\n {withHandle && (\n <div className=\"bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border\">\n <GripVerticalIcon className=\"size-2.5\" />\n </div>\n )}\n </Separator>\n );\n};\n\nexport { ResizablePanelGroup, ResizablePanel, ResizableHandle };\n"],"mappings":";AAgBI;AAPJ,SAAS,wBAAwB;AACjC,SAAS,OAAO,OAAO,iBAAiB;AAExC,SAAS,UAAU;AAEnB,MAAM,sBAAsB,CAAC,EAAE,WAAW,GAAG,MAAM,MAA0C;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,qEAAqE,SAAS;AAAA,MAC3F,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,MAAM,iBAAiB,CAAC,EAAE,GAAG,MAAM,MAA0C;AAC3E,SAAO,oBAAC,SAAM,aAAU,mBAAmB,GAAG,OAAO;AACvD;AAEA,MAAM,kBAAkB,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAEM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH,wBACC,oBAAC,SAAI,WAAU,6EACb,8BAAC,oBAAiB,WAAU,YAAW,GACzC;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type SaveStatusValue = "idle" | "pending" | "saving" | "saved" | "error";
|
|
4
|
+
interface SaveStatusProps {
|
|
5
|
+
status: SaveStatusValue;
|
|
6
|
+
/** Shown as a tooltip only. The visible copy on failure is always "Save failed". */
|
|
7
|
+
error?: string | null;
|
|
8
|
+
/** Omit to render the failure without a Retry control. */
|
|
9
|
+
onRetry?: () => void;
|
|
10
|
+
/** Time of the last successful save. Shown in the title: "Saved at 12:41". */
|
|
11
|
+
savedAt?: Date | number | null;
|
|
12
|
+
/** Default "Saved". */
|
|
13
|
+
savedLabel?: string;
|
|
14
|
+
/** Copy for `pending`. Default: nothing (or the kept failure, see below). */
|
|
15
|
+
pendingLabel?: string;
|
|
16
|
+
/** How long "Saved" stays before it fades. Default 2000. 0 keeps it. */
|
|
17
|
+
savedLingerMs?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `Saving…`, `Saved` and `Save failed · Retry`, in one quiet place near the content (the toolbar's
|
|
22
|
+
* right-hand group, first, so the primary action stays last). Autosaved surfaces have no Save
|
|
23
|
+
* button; this is how the user knows their work is safe.
|
|
24
|
+
*
|
|
25
|
+
* A persistent live region announces only "Saved" (per-keystroke "Saving" announcements are
|
|
26
|
+
* noise); a failure mounts its own `role="alert"`. Feed it from `useAutosave`/`useSaveTracker`
|
|
27
|
+
* via `saveStatusProps(state)`.
|
|
28
|
+
*/
|
|
29
|
+
declare const SaveStatus: ({ status, error, onRetry, savedAt, savedLabel, pendingLabel, savedLingerMs, className, }: SaveStatusProps) => React.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { SaveStatus, type SaveStatusProps, type SaveStatusValue };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type SaveStatusValue = "idle" | "pending" | "saving" | "saved" | "error";
|
|
4
|
+
interface SaveStatusProps {
|
|
5
|
+
status: SaveStatusValue;
|
|
6
|
+
/** Shown as a tooltip only. The visible copy on failure is always "Save failed". */
|
|
7
|
+
error?: string | null;
|
|
8
|
+
/** Omit to render the failure without a Retry control. */
|
|
9
|
+
onRetry?: () => void;
|
|
10
|
+
/** Time of the last successful save. Shown in the title: "Saved at 12:41". */
|
|
11
|
+
savedAt?: Date | number | null;
|
|
12
|
+
/** Default "Saved". */
|
|
13
|
+
savedLabel?: string;
|
|
14
|
+
/** Copy for `pending`. Default: nothing (or the kept failure, see below). */
|
|
15
|
+
pendingLabel?: string;
|
|
16
|
+
/** How long "Saved" stays before it fades. Default 2000. 0 keeps it. */
|
|
17
|
+
savedLingerMs?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `Saving…`, `Saved` and `Save failed · Retry`, in one quiet place near the content (the toolbar's
|
|
22
|
+
* right-hand group, first, so the primary action stays last). Autosaved surfaces have no Save
|
|
23
|
+
* button; this is how the user knows their work is safe.
|
|
24
|
+
*
|
|
25
|
+
* A persistent live region announces only "Saved" (per-keystroke "Saving" announcements are
|
|
26
|
+
* noise); a failure mounts its own `role="alert"`. Feed it from `useAutosave`/`useSaveTracker`
|
|
27
|
+
* via `saveStatusProps(state)`.
|
|
28
|
+
*/
|
|
29
|
+
declare const SaveStatus: ({ status, error, onRetry, savedAt, savedLabel, pendingLabel, savedLingerMs, className, }: SaveStatusProps) => React.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { SaveStatus, type SaveStatusProps, type SaveStatusValue };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var save_status_exports = {};
|
|
21
|
+
__export(save_status_exports, {
|
|
22
|
+
SaveStatus: () => SaveStatus
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(save_status_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
var import_utils = require("../lib/utils.js");
|
|
28
|
+
const FADE_MS = 300;
|
|
29
|
+
const DEFAULT_LINGER_MS = 2e3;
|
|
30
|
+
const FAINT = "text-[color:var(--text-faint,var(--text-color-muted))]";
|
|
31
|
+
const prefersReducedMotion = () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
32
|
+
const savedTitle = (savedAt, label) => {
|
|
33
|
+
if (savedAt == null) return void 0;
|
|
34
|
+
const time = new Date(savedAt).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
35
|
+
return `${label} at ${time}`;
|
|
36
|
+
};
|
|
37
|
+
const useSavedPhase = (status, savedAt, lingerMs) => {
|
|
38
|
+
const [track, setTrack] = (0, import_react.useState)({ status, savedAt, epoch: 0 });
|
|
39
|
+
if (track.status !== status || track.savedAt !== savedAt) {
|
|
40
|
+
setTrack({ status, savedAt, epoch: status === "saved" ? track.epoch + 1 : track.epoch });
|
|
41
|
+
}
|
|
42
|
+
const [faded, setFaded] = (0, import_react.useState)(
|
|
43
|
+
() => status === "saved" && savedAt !== null && lingerMs > 0 && Date.now() - savedAt >= lingerMs ? { epoch: 0, phase: "gone" } : null
|
|
44
|
+
);
|
|
45
|
+
const epoch = track.epoch;
|
|
46
|
+
(0, import_react.useEffect)(() => {
|
|
47
|
+
if (status !== "saved" || lingerMs <= 0) return;
|
|
48
|
+
let removeTimer;
|
|
49
|
+
const fadeTimer = setTimeout(() => {
|
|
50
|
+
if (prefersReducedMotion()) {
|
|
51
|
+
setFaded({ epoch, phase: "gone" });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setFaded({ epoch, phase: "fading" });
|
|
55
|
+
removeTimer = setTimeout(() => setFaded({ epoch, phase: "gone" }), FADE_MS);
|
|
56
|
+
}, lingerMs);
|
|
57
|
+
return () => {
|
|
58
|
+
clearTimeout(fadeTimer);
|
|
59
|
+
clearTimeout(removeTimer);
|
|
60
|
+
};
|
|
61
|
+
}, [status, lingerMs, epoch]);
|
|
62
|
+
return faded && faded.epoch === epoch ? faded.phase : "shown";
|
|
63
|
+
};
|
|
64
|
+
const SaveStatus = ({
|
|
65
|
+
status,
|
|
66
|
+
error,
|
|
67
|
+
onRetry,
|
|
68
|
+
savedAt,
|
|
69
|
+
savedLabel = "Saved",
|
|
70
|
+
pendingLabel,
|
|
71
|
+
savedLingerMs = DEFAULT_LINGER_MS,
|
|
72
|
+
className
|
|
73
|
+
}) => {
|
|
74
|
+
const savedAtMs = savedAt == null ? null : new Date(savedAt).getTime();
|
|
75
|
+
const phase = useSavedPhase(status, savedAtMs, savedLingerMs);
|
|
76
|
+
const [kept, setKept] = (0, import_react.useState)(null);
|
|
77
|
+
let nextKept = kept;
|
|
78
|
+
if (status === "error")
|
|
79
|
+
nextKept = kept && kept.error === (error ?? null) ? kept : { error: error ?? null, retry: onRetry };
|
|
80
|
+
else if (status !== "pending") nextKept = null;
|
|
81
|
+
if (nextKept !== kept) setKept(nextKept);
|
|
82
|
+
const failure = status === "error" || status === "pending" && kept !== null;
|
|
83
|
+
const failureDetail = status === "error" ? error : kept?.error;
|
|
84
|
+
const retry = onRetry ?? kept?.retry;
|
|
85
|
+
const savedVisible = status === "saved" && phase !== "gone";
|
|
86
|
+
const base = (0, import_utils.cn)("inline-flex items-center gap-1.5 text-xs tabular-nums", className);
|
|
87
|
+
let visual = null;
|
|
88
|
+
if (failure) {
|
|
89
|
+
visual = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
90
|
+
"span",
|
|
91
|
+
{
|
|
92
|
+
role: "alert",
|
|
93
|
+
"data-status": "error",
|
|
94
|
+
title: failureDetail ?? void 0,
|
|
95
|
+
className: (0, import_utils.cn)(base, "text-error-foreground"),
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Save failed" }),
|
|
98
|
+
retry ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
100
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
type: "button",
|
|
104
|
+
onClick: retry,
|
|
105
|
+
className: "text-foreground focus-visible:ring-ring/50 relative rounded-sm font-medium outline-none after:absolute after:-inset-2 hover:underline focus-visible:ring-[3px]",
|
|
106
|
+
children: "Retry"
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
] }) : null
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
} else if (status === "saving") {
|
|
114
|
+
visual = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
115
|
+
"span",
|
|
116
|
+
{
|
|
117
|
+
"aria-hidden": true,
|
|
118
|
+
"data-status": "saving",
|
|
119
|
+
className: (0, import_utils.cn)(base, FAINT, "animate-pulse motion-reduce:animate-none"),
|
|
120
|
+
children: "Saving\u2026"
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
} else if (status === "pending" && pendingLabel) {
|
|
124
|
+
visual = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "data-status": "pending", className: (0, import_utils.cn)(base, FAINT), children: pendingLabel });
|
|
125
|
+
} else if (savedVisible) {
|
|
126
|
+
visual = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
127
|
+
"span",
|
|
128
|
+
{
|
|
129
|
+
"aria-hidden": true,
|
|
130
|
+
"data-status": "saved",
|
|
131
|
+
title: savedTitle(savedAt, savedLabel),
|
|
132
|
+
className: (0, import_utils.cn)(
|
|
133
|
+
base,
|
|
134
|
+
FAINT,
|
|
135
|
+
phase === "fading" && "opacity-0 transition-opacity duration-300 motion-reduce:transition-none"
|
|
136
|
+
),
|
|
137
|
+
children: savedLabel
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
142
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { role: "status", "aria-live": "polite", "data-slot": "save-status-live", className: "sr-only", children: savedVisible && !failure ? savedLabel : "" }),
|
|
143
|
+
visual
|
|
144
|
+
] });
|
|
145
|
+
};
|
|
146
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
147
|
+
0 && (module.exports = {
|
|
148
|
+
SaveStatus
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=save-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/primitives/save-status.tsx"],"sourcesContent":["/*\n * @graph8/sdk/ui — GENERATED FROM frontend/components/ui/save-status.tsx. DO NOT EDIT.\n *\n * Edit the app source, then run: npm run generate:ui --prefix sdk/js\n * Hand edits are overwritten and will fail sdk/js/tests/ui/drift.test.ts.\n */\n\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nexport type SaveStatusValue = \"idle\" | \"pending\" | \"saving\" | \"saved\" | \"error\";\n\nexport interface SaveStatusProps {\n status: SaveStatusValue;\n /** Shown as a tooltip only. The visible copy on failure is always \"Save failed\". */\n error?: string | null;\n /** Omit to render the failure without a Retry control. */\n onRetry?: () => void;\n /** Time of the last successful save. Shown in the title: \"Saved at 12:41\". */\n savedAt?: Date | number | null;\n /** Default \"Saved\". */\n savedLabel?: string;\n /** Copy for `pending`. Default: nothing (or the kept failure, see below). */\n pendingLabel?: string;\n /** How long \"Saved\" stays before it fades. Default 2000. 0 keeps it. */\n savedLingerMs?: number;\n className?: string;\n}\n\nconst FADE_MS = 300;\nconst DEFAULT_LINGER_MS = 2000;\n// Faint text. Falls back to the muted foreground while the 2026 theme is off.\nconst FAINT = \"text-[color:var(--text-faint,var(--text-color-muted))]\";\n\nconst prefersReducedMotion = (): boolean =>\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\nconst savedTitle = (\n savedAt: Date | number | null | undefined,\n label: string\n): string | undefined => {\n if (savedAt == null) return undefined;\n const time = new Date(savedAt).toLocaleTimeString([], { hour: \"numeric\", minute: \"2-digit\" });\n return `${label} at ${time}`;\n};\n\ntype SavedPhase = \"shown\" | \"fading\" | \"gone\";\n\n/** \"Saved\" lingers, fades over 300ms, then unmounts. A new save restarts it. */\nconst useSavedPhase = (\n status: SaveStatusValue,\n savedAt: number | null,\n lingerMs: number\n): SavedPhase => {\n // Adjusting state during render (the documented pattern) so the very first render of a new\n // \"saved\" is already visible; an effect would show one frame of the previous phase.\n const [track, setTrack] = useState({ status, savedAt, epoch: 0 });\n if (track.status !== status || track.savedAt !== savedAt) {\n setTrack({ status, savedAt, epoch: status === \"saved\" ? track.epoch + 1 : track.epoch });\n }\n // A \"saved\" that is already older than its linger when the component first renders (a remount, a\n // tab returning) is history, not news: start it gone.\n const [faded, setFaded] = useState<{ epoch: number; phase: \"fading\" | \"gone\" } | null>(() =>\n status === \"saved\" && savedAt !== null && lingerMs > 0 && Date.now() - savedAt >= lingerMs\n ? { epoch: 0, phase: \"gone\" }\n : null\n );\n const epoch = track.epoch;\n\n useEffect(() => {\n if (status !== \"saved\" || lingerMs <= 0) return;\n let removeTimer: ReturnType<typeof setTimeout> | undefined;\n const fadeTimer = setTimeout(() => {\n if (prefersReducedMotion()) {\n setFaded({ epoch, phase: \"gone\" });\n return;\n }\n setFaded({ epoch, phase: \"fading\" });\n removeTimer = setTimeout(() => setFaded({ epoch, phase: \"gone\" }), FADE_MS);\n }, lingerMs);\n return () => {\n clearTimeout(fadeTimer);\n clearTimeout(removeTimer);\n };\n }, [status, lingerMs, epoch]);\n\n return faded && faded.epoch === epoch ? faded.phase : \"shown\";\n};\n\n/**\n * `Saving…`, `Saved` and `Save failed · Retry`, in one quiet place near the content (the toolbar's\n * right-hand group, first, so the primary action stays last). Autosaved surfaces have no Save\n * button; this is how the user knows their work is safe.\n *\n * A persistent live region announces only \"Saved\" (per-keystroke \"Saving\" announcements are\n * noise); a failure mounts its own `role=\"alert\"`. Feed it from `useAutosave`/`useSaveTracker`\n * via `saveStatusProps(state)`.\n */\nexport const SaveStatus = ({\n status,\n error,\n onRetry,\n savedAt,\n savedLabel = \"Saved\",\n pendingLabel,\n savedLingerMs = DEFAULT_LINGER_MS,\n className,\n}: SaveStatusProps) => {\n const savedAtMs = savedAt == null ? null : new Date(savedAt).getTime();\n const phase = useSavedPhase(status, savedAtMs, savedLingerMs);\n\n // A failure stays on screen through `pending` (the user typed again) until the next attempt\n // starts saving, so a retry-by-typing never hides that the last change did not land.\n const [kept, setKept] = useState<{ error: string | null; retry?: () => void } | null>(null);\n let nextKept = kept;\n if (status === \"error\")\n nextKept =\n kept && kept.error === (error ?? null) ? kept : { error: error ?? null, retry: onRetry };\n else if (status !== \"pending\") nextKept = null;\n if (nextKept !== kept) setKept(nextKept);\n const failure = status === \"error\" || (status === \"pending\" && kept !== null);\n const failureDetail = status === \"error\" ? error : kept?.error;\n // While the user types after a failure the source may stop offering a retry; the kept one still works.\n const retry = onRetry ?? kept?.retry;\n\n const savedVisible = status === \"saved\" && phase !== \"gone\";\n const base = cn(\"inline-flex items-center gap-1.5 text-xs tabular-nums\", className);\n\n let visual = null;\n if (failure) {\n visual = (\n <span\n role=\"alert\"\n data-status=\"error\"\n title={failureDetail ?? undefined}\n className={cn(base, \"text-error-foreground\")}\n >\n <span>Save failed</span>\n {retry ? (\n <>\n <span aria-hidden>·</span>\n <button\n type=\"button\"\n onClick={retry}\n className=\"text-foreground focus-visible:ring-ring/50 relative rounded-sm font-medium outline-none after:absolute after:-inset-2 hover:underline focus-visible:ring-[3px]\"\n >\n Retry\n </button>\n </>\n ) : null}\n </span>\n );\n } else if (status === \"saving\") {\n visual = (\n <span\n aria-hidden\n data-status=\"saving\"\n className={cn(base, FAINT, \"animate-pulse motion-reduce:animate-none\")}\n >\n Saving…\n </span>\n );\n } else if (status === \"pending\" && pendingLabel) {\n visual = (\n <span data-status=\"pending\" className={cn(base, FAINT)}>\n {pendingLabel}\n </span>\n );\n } else if (savedVisible) {\n visual = (\n <span\n aria-hidden\n data-status=\"saved\"\n title={savedTitle(savedAt, savedLabel)}\n className={cn(\n base,\n FAINT,\n phase === \"fading\" &&\n \"opacity-0 transition-opacity duration-300 motion-reduce:transition-none\"\n )}\n >\n {savedLabel}\n </span>\n );\n }\n\n return (\n <>\n <span role=\"status\" aria-live=\"polite\" data-slot=\"save-status-live\" className=\"sr-only\">\n {savedVisible && !failure ? savedLabel : \"\"}\n </span>\n {visual}\n </>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { cn } from "../lib/utils.mjs";
|
|
5
|
+
const FADE_MS = 300;
|
|
6
|
+
const DEFAULT_LINGER_MS = 2e3;
|
|
7
|
+
const FAINT = "text-[color:var(--text-faint,var(--text-color-muted))]";
|
|
8
|
+
const prefersReducedMotion = () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
9
|
+
const savedTitle = (savedAt, label) => {
|
|
10
|
+
if (savedAt == null) return void 0;
|
|
11
|
+
const time = new Date(savedAt).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
12
|
+
return `${label} at ${time}`;
|
|
13
|
+
};
|
|
14
|
+
const useSavedPhase = (status, savedAt, lingerMs) => {
|
|
15
|
+
const [track, setTrack] = useState({ status, savedAt, epoch: 0 });
|
|
16
|
+
if (track.status !== status || track.savedAt !== savedAt) {
|
|
17
|
+
setTrack({ status, savedAt, epoch: status === "saved" ? track.epoch + 1 : track.epoch });
|
|
18
|
+
}
|
|
19
|
+
const [faded, setFaded] = useState(
|
|
20
|
+
() => status === "saved" && savedAt !== null && lingerMs > 0 && Date.now() - savedAt >= lingerMs ? { epoch: 0, phase: "gone" } : null
|
|
21
|
+
);
|
|
22
|
+
const epoch = track.epoch;
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (status !== "saved" || lingerMs <= 0) return;
|
|
25
|
+
let removeTimer;
|
|
26
|
+
const fadeTimer = setTimeout(() => {
|
|
27
|
+
if (prefersReducedMotion()) {
|
|
28
|
+
setFaded({ epoch, phase: "gone" });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
setFaded({ epoch, phase: "fading" });
|
|
32
|
+
removeTimer = setTimeout(() => setFaded({ epoch, phase: "gone" }), FADE_MS);
|
|
33
|
+
}, lingerMs);
|
|
34
|
+
return () => {
|
|
35
|
+
clearTimeout(fadeTimer);
|
|
36
|
+
clearTimeout(removeTimer);
|
|
37
|
+
};
|
|
38
|
+
}, [status, lingerMs, epoch]);
|
|
39
|
+
return faded && faded.epoch === epoch ? faded.phase : "shown";
|
|
40
|
+
};
|
|
41
|
+
const SaveStatus = ({
|
|
42
|
+
status,
|
|
43
|
+
error,
|
|
44
|
+
onRetry,
|
|
45
|
+
savedAt,
|
|
46
|
+
savedLabel = "Saved",
|
|
47
|
+
pendingLabel,
|
|
48
|
+
savedLingerMs = DEFAULT_LINGER_MS,
|
|
49
|
+
className
|
|
50
|
+
}) => {
|
|
51
|
+
const savedAtMs = savedAt == null ? null : new Date(savedAt).getTime();
|
|
52
|
+
const phase = useSavedPhase(status, savedAtMs, savedLingerMs);
|
|
53
|
+
const [kept, setKept] = useState(null);
|
|
54
|
+
let nextKept = kept;
|
|
55
|
+
if (status === "error")
|
|
56
|
+
nextKept = kept && kept.error === (error ?? null) ? kept : { error: error ?? null, retry: onRetry };
|
|
57
|
+
else if (status !== "pending") nextKept = null;
|
|
58
|
+
if (nextKept !== kept) setKept(nextKept);
|
|
59
|
+
const failure = status === "error" || status === "pending" && kept !== null;
|
|
60
|
+
const failureDetail = status === "error" ? error : kept?.error;
|
|
61
|
+
const retry = onRetry ?? kept?.retry;
|
|
62
|
+
const savedVisible = status === "saved" && phase !== "gone";
|
|
63
|
+
const base = cn("inline-flex items-center gap-1.5 text-xs tabular-nums", className);
|
|
64
|
+
let visual = null;
|
|
65
|
+
if (failure) {
|
|
66
|
+
visual = /* @__PURE__ */ jsxs(
|
|
67
|
+
"span",
|
|
68
|
+
{
|
|
69
|
+
role: "alert",
|
|
70
|
+
"data-status": "error",
|
|
71
|
+
title: failureDetail ?? void 0,
|
|
72
|
+
className: cn(base, "text-error-foreground"),
|
|
73
|
+
children: [
|
|
74
|
+
/* @__PURE__ */ jsx("span", { children: "Save failed" }),
|
|
75
|
+
retry ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
76
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
"button",
|
|
79
|
+
{
|
|
80
|
+
type: "button",
|
|
81
|
+
onClick: retry,
|
|
82
|
+
className: "text-foreground focus-visible:ring-ring/50 relative rounded-sm font-medium outline-none after:absolute after:-inset-2 hover:underline focus-visible:ring-[3px]",
|
|
83
|
+
children: "Retry"
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
] }) : null
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
} else if (status === "saving") {
|
|
91
|
+
visual = /* @__PURE__ */ jsx(
|
|
92
|
+
"span",
|
|
93
|
+
{
|
|
94
|
+
"aria-hidden": true,
|
|
95
|
+
"data-status": "saving",
|
|
96
|
+
className: cn(base, FAINT, "animate-pulse motion-reduce:animate-none"),
|
|
97
|
+
children: "Saving\u2026"
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
} else if (status === "pending" && pendingLabel) {
|
|
101
|
+
visual = /* @__PURE__ */ jsx("span", { "data-status": "pending", className: cn(base, FAINT), children: pendingLabel });
|
|
102
|
+
} else if (savedVisible) {
|
|
103
|
+
visual = /* @__PURE__ */ jsx(
|
|
104
|
+
"span",
|
|
105
|
+
{
|
|
106
|
+
"aria-hidden": true,
|
|
107
|
+
"data-status": "saved",
|
|
108
|
+
title: savedTitle(savedAt, savedLabel),
|
|
109
|
+
className: cn(
|
|
110
|
+
base,
|
|
111
|
+
FAINT,
|
|
112
|
+
phase === "fading" && "opacity-0 transition-opacity duration-300 motion-reduce:transition-none"
|
|
113
|
+
),
|
|
114
|
+
children: savedLabel
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
119
|
+
/* @__PURE__ */ jsx("span", { role: "status", "aria-live": "polite", "data-slot": "save-status-live", className: "sr-only", children: savedVisible && !failure ? savedLabel : "" }),
|
|
120
|
+
visual
|
|
121
|
+
] });
|
|
122
|
+
};
|
|
123
|
+
export {
|
|
124
|
+
SaveStatus
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=save-status.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/primitives/save-status.tsx"],"sourcesContent":["/*\n * @graph8/sdk/ui — GENERATED FROM frontend/components/ui/save-status.tsx. DO NOT EDIT.\n *\n * Edit the app source, then run: npm run generate:ui --prefix sdk/js\n * Hand edits are overwritten and will fail sdk/js/tests/ui/drift.test.ts.\n */\n\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nexport type SaveStatusValue = \"idle\" | \"pending\" | \"saving\" | \"saved\" | \"error\";\n\nexport interface SaveStatusProps {\n status: SaveStatusValue;\n /** Shown as a tooltip only. The visible copy on failure is always \"Save failed\". */\n error?: string | null;\n /** Omit to render the failure without a Retry control. */\n onRetry?: () => void;\n /** Time of the last successful save. Shown in the title: \"Saved at 12:41\". */\n savedAt?: Date | number | null;\n /** Default \"Saved\". */\n savedLabel?: string;\n /** Copy for `pending`. Default: nothing (or the kept failure, see below). */\n pendingLabel?: string;\n /** How long \"Saved\" stays before it fades. Default 2000. 0 keeps it. */\n savedLingerMs?: number;\n className?: string;\n}\n\nconst FADE_MS = 300;\nconst DEFAULT_LINGER_MS = 2000;\n// Faint text. Falls back to the muted foreground while the 2026 theme is off.\nconst FAINT = \"text-[color:var(--text-faint,var(--text-color-muted))]\";\n\nconst prefersReducedMotion = (): boolean =>\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\nconst savedTitle = (\n savedAt: Date | number | null | undefined,\n label: string\n): string | undefined => {\n if (savedAt == null) return undefined;\n const time = new Date(savedAt).toLocaleTimeString([], { hour: \"numeric\", minute: \"2-digit\" });\n return `${label} at ${time}`;\n};\n\ntype SavedPhase = \"shown\" | \"fading\" | \"gone\";\n\n/** \"Saved\" lingers, fades over 300ms, then unmounts. A new save restarts it. */\nconst useSavedPhase = (\n status: SaveStatusValue,\n savedAt: number | null,\n lingerMs: number\n): SavedPhase => {\n // Adjusting state during render (the documented pattern) so the very first render of a new\n // \"saved\" is already visible; an effect would show one frame of the previous phase.\n const [track, setTrack] = useState({ status, savedAt, epoch: 0 });\n if (track.status !== status || track.savedAt !== savedAt) {\n setTrack({ status, savedAt, epoch: status === \"saved\" ? track.epoch + 1 : track.epoch });\n }\n // A \"saved\" that is already older than its linger when the component first renders (a remount, a\n // tab returning) is history, not news: start it gone.\n const [faded, setFaded] = useState<{ epoch: number; phase: \"fading\" | \"gone\" } | null>(() =>\n status === \"saved\" && savedAt !== null && lingerMs > 0 && Date.now() - savedAt >= lingerMs\n ? { epoch: 0, phase: \"gone\" }\n : null\n );\n const epoch = track.epoch;\n\n useEffect(() => {\n if (status !== \"saved\" || lingerMs <= 0) return;\n let removeTimer: ReturnType<typeof setTimeout> | undefined;\n const fadeTimer = setTimeout(() => {\n if (prefersReducedMotion()) {\n setFaded({ epoch, phase: \"gone\" });\n return;\n }\n setFaded({ epoch, phase: \"fading\" });\n removeTimer = setTimeout(() => setFaded({ epoch, phase: \"gone\" }), FADE_MS);\n }, lingerMs);\n return () => {\n clearTimeout(fadeTimer);\n clearTimeout(removeTimer);\n };\n }, [status, lingerMs, epoch]);\n\n return faded && faded.epoch === epoch ? faded.phase : \"shown\";\n};\n\n/**\n * `Saving…`, `Saved` and `Save failed · Retry`, in one quiet place near the content (the toolbar's\n * right-hand group, first, so the primary action stays last). Autosaved surfaces have no Save\n * button; this is how the user knows their work is safe.\n *\n * A persistent live region announces only \"Saved\" (per-keystroke \"Saving\" announcements are\n * noise); a failure mounts its own `role=\"alert\"`. Feed it from `useAutosave`/`useSaveTracker`\n * via `saveStatusProps(state)`.\n */\nexport const SaveStatus = ({\n status,\n error,\n onRetry,\n savedAt,\n savedLabel = \"Saved\",\n pendingLabel,\n savedLingerMs = DEFAULT_LINGER_MS,\n className,\n}: SaveStatusProps) => {\n const savedAtMs = savedAt == null ? null : new Date(savedAt).getTime();\n const phase = useSavedPhase(status, savedAtMs, savedLingerMs);\n\n // A failure stays on screen through `pending` (the user typed again) until the next attempt\n // starts saving, so a retry-by-typing never hides that the last change did not land.\n const [kept, setKept] = useState<{ error: string | null; retry?: () => void } | null>(null);\n let nextKept = kept;\n if (status === \"error\")\n nextKept =\n kept && kept.error === (error ?? null) ? kept : { error: error ?? null, retry: onRetry };\n else if (status !== \"pending\") nextKept = null;\n if (nextKept !== kept) setKept(nextKept);\n const failure = status === \"error\" || (status === \"pending\" && kept !== null);\n const failureDetail = status === \"error\" ? error : kept?.error;\n // While the user types after a failure the source may stop offering a retry; the kept one still works.\n const retry = onRetry ?? kept?.retry;\n\n const savedVisible = status === \"saved\" && phase !== \"gone\";\n const base = cn(\"inline-flex items-center gap-1.5 text-xs tabular-nums\", className);\n\n let visual = null;\n if (failure) {\n visual = (\n <span\n role=\"alert\"\n data-status=\"error\"\n title={failureDetail ?? undefined}\n className={cn(base, \"text-error-foreground\")}\n >\n <span>Save failed</span>\n {retry ? (\n <>\n <span aria-hidden>·</span>\n <button\n type=\"button\"\n onClick={retry}\n className=\"text-foreground focus-visible:ring-ring/50 relative rounded-sm font-medium outline-none after:absolute after:-inset-2 hover:underline focus-visible:ring-[3px]\"\n >\n Retry\n </button>\n </>\n ) : null}\n </span>\n );\n } else if (status === \"saving\") {\n visual = (\n <span\n aria-hidden\n data-status=\"saving\"\n className={cn(base, FAINT, \"animate-pulse motion-reduce:animate-none\")}\n >\n Saving…\n </span>\n );\n } else if (status === \"pending\" && pendingLabel) {\n visual = (\n <span data-status=\"pending\" className={cn(base, FAINT)}>\n {pendingLabel}\n </span>\n );\n } else if (savedVisible) {\n visual = (\n <span\n aria-hidden\n data-status=\"saved\"\n title={savedTitle(savedAt, savedLabel)}\n className={cn(\n base,\n FAINT,\n phase === \"fading\" &&\n \"opacity-0 transition-opacity duration-300 motion-reduce:transition-none\"\n )}\n >\n {savedLabel}\n </span>\n );\n }\n\n return (\n <>\n <span role=\"status\" aria-live=\"polite\" data-slot=\"save-status-live\" className=\"sr-only\">\n {savedVisible && !failure ? savedLabel : \"\"}\n </span>\n {visual}\n </>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
3
|
+
|
|
4
|
+
declare function Separator({ className, orientation, decorative, ...props }: React.ComponentProps<typeof SeparatorPrimitive.Root>): React.JSX.Element;
|
|
5
|
+
|
|
6
|
+
export { Separator };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
3
|
+
|
|
4
|
+
declare function Separator({ className, orientation, decorative, ...props }: React.ComponentProps<typeof SeparatorPrimitive.Root>): React.JSX.Element;
|
|
5
|
+
|
|
6
|
+
export { Separator };
|