react-toolkits 0.0.1

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.
Files changed (50) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.js +4 -0
  3. package/.turbo/turbo-build.log +20 -0
  4. package/CHANGELOG.md +10 -0
  5. package/dist/512_orange_nobackground-L6MFCL6M.png +0 -0
  6. package/dist/index.css +230 -0
  7. package/dist/index.css.map +1 -0
  8. package/dist/index.d.mts +191 -0
  9. package/dist/index.esm.js +3152 -0
  10. package/dist/index.esm.js.map +1 -0
  11. package/package.json +63 -0
  12. package/postcss.config.js +9 -0
  13. package/src/assets/512_orange_nobackground.png +0 -0
  14. package/src/components/DynamicTags/index.tsx +160 -0
  15. package/src/components/FilterForm/index.tsx +62 -0
  16. package/src/components/FormModal/hooks.tsx +48 -0
  17. package/src/components/FormModal/index.tsx +138 -0
  18. package/src/components/Highlight/index.tsx +51 -0
  19. package/src/components/PermissionButton/index.tsx +36 -0
  20. package/src/components/QueryList/index.tsx +158 -0
  21. package/src/components/index.ts +27 -0
  22. package/src/constants/index.ts +3 -0
  23. package/src/features/permission/components/PermissionList.tsx +129 -0
  24. package/src/features/permission/hooks/index.ts +140 -0
  25. package/src/features/permission/index.ts +5 -0
  26. package/src/features/permission/types/index.ts +33 -0
  27. package/src/hooks/index.ts +2 -0
  28. package/src/hooks/use-fetcher.tsx +102 -0
  29. package/src/hooks/use-permission.tsx +58 -0
  30. package/src/index.ts +7 -0
  31. package/src/layouts/Layout.tsx +81 -0
  32. package/src/layouts/NavBar.tsx +176 -0
  33. package/src/layouts/index.ts +6 -0
  34. package/src/pages/Login/default.tsx +864 -0
  35. package/src/pages/Login/index.tsx +111 -0
  36. package/src/pages/index.ts +4 -0
  37. package/src/pages/permission/RoleDetail.tsx +40 -0
  38. package/src/pages/permission/RoleList.tsx +226 -0
  39. package/src/pages/permission/UserList.tsx +248 -0
  40. package/src/pages/permission/index.tsx +31 -0
  41. package/src/shims.d.ts +20 -0
  42. package/src/stores/index.ts +3 -0
  43. package/src/stores/menu.ts +27 -0
  44. package/src/stores/queryTrigger.ts +27 -0
  45. package/src/stores/token.ts +25 -0
  46. package/src/styles/index.css +5 -0
  47. package/src/types/index.ts +27 -0
  48. package/tailwind.config.js +5 -0
  49. package/tsconfig.json +11 -0
  50. package/tsup.config.ts +26 -0
@@ -0,0 +1,176 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { useMenuStore } from '@/stores'
3
+ import Icon, * as Icons from '@ant-design/icons'
4
+ import { Menu } from 'antd'
5
+ import type {
6
+ ItemType,
7
+ MenuDividerType,
8
+ MenuItemGroupType,
9
+ MenuItemType,
10
+ SubMenuType,
11
+ } from 'antd/es/menu/hooks/useItems'
12
+ import type { FC, ForwardRefExoticComponent, ReactNode } from 'react'
13
+ import { useCallback, useEffect, useMemo, useState } from 'react'
14
+ import { Link, useLocation } from 'react-router-dom'
15
+ import type { Merge } from 'ts-essentials'
16
+
17
+ // 扩展 antd Menu 的类型,使其支持一些我们想要的自定义字段。
18
+ type MenuItemType2 = Merge<
19
+ Omit<MenuItemType, 'icon'>,
20
+ {
21
+ code /** 权限编号 **/?: string
22
+ route /** 前端路由地址 **/?: string
23
+ icon?: string
24
+ }
25
+ >
26
+
27
+ type SubMenuType2 = Merge<
28
+ Omit<SubMenuType, 'icon'>,
29
+ {
30
+ children?: ItemType2[]
31
+ icon?: string
32
+ }
33
+ >
34
+
35
+ type MenuItemGroupType2 = Merge<MenuItemGroupType, { children?: ItemType2[] }>
36
+
37
+ export type ItemType2 = MenuItemType2 | SubMenuType2 | MenuItemGroupType2 | MenuDividerType | null
38
+
39
+ const withLink = (label?: ReactNode, route?: string): ReactNode => {
40
+ if (!label) {
41
+ return <></>
42
+ }
43
+
44
+ if (route) {
45
+ return <Link to={route}>{label}</Link>
46
+ }
47
+
48
+ return label
49
+ }
50
+
51
+ /**
52
+ * 转换导航配置,主要做了以下几件事情
53
+ * 1. 用 Link 元素包装 route
54
+ * 2. 收集 code,用于权限判断
55
+ */
56
+ function transformItems(items: ItemType2[]) {
57
+ const result: ItemType[] = []
58
+
59
+ for (let i = 0; i < items.length; i++) {
60
+ if (items[i] === null) {
61
+ result[i] = null
62
+ } else if ((items[i] as MenuDividerType).type === 'divider') {
63
+ result[i] = { ...items[i] } as MenuDividerType
64
+ } else {
65
+ // 引入 icon
66
+ const iconName = (items[i] as MenuItemType2 | SubMenuType2).icon
67
+
68
+ if ((items[i] as SubMenuType2 | MenuItemGroupType2).children) {
69
+ const { children, ...restProps } = items[i] as SubMenuType2 | MenuItemGroupType2
70
+ result[i] = {
71
+ ...restProps,
72
+ children: transformItems(children ?? []),
73
+ icon: iconName ? <Icon component={(Icons as any)[iconName] as ForwardRefExoticComponent<any>} /> : null,
74
+ } as SubMenuType | MenuItemGroupType
75
+ } else {
76
+ const { route, label, code, ...restProps } = items[i] as MenuItemType2
77
+ // const isPass = code
78
+ // ? await httpClient.post<PermissionCheckResult>('/usystem/user/check', { permissions: [code] }).then(res => {
79
+ // if (res.has_all) {
80
+ // return true
81
+ // }
82
+ //
83
+ // return res[code] ?? false
84
+ // })
85
+ // : true
86
+
87
+ const isPass = true
88
+
89
+ result[i] = isPass
90
+ ? ({
91
+ ...restProps,
92
+ label: withLink(label, route),
93
+ icon: iconName ? <Icon component={(Icons as any)[iconName] as ForwardRefExoticComponent<any>} /> : null,
94
+ } as MenuItemType)
95
+ : null
96
+ }
97
+ }
98
+ }
99
+
100
+ return result
101
+ }
102
+
103
+ // 拍平导航配置,并且注入 keypath 字段
104
+ function flatItems(
105
+ items: ItemType2[],
106
+ result: Merge<MenuItemType2, { keypath?: string[] }>[] = [],
107
+ keypath: string[] = [],
108
+ ) {
109
+ for (const item of items) {
110
+ const children = (item as SubMenuType2 | MenuItemGroupType2)!.children as ItemType2[]
111
+
112
+ if (Array.isArray(children)) {
113
+ const _keys =
114
+ (item as MenuItemGroupType2)!.type !== 'group' && item!.key ? [...keypath, item!.key as string] : keypath
115
+ flatItems(children, result, _keys)
116
+ } else {
117
+ result.push(Object.assign(item as MenuItemType2, { keypath }))
118
+ }
119
+ }
120
+
121
+ return result
122
+ }
123
+
124
+ export interface NavBarProps {
125
+ items: ItemType2[]
126
+ }
127
+
128
+ const NavBar: FC<NavBarProps> = props => {
129
+ const { items } = props
130
+ const location = useLocation()
131
+ const flattenItems = useMemo(() => flatItems(items ?? []), [items])
132
+ const [internalItems, setInternalItems] = useState<ItemType<MenuItemType>[]>([])
133
+
134
+ useEffect(() => {
135
+ setInternalItems(transformItems(items ?? []))
136
+ }, [items])
137
+
138
+ const openKeys = useMenuStore(state => state.openKeys)
139
+ const selectedKeys = useMenuStore(state => state.selectedKeys)
140
+ const setOpenKeys = useMenuStore(state => state.setOpenKeys)
141
+ const setSelectedKeys = useMenuStore(state => state.setSelectedKeys)
142
+
143
+ const onOpenChange = useCallback(
144
+ (keys: string[]) => {
145
+ const latestOpenKey = keys?.find(key => openKeys?.indexOf(key) === -1)
146
+ const match = flattenItems.find(item => latestOpenKey === item.key)
147
+ const _openKeys = (match?.keypath ?? [latestOpenKey]) as string[]
148
+ setOpenKeys(_openKeys)
149
+ },
150
+ [flattenItems, openKeys, setOpenKeys],
151
+ )
152
+
153
+ useEffect(() => {
154
+ const match = flattenItems.find(item => location.pathname === item.route)
155
+
156
+ if (match) {
157
+ const key = match.key as string
158
+ const keypath = match.keypath as string[]
159
+ setSelectedKeys([key])
160
+ setOpenKeys(keypath)
161
+ }
162
+ }, [flattenItems, location, setOpenKeys, setSelectedKeys])
163
+
164
+ return (
165
+ <Menu
166
+ style={{ borderRight: 'none' }}
167
+ items={internalItems}
168
+ mode="inline"
169
+ openKeys={openKeys}
170
+ selectedKeys={selectedKeys}
171
+ onOpenChange={onOpenChange}
172
+ />
173
+ )
174
+ }
175
+
176
+ export default NavBar
@@ -0,0 +1,6 @@
1
+ import type { LayoutProps } from './Layout'
2
+ import Layout from './Layout'
3
+ import type { ItemType2, NavBarProps } from './NavBar'
4
+
5
+ export { Layout }
6
+ export type { ItemType2, LayoutProps, NavBarProps }