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.
- package/README.md +220 -244
- 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 +35 -49
- package/tools/cli.cjs +59 -0
- package/tools/create-nuxt-platform.cjs +57 -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-nuxt.cjs +63 -0
- package/tools/modules/templates.cjs +130 -0
- package/tools/modules/transform-nuxt.cjs +59 -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 -377
- package/dist/index.cjs.map +0 -1
- package/dist/index.css +0 -172
- package/dist/index.js +0 -361
- 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/index.types.d.ts +0 -1
- package/dist/types/vue/components/ActionBar.d.ts +0 -5
- package/dist/types/vue/components/ActionItem.d.ts +0 -15
- package/dist/types/vue/components/Button.d.ts +0 -26
- package/dist/types/vue/components/ContentView.d.ts +0 -3
- 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 -26
- 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/ListView.d.ts +0 -24
- package/dist/types/vue/components/Page.d.ts +0 -5
- package/dist/types/vue/components/StackLayout.d.ts +0 -5
- package/dist/types/vue/components/TabView.d.ts +0 -26
- package/dist/types/vue/components/TabViewItem.d.ts +0 -24
- package/dist/types/vue/index.d.ts +0 -18
- package/dist/types/vue/index.types.d.ts +0 -17
- package/dist/types/vue.d.ts +0 -266
- package/dist/vue.cjs +0 -377
- package/dist/vue.cjs.map +0 -1
- package/dist/vue.css +0 -172
- package/dist/vue.js +0 -361
- package/dist/vue.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,270 +1,246 @@
|
|
|
1
1
|
# NativeScript for Web
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
中文: [README_ZH.md](README_ZH.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/nativescript-web-adapter)
|
|
6
|
+
[](LICENSE)
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
10
|
+
---
|
|
10
11
|
|
|
11
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
Install the adapter from npm:
|
|
19
|
-
|
|
20
|
-
```
|
|
14
|
+
```bash
|
|
21
15
|
npm install nativescript-web-adapter
|
|
22
16
|
```
|
|
23
17
|
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
26
|
+
nuxt
|
|
70
27
|
|
|
71
28
|
```bash
|
|
72
|
-
|
|
29
|
+
npx ns-web nuxt
|
|
73
30
|
```
|
|
74
31
|
|
|
75
|
-
|
|
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
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
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
|
+
<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>
|