1- import * as React from 'react'
2- import { useCurrentFramework } from './FrameworkSelect'
3- import { useLocalStorage } from '~/utils/useLocalStorage'
1+ import { useLocalCurrentFramework } from './FrameworkSelect'
2+ import { useCurrentUserQuery } from '~/hooks/useCurrentUser'
3+ import { useParams } from '@tanstack/react-router'
4+ import { create } from 'zustand'
45import { Tabs , type TabDefinition } from './Tabs'
56import { CodeBlock } from './CodeBlock'
67import type { Framework } from '~/libraries/types'
78
89type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'
910type InstallMode = 'install' | 'dev-install'
1011
12+ // Use zustand for cross-component synchronization
13+ // This ensures all PackageManagerTabs instances on the page stay in sync
14+ const usePackageManagerStore = create < {
15+ packageManager : PackageManager
16+ setPackageManager : ( pm : PackageManager ) => void
17+ } > ( ( set ) => ( {
18+ packageManager :
19+ typeof document !== 'undefined'
20+ ? ( localStorage . getItem ( 'packageManager' ) as PackageManager ) || 'npm'
21+ : 'npm' ,
22+ setPackageManager : ( pm : PackageManager ) => {
23+ localStorage . setItem ( 'packageManager' , pm )
24+ set ( { packageManager : pm } )
25+ } ,
26+ } ) )
27+
1128type PackageManagerTabsProps = {
1229 id : string
13- packagesByFramework : Record < string , string >
30+ packagesByFramework : Record < string , string [ ] >
1431 mode : InstallMode
1532 frameworks : Framework [ ]
1633}
@@ -19,51 +36,74 @@ const PACKAGE_MANAGERS: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun']
1936
2037function getInstallCommand (
2138 packageManager : PackageManager ,
22- packages : string ,
39+ packages : string [ ] ,
2340 mode : InstallMode ,
24- ) : string {
41+ ) : string [ ] {
42+ const commands : string [ ] = [ ]
43+
2544 if ( mode === 'dev-install' ) {
45+ for ( const pkg of packages ) {
46+ switch ( packageManager ) {
47+ case 'npm' :
48+ commands . push ( `npm i -D ${ pkg } ` )
49+ break
50+ case 'pnpm' :
51+ commands . push ( `pnpm add -D ${ pkg } ` )
52+ break
53+ case 'yarn' :
54+ commands . push ( `yarn add -D ${ pkg } ` )
55+ break
56+ case 'bun' :
57+ commands . push ( `bun add -d ${ pkg } ` )
58+ break
59+ }
60+ }
61+ return commands
62+ }
63+
64+ // install mode
65+ for ( const pkg of packages ) {
2666 switch ( packageManager ) {
2767 case 'npm' :
28- return `npm i -D ${ packages } `
68+ commands . push ( `npm i ${ pkg } ` )
69+ break
2970 case 'pnpm' :
30- return `pnpm add -D ${ packages } `
71+ commands . push ( `pnpm add ${ pkg } ` )
72+ break
3173 case 'yarn' :
32- return `yarn add -D ${ packages } `
74+ commands . push ( `yarn add ${ pkg } ` )
75+ break
3376 case 'bun' :
34- return `bun add -d ${ packages } `
77+ commands . push ( `bun add ${ pkg } ` )
78+ break
3579 }
3680 }
37-
38- // install mode
39- switch ( packageManager ) {
40- case 'npm' :
41- return `npm i ${ packages } `
42- case 'pnpm' :
43- return `pnpm add ${ packages } `
44- case 'yarn' :
45- return `yarn add ${ packages } `
46- case 'bun' :
47- return `bun add ${ packages } `
48- }
81+ return commands
4982}
5083
5184export function PackageManagerTabs ( {
5285 id,
5386 packagesByFramework,
5487 mode,
55- frameworks,
5688} : PackageManagerTabsProps ) {
57- const { framework : currentFramework } = useCurrentFramework ( frameworks )
58- const [ storedPackageManager , setStoredPackageManager ] =
59- useLocalStorage < PackageManager > ( 'packageManager' , PACKAGE_MANAGERS [ 0 ] )
89+ const { packageManager : storedPackageManager , setPackageManager } =
90+ usePackageManagerStore ( )
91+
92+ const { framework : paramsFramework } = useParams ( { strict : false } )
93+ const localCurrentFramework = useLocalCurrentFramework ( )
94+ const userQuery = useCurrentUserQuery ( )
95+ const userFramework = userQuery . data ?. lastUsedFramework
96+
97+ const actualFramework = ( paramsFramework ||
98+ userFramework ||
99+ localCurrentFramework . currentFramework ||
100+ 'react' ) as Framework
60101
61- // Normalize framework key to lowercase for lookup
62- const normalizedFramework = currentFramework . toLowerCase ( )
102+ const normalizedFramework = actualFramework . toLowerCase ( )
63103 const packages = packagesByFramework [ normalizedFramework ]
64104
65105 // Hide component if current framework not in package list
66- if ( ! packages ) {
106+ if ( ! packages || packages . length === 0 ) {
67107 return null
68108 }
69109
@@ -81,10 +121,11 @@ export function PackageManagerTabs({
81121
82122 // Generate children (command blocks) for each package manager
83123 const children = PACKAGE_MANAGERS . map ( ( pm ) => {
84- const command = getInstallCommand ( pm , packages , mode )
124+ const commands = getInstallCommand ( pm , packages , mode )
125+ const commandText = commands . join ( '\n' )
85126 return (
86127 < CodeBlock key = { pm } >
87- < code className = "language-bash" > { command } </ code >
128+ < code className = "language-bash" > { commandText } </ code >
88129 </ CodeBlock >
89130 )
90131 } )
@@ -95,7 +136,7 @@ export function PackageManagerTabs({
95136 tabs = { tabs }
96137 children = { children }
97138 activeSlug = { selectedPackageManager }
98- onTabChange = { ( slug ) => setStoredPackageManager ( slug as PackageManager ) }
139+ onTabChange = { ( slug ) => setPackageManager ( slug as PackageManager ) }
99140 />
100141 )
101142}
0 commit comments