generator-bitloops 0.3.8 → 0.3.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-bitloops",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Next.js with TypeScript, Tailwind, Storybook and Cypress generator by Bitloops",
5
5
  "license": "MIT",
6
6
  "author": "Bitloops S.A.",
package/setup/index.js CHANGED
@@ -8,9 +8,11 @@ import { fileURLToPath } from 'url';
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
 
11
-
12
11
  function toKebabCase(str) {
13
- return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase().replace(/\s+/g, '-');
12
+ return str
13
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
14
+ .toLowerCase()
15
+ .replace(/\s+/g, '-');
14
16
  }
15
17
 
16
18
  export default class extends Generator {
@@ -68,7 +70,7 @@ export default class extends Generator {
68
70
  default: false,
69
71
  });
70
72
 
71
- this.installNextJS = async function() {
73
+ this.installNextJS = async function () {
72
74
  // Clone Next.js template with Tailwind if specified, using the project name
73
75
  const createNextAppCommand = ['-y', 'create-next-app@14.2.16'];
74
76
  createNextAppCommand.push(toKebabCase(this.options.project)); // Use the project name for the directory
@@ -80,52 +82,71 @@ export default class extends Generator {
80
82
  createNextAppCommand.push('@/*');
81
83
  createNextAppCommand.push('--use-npm');
82
84
  createNextAppCommand.push('--eslint');
83
-
85
+
84
86
  if (this.options.typescript) {
85
87
  createNextAppCommand.push('--typescript'); // This will avoid the TypeScript prompt
86
88
  } else {
87
89
  createNextAppCommand.push('--js');
88
90
  }
89
-
91
+
90
92
  if (this.options.tailwind) {
91
93
  createNextAppCommand.push('--tailwind');
92
94
  }
93
-
94
- this.log("Installing Next.js...");
95
- const patchPackages = '';//'next@14 react@18 react-dom@18';
95
+
96
+ this.log('Installing Next.js...');
97
+ const patchPackages = ''; //'next@14 react@18 react-dom@18';
96
98
  const additionalPackages = `react-tooltip ${patchPackages}`;
97
- await new Promise((resolve, error) => {exec(`npx ${createNextAppCommand.join(' ')} && cd ${toKebabCase(this.options.project)} && npm install ${additionalPackages}`).on('exit', (code) => {
98
- this.destinationRoot(this.destinationPath(toKebabCase(this.options.project)));
99
- resolve();
100
- });});
101
- }
99
+ await new Promise((resolve, error) => {
100
+ exec(
101
+ `npx ${createNextAppCommand.join(' ')} && cd ${toKebabCase(
102
+ this.options.project
103
+ )} && npm install ${additionalPackages}`
104
+ ).on('exit', (code) => {
105
+ this.destinationRoot(
106
+ this.destinationPath(toKebabCase(this.options.project))
107
+ );
108
+ resolve();
109
+ });
110
+ });
111
+ };
102
112
 
103
- this.installStorybook = function() {
113
+ this.installStorybook = function () {
104
114
  // Conditionally initialize Storybook
105
115
  if (this.options.storybook) {
106
116
  this.log('Installing Storybook...');
107
- this.spawnCommandSync('npx', ['-y', 'storybook@^8.4', 'init', '--no-dev']);
117
+ this.spawnCommandSync('npx', [
118
+ '-y',
119
+ 'storybook@^8.4',
120
+ 'init',
121
+ '--no-dev',
122
+ ]);
108
123
  this.log('Storybook installed!');
109
124
  // if (this.options.tailwind && this.options.storybook) {
110
125
  // Tailwind CSS specific setup for older versions of Storybook
111
126
  // this.spawnCommandSync('npx', ['storybook@latest', 'add', '@storybook/addon-styling-webpack']);
112
127
  // }
113
128
  }
114
- }
115
-
116
- this.installCypress = function() {
129
+ };
130
+
131
+ this.installCypress = function () {
117
132
  // Conditionally add Cypress
118
133
  if (this.options.cypress) {
119
134
  this.log('Installing Cypress...');
120
135
  this.spawnCommandSync('npm', ['install', '--save-dev', 'cypress']);
121
136
  this.log('Cypress installed!');
122
137
  if (this.options.bitloops) {
123
- this.spawnCommandSync('npm', ['install', '--save-dev', 'mochawesome', 'mochawesome-merge', 'mochawesome-report-generator']);
138
+ this.spawnCommandSync('npm', [
139
+ 'install',
140
+ '--save-dev',
141
+ 'mochawesome',
142
+ 'mochawesome-merge',
143
+ 'mochawesome-report-generator',
144
+ ]);
124
145
  }
125
146
  }
126
- }
127
-
128
- this.patchFiles = async function() {
147
+ };
148
+
149
+ this.patchFiles = async function () {
129
150
  // Conditionally initialize Storybook
130
151
  if (this.options.storybook) {
131
152
  this.log('Making Storybook changes...');
@@ -134,102 +155,134 @@ export default class extends Generator {
134
155
  this.log('Setting up Tailwind CSS with Storybook...');
135
156
  this.fs.copyTpl(
136
157
  this.templatePath('storybook.preview.ts'),
137
- this.destinationPath('.storybook/preview.ts'),
138
- );
158
+ this.destinationPath('.storybook/preview.ts')
159
+ );
139
160
  }
140
161
  this.log('Removing default Storybook stories...');
141
162
  try {
142
- fs.rmSync(this.destinationPath('src/stories'), { recursive: true, force: true });
163
+ fs.rmSync(this.destinationPath('src/stories'), {
164
+ recursive: true,
165
+ force: true,
166
+ });
143
167
  console.log('Sample stories directory deleted successfully!');
144
168
  } catch (err) {
145
- console.error('Error deleting sample stories directory:', err);
169
+ console.error('Error deleting sample stories directory:', err);
146
170
  }
147
171
  fs.unlinkSync(this.destinationPath('tailwind.config.ts'));
148
172
  this.fs.copyTpl(
149
173
  this.templatePath('tailwind.config.ts'),
150
- this.destinationPath('tailwind.config.ts'),
174
+ this.destinationPath('tailwind.config.ts')
151
175
  );
152
176
  }
153
-
177
+
154
178
  if (this.options.cypress) {
155
179
  this.log('Adding Cypress config...');
156
180
  this.fs.copyTpl(
157
181
  this.templatePath('cypress.config.ts'),
158
- this.destinationPath('cypress.config.ts'),
159
- );
182
+ this.destinationPath('cypress.config.ts')
183
+ );
160
184
  }
161
-
185
+
162
186
  fs.unlinkSync(this.destinationPath('src/app/page.tsx'));
163
187
  this.fs.copyTpl(
164
188
  this.templatePath('next.app.page.tsx'),
165
- this.destinationPath('src/app/page.tsx'),
166
- );
167
-
189
+ this.destinationPath('src/app/page.tsx')
190
+ );
191
+
168
192
  fs.unlinkSync(this.destinationPath('src/app/layout.tsx'));
169
193
  this.fs.copyTpl(
170
194
  this.templatePath('next.app.layout.tsx'),
171
195
  this.destinationPath('src/app/layout.tsx'),
172
- { projectName: this.options.project },
196
+ { projectName: this.options.project }
173
197
  );
174
-
198
+
175
199
  this.log('Adding Meyer reset in global.css...');
176
200
  fs.unlinkSync(this.destinationPath('src/app/globals.css'));
177
201
  this.fs.copyTpl(
178
202
  this.templatePath('globals.css'),
179
- this.destinationPath('src/app/globals.css'),
180
- );
203
+ this.destinationPath('src/app/globals.css')
204
+ );
181
205
 
182
206
  if (this.options.bitloops) {
183
207
  this.log('Adding Bitloops support components...');
184
- const path = 'src/components/bitloops/Unsupported.tsx';
208
+ const unsupportedPath =
209
+ 'src/components/bitloops/unsupported/Unsupported.tsx';
210
+ this.fs.copyTpl(
211
+ this.templatePath(unsupportedPath),
212
+ this.destinationPath(unsupportedPath)
213
+ );
214
+ const buttonPath = 'src/components/bitloops/button/Button.tsx';
185
215
  this.fs.copyTpl(
186
- this.templatePath(path),
187
- this.destinationPath(path),
188
- );
216
+ this.templatePath(buttonPath),
217
+ this.destinationPath(buttonPath)
218
+ );
189
219
  if (this.options.storybook) {
190
- const path = 'src/components/bitloops/Unsupported.stories.tsx';
220
+ const unsupportedPath =
221
+ 'src/components/bitloops/unsupported/Unsupported.stories.tsx';
191
222
  this.fs.copyTpl(
192
- this.templatePath(path),
193
- this.destinationPath(path),
194
- );
223
+ this.templatePath(unsupportedPath),
224
+ this.destinationPath(unsupportedPath)
225
+ );
226
+ const buttonPath =
227
+ 'src/components/bitloops/button/Button.stories.tsx';
228
+ this.fs.copyTpl(
229
+ this.templatePath(buttonPath),
230
+ this.destinationPath(buttonPath)
231
+ );
195
232
  }
196
233
  if (this.options.cypress) {
197
234
  const path = 'cypress/helpers/index.ts';
198
- this.fs.copyTpl(
199
- this.templatePath(path),
200
- this.destinationPath(path),
201
- );
235
+ this.fs.copyTpl(this.templatePath(path), this.destinationPath(path));
202
236
  }
237
+ this.spawnCommandSync('npm', [
238
+ 'install',
239
+ '--save-dev',
240
+ 'react-aria-components',
241
+ ]);
203
242
  }
204
- }
243
+ };
205
244
 
206
- this.commitChanges = async function() {
245
+ this.commitChanges = async function () {
207
246
  this.log('Committing changes to git...');
208
- await new Promise((resolve) => {exec(`cd ${toKebabCase(this.options.project)} && git add . && git commit -m "Initial setup"`).on('exit', (code) => {
209
- if (code !== 0) {
210
- this.log('Error committing changes to git! ', code);
247
+ await new Promise((resolve) => {
248
+ exec(
249
+ `cd ${toKebabCase(
250
+ this.options.project
251
+ )} && git add . && git commit -m "Initial setup"`
252
+ ).on('exit', (code) => {
253
+ if (code !== 0) {
254
+ this.log('Error committing changes to git! ', code);
255
+ resolve();
256
+ }
257
+ this.log('Git changes committed!');
211
258
  resolve();
212
- }
213
- this.log('Git changes committed!');
214
- resolve();
215
- });});
216
- }
259
+ });
260
+ });
261
+ };
217
262
  }
218
263
 
219
264
  initializing() {
220
265
  // Check if the project name and --nextjs flag are provided
221
266
  if (!this.options.project) {
222
- this.log("Error: --project option is required to specify the project name.");
267
+ this.log(
268
+ 'Error: --project option is required to specify the project name.'
269
+ );
223
270
  process.exit(1);
224
271
  }
225
272
 
226
273
  if (!this.options.nextjs) {
227
- this.log("Error: --nextjs option is currently required to scaffold a project.");
274
+ this.log(
275
+ 'Error: --nextjs option is currently required to scaffold a project.'
276
+ );
228
277
  process.exit(1);
229
278
  }
230
279
 
231
- this.log(`Initializing project ${toKebabCase(this.options.project)} with the selected options...`);
232
- }
280
+ this.log(
281
+ `Initializing project ${toKebabCase(
282
+ this.options.project
283
+ )} with the selected options...`
284
+ );
285
+ }
233
286
 
234
287
  async main() {
235
288
  await this.installNextJS();
@@ -242,12 +295,21 @@ export default class extends Generator {
242
295
  }
243
296
 
244
297
  end() {
245
- this.log(`Your Bitloops project '${toKebabCase(this.options.project)}' setup is complete! 🎉🎉🎉`);
298
+ this.log(
299
+ `Your Bitloops project '${toKebabCase(
300
+ this.options.project
301
+ )}' setup is complete! 🎉🎉🎉`
302
+ );
246
303
  this.log('');
247
304
  this.log('Use the following commands to start:');
248
- this.log("- `npm run dev` to start the Next.js app.");
249
- if (this.options.storybook) this.log("- `npm run storybook` to start Storybook.");
250
- if (this.options.cypress) this.log("- `npx cypress open --e2e --browser chrome` to open Cypress.");
251
- if (this.options.cypress) this.log("- `npx cypress run --e2e --browser chrome` to run Cypress on the terminal.");
305
+ this.log('- `npm run dev` to start the Next.js app.');
306
+ if (this.options.storybook)
307
+ this.log('- `npm run storybook` to start Storybook.');
308
+ if (this.options.cypress)
309
+ this.log('- `npx cypress open --e2e --browser chrome` to open Cypress.');
310
+ if (this.options.cypress)
311
+ this.log(
312
+ '- `npx cypress run --e2e --browser chrome` to run Cypress on the terminal.'
313
+ );
252
314
  }
253
- };
315
+ }
@@ -0,0 +1,34 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { ButtonElement, ButtonElementProps } from './Button';
3
+
4
+ const meta: Meta<typeof ButtonElement> = {
5
+ title: 'Bitloops/Button',
6
+ component: ButtonElement,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ };
12
+
13
+ export default meta;
14
+
15
+ const props: ButtonElementProps = {
16
+ disabled: false,
17
+ onPress: () => {
18
+ console.log('Button pressed');
19
+ },
20
+ className:
21
+ 'border-purple-700 bg-purple-700 border opacity-100 w-40 flex-col items-center border-solid',
22
+ children: (
23
+ <p className='text-white opacity-100 text-lg font-mono'>Hello World!</p>
24
+ ),
25
+ };
26
+
27
+ type Story = StoryObj<typeof ButtonElement>;
28
+
29
+ export const Default: Story = {
30
+ args: props,
31
+ parameters: {
32
+ layout: 'fullscreen',
33
+ },
34
+ };
@@ -0,0 +1,22 @@
1
+ import { Button as AriaButton } from 'react-aria-components';
2
+
3
+ export type ButtonElementProps = {
4
+ name?: string;
5
+ disabled?: boolean;
6
+ onPress: (e?: unknown) => void;
7
+ children?: React.ReactNode;
8
+ className?: string;
9
+ };
10
+ export function ButtonElement(props: ButtonElementProps) {
11
+ const { name, disabled, children, className, onPress } = props;
12
+ return (
13
+ <AriaButton
14
+ name={name}
15
+ isDisabled={disabled}
16
+ onPress={onPress}
17
+ className={className}
18
+ >
19
+ {children}
20
+ </AriaButton>
21
+ );
22
+ }