chore(ui): Layer architecture for <ConfigureSSO />#8493
chore(ui): Layer architecture for <ConfigureSSO />#8493iagodahlem wants to merge 30 commits intomainfrom
<ConfigureSSO />#8493Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 80a1933 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
aee336b to
1e69b19
Compare
…rActions context Adds a parallel wizard primitive at packages/ui/src/components/ConfigureSSO/elements/Wizard/, copied verbatim from packages/ui/src/components/ConfigureSSO/wizard/, then refactored: - Renamed exports from ConfigureSSOWizard / useConfigureSSOWizard to Wizard / useWizard. - Split FooterActionsContext from WizardContext. WizardContext owns navigation only (activeSteps, currentStep, goNext, goPrev, isLoading). FooterActionsContext owns step-action registration (continueAction, setContinueAction, chrome stack registry). - Stripped UI from the Wizard root: removed Header, Footer, StepIndicator, Body, and helpers. Wizard now provides context + step extraction + active-step rendering only. Header and Footer will be added back as ConfigureSSO layout components in a follow-up. - Preserved nested-wizard URL scoping via Option (a): the Wizard root keeps a Switch with a Route per step, so each Route children get a scoped RouteContext for nested wizards. Step itself stays a null-returning descriptor (its children are harvested by extractSteps and rendered inside the Switch). This stays close to the existing shape and avoids requiring a free-floating Route from Step. Laura's existing wizard/ folder is untouched and still in use by ConfigureSSO.tsx. The new elements/Wizard/ is dormant until ConfigureSSO.tsx switches over in a later commit.
The Wizard primitive renders step children directly inside each Route, with no Col wrapper and no element descriptors. Layout sizing belongs to the host's ConfigureSSO layout component, and per-step descriptors belong to each step's own root element — neither is the wizard's concern.
Extracts the numbered breadcrumb rendering from the existing wizard Header into a presentational primitive at packages/ui/src/components/ ConfigureSSO/elements/Breadcrumbs/. The primitive takes items, currentIndex, and onItemClick — no awareness of the wizard or its context. Wires existing element descriptors (configureSSOWizardHeader*) through to the same DOM elements they covered in the old Header.
Replaces the items/currentIndex prop pair with `<Breadcrumbs.Item>` children and a `currentId` prop on the parent. Mirrors the pattern used by `<Wizard>` / `<Wizard.Step>` in the same component folder. Breadcrumbs walks its children via an extractItems helper (with fragment support) and computes the active index from `currentId` internally. Reachability logic, element descriptors, and the visual rendering are unchanged.
Adds three new top-level components under packages/ui/src/components/ ConfigureSSO/ that consume the wizard primitive and the breadcrumbs primitive: - ConfigureSSOLayout: ProfileCard shell with the navbar sidebar and a body Col that owns the flex sizing for the wizard's step output. - ConfigureSSOHeader: thin wrapper that drives the declarative Breadcrumbs primitive from the wizard's active steps + currentStep. - ConfigureSSOFooter: shared Previous / Continue footer that dispatches to the deepest mounted wizard via the FooterActions context registry. Nothing wires these in yet — that swap lands in a follow-up commit.
Removes the shared StepLayout wrapper from each step file and inlines the header (Heading + subtitle) plus body Col directly. Each step now owns its own visual chrome: - ProvideEmailStep, VerifyDomainStep, ConfigureCreateAppStep, TestConfigurationStep render their own header row and body. - ConfirmationStep drops the header entirely per the Figma design. Step files also switch wizard hook imports from the old wizard/ folder to the new elements/Wizard/ primitive, and each step attaches its own configureSSOWizardBody descriptor at its outermost rendered element. Flow.Part does not accept elementDescriptor / elementId props, so each step uses the fallback shape: a Col wrapper inside Flow.Part carries the descriptor. The wrapper Col keeps flex: 1 / minHeight: 0 so the inner body Col's flex: 1 / overflowY: auto continues to size against the layout's flex column context. useRegisterContinueAction usage is unchanged in this commit; the move to a Wizard.Step canContinue prop lands separately. The shared StepLayout file is left on disk (no more imports) and gets removed in a final cleanup commit.
Wires the new ConfigureSSO surface into the layered components shipped in the previous commits: - ConfigureSSO.tsx adopts the new shape — Flow.Part wrap inside Flow.Root for convention parity with OrganizationProfile, an initial load gate at the root that returns a centered spinner inside ConfigureSSOLayout, and a FooterActionsProvider wrap around the layout. The inline ProfileCard / NavBar / Col chrome moves out; ConfigureSSOLayout owns it now. - ConfigureSSOSteps switches its wizard imports from the old wizard/ folder to the new elements/Wizard/ primitive. The declarative step tree shape is preserved. - isLoading is lifted out of ConfigureSSOFlowContext and out of the wizard's context value. The root-level gate handles initial loading; subsequent re-fetches no longer flip the wizard into a loading state in context. ConfigureSSOFooter drops the isLoading-driven disable. - The Wizard primitive no longer imports useConfigureSSOFlow — it's a fully generic primitive at the navigation layer now. - The unused legacy wizard folder also drops its isLoading reads (spinner branch in Body, skeleton in Header, force-disable in Footer) so the typechecker stays clean while it sits on disk. The old wizard/ folder is unused after this commit but stays on disk for a final cleanup commit.
Replaces the route-based wizard primitive with a state-driven version:
- Wizard renders {children} directly. Header, Footer, and step
descriptors all render as siblings inside the wizard scope. The
Switch / Route / useRouter routing layer is gone.
- Wizard.Step is a self-rendering component now: it registers itself
with the parent wizard via useLayoutEffect on mount, then renders
its children only when its id matches the wizard's currentStep.
Inactive steps render null.
- Active-step state is internal — first registered step becomes the
default; goNext / goPrev / goToStep mutate that state. Nested
wizards still bubble to parent.goNext on inner-last-step continue.
- Step descriptors no longer carry a path; navigation is purely by id.
- Footer now reads the deepest wizard's value from reactive context
state (not a ref), so navigation inside a nested wizard re-renders
the Footer and isFirstStep / isLastStep stay in sync.
Also picks up earlier in-flight work in ConfigureSSO: rename
ConfigureSSOLayout to ConfigureSSOCard (the inner Col flex wrapper
was dropped — the body Col on the card scrollbox owns sizing now),
and Header / Steps / Footer mount as siblings inside the wizard
scope so the breadcrumb and footer chrome render alongside the
active step body.
Splits the navbar chrome into ConfigureSSONavbar so the layout composition is more readable. Adds a ConfigureSSOSkeleton that mirrors the live shell — breadcrumb placeholders, centered content spinner, disabled footer buttons — used by the initial-load gate. Drops the orphaned ConfigureSSOCard (replaced by inline ProfileCard.Root + the new navbar component). Adjusts breadcrumb bullet sizing and the separator caret to match the latest visual direction.
- Add elements/ProfileCard with ProfileCardHeader + ProfileCardFooter primitives (semantic <header>/<footer>, border + padding chrome). - ConfigureSSOHeader, ConfigureSSOFooter, and ConfigureSSOSkeleton wrap their content in the new primitives instead of inlining the Flex chrome. - Breadcrumbs primitive trimmed: outer Flex no longer renders its own border / padding (lives in ProfileCardHeader now). Bullet refined — neutralAlpha400 background, foreground-on-completed label color, white check, number wrapped in Text for color contrast. Descriptor placement flagged with TODOs for the cleanup sweep. - Wrap the wizard tree in ConfigureSSOFlowProvider so steps can read enterpriseConnection state. - VerifyDomainStep's placeholder isDisabled commented out for manual step-navigation testing until verification ships.
Renames the wizard's step-indicator primitive to its conventional name (Stepper). Strips state derivation from the primitive so it's purely presentational: - elements/Breadcrumbs/* moves to elements/Stepper/*. Types are renamed accordingly; the BreadcrumbsActiveItem internal type is dropped. - The Stepper container no longer walks its children to extract descriptors — children-as-array is used only to insert the chevron separator between items. - Stepper.Item becomes a fully self-rendering component. It takes label, bullet (ReactNode — caller passes the number or check icon), isCurrent, isCompleted, isReachable, and onClick. The primitive doesn't compute reachability or pick the bullet shape. - ConfigureSSOHeader takes ownership of the wizard → stepper mapping: reads useWizard() for activeSteps + currentStep, computes per-item flags, decides whether to render the check or the index number in the bullet, and wires onClick to goToStep. Visual rendering is identical. Descriptor placement is left for the final descriptor sweep (todo comments preserved where Iago left them).
Extends the elements/ProfileCard.tsx primitive set: - ProfileCardBody: <main>-semantic scrollable container that sits between header and footer in the card layout. Adds flex sizing and overflowY:auto. - ProfileCardSection: titled-or-untitled content block. Optionally takes localized title + subtitle. Multiple sections can stack inside a single ProfileCardBody. Confirmation step uses the no-title shape per Figma. Refactors all five ConfigureSSO step files to render their body content via these primitives instead of inlining the Heading + subtitle + body Col chrome. Each step is now noticeably shorter and the visual chrome lives in one place. Per-step descriptor wrapping (configureSSOWizardBody) is left in place — descriptor placement migration is a separate cleanup pass.
Adds a compound Skeleton on the Stepper that renders a placeholder
stepper given a totalSteps count. Each placeholder item mirrors the
real Stepper.Item layout (bullet + label) with washed-out
neutralAlpha100 backgrounds, with a same-tone chevron separator
between items.
ConfigureSSOSkeleton drops its inline BreadcrumbItemSkeleton and
BreadcrumItemIconSkeleton helpers in favor of
<Stepper.Skeleton totalSteps={4} />. The two skeleton helpers were
internalized to the Stepper module — they're not exported.
…ining steps
- Renames steps/StepLayout.tsx to steps/Step.tsx and compounds the
four primitives under a single Step namespace: Step is the layout
wrapper, Step.Section is the padded content block, Step.Header is
the section variant with the bottom-border title row, Step.Body is
the section variant for the scrollable main area. Mirrors the
Stepper.Item / Stepper.Skeleton pattern.
- Fixes sx-merging in Step / Step.Section / Step.Body by adopting
the codebase's array-form pattern (sx={[default, userSx]}). The
previous spread-into-object approach broke when a function-form sx
was passed and Step.Body silently dropped user sx entirely.
- Refactors ProvideEmailStep, ConfigureCreateAppStep,
TestConfigurationStep, and ConfirmationStep to the same shape
VerifyDomainStep already uses: <Step><Step.Header /><Step.Body /></Step>
with the per-step descriptor on the outer Step wrapper.
Confirmation drops the header per Figma; Body provides its own
padding.
- Promotes the Step compound primitive to packages/ui/src/components/ ConfigureSSO/elements/Step.tsx — it lives alongside the other shared step-level primitives (Stepper, ProfileCard) instead of inside the steps/ folder. - Updates all five step files to import Step from ../elements/Step. - Drops ProfileCardBody and ProfileCardSection from elements/ProfileCard.tsx — those responsibilities now live on Step.Body and Step.Section, so the ProfileCard module is back to just Header and Footer chrome. - ConfigureSSOSkeleton calls Stepper.Skeleton without an explicit totalSteps; the default of 4 is used.
Replace flat `colorMutedForeground` background with the shared `common.mutedBackground` helper for visual consistency with other muted surfaces.
Each step now renders its own <Step.Footer />. The shared ConfigureSSOFooter and the FooterActionsContext registry that backed it (continueAction state, the deepest-mounted-wizard stack with push/pop/publishWizardValue, and useRegisterContinueAction) are all gone. The Wizard primitive simplifies accordingly: no more wrapping the outermost wizard in FooterActionsProvider, no more registering each wizard's value into a chrome stack. useWizard().goNext already handles nested fall-through via parentWizard?.goNext, so a step rendered inside a nested wizard has its <Step.Footer />'s useWizard() naturally point at the right wizard — no out-of-band ref needed. Step.Footer is added as a compound member of Step in elements/Step.tsx alongside Section/Header/Body. It reads useWizard for sane defaults (goNext, goPrev, isFirstStep, isLastStep) and accepts override props for the cases that need them (continueDisabled, continueLoading, onContinue, hidePrevious, etc.). All five step files updated. Confirmation uses <Step.Footer hideContinue /> since it's the last step. ConfigureSSOFooter and elements/Wizard/FooterActionsContext are deleted.
Keeps the footer at a consistent height even when its buttons are hidden or replaced — useful for step-specific footer compositions that may render different button sets per step.
Replaces the prop-heavy Step.Footer (with previousLabel / continueLabel / hidePrevious / hideContinue / *Disabled / *Loading / on*) with a compound primitive set: - Step.Footer is now a thin wrapper around ProfileCardFooter that accepts arbitrary children. - Step.Footer.Previous and Step.Footer.Continue are purely presentational buttons (no useWizard, no defaults). Each accepts onClick, isDisabled, isLoading, and optional label. Each step destructures useWizard at the top and wires goNext / goPrev / isFirstStep / isLastStep into the buttons explicitly. Confirmation drops the Continue button entirely. ConfigureSSOSkeleton also adopts Step.Footer with both buttons disabled — the skeleton now mirrors the live shell using the same primitives, with no wizard context required. The whole footer surface is reusable outside the wizard now and shrinks dramatically at the call site.
The verify-email-domain step now has a single outer wrapper that owns the Flow.Part + Step + Step.Header chrome. The two inner sub-steps (ProvideEmail and VerifyEmailAddress) are content-only (Step.Body + Step.Footer) and share the outer header through an inner Wizard. Step.Header sits inside the inner Wizard so its descendants — specifically the new Step.Counter — see the inner wizard's state. - VerifyDomainStep.tsx is renamed to VerifyEmailAddressStep.tsx to free the outer name and clarify what the inner content actually does (verify the user's email address as proof of domain ownership). Both inner files now render only the body + footer for their sub-screen. - New VerifyEmailDomainStep.tsx is the outer step. It reads the user's primary email address, conditionally renders the ProvideEmail sub-step, and always renders the VerifyEmailAddressStep sub-step. - ConfigureSSO.tsx drops its useUser read and the inline inner Wizard for verify-email-domain — the outer step encapsulates both. The Configure outer step keeps its inline inner Wizard for now (single sub-step there). Adds Step.Counter as a pure-UI compound member (takes total + current numbers, auto-hides when total <= 1). Step.Header now positions its children as the right-side slot of the title row, matching the original Laura layout.
Reorganizes the steps directory and rebalances responsibilities between Step.Body and Step.Section: - The verify-domain wrapper, ProvideEmailStep, and the inner email-verification screen all live in a single VerifyDomainStep.tsx file. The renamed inner screen is EnterVerificationCodeStep — its job is the actual code entry; the wrapper handles the shared header and provider routing. - The configure outer step is consolidated into a single ConfigureStep component (no inner wizard yet — it's a single screen for now). ConfigureCreateAppStep is gone. - Step.Body becomes a scrollable container with no padding — pure flex+scroll wrapper. Steps that want padded content add a Step.Section inside Body. ConfirmationStep and TestConfigurationStep adopt the new Step.Body + Step.Section shape. - ConfigureSSO.tsx updates the wizard tree: outer step ids are verify-domain / configure / test / confirmation. The verify-domain step renders the new VerifyDomainStep wrapper directly; configure step renders ConfigureStep directly (no inline inner wizard).
…ections Adds a separate Step.Section for the test SSO URL with a bottom border divider, and updates the placeholder text in the existing section to indicate test results.
Wrap wizard steps in a single Step.Body at the VerifyDomainStep level instead of duplicating Step.Body inside each inner step. Inner steps (ProvideEmail, EnterVerificationCode) now render Step.Section directly with flex/center alignment, matching the layout used in ConfirmationStep.
Adds the Select Provider step at the top of the ConfigureSSO wizard tree. The step is structurally a regular wizard step — same Step chrome, same goNext / goPrev mechanics, same per-step descriptor — but ConfigureSSOHeader filters it out of the breadcrumb by id so it doesn't appear in the Stepper. When the user is on Select Provider, no breadcrumb bullet is highlighted (currentIndex resolves to -1 against the filtered list, all items render muted) — matches the design intent. The step body is placeholder UI for now. The provider tile selection, the FlowProvider integration, and the initial-step derivation all land separately when we actually build the Select Provider screen.
The wizard now accepts an optional initialStepId prop. When passed, that becomes the active step on mount; when omitted, the existing "first registered step becomes default" behavior is preserved. This is the hook the host needs to land server-derived initial step logic later — e.g., ConfigureSSO computing the initial step from the user's enterprise connection state. Hosts that don't pass it work unchanged.
Removes the trailing period from the description text in the SelectProvider and VerifyDomain wizard steps for consistency.
2987dc3 to
7f84287
Compare
Removes the ConfigureSSOSteps wrapper and renders the Wizard.Step children directly inside the Wizard. Also sets the initial step to `configure` so the wizard opens on the configuration step.
<ConfigureSSO />
Adds a patch-level changeset for @clerk/ui covering the layered primitive refactor on <__experimental_ConfigureSSO />. Also reverts the sandbox template's local-dev publishable key back to the original value tracked in main.
Delete the wizard subdirectory under ConfigureSSO, including ConfigureSSOWizard, ConfigureSSOWizardContext, types, and index, now that the wizard steps have been inlined into the parent component.
Let the Wizard fall back to its default first step instead of forcing the `configure` step on mount.
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
📝 WalkthroughWalkthroughThis PR refactors the experimental Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ui/src/components/ConfigureSSO/elements/ProfileCard.tsx`:
- Line 4: The type alias ProfileCardHeaderProps uses React.PropsWithChildren but
the React namespace isn't imported; import PropsWithChildren from 'react' and
update the type to use PropsWithChildren (or keep React.PropsWithChildren but
ensure React is imported) so the ProfileCardHeaderProps definition and any
usages compile without TS2304; search for ProfileCardHeaderProps and the
ProfileCard component in ProfileCard.tsx to apply the import and type fix.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: c35dd481-dca7-44f9-9bb6-4cacc4aef0f0
📒 Files selected for processing (29)
.changeset/wizard-architecture-layers.mdpackages/ui/src/components/ConfigureSSO/ConfigureSSO.tsxpackages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsxpackages/ui/src/components/ConfigureSSO/ConfigureSSOHeader.tsxpackages/ui/src/components/ConfigureSSO/ConfigureSSONavbar.tsxpackages/ui/src/components/ConfigureSSO/ConfigureSSOSkeleton.tsxpackages/ui/src/components/ConfigureSSO/elements/ProfileCard.tsxpackages/ui/src/components/ConfigureSSO/elements/Step.tsxpackages/ui/src/components/ConfigureSSO/elements/Stepper/Stepper.tsxpackages/ui/src/components/ConfigureSSO/elements/Stepper/index.tspackages/ui/src/components/ConfigureSSO/elements/Stepper/types.tspackages/ui/src/components/ConfigureSSO/elements/Wizard/Wizard.tsxpackages/ui/src/components/ConfigureSSO/elements/Wizard/WizardContext.tsxpackages/ui/src/components/ConfigureSSO/elements/Wizard/index.tspackages/ui/src/components/ConfigureSSO/elements/Wizard/types.tspackages/ui/src/components/ConfigureSSO/steps/ConfigureCreateAppStep.tsxpackages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsxpackages/ui/src/components/ConfigureSSO/steps/ConfirmationStep.tsxpackages/ui/src/components/ConfigureSSO/steps/ProvideEmailStep.tsxpackages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsxpackages/ui/src/components/ConfigureSSO/steps/StepLayout.tsxpackages/ui/src/components/ConfigureSSO/steps/TestConfigurationStep.tsxpackages/ui/src/components/ConfigureSSO/steps/VerifyDomainStep.tsxpackages/ui/src/components/ConfigureSSO/steps/index.tspackages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizard.tsxpackages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizardContext.tsxpackages/ui/src/components/ConfigureSSO/wizard/index.tspackages/ui/src/components/ConfigureSSO/wizard/types.tspackages/ui/src/elements/contexts/index.tsx
💤 Files with no reviewable changes (7)
- packages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizardContext.tsx
- packages/ui/src/components/ConfigureSSO/wizard/types.ts
- packages/ui/src/components/ConfigureSSO/wizard/index.ts
- packages/ui/src/components/ConfigureSSO/steps/ConfigureCreateAppStep.tsx
- packages/ui/src/components/ConfigureSSO/steps/StepLayout.tsx
- packages/ui/src/components/ConfigureSSO/steps/ProvideEmailStep.tsx
- packages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizard.tsx
| import { descriptors, Flex } from '@/customizables'; | ||
| import { common } from '@/styledSystem'; | ||
|
|
||
| type ProfileCardHeaderProps = React.PropsWithChildren; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if any other tsx/ts files in this package use React.PropsWithChildren without a React import
rg -l 'React\.PropsWithChildren' --type=ts --type=tsx | head -20
rg -n 'React\.PropsWithChildren' --type=ts 2>/dev/null | head -20
rg -n 'React\.PropsWithChildren' -g '*.tsx' | head -20
# Check if files that use React.PropsWithChildren also import React
rg -l 'React\.PropsWithChildren' -g '*.tsx' | xargs -I{} sh -c 'echo "=== {} ==="; head -5 {}'Repository: clerk/javascript
Length of output: 19549
🏁 Script executed:
cat -n packages/ui/src/components/ConfigureSSO/elements/ProfileCard.tsxRepository: clerk/javascript
Length of output: 1452
🏁 Script executed:
cat packages/ui/tsconfig.jsonRepository: clerk/javascript
Length of output: 1134
🏁 Script executed:
cat packages/ui/src/global.d.tsRepository: clerk/javascript
Length of output: 767
🏁 Script executed:
# Check if there's a React ambient global declaration or if `@types/react` has export as namespace
cat packages/ui/src/global.d.ts | head -20
# Check if there's a root tsconfig or other global.d.ts files
fd global.d.ts packages/
# Check package.json for `@types/react`
grep -A 5 -B 5 '@types/react' packages/ui/package.jsonRepository: clerk/javascript
Length of output: 1232
🏁 Script executed:
cat packages/ui/package.json | grep -A 10 -B 2 '@types/react'Repository: clerk/javascript
Length of output: 42
🏁 Script executed:
cat packages/ui/package.json | head -50Repository: clerk/javascript
Length of output: 1491
🏁 Script executed:
cat packages/ui/package.json | grep -E '"(dependencies|devDependencies|peerDependencies)"' -A 20Repository: clerk/javascript
Length of output: 1466
🏁 Script executed:
# Verify that TypeScript would error on this by checking if there's any build configuration that adds ambient React
# Also check the root tsconfig or any type roots
cat tsconfig.json 2>/dev/null | head -30 || echo "No root tsconfig"Repository: clerk/javascript
Length of output: 732
🏁 Script executed:
# Let's verify that the code would actually fail to compile by checking if there's a build output or error
# Also check ConfigureSSONavbar.tsx to confirm it properly imports React
head -15 packages/ui/src/components/ConfigureSSO/ConfigureSSONavbar.tsxRepository: clerk/javascript
Length of output: 699
Import PropsWithChildren from 'react' to fix TypeScript compilation error.
Lines 4 and 20 reference React.PropsWithChildren without importing the React namespace. The jsx: react-jsx setting in tsconfig only enables JSX syntax without importing React—it does not make React.* available as a namespace. This causes a TS2304: Cannot find name 'React' error.
🔧 Proposed fix
+import { type PropsWithChildren } from 'react';
import { descriptors, Flex } from '@/customizables';
import { common } from '@/styledSystem';
-type ProfileCardHeaderProps = React.PropsWithChildren;
+type ProfileCardHeaderProps = PropsWithChildren;
// ...
-type ProfileCardFooterProps = React.PropsWithChildren;
+type ProfileCardFooterProps = PropsWithChildren;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| type ProfileCardHeaderProps = React.PropsWithChildren; | |
| type ProfileCardHeaderProps = PropsWithChildren; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ui/src/components/ConfigureSSO/elements/ProfileCard.tsx` at line 4,
The type alias ProfileCardHeaderProps uses React.PropsWithChildren but the React
namespace isn't imported; import PropsWithChildren from 'react' and update the
type to use PropsWithChildren (or keep React.PropsWithChildren but ensure React
is imported) so the ProfileCardHeaderProps definition and any usages compile
without TS2304; search for ProfileCardHeaderProps and the ProfileCard component
in ProfileCard.tsx to apply the import and type fix.
|
|
||
| return ( | ||
| <Flex | ||
| // TODO: add descriptor |
There was a problem hiding this comment.
Do you think it's feasible to add descriptors on this PR? or on a follow up?
| sx={theme => ({ | ||
| gap: theme.space.$1x5, | ||
| padding: 0, | ||
| color: isCurrent || isCompleted ? theme.colors.$colorForeground : theme.colors.$colorMutedForeground, |
There was a problem hiding this comment.
Should we already introduce the "green mark" style for the step item here, if completed? Also can do in a follow up
Summary
Refactors the
<__experimental_ConfigureSSO />UI surface into a layered architecture that separates the navigation primitive (Wizard) from the layout primitives (Step, Stepper, ProfileCard) from the per-step content. No public component API change — the<__experimental_ConfigureSSO />export keeps its current shape.Why
The wizard primitive that landed in #8468 ships a working declarative API plus an imperative
useRegisterContinueActionregistry, but it owns its own chrome (Header, Footer, Body), couples step gating to a wizard-wideFooterActionsContext, and runs URL routing throughSwitch/Route. That made the breadcrumb non-reusable, blocked per-step footer customization, and required adeepestWizardworkaround to dispatch correctly across nested wizards.This PR reshapes the surface so each layer has a single job:
Switch/Route, no URL coupling. Steps register themselves viauseLayoutEffectand render self when active.goNext/goPrevbubble through nested wizards naturally.<Stepper.Item>is a self-rendering button + bullet + label.<Stepper.Skeleton>mirrors it for the loading state.Step.Header,Step.Body,Step.Section,Step.Counter,Step.FooterwithFooter.Previous/Footer.Continue). All UI-only, no wizard coupling — the same primitives drive the live shell and the skeleton.<header>/<footer>chrome with the consistent border + padding the surface uses.The host (
ConfigureSSO.tsx) wires the layers together. Each step file is short, opinionated about its own behavior, and assembles the primitives from above.What changed
New primitives at
packages/ui/src/components/ConfigureSSO/elements/:Wizard/— state-driven, children-rendering wizard with an optionalinitialStepId+Wizard.Stepregistration viauseLayoutEffect. Drops the previous routing layer entirely.Stepper/— declarative<Stepper>+<Stepper.Item>+<Stepper.Skeleton>. The container only handles flex layout + separator insertion between items; current/completed/reachable computation moves to the host.Step.tsx— the<Step>layout wrapper plus the compound members listed above. The Footer button compounds (Step.Footer.Previous,Step.Footer.Continue) take their ownonClick/isDisabled/isLoadingprops — nouseWizardinside, which is why the same Footer primitives work inConfigureSSOSkeleton.ProfileCard.tsx— header / footer chrome.Surface-level wiring:
ConfigureSSO.tsxadopts the new shape end-to-end. The inline ProfileCard + NavBar layout collapses into composed primitives. The wizard's old internal chrome is gone.ConfigureSSOHeaderreadsuseWizard()and maps the active steps into<Stepper.Item>s; it also filtersselect-providerout of the breadcrumb by id.useWizard()directly, owns its own<Step.Footer>with explicitgoPrev/goNexthandlers, and renders its body viaStep.Body+Step.Section.SelectProviderStepboilerplate is added as the first wizard step. It's filtered out of the breadcrumb inConfigureSSOHeaderby id (nohiddenflag on the wizard primitive — kept the primitive clean). Real provider-tile UI lands separately.FooterActionsContextregistry (push / pop /deepestWizardplumbing) is gone — per-step footer rendering removes the need for it.Out of scope — planned follow-ups
FlowProvider.providerstatederiveInitialStep(connection)and wiring toWizard.initialStepId// TODO: add descriptorcomments mark the placementsPrevious/Continue/Step X / YTest plan
<__experimental_ConfigureSSO />end-to-end with the placeholder contentStep.Counterdoesn't render (single inner step → badge auto-hides)ConfigureSSOSkeletononce on cold start; subsequent re-fetches don't re-trigger the full skeletonType of change