neo.mjs 6.1.5 → 6.2.1

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.1.5'
23
+ * @member {String} version='6.2.1'
24
24
  */
25
- version: '6.1.5'
25
+ version: '6.2.1'
26
26
  }
27
27
 
28
28
  /**
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import chalk from 'chalk';
4
- import { Command } from 'commander/esm.mjs';
4
+ import {Command} from 'commander/esm.mjs';
5
5
  import envinfo from 'envinfo';
6
6
  import fs from 'fs-extra';
7
7
  import inquirer from 'inquirer';
@@ -10,36 +10,37 @@ import path from 'path';
10
10
  import {fileURLToPath} from 'url';
11
11
 
12
12
  const
13
- __dirname = fileURLToPath(new URL('../', import.meta.url)),
14
- cwd = process.cwd(),
15
- requireJson = path => JSON.parse(fs.readFileSync((path))),
16
- packageJson = requireJson(path.join(__dirname, 'package.json')),
17
- insideNeo = process.env.npm_package_name === 'neo.mjs',
18
- program = new Command(),
19
- programName = `${packageJson.name} create-class`,
20
- questions = [],
21
- /**
22
- * Maintain a list of dir-names recognized as source root directories.
23
- * When not using dot notation with a class-name, the program assumes
24
- * that we want to create the class inside the cwd. The proper namespace
25
- * is then looked up by traversing the directory path up to the first
26
- * folder that matches an entry in "sourceRootDirs". The owning
27
- * folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
28
- * namespace for this created class.
29
- * Can be overwritten with the -s option.
30
- * @type {String[]}
31
- */
32
- sourceRootDirs = ['apps'];
13
+ __dirname = fileURLToPath(new URL('../', import.meta.url)),
14
+ cwd = process.cwd(),
15
+ requireJson = path => JSON.parse(fs.readFileSync((path))),
16
+ packageJson = requireJson(path.join(__dirname, 'package.json')),
17
+ insideNeo = process.env.npm_package_name === 'neo.mjs',
18
+ program = new Command(),
19
+ programName = `${packageJson.name} create-class`,
20
+ questions = [],
21
+ /**
22
+ * Maintain a list of dir-names recognized as source root directories.
23
+ * When not using dot notation with a class-name, the program assumes
24
+ * that we want to create the class inside the cwd. The proper namespace
25
+ * is then looked up by traversing the directory path up to the first
26
+ * folder that matches an entry in "sourceRootDirs". The owning
27
+ * folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
28
+ * namespace for this created class.
29
+ * Can be overwritten with the -s option.
30
+ * @type {String[]}
31
+ */
32
+ sourceRootDirs = ['apps'];
33
33
 
34
34
  program
35
35
  .name(programName)
36
36
  .version(packageJson.version)
37
- .option('-i, --info', 'print environment debug info')
38
- .option('-d, --drop', 'drops class in the currently selected folder')
37
+ .option('-i, --info', 'print environment debug info')
38
+ .option('-d, --drop', 'drops class in the currently selected folder')
39
39
  .option('-n, --singleton <value>', 'Create a singleton? Pick "yes" or "no"')
40
- .option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
40
+ .option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
41
41
  .option('-b, --baseClass <value>')
42
42
  .option('-c, --className <value>')
43
+ .option('-r, --scss <value>')
43
44
  .allowUnknownOption()
44
45
  .on('--help', () => {
45
46
  console.log('\nIn case you have any issues, please create a ticket here:');
@@ -144,9 +145,11 @@ if (programOpts.info) {
144
145
  className = programOpts.className || answers.className,
145
146
  singleton = programOpts.singleton || answers.singleton || 'no',
146
147
  isDrop = programOpts.drop,
148
+ scssClass = programOpts.scss,
147
149
  isSingleton = singleton === 'yes',
148
150
  startDate = new Date(),
149
- baseType, classFolder, configName, file, folderDelta, importName, importPath, index, ns, root, rootLowerCase, viewFile;
151
+ baseType, classFolder, configName, file, folderDelta, importName, importPath, index, ns, root, rootLowerCase,
152
+ viewFile;
150
153
 
151
154
  if (className.endsWith('.mjs')) {
152
155
  className = className.slice(0, -4);
@@ -241,7 +244,8 @@ if (programOpts.info) {
241
244
  file,
242
245
  folderDelta,
243
246
  ns,
244
- root
247
+ root,
248
+ scssClass
245
249
  });
246
250
 
247
251
  if (baseClass === 'data.Model') {
@@ -259,7 +263,7 @@ if (programOpts.info) {
259
263
  * @param {Number} index=contentArray.length - 1
260
264
  * @returns {String[]}
261
265
  */
262
- function addComma(contentArray, index=contentArray.length - 1) {
266
+ function addComma(contentArray, index = contentArray.length - 1) {
263
267
  contentArray[index] += ',';
264
268
  return contentArray;
265
269
  }
@@ -329,7 +333,7 @@ if (programOpts.info) {
329
333
  content.splice(i, 0, `import ${importName} from '${opts.importPath}';`);
330
334
 
331
335
  // find the longest import module name
332
- for (i=0; i < len; i++) {
336
+ for (i = 0; i < len; i++) {
333
337
  codeLine = content[i];
334
338
 
335
339
  if (codeLine === '') {
@@ -340,7 +344,7 @@ if (programOpts.info) {
340
344
  }
341
345
 
342
346
  // adjust the block-formatting for imports
343
- for (i=0; i < len; i++) {
347
+ for (i = 0; i < len; i++) {
344
348
  codeLine = content[i];
345
349
 
346
350
  if (codeLine === '') {
@@ -353,7 +357,7 @@ if (programOpts.info) {
353
357
  if (adjustSpaces > 0) {
354
358
  spaces = '';
355
359
 
356
- for (j=0; j < adjustSpaces; j++) {
360
+ for (j = 0; j < adjustSpaces; j++) {
357
361
  spaces += ' ';
358
362
  }
359
363
 
@@ -396,7 +400,7 @@ if (programOpts.info) {
396
400
  }
397
401
 
398
402
  if (className > configName) {
399
- for (j=i; j > 0; j--) {
403
+ for (j = i; j > 0; j--) {
400
404
  if (content[j].includes('/**')) {
401
405
  addConfig({
402
406
  baseType,
@@ -444,7 +448,8 @@ if (programOpts.info) {
444
448
  file,
445
449
  folderDelta,
446
450
  ns,
447
- root
451
+ root,
452
+ scssClass = undefined,
448
453
  } = opts, baseFileName;
449
454
 
450
455
  fs.mkdirpSync(classFolder, {recursive: true});
@@ -464,10 +469,11 @@ if (programOpts.info) {
464
469
  file,
465
470
  folderDelta,
466
471
  ns,
467
- root
472
+ root,
473
+ scssClass
468
474
  }));
469
475
 
470
- switch(baseClass) {
476
+ switch (baseClass) {
471
477
  case 'controller.Component': {
472
478
  baseType = 'Neo.controller.Component';
473
479
  configName = 'controller';
@@ -555,7 +561,9 @@ if (programOpts.info) {
555
561
  isSingleton = opts.isSingleton,
556
562
  file = opts.file,
557
563
  i = 0,
558
- importDelta = '';
564
+ importDelta = '',
565
+ scssClass = opts.scssClass,
566
+ isScss = scssClass !== null && scssClass !== undefined;
559
567
 
560
568
  if (root === 'Neo') {
561
569
  if (className.startsWith('Neo.examples')) {
@@ -592,6 +600,13 @@ if (programOpts.info) {
592
600
  ` className: '${className}'`
593
601
  );
594
602
 
603
+ isScss && addComma(classContent).push(
604
+ " /**",
605
+ ` * @member {String[]} baseCls=['${scssClass}']`,
606
+ " * @protected",
607
+ " */",
608
+ ` baseCls: ['${scssClass}']`);
609
+
595
610
  baseClass === 'table.Container' && addComma(classContent).push(
596
611
  " /**",
597
612
  " * @member {Object[]} columns",
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env node
2
+
3
+ import chalk from 'chalk';
4
+ import {spawnSync} from 'child_process';
5
+ import {Command} from 'commander/esm.mjs';
6
+ import envinfo from 'envinfo';
7
+ import fs from 'fs-extra';
8
+ import inquirer from 'inquirer';
9
+ import path from 'path';
10
+ import {fileURLToPath} from 'url';
11
+
12
+ const
13
+ __dirname = fileURLToPath(new URL('../', import.meta.url)),
14
+ cwd = process.cwd(),
15
+ requireJson = path => JSON.parse(fs.readFileSync((path))),
16
+ packageJson = requireJson(path.join(__dirname, 'package.json')),
17
+ program = new Command(),
18
+ programName = `${packageJson.name} create-class`,
19
+ questions = [],
20
+ /**
21
+ * Maintain a list of dir-names recognized as source root directories.
22
+ * When not using dot notation with a class-name, the program assumes
23
+ * that we want to create the class inside the cwd. The proper namespace
24
+ * is then looked up by traversing the directory path up to the first
25
+ * folder that matches an entry in "sourceRootDirs". The owning
26
+ * folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
27
+ * namespace for this created class.
28
+ * Can be overwritten with the -s option.
29
+ * @type {String[]}
30
+ */
31
+ sourceRootDirs = ['apps'];
32
+
33
+ program
34
+ .name(programName)
35
+ .version(packageJson.version)
36
+ .option('-i, --info', 'print environment debug info')
37
+ .option('-n, --singleton <value>', 'Create a singleton? Pick "yes" or "no"')
38
+ .option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
39
+ .option('-b, --baseClass <value>')
40
+ .option('-c, --className <value>')
41
+ .allowUnknownOption()
42
+ .on('--help', () => {
43
+ console.log('\nIn case you have any issues, please create a ticket here:');
44
+ console.log(chalk.cyan(process.env.npm_package_bugs_url));
45
+ })
46
+ .parse(process.argv);
47
+
48
+ const programOpts = program.opts();
49
+
50
+ if (programOpts.info) {
51
+ console.log(chalk.bold('\nEnvironment Info:'));
52
+ console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
53
+ console.log(` running from ${cwd}`);
54
+
55
+ envinfo
56
+ .run({
57
+ System : ['OS', 'CPU'],
58
+ Binaries : ['Node', 'npm', 'Yarn'],
59
+ Browsers : ['Chrome', 'Edge', 'Firefox', 'Safari'],
60
+ npmPackages: ['neo.mjs']
61
+ }, {
62
+ duplicates : true,
63
+ showNotFound: true
64
+ })
65
+ .then(console.log);
66
+ } else {
67
+ console.log(chalk.green(programName));
68
+
69
+ let answers = {},
70
+ answer;
71
+
72
+ if (!programOpts.className) {
73
+ answer = await inquirer.prompt({
74
+ type : 'input',
75
+ name : 'className',
76
+ message: 'Please choose the namespace for your class:',
77
+ default: 'Covid.view.MyContainer'
78
+ });
79
+
80
+ Object.assign(answers, answer);
81
+ }
82
+
83
+ if (!programOpts.baseClass) {
84
+ questions.push({
85
+ type : 'list',
86
+ name : 'baseClass',
87
+ message: 'Please pick the base class, which you want to extend:',
88
+ default: guessBaseClass(programOpts.className || answers.className),
89
+
90
+ choices: [
91
+ 'component.Base',
92
+ 'container.Base',
93
+ 'container.Viewport',
94
+ 'controller.Component',
95
+ 'core.Base',
96
+ 'data.Model',
97
+ 'data.Store',
98
+ 'model.Component',
99
+ 'tab.Container',
100
+ 'table.Container'
101
+ ]
102
+ });
103
+ }
104
+
105
+
106
+ if (!programOpts.singleton) {
107
+ questions.push({
108
+ type : 'list',
109
+ name : 'singleton',
110
+ message: 'Singleton?',
111
+ default: 'no',
112
+ choices: ['yes', 'no']
113
+ });
114
+ }
115
+
116
+ answer = await inquirer.prompt(questions);
117
+
118
+ Object.assign(answers, answer);
119
+
120
+ let baseClass = programOpts.baseClass || answers.baseClass,
121
+ className = programOpts.className || answers.className,
122
+ singleton = programOpts.singleton || answers.singleton || 'no';
123
+
124
+ let ns = className.split('.');
125
+ ns.pop();
126
+ let root = ns.shift();
127
+ let rootLowerCase = root.toLowerCase();
128
+
129
+
130
+ if (!baseClass && !className) {
131
+ console.error(chalk.red('className and baseClass must be defined'));
132
+ process.exit(1);
133
+ }
134
+
135
+ const scssClassName = getScssClassName(className, rootLowerCase);
136
+
137
+ let childProcess = spawnSync('node', [
138
+ './buildScripts/createClass.mjs',
139
+ '-c',
140
+ className,
141
+ '-b',
142
+ baseClass,
143
+ '-n',
144
+ singleton,
145
+ '-r',
146
+ scssClassName
147
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
148
+ childProcess.status && process.exit(childProcess.status);
149
+
150
+
151
+ //create scss stubs only if it is a NEO component or a view component
152
+ const resultView = ns.filter(f => f === 'view');
153
+ if (rootLowerCase === 'neo' || resultView.length > 0) {
154
+ let childProcess = spawnSync('node', [
155
+ './buildScripts/tools/createScss.mjs',
156
+ '-c',
157
+ className,
158
+ '-b',
159
+ baseClass
160
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
161
+ childProcess.status && process.exit(childProcess.status);
162
+ }
163
+
164
+ // create only example stub when it is a NEO component
165
+ if (rootLowerCase === 'neo') {
166
+ let childProcess = spawnSync('node', [
167
+ './buildScripts/tools/createExample.mjs',
168
+ // '--',
169
+ '-c',
170
+ className
171
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
172
+ childProcess.status && process.exit(childProcess.status);
173
+ }
174
+
175
+ //re-build the themes
176
+ let buildThemes = spawnSync('node', [
177
+ './buildScripts/buildThemes.mjs',
178
+ // '--',
179
+ '-f',
180
+ '-e',
181
+ 'all',
182
+ '-n'
183
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
184
+ buildThemes.status && process.exit(buildThemes.status);
185
+
186
+
187
+ // start the dev server
188
+ if (rootLowerCase === 'neo') {
189
+ let temp = className.split('.');
190
+ temp.splice(0, 1); //remove Neo namespace
191
+ let componentPath = `/examples/${temp.join('/')}`;
192
+ componentPath = componentPath.toLowerCase();
193
+
194
+ let startServer = spawnSync('webpack', [
195
+ 'serve',
196
+ '-c',
197
+ './buildScripts/webpack/webpack.server.config.mjs',
198
+ '--open',
199
+ componentPath
200
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
201
+ startServer.status && process.exit(startServer.status);
202
+ }
203
+ }
204
+
205
+ function guessBaseClass(className) {
206
+ className = className.toLowerCase();
207
+
208
+ if (className.includes('.model.')) {
209
+ return 'data.Model';
210
+ }
211
+
212
+ if (className.includes('.store.')) {
213
+ return 'data.Store';
214
+ }
215
+
216
+ if (className.endsWith('component')) {
217
+ return 'component.Base';
218
+ }
219
+
220
+ if (className.endsWith('controller')) {
221
+ return 'controller.Component';
222
+ }
223
+
224
+ if (className.endsWith('model')) {
225
+ return 'model.Component';
226
+ }
227
+
228
+ if (className.includes('table')) {
229
+ return 'table.Container';
230
+ }
231
+
232
+ if (className.includes('tab')) {
233
+ return 'tab.Container';
234
+ }
235
+
236
+ return 'container.Base';
237
+ }
238
+
239
+ function getScssClassName(className) {
240
+ //template
241
+ let classItems = className.split('.');
242
+ let result = [];
243
+
244
+ classItems.forEach(item => {
245
+ let temp = item.split(/(?=[A-Z])/);
246
+ result.push(temp.join('-').toLowerCase());
247
+ });
248
+
249
+ return result.join('-');
250
+ }
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {Command} from 'commander/esm.mjs';
4
+ import fs from 'fs-extra';
5
+ import os from 'os';
6
+ import path from 'path';
7
+ import {fileURLToPath} from 'url';
8
+
9
+ const
10
+ __dirname = fileURLToPath(new URL('../../', import.meta.url)),
11
+ cwd = process.cwd(),
12
+ requireJson = path => JSON.parse(fs.readFileSync((path))),
13
+ packageJson = requireJson(path.join(__dirname, 'package.json')),
14
+ program = new Command();
15
+
16
+ program
17
+ .version(packageJson.version)
18
+ .option('-b, --baseClass <value>')
19
+ .option('-c, --className <value>')
20
+ .allowUnknownOption()
21
+ .parse(process.argv);
22
+
23
+ const programOpts = program.opts();
24
+ let className = programOpts.className;
25
+
26
+ let ns = className.split('.');
27
+ ns.splice(0, 1); //remove Neo namespace
28
+ let componentPath = ns.join('/');
29
+ componentPath = componentPath.toLowerCase();
30
+ const componentChunk = ns.join('.')
31
+ const name = ns.pop();
32
+ let classFolder = path.join(cwd, 'examples', `/${componentPath}`);
33
+
34
+ if (!fs.existsSync(classFolder)) {
35
+ fs.mkdirpSync(classFolder, {recursive: true});
36
+ }
37
+
38
+ createAppMjs(classFolder, componentChunk);
39
+ createIndexHtml(classFolder, name);
40
+ createNeoConfig(classFolder, componentPath);
41
+ createMainContainer(classFolder, componentPath, componentChunk, name);
42
+
43
+
44
+ function createAppMjs(classFolder, componentChunk) {
45
+ let template = [];
46
+
47
+ template.push(
48
+ "import MainContainer from './MainContainer.mjs';",
49
+ "",
50
+ "export const onStart = () => Neo.app({",
51
+ " mainView: MainContainer,",
52
+ ` name : 'Neo.examples.${componentChunk}'`,
53
+ "});");
54
+
55
+ const file = `${classFolder}/app.mjs`;
56
+ fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
57
+ }
58
+
59
+ function createIndexHtml(classFolder, title) {
60
+ const template = [];
61
+
62
+ template.push(
63
+ '<!DOCTYPE HTML>',
64
+ '<html>',
65
+ '<head>',
66
+ ' <meta name="viewport" content="width=device-width, initial-scale=1">',
67
+ ' <meta charset="UTF-8">',
68
+ ` <title>Neo ${title}</title>`,
69
+ '</head>',
70
+ '<body>',
71
+ ' <script src="../../../src/MicroLoader.mjs" type="module"></script>',
72
+ '</body>',
73
+ '</html>`');
74
+
75
+ const file = `${classFolder}/index.html`;
76
+ fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
77
+ }
78
+
79
+ function createNeoConfig(classFolder, componentPath) {
80
+ const template = [];
81
+
82
+ template.push(
83
+ '{',
84
+ ` "appPath" : "examples/${componentPath}/app.mjs",`,
85
+ ' "basePath" : "../../../",',
86
+ ' "environment": "development",',
87
+ ' "mainPath" : "./Main.mjs"',
88
+ '}'
89
+ );
90
+ const file = `${classFolder}/neo-config.json`;
91
+ fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
92
+
93
+ }
94
+
95
+
96
+ function createMainContainer(classFolder, componentPath, componentChunk, name) {
97
+ const template = [];
98
+
99
+ template.push(
100
+ "import ConfigurationViewport from '../../ConfigurationViewport.mjs';",
101
+ "import NumberField from '../../../src/form/field/Number.mjs';",
102
+ `import ${name} from '../../../src/${componentPath}.mjs';`,
103
+ "",
104
+ "/**",
105
+ ` * @class Neo.examples.${componentChunk.toLowerCase()}.MainContainer`,
106
+ " * @extends Neo.examples.ConfigurationViewport",
107
+ " */",
108
+ "class MainContainer extends ConfigurationViewport {",
109
+ " static config = {",
110
+ ` className: 'Neo.examples.${componentChunk.toLowerCase()}.MainContainer',`,
111
+ " autoMount: true,",
112
+ " configItemLabelWidth: 110,",
113
+ " configItemWidth: 230,",
114
+ " layout: { ntype: 'hbox', align: 'stretch' }",
115
+ " }",
116
+ "",
117
+ " createConfigurationComponents() {",
118
+ " let me = this;",
119
+ "",
120
+ " return [{",
121
+ " module: NumberField,",
122
+ " clearable: true,",
123
+ " labelText: 'height',",
124
+ " listeners: { change: me.onConfigChange.bind(me, 'height') },",
125
+ " maxValue: 100,",
126
+ " minValue: 20,",
127
+ " stepSize: 2,",
128
+ " style: { marginTop: '10px' },",
129
+ " value: me.exampleComponent.height",
130
+ " }, {",
131
+ " module: NumberField,",
132
+ " clearable: true,",
133
+ " labelText: 'width',",
134
+ " listeners: { change: me.onConfigChange.bind(me, 'width') },",
135
+ " maxValue: 300,",
136
+ " minValue: 100,",
137
+ " stepSize: 5,",
138
+ " style: { marginTop: '10px' },",
139
+ " value: me.exampleComponent.width",
140
+ " }]",
141
+ " }",
142
+ "",
143
+ " createExampleComponent() {",
144
+ " return Neo.create({",
145
+ ` module: ${name},`,
146
+ " height: 30,",
147
+ " width: 100",
148
+ " // property_xy: <value>",
149
+ " })",
150
+ " }",
151
+ "}",
152
+ "",
153
+ "Neo.applyClassConfig(MainContainer);",
154
+ "",
155
+ "export default MainContainer;"
156
+ );
157
+ const file = `${classFolder}/MainContainer.mjs`;
158
+ fs.writeFileSync(file, `${template.join(os.EOL)}${os.EOL}`);
159
+ }
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {Command} from 'commander/esm.mjs';
4
+ import fs from 'fs-extra';
5
+ import os from 'os';
6
+ import path from 'path';
7
+ import {fileURLToPath} from 'url';
8
+
9
+ const
10
+ __dirname = fileURLToPath(new URL('../../', import.meta.url)),
11
+ cwd = process.cwd(),
12
+ requireJson = path => JSON.parse(fs.readFileSync((path))),
13
+ packageJson = requireJson(path.join(__dirname, 'package.json')),
14
+ program = new Command();
15
+
16
+ program
17
+ .version(packageJson.version)
18
+ .option('-b, --baseClass <value>')
19
+ .option('-c, --className <value>')
20
+ .allowUnknownOption()
21
+ .parse(process.argv);
22
+
23
+ const programOpts = program.opts();
24
+
25
+ let className = programOpts.className;
26
+
27
+ let ns = className.split('.');
28
+ let file = ns.pop();
29
+ let root = ns.shift();
30
+ let rootLowerCase = root.toLowerCase();
31
+
32
+ // let classFolder = path.join(cwd, '/src/', ns.join('/'));
33
+ const forNonNeoPathArray = ns.filter(f => f !== 'view');
34
+ let nonNeoPath = `apps/${rootLowerCase}`;
35
+ if (forNonNeoPathArray.length > 0) {
36
+ nonNeoPath = nonNeoPath.concat('/', forNonNeoPathArray.join('/'));
37
+ }
38
+
39
+ let classFolder = path.join(cwd, 'resources/scss/src/', rootLowerCase === 'neo' ? `/${ns.join('/')}` : nonNeoPath);
40
+
41
+ if (!fs.existsSync(classFolder)) {
42
+ fs.mkdirpSync(classFolder, {recursive: true});
43
+ }
44
+
45
+ const scssClassName = getScssClassName(className);
46
+ const template = `.${scssClassName} {
47
+ // add css information here
48
+ background-color: var(--${scssClassName.toLowerCase()}-background-color); // this is an example
49
+ }`;
50
+ createScssStub(classFolder, file, template);
51
+
52
+ // iterate over themes
53
+ let themeFoldersPath = path.join(cwd, 'resources/scss/');
54
+
55
+ const themeFolders = listDirectories(themeFoldersPath);
56
+
57
+ themeFolders.forEach(theme => {
58
+ const forNonNeoPathArray = ns.filter(f => f !== 'view');
59
+ let nonNeoPath = `apps/${rootLowerCase}`;
60
+ if (forNonNeoPathArray.length > 0) {
61
+ nonNeoPath = nonNeoPath.concat('/', forNonNeoPathArray.join('/'));
62
+ }
63
+ classFolder = path.join(cwd, 'resources/scss/', theme, rootLowerCase === 'neo' ? `/${ns.join('/')}` : nonNeoPath);
64
+ if (!fs.existsSync(classFolder)) {
65
+ fs.mkdirpSync(classFolder, {recursive: true});
66
+ }
67
+ const exampleColor = theme.includes('dark') ? 'darkgreen' : 'green';
68
+ const themeTemplate = `:root .${rootLowerCase}-${theme} { // .${scssClassName}
69
+ // add css theme information here
70
+ --${scssClassName.toLowerCase()}-background-color: ${exampleColor}; //example
71
+ }`;
72
+ createScssStub(classFolder, file, themeTemplate);
73
+ })
74
+
75
+ function listDirectories(path) {
76
+ return fs.readdirSync(path, {withFileTypes: true})
77
+ .filter(dirent => dirent.isDirectory() && dirent.name.startsWith('theme'))
78
+ .map(dirent => dirent.name);
79
+ }
80
+
81
+ function createScssStub(classFolder, file, template) {
82
+ const scssFile = `${classFolder}/${file}.scss`;
83
+
84
+ fs.writeFileSync(scssFile, `${template}${os.EOL}`);
85
+ }
86
+
87
+ function getScssClassName(className) {
88
+ let classItems = className.split('.');
89
+ let result = [];
90
+
91
+ classItems.forEach(item => {
92
+ let temp = item.split(/(?=[A-Z])/);
93
+ result.push(temp.join('-').toLowerCase());
94
+ });
95
+
96
+ return result.join('-');
97
+ }
98
+
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.1.5'
23
+ * @member {String} version='6.2.1'
24
24
  */
25
- version: '6.1.5'
25
+ version: '6.2.1'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.1.5",
3
+ "version": "6.2.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -19,6 +19,7 @@
19
19
  "build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
20
20
  "create-app": "node ./buildScripts/createApp.mjs",
21
21
  "create-class": "node ./buildScripts/createClass.mjs",
22
+ "create-component": "node ./buildScripts/createComponent.mjs",
22
23
  "generate-docs-json": "node ./buildScripts/docs/jsdocx.mjs",
23
24
  "inject-package-version": "node ./buildScripts/injectPackageVersion.mjs",
24
25
  "server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '6.1.5'
239
+ * @default '6.2.1'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '6.1.5'
244
+ version: '6.2.1'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
package/src/menu/List.mjs CHANGED
@@ -357,9 +357,12 @@ class List extends BaseList {
357
357
 
358
358
  record.handler?.call(me, record);
359
359
 
360
- if (me.hideOnLeafItemClick && !record.items) {
361
- me.unmount()
362
- }
360
+ record.route && Neo.Main.setRoute({
361
+ appName: me.appName,
362
+ value : record.route
363
+ });
364
+
365
+ me.hideOnLeafItemClick && !record.items && me.unmount();
363
366
 
364
367
  if (record.items) {
365
368
  submenu = me.subMenuMap?.[me.getMenuMapId(recordId)];
@@ -33,6 +33,9 @@ class Model extends BaseModel {
33
33
  }, {
34
34
  name: 'items', // optional
35
35
  type: 'Array'
36
+ }, {
37
+ name: 'route',
38
+ type: 'String'
36
39
  }, {
37
40
  name: 'text',
38
41
  type: 'String'