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.
Files changed (88) hide show
  1. package/README.md +220 -168
  2. package/core/components/AbsoluteLayout.vue +11 -0
  3. package/core/components/ActionBar.vue +11 -0
  4. package/core/components/ActionItem.vue +11 -0
  5. package/core/components/ActivityIndicator.vue +15 -0
  6. package/core/components/Button.vue +41 -0
  7. package/core/components/DatePicker.vue +27 -0
  8. package/core/components/DockLayout.vue +23 -0
  9. package/core/components/FlexboxLayout.vue +11 -0
  10. package/core/components/Frame.vue +11 -0
  11. package/core/components/GridLayout.vue +85 -0
  12. package/core/components/HtmlView.vue +13 -0
  13. package/core/components/Image.vue +12 -0
  14. package/core/components/ImageCacheIt.vue +12 -0
  15. package/core/components/Label.vue +15 -0
  16. package/core/components/ListPicker.vue +21 -0
  17. package/core/components/ListView.vue +12 -0
  18. package/core/components/NavigationButton.vue +28 -0
  19. package/core/components/Page.vue +18 -0
  20. package/core/components/Placeholder.vue +11 -0
  21. package/core/components/Progress.vue +12 -0
  22. package/core/components/RootLayout.vue +11 -0
  23. package/core/components/ScrollView.vue +11 -0
  24. package/core/components/SearchBar.vue +22 -0
  25. package/core/components/SegmentedBar.vue +50 -0
  26. package/core/components/SegmentedBarItem.vue +21 -0
  27. package/core/components/Slider.vue +18 -0
  28. package/core/components/StackLayout.vue +11 -0
  29. package/core/components/Switch.vue +26 -0
  30. package/core/components/TabView.vue +48 -0
  31. package/core/components/TabViewItem.vue +27 -0
  32. package/core/components/TextField.vue +15 -0
  33. package/core/components/TextView.vue +18 -0
  34. package/core/components/TimePicker.vue +21 -0
  35. package/core/components/WebView.vue +13 -0
  36. package/core/components/WrapLayout.vue +11 -0
  37. package/core/components/index.js +3 -0
  38. package/core/components/index.ts +35 -0
  39. package/core/composables/dialogs.ts +31 -0
  40. package/core/composables/index.js +3 -0
  41. package/core/composables/index.ts +4 -0
  42. package/core/composables/useActionBar.js +7 -0
  43. package/core/composables/useActionBar.ts +19 -0
  44. package/core/composables/useFrame.js +8 -0
  45. package/core/composables/useFrame.ts +25 -0
  46. package/core/composables/usePage.js +8 -0
  47. package/core/composables/usePage.ts +25 -0
  48. package/core/env.d.ts +7 -0
  49. package/core/index.js +4 -0
  50. package/core/index.ts +85 -0
  51. package/core/types.ts +12 -0
  52. package/dist/nativescript-web-adapter.es.js +83 -0
  53. package/dist/nativescript-web-adapter.umd.js +1 -0
  54. package/dist/style.css +1 -0
  55. package/package.json +34 -46
  56. package/tools/cli.cjs +45 -0
  57. package/tools/create-web-platform.cjs +76 -0
  58. package/tools/create-web-platform.js +196 -0
  59. package/tools/modules/appPatch.cjs +27 -0
  60. package/tools/modules/copy.cjs +84 -0
  61. package/tools/modules/router.cjs +46 -0
  62. package/tools/modules/templates.cjs +130 -0
  63. package/tools/modules/transform.cjs +93 -0
  64. package/dist/core.cjs +0 -3
  65. package/dist/core.cjs.map +0 -1
  66. package/dist/core.js +0 -2
  67. package/dist/core.js.map +0 -1
  68. package/dist/index.cjs +0 -240
  69. package/dist/index.cjs.map +0 -1
  70. package/dist/index.js +0 -229
  71. package/dist/index.js.map +0 -1
  72. package/dist/types/core/index.d.ts +0 -8
  73. package/dist/types/index.d.ts +0 -1
  74. package/dist/types/vue/components/ActionBar.d.ts +0 -5
  75. package/dist/types/vue/components/Button.d.ts +0 -26
  76. package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
  77. package/dist/types/vue/components/Frame.d.ts +0 -3
  78. package/dist/types/vue/components/GridLayout.d.ts +0 -27
  79. package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
  80. package/dist/types/vue/components/Label.d.ts +0 -26
  81. package/dist/types/vue/components/Page.d.ts +0 -5
  82. package/dist/types/vue/components/StackLayout.d.ts +0 -5
  83. package/dist/types/vue/index.d.ts +0 -12
  84. package/dist/types/vue.d.ts +0 -169
  85. package/dist/vue.cjs +0 -240
  86. package/dist/vue.cjs.map +0 -1
  87. package/dist/vue.js +0 -229
  88. 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
@@ -1,3 +0,0 @@
1
- 'use strict';
2
-
3
- //# sourceMappingURL=core.cjs.map
package/dist/core.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/dist/core.js DELETED
@@ -1,2 +0,0 @@
1
-
2
- //# sourceMappingURL=core.js.map
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