Skip to content

Commit 011bbb6

Browse files
committed
feat: add support for python package managers and minor ui improvements
1 parent a50b70a commit 011bbb6

File tree

7 files changed

+180
-27
lines changed

7 files changed

+180
-27
lines changed

README.md

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Visit the [Storybook](https://react-install-command.vercel.app/) for examples an
1010

1111
## Features
1212

13-
- 🚀 Support for major package managers (npm, Yarn, pnpm, Bun, Deno).
13+
- 🚀 Support for major package managers (npm, Yarn, pnpm, Bun, Deno, uv, pip).
1414
- 🌓 Dark, light and system theme support out of the box.
1515
- 🔄 Interactive tab switching between package managers.
1616
- 📋 One-click copy to clipboard.
@@ -78,7 +78,7 @@ import { InstallCommand } from 'react-install-command';
7878
<InstallCommand
7979
packageName="react"
8080
registry="npm"
81-
managers={[defaultManagers[4]]} // Only Deno manager
81+
managers={[javascriptManagers[4]]} // Only Deno manager
8282
/>
8383

8484
// Mixed registry packages
@@ -87,6 +87,44 @@ import { InstallCommand } from 'react-install-command';
8787
/>
8888
```
8989

90+
### Python Package Managers
91+
92+
```tsx
93+
// Using Python managers (uv, pip)
94+
<InstallCommand
95+
packageName="requests"
96+
managers={pythonManagers}
97+
/>
98+
99+
// Python dev dependency
100+
<InstallCommand
101+
packageName="pytest"
102+
managers={pythonManagers}
103+
isDev
104+
/>
105+
106+
// Python package with version
107+
<InstallCommand
108+
packageName="django"
109+
managers={pythonManagers}
110+
version="4.2.0"
111+
/>
112+
113+
// Python package with tag
114+
<InstallCommand
115+
packageName="fastapi"
116+
managers={pythonManagers}
117+
tag="latest"
118+
/>
119+
120+
// Python global installation
121+
<InstallCommand
122+
packageName="black"
123+
managers={pythonManagers}
124+
isGlobal
125+
/>
126+
```
127+
90128
### Theming
91129

92130
```tsx
@@ -138,9 +176,24 @@ import { InstallCommand } from 'react-install-command';
138176
<InstallCommand
139177
packageName="react"
140178
managers={[
141-
defaultManagers[2], // pnpm first
142-
defaultManagers[0], // npm second
143-
defaultManagers[1], // yarn third
179+
javascriptManagers[2], // pnpm first
180+
javascriptManagers[0], // npm second
181+
javascriptManagers[1], // yarn third
182+
]}
183+
/>
184+
185+
// Using Python managers
186+
<InstallCommand
187+
packageName="requests"
188+
managers={pythonManagers}
189+
/>
190+
191+
// Mixed JavaScript and Python managers
192+
<InstallCommand
193+
packageName="react"
194+
managers={[
195+
...javascriptManagers.slice(0, 2), // npm, yarn
196+
...pythonManagers // uv, pip
144197
]}
145198
/>
146199
```
@@ -327,7 +380,7 @@ Then use it in your component:
327380
| tag | string | undefined | Tag for the package |
328381
| registry | "npm" \| "jsr" | undefined | Package registry to use (for Deno packages) |
329382
| theme | "light" \| "dark" \| "system" | "system" | The color theme to use |
330-
| managers | Manager[] | defaultManagers | Array of package managers to display |
383+
| managers | Manager[] | javascriptManagers | Array of package managers to display |
331384
| customCommands | Record<string, string> | undefined | Custom commands to override the defaults |
332385
| slots | Slots | {} | Custom slot components for rendering |
333386
| slotClassNames | SlotClassNames | {} | Custom classNames for each slot |
@@ -363,6 +416,31 @@ interface Manager {
363416
}
364417
```
365418

419+
### Available Package Managers
420+
421+
The component provides pre-configured manager arrays:
422+
423+
- `javascriptManagers`: npm, Yarn, pnpm, Bun, Deno
424+
- `pythonManagers`: uv, pip
425+
426+
You can import these arrays:
427+
428+
```tsx
429+
import { javascriptManagers, pythonManagers } from 'react-install-command';
430+
431+
// Use JavaScript managers (default)
432+
<InstallCommand packageName="react" managers={javascriptManagers} />
433+
434+
// Use Python managers
435+
<InstallCommand packageName="requests" managers={pythonManagers} />
436+
437+
// Mix managers
438+
<InstallCommand
439+
packageName="react"
440+
managers={[...javascriptManagers.slice(0, 2), ...pythonManagers]}
441+
/>
442+
```
443+
366444
### Slots
367445

368446
```typescript

docs/readme.png

-68.9 KB
Binary file not shown.

src/InstallCommand.test.tsx

Whitespace-only changes.

src/InstallCommand.tsx

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface Manager {
2121
useShorthand?: boolean;
2222
version?: string;
2323
tag?: string;
24-
registry?: "npm" | "jsr";
24+
registry?: "npm" | "jsr" | "pypi";
2525
},
2626
) => string;
2727
}
@@ -92,7 +92,7 @@ export const defaultCopyIcon = () => (
9292
/>
9393
);
9494

95-
export const defaultManagers: Manager[] = [
95+
export const javascriptManagers: Manager[] = [
9696
{
9797
id: "npm",
9898
name: "npm",
@@ -189,11 +189,12 @@ export const defaultManagers: Manager[] = [
189189
tag,
190190
} = options;
191191

192+
const command = useShorthand ? "i" : "install";
192193
const flags = [
194+
isDev && (useShorthand ? "-D" : "--save-dev"),
195+
isPeer && "--save-peer",
196+
isOptional && "--save-optional",
193197
isGlobal && "-g",
194-
isDev && "-D",
195-
isPeer && "-P",
196-
isOptional && "-O",
197198
]
198199
.filter(Boolean)
199200
.join(" ");
@@ -204,7 +205,7 @@ export const defaultManagers: Manager[] = [
204205
? `${pkg}@${tag}`
205206
: pkg;
206207

207-
return `pnpm add${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
208+
return `pnpm ${command}${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
208209
},
209210
},
210211
{
@@ -219,13 +220,22 @@ export const defaultManagers: Manager[] = [
219220
/>
220221
),
221222
getCommand: (pkg: string, options) => {
222-
const { isDev, isPeer, isOptional, isGlobal, version, tag } = options;
223+
const {
224+
isDev,
225+
isPeer,
226+
isOptional,
227+
isGlobal,
228+
useShorthand,
229+
version,
230+
tag,
231+
} = options;
223232

233+
const command = useShorthand ? "i" : "install";
224234
const flags = [
225-
isGlobal && "-g",
226-
isDev && "-d",
235+
isDev && (useShorthand ? "-d" : "--dev"),
227236
isPeer && "--peer",
228237
isOptional && "--optional",
238+
isGlobal && "-g",
229239
]
230240
.filter(Boolean)
231241
.join(" ");
@@ -236,7 +246,7 @@ export const defaultManagers: Manager[] = [
236246
? `${pkg}@${tag}`
237247
: pkg;
238248

239-
return `bun add${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
249+
return `bun ${command}${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
240250
},
241251
},
242252
{
@@ -279,6 +289,59 @@ export const defaultManagers: Manager[] = [
279289
},
280290
];
281291

292+
export const pythonManagers: Manager[] = [
293+
{
294+
id: "uv",
295+
name: "uv",
296+
icon: () => (
297+
<Icon
298+
icon="catppuccin:uv"
299+
width={24}
300+
height={24}
301+
aria-label="uv package manager"
302+
/>
303+
),
304+
getCommand: (pkg: string, options) => {
305+
const { isDev, isGlobal, version, tag } = options;
306+
307+
const flags = [isDev && "--dev"].filter(Boolean).join(" ");
308+
309+
const pkgWithVersion = version
310+
? `${pkg}==${version}`
311+
: tag
312+
? `${pkg}@${tag}`
313+
: pkg;
314+
315+
return `uv add${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
316+
},
317+
},
318+
{
319+
id: "pip",
320+
name: "pip",
321+
icon: () => (
322+
<Icon
323+
icon="logos:python"
324+
width={24}
325+
height={24}
326+
aria-label="pip package manager"
327+
/>
328+
),
329+
getCommand: (pkg: string, options) => {
330+
const { isDev, isGlobal, version, tag } = options;
331+
332+
const flags = [].filter(Boolean).join(" ");
333+
334+
const pkgWithVersion = version
335+
? `${pkg}==${version}`
336+
: tag
337+
? `${pkg}@${tag}`
338+
: pkg;
339+
340+
return `pip install${flags ? ` ${flags}` : ""} ${pkgWithVersion}`;
341+
},
342+
},
343+
];
344+
282345
export const defaultSlots = {
283346
root: ({ children, className }: SlotProps) => (
284347
<div className={cn("install-block", className)}>{children}</div>
@@ -431,11 +494,11 @@ export interface InstallCommandProps {
431494
* Package registry to use (for Deno packages)
432495
* @default undefined
433496
*/
434-
registry?: "npm" | "jsr";
497+
registry?: "npm" | "jsr" | "pypi";
435498

436499
/**
437500
* Array of package managers to display
438-
* @default defaultManagers
501+
* @default javascriptManagers
439502
*/
440503
managers?: Manager[];
441504

@@ -515,7 +578,7 @@ export const InstallCommand = ({
515578
version,
516579
tag,
517580
registry,
518-
managers = defaultManagers,
581+
managers = javascriptManagers,
519582
customCommands,
520583
slots = {},
521584
slotClassNames = {},

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ export type {
1010
SlotClassNames,
1111
StorageType,
1212
} from "./InstallCommand";
13-
export { defaultManagers, cn } from "./InstallCommand";
13+
export { javascriptManagers, pythonManagers, cn } from "./InstallCommand";

src/stories/InstallCommand.stories.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import "../styles.css";
33
import { Icon } from "@iconify/react";
44
import type { Meta, StoryObj } from "@storybook/react";
55
import type { ReactNode } from "react";
6-
import { InstallCommand, type Manager, cn, defaultManagers } from "..";
6+
import {
7+
InstallCommand,
8+
type Manager,
9+
cn,
10+
javascriptManagers,
11+
pythonManagers,
12+
} from "..";
713
import { ComponentScreenshot } from "../ComponentScreenshot";
814

915
// Define types for the manager options
@@ -15,7 +21,7 @@ interface ManagerOptions {
1521
useShorthand?: boolean;
1622
version?: string;
1723
tag?: string;
18-
registry?: "npm" | "jsr";
24+
registry?: "npm" | "jsr" | "pypi";
1925
}
2026

2127
// Define types for slot props
@@ -142,6 +148,13 @@ export const SpecificTag: Story = {
142148
},
143149
};
144150

151+
export const PythonInstall: Story = {
152+
args: {
153+
packageName,
154+
managers: pythonManagers,
155+
},
156+
};
157+
145158
// Complex installation example
146159
export const ComplexInstallation: Story = {
147160
args: {
@@ -164,9 +177,9 @@ export const CustomDefaultManager: Story = {
164177
args: {
165178
packageName: "react",
166179
managers: [
167-
defaultManagers[2], // pnpm
168-
defaultManagers[0], // npm
169-
defaultManagers[1], // yarn
180+
javascriptManagers[2], // pnpm
181+
javascriptManagers[0], // npm
182+
javascriptManagers[1], // yarn
170183
],
171184
},
172185
parameters: {
@@ -293,7 +306,7 @@ export const DenoNpmPackage: Story = {
293306
args: {
294307
packageName: "react",
295308
registry: "npm",
296-
managers: [defaultManagers[4]], // Only Deno manager
309+
managers: [javascriptManagers[4]], // Only Deno manager
297310
},
298311
parameters: {
299312
docs: {

src/styles.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@
223223
}
224224

225225
.install-block-text-command {
226-
font-weight: 600;
227226
color: var(--primary);
228227
}
229228

0 commit comments

Comments
 (0)