@shwfed/nuxt 0.1.75 → 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,25 +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({
31
+ title: () => active.value && nameOf(active.value),
34
32
  bodyAttrs: {
35
33
  style: {
36
34
  "--primary": "#2DA8BC",
@@ -38,221 +36,18 @@ useHead({
38
36
  }
39
37
  }
40
38
  });
41
- const props = defineProps({
42
- dsl: { type: null, required: false }
43
- });
44
- const ui = reactive({
45
- isCommandPaletteOpen: false,
46
- isProfileDropdownOpen: false
47
- });
48
39
  const { start: startProfileCloseTimer, stop: stopProfileCloseTimer } = useTimeoutFn(() => {
49
40
  ui.isProfileDropdownOpen = false;
50
41
  }, 150, { immediate: false });
51
42
  const { meta_k } = useMagicKeys();
52
43
  whenever(() => meta_k?.value, () => ui.isCommandPaletteOpen = !ui.isCommandPaletteOpen);
53
44
  setGlobalDslContext(await props.dsl?.pipe(Effect.scoped).pipe(Effect.runPromise) ?? {});
54
- const navigationItem = z.object({
55
- id: z.union([z.string(), z.number()]),
56
- title: z.string(),
57
- icon: z.string().optional(),
58
- route: z.string(),
59
- keywords: z.array(z.string()).optional()
60
- });
61
- const navigationGroup = z.object({
62
- id: z.union([z.string(), z.number()]),
63
- title: z.string(),
64
- icon: z.string().optional(),
65
- children: z.array(navigationItem)
66
- });
67
- const navigationEntry = z.union([navigationGroup, navigationItem]);
68
- const navigationItems = computed(() => {
69
- try {
70
- const result = $dsl.evaluate`${config.sidebar.menus}`();
71
- return z.array(navigationEntry).parse(result);
72
- } catch {
73
- return [];
74
- }
75
- });
76
45
  const {
77
46
  isFavorited: isNavigationFavorited,
78
47
  canBeFavorited: canBeNavigationFavorited,
79
48
  toggle: toggleNavigationFavorite,
80
49
  withFavorites: navigations
81
- } = useFavorite("navigation", navigationItems);
82
- const isNavigationItemActive = (itemRoute) => isRouteActive(route.path, itemRoute);
83
- const getTabLabel = (tab) => {
84
- return resolveNavigationTitle(navigationItems.value, tab);
85
- };
86
- const activeTabLabel = computed(() => {
87
- if (active.value === void 0)
88
- return void 0;
89
- return getTabLabel(active.value);
90
- });
91
- useHead(() => ({
92
- title: activeTabLabel.value
93
- }));
94
- const profileName = computed(() => {
95
- if (config.profile.name === void 0)
96
- return t("profile");
97
- try {
98
- const content = $md.inline`${config.profile.name}`();
99
- const plainText = content.replace(/<[^>]*>/g, "").trim();
100
- if (plainText.length === 0)
101
- return t("profile");
102
- return plainText;
103
- } catch {
104
- return t("profile");
105
- }
106
- });
107
- const commandItem = z.object({
108
- id: z.union([z.string(), z.number()]),
109
- title: z.string(),
110
- icon: z.string().optional(),
111
- hidden: z.string().optional(),
112
- disabled: z.string().optional(),
113
- effect: z.string().optional(),
114
- keywords: z.array(z.string()).optional()
115
- });
116
- const commandGroup = z.object({
117
- id: z.union([z.string(), z.number()]),
118
- title: z.string(),
119
- icon: z.string().optional(),
120
- children: z.array(commandItem)
121
- });
122
- const evaluateDslBoolean = (expression) => {
123
- if (expression === void 0)
124
- return false;
125
- try {
126
- return $dsl.evaluate`${expression}`() === true;
127
- } catch {
128
- return false;
129
- }
130
- };
131
- const normalizeEffectExpression = (expression) => {
132
- return expression.replace(/([{,]\s*)([a-z_][\w-]*)(\s*:)/gi, "$1'$2'$3");
133
- };
134
- const profileCommands = computed(() => {
135
- if (config.commands === void 0)
136
- return [];
137
- try {
138
- const result = $dsl.evaluate`${config.commands}`();
139
- const entries = z.array(z.union([commandGroup, commandItem])).parse(result);
140
- const normalized = [];
141
- for (const entry of entries) {
142
- if ("children" in entry) {
143
- const children = entry.children.filter((child) => !evaluateDslBoolean(child.hidden)).map((child) => ({
144
- id: child.id,
145
- title: child.title,
146
- icon: child.icon,
147
- disabled: evaluateDslBoolean(child.disabled),
148
- effect: child.effect,
149
- keywords: child.keywords
150
- }));
151
- if (children.length > 0) {
152
- normalized.push({
153
- id: entry.id,
154
- title: entry.title,
155
- icon: entry.icon,
156
- children
157
- });
158
- }
159
- continue;
160
- }
161
- if (evaluateDslBoolean(entry.hidden))
162
- continue;
163
- normalized.push({
164
- id: entry.id,
165
- title: entry.title,
166
- icon: entry.icon,
167
- disabled: evaluateDslBoolean(entry.disabled),
168
- effect: entry.effect,
169
- keywords: entry.keywords
170
- });
171
- }
172
- return normalized;
173
- } catch {
174
- return [];
175
- }
176
- });
177
- const isBodyInit = (value) => {
178
- return typeof value === "string" || value instanceof Blob || value instanceof ArrayBuffer || ArrayBuffer.isView(value) || value instanceof FormData || value instanceof URLSearchParams || value instanceof ReadableStream;
179
- };
180
- const toApiRequestBody = (value) => {
181
- if (value === void 0 || value === null)
182
- return value;
183
- if (isBodyInit(value))
184
- return value;
185
- if (typeof value === "object")
186
- return value;
187
- return void 0;
188
- };
189
- const executeCommandEffect = async (effect) => {
190
- if (effect === void 0)
191
- return false;
192
- let action;
193
- try {
194
- let result;
195
- try {
196
- result = $dsl.evaluate`${effect}`();
197
- } catch {
198
- result = $dsl.evaluate`${normalizeEffectExpression(effect)}`();
199
- }
200
- action = commandActionSchema.parse(result);
201
- await executeCommandAction(action, {
202
- logout: $logout,
203
- request: async (requestAction) => $api(requestAction.url, {
204
- method: requestAction.method,
205
- body: toApiRequestBody(requestAction.body),
206
- query: requestAction.query,
207
- headers: requestAction.headers
208
- })
209
- });
210
- return true;
211
- } catch (error) {
212
- if (action?.type === "request") {
213
- const message = error instanceof Error && error.message.length > 0 ? error.message : "Request failed";
214
- $toast.error(message);
215
- }
216
- return false;
217
- }
218
- };
219
- const executeProfileCommand = async (effect) => {
220
- if (effect === void 0 || await executeCommandEffect(effect))
221
- ui.isProfileDropdownOpen = false;
222
- };
223
- const normalizedNavigationForPalette = computed(() => {
224
- try {
225
- return z.array(navigationEntry).parse(navigations.value);
226
- } catch {
227
- return navigationItems.value;
228
- }
229
- });
230
- const paletteNavigation = computed(() => splitNavigationForPalette(normalizedNavigationForPalette.value));
231
- const favoriteRoutesForPalette = computed(() => paletteNavigation.value.favoriteRoutes);
232
- const navigationForPalette = computed(() => paletteNavigation.value.navigationEntries);
233
- const commandForPalette = computed(() => normalizeCommandsForPalette(profileCommands.value));
234
- const executePaletteItem = async (item) => {
235
- if (item.type === "route") {
236
- activateTab(item.route);
237
- ui.isCommandPaletteOpen = false;
238
- return;
239
- }
240
- if (item.effect !== void 0 && !await executeCommandEffect(item.effect))
241
- return;
242
- ui.isCommandPaletteOpen = false;
243
- };
244
- watch(
245
- () => route.path,
246
- (path) => {
247
- applyRootNavigationFallback({
248
- path,
249
- items: navigationItems.value,
250
- tabs: tabs.value,
251
- activateTab
252
- });
253
- },
254
- { immediate: true }
255
- );
50
+ } = useFavorite("navigation", () => props.sidebar ?? []);
256
51
  </script>
257
52
 
258
53
  <template>
@@ -276,102 +71,68 @@ watch(
276
71
  </section>
277
72
  </CommandEmpty>
278
73
 
279
- <CommandGroup
280
- v-if="favoriteRoutesForPalette.length > 0"
281
- :heading="t('favorites')"
282
- >
283
- <CommandItem
284
- v-for="menu in favoriteRoutesForPalette"
285
- :key="`fav:${menu.id}:${menu.route}`"
286
- :value="createPaletteItemValue('fav', `${menu.id}:${menu.route}`)"
287
- @select="executePaletteItem({ type: 'route', route: menu.route })"
288
- >
289
- <span>{{ menu.title }}</span>
290
- <span
291
- v-if="menu.keywords.length > 0"
292
- class="sr-only"
293
- >
294
- {{ menu.keywords.join(" ") }}
295
- </span>
296
- </CommandItem>
297
- </CommandGroup>
298
-
299
74
  <template
300
- v-for="navigation in navigationForPalette"
301
- :key="navigation.id"
75
+ v-for="command in props.commands"
76
+ :key="command.id"
302
77
  >
303
78
  <CommandGroup
304
- v-if="'children' in navigation"
305
- :heading="navigation.title"
79
+ v-if="'children' in command"
80
+ :heading="command.title"
306
81
  >
307
82
  <CommandItem
308
- v-for="menu in navigation.children"
309
- :key="menu.id"
310
- :value="createPaletteItemValue('nav', menu.id, navigation.id)"
311
- @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)"
312
90
  >
313
- <span>{{ menu.title }}</span>
314
- <span
315
- v-if="menu.keywords.length > 0"
316
- class="sr-only"
317
- >
318
- {{ menu.keywords.join(" ") }}
91
+ <span>{{ child.title }}</span>
92
+ <span class="sr-only">
93
+ {{ child.keywords?.join(" ") }}
319
94
  </span>
320
95
  </CommandItem>
321
96
  </CommandGroup>
322
97
  <CommandGroup v-else>
323
98
  <CommandItem
324
- :value="createPaletteItemValue('nav', navigation.id)"
325
- @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)"
326
104
  >
327
- <span>{{ navigation.title }}</span>
328
- <span
329
- v-if="navigation.keywords.length > 0"
330
- class="sr-only"
331
- >
332
- {{ navigation.keywords.join(" ") }}
105
+ <span>{{ command.title }}</span>
106
+ <span class="sr-only">
107
+ {{ command.keywords?.join(" ") }}
333
108
  </span>
334
109
  </CommandItem>
335
110
  </CommandGroup>
336
111
  </template>
337
112
 
338
113
  <template
339
- v-for="command in commandForPalette"
340
- :key="command.id"
114
+ v-for="navigation in props.sidebar"
115
+ :key="navigation.id"
341
116
  >
342
117
  <CommandGroup
343
- v-if="'children' in command"
344
- :heading="command.title"
118
+ v-if="'children' in navigation"
119
+ :heading="navigation.title"
345
120
  >
346
121
  <CommandItem
347
- v-for="child in command.children"
348
- :key="child.id"
349
- :value="createPaletteItemValue('cmd', child.id, command.id)"
350
- :disabled="child.disabled"
351
- @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)"
352
126
  >
353
- <span>{{ child.title }}</span>
354
- <span
355
- v-if="child.keywords.length > 0"
356
- class="sr-only"
357
- >
358
- {{ child.keywords.join(" ") }}
359
- </span>
127
+ <span>{{ menu.title }}</span>
360
128
  </CommandItem>
361
129
  </CommandGroup>
362
130
  <CommandGroup v-else>
363
131
  <CommandItem
364
- :value="createPaletteItemValue('cmd', command.id)"
365
- :disabled="command.disabled"
366
- @select="executePaletteItem({ type: 'command', effect: command.effect })"
132
+ :value="navigation.id"
133
+ @select="$router.replace(navigation.route)"
367
134
  >
368
- <span>{{ command.title }}</span>
369
- <span
370
- v-if="command.keywords.length > 0"
371
- class="sr-only"
372
- >
373
- {{ command.keywords.join(" ") }}
374
- </span>
135
+ <span>{{ navigation.title }}</span>
375
136
  </CommandItem>
376
137
  </CommandGroup>
377
138
  </template>
@@ -400,7 +161,7 @@ watch(
400
161
  @click.prevent="stopProfileCloseTimer();
401
162
  ui.isProfileDropdownOpen = true"
402
163
  >
403
- {{ profileName }}
164
+ <slot name="profile" />
404
165
  </button>
405
166
  </DropdownMenuTrigger>
406
167
  <DropdownMenuContent
@@ -411,33 +172,37 @@ watch(
411
172
  startProfileCloseTimer()"
412
173
  >
413
174
  <template
414
- v-for="command in profileCommands"
175
+ v-for="command in props.commands"
415
176
  :key="command.id"
416
177
  >
417
- <template v-if="'children' in command">
178
+ <template v-if="'children' in command && command.children.some((child2) => !child2.hidden)">
418
179
  <DropdownMenuLabel>
419
180
  {{ command.title }}
420
181
  </DropdownMenuLabel>
421
182
  <DropdownMenuGroup>
422
- <DropdownMenuItem
183
+ <template
423
184
  v-for="child in command.children"
424
185
  :key="child.id"
425
- :disabled="child.disabled"
426
- @select="executeProfileCommand(child.effect)"
427
186
  >
428
- <Icon
429
- v-if="child.icon"
430
- :icon="child.icon"
431
- />
432
- {{ child.title }}
433
- </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>
434
199
  </DropdownMenuGroup>
435
200
  <DropdownMenuSeparator />
436
201
  </template>
437
202
  <DropdownMenuItem
438
- v-else
203
+ v-else-if="!('children' in command) && !command.hidden"
439
204
  :disabled="command.disabled"
440
- @select="executeProfileCommand(command.effect)"
205
+ @select="command.effect?.pipe(Effect.runPromise)"
441
206
  >
442
207
  <Icon
443
208
  v-if="command.icon"
@@ -446,7 +211,7 @@ watch(
446
211
  {{ command.title }}
447
212
  </DropdownMenuItem>
448
213
  </template>
449
- <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)" />
450
215
  <DropdownMenuItem disabled>
451
216
  <Icon icon="fluent:history-20-regular" />
452
217
  {{ t("build") }}
@@ -503,11 +268,11 @@ watch(
503
268
  <SidebarMenuButton
504
269
  v-if="'route' in menu"
505
270
  as-child
506
- :is-active="isNavigationItemActive(menu.route)"
271
+ :is-active="active === menu.route"
507
272
  >
508
273
  <button
509
274
  type="button"
510
- @click="activateTab(menu.route)"
275
+ @click="active = menu.route"
511
276
  >
512
277
  <Icon
513
278
  v-if="menu.icon"
@@ -539,11 +304,11 @@ watch(
539
304
  <SidebarMenuItem>
540
305
  <SidebarMenuButton
541
306
  as-child
542
- :is-active="isNavigationItemActive(group.route)"
307
+ :is-active="active === group.route"
543
308
  >
544
309
  <button
545
310
  type="button"
546
- @click="activateTab(group.route)"
311
+ @click="active = group.route"
547
312
  >
548
313
  <Icon
549
314
  v-if="group.icon"
@@ -564,7 +329,7 @@ watch(
564
329
  <main class="flex-1 flex flex-col bg-zinc-100 overflow-hidden">
565
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">
566
331
  <div
567
- v-for="tab in tabList"
332
+ v-for="tab in tabs"
568
333
  :key="tab"
569
334
  :class="[
570
335
  'h-8 max-w-60 border rounded px-2 text-sm flex items-center gap-2 shrink-0 min-w-0 transition-colors',
@@ -574,14 +339,15 @@ watch(
574
339
  <button
575
340
  type="button"
576
341
  class="truncate cursor-pointer"
577
- @click="activateTab(tab)"
342
+ @click="active = tab"
578
343
  >
579
- {{ getTabLabel(tab) }}
344
+ {{ nameOf(tab) }}
580
345
  </button>
581
346
  <button
347
+ v-if="tabs.size !== 1"
582
348
  type="button"
583
349
  class="cursor-pointer text-zinc-500 hover:text-zinc-900"
584
- @click.stop="closeTab(tab)"
350
+ @click.stop="close(tab)"
585
351
  >
586
352
  <Icon icon="fluent:dismiss-20-regular" />
587
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 {};