@gm-pc/react 1.9.2-beta.4 → 1.10.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gm-pc/react",
3
- "version": "1.9.2-beta.4",
3
+ "version": "1.10.3",
4
4
  "description": "观麦前端基础组件库",
5
5
  "author": "liyatang <liyatang@qq.com>",
6
6
  "homepage": "https://github.com/gmfe/gm-pc#readme",
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "@gm-common/hooks": "^2.10.0",
26
26
  "@gm-common/tool": "^2.10.0",
27
- "@gm-pc/locales": "^1.9.2-beta.4",
27
+ "@gm-pc/locales": "^1.10.3",
28
28
  "big.js": "^6.0.1",
29
29
  "classnames": "^2.2.5",
30
30
  "lodash": "^4.17.19",
@@ -33,6 +33,7 @@
33
33
  "react-window": "^1.8.5"
34
34
  },
35
35
  "devDependencies": {
36
+ "@types/react-router-dom": "^5.3.3",
36
37
  "react": "^16.14.0",
37
38
  "react-dom": "^16.14.0"
38
39
  },
@@ -44,7 +45,8 @@
44
45
  "moment": "^2.29.1",
45
46
  "react": "^16.14.0",
46
47
  "react-dom": "^16.14.0",
48
+ "react-router-dom": "^5.2.0",
47
49
  "react-window": "^1.8.5"
48
50
  },
49
- "gitHead": "61448487507b1f2a534b9a5393b54d2438229fc2"
51
+ "gitHead": "aa6eb9903ad34576fd9266cc0ac7813a46f21436"
50
52
  }
@@ -5,7 +5,7 @@
5
5
  }
6
6
 
7
7
  .gm-nav {
8
- width: 136px;
8
+ width: inherit;
9
9
  height: 100vh;
10
10
  background: var(--gm-nav-background-color);
11
11
 
@@ -0,0 +1,7 @@
1
+ import { createContext } from 'react'
2
+ import VBrowser from '../v_browser'
3
+
4
+ const BrowserContext = createContext<VBrowser>(undefined as any)
5
+ BrowserContext.displayName = 'VBrowserContext'
6
+
7
+ export default BrowserContext
@@ -0,0 +1,7 @@
1
+ import { createContext } from 'react'
2
+ import { VBrowserWindow } from '../types'
3
+
4
+ const BrowserWindowContext = createContext<VBrowserWindow>(undefined as any)
5
+ BrowserWindowContext.displayName = 'VBrowserWindowContext'
6
+
7
+ export default BrowserWindowContext
@@ -0,0 +1,40 @@
1
+ import { reaction } from 'mobx'
2
+ import React, { useEffect, useContext } from 'react'
3
+ import BrowserContext from '../context/browser'
4
+ import BrowserWindowContext from '../context/browserWindow'
5
+
6
+ type Noop = () => void
7
+ /**
8
+ * 多窗口中的子页面组件因为被缓存,原来的useEffect受到影响: effect仅在子窗口创建时触发,销毁函数仅在窗口关闭时触发;子窗口失活时依然会观察deps,并触发effect;
9
+ *
10
+ * 根据情况可以考虑使用useWindowEffect来替换useEffect,功能: 窗口激活时、deps更新时,触发fn执行; 窗口失活时执行fn返回的销毁函数; 如果子窗口为失活状态,不观察deps的更新;
11
+ *
12
+ */
13
+ export default function useWindowEffect(fn: () => Noop | void, deps: Array<any>) {
14
+ const browser = useContext(BrowserContext)
15
+ const browserWindow = useContext(BrowserWindowContext)
16
+
17
+ let cb: Noop | void
18
+ useEffect(() => {
19
+ if (!browser || !browserWindow) {
20
+ console.warn('useWindowEffect需要在VBrowser中使用, 否则将回退到useEffect')
21
+ cb = fn()
22
+ return cb
23
+ }
24
+
25
+ const alive = browserWindow.path === browser.activeWindow?.path
26
+ if (!alive) return
27
+
28
+ const dispose = reaction(
29
+ () => browser.activeWindow,
30
+ (cur, pre) => {
31
+ const activate = cur?.path === browserWindow.path
32
+ const deactivate = pre?.path === browserWindow.path
33
+ if (activate) cb = fn()
34
+ if (deactivate) cb && cb()
35
+ }
36
+ )
37
+ cb = fn()
38
+ return dispose
39
+ }, deps)
40
+ }
@@ -0,0 +1,4 @@
1
+ export { default as VBrowser } from './v_browser'
2
+ export { default as IframePortal } from './ui/iframe_portal'
3
+ export type { VBrowserProps } from './types'
4
+ export { default as useWindowEffect } from './hooks/useWindowEffect'
@@ -0,0 +1,10 @@
1
+ import React from 'react'
2
+ import { observable } from 'mobx'
3
+
4
+ const store = observable({})
5
+
6
+ export const ComSwitch = () => <div />
7
+
8
+ export default {
9
+ title: '表单/V-Browser',
10
+ }
@@ -0,0 +1,39 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ export interface VBrowserWindow {
4
+ path: string
5
+ query?: { [key: string]: string }
6
+ /** 窗口图标 */
7
+ faviconURL?: string
8
+ /** 窗口名,如果不存在将尝试从vBrowser的autoTitle中取 */
9
+ title?: ReactNode | Element
10
+ /** 可否关闭,默认为true */
11
+ closeable?: boolean
12
+ }
13
+
14
+ export interface VBrowserProps {
15
+ /** 窗口数量限制 */
16
+ maxLength?: number
17
+ /** 这里的路由将全屏显示,且不会呈现在Tab栏中 */
18
+ onReady?: Function
19
+ /** 重新打开vBrowser时恢复已打开窗口, 默认为true */
20
+ restore?: boolean
21
+ /** 窗口变化事件 */
22
+ onChange?: (
23
+ from: VBrowserWindow | undefined,
24
+ to: VBrowserWindow,
25
+ windows: VBrowserWindow[]
26
+ ) => void
27
+ /** 窗口打开/切换前调用,返回false会阻止窗口打开/切换 */
28
+ auth?: (from?: VBrowserWindow, to?: VBrowserWindow) => Promise<boolean> | boolean
29
+ onError?: (error: { code: number; message: string }) => void
30
+ autoTitle?: (path: string) => string
31
+ }
32
+
33
+ export interface CacheItem {
34
+ vNode: JSX.Element & {
35
+ ref: {
36
+ current: HTMLDivElement | undefined
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,28 @@
1
+ import React, { FC, useEffect, useState } from 'react'
2
+ import { pages } from '../v_browser'
3
+
4
+ interface IframePortalProps {}
5
+
6
+ /**
7
+ * 此组件使用在Switch中,用来访问任意子页面,子页面路径通过url参数path指定
8
+ */
9
+ const IframePortal: FC<IframePortalProps> = () => {
10
+ const [component, setComponent] = useState<JSX.Element | null>(null)
11
+
12
+ useEffect(() => {
13
+ const query = new URLSearchParams(location.href.split('?')[1] || '')
14
+ const path = query.get('path')
15
+ const page = pages.find((p) => p.path === path)
16
+ if (!page) throw new Error('[VWindow] page not found: ' + path)
17
+ page.loader().then((module) => {
18
+ const Component = module.default
19
+ setComponent(<Component />)
20
+ console.timeEnd('IframePortal')
21
+ return null
22
+ })
23
+ }, [])
24
+
25
+ return component
26
+ }
27
+
28
+ export default IframePortal
@@ -0,0 +1,204 @@
1
+ /* eslint-disable dot-notation */
2
+ import React, { createRef, FC, useContext, useEffect, useRef, useState } from 'react'
3
+ import { createPortal } from 'react-dom'
4
+ import { observer } from 'mobx-react'
5
+ import classNames from 'classnames'
6
+ import Context from '../context/browser'
7
+ import { pages } from '../v_browser'
8
+ import WindowWrapper from './window_wrapper'
9
+ import Delete from '../../../svg/vbrowser-tab-delete.svg'
10
+ import Left from '../../../svg/vbrowser-tab-left.svg'
11
+ import Right from '../../../svg/vbrowser-tab-right.svg'
12
+ import { clamp, throttle } from 'lodash'
13
+ import BrowserWindowContext from '../context/browserWindow'
14
+ import './style.less'
15
+
16
+ const VBrowserContainer: FC<{ className?: string }> = observer(
17
+ ({ className, ...props }) => {
18
+ const containerRef = createRef<HTMLDivElement>()
19
+ const browser = useContext(Context)
20
+ const leftInterval = useRef<number>()
21
+ const rightInterval = useRef<number>()
22
+
23
+ const [state, setState] = useState({ scrollLeft: 0, scrollWidth: 0, width: 0 })
24
+
25
+ useEffect(() => {
26
+ const container = containerRef.current
27
+ if (container) {
28
+ container.appendChild(browser['_portal'])
29
+ }
30
+ browser.mounted = true
31
+ }, [])
32
+
33
+ // #region Tabs滚动处理
34
+ useEffect(() => {
35
+ const wrapper: HTMLDivElement | null = document.querySelector(
36
+ '.v-browser-tabs-items'
37
+ )
38
+ if (!wrapper) return
39
+ const onScroll = throttle(() => {
40
+ setState({
41
+ width: wrapper.getBoundingClientRect().width,
42
+ scrollWidth: wrapper.scrollWidth,
43
+ scrollLeft: wrapper.scrollLeft,
44
+ })
45
+ }, 20)
46
+ wrapper.addEventListener('scroll', onScroll)
47
+ onScroll()
48
+ return () => {
49
+ wrapper.removeEventListener('scroll', onScroll)
50
+ }
51
+ }, [browser.windows.length])
52
+
53
+ const _handleScroll = (offset: number) => {
54
+ const wrapper = document.querySelector('.v-browser-tabs-items')
55
+ if (!wrapper) return
56
+ wrapper.scrollTo({
57
+ left: clamp(wrapper.scrollLeft + offset, 0, wrapper.scrollWidth),
58
+ behavior: 'smooth',
59
+ })
60
+ }
61
+ // #endregion
62
+
63
+ const portal = useRef(
64
+ createPortal(
65
+ pages.map((page, i) => {
66
+ return (
67
+ <BrowserWindowContext.Provider key={i} value={page}>
68
+ <WindowWrapper key={i} path={page.path} />
69
+ </BrowserWindowContext.Provider>
70
+ )
71
+ }),
72
+ browser['_portal']
73
+ )
74
+ )
75
+ return (
76
+ <div
77
+ className={classNames('v-browser tw-relative', {
78
+ 'hiding-tabs': browser['_hidingTabs'],
79
+ })}
80
+ >
81
+ <div
82
+ className={classNames(
83
+ 'v-browser-tabs tw-w-full tw-flex tw-items-center tw-overflow-x-auto tw-shadow',
84
+ { 'tw-hidden': browser['_hidingTabs'] }
85
+ )}
86
+ >
87
+ <div
88
+ className={classNames('v-browser-tabs-left tw-font-sm tw-px-2.5', {
89
+ disabled: state.scrollLeft === 0,
90
+ })}
91
+ // onClick={(e) => {
92
+ // e.stopPropagation()
93
+ // _handleScroll(-150)
94
+ // }}
95
+ onMouseEnter={() => {
96
+ leftInterval.current = setInterval(() => {
97
+ _handleScroll(-15)
98
+ }, 0) as any
99
+ }}
100
+ onMouseLeave={() => {
101
+ clearInterval(leftInterval.current)
102
+ }}
103
+ >
104
+ <Left
105
+ className={classNames(
106
+ 'v-browser-tabs-arrow tw-w-3.5 tw-h-3.5 tw-text-gray-500',
107
+ {}
108
+ )}
109
+ />
110
+ </div>
111
+ <div className='v-browser-tabs-items tw-w-full tw-h-full tw-flex tw-items-center'>
112
+ {browser.windows.map((w, i) => {
113
+ return (
114
+ <div
115
+ key={i}
116
+ className={classNames(
117
+ 'v-browser-tabs-items-item tw-font-sm tw-px-2.5 tw-flex-shrink-0 tw-flex tw-items-center tw-truncate tw-w-min',
118
+ {
119
+ active: i === browser.activeIndex,
120
+ border:
121
+ i !== browser.windows.length - 1 &&
122
+ i !== browser.activeIndex &&
123
+ i !== browser.activeIndex - 1,
124
+ }
125
+ )}
126
+ data-tab-id={w.path}
127
+ onClick={() => browser.switchWindow(w)}
128
+ >
129
+ <div
130
+ className='tw-flex-grow tw-text-sm'
131
+ style={{ minWidth: typeof w.title !== 'string' ? 'auto' : '100px' }}
132
+ >
133
+ <div className='tw-flex tw-items-center'>
134
+ {w.faviconURL && (
135
+ <img
136
+ src={w.faviconURL}
137
+ className='tw-w-3.5 tw-h-3.5 tw-mr-0.5'
138
+ style={{ color: '#6A6A6A' }}
139
+ />
140
+ )}
141
+ <span>{w.title || '-'}</span>
142
+ </div>
143
+ </div>
144
+
145
+ <div className='tw-pl-2 tw-flex tw-items-center'>
146
+ <Delete
147
+ className={classNames(
148
+ 'v-browser-tabs-items-item-close tw-w-3.5 tw-h-3.5',
149
+ {
150
+ 'tw-hidden': !w.closeable,
151
+ }
152
+ )}
153
+ onClick={(e) => {
154
+ e.stopPropagation()
155
+ browser.close(w)
156
+ }}
157
+ />
158
+ </div>
159
+ </div>
160
+ )
161
+ })}
162
+ </div>
163
+
164
+ <div
165
+ className={classNames('v-browser-tabs-right tw-font-sm tw-px-2.5', {
166
+ disabled: state.scrollWidth - state.width - state.scrollLeft === 0,
167
+ })}
168
+ // onClick={(e) => {
169
+ // e.stopPropagation()
170
+ // _handleScroll(150)
171
+ // }}
172
+ onMouseEnter={() => {
173
+ rightInterval.current = setInterval(() => {
174
+ _handleScroll(+15)
175
+ }, 0) as any
176
+ }}
177
+ onMouseLeave={() => {
178
+ clearInterval(rightInterval.current)
179
+ }}
180
+ >
181
+ <Right
182
+ className={classNames(
183
+ 'v-browser-tabs-arrow tw-w-3.5 tw-h-3.5 tw-text-gray-500'
184
+ )}
185
+ />
186
+ </div>
187
+ </div>
188
+
189
+ <div className='v-browser-window-wrapper'>
190
+ <div
191
+ className={classNames('v-browser-window', className, {
192
+ 'hiding-tabs': browser['_hidingTabs'],
193
+ })}
194
+ ref={containerRef}
195
+ {...props}
196
+ />
197
+ {portal.current}
198
+ </div>
199
+ </div>
200
+ )
201
+ }
202
+ )
203
+
204
+ export default VBrowserContainer
@@ -0,0 +1,118 @@
1
+ :root {
2
+ --v-browser-tabs-bg: white;
3
+ --v-browser-tabs-text-color: #333;
4
+ --v-browser-tabs-height: 40px;
5
+ }
6
+
7
+ .v-browser {
8
+ height: calc(100vh - var(--gm-framework-size-top-right-height));
9
+ overflow: hidden;
10
+
11
+ &-tabs {
12
+ position: relative;
13
+ height: var(--v-browser-tabs-height);
14
+ background-color: var(--v-browser-tabs-bg);
15
+ z-index: 100;
16
+ color: var(--v-browser-tabs-text-color);
17
+ user-select: none;
18
+ padding: 0 40px;
19
+
20
+ &::-webkit-scrollbar {
21
+ display: none; /* for Chrome, Safari, and Opera */
22
+ }
23
+
24
+ &-left,
25
+ &-right {
26
+ width: 40px;
27
+ cursor: pointer;
28
+ position: absolute;
29
+ background-color: var(--v-browser-tabs-bg);
30
+ height: var(--v-browser-tabs-height);
31
+ display: flex;
32
+ justify-content: center;
33
+ align-items: center;
34
+ }
35
+
36
+ &-left {
37
+ left: 0;
38
+ }
39
+
40
+ &-right {
41
+ right: 0;
42
+ }
43
+
44
+ &-items {
45
+ overflow-x: auto;
46
+
47
+ &::-webkit-scrollbar {
48
+ display: none;
49
+ }
50
+
51
+ &-item {
52
+ height: 100%;
53
+ cursor: pointer;
54
+ position: relative;
55
+
56
+ &.active {
57
+ background-color: #dae7ff !important;
58
+ }
59
+
60
+ &.border::after {
61
+ content: '';
62
+ position: absolute;
63
+ right: 0;
64
+ width: 1px;
65
+ height: 24px;
66
+ background-color: #e8ecf3;
67
+ }
68
+
69
+ &:hover::after {
70
+ content: none;
71
+ }
72
+
73
+ &-close:hover {
74
+ filter: brightness(0);
75
+ }
76
+ }
77
+ }
78
+
79
+ &-left,
80
+ &-right,
81
+ &-items-item {
82
+ &:hover {
83
+ background-color: #f7f7f7;
84
+
85
+ .v-browser-tabs-arrow {
86
+ filter: brightness(0);
87
+ }
88
+ }
89
+
90
+ &.disabled {
91
+ opacity: 0.25;
92
+ }
93
+ }
94
+ }
95
+
96
+ &.hiding-tabs {
97
+ height: 100vh;
98
+ }
99
+
100
+ &-window {
101
+ .v-browser-window-content {
102
+ height:
103
+ calc(
104
+ 100vh - var(--gm-framework-size-top-right-height) - var(--v-browser-tabs-height)
105
+ );
106
+ overflow: auto;
107
+ background-color: white;
108
+ }
109
+
110
+ &.hiding-tabs {
111
+ height: 100vh;
112
+
113
+ .v-browser-window-content {
114
+ height: 100vh;
115
+ }
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,66 @@
1
+ /* eslint-disable dot-notation */
2
+ import { get } from 'lodash'
3
+ import { observer } from 'mobx-react'
4
+ import React, { createRef, FC, useContext, useEffect } from 'react'
5
+ import BrowserContext from '../context/browser'
6
+ import { CacheItem } from '../types'
7
+ import { pages } from '../v_browser'
8
+
9
+ interface WindowWrapperProps {
10
+ path: string
11
+ }
12
+ const WindowWrapper: FC<WindowWrapperProps> = ({ path }) => {
13
+ const placeholder = (<div className='v-browser-placeholder' />) as CacheItem['vNode']
14
+ const browser = useContext(BrowserContext)
15
+ const w = browser.windows.find((w) => w.path === path)
16
+
17
+ const _handleShow = (vNode: CacheItem['vNode']) => {
18
+ const active = browser.activeWindow?.path === path
19
+ if (vNode?.ref.current) vNode.ref.current.style.display = 'none'
20
+ // 激活窗口
21
+ if (vNode && active) {
22
+ if (!vNode.ref.current) return
23
+ vNode.ref.current.style.display = 'block'
24
+ browser['_fire']('show', w!)
25
+ }
26
+ }
27
+
28
+ useEffect(() => {
29
+ const active = browser.activeWindow?.path === path
30
+ const vNode = get(browser['_cache'], [path, 'vNode'])
31
+ if (!vNode && active) {
32
+ // 创建缓存
33
+ const page = pages.find((p) => p.path === path)
34
+ if (!page) throw new Error('[VBrowser] page not found: ' + path)
35
+ page.loader().then((module) => {
36
+ const Component = module.default
37
+ const vNode = (
38
+ <div
39
+ className='v-browser-window-content'
40
+ data-vbrowser-window={path}
41
+ ref={createRef()}
42
+ >
43
+ <Component />
44
+ </div>
45
+ ) as CacheItem['vNode']
46
+ browser['_setCache'](path, { vNode })
47
+ browser['_fire']('show', w!)
48
+ return null
49
+ })
50
+ return
51
+ }
52
+
53
+ _handleShow(vNode)
54
+ }, [browser.activeWindow?.path])
55
+
56
+ // 创建缓存完成
57
+ useEffect(() => {
58
+ const vNode = get(browser['_cache'], [path, 'vNode'])
59
+ if (!vNode) return
60
+ _handleShow(vNode)
61
+ }, [browser['_cache'][path]])
62
+
63
+ return get(browser['_cache'], [path, 'vNode']) || placeholder
64
+ }
65
+
66
+ export default observer(WindowWrapper)
@@ -0,0 +1,264 @@
1
+ import React from 'react'
2
+ import { makeAutoObservable, observable, reaction, when } from 'mobx'
3
+ import VBrowserContainer from './ui/index'
4
+ import BrowserContext from './context/browser'
5
+ import { CacheItem, VBrowserProps, VBrowserWindow } from './types'
6
+ import { parse, stringify } from 'querystring'
7
+ import { isEqual } from 'lodash'
8
+
9
+ // @ts-ignore
10
+ const req = require.context('/src/pages', true, __AUTO_ROUTER_REG__, 'lazy')
11
+ export const pages = req.keys().map((key) => {
12
+ return {
13
+ path: key.replace(/^\./, '').replace('/index.page.tsx', ''),
14
+ loader: () => Promise.resolve(req(key)),
15
+ }
16
+ })
17
+
18
+ const STORAGE_KEY = 'vbrowser-cache'
19
+
20
+ type EventName = 'error' | 'change' | 'close' | 'show'
21
+
22
+ interface VBrowser {
23
+ on(e: 'error', fn: (err: Error) => void): void
24
+ on(e: 'change', fn: (to: VBrowserWindow, from: VBrowserWindow) => void): void
25
+ on(e: 'close', fn: (w: VBrowserWindow) => void): void
26
+ on(e: 'show', fn: (w: VBrowserWindow) => void): void
27
+ }
28
+
29
+ class VBrowser implements VBrowser {
30
+ constructor(props: VBrowserProps) {
31
+ this.props = props
32
+ this.props.restore = this.props.restore ?? true
33
+ this.ui = (
34
+ <BrowserContext.Provider value={this}>
35
+ <VBrowserContainer />
36
+ </BrowserContext.Provider>
37
+ )
38
+ this._loadStash().then(async () => {
39
+ await when(() => this.mounted)
40
+ this.props.onReady && this.props.onReady()
41
+ return null
42
+ })
43
+ makeAutoObservable(this, { ui: false, windows: observable.shallow })
44
+ }
45
+
46
+ props!: VBrowserProps
47
+
48
+ /** 窗口列表 */
49
+ windows: VBrowserWindow[] = []
50
+ /** 选中窗口索引 */
51
+ activeIndex = -1
52
+ /** 选中窗口 */
53
+ get activeWindow() {
54
+ return this.windows[this.activeIndex] as VBrowserWindow | undefined
55
+ }
56
+
57
+ /** 切换已打开窗口 */
58
+ switchWindow(w: number | VBrowserWindow) {
59
+ const oldWindow = this.activeWindow
60
+ if (typeof w === 'number') {
61
+ this.activeIndex = w
62
+ } else {
63
+ const index = this.windows.findIndex((item) => item.path === w.path)
64
+ if (index === -1) {
65
+ throw new Error(`窗口不存在(${w.path} )`)
66
+ }
67
+ this.activeIndex = index
68
+ }
69
+ setTimeout(() => this._scrollToActiveTab(), 100)
70
+
71
+ this.props.onChange &&
72
+ this.props.onChange(oldWindow, this.windows[this.activeIndex], this.windows)
73
+ this._stash()
74
+ }
75
+
76
+ /** 打开新子窗口,路由已打开则判断query是否相等,相等则切换,不相等则销毁重新加载,未打开则新建子窗口
77
+ *
78
+ * target为'_blank'时,新开浏览器窗口
79
+ */
80
+ async open(
81
+ w: VBrowserWindow | string,
82
+ { target = '_self' }: { target: '_self' | '_blank' } = { target: '_self' }
83
+ ) {
84
+ await when(() => this.mounted)
85
+ // #region 格式化
86
+ if (typeof w === 'string') {
87
+ w = { path: w.split('?')[0], query: parse(w.split('?')[1]) as {} }
88
+ }
89
+ w.closeable = w.closeable ?? true
90
+ w.title = w.title ?? (this.props.autoTitle && this.props.autoTitle(w.path)) ?? '-'
91
+ // #endregion
92
+
93
+ // #region 鉴权
94
+ let pass = true
95
+ const auth = this.props.auth || (() => true)
96
+ // @ts-ignore
97
+ if (auth[Symbol.toStringTag] === 'AsyncFunction') {
98
+ pass = (await auth(this.activeWindow, w as VBrowserWindow)) ?? false
99
+ } else {
100
+ pass = (auth(this.activeWindow, w as VBrowserWindow) as boolean) ?? false
101
+ }
102
+ if (!pass) return this._fire('error', new Error('鉴权失败'))
103
+ if (!pages.find((p) => p.path === (w as VBrowserWindow).path)) {
104
+ console.error(w.path, '页面不存在')
105
+ }
106
+ // #endregion
107
+
108
+ // #region 打开新子窗口
109
+ if (target === '_self') {
110
+ const index = this.windows.findIndex(
111
+ (item) => item.path === (w as VBrowserWindow).path
112
+ )
113
+ if (index === -1) {
114
+ if (this.props.maxLength && this.windows.length >= this.props.maxLength) {
115
+ this.props.onError &&
116
+ this.props.onError({ code: 0, message: '超过最大允许的窗口数量' })
117
+ return
118
+ }
119
+ this.windows.push(w)
120
+ } else {
121
+ /**
122
+ * 打开已存在的相同路由的子窗口,此时情况比较复杂
123
+ * 当前浏览器窗口中不能开多个相同路由的子窗口,因为存在store共用冲突
124
+ * 如果参数相同,切换到已存在的窗口
125
+ * 如果不相同,销毁旧窗口重新新建,以重新触发其中的生命周期
126
+ */
127
+ const oldW = this.windows[index]
128
+ if (!isEqual(oldW.query, w.query)) {
129
+ // 删除缓存,使其需要重建
130
+ delete this._cache[w.path]
131
+ }
132
+ Object.assign(this.windows[index], w)
133
+ }
134
+
135
+ this.switchWindow(w as VBrowserWindow)
136
+ }
137
+ // #endregion
138
+
139
+ // #region 打开新浏览器窗口
140
+ if (target === '_blank') {
141
+ // 避免继承
142
+ const currentCache = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}')
143
+ const newCache = { windows: [] as VBrowserWindow[], activeIndex: 0 }
144
+ newCache.windows.push(...this.windows.filter((w) => !w.closeable))
145
+ newCache.windows.push(w)
146
+ newCache.activeIndex = newCache.windows.findIndex(
147
+ (item) => item.path === (w as VBrowserWindow).path
148
+ )
149
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(newCache))
150
+ window.open(`#${w.path}?${stringify(w.query || {})}`, '_blank')
151
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(currentCache))
152
+ }
153
+ // #endregion
154
+ }
155
+
156
+ /** 关闭窗口 */
157
+ close(i: number | VBrowserWindow) {
158
+ if (typeof i !== 'number') {
159
+ i = this.windows.findIndex((item) => item.path === (i as VBrowserWindow).path)
160
+ }
161
+ const originWindows = this.windows.slice()
162
+ const activeWindow = this.activeWindow
163
+ this.windows.splice(i, 1)
164
+ delete this._cache[i]
165
+ if (this.activeIndex === i) {
166
+ const left = originWindows.slice(0, i).reverse()[0]
167
+ const right = originWindows.slice(i + 1, originWindows.length)[0]
168
+ const to = this.windows.findIndex(
169
+ (w) => w.path === left?.path || w.path === right?.path
170
+ )
171
+ this.switchWindow(to)
172
+ } else {
173
+ this.switchWindow(this.windows.indexOf(activeWindow!))
174
+ }
175
+ }
176
+
177
+ private _scrollToActiveTab() {
178
+ const tabEl: HTMLDivElement | null = document.querySelector(
179
+ `[data-tab-id="${this.activeWindow?.path}"]`
180
+ )
181
+ if (!tabEl) return
182
+ tabEl.scrollIntoView()
183
+ }
184
+
185
+ readonly ui!: JSX.Element
186
+
187
+ /** ui是否已挂载 */
188
+ mounted = false
189
+
190
+ /** 是否隐藏标签栏 */
191
+ private _hidingTabs = false
192
+
193
+ private readonly _portal = document.createElement('div')
194
+
195
+ /** 窗口组件的缓存 */
196
+ private _cache: { [key: string]: CacheItem } = {}
197
+ /** 设置缓存 */
198
+ private _setCache(key: string, { vNode }: CacheItem) {
199
+ // key被重新设置会使原有的子窗口被销毁
200
+ this._cache[key] = { vNode }
201
+ }
202
+
203
+ // 保存已开窗口
204
+ private async _stash() {
205
+ const windows = this.windows.slice().map((item) => ({ ...item }))
206
+ const string = JSON.stringify({
207
+ windows,
208
+ activeIndex: this.activeIndex,
209
+ })
210
+ sessionStorage.setItem(STORAGE_KEY, string)
211
+ }
212
+
213
+ // 恢复已开窗口
214
+ private _loadStash() {
215
+ return new Promise((resolve, reject) => {
216
+ const { windows = [], activeIndex = 0 } = JSON.parse(
217
+ sessionStorage.getItem(STORAGE_KEY) || '{}'
218
+ )
219
+ if (windows.length === 0) return resolve(undefined)
220
+ this.windows = windows
221
+ const onShow = (w: VBrowserWindow) => {
222
+ this.switchWindow(activeIndex)
223
+ this.off('show', onShow)
224
+ resolve(undefined)
225
+ }
226
+ this.on('show', onShow)
227
+ })
228
+ }
229
+
230
+ /** 隐藏标签栏 */
231
+ hideTabs() {
232
+ this._hidingTabs = true
233
+ }
234
+
235
+ /** 显示标签栏 */
236
+ showTabs() {
237
+ this._hidingTabs = false
238
+ }
239
+
240
+ private _events: {
241
+ [eventName: string]: Array<{ event: Function }>
242
+ } = {}
243
+
244
+ on(eventName: EventName, event: Function) {
245
+ if (!this._events[eventName]) {
246
+ this._events[eventName] = []
247
+ }
248
+ this._events[eventName].push({ event })
249
+ return this
250
+ }
251
+
252
+ off(eventName: EventName, event: Function) {
253
+ const events = this._events[eventName] || []
254
+ const index = events.findIndex((item) => item.event === event)
255
+ events.splice(index, 1)
256
+ }
257
+
258
+ private _fire(eventName: EventName, ...args: any[]) {
259
+ const events = this._events[eventName] || []
260
+ events.forEach((item) => item.event(...args))
261
+ }
262
+ }
263
+
264
+ export default VBrowser
package/src/index.ts CHANGED
@@ -56,3 +56,4 @@ export * from './component/uploader'
56
56
  export * from './component/recommend_input'
57
57
  export * from './component/card'
58
58
  export * from './component/controlled_form'
59
+ export * from './component/v_browser'
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <title>icon/tab-delete</title>
4
+ <g id="控件" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
5
+ <g id="icon/tab-delete" fill="#6a6a6a">
6
+ <path d="M10,4 C10.4142136,4 10.75,4.33578644 10.75,4.75 L10.75,9.25 L15.25,9.25 C15.6642136,9.25 16,9.58578644 16,10 C16,10.4142136 15.6642136,10.75 15.25,10.75 L10.75,10.75 L10.75,15.25 C10.75,15.6642136 10.4142136,16 10,16 C9.58578644,16 9.25,15.6642136 9.25,15.25 L9.25,10.75 L4.75,10.75 C4.33578644,10.75 4,10.4142136 4,10 C4,9.58578644 4.33578644,9.25 4.75,9.25 L9.25,9.25 L9.25,4.75 C9.25,4.33578644 9.58578644,4 10,4 Z" id="形状结合" transform="translate(10.000000, 10.000000) rotate(-315.000000) translate(-10.000000, -10.000000) "></path>
7
+ </g>
8
+ </g>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <title>icon/左右滑动/禁用@2x</title>
4
+ <g id="控件" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
5
+ <g id="icon/左右滑动/禁用" stroke="#575757" stroke-width="1.5">
6
+ <path d="M7.8822128,6.07106781 L7.8822128,13.8710678 C7.8822128,13.9815248 7.97175585,14.0710678 8.0822128,14.0710678 L15.8822128,14.0710678 L15.8822128,14.0710678" id="路径-4" transform="translate(11.882213, 10.071068) rotate(-315.000000) translate(-11.882213, -10.071068) "></path>
7
+ </g>
8
+ </g>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <title>icon/左右滑动/禁用@2x</title>
4
+ <g id="控件" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
5
+ <g id="icon/左右滑动/右/禁用" stroke="#575757" stroke-width="1.5">
6
+ <path d="M3.8822128,6.07106781 L3.8822128,13.8710678 C3.8822128,13.9815248 3.97175585,14.0710678 4.0822128,14.0710678 L11.8822128,14.0710678 L11.8822128,14.0710678" id="路径-4" transform="translate(7.882213, 10.071068) rotate(-135.000000) translate(-7.882213, -10.071068) "></path>
7
+ </g>
8
+ </g>
9
+ </svg>
package/yarn-error.log ADDED
@@ -0,0 +1,267 @@
1
+ Arguments:
2
+ /usr/local/bin/node /usr/local/bin/yarn add react-router-dom^5.2.0 --peer
3
+
4
+ PATH:
5
+ /opt/intel/openvino_2021/deployment_tools/model_optimizer:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/usr/local/go/bin:/opt/X11/bin:/Library/Apple/usr/bin:/Users/jawei/google-cloud-sdk/bin:/Users/jawei/opt/anaconda3/bin:/Users/jawei/opt/anaconda3/condabin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/Users/jawei/flutter/bin:/Users/yuanzhiying/Library/flutter/bin:/usr/local/go/bin
6
+
7
+ Yarn version:
8
+ 1.22.10
9
+
10
+ Node version:
11
+ 14.15.1
12
+
13
+ Platform:
14
+ darwin x64
15
+
16
+ Trace:
17
+ Error: https://registry.npm.taobao.org/react-router-dom%5E5.2.0: [NOT_FOUND] react-router-dom^5.2.0 not found
18
+ at Request.params.callback [as _callback] (/usr/local/lib/node_modules/yarn/lib/cli.js:66988:18)
19
+ at Request.self.callback (/usr/local/lib/node_modules/yarn/lib/cli.js:140662:22)
20
+ at Request.emit (events.js:315:20)
21
+ at Request.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141634:10)
22
+ at Request.emit (events.js:315:20)
23
+ at Gunzip.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141556:12)
24
+ at Object.onceWrapper (events.js:421:28)
25
+ at Gunzip.emit (events.js:315:20)
26
+ at endReadableNT (_stream_readable.js:1327:12)
27
+ at processTicksAndRejections (internal/process/task_queues.js:80:21)
28
+
29
+ npm manifest:
30
+ {
31
+ "name": "@gm-pc/react",
32
+ "version": "1.7.4-alpha.0",
33
+ "description": "观麦前端基础组件库",
34
+ "author": "liyatang <liyatang@qq.com>",
35
+ "homepage": "https://github.com/gmfe/gm-pc#readme",
36
+ "license": "ISC",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "main": "src/index.ts",
41
+ "module": "src/index.ts",
42
+ "types": "src/index.ts",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/gmfe/gm-pc.git"
46
+ },
47
+ "scripts": {
48
+ "test": "echo \"Error: run tests from root\" && exit 1"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/gmfe/gm-pc/issues"
52
+ },
53
+ "dependencies": {
54
+ "@gm-common/hooks": "^2.10.0",
55
+ "@gm-common/tool": "^2.10.0",
56
+ "@gm-pc/locales": "^1.7.4-alpha.0",
57
+ "big.js": "^6.0.1",
58
+ "classnames": "^2.2.5",
59
+ "lodash": "^4.17.19",
60
+ "modern-normalize": "^1.0.0",
61
+ "moment": "^2.29.1",
62
+ "react-window": "^1.8.5"
63
+ },
64
+ "devDependencies": {
65
+ "@types/react-router-dom": "^5.3.3",
66
+ "react": "^16.14.0",
67
+ "react-dom": "^16.14.0"
68
+ },
69
+ "peerDependencies": {
70
+ "big.js": "^6.0.1",
71
+ "classnames": "^2.2.5",
72
+ "lodash": "^4.17.19",
73
+ "modern-normalize": "^1.0.0",
74
+ "moment": "^2.29.1",
75
+ "react": "^16.14.0",
76
+ "react-dom": "^16.14.0",
77
+ "react-router-dom": "^5.2.0",
78
+ "react-window": "^1.8.5"
79
+ }
80
+ }
81
+
82
+ yarn manifest:
83
+ No manifest
84
+
85
+ Lockfile:
86
+ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
87
+ # yarn lockfile v1
88
+
89
+
90
+ "@babel/runtime@^7.0.0":
91
+ version "7.12.1"
92
+ resolved "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.12.1.tgz?cache=0&sync_timestamp=1602799933339&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
93
+ integrity sha1-tBFqa2cR0BCy2tO3tuQ78bmVR0A=
94
+ dependencies:
95
+ regenerator-runtime "^0.13.4"
96
+
97
+ "@gm-common/hooks@^2.10.0":
98
+ version "2.10.0"
99
+ resolved "https://registry.npmmirror.com/@gm-common/hooks/download/@gm-common/hooks-2.10.0.tgz#c67e02875b4d266ef911e7828257d957e923826b"
100
+ integrity sha1-xn4Ch1tNJm75EeeCglfZV+kjgms=
101
+ dependencies:
102
+ "@gm-common/tool" "^2.10.0"
103
+ ts-config-gm-react-app "^3.4.5"
104
+
105
+ "@gm-common/tool@^2.10.0":
106
+ version "2.10.0"
107
+ resolved "https://registry.npmmirror.com/@gm-common/tool/download/@gm-common/tool-2.10.0.tgz#f4f512233ff1118eff8bbdeca9762f0e65ce26bd"
108
+ integrity sha1-9PUSIz/xEY7/i73sqXYvDmXOJr0=
109
+ dependencies:
110
+ lodash "^4.17.20"
111
+
112
+ "@gm-pc/locales@^1.7.4-alpha.0":
113
+ version "1.8.6-alpha.0"
114
+ resolved "https://registry.npmmirror.com/@gm-pc/locales/-/locales-1.8.6-alpha.0.tgz#9fc9918454ee774c0d61ff41f5b33343411dd3c3"
115
+ integrity sha512-iNAdAuu8bg7F3xB7Vr0DgvY+jpJ1lxkOTAOw+2BK3ljI1eRTbIYkqvazX9ImrdcaB+7R0sbDGUMeR8Ca7iRY3w==
116
+
117
+ "@types/history@^4.7.11":
118
+ version "4.7.11"
119
+ resolved "https://registry.npmmirror.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
120
+ integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
121
+
122
+ "@types/prop-types@*":
123
+ version "15.7.4"
124
+ resolved "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
125
+ integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
126
+
127
+ "@types/react-router-dom@^5.3.3":
128
+ version "5.3.3"
129
+ resolved "https://registry.npmmirror.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83"
130
+ integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==
131
+ dependencies:
132
+ "@types/history" "^4.7.11"
133
+ "@types/react" "*"
134
+ "@types/react-router" "*"
135
+
136
+ "@types/react-router@*":
137
+ version "5.1.18"
138
+ resolved "https://registry.npmmirror.com/@types/react-router/-/react-router-5.1.18.tgz#c8851884b60bc23733500d86c1266e1cfbbd9ef3"
139
+ integrity sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==
140
+ dependencies:
141
+ "@types/history" "^4.7.11"
142
+ "@types/react" "*"
143
+
144
+ "@types/react@*":
145
+ version "17.0.39"
146
+ resolved "https://registry.npmmirror.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce"
147
+ integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==
148
+ dependencies:
149
+ "@types/prop-types" "*"
150
+ "@types/scheduler" "*"
151
+ csstype "^3.0.2"
152
+
153
+ "@types/scheduler@*":
154
+ version "0.16.2"
155
+ resolved "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
156
+ integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
157
+
158
+ big.js@^6.0.1:
159
+ version "6.0.1"
160
+ resolved "https://registry.npm.taobao.org/big.js/download/big.js-6.0.1.tgz#9e0a2e8b1825ce006cd4a096d6f294738cd5cff6"
161
+ integrity sha1-ngouixglzgBs1KCW1vKUc4zVz/Y=
162
+
163
+ classnames@^2.2.5:
164
+ version "2.2.6"
165
+ resolved "https://registry.npm.taobao.org/classnames/download/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
166
+ integrity sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=
167
+
168
+ csstype@^3.0.2:
169
+ version "3.0.10"
170
+ resolved "https://registry.npmmirror.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
171
+ integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
172
+
173
+ "js-tokens@^3.0.0 || ^4.0.0":
174
+ version "4.0.0"
175
+ resolved "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
176
+ integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk=
177
+
178
+ lodash@^4.17.19, lodash@^4.17.20:
179
+ version "4.17.20"
180
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
181
+ integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
182
+
183
+ loose-envify@^1.1.0, loose-envify@^1.4.0:
184
+ version "1.4.0"
185
+ resolved "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
186
+ integrity sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=
187
+ dependencies:
188
+ js-tokens "^3.0.0 || ^4.0.0"
189
+
190
+ "memoize-one@>=3.1.1 <6":
191
+ version "5.1.1"
192
+ resolved "https://registry.npm.taobao.org/memoize-one/download/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
193
+ integrity sha1-BHtuMZm1COrsA1BN5xIpuOsddcA=
194
+
195
+ modern-normalize@^1.0.0:
196
+ version "1.0.0"
197
+ resolved "https://registry.npm.taobao.org/modern-normalize/download/modern-normalize-1.0.0.tgz#539d84a1e141338b01b346f3e27396d0ed17601e"
198
+ integrity sha1-U52EoeFBM4sBs0bz4nOW0O0XYB4=
199
+
200
+ moment@^2.29.1:
201
+ version "2.29.1"
202
+ resolved "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
203
+ integrity sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M=
204
+
205
+ object-assign@^4.1.1:
206
+ version "4.1.1"
207
+ resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
208
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
209
+
210
+ prop-types@^15.6.2:
211
+ version "15.7.2"
212
+ resolved "https://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
213
+ integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU=
214
+ dependencies:
215
+ loose-envify "^1.4.0"
216
+ object-assign "^4.1.1"
217
+ react-is "^16.8.1"
218
+
219
+ react-dom@^16.14.0:
220
+ version "16.14.0"
221
+ resolved "https://registry.npm.taobao.org/react-dom/download/react-dom-16.14.0.tgz?cache=0&sync_timestamp=1603367590403&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dom%2Fdownload%2Freact-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
222
+ integrity sha1-etg47Cmnd/s8dcOhkPZhz5Kri4k=
223
+ dependencies:
224
+ loose-envify "^1.1.0"
225
+ object-assign "^4.1.1"
226
+ prop-types "^15.6.2"
227
+ scheduler "^0.19.1"
228
+
229
+ react-is@^16.8.1:
230
+ version "16.13.1"
231
+ resolved "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz?cache=0&sync_timestamp=1603367576715&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
232
+ integrity sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ=
233
+
234
+ react-window@^1.8.5:
235
+ version "1.8.6"
236
+ resolved "https://registry.npm.taobao.org/react-window/download/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112"
237
+ integrity sha1-0BGVCsZDqZQRhjJmWq0MY4LioRI=
238
+ dependencies:
239
+ "@babel/runtime" "^7.0.0"
240
+ memoize-one ">=3.1.1 <6"
241
+
242
+ react@^16.14.0:
243
+ version "16.14.0"
244
+ resolved "https://registry.npm.taobao.org/react/download/react-16.14.0.tgz?cache=0&sync_timestamp=1603367592109&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
245
+ integrity sha1-lNd23dCqo32j7aj8W2sYpMmjEU0=
246
+ dependencies:
247
+ loose-envify "^1.1.0"
248
+ object-assign "^4.1.1"
249
+ prop-types "^15.6.2"
250
+
251
+ regenerator-runtime@^0.13.4:
252
+ version "0.13.7"
253
+ resolved "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.7.tgz?cache=0&sync_timestamp=1595456311465&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
254
+ integrity sha1-ysLazIoepnX+qrrriugziYrkb1U=
255
+
256
+ scheduler@^0.19.1:
257
+ version "0.19.1"
258
+ resolved "https://registry.npm.taobao.org/scheduler/download/scheduler-0.19.1.tgz?cache=0&sync_timestamp=1603367591660&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fscheduler%2Fdownload%2Fscheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
259
+ integrity sha1-Tz4u0sGn1laB9MhU+oxaHMtA8ZY=
260
+ dependencies:
261
+ loose-envify "^1.1.0"
262
+ object-assign "^4.1.1"
263
+
264
+ ts-config-gm-react-app@^3.4.5:
265
+ version "3.4.7"
266
+ resolved "https://registry.npmjs.org/ts-config-gm-react-app/-/ts-config-gm-react-app-3.4.7.tgz#51decbf847c991ae8e3bd950f3f84cfb0523ba4b"
267
+ integrity sha512-1XOMmAIEiUr2R0JTasF30zj5ZRZgVTOx/ycZJOh2xusQCYC4n1/wGbXfEzm8Dzhv2YSWHEWPVHpytAM3mYsu9Q==