@gntik-ai/blocks 0.0.0-stage → 0.6.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/dist/index.d.ts +3626 -0
- package/dist/index.js +15417 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -3
- package/src/ai/AssistantCardGrid/AssistantCardGrid.test.tsx +32 -0
- package/src/ai/AssistantCardGrid/AssistantCardGrid.tsx +98 -0
- package/src/ai/AssistantCardGrid/block.meta.ts +10 -0
- package/src/ai/AssistantCardGrid/fixtures.ts +72 -0
- package/src/ai/EvaluationScorecard/EvaluationScorecard.test.tsx +39 -0
- package/src/ai/EvaluationScorecard/EvaluationScorecard.tsx +233 -0
- package/src/ai/EvaluationScorecard/block.meta.ts +10 -0
- package/src/ai/EvaluationScorecard/fixtures.ts +79 -0
- package/src/ai/ModelKeysList/ModelKeysList.test.tsx +44 -0
- package/src/ai/ModelKeysList/ModelKeysList.tsx +203 -0
- package/src/ai/ModelKeysList/block.meta.ts +10 -0
- package/src/ai/ModelKeysList/fixtures.ts +44 -0
- package/src/ai/PromptEditor/PromptEditor.test.tsx +97 -0
- package/src/ai/PromptEditor/PromptEditor.tsx +202 -0
- package/src/ai/PromptEditor/block.meta.ts +10 -0
- package/src/ai/PromptEditor/examples/controlled-variables.tsx +23 -0
- package/src/ai/PromptEditor/fixtures.ts +12 -0
- package/src/ai/TokenCostCard/TokenCostCard.test.tsx +36 -0
- package/src/ai/TokenCostCard/TokenCostCard.tsx +130 -0
- package/src/ai/TokenCostCard/block.meta.ts +9 -0
- package/src/ai/TokenCostCard/fixtures.ts +18 -0
- package/src/ai/TraceWaterfall/TraceWaterfall.test.tsx +119 -0
- package/src/ai/TraceWaterfall/TraceWaterfall.tsx +317 -0
- package/src/ai/TraceWaterfall/block.meta.ts +10 -0
- package/src/ai/TraceWaterfall/examples/no-details.tsx +6 -0
- package/src/ai/TraceWaterfall/examples/running.tsx +16 -0
- package/src/ai/TraceWaterfall/fixtures.ts +133 -0
- package/src/ai/TraceWaterfall/span-details.tsx +51 -0
- package/src/ai/index.ts +13 -0
- package/src/auth/ForgotPasswordForm/ForgotPasswordForm.test.tsx +209 -0
- package/src/auth/ForgotPasswordForm/ForgotPasswordForm.tsx +211 -0
- package/src/auth/ForgotPasswordForm/block.meta.ts +10 -0
- package/src/auth/ForgotPasswordForm/examples/UsernameOrEmail.tsx +24 -0
- package/src/auth/MfaChallenge/MfaChallenge.test.tsx +35 -0
- package/src/auth/MfaChallenge/MfaChallenge.tsx +170 -0
- package/src/auth/MfaChallenge/block.meta.ts +9 -0
- package/src/auth/ResetPasswordForm/ResetPasswordForm.test.tsx +27 -0
- package/src/auth/ResetPasswordForm/ResetPasswordForm.tsx +100 -0
- package/src/auth/ResetPasswordForm/block.meta.ts +10 -0
- package/src/auth/SignInForm/SignInForm.test.tsx +222 -0
- package/src/auth/SignInForm/SignInForm.tsx +226 -0
- package/src/auth/SignInForm/block.meta.ts +22 -0
- package/src/auth/SignInForm/examples/Username.tsx +26 -0
- package/src/auth/SignUpForm/SignUpForm.configured.test.tsx +316 -0
- package/src/auth/SignUpForm/SignUpForm.test.tsx +33 -0
- package/src/auth/SignUpForm/SignUpForm.tsx +298 -0
- package/src/auth/SignUpForm/block.meta.ts +22 -0
- package/src/auth/SignUpForm/examples/CustomFields.tsx +56 -0
- package/src/auth/SignUpForm/examples/Error.tsx +5 -0
- package/src/auth/SignUpForm/examples/Loading.tsx +6 -0
- package/src/auth/SignUpForm/examples/NoTerms.tsx +6 -0
- package/src/auth/SignUpForm/examples/Submitting.tsx +5 -0
- package/src/auth/SignUpForm/examples/Unavailable.tsx +15 -0
- package/src/auth/SsoButtons/SsoButtons.test.tsx +23 -0
- package/src/auth/SsoButtons/SsoButtons.tsx +52 -0
- package/src/auth/SsoButtons/block.meta.ts +9 -0
- package/src/auth/SsoButtons/fixtures.ts +15 -0
- package/src/auth/index.ts +16 -0
- package/src/auth/shared.tsx +147 -0
- package/src/billing/CostBreakdown/CostBreakdown.test.tsx +24 -0
- package/src/billing/CostBreakdown/CostBreakdown.tsx +95 -0
- package/src/billing/CostBreakdown/block.meta.ts +10 -0
- package/src/billing/CostBreakdown/fixtures.ts +9 -0
- package/src/billing/InvoiceTable/InvoiceTable.test.tsx +29 -0
- package/src/billing/InvoiceTable/InvoiceTable.tsx +130 -0
- package/src/billing/InvoiceTable/block.meta.ts +10 -0
- package/src/billing/InvoiceTable/fixtures.ts +38 -0
- package/src/billing/PaymentMethodCard/PaymentMethodCard.test.tsx +28 -0
- package/src/billing/PaymentMethodCard/PaymentMethodCard.tsx +103 -0
- package/src/billing/PaymentMethodCard/block.meta.ts +10 -0
- package/src/billing/PaymentMethodCard/fixtures.ts +12 -0
- package/src/billing/PlanCard/PlanCard.baseline.test.tsx +26 -0
- package/src/billing/PlanCard/PlanCard.summary.test.tsx +227 -0
- package/src/billing/PlanCard/PlanCard.test.tsx +27 -0
- package/src/billing/PlanCard/PlanCard.tsx +140 -0
- package/src/billing/PlanCard/PlanSummary.tsx +101 -0
- package/src/billing/PlanCard/README.md +23 -0
- package/src/billing/PlanCard/__snapshots__/PlanCard.baseline.test.tsx.snap +5 -0
- package/src/billing/PlanCard/block.meta.ts +60 -0
- package/src/billing/PlanCard/examples/SummaryActionsOnly.tsx +12 -0
- package/src/billing/PlanCard/examples/SummaryFeaturesOnly.tsx +14 -0
- package/src/billing/PlanCard/examples/SummaryFull.tsx +28 -0
- package/src/billing/PlanCard/examples/SummaryMinimal.tsx +5 -0
- package/src/billing/PlanCard/examples/SummaryPriceOnly.tsx +15 -0
- package/src/billing/PlanCard/examples/SummaryRenewalOnly.tsx +14 -0
- package/src/billing/PlanCard/examples/SummaryUnassigned.tsx +5 -0
- package/src/billing/PlanCard/examples/SummaryUnassignedNoLabel.tsx +5 -0
- package/src/billing/PlanCard/examples/SummaryZeroPrice.tsx +15 -0
- package/src/billing/PlanCard/fixtures.ts +19 -0
- package/src/billing/PlanDefinitionCard/PlanDefinitionCard.test.tsx +111 -0
- package/src/billing/PlanDefinitionCard/PlanDefinitionCard.tsx +86 -0
- package/src/billing/PlanDefinitionCard/README.md +29 -0
- package/src/billing/PlanDefinitionCard/block.meta.ts +46 -0
- package/src/billing/PlanDefinitionCard/examples/Compact.tsx +23 -0
- package/src/billing/PlanDefinitionCard/examples/Full.tsx +23 -0
- package/src/billing/PlanDefinitionCard/fixtures.ts +12 -0
- package/src/billing/QuotaMeters/QuotaMeters.test.tsx +23 -0
- package/src/billing/QuotaMeters/QuotaMeters.tsx +92 -0
- package/src/billing/QuotaMeters/block.meta.ts +10 -0
- package/src/billing/QuotaMeters/fixtures.ts +9 -0
- package/src/billing/SpendVsBudget/SpendVsBudget.test.tsx +24 -0
- package/src/billing/SpendVsBudget/SpendVsBudget.tsx +105 -0
- package/src/billing/SpendVsBudget/block.meta.ts +10 -0
- package/src/billing/SpendVsBudget/fixtures.ts +18 -0
- package/src/billing/format.ts +42 -0
- package/src/billing/index.ts +21 -0
- package/src/builders/CodePanel/CodePanel.test.tsx +280 -0
- package/src/builders/CodePanel/CodePanel.tsx +239 -0
- package/src/builders/CodePanel/block.meta.ts +10 -0
- package/src/builders/CodePanel/examples/controlled.tsx +15 -0
- package/src/builders/CodePanel/examples/diagnostics.tsx +40 -0
- package/src/builders/CodePanel/fixtures.ts +95 -0
- package/src/builders/CodePanel/marker-store.ts +90 -0
- package/src/builders/CodePanel/markers.ts +62 -0
- package/src/builders/FlowBuilder/FlowBuilder.test.tsx +480 -0
- package/src/builders/FlowBuilder/FlowBuilder.tsx +343 -0
- package/src/builders/FlowBuilder/block.meta.ts +20 -0
- package/src/builders/FlowBuilder/connections.ts +67 -0
- package/src/builders/FlowBuilder/decorated-nodes.ts +80 -0
- package/src/builders/FlowBuilder/examples/extensions.tsx +120 -0
- package/src/builders/FlowBuilder/extensions.ts +37 -0
- package/src/builders/FlowBuilder/fixtures.ts +80 -0
- package/src/builders/FlowBuilder/parts.tsx +196 -0
- package/src/builders/FlowBuilder/problems.tsx +40 -0
- package/src/builders/LogViewer/LogViewer.test.tsx +97 -0
- package/src/builders/LogViewer/LogViewer.tsx +253 -0
- package/src/builders/LogViewer/block.meta.ts +10 -0
- package/src/builders/LogViewer/fixtures.ts +49 -0
- package/src/builders/index.ts +15 -0
- package/src/data-display/ActivityFeed/ActivityFeed.test.tsx +62 -0
- package/src/data-display/ActivityFeed/ActivityFeed.tsx +118 -0
- package/src/data-display/ActivityFeed/block.meta.ts +10 -0
- package/src/data-display/ActivityFeed/fixtures.ts +29 -0
- package/src/data-display/ChartCard/ChartCard.ranges.test.tsx +282 -0
- package/src/data-display/ChartCard/ChartCard.test.tsx +54 -0
- package/src/data-display/ChartCard/ChartCard.tsx +218 -0
- package/src/data-display/ChartCard/block.meta.ts +10 -0
- package/src/data-display/ChartCard/examples/custom-ranges.tsx +37 -0
- package/src/data-display/ChartCard/examples/heatmap.tsx +20 -0
- package/src/data-display/ChartCard/examples/toolbar-owned-range.tsx +34 -0
- package/src/data-display/ChartCard/fixtures.ts +82 -0
- package/src/data-display/CommentThread/CommentThread.test.tsx +29 -0
- package/src/data-display/CommentThread/CommentThread.tsx +120 -0
- package/src/data-display/CommentThread/block.meta.ts +10 -0
- package/src/data-display/CommentThread/fixtures.ts +28 -0
- package/src/data-display/DescriptionListCard/DescriptionListCard.test.tsx +28 -0
- package/src/data-display/DescriptionListCard/DescriptionListCard.tsx +120 -0
- package/src/data-display/DescriptionListCard/block.meta.ts +9 -0
- package/src/data-display/DescriptionListCard/fixtures.ts +12 -0
- package/src/data-display/KpiRow/KpiRow.test.tsx +29 -0
- package/src/data-display/KpiRow/KpiRow.tsx +101 -0
- package/src/data-display/KpiRow/block.meta.ts +10 -0
- package/src/data-display/KpiRow/fixtures.ts +34 -0
- package/src/data-display/ResourceCardGrid/ResourceCardGrid.test.tsx +22 -0
- package/src/data-display/ResourceCardGrid/ResourceCardGrid.tsx +98 -0
- package/src/data-display/ResourceCardGrid/block.meta.ts +10 -0
- package/src/data-display/ResourceCardGrid/fixtures.ts +72 -0
- package/src/data-display/StatCard/StatCard.test.tsx +30 -0
- package/src/data-display/StatCard/StatCard.tsx +138 -0
- package/src/data-display/StatCard/block.meta.ts +10 -0
- package/src/data-display/StatCard/fixtures.ts +26 -0
- package/src/data-display/StatusTimeline/StatusTimeline.test.tsx +153 -0
- package/src/data-display/StatusTimeline/StatusTimeline.tsx +114 -0
- package/src/data-display/StatusTimeline/block.meta.ts +10 -0
- package/src/data-display/StatusTimeline/examples/Empty.tsx +6 -0
- package/src/data-display/StatusTimeline/fixtures.ts +62 -0
- package/src/data-display/index.ts +34 -0
- package/src/data-display/shared/TrendDelta.tsx +60 -0
- package/src/feedback/ConfirmDestructive/ConfirmDestructive.test.tsx +47 -0
- package/src/feedback/ConfirmDestructive/ConfirmDestructive.tsx +145 -0
- package/src/feedback/ConfirmDestructive/block.meta.ts +10 -0
- package/src/feedback/EmptyStates/EmptyStates.test.tsx +48 -0
- package/src/feedback/EmptyStates/EmptyStates.tsx +191 -0
- package/src/feedback/EmptyStates/block.meta.ts +10 -0
- package/src/feedback/EmptyStates/fixtures.ts +6 -0
- package/src/feedback/ErrorPanel/ErrorPanel.test.tsx +37 -0
- package/src/feedback/ErrorPanel/ErrorPanel.tsx +146 -0
- package/src/feedback/ErrorPanel/block.meta.ts +10 -0
- package/src/feedback/InlineCallout/InlineCallout.test.tsx +33 -0
- package/src/feedback/InlineCallout/InlineCallout.tsx +81 -0
- package/src/feedback/InlineCallout/block.meta.ts +9 -0
- package/src/feedback/Skeletons/Skeletons.test.tsx +25 -0
- package/src/feedback/Skeletons/Skeletons.tsx +142 -0
- package/src/feedback/Skeletons/block.meta.ts +10 -0
- package/src/feedback/SystemBanner/SystemBanner.test.tsx +29 -0
- package/src/feedback/SystemBanner/SystemBanner.tsx +105 -0
- package/src/feedback/SystemBanner/block.meta.ts +9 -0
- package/src/feedback/index.ts +14 -0
- package/src/feedback/types.ts +13 -0
- package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.test.tsx +36 -0
- package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.tsx +197 -0
- package/src/forms/CreateApiKeyDialog/block.meta.ts +10 -0
- package/src/forms/CreateApiKeyDialog/fixtures.ts +31 -0
- package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.test.tsx +339 -0
- package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +193 -0
- package/src/forms/CredentialDisclosureDialog/block.meta.ts +10 -0
- package/src/forms/CredentialDisclosureDialog/examples/Fresh.tsx +32 -0
- package/src/forms/CredentialDisclosureDialog/examples/ResponseGating.tsx +69 -0
- package/src/forms/CredentialDisclosureDialog/examples/Stored.tsx +32 -0
- package/src/forms/CredentialDisclosureDialog/fixtures.ts +14 -0
- package/src/forms/DangerZone/ConfirmDestructiveDialog.tsx +101 -0
- package/src/forms/DangerZone/DangerZone.test.tsx +28 -0
- package/src/forms/DangerZone/DangerZone.tsx +86 -0
- package/src/forms/DangerZone/block.meta.ts +10 -0
- package/src/forms/DangerZone/fixtures.ts +36 -0
- package/src/forms/DateRangeFilter/DateRangeFilter.test.tsx +26 -0
- package/src/forms/DateRangeFilter/DateRangeFilter.tsx +83 -0
- package/src/forms/DateRangeFilter/block.meta.ts +9 -0
- package/src/forms/DialogWizard/DialogWizard.test.tsx +95 -0
- package/src/forms/DialogWizard/DialogWizard.tsx +39 -0
- package/src/forms/DialogWizard/block.meta.ts +10 -0
- package/src/forms/DialogWizard/examples/CreateResource.tsx +65 -0
- package/src/forms/DialogWizard/fixtures.ts +20 -0
- package/src/forms/FileUploadPanel/FileUploadPanel.test.tsx +43 -0
- package/src/forms/FileUploadPanel/FileUploadPanel.tsx +244 -0
- package/src/forms/FileUploadPanel/block.meta.ts +10 -0
- package/src/forms/FileUploadPanel/fixtures.ts +66 -0
- package/src/forms/FormSection/FormSection.test.tsx +34 -0
- package/src/forms/FormSection/FormSection.tsx +77 -0
- package/src/forms/FormSection/block.meta.ts +9 -0
- package/src/forms/InviteMembersDialog/InviteMembersDialog.test.tsx +37 -0
- package/src/forms/InviteMembersDialog/InviteMembersDialog.tsx +183 -0
- package/src/forms/InviteMembersDialog/block.meta.ts +10 -0
- package/src/forms/InviteMembersDialog/fixtures.ts +14 -0
- package/src/forms/SettingsRow/SettingsRow.test.tsx +50 -0
- package/src/forms/SettingsRow/SettingsRow.tsx +74 -0
- package/src/forms/SettingsRow/block.meta.ts +9 -0
- package/src/forms/ValidationSummary/ValidationSummary.test.tsx +46 -0
- package/src/forms/ValidationSummary/ValidationSummary.tsx +75 -0
- package/src/forms/ValidationSummary/block.meta.ts +9 -0
- package/src/forms/ValidationSummary/fixtures.ts +13 -0
- package/src/forms/index.ts +27 -0
- package/src/index.ts +14 -0
- package/src/marketing/ComparisonTable/ComparisonTable.test.tsx +69 -0
- package/src/marketing/ComparisonTable/ComparisonTable.tsx +245 -0
- package/src/marketing/ComparisonTable/block.meta.ts +10 -0
- package/src/marketing/ComparisonTable/examples/options.tsx +48 -0
- package/src/marketing/ComparisonTable/fixtures.ts +83 -0
- package/src/marketing/Faq/Faq.test.tsx +25 -0
- package/src/marketing/Faq/Faq.tsx +68 -0
- package/src/marketing/Faq/block.meta.ts +10 -0
- package/src/marketing/Faq/fixtures.ts +32 -0
- package/src/marketing/FeatureGrid/FeatureGrid.test.tsx +19 -0
- package/src/marketing/FeatureGrid/FeatureGrid.tsx +79 -0
- package/src/marketing/FeatureGrid/block.meta.ts +10 -0
- package/src/marketing/FeatureGrid/fixtures.ts +36 -0
- package/src/marketing/Hero/Hero.test.tsx +33 -0
- package/src/marketing/Hero/Hero.tsx +107 -0
- package/src/marketing/Hero/block.meta.ts +10 -0
- package/src/marketing/PricingTable/PricingTable.test.tsx +92 -0
- package/src/marketing/PricingTable/PricingTable.tsx +323 -0
- package/src/marketing/PricingTable/block.meta.ts +10 -0
- package/src/marketing/PricingTable/fixtures.ts +34 -0
- package/src/marketing/actions.tsx +40 -0
- package/src/marketing/index.ts +15 -0
- package/src/meta.ts +25 -0
- package/src/page-chrome/BulkActionBar/BulkActionBar.test.tsx +34 -0
- package/src/page-chrome/BulkActionBar/BulkActionBar.tsx +76 -0
- package/src/page-chrome/BulkActionBar/block.meta.ts +9 -0
- package/src/page-chrome/PageHeader/PageHeader.test.tsx +68 -0
- package/src/page-chrome/PageHeader/PageHeader.tsx +152 -0
- package/src/page-chrome/PageHeader/block.meta.ts +10 -0
- package/src/page-chrome/PageHeader/fixtures.ts +29 -0
- package/src/page-chrome/PageToolbar/PageToolbar.test.tsx +38 -0
- package/src/page-chrome/PageToolbar/PageToolbar.tsx +138 -0
- package/src/page-chrome/PageToolbar/block.meta.ts +10 -0
- package/src/page-chrome/PageToolbar/fixtures.ts +8 -0
- package/src/page-chrome/SectionHeader/SectionHeader.test.tsx +28 -0
- package/src/page-chrome/SectionHeader/SectionHeader.tsx +73 -0
- package/src/page-chrome/SectionHeader/block.meta.ts +9 -0
- package/src/page-chrome/StickyActionBar/StickyActionBar.test.tsx +29 -0
- package/src/page-chrome/StickyActionBar/StickyActionBar.tsx +66 -0
- package/src/page-chrome/StickyActionBar/block.meta.ts +9 -0
- package/src/page-chrome/index.ts +13 -0
- package/src/page-chrome/types.ts +25 -0
- package/src/scheduling/AgendaList/AgendaList.test.tsx +28 -0
- package/src/scheduling/AgendaList/AgendaList.tsx +165 -0
- package/src/scheduling/AgendaList/block.meta.ts +10 -0
- package/src/scheduling/MonthCalendar/MonthCalendar.test.tsx +32 -0
- package/src/scheduling/MonthCalendar/MonthCalendar.tsx +223 -0
- package/src/scheduling/MonthCalendar/block.meta.ts +10 -0
- package/src/scheduling/TimeSlotPicker/TimeSlotPicker.test.tsx +26 -0
- package/src/scheduling/TimeSlotPicker/TimeSlotPicker.tsx +115 -0
- package/src/scheduling/TimeSlotPicker/block.meta.ts +10 -0
- package/src/scheduling/TimeSlotPicker/fixtures.ts +10 -0
- package/src/scheduling/WeekCalendar/WeekCalendar.test.tsx +27 -0
- package/src/scheduling/WeekCalendar/WeekCalendar.tsx +274 -0
- package/src/scheduling/WeekCalendar/block.meta.ts +10 -0
- package/src/scheduling/index.ts +11 -0
- package/src/scheduling/shared/CalendarHeader.tsx +54 -0
- package/src/scheduling/shared/EventTile.tsx +21 -0
- package/src/scheduling/shared/dates.ts +98 -0
- package/src/scheduling/shared/events.ts +90 -0
- package/src/scheduling/shared/fixtures.ts +54 -0
- package/src/shell/AppSidebar/AppSidebar.test.tsx +38 -0
- package/src/shell/AppSidebar/AppSidebar.tsx +226 -0
- package/src/shell/AppSidebar/block.meta.ts +10 -0
- package/src/shell/AppSidebar/fixtures.ts +58 -0
- package/src/shell/AppTopbar/AppTopbar.test.tsx +41 -0
- package/src/shell/AppTopbar/AppTopbar.tsx +82 -0
- package/src/shell/AppTopbar/block.meta.ts +19 -0
- package/src/shell/AppTopbar/fixtures.ts +22 -0
- package/src/shell/EnvironmentBadge/EnvironmentBadge.test.tsx +22 -0
- package/src/shell/EnvironmentBadge/EnvironmentBadge.tsx +55 -0
- package/src/shell/EnvironmentBadge/block.meta.ts +10 -0
- package/src/shell/GlobalSearch/GlobalSearch.test.tsx +28 -0
- package/src/shell/GlobalSearch/GlobalSearch.tsx +80 -0
- package/src/shell/GlobalSearch/block.meta.ts +10 -0
- package/src/shell/GlobalSearch/fixtures.ts +64 -0
- package/src/shell/index.ts +11 -0
- package/src/styles.css +2 -0
- package/src/tables/DataTable/DataTable.edit-views.test.tsx +249 -0
- package/src/tables/DataTable/DataTable.labels.test.tsx +291 -0
- package/src/tables/DataTable/DataTable.layout.test.tsx +188 -0
- package/src/tables/DataTable/DataTable.overflow-labels.test.tsx +59 -0
- package/src/tables/DataTable/DataTable.single-select.test.tsx +501 -0
- package/src/tables/DataTable/DataTable.test.tsx +268 -0
- package/src/tables/DataTable/DataTable.tsx +531 -0
- package/src/tables/DataTable/block.meta.ts +129 -0
- package/src/tables/DataTable/column-menu.tsx +112 -0
- package/src/tables/DataTable/column-sizing.ts +166 -0
- package/src/tables/DataTable/data-table-body.tsx +195 -0
- package/src/tables/DataTable/data-table-props.ts +159 -0
- package/src/tables/DataTable/data-table-row.tsx +231 -0
- package/src/tables/DataTable/data-table-utils.ts +195 -0
- package/src/tables/DataTable/density-toggle.tsx +33 -0
- package/src/tables/DataTable/editable-cell.tsx +287 -0
- package/src/tables/DataTable/examples/editable.tsx +71 -0
- package/src/tables/DataTable/examples/grouped.tsx +18 -0
- package/src/tables/DataTable/examples/resizable-pinned.tsx +20 -0
- package/src/tables/DataTable/examples/saved-views.tsx +61 -0
- package/src/tables/DataTable/examples/single-selection.tsx +55 -0
- package/src/tables/DataTable/examples/virtualized.tsx +20 -0
- package/src/tables/DataTable/fixtures.ts +119 -0
- package/src/tables/DataTable/header-cell.tsx +90 -0
- package/src/tables/DataTable/labels.ts +54 -0
- package/src/tables/DataTable/resize-handle.tsx +91 -0
- package/src/tables/DataTable/single-selection.tsx +149 -0
- package/src/tables/DataTable/use-table-views.ts +79 -0
- package/src/tables/DataTable/use-virtual-rows.ts +83 -0
- package/src/tables/DataTable/views.tsx +193 -0
- package/src/tables/FilterBar/FilterBar.labels.test.tsx +69 -0
- package/src/tables/FilterBar/FilterBar.test.tsx +43 -0
- package/src/tables/FilterBar/FilterBar.tsx +232 -0
- package/src/tables/FilterBar/block.meta.ts +32 -0
- package/src/tables/FilterBar/fixtures.ts +32 -0
- package/src/tables/InlineEditRow/InlineEditRow.test.tsx +41 -0
- package/src/tables/InlineEditRow/InlineEditRow.tsx +215 -0
- package/src/tables/InlineEditRow/block.meta.ts +10 -0
- package/src/tables/InlineEditRow/fixtures.ts +28 -0
- package/src/tables/PaginationFooter/PaginationFooter.labels.test.tsx +57 -0
- package/src/tables/PaginationFooter/PaginationFooter.test.tsx +29 -0
- package/src/tables/PaginationFooter/PaginationFooter.tsx +118 -0
- package/src/tables/PaginationFooter/block.meta.ts +33 -0
- package/src/tables/SubordinateList/SubordinateList.test.tsx +351 -0
- package/src/tables/SubordinateList/SubordinateList.tsx +140 -0
- package/src/tables/SubordinateList/block.meta.ts +10 -0
- package/src/tables/SubordinateList/examples/ResourceForm.tsx +129 -0
- package/src/tables/SubordinateList/examples/empty.tsx +5 -0
- package/src/tables/SubordinateList/examples/error.tsx +5 -0
- package/src/tables/SubordinateList/examples/loading.tsx +5 -0
- package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.test.tsx +159 -0
- package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.tsx +60 -0
- package/src/tables/TruncatedCollectionFooter/block.meta.ts +10 -0
- package/src/tables/TruncatedCollectionFooter/examples/exact.tsx +6 -0
- package/src/tables/TruncatedCollectionFooter/examples/has-more.tsx +12 -0
- package/src/tables/TruncatedCollectionFooter/fixtures.ts +2 -0
- package/src/tables/index.ts +45 -0
- package/src/team/MembersTable/MembersTable.test.tsx +29 -0
- package/src/team/MembersTable/MembersTable.tsx +141 -0
- package/src/team/MembersTable/block.meta.ts +9 -0
- package/src/team/MembersTable/fixtures.ts +19 -0
- package/src/team/NotificationMatrix/NotificationMatrix.test.tsx +36 -0
- package/src/team/NotificationMatrix/NotificationMatrix.tsx +144 -0
- package/src/team/NotificationMatrix/block.meta.ts +9 -0
- package/src/team/NotificationMatrix/fixtures.ts +43 -0
- package/src/team/PendingInvitations/PendingInvitations.test.tsx +30 -0
- package/src/team/PendingInvitations/PendingInvitations.tsx +132 -0
- package/src/team/PendingInvitations/block.meta.ts +9 -0
- package/src/team/PendingInvitations/fixtures.ts +39 -0
- package/src/team/ProfileHeader/ProfileHeader.test.tsx +29 -0
- package/src/team/ProfileHeader/ProfileHeader.tsx +106 -0
- package/src/team/ProfileHeader/block.meta.ts +10 -0
- package/src/team/ProfileHeader/fixtures.ts +28 -0
- package/src/team/SessionsDevices/SessionsDevices.test.tsx +30 -0
- package/src/team/SessionsDevices/SessionsDevices.tsx +126 -0
- package/src/team/SessionsDevices/block.meta.ts +10 -0
- package/src/team/SessionsDevices/fixtures.ts +58 -0
- package/src/team/index.ts +15 -0
- package/src/test/a11y.ts +18 -0
- package/src/test/heading-levels.test.tsx +69 -0
- package/src/test/setup.ts +36 -0
- package/README.md +0 -3
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Alert,
|
|
3
|
+
Button,
|
|
4
|
+
Checkbox,
|
|
5
|
+
Field,
|
|
6
|
+
FieldDescription,
|
|
7
|
+
FieldError,
|
|
8
|
+
FieldLabel,
|
|
9
|
+
Input,
|
|
10
|
+
Link,
|
|
11
|
+
PasswordInput,
|
|
12
|
+
Skeleton,
|
|
13
|
+
cn,
|
|
14
|
+
} from '@gntik-ai/ui';
|
|
15
|
+
import { Mail, User } from '@gntik-ai/icons';
|
|
16
|
+
import { useId, useState, type MouseEvent, type ReactNode } from 'react';
|
|
17
|
+
import { SsoButtons } from '../SsoButtons/SsoButtons';
|
|
18
|
+
import {
|
|
19
|
+
AuthDivider,
|
|
20
|
+
AuthHeader,
|
|
21
|
+
EMAIL_RE,
|
|
22
|
+
authFormClass,
|
|
23
|
+
authSignUpFieldError,
|
|
24
|
+
useAsyncSubmit,
|
|
25
|
+
type AuthSignUpField,
|
|
26
|
+
type AuthUnavailableState,
|
|
27
|
+
type AuthSignUpValidationMessages,
|
|
28
|
+
} from '../shared';
|
|
29
|
+
import { ValidationSummary, type ValidationIssue } from '../../forms/ValidationSummary/ValidationSummary';
|
|
30
|
+
|
|
31
|
+
export interface SignUpValues {
|
|
32
|
+
name: string;
|
|
33
|
+
email: string;
|
|
34
|
+
password: string;
|
|
35
|
+
/** Present only in configured mode. Text/email values are trimmed and keyed by field id. */
|
|
36
|
+
fields?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SignUpFormProps {
|
|
40
|
+
/** Ordered text/email inputs before Password. Omit to keep the default fields and payload. */
|
|
41
|
+
fields?: readonly AuthSignUpField[];
|
|
42
|
+
messages?: AuthSignUpValidationMessages;
|
|
43
|
+
/** Replaces all account creation controls with a consumer-supplied callout. */
|
|
44
|
+
unavailable?: AuthUnavailableState;
|
|
45
|
+
/** Resolving policy, separate from loading (an account submission). No form is rendered. */
|
|
46
|
+
policyLoading?: boolean;
|
|
47
|
+
/** Creates the account. A returned promise shows the loading state; a rejection shows in the alert. */
|
|
48
|
+
onSubmit?: (values: SignUpValues) => void | Promise<void>;
|
|
49
|
+
error?: string | null;
|
|
50
|
+
loading?: boolean;
|
|
51
|
+
/** Optional password guidance; receives the current minimum length when a function is supplied. */
|
|
52
|
+
passwordHelp?: ReactNode | ((minimum: number) => ReactNode);
|
|
53
|
+
/** Minimum password length. Defaults to 8. */
|
|
54
|
+
minPasswordLength?: number;
|
|
55
|
+
/** Omit to require consent; false removes the checkbox and consent validation. */
|
|
56
|
+
terms?: false;
|
|
57
|
+
termsHref?: string;
|
|
58
|
+
privacyHref?: string;
|
|
59
|
+
signInHref?: string;
|
|
60
|
+
onSignIn?: () => void;
|
|
61
|
+
/** SSO area under the divider; defaults to SsoButtons, `null` hides it. */
|
|
62
|
+
sso?: ReactNode;
|
|
63
|
+
eyebrow?: ReactNode;
|
|
64
|
+
title?: ReactNode;
|
|
65
|
+
description?: ReactNode;
|
|
66
|
+
className?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Account creation: name, work email, password with a strength meter and a required terms checkbox. */
|
|
70
|
+
export function SignUpForm({
|
|
71
|
+
fields,
|
|
72
|
+
messages,
|
|
73
|
+
unavailable,
|
|
74
|
+
policyLoading = false,
|
|
75
|
+
onSubmit,
|
|
76
|
+
error: errorProp,
|
|
77
|
+
loading: loadingProp,
|
|
78
|
+
minPasswordLength = 8,
|
|
79
|
+
passwordHelp,
|
|
80
|
+
terms: termsProp,
|
|
81
|
+
termsHref = '#',
|
|
82
|
+
privacyHref = '#',
|
|
83
|
+
signInHref = '#',
|
|
84
|
+
onSignIn,
|
|
85
|
+
sso = <SsoButtons />,
|
|
86
|
+
eyebrow = 'Get started',
|
|
87
|
+
title = 'Create your account',
|
|
88
|
+
description = 'Set up a workspace for your team in a couple of minutes.',
|
|
89
|
+
className,
|
|
90
|
+
}: SignUpFormProps) {
|
|
91
|
+
const termsErrorId = useId();
|
|
92
|
+
const fieldPrefix = useId();
|
|
93
|
+
const passwordId = `${fieldPrefix}-password`;
|
|
94
|
+
const termsId = `${fieldPrefix}-terms`;
|
|
95
|
+
const [fieldValues, setFieldValues] = useState<Record<string, string>>({});
|
|
96
|
+
const [submitCount, setSubmitCount] = useState(0);
|
|
97
|
+
const fieldValue = (id: string) => (Object.hasOwn(fieldValues, id) ? (fieldValues[id] ?? '') : '');
|
|
98
|
+
const configuredErrors: ValidationIssue[] = (fields ?? []).flatMap((field) => {
|
|
99
|
+
const message = authSignUpFieldError(fieldValue(field.id), field);
|
|
100
|
+
return message ? [{ fieldId: `${fieldPrefix}-field-${field.id}`, label: field.label, message }] : [];
|
|
101
|
+
});
|
|
102
|
+
const [name, setName] = useState('');
|
|
103
|
+
const [email, setEmail] = useState('');
|
|
104
|
+
const [password, setPassword] = useState('');
|
|
105
|
+
const [terms, setTerms] = useState(false);
|
|
106
|
+
const [submitted, setSubmitted] = useState(false);
|
|
107
|
+
const { loading, error, run } = useAsyncSubmit('The account could not be created.');
|
|
108
|
+
const busy = loadingProp ?? loading;
|
|
109
|
+
const alert = errorProp ?? error;
|
|
110
|
+
const nameInvalid = submitted && name.trim() === '';
|
|
111
|
+
const emailInvalid = submitted && !EMAIL_RE.test(email.trim());
|
|
112
|
+
const passwordInvalid =
|
|
113
|
+
(submitted || (fields !== undefined && password.length > 0)) && password.length < minPasswordLength;
|
|
114
|
+
const termsInvalid = submitted && termsProp !== false && !terms;
|
|
115
|
+
|
|
116
|
+
const passwordError =
|
|
117
|
+
messages?.passwordTooShort?.(minPasswordLength) ?? `Use at least ${minPasswordLength} characters.`;
|
|
118
|
+
const termsError = messages?.termsRequired ?? 'Accept the terms to continue.';
|
|
119
|
+
const summaryErrors = [
|
|
120
|
+
...configuredErrors,
|
|
121
|
+
...(password.length < minPasswordLength
|
|
122
|
+
? [{ fieldId: passwordId, label: 'Password', message: passwordError }]
|
|
123
|
+
: []),
|
|
124
|
+
...(termsProp !== false && !terms ? [{ fieldId: termsId, label: 'Terms', message: termsError }] : []),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
if (unavailable)
|
|
128
|
+
return (
|
|
129
|
+
<div className={cn(authFormClass, className)}>
|
|
130
|
+
<Alert tone="info" title={unavailable.title} description={unavailable.message} actions={unavailable.action} />
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (policyLoading)
|
|
135
|
+
return (
|
|
136
|
+
<div className={cn(authFormClass, 'flex flex-col gap-4', className)}>
|
|
137
|
+
<span role="status" className="sr-only">
|
|
138
|
+
Loading sign-up policy…
|
|
139
|
+
</span>
|
|
140
|
+
<Skeleton aria-hidden className="h-8 w-3/4" />
|
|
141
|
+
<Skeleton aria-hidden className="h-4 w-full" />
|
|
142
|
+
<Skeleton aria-hidden className="h-12 w-full" />
|
|
143
|
+
<Skeleton aria-hidden className="h-12 w-full" />
|
|
144
|
+
<Skeleton aria-hidden className="h-12 w-full" />
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div className={cn(authFormClass, className)}>
|
|
150
|
+
<AuthHeader eyebrow={eyebrow} title={title} description={description} />
|
|
151
|
+
<form
|
|
152
|
+
noValidate
|
|
153
|
+
aria-label="Create account"
|
|
154
|
+
className="flex flex-col gap-4"
|
|
155
|
+
onSubmit={(e) => {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
setSubmitted(true);
|
|
158
|
+
if (fields !== undefined) {
|
|
159
|
+
setSubmitCount((count) => count + 1);
|
|
160
|
+
if (summaryErrors.length > 0) return;
|
|
161
|
+
const values = Object.fromEntries(fields.map((field) => [field.id, fieldValue(field.id).trim()]));
|
|
162
|
+
void run(() =>
|
|
163
|
+
onSubmit?.({ name: values.name ?? '', email: values.email ?? '', password, fields: values }),
|
|
164
|
+
);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (
|
|
168
|
+
name.trim() === '' ||
|
|
169
|
+
!EMAIL_RE.test(email.trim()) ||
|
|
170
|
+
password.length < minPasswordLength ||
|
|
171
|
+
(termsProp !== false && !terms)
|
|
172
|
+
)
|
|
173
|
+
return;
|
|
174
|
+
void run(() => onSubmit?.({ name: name.trim(), email: email.trim(), password }));
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
{alert && <Alert tone="destructive" description={alert} />}
|
|
178
|
+
{fields !== undefined && submitted && (
|
|
179
|
+
// Destructive text needs an untinted surface to meet contrast in the light theme.
|
|
180
|
+
<ValidationSummary errors={summaryErrors} submitCount={submitCount} className="bg-background" />
|
|
181
|
+
)}
|
|
182
|
+
{fields !== undefined ? (
|
|
183
|
+
fields.map((field) => {
|
|
184
|
+
const message = authSignUpFieldError(fieldValue(field.id), field);
|
|
185
|
+
const invalid = submitted && message !== null;
|
|
186
|
+
return (
|
|
187
|
+
<Field key={field.id} invalid={invalid}>
|
|
188
|
+
<FieldLabel>{field.label}</FieldLabel>
|
|
189
|
+
<Input
|
|
190
|
+
id={`${fieldPrefix}-field-${field.id}`}
|
|
191
|
+
type={field.type ?? 'text'}
|
|
192
|
+
autoComplete={field.autoComplete}
|
|
193
|
+
placeholder={field.placeholder}
|
|
194
|
+
required={field.required}
|
|
195
|
+
value={fieldValue(field.id)}
|
|
196
|
+
onValueChange={(value) => setFieldValues((values) => ({ ...values, [field.id]: value }))}
|
|
197
|
+
/>
|
|
198
|
+
{field.help != null && <FieldDescription>{field.help}</FieldDescription>}
|
|
199
|
+
<FieldError match={invalid}>{message}</FieldError>
|
|
200
|
+
</Field>
|
|
201
|
+
);
|
|
202
|
+
})
|
|
203
|
+
) : (
|
|
204
|
+
<>
|
|
205
|
+
<Field invalid={nameInvalid}>
|
|
206
|
+
<FieldLabel>Full name</FieldLabel>
|
|
207
|
+
<Input
|
|
208
|
+
leadingIcon={User}
|
|
209
|
+
autoComplete="name"
|
|
210
|
+
placeholder="Avery Collins"
|
|
211
|
+
value={name}
|
|
212
|
+
onValueChange={setName}
|
|
213
|
+
required
|
|
214
|
+
/>
|
|
215
|
+
<FieldError match={nameInvalid}>Enter your name.</FieldError>
|
|
216
|
+
</Field>
|
|
217
|
+
<Field invalid={emailInvalid}>
|
|
218
|
+
<FieldLabel>Work email</FieldLabel>
|
|
219
|
+
<Input
|
|
220
|
+
type="email"
|
|
221
|
+
leadingIcon={Mail}
|
|
222
|
+
autoComplete="email"
|
|
223
|
+
placeholder="name@company.com"
|
|
224
|
+
value={email}
|
|
225
|
+
onValueChange={setEmail}
|
|
226
|
+
required
|
|
227
|
+
/>
|
|
228
|
+
<FieldError match={emailInvalid}>Enter a valid email address.</FieldError>
|
|
229
|
+
</Field>
|
|
230
|
+
</>
|
|
231
|
+
)}
|
|
232
|
+
<Field invalid={passwordInvalid}>
|
|
233
|
+
<FieldLabel>Password</FieldLabel>
|
|
234
|
+
<PasswordInput
|
|
235
|
+
id={fields !== undefined ? passwordId : undefined}
|
|
236
|
+
showStrength
|
|
237
|
+
strength={password.length > 0 && password.length < minPasswordLength ? 0 : undefined}
|
|
238
|
+
value={password}
|
|
239
|
+
onValueChange={setPassword}
|
|
240
|
+
required
|
|
241
|
+
/>
|
|
242
|
+
{passwordHelp != null && (
|
|
243
|
+
<FieldDescription>
|
|
244
|
+
{typeof passwordHelp === 'function' ? passwordHelp(minPasswordLength) : passwordHelp}
|
|
245
|
+
</FieldDescription>
|
|
246
|
+
)}
|
|
247
|
+
<FieldError match={passwordInvalid}>{passwordError}</FieldError>
|
|
248
|
+
</Field>
|
|
249
|
+
{termsProp !== false && (
|
|
250
|
+
<div>
|
|
251
|
+
<Checkbox
|
|
252
|
+
render={fields !== undefined ? <span id={termsId} /> : undefined}
|
|
253
|
+
checked={terms}
|
|
254
|
+
onCheckedChange={setTerms}
|
|
255
|
+
aria-invalid={termsInvalid || undefined}
|
|
256
|
+
aria-describedby={termsInvalid ? termsErrorId : undefined}
|
|
257
|
+
label={
|
|
258
|
+
<>
|
|
259
|
+
I agree to the <Link href={termsHref}>Terms</Link> and <Link href={privacyHref}>Privacy Policy</Link>.
|
|
260
|
+
</>
|
|
261
|
+
}
|
|
262
|
+
/>
|
|
263
|
+
{termsInvalid && (
|
|
264
|
+
<p id={termsErrorId} className="mt-1.5 text-[12.5px] text-destructive-text">
|
|
265
|
+
{termsError}
|
|
266
|
+
</p>
|
|
267
|
+
)}
|
|
268
|
+
</div>
|
|
269
|
+
)}
|
|
270
|
+
<Button type="submit" size="lg" loading={busy} className="mt-2 w-full">
|
|
271
|
+
Create account
|
|
272
|
+
</Button>
|
|
273
|
+
</form>
|
|
274
|
+
{sso != null && (
|
|
275
|
+
<>
|
|
276
|
+
<AuthDivider>Or sign up with</AuthDivider>
|
|
277
|
+
{sso}
|
|
278
|
+
</>
|
|
279
|
+
)}
|
|
280
|
+
<p className="mt-7 text-center text-[13px] text-muted-foreground">
|
|
281
|
+
Already have an account?{' '}
|
|
282
|
+
<Link
|
|
283
|
+
href={signInHref}
|
|
284
|
+
onClick={
|
|
285
|
+
onSignIn
|
|
286
|
+
? (e: MouseEvent) => {
|
|
287
|
+
e.preventDefault();
|
|
288
|
+
onSignIn();
|
|
289
|
+
}
|
|
290
|
+
: undefined
|
|
291
|
+
}
|
|
292
|
+
>
|
|
293
|
+
Sign in
|
|
294
|
+
</Link>
|
|
295
|
+
</p>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BlockMeta } from '../../meta';
|
|
2
|
+
|
|
3
|
+
export const meta: BlockMeta = {
|
|
4
|
+
name: 'Sign-up form',
|
|
5
|
+
family: 'auth',
|
|
6
|
+
status: 'stable',
|
|
7
|
+
description:
|
|
8
|
+
'Account creation with default name/email fields or ordered text/email fields (values.fields), a password strength meter and required consent (terms=false opts out). minPasswordLength defaults to 8 and drives length validation and the insufficient-length meter; optional passwordHelp can receive the minimum. Configured fields support help, required, autoComplete and validation messages, with a linked validation summary on invalid submit. policyLoading renders skeletons without a form; unavailable replaces the form with consumer title, message and optional action. loading remains submitting; error is form-level feedback. Examples: custom-fields, no-terms, unavailable, loading, submitting and error.',
|
|
9
|
+
uses: [
|
|
10
|
+
'Field',
|
|
11
|
+
'Input',
|
|
12
|
+
'PasswordInput',
|
|
13
|
+
'Checkbox',
|
|
14
|
+
'Button',
|
|
15
|
+
'Alert',
|
|
16
|
+
'Link',
|
|
17
|
+
'SsoButtons',
|
|
18
|
+
'Skeleton',
|
|
19
|
+
'FieldDescription',
|
|
20
|
+
'ValidationSummary',
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SignUpForm } from '../SignUpForm';
|
|
2
|
+
|
|
3
|
+
/** Ordered text/email fields, kit validation, and values.fields keyed by these ids. */
|
|
4
|
+
export default function CustomFields() {
|
|
5
|
+
return (
|
|
6
|
+
<SignUpForm
|
|
7
|
+
sso={null}
|
|
8
|
+
minPasswordLength={12}
|
|
9
|
+
passwordHelp={(minimum) => `Use at least ${minimum} characters.`}
|
|
10
|
+
fields={[
|
|
11
|
+
{
|
|
12
|
+
id: 'username',
|
|
13
|
+
label: 'Username',
|
|
14
|
+
placeholder: 'Account name',
|
|
15
|
+
help: 'Choose your account name.',
|
|
16
|
+
required: true,
|
|
17
|
+
type: 'text',
|
|
18
|
+
autoComplete: 'username',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'displayName',
|
|
22
|
+
label: 'Display name',
|
|
23
|
+
placeholder: 'Avery Collins',
|
|
24
|
+
help: 'The name others will see.',
|
|
25
|
+
required: true,
|
|
26
|
+
autoComplete: 'name',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'email',
|
|
30
|
+
label: 'Email',
|
|
31
|
+
placeholder: 'you@example.com',
|
|
32
|
+
help: 'For account notifications.',
|
|
33
|
+
required: true,
|
|
34
|
+
type: 'email',
|
|
35
|
+
autoComplete: 'email',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'tenant',
|
|
39
|
+
label: 'Tenant identifier',
|
|
40
|
+
placeholder: 'Organization',
|
|
41
|
+
help: 'Your organization identifier.',
|
|
42
|
+
required: true,
|
|
43
|
+
autoComplete: 'off',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'workspace',
|
|
47
|
+
label: 'Workspace identifier',
|
|
48
|
+
placeholder: 'Workspace',
|
|
49
|
+
help: 'Optional. Leave empty to choose later.',
|
|
50
|
+
required: false,
|
|
51
|
+
autoComplete: 'off',
|
|
52
|
+
},
|
|
53
|
+
]}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SignUpForm } from '../SignUpForm';
|
|
2
|
+
|
|
3
|
+
/** Explicit opt-out; omitting terms continues to require consent. */
|
|
4
|
+
export default function NoTerms() {
|
|
5
|
+
return <SignUpForm terms={false} sso={null} passwordHelp={(minimum) => `Use at least ${minimum} characters.`} />;
|
|
6
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Link } from '@gntik-ai/ui';
|
|
2
|
+
import { SignUpForm } from '../SignUpForm';
|
|
3
|
+
|
|
4
|
+
/** No account creation form or submit control while self-service is unavailable. */
|
|
5
|
+
export default function Unavailable() {
|
|
6
|
+
return (
|
|
7
|
+
<SignUpForm
|
|
8
|
+
unavailable={{
|
|
9
|
+
title: 'Registration unavailable',
|
|
10
|
+
message: 'Contact your administrator to request an account.',
|
|
11
|
+
action: <Link href="mailto:admin@example.com">Request access</Link>,
|
|
12
|
+
}}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { expectNoAxeViolations } from '../../test/a11y';
|
|
4
|
+
import { SsoButtons } from './SsoButtons';
|
|
5
|
+
|
|
6
|
+
describe('SsoButtons', () => {
|
|
7
|
+
it('renders the default providers in a named group', async () => {
|
|
8
|
+
const { container } = render(<SsoButtons />);
|
|
9
|
+
expect(screen.getByRole('group', { name: 'Single sign-on' })).toBeInTheDocument();
|
|
10
|
+
expect(screen.getByRole('button', { name: 'Continue with SSO' })).toBeInTheDocument();
|
|
11
|
+
await expectNoAxeViolations(container);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('reports the chosen provider and shows its loading state', async () => {
|
|
15
|
+
const onSelect = vi.fn();
|
|
16
|
+
const { rerender } = render(<SsoButtons onSelect={onSelect} />);
|
|
17
|
+
await userEvent.click(screen.getByRole('button', { name: 'Continue with Google' }));
|
|
18
|
+
expect(onSelect).toHaveBeenCalledWith('google');
|
|
19
|
+
rerender(<SsoButtons onSelect={onSelect} loadingId="google" />);
|
|
20
|
+
expect(screen.getByRole('button', { name: 'Continue with Google' })).toHaveAttribute('aria-busy', 'true');
|
|
21
|
+
expect(screen.getByRole('button', { name: 'Continue with SSO' })).toBeDisabled();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Button, cn } from '@gntik-ai/ui';
|
|
2
|
+
import { ssoProviders, type SsoProvider } from './fixtures';
|
|
3
|
+
|
|
4
|
+
export type { SsoProvider } from './fixtures';
|
|
5
|
+
|
|
6
|
+
export interface SsoButtonsProps {
|
|
7
|
+
providers?: SsoProvider[];
|
|
8
|
+
/** Called with the provider id. */
|
|
9
|
+
onSelect?: (providerId: string) => void;
|
|
10
|
+
/** Provider currently redirecting (shows a spinner and disables the others). */
|
|
11
|
+
loadingId?: string | null;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** `stack` (full-width rows, default) or `grid` (two columns from `sm`). */
|
|
14
|
+
layout?: 'stack' | 'grid';
|
|
15
|
+
/** Accessible name of the group. */
|
|
16
|
+
label?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Neutral single-sign-on buttons: text labels and lucide icons, no brand colours or logos. */
|
|
21
|
+
export function SsoButtons({
|
|
22
|
+
providers = ssoProviders,
|
|
23
|
+
onSelect,
|
|
24
|
+
loadingId = null,
|
|
25
|
+
disabled = false,
|
|
26
|
+
layout = 'stack',
|
|
27
|
+
label = 'Single sign-on',
|
|
28
|
+
className,
|
|
29
|
+
}: SsoButtonsProps) {
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
role="group"
|
|
33
|
+
aria-label={label}
|
|
34
|
+
className={cn('grid gap-2.5', layout === 'grid' && 'sm:grid-cols-2', className)}
|
|
35
|
+
>
|
|
36
|
+
{providers.map((p) => (
|
|
37
|
+
<Button
|
|
38
|
+
key={p.id}
|
|
39
|
+
variant="secondary"
|
|
40
|
+
size="lg"
|
|
41
|
+
icon={p.icon}
|
|
42
|
+
loading={loadingId === p.id}
|
|
43
|
+
disabled={disabled || (loadingId != null && loadingId !== p.id)}
|
|
44
|
+
onClick={() => onSelect?.(p.id)}
|
|
45
|
+
className="w-full text-[13.5px] font-medium"
|
|
46
|
+
>
|
|
47
|
+
{p.label}
|
|
48
|
+
</Button>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BlockMeta } from '../../meta';
|
|
2
|
+
|
|
3
|
+
export const meta: BlockMeta = {
|
|
4
|
+
name: 'SSO buttons',
|
|
5
|
+
family: 'auth',
|
|
6
|
+
status: 'stable',
|
|
7
|
+
description: 'Neutral "Continue with …" provider buttons with lucide icons and a per-provider loading state.',
|
|
8
|
+
uses: ['Button'],
|
|
9
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Building2, Globe, KeyRound, type LucideIcon } from '@gntik-ai/icons';
|
|
2
|
+
|
|
3
|
+
export interface SsoProvider {
|
|
4
|
+
id: string;
|
|
5
|
+
/** Full button text, e.g. "Continue with SSO". */
|
|
6
|
+
label: string;
|
|
7
|
+
/** A neutral lucide icon (no brand logos or colours). */
|
|
8
|
+
icon?: LucideIcon;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ssoProviders: SsoProvider[] = [
|
|
12
|
+
{ id: 'sso', label: 'Continue with SSO', icon: Building2 },
|
|
13
|
+
{ id: 'google', label: 'Continue with Google', icon: Globe },
|
|
14
|
+
{ id: 'passkey', label: 'Continue with a passkey', icon: KeyRound },
|
|
15
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './ForgotPasswordForm/ForgotPasswordForm';
|
|
2
|
+
export { meta as forgotPasswordFormMeta } from './ForgotPasswordForm/block.meta';
|
|
3
|
+
export * from './MfaChallenge/MfaChallenge';
|
|
4
|
+
export { meta as mfaChallengeMeta } from './MfaChallenge/block.meta';
|
|
5
|
+
export * from './ResetPasswordForm/ResetPasswordForm';
|
|
6
|
+
export { meta as resetPasswordFormMeta } from './ResetPasswordForm/block.meta';
|
|
7
|
+
export * from './SignInForm/SignInForm';
|
|
8
|
+
export { meta as signInFormMeta } from './SignInForm/block.meta';
|
|
9
|
+
export * from './SignUpForm/SignUpForm';
|
|
10
|
+
export { meta as signUpFormMeta } from './SignUpForm/block.meta';
|
|
11
|
+
export * from './SsoButtons/SsoButtons';
|
|
12
|
+
export { meta as ssoButtonsMeta } from './SsoButtons/block.meta';
|
|
13
|
+
export { ssoProviders } from './SsoButtons/fixtures';
|
|
14
|
+
export { AuthHeader, AuthDivider, type AuthHeaderProps } from './shared';
|
|
15
|
+
export type { AuthIdentifierConfig, AuthValidationMessages, AuthFormAccessibilityProps } from './shared';
|
|
16
|
+
export type { AuthSignUpField, AuthUnavailableState, AuthSignUpValidationMessages } from './shared';
|