@leduchai/vmeta-ui-shell 0.1.3 → 0.1.5
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 +22 -6
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +23 -7
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
module.exports = __toCommonJS(index_exports);
|
|
29
29
|
var import_react = require("react");
|
|
30
30
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
var allowAllPermissions = () => true;
|
|
31
32
|
function isMenuItemActive(item, activePath) {
|
|
32
33
|
if (item.match === "exact") return activePath === item.href;
|
|
33
34
|
if (item.match === "prefix") return activePath === item.href || activePath.startsWith(`${item.href}/`);
|
|
@@ -59,13 +60,16 @@ function VmetaSidebar({
|
|
|
59
60
|
activePath,
|
|
60
61
|
collapsed = false,
|
|
61
62
|
storageKey = `vmeta:${app.appId}:menu-groups`,
|
|
63
|
+
idPrefix,
|
|
62
64
|
account,
|
|
63
65
|
footer,
|
|
64
66
|
showCollapse = false,
|
|
65
|
-
canAccess =
|
|
67
|
+
canAccess = allowAllPermissions,
|
|
66
68
|
onNavigate,
|
|
67
69
|
onCollapsedChange
|
|
68
70
|
}) {
|
|
71
|
+
const generatedId = (0, import_react.useId)().replace(/:/g, "");
|
|
72
|
+
const groupIdPrefix = idPrefix ?? `vmeta-menu-${app.appId}-${generatedId}`;
|
|
69
73
|
const visibleGroups = (0, import_react.useMemo)(
|
|
70
74
|
() => groups.map((group) => ({
|
|
71
75
|
...group,
|
|
@@ -83,7 +87,10 @@ function VmetaSidebar({
|
|
|
83
87
|
setOpenKeys(defaultOpenKeys);
|
|
84
88
|
return;
|
|
85
89
|
}
|
|
86
|
-
|
|
90
|
+
const nextOpenKeys = stored.filter(
|
|
91
|
+
(key) => typeof key === "string" && defaultOpenKeys.includes(key)
|
|
92
|
+
);
|
|
93
|
+
setOpenKeys((current) => current.length === nextOpenKeys.length && current.every((key, index) => key === nextOpenKeys[index]) ? current : nextOpenKeys);
|
|
87
94
|
} catch {
|
|
88
95
|
setOpenKeys(defaultOpenKeys);
|
|
89
96
|
}
|
|
@@ -124,14 +131,14 @@ function VmetaSidebar({
|
|
|
124
131
|
className: "vmeta-menu-group__toggle",
|
|
125
132
|
onClick: () => toggleGroup(group.key),
|
|
126
133
|
"aria-expanded": open,
|
|
127
|
-
"aria-controls":
|
|
134
|
+
"aria-controls": `${groupIdPrefix}-${group.key}`,
|
|
128
135
|
children: [
|
|
129
136
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: group.label }),
|
|
130
137
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `vmeta-menu-group__chevron ${open ? "is-open" : ""}`, "aria-hidden": "true", children: "\u2304" })
|
|
131
138
|
]
|
|
132
139
|
}
|
|
133
140
|
),
|
|
134
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { id:
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { id: `${groupIdPrefix}-${group.key}`, className: `vmeta-menu-group__items ${open ? "is-open" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: group.children.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VmetaMenuButton, { item, active: isMenuItemActive(item, activePath), onNavigate: navigate }, item.key)) }) })
|
|
135
142
|
] }, group.key);
|
|
136
143
|
}) }),
|
|
137
144
|
footer && !collapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "vmeta-sidebar__footer", children: footer }),
|
|
@@ -192,15 +199,24 @@ function VmetaAppShell({
|
|
|
192
199
|
canAccess,
|
|
193
200
|
onNavigate
|
|
194
201
|
}) {
|
|
195
|
-
const [collapsed, setCollapsed] = (0, import_react.useState)(
|
|
202
|
+
const [collapsed, setCollapsed] = (0, import_react.useState)(false);
|
|
196
203
|
const [menuOpen, setMenuOpen] = (0, import_react.useState)(false);
|
|
204
|
+
(0, import_react.useEffect)(() => {
|
|
205
|
+
setCollapsed(readStoredBoolean(storageKey, false));
|
|
206
|
+
}, [storageKey]);
|
|
197
207
|
const updateCollapsed = (value) => {
|
|
198
208
|
setCollapsed(value);
|
|
199
209
|
writeStorage(storageKey, String(value));
|
|
200
210
|
};
|
|
201
211
|
const navigate = (item) => {
|
|
202
212
|
setMenuOpen(false);
|
|
203
|
-
onNavigate
|
|
213
|
+
if (onNavigate) {
|
|
214
|
+
onNavigate(item);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (typeof window === "undefined") return;
|
|
218
|
+
if (item.external) window.open(item.href, "_blank", "noopener,noreferrer");
|
|
219
|
+
else window.location.assign(item.href);
|
|
204
220
|
};
|
|
205
221
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className: `vmeta-app-shell ${collapsed ? "is-collapsed" : ""}`, children: [
|
|
206
222
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
package/dist/index.d.cts
CHANGED
|
@@ -48,6 +48,7 @@ interface VmetaSidebarProps {
|
|
|
48
48
|
activePath: string;
|
|
49
49
|
collapsed?: boolean;
|
|
50
50
|
storageKey?: string;
|
|
51
|
+
idPrefix?: string;
|
|
51
52
|
account?: VmetaAccount;
|
|
52
53
|
footer?: ReactNode;
|
|
53
54
|
showCollapse?: boolean;
|
|
@@ -55,7 +56,7 @@ interface VmetaSidebarProps {
|
|
|
55
56
|
onNavigate?: (item: VmetaMenuItem) => void;
|
|
56
57
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
57
58
|
}
|
|
58
|
-
declare function VmetaSidebar({ app, groups, activePath, collapsed, storageKey, account, footer, showCollapse, canAccess, onNavigate, onCollapsedChange, }: VmetaSidebarProps): react_jsx_runtime.JSX.Element;
|
|
59
|
+
declare function VmetaSidebar({ app, groups, activePath, collapsed, storageKey, idPrefix, account, footer, showCollapse, canAccess, onNavigate, onCollapsedChange, }: VmetaSidebarProps): react_jsx_runtime.JSX.Element;
|
|
59
60
|
interface VmetaAppShellProps {
|
|
60
61
|
app: VmetaAppIdentity;
|
|
61
62
|
groups: VmetaMenuGroup[];
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ interface VmetaSidebarProps {
|
|
|
48
48
|
activePath: string;
|
|
49
49
|
collapsed?: boolean;
|
|
50
50
|
storageKey?: string;
|
|
51
|
+
idPrefix?: string;
|
|
51
52
|
account?: VmetaAccount;
|
|
52
53
|
footer?: ReactNode;
|
|
53
54
|
showCollapse?: boolean;
|
|
@@ -55,7 +56,7 @@ interface VmetaSidebarProps {
|
|
|
55
56
|
onNavigate?: (item: VmetaMenuItem) => void;
|
|
56
57
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
57
58
|
}
|
|
58
|
-
declare function VmetaSidebar({ app, groups, activePath, collapsed, storageKey, account, footer, showCollapse, canAccess, onNavigate, onCollapsedChange, }: VmetaSidebarProps): react_jsx_runtime.JSX.Element;
|
|
59
|
+
declare function VmetaSidebar({ app, groups, activePath, collapsed, storageKey, idPrefix, account, footer, showCollapse, canAccess, onNavigate, onCollapsedChange, }: VmetaSidebarProps): react_jsx_runtime.JSX.Element;
|
|
59
60
|
interface VmetaAppShellProps {
|
|
60
61
|
app: VmetaAppIdentity;
|
|
61
62
|
groups: VmetaMenuGroup[];
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
|
-
import { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { useEffect, useId, useMemo, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var allowAllPermissions = () => true;
|
|
6
7
|
function isMenuItemActive(item, activePath) {
|
|
7
8
|
if (item.match === "exact") return activePath === item.href;
|
|
8
9
|
if (item.match === "prefix") return activePath === item.href || activePath.startsWith(`${item.href}/`);
|
|
@@ -34,13 +35,16 @@ function VmetaSidebar({
|
|
|
34
35
|
activePath,
|
|
35
36
|
collapsed = false,
|
|
36
37
|
storageKey = `vmeta:${app.appId}:menu-groups`,
|
|
38
|
+
idPrefix,
|
|
37
39
|
account,
|
|
38
40
|
footer,
|
|
39
41
|
showCollapse = false,
|
|
40
|
-
canAccess =
|
|
42
|
+
canAccess = allowAllPermissions,
|
|
41
43
|
onNavigate,
|
|
42
44
|
onCollapsedChange
|
|
43
45
|
}) {
|
|
46
|
+
const generatedId = useId().replace(/:/g, "");
|
|
47
|
+
const groupIdPrefix = idPrefix ?? `vmeta-menu-${app.appId}-${generatedId}`;
|
|
44
48
|
const visibleGroups = useMemo(
|
|
45
49
|
() => groups.map((group) => ({
|
|
46
50
|
...group,
|
|
@@ -58,7 +62,10 @@ function VmetaSidebar({
|
|
|
58
62
|
setOpenKeys(defaultOpenKeys);
|
|
59
63
|
return;
|
|
60
64
|
}
|
|
61
|
-
|
|
65
|
+
const nextOpenKeys = stored.filter(
|
|
66
|
+
(key) => typeof key === "string" && defaultOpenKeys.includes(key)
|
|
67
|
+
);
|
|
68
|
+
setOpenKeys((current) => current.length === nextOpenKeys.length && current.every((key, index) => key === nextOpenKeys[index]) ? current : nextOpenKeys);
|
|
62
69
|
} catch {
|
|
63
70
|
setOpenKeys(defaultOpenKeys);
|
|
64
71
|
}
|
|
@@ -99,14 +106,14 @@ function VmetaSidebar({
|
|
|
99
106
|
className: "vmeta-menu-group__toggle",
|
|
100
107
|
onClick: () => toggleGroup(group.key),
|
|
101
108
|
"aria-expanded": open,
|
|
102
|
-
"aria-controls":
|
|
109
|
+
"aria-controls": `${groupIdPrefix}-${group.key}`,
|
|
103
110
|
children: [
|
|
104
111
|
/* @__PURE__ */ jsx("span", { children: group.label }),
|
|
105
112
|
/* @__PURE__ */ jsx("span", { className: `vmeta-menu-group__chevron ${open ? "is-open" : ""}`, "aria-hidden": "true", children: "\u2304" })
|
|
106
113
|
]
|
|
107
114
|
}
|
|
108
115
|
),
|
|
109
|
-
/* @__PURE__ */ jsx("div", { id:
|
|
116
|
+
/* @__PURE__ */ jsx("div", { id: `${groupIdPrefix}-${group.key}`, className: `vmeta-menu-group__items ${open ? "is-open" : ""}`, children: /* @__PURE__ */ jsx("div", { children: group.children.map((item) => /* @__PURE__ */ jsx(VmetaMenuButton, { item, active: isMenuItemActive(item, activePath), onNavigate: navigate }, item.key)) }) })
|
|
110
117
|
] }, group.key);
|
|
111
118
|
}) }),
|
|
112
119
|
footer && !collapsed && /* @__PURE__ */ jsx("div", { className: "vmeta-sidebar__footer", children: footer }),
|
|
@@ -167,15 +174,24 @@ function VmetaAppShell({
|
|
|
167
174
|
canAccess,
|
|
168
175
|
onNavigate
|
|
169
176
|
}) {
|
|
170
|
-
const [collapsed, setCollapsed] = useState(
|
|
177
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
171
178
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
setCollapsed(readStoredBoolean(storageKey, false));
|
|
181
|
+
}, [storageKey]);
|
|
172
182
|
const updateCollapsed = (value) => {
|
|
173
183
|
setCollapsed(value);
|
|
174
184
|
writeStorage(storageKey, String(value));
|
|
175
185
|
};
|
|
176
186
|
const navigate = (item) => {
|
|
177
187
|
setMenuOpen(false);
|
|
178
|
-
onNavigate
|
|
188
|
+
if (onNavigate) {
|
|
189
|
+
onNavigate(item);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (typeof window === "undefined") return;
|
|
193
|
+
if (item.external) window.open(item.href, "_blank", "noopener,noreferrer");
|
|
194
|
+
else window.location.assign(item.href);
|
|
179
195
|
};
|
|
180
196
|
return /* @__PURE__ */ jsxs("main", { className: `vmeta-app-shell ${collapsed ? "is-collapsed" : ""}`, children: [
|
|
181
197
|
/* @__PURE__ */ jsx(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leduchai/vmeta-ui-shell",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Application shell, sidebar, menu va header dung chung cua VMETA.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "tsup src/index.tsx --format esm,cjs --dts --clean --external react --external react-dom && node ../../scripts/copy-file.mjs src/styles.css dist/styles.css"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@leduchai/vmeta-ui-tokens": "0.1.
|
|
24
|
+
"@leduchai/vmeta-ui-tokens": "0.1.5"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": ">=18 <20",
|