@vitus-labs/elements 0.41.0 → 0.44.0

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.
@@ -155,7 +155,7 @@
155
155
  ${({ $contentType }) => calculateGap({
156
156
  direction: t.parentDirection,
157
157
  type: $contentType,
158
- value: unistyle.value([t.gap], rootSize),
158
+ value: unistyle.value(t.gap, rootSize),
159
159
  css,
160
160
  })}
161
161
  `};
@@ -713,8 +713,8 @@
713
713
  var useOverlay = ({ isOpen = false, openOn = 'click', // click | hover
714
714
  closeOn = 'click', // click | 'clickOnTrigger' | 'clickOutsideContent' | hover | manual
715
715
  type = 'dropdown', // dropdown | tooltip | popover | modal
716
- align = 'bottom', // * main align prop * top | left | bottom | right
717
716
  position = 'fixed', // absolute | fixed | relative | static
717
+ align = 'bottom', // * main align prop * top | left | bottom | right
718
718
  alignX = 'left', // left | center | right
719
719
  alignY = 'bottom', // top | center | bottom
720
720
  offsetX = 0, offsetY = 0, throttleDelay = 200, customScrollListener, closeOnEsc = true, disabled, onOpen, onClose, }) => {
@@ -722,9 +722,6 @@
722
722
  const ctx = useOverlayContext();
723
723
  const [blocked, handleBlocked] = React.useState(false);
724
724
  const [active, handleActive] = React.useState(isOpen);
725
- const [innerAlign, setInnerAlign] = React.useState(align);
726
- const [innerAlignX, setInnerAlignX] = React.useState(alignX);
727
- const [innerAlignY, setInnerAlignY] = React.useState(alignY);
728
725
  const triggerRef = React.useRef();
729
726
  const contentRef = React.useRef();
730
727
  const setBlocked = React.useCallback(() => handleBlocked(true), []);
@@ -735,39 +732,36 @@
735
732
  const hideContent = React.useCallback(() => {
736
733
  handleActive(false);
737
734
  }, []);
738
- React.useEffect(() => {
739
- if (active) {
740
- if (onOpen)
741
- onOpen();
742
- }
743
- else {
744
- if (onClose)
745
- onClose();
746
- }
747
- }, [active, onOpen, onClose]);
748
735
  React.useEffect(() => {
749
736
  if (disabled) {
750
737
  hideContent();
751
738
  }
752
739
  }, [disabled]);
740
+ // calculate position on every position change state
741
+ React.useEffect(() => {
742
+ if (active) {
743
+ // hack-ish way to correctly calculate position for the first time
744
+ // without calling it twice the posittion is somehow wrong
745
+ calculateContentPosition();
746
+ calculateContentPosition();
747
+ }
748
+ }, [active, align, alignX, alignX]);
753
749
  // if an Overlay has an Overlay child, this will prevent closing parent child
754
750
  // + calculate correct position when an Overlay is opened
755
751
  React.useEffect(() => {
756
752
  if (active) {
753
+ if (onOpen)
754
+ onOpen();
757
755
  if (ctx?.setBlocked)
758
756
  ctx.setBlocked();
759
757
  }
760
758
  else {
759
+ if (onClose)
760
+ onClose();
761
761
  if (ctx?.setUnblocked)
762
762
  ctx.setUnblocked();
763
763
  }
764
- }, [active, ctx]);
765
- // calculate position on every position change state
766
- React.useEffect(() => {
767
- if (active) {
768
- calculateContentPosition();
769
- }
770
- }, [active, innerAlign, innerAlignX, innerAlignY]);
764
+ }, [active, onOpen, onClose]);
771
765
  // handles calculating correct position of content
772
766
  // on document events (or custom scroll if set)
773
767
  React.useEffect(() => {
@@ -865,88 +859,105 @@
865
859
  }
866
860
  return;
867
861
  }
868
- const triggerDimensions = triggerRef.current.getBoundingClientRect();
869
- const contentDimensions = contentRef.current.getBoundingClientRect();
870
862
  const overlayPosition = {
871
863
  position,
872
864
  };
865
+ const t = triggerRef.current.getBoundingClientRect();
866
+ const c = contentRef.current.getBoundingClientRect();
873
867
  if (['dropdown', 'tooltip', 'popover'].includes(type)) {
868
+ // align is top or bottom
874
869
  if (['top', 'bottom'].includes(align)) {
875
- const positionTop = triggerDimensions.top - offsetY - contentDimensions.height;
876
- const positionBottom = triggerDimensions.bottom + offsetY;
877
- const positionLeft = triggerDimensions.left - offsetX;
878
- const positionRight = triggerDimensions.right + offsetX - contentDimensions.width;
870
+ // axe Y position
871
+ // (assigned as top position)
872
+ const top = t.top - offsetY - c.height;
873
+ const bottom = t.bottom + offsetY;
874
+ // axe X position
875
+ // content position to trigger position
876
+ // (assigned as left position)
877
+ const left = t.left + offsetX;
878
+ const right = t.right - offsetX - c.width;
879
+ // calculate possible position
880
+ const isTop = top >= 0; // represents window.height = 0
881
+ const isBottom = bottom + c.height <= window.innerHeight;
882
+ const isLeft = left + c.width <= window.innerWidth;
883
+ const isRight = right >= 0; // represents window.width = 0
879
884
  if (align === 'top') {
880
- const isTop = positionTop >= 0;
881
- setInnerAlign(isTop ? 'top' : 'bottom');
882
- overlayPosition.top = isTop ? positionTop : positionBottom;
885
+ overlayPosition.top = isTop ? top : bottom;
883
886
  }
884
- else {
885
- const isBottom = positionBottom + contentDimensions.height <= window.innerHeight;
886
- setInnerAlign(isBottom ? 'bottom' : 'top');
887
- overlayPosition.top = isBottom ? positionBottom : positionTop;
887
+ else if (align === 'bottom') {
888
+ overlayPosition.top = isBottom ? bottom : top;
889
+ }
890
+ // left
891
+ if (alignX === 'left') {
892
+ overlayPosition.left = isLeft ? left : right;
888
893
  }
889
- switch (alignX) {
890
- case 'right': {
891
- const isRight = positionRight >= 0;
892
- setInnerAlignX(isRight ? 'right' : 'left');
893
- overlayPosition.left = isRight ? positionRight : positionLeft;
894
- break;
894
+ // center
895
+ else if (alignX === 'center') {
896
+ const center = t.left + (t.right - t.left) / 2 - c.width / 2;
897
+ const isCenteredLeft = center >= 0;
898
+ const isCenteredRight = center + c.width <= window.innerWidth;
899
+ if (isCenteredLeft && isCenteredRight) {
900
+ overlayPosition.left = center;
895
901
  }
896
- case 'center': {
897
- overlayPosition.left =
898
- triggerDimensions.left +
899
- (triggerDimensions.right - triggerDimensions.left) / 2 -
900
- contentDimensions.width / 2;
901
- break;
902
+ else if (isCenteredLeft) {
903
+ overlayPosition.left = left;
902
904
  }
903
- case 'left':
904
- default: {
905
- const isLeft = positionLeft + contentDimensions.width <= window.innerWidth;
906
- setInnerAlignX(isLeft ? 'left' : 'right');
907
- overlayPosition.left = isLeft ? positionLeft : positionRight;
908
- break;
905
+ else if (isCenteredRight) {
906
+ overlayPosition.left = right;
909
907
  }
910
908
  }
909
+ // right
910
+ else if (alignX === 'right') {
911
+ overlayPosition.left = isRight ? right : left;
912
+ }
911
913
  }
914
+ // align is left or right
912
915
  else if (['left', 'right'].includes(align)) {
913
- const positionLeft = triggerDimensions.left - offsetX - contentDimensions.width;
914
- const positionRight = triggerDimensions.right + offsetX;
915
- const positionTop = triggerDimensions.top + offsetY;
916
- const positionBottom = triggerDimensions.bottom - offsetY - contentDimensions.height;
916
+ // axe X position
917
+ // (assigned as left position)
918
+ const left = t.left - offsetX - c.width;
919
+ const right = t.right + offsetX;
920
+ // axe Y position
921
+ // content position to trigger position
922
+ // (assigned as top position)
923
+ const top = t.top + offsetY;
924
+ const bottom = t.bottom - offsetY - c.height;
925
+ const isLeft = left >= 0;
926
+ const isRight = right + c.width <= window.innerWidth;
927
+ const isTop = top + c.height <= window.innerHeight;
928
+ const isBottom = bottom >= 0;
917
929
  if (align === 'left') {
918
- const isLeft = positionLeft >= 0;
919
- setInnerAlign(isLeft ? 'left' : 'right');
920
- overlayPosition.left = isLeft ? positionLeft : positionRight;
930
+ overlayPosition.left = isLeft ? left : right;
921
931
  }
922
- else {
923
- const isRight = positionRight + contentDimensions.width <= window.innerWidth;
924
- setInnerAlign(isRight ? 'right' : 'left');
925
- overlayPosition.left = isRight ? positionRight : positionLeft;
932
+ else if (align === 'right') {
933
+ overlayPosition.left = isRight ? right : left;
934
+ }
935
+ // top
936
+ if (alignY === 'top') {
937
+ overlayPosition.top = isTop ? top : bottom;
926
938
  }
927
- switch (alignY) {
928
- case 'top': {
929
- const isTop = positionTop + contentDimensions.height <= window.innerHeight;
930
- setInnerAlignY(isTop ? 'top' : 'bottom');
931
- overlayPosition.top = isTop ? positionTop : positionBottom;
932
- break;
939
+ // center
940
+ else if (alignY === 'center') {
941
+ const center = t.top + (t.bottom - t.top) / 2 - c.height / 2;
942
+ const isCenteredTop = center >= 0;
943
+ const isCenteredBottom = center + c.height <= window.innerHeight;
944
+ if (isCenteredTop && isCenteredBottom) {
945
+ overlayPosition.top = center;
933
946
  }
934
- case 'center':
935
- overlayPosition.top =
936
- triggerDimensions.top -
937
- offsetY +
938
- (triggerDimensions.bottom - triggerDimensions.top) / 2 -
939
- contentDimensions.height / 2;
940
- break;
941
- case 'bottom':
942
- default: {
943
- const isBottom = positionBottom >= 0;
944
- setInnerAlignY(isBottom ? 'bottom' : 'top');
945
- overlayPosition.top = isBottom ? positionBottom : positionTop;
947
+ else if (isCenteredTop) {
948
+ overlayPosition.top = top;
946
949
  }
950
+ else if (isCenteredBottom) {
951
+ overlayPosition.top = bottom;
952
+ }
953
+ }
954
+ // bottom
955
+ else if (alignY === 'bottom') {
956
+ overlayPosition.top = isBottom ? bottom : top;
947
957
  }
948
958
  }
949
959
  }
960
+ // modal type
950
961
  else if (type === 'modal') {
951
962
  switch (alignX) {
952
963
  case 'right':
@@ -957,8 +968,7 @@
957
968
  break;
958
969
  case 'center':
959
970
  default:
960
- overlayPosition.left =
961
- window.innerWidth / 2 - contentDimensions.width / 2;
971
+ overlayPosition.left = window.innerWidth / 2 - c.width / 2;
962
972
  break;
963
973
  }
964
974
  switch (alignY) {
@@ -966,8 +976,7 @@
966
976
  overlayPosition.top = offsetY;
967
977
  break;
968
978
  case 'center':
969
- overlayPosition.top =
970
- window.innerHeight / 2 - contentDimensions.height / 2;
979
+ overlayPosition.top = window.innerHeight / 2 - c.height / 2;
971
980
  break;
972
981
  case 'bottom':
973
982
  default:
@@ -975,12 +984,13 @@
975
984
  break;
976
985
  }
977
986
  }
987
+ const calc = (param) => unistyle.value(param, rootSize);
978
988
  // ADD POSITION STYLES TO CONTENT
979
- contentRef.current.style.position = overlayPosition.position;
980
- contentRef.current.style.top = unistyle.value([overlayPosition.top], rootSize);
981
- contentRef.current.style.bottom = unistyle.value([overlayPosition.bottom], rootSize);
982
- contentRef.current.style.left = unistyle.value([overlayPosition.left], rootSize);
983
- contentRef.current.style.right = unistyle.value([overlayPosition.right], rootSize);
989
+ contentRef.current.style.position = position;
990
+ contentRef.current.style.top = calc(overlayPosition.top);
991
+ contentRef.current.style.bottom = calc(overlayPosition.bottom);
992
+ contentRef.current.style.left = calc(overlayPosition.left);
993
+ contentRef.current.style.right = calc(overlayPosition.right);
984
994
  };
985
995
  const handleVisibilityByEventType = (e) => {
986
996
  if (!active) {
@@ -1027,9 +1037,9 @@
1027
1037
  triggerRef,
1028
1038
  contentRef,
1029
1039
  active,
1030
- align: innerAlign,
1031
- alignX: innerAlignX,
1032
- alignY: innerAlignY,
1040
+ align,
1041
+ alignX,
1042
+ alignY,
1033
1043
  showContent,
1034
1044
  hideContent,
1035
1045
  blocked,