diff --git a/Api/Ewide.Core/Ewide.Core.xml b/Api/Ewide.Core/Ewide.Core.xml index 8e83b57..113caf5 100644 --- a/Api/Ewide.Core/Ewide.Core.xml +++ b/Api/Ewide.Core/Ewide.Core.xml @@ -5536,6 +5536,12 @@ + + + 获取接收到的通知公告总数 + + + 更新发布信息 diff --git a/Api/Ewide.Core/Service/Notice/SysNoticeService.cs b/Api/Ewide.Core/Service/Notice/SysNoticeService.cs index 26e20ad..9825efd 100644 --- a/Api/Ewide.Core/Service/Notice/SysNoticeService.cs +++ b/Api/Ewide.Core/Service/Notice/SysNoticeService.cs @@ -1,4 +1,6 @@ -using Furion.DatabaseAccessor; +using Dapper; +using Ewide.Core.Extension; +using Furion.DatabaseAccessor; using Furion.DatabaseAccessor.Extensions; using Furion.DependencyInjection; using Furion.DynamicApiController; @@ -9,6 +11,7 @@ using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Ewide.Core.Service.Notice @@ -26,15 +29,20 @@ namespace Ewide.Core.Service.Notice private readonly ISysNoticeUserService _sysNoticeUserService; + private readonly IDapperRepository _dapperRepository; + + public SysNoticeService(IRepository sysNoticeRep, IRepository sysNoticeUserRep, IUserManager userManager, - ISysNoticeUserService sysNoticeUserService) + ISysNoticeUserService sysNoticeUserService, IDapperRepository dapperRepository) { _sysNoticeRep = sysNoticeRep; _sysNoticeUserRep = sysNoticeUserRep; _userManager = userManager; _sysNoticeUserService = sysNoticeUserService; + + _dapperRepository = dapperRepository; } /// @@ -150,7 +158,6 @@ namespace Ewide.Core.Service.Notice var noticeUserRead = new NoticeUserRead { UserId = u.UserId, - UserName = _userManager.Name, ReadStatus = u.ReadStatus, ReadTime = u.ReadTime }; @@ -158,18 +165,17 @@ namespace Ewide.Core.Service.Notice }); } var noticeResult = notice.Adapt(); - noticeResult.NoticeUserIdList = noticeUserIdList; - noticeResult.NoticeUserReadInfoList = noticeUserReadInfoList; + if (_userManager.SuperAdmin) + { + noticeResult.NoticeUserIdList = noticeUserIdList; + noticeResult.NoticeUserReadInfoList = noticeUserReadInfoList; + } // 如果该条通知公告为已发布,则将当前用户的该条通知公告设置为已读 if (notice.Status == (int)NoticeStatus.PUBLIC) await _sysNoticeUserService.Read(notice.Id, _userManager.UserId, (int)NoticeUserStatus.READ); return noticeResult; } - [HttpGet("/sysNotice/detailById")] - public async Task GetNotice(string id) - { - return await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == id); - } + /// /// 修改通知公告状态 /// @@ -201,18 +207,45 @@ namespace Ewide.Core.Service.Notice /// /// /// - [HttpGet("/sysNotice/received")] - public async Task ReceivedNoticePageList([FromQuery] NoticeInput input) + [HttpPost("/sysNotice/received")] + public async Task ReceivedNoticePageList([FromBody] NoticeInput input) { - var searchValue = !string.IsNullOrEmpty(input.SearchValue?.Trim()); - var notices = await _sysNoticeRep.DetachedEntities.Join(_sysNoticeUserRep.DetachedEntities, u => u.Id, e => e.NoticeId, (u, e) => new { u, e }) - .Where(u => u.e.UserId == _userManager.UserId) - .Where(searchValue, u => EF.Functions.Like(u.u.Title, $"%{input.SearchValue.Trim()}%") || EF.Functions.Like(u.u.Content, $"%{input.SearchValue.Trim()}%")) - .Where(input.Type > 0, u => u.u.Type == input.Type) - .Where(u => u.u.Status != (int)NoticeStatus.DELETED) - .Select(u => u.u.Adapt()) - .ToPagedListAsync(input.PageIndex, input.PageSize); - return PageDataResult.PageResult(notices); + var sql = @"SELECT +SN.*, +SU.Avatar +FROM sys_notice SN +LEFT JOIN sys_notice_user SNU ON SN.Id = SNU.NoticeId +LEFT JOIN sys_user SU ON SN.PublicUserId = SU.Id +WHERE SNU.UserId = @UserId AND SN.Status <> @Status"; + + var data = await _dapperRepository.QueryPageDataDynamic( + sql, + input, + new + { + _userManager.UserId, + Status = (int)NoticeStatus.DELETED + } + ); + + data.Items = data.Items.Select(p => { + var r = p.Adapt(); + r.Content = Regex.Replace(r.Content, @"<\/?.+?\/?>", "").Replace("\r\n", ""); + return r; + }); + + return data; + + } + + /// + /// 获取接收到的通知公告总数 + /// + /// + [HttpGet("/sysNotice/unread")] + public async Task GetUnreadCount() + { + return await _sysNoticeUserRep.Where(u => u.UserId == _userManager.UserId && u.ReadStatus == (int)NoticeUserStatus.UNREAD).CountAsync(); } /// diff --git a/Api/Ewide.Core/Service/Notice/SysNoticeUserService.cs b/Api/Ewide.Core/Service/Notice/SysNoticeUserService.cs index 845a8e3..fea4020 100644 --- a/Api/Ewide.Core/Service/Notice/SysNoticeUserService.cs +++ b/Api/Ewide.Core/Service/Notice/SysNoticeUserService.cs @@ -48,18 +48,7 @@ namespace Ewide.Core.Service.Notice }.InsertAsync(); } } - [HttpGet("/NoticeUser/getCount")] - public async Task GetCount() - { - return await _sysNoticeUserRep.Where(u => u.UserId == _userManager.UserId && u.ReadStatus == (int)NoticeUserStatus.UNREAD).CountAsync(); - } - [HttpGet("/NoticeUser/GetNoticeInfo")] - public async Task> GetNoticeInfo() - { - var noticeIdList = await _sysNoticeUserRep.Where(u => u.UserId == _userManager.UserId && u.ReadStatus == (int)NoticeUserStatus.UNREAD).Select(p => p.NoticeId).ToListAsync(); - return await _sysNoticeRep.Where(s => noticeIdList.Contains(s.Id)).ToListAsync(); - } /// /// 更新 /// diff --git a/Api/Ewide.Core/applicationconfig.json b/Api/Ewide.Core/applicationconfig.json index 0266d1e..9008b08 100644 --- a/Api/Ewide.Core/applicationconfig.json +++ b/Api/Ewide.Core/applicationconfig.json @@ -97,7 +97,10 @@ "sysFileInfo:preview", "sysUser:updateInfo", "sysUser:updatePwd", - "sysUser:updateAvatar" + "sysUser:updateAvatar", + "sysNotice:received", + "sysNotice:unread", + "sysNotice:detail" ] } } \ No newline at end of file diff --git a/web-react/craco.config.js b/web-react/craco.config.js index 2cde7a0..0b2c146 100644 --- a/web-react/craco.config.js +++ b/web-react/craco.config.js @@ -29,7 +29,7 @@ module.exports = { ], webpack: { plugins: [ - new MonacoWebpackPlugin() + //new MonacoWebpackPlugin() ] } } \ No newline at end of file diff --git a/web-react/package.json b/web-react/package.json index 04d6bff..e486365 100644 --- a/web-react/package.json +++ b/web-react/package.json @@ -23,6 +23,7 @@ "react-color": "^2.19.3", "react-cropper": "^2.1.8", "react-dom": "^17.0.2", + "react-infinite-scroller": "^1.2.4", "react-json-view": "^1.21.3", "react-monaco-editor": "^0.43.0", "react-router": "^5.2.0", diff --git a/web-react/src/assets/style/dark/lib/form.less b/web-react/src/assets/style/dark/lib/form.less index e770583..9a5fc4e 100644 --- a/web-react/src/assets/style/dark/lib/form.less +++ b/web-react/src/assets/style/dark/lib/form.less @@ -151,6 +151,8 @@ flex: 0 0 100%; width: 100%; + + text-align: inherit; } } .yo-form--short { diff --git a/web-react/src/assets/style/dark/lib/visibility.less b/web-react/src/assets/style/dark/lib/visibility.less index 3e16f62..a3d6235 100644 --- a/web-react/src/assets/style/dark/lib/visibility.less +++ b/web-react/src/assets/style/dark/lib/visibility.less @@ -21,26 +21,25 @@ display: flex; } .ellipsis { + display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.ellipsis-2 { +.ellipsis-line(@line) { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; text-overflow: ellipsis; + word-break: break-all; - -webkit-line-clamp: 2; + -webkit-line-clamp: @line; +} +.ellipsis-2 { + .ellipsis-line(2); } .ellipsis-3 { - display: -webkit-box; - overflow: hidden; - -webkit-box-orient: vertical; - - text-overflow: ellipsis; - - -webkit-line-clamp: 3; + .ellipsis-line(3); } diff --git a/web-react/src/assets/style/dark/main.less b/web-react/src/assets/style/dark/main.less index 3ea8756..1060b2f 100644 --- a/web-react/src/assets/style/dark/main.less +++ b/web-react/src/assets/style/dark/main.less @@ -94,44 +94,76 @@ transition: @animation-duration-slow; transition-property: color; - // 特殊工具按钮 - .theme-toggle { - position: relative; - - overflow: hidden; - - width: 20px; - height: 20px; - margin: 7px 0; - - border-radius: 50%; - &--real { - width: 100%; - height: 100%; - - border-radius: 50%; - background-color: #fff; - } - &--imaginary { - position: absolute; - top: 6px; - left: -6px; - - width: 18px; - height: 18px; - - transform: @animation-duration-slow transform; - transform: rotate(45deg) scaleY(1); - transform-origin: top right; - - border-radius: 50%; - background-color: fade(@layout-header-background, 70%); - } - } } &:active { box-shadow: inset 1px 1px 10px rgba(0, 0, 0, .05); } + // 特殊工具按钮 + .theme-toggle { + position: relative; + + overflow: hidden; + + width: 20px; + height: 20px; + margin: 7px 0; + + border-radius: 50%; + &--real { + position: relative; + + width: 20px; + height: 20px; + + transition: @animation-duration-slow background-color; + + border-radius: 50%; + background-color: fade(@white, 60%); + &::before { + position: absolute; + top: 5px; + left: 5px; + + width: 10px; + height: 10px; + + content: ''; + transition: @animation-duration-slow transform; + transform: scale(0); + + border: 2px solid @layout-header-background; + border-radius: 50%; + } + } + &--imaginary { + position: absolute; + top: 6px; + right: -6px; + + width: 18px; + height: 18px; + + transition: @animation-duration-slow transform; + transform: rotate(45deg) scaleY(1); + transform-origin: top right; + + border-radius: 50%; + background-color: @layout-header-background; + } + } + &:hover { + .theme-toggle { + &--real { + background-color: @white; + &::before { + transform: scale(1); + } + } + &--imaginary { + transform: rotate(45deg) scaleY(0); + } + } + } } .ant-select-auto-complete { margin: (@layout-header-height - 10px - 30px) / 2 @padding-md; diff --git a/web-react/src/assets/style/default/lib/form.less b/web-react/src/assets/style/default/lib/form.less index 69ea80c..a53f1c6 100644 --- a/web-react/src/assets/style/default/lib/form.less +++ b/web-react/src/assets/style/default/lib/form.less @@ -151,6 +151,8 @@ flex: 0 0 100%; width: 100%; + + text-align: inherit; } } .yo-form--short { diff --git a/web-react/src/assets/style/default/lib/visibility.less b/web-react/src/assets/style/default/lib/visibility.less index 3e16f62..a3d6235 100644 --- a/web-react/src/assets/style/default/lib/visibility.less +++ b/web-react/src/assets/style/default/lib/visibility.less @@ -21,26 +21,25 @@ display: flex; } .ellipsis { + display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.ellipsis-2 { +.ellipsis-line(@line) { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; text-overflow: ellipsis; + word-break: break-all; - -webkit-line-clamp: 2; + -webkit-line-clamp: @line; +} +.ellipsis-2 { + .ellipsis-line(2); } .ellipsis-3 { - display: -webkit-box; - overflow: hidden; - -webkit-box-orient: vertical; - - text-overflow: ellipsis; - - -webkit-line-clamp: 3; + .ellipsis-line(3); } diff --git a/web-react/src/assets/style/default/main.less b/web-react/src/assets/style/default/main.less index fa81795..8f1100f 100644 --- a/web-react/src/assets/style/default/main.less +++ b/web-react/src/assets/style/default/main.less @@ -98,6 +98,72 @@ &:active { box-shadow: inset 1px 1px 10px rgba(0, 0, 0, .05); } + // 特殊工具按钮 + .theme-toggle { + position: relative; + + overflow: hidden; + + width: 20px; + height: 20px; + margin: 7px 0; + + border-radius: 50%; + &--real { + position: relative; + + width: 100%; + height: 100%; + + transition: @animation-duration-slow background-color; + + border-radius: 50%; + background-color: fade(@white, 60%); + &::before { + position: absolute; + top: 5px; + left: 5px; + + width: 10px; + height: 10px; + + content: ''; + transition: @animation-duration-slow transform; + transform: scale(1); + + border: 2px solid @layout-header-background; + border-radius: 50%; + } + } + &--imaginary { + position: absolute; + top: 6px; + right: -6px; + + width: 18px; + height: 18px; + + transition: @animation-duration-slow transform; + transform: rotate(45deg) scaleY(0); + transform-origin: top right; + + border-radius: 50%; + background-color: #334454; + } + } + &:hover { + .theme-toggle { + &--real { + background-color: @white; + &::before { + transform: scale(0); + } + } + &--imaginary { + transform: rotate(45deg) scaleY(1); + } + } + } } .ant-select-auto-complete { margin: (@layout-header-height - 10px - 30px) / 2 @padding-md; diff --git a/web-react/src/common/api/requests/sys/index.js b/web-react/src/common/api/requests/sys/index.js index ab2797e..4f94a58 100644 --- a/web-react/src/common/api/requests/sys/index.js +++ b/web-react/src/common/api/requests/sys/index.js @@ -9,6 +9,7 @@ import logManage from './logManage' import machineManage from './machineManage' import menuManage from './menuManage' import noticeManage from './noticeManage' +import noticeReceiveManage from './noticeReceiveManage' import onlineUserManage from './onlineUserManage' import orgManage from './orgManage' import posManage from './posManage' @@ -31,6 +32,7 @@ const urls = { ...machineManage, ...menuManage, ...noticeManage, + ...noticeReceiveManage, ...onlineUserManage, ...orgManage, ...posManage, diff --git a/web-react/src/common/api/requests/sys/noticeManage.js b/web-react/src/common/api/requests/sys/noticeManage.js index 5b9e1fb..c1c692f 100644 --- a/web-react/src/common/api/requests/sys/noticeManage.js +++ b/web-react/src/common/api/requests/sys/noticeManage.js @@ -28,20 +28,6 @@ const urls = { * 修改状态 */ sysNoticeChangeStatus: ['/sysNotice/changeStatus', 'post'], - - /** - * 获取Notice总数 - */ - sysNoticeGetCount: ['/NoticeUser/getCount', 'get'], - - /** - * 获取Notice详细 - */ - sysNoticeInfo: ['/NoticeUser/GetNoticeInfo', 'get'], - /** - * 获取Notice详细ByID - */ - sysNoticeShow: ['/sysNotice/detailById', 'get'], } export default urls diff --git a/web-react/src/common/api/requests/sys/noticeReceiveManage.js b/web-react/src/common/api/requests/sys/noticeReceiveManage.js index ddff640..85d50ef 100644 --- a/web-react/src/common/api/requests/sys/noticeReceiveManage.js +++ b/web-react/src/common/api/requests/sys/noticeReceiveManage.js @@ -1,8 +1,12 @@ const urls = { /** + * 获取接收到的通知公告总数 + */ + sysNoticeUnread: ['/sysNotice/unread', 'get'], + /** * 查询我收到的系统通知公告 */ - sysNoticeReceived: ['/sysNotice/received', 'get'], + sysNoticeReceived: ['/sysNotice/received', 'post'], } export default urls \ No newline at end of file diff --git a/web-react/src/components/form/braft-editor/index.jsx b/web-react/src/components/form/braft-editor/index.jsx index d6d09b0..510c247 100644 --- a/web-react/src/components/form/braft-editor/index.jsx +++ b/web-react/src/components/form/braft-editor/index.jsx @@ -7,7 +7,7 @@ import 'braft-editor/dist/index.css' export default class index extends Component { state = { editorState: BraftEditor.createEditorState(this.props.value), // 设置编辑器初始内容 - outputHTML: '

', + outputHTML: '', } /** * mount后回调 @@ -43,7 +43,7 @@ export default class index extends Component { const { editorState, outputHTML } = this.state //localStorage.setItem('props', JSON.stringify(this.props)) - const controls = ['bold', 'italic', 'underline', 'text-color', 'separator', 'media'] + const controls = ['bold', 'italic', 'underline', 'text-color', 'separator'] return ( }> -
+
- + { + const v = value.replace(/<\/?.+?\/?>/g, '') + if (!v) { + throw Error('请输入内容') + } + }, + }, + ]} > diff --git a/web-react/src/pages/system/notice/index.jsx b/web-react/src/pages/system/notice/index.jsx index 5a94045..0b37040 100644 --- a/web-react/src/pages/system/notice/index.jsx +++ b/web-react/src/pages/system/notice/index.jsx @@ -28,7 +28,7 @@ const apiAction = { * 用于弹窗标题 * [必要] */ -const name = '啥玩意' +const name = '通知公告' /** * 统一配置权限标识 @@ -253,6 +253,7 @@ export default class index extends Component { this.table.current.onReloadData()} @@ -264,6 +265,7 @@ export default class index extends Component { this.table.current.onReloadData()} diff --git a/web-react/src/views/main/_layout/header/index.jsx b/web-react/src/views/main/_layout/header/index.jsx index e289d28..0cdf6c8 100644 --- a/web-react/src/views/main/_layout/header/index.jsx +++ b/web-react/src/views/main/_layout/header/index.jsx @@ -1,23 +1,19 @@ import React, { Component, useState } from 'react' -import { Layout, Badge, Popover, Menu, Modal } from 'antd' +import { Layout, Badge, Popover, Menu, Modal, Tooltip, Popconfirm } from 'antd' import { AntIcon, Container } from 'components' -import Logo from '../logo' -import User from './user' -import Search from './search' import store from 'store' import { api } from 'common/api' +import Logo from '../logo' +import Search from './search' +import Notice from './notice' +import User from './user' + const { getState, subscribe, dispatch } = store export default class index extends Component { state = { ...getState('layout'), - notice: { - count: 0, - data: [], - }, - modalVisible: false, - currentNotice: {}, } constructor(props) { @@ -28,10 +24,6 @@ export default class index extends Component { }) } - componentDidMount() { - this.loadNotice() - } - componentWillUnmount() { this.unsubscribe() } @@ -43,27 +35,8 @@ export default class index extends Component { }) } - async loadNotice() { - const { data } = await api.sysNoticeGetCount() - const items = await api.sysNoticeInfo() - this.setState({ - notice: { - count: data, - data: items.data, - }, - }) - } - async showDetail(params, visible) { - this.setState({ currentNotice: params }) - - if (visible) { - this.setState({ modalVisible: visible }) - } else { - this.setState({ modalVisible: visible }) - } - } render() { - const { allowSiderCollapsed, notice, currentNotice } = this.state + const { allowSiderCollapsed, theme } = this.state return ( @@ -80,57 +53,38 @@ export default class index extends Component {
- window.realodContentWindow()} - > - - - - - {notice.data.map(item => ( - this.showDetail(item, true)} - key={item.id} - > - {item.title} - - ))} - - } - > - - - - - - - this.showDetail(false)} - onCancel={() => this.showDetail(false)} - style={{ zIndex: 1000 }} + + window.realodContentWindow()} > -
-
-
-
- 发布人:{currentNotice.createdUserName} - {' '} - 发布时间:{currentNotice.createdTime} -
-
-
+ + + + + + { + dispatch({ + type: 'SET_THEME', + theme: { default: 'dark', dark: 'default' }[theme], + }) + window.location.reload() + }} + > + +
+
+
+
+ + +
diff --git a/web-react/src/views/main/_layout/header/notice.jsx b/web-react/src/views/main/_layout/header/notice.jsx new file mode 100644 index 0000000..dd89eab --- /dev/null +++ b/web-react/src/views/main/_layout/header/notice.jsx @@ -0,0 +1,145 @@ +import React, { Component } from 'react' +import { Badge, Divider, List, Menu, Modal, Popover, Row, Spin } from 'antd' +import { AntIcon, Image } from 'components' +import { api } from 'common/api' +import InfiniteScroll from 'react-infinite-scroller' +import moment from 'moment' + +export default class notice extends Component { + state = { + count: 0, + list: [], + + loading: false, + hasMore: true, + + detailVisible: false, + detailLoading: false, + detailData: {}, + } + + async componentDidMount() { + const { data: count } = await api.sysNoticeUnread() + this.setState({ count }) + } + + finish() { + this.setState({ loading: false, hasMore: false }) + } + + async onInfiniteOnLoad(pageIndex) { + this.setState({ loading: true }) + const { list } = this.state + if (list.length >= 30) { + return this.finish() + } + + const { + data: { items }, + } = await api.sysNoticeReceived({ + pageIndex, + pageSize: 5, + sortField: 'createdTime', + sortOrder: 'descend', + }) + + if (!items.length) { + return this.finish() + } + + this.setState({ + list: [...list, ...items], + loading: false, + }) + } + + async onOpenDetail(id) { + this.setState({ detailLoading: true, detailVisible: true }) + const { data } = await api.sysNoticeDetail({ id }) + this.setState({ + detailLoading: false, + detailData: data, + }) + } + + renderList() { + const { list, loading, hasMore } = this.state + return ( + this.onInfiniteOnLoad(pageIndex)} + hasMore={!loading && hasMore} + useWindow={false} + threshold={100} + > + ( + + } + title={ + this.onOpenDetail(item.id)} + > + {item.title} + + } + description={moment(item.createdTime || item.publicTime).fromNow()} + /> +
{item.content}
+
+ )} + > + {loading && hasMore && ( +
+ } /> +
+ )} +
+
+ ) + } + + render() { + const { count, detailLoading, detailVisible, detailData } = this.state + + return ( + + + + + + + + this.setState({ detailVisible: false, detailData: {} })} + > + }> +
{detailData.title}
+ +
+ + + 发布人:{detailData.publicUserName} + 发布时间:{detailData.publicTime} + +
+
+
+ ) + } +} diff --git a/web-react/yarn.lock b/web-react/yarn.lock index 963891e..a636c28 100644 --- a/web-react/yarn.lock +++ b/web-react/yarn.lock @@ -9285,7 +9285,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU= @@ -9877,6 +9877,13 @@ react-error-overlay@^6.0.9: resolved "https://registry.nlark.com/react-error-overlay/download/react-error-overlay-6.0.9.tgz?cache=0&sync_timestamp=1618847933355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-error-overlay%2Fdownload%2Freact-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha1-PHQwEMk1lgjDdezWvHbzXZOZWwo= +react-infinite-scroller@^1.2.4: + version "1.2.4" + resolved "https://registry.npm.taobao.org/react-infinite-scroller/download/react-infinite-scroller-1.2.4.tgz#f67eaec4940a4ce6417bebdd6e3433bfc38826e9" + integrity sha1-9n6uxJQKTOZBe+vdbjQzv8OIJuk= + dependencies: + prop-types "^15.5.8" + react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.nlark.com/react-is/download/react-is-16.13.1.tgz?cache=0&sync_timestamp=1623273254569&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"