@svadmin/ui 0.40.3 → 0.40.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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { captureAdminContext, getResources, canAccessAsync } from '@svadmin/core';
|
|
2
|
+
import { captureAdminContext, getResources, canAccessAsync, getAccessControlProvider } from '@svadmin/core';
|
|
3
3
|
import type { Identity, MenuItem } from '@svadmin/core';
|
|
4
4
|
import { getPath } from '../router-state.svelte.js';
|
|
5
5
|
import { useTranslation } from '@svadmin/core/i18n';
|
|
@@ -103,6 +103,62 @@
|
|
|
103
103
|
items: NavItem[];
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
async function hasCustomMenuAccess(menuItem: MenuItem): Promise<boolean> {
|
|
107
|
+
const resource = menuItem.meta?.resource;
|
|
108
|
+
if (!resource) return true;
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const { can } = await canAccessAsync(resource, menuItem.meta?.action ?? 'list');
|
|
112
|
+
return can;
|
|
113
|
+
} catch {
|
|
114
|
+
// Permission-provider failures must not expose protected navigation.
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function isVisibleCustomMenuItem(candidate: MenuItem | null): candidate is MenuItem {
|
|
120
|
+
return candidate !== null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function snapshotCustomMenuItems(menuItems: MenuItem[]): MenuItem[] {
|
|
124
|
+
return menuItems.map((menuItem) => ({
|
|
125
|
+
...menuItem,
|
|
126
|
+
meta: menuItem.meta ? { ...menuItem.meta } : undefined,
|
|
127
|
+
children: menuItem.children ? snapshotCustomMenuItems(menuItem.children) : undefined,
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function visibleCustomMenuItem(menuItem: MenuItem): Promise<MenuItem | null> {
|
|
132
|
+
if (menuItem.meta?.hidden || !await hasCustomMenuAccess(menuItem)) return null;
|
|
133
|
+
if (!menuItem.children) return menuItem;
|
|
134
|
+
|
|
135
|
+
const children = await visibleCustomMenuItems(menuItem.children);
|
|
136
|
+
if (children.length === 0 && !menuItem.href) return null;
|
|
137
|
+
return { ...menuItem, children };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function visibleCustomMenuItems(menuItems: MenuItem[]): Promise<MenuItem[]> {
|
|
141
|
+
const filteredItems = await Promise.all(menuItems.map(visibleCustomMenuItem));
|
|
142
|
+
return filteredItems.filter(isVisibleCustomMenuItem);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let customMenuItems = $state.raw<MenuItem[]>([]);
|
|
146
|
+
|
|
147
|
+
$effect(() => {
|
|
148
|
+
const configuredMenu = menu?.length ? snapshotCustomMenuItems(menu) : [];
|
|
149
|
+
// Provider swaps must invalidate checks nested below public menu groups.
|
|
150
|
+
getAccessControlProvider();
|
|
151
|
+
customMenuItems = [];
|
|
152
|
+
if (configuredMenu.length === 0) return;
|
|
153
|
+
|
|
154
|
+
let cancelled = false;
|
|
155
|
+
void visibleCustomMenuItems(configuredMenu).then((visibleItems) => {
|
|
156
|
+
if (!cancelled) customMenuItems = visibleItems;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return () => { cancelled = true; };
|
|
160
|
+
});
|
|
161
|
+
|
|
106
162
|
let navItems = $state.raw<NavItem[]>([]);
|
|
107
163
|
|
|
108
164
|
$effect(() => {
|
|
@@ -239,7 +295,7 @@
|
|
|
239
295
|
<nav aria-label="Main menu" class="pb-4" class:px-[10px]={!collapsed} class:px-2={collapsed}>
|
|
240
296
|
{#if menu && menu.length > 0}
|
|
241
297
|
<div class="space-y-[2px]">
|
|
242
|
-
{#each
|
|
298
|
+
{#each customMenuItems as item (item.name)}
|
|
243
299
|
<SidebarItem {item} currentPath={path} {collapsed} depth={0} />
|
|
244
300
|
{/each}
|
|
245
301
|
</div>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script
|
|
2
|
+
lang="ts"
|
|
3
|
+
generics="Type extends HTMLInputTypeAttribute | undefined = undefined"
|
|
4
|
+
>
|
|
2
5
|
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements";
|
|
3
6
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
4
7
|
|
|
5
|
-
type
|
|
8
|
+
type InputValue = HTMLInputAttributes["value"];
|
|
6
9
|
|
|
7
10
|
type Props = WithElementRef<
|
|
8
|
-
Omit<HTMLInputAttributes, "type"> &
|
|
9
|
-
(
|
|
11
|
+
Omit<HTMLInputAttributes, "type" | "value"> &
|
|
12
|
+
(Type extends "file"
|
|
13
|
+
? { type: "file"; files?: FileList; value?: never }
|
|
14
|
+
: { type?: Type; files?: undefined; value?: InputValue })
|
|
10
15
|
>;
|
|
11
16
|
|
|
12
17
|
let {
|
|
@@ -30,7 +35,6 @@
|
|
|
30
35
|
)}
|
|
31
36
|
type="file"
|
|
32
37
|
bind:files
|
|
33
|
-
bind:value
|
|
34
38
|
{...restProps}
|
|
35
39
|
/>
|
|
36
40
|
{:else}
|
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements";
|
|
2
2
|
import { type WithElementRef } from "../../../utils.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
declare function $$render<Type extends HTMLInputTypeAttribute | undefined = undefined>(): {
|
|
4
|
+
props: WithElementRef<Omit<HTMLInputAttributes, "type" | "value"> & (Type extends "file" ? {
|
|
5
|
+
type: "file";
|
|
6
|
+
files?: FileList;
|
|
7
|
+
value?: never;
|
|
8
|
+
} : {
|
|
9
|
+
type?: Type;
|
|
10
|
+
files?: undefined;
|
|
11
|
+
value?: any;
|
|
12
|
+
})>;
|
|
13
|
+
exports: {};
|
|
14
|
+
bindings: "value" | "ref" | "files";
|
|
15
|
+
slots: {};
|
|
16
|
+
events: {};
|
|
17
|
+
};
|
|
18
|
+
declare class __sveltets_Render<Type extends HTMLInputTypeAttribute | undefined = undefined> {
|
|
19
|
+
props(): ReturnType<typeof $$render<Type>>['props'];
|
|
20
|
+
events(): ReturnType<typeof $$render<Type>>['events'];
|
|
21
|
+
slots(): ReturnType<typeof $$render<Type>>['slots'];
|
|
22
|
+
bindings(): "value" | "ref" | "files";
|
|
23
|
+
exports(): {};
|
|
24
|
+
}
|
|
25
|
+
interface $$IsomorphicComponent {
|
|
26
|
+
new <Type extends HTMLInputTypeAttribute | undefined = undefined>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Type>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Type>['props']>, ReturnType<__sveltets_Render<Type>['events']>, ReturnType<__sveltets_Render<Type>['slots']>> & {
|
|
27
|
+
$$bindings?: ReturnType<__sveltets_Render<Type>['bindings']>;
|
|
28
|
+
} & ReturnType<__sveltets_Render<Type>['exports']>;
|
|
29
|
+
<Type extends HTMLInputTypeAttribute | undefined = undefined>(internal: unknown, props: ReturnType<__sveltets_Render<Type>['props']> & {}): ReturnType<__sveltets_Render<Type>['exports']>;
|
|
30
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
31
|
+
}
|
|
32
|
+
declare const Input: $$IsomorphicComponent;
|
|
33
|
+
type Input<Type extends HTMLInputTypeAttribute | undefined = undefined> = InstanceType<typeof Input<Type>>;
|
|
13
34
|
export default Input;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/ui",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.5",
|
|
4
4
|
"description": "Pre-built admin UI components — AdminApp, AutoTable, AutoForm, Sidebar, Layout",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"./components/*": "./dist/components/*"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@svadmin/core": "^0.34.
|
|
42
|
+
"@svadmin/core": "^0.34.2",
|
|
43
43
|
"@tanstack/svelte-query": "^6.1.38",
|
|
44
44
|
"highlight.js": "^11.11.1",
|
|
45
|
-
"isomorphic-dompurify": "^3.
|
|
46
|
-
"marked": "^18.0.
|
|
45
|
+
"isomorphic-dompurify": "^3.22.0",
|
|
46
|
+
"marked": "^18.0.9",
|
|
47
47
|
"marked-highlight": "^2.2.4",
|
|
48
48
|
"svelte": "^5.56.8"
|
|
49
49
|
},
|
|
@@ -75,15 +75,15 @@
|
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@floating-ui/dom": "^1.8.0",
|
|
78
|
-
"@lucide/svelte": "^1.
|
|
79
|
-
"@tanstack/svelte-store": "^0.12.
|
|
80
|
-
"@tanstack/svelte-table": "9.
|
|
81
|
-
"@tanstack/table-core": "9.
|
|
78
|
+
"@lucide/svelte": "^1.30.0",
|
|
79
|
+
"@tanstack/svelte-store": "^0.12.1",
|
|
80
|
+
"@tanstack/svelte-table": "9.1.2",
|
|
81
|
+
"@tanstack/table-core": "9.1.2",
|
|
82
82
|
"bits-ui": "^2.18.1",
|
|
83
83
|
"clsx": "^2.1.1",
|
|
84
84
|
"svelte-sonner": "^1.1.1",
|
|
85
85
|
"tailwind-merge": "^3.6.0",
|
|
86
|
-
"tailwind-variants": "^3.3.
|
|
86
|
+
"tailwind-variants": "^3.3.1"
|
|
87
87
|
},
|
|
88
88
|
"license": "MIT",
|
|
89
89
|
"author": "zuohuadong",
|
|
@@ -97,12 +97,12 @@
|
|
|
97
97
|
"url": "https://github.com/zuohuadong/svadmin/issues"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
|
-
"@happy-dom/global-registrator": "^20.11.
|
|
101
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
100
|
+
"@happy-dom/global-registrator": "^20.11.2",
|
|
101
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
102
102
|
"@testing-library/dom": "^10.4.1",
|
|
103
103
|
"@testing-library/svelte": "^5.4.2",
|
|
104
|
-
"@testing-library/user-event": "^14.6.
|
|
105
|
-
"happy-dom": "^20.11.
|
|
104
|
+
"@testing-library/user-event": "^14.6.3",
|
|
105
|
+
"happy-dom": "^20.11.2",
|
|
106
106
|
"vitest": "^4.1.10"
|
|
107
107
|
},
|
|
108
108
|
"scripts": {
|