@vitus-labs/elements 0.22.0 → 0.23.0-alpha.2

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,8 +1,8 @@
1
1
  import { makeItResponsive, alignContent, extendCss, value } from '@vitus-labs/unistyle';
2
2
  export { Provider } from '@vitus-labs/unistyle';
3
- import React, { forwardRef, memo, useMemo, createRef, Children, useState, useEffect, createContext, useContext, useRef, useCallback } from 'react';
3
+ import React, { forwardRef, memo, useMemo, createRef, useCallback, Children, useState, useEffect, createContext, useContext, useRef } from 'react';
4
4
  import { config, renderContent, get, isEmpty, pick, omit, context as context$1, throttle } from '@vitus-labs/core';
5
- import ReactDOM from 'react-dom';
5
+ import { createPortal } from 'react-dom';
6
6
 
7
7
  // eslint-disable-next-line import/prefer-default-export
8
8
  const PKG_NAME = '@vitus-labs/elements';
@@ -33,7 +33,7 @@ const styles$2 = ({ theme: t, css }) => css `
33
33
  `};
34
34
  `};
35
35
 
36
- ${t.contentAlignY === 'block' &&
36
+ ${t.alignY === 'block' &&
37
37
  css `
38
38
  height: 100%;
39
39
  `};
@@ -51,10 +51,7 @@ const styles$2 = ({ theme: t, css }) => css `
51
51
 
52
52
  ${t.extraStyles && extendCss(t.extraStyles)};
53
53
  `;
54
- const platformStyles = config.css `
55
- box-sizing: border-box;
56
- `
57
- ;
54
+ const platformStyles = 'box-sizing: border-box;' ;
58
55
  var Styled$2 = config.styled(config.component) `
59
56
  position: relative;
60
57
  ${platformStyles};
@@ -75,7 +72,7 @@ var Styled$2 = config.styled(config.component) `
75
72
  })};
76
73
  `;
77
74
 
78
- const component$7 = forwardRef(({ children, tag, block, extendCss, direction, alignX, alignY, equalCols, isInline, ...props }, ref) => {
75
+ const component$a = forwardRef(({ children, tag, block, extendCss, direction, alignX, alignY, equalCols, isInline, ...props }, ref) => {
79
76
  const debugProps = process.env.NODE_ENV !== 'production'
80
77
  ? {
81
78
  'data-vl-element': 'Element',
@@ -89,6 +86,8 @@ const component$7 = forwardRef(({ children, tag, block, extendCss, direction, al
89
86
  };
90
87
  const needsFix = !props.dangerouslySetInnerHTML && tag && isWebFixNeeded(tag)
91
88
  ;
89
+ // eslint-disable-next-line no-nested-ternary
90
+ const asTag = (isInline ? 'span' : 'div') ;
92
91
  if (!needsFix || false) {
93
92
  return (React.createElement(Styled$2, { ...COMMON_PROPS, "$element": {
94
93
  block,
@@ -103,7 +102,7 @@ const component$7 = forwardRef(({ children, tag, block, extendCss, direction, al
103
102
  block,
104
103
  extraStyles: extendCss,
105
104
  } },
106
- React.createElement(Styled$2, { as: isInline ? 'span' : 'div', "$childFix": true, "$element": {
105
+ React.createElement(Styled$2, { as: asTag, "$childFix": true, "$element": {
107
106
  direction,
108
107
  alignX,
109
108
  alignY,
@@ -181,7 +180,7 @@ var Styled$1 = config.styled(config.component) `
181
180
  })};
182
181
  `;
183
182
 
184
- const component$5 = ({ contentType, tag, parentDirection, direction, alignX, alignY, equalCols, gap, extendCss, ...props }) => {
183
+ const component$8 = ({ contentType, tag, parentDirection, direction, alignX, alignY, equalCols, gap, extendCss, ...props }) => {
185
184
  const debugProps = process.env.NODE_ENV !== 'production'
186
185
  ? {
187
186
  'data-vl-element': contentType,
@@ -197,7 +196,7 @@ const component$5 = ({ contentType, tag, parentDirection, direction, alignX, ali
197
196
  extraStyles: extendCss,
198
197
  }, ...debugProps, ...props }));
199
198
  };
200
- var component$6 = memo(component$5);
199
+ var component$9 = memo(component$8);
201
200
 
202
201
  const INLINE_ELEMENTS = {
203
202
  span: true,
@@ -253,35 +252,17 @@ const EMPTY_ELEMENTS = {
253
252
  const isInlineElement = (tag) => tag ? INLINE_ELEMENTS[tag] : false;
254
253
  const getShouldBeEmpty = (tag) => tag ? EMPTY_ELEMENTS[tag] : false;
255
254
 
256
- const defaultDirection = 'inline';
257
- const defaultContentDirection = 'rows';
255
+ const defaultBeforeAfterDirection = 'inline';
256
+ const defaultDirection = 'rows';
258
257
  const defaultAlignX = 'left';
259
258
  const defaultAlignY = 'center';
260
- const component$4 = forwardRef(({ innerRef, tag, label, content, children, beforeContent, afterContent, block, equalCols, gap, direction, alignX = defaultAlignX, alignY = defaultAlignY, css, contentCss, beforeContentCss, afterContentCss, contentDirection = defaultContentDirection, contentAlignX = defaultAlignX, contentAlignY = defaultAlignY, beforeContentDirection = defaultDirection, beforeContentAlignX = defaultAlignX, beforeContentAlignY = defaultAlignY, afterContentDirection = defaultDirection, afterContentAlignX = defaultAlignX, afterContentAlignY = defaultAlignY, ...props }, ref) => {
259
+ const component$7 = forwardRef(({ innerRef, tag, label, content, children, beforeContent, afterContent, block, equalCols, gap, direction = defaultDirection, alignX = defaultAlignX, alignY = defaultAlignY, css, contentCss, beforeContentCss, afterContentCss, contentDirection = defaultDirection, contentAlignX = defaultAlignX, contentAlignY = defaultAlignY, beforeContentDirection = defaultBeforeAfterDirection, beforeContentAlignX = defaultAlignX, beforeContentAlignY = defaultAlignY, afterContentDirection = defaultBeforeAfterDirection, afterContentAlignX = defaultAlignX, afterContentAlignY = defaultAlignY, ...props }, ref) => {
261
260
  // --------------------------------------------------------
262
261
  // check if should render only single element
263
262
  // --------------------------------------------------------
264
263
  const shouldBeEmpty = !!props.dangerouslySetInnerHTML ||
265
264
  (tag && getShouldBeEmpty(tag));
266
265
  // --------------------------------------------------------
267
- // common wrapper props
268
- // --------------------------------------------------------
269
- const WRAPPER_PROPS = {
270
- ref: ref || innerRef,
271
- extendCss: css,
272
- tag,
273
- block,
274
- contentDirection,
275
- alignX: contentAlignX,
276
- alignY: contentAlignY,
277
- as: undefined, // reset styled-components `as` prop
278
- };
279
- // --------------------------------------------------------
280
- // return simple/empty element like input
281
- // --------------------------------------------------------
282
- if (shouldBeEmpty)
283
- return React.createElement(component$7, { ...WRAPPER_PROPS, ...props });
284
- // --------------------------------------------------------
285
266
  // if not single element, calculate values
286
267
  // --------------------------------------------------------
287
268
  const isSimpleElement = !beforeContent && !afterContent;
@@ -291,8 +272,8 @@ const component$4 = forwardRef(({ innerRef, tag, label, content, children, befor
291
272
  // --------------------------------------------------------
292
273
  // direction & alignX & alignY calculations
293
274
  // --------------------------------------------------------
294
- const calculateDirection = useMemo(() => {
295
- let wrapperDirection;
275
+ const { wrapperDirection, wrapperAlignX, wrapperAlignY } = useMemo(() => {
276
+ let wrapperDirection = direction;
296
277
  let wrapperAlignX = alignX;
297
278
  let wrapperAlignY = alignY;
298
279
  if (isSimpleElement) {
@@ -315,21 +296,39 @@ const component$4 = forwardRef(({ innerRef, tag, label, content, children, befor
315
296
  contentDirection,
316
297
  contentAlignX,
317
298
  contentAlignY,
299
+ alignX,
300
+ alignY,
318
301
  direction,
319
302
  ]);
320
- const { wrapperDirection, wrapperAlignX, wrapperAlignY } = calculateDirection;
321
- const beforeContentRenderOutput = useMemo(() => renderContent(beforeContent), [beforeContent]);
322
- const afterContentRenderOutput = useMemo(() => renderContent(afterContent), [afterContent]);
323
- const contentRenderOutput = useMemo(() => renderContent(CHILDREN), [CHILDREN]);
324
- return (React.createElement(component$7, { ...props, ...WRAPPER_PROPS, isInline: isInline, direction: wrapperDirection, alignX: wrapperAlignX, alignY: wrapperAlignY },
325
- beforeContent && (React.createElement(component$6, { tag: SUB_TAG, contentType: "before", parentDirection: wrapperDirection, extendCss: beforeContentCss, direction: beforeContentDirection, alignX: beforeContentAlignX, alignY: beforeContentAlignY, equalCols: equalCols, gap: gap }, beforeContentRenderOutput)),
326
- isSimpleElement ? (contentRenderOutput) : (React.createElement(component$6, { tag: SUB_TAG, contentType: "content", parentDirection: wrapperDirection, extendCss: contentCss, direction: contentDirection, alignX: contentAlignX, alignY: contentAlignY, equalCols: equalCols }, contentRenderOutput)),
327
- afterContent && (React.createElement(component$6, { tag: SUB_TAG, contentType: "after", parentDirection: wrapperDirection, extendCss: afterContentCss, direction: afterContentDirection, alignX: afterContentAlignX, alignY: afterContentAlignY, equalCols: equalCols, gap: gap }, afterContentRenderOutput))));
303
+ // --------------------------------------------------------
304
+ // common wrapper props
305
+ // --------------------------------------------------------
306
+ const WRAPPER_PROPS = {
307
+ ref: ref || innerRef,
308
+ extendCss: css,
309
+ tag,
310
+ block,
311
+ direction: wrapperDirection,
312
+ alignX: wrapperAlignX,
313
+ alignY: wrapperAlignY,
314
+ as: undefined, // reset styled-components `as` prop
315
+ };
316
+ // --------------------------------------------------------
317
+ // return simple/empty element like input or image etc.
318
+ // --------------------------------------------------------
319
+ if (shouldBeEmpty) {
320
+ return React.createElement(component$a, { ...props, ...WRAPPER_PROPS });
321
+ }
322
+ const contentRenderOutput = renderContent(CHILDREN);
323
+ return (React.createElement(component$a, { ...props, ...WRAPPER_PROPS, isInline: isInline },
324
+ beforeContent && (React.createElement(component$9, { tag: SUB_TAG, contentType: "before", parentDirection: wrapperDirection, extendCss: beforeContentCss, direction: beforeContentDirection, alignX: beforeContentAlignX, alignY: beforeContentAlignY, equalCols: equalCols, gap: gap }, renderContent(beforeContent))),
325
+ isSimpleElement ? (contentRenderOutput) : (React.createElement(component$9, { tag: SUB_TAG, contentType: "content", parentDirection: wrapperDirection, extendCss: contentCss, direction: contentDirection, alignX: contentAlignX, alignY: contentAlignY, equalCols: equalCols }, contentRenderOutput)),
326
+ afterContent && (React.createElement(component$9, { tag: SUB_TAG, contentType: "after", parentDirection: wrapperDirection, extendCss: afterContentCss, direction: afterContentDirection, alignX: afterContentAlignX, alignY: afterContentAlignY, equalCols: equalCols, gap: gap }, renderContent(afterContent)))));
328
327
  });
329
328
  const name$4 = `${PKG_NAME}/Element`;
330
- component$4.displayName = name$4;
331
- component$4.pkgName = PKG_NAME;
332
- component$4.VITUS_LABS__COMPONENT = name$4;
329
+ component$7.displayName = name$4;
330
+ component$7.pkgName = PKG_NAME;
331
+ component$7.VITUS_LABS__COMPONENT = name$4;
333
332
 
334
333
  /* eslint-disable no-param-reassign */
335
334
  const isNumber = (a, b) => Number.isInteger(a) && Number.isInteger(b);
@@ -394,15 +393,16 @@ const attachItemProps = ({ i, length, }) => {
394
393
  position,
395
394
  };
396
395
  };
397
- const component$3 = (props) => {
396
+ const component$6 = (props) => {
398
397
  const { itemKey, valueName, children, component, data, wrapComponent: Wrapper, wrapProps, itemProps, } = props;
399
- const renderedElement = (component, props) => renderContent(component, props);
400
- const injectItemProps = typeof itemProps === 'function'
401
- ? (props, extendedProps) => itemProps(props, extendedProps)
402
- : () => itemProps;
403
- const injectWrapItemProps = typeof wrapProps === 'function'
404
- ? (props, extendedProps) => wrapProps(props, extendedProps)
405
- : () => wrapProps;
398
+ const renderedElement = renderContent;
399
+ const injectItemProps = useMemo(() => (typeof itemProps === 'function' ? itemProps : () => itemProps), [itemProps]);
400
+ const injectWrapItemProps = useMemo(() => (typeof wrapProps === 'function' ? wrapProps : () => wrapProps), [wrapProps]);
401
+ const getKey = useCallback((item, index) => {
402
+ if (typeof itemKey === 'function')
403
+ return itemKey(item, index);
404
+ return index;
405
+ }, []);
406
406
  // --------------------------------------------------------
407
407
  // render children
408
408
  // --------------------------------------------------------
@@ -436,18 +436,11 @@ const component$3 = (props) => {
436
436
  // render array of strings or numbers
437
437
  // --------------------------------------------------------
438
438
  const renderSimpleArray = (data) => {
439
- const renderData = data.filter((item) => item !== null || item !== undefined // remove empty values
440
- );
441
- const { length } = renderData;
442
- // if it's empty
443
- if (renderData.length === 0)
439
+ const { length } = data;
440
+ // if the data array is empty
441
+ if (data.length === 0)
444
442
  return null;
445
- const getKey = (item, index) => {
446
- if (typeof itemKey === 'function')
447
- return itemKey(item, index);
448
- return index;
449
- };
450
- return renderData.map((item, i) => {
443
+ return data.map((item, i) => {
451
444
  const key = getKey(item, i);
452
445
  const keyName = valueName || 'children';
453
446
  const extendedProps = attachItemProps({
@@ -521,11 +514,11 @@ const component$3 = (props) => {
521
514
  // render props component + data
522
515
  // --------------------------------------------------------
523
516
  if (component && Array.isArray(data)) {
524
- const clearData = data.filter((item) => item !== null && item !== undefined);
525
- const isSimpleArray = clearData.every((item) => typeof item === 'string' || typeof item === 'number');
517
+ const clearData = useMemo(() => data.filter((item) => item !== null && item !== undefined), [data]);
518
+ const isSimpleArray = useMemo(() => clearData.every((item) => typeof item === 'string' || typeof item === 'number'), [clearData]);
526
519
  if (isSimpleArray)
527
520
  return renderSimpleArray(clearData);
528
- const isComplexArray = clearData.every((item) => typeof item === 'object');
521
+ const isComplexArray = useMemo(() => clearData.every((item) => typeof item === 'object'), [clearData]);
529
522
  if (isComplexArray)
530
523
  return renderComplexArray(clearData);
531
524
  return null;
@@ -538,19 +531,19 @@ const component$3 = (props) => {
538
531
  };
539
532
  return renderItems();
540
533
  };
541
- component$3.isIterator = true;
542
- component$3.RESERVED_PROPS = RESERVED_PROPS;
534
+ component$6.isIterator = true;
535
+ component$6.RESERVED_PROPS = RESERVED_PROPS;
543
536
 
544
- const Component$2 = forwardRef(({ rootElement = false, ...props }, ref) => {
545
- const renderedList = React.createElement(component$3, { ...pick(props, component$3.RESERVED_PROPS) });
537
+ const component$5 = forwardRef(({ rootElement = false, ...props }, ref) => {
538
+ const renderedList = React.createElement(component$6, { ...pick(props, component$6.RESERVED_PROPS) });
546
539
  if (!rootElement)
547
540
  return renderedList;
548
- return (React.createElement(component$4, { ref: ref, ...omit(props, component$3.RESERVED_PROPS) }, renderedList));
541
+ return (React.createElement(component$7, { ref: ref, ...omit(props, component$6.RESERVED_PROPS) }, renderedList));
549
542
  });
550
543
  const name$3 = `${PKG_NAME}/List`;
551
- Component$2.displayName = name$3;
552
- Component$2.pkgName = PKG_NAME;
553
- Component$2.VITUS_LABS__COMPONENT = name$3;
544
+ component$5.displayName = name$3;
545
+ component$5.pkgName = PKG_NAME;
546
+ component$5.VITUS_LABS__COMPONENT = name$3;
554
547
 
555
548
  const RESERVED_KEYS = [
556
549
  'type',
@@ -558,7 +551,7 @@ const RESERVED_KEYS = [
558
551
  'itemProps',
559
552
  'activeItemRequired',
560
553
  ];
561
- const Component$1 = (WrappedComponent) => {
554
+ const component$4 = (WrappedComponent) => {
562
555
  const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
563
556
  const Enhanced = (props) => {
564
557
  const { type = 'single', activeItemRequired, activeItems, itemProps = {}, ...rest } = props;
@@ -677,11 +670,11 @@ const Component$1 = (WrappedComponent) => {
677
670
  return React.createElement(WrappedComponent, { ...rest, itemProps: attachItemProps });
678
671
  };
679
672
  Enhanced.RESERVED_KEYS = RESERVED_KEYS;
680
- Enhanced.displayName = `vitus-labs/elements/List/withActiveState(${displayName})`;
673
+ Enhanced.displayName = `@vitus-labs/elements/List/withActiveState(${displayName})`;
681
674
  return Enhanced;
682
675
  };
683
676
 
684
- const component$2 = ({ position = document.body , tag = 'div', children, }) => {
677
+ const component$3 = ({ position = document.body , tag = 'div', children, }) => {
685
678
  const [element] = useState(document.createElement(tag) );
686
679
  if (!position || !element)
687
680
  return null;
@@ -691,17 +684,17 @@ const component$2 = ({ position = document.body , tag = 'div', children, }) => {
691
684
  position.removeChild(element);
692
685
  };
693
686
  }, []);
694
- return ReactDOM.createPortal(children, element);
687
+ return createPortal(children, element);
695
688
  };
696
689
  const name$2 = `${PKG_NAME}/Portal`;
697
- component$2.displayName = name$2;
698
- component$2.pkgName = PKG_NAME;
699
- component$2.VITUS_LABS__COMPONENT = name$2;
690
+ component$3.displayName = name$2;
691
+ component$3.pkgName = PKG_NAME;
692
+ component$3.VITUS_LABS__COMPONENT = name$2;
700
693
 
701
694
  const context = createContext({});
702
695
  const { Provider } = context;
703
696
  const useOverlayContext = () => useContext(context);
704
- const component$1 = ({ children, blocked, setBlocked, setUnblocked, }) => (React.createElement(Provider, { value: { blocked, setBlocked, setUnblocked } }, children));
697
+ const component$2 = ({ children, blocked, setBlocked, setUnblocked, }) => (React.createElement(Provider, { value: { blocked, setBlocked, setUnblocked } }, children));
705
698
 
706
699
  var useOverlay = ({ isOpen = false, openOn = 'click', // click | hover
707
700
  closeOn = 'click', // click | 'clickOnTrigger' | 'clickOutsideContent' | hover | manual
@@ -710,11 +703,11 @@ align = 'bottom', // * main align prop * top | left | bottom | right
710
703
  position = 'fixed', // absolute | fixed | relative | static
711
704
  alignX = 'left', // left | center | right
712
705
  alignY = 'bottom', // top | center | bottom
713
- offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc = true, disabled, }) => {
706
+ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc = true, disabled, onOpen, onClose, }) => {
714
707
  const { rootSize } = useContext(context$1);
715
708
  const ctx = useOverlayContext();
716
709
  const [blocked, handleBlocked] = useState(false);
717
- const [visible, setVisible] = useState(isOpen);
710
+ const [active, handleActive] = useState(isOpen);
718
711
  const [innerAlign, setInnerAlign] = useState(align);
719
712
  const [innerAlignX, setInnerAlignX] = useState(alignX);
720
713
  const [innerAlignY, setInnerAlignY] = useState(alignY);
@@ -722,116 +715,126 @@ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc
722
715
  const contentRef = useRef();
723
716
  const setBlocked = useCallback(() => handleBlocked(true), []);
724
717
  const setUnblocked = useCallback(() => handleBlocked(false), []);
718
+ const showContent = useCallback(() => {
719
+ handleActive(true);
720
+ }, []);
721
+ const hideContent = useCallback(() => {
722
+ handleActive(false);
723
+ }, []);
724
+ const hasCustomListener = !!customScrollListener;
725
725
  // if an Overlay has an Overlay child, this will prevent closing parent child
726
+ // + calculate correct position when an Overlay is opened
726
727
  useEffect(() => {
727
- if (visible && ctx?.setBlocked)
728
- ctx.setBlocked();
729
- else if (!visible && ctx?.setUnblocked)
730
- ctx.setUnblocked();
731
- }, [visible]);
732
- // calculate correct position when an Overlay is opened
733
- useEffect(() => {
734
- if (visible)
728
+ if (active) {
735
729
  calculateContentPosition();
736
- }, [visible]);
737
- // handles calculationg correct position of content
730
+ if (ctx?.setBlocked)
731
+ ctx.setBlocked();
732
+ if (onOpen)
733
+ onOpen();
734
+ }
735
+ else {
736
+ if (ctx?.setUnblocked)
737
+ ctx.setUnblocked();
738
+ if (onClose)
739
+ onClose();
740
+ }
741
+ }, [active]);
742
+ // handles calculating correct position of content
738
743
  // on document events (or custom scroll if set)
739
744
  useEffect(() => {
740
- if (visible) {
741
- window.addEventListener('resize', handleContentPosition, false);
742
- window.addEventListener('scroll', handleContentPosition, false);
743
- if (customScrollListener) {
744
- customScrollListener.addEventListener('scroll', handleContentPosition, false);
745
- }
745
+ if (!active)
746
+ return undefined;
747
+ window.addEventListener('resize', handleContentPosition, false);
748
+ window.addEventListener('scroll', handleContentPosition, false);
749
+ if (hasCustomListener) {
750
+ customScrollListener.addEventListener('scroll', handleContentPosition, false);
746
751
  }
747
752
  return () => {
748
753
  window.removeEventListener('resize', handleContentPosition, false);
749
754
  window.removeEventListener('scroll', handleContentPosition, false);
750
- if (customScrollListener) {
755
+ if (hasCustomListener) {
751
756
  customScrollListener.removeEventListener('scroll', handleContentPosition, false);
752
757
  }
753
758
  };
754
- }, [visible, customScrollListener]);
759
+ }, [active, customScrollListener]);
755
760
  // make sure scrolling is blocked in case of modal windows or when
756
761
  // customScroll is set
757
762
  useEffect(() => {
758
- if (visible) {
759
- if (customScrollListener) {
763
+ const shouldSetOverflow = type === 'modal' && document.body;
764
+ if (active) {
765
+ if (hasCustomListener) {
760
766
  // eslint-disable-next-line no-param-reassign
761
767
  customScrollListener.style.overflow = 'hidden';
762
768
  }
763
- else if (type === 'modal' && document.body) {
769
+ if (shouldSetOverflow) {
764
770
  document.body.style.overflow = 'hidden';
765
771
  }
766
772
  }
767
773
  return () => {
768
- if (customScrollListener) {
774
+ if (hasCustomListener) {
769
775
  // eslint-disable-next-line no-param-reassign
770
776
  customScrollListener.style.overflow = '';
771
777
  }
772
- else if (type === 'modal' && document.body) {
778
+ if (shouldSetOverflow) {
773
779
  document.body.style.overflow = '';
774
780
  }
775
781
  };
776
- }, [visible, type, customScrollListener]);
782
+ }, [active, type, customScrollListener]);
783
+ // only when content is active handle closing
777
784
  useEffect(() => {
778
- // enable overlay manipulation only when the state is NOT blocked=true
779
- // nor in disabled state
780
- if (!blocked || !disabled) {
781
- if (openOn === 'click' ||
782
- closeOn === 'click' ||
783
- closeOn === 'clickOnTrigger' ||
784
- closeOn === 'clickOutsideContent') {
785
- window.addEventListener('click', handleVisibilityByEventType, false);
786
- }
787
- if (openOn === 'hover' || closeOn === 'hover') {
788
- window.addEventListener('mousemove', handleMouseMove, false);
789
- }
790
- // only when content is visible
791
- if (visible) {
792
- if (customScrollListener) {
793
- customScrollListener.addEventListener('scroll', handleMouseMove, false);
794
- }
795
- window.addEventListener('scroll', handleMouseMove, false);
796
- if (closeOnEsc) {
797
- window.addEventListener('keydown', handleEscKey);
798
- }
799
- }
785
+ if (!active)
786
+ return undefined;
787
+ window.addEventListener('scroll', handleVisibility, false);
788
+ if (hasCustomListener) {
789
+ customScrollListener.addEventListener('scroll', handleVisibility, false);
790
+ }
791
+ if (closeOnEsc) {
792
+ window.addEventListener('keydown', handleEscKey, false);
800
793
  }
801
794
  return () => {
802
- window.removeEventListener('scroll', handleMouseMove, false);
803
- window.removeEventListener('click', handleVisibilityByEventType, false);
804
- window.removeEventListener('mousemove', handleMouseMove, false);
805
- if (closeOnEsc) {
806
- window.removeEventListener('keydown', handleEscKey);
795
+ window.removeEventListener('scroll', handleVisibility, false);
796
+ if (hasCustomListener) {
797
+ customScrollListener.removeEventListener('scroll', handleVisibility, false);
807
798
  }
808
- if (customScrollListener) {
809
- customScrollListener.removeEventListener('scroll', handleMouseMove, false);
799
+ if (closeOnEsc) {
800
+ window.removeEventListener('keydown', handleEscKey, false);
810
801
  }
811
802
  };
812
- }, [openOn, closeOn, visible, blocked, disabled]);
813
- const observeTrigger = (e) => {
814
- if (e && e.target && triggerRef.current) {
815
- return (triggerRef.current.contains(e.target) || e.target === triggerRef.current);
803
+ }, [active, customScrollListener]);
804
+ useEffect(() => {
805
+ // enable overlay manipulation only when the state is NOT blocked=true
806
+ // nor in disabled state
807
+ if (blocked || disabled)
808
+ return undefined;
809
+ if (openOn === 'click' ||
810
+ closeOn === 'click' ||
811
+ closeOn === 'clickOnTrigger' ||
812
+ closeOn === 'clickOutsideContent') {
813
+ window.addEventListener('click', handleClick, false);
816
814
  }
817
- return false;
818
- };
819
- const observeContent = (e) => {
820
- if (e && e.target && contentRef.current) {
821
- return (contentRef.current.contains(e.target) || e.target === contentRef.current);
815
+ if (openOn === 'hover' || closeOn === 'hover') {
816
+ window.addEventListener('mousemove', handleVisibility, false);
817
+ }
818
+ return () => {
819
+ window.removeEventListener('click', handleClick, false);
820
+ window.removeEventListener('mousemove', handleVisibility, false);
821
+ };
822
+ }, [openOn, closeOn, blocked, disabled]);
823
+ const isNodeOrChild = (ref) => (e) => {
824
+ if (e && e.target && ref.current) {
825
+ return ref.current.contains(e.target) || e.target === ref.current;
822
826
  }
823
827
  return false;
824
828
  };
825
- const showContent = useCallback(() => {
826
- setVisible(true);
827
- }, []);
828
- const hideContent = useCallback(() => {
829
- setVisible(false);
830
- }, []);
829
+ const isTrigger = isNodeOrChild(triggerRef);
830
+ const isContent = isNodeOrChild(contentRef);
831
831
  const calculateContentPosition = () => {
832
- if (!visible)
832
+ if (!active)
833
833
  return;
834
834
  if (!triggerRef.current || !contentRef.current) {
835
+ if (process.env.NODE_ENV === 'development') {
836
+ console.warn('Cannot access `ref` of trigger or content component.');
837
+ }
835
838
  return;
836
839
  }
837
840
  const triggerDimensions = triggerRef.current.getBoundingClientRect();
@@ -952,21 +955,17 @@ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc
952
955
  contentRef.current.style.right = value([overlayPosition.right], rootSize);
953
956
  };
954
957
  const handleVisibilityByEventType = (e) => {
955
- if (!visible && !disabled) {
956
- if (openOn === 'hover' && e.type === 'mousemove') {
957
- if (observeTrigger(e)) {
958
- showContent();
959
- }
960
- }
961
- if (openOn === 'click' && e.type === 'click') {
962
- if (observeTrigger(e)) {
958
+ if (!active) {
959
+ if ((openOn === 'hover' && e.type === 'mousemove') ||
960
+ (openOn === 'click' && e.type === 'click')) {
961
+ if (isTrigger(e)) {
963
962
  showContent();
964
963
  }
965
964
  }
966
965
  }
967
- if (visible) {
966
+ if (active) {
968
967
  if (closeOn === 'hover' && e.type === 'mousemove') {
969
- if (!observeTrigger(e) && !observeContent(e)) {
968
+ if (!isTrigger(e) && !isContent(e)) {
970
969
  hideContent();
971
970
  }
972
971
  }
@@ -977,19 +976,20 @@ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc
977
976
  hideContent();
978
977
  }
979
978
  if (closeOn === 'clickOnTrigger' && e.type === 'click') {
980
- if (observeTrigger(e)) {
979
+ if (isTrigger(e)) {
981
980
  hideContent();
982
981
  }
983
982
  }
984
983
  if (closeOn === 'clickOutsideContent' && e.type === 'click') {
985
- if (!observeContent(e)) {
984
+ if (!isContent(e)) {
986
985
  hideContent();
987
986
  }
988
987
  }
989
988
  }
990
989
  };
991
990
  const handleContentPosition = throttle(calculateContentPosition, throttleDelay);
992
- const handleMouseMove = throttle(handleVisibilityByEventType, throttleDelay);
991
+ const handleClick = useCallback(handleVisibilityByEventType, []);
992
+ const handleVisibility = useCallback(throttle(handleVisibilityByEventType, throttleDelay), []);
993
993
  const handleEscKey = (e) => {
994
994
  if (e.key === 'Escape') {
995
995
  hideContent();
@@ -998,7 +998,7 @@ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc
998
998
  return {
999
999
  triggerRef,
1000
1000
  contentRef,
1001
- active: visible,
1001
+ active,
1002
1002
  align: innerAlign,
1003
1003
  alignX: innerAlignX,
1004
1004
  alignY: innerAlignY,
@@ -1010,19 +1010,20 @@ offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc
1010
1010
  };
1011
1011
  };
1012
1012
 
1013
- const Component = ({ children, trigger, DOMLocation, triggerRefName = 'ref', contentRefName = 'ref', ...props }) => {
1013
+ const component$1 = ({ children, trigger, DOMLocation, triggerRefName = 'ref', contentRefName = 'ref', ...props }) => {
1014
1014
  const { active, triggerRef, contentRef, showContent, hideContent, align, alignX, alignY, ...ctx } = useOverlay(props);
1015
- const passHandlers = useMemo(() => props.openOn === 'manual' ||
1016
- props.closeOn === 'manual' ||
1017
- props.closeOn === 'clickOutsideContent', [props.openOn, props.closeOn]);
1015
+ const { openOn, closeOn } = props;
1016
+ const passHandlers = useMemo(() => openOn === 'manual' ||
1017
+ closeOn === 'manual' ||
1018
+ closeOn === 'clickOutsideContent', [openOn, closeOn]);
1018
1019
  return (React.createElement(React.Fragment, null,
1019
1020
  renderContent(trigger, {
1020
1021
  [triggerRefName]: triggerRef,
1021
1022
  active,
1022
1023
  ...(passHandlers ? { showContent, hideContent } : {}),
1023
1024
  }),
1024
- active && (React.createElement(component$2, { position: DOMLocation },
1025
- React.createElement(component$1, { ...ctx }, renderContent(children, {
1025
+ active && (React.createElement(component$3, { position: DOMLocation },
1026
+ React.createElement(component$2, { ...ctx }, renderContent(children, {
1026
1027
  [contentRefName]: contentRef,
1027
1028
  active,
1028
1029
  align,
@@ -1031,10 +1032,10 @@ const Component = ({ children, trigger, DOMLocation, triggerRefName = 'ref', con
1031
1032
  ...(passHandlers ? { showContent, hideContent } : {}),
1032
1033
  }))))));
1033
1034
  };
1034
- const name$1 = `${PKG_NAME}/Ovelay`;
1035
- Component.displayName = name$1;
1036
- Component.pkgName = PKG_NAME;
1037
- Component.VITUS_LABS__COMPONENT = name$1;
1035
+ const name$1 = `${PKG_NAME}/Overlay`;
1036
+ component$1.displayName = name$1;
1037
+ component$1.pkgName = PKG_NAME;
1038
+ component$1.VITUS_LABS__COMPONENT = name$1;
1038
1039
 
1039
1040
  const styles = ({ css, theme: t }) => css `
1040
1041
  ${t.extraStyles && extendCss(t.extraStyles)};
@@ -1064,5 +1065,5 @@ component.pkgName = PKG_NAME;
1064
1065
  component.VITUS_LABS__COMPONENT = name;
1065
1066
  component.isText = true;
1066
1067
 
1067
- export { component$4 as Element, Component$2 as List, Component as Overlay, component$2 as Portal, component as Text, useOverlay, Component$1 as withActiveState, withEqualBeforeAfter as withEqualSizeBeforeAfter };
1068
+ export { component$7 as Element, component$5 as List, component$1 as Overlay, component$3 as Portal, component as Text, useOverlay, component$4 as withActiveState, withEqualBeforeAfter as withEqualSizeBeforeAfter };
1068
1069
  //# sourceMappingURL=vitus-labs-elements.browser.js.map