plusui-native 0.2.4 → 0.2.7

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.
@@ -89,9 +89,11 @@ npm run build:all
89
89
  This creates platform-specific builds in:
90
90
  ```
91
91
  build/
92
- ├── Windows/ # Windows executable
93
- ├── MacOS/ # macOS app bundle
94
- └── Linux/ # Linux binary
92
+ ├── Windows/ # Windows builds
93
+ ├── MacOS/ # macOS builds
94
+ ├── Linux/ # Linux builds
95
+ ├── Android/ # Android builds
96
+ └── iOS/ # iOS builds
95
97
  ```
96
98
 
97
99
  ### Platform-specific builds
@@ -142,20 +144,18 @@ just help # Show all commands
142
144
 
143
145
  ## Calling C++ from TypeScript
144
146
 
145
- Use the `plusui-native-core` SDK to interact with the native backend:
147
+ Use the local `frontend/src/plusui.ts` bridge to interact with the native backend:
146
148
 
147
149
  ```tsx
148
- import { createPlusUI } from 'plusui-native-core';
149
-
150
- const plusui = createPlusUI();
150
+ import { win } from './plusui';
151
151
 
152
152
  // Window controls
153
- await plusui.window.minimize();
154
- await plusui.window.maximize();
155
- await plusui.window.close();
153
+ await win.minimize();
154
+ await win.maximize();
155
+ await win.close();
156
156
 
157
157
  // Get window info
158
- const size = await plusui.window.getSize();
158
+ const size = await win.getSize();
159
159
  console.log(`Window size: ${size.width}x${size.height}`);
160
160
  ```
161
161
 
@@ -164,5 +164,5 @@ console.log(`Window size: ${size.width}x${size.height}`);
164
164
  - [PlusUI Documentation](https://github.com/yourorg/plusui)
165
165
  - [React Documentation](https://react.dev/)
166
166
  - [Vite Documentation](https://vitejs.dev/)
167
-
168
-
167
+
168
+
@@ -1,217 +1,173 @@
1
- import { mkdir, readdir, readFile, writeFile, copyFile, stat } from 'fs/promises';
2
- import { join, dirname, resolve } from 'path';
3
- import { existsSync } from 'fs';
4
- import { fileURLToPath } from 'url';
5
- import { EnvironmentDoctor } from '../src/doctor/index.js';
6
- import chalk from 'chalk';
7
- import { execSync, spawn } from 'child_process';
8
-
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = dirname(__filename);
11
-
12
- export class TemplateManager {
13
- constructor() {
14
- this.templatesDir = __dirname;
15
- }
16
-
17
- async create(projectName, options = {}) {
18
- const template = options.template || 'react';
19
- const templatePath = join(this.templatesDir, template);
20
-
21
- console.log(chalk.bold(`\nCreating PlusUI project: ${projectName}\n`));
22
-
23
- // 1. Check environment first
24
- console.log(chalk.blue('Checking environment...'));
25
- const doctor = new EnvironmentDoctor();
26
- const quickCheck = await doctor.quickCheck();
27
-
28
- if (!quickCheck.ready) {
29
- console.log(chalk.red('\n✗ Environment not ready!\n'));
30
- console.log(chalk.yellow('Run: plusui doctor --fix\n'));
31
- throw new Error('Environment check failed');
32
- }
33
-
34
- console.log(chalk.green('✓ Environment ready\n'));
35
-
36
- // 2. Create project directory
37
- console.log(chalk.blue('Creating project structure...'));
38
- const projectPath = resolve(projectName);
39
-
40
- if (existsSync(projectPath)) {
41
- throw new Error(`Directory ${projectName} already exists`);
42
- }
43
-
44
- await mkdir(projectPath, { recursive: true });
45
-
46
- // 3. Prepare template variables
47
- const variables = {
48
- PROJECT_NAME: projectName,
49
- PROJECT_NAME_LOWER: projectName.toLowerCase(),
50
- PROJECT_VERSION: '0.1.0',
51
- PLUSUI_CORE_PATH: this.resolvePlusUIPath()
52
- };
53
-
54
- // 4. Copy template files
55
- await this.copyTemplate(templatePath, projectPath, variables);
56
-
57
- // 5. Copy base files
58
- const basePath = join(this.templatesDir, 'base');
59
- await this.copyTemplate(basePath, projectPath, variables, true);
60
-
61
- console.log(chalk.green('✓ Project structure created\n'));
62
-
63
- // 6. Install npm dependencies
64
- console.log(chalk.blue('Installing dependencies...'));
65
- await this.runNpmInstall(projectPath);
66
- console.log(chalk.green('✓ Dependencies installed\n'));
67
-
68
- // 7. Print success message
69
- this.printSuccessMessage(projectName);
70
-
71
- return { success: true, path: projectPath };
72
- }
73
-
74
- async copyTemplate(templatePath, destPath, variables, skipSubdirs = false) {
75
- if (!existsSync(templatePath)) {
76
- return;
77
- }
78
-
79
- const entries = await readdir(templatePath, { withFileTypes: true });
80
-
81
- for (const entry of entries) {
82
- const srcPath = join(templatePath, entry.name);
83
- const destName = entry.name.replace('.template', '');
84
- const destFilePath = join(destPath, destName);
85
-
86
- if (entry.isDirectory()) {
87
- if (!skipSubdirs) {
88
- await mkdir(destFilePath, { recursive: true });
89
- await this.copyTemplate(srcPath, destFilePath, variables, false);
90
- }
91
- } else {
92
- // Ensure parent directory exists
93
- await mkdir(dirname(destFilePath), { recursive: true });
94
-
95
- // Read file content
96
- let content = await readFile(srcPath, 'utf8');
97
-
98
- // Replace variables
99
- content = this.replaceVariables(content, variables);
100
-
101
- // Write to destination
102
- await writeFile(destFilePath, content, 'utf8');
103
- }
104
- }
105
- }
106
-
107
- replaceVariables(content, variables) {
108
- let result = content;
109
-
110
- for (const [key, value] of Object.entries(variables)) {
111
- const placeholder = `{{${key}}}`;
112
- result = result.split(placeholder).join(value);
113
- }
114
-
115
- return result;
116
- }
117
-
118
- resolvePlusUIPath() {
119
- // Strategy:
120
- // 1. Check for global plusui-native-core installation
121
- // 2. Check for local development version
122
- // 3. Fall back to npm registry
123
-
124
- try {
125
- // Check if running in development (from PlusUI repo)
126
- const localCorePath = resolve(__dirname, '../../plusui-sdk/packages/core');
127
- if (existsSync(localCorePath)) {
128
- // Convert Windows backslashes to forward slashes for JSON compatibility
129
- return `file:${localCorePath.replace(/\\/g, '/')}`;
130
- }
131
-
132
- // Check global installation
133
- const globalPath = this.resolveGlobalPackage('plusui-native-core');
134
- if (globalPath) {
135
- return globalPath;
136
- }
137
- } catch (e) {
138
- // Ignore errors, fall back to npm
139
- }
140
-
141
- // Fall back to npm registry (when published)
142
- return '^0.1.0';
143
- }
144
-
145
- resolveGlobalPackage(packageName) {
146
- try {
147
- const result = execSync(`npm root -g`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
148
- const globalRoot = result.trim();
149
- const packagePath = join(globalRoot, packageName);
150
-
151
- if (existsSync(packagePath)) {
152
- return packagePath;
153
- }
154
- } catch (e) {
155
- // npm not available or package not found
156
- }
157
-
158
- return null;
159
- }
160
-
161
- async runNpmInstall(projectPath) {
162
- return new Promise((resolve, reject) => {
163
- const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
164
-
165
- // Install root dependencies
166
- const rootProc = spawn(npm, ['install'], {
167
- cwd: projectPath,
168
- stdio: 'inherit',
169
- shell: true
170
- });
171
-
172
- rootProc.on('close', (code) => {
173
- if (code !== 0) {
174
- reject(new Error(`npm install failed with code ${code}`));
175
- return;
176
- }
177
-
178
- // Install frontend dependencies
179
- const frontendPath = join(projectPath, 'frontend');
180
- if (existsSync(join(frontendPath, 'package.json'))) {
181
- const frontendProc = spawn(npm, ['install'], {
182
- cwd: frontendPath,
183
- stdio: 'inherit',
184
- shell: true
185
- });
186
-
187
- frontendProc.on('close', (feCode) => {
188
- if (feCode === 0) {
189
- resolve();
190
- } else {
191
- reject(new Error(`frontend npm install failed with code ${feCode}`));
192
- }
193
- });
194
-
195
- frontendProc.on('error', reject);
196
- } else {
197
- resolve();
198
- }
199
- });
200
-
201
- rootProc.on('error', reject);
202
- });
203
- }
204
-
205
- printSuccessMessage(projectName) {
206
- console.log(chalk.green.bold('\n✓ Project created successfully!\n'));
207
- console.log(chalk.bold('Next steps:\n'));
208
- console.log(chalk.cyan(` cd ${projectName}`));
209
- console.log(chalk.cyan(` npm run dev`));
210
- console.log();
211
- console.log(chalk.gray('This will start the development server with hot reload.'));
212
- console.log(chalk.gray('Edit frontend/src/App.tsx and main.cpp to get started!'));
213
- console.log();
214
- }
215
- }
216
-
217
-
1
+ import { mkdir, readdir, readFile, writeFile, copyFile, stat } from 'fs/promises';
2
+ import { join, dirname, resolve } from 'path';
3
+ import { existsSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
5
+ import { EnvironmentDoctor } from '../src/doctor/index.js';
6
+ import chalk from 'chalk';
7
+ import { spawn } from 'child_process';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+
12
+ export class TemplateManager {
13
+ constructor() {
14
+ this.templatesDir = __dirname;
15
+ }
16
+
17
+ async create(projectName, options = {}) {
18
+ const template = options.template || 'react';
19
+ const templatePath = join(this.templatesDir, template);
20
+
21
+ console.log(chalk.bold(`\nCreating PlusUI project: ${projectName}\n`));
22
+
23
+ // 1. Check environment first
24
+ console.log(chalk.blue('Checking environment...'));
25
+ const doctor = new EnvironmentDoctor();
26
+ const quickCheck = await doctor.quickCheck();
27
+
28
+ if (!quickCheck.ready) {
29
+ console.log(chalk.red('\n✗ Environment not ready!\n'));
30
+ console.log(chalk.yellow('Run: plusui doctor --fix\n'));
31
+ throw new Error('Environment check failed');
32
+ }
33
+
34
+ console.log(chalk.green('✓ Environment ready\n'));
35
+
36
+ // 2. Create project directory
37
+ console.log(chalk.blue('Creating project structure...'));
38
+ const projectPath = resolve(projectName);
39
+
40
+ if (existsSync(projectPath)) {
41
+ throw new Error(`Directory ${projectName} already exists`);
42
+ }
43
+
44
+ await mkdir(projectPath, { recursive: true });
45
+
46
+ // 3. Prepare template variables
47
+ const variables = {
48
+ PROJECT_NAME: projectName,
49
+ PROJECT_NAME_LOWER: projectName.toLowerCase(),
50
+ PROJECT_VERSION: '0.1.0'
51
+ };
52
+
53
+ // 4. Copy template files
54
+ await this.copyTemplate(templatePath, projectPath, variables);
55
+
56
+ // 5. Copy base files
57
+ const basePath = join(this.templatesDir, 'base');
58
+ await this.copyTemplate(basePath, projectPath, variables, true);
59
+
60
+ console.log(chalk.green('✓ Project structure created\n'));
61
+
62
+ // 6. Install npm dependencies
63
+ console.log(chalk.blue('Installing dependencies...'));
64
+ await this.runNpmInstall(projectPath);
65
+ console.log(chalk.green('✓ Dependencies installed\n'));
66
+
67
+ // 7. Print success message
68
+ this.printSuccessMessage(projectName);
69
+
70
+ return { success: true, path: projectPath };
71
+ }
72
+
73
+ async copyTemplate(templatePath, destPath, variables, skipSubdirs = false) {
74
+ if (!existsSync(templatePath)) {
75
+ return;
76
+ }
77
+
78
+ const entries = await readdir(templatePath, { withFileTypes: true });
79
+
80
+ for (const entry of entries) {
81
+ const srcPath = join(templatePath, entry.name);
82
+ const destName = entry.name.replace('.template', '');
83
+ const destFilePath = join(destPath, destName);
84
+
85
+ if (entry.isDirectory()) {
86
+ if (!skipSubdirs) {
87
+ await mkdir(destFilePath, { recursive: true });
88
+ await this.copyTemplate(srcPath, destFilePath, variables, false);
89
+ }
90
+ } else {
91
+ // Ensure parent directory exists
92
+ await mkdir(dirname(destFilePath), { recursive: true });
93
+
94
+ // Read file content
95
+ let content = await readFile(srcPath, 'utf8');
96
+
97
+ // Replace variables
98
+ content = this.replaceVariables(content, variables);
99
+
100
+ // Write to destination
101
+ await writeFile(destFilePath, content, 'utf8');
102
+ }
103
+ }
104
+ }
105
+
106
+ replaceVariables(content, variables) {
107
+ let result = content;
108
+
109
+ for (const [key, value] of Object.entries(variables)) {
110
+ const placeholder = `{{${key}}}`;
111
+ result = result.split(placeholder).join(value);
112
+ }
113
+
114
+ return result;
115
+ }
116
+
117
+ async runNpmInstall(projectPath) {
118
+ return new Promise((resolve, reject) => {
119
+ const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
120
+
121
+ // Install root dependencies
122
+ const rootProc = spawn(npm, ['install'], {
123
+ cwd: projectPath,
124
+ stdio: 'inherit',
125
+ shell: true
126
+ });
127
+
128
+ rootProc.on('close', (code) => {
129
+ if (code !== 0) {
130
+ reject(new Error(`npm install failed with code ${code}`));
131
+ return;
132
+ }
133
+
134
+ // Install frontend dependencies
135
+ const frontendPath = join(projectPath, 'frontend');
136
+ if (existsSync(join(frontendPath, 'package.json'))) {
137
+ const frontendProc = spawn(npm, ['install'], {
138
+ cwd: frontendPath,
139
+ stdio: 'inherit',
140
+ shell: true
141
+ });
142
+
143
+ frontendProc.on('close', (feCode) => {
144
+ if (feCode === 0) {
145
+ resolve();
146
+ } else {
147
+ reject(new Error(`frontend npm install failed with code ${feCode}`));
148
+ }
149
+ });
150
+
151
+ frontendProc.on('error', reject);
152
+ } else {
153
+ resolve();
154
+ }
155
+ });
156
+
157
+ rootProc.on('error', reject);
158
+ });
159
+ }
160
+
161
+ printSuccessMessage(projectName) {
162
+ console.log(chalk.green.bold('\n✓ Project created successfully!\n'));
163
+ console.log(chalk.bold('Next steps:\n'));
164
+ console.log(chalk.cyan(` cd ${projectName}`));
165
+ console.log(chalk.cyan(` npm run dev`));
166
+ console.log();
167
+ console.log(chalk.gray('This will start the development server with hot reload.'));
168
+ console.log(chalk.gray('Edit frontend/src/App.tsx and main.cpp to get started!'));
169
+ console.log();
170
+ }
171
+ }
172
+
173
+
@@ -24,7 +24,15 @@ endif()
24
24
  # Strategy: Check multiple locations for the Core library
25
25
  set(PLUSUI_FOUND FALSE)
26
26
 
27
- # Location 1: Local development (sibling to project inside PlusUI repo)
27
+ # Location 1: Project-local Core directory
28
+ set(PLUSUI_CORE_LOCAL "${CMAKE_SOURCE_DIR}/Core")
29
+ if(EXISTS "${PLUSUI_CORE_LOCAL}/CMakeLists.txt")
30
+ message(STATUS "Found PlusUI Core at: ${PLUSUI_CORE_LOCAL}")
31
+ add_subdirectory("${PLUSUI_CORE_LOCAL}" "${CMAKE_BINARY_DIR}/plusui-core")
32
+ set(PLUSUI_FOUND TRUE)
33
+ endif()
34
+
35
+ # Location 2: Local development (sibling to project inside PlusUI repo)
28
36
  set(PLUSUI_CORE_DEV "${CMAKE_SOURCE_DIR}/../Core")
29
37
  if(EXISTS "${PLUSUI_CORE_DEV}/CMakeLists.txt")
30
38
  message(STATUS "Found PlusUI Core at: ${PLUSUI_CORE_DEV}")
@@ -32,17 +40,23 @@ if(EXISTS "${PLUSUI_CORE_DEV}/CMakeLists.txt")
32
40
  set(PLUSUI_FOUND TRUE)
33
41
  endif()
34
42
 
35
- # Location 2: Installed via npm (node_modules)
43
+ # Location 3: Installed via npm (separate core package)
36
44
  if(NOT PLUSUI_FOUND)
37
- set(PLUSUI_CORE_NPM "${CMAKE_SOURCE_DIR}/node_modules/plusui-native-core/Core")
45
+ set(PLUSUI_CORE_NPM "${CMAKE_SOURCE_DIR}/node_modules/plusui-native-core")
46
+ set(PLUSUI_CORE_NPM_LEGACY "${CMAKE_SOURCE_DIR}/node_modules/plusui-native-core/Core")
47
+
38
48
  if(EXISTS "${PLUSUI_CORE_NPM}/CMakeLists.txt")
39
49
  message(STATUS "Found PlusUI Core in node_modules: ${PLUSUI_CORE_NPM}")
40
50
  add_subdirectory("${PLUSUI_CORE_NPM}" "${CMAKE_BINARY_DIR}/plusui-core")
41
51
  set(PLUSUI_FOUND TRUE)
52
+ elseif(EXISTS "${PLUSUI_CORE_NPM_LEGACY}/CMakeLists.txt")
53
+ message(STATUS "Found PlusUI Core in node_modules (legacy): ${PLUSUI_CORE_NPM_LEGACY}")
54
+ add_subdirectory("${PLUSUI_CORE_NPM_LEGACY}" "${CMAKE_BINARY_DIR}/plusui-core")
55
+ set(PLUSUI_FOUND TRUE)
42
56
  endif()
43
57
  endif()
44
58
 
45
- # Location 3: Parent directory development structure
59
+ # Location 4: Parent directory development structure
46
60
  if(NOT PLUSUI_FOUND)
47
61
  set(PLUSUI_CORE_PARENT "${CMAKE_SOURCE_DIR}/../../Core")
48
62
  if(EXISTS "${PLUSUI_CORE_PARENT}/CMakeLists.txt")
@@ -56,11 +70,13 @@ if(NOT PLUSUI_FOUND)
56
70
  message(FATAL_ERROR "
57
71
  PlusUI Core not found!
58
72
 
59
- Make sure you have run 'npm install' or that this project is inside the PlusUI repository.
73
+ Install dependencies (npm install) or add a Core folder in this project root.
60
74
 
61
75
  Searched locations:
76
+ - ${PLUSUI_CORE_LOCAL}
62
77
  - ${PLUSUI_CORE_DEV}
63
- - ${PLUSUI_CORE_NPM}
78
+ - ${PLUSUI_CORE_NPM}
79
+ - ${PLUSUI_CORE_NPM_LEGACY}
64
80
  - ${PLUSUI_CORE_PARENT}
65
81
  ")
66
82
  endif()
@@ -101,13 +117,7 @@ if(WIN32)
101
117
  endif()
102
118
 
103
119
  target_link_libraries({{PROJECT_NAME}} PRIVATE ole32 shell32 shlwapi user32 version)
104
-
105
- # Set subsystem to Windows for release builds (no console window)
106
- if(NOT PLUSUI_DEV_MODE)
107
- set_target_properties({{PROJECT_NAME}} PROPERTIES
108
- WIN32_EXECUTABLE TRUE
109
- )
110
- endif()
120
+ # Keep default console subsystem so standard int main() works in all build modes.
111
121
  elseif(APPLE)
112
122
  # macOS: WebKit
113
123
  find_library(WEBKIT_LIBRARY WebKit REQUIRED)
@@ -147,5 +157,5 @@ endif()
147
157
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
148
158
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
149
159
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
150
-
151
-
160
+
161
+
@@ -10,8 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "react": "^18.2.0",
13
- "react-dom": "^18.2.0",
14
- "plusui-native-core": "{{PLUSUI_CORE_PATH}}"
13
+ "react-dom": "^18.2.0"
15
14
  },
16
15
  "devDependencies": {
17
16
  "@types/react": "^18.2.0",
@@ -20,5 +19,5 @@
20
19
  "typescript": "^5.3.0",
21
20
  "vite": "^5.0.0"
22
21
  }
23
- }
24
-
22
+ }
23
+
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect } from 'react';
2
- import { win, browser, router, app } from 'plusui-native-core';
2
+ import { win, browser, router, app } from './plusui';
3
3
 
4
4
  // Define routes for your app (optional - for SPA routing)
5
5
  const routes = {
@@ -130,5 +130,5 @@ function App() {
130
130
  );
131
131
  }
132
132
 
133
- export default App;
134
-
133
+ export default App;
134
+