mick-templates 1.1.2 → 1.1.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/app.tsx +48 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mick-templates",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "CLI tool for creating projects from templates",
5
5
  "bin": {
6
6
  "mick-templates": "bin/cli.js"
package/src/app.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from "react";
1
+ import React, { useState, useEffect, useCallback } from "react";
2
2
  import { readdirSync, existsSync } from "fs";
3
3
  import { LanguageSelect } from "./components/LanguageSelect.js";
4
4
  import { OverwritePrompt } from "./components/OverwritePrompt.js";
@@ -14,13 +14,47 @@ interface Props {
14
14
  skipInstall?: boolean;
15
15
  }
16
16
 
17
- export function App({ template, projectName, language: initialLang, skipInstall = false }: Props) {
17
+ export function App({
18
+ template,
19
+ projectName,
20
+ language: initialLang,
21
+ skipInstall = false,
22
+ }: Props) {
18
23
  const [step, setStep] = useState<Step>("processing");
19
24
  const [language, setLanguage] = useState<Language | undefined>(initialLang);
25
+ const [isCreating, setIsCreating] = useState(false);
20
26
  const [targetDir, setTargetDir] = useState("");
21
27
  const [error, setError] = useState("");
22
28
 
23
- const needsOverwrite = !projectName && existsSync(process.cwd()) && readdirSync(process.cwd()).length > 0;
29
+ const needsOverwrite =
30
+ !projectName &&
31
+ existsSync(process.cwd()) &&
32
+ readdirSync(process.cwd()).length > 0;
33
+
34
+ const runCreate = useCallback(
35
+ async (lang: Language, overwrite: boolean) => {
36
+ if (isCreating) return;
37
+ setIsCreating(true);
38
+ setStep("processing");
39
+ try {
40
+ const dir = await createProject({
41
+ template,
42
+ projectName,
43
+ language: lang,
44
+ overwrite,
45
+ skipInstall,
46
+ });
47
+ setTargetDir(dir);
48
+ setStep("done");
49
+ } catch (e) {
50
+ setError(e instanceof Error ? e.message : String(e));
51
+ setStep("error");
52
+ } finally {
53
+ setIsCreating(false);
54
+ }
55
+ },
56
+ [isCreating, template, projectName, skipInstall]
57
+ );
24
58
 
25
59
  useEffect(() => {
26
60
  // Determine initial step
@@ -34,37 +68,26 @@ export function App({ template, projectName, language: initialLang, skipInstall
34
68
  return;
35
69
  }
36
70
 
37
- // Don't run if we're waiting for user input
38
- if (step === "language" || step === "overwrite") return;
71
+ // Don't run if we're waiting for user input or already creating
72
+ if (
73
+ step === "language" ||
74
+ step === "overwrite" ||
75
+ isCreating ||
76
+ step === "done" ||
77
+ step === "error"
78
+ )
79
+ return;
39
80
 
40
81
  // Create project
41
82
  runCreate(language, false);
42
- }, [language]);
43
-
44
- const runCreate = async (lang: Language, overwrite: boolean) => {
45
- setStep("processing");
46
- try {
47
- const dir = await createProject({
48
- template,
49
- projectName,
50
- language: lang,
51
- overwrite,
52
- skipInstall,
53
- });
54
- setTargetDir(dir);
55
- setStep("done");
56
- } catch (e) {
57
- setError(e instanceof Error ? e.message : String(e));
58
- setStep("error");
59
- }
60
- };
83
+ }, [language, step, isCreating, needsOverwrite, runCreate]);
61
84
 
62
85
  const handleLanguageSelect = (lang: Language) => {
63
86
  setLanguage(lang);
64
87
  if (needsOverwrite) {
65
88
  setStep("overwrite");
66
89
  } else {
67
- runCreate(lang, false);
90
+ setStep("processing");
68
91
  }
69
92
  };
70
93
 
@@ -85,4 +108,3 @@ export function App({ template, projectName, language: initialLang, skipInstall
85
108
 
86
109
  return <Status status={step} targetDir={targetDir} error={error} />;
87
110
  }
88
-