@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 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
+ });