ding-react-admin 2.1.0 → 2.2.0

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,8 +1,15 @@
1
+ import { FlatNavItem } from '../layouts/navFilter';
1
2
  import { NavItem } from '../types';
2
3
  export type AppHubProps = {
3
4
  apps: NavItem[];
5
+ /** Flattened leaf menus from all apps — enables cross-app search when set. */
6
+ menuItems?: FlatNavItem[];
4
7
  onAppClick?: (app: NavItem) => void;
8
+ onMenuClick?: (item: FlatNavItem) => void;
9
+ menuSearchPlaceholder?: string;
5
10
  className?: string;
11
+ /** Max width of the centered hub content. Default `960`. */
12
+ maxWidth?: number;
6
13
  };
7
- export declare function AppHub({ apps, onAppClick, className }: AppHubProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function AppHub({ apps, menuItems, onAppClick, onMenuClick, menuSearchPlaceholder, className, maxWidth, }: AppHubProps): import("react/jsx-runtime").JSX.Element;
8
15
  //# sourceMappingURL=AppHub.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppHub.d.ts","sourceRoot":"","sources":["../../../src/components/AppHub.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,WAAW,2CAoClE"}
1
+ {"version":3,"file":"AppHub.d.ts","sourceRoot":"","sources":["../../../src/components/AppHub.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,SAAS,EACT,UAAU,EACV,WAAW,EACX,qBAAmD,EACnD,SAAS,EACT,QAAc,GACf,EAAE,WAAW,2CA2Gb"}
@@ -17,6 +17,8 @@ export { applyInMemoryListParams, filterRows, getById as getRowById, } from './d
17
17
  export type { CombineResourceHandlersOptions, ResourceAction, ResourceGuard, ResourceHandlerEntry, ResourceHandlerMap, ResourceHandlers, } from './data/resourceHandlers';
18
18
  export type { ResourcePermissions } from './permissions/resourcePermissions';
19
19
  export { filterNavByPermission } from './permissions/resourcePermissions';
20
+ export { flattenNavLeaves, filterFlatNavItems, filterNavItems, getNavItemLabel, } from './layouts/navFilter';
21
+ export type { FlatNavItem } from './layouts/navFilter';
20
22
  export type { MemoryResourceHandlersConfig } from './data/createMemoryResourceHandlers';
21
23
  export type { PermissionsChecker } from './context/PermissionsProvider';
22
24
  export { LoginPage } from './pages/LoginPage';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,17 @@
1
+ import { ReactNode } from 'react';
1
2
  import { NavItem } from '../types';
2
- export declare function getNavItemLabel(item: NavItem): string;
3
+ export type FlatNavItem = {
4
+ path: string;
5
+ label: ReactNode;
6
+ group?: string;
7
+ Icon?: NavItem["Icon"];
8
+ };
9
+ export declare function getNavItemLabel(item: Pick<NavItem, "label">): string;
3
10
  export declare function filterNavItems(items: NavItem[], query: string): NavItem[];
11
+ /** Leaf menu rows from a nav tree, optionally tagged with an app/group name. */
12
+ export declare function flattenNavLeaves(items: NavItem[], options?: {
13
+ group?: string;
14
+ }): FlatNavItem[];
15
+ export declare function filterFlatNavItems(items: FlatNavItem[], query: string): FlatNavItem[];
4
16
  export declare function collectSubmenuKeys(items: NavItem[]): string[];
5
17
  //# sourceMappingURL=navFilter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"navFilter.d.ts","sourceRoot":"","sources":["../../../src/layouts/navFilter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAKrD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAyBzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAY7D"}
1
+ {"version":3,"file":"navFilter.d.ts","sourceRoot":"","sources":["../../../src/layouts/navFilter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,CAKpE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAyBzE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EAAE,EAChB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B,WAAW,EAAE,CAqBf;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAAE,EACpB,KAAK,EAAE,MAAM,GACZ,WAAW,EAAE,CASf;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAY7D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ding-react-admin",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Composable admin shell (Ant Design + React Router): quick-start AdminApp or build your own layout.",
@@ -1,17 +1,40 @@
1
- import { Card, Col, Row, Space, Typography } from "antd";
1
+ import { Card, Col, List, Row, Space, Typography, theme } from "antd";
2
+ import { useMemo, useState } from "react";
2
3
  import { useNavigate } from "react-router-dom";
4
+ import {
5
+ filterFlatNavItems,
6
+ getNavItemLabel,
7
+ } from "../layouts/navFilter";
8
+ import type { FlatNavItem } from "../layouts/navFilter";
3
9
  import type { NavItem } from "../types";
10
+ import { NavMenuSearch } from "./NavMenuSearch";
4
11
 
5
12
  export type AppHubProps = {
6
13
  apps: NavItem[];
14
+ /** Flattened leaf menus from all apps — enables cross-app search when set. */
15
+ menuItems?: FlatNavItem[];
7
16
  onAppClick?: (app: NavItem) => void;
17
+ onMenuClick?: (item: FlatNavItem) => void;
18
+ menuSearchPlaceholder?: string;
8
19
  className?: string;
20
+ /** Max width of the centered hub content. Default `960`. */
21
+ maxWidth?: number;
9
22
  };
10
23
 
11
- export function AppHub({ apps, onAppClick, className }: AppHubProps) {
24
+ export function AppHub({
25
+ apps,
26
+ menuItems,
27
+ onAppClick,
28
+ onMenuClick,
29
+ menuSearchPlaceholder = "Search menus across apps…",
30
+ className,
31
+ maxWidth = 960,
32
+ }: AppHubProps) {
12
33
  const navigate = useNavigate();
34
+ const { token } = theme.useToken();
35
+ const [query, setQuery] = useState("");
13
36
 
14
- const handleClick = (app: NavItem) => {
37
+ const handleAppClick = (app: NavItem) => {
15
38
  if (onAppClick) {
16
39
  onAppClick(app);
17
40
  return;
@@ -19,29 +42,98 @@ export function AppHub({ apps, onAppClick, className }: AppHubProps) {
19
42
  navigate(app.path);
20
43
  };
21
44
 
45
+ const handleMenuClick = (item: FlatNavItem) => {
46
+ if (onMenuClick) {
47
+ onMenuClick(item);
48
+ return;
49
+ }
50
+ navigate(item.path);
51
+ };
52
+
53
+ const trimmedQuery = query.trim();
54
+ const menuResults = useMemo(
55
+ () =>
56
+ menuItems && trimmedQuery
57
+ ? filterFlatNavItems(menuItems, trimmedQuery)
58
+ : [],
59
+ [menuItems, trimmedQuery],
60
+ );
61
+ const isSearching = Boolean(menuItems && trimmedQuery);
62
+
22
63
  return (
23
- <Row gutter={[16, 16]} className={className}>
24
- {apps.map((app) => {
25
- const Icon = app.Icon;
26
- return (
27
- <Col key={app.path} xs={12} sm={8} md={6} lg={4}>
28
- <Card
29
- hoverable
30
- onClick={() => handleClick(app)}
31
- styles={{ body: { textAlign: "center" } }}
32
- >
33
- <Space orientation="vertical" size="small">
34
- {Icon ? (
35
- <span style={{ fontSize: 32, lineHeight: 1 }}>
36
- <Icon />
37
- </span>
38
- ) : null}
39
- <Typography.Text strong>{app.label}</Typography.Text>
40
- </Space>
41
- </Card>
42
- </Col>
43
- );
44
- })}
45
- </Row>
64
+ <div
65
+ className={className}
66
+ style={{
67
+ width: "100%",
68
+ maxWidth,
69
+ marginInline: "auto",
70
+ paddingInline: token.paddingMD,
71
+ }}
72
+ >
73
+ {menuItems?.length ? (
74
+ <div style={{ maxWidth: 480, margin: "0 auto 24px" }}>
75
+ <NavMenuSearch
76
+ value={query}
77
+ onChange={setQuery}
78
+ placeholder={menuSearchPlaceholder}
79
+ variant="app"
80
+ />
81
+ </div>
82
+ ) : null}
83
+
84
+ {isSearching ? (
85
+ <List
86
+ bordered
87
+ dataSource={menuResults}
88
+ locale={{ emptyText: "No menus match your search." }}
89
+ style={{ background: token.colorBgContainer, borderRadius: token.borderRadiusLG }}
90
+ renderItem={(item) => {
91
+ const Icon = item.Icon;
92
+ return (
93
+ <List.Item
94
+ style={{ cursor: "pointer" }}
95
+ onClick={() => handleMenuClick(item)}
96
+ >
97
+ <List.Item.Meta
98
+ avatar={
99
+ Icon ? (
100
+ <span style={{ fontSize: 20, lineHeight: 1 }}>
101
+ <Icon />
102
+ </span>
103
+ ) : undefined
104
+ }
105
+ title={getNavItemLabel(item)}
106
+ description={item.group}
107
+ />
108
+ </List.Item>
109
+ );
110
+ }}
111
+ />
112
+ ) : (
113
+ <Row gutter={[16, 16]} justify="center">
114
+ {apps.map((app) => {
115
+ const Icon = app.Icon;
116
+ return (
117
+ <Col key={app.path} xs={12} sm={8} md={6} lg={4} style={{ maxWidth: 200 }}>
118
+ <Card
119
+ hoverable
120
+ onClick={() => handleAppClick(app)}
121
+ styles={{ body: { textAlign: "center", padding: token.paddingLG } }}
122
+ >
123
+ <Space orientation="vertical" size="middle">
124
+ {Icon ? (
125
+ <span style={{ fontSize: 40, lineHeight: 1 }}>
126
+ <Icon />
127
+ </span>
128
+ ) : null}
129
+ <Typography.Text strong>{app.label}</Typography.Text>
130
+ </Space>
131
+ </Card>
132
+ </Col>
133
+ );
134
+ })}
135
+ </Row>
136
+ )}
137
+ </div>
46
138
  );
47
139
  }
package/src/index.ts CHANGED
@@ -83,6 +83,13 @@ export type {
83
83
  } from "./data/resourceHandlers";
84
84
  export type { ResourcePermissions } from "./permissions/resourcePermissions";
85
85
  export { filterNavByPermission } from "./permissions/resourcePermissions";
86
+ export {
87
+ flattenNavLeaves,
88
+ filterFlatNavItems,
89
+ filterNavItems,
90
+ getNavItemLabel,
91
+ } from "./layouts/navFilter";
92
+ export type { FlatNavItem } from "./layouts/navFilter";
86
93
  export type { MemoryResourceHandlersConfig } from "./data/createMemoryResourceHandlers";
87
94
  export type { PermissionsChecker } from "./context/PermissionsProvider";
88
95
  export { LoginPage } from "./pages/LoginPage";
@@ -1,6 +1,14 @@
1
+ import type { ReactNode } from "react";
1
2
  import type { NavItem } from "../types";
2
3
 
3
- export function getNavItemLabel(item: NavItem): string {
4
+ export type FlatNavItem = {
5
+ path: string;
6
+ label: ReactNode;
7
+ group?: string;
8
+ Icon?: NavItem["Icon"];
9
+ };
10
+
11
+ export function getNavItemLabel(item: Pick<NavItem, "label">): string {
4
12
  const { label } = item;
5
13
  if (typeof label === "string") return label;
6
14
  if (typeof label === "number") return String(label);
@@ -34,6 +42,47 @@ export function filterNavItems(items: NavItem[], query: string): NavItem[] {
34
42
  return walk(items);
35
43
  }
36
44
 
45
+ /** Leaf menu rows from a nav tree, optionally tagged with an app/group name. */
46
+ export function flattenNavLeaves(
47
+ items: NavItem[],
48
+ options?: { group?: string },
49
+ ): FlatNavItem[] {
50
+ const group = options?.group;
51
+ const result: FlatNavItem[] = [];
52
+
53
+ function walk(nodes: NavItem[]) {
54
+ for (const node of nodes) {
55
+ if (node.children?.length) {
56
+ walk(node.children);
57
+ } else {
58
+ result.push({
59
+ path: node.path,
60
+ label: node.label,
61
+ Icon: node.Icon,
62
+ group,
63
+ });
64
+ }
65
+ }
66
+ }
67
+
68
+ walk(items);
69
+ return result;
70
+ }
71
+
72
+ export function filterFlatNavItems(
73
+ items: FlatNavItem[],
74
+ query: string,
75
+ ): FlatNavItem[] {
76
+ const q = query.trim().toLowerCase();
77
+ if (!q) return [];
78
+
79
+ return items.filter((item) => {
80
+ const label = getNavItemLabel(item).toLowerCase();
81
+ const group = (item.group ?? "").toLowerCase();
82
+ return label.includes(q) || group.includes(q);
83
+ });
84
+ }
85
+
37
86
  export function collectSubmenuKeys(items: NavItem[]): string[] {
38
87
  const keys: string[] = [];
39
88
  function walk(nodes: NavItem[]) {