@os-design/core 1.0.199 → 1.0.200

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.
Files changed (99) hide show
  1. package/package.json +21 -13
  2. package/src/@types/emotion.d.ts +7 -0
  3. package/src/Alert/index.tsx +112 -0
  4. package/src/Avatar/index.tsx +173 -0
  5. package/src/Avatar/utils/nameToInitials.ts +12 -0
  6. package/src/Avatar/utils/strToHue.ts +13 -0
  7. package/src/AvatarSkeleton/index.tsx +29 -0
  8. package/src/Breadcrumb/index.tsx +93 -0
  9. package/src/BreadcrumbItem/index.tsx +83 -0
  10. package/src/Button/ButtonContent.tsx +91 -0
  11. package/src/Button/index.tsx +225 -0
  12. package/src/Button/utils/useButtonColors.ts +84 -0
  13. package/src/Checkbox/index.tsx +225 -0
  14. package/src/CheckboxSkeleton/index.tsx +50 -0
  15. package/src/DatePicker/DatePickerCalendar.tsx +220 -0
  16. package/src/DatePicker/index.tsx +568 -0
  17. package/src/Drawer/index.tsx +212 -0
  18. package/src/Form/FormConfigContext.ts +16 -0
  19. package/src/Form/index.tsx +49 -0
  20. package/src/FormDivider/index.tsx +74 -0
  21. package/src/FormItem/index.tsx +118 -0
  22. package/src/Gallery/Status.tsx +62 -0
  23. package/src/Gallery/index.tsx +290 -0
  24. package/src/GlobalStyles/index.tsx +17 -0
  25. package/src/GlobalStyles/resetStyles.ts +17 -0
  26. package/src/GlobalStyles/typographyStyles.ts +78 -0
  27. package/src/HeaderSkeleton/index.tsx +64 -0
  28. package/src/Image/index.tsx +104 -0
  29. package/src/ImageSkeleton/index.tsx +22 -0
  30. package/src/Input/index.tsx +330 -0
  31. package/src/Input/utils/getFocusableElements.ts +8 -0
  32. package/src/InputNumber/index.tsx +208 -0
  33. package/src/InputNumber/utils/defaultLocale.ts +9 -0
  34. package/src/InputPassword/index.tsx +201 -0
  35. package/src/InputPassword/utils/defaultLocale.ts +11 -0
  36. package/src/InputSearch/index.tsx +111 -0
  37. package/src/InputSearch/utils/defaultLocale.ts +9 -0
  38. package/src/InputSkeleton/index.tsx +28 -0
  39. package/src/Layout/LayoutContext.ts +21 -0
  40. package/src/Layout/index.tsx +44 -0
  41. package/src/Link/index.tsx +129 -0
  42. package/src/LinkButton/index.tsx +100 -0
  43. package/src/List/WindowScroller.tsx +53 -0
  44. package/src/List/index.tsx +255 -0
  45. package/src/List/utils/bodyPointerEvents.ts +24 -0
  46. package/src/List/utils/frameTimeout.ts +36 -0
  47. package/src/List/utils/useRWLoadNext.ts +38 -0
  48. package/src/ListItem/index.tsx +92 -0
  49. package/src/ListItemActions/index.tsx +207 -0
  50. package/src/ListItemLink/index.tsx +63 -0
  51. package/src/ListSkeleton/index.tsx +115 -0
  52. package/src/LogoLink/index.tsx +93 -0
  53. package/src/LogoLink/logo.example.svg +18 -0
  54. package/src/Menu/index.tsx +128 -0
  55. package/src/Menu/utils/useFocusWithArrows.ts +50 -0
  56. package/src/MenuDivider/index.tsx +22 -0
  57. package/src/MenuGroup/index.tsx +190 -0
  58. package/src/MenuItem/index.tsx +108 -0
  59. package/src/Modal/index.tsx +411 -0
  60. package/src/Modal/utils/defaultLocale.ts +9 -0
  61. package/src/Navigation/index.tsx +214 -0
  62. package/src/Navigation/utils/useScrollFlags.ts +39 -0
  63. package/src/NavigationItem/index.tsx +136 -0
  64. package/src/PageContent/index.tsx +99 -0
  65. package/src/PageHeader/index.tsx +246 -0
  66. package/src/PageHeader/utils/defaultLocale.ts +9 -0
  67. package/src/PageHeaderInputSearch/index.tsx +145 -0
  68. package/src/PageHeaderInputSearch/utils/defaultLocale.ts +16 -0
  69. package/src/PageHeaderSkeleton/index.tsx +33 -0
  70. package/src/ParagraphSkeleton/index.tsx +65 -0
  71. package/src/Popover/index.tsx +243 -0
  72. package/src/Popover/utils/usePopoverPosition.ts +216 -0
  73. package/src/Progress/index.tsx +100 -0
  74. package/src/RadioGroup/index.tsx +165 -0
  75. package/src/RadioGroupSkeleton/index.tsx +36 -0
  76. package/src/Result/index.tsx +109 -0
  77. package/src/ScrollButton/index.tsx +159 -0
  78. package/src/ScrollButton/utils/useContainerPosition.ts +41 -0
  79. package/src/ScrollButton/utils/useVisibility.ts +56 -0
  80. package/src/Select/index.tsx +970 -0
  81. package/src/Select/utils/defaultLocale.ts +11 -0
  82. package/src/Skeleton/index.tsx +52 -0
  83. package/src/Switch/index.tsx +217 -0
  84. package/src/SwitchSkeleton/index.tsx +30 -0
  85. package/src/Tag/index.tsx +75 -0
  86. package/src/TagLink/index.tsx +53 -0
  87. package/src/TagList/index.tsx +95 -0
  88. package/src/TagListSkeleton/index.tsx +38 -0
  89. package/src/TagSkeleton/index.tsx +40 -0
  90. package/src/TextArea/index.tsx +231 -0
  91. package/src/TextAreaSkeleton/index.tsx +20 -0
  92. package/src/ThemeSwitcher/index.tsx +39 -0
  93. package/src/TimePicker/index.tsx +142 -0
  94. package/src/Video/index.tsx +41 -0
  95. package/src/index.ts +125 -0
  96. package/src/message/AlertIcon.tsx +50 -0
  97. package/src/message/Message.tsx +108 -0
  98. package/src/message/index.tsx +64 -0
  99. package/src/message/styles.ts +25 -0
@@ -0,0 +1,165 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import { m } from '@os-design/media';
4
+ import { WithSize } from '@os-design/styles';
5
+ import { clr } from '@os-design/theming';
6
+ import { omitEmotionProps, useForwardedState } from '@os-design/utils';
7
+ import React, { forwardRef } from 'react';
8
+ import Button, { ButtonProps } from '../Button';
9
+
10
+ export interface RadioGroupOption
11
+ extends Omit<ButtonProps, 'type' | 'wide' | 'size'> {
12
+ /**
13
+ * The title of the option.
14
+ */
15
+ title: string;
16
+ /**
17
+ * The value of the option.
18
+ */
19
+ value: string;
20
+ }
21
+
22
+ type JsxDivProps = Omit<
23
+ JSX.IntrinsicElements['div'],
24
+ 'value' | 'defaultValue' | 'onChange' | 'ref'
25
+ >;
26
+ export interface RadioGroupProps extends JsxDivProps, WithSize {
27
+ /**
28
+ * Options of the radio group.
29
+ * @default undefined
30
+ */
31
+ options?: RadioGroupOption[];
32
+ /**
33
+ * Whether the radio group has full width.
34
+ * Possible values:
35
+ * `default` – the radio group has full width if the screen width is less than xs;
36
+ * `always` – the radio group always has full width;
37
+ * `never` – the radio group never has full width.
38
+ * @default default
39
+ */
40
+ wide?: 'default' | 'always' | 'never';
41
+ /**
42
+ * Whether the radio group is disabled.
43
+ * @default false
44
+ */
45
+ disabled?: boolean;
46
+ /**
47
+ * Selected option.
48
+ * @default false
49
+ */
50
+ value?: string;
51
+ /**
52
+ * The default value.
53
+ * @default undefined
54
+ */
55
+ defaultValue?: string;
56
+ /**
57
+ * The change event handler.
58
+ * @default undefined
59
+ */
60
+ onChange?: (value: string) => void;
61
+ }
62
+
63
+ const wideDefaultStyles = (p) =>
64
+ p.wide === 'default' &&
65
+ css`
66
+ ${m.max.xxs} {
67
+ width: 100%;
68
+ & > button {
69
+ flex: 1;
70
+ }
71
+ }
72
+ `;
73
+
74
+ const wideAlwaysStyles = (p) =>
75
+ p.wide === 'always' &&
76
+ css`
77
+ width: 100%;
78
+ & > button {
79
+ flex: 1;
80
+ }
81
+ `;
82
+
83
+ type ContainerProps = Required<Pick<RadioGroupProps, 'wide' | 'disabled'>>;
84
+ const Container = styled(
85
+ 'div',
86
+ omitEmotionProps('wide', 'disabled')
87
+ )<ContainerProps>`
88
+ display: inline-flex;
89
+ flex-wrap: wrap;
90
+
91
+ border-radius: ${(p) => p.theme.borderRadius}em;
92
+ overflow: hidden;
93
+ border: 1px solid
94
+ ${(p) =>
95
+ p.disabled
96
+ ? clr(p.theme.buttonDisabledGhostColorText)
97
+ : clr(p.theme.colorPrimary)};
98
+
99
+ ${wideDefaultStyles};
100
+ ${wideAlwaysStyles};
101
+ `;
102
+
103
+ const StyledButton = styled(Button)`
104
+ border-radius: 0;
105
+ `;
106
+
107
+ /**
108
+ * The radio buttons that allow a user to select only one of a limited number of options.
109
+ */
110
+ const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
111
+ (
112
+ {
113
+ options = [],
114
+ wide = 'default',
115
+ disabled = false,
116
+ value,
117
+ defaultValue,
118
+ onChange = () => {},
119
+ size,
120
+ ...rest
121
+ },
122
+ ref
123
+ ) => {
124
+ const [forwardedValue, setForwardedValue] = useForwardedState({
125
+ value,
126
+ defaultValue,
127
+ onChange,
128
+ });
129
+
130
+ return (
131
+ <div>
132
+ <Container wide={wide} disabled={disabled} {...rest} ref={ref}>
133
+ {options?.map(
134
+ ({
135
+ title,
136
+ value: valueOption,
137
+ disabled: disabledOption,
138
+ onClick = () => {},
139
+ ...buttonRest
140
+ }) => (
141
+ <StyledButton
142
+ key={valueOption}
143
+ type={forwardedValue === valueOption ? 'primary' : 'ghost'}
144
+ wide='never'
145
+ disabled={disabled || disabledOption}
146
+ size={size}
147
+ onClick={(e) => {
148
+ setForwardedValue(valueOption);
149
+ onClick(e);
150
+ }}
151
+ {...buttonRest}
152
+ >
153
+ {title}
154
+ </StyledButton>
155
+ )
156
+ )}
157
+ </Container>
158
+ </div>
159
+ );
160
+ }
161
+ );
162
+
163
+ RadioGroup.displayName = 'RadioGroup';
164
+
165
+ export default RadioGroup;
@@ -0,0 +1,36 @@
1
+ import styled from '@emotion/styled';
2
+
3
+ import { sizeStyles, WithSize } from '@os-design/styles';
4
+ import { omitEmotionProps } from '@os-design/utils';
5
+ import React, { forwardRef } from 'react';
6
+
7
+ import Skeleton, { SkeletonProps } from '../Skeleton';
8
+
9
+ export interface RadioGroupSkeletonProps extends SkeletonProps, WithSize {
10
+ /**
11
+ * The width of the skeleton.
12
+ * @default 10em
13
+ */
14
+ width?: string;
15
+ }
16
+
17
+ const StyledRadioGroupSkeleton = styled(
18
+ Skeleton,
19
+ omitEmotionProps('size')
20
+ )<WithSize>`
21
+ height: calc(${(p) => p.theme.baseHeight}em + 2px);
22
+ ${sizeStyles};
23
+ `;
24
+
25
+ /**
26
+ * Provides a radio group placeholder while a user waits for the content to load.
27
+ */
28
+ const RadioGroupSkeleton = forwardRef<HTMLDivElement, RadioGroupSkeletonProps>(
29
+ ({ width = '10em', ...rest }, ref) => (
30
+ <StyledRadioGroupSkeleton width={width} {...rest} ref={ref} />
31
+ )
32
+ );
33
+
34
+ RadioGroupSkeleton.displayName = 'RadioGroupSkeleton';
35
+
36
+ export default RadioGroupSkeleton;
@@ -0,0 +1,109 @@
1
+ import styled from '@emotion/styled';
2
+ import { m } from '@os-design/media';
3
+ import { sizeStyles, WithSize } from '@os-design/styles';
4
+ import { clr } from '@os-design/theming';
5
+ import { omitEmotionProps } from '@os-design/utils';
6
+ import React, { forwardRef } from 'react';
7
+
8
+ type JsxDivProps = Omit<JSX.IntrinsicElements['div'], 'ref'>;
9
+ export interface ResultProps extends JsxDivProps, WithSize {
10
+ /**
11
+ * The title of the result.
12
+ */
13
+ title: string;
14
+ /**
15
+ * The description that is under the title.
16
+ * @default undefined
17
+ */
18
+ description?: string;
19
+ /**
20
+ * The icon that is located above the title.
21
+ * @default undefined
22
+ */
23
+ icon?: React.ReactElement;
24
+ /**
25
+ * Active elements.
26
+ * @default undefined
27
+ */
28
+ actions?: React.ReactNode;
29
+ }
30
+
31
+ const Container = styled('div', omitEmotionProps('size'))<WithSize>`
32
+ display: flex;
33
+ flex-direction: column;
34
+ align-items: center;
35
+
36
+ color: ${(p) => clr(p.theme.colorText)};
37
+ padding: 2.6em 0;
38
+
39
+ ${sizeStyles};
40
+ `;
41
+
42
+ const IconContainer = styled.div`
43
+ font-size: 6em;
44
+ line-height: 1;
45
+ color: ${(p) => clr(p.theme.resultColorIcon)};
46
+ margin-bottom: 0.1em;
47
+ `;
48
+
49
+ const Text = styled.div`
50
+ text-align: center;
51
+ max-width: 28em;
52
+ `;
53
+
54
+ const Title = styled(Text)`
55
+ font-size: ${(p) => p.theme.sizes.large}em;
56
+ font-weight: 500;
57
+ `;
58
+
59
+ const Description = styled(Text)`
60
+ font-size: ${(p) => p.theme.sizes.small}em;
61
+ color: ${(p) => clr(p.theme.resultColorDescription)};
62
+ margin-top: 0.5em;
63
+ `;
64
+
65
+ const ActiveElements = styled.div`
66
+ margin-top: 2em;
67
+
68
+ display: flex;
69
+ flex-direction: column;
70
+ justify-content: center;
71
+ align-items: center;
72
+
73
+ & > *:not(:first-of-type) {
74
+ margin-top: 0.5em;
75
+ }
76
+
77
+ ${m.min.sm} {
78
+ flex-direction: row;
79
+
80
+ & > *:not(:first-of-type) {
81
+ margin-top: 0;
82
+ margin-left: 0.5em;
83
+ }
84
+ }
85
+ `;
86
+
87
+ const ChildrenContainer = styled.div`
88
+ margin-top: 2em;
89
+ `;
90
+
91
+ /**
92
+ * Used to give the user feedback instead of results.
93
+ * For example, error happened, results not found, no results yet.
94
+ */
95
+ const Result = forwardRef<HTMLDivElement, ResultProps>(
96
+ ({ title, description, icon, actions, children, ...rest }, ref) => (
97
+ <Container {...rest} ref={ref}>
98
+ {icon && <IconContainer>{icon}</IconContainer>}
99
+ <Title>{title}</Title>
100
+ {description && <Description>{description}</Description>}
101
+ {actions && <ActiveElements>{actions}</ActiveElements>}
102
+ {children && <ChildrenContainer>{children}</ChildrenContainer>}
103
+ </Container>
104
+ )
105
+ );
106
+
107
+ Result.displayName = 'Result';
108
+
109
+ export default Result;
@@ -0,0 +1,159 @@
1
+ import { css, keyframes } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import { Down, Up } from '@os-design/icons';
4
+ import Portal from '@os-design/portal';
5
+ import { clr, ThemeOverrider, useTheme } from '@os-design/theming';
6
+ import { omitEmotionProps, useClosable } from '@os-design/utils';
7
+
8
+ import React, {
9
+ forwardRef,
10
+ MouseEventHandler,
11
+ RefObject,
12
+ useCallback,
13
+ } from 'react';
14
+ import Button, { ButtonProps } from '../Button';
15
+ import useContainerPosition, {
16
+ ContainerPosition,
17
+ } from './utils/useContainerPosition';
18
+ import useVisibility from './utils/useVisibility';
19
+
20
+ export interface ScrollButtonProps extends Omit<ButtonProps, 'type' | 'wide'> {
21
+ /**
22
+ * The container that needs to be scrolled.
23
+ * @default undefined
24
+ */
25
+ container?: Element | RefObject<Element>;
26
+ /**
27
+ * Where the container should be scrolled.
28
+ * @default top
29
+ */
30
+ scrollTo?: 'top' | 'bottom';
31
+ /**
32
+ * The min scroll offset when the button is visible.
33
+ * @default 500
34
+ */
35
+ minOffset?: number;
36
+ }
37
+
38
+ const fadeIn = keyframes`
39
+ from { opacity: 0; }
40
+ to { opacity: 1; }
41
+ `;
42
+
43
+ const fadeOut = keyframes`
44
+ from { opacity: 1; }
45
+ to { opacity: 0; }
46
+ `;
47
+
48
+ const visibleStyles = (p) =>
49
+ p.visible &&
50
+ css`
51
+ animation: ${fadeIn} ${p.theme.transitionDelay}ms forwards;
52
+ `;
53
+
54
+ const invisibleStyles = (p) =>
55
+ !p.visible &&
56
+ css`
57
+ animation: ${fadeOut} ${p.theme.transitionDelay}ms forwards;
58
+ `;
59
+
60
+ interface StyledButtonProps {
61
+ visible: boolean;
62
+ containerPosition: ContainerPosition;
63
+ }
64
+ const StyledButton = styled(
65
+ Button,
66
+ omitEmotionProps('visible', 'containerPosition')
67
+ )<StyledButtonProps>`
68
+ position: fixed;
69
+ right: ${(p) =>
70
+ p.containerPosition.right > 0
71
+ ? `calc(${p.containerPosition.right}px + ${p.theme.scrollButtonMargin}em)`
72
+ : `${p.theme.scrollButtonMargin}em`};
73
+ bottom: ${(p) =>
74
+ `calc(${
75
+ p.containerPosition.bottom > 0 ? `${p.containerPosition.bottom}px + ` : ''
76
+ }${p.theme.scrollButtonMargin}em + env(safe-area-inset-bottom))`};
77
+ box-shadow: 0 0.15em 0.8em ${(p) => clr(p.theme.scrollButtonColorBoxShadow)};
78
+
79
+ ${visibleStyles};
80
+ ${invisibleStyles};
81
+ `;
82
+
83
+ /**
84
+ * The button to scroll to either the top or bottom of the container.
85
+ */
86
+ const ScrollButton = forwardRef<HTMLButtonElement, ScrollButtonProps>(
87
+ (
88
+ {
89
+ container,
90
+ scrollTo = 'top',
91
+ minOffset = 500,
92
+ onClick = () => {},
93
+ ...rest
94
+ },
95
+ ref
96
+ ) => {
97
+ const visible = useVisibility({ container, scrollTo, minOffset });
98
+ const containerPosition = useContainerPosition(container);
99
+ const { theme } = useTheme();
100
+ const mounted = useClosable(visible, theme.transitionDelay);
101
+
102
+ // Scroll through the container when the user clicks the button
103
+ const clickHandler = useCallback<MouseEventHandler<HTMLButtonElement>>(
104
+ (e) => {
105
+ // Scroll the window if the container is not defined
106
+ if (!container) {
107
+ window.scrollTo({
108
+ top: scrollTo === 'top' ? 0 : document.body.scrollHeight,
109
+ });
110
+ return;
111
+ }
112
+
113
+ // Otherwise scroll the container
114
+ const containerElement =
115
+ container instanceof Element ? container : container.current;
116
+ if (!containerElement) return;
117
+
118
+ containerElement.scrollTo({
119
+ top: scrollTo === 'top' ? 0 : containerElement.scrollHeight,
120
+ });
121
+
122
+ // Call the passed onClick handler
123
+ onClick(e);
124
+ },
125
+ [container, scrollTo, onClick]
126
+ );
127
+
128
+ if (!mounted) return null;
129
+
130
+ return (
131
+ <Portal container={container}>
132
+ <ThemeOverrider
133
+ overrides={(t) => ({
134
+ buttonPrimaryColorBg: t.scrollButtonColorBg,
135
+ buttonPrimaryColorText: t.scrollButtonColorText,
136
+ buttonPrimaryColorBgHover: t.scrollButtonColorBgHover,
137
+ })}
138
+ >
139
+ <StyledButton
140
+ visible={visible}
141
+ containerPosition={containerPosition}
142
+ wide='never'
143
+ size='small'
144
+ onClick={clickHandler}
145
+ aria-label={`Scroll to ${scrollTo}`}
146
+ {...rest}
147
+ ref={ref}
148
+ >
149
+ {scrollTo === 'top' ? <Up /> : <Down />}
150
+ </StyledButton>
151
+ </ThemeOverrider>
152
+ </Portal>
153
+ );
154
+ }
155
+ );
156
+
157
+ ScrollButton.displayName = 'ScrollButton';
158
+
159
+ export default ScrollButton;
@@ -0,0 +1,41 @@
1
+ import { useBrowserLayoutEffect, useResizeObserver } from '@os-design/utils';
2
+ import { RefObject, useCallback, useState } from 'react';
3
+
4
+ export interface ContainerPosition {
5
+ right: number;
6
+ bottom: number;
7
+ }
8
+
9
+ /**
10
+ * Calculates the position of the container.
11
+ */
12
+ const useContainerPosition = (
13
+ container?: Element | RefObject<Element>
14
+ ): ContainerPosition => {
15
+ const [position, setPosition] = useState<ContainerPosition>({
16
+ right: 0,
17
+ bottom: 0,
18
+ });
19
+
20
+ const updatePosition = useCallback(() => {
21
+ if (!container) return;
22
+ const element =
23
+ container instanceof Element ? container : container.current;
24
+ if (!element) return;
25
+
26
+ const { right, bottom } = element.getBoundingClientRect();
27
+ const { innerWidth, innerHeight } = window;
28
+
29
+ setPosition({
30
+ right: innerWidth - right,
31
+ bottom: innerHeight - bottom,
32
+ });
33
+ }, [container]);
34
+
35
+ useBrowserLayoutEffect(() => updatePosition(), [updatePosition]);
36
+ useResizeObserver(container as never, updatePosition);
37
+
38
+ return position;
39
+ };
40
+
41
+ export default useContainerPosition;
@@ -0,0 +1,56 @@
1
+ import { useBrowserLayoutEffect, useEvent } from '@os-design/utils';
2
+ import { RefObject, useCallback, useState } from 'react';
3
+
4
+ interface UseVisibilityProps {
5
+ container?: Element | RefObject<Element>;
6
+ scrollTo: 'top' | 'bottom';
7
+ minOffset: number;
8
+ }
9
+
10
+ /**
11
+ * Controls the visibility of the button.
12
+ */
13
+ const useVisibility = ({
14
+ container,
15
+ scrollTo,
16
+ minOffset,
17
+ }: UseVisibilityProps): boolean => {
18
+ const [visible, setVisible] = useState(false);
19
+
20
+ // Update the visibility of the button when the user scrolls the container
21
+ const updateVisibility = useCallback(() => {
22
+ let offset = 0;
23
+
24
+ if (!container) {
25
+ offset =
26
+ scrollTo === 'top'
27
+ ? window.scrollY
28
+ : document.body.scrollHeight - window.scrollY - window.innerHeight;
29
+ } else {
30
+ const containerElement =
31
+ container instanceof Element ? container : container.current;
32
+ if (containerElement === null) return;
33
+
34
+ offset =
35
+ scrollTo === 'top'
36
+ ? containerElement.scrollTop
37
+ : containerElement.scrollHeight -
38
+ containerElement.scrollTop -
39
+ containerElement.clientHeight;
40
+ }
41
+
42
+ setVisible(offset >= minOffset);
43
+ }, [container, scrollTo, minOffset]);
44
+
45
+ useBrowserLayoutEffect(() => updateVisibility(), [updateVisibility]);
46
+ useEvent(
47
+ container ||
48
+ ((typeof window !== 'undefined' ? window : undefined) as EventTarget),
49
+ 'scroll',
50
+ updateVisibility
51
+ );
52
+
53
+ return visible;
54
+ };
55
+
56
+ export default useVisibility;