@thelacanians/vue-native-navigation 0.1.0
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/dist/index.cjs +393 -0
- package/dist/index.d.cts +376 -0
- package/dist/index.d.ts +376 -0
- package/dist/index.js +370 -0
- package/package.json +41 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
RouterView: () => RouterView,
|
|
24
|
+
VNavigationBar: () => VNavigationBar,
|
|
25
|
+
VTabBar: () => VTabBar,
|
|
26
|
+
createRouter: () => createRouter,
|
|
27
|
+
createTabNavigator: () => createTabNavigator,
|
|
28
|
+
useRoute: () => useRoute,
|
|
29
|
+
useRouter: () => useRouter
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
var import_runtime_core = require("@vue/runtime-core");
|
|
33
|
+
var ROUTER_KEY = /* @__PURE__ */ Symbol("router");
|
|
34
|
+
var ROUTE_KEY = /* @__PURE__ */ Symbol("route");
|
|
35
|
+
var keyCounter = 0;
|
|
36
|
+
function createRouter(routes) {
|
|
37
|
+
if (routes.length === 0) {
|
|
38
|
+
throw new Error("[vue-native/navigation] createRouter requires at least one route");
|
|
39
|
+
}
|
|
40
|
+
const routeMap = new Map(routes.map((r) => [r.name, r]));
|
|
41
|
+
const initialEntry = { config: routes[0], params: {}, key: keyCounter++ };
|
|
42
|
+
const stack = (0, import_runtime_core.ref)([initialEntry]);
|
|
43
|
+
const currentRoute = (0, import_runtime_core.shallowRef)(initialEntry);
|
|
44
|
+
const canGoBack = (0, import_runtime_core.computed)(() => stack.value.length > 1);
|
|
45
|
+
function navigate(name, params = {}) {
|
|
46
|
+
const config = routeMap.get(name);
|
|
47
|
+
if (!config) {
|
|
48
|
+
console.warn(`[vue-native/navigation] Route "${name}" not found`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const entry = { config, params, key: keyCounter++ };
|
|
52
|
+
stack.value = [...stack.value, entry];
|
|
53
|
+
currentRoute.value = entry;
|
|
54
|
+
}
|
|
55
|
+
function goBack() {
|
|
56
|
+
if (stack.value.length <= 1) return;
|
|
57
|
+
const newStack = stack.value.slice(0, -1);
|
|
58
|
+
stack.value = newStack;
|
|
59
|
+
currentRoute.value = newStack[newStack.length - 1];
|
|
60
|
+
}
|
|
61
|
+
function replace(name, params = {}) {
|
|
62
|
+
const config = routeMap.get(name);
|
|
63
|
+
if (!config) {
|
|
64
|
+
console.warn(`[vue-native/navigation] Route "${name}" not found`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const entry = { config, params, key: keyCounter++ };
|
|
68
|
+
stack.value = [...stack.value.slice(0, -1), entry];
|
|
69
|
+
currentRoute.value = entry;
|
|
70
|
+
}
|
|
71
|
+
function reset(name, params = {}) {
|
|
72
|
+
const config = routeMap.get(name);
|
|
73
|
+
if (!config) {
|
|
74
|
+
console.warn(`[vue-native/navigation] Route "${name}" not found`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const entry = { config, params, key: keyCounter++ };
|
|
78
|
+
stack.value = [entry];
|
|
79
|
+
currentRoute.value = entry;
|
|
80
|
+
}
|
|
81
|
+
const router = {
|
|
82
|
+
currentRoute,
|
|
83
|
+
stack,
|
|
84
|
+
canGoBack,
|
|
85
|
+
navigate,
|
|
86
|
+
push: navigate,
|
|
87
|
+
goBack,
|
|
88
|
+
pop: goBack,
|
|
89
|
+
replace,
|
|
90
|
+
reset,
|
|
91
|
+
install(app) {
|
|
92
|
+
app.provide(ROUTER_KEY, router);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return router;
|
|
96
|
+
}
|
|
97
|
+
function useRouter() {
|
|
98
|
+
const router = (0, import_runtime_core.inject)(ROUTER_KEY);
|
|
99
|
+
if (!router) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
"[vue-native/navigation] useRouter() called outside of router context. Make sure app.use(router) is called."
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return router;
|
|
105
|
+
}
|
|
106
|
+
function useRoute() {
|
|
107
|
+
const perScreenRoute = (0, import_runtime_core.inject)(ROUTE_KEY);
|
|
108
|
+
if (perScreenRoute) return perScreenRoute;
|
|
109
|
+
const router = useRouter();
|
|
110
|
+
return (0, import_runtime_core.computed)(() => ({
|
|
111
|
+
name: router.currentRoute.value.config.name,
|
|
112
|
+
params: router.currentRoute.value.params,
|
|
113
|
+
options: router.currentRoute.value.config.options ?? {}
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
var RouteProvider = (0, import_runtime_core.defineComponent)({
|
|
117
|
+
name: "RouteProvider",
|
|
118
|
+
props: {
|
|
119
|
+
entry: { type: Object, required: true }
|
|
120
|
+
},
|
|
121
|
+
setup(props, { slots }) {
|
|
122
|
+
const routeLocation = (0, import_runtime_core.computed)(() => ({
|
|
123
|
+
name: props.entry.config.name,
|
|
124
|
+
params: props.entry.params,
|
|
125
|
+
options: props.entry.config.options ?? {}
|
|
126
|
+
}));
|
|
127
|
+
(0, import_runtime_core.provide)(ROUTE_KEY, routeLocation);
|
|
128
|
+
return () => slots.default?.();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
var RouterView = (0, import_runtime_core.defineComponent)({
|
|
132
|
+
name: "RouterView",
|
|
133
|
+
setup() {
|
|
134
|
+
const router = useRouter();
|
|
135
|
+
return () => {
|
|
136
|
+
const entries = router.stack.value;
|
|
137
|
+
return (0, import_runtime_core.h)(
|
|
138
|
+
"VView",
|
|
139
|
+
{
|
|
140
|
+
style: {
|
|
141
|
+
flex: 1,
|
|
142
|
+
overflow: "hidden",
|
|
143
|
+
position: "relative"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
entries.map((entry, index) => {
|
|
147
|
+
const isTop = index === entries.length - 1;
|
|
148
|
+
return (0, import_runtime_core.h)(
|
|
149
|
+
"VView",
|
|
150
|
+
{
|
|
151
|
+
key: entry.key,
|
|
152
|
+
style: {
|
|
153
|
+
position: "absolute",
|
|
154
|
+
top: 0,
|
|
155
|
+
left: 0,
|
|
156
|
+
right: 0,
|
|
157
|
+
bottom: 0,
|
|
158
|
+
transform: isTop ? [] : [{ translateX: -50 }],
|
|
159
|
+
// Hide off-screen screens from the accessibility tree and
|
|
160
|
+
// prevent touch events from reaching them.
|
|
161
|
+
opacity: isTop ? 1 : 0
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
[
|
|
165
|
+
(0, import_runtime_core.h)(
|
|
166
|
+
RouteProvider,
|
|
167
|
+
{ entry },
|
|
168
|
+
() => (0, import_runtime_core.h)(entry.config.component, { routeParams: entry.params })
|
|
169
|
+
)
|
|
170
|
+
]
|
|
171
|
+
);
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
var VNavigationBar = (0, import_runtime_core.defineComponent)({
|
|
178
|
+
name: "VNavigationBar",
|
|
179
|
+
props: {
|
|
180
|
+
/** Screen title, rendered centered in the bar. */
|
|
181
|
+
title: { type: String, default: "" },
|
|
182
|
+
/** Whether to show the back chevron + backTitle on the left. */
|
|
183
|
+
showBack: { type: Boolean, default: false },
|
|
184
|
+
/** Text shown next to the back chevron. Defaults to "Back". */
|
|
185
|
+
backTitle: { type: String, default: "Back" },
|
|
186
|
+
/** Background colour of the bar. */
|
|
187
|
+
backgroundColor: { type: String, default: "#FFFFFF" },
|
|
188
|
+
/** Colour used for the back button text. */
|
|
189
|
+
tintColor: { type: String, default: "#007AFF" },
|
|
190
|
+
/** Colour of the title text. */
|
|
191
|
+
titleColor: { type: String, default: "#000000" }
|
|
192
|
+
},
|
|
193
|
+
emits: ["back"],
|
|
194
|
+
setup(props, { emit }) {
|
|
195
|
+
return () => (0, import_runtime_core.h)(
|
|
196
|
+
"VView",
|
|
197
|
+
{
|
|
198
|
+
style: {
|
|
199
|
+
flexDirection: "row",
|
|
200
|
+
alignItems: "center",
|
|
201
|
+
height: 44,
|
|
202
|
+
backgroundColor: props.backgroundColor,
|
|
203
|
+
paddingHorizontal: 16,
|
|
204
|
+
borderBottomWidth: 0.5,
|
|
205
|
+
borderBottomColor: "#C8C8CC"
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
[
|
|
209
|
+
// ── Left slot: back button or spacer ──────────────────────────────
|
|
210
|
+
props.showBack ? (0, import_runtime_core.h)(
|
|
211
|
+
"VButton",
|
|
212
|
+
{
|
|
213
|
+
style: {
|
|
214
|
+
flexDirection: "row",
|
|
215
|
+
alignItems: "center",
|
|
216
|
+
paddingHorizontal: 0,
|
|
217
|
+
paddingVertical: 8,
|
|
218
|
+
minWidth: 60,
|
|
219
|
+
backgroundColor: "transparent"
|
|
220
|
+
},
|
|
221
|
+
onPress: () => emit("back")
|
|
222
|
+
},
|
|
223
|
+
() => (0, import_runtime_core.h)(
|
|
224
|
+
"VText",
|
|
225
|
+
{ style: { color: props.tintColor, fontSize: 17 } },
|
|
226
|
+
() => `\u2039 ${props.backTitle}`
|
|
227
|
+
)
|
|
228
|
+
) : (0, import_runtime_core.h)("VView", { style: { minWidth: 60 } }),
|
|
229
|
+
// ── Center: title ────────────────────────────────────────────────
|
|
230
|
+
(0, import_runtime_core.h)("VView", { style: { flex: 1, alignItems: "center" } }, [
|
|
231
|
+
(0, import_runtime_core.h)(
|
|
232
|
+
"VText",
|
|
233
|
+
{
|
|
234
|
+
style: {
|
|
235
|
+
fontSize: 17,
|
|
236
|
+
fontWeight: "600",
|
|
237
|
+
color: props.titleColor
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
() => props.title
|
|
241
|
+
)
|
|
242
|
+
]),
|
|
243
|
+
// ── Right slot: spacer to balance left side ───────────────────────
|
|
244
|
+
(0, import_runtime_core.h)("VView", { style: { minWidth: 60 } })
|
|
245
|
+
]
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
var VTabBar = (0, import_runtime_core.defineComponent)({
|
|
250
|
+
name: "VTabBar",
|
|
251
|
+
props: {
|
|
252
|
+
/** Array of tab descriptors. */
|
|
253
|
+
tabs: { type: Array, required: true },
|
|
254
|
+
/** Name of the currently active tab (v-model). */
|
|
255
|
+
modelValue: { type: String, default: "" },
|
|
256
|
+
/** Text / icon colour for the active tab. */
|
|
257
|
+
activeColor: { type: String, default: "#007AFF" },
|
|
258
|
+
/** Text / icon colour for inactive tabs. */
|
|
259
|
+
inactiveColor: { type: String, default: "#8E8E93" },
|
|
260
|
+
/** Background colour of the tab bar. */
|
|
261
|
+
backgroundColor: { type: String, default: "#F9F9F9" }
|
|
262
|
+
},
|
|
263
|
+
emits: ["update:modelValue"],
|
|
264
|
+
setup(props, { emit }) {
|
|
265
|
+
return () => (0, import_runtime_core.h)(
|
|
266
|
+
"VView",
|
|
267
|
+
{
|
|
268
|
+
style: {
|
|
269
|
+
flexDirection: "row",
|
|
270
|
+
backgroundColor: props.backgroundColor,
|
|
271
|
+
borderTopWidth: 0.5,
|
|
272
|
+
borderTopColor: "#C8C8CC",
|
|
273
|
+
paddingBottom: 4
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
props.tabs.map((tab) => {
|
|
277
|
+
const isActive = props.modelValue === tab.name;
|
|
278
|
+
return (0, import_runtime_core.h)(
|
|
279
|
+
"VButton",
|
|
280
|
+
{
|
|
281
|
+
key: tab.name,
|
|
282
|
+
style: {
|
|
283
|
+
flex: 1,
|
|
284
|
+
alignItems: "center",
|
|
285
|
+
paddingVertical: 8,
|
|
286
|
+
backgroundColor: "transparent"
|
|
287
|
+
},
|
|
288
|
+
onPress: () => emit("update:modelValue", tab.name)
|
|
289
|
+
},
|
|
290
|
+
() => [
|
|
291
|
+
// Icon (optional)
|
|
292
|
+
tab.icon != null ? (0, import_runtime_core.h)(
|
|
293
|
+
"VText",
|
|
294
|
+
{
|
|
295
|
+
style: {
|
|
296
|
+
fontSize: 24,
|
|
297
|
+
marginBottom: 2,
|
|
298
|
+
color: isActive ? props.activeColor : props.inactiveColor
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
() => tab.icon
|
|
302
|
+
) : null,
|
|
303
|
+
// Label
|
|
304
|
+
(0, import_runtime_core.h)(
|
|
305
|
+
"VText",
|
|
306
|
+
{
|
|
307
|
+
style: {
|
|
308
|
+
fontSize: 10,
|
|
309
|
+
color: isActive ? props.activeColor : props.inactiveColor,
|
|
310
|
+
fontWeight: isActive ? "600" : "400"
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
() => tab.label ?? tab.name
|
|
314
|
+
)
|
|
315
|
+
]
|
|
316
|
+
);
|
|
317
|
+
})
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
function createTabNavigator() {
|
|
322
|
+
const activeTab = (0, import_runtime_core.ref)("");
|
|
323
|
+
const TabNavigator = (0, import_runtime_core.defineComponent)({
|
|
324
|
+
name: "TabNavigator",
|
|
325
|
+
props: {
|
|
326
|
+
/** Ordered list of tab screen descriptors. */
|
|
327
|
+
screens: { type: Array, required: true },
|
|
328
|
+
/** Which tab is shown first. Defaults to the first screen. */
|
|
329
|
+
initialTab: { type: String, default: "" },
|
|
330
|
+
/** Active tab icon / label colour. */
|
|
331
|
+
activeColor: { type: String, default: "#007AFF" },
|
|
332
|
+
/** Inactive tab icon / label colour. */
|
|
333
|
+
inactiveColor: { type: String, default: "#8E8E93" },
|
|
334
|
+
/** Background colour of the tab bar. */
|
|
335
|
+
tabBarBackgroundColor: { type: String, default: "#F9F9F9" }
|
|
336
|
+
},
|
|
337
|
+
setup(props) {
|
|
338
|
+
return () => {
|
|
339
|
+
const screens = props.screens;
|
|
340
|
+
if (screens.length === 0) return null;
|
|
341
|
+
if (activeTab.value === "") {
|
|
342
|
+
activeTab.value = props.initialTab || screens[0].name;
|
|
343
|
+
}
|
|
344
|
+
const currentScreen = screens.find((s) => s.name === activeTab.value) ?? screens[0];
|
|
345
|
+
const tabs = screens.map((s) => ({
|
|
346
|
+
name: s.name,
|
|
347
|
+
label: s.label,
|
|
348
|
+
icon: s.icon
|
|
349
|
+
}));
|
|
350
|
+
return (0, import_runtime_core.h)("VView", { style: { flex: 1 } }, [
|
|
351
|
+
// ── Screen area ─────────────────────────────────────────────────
|
|
352
|
+
(0, import_runtime_core.h)("VView", { style: { flex: 1 } }, [
|
|
353
|
+
(0, import_runtime_core.h)(currentScreen.component)
|
|
354
|
+
]),
|
|
355
|
+
// ── Tab bar ──────────────────────────────────────────────────────
|
|
356
|
+
(0, import_runtime_core.h)(VTabBar, {
|
|
357
|
+
tabs,
|
|
358
|
+
modelValue: activeTab.value,
|
|
359
|
+
activeColor: props.activeColor,
|
|
360
|
+
inactiveColor: props.inactiveColor,
|
|
361
|
+
backgroundColor: props.tabBarBackgroundColor,
|
|
362
|
+
"onUpdate:modelValue": (name) => {
|
|
363
|
+
activeTab.value = name;
|
|
364
|
+
}
|
|
365
|
+
})
|
|
366
|
+
]);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
const TabScreen = (0, import_runtime_core.defineComponent)({
|
|
371
|
+
name: "TabScreen",
|
|
372
|
+
props: {
|
|
373
|
+
name: { type: String, required: true },
|
|
374
|
+
label: { type: String, default: void 0 },
|
|
375
|
+
icon: { type: String, default: void 0 },
|
|
376
|
+
component: { type: Object, required: true }
|
|
377
|
+
},
|
|
378
|
+
setup() {
|
|
379
|
+
return () => null;
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
return { TabNavigator, TabScreen, activeTab };
|
|
383
|
+
}
|
|
384
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
385
|
+
0 && (module.exports = {
|
|
386
|
+
RouterView,
|
|
387
|
+
VNavigationBar,
|
|
388
|
+
VTabBar,
|
|
389
|
+
createRouter,
|
|
390
|
+
createTabNavigator,
|
|
391
|
+
useRoute,
|
|
392
|
+
useRouter
|
|
393
|
+
});
|