@kne/system-layout 0.2.0-alpha.23 → 0.2.0-alpha.25
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/README.md +593 -18
- package/dist/{index-358d7b21.js → index-ce544506.js} +1 -1
- package/dist/{index-358d7b21.js.map → index-ce544506.js.map} +1 -1
- package/dist/index.css +467 -76
- package/dist/index.css.map +1 -1
- package/dist/index.js +171 -48
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +169 -45
- package/dist/index.modern.js.map +1 -1
- package/package.json +3 -1
package/dist/index.modern.js
CHANGED
|
@@ -10,7 +10,7 @@ import Icon from '@kne/react-icon';
|
|
|
10
10
|
import ensureSlash from '@kne/ensure-slash';
|
|
11
11
|
import isPlainObject from 'lodash/isPlainObject';
|
|
12
12
|
import VirtualList from 'rc-virtual-list';
|
|
13
|
-
import { useScrollElement, usePopupContainer, useResponsiveContext, useIsMobile, RESPONSIVE_BOUNDARY_CLASS, RESPONSIVE_CONTAINER_CLASS, RESPONSIVE_SCROLL_CLASS, findResponsiveScroll, getDefaultScrollElement, ResponsiveProvider,
|
|
13
|
+
import { useScrollElement, usePopupContainer, useResponsiveContext, useIsMobile, RESPONSIVE_BOUNDARY_CLASS, RESPONSIVE_CONTAINER_CLASS, RESPONSIVE_SCROLL_CLASS, findScrollParent, findResponsiveScroll, getDefaultScrollElement, ResponsiveProvider, IS_MOBILE_QUERY } from '@kne/responsive-utils';
|
|
14
14
|
export { MOBILE_BREAKPOINT, RESPONSIVE_BOUNDARY_CLASS, RESPONSIVE_CONTAINER_CLASS, RESPONSIVE_SCROLL_CLASS, ResponsiveProvider, MOBILE_BREAKPOINT as mobileBreakpoint, useBreakpoint, useIsMobile, useMediaQuery, usePopupContainer, useResponsiveContext, useScrollElement } from '@kne/responsive-utils';
|
|
15
15
|
import defaultLogo from './defaultLogo~beHinxEU.svg';
|
|
16
16
|
import { ReactComponent } from './expand~bdCTnjYJ.svg';
|
|
@@ -535,19 +535,48 @@ const ErrorBoundary = props => {
|
|
|
535
535
|
}));
|
|
536
536
|
};
|
|
537
537
|
|
|
538
|
-
const
|
|
539
|
-
|
|
538
|
+
const normalizeMarkedScrollElement = marked => {
|
|
539
|
+
if (!marked) {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
if (typeof marked.getScrollElement === 'function') {
|
|
543
|
+
const fromApi = marked.getScrollElement();
|
|
544
|
+
if (fromApi) {
|
|
545
|
+
return fromApi;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (marked.nodeType === 1) {
|
|
549
|
+
const wrapper = marked.querySelector('.simplebar-content-wrapper');
|
|
550
|
+
if (wrapper) {
|
|
551
|
+
return wrapper;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return marked;
|
|
555
|
+
};
|
|
556
|
+
const resolveDocumentScrollElement = () => {
|
|
557
|
+
if (typeof document === 'undefined') {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
// 真实移动端滚 document,不要走 getDefaultScrollElement:
|
|
561
|
+
// 它会 document.querySelector(.kne-responsive-scroll),容易绑到宿主页无关节点。
|
|
562
|
+
return document.scrollingElement || document.documentElement || document.body || null;
|
|
540
563
|
};
|
|
541
564
|
const resolvePageScrollElement = (pageScrollRef, openScrollbar, deviceIsMobile) => {
|
|
542
565
|
if (deviceIsMobile && !openScrollbar) {
|
|
543
566
|
const _anchor = pageScrollRef.current;
|
|
544
|
-
if (_anchor
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
567
|
+
if (_anchor) {
|
|
568
|
+
// 优先真实可滚祖先(example 手机外框 SimpleBar content-wrapper)
|
|
569
|
+
const scrollParent = findScrollParent(_anchor);
|
|
570
|
+
if (scrollParent) {
|
|
571
|
+
return scrollParent;
|
|
572
|
+
}
|
|
573
|
+
// class 标记的外层可能不是滚动节点,需归一到 content-wrapper
|
|
574
|
+
const marked = normalizeMarkedScrollElement(findResponsiveScroll(_anchor.parentElement || _anchor));
|
|
575
|
+
if (marked) {
|
|
576
|
+
return marked;
|
|
548
577
|
}
|
|
549
578
|
}
|
|
550
|
-
return
|
|
579
|
+
return resolveDocumentScrollElement();
|
|
551
580
|
}
|
|
552
581
|
const anchor = pageScrollRef.current;
|
|
553
582
|
if (anchor && typeof anchor.getScrollElement === 'function') {
|
|
@@ -561,6 +590,10 @@ const resolvePageScrollElement = (pageScrollRef, openScrollbar, deviceIsMobile)
|
|
|
561
590
|
}
|
|
562
591
|
return findResponsiveScroll(anchor) || getDefaultScrollElement();
|
|
563
592
|
};
|
|
593
|
+
|
|
594
|
+
// 始终覆盖本页 scroller(否则嵌套在 Global 下 sticky 会绑到 body)。
|
|
595
|
+
// container 模式(example 手机外框)保留外层 boundary,toolbar/menu 才能 portal 到
|
|
596
|
+
// .example-driver-device-scroll(非滚动内容区),absolute/fixed 相对手机视口生效。
|
|
564
597
|
const LayoutResponsiveScope = ({
|
|
565
598
|
boundaryRef,
|
|
566
599
|
scrollRef,
|
|
@@ -568,13 +601,17 @@ const LayoutResponsiveScope = ({
|
|
|
568
601
|
children
|
|
569
602
|
}) => {
|
|
570
603
|
const parent = useResponsiveContext();
|
|
571
|
-
|
|
572
|
-
return children;
|
|
573
|
-
}
|
|
604
|
+
const inheritBoundary = parent.mode === 'container';
|
|
574
605
|
return /*#__PURE__*/jsx(ResponsiveProvider, {
|
|
606
|
+
mode: parent.mode,
|
|
607
|
+
containerWidth: parent.containerWidth,
|
|
575
608
|
boundaryRef: boundaryRef,
|
|
576
609
|
scrollRef: scrollRef,
|
|
577
610
|
getScrollElement: getScrollElement,
|
|
611
|
+
getBoundaryElement: inheritBoundary ? () => {
|
|
612
|
+
const fromParent = typeof parent.getBoundaryElement === 'function' ? parent.getBoundaryElement() : null;
|
|
613
|
+
return fromParent || null;
|
|
614
|
+
} : undefined,
|
|
578
615
|
children: children
|
|
579
616
|
});
|
|
580
617
|
};
|
|
@@ -957,7 +994,7 @@ const Layout = ({
|
|
|
957
994
|
});
|
|
958
995
|
};
|
|
959
996
|
|
|
960
|
-
var style = {"page":"kne-system-layout_c1kXt","page-header":"kne-system-layout_h-YXH","is-
|
|
997
|
+
var style = {"page":"kne-system-layout_c1kXt","page-header":"kne-system-layout_h-YXH","is-viewport":"kne-system-layout_XjOj5","is-boundary":"kne-system-layout_Q-5NT","page-title-outer":"kne-system-layout_jhcGo","page-title":"kne-system-layout_IOVGr","page-title-extra":"kne-system-layout_mKsLu","page-title-actions":"kne-system-layout_XTAI-","is-scrolled":"kne-system-layout_dEXMy","capsule-click":"kne-system-layout_Ps1FA","back-icon":"kne-system-layout_07Mna","has-float":"kne-system-layout_SD6-j","page-top":"kne-system-layout_Y1y7o","page-inner":"kne-system-layout_wHWje","no-padding":"kne-system-layout_tBnAD","is-mobile":"kne-system-layout_yRZMx","page-header-boundary-overlay":"kne-system-layout_4pjtx","page-loading":"kne-system-layout_vcf3J","page-bottom":"kne-system-layout_vXk1s"};
|
|
961
998
|
|
|
962
999
|
const PageLoading = () => {
|
|
963
1000
|
return /*#__PURE__*/jsx(Flex, {
|
|
@@ -991,8 +1028,15 @@ const Page = ({
|
|
|
991
1028
|
} = useContext();
|
|
992
1029
|
const navigate = useNavigate();
|
|
993
1030
|
const getScrollElement = useScrollElement();
|
|
1031
|
+
const getBoundaryElement = usePopupContainer();
|
|
1032
|
+
const {
|
|
1033
|
+
mode
|
|
1034
|
+
} = useResponsiveContext();
|
|
994
1035
|
const navbarRef = useRef(null);
|
|
995
1036
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
1037
|
+
const useBoundaryMount = deviceIsMobile && mode === 'container';
|
|
1038
|
+
const useViewportFixed = deviceIsMobile && mode !== 'container';
|
|
1039
|
+
const boundaryTarget = useBoundaryMount ? getBoundaryElement() : null;
|
|
996
1040
|
useEffect(() => {
|
|
997
1041
|
setToolbarShow && setToolbarShow(!!_toolbar);
|
|
998
1042
|
setNavbarShow && setNavbarShow(!!_navbar);
|
|
@@ -1001,35 +1045,120 @@ const Page = ({
|
|
|
1001
1045
|
if (!deviceIsMobile || !_navbar) {
|
|
1002
1046
|
return;
|
|
1003
1047
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1048
|
+
let boundKey = null;
|
|
1049
|
+
let remove = null;
|
|
1050
|
+
const bind = () => {
|
|
1051
|
+
const scrollEl = getScrollElement();
|
|
1052
|
+
if (!scrollEl) {
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
const isDocumentScroll = typeof document !== 'undefined' && (scrollEl === document.scrollingElement || scrollEl === document.documentElement || scrollEl === document.body);
|
|
1056
|
+
// document 滚动在部分环境听 element 不稳定,统一挂 window
|
|
1057
|
+
const listenTarget = isDocumentScroll ? window : scrollEl;
|
|
1058
|
+
if (!listenTarget || typeof listenTarget.addEventListener !== 'function') {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
const nextKey = isDocumentScroll ? 'window' : scrollEl;
|
|
1062
|
+
if (nextKey === boundKey) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (typeof remove === 'function') {
|
|
1066
|
+
remove();
|
|
1067
|
+
}
|
|
1068
|
+
boundKey = nextKey;
|
|
1069
|
+
const readScrollTop = () => {
|
|
1070
|
+
if (isDocumentScroll) {
|
|
1071
|
+
var _ref, _document$scrollingEl, _document$scrollingEl2;
|
|
1072
|
+
return (_ref = (_document$scrollingEl = (_document$scrollingEl2 = document.scrollingElement) == null ? void 0 : _document$scrollingEl2.scrollTop) != null ? _document$scrollingEl : window.scrollY) != null ? _ref : 0;
|
|
1073
|
+
}
|
|
1074
|
+
return scrollEl.scrollTop || 0;
|
|
1075
|
+
};
|
|
1076
|
+
const handleScroll = () => {
|
|
1077
|
+
const threshold = navbarRef.current ? navbarRef.current.offsetHeight : 48;
|
|
1078
|
+
setIsScrolled(readScrollTop() > threshold);
|
|
1079
|
+
};
|
|
1080
|
+
handleScroll();
|
|
1081
|
+
listenTarget.addEventListener('scroll', handleScroll, {
|
|
1082
|
+
passive: true
|
|
1083
|
+
});
|
|
1084
|
+
remove = () => listenTarget.removeEventListener('scroll', handleScroll);
|
|
1085
|
+
};
|
|
1086
|
+
bind();
|
|
1087
|
+
// SimpleBar / kne-responsive-scroll 可能在下一帧才就绪,补一次绑定
|
|
1088
|
+
const raf = requestAnimationFrame(bind);
|
|
1089
|
+
return () => {
|
|
1090
|
+
cancelAnimationFrame(raf);
|
|
1091
|
+
if (typeof remove === 'function') {
|
|
1092
|
+
remove();
|
|
1093
|
+
}
|
|
1011
1094
|
};
|
|
1012
|
-
handleScroll();
|
|
1013
|
-
scrollEl.addEventListener('scroll', handleScroll, {
|
|
1014
|
-
passive: true
|
|
1015
|
-
});
|
|
1016
|
-
return () => scrollEl.removeEventListener('scroll', handleScroll);
|
|
1017
1095
|
}, [deviceIsMobile, _navbar, getScrollElement, scrollReady]);
|
|
1018
|
-
const
|
|
1096
|
+
const titleExtraContent = (() => {
|
|
1097
|
+
if (_extra) {
|
|
1098
|
+
if (deviceIsMobile && userAvatar) {
|
|
1099
|
+
return /*#__PURE__*/jsxs(Flex, {
|
|
1100
|
+
gap: 4,
|
|
1101
|
+
align: "center",
|
|
1102
|
+
children: [_extra, /*#__PURE__*/jsx(Image.Avatar, {
|
|
1103
|
+
id: userAvatar,
|
|
1104
|
+
src: userAvatar,
|
|
1105
|
+
shape: "circle",
|
|
1106
|
+
size: 30,
|
|
1107
|
+
alt: "avatar"
|
|
1108
|
+
})]
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
return _extra;
|
|
1112
|
+
}
|
|
1113
|
+
if (deviceIsMobile && (buttonProps || userAvatar)) {
|
|
1114
|
+
const actions = buttonProps ? /*#__PURE__*/jsx("div", {
|
|
1115
|
+
className: classnames('page-title-actions', style['page-title-actions']),
|
|
1116
|
+
children: /*#__PURE__*/jsx(ButtonGroup, _extends({}, Object.assign({}, buttonProps, {
|
|
1117
|
+
showLength: 0,
|
|
1118
|
+
moreType: 'link'
|
|
1119
|
+
})))
|
|
1120
|
+
}) : null;
|
|
1121
|
+
const avatar = userAvatar ? /*#__PURE__*/jsx(Image.Avatar, {
|
|
1122
|
+
id: userAvatar,
|
|
1123
|
+
src: userAvatar,
|
|
1124
|
+
shape: "circle",
|
|
1125
|
+
size: 30,
|
|
1126
|
+
alt: "avatar"
|
|
1127
|
+
}) : null;
|
|
1128
|
+
// 仅更多按钮时不要套带 gap 的 Flex,否则 ButtonGroup 测宽空节点也会吃 gap,导致不居中
|
|
1129
|
+
if (actions && avatar) {
|
|
1130
|
+
return /*#__PURE__*/jsxs(Flex, {
|
|
1131
|
+
gap: 4,
|
|
1132
|
+
align: "center",
|
|
1133
|
+
children: [actions, avatar]
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
return actions || avatar;
|
|
1137
|
+
}
|
|
1138
|
+
if (buttonProps) {
|
|
1139
|
+
return /*#__PURE__*/jsx(ButtonGroup, _extends({}, buttonProps));
|
|
1140
|
+
}
|
|
1141
|
+
return null;
|
|
1142
|
+
})();
|
|
1143
|
+
const navbarInner = _navbar ? /*#__PURE__*/jsxs(Flex, {
|
|
1019
1144
|
ref: navbarRef,
|
|
1020
1145
|
justify: "space-between",
|
|
1021
1146
|
align: "center",
|
|
1022
1147
|
gap: 20,
|
|
1023
1148
|
className: classnames('page-header', style['page-header'], {
|
|
1149
|
+
['is-mobile']: deviceIsMobile,
|
|
1150
|
+
[style['is-mobile']]: deviceIsMobile,
|
|
1024
1151
|
['is-scrolled']: isScrolled,
|
|
1025
|
-
[style['is-scrolled']]: isScrolled
|
|
1152
|
+
[style['is-scrolled']]: isScrolled,
|
|
1153
|
+
[style['is-boundary']]: useBoundaryMount && !!boundaryTarget,
|
|
1154
|
+
[style['is-viewport']]: useViewportFixed || useBoundaryMount && !boundaryTarget
|
|
1026
1155
|
}),
|
|
1027
1156
|
children: [/*#__PURE__*/jsxs(Flex, {
|
|
1028
1157
|
className: classnames('page-title-outer', style['page-title-outer']),
|
|
1029
1158
|
align: "center",
|
|
1030
1159
|
gap: 4,
|
|
1031
1160
|
children: [back && /*#__PURE__*/jsx(Button, {
|
|
1032
|
-
type: "
|
|
1161
|
+
type: "link",
|
|
1033
1162
|
icon: /*#__PURE__*/jsx(Icon, {
|
|
1034
1163
|
className: style['back-icon'],
|
|
1035
1164
|
type: "a-Typearrow_forward_ios",
|
|
@@ -1052,24 +1181,19 @@ const Page = ({
|
|
|
1052
1181
|
className: classnames('page-title', style['page-title']),
|
|
1053
1182
|
children: title
|
|
1054
1183
|
})]
|
|
1055
|
-
}), /*#__PURE__*/jsx("div", {
|
|
1056
|
-
className: classnames('page-title-extra', style['page-title-extra']),
|
|
1057
|
-
children:
|
|
1058
|
-
|
|
1059
|
-
align: "center",
|
|
1060
|
-
children: [buttonProps && /*#__PURE__*/jsx(ButtonGroup, _extends({}, Object.assign({}, buttonProps, deviceIsMobile ? {
|
|
1061
|
-
showLength: 0,
|
|
1062
|
-
moreType: 'link'
|
|
1063
|
-
} : {}))), /*#__PURE__*/jsx(Image.Avatar, {
|
|
1064
|
-
id: userAvatar,
|
|
1065
|
-
src: userAvatar,
|
|
1066
|
-
shape: "circle",
|
|
1067
|
-
size: 30,
|
|
1068
|
-
alt: "avatar"
|
|
1069
|
-
})]
|
|
1070
|
-
}) : buttonProps && /*#__PURE__*/jsx(ButtonGroup, _extends({}, buttonProps))
|
|
1071
|
-
})]
|
|
1184
|
+
}), titleExtraContent ? /*#__PURE__*/jsx("div", {
|
|
1185
|
+
className: classnames('page-title-extra', style['page-title-extra'], style['has-float']),
|
|
1186
|
+
children: titleExtraContent
|
|
1187
|
+
}) : null]
|
|
1072
1188
|
}) : null;
|
|
1189
|
+
const navbarEl = navbarInner && useBoundaryMount && boundaryTarget ? /*#__PURE__*/createPortal(/*#__PURE__*/jsx("div", {
|
|
1190
|
+
className: classnames('page-header-boundary-overlay', style['page-header-boundary-overlay']),
|
|
1191
|
+
style: {
|
|
1192
|
+
'--safe-area-inset-top': 'env(safe-area-inset-top)',
|
|
1193
|
+
'--safe-area-inset-bottom': 'env(safe-area-inset-bottom)'
|
|
1194
|
+
},
|
|
1195
|
+
children: navbarInner
|
|
1196
|
+
}), boundaryTarget) : navbarInner;
|
|
1073
1197
|
const pageInnerClassNameOrigin = classnames('page-inner', style['page-inner']);
|
|
1074
1198
|
const pageInnerClassName = classnames(pageInnerClassNameOrigin, {
|
|
1075
1199
|
['no-padding']: noPadding,
|
|
@@ -1127,7 +1251,7 @@ const isMobile = () => {
|
|
|
1127
1251
|
const transparentBgContainer = {
|
|
1128
1252
|
colorBgContainer: 'transparent'
|
|
1129
1253
|
};
|
|
1130
|
-
const transparentBgContainerComponents = ['Input', 'InputNumber', 'Card', 'Tree', 'Select', 'DatePicker'];
|
|
1254
|
+
const transparentBgContainerComponents = ['Input', 'InputNumber', 'Card', 'Tree', 'Select', 'DatePicker', 'Tabs'];
|
|
1131
1255
|
const themeToken = {
|
|
1132
1256
|
components: merge({}, transform(transparentBgContainerComponents, (result, component) => {
|
|
1133
1257
|
result[component] = transparentBgContainer;
|