@kne/system-layout 0.2.0-alpha.2 → 0.2.0-alpha.21

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,14 +1,17 @@
1
- import { isValidElement, useContext as useContext$1, createContext, useState, useMemo, useRef, useEffect } from 'react';
2
- import { Flex, Alert, Button, Row, Col } from 'antd';
1
+ import { useRef, useState, useCallback, useMemo, useLayoutEffect, isValidElement, useContext as useContext$1, createContext, useEffect } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+ import { Flex, Alert, Button, Row, Col, Skeleton } from 'antd';
3
4
  import classnames from 'classnames';
4
5
  import localStorage from '@kne/local-storage';
5
6
  import { Image } from '@kne/react-file';
6
- import { jsx, jsxs } from 'react/jsx-runtime';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
8
  import { useLocation, useNavigate } from 'react-router-dom';
8
9
  import Icon from '@kne/react-icon';
9
10
  import ensureSlash from '@kne/ensure-slash';
10
11
  import isPlainObject from 'lodash/isPlainObject';
11
- import { createPortal } from 'react-dom';
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, defaultResponsiveContextValue, IS_MOBILE_QUERY } from '@kne/responsive-utils';
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';
12
15
  import defaultLogo from './defaultLogo~beHinxEU.svg';
13
16
  import { ReactComponent } from './expand~bdCTnjYJ.svg';
14
17
  import ReactErrorBoundary from '@kne/react-error-boundary';
@@ -16,6 +19,8 @@ import { createWithIntlProvider, useIntl } from '@kne/react-intl';
16
19
  import SimpleBar from 'simplebar-react';
17
20
  import 'simplebar-react/dist/simplebar.min.css';
18
21
  import ButtonGroup from '@kne/button-group';
22
+ import merge from 'lodash/merge';
23
+ import transform from 'lodash/transform';
19
24
 
20
25
  function _extends() {
21
26
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -27,7 +32,7 @@ function _extends() {
27
32
  }, _extends.apply(null, arguments);
28
33
  }
29
34
 
30
- var style$3 = {"layout":"_sK89O","has-toolbar":"_gyKfI","menu":"_-LpWn","open":"_G-zuN","layer-menu":"_6TCwG","ai-entry":"_5qnw5","page":"_HnwkM","toolbar":"_h8PAW","page-children":"_OM1Q2","is-mobile":"_udBgQ","menu-inner":"_7wq3X","logo":"_-T-Dc","menu-header":"_LOrmu","logo-img":"_2cRWf","expand-btn-wrapper":"_5D-Oq","expand-btn-bg":"_p4eOE","expand-btn":"_8dzE7","username":"_b7XeQ","user-description":"_U0YTk","menu-list":"_8gqbZ","ai-dialog-window":"_UAJc-","pulse-dialog-window":"_VjIWn","page-dialog-outer":"_I7Anv","page-dialog":"_UhsFd","pulse-page-dialog":"_H7slV","page-window-content":"_2mdNn","is-scroller":"_6gjkS","page-content":"_nyAa2","ai-dialog-window-title":"_33Tja","ai-dialog-window-content":"_YmBhl"};
35
+ var style$3 = {"kne-responsive-boundary":"kne-system-layout_VtEb1","kne-responsive-scroll":"kne-system-layout_UMzfg","layout":"kne-system-layout_sK89O","has-toolbar":"kne-system-layout_gyKfI","has-navbar":"kne-system-layout_X1wZG","menu":"kne-system-layout_-LpWn","open":"kne-system-layout_G-zuN","layer-menu":"kne-system-layout_6TCwG","ai-entry":"kne-system-layout_5qnw5","page":"kne-system-layout_HnwkM","page-content":"kne-system-layout_nyAa2","toolbar":"kne-system-layout_h8PAW","page-children":"kne-system-layout_OM1Q2","is-scroller":"kne-system-layout_6gjkS","is-mobile":"kne-system-layout_udBgQ","logo":"kne-system-layout_-T-Dc","menu-header":"kne-system-layout_LOrmu","menu-boundary-overlay":"kne-system-layout_-cMpV","is-portaled":"kne-system-layout_leFsD","logo-img":"kne-system-layout_2cRWf","expand-btn-wrapper":"kne-system-layout_5D-Oq","expand-btn-bg":"kne-system-layout_p4eOE","expand-btn":"kne-system-layout_8dzE7","menu-inner":"kne-system-layout_7wq3X","menu-list":"kne-system-layout_8gqbZ","username":"kne-system-layout_b7XeQ","user-description":"kne-system-layout_U0YTk","ai-dialog-window":"kne-system-layout_UAJc-","pulse-dialog-window":"kne-system-layout_VjIWn","is-mobile-full":"kne-system-layout_tiNSQ","is-viewport":"kne-system-layout_UxwXs","ai-dialog-window-title":"kne-system-layout_33Tja","ai-dialog-window-content":"kne-system-layout_YmBhl","ai-boundary-overlay":"kne-system-layout_Nt0Rj","ai-entry-mobile":"kne-system-layout_ln2Ag","is-boundary":"kne-system-layout_dWwHX","page-dialog-outer":"kne-system-layout_I7Anv","page-dialog":"kne-system-layout_UhsFd","pulse-page-dialog":"kne-system-layout_H7slV","page-window-content":"kne-system-layout_2mdNn"};
31
36
 
32
37
  const UserCard = ({
33
38
  name,
@@ -35,7 +40,8 @@ const UserCard = ({
35
40
  email,
36
41
  phone,
37
42
  description,
38
- menuOpen
43
+ menuOpen,
44
+ extra
39
45
  }) => {
40
46
  if (!menuOpen) {
41
47
  return /*#__PURE__*/jsx(Image.Avatar, {
@@ -63,13 +69,17 @@ const UserCard = ({
63
69
  }), /*#__PURE__*/jsx("div", {
64
70
  className: classnames('user-description', style$3['user-description']),
65
71
  children: email || phone || description || '-'
66
- })]
72
+ }), extra]
67
73
  })]
68
74
  });
69
75
  };
70
76
 
71
- var style$2 = {"menu-group":"_Rfzv4","menu-item-icon":"_qoDtD","menu-group-split":"_socoO","menu-item":"_Xa-2h"};
77
+ var style$2 = {"menu-list":"kne-system-layout_dVWvr","menu-group":"kne-system-layout_Rfzv4","menu-item-icon":"kne-system-layout_qoDtD","menu-group-split":"kne-system-layout_socoO","menu-item":"kne-system-layout_Xa-2h"};
72
78
 
79
+ const MENU_ITEM_HEIGHT = 52;
80
+ const MENU_GROUP_HEIGHT = 48;
81
+ const MENU_GROUP_SPLIT_HEIGHT = 17;
82
+ const getItemKey = (item, index) => item.key || item.path || index;
73
83
  const Menu = ({
74
84
  className,
75
85
  menuOpen,
@@ -80,94 +90,174 @@ const Menu = ({
80
90
  }) => {
81
91
  const location = useLocation();
82
92
  const navigate = useNavigate();
93
+ const listRef = useRef(null);
94
+ const virtualListRef = useRef(null);
95
+ const [listHeight, setListHeight] = useState(0);
83
96
  const currentPathname = _base ? location.pathname.replace(new RegExp(`^${_base}`), '') : location.pathname;
84
- return /*#__PURE__*/jsx("div", {
85
- className: classnames('menu', className, style$2['menu-list']),
86
- children: items.map((item, index) => {
87
- var _items;
88
- const active = (() => {
89
- if (typeof activeKey === 'string') {
90
- return activeKey === item.key;
97
+ const isItemActive = useCallback(item => {
98
+ if (typeof activeKey === 'string') {
99
+ return activeKey === item.key;
100
+ }
101
+ if (typeof activeKey === 'function') {
102
+ return activeKey(item, {
103
+ menuOpen,
104
+ base: _base
105
+ });
106
+ }
107
+ if (typeof item.path === 'string') {
108
+ return ensureSlash(currentPathname) === ensureSlash(item.path);
109
+ }
110
+ return false;
111
+ }, [activeKey, _base, currentPathname, menuOpen]);
112
+ const getEstimatedItemHeight = useCallback((item, index) => {
113
+ var _items;
114
+ const hasGroup = item.group && item.group !== ((_items = items[index - 1]) == null ? void 0 : _items.group);
115
+ if (!hasGroup) {
116
+ return MENU_ITEM_HEIGHT;
117
+ }
118
+ return MENU_ITEM_HEIGHT + (menuOpen ? MENU_GROUP_HEIGHT : MENU_GROUP_SPLIT_HEIGHT);
119
+ }, [items, menuOpen]);
120
+ const estimatedItemHeight = useMemo(() => {
121
+ if (!items.length) {
122
+ return MENU_ITEM_HEIGHT;
123
+ }
124
+ const total = items.reduce((sum, item, index) => sum + getEstimatedItemHeight(item, index), 0);
125
+ return Math.max(MENU_ITEM_HEIGHT, Math.ceil(total / items.length));
126
+ }, [getEstimatedItemHeight, items]);
127
+ const listData = useMemo(() => items.map((item, index) => ({
128
+ item,
129
+ index,
130
+ key: getItemKey(item, index)
131
+ })), [items]);
132
+ const activeIndex = useMemo(() => listData.findIndex(({
133
+ item
134
+ }) => isItemActive(item)), [isItemActive, listData]);
135
+ useLayoutEffect(() => {
136
+ const el = listRef.current;
137
+ if (!el) {
138
+ return;
139
+ }
140
+ const updateHeight = () => {
141
+ const styles = getComputedStyle(el);
142
+ const paddingY = parseFloat(styles.paddingTop) + parseFloat(styles.paddingBottom);
143
+ setListHeight(el.clientHeight - paddingY);
144
+ };
145
+ updateHeight();
146
+ const observer = new ResizeObserver(updateHeight);
147
+ observer.observe(el);
148
+ return () => observer.disconnect();
149
+ }, []);
150
+ useLayoutEffect(() => {
151
+ var _virtualListRef$curre;
152
+ if (activeIndex < 0 || listHeight <= 0) {
153
+ return;
154
+ }
155
+ (_virtualListRef$curre = virtualListRef.current) == null || _virtualListRef$curre.scrollTo({
156
+ index: activeIndex,
157
+ align: 'auto'
158
+ });
159
+ }, [activeIndex, listHeight, menuOpen, listData.length]);
160
+ const renderMenuItem = (item, index) => {
161
+ var _items2;
162
+ const active = isItemActive(item);
163
+ const icon = typeof item.icon === 'function' ? item.icon({
164
+ menuOpen,
165
+ active
166
+ }) : item.icon;
167
+ const hasGroup = item.group && item.group !== ((_items2 = items[index - 1]) == null ? void 0 : _items2.group);
168
+ return /*#__PURE__*/jsxs("div", {
169
+ title: item.label,
170
+ onClick: e => {
171
+ if (active) {
172
+ return;
91
173
  }
92
- if (typeof activeKey === 'function') {
93
- return activeKey(item, {
174
+ onChange && onChange(item, {
175
+ menuOpen,
176
+ base: _base
177
+ });
178
+ if (typeof item.onClick === 'function') {
179
+ item.onClick(item, {
94
180
  menuOpen,
95
- base: _base
181
+ base: _base,
182
+ event: e
96
183
  });
184
+ return;
97
185
  }
98
- if (typeof item.path === 'string') {
99
- return ensureSlash(currentPathname) === ensureSlash(item.path);
186
+ if (item.path) {
187
+ navigate(ensureSlash(`${_base}${item.path}`));
100
188
  }
101
- return false;
102
- })();
103
- const icon = typeof item.icon === 'function' ? item.icon({
104
- menuOpen,
105
- active
106
- }) : item.icon;
107
- const hasGroup = item.group && item.group !== ((_items = items[index - 1]) == null ? void 0 : _items.group);
108
- return /*#__PURE__*/jsxs("div", {
109
- title: item.label,
110
- onClick: e => {
111
- if (active) {
112
- return;
189
+ },
190
+ children: [hasGroup && menuOpen ? /*#__PURE__*/jsx("div", {
191
+ className: classnames('menu-group', style$2['menu-group']),
192
+ children: item.groupLabel || item.group
193
+ }) : null, hasGroup && !menuOpen ? /*#__PURE__*/jsx("div", {
194
+ className: classnames('menu-group-split', style$2['menu-group-split'])
195
+ }) : null, /*#__PURE__*/jsxs(Flex, {
196
+ className: classnames('menu-item', style$2['menu-item'], {
197
+ ['is-active']: active,
198
+ ['is-closed']: !menuOpen
199
+ }),
200
+ align: "center",
201
+ gap: 8,
202
+ children: [(icon => {
203
+ if (typeof icon === 'string') {
204
+ return /*#__PURE__*/jsx(Icon, {
205
+ className: classnames('menu-item-icon', style$2['menu-item-icon']),
206
+ type: icon,
207
+ fontClassName: "system"
208
+ });
113
209
  }
114
- onChange && onChange(item, {
115
- menuOpen,
116
- base: _base
117
- });
118
- if (typeof item.onClick === 'function') {
119
- item.onClick(item, {
120
- menuOpen,
121
- base: _base,
122
- event: e
210
+ if (/*#__PURE__*/isValidElement(icon)) {
211
+ return /*#__PURE__*/jsx("span", {
212
+ className: classnames('menu-item-icon', style$2['menu-item-icon']),
213
+ children: icon
123
214
  });
124
- return;
125
215
  }
126
- if (item.path) {
127
- navigate(ensureSlash(`${_base}${item.path}`));
216
+ if (isPlainObject(icon) && typeof icon.type === 'string') {
217
+ return /*#__PURE__*/jsx(Icon, _extends({}, icon, {
218
+ className: classnames('menu-item-icon', style$2['menu-item-icon'])
219
+ }));
128
220
  }
129
- },
130
- children: [hasGroup && menuOpen ? /*#__PURE__*/jsx("div", {
131
- className: classnames('menu-group', style$2['menu-group']),
132
- children: item.groupLabel || item.group
133
- }) : null, hasGroup && !menuOpen ? /*#__PURE__*/jsx("div", {
134
- className: classnames('menu-group-split', style$2['menu-group-split'])
135
- }) : null, /*#__PURE__*/jsxs(Flex, {
136
- className: classnames('menu-item', style$2['menu-item'], {
137
- ['is-active']: active,
138
- ['is-closed']: !menuOpen
139
- }),
140
- align: "center",
141
- gap: 8,
142
- children: [(icon => {
143
- if (typeof icon === 'string') {
144
- return /*#__PURE__*/jsx(Icon, {
145
- className: classnames('menu-item-icon', style$2['menu-item-icon']),
146
- type: icon,
147
- fontClassName: "system"
148
- });
149
- }
150
- if (/*#__PURE__*/isValidElement(icon)) {
151
- return /*#__PURE__*/jsx("span", {
152
- className: classnames('menu-item-icon', style$2['menu-item-icon']),
153
- children: icon
154
- });
155
- }
156
- if (isPlainObject(icon) && typeof icon.type === 'string') {
157
- return /*#__PURE__*/jsx(Icon, _extends({}, icon, {
158
- className: classnames('menu-item-icon', style$2['menu-item-icon'])
159
- }));
160
- }
161
- return null;
162
- })(icon), menuOpen && item.label]
163
- })]
164
- }, item.key || item.path || index);
165
- })
221
+ return null;
222
+ })(icon), menuOpen && item.label]
223
+ })]
224
+ }, getItemKey(item, index));
225
+ };
226
+ return /*#__PURE__*/jsx("div", {
227
+ ref: listRef,
228
+ className: classnames('menu', className, style$2['menu-list']),
229
+ children: listHeight > 0 ? /*#__PURE__*/jsx(VirtualList, {
230
+ ref: virtualListRef,
231
+ data: listData,
232
+ height: listHeight,
233
+ itemHeight: estimatedItemHeight,
234
+ itemKey: "key",
235
+ virtual: listData.length > 0,
236
+ children: ({
237
+ item,
238
+ index
239
+ }) => renderMenuItem(item, index)
240
+ }) : null
166
241
  });
167
242
  };
168
243
 
169
- var style$1 = {"toolbar":"_SLK-0","toolbar-list":"_GTQvM","toolbar-item":"_fAZ3n","toolbar-item-icon":"_qOB9o","toolbar-item-label":"_h48es"};
244
+ var style$1 = {"toolbar":"kne-system-layout_SLK-0","toolbar-inline":"kne-system-layout_RgKpk","toolbar-boundary-overlay":"kne-system-layout_VEMgn","toolbar-list":"kne-system-layout_GTQvM","is-viewport":"kne-system-layout_c6f0m","is-boundary":"kne-system-layout_3ctCY","toolbar-item":"kne-system-layout_fAZ3n","toolbar-item-icon":"kne-system-layout_qOB9o","is-hidden":"kne-system-layout_ss5zk","toolbar-item-label":"kne-system-layout_h48es","toolbar-indicator":"kne-system-layout_1s-bc","toolbar-click":"kne-system-layout_Ys3yu"};
170
245
 
246
+ const context = /*#__PURE__*/createContext({});
247
+ const useContext = () => {
248
+ return useContext$1(context);
249
+ };
250
+ const {
251
+ Provider,
252
+ Consumer
253
+ } = context;
254
+
255
+ const resolveTarget = target => {
256
+ if (!target) {
257
+ return null;
258
+ }
259
+ return typeof target === 'function' ? target() : target;
260
+ };
171
261
  const Toolbar = ({
172
262
  show: _show = true,
173
263
  className,
@@ -179,88 +269,225 @@ const Toolbar = ({
179
269
  }) => {
180
270
  const location = useLocation();
181
271
  const navigate = useNavigate();
272
+ const getScrollElement = useScrollElement();
273
+ const getBoundaryElement = usePopupContainer();
274
+ const {
275
+ mode
276
+ } = useResponsiveContext();
277
+ const isMobile = useIsMobile();
278
+ const {
279
+ scrollReady
280
+ } = useContext();
182
281
  const currentPathname = _base ? location.pathname.replace(new RegExp(`^${_base}`), '') : location.pathname;
183
282
  const toolbarMenu = items.filter(item => item.toolbar);
283
+ const itemRefs = useRef([]);
284
+ const firstRenderRef = useRef(true);
285
+ const [indicator, setIndicator] = useState({
286
+ left: 0,
287
+ width: 0,
288
+ scale: 1,
289
+ visible: false
290
+ });
291
+ const [clicked, setClicked] = useState(false);
292
+ const [scrolling, setScrolling] = useState(false);
293
+ const scrollTimerRef = useRef(null);
294
+ const activeIndex = toolbarMenu.findIndex(item => {
295
+ if (typeof activeKey === 'string') {
296
+ return activeKey === item.key;
297
+ }
298
+ if (typeof activeKey === 'function') {
299
+ return activeKey(item, {
300
+ base: _base
301
+ });
302
+ }
303
+ if (typeof item.path === 'string') {
304
+ return ensureSlash(currentPathname) === ensureSlash(item.path);
305
+ }
306
+ return false;
307
+ });
308
+ const displayIndex = activeIndex >= 0 ? activeIndex : 0;
309
+ const listRef = useRef(null);
310
+ const explicitTarget = resolveTarget(target);
311
+ const useBoundaryMount = isMobile && mode === 'container' && !explicitTarget;
312
+ const useViewportFixed = isMobile && mode !== 'container' && !explicitTarget;
313
+ const boundaryTarget = useBoundaryMount ? getBoundaryElement() : null;
314
+ useLayoutEffect(() => {
315
+ if (activeIndex < 0) {
316
+ return;
317
+ }
318
+ const item = itemRefs.current[activeIndex];
319
+ const list = listRef.current;
320
+ if (!item || !list) {
321
+ return;
322
+ }
323
+ const itemRect = item.getBoundingClientRect();
324
+ const listRect = list.getBoundingClientRect();
325
+ const newLeft = itemRect.left - listRect.left;
326
+ const newWidth = itemRect.width;
327
+ if (firstRenderRef.current) {
328
+ firstRenderRef.current = false;
329
+ setIndicator({
330
+ left: newLeft,
331
+ width: newWidth,
332
+ scale: 1,
333
+ visible: true
334
+ });
335
+ return;
336
+ }
337
+ setIndicator(prev => _extends({}, prev, {
338
+ scale: 1.15
339
+ }));
340
+ const t1 = setTimeout(() => {
341
+ setIndicator(prev => _extends({}, prev, {
342
+ left: newLeft,
343
+ width: newWidth
344
+ }));
345
+ }, 120);
346
+ const t2 = setTimeout(() => {
347
+ setIndicator(prev => _extends({}, prev, {
348
+ scale: 1
349
+ }));
350
+ }, 380);
351
+ return () => {
352
+ clearTimeout(t1);
353
+ clearTimeout(t2);
354
+ };
355
+ }, [activeIndex, _show, target, useBoundaryMount, useViewportFixed]);
356
+ useEffect(() => {
357
+ const scrollEl = getScrollElement();
358
+ if (!scrollEl || typeof scrollEl.addEventListener !== 'function') {
359
+ return;
360
+ }
361
+ const handleScroll = () => {
362
+ setScrolling(true);
363
+ if (scrollTimerRef.current) {
364
+ clearTimeout(scrollTimerRef.current);
365
+ }
366
+ scrollTimerRef.current = setTimeout(() => {
367
+ setScrolling(false);
368
+ }, 500);
369
+ };
370
+ scrollEl.addEventListener('scroll', handleScroll, {
371
+ passive: true
372
+ });
373
+ return () => {
374
+ scrollEl.removeEventListener('scroll', handleScroll);
375
+ if (scrollTimerRef.current) {
376
+ clearTimeout(scrollTimerRef.current);
377
+ }
378
+ };
379
+ }, [getScrollElement, _show, scrollReady]);
184
380
  if (!_show) {
185
381
  return null;
186
382
  }
187
- return /*#__PURE__*/jsx("div", {
188
- className: classnames('toolbar', style$1['toolbar'], className),
189
- children: /*#__PURE__*/createPortal(/*#__PURE__*/jsx(Flex, {
190
- className: classnames('toolbar-list', style$1['toolbar-list']),
191
- children: toolbarMenu.map((item, index) => {
192
- const active = (() => {
193
- if (typeof activeKey === 'string') {
194
- return activeKey === item.key;
383
+ const toolbarList = /*#__PURE__*/jsxs(Flex, {
384
+ ref: listRef,
385
+ className: classnames('toolbar-list', style$1['toolbar-list'], {
386
+ ['is-clicked']: clicked,
387
+ ['is-scrolling']: scrolling,
388
+ [style$1['is-boundary']]: useBoundaryMount,
389
+ [style$1['is-viewport']]: useViewportFixed
390
+ }),
391
+ style: {
392
+ '--toolbar-count': toolbarMenu.length || 1
393
+ },
394
+ onAnimationEnd: () => {
395
+ if (clicked) {
396
+ setClicked(false);
397
+ }
398
+ },
399
+ children: [indicator.visible && /*#__PURE__*/jsx("div", {
400
+ className: classnames('toolbar-indicator', style$1['toolbar-indicator']),
401
+ style: {
402
+ left: `${indicator.left}px`,
403
+ width: `${indicator.width}px`,
404
+ transform: `scale(${indicator.scale})`
405
+ }
406
+ }), toolbarMenu.map((item, index) => {
407
+ const active = index === activeIndex;
408
+ const icon = typeof item.icon === 'function' ? item.icon({
409
+ active
410
+ }) : item.icon;
411
+ return /*#__PURE__*/jsxs(Flex, {
412
+ ref: el => {
413
+ itemRefs.current[index] = el;
414
+ },
415
+ vertical: true,
416
+ flex: 1,
417
+ justify: "center",
418
+ align: "center",
419
+ className: classnames('toolbar-item', style$1['toolbar-item'], {
420
+ ['is-active']: active,
421
+ [style$1['is-hidden']]: scrolling && index !== displayIndex
422
+ }),
423
+ onClick: e => {
424
+ if (active) {
425
+ return;
195
426
  }
196
- if (typeof activeKey === 'function') {
197
- return activeKey(item, {
198
- base: _base
427
+ setClicked(true);
428
+ onChange && onChange(item, {
429
+ base: _base
430
+ });
431
+ if (typeof item.onClick === 'function') {
432
+ item.onClick(item, {
433
+ base: _base,
434
+ event: e
199
435
  });
436
+ return;
200
437
  }
201
- if (typeof item.path === 'string') {
202
- return ensureSlash(currentPathname) === ensureSlash(item.path);
438
+ if (item.path) {
439
+ navigate(ensureSlash(`${_base}${item.path}`));
203
440
  }
204
- return false;
205
- })();
206
- const icon = typeof item.icon === 'function' ? item.icon({
207
- active
208
- }) : item.icon;
209
- return /*#__PURE__*/jsxs(Flex, {
210
- vertical: true,
211
- flex: 1,
212
- justify: "center",
213
- align: "center",
214
- className: classnames('toolbar-item', style$1['toolbar-item'], {
215
- ['is-active']: active
216
- }),
217
- onClick: e => {
218
- if (active) {
219
- return;
220
- }
221
- onChange && onChange(item, {
222
- base: _base
441
+ },
442
+ children: [(icon => {
443
+ if (typeof icon === 'string') {
444
+ return /*#__PURE__*/jsx(Icon, {
445
+ className: classnames('toolbar-item-icon', style$1['toolbar-item-icon']),
446
+ type: icon,
447
+ fontClassName: "system"
223
448
  });
224
- if (typeof item.onClick === 'function') {
225
- item.onClick(item, {
226
- menuOpen,
227
- base: _base,
228
- event: e
229
- });
230
- return;
231
- }
232
- if (item.path) {
233
- navigate(ensureSlash(`${_base}${item.path}`));
234
- }
235
- },
236
- children: [(icon => {
237
- if (typeof icon === 'string') {
238
- return /*#__PURE__*/jsx(Icon, {
239
- className: classnames('toolbar-item-icon', style$1['toolbar-item-icon']),
240
- type: icon,
241
- fontClassName: "system"
242
- });
243
- }
244
- if (/*#__PURE__*/isValidElement(icon)) {
245
- return /*#__PURE__*/jsx("span", {
246
- className: classnames('toolbar-item-icon', style$1['toolbar-item-icon']),
247
- children: icon
248
- });
249
- }
250
- if (isPlainObject(icon) && typeof icon.type === 'string') {
251
- return /*#__PURE__*/jsx(Icon, _extends({}, icon, {
252
- className: classnames('toolbar-item-icon', style$1['toolbar-item-icon'])
253
- }));
254
- }
255
- return null;
256
- })(icon), /*#__PURE__*/jsx("div", {
257
- className: classnames('toolbar-item-label', style$1['toolbar-item-label']),
258
- children: item.label
259
- })]
260
- }, item.key || item.path || index);
261
- })
262
- }), target ? typeof target === 'function' ? target() : target : document.body)
449
+ }
450
+ if (/*#__PURE__*/isValidElement(icon)) {
451
+ return /*#__PURE__*/jsx("span", {
452
+ className: classnames('toolbar-item-icon', style$1['toolbar-item-icon']),
453
+ children: icon
454
+ });
455
+ }
456
+ if (isPlainObject(icon) && typeof icon.type === 'string') {
457
+ return /*#__PURE__*/jsx(Icon, _extends({}, icon, {
458
+ className: classnames('toolbar-item-icon', style$1['toolbar-item-icon'])
459
+ }));
460
+ }
461
+ return null;
462
+ })(icon), /*#__PURE__*/jsx("div", {
463
+ className: classnames('toolbar-item-label', style$1['toolbar-item-label']),
464
+ children: item.label
465
+ })]
466
+ }, item.key || item.path || index);
467
+ })]
263
468
  });
469
+ if (useBoundaryMount && boundaryTarget) {
470
+ return /*#__PURE__*/jsx("div", {
471
+ className: classnames('toolbar', style$1['toolbar'], className),
472
+ children: /*#__PURE__*/createPortal(/*#__PURE__*/jsx("div", {
473
+ className: classnames('toolbar-boundary-overlay', style$1['toolbar-boundary-overlay']),
474
+ children: toolbarList
475
+ }), boundaryTarget)
476
+ });
477
+ }
478
+ if (useViewportFixed) {
479
+ return /*#__PURE__*/jsx("div", {
480
+ className: classnames('toolbar', style$1['toolbar'], style$1['toolbar-inline'], className),
481
+ children: toolbarList
482
+ });
483
+ }
484
+ if (explicitTarget) {
485
+ return /*#__PURE__*/jsx("div", {
486
+ className: classnames('toolbar', style$1['toolbar'], className),
487
+ children: /*#__PURE__*/createPortal(toolbarList, explicitTarget)
488
+ });
489
+ }
490
+ return null;
264
491
  };
265
492
 
266
493
  const locale$1 = {
@@ -308,20 +535,127 @@ const ErrorBoundary = props => {
308
535
  }));
309
536
  };
310
537
 
311
- const isMobile = () => {
312
- return /iPhone|iPod|Android|ios|iPad/i.test(navigator.userAgent);
538
+ const hasParentResponsiveProvider = parent => {
539
+ return parent.getBoundaryElement !== defaultResponsiveContextValue.getBoundaryElement || parent.getScrollElement !== defaultResponsiveContextValue.getScrollElement;
313
540
  };
314
-
315
- const context = /*#__PURE__*/createContext({});
316
- const useContext = () => {
317
- return useContext$1(context);
541
+ const resolvePageScrollElement = (pageScrollRef, openScrollbar, deviceIsMobile) => {
542
+ if (deviceIsMobile && !openScrollbar) {
543
+ const _anchor = pageScrollRef.current;
544
+ if (_anchor && _anchor.parentElement) {
545
+ const parentScroll = findResponsiveScroll(_anchor.parentElement);
546
+ if (parentScroll) {
547
+ return parentScroll;
548
+ }
549
+ }
550
+ return getDefaultScrollElement();
551
+ }
552
+ const anchor = pageScrollRef.current;
553
+ if (anchor && typeof anchor.getScrollElement === 'function') {
554
+ return anchor.getScrollElement();
555
+ }
556
+ if (anchor && anchor.nodeType === 1 && openScrollbar) {
557
+ const wrapper = anchor.querySelector('.simplebar-content-wrapper');
558
+ if (wrapper) {
559
+ return wrapper;
560
+ }
561
+ }
562
+ return findResponsiveScroll(anchor) || getDefaultScrollElement();
563
+ };
564
+ const LayoutResponsiveScope = ({
565
+ boundaryRef,
566
+ scrollRef,
567
+ getScrollElement,
568
+ children
569
+ }) => {
570
+ const parent = useResponsiveContext();
571
+ if (hasParentResponsiveProvider(parent)) {
572
+ return children;
573
+ }
574
+ return /*#__PURE__*/jsx(ResponsiveProvider, {
575
+ boundaryRef: boundaryRef,
576
+ scrollRef: scrollRef,
577
+ getScrollElement: getScrollElement,
578
+ children: children
579
+ });
318
580
  };
319
- const {
320
- Provider,
321
- Consumer
322
- } = context;
323
-
324
581
  const LayoutMenuOpenKey = 'LAYOUT_MENU_OPEN';
582
+ const DRAG_THRESHOLD = 4;
583
+ const MobileAiEntry = ({
584
+ variant,
585
+ onOpen
586
+ }) => {
587
+ const btnRef = useRef(null);
588
+ const dragRef = useRef(null);
589
+ const [pos, setPos] = useState(null);
590
+ const handlePointerDown = event => {
591
+ const node = btnRef.current;
592
+ if (!node) {
593
+ return;
594
+ }
595
+ // 与 toolbar 一致:boundary 模式下相对定位容器为 offsetParent,viewport 模式下相对视口
596
+ const container = node.offsetParent;
597
+ const rect = node.getBoundingClientRect();
598
+ const refLeft = container ? container.getBoundingClientRect().left : 0;
599
+ const refTop = container ? container.getBoundingClientRect().top : 0;
600
+ dragRef.current = {
601
+ startX: event.clientX,
602
+ startY: event.clientY,
603
+ originLeft: rect.left - refLeft,
604
+ originTop: rect.top - refTop,
605
+ refWidth: container ? container.clientWidth : window.innerWidth,
606
+ refHeight: container ? container.clientHeight : window.innerHeight,
607
+ size: node.offsetWidth,
608
+ moved: false
609
+ };
610
+ node.setPointerCapture == null || node.setPointerCapture(event.pointerId);
611
+ };
612
+ const handlePointerMove = event => {
613
+ const drag = dragRef.current;
614
+ if (!drag) {
615
+ return;
616
+ }
617
+ const dx = event.clientX - drag.startX;
618
+ const dy = event.clientY - drag.startY;
619
+ if (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD) {
620
+ drag.moved = true;
621
+ }
622
+ const maxLeft = Math.max(8, drag.refWidth - drag.size - 8);
623
+ const maxTop = Math.max(8, drag.refHeight - drag.size - 8);
624
+ setPos({
625
+ left: Math.min(Math.max(8, drag.originLeft + dx), maxLeft),
626
+ top: Math.min(Math.max(8, drag.originTop + dy), maxTop)
627
+ });
628
+ };
629
+ const handlePointerUp = event => {
630
+ var _btnRef$current;
631
+ const drag = dragRef.current;
632
+ dragRef.current = null;
633
+ (_btnRef$current = btnRef.current) == null || _btnRef$current.releasePointerCapture == null || _btnRef$current.releasePointerCapture(event.pointerId);
634
+ if (drag && !drag.moved) {
635
+ onOpen();
636
+ }
637
+ };
638
+ return /*#__PURE__*/jsx("div", {
639
+ ref: btnRef,
640
+ className: classnames('ai-entry-mobile', style$3['ai-entry-mobile'], {
641
+ [style$3['is-viewport']]: variant === 'viewport',
642
+ [style$3['is-boundary']]: variant !== 'viewport'
643
+ }),
644
+ style: pos ? {
645
+ left: `${pos.left}px`,
646
+ top: `${pos.top}px`,
647
+ right: 'auto',
648
+ bottom: 'auto'
649
+ } : undefined,
650
+ onPointerDown: handlePointerDown,
651
+ onPointerMove: handlePointerMove,
652
+ onPointerUp: handlePointerUp,
653
+ children: /*#__PURE__*/jsx(Icon, {
654
+ type: "system-prompt",
655
+ colorful: true
656
+ })
657
+ });
658
+ };
325
659
  const Layout = ({
326
660
  className,
327
661
  menu,
@@ -338,277 +672,469 @@ const Layout = ({
338
672
  children
339
673
  }) => {
340
674
  const localMenuOpen = localStorage.getItem(LayoutMenuOpenKey);
341
- const [menuOpen, setMenuOpen] = useState(typeof localMenuOpen === 'boolean' ? localMenuOpen : true);
675
+ const isMobile = useIsMobile();
676
+ const responsiveContext = useResponsiveContext();
677
+ const deviceIsMobile = typeof isMobileProps === 'boolean' ? isMobileProps : isMobile;
678
+ const useMenuPortal = deviceIsMobile && responsiveContext.mode === 'container';
679
+ const [menuPortalTarget, setMenuPortalTarget] = useState(null);
680
+ const [menuOpen, setMenuOpen] = useState(typeof localMenuOpen === 'boolean' && !deviceIsMobile ? localMenuOpen : !deviceIsMobile);
342
681
  const [toolbarShow, setToolbarShow] = useState(true);
682
+ const [navbarShow, setNavbarShow] = useState(true);
343
683
  const [aiType, setAiType] = useState('closed');
344
- const deviceIsMobile = typeof isMobileProps === 'boolean' ? isMobileProps : isMobile();
684
+ const [scrollReady, setScrollReady] = useState(0);
345
685
  const openScrollbar = typeof openScrollbarProps === 'boolean' ? openScrollbarProps : !deviceIsMobile && !window.__COMPONENTS_CORE_SIMPLE_BAR_DISABLED;
346
686
  const userAvatar = userInfo == null ? void 0 : userInfo.avatar;
347
687
  const contextValue = useMemo(() => {
348
688
  return {
349
689
  setToolbarShow,
690
+ setNavbarShow,
350
691
  setMenuOpen,
351
692
  deviceIsMobile,
693
+ scrollReady,
352
694
  logo: Object.assign({}, logo ? logo : {
353
695
  src: defaultLogo
354
696
  }),
355
697
  userAvatar
356
698
  };
357
- }, [deviceIsMobile, logo, userAvatar]);
699
+ }, [deviceIsMobile, logo, userAvatar, scrollReady]);
358
700
  const topRef = useRef(null);
701
+ const pageRef = useRef(null);
702
+ const layoutBoundaryRef = useRef(null);
703
+ const pageScrollRef = useRef(null);
359
704
  const location = useLocation();
705
+ const getPageScrollElement = useCallback(() => {
706
+ return resolvePageScrollElement(pageScrollRef, openScrollbar, deviceIsMobile);
707
+ }, [openScrollbar, deviceIsMobile]);
708
+ const handlePageScrollRef = useCallback(node => {
709
+ pageScrollRef.current = node;
710
+ if (node) {
711
+ setScrollReady(version => version + 1);
712
+ }
713
+ }, []);
714
+ useEffect(() => {
715
+ if (!useMenuPortal) {
716
+ setMenuPortalTarget(null);
717
+ return;
718
+ }
719
+ const target = typeof responsiveContext.getBoundaryElement === 'function' ? responsiveContext.getBoundaryElement() : null;
720
+ setMenuPortalTarget(target || null);
721
+ }, [useMenuPortal, responsiveContext, scrollReady]);
360
722
  useEffect(() => {
361
- topRef.current && topRef.current.scrollIntoView();
362
- }, [location]);
363
- return /*#__PURE__*/jsxs(Provider, {
364
- value: contextValue,
723
+ var _topRef$current;
724
+ const scrollEl = getPageScrollElement();
725
+ if (scrollEl && typeof scrollEl.scrollTo === 'function') {
726
+ scrollEl.scrollTo(0, 0);
727
+ return;
728
+ }
729
+ (_topRef$current = topRef.current) == null || _topRef$current.scrollIntoView();
730
+ }, [location, getPageScrollElement]);
731
+ const userCard = /*#__PURE__*/jsx(UserCard, _extends({
732
+ menuOpen: menuOpen
733
+ }, Object.assign({}, userInfo)));
734
+ const menuPortalVars = useMenuPortal ? {
735
+ '--menu-max-width': _menuMaxWidth,
736
+ '--menu-min-width': _menuMinWidth,
737
+ '--background': _background
738
+ } : undefined;
739
+ const layerMenuNode = deviceIsMobile ? /*#__PURE__*/jsx("div", {
740
+ className: classnames('layer-menu', style$3['layer-menu'], {
741
+ ['open']: menuOpen,
742
+ [style$3['open']]: menuOpen,
743
+ [style$3['is-portaled']]: useMenuPortal
744
+ }),
745
+ style: menuPortalVars,
746
+ onClick: () => {
747
+ setMenuOpen(false);
748
+ }
749
+ }) : null;
750
+ const menuNode = /*#__PURE__*/jsxs("div", {
751
+ className: classnames('menu', style$3['menu'], {
752
+ ['open']: menuOpen,
753
+ [style$3['open']]: menuOpen,
754
+ [style$3['is-portaled']]: useMenuPortal
755
+ }),
756
+ style: menuPortalVars,
365
757
  children: [/*#__PURE__*/jsx("div", {
366
- ref: topRef
367
- }), /*#__PURE__*/jsxs("div", {
368
- className: classnames(className, 'layout', style$3['layout'], {
369
- 'is-mobile': deviceIsMobile,
370
- [style$3['is-mobile']]: deviceIsMobile,
371
- 'has-toolbar': toolbarShow,
372
- [style$3['has-toolbar']]: toolbarShow
373
- }),
374
- style: {
375
- '--menu-max-width': _menuMaxWidth,
376
- '--menu-min-width': _menuMinWidth,
377
- '--background': _background
758
+ className: classnames('logo', style$3['logo']),
759
+ children: /*#__PURE__*/jsx(Image, _extends({
760
+ className: style$3['logo-img']
761
+ }, contextValue.logo))
762
+ }), /*#__PURE__*/jsx("div", {
763
+ className: classnames('expand-btn-wrapper', style$3['expand-btn-wrapper']),
764
+ onClick: () => {
765
+ setMenuOpen(menuOpen => {
766
+ localStorage.setItem(LayoutMenuOpenKey, !menuOpen);
767
+ return !menuOpen;
768
+ });
378
769
  },
379
- children: [deviceIsMobile && /*#__PURE__*/jsx("div", {
380
- className: classnames('layer-menu', style$3['layer-menu'], {
381
- ['open']: menuOpen,
382
- [style$3['open']]: menuOpen
383
- }),
770
+ children: /*#__PURE__*/jsx(ReactComponent, {
771
+ className: classnames('expand-btn', style$3['expand-btn'], {
772
+ 'is-closed': !menuOpen
773
+ })
774
+ })
775
+ }), /*#__PURE__*/jsxs("div", {
776
+ className: classnames('menu-inner', style$3['menu-inner']),
777
+ children: [/*#__PURE__*/jsx("div", {
778
+ className: classnames('menu-header', style$3['menu-header']),
779
+ children: /*#__PURE__*/jsx(ErrorBoundary, {
780
+ children: menuHeader ? typeof menuHeader === 'function' ? menuHeader({
781
+ menuOpen,
782
+ userCard
783
+ }) : menuHeader : userCard
784
+ })
785
+ }), /*#__PURE__*/jsx(ErrorBoundary, {
786
+ children: /*#__PURE__*/jsx(Menu, _extends({
787
+ className: classnames('menu-list', style$3['menu-list']),
788
+ menuOpen: menuOpen
789
+ }, menu, {
790
+ onChange: () => {
791
+ deviceIsMobile && setMenuOpen(false);
792
+ }
793
+ }))
794
+ }), _aiDialog && !deviceIsMobile && /*#__PURE__*/jsx("div", {
795
+ className: classnames('ai-entry', style$3['ai-entry']),
384
796
  onClick: () => {
385
- setMenuOpen(false);
386
- }
797
+ setAiType('small');
798
+ },
799
+ children: /*#__PURE__*/jsx(Icon, {
800
+ type: "system-prompt",
801
+ colorful: true
802
+ })
803
+ })]
804
+ })]
805
+ });
806
+ const portalMenu = useMenuPortal && menuPortalTarget;
807
+ const aiDialogWindow = _aiDialog && aiType === 'small' ? /*#__PURE__*/jsxs("div", {
808
+ className: classnames('ai-dialog-window', style$3['ai-dialog-window'], {
809
+ 'is-mobile-full': deviceIsMobile,
810
+ [style$3['is-mobile-full']]: deviceIsMobile,
811
+ [style$3['is-viewport']]: deviceIsMobile && !portalMenu
812
+ }),
813
+ children: [/*#__PURE__*/jsxs(Flex, {
814
+ className: classnames('ai-dialog-window-title', style$3['ai-dialog-window-title']),
815
+ children: [/*#__PURE__*/jsx("div", {
816
+ children: _aiDialog.title
387
817
  }), /*#__PURE__*/jsxs(Flex, {
388
- children: [/*#__PURE__*/jsxs("div", {
389
- className: classnames('menu', style$3['menu'], {
390
- ['open']: menuOpen,
391
- [style$3['open']]: menuOpen
392
- }),
393
- children: [/*#__PURE__*/jsx("div", {
394
- className: classnames('logo', style$3['logo']),
395
- children: /*#__PURE__*/jsx(Image, _extends({
396
- className: style$3['logo-img']
397
- }, contextValue.logo))
398
- }), /*#__PURE__*/jsx("div", {
399
- className: classnames('expand-btn-wrapper', style$3['expand-btn-wrapper']),
400
- onClick: () => {
401
- setMenuOpen(menuOpen => {
402
- localStorage.setItem(LayoutMenuOpenKey, !menuOpen);
403
- return !menuOpen;
404
- });
405
- },
406
- children: /*#__PURE__*/jsx(ReactComponent, {
407
- className: classnames('expand-btn', style$3['expand-btn'], {
408
- 'is-closed': !menuOpen
409
- })
410
- })
411
- }), /*#__PURE__*/jsxs("div", {
412
- className: classnames('menu-inner', style$3['menu-inner']),
413
- children: [/*#__PURE__*/jsx("div", {
414
- className: classnames('menu-header', style$3['menu-header']),
415
- children: /*#__PURE__*/jsx(ErrorBoundary, {
416
- children: menuHeader ? typeof menuHeader === 'function' ? menuHeader({
417
- menuOpen
418
- }) : menuHeader : /*#__PURE__*/jsx(UserCard, _extends({
419
- menuOpen: menuOpen
420
- }, Object.assign({}, userInfo)))
421
- })
422
- }), /*#__PURE__*/jsx(ErrorBoundary, {
423
- children: /*#__PURE__*/jsx(Menu, _extends({
424
- className: classnames('menu-list', style$3['menu-list']),
425
- menuOpen: menuOpen
426
- }, menu, {
427
- onChange: () => {
428
- deviceIsMobile && setMenuOpen(false);
429
- }
430
- }))
431
- }), _aiDialog && /*#__PURE__*/jsx("div", {
432
- className: classnames('ai-entry', style$3['ai-entry']),
433
- onClick: () => {
434
- setAiType('small');
435
- },
436
- children: /*#__PURE__*/jsx(Icon, {
437
- type: "system-prompt",
438
- colorful: true
439
- })
440
- })]
441
- })]
442
- }), /*#__PURE__*/jsx(Flex, {
443
- flex: 1,
444
- className: classnames('page', style$3['page']),
445
- children: /*#__PURE__*/jsxs(Row, {
446
- className: classnames('page-content', style$3['page-content']),
447
- children: [!deviceIsMobile && _aiDialog && aiType === 'inner' && /*#__PURE__*/jsx(Col, {
448
- span: 8,
449
- className: classnames('page-dialog-outer', style$3['page-dialog-outer']),
450
- children: /*#__PURE__*/jsxs("div", {
451
- className: classnames('page-dialog', style$3['page-dialog']),
452
- children: [/*#__PURE__*/jsxs(Flex, {
453
- className: classnames('ai-dialog-window-title', style$3['ai-dialog-window-title']),
454
- children: [/*#__PURE__*/jsx("div", {
455
- children: _aiDialog.title
456
- }), /*#__PURE__*/jsx(Flex, {
457
- gap: 10,
458
- children: /*#__PURE__*/jsx(Icon, {
459
- className: "btn",
460
- type: "icon-a-Typeclose",
461
- fontClassName: "system",
462
- onClick: () => {
463
- setAiType('closed');
464
- }
818
+ gap: 10,
819
+ children: [!deviceIsMobile && /*#__PURE__*/jsx(Icon, {
820
+ className: "btn",
821
+ type: "icon-a-Typeopen_in_full",
822
+ fontClassName: "system",
823
+ onClick: () => {
824
+ setAiType('inner');
825
+ }
826
+ }), /*#__PURE__*/jsx(Icon, {
827
+ className: "btn",
828
+ type: "icon-a-Typeclose",
829
+ fontClassName: "system",
830
+ onClick: () => {
831
+ setAiType('closed');
832
+ }
833
+ })]
834
+ })]
835
+ }), /*#__PURE__*/jsx(ErrorBoundary, {
836
+ children: /*#__PURE__*/jsx("div", {
837
+ className: classnames('ai-dialog-window-content', style$3['ai-dialog-window-content']),
838
+ children: _aiDialog.content
839
+ })
840
+ })]
841
+ }) : null;
842
+ const aiEntryMobile = deviceIsMobile && _aiDialog && aiType === 'closed' ? /*#__PURE__*/jsx(MobileAiEntry, {
843
+ variant: portalMenu ? 'boundary' : 'viewport',
844
+ onOpen: () => setAiType('small')
845
+ }) : null;
846
+
847
+ // portal 到 boundary(popup 挂载点)时,layout 上的 CSS 变量不会随 portal 继承,需要显式透传
848
+ const aiPortalVars = {
849
+ '--background': _background,
850
+ '--toolbar-height': deviceIsMobile && toolbarShow ? '72px' : '0px',
851
+ '--safe-area-inset-top': 'env(safe-area-inset-top)',
852
+ '--safe-area-inset-bottom': 'env(safe-area-inset-bottom)'
853
+ };
854
+ const aiOverlayContent = aiDialogWindow || aiEntryMobile ? /*#__PURE__*/jsxs(Fragment, {
855
+ children: [aiDialogWindow, aiEntryMobile]
856
+ }) : null;
857
+ const aiOverlay = !aiOverlayContent ? null : portalMenu ? /*#__PURE__*/createPortal(/*#__PURE__*/jsx("div", {
858
+ className: classnames('ai-boundary-overlay', style$3['ai-boundary-overlay']),
859
+ style: aiPortalVars,
860
+ children: aiOverlayContent
861
+ }), menuPortalTarget) : aiOverlayContent;
862
+ return /*#__PURE__*/jsx(LayoutResponsiveScope, {
863
+ boundaryRef: layoutBoundaryRef,
864
+ scrollRef: pageScrollRef,
865
+ getScrollElement: getPageScrollElement,
866
+ children: /*#__PURE__*/jsxs(Provider, {
867
+ value: contextValue,
868
+ children: [/*#__PURE__*/jsx("div", {
869
+ ref: topRef
870
+ }), /*#__PURE__*/jsxs("div", {
871
+ ref: layoutBoundaryRef,
872
+ className: classnames(className, 'layout', style$3['layout'], RESPONSIVE_BOUNDARY_CLASS, {
873
+ 'is-mobile': deviceIsMobile,
874
+ [style$3['is-mobile']]: deviceIsMobile,
875
+ 'has-toolbar': deviceIsMobile && toolbarShow,
876
+ [style$3['has-toolbar']]: deviceIsMobile && toolbarShow,
877
+ 'has-navbar': deviceIsMobile && navbarShow,
878
+ [style$3['has-navbar']]: deviceIsMobile && navbarShow
879
+ }),
880
+ style: {
881
+ '--menu-max-width': _menuMaxWidth,
882
+ '--menu-min-width': _menuMinWidth,
883
+ '--background': _background
884
+ },
885
+ children: [!portalMenu && layerMenuNode, /*#__PURE__*/jsxs(Flex, {
886
+ style: {
887
+ flex: 1,
888
+ minHeight: 0,
889
+ width: '100%',
890
+ height: 0
891
+ },
892
+ children: [!portalMenu && menuNode, portalMenu && /*#__PURE__*/createPortal(/*#__PURE__*/jsxs("div", {
893
+ className: classnames(style$3['menu-boundary-overlay']),
894
+ style: menuPortalVars,
895
+ children: [layerMenuNode, menuNode]
896
+ }), menuPortalTarget), /*#__PURE__*/jsx(Flex, {
897
+ flex: 1,
898
+ ref: pageRef,
899
+ className: classnames('page', style$3['page']),
900
+ children: /*#__PURE__*/jsxs(Row, {
901
+ className: classnames('page-content', style$3['page-content']),
902
+ children: [!deviceIsMobile && _aiDialog && aiType === 'inner' && /*#__PURE__*/jsx(Col, {
903
+ span: 8,
904
+ className: classnames('page-dialog-outer', style$3['page-dialog-outer']),
905
+ children: /*#__PURE__*/jsxs("div", {
906
+ className: classnames('page-dialog', style$3['page-dialog']),
907
+ children: [/*#__PURE__*/jsxs(Flex, {
908
+ className: classnames('ai-dialog-window-title', style$3['ai-dialog-window-title']),
909
+ children: [/*#__PURE__*/jsx("div", {
910
+ children: _aiDialog.title
911
+ }), /*#__PURE__*/jsx(Flex, {
912
+ gap: 10,
913
+ children: /*#__PURE__*/jsx(Icon, {
914
+ className: "btn",
915
+ type: "icon-a-Typeclose",
916
+ fontClassName: "system",
917
+ onClick: () => {
918
+ setAiType('closed');
919
+ }
920
+ })
921
+ })]
922
+ }), /*#__PURE__*/jsx(ErrorBoundary, {
923
+ children: /*#__PURE__*/jsx("div", {
924
+ className: classnames('page-window-content', style$3['page-window-content']),
925
+ children: _aiDialog.content
465
926
  })
466
927
  })]
467
- }), /*#__PURE__*/jsx(ErrorBoundary, {
468
- children: /*#__PURE__*/jsx("div", {
469
- className: classnames('page-window-content', style$3['page-window-content']),
470
- children: _aiDialog.content
928
+ })
929
+ }), /*#__PURE__*/jsx(Col, {
930
+ span: !deviceIsMobile && _aiDialog && aiType === 'inner' ? 16 : 24,
931
+ className: RESPONSIVE_CONTAINER_CLASS,
932
+ children: /*#__PURE__*/jsx(ErrorBoundary, {
933
+ children: openScrollbar ? /*#__PURE__*/jsx(SimpleBar, {
934
+ ref: handlePageScrollRef,
935
+ className: classnames('page-children', style$3['page-children'], RESPONSIVE_SCROLL_CLASS, {
936
+ ['has-left']: aiType === 'inner'
937
+ }),
938
+ children: children
939
+ }) : /*#__PURE__*/jsx("div", {
940
+ ref: handlePageScrollRef,
941
+ className: classnames('page-children', style$3['page-children'], !deviceIsMobile && 'is-scroller', !deviceIsMobile && style$3['is-scroller'], !deviceIsMobile && RESPONSIVE_SCROLL_CLASS, {
942
+ ['has-left']: aiType === 'inner'
943
+ }),
944
+ children: children
471
945
  })
472
- })]
473
- })
474
- }), /*#__PURE__*/jsx(Col, {
475
- span: !deviceIsMobile && _aiDialog && aiType === 'inner' ? 16 : 24,
476
- children: /*#__PURE__*/jsx(ErrorBoundary, {
477
- children: openScrollbar ? /*#__PURE__*/jsx(SimpleBar, {
478
- className: classnames('page-children', style$3['page-children'], {
479
- ['has-left']: aiType === 'inner'
480
- }),
481
- children: children
482
- }) : /*#__PURE__*/jsx("div", {
483
- className: classnames('page-children', 'is-scroller', style$3['page-children'], style$3['is-scroller'], {
484
- ['has-left']: aiType === 'inner'
485
- }),
486
- children: children
487
946
  })
488
- })
489
- })]
490
- })
491
- }), _aiDialog && aiType === 'small' && /*#__PURE__*/jsxs("div", {
492
- className: classnames('ai-dialog-window', style$3['ai-dialog-window']),
493
- children: [/*#__PURE__*/jsxs(Flex, {
494
- className: classnames('ai-dialog-window-title', style$3['ai-dialog-window-title']),
495
- children: [/*#__PURE__*/jsx("div", {
496
- children: _aiDialog.title
497
- }), /*#__PURE__*/jsxs(Flex, {
498
- gap: 10,
499
- children: [/*#__PURE__*/jsx(Icon, {
500
- className: "btn",
501
- type: "icon-a-Typeopen_in_full",
502
- fontClassName: "system",
503
- onClick: () => {
504
- setAiType('inner');
505
- }
506
- }), /*#__PURE__*/jsx(Icon, {
507
- className: "btn",
508
- type: "icon-a-Typeclose",
509
- fontClassName: "system",
510
- onClick: () => {
511
- setAiType('closed');
512
- }
513
947
  })]
514
- })]
515
- }), /*#__PURE__*/jsx(ErrorBoundary, {
516
- children: /*#__PURE__*/jsx("div", {
517
- className: classnames('ai-dialog-window-content', style$3['ai-dialog-window-content']),
518
- children: _aiDialog.content
519
948
  })
520
949
  })]
521
- })]
522
- }), /*#__PURE__*/jsx(Toolbar, _extends({}, menu, {
523
- className: classnames(style$3['toolbar']),
524
- show: toolbarShow,
525
- target: toolbarTarget
526
- }))]
527
- })]
950
+ }), aiOverlay, /*#__PURE__*/jsx(Toolbar, _extends({}, menu, {
951
+ className: classnames(style$3['toolbar']),
952
+ show: deviceIsMobile && toolbarShow,
953
+ target: toolbarTarget
954
+ }))]
955
+ })]
956
+ })
528
957
  });
529
958
  };
530
959
 
531
- var style = {"page":"_c1kXt","page-header":"_h-YXH","page-title":"_IOVGr","page-title-extra":"_mKsLu","page-inner":"_wHWje","is-mobile":"_yRZMx","back-icon":"_07Mna"};
960
+ var style = {"page":"kne-system-layout_c1kXt","page-header":"kne-system-layout_h-YXH","is-scrolled":"kne-system-layout_dEXMy","page-title-outer":"kne-system-layout_jhcGo","capsule-click":"kne-system-layout_Ps1FA","page-title-extra":"kne-system-layout_mKsLu","page-title":"kne-system-layout_IOVGr","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-loading":"kne-system-layout_vcf3J","page-bottom":"kne-system-layout_vXk1s","back-icon":"kne-system-layout_07Mna"};
532
961
 
962
+ const PageLoading = () => {
963
+ return /*#__PURE__*/jsx(Flex, {
964
+ flex: 1,
965
+ justify: "center",
966
+ children: /*#__PURE__*/jsx("div", {
967
+ className: style['page-loading'],
968
+ children: /*#__PURE__*/jsx(Skeleton, {
969
+ active: true
970
+ })
971
+ })
972
+ });
973
+ };
533
974
  const Page = ({
534
975
  title,
535
976
  extra: _extra = null,
536
977
  back,
537
978
  buttonProps,
538
979
  children,
539
- toolbar: _toolbar = true
980
+ toolbar: _toolbar = true,
981
+ navbar: _navbar = true,
982
+ noPadding
540
983
  }) => {
541
984
  const {
542
985
  setToolbarShow,
986
+ setNavbarShow,
543
987
  setMenuOpen,
544
988
  deviceIsMobile,
545
- userAvatar
989
+ userAvatar,
990
+ scrollReady
546
991
  } = useContext();
992
+ const navigate = useNavigate();
993
+ const getScrollElement = useScrollElement();
994
+ const navbarRef = useRef(null);
995
+ const [isScrolled, setIsScrolled] = useState(false);
547
996
  useEffect(() => {
548
997
  setToolbarShow && setToolbarShow(!!_toolbar);
549
- }, [_toolbar]);
550
- return /*#__PURE__*/jsxs(Flex, {
551
- vertical: true,
552
- gap: 24,
553
- className: classnames('page', style['page'], {
554
- ['is-mobile']: deviceIsMobile,
555
- [style['is-mobile']]: deviceIsMobile
998
+ setNavbarShow && setNavbarShow(!!_navbar);
999
+ }, [_toolbar, _navbar]);
1000
+ useEffect(() => {
1001
+ if (!deviceIsMobile || !_navbar) {
1002
+ return;
1003
+ }
1004
+ const scrollEl = getScrollElement();
1005
+ if (!scrollEl || typeof scrollEl.addEventListener !== 'function') {
1006
+ return;
1007
+ }
1008
+ const handleScroll = () => {
1009
+ const threshold = navbarRef.current ? navbarRef.current.offsetHeight : 48;
1010
+ setIsScrolled(scrollEl.scrollTop > threshold);
1011
+ };
1012
+ handleScroll();
1013
+ scrollEl.addEventListener('scroll', handleScroll, {
1014
+ passive: true
1015
+ });
1016
+ return () => scrollEl.removeEventListener('scroll', handleScroll);
1017
+ }, [deviceIsMobile, _navbar, getScrollElement, scrollReady]);
1018
+ const navbarEl = _navbar ? /*#__PURE__*/jsxs(Flex, {
1019
+ ref: navbarRef,
1020
+ justify: "space-between",
1021
+ align: "center",
1022
+ gap: 20,
1023
+ className: classnames('page-header', style['page-header'], {
1024
+ ['is-scrolled']: isScrolled,
1025
+ [style['is-scrolled']]: isScrolled
556
1026
  }),
557
1027
  children: [/*#__PURE__*/jsxs(Flex, {
558
- justify: "space-between",
1028
+ className: classnames('page-title-outer', style['page-title-outer']),
559
1029
  align: "center",
560
- gap: 20,
561
- className: classnames('page-header', style['page-header']),
562
- children: [/*#__PURE__*/jsxs(Flex, {
563
- className: classnames('page-title-outer', style['page-title-outer']),
564
- align: "center",
565
- gap: 4,
566
- children: [back && /*#__PURE__*/jsx(Button, {
567
- type: "text",
568
- icon: /*#__PURE__*/jsx(Icon, {
569
- className: style['back-icon'],
570
- type: "a-Typearrow_forward_ios",
571
- fontClassName: "system"
572
- })
573
- }), !back && deviceIsMobile && /*#__PURE__*/jsx(Button, {
574
- type: "link",
575
- icon: /*#__PURE__*/jsx(Icon, {
576
- className: style['back-icon'],
577
- type: "a-Typeequal",
578
- fontClassName: "system"
579
- }),
580
- onClick: () => {
581
- setMenuOpen(open => !open);
582
- }
583
- }), /*#__PURE__*/jsx("div", {
584
- className: classnames('page-title', style['page-title']),
585
- children: title
586
- })]
1030
+ gap: 4,
1031
+ children: [back && /*#__PURE__*/jsx(Button, {
1032
+ type: "text",
1033
+ icon: /*#__PURE__*/jsx(Icon, {
1034
+ className: style['back-icon'],
1035
+ type: "a-Typearrow_forward_ios",
1036
+ fontClassName: "system"
1037
+ }),
1038
+ onClick: () => {
1039
+ navigate(-1);
1040
+ }
1041
+ }), !back && deviceIsMobile && /*#__PURE__*/jsx(Button, {
1042
+ type: "link",
1043
+ icon: /*#__PURE__*/jsx(Icon, {
1044
+ className: style['back-icon'],
1045
+ type: "a-Typeequal",
1046
+ fontClassName: "system"
1047
+ }),
1048
+ onClick: () => {
1049
+ setMenuOpen(open => !open);
1050
+ }
587
1051
  }), /*#__PURE__*/jsx("div", {
588
- className: classnames('page-title-extra', style['page-title-extra']),
589
- children: _extra ? _extra : deviceIsMobile ? /*#__PURE__*/jsxs(Flex, {
590
- gap: 4,
591
- align: "center",
592
- children: [buttonProps && /*#__PURE__*/jsx(ButtonGroup, _extends({}, Object.assign({}, buttonProps, deviceIsMobile ? {
593
- showLength: 0,
594
- moreType: 'link'
595
- } : {}))), /*#__PURE__*/jsx(Image.Avatar, {
596
- id: userAvatar,
597
- src: userAvatar,
598
- shape: "circle",
599
- size: 30,
600
- alt: "avatar"
601
- })]
602
- }) : buttonProps && /*#__PURE__*/jsx(ButtonGroup, _extends({}, buttonProps))
1052
+ className: classnames('page-title', style['page-title']),
1053
+ children: title
603
1054
  })]
604
1055
  }), /*#__PURE__*/jsx("div", {
605
- className: classnames('page-inner', style['page-inner']),
606
- children: children
1056
+ className: classnames('page-title-extra', style['page-title-extra']),
1057
+ children: _extra ? _extra : deviceIsMobile ? /*#__PURE__*/jsxs(Flex, {
1058
+ gap: 4,
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))
607
1071
  })]
1072
+ }) : null;
1073
+ const pageInnerClassNameOrigin = classnames('page-inner', style['page-inner']);
1074
+ const pageInnerClassName = classnames(pageInnerClassNameOrigin, {
1075
+ ['no-padding']: noPadding,
1076
+ [style['no-padding']]: noPadding
608
1077
  });
1078
+ const render = ({
1079
+ children,
1080
+ className
1081
+ }) => {
1082
+ return /*#__PURE__*/jsxs(Fragment, {
1083
+ children: [/*#__PURE__*/jsx("div", {
1084
+ className: style['page-top']
1085
+ }), /*#__PURE__*/jsxs(Flex, {
1086
+ vertical: true,
1087
+ flex: 1,
1088
+ children: [navbarEl, /*#__PURE__*/jsx(Flex, {
1089
+ vertical: true,
1090
+ flex: 1,
1091
+ className: classnames(pageInnerClassNameOrigin, className),
1092
+ children: children
1093
+ })]
1094
+ }), /*#__PURE__*/jsx("div", {
1095
+ className: style['page-bottom']
1096
+ })]
1097
+ });
1098
+ };
1099
+ return /*#__PURE__*/jsx(Flex, {
1100
+ vertical: true,
1101
+ flex: 1,
1102
+ className: classnames('page', style['page'], {
1103
+ ['is-mobile']: deviceIsMobile,
1104
+ [style['is-mobile']]: deviceIsMobile
1105
+ }),
1106
+ children: typeof children === 'function' ? children({
1107
+ navbar: navbarEl,
1108
+ className: pageInnerClassName,
1109
+ render,
1110
+ pageLoading: render({
1111
+ children: /*#__PURE__*/jsx(PageLoading, {})
1112
+ })
1113
+ }) : render({
1114
+ children
1115
+ })
1116
+ });
1117
+ };
1118
+ Page.PageLoading = PageLoading;
1119
+
1120
+ const isMobile = () => {
1121
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
1122
+ return false;
1123
+ }
1124
+ return window.matchMedia(IS_MOBILE_QUERY).matches;
1125
+ };
1126
+
1127
+ const transparentBgContainer = {
1128
+ colorBgContainer: 'transparent'
1129
+ };
1130
+ const transparentBgContainerComponents = ['Input', 'InputNumber', 'Card', 'Tree', 'Select', 'DatePicker'];
1131
+ const themeToken = {
1132
+ components: merge({}, transform(transparentBgContainerComponents, (result, component) => {
1133
+ result[component] = transparentBgContainer;
1134
+ }, {}))
609
1135
  };
610
1136
 
611
1137
  import('./index-0916fdba.js');
612
1138
 
613
- export { Layout, Page, Layout as default, isMobile, useContext as useLayoutContext };
1139
+ export { Layout, Page, Layout as default, isMobile, themeToken, useContext as useLayoutContext };
614
1140
  //# sourceMappingURL=index.modern.js.map