nativescript-web-adapter 0.1.2 → 0.1.5

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 (100) hide show
  1. package/README.md +220 -244
  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 +35 -49
  56. package/tools/cli.cjs +59 -0
  57. package/tools/create-nuxt-platform.cjs +57 -0
  58. package/tools/create-web-platform.cjs +76 -0
  59. package/tools/create-web-platform.js +196 -0
  60. package/tools/modules/appPatch.cjs +27 -0
  61. package/tools/modules/copy.cjs +84 -0
  62. package/tools/modules/router.cjs +46 -0
  63. package/tools/modules/templates-nuxt.cjs +63 -0
  64. package/tools/modules/templates.cjs +130 -0
  65. package/tools/modules/transform-nuxt.cjs +59 -0
  66. package/tools/modules/transform.cjs +93 -0
  67. package/dist/core.cjs +0 -3
  68. package/dist/core.cjs.map +0 -1
  69. package/dist/core.js +0 -2
  70. package/dist/core.js.map +0 -1
  71. package/dist/index.cjs +0 -377
  72. package/dist/index.cjs.map +0 -1
  73. package/dist/index.css +0 -172
  74. package/dist/index.js +0 -361
  75. package/dist/index.js.map +0 -1
  76. package/dist/types/core/index.d.ts +0 -8
  77. package/dist/types/index.d.ts +0 -1
  78. package/dist/types/index.types.d.ts +0 -1
  79. package/dist/types/vue/components/ActionBar.d.ts +0 -5
  80. package/dist/types/vue/components/ActionItem.d.ts +0 -15
  81. package/dist/types/vue/components/Button.d.ts +0 -26
  82. package/dist/types/vue/components/ContentView.d.ts +0 -3
  83. package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
  84. package/dist/types/vue/components/Frame.d.ts +0 -3
  85. package/dist/types/vue/components/GridLayout.d.ts +0 -26
  86. package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
  87. package/dist/types/vue/components/Label.d.ts +0 -26
  88. package/dist/types/vue/components/ListView.d.ts +0 -24
  89. package/dist/types/vue/components/Page.d.ts +0 -5
  90. package/dist/types/vue/components/StackLayout.d.ts +0 -5
  91. package/dist/types/vue/components/TabView.d.ts +0 -26
  92. package/dist/types/vue/components/TabViewItem.d.ts +0 -24
  93. package/dist/types/vue/index.d.ts +0 -18
  94. package/dist/types/vue/index.types.d.ts +0 -17
  95. package/dist/types/vue.d.ts +0 -266
  96. package/dist/vue.cjs +0 -377
  97. package/dist/vue.cjs.map +0 -1
  98. package/dist/vue.css +0 -172
  99. package/dist/vue.js +0 -361
  100. package/dist/vue.js.map +0 -1
package/README.md CHANGED
@@ -1,270 +1,246 @@
1
1
  # NativeScript for Web
2
2
 
3
- Read this in Chinese: [README_ZH.md](README_ZH.md)
3
+ 中文: [README_ZH.md](README_ZH.md)
4
4
 
5
- Map common NativeScript UI tags to browser-ready Vue 3 components, enabling the same SFC to run on both Native and Web. Inspired by React Native for Web.
5
+ [![npm](https://img.shields.io/npm/v/nativescript-web-adapter.svg?logo=npm&label=npm)](https://www.npmjs.com/package/nativescript-web-adapter)
6
+ [![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
7
 
7
- Ideal for quickly previewing, debugging, or shipping a simplified web version of existing NativeScript Vue projects.
8
+ This project is a “web adapter” for NativeScript‑Vue‑Vite. It can transform native app code into a pure Vue Web project that runs in the browser (generated under `platforms/web/`).
8
9
 
9
- ## Features
10
+ ---
10
11
 
11
- - Same tag names: use `Page`, `ActionBar`, `GridLayout`, `Label`, `Button`, `ImageCacheIt` directly in SFCs.
12
- - Prop and event mapping: common props/events are translated to DOM (e.g., `tap` → `click`).
13
- - Lightweight implementation: focuses on frequently used layouts and controls.
14
- - Pluggable: registered as a Vue plugin; no invasive app changes.
12
+ ## Quick Start
15
13
 
16
- ## Installation
17
-
18
- Install the adapter from npm:
19
-
20
- ```
14
+ ```bash
21
15
  npm install nativescript-web-adapter
22
16
  ```
23
17
 
24
- This package expects `vue` as a peer dependency. If not already present:
25
-
26
- ```
27
- npm install vue@^3.4.0
28
- ```
29
-
30
- ## Quick Start (Web)
31
-
32
- 1) Register the plugin
18
+ Compile the web template install dependencies start the web project's dev server:
33
19
 
34
- ```ts
35
- // src/web/main.ts
36
- import { createApp } from 'vue';
37
- import { NativeScriptWebPlugin } from 'nativescript-web-adapter';
38
- import Home from '@/components/Home.vue';
39
- import '@/app.css';
20
+ vue
40
21
 
41
- const app = createApp(Home);
42
- app.use(NativeScriptWebPlugin);
43
- app.mount('#app');
44
- ```
45
-
46
- 2) Vite aliases (map NS deps to the adapter for browser)
47
-
48
- ```ts
49
- // vite.web.config.ts
50
- import { defineConfig } from 'vite';
51
- import vue from '@vitejs/plugin-vue';
52
- import path from 'path';
53
-
54
- export default defineConfig({
55
- plugins: [vue()],
56
- resolve: {
57
- alias: {
58
- '@': path.resolve(__dirname, 'src'),
59
- '~': path.resolve(__dirname, 'src'),
60
- // map SFC imports of nativescript-vue to browser vue
61
- 'nativescript-vue': 'vue',
62
- // map @nativescript/core types/APIs to adapter core (browser-only)
63
- '@nativescript/core': 'nativescript-web-adapter/core'
64
- }
65
- }
66
- });
22
+ ```bash
23
+ npx ns-web vue
67
24
  ```
68
25
 
69
- 3) Start the dev server
26
+ nuxt
70
27
 
71
28
  ```bash
72
- npm run dev:web
29
+ npx ns-web nuxt
73
30
  ```
74
31
 
75
- ## Usage Example
76
-
77
- ```vue
78
- <template>
79
- <Frame>
80
- <Page class="bg-[#251353]">
81
- <ActionBar>
82
- <Label text="ViteConf 2025" class="font-bold text-lg" />
83
- </ActionBar>
84
-
85
- <GridLayout rows="auto,*">
86
- <ImageCacheIt
87
- src="https://example.com/cover.jpg"
88
- stretch="aspectFill"
89
- class="align-top"
90
- style="width:100dvw"
91
- />
92
-
93
- <GridLayout row="1" rows="*,auto,*" class="gradient-purple p-6">
94
- <Label
95
- class="text-xl align-middle text-center text-[#77c9fa] font-bold"
96
- text="Hype Counter: 31485"
97
- />
98
-
99
- <Button
100
- row="1"
101
- class="p-6 text-white font-bold border-4 border-[#77c9fa] rounded-lg text-xl gradient-light-purple"
102
- horizontalAlignment="center"
103
- >
104
- Enter Now
105
- </Button>
106
- </GridLayout>
107
- </GridLayout>
108
- </Page>
109
- </Frame>
110
- </template>
111
- ```
112
-
113
- ## Component Mapping
114
-
115
- - `Page` → DOM `main`
116
- - `ActionBar` → DOM `header`
117
- - `Frame` → DOM `div`
118
- - `Label` → DOM `span`
119
- - `Button` → DOM `button`
120
- - `StackLayout` → DOM `div` (`display:flex; flex-direction:column`)
121
- - `FlexboxLayout` → DOM `div` (`display:flex`; supports `flexDirection`, `justifyContent`, `alignItems`)
122
- - `GridLayout` → DOM `div` (`display:grid`; details below)
123
- - `ImageCacheIt` → DOM `img` (simple replacement; uses `img` with `stretch` support)
124
-
125
- ## Newly Supported Components
126
-
127
- - `ActionItem` → DOM `div` inside `ActionBar`
128
- - Renders slot content (e.g., a `Button`)
129
- - Supports `ios.position="right"` to push the item to the right (`margin-left:auto`)
130
-
131
- - `ContentView` → DOM `div`
132
- - A simple container that passes classes and styles through
32
+ iOS
133
33
 
134
- - `ListView` → DOM `div`
135
- - Accepts `:items` (array) and renders the default slot for each item
136
- - Supports `separatorColor` (e.g., `transparent` or `rgba(...)`)
137
- - Minimal, performant rendering aimed at common list use cases
138
-
139
- ## Custom CSS Usage
140
-
141
- - Built-in base classes are provided for web rendering in `dist/vue.css`.
142
- - Optional import (recommended for consistent base styles):
143
-
144
- ```ts
145
- // src/web/main.ts
146
- import 'nativescript-web-adapter/dist/vue.css';
34
+ ```bash
35
+ ns run ios
147
36
  ```
148
37
 
149
- - You can define your own classes in `src/app.css` and apply them to NS tags.
150
- - Example list styling that pairs well with `ListView` and `GridLayout`:
151
-
152
- ```css
153
- /* src/app.css */
154
- .list-container {}
155
- .list-item { display:grid; grid-template-columns:1fr auto; align-items:center; padding:12px 16px; border-bottom:1px solid rgba(255,255,255,0.12); }
156
- .list-item:hover { background:rgba(255,255,255,0.06); border-radius:12px; }
157
- .list-title { font-size:18px; color:#fff; }
158
- .list-dot { width:20px; height:20px; border-radius:9999px; background:#fff; }
159
- .back-button { padding:8px 12px; color:#fff; font-weight:600; border:2px solid #77c9fa; border-radius:12px; font-size:14px; background:linear-gradient(to bottom, #6544b7, #251353); }
160
- ```
38
+ Android
161
39
 
162
- - Example usage in a SFC:
163
-
164
- ```vue
165
- <template>
166
- <Page>
167
- <ActionBar title="Details">
168
- <!-- Web-only back button; native uses system back -->
169
- <ActionItem>
170
- <Button text="Back" class="back-button" @tap="goBack" />
171
- </ActionItem>
172
- </ActionBar>
173
-
174
- <ListView :items="items" separatorColor="rgba(255,255,255,0.12)" class="list-container">
175
- <template #default="{ item }">
176
- <GridLayout columns="*, auto" class="list-item">
177
- <Label :text="item" class="list-title" />
178
- <ContentView col="1" class="list-dot" />
179
- </GridLayout>
180
- </template>
181
- </ListView>
182
- </Page>
183
- </template>
40
+ ```bash
41
+ ns run android
184
42
  ```
185
43
 
186
- ## Extending the Adapter & Contributing
44
+ ## Table of Contents
45
+
46
+ - Background & Goals
47
+ - Tech Stack & Dependencies
48
+ - Native Side (NativeScript)
49
+ - Web Side (Generated Vue Project)
50
+ - Web Adapter (Generator & Package)
51
+ - Run & Build
52
+ - Transformation & Adaptation Rules (Detailed)
53
+ - Styles & Tailwind Configuration
54
+ - Types & TS Configuration
55
+ - HMR (Hot Module Replacement)
56
+ - FAQ & Limitations
57
+ - Improvements & Upgrade Suggestions
58
+
59
+ ---
60
+
61
+ ## Background & Goals
62
+
63
+ - Provide a native app example using `nativescript-vue` + `@nativescript/vite`, showcasing development and HMR on iOS/Android.
64
+ - Provide a “web adapter” (local package `nativescript-web-adapter`) that scans and transforms the project's `src/` code to generate a Vue application that runs in the browser, enabling quick preview and collaboration on desktop browsers.
65
+ - The generated Web project lives in `platforms/web/` with its own Vite config, dependencies, and entry files, without affecting the native side.
66
+
67
+ ---
68
+
69
+ ## Tech Stack & Dependencies
70
+
71
+ - Native side (NativeScript):
72
+ - `nativescript-vue@3.0.1` (uses `patch-package` to inject HMR helpers)
73
+ - `@nativescript/core@alpha`, `@nativescript/vite@^0.0.1-alpha.7` (NativeScript v9 prerelease)
74
+ - Example native plugins: `@triniwiz/nativescript-image-cache-it`, `@valor/nativescript-websockets`, `nativescript-inappbrowser`
75
+ - Web side (generated project):
76
+ - `vue@^3.4`, `vue-router@^4.2`
77
+ - `vite@^5`, `@vitejs/plugin-vue@^5`
78
+ - `tailwindcss@^3.4`, `postcss`, `autoprefixer`
79
+ - Adapter package (local):
80
+ - `nativescript-web-adapter/` uses Vite library mode to build UMD/ESM, with built-in generator scripts and a simple CLI.
81
+
82
+ ---
83
+
84
+ ## Native Side (NativeScript)
85
+
86
+ - Entry `src/app.ts`:
87
+ - Starts the native app via `createApp(Home).start()` from `nativescript-vue`.
88
+ - Registers the native element `ImageCacheIt`.
89
+ - On Android, uses `Application.on(Application.launchEvent)` to adjust system status/navigation bar styles.
90
+ - Page `src/components/Home.vue`:
91
+ - Uses NS layouts and components such as `Frame/Page/ActionBar/GridLayout/Label/Button/ImageCacheIt`.
92
+ - Uses `@tap` to open native links (iOS uses `UIApplication.openURL`, Android uses `Intent`).
93
+ - Maintains a simple counter in `mounted/unmounted` to demonstrate HMR and state refresh.
94
+ - Global init `src/globals.ts`:
95
+ - Defines touch animations (iOS: `UIView.animate`, Android: `View.animate`), replaced by a no‑op shim on the Web side.
96
+ - Native Vite config `vite.config.ts`:
97
+ - `export default defineConfig(({ mode }) => mergeConfig(vueConfig({ mode }), {}))` merges the NS official Vite template to support HMR and build.
98
+ - Tailwind & styles:
99
+ - `src/app.css` defines theme colors and gradient classes (`gradient-purple/gradient-light-purple`), and sets the `ActionBar` primary color.
100
+ - `tailwind.config.js` uses `darkMode: ["class", ".ns-dark"]` and disables `preflight` (matching native rendering).
101
+
102
+ ---
103
+
104
+ ## Web Side (Generated Vue Project)
105
+
106
+ - Output location: `platforms/web/`
107
+ - Example structure:
187
108
 
188
- ### Add a New Component
189
-
190
- 1. Create the component under `src/vue/components/YourComponent.ts` using `defineComponent` and map props/events to DOM.
191
- 2. Register it in `src/vue/index.ts` under the plugin so it becomes available in Vue.
192
- 3. Export its types in `src/vue/index.types.ts` to keep type parity.
193
- 4. Add baseline styles in `src/vue/adapter.css` (class name convention: `.ns-your-component`).
194
- 5. Build the adapter with `npm run build` and test in the demo project (`npm run dev:web`).
195
-
196
- ### PR Guidelines
197
-
198
- - Keep implementations lightweight and focused on common use cases.
199
- - Preserve NativeScript semantics where reasonable; document any deviations.
200
- - Map events consistently (e.g., `tap` → `click`).
201
- - Include type exports, baseline CSS, and an example snippet in the docs.
202
- - Add or update tests where applicable (`tests/*`).
203
- - Keep code style consistent with existing files; avoid introducing heavy dependencies.
204
-
205
- ## GridLayout: Design & Behavior
206
-
207
- - Container styles
208
- - `display: grid`
209
- - `grid-template-columns`: defaults to single column `1fr` when `columns` is not provided
210
- - `grid-template-rows`: parsed from `rows` (optional)
211
- - `grid-auto-flow: row`: auto-stacks vertically by rows
212
- - `width: 100%`, `height: 100%`
213
-
214
- - Track parsing (`rows`/`columns`)
215
- - Comma-separated: e.g., `"auto,*"`, `"*,auto,*"`
216
- - `*` → `1fr`, `auto` → `auto`, numbers → pixels (e.g., `60` → `60px`)
217
- - Example: `rows="auto,*"` → `grid-template-rows: auto 1fr`
218
-
219
- - Child placement & span
220
- - Indexing: NativeScript is 0-based; CSS Grid is 1-based. `row=0` → `grid-row-start:1`, `col=0` → `grid-column-start:1`
221
- - Default column: if `col`/`column` is not set, we enforce `grid-column-start:1` to avoid implicit multi-column side-by-side layout
222
- - Span: `rowSpan` → `grid-row-end: span n`; `colSpan` → `grid-column-end: span n`
223
-
224
- - Alignment
225
- - Horizontal: `horizontalAlignment` (`left|center|right|stretch`) → `justify-self`
226
- - Vertical: `verticalAlignment` (`top|center|bottom|stretch`) → `align-self`
227
-
228
- ## Other Props & Events
229
-
230
- - Events: `tap` → DOM `click` (the adapter emits `tap` on `onClick`)
231
- - `Label` alignment: `horizontalAlignment="center"` → `text-align:center`
232
- - `ImageCacheIt`:
233
- - `stretch="aspectFill"` → `object-fit: cover`
234
- - `stretch="aspectFit"` → `object-fit: contain`
235
- - default styles: `width:100%`, `display:block`, `object-position:center`
236
-
237
- ## Layout Tips (Aligning Web with iOS)
238
-
239
- - Make the outer `main` full viewport height: `main { height: 100vh; }` to match Grid remaining-space behavior.
240
- - For full-width images: use `style="width:100dvw"` or container `width:100%`; ensure no implicit columns. Optionally set inner `GridLayout` `columns="1*"`.
241
- - If children appear side-by-side: check if `columns` is declared or `col` is set; by default we fix to column 1.
242
-
243
- ## Compatibility & Limitations
244
-
245
- - The adapter focuses on common UI/layout features; complex native measurements, animations, and platform APIs are out of scope for the browser.
246
- - Visual differences (fonts, line height, shadows) exist between iOS/Android and browsers; tweak via Tailwind/CSS.
247
- - Events follow the DOM model; certain native events are not applicable.
248
-
249
- ## Development & Build
250
-
251
- - Build the adapter: `npm run build` (outputs `dist/index.js`, `dist/vue.js`, `dist/core.js` and types)
252
- - Run tests: `npm run test`
253
- - Demo project in this repo: `npm run dev:web` starts the browser preview.
254
-
255
- ## Package Structure (Adapter Subpackage)
256
-
257
- - `src/vue/components/*`: implementation of UI components
258
- - `src/vue/index.ts`: Vue plugin entry (registers all components)
259
- - `src/core`: minimal types/placeholders for `@nativescript/core` in browser
260
- - `dist/*`: build outputs and type declarations
261
-
262
- ## Design Rationale
263
-
264
- - Keep NativeScript tag parity to reduce migration and dual-edge maintenance costs.
265
- - Use standard web layout primitives (Flex/Grid) for debuggability and extensibility.
266
- - Clear mapping rules: 0→1 index conversion, `*`/`auto`/px track parsing, and alignment/span mapping — minimal surprises.
267
-
268
- ## Feedback & Improvements
109
+ ```
110
+ platforms/web/
111
+ package.json # generated (includes vue + vue-router)
112
+ vite.config.ts # generated (server.port = 3005, strictPort = true)
113
+ index.html
114
+ postcss.config.js
115
+ tailwind.config.js
116
+ src/
117
+ App.vue # root component (<router-view />)
118
+ app.ts # entry (register adapter web components, mount '#app')
119
+ router/index.ts # default route (Home)
120
+ globals.ts # web shim: initGlobals() no-op
121
+ components/
122
+ Home.vue # copied and transformed from native
123
+ websfc/ # adapter web components (ActionBar/Page/Frame)
124
+ composables/
125
+ websfc/ # adapter composables (useActionBar/usePage/useFrame)
126
+ ```
269
127
 
270
- Try it in your projects and share feedback. If you need more components or refined behaviors (absolute positioning, interactions), add implementations under `src/vue/components` following the existing pattern, and submit a PR.
128
+ - Default dev URL: `http://localhost:3005/` (if the port is taken, it fails directly; set `strictPort` to `false` in `vite.config.ts` to enable fallback).
129
+
130
+ ---
131
+
132
+ ## Web Adapter (Generator & Package)
133
+
134
+ - Location: `nativescript-web-adapter/`
135
+ - Key files:
136
+ - `tools/create-web-platform.cjs`: generation script (copy, transform, write templates).
137
+ - `core/components/*.vue`: web SFC containers (`ActionBar/Page/Frame`).
138
+ - `core/composables/*.ts`: composables (`useActionBar/usePage/useFrame`).
139
+ - `core/types.ts`: component type aliases and composable type exports.
140
+ - `index.ts`: adapter installer (`install(app)` registers components and attaches `$ns`).
141
+ - `vite.config.ts`: library mode build (`external: ['vue']`, outputs UMD/ESM).
142
+ - CLI: `tools/cli.cjs`
143
+ - Local command: `node nativescript-web-adapter/tools/cli.cjs init`
144
+ - Includes a `create:web` NPM script (for the root project to call).
145
+
146
+ ---
147
+
148
+ ## Run & Build
149
+
150
+ - Native side (with HMR):
151
+ - `npm run dev:ios`: run Vite (port `5173`) and NS iOS debug in parallel.
152
+ - `npm run dev:android`: run Vite and NS Android debug in parallel.
153
+ - `npm run ios` / `npm run android`: use `ns debug` for debugging builds.
154
+ - Generate and run the Web project:
155
+ - `npm run dev:web`: run the adapter generator, then enter `platforms/web`, install deps, and start the Web Vite dev server.
156
+ - On first run, it creates `platforms/web` along with required templates and configuration.
157
+
158
+ ---
159
+
160
+ ## Transformation & Adaptation Rules (Detailed)
161
+
162
+ The generator’s `transformContent()` currently performs only necessary code‑level replacements and no longer replaces NS tags in SFC templates with native HTML tags; the UI is handled by custom web components.
163
+
164
+ - Import replacements and removals:
165
+ - `from 'nativescript-vue'` → `from 'vue'`
166
+ - Remove `import ... from '@nativescript/core'` (the web build does not load the native runtime)
167
+ - Remove `import ... from '@nativescript/web-adapter'` (the generated web project uses local components directly)
168
+ - Platform declarations and native calls cleanup:
169
+ - Remove common native declarations (e.g., `declare var com;`).
170
+ - Remove `Application.on(...)` and similar platform event registrations (including those with `__ANDROID__` or `Application.launchEvent`).
171
+ - Template retains NS tags:
172
+ - Components kept and registered on the Web: `ActionBar/Page/Frame/StackLayout/GridLayout/FlexboxLayout/WrapLayout/ScrollView/Label/Button/Image/HtmlView/ImageCacheIt`.
173
+ - Special downgrade: `ImageCacheIt` is implemented as a simple `<img>` on the Web (also provided as a web component of the same name for consistent usage).
174
+ - Unified native link opening logic:
175
+ - Replace the example `enterNow(...)` with the browser implementation: `window.open('https://viteconf.amsterdam', '_blank')`.
176
+ - Other cleanup:
177
+ - Remove lines involving `android.*`, `UIApplication`, `NSURL`, `NSDictionary`, `intent`, etc.
178
+ - Remove leftover `else { ... }` native branch blocks.
179
+ - Comment out `registerElement(...)` (not needed on the Web).
180
+ - Special file handling:
181
+ - Replace `globals.ts` with a no‑op shim: `export function initGlobals() { /* web shim: no-op */ }`.
182
+
183
+ > Tip: The current transformation is regex‑driven and covers common patterns. For complex conditional branches, dynamic templates, and advanced native APIs, consider moving to TypeScript/Vue SFC AST‑based transformations to improve accuracy and maintainability.
184
+
185
+ ---
186
+
187
+ ## Styles & Tailwind Configuration
188
+
189
+ - Native side:
190
+ - `src/app.css` uses `@tailwind base/components/utilities` and defines theme styles and gradient backgrounds.
191
+ - `tailwind.config.js`:
192
+ - `content: ["./src/**/*.{css,vue,ts,tsx}"]`
193
+ - `darkMode: ["class", ".ns-dark"]`
194
+ - `corePlugins.preflight: false` (disables browser preset resets)
195
+ - Web side (generated):
196
+ - `tailwind.config.js` scans `./index.html` and `./src/**/*.{vue,js,ts,jsx,tsx}` and uses standard browser presets.
197
+ - `postcss.config.js`: enables `tailwindcss` and `autoprefixer`.
198
+
199
+ ---
200
+
201
+ ## Types & TS Configuration
202
+
203
+ - Root `tsconfig.json`:
204
+ - `strict: true`, target and module set to `esnext`.
205
+ - Path aliases: `~/*`, `@/*` → `src/*`.
206
+ - `vueCompilerOptions.lib = "nativescript-vue"` instructs SFC compilation for the NS environment.
207
+ - Type declarations:
208
+ - Native side `types/shims.vue.d.ts`: points `*.vue` types to `nativescript-vue`’s `DefineComponent`.
209
+ - Adapter side `core/env.d.ts`: points `*.vue` types to `vue`’s `DefineComponent`, consistent with browser compilation.
210
+ - Adapter `core/types.ts`: provides type aliases for `ActionBar/Page/Frame` components and exports state types for `useActionBar/usePage/useFrame`.
211
+
212
+ ---
213
+
214
+ ## HMR (Hot Module Replacement)
215
+
216
+ - Native side:
217
+ - Uses `@nativescript/vite` with `vite serve -- --env.hmr` to establish an HMR channel, pushing changes to the device.
218
+ - `patches/nativescript-vue+3.0.1.patch` injects within `app.start`: `globalThis.__NS_VUE_APP__ = app`, helping restore state in deep navigation stacks (e.g., when returning during HMR).
219
+ - Web side:
220
+ - Independent Vite (`platforms/web/vite.config.ts`) runs on port `3005`, using standard Vue HMR and route refresh.
221
+
222
+ ---
223
+
224
+ ## FAQ & Limitations
225
+
226
+ - Native APIs & plugins:
227
+ - Complex native interactions (platform‑specific modules, system services) cannot be automatically converted to the Web. They require manual replacement or browser fallback implementations (e.g., `InAppBrowser` → `window.open` wrapper).
228
+ - Layout & semantic mapping is limited:
229
+ - Basic web components are provided (`ActionBar/Page/Frame/Grid/Stack/Flex/Wrap/Scroll/Label/Button/Image/HtmlView/ImageCacheIt`). More detailed property‑to‑style mappings will be added later (e.g., `flexDirection/row`, grid rows/columns).
230
+ - Regex‑driven transformation:
231
+ - Edge cases may exist for complex code and templates. Gradually moving to AST‑level transformation is recommended.
232
+ - Generator template duplicate writes:
233
+ - The generator currently writes `platforms/web/package.json` twice (with different dependency versions). This can be streamlined into a single write to reduce maintenance cost.
234
+
235
+ ---
236
+
237
+ ## Improvements & Upgrade Suggestions
238
+
239
+ 1. Transformation engine upgrade:
240
+ - Replace regex with TypeScript and Vue SFC AST to precisely handle imports, calls, templates, and directive mappings.
241
+ 2. Global initialization & animations:
242
+ - Provide optional web animation implementations (CSS transitions/GSAP) for `globals.ts` to keep interaction behavior consistent.
243
+ 3. Tests & validation:
244
+ - Add unit tests and e2e tests for transformation rules and template generation to ensure stability across different project structures.
245
+
246
+ ---
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-absolute"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'AbsoluteLayout' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-absolute { position: relative; width: 100%; height: 100%; }
11
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <header class="ns-actionbar"><slot /></header>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'ActionBar' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-actionbar { padding: 12px; }
11
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <button class="ns-actionitem"><slot /></button>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'ActionItem' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-actionitem { background: transparent; border: none; color: inherit; cursor: pointer; padding: 8px; }
11
+ </style>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div class="ns-activity-indicator" :class="{ busy }" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ const props = defineProps<{ busy?: boolean }>();
7
+ const busy = props.busy ?? true;
8
+ defineOptions({ name: 'ActivityIndicator' });
9
+ </script>
10
+
11
+ <style scoped>
12
+ .ns-activity-indicator { width: 20px; height: 20px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.3); border-top-color: currentColor; opacity: 0.8; }
13
+ .ns-activity-indicator.busy { animation: ns-spin 0.8s linear infinite; }
14
+ @keyframes ns-spin { to { transform: rotate(360deg) } }
15
+ </style>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <button class="ns-button" :style="btnStyle" @click="$emit('tap', $event)"><slot /></button>
3
+
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ import { computed } from 'vue';
8
+ defineOptions({ name: 'Button' });
9
+ const emit = defineEmits<{ (e: 'tap', evt: MouseEvent): void }>();
10
+ const props = defineProps<{ horizontalAlignment?: string }>();
11
+
12
+ const btnStyle = computed<Record<string, string>>(() => {
13
+ const style: Record<string, string> = {};
14
+ const h = props.horizontalAlignment?.toLowerCase();
15
+ if (h === 'center') {
16
+ style.display = 'block';
17
+ style.width = 'fit-content';
18
+ style.marginLeft = 'auto';
19
+ style.marginRight = 'auto';
20
+ style.alignSelf = 'center';
21
+ style.justifySelf = 'center';
22
+ } else if (h === 'right') {
23
+ style.display = 'block';
24
+ style.width = 'fit-content';
25
+ style.marginLeft = 'auto';
26
+ style.alignSelf = 'flex-end';
27
+ style.justifySelf = 'end';
28
+ } else if (h === 'left') {
29
+ style.display = 'block';
30
+ style.width = 'fit-content';
31
+ style.marginRight = 'auto';
32
+ style.alignSelf = 'flex-start';
33
+ style.justifySelf = 'start';
34
+ }
35
+ return style;
36
+ });
37
+ </script>
38
+
39
+ <style scoped>
40
+ .ns-button { cursor: pointer; }
41
+ </style>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <input class="ns-datepicker" type="date" :value="valueStr" @input="onInput" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { computed } from 'vue';
7
+ defineOptions({ name: 'DatePicker' });
8
+ const props = defineProps<{ date?: string | Date }>();
9
+ const emit = defineEmits<{ (e: 'update:date', v: string | Date): void; (e: 'change', v: string | Date): void }>();
10
+
11
+ function pad(n: number) { return n < 10 ? `0${n}` : String(n); }
12
+ const valueStr = computed(() => {
13
+ if (!props.date) return '';
14
+ const d = typeof props.date === 'string' ? new Date(props.date) : props.date;
15
+ if (isNaN(d.getTime())) return '';
16
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
17
+ });
18
+ function onInput(e: Event) {
19
+ const v = (e.target as HTMLInputElement).value;
20
+ emit('update:date', v);
21
+ emit('change', v);
22
+ }
23
+ </script>
24
+
25
+ <style scoped>
26
+ .ns-datepicker { padding: 6px 8px; }
27
+ </style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div class="ns-dock">
3
+ <div class="ns-dock-top"><slot name="top" /></div>
4
+ <div class="ns-dock-middle">
5
+ <div class="ns-dock-left"><slot name="left" /></div>
6
+ <div class="ns-dock-center"><slot /></div>
7
+ <div class="ns-dock-right"><slot name="right" /></div>
8
+ </div>
9
+ <div class="ns-dock-bottom"><slot name="bottom" /></div>
10
+ </div>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ defineOptions({ name: 'DockLayout' });
15
+ </script>
16
+
17
+ <style scoped>
18
+ .ns-dock { display: flex; flex-direction: column; width: 100%; height: 100%; }
19
+ .ns-dock-top, .ns-dock-bottom { flex: 0 0 auto; }
20
+ .ns-dock-middle { display: flex; flex: 1 1 auto; min-height: 0; }
21
+ .ns-dock-left, .ns-dock-right { flex: 0 0 auto; }
22
+ .ns-dock-center { flex: 1 1 auto; min-width: 0; }
23
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-flex"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'FlexboxLayout' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-flex { display: flex; }
11
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-frame"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Frame' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ /* .ns-frame { } */
11
+ </style>