@shwfed/nuxt 0.1.74 → 0.1.76

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.
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
- import { useHead, useNuxtApp, useRoute, useRuntimeConfig } from "#app";
3
- import { computed, reactive, watch } from "vue";
2
+ import { useHead, useNuxtApp } from "#app";
3
+ import { reactive } from "vue";
4
4
  import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "./ui/command";
5
5
  import { TooltipProvider } from "./ui/tooltip";
6
6
  import { Toaster } from "vue-sonner";
@@ -12,26 +12,23 @@ import { setGlobalDslContext } from "../plugins/cel/context";
12
12
  import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "./ui/sidebar";
13
13
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible";
14
14
  import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./ui/dropdown-menu";
15
- import { z } from "zod";
16
15
  import Logo from "./logo.vue";
17
16
  import { useFavorite } from "../composables/useFavorite";
18
17
  import { useNavigationTabs } from "../composables/useNavigationTabs";
19
- import { commandActionSchema, executeCommandAction } from "../utils/command";
20
- import { createPaletteItemValue, normalizeCommandsForPalette, splitNavigationForPalette } from "../utils/command-palette";
21
- import { resolveNavigationTitle } from "../utils/navigation-title";
22
- import { isRouteActive } from "../utils/route";
23
- import { applyRootNavigationFallback } from "../utils/sidebar-fallback";
24
- const { $dsl, $logout, $md, $api, $toast } = useNuxtApp();
18
+ const { $dsl } = useNuxtApp();
25
19
  const { t } = useI18n();
26
- const route = useRoute();
27
- const { tabs, active, tabList, activateTab, closeTab } = useNavigationTabs();
28
- const {
29
- public: {
30
- shwfed: config
31
- }
32
- } = useRuntimeConfig();
20
+ const props = defineProps({
21
+ dsl: { type: null, required: false },
22
+ sidebar: { type: Array, required: false },
23
+ commands: { type: Array, required: false }
24
+ });
25
+ const { active, tabs, nameOf, close } = useNavigationTabs(() => props.sidebar ?? []);
26
+ const ui = reactive({
27
+ isCommandPaletteOpen: false,
28
+ isProfileDropdownOpen: false
29
+ });
33
30
  useHead({
34
- title: () => active.value && getTabLabel(active.value),
31
+ title: () => active.value && nameOf(active.value),
35
32
  bodyAttrs: {
36
33
  style: {
37
34
  "--primary": "#2DA8BC",
@@ -39,213 +36,18 @@ useHead({
39
36
  }
40
37
  }
41
38
  });
42
- const props = defineProps({
43
- dsl: { type: null, required: false }
44
- });
45
- const ui = reactive({
46
- isCommandPaletteOpen: false,
47
- isProfileDropdownOpen: false
48
- });
49
39
  const { start: startProfileCloseTimer, stop: stopProfileCloseTimer } = useTimeoutFn(() => {
50
40
  ui.isProfileDropdownOpen = false;
51
41
  }, 150, { immediate: false });
52
42
  const { meta_k } = useMagicKeys();
53
43
  whenever(() => meta_k?.value, () => ui.isCommandPaletteOpen = !ui.isCommandPaletteOpen);
54
44
  setGlobalDslContext(await props.dsl?.pipe(Effect.scoped).pipe(Effect.runPromise) ?? {});
55
- const navigationItem = z.object({
56
- id: z.union([z.string(), z.number()]),
57
- title: z.string(),
58
- icon: z.string().optional(),
59
- route: z.string(),
60
- keywords: z.array(z.string()).optional()
61
- });
62
- const navigationGroup = z.object({
63
- id: z.union([z.string(), z.number()]),
64
- title: z.string(),
65
- icon: z.string().optional(),
66
- children: z.array(navigationItem)
67
- });
68
- const navigationEntry = z.union([navigationGroup, navigationItem]);
69
- const navigationItems = computed(() => {
70
- try {
71
- const result = $dsl.evaluate`${config.sidebar.menus}`();
72
- return z.array(navigationEntry).parse(result);
73
- } catch {
74
- return [];
75
- }
76
- });
77
45
  const {
78
46
  isFavorited: isNavigationFavorited,
79
47
  canBeFavorited: canBeNavigationFavorited,
80
48
  toggle: toggleNavigationFavorite,
81
49
  withFavorites: navigations
82
- } = useFavorite("navigation", navigationItems);
83
- const isNavigationItemActive = (itemRoute) => isRouteActive(route.path, itemRoute);
84
- const getTabLabel = (tab) => {
85
- return resolveNavigationTitle(navigationItems.value, tab);
86
- };
87
- const profileName = computed(() => {
88
- if (config.profile.name === void 0)
89
- return t("profile");
90
- try {
91
- const content = $md.inline`${config.profile.name}`();
92
- const plainText = content.replace(/<[^>]*>/g, "").trim();
93
- if (plainText.length === 0)
94
- return t("profile");
95
- return plainText;
96
- } catch {
97
- return t("profile");
98
- }
99
- });
100
- const commandItem = z.object({
101
- id: z.union([z.string(), z.number()]),
102
- title: z.string(),
103
- icon: z.string().optional(),
104
- hidden: z.string().optional(),
105
- disabled: z.string().optional(),
106
- effect: z.string().optional(),
107
- keywords: z.array(z.string()).optional()
108
- });
109
- const commandGroup = z.object({
110
- id: z.union([z.string(), z.number()]),
111
- title: z.string(),
112
- icon: z.string().optional(),
113
- children: z.array(commandItem)
114
- });
115
- const evaluateDslBoolean = (expression) => {
116
- if (expression === void 0)
117
- return false;
118
- try {
119
- return $dsl.evaluate`${expression}`() === true;
120
- } catch {
121
- return false;
122
- }
123
- };
124
- const normalizeEffectExpression = (expression) => {
125
- return expression.replace(/([{,]\s*)([a-z_][\w-]*)(\s*:)/gi, "$1'$2'$3");
126
- };
127
- const profileCommands = computed(() => {
128
- if (config.commands === void 0)
129
- return [];
130
- try {
131
- const result = $dsl.evaluate`${config.commands}`();
132
- const entries = z.array(z.union([commandGroup, commandItem])).parse(result);
133
- const normalized = [];
134
- for (const entry of entries) {
135
- if ("children" in entry) {
136
- const children = entry.children.filter((child) => !evaluateDslBoolean(child.hidden)).map((child) => ({
137
- id: child.id,
138
- title: child.title,
139
- icon: child.icon,
140
- disabled: evaluateDslBoolean(child.disabled),
141
- effect: child.effect,
142
- keywords: child.keywords
143
- }));
144
- if (children.length > 0) {
145
- normalized.push({
146
- id: entry.id,
147
- title: entry.title,
148
- icon: entry.icon,
149
- children
150
- });
151
- }
152
- continue;
153
- }
154
- if (evaluateDslBoolean(entry.hidden))
155
- continue;
156
- normalized.push({
157
- id: entry.id,
158
- title: entry.title,
159
- icon: entry.icon,
160
- disabled: evaluateDslBoolean(entry.disabled),
161
- effect: entry.effect,
162
- keywords: entry.keywords
163
- });
164
- }
165
- return normalized;
166
- } catch {
167
- return [];
168
- }
169
- });
170
- const isBodyInit = (value) => {
171
- return typeof value === "string" || value instanceof Blob || value instanceof ArrayBuffer || ArrayBuffer.isView(value) || value instanceof FormData || value instanceof URLSearchParams || value instanceof ReadableStream;
172
- };
173
- const toApiRequestBody = (value) => {
174
- if (value === void 0 || value === null)
175
- return value;
176
- if (isBodyInit(value))
177
- return value;
178
- if (typeof value === "object")
179
- return value;
180
- return void 0;
181
- };
182
- const executeCommandEffect = async (effect) => {
183
- if (effect === void 0)
184
- return false;
185
- let action;
186
- try {
187
- let result;
188
- try {
189
- result = $dsl.evaluate`${effect}`();
190
- } catch {
191
- result = $dsl.evaluate`${normalizeEffectExpression(effect)}`();
192
- }
193
- action = commandActionSchema.parse(result);
194
- await executeCommandAction(action, {
195
- logout: $logout,
196
- request: async (requestAction) => $api(requestAction.url, {
197
- method: requestAction.method,
198
- body: toApiRequestBody(requestAction.body),
199
- query: requestAction.query,
200
- headers: requestAction.headers
201
- })
202
- });
203
- return true;
204
- } catch (error) {
205
- if (action?.type === "request") {
206
- const message = error instanceof Error && error.message.length > 0 ? error.message : "Request failed";
207
- $toast.error(message);
208
- }
209
- return false;
210
- }
211
- };
212
- const executeProfileCommand = async (effect) => {
213
- if (effect === void 0 || await executeCommandEffect(effect))
214
- ui.isProfileDropdownOpen = false;
215
- };
216
- const normalizedNavigationForPalette = computed(() => {
217
- try {
218
- return z.array(navigationEntry).parse(navigations.value);
219
- } catch {
220
- return navigationItems.value;
221
- }
222
- });
223
- const paletteNavigation = computed(() => splitNavigationForPalette(normalizedNavigationForPalette.value));
224
- const favoriteRoutesForPalette = computed(() => paletteNavigation.value.favoriteRoutes);
225
- const navigationForPalette = computed(() => paletteNavigation.value.navigationEntries);
226
- const commandForPalette = computed(() => normalizeCommandsForPalette(profileCommands.value));
227
- const executePaletteItem = async (item) => {
228
- if (item.type === "route") {
229
- activateTab(item.route);
230
- ui.isCommandPaletteOpen = false;
231
- return;
232
- }
233
- if (item.effect !== void 0 && !await executeCommandEffect(item.effect))
234
- return;
235
- ui.isCommandPaletteOpen = false;
236
- };
237
- watch(
238
- () => route.path,
239
- (path) => {
240
- applyRootNavigationFallback({
241
- path,
242
- items: navigationItems.value,
243
- tabs: tabs.value,
244
- activateTab
245
- });
246
- },
247
- { immediate: true }
248
- );
50
+ } = useFavorite("navigation", () => props.sidebar ?? []);
249
51
  </script>
250
52
 
251
53
  <template>
@@ -269,102 +71,68 @@ watch(
269
71
  </section>
270
72
  </CommandEmpty>
271
73
 
272
- <CommandGroup
273
- v-if="favoriteRoutesForPalette.length > 0"
274
- :heading="t('favorites')"
275
- >
276
- <CommandItem
277
- v-for="menu in favoriteRoutesForPalette"
278
- :key="`fav:${menu.id}:${menu.route}`"
279
- :value="createPaletteItemValue('fav', `${menu.id}:${menu.route}`)"
280
- @select="executePaletteItem({ type: 'route', route: menu.route })"
281
- >
282
- <span>{{ menu.title }}</span>
283
- <span
284
- v-if="menu.keywords.length > 0"
285
- class="sr-only"
286
- >
287
- {{ menu.keywords.join(" ") }}
288
- </span>
289
- </CommandItem>
290
- </CommandGroup>
291
-
292
74
  <template
293
- v-for="navigation in navigationForPalette"
294
- :key="navigation.id"
75
+ v-for="command in props.commands"
76
+ :key="command.id"
295
77
  >
296
78
  <CommandGroup
297
- v-if="'children' in navigation"
298
- :heading="navigation.title"
79
+ v-if="'children' in command"
80
+ :heading="command.title"
299
81
  >
300
82
  <CommandItem
301
- v-for="menu in navigation.children"
302
- :key="menu.id"
303
- :value="createPaletteItemValue('nav', menu.id, navigation.id)"
304
- @select="executePaletteItem({ type: 'route', route: menu.route })"
83
+ v-for="child in command.children.filter((child2) => !child2.hidden)"
84
+ :key="child.id"
85
+ :value="child.id"
86
+ :disabled="child.disabled"
87
+ @select="child.effect?.pipe(Effect.tap(() => {
88
+ ui.isCommandPaletteOpen = false;
89
+ })).pipe(Effect.runPromise)"
305
90
  >
306
- <span>{{ menu.title }}</span>
307
- <span
308
- v-if="menu.keywords.length > 0"
309
- class="sr-only"
310
- >
311
- {{ menu.keywords.join(" ") }}
91
+ <span>{{ child.title }}</span>
92
+ <span class="sr-only">
93
+ {{ child.keywords?.join(" ") }}
312
94
  </span>
313
95
  </CommandItem>
314
96
  </CommandGroup>
315
97
  <CommandGroup v-else>
316
98
  <CommandItem
317
- :value="createPaletteItemValue('nav', navigation.id)"
318
- @select="executePaletteItem({ type: 'route', route: navigation.route })"
99
+ :value="command.id"
100
+ :disabled="command.disabled"
101
+ @select="command.effect?.pipe(Effect.tap(() => {
102
+ ui.isCommandPaletteOpen = false;
103
+ })).pipe(Effect.runPromise)"
319
104
  >
320
- <span>{{ navigation.title }}</span>
321
- <span
322
- v-if="navigation.keywords.length > 0"
323
- class="sr-only"
324
- >
325
- {{ navigation.keywords.join(" ") }}
105
+ <span>{{ command.title }}</span>
106
+ <span class="sr-only">
107
+ {{ command.keywords?.join(" ") }}
326
108
  </span>
327
109
  </CommandItem>
328
110
  </CommandGroup>
329
111
  </template>
330
112
 
331
113
  <template
332
- v-for="command in commandForPalette"
333
- :key="command.id"
114
+ v-for="navigation in props.sidebar"
115
+ :key="navigation.id"
334
116
  >
335
117
  <CommandGroup
336
- v-if="'children' in command"
337
- :heading="command.title"
118
+ v-if="'children' in navigation"
119
+ :heading="navigation.title"
338
120
  >
339
121
  <CommandItem
340
- v-for="child in command.children"
341
- :key="child.id"
342
- :value="createPaletteItemValue('cmd', child.id, command.id)"
343
- :disabled="child.disabled"
344
- @select="executePaletteItem({ type: 'command', effect: child.effect })"
122
+ v-for="menu in navigation.children"
123
+ :key="menu.id"
124
+ :value="menu.id"
125
+ @select="$router.replace(menu.route)"
345
126
  >
346
- <span>{{ child.title }}</span>
347
- <span
348
- v-if="child.keywords.length > 0"
349
- class="sr-only"
350
- >
351
- {{ child.keywords.join(" ") }}
352
- </span>
127
+ <span>{{ menu.title }}</span>
353
128
  </CommandItem>
354
129
  </CommandGroup>
355
130
  <CommandGroup v-else>
356
131
  <CommandItem
357
- :value="createPaletteItemValue('cmd', command.id)"
358
- :disabled="command.disabled"
359
- @select="executePaletteItem({ type: 'command', effect: command.effect })"
132
+ :value="navigation.id"
133
+ @select="$router.replace(navigation.route)"
360
134
  >
361
- <span>{{ command.title }}</span>
362
- <span
363
- v-if="command.keywords.length > 0"
364
- class="sr-only"
365
- >
366
- {{ command.keywords.join(" ") }}
367
- </span>
135
+ <span>{{ navigation.title }}</span>
368
136
  </CommandItem>
369
137
  </CommandGroup>
370
138
  </template>
@@ -393,7 +161,7 @@ watch(
393
161
  @click.prevent="stopProfileCloseTimer();
394
162
  ui.isProfileDropdownOpen = true"
395
163
  >
396
- {{ profileName }}
164
+ <slot name="profile" />
397
165
  </button>
398
166
  </DropdownMenuTrigger>
399
167
  <DropdownMenuContent
@@ -404,33 +172,37 @@ watch(
404
172
  startProfileCloseTimer()"
405
173
  >
406
174
  <template
407
- v-for="command in profileCommands"
175
+ v-for="command in props.commands"
408
176
  :key="command.id"
409
177
  >
410
- <template v-if="'children' in command">
178
+ <template v-if="'children' in command && command.children.some((child2) => !child2.hidden)">
411
179
  <DropdownMenuLabel>
412
180
  {{ command.title }}
413
181
  </DropdownMenuLabel>
414
182
  <DropdownMenuGroup>
415
- <DropdownMenuItem
183
+ <template
416
184
  v-for="child in command.children"
417
185
  :key="child.id"
418
- :disabled="child.disabled"
419
- @select="executeProfileCommand(child.effect)"
420
186
  >
421
- <Icon
422
- v-if="child.icon"
423
- :icon="child.icon"
424
- />
425
- {{ child.title }}
426
- </DropdownMenuItem>
187
+ <DropdownMenuItem
188
+ v-if="!child.hidden"
189
+ :disabled="child.disabled"
190
+ @select="child.effect?.pipe(Effect.runPromise)"
191
+ >
192
+ <Icon
193
+ v-if="child.icon"
194
+ :icon="child.icon"
195
+ />
196
+ {{ child.title }}
197
+ </DropdownMenuItem>
198
+ </template>
427
199
  </DropdownMenuGroup>
428
200
  <DropdownMenuSeparator />
429
201
  </template>
430
202
  <DropdownMenuItem
431
- v-else
203
+ v-else-if="!('children' in command) && !command.hidden"
432
204
  :disabled="command.disabled"
433
- @select="executeProfileCommand(command.effect)"
205
+ @select="command.effect?.pipe(Effect.runPromise)"
434
206
  >
435
207
  <Icon
436
208
  v-if="command.icon"
@@ -439,7 +211,7 @@ watch(
439
211
  {{ command.title }}
440
212
  </DropdownMenuItem>
441
213
  </template>
442
- <DropdownMenuSeparator v-if="profileCommands.length > 0" />
214
+ <DropdownMenuSeparator v-if="props.commands?.some((command2) => 'children' in command2 ? command2.children.some((child2) => !child2.hidden) : !command2.hidden)" />
443
215
  <DropdownMenuItem disabled>
444
216
  <Icon icon="fluent:history-20-regular" />
445
217
  {{ t("build") }}
@@ -496,11 +268,11 @@ watch(
496
268
  <SidebarMenuButton
497
269
  v-if="'route' in menu"
498
270
  as-child
499
- :is-active="isNavigationItemActive(menu.route)"
271
+ :is-active="active === menu.route"
500
272
  >
501
273
  <button
502
274
  type="button"
503
- @click="activateTab(menu.route)"
275
+ @click="active = menu.route"
504
276
  >
505
277
  <Icon
506
278
  v-if="menu.icon"
@@ -532,11 +304,11 @@ watch(
532
304
  <SidebarMenuItem>
533
305
  <SidebarMenuButton
534
306
  as-child
535
- :is-active="isNavigationItemActive(group.route)"
307
+ :is-active="active === group.route"
536
308
  >
537
309
  <button
538
310
  type="button"
539
- @click="activateTab(group.route)"
311
+ @click="active = group.route"
540
312
  >
541
313
  <Icon
542
314
  v-if="group.icon"
@@ -557,7 +329,7 @@ watch(
557
329
  <main class="flex-1 flex flex-col bg-zinc-100 overflow-hidden">
558
330
  <nav class="bg-white p-1 border-b border-zinc-100 h-10 flex items-center justify-start gap-1 overflow-x-auto min-w-0">
559
331
  <div
560
- v-for="tab in tabList"
332
+ v-for="tab in tabs"
561
333
  :key="tab"
562
334
  :class="[
563
335
  'h-8 max-w-60 border rounded px-2 text-sm flex items-center gap-2 shrink-0 min-w-0 transition-colors',
@@ -567,14 +339,15 @@ watch(
567
339
  <button
568
340
  type="button"
569
341
  class="truncate cursor-pointer"
570
- @click="activateTab(tab)"
342
+ @click="active = tab"
571
343
  >
572
- {{ getTabLabel(tab) }}
344
+ {{ nameOf(tab) }}
573
345
  </button>
574
346
  <button
347
+ v-if="tabs.size !== 1"
575
348
  type="button"
576
349
  class="cursor-pointer text-zinc-500 hover:text-zinc-900"
577
- @click.stop="closeTab(tab)"
350
+ @click.stop="close(tab)"
578
351
  >
579
352
  <Icon icon="fluent:dismiss-20-regular" />
580
353
  </button>
@@ -1,5 +1,21 @@
1
1
  import type { Scope } from 'effect';
2
2
  import { Effect } from 'effect';
3
+ import { type Sidebar as SidebarType } from '../composables/useNavigationTabs.js';
4
+ type ProfileCommandInputItem = Readonly<{
5
+ id: string | number;
6
+ title: string;
7
+ icon?: string;
8
+ hidden?: boolean;
9
+ disabled?: boolean;
10
+ effect?: Effect.Effect<void>;
11
+ keywords?: Array<string>;
12
+ }>;
13
+ type ProfileCommandInputGroup = Readonly<{
14
+ id: string | number;
15
+ title: string;
16
+ icon?: string;
17
+ children: Array<ProfileCommandInputItem>;
18
+ }>;
3
19
  type __VLS_Props = {
4
20
  /**
5
21
  * 应用的全局 DSL(CEL)执行上下文。传入一个 Effect,在应用启动时运行一次;
@@ -38,12 +54,26 @@ type __VLS_Props = {
38
54
  * // CEL 中可访问 user.name、permissions.canEdit 等;失败时在 effect 内兜底,不抛错
39
55
  */
40
56
  dsl?: Effect.Effect<Record<string, unknown>, never, Scope.Scope>;
57
+ /**
58
+ * Sidebar config.
59
+ *
60
+ * `menus` is structured navigation data.
61
+ */
62
+ sidebar?: SidebarType;
63
+ /**
64
+ * Profile command config.
65
+ *
66
+ * Structured command entries for profile menu and command palette.
67
+ */
68
+ commands?: Array<ProfileCommandInputItem | ProfileCommandInputGroup>;
41
69
  };
42
- declare var __VLS_122: {}, __VLS_346: {};
70
+ declare var __VLS_108: {}, __VLS_124: {}, __VLS_334: {};
43
71
  type __VLS_Slots = {} & {
44
- menu?: (props: typeof __VLS_122) => any;
72
+ menu?: (props: typeof __VLS_108) => any;
73
+ } & {
74
+ profile?: (props: typeof __VLS_124) => any;
45
75
  } & {
46
- default?: (props: typeof __VLS_346) => any;
76
+ default?: (props: typeof __VLS_334) => any;
47
77
  };
48
78
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
49
79
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -7,7 +7,7 @@ type Group<K extends string | number> = Readonly<{
7
7
  children: Array<Item<K>>;
8
8
  }>;
9
9
  type Favoritable<K extends string | number> = Item<K> | Group<K>;
10
- export declare function useFavorite<K extends string | number, T extends Favoritable<K>>(key: string, items: MaybeRefOrGetter<Array<T>>): {
10
+ export declare function useFavorite<K extends string | number, T extends Favoritable<K>>(key: string, items: MaybeRefOrGetter<ReadonlyArray<T>>): {
11
11
  favorite: <I extends Item<K>>(item: I, of: K) => void;
12
12
  unfavorite: <I extends Item<K>>(item: I, of?: K) => void;
13
13
  toggle: <I extends Item<K>>(item: I, of: K) => void;
@@ -1,7 +1,21 @@
1
- export declare function useNavigationTabs(): {
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ type SidebarMenuItem = Readonly<{
3
+ id: string | number;
4
+ title: string;
5
+ icon?: string;
6
+ route: string;
7
+ }>;
8
+ type SidebarMenuGroup = Readonly<{
9
+ id: string | number;
10
+ title: string;
11
+ icon?: string;
12
+ children: Array<SidebarMenuItem>;
13
+ }>;
14
+ export type Sidebar = ReadonlyArray<SidebarMenuItem | SidebarMenuGroup>;
15
+ export declare function useNavigationTabs(navigations: MaybeRefOrGetter<Sidebar>): {
2
16
  tabs: import("@vueuse/shared").RemovableRef<Set<string>>;
3
- tabList: import("vue").ComputedRef<string[]>;
4
- active: import("@vueuse/shared").RemovableRef<string | undefined>;
5
- activateTab: (tab: string) => void;
6
- closeTab: (tab: string) => void;
17
+ nameOf: (path: string) => string | undefined;
18
+ close: (raw: string) => void;
19
+ active: import("vue").WritableComputedRef<string | undefined, string>;
7
20
  };
21
+ export {};