@frigear-nu/menu 0.1.1 → 0.1.2
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/module.json +1 -1
- package/dist/runtime/app/composables/useMenu.js +2 -2
- package/dist/runtime/app/plugins/menus.d.ts +4 -5
- package/dist/runtime/app/plugins/menus.js +12 -7
- package/dist/runtime/app/utils/extend.js +2 -2
- package/dist/runtime/app/utils/state.d.ts +14 -11
- package/dist/runtime/app/utils/state.js +21 -5
- package/dist/runtime/server/utils.js +4 -4
- package/package.json +2 -2
package/dist/module.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { computed, unref } from "vue";
|
|
2
2
|
import { useAsyncData, useNuxtApp, useRuntimeConfig } from "#imports";
|
|
3
3
|
import { collectMenuItems, matchesMenuGroup, parseMenuPath, sortByOrder, translateMenuItem } from "../../utils/menu.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getAppMenuStore } from "../utils/state.js";
|
|
5
5
|
function useMenuLocale() {
|
|
6
6
|
const nuxtApp = useNuxtApp();
|
|
7
7
|
return computed(() => nuxtApp.$i18n?.locale?.value);
|
|
@@ -30,7 +30,7 @@ export const useMenu = (path) => {
|
|
|
30
30
|
() => `menu:${path}:${locale.value ?? ""}`,
|
|
31
31
|
async () => {
|
|
32
32
|
const i18n = nuxtApp.$i18n?.t && nuxtApp.$i18n.te ? nuxtApp.$i18n : void 0;
|
|
33
|
-
const registered = collectMenuItems(
|
|
33
|
+
const registered = collectMenuItems(getAppMenuStore(nuxtApp)[menu], parsed).map((item) => translateMenuItem(item, i18n));
|
|
34
34
|
const content = await loadContentItems(menu, parsed, unref(locale));
|
|
35
35
|
const result = sortByOrder([...content, ...registered]);
|
|
36
36
|
await nuxtApp.callHook("menus:visible", menu);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Populates
|
|
3
|
-
* build time (`extendMenu`), then by running every registered module's dynamic `runtime/menus.ts`
|
|
4
|
-
* source once per app instance (server: once per request, client: once on hydration).
|
|
5
|
-
*
|
|
6
|
-
* accumulate duplicate items.
|
|
2
|
+
* Populates this app instance's menu state, consumed by `useMenu`: first with every item registered
|
|
3
|
+
* at build time (`extendMenu`), then by running every registered module's dynamic `runtime/menus.ts`
|
|
4
|
+
* source once per app instance (server: once per request, client: once on hydration). The state is
|
|
5
|
+
* held per app instance, so concurrent server requests never share or clobber each other's menus.
|
|
7
6
|
*/
|
|
8
7
|
declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
|
|
9
8
|
export default _default;
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import { defineNuxtPlugin } from "#imports";
|
|
1
|
+
import { defineNuxtPlugin, tryUseNuxtApp } from "#imports";
|
|
2
2
|
import { staticItems, sources } from "#menus/sources";
|
|
3
|
-
import { pushMenuItems, resetMenus } from "../utils/state.js";
|
|
3
|
+
import { getAppMenuStore, pushMenuItems, resetMenus, setAppMenuStoreResolver } from "../utils/state.js";
|
|
4
4
|
export default defineNuxtPlugin({
|
|
5
5
|
name: "frigear-nu:menus",
|
|
6
|
-
async setup() {
|
|
7
|
-
|
|
6
|
+
async setup(nuxtApp) {
|
|
7
|
+
const store = getAppMenuStore(nuxtApp);
|
|
8
|
+
setAppMenuStoreResolver(() => {
|
|
9
|
+
const app = tryUseNuxtApp();
|
|
10
|
+
return app ? getAppMenuStore(app) : void 0;
|
|
11
|
+
});
|
|
12
|
+
resetMenus(store);
|
|
8
13
|
for (const [menu, groups] of Object.entries(staticItems)) {
|
|
9
14
|
for (const [group, items] of Object.entries(groups)) {
|
|
10
|
-
if (items.length > 0) pushMenuItems(menu, group, items);
|
|
15
|
+
if (items.length > 0) pushMenuItems(store, menu, group, items);
|
|
11
16
|
}
|
|
12
17
|
}
|
|
13
18
|
for (const { menu, source } of sources) {
|
|
14
19
|
const items = [];
|
|
15
|
-
await source(items);
|
|
16
|
-
if (items.length > 0) pushMenuItems(menu, "", items);
|
|
20
|
+
await nuxtApp.runWithContext(() => source(items));
|
|
21
|
+
if (items.length > 0) pushMenuItems(store, menu, "", items);
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseMenuPath } from "../../utils/menu.js";
|
|
2
|
-
import { pushMenuItems } from "./state.js";
|
|
2
|
+
import { currentMenuStore, pushMenuItems } from "./state.js";
|
|
3
3
|
export function extendMenuItem(path, item) {
|
|
4
4
|
const { menu, group, wildcard } = parseMenuPath(path);
|
|
5
5
|
if (wildcard) {
|
|
6
6
|
throw new Error(`[@frigear-nu/menu] Cannot register items into wildcard path "${path}" - wildcards are only supported when reading a menu via \`useMenu\`.`);
|
|
7
7
|
}
|
|
8
|
-
pushMenuItems(menu, group, item);
|
|
8
|
+
pushMenuItems(currentMenuStore(), menu, group, item);
|
|
9
9
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { MenuItem } from '../../../types.js';
|
|
2
|
+
/** Every menu's items, keyed by menu name then by group (`''` for the root group). */
|
|
3
|
+
export type MenuStore = Record<string, Record<string, MenuItem[]>>;
|
|
4
|
+
export declare function createMenuStore(): MenuStore;
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
+
* Process-wide store, used only when no Nuxt app is in scope: the Nitro `useMenu` (populated once per
|
|
7
|
+
* process from the runtime config) and calls made outside an app context. It is never read by the
|
|
8
|
+
* Vue renderer, which uses the per-app store below.
|
|
6
9
|
*/
|
|
7
|
-
export declare const
|
|
8
|
-
export declare function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
|
-
export declare function resetMenus(): void;
|
|
10
|
+
export declare const processMenuStore: MenuStore;
|
|
11
|
+
export declare function getAppMenuStore(nuxtApp: object): MenuStore;
|
|
12
|
+
export declare function setAppMenuStoreResolver(resolver: () => MenuStore | undefined): void;
|
|
13
|
+
/** The store of the Nuxt app currently in scope, or the process-wide store outside any app. */
|
|
14
|
+
export declare function currentMenuStore(): MenuStore;
|
|
15
|
+
export declare function pushMenuItems(store: MenuStore, menu: string, group: string, items: MenuItem | MenuItem[]): void;
|
|
16
|
+
/** Empties every registered menu/group's items in place, so a (re)population never accumulates duplicates. */
|
|
17
|
+
export declare function resetMenus(store: MenuStore): void;
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { reactive } from "vue";
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export function createMenuStore() {
|
|
3
|
+
return reactive({});
|
|
4
|
+
}
|
|
5
|
+
export const processMenuStore = createMenuStore();
|
|
6
|
+
const appStores = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
export function getAppMenuStore(nuxtApp) {
|
|
8
|
+
let store = appStores.get(nuxtApp);
|
|
9
|
+
if (!store) appStores.set(nuxtApp, store = createMenuStore());
|
|
10
|
+
return store;
|
|
11
|
+
}
|
|
12
|
+
let resolveAppStore;
|
|
13
|
+
export function setAppMenuStoreResolver(resolver) {
|
|
14
|
+
resolveAppStore = resolver;
|
|
15
|
+
}
|
|
16
|
+
export function currentMenuStore() {
|
|
17
|
+
return resolveAppStore?.() ?? processMenuStore;
|
|
18
|
+
}
|
|
19
|
+
export function pushMenuItems(store, menu, group, items) {
|
|
20
|
+
const groups = store[menu] ??= {};
|
|
5
21
|
const list = groups[group] ??= [];
|
|
6
22
|
list.push(...Array.isArray(items) ? items : [items]);
|
|
7
23
|
}
|
|
8
|
-
export function resetMenus() {
|
|
9
|
-
for (const groups of Object.values(
|
|
24
|
+
export function resetMenus(store) {
|
|
25
|
+
for (const groups of Object.values(store)) {
|
|
10
26
|
for (const list of Object.values(groups)) list.length = 0;
|
|
11
27
|
}
|
|
12
28
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "nitropack/runtime";
|
|
2
2
|
import { staticItems, sources } from "#menus/server-sources";
|
|
3
3
|
import { collectMenuItems, matchesMenuGroup, parseMenuPath, sortByOrder } from "../utils/menu.js";
|
|
4
|
-
import { menus, pushMenuItems, resetMenus } from "../app/utils/state.js";
|
|
4
|
+
import { processMenuStore as menus, pushMenuItems, resetMenus } from "../app/utils/state.js";
|
|
5
5
|
let registered;
|
|
6
6
|
function registerItems() {
|
|
7
7
|
registered ??= (async () => {
|
|
8
|
-
resetMenus();
|
|
8
|
+
resetMenus(menus);
|
|
9
9
|
for (const [menu, groups] of Object.entries(staticItems)) {
|
|
10
10
|
for (const [group, items] of Object.entries(groups)) {
|
|
11
|
-
if (items.length > 0) pushMenuItems(menu, group, items);
|
|
11
|
+
if (items.length > 0) pushMenuItems(menus, menu, group, items);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
for (const { menu, source } of sources) {
|
|
15
15
|
const items = [];
|
|
16
16
|
await source(items);
|
|
17
|
-
if (items.length > 0) pushMenuItems(menu, "", items);
|
|
17
|
+
if (items.length > 0) pushMenuItems(menus, menu, "", items);
|
|
18
18
|
}
|
|
19
19
|
})().catch((error) => {
|
|
20
20
|
registered = void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frigear-nu/menu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Named, shareable navigation menus - modules contribute items (extendMenu / a runtime/menus.ts source) and/or Nuxt Content, consumers read them via useMenu and render them however they like.",
|
|
5
5
|
"homepage": "https://docs.frigear.dev/modules/menu",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@nuxt/kit": "^4.6.1",
|
|
34
|
-
"@frigear-nu/module-kit": "1.1.
|
|
34
|
+
"@frigear-nu/module-kit": "1.1.2",
|
|
35
35
|
"zod": "^4.6.5"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|