nativescript-web-adapter 0.1.1 → 0.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.
- package/README.md +220 -168
- package/core/components/AbsoluteLayout.vue +11 -0
- package/core/components/ActionBar.vue +11 -0
- package/core/components/ActionItem.vue +11 -0
- package/core/components/ActivityIndicator.vue +15 -0
- package/core/components/Button.vue +41 -0
- package/core/components/DatePicker.vue +27 -0
- package/core/components/DockLayout.vue +23 -0
- package/core/components/FlexboxLayout.vue +11 -0
- package/core/components/Frame.vue +11 -0
- package/core/components/GridLayout.vue +85 -0
- package/core/components/HtmlView.vue +13 -0
- package/core/components/Image.vue +12 -0
- package/core/components/ImageCacheIt.vue +12 -0
- package/core/components/Label.vue +15 -0
- package/core/components/ListPicker.vue +21 -0
- package/core/components/ListView.vue +12 -0
- package/core/components/NavigationButton.vue +28 -0
- package/core/components/Page.vue +18 -0
- package/core/components/Placeholder.vue +11 -0
- package/core/components/Progress.vue +12 -0
- package/core/components/RootLayout.vue +11 -0
- package/core/components/ScrollView.vue +11 -0
- package/core/components/SearchBar.vue +22 -0
- package/core/components/SegmentedBar.vue +50 -0
- package/core/components/SegmentedBarItem.vue +21 -0
- package/core/components/Slider.vue +18 -0
- package/core/components/StackLayout.vue +11 -0
- package/core/components/Switch.vue +26 -0
- package/core/components/TabView.vue +48 -0
- package/core/components/TabViewItem.vue +27 -0
- package/core/components/TextField.vue +15 -0
- package/core/components/TextView.vue +18 -0
- package/core/components/TimePicker.vue +21 -0
- package/core/components/WebView.vue +13 -0
- package/core/components/WrapLayout.vue +11 -0
- package/core/components/index.js +3 -0
- package/core/components/index.ts +35 -0
- package/core/composables/dialogs.ts +31 -0
- package/core/composables/index.js +3 -0
- package/core/composables/index.ts +4 -0
- package/core/composables/useActionBar.js +7 -0
- package/core/composables/useActionBar.ts +19 -0
- package/core/composables/useFrame.js +8 -0
- package/core/composables/useFrame.ts +25 -0
- package/core/composables/usePage.js +8 -0
- package/core/composables/usePage.ts +25 -0
- package/core/env.d.ts +7 -0
- package/core/index.js +4 -0
- package/core/index.ts +85 -0
- package/core/types.ts +12 -0
- package/dist/nativescript-web-adapter.es.js +83 -0
- package/dist/nativescript-web-adapter.umd.js +1 -0
- package/dist/style.css +1 -0
- package/package.json +34 -46
- package/tools/cli.cjs +45 -0
- package/tools/create-web-platform.cjs +76 -0
- package/tools/create-web-platform.js +196 -0
- package/tools/modules/appPatch.cjs +27 -0
- package/tools/modules/copy.cjs +84 -0
- package/tools/modules/router.cjs +46 -0
- package/tools/modules/templates.cjs +130 -0
- package/tools/modules/transform.cjs +93 -0
- package/dist/core.cjs +0 -3
- package/dist/core.cjs.map +0 -1
- package/dist/core.js +0 -2
- package/dist/core.js.map +0 -1
- package/dist/index.cjs +0 -240
- package/dist/index.cjs.map +0 -1
- package/dist/index.js +0 -229
- package/dist/index.js.map +0 -1
- package/dist/types/core/index.d.ts +0 -8
- package/dist/types/index.d.ts +0 -1
- package/dist/types/vue/components/ActionBar.d.ts +0 -5
- package/dist/types/vue/components/Button.d.ts +0 -26
- package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
- package/dist/types/vue/components/Frame.d.ts +0 -3
- package/dist/types/vue/components/GridLayout.d.ts +0 -27
- package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
- package/dist/types/vue/components/Label.d.ts +0 -26
- package/dist/types/vue/components/Page.d.ts +0 -5
- package/dist/types/vue/components/StackLayout.d.ts +0 -5
- package/dist/types/vue/index.d.ts +0 -12
- package/dist/types/vue.d.ts +0 -169
- package/dist/vue.cjs +0 -240
- package/dist/vue.cjs.map +0 -1
- package/dist/vue.js +0 -229
- package/dist/vue.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function patchAppForWeb(webDir) {
|
|
5
|
+
try {
|
|
6
|
+
const appPath = path.join(webDir, 'src', 'app.ts');
|
|
7
|
+
if (!fs.existsSync(appPath)) {
|
|
8
|
+
console.warn('[web-adapter] 未找到 app.ts,跳过 app 修补');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 动态扫描 websfc 组件目录,生成 import 与注册语句
|
|
13
|
+
const websfcDir = path.join(webDir, 'src', 'components', 'websfc');
|
|
14
|
+
const entries = fs.existsSync(websfcDir) ? fs.readdirSync(websfcDir) : [];
|
|
15
|
+
const vueFiles = entries.filter(f => f.endsWith('.vue'));
|
|
16
|
+
const imports = vueFiles.map(f => `import ${path.basename(f, '.vue')} from './components/websfc/${f}';`).join('\n');
|
|
17
|
+
const registers = vueFiles.map(f => `app.component("${path.basename(f, '.vue')}", ${path.basename(f, '.vue')});`).join('\n');
|
|
18
|
+
const content = `${imports}\nimport * as ns from './composables/websfc/index.ts';\nimport { createApp } from 'vue';\nimport { initGlobals } from "./globals";\nimport router from './router';\nimport App from './App.vue';\nimport './app.css';\n\ninitGlobals();\n\nconst app = createApp(App);\n\n// Register web components\n${registers}\n\n// Register global composables for dialogs, frame, page, etc.\napp.config.globalProperties.$ns = ns;\n\napp.use(router);\napp.mount('#app');`;
|
|
19
|
+
|
|
20
|
+
fs.writeFileSync(appPath, content, 'utf8');
|
|
21
|
+
console.log('[web-adapter] 已修补 app.ts');
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error('[web-adapter] 修补 app.ts 时出错:', err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { patchAppForWeb };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function copyAdapterComponents(srcDir, destDir) {
|
|
5
|
+
if (!fs.existsSync(srcDir)) {
|
|
6
|
+
console.warn('[web-adapter] 适配器组件目录不存在:', srcDir);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (!fs.existsSync(destDir)) {
|
|
10
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
15
|
+
const destPath = path.join(destDir, entry.name);
|
|
16
|
+
if (entry.isDirectory()) {
|
|
17
|
+
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
|
|
18
|
+
copyAdapterComponents(srcPath, destPath);
|
|
19
|
+
} else {
|
|
20
|
+
try {
|
|
21
|
+
fs.copyFileSync(srcPath, destPath);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error('[web-adapter] 复制组件失败:', srcPath, err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function copyAdapterComposables(srcDir, destDir) {
|
|
30
|
+
if (!fs.existsSync(srcDir)) {
|
|
31
|
+
console.warn('[web-adapter] 适配器 composables 目录不存在:', srcDir);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!fs.existsSync(destDir)) {
|
|
35
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
40
|
+
const destPath = path.join(destDir, entry.name);
|
|
41
|
+
if (entry.isDirectory()) {
|
|
42
|
+
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
|
|
43
|
+
copyAdapterComposables(srcPath, destPath);
|
|
44
|
+
} else {
|
|
45
|
+
try {
|
|
46
|
+
fs.copyFileSync(srcPath, destPath);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error('[web-adapter] 复制 composable 文件失败:', srcPath, err);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function copySourceFiles(src, dest, transformContent) {
|
|
55
|
+
if (!fs.existsSync(src)) {
|
|
56
|
+
console.warn('[web-adapter] 源代码目录不存在:', src);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!fs.existsSync(dest)) {
|
|
60
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
const srcPath = path.join(src, entry.name);
|
|
65
|
+
const destPath = path.join(dest, entry.name);
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
copySourceFiles(srcPath, destPath, transformContent);
|
|
68
|
+
} else {
|
|
69
|
+
try {
|
|
70
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
71
|
+
content = transformContent ? transformContent(content, srcPath) : content;
|
|
72
|
+
fs.writeFileSync(destPath, content);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error('[web-adapter] 复制文件失败:', srcPath, err);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
copyAdapterComponents,
|
|
82
|
+
copyAdapterComposables,
|
|
83
|
+
copySourceFiles,
|
|
84
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function buildRouterFromPages(webDir) {
|
|
5
|
+
const pagesDir = path.join(webDir, 'src', 'pages');
|
|
6
|
+
const lines = [];
|
|
7
|
+
lines.push(`import { createRouter, createWebHistory } from 'vue-router'`);
|
|
8
|
+
let routes = [];
|
|
9
|
+
if (fs.existsSync(pagesDir)) {
|
|
10
|
+
const entries = fs.readdirSync(pagesDir, { withFileTypes: true });
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
if (!entry.isFile()) continue;
|
|
13
|
+
if (!/\.vue$/i.test(entry.name)) continue;
|
|
14
|
+
const base = entry.name.replace(/\.vue$/i, '');
|
|
15
|
+
const importName = toIdentifier(base);
|
|
16
|
+
lines.push(`import ${importName} from '../pages/${entry.name}'`);
|
|
17
|
+
const routePath = base.toLowerCase() === 'index' ? '/' : `/${base}`;
|
|
18
|
+
routes.push(` { path: '${routePath}', name: '${base}', component: ${importName} }`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (routes.length === 0) {
|
|
22
|
+
lines.push(`import Home from '../components/Home.vue'`);
|
|
23
|
+
routes.push(` { path: '/', name: 'Home', component: Home }`);
|
|
24
|
+
}
|
|
25
|
+
lines.push('');
|
|
26
|
+
lines.push('const routes = [');
|
|
27
|
+
lines.push(routes.join(',\n'));
|
|
28
|
+
lines.push(']');
|
|
29
|
+
lines.push('');
|
|
30
|
+
lines.push('const router = createRouter({');
|
|
31
|
+
lines.push(' history: createWebHistory(),');
|
|
32
|
+
lines.push(' routes');
|
|
33
|
+
lines.push('})');
|
|
34
|
+
lines.push('');
|
|
35
|
+
lines.push('export default router');
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function toIdentifier(name) {
|
|
40
|
+
let id = name.replace(/[^a-zA-Z0-9_$]/g, '_');
|
|
41
|
+
if (/^[0-9]/.test(id)) id = '_' + id;
|
|
42
|
+
id = id.replace(/(^|_)([a-z])/g, (m, p1, p2) => p1 + p2.toUpperCase());
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { buildRouterFromPages, toIdentifier };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function createWebPlatformFiles(webDir) {
|
|
5
|
+
const projectRoot = path.dirname(path.dirname(webDir));
|
|
6
|
+
// 创建或更新 package.json
|
|
7
|
+
fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify({
|
|
8
|
+
"name": "web-platform",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"private": true,
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "vite",
|
|
13
|
+
"build": "vue-tsc --noEmit && vite build",
|
|
14
|
+
"preview": "vite preview"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"vue": "^3.3.4",
|
|
18
|
+
"vue-router": "^4.2.5"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@vitejs/plugin-vue": "^4.2.3",
|
|
22
|
+
"typescript": "^5.0.2",
|
|
23
|
+
"vite": "^4.4.5",
|
|
24
|
+
"vue-tsc": "^1.8.5",
|
|
25
|
+
"autoprefixer": "^10.4.16",
|
|
26
|
+
"postcss": "^8.4.31",
|
|
27
|
+
"tailwindcss": "^3.4.0"
|
|
28
|
+
}
|
|
29
|
+
}, null, 2));
|
|
30
|
+
|
|
31
|
+
// index.html
|
|
32
|
+
fs.writeFileSync(path.join(webDir, 'index.html'), `<!DOCTYPE html>
|
|
33
|
+
<html lang="en">
|
|
34
|
+
<head>
|
|
35
|
+
<meta charset="UTF-8" />
|
|
36
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
37
|
+
<title>NS Vue Web</title>
|
|
38
|
+
</head>
|
|
39
|
+
<body>
|
|
40
|
+
<div id="app"></div>
|
|
41
|
+
<script type="module" src="/src/app.ts"></script>
|
|
42
|
+
</body>
|
|
43
|
+
</html>`);
|
|
44
|
+
|
|
45
|
+
// vite.config.ts
|
|
46
|
+
const packageJson = {
|
|
47
|
+
name: "ns-vue-web-platform",
|
|
48
|
+
private: true,
|
|
49
|
+
scripts: {
|
|
50
|
+
dev: "vite",
|
|
51
|
+
build: "vite build"
|
|
52
|
+
},
|
|
53
|
+
dependencies: {
|
|
54
|
+
"vue": "^3.4.0",
|
|
55
|
+
"vue-router": "^4.2.5"
|
|
56
|
+
},
|
|
57
|
+
devDependencies: {
|
|
58
|
+
"@vitejs/plugin-vue": "^5.0.0",
|
|
59
|
+
"typescript": "^5.0.0",
|
|
60
|
+
"vite": "^5.0.0",
|
|
61
|
+
"autoprefixer": "^10.4.16",
|
|
62
|
+
"postcss": "^8.4.31",
|
|
63
|
+
"tailwindcss": "^3.4.0"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
fs.writeFileSync(
|
|
67
|
+
path.join(webDir, 'package.json'),
|
|
68
|
+
JSON.stringify(packageJson, null, 2)
|
|
69
|
+
);
|
|
70
|
+
const viteConfig = `import { defineConfig } from 'vite';
|
|
71
|
+
import vue from '@vitejs/plugin-vue';
|
|
72
|
+
import path from 'path';
|
|
73
|
+
|
|
74
|
+
export default defineConfig({
|
|
75
|
+
plugins: [vue()],
|
|
76
|
+
resolve: {
|
|
77
|
+
alias: {
|
|
78
|
+
'@': path.resolve(__dirname, './src')
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
server: {
|
|
82
|
+
port: 3005,
|
|
83
|
+
strictPort: false
|
|
84
|
+
}
|
|
85
|
+
});`;
|
|
86
|
+
fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig);
|
|
87
|
+
|
|
88
|
+
// postcss & tailwind configs: 复用根配置(如果存在),否则写默认
|
|
89
|
+
const rootPostcss = path.join(projectRoot, 'postcss.config.js');
|
|
90
|
+
const rootTailwind = path.join(projectRoot, 'tailwind.config.js');
|
|
91
|
+
try {
|
|
92
|
+
if (fs.existsSync(rootPostcss)) {
|
|
93
|
+
fs.copyFileSync(rootPostcss, path.join(webDir, 'postcss.config.js'));
|
|
94
|
+
} else {
|
|
95
|
+
const postcssConfig = `module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};`;
|
|
96
|
+
fs.writeFileSync(path.join(webDir, 'postcss.config.js'), postcssConfig);
|
|
97
|
+
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.warn('[web-adapter] 复制 postcss 配置失败,使用默认:', e?.message);
|
|
100
|
+
const postcssConfig = `module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};`;
|
|
101
|
+
fs.writeFileSync(path.join(webDir, 'postcss.config.js'), postcssConfig);
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
if (fs.existsSync(rootTailwind)) {
|
|
105
|
+
fs.copyFileSync(rootTailwind, path.join(webDir, 'tailwind.config.js'));
|
|
106
|
+
} else {
|
|
107
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\n "./index.html",\n "./src/**/*.{vue,js,ts,jsx,tsx}",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};`;
|
|
108
|
+
fs.writeFileSync(path.join(webDir, 'tailwind.config.js'), tailwindConfig);
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.warn('[web-adapter] 复制 tailwind 配置失败,使用默认:', e?.message);
|
|
112
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\n "./index.html",\n "./src/**/*.{vue,js,ts,jsx,tsx}",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};`;
|
|
113
|
+
fs.writeFileSync(path.join(webDir, 'tailwind.config.js'), tailwindConfig);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// App.vue(根组件占位,仅渲染 <router-view/>)
|
|
117
|
+
const appVueContent = `<template>
|
|
118
|
+
<router-view></router-view>
|
|
119
|
+
</template>
|
|
120
|
+
|
|
121
|
+
<script setup lang="ts">
|
|
122
|
+
// App root component
|
|
123
|
+
</script>`;
|
|
124
|
+
const appVuePath = path.join(webDir, 'src', 'App.vue');
|
|
125
|
+
const srcDir = path.join(webDir, 'src');
|
|
126
|
+
if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir, { recursive: true });
|
|
127
|
+
fs.writeFileSync(appVuePath, appVueContent, 'utf8');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = { createWebPlatformFiles };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Transform module: handle script-level transformations only
|
|
2
|
+
// - Replace 'nativescript-vue' imports with 'vue'
|
|
3
|
+
// - Remove '@nativescript/core' and adapter imports
|
|
4
|
+
// - Clean platform-specific globals and handlers
|
|
5
|
+
// - Keep template tags intact for custom web components to handle
|
|
6
|
+
|
|
7
|
+
function transformContent(content, srcPath) {
|
|
8
|
+
// globals.ts shim for web
|
|
9
|
+
if (srcPath && /globals\.ts$/.test(srcPath)) {
|
|
10
|
+
return "export function initGlobals() { /* web shim: no-op */ }\n";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Import replacements
|
|
14
|
+
content = content.replace(/from\s+['\"](nativescript-vue)['\"]/g, "from 'vue'");
|
|
15
|
+
content = content.replace(/import\s+.*@nativescript\/core.*;?\n?/g, '');
|
|
16
|
+
content = content.replace(/import\s+.*nativescript-web-adapter.*;?\n?/g, '');
|
|
17
|
+
|
|
18
|
+
// Platform/global cleanup
|
|
19
|
+
content = content.replace(/declare\s+var\s+com[:\s\w]*;?\n?/g, '');
|
|
20
|
+
|
|
21
|
+
// Demo-specific native function replacement
|
|
22
|
+
content = content.replace(/function\s+enterNow\([^\)]*\)\s*\{[\s\S]*?\}\n?/g, "function enterNow() { window.open(\"https://viteconf.amsterdam\", '_blank'); }\n");
|
|
23
|
+
content = content.replace(/function\s+enterNow\([^\)]*\)\s*\{[\s\S]*?\}\s*[\s\S]*?let interval/g, 'function enterNow() { window.open("https://viteconf.amsterdam", \'_blank\'); }\n\nlet interval');
|
|
24
|
+
|
|
25
|
+
// Navigation: compile-time transform for web
|
|
26
|
+
// $navigateTo(Test) -> router.push('/Test')
|
|
27
|
+
// $navigateBack() -> router.go(-1)
|
|
28
|
+
// Frame.navigate(...) -> router.push('/...')
|
|
29
|
+
// Frame.goBack() -> router.go(-1)
|
|
30
|
+
if (srcPath && /\.vue$/i.test(srcPath)) {
|
|
31
|
+
const hasNavigateTo = /\$navigateTo\(\s*[A-Za-z_][A-Za-z0-9_]*\s*\)/.test(content);
|
|
32
|
+
const hasNavigateBack = /\$navigateBack\(\s*\)/.test(content);
|
|
33
|
+
const hasFrameNav = /Frame\.(navigate|goBack)\(/.test(content);
|
|
34
|
+
const hasFrameTopmost = /Frame\.topmost\(\)\.(navigate|goBack)\(/.test(content);
|
|
35
|
+
if (hasNavigateTo || hasNavigateBack || hasFrameNav || hasFrameTopmost) {
|
|
36
|
+
// Replace any property chain ending with $navigateTo(Symbol) -> router.push('/Symbol')
|
|
37
|
+
content = content.replace(/(?:this\.|[A-Za-z_$]+\?\.|[A-Za-z_$]+\.)*\$navigateTo\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
|
|
38
|
+
// Replace any property chain ending with $navigateBack() -> router.go(-1)
|
|
39
|
+
content = content.replace(/(?:this\.|[A-Za-z_$]+\?\.|[A-Za-z_$]+\.)*\$navigateBack\(\s*\)/g, 'router.go(-1)');
|
|
40
|
+
// Replace Frame.goBack() -> router.go(-1)
|
|
41
|
+
content = content.replace(/Frame\.goBack\(\s*\)/g, 'router.go(-1)');
|
|
42
|
+
// Replace Frame.navigate(Identifier) -> router.push('/Identifier')
|
|
43
|
+
content = content.replace(/Frame\.navigate\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
|
|
44
|
+
// Replace Frame.navigate('pages/Test') or module path -> router.push('/Test')
|
|
45
|
+
content = content.replace(/Frame\.navigate\(\s*['\"]([^'\"]+)['\"]\s*\)/g, (m, p1) => {
|
|
46
|
+
const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
|
|
47
|
+
return `router.push('/${base}')`;
|
|
48
|
+
});
|
|
49
|
+
// Replace Frame.navigate({ moduleName: 'pages/Test' }) -> router.push('/Test')
|
|
50
|
+
content = content.replace(/Frame\.navigate\(\s*\{[\s\S]*?moduleName\s*:\s*['\"]([^'\"]+)['\"][\s\S]*?\}\s*\)/g, (m, p1) => {
|
|
51
|
+
const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
|
|
52
|
+
return `router.push('/${base}')`;
|
|
53
|
+
});
|
|
54
|
+
// Replace Frame.topmost().goBack() -> router.go(-1)
|
|
55
|
+
content = content.replace(/Frame\.topmost\(\)\.goBack\(\s*\)/g, 'router.go(-1)');
|
|
56
|
+
// Replace Frame.topmost().navigate(Identifier) -> router.push('/Identifier')
|
|
57
|
+
content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
|
|
58
|
+
// Replace Frame.topmost().navigate('pages/Test') -> router.push('/Test')
|
|
59
|
+
content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*['\"]([^'\"]+)['\"]\s*\)/g, (m, p1) => {
|
|
60
|
+
const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
|
|
61
|
+
return `router.push('/${base}')`;
|
|
62
|
+
});
|
|
63
|
+
// Replace Frame.topmost().navigate({ moduleName: 'pages/Test' }) -> router.push('/Test')
|
|
64
|
+
content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*\{[\s\S]*?moduleName\s*:\s*['\"]([^'\"]+)['\"][\s\S]*?\}\s*\)/g, (m, p1) => {
|
|
65
|
+
const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
|
|
66
|
+
return `router.push('/${base}')`;
|
|
67
|
+
});
|
|
68
|
+
// Ensure router import inside <script> block
|
|
69
|
+
if (!/import\s+router\s+from\s+['\"]@\/router['\"]/.test(content)) {
|
|
70
|
+
content = content.replace(/(<script[^>]*>)/i, "$1\nimport router from '@/router';\n");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Remove platform residual lines and blocks
|
|
76
|
+
content = content.replace(/.*(nativeApp|android\.|UIApplication|NSURL|NSDictionary|com\.tns|intent|startActivity|android\.content).*/g, '');
|
|
77
|
+
content = content.replace(/else\s*\{[\s\S]*?\}/g, '');
|
|
78
|
+
|
|
79
|
+
// Fix markup formatting artifacts
|
|
80
|
+
content = content.replace(/\/\s+\/>/g, '\/>');
|
|
81
|
+
|
|
82
|
+
// Remove registerElement
|
|
83
|
+
content = content.replace(/registerElement\([^)]+\);?\n?/g, '// registerElement removed for web\n');
|
|
84
|
+
|
|
85
|
+
// Remove Application.on handlers if present
|
|
86
|
+
if (content.includes('__ANDROID__') || content.includes('Application.launchEvent')) {
|
|
87
|
+
content = content.replace(/Application\.on[\s\S]*?}\);/g, '');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return content;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { transformContent };
|
package/dist/core.cjs
DELETED
package/dist/core.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"core.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/core.js
DELETED
package/dist/core.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/index.cjs
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var vue = require('vue');
|
|
4
|
-
|
|
5
|
-
const Label = vue.defineComponent({
|
|
6
|
-
name: 'NSLabel',
|
|
7
|
-
props: {
|
|
8
|
-
text: { type: String, default: '' },
|
|
9
|
-
horizontalAlignment: { type: String, default: undefined }
|
|
10
|
-
},
|
|
11
|
-
emits: ['tap'],
|
|
12
|
-
setup(props, { slots, attrs, emit }) {
|
|
13
|
-
var _a;
|
|
14
|
-
const style = {};
|
|
15
|
-
if (props.horizontalAlignment) {
|
|
16
|
-
const map = { center: 'center', left: 'left', right: 'right' };
|
|
17
|
-
style.textAlign = (_a = map[String(props.horizontalAlignment).toLowerCase()]) !== null && _a !== void 0 ? _a : undefined;
|
|
18
|
-
}
|
|
19
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
20
|
-
return () => vue.h('span', { style, onClick, ...attrs }, slots.default ? slots.default() : props.text);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const Button = vue.defineComponent({
|
|
25
|
-
name: 'NSButton',
|
|
26
|
-
props: {
|
|
27
|
-
text: { type: String, default: '' },
|
|
28
|
-
horizontalAlignment: { type: String, default: undefined }
|
|
29
|
-
},
|
|
30
|
-
emits: ['tap'],
|
|
31
|
-
setup(props, { emit, slots, attrs }) {
|
|
32
|
-
var _a;
|
|
33
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
34
|
-
const style = {};
|
|
35
|
-
if (props.horizontalAlignment) {
|
|
36
|
-
const map = {
|
|
37
|
-
center: 'center',
|
|
38
|
-
left: 'start',
|
|
39
|
-
right: 'end',
|
|
40
|
-
stretch: 'stretch'
|
|
41
|
-
};
|
|
42
|
-
style.justifySelf = (_a = map[String(props.horizontalAlignment).toLowerCase()]) !== null && _a !== void 0 ? _a : undefined;
|
|
43
|
-
}
|
|
44
|
-
return () => vue.h('button', { onClick, style, ...attrs }, slots.default ? slots.default() : props.text);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const StackLayout = vue.defineComponent({
|
|
49
|
-
name: 'NSStackLayout',
|
|
50
|
-
emits: ['tap'],
|
|
51
|
-
setup(_, { slots, attrs, emit }) {
|
|
52
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
53
|
-
return () => { var _a; return vue.h('div', { style: { display: 'flex', flexDirection: 'column' }, onClick, ...attrs }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); };
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const FlexboxLayout = vue.defineComponent({
|
|
58
|
-
name: 'NSFlexboxLayout',
|
|
59
|
-
props: {
|
|
60
|
-
flexDirection: { type: String, default: 'row' },
|
|
61
|
-
justifyContent: { type: String, default: 'flex-start' },
|
|
62
|
-
alignItems: { type: String, default: 'stretch' }
|
|
63
|
-
},
|
|
64
|
-
emits: ['tap'],
|
|
65
|
-
setup(props, { slots, attrs, emit }) {
|
|
66
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
67
|
-
return () => { var _a; return vue.h('div', { style: { display: 'flex', flexDirection: props.flexDirection, justifyContent: props.justifyContent, alignItems: props.alignItems }, onClick, ...attrs }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); };
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
function parseTracks(tracks) {
|
|
72
|
-
if (!tracks)
|
|
73
|
-
return undefined;
|
|
74
|
-
return tracks.split(',').map(s => s.trim()).map(t => {
|
|
75
|
-
if (t === '*' || t === 'auto')
|
|
76
|
-
return t === '*' ? '1fr' : 'auto';
|
|
77
|
-
if (/^\d+$/.test(t))
|
|
78
|
-
return `${t}px`;
|
|
79
|
-
return t;
|
|
80
|
-
}).join(' ');
|
|
81
|
-
}
|
|
82
|
-
const GridLayout = vue.defineComponent({
|
|
83
|
-
name: 'NSGridLayout',
|
|
84
|
-
props: {
|
|
85
|
-
rows: { type: String, default: undefined },
|
|
86
|
-
columns: { type: String, default: undefined }
|
|
87
|
-
},
|
|
88
|
-
emits: ['tap'],
|
|
89
|
-
setup(props, { slots, attrs, emit }) {
|
|
90
|
-
var _a, _b;
|
|
91
|
-
const containerStyle = {
|
|
92
|
-
display: 'grid',
|
|
93
|
-
// NS 默认一列:确保子项按行堆叠,而不是同一行多列并排
|
|
94
|
-
gridTemplateColumns: (_a = parseTracks(props.columns)) !== null && _a !== void 0 ? _a : '1fr',
|
|
95
|
-
// 行可选;若未指定,默认自适应内容
|
|
96
|
-
gridTemplateRows: (_b = parseTracks(props.rows)) !== null && _b !== void 0 ? _b : undefined,
|
|
97
|
-
// 以“按行”自动布局,默认逐行堆叠
|
|
98
|
-
gridAutoFlow: 'row',
|
|
99
|
-
width: '100%',
|
|
100
|
-
height: '100%'
|
|
101
|
-
};
|
|
102
|
-
const mapChild = (child) => {
|
|
103
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
104
|
-
if (!vue.isVNode(child))
|
|
105
|
-
return child;
|
|
106
|
-
const cprops = { ...(child.props || {}) };
|
|
107
|
-
const style = { ...(cprops.style || {}) };
|
|
108
|
-
// Row/Column placement: NativeScript uses 0-based indices; CSS Grid is 1-based
|
|
109
|
-
const row = (_a = cprops.row) !== null && _a !== void 0 ? _a : cprops['row'];
|
|
110
|
-
const col = (_c = (_b = cprops.col) !== null && _b !== void 0 ? _b : cprops['col']) !== null && _c !== void 0 ? _c : cprops.column;
|
|
111
|
-
if (row != null) {
|
|
112
|
-
const r = Number(row);
|
|
113
|
-
if (!isNaN(r))
|
|
114
|
-
style.gridRowStart = r + 1;
|
|
115
|
-
}
|
|
116
|
-
if (col != null) {
|
|
117
|
-
const c = Number(col);
|
|
118
|
-
if (!isNaN(c))
|
|
119
|
-
style.gridColumnStart = c + 1;
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// 未声明列时,强制放在第 1 列,避免隐式多列导致并排
|
|
123
|
-
style.gridColumnStart = 1;
|
|
124
|
-
}
|
|
125
|
-
// Horizontal alignment mapping
|
|
126
|
-
const ha = (_d = cprops.horizontalAlignment) !== null && _d !== void 0 ? _d : cprops['horizontalAlignment'];
|
|
127
|
-
if (ha) {
|
|
128
|
-
const map = {
|
|
129
|
-
center: 'center',
|
|
130
|
-
left: 'start',
|
|
131
|
-
right: 'end',
|
|
132
|
-
stretch: 'stretch'
|
|
133
|
-
};
|
|
134
|
-
style.justifySelf = (_e = map[String(ha).toLowerCase()]) !== null && _e !== void 0 ? _e : style.justifySelf;
|
|
135
|
-
}
|
|
136
|
-
// Vertical alignment mapping
|
|
137
|
-
const va = (_f = cprops.verticalAlignment) !== null && _f !== void 0 ? _f : cprops['verticalAlignment'];
|
|
138
|
-
if (va) {
|
|
139
|
-
const map = {
|
|
140
|
-
center: 'center',
|
|
141
|
-
top: 'start',
|
|
142
|
-
bottom: 'end',
|
|
143
|
-
stretch: 'stretch'
|
|
144
|
-
};
|
|
145
|
-
style.alignSelf = (_g = map[String(va).toLowerCase()]) !== null && _g !== void 0 ? _g : style.alignSelf;
|
|
146
|
-
}
|
|
147
|
-
// Row/Column span mapping
|
|
148
|
-
const rowSpan = (_h = cprops.rowSpan) !== null && _h !== void 0 ? _h : cprops['rowSpan'];
|
|
149
|
-
if (rowSpan != null) {
|
|
150
|
-
const rs = Number(rowSpan);
|
|
151
|
-
if (!isNaN(rs) && rs > 1)
|
|
152
|
-
style.gridRowEnd = `span ${rs}`;
|
|
153
|
-
}
|
|
154
|
-
const colSpan = (_j = cprops.colSpan) !== null && _j !== void 0 ? _j : cprops['colSpan'];
|
|
155
|
-
if (colSpan != null) {
|
|
156
|
-
const cs = Number(colSpan);
|
|
157
|
-
if (!isNaN(cs) && cs > 1)
|
|
158
|
-
style.gridColumnEnd = `span ${cs}`;
|
|
159
|
-
}
|
|
160
|
-
cprops.style = style;
|
|
161
|
-
return vue.h(child.type, cprops, child.children);
|
|
162
|
-
};
|
|
163
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
164
|
-
return () => {
|
|
165
|
-
var _a, _b;
|
|
166
|
-
const children = (_b = (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)) !== null && _b !== void 0 ? _b : [];
|
|
167
|
-
const mapped = children.map(mapChild);
|
|
168
|
-
return vue.h('div', { style: containerStyle, onClick, ...attrs }, mapped);
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const Page = vue.defineComponent({
|
|
174
|
-
name: 'NSPage',
|
|
175
|
-
emits: ['tap'],
|
|
176
|
-
setup(_, { slots, attrs, emit }) {
|
|
177
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
178
|
-
return () => { var _a; return vue.h('main', { onClick, ...attrs }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); };
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
const Frame = vue.defineComponent({
|
|
183
|
-
name: 'NSFrame',
|
|
184
|
-
setup(_, { slots, attrs }) {
|
|
185
|
-
return () => { var _a; return vue.h('div', { ...attrs }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); };
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const ActionBar = vue.defineComponent({
|
|
190
|
-
name: 'NSActionBar',
|
|
191
|
-
emits: ['tap'],
|
|
192
|
-
setup(_, { slots, attrs, emit }) {
|
|
193
|
-
const onClick = (e) => emit('tap', { eventName: 'tap', object: e.currentTarget });
|
|
194
|
-
return () => { var _a; return vue.h('header', { onClick, ...attrs }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); };
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
const ImageCacheIt = vue.defineComponent({
|
|
199
|
-
name: 'ImageCacheIt',
|
|
200
|
-
props: {
|
|
201
|
-
src: { type: String, required: true },
|
|
202
|
-
stretch: { type: String, default: 'aspectFill' }
|
|
203
|
-
},
|
|
204
|
-
setup(props, { attrs }) {
|
|
205
|
-
const style = { width: '100%', display: 'block', objectPosition: 'center' };
|
|
206
|
-
if (props.stretch === 'aspectFill') {
|
|
207
|
-
style.objectFit = 'cover';
|
|
208
|
-
}
|
|
209
|
-
else if (props.stretch === 'aspectFit') {
|
|
210
|
-
style.objectFit = 'contain';
|
|
211
|
-
}
|
|
212
|
-
return () => vue.h('img', { src: props.src, style, ...attrs });
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const NativeScriptWebPlugin = {
|
|
217
|
-
install(app) {
|
|
218
|
-
app.component('Label', Label);
|
|
219
|
-
app.component('Button', Button);
|
|
220
|
-
app.component('StackLayout', StackLayout);
|
|
221
|
-
app.component('FlexboxLayout', FlexboxLayout);
|
|
222
|
-
app.component('GridLayout', GridLayout);
|
|
223
|
-
app.component('Page', Page);
|
|
224
|
-
app.component('Frame', Frame);
|
|
225
|
-
app.component('ActionBar', ActionBar);
|
|
226
|
-
app.component('ImageCacheIt', ImageCacheIt);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
exports.ActionBar = ActionBar;
|
|
231
|
-
exports.Button = Button;
|
|
232
|
-
exports.FlexboxLayout = FlexboxLayout;
|
|
233
|
-
exports.Frame = Frame;
|
|
234
|
-
exports.GridLayout = GridLayout;
|
|
235
|
-
exports.ImageCacheIt = ImageCacheIt;
|
|
236
|
-
exports.Label = Label;
|
|
237
|
-
exports.NativeScriptWebPlugin = NativeScriptWebPlugin;
|
|
238
|
-
exports.Page = Page;
|
|
239
|
-
exports.StackLayout = StackLayout;
|
|
240
|
-
//# sourceMappingURL=index.cjs.map
|