@jetbrains/kotlin-web-site-ui 4.2.0-alpha.2 → 4.2.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
- import React__default, { useState, useContext, useRef, useCallback, useLayoutEffect } from 'react';
1
+ import React__default, { useState, useContext, useRef, useCallback, useLayoutEffect, useEffect } from 'react';
2
+ import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock';
2
3
  import useScrollbarSize from 'react-scrollbar-size';
3
4
  import { ThemeProvider } from '@rescui/ui-contexts';
4
5
  import Input from '@rescui/input';
@@ -53,6 +54,12 @@ const FullSearch = ({
53
54
  }
54
55
  }
55
56
  }, [hits, inputValue]);
57
+ useLayoutEffect(() => {
58
+ if (ref.current) disableBodyScroll(ref.current);
59
+ }, [ref]);
60
+ useEffect(() => {
61
+ return clearAllBodyScrollLocks;
62
+ }, []);
56
63
  return React__default.createElement(ThemeProvider, {
57
64
  theme: 'light'
58
65
  }, React__default.createElement("div", {
@@ -1,7 +1,6 @@
1
1
  import React__default, { forwardRef, useState, useMemo, useRef, useImperativeHandle, useLayoutEffect, useCallback, useEffect } from 'react';
2
2
  import { ThemeProvider } from '@rescui/ui-contexts';
3
3
  import FocusManager from '@rescui/focus-manager';
4
- import useResizeObserver from '@react-hook/resize-observer';
5
4
  import OutsideClickHandler from 'react-outside-click-handler';
6
5
  import { LogoLarge } from './logo-large/logo-large.js';
7
6
  import styles from './header.module.pcss.js';
@@ -15,7 +14,8 @@ import classNames from 'classnames';
15
14
  import { SearchWrapper } from './search-wrapper/search-wrapper.js';
16
15
  import { isMacOs } from './is-macos.js';
17
16
  import { KEY_K_CODE } from './key-codes.js';
18
- const MENU_POPUP_BREAKPOINT = 640;
17
+ import useResizeObserver from '@react-hook/resize-observer';
18
+ const BREAKPOINT_XS = 640;
19
19
  const Header = forwardRef(({
20
20
  productWebUrl,
21
21
  hasSearch = false,
@@ -27,21 +27,20 @@ const Header = forwardRef(({
27
27
  linkHandler,
28
28
  isPlayground,
29
29
  isUrlActive,
30
- searchConfig,
31
- noScrollClassName
30
+ searchConfig
32
31
  }, forwardedRef) => {
33
32
  const [menuPopupExpanded, setMenuPopupExpanded] = useState(false);
34
- const [isMenuPopupVisible, setIsMenuPopupVisible] = useState(false);
35
33
  const [isSearchBoxVisible, setSearchBoxVisible] = useState(false);
36
34
  const [fullSearchActive, setFullSearchActive] = useState(false);
37
35
  const items = useMemo(() => getNavScheme(isUrlActive, currentUrl, isPlayground), [isUrlActive, currentUrl, isPlayground]);
38
36
  const itemsWithoutHomeSection = useMemo(() => items.slice(1), [items]);
39
37
  const headerRef = useRef(null);
40
38
  useImperativeHandle(forwardedRef, () => headerRef.current);
39
+ const [isMenuPopupVisible, setMenuPopupVisible] = useState(false);
41
40
  useLayoutEffect(() => {
42
- setIsMenuPopupVisible((headerRef.current?.getBoundingClientRect?.().width ?? 0) <= MENU_POPUP_BREAKPOINT);
41
+ setMenuPopupVisible((headerRef.current?.getBoundingClientRect?.().width ?? 0) <= BREAKPOINT_XS);
43
42
  }, [headerRef]);
44
- useResizeObserver(headerRef, entry => setIsMenuPopupVisible(entry.contentRect.width <= MENU_POPUP_BREAKPOINT));
43
+ useResizeObserver(headerRef, entry => setMenuPopupVisible(entry.contentRect.width <= BREAKPOINT_XS));
45
44
  const handleSearchButtonClick = useCallback(() => {
46
45
  setSearchBoxVisible(!isSearchBoxVisible);
47
46
  }, []);
@@ -70,15 +69,6 @@ const Header = forwardRef(({
70
69
  };
71
70
  }
72
71
  }, [fullSearchKeyHandler]);
73
- useEffect(() => {
74
- if (typeof document !== `undefined` && noScrollClassName) {
75
- if (fullSearchActive) {
76
- document.body.classList.add(noScrollClassName);
77
- } else {
78
- document.body.classList.remove(noScrollClassName);
79
- }
80
- }
81
- }, [fullSearchActive]);
82
72
  return React__default.createElement(ThemeProvider, {
83
73
  theme: 'dark'
84
74
  }, React__default.createElement(SearchWrapper, {
@@ -1,4 +1,4 @@
1
- import React__default, { useState } from 'react';
1
+ import React__default, { useState, useRef, useEffect, useCallback } from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import classNames from 'classnames';
4
4
  import styles from './dropdown-menu.module.pcss.js';
@@ -7,6 +7,7 @@ import SvgArrowDropdownIcon from './arrow-dropdown-icon.svg.js';
7
7
  import { useTheme } from '@rescui/ui-contexts';
8
8
  import Button from '@rescui/button';
9
9
  import { CloseIcon } from '@rescui/icons';
10
+ import { clearAllBodyScrollLocks, enableBodyScroll, disableBodyScroll } from 'body-scroll-lock';
10
11
 
11
12
  const DropdownMenu = ({
12
13
  homeUrl,
@@ -19,11 +20,14 @@ const DropdownMenu = ({
19
20
  }) => {
20
21
  const theme = useTheme();
21
22
  const textCn = useTextStyles();
22
- const [portalRoot, setPortalRoot] = React__default.useState(null);
23
- React__default.useEffect(() => {
23
+ const [portalRoot, setPortalRoot] = useState(null);
24
+ const navRef = useRef(null);
25
+ useEffect(() => {
24
26
  if (typeof document !== `undefined`) {
25
27
  setPortalRoot(document.body);
26
28
  }
29
+
30
+ return clearAllBodyScrollLocks;
27
31
  }, []);
28
32
 
29
33
  let _items = (mobileOverview ? [{
@@ -35,9 +39,13 @@ const DropdownMenu = ({
35
39
 
36
40
  const activeItem = _items[_activeIndex];
37
41
  const [isExpanded, setIsExpanded] = useState(false);
42
+ const handleClick = useCallback(() => {
43
+ if (navRef.current) {
44
+ isExpanded ? enableBodyScroll(navRef.current) : disableBodyScroll(navRef.current);
45
+ }
38
46
 
39
- const handleClick = () => setIsExpanded(!isExpanded);
40
-
47
+ setIsExpanded(!isExpanded);
48
+ }, [isExpanded, navRef]);
41
49
  return React__default.createElement(React__default.Fragment, null, React__default.createElement("div", {
42
50
  className: classNames(styles.dropdownMenu, {
43
51
  [styles.dropdownMenuExpanded]: isExpanded
@@ -51,6 +59,7 @@ const DropdownMenu = ({
51
59
  }, activeItem.title), React__default.createElement(SvgArrowDropdownIcon, {
52
60
  className: styles.icon
53
61
  })), React__default.createElement("nav", {
62
+ ref: navRef,
54
63
  className: classNames(styles.dropdownList, {
55
64
  [styles.dropdownListDarkTheme]: theme === 'dark'
56
65
  })
@@ -75,12 +75,6 @@
75
75
  color: var(--ktl-color-primary-light-theme);
76
76
  }
77
77
 
78
- @media (max-width: 640px) {
79
- .ktl-horizontal-menu-module_horizontal-menu_pB2-S {
80
- display: none;
81
- }
82
- }
83
-
84
78
  :root {
85
79
  --ktl-light-grey: #f4f4f4;
86
80
  --ktl-dark-100: rgba(39, 40, 44, 1);
@@ -119,7 +113,7 @@
119
113
  }
120
114
 
121
115
  .ktl-dropdown-menu-module_dropdown-menu_tq2uU {
122
- display: none;
116
+ display: block;
123
117
  height: 100%;
124
118
  justify-self: flex-start;
125
119
  white-space: nowrap;
@@ -225,12 +219,6 @@
225
219
  background: #ffffff;
226
220
  }
227
221
 
228
- @media (max-width: 640px) {
229
- .ktl-dropdown-menu-module_dropdown-menu_tq2uU {
230
- display: block;
231
- }
232
- }
233
-
234
222
  @-webkit-keyframes ktl-dropdown-menu-module_fadein_MySnq {
235
223
  0% {
236
224
  opacity: 0;
@@ -1,12 +1,13 @@
1
- import React__default from 'react';
1
+ import React__default, { forwardRef, useRef, useImperativeHandle, useState, useLayoutEffect } from 'react';
2
2
  import { useTheme } from '@rescui/ui-contexts';
3
3
  import classNames from 'classnames';
4
4
  import styles from './top-menu.module.pcss.js';
5
5
  import { useTextStyles } from '@rescui/typography';
6
6
  import { HorizontalMenu } from './horizontal-menu/horizontal-menu.js';
7
7
  import { DropdownMenu } from './dropdown-menu/dropdown-menu.js';
8
-
9
- const TopMenu = ({
8
+ import useResizeObserver from '@react-hook/resize-observer';
9
+ const BREAKPOINT_XS = 640;
10
+ const TopMenu = forwardRef(({
10
11
  homeUrl,
11
12
  title,
12
13
  mobileTitle,
@@ -15,21 +16,27 @@ const TopMenu = ({
15
16
  linkHandler = () => {},
16
17
  className,
17
18
  children,
18
- forwardedRef,
19
19
  mobileOverview
20
- }) => {
20
+ }, forwardedRef) => {
21
21
  const theme = useTheme();
22
22
  const textCn = useTextStyles();
23
+ const menuRef = useRef(null);
24
+ useImperativeHandle(forwardedRef, () => menuRef.current);
25
+ const [isMobileMenuVisible, setMobileMenuVisible] = useState(false);
26
+ useLayoutEffect(() => {
27
+ setMobileMenuVisible((menuRef.current?.getBoundingClientRect?.().width ?? 0) <= BREAKPOINT_XS);
28
+ }, [menuRef]);
29
+ useResizeObserver(menuRef, entry => setMobileMenuVisible(entry.contentRect.width <= BREAKPOINT_XS));
23
30
  return React__default.createElement("div", {
31
+ ref: menuRef,
24
32
  className: classNames(styles.topMenu, className, {
25
33
  [styles.topMenuDarkTheme]: theme === 'dark'
26
- }),
27
- ref: forwardedRef
34
+ })
28
35
  }, React__default.createElement("a", {
29
36
  href: homeUrl,
30
37
  className: classNames(styles.logo, textCn('rs-h3')),
31
38
  onClick: event => linkHandler(event, homeUrl)
32
- }, title), React__default.createElement(DropdownMenu, {
39
+ }, title), isMobileMenuVisible ? React__default.createElement(DropdownMenu, {
33
40
  items: items,
34
41
  activeIndex: activeIndex,
35
42
  linkHandler: linkHandler,
@@ -37,11 +44,10 @@ const TopMenu = ({
37
44
  mobileTitle: mobileTitle,
38
45
  homeUrl: homeUrl,
39
46
  mobileOverview: mobileOverview
40
- }), React__default.createElement(HorizontalMenu, {
47
+ }) : React__default.createElement(HorizontalMenu, {
41
48
  items: items,
42
49
  activeIndex: activeIndex,
43
50
  linkHandler: linkHandler
44
51
  }), children);
45
- };
46
-
52
+ });
47
53
  export { TopMenu };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jetbrains/kotlin-web-site-ui",
3
3
  "description": "UI components for Kotlin web sites development",
4
- "version": "4.2.0-alpha.2",
4
+ "version": "4.2.0-alpha.3",
5
5
  "license": "Apache-2.0",
6
6
  "author": "JetBrains",
7
7
  "files": [