@cypress-design/react-tooltip 0.6.2 → 0.7.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.
@@ -2,5 +2,5 @@ $ yarn build:module && yarn build:types
2
2
  $ rollup -c ./rollup.config.mjs
3
3
  
4
4
  ./index.ts → ./dist/index.umd.js, ./dist/index.es.mjs...
5
- created ./dist/index.umd.js, ./dist/index.es.mjs in 29.8s
5
+ created ./dist/index.umd.js, ./dist/index.es.mjs in 42.9s
6
6
  $ tsc --project ./tsconfig.build.json
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @cypress-design/react-tooltip
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#265](https://github.com/cypress-io/cypress-design/pull/265) [`a69b7ee`](https://github.com/cypress-io/cypress-design/commit/a69b7ee3e7ca0900362b463f9925ba6ff6f4332f) Thanks [@elevatebart](https://github.com/elevatebart)! - add forceOpen prop
8
+
9
+ ### Patch Changes
10
+
11
+ - [#265](https://github.com/cypress-io/cypress-design/pull/265) [`a69b7ee`](https://github.com/cypress-io/cypress-design/commit/a69b7ee3e7ca0900362b463f9925ba6ff6f4332f) Thanks [@elevatebart](https://github.com/elevatebart)! - avoid creating empty divs
12
+
13
+ ## 0.6.3
14
+
15
+ ### Patch Changes
16
+
17
+ - [#259](https://github.com/cypress-io/cypress-design/pull/259) [`fdd8839`](https://github.com/cypress-io/cypress-design/commit/fdd883952476a852973adc671dadc817883251ec) Thanks [@elevatebart](https://github.com/elevatebart)! - when tooltip overflows, shift it back
18
+
3
19
  ## 0.6.2
4
20
 
5
21
  ### Patch Changes
package/Tooltip.tsx CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  offset,
6
6
  flip,
7
7
  arrow,
8
+ shift,
8
9
  autoUpdate,
9
10
  useFloating,
10
11
  useInteractions,
@@ -44,6 +45,11 @@ export interface TooltipProps {
44
45
  * If set, the tooltip will always respect the given placement
45
46
  */
46
47
  forcePlacement?: boolean
48
+ /**
49
+ * Make sure the tooltip stays always open.
50
+ * This is useful for debugging.
51
+ */
52
+ forceOpen?: boolean
47
53
  }
48
54
 
49
55
  const ROTATE_MAP = {
@@ -64,23 +70,17 @@ export const Tooltip: React.FC<
64
70
  disabled,
65
71
  interactive,
66
72
  forcePlacement,
73
+ forceOpen = false,
67
74
  ...rest
68
75
  }) => {
69
76
  const arrowRef = React.useRef(null)
70
77
  const [open, setOpen] = React.useState(false)
71
78
 
72
- const [container] = React.useState(() => {
73
- // This will be executed only on the initial render
74
- // https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
75
- return document.createElement('div')
76
- })
77
-
78
79
  React.useEffect(() => {
79
- document.body.appendChild(container)
80
- return () => {
81
- document.body.removeChild(container)
80
+ if (forceOpen) {
81
+ setOpen(true)
82
82
  }
83
- }, [])
83
+ }, [forceOpen])
84
84
 
85
85
  const {
86
86
  x,
@@ -104,6 +104,7 @@ export const Tooltip: React.FC<
104
104
  : flip(),
105
105
  offset(interactive ? 0 : 16),
106
106
  arrow({ element: arrowRef, padding: 24 }),
107
+ shift({ padding: 16 }),
107
108
  ],
108
109
  whileElementsMounted: autoUpdate,
109
110
  })
@@ -111,13 +112,13 @@ export const Tooltip: React.FC<
111
112
  const { getReferenceProps, getFloatingProps } = useInteractions([
112
113
  useHover(context, {
113
114
  handleClose: interactive ? safePolygon() : undefined,
114
- enabled: !disabled,
115
+ enabled: !disabled && !forceOpen,
115
116
  }),
116
117
  useFocus(context, {
117
- enabled: !disabled,
118
+ enabled: !disabled && !forceOpen,
118
119
  }),
119
120
  useRole(context, { role: 'tooltip' }),
120
- useDismiss(context),
121
+ ...(!forceOpen ? [useDismiss(context)] : []),
121
122
  ])
122
123
 
123
124
  const placementSide = calculatedPlacement.split(
@@ -2,13 +2,115 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { mount } from 'cypress/react18'
5
- import TooltipStory from './Tooltip.rootstory'
5
+ import { Placement } from '@floating-ui/react-dom-interactions'
6
6
  import assertions from '../assertions'
7
+ import Tooltip from './Tooltip'
8
+
9
+ const TooltipStoryMulti = ({
10
+ color = 'light',
11
+ placement,
12
+ disabled,
13
+ tabindex = 1,
14
+ }: {
15
+ color?: 'light' | 'dark'
16
+ placement?: Placement
17
+ disabled?: boolean
18
+ tabindex?: number
19
+ } = {}) => (
20
+ <div className="flex flex-col items-center center gap-20">
21
+ <Tooltip
22
+ className="w-1/2 p-4 bg-red-200"
23
+ popper={<div className="p-4 text-gray-800 bg-jade-200">PopovDyn</div>}
24
+ color={color}
25
+ placement={placement}
26
+ tabIndex={tabindex}
27
+ disabled={disabled}
28
+ >
29
+ <div>Hover Me (dynamic: {placement?.toString()})</div>
30
+ </Tooltip>
31
+ <Tooltip
32
+ className="w-1/2 p-4 bg-red-200"
33
+ popper={
34
+ <div className="h-[200px] flex items-center justify-center">Popov</div>
35
+ }
36
+ color={color}
37
+ placement="top"
38
+ forcePlacement
39
+ >
40
+ <div>Force Placement to the top</div>
41
+ </Tooltip>
42
+ <Tooltip
43
+ className="w-1/2 p-4 bg-red-200"
44
+ popper={<div>PopovInt</div>}
45
+ color={color}
46
+ placement={placement}
47
+ interactive
48
+ >
49
+ <div>Interactive {placement?.toString()}</div>
50
+ </Tooltip>
51
+ {(['top', 'right', 'bottom', 'left', 'top-start'] as const).map(
52
+ (placement) => (
53
+ <Tooltip
54
+ className="w-1/2 p-4 bg-indigo-200"
55
+ placement={placement}
56
+ key={placement}
57
+ color={color}
58
+ tabIndex={tabindex}
59
+ disabled={disabled}
60
+ popper={
61
+ <div className="p-4 text-gray-800 bg-jade-200">
62
+ Popover ({placement})
63
+ </div>
64
+ }
65
+ >
66
+ <div>Hover Me ({placement})</div>
67
+ </Tooltip>
68
+ )
69
+ )}
70
+ </div>
71
+ )
7
72
 
8
73
  describe('Tooltip', { viewportHeight: 800, viewportWidth: 800 }, () => {
9
- function mountStory(options: Parameters<typeof TooltipStory>[0] = {}) {
10
- mount(<TooltipStory {...options} tabindex={1} />)
74
+ function mountStory(
75
+ options: { single?: boolean } & Parameters<typeof TooltipStoryMulti>[0] = {}
76
+ ) {
77
+ const { single, tabindex = 1, ...rest } = options
78
+ if (single) {
79
+ mount(
80
+ <Tooltip
81
+ {...rest}
82
+ tabIndex={tabindex}
83
+ popper={
84
+ <div className="w-[300px]">
85
+ popit: Lorem ipsum dolor sit amet consectetur adipisicing elit.
86
+ Quisquam, voluptatum.
87
+ </div>
88
+ }
89
+ className="m-4 p-4 bg-red-300 w-[150px]"
90
+ >
91
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam,
92
+ voluptatum.
93
+ </Tooltip>
94
+ )
95
+ } else {
96
+ mount(<TooltipStoryMulti {...rest} tabindex={tabindex} />)
97
+ }
11
98
  }
12
99
 
13
100
  assertions(mountStory, 'react')
101
+
102
+ it('forceOpen', () => {
103
+ mount(
104
+ <div className="text-center">
105
+ <Tooltip
106
+ className="border inline-block m-16 p-3"
107
+ popper="should be visible"
108
+ forceOpen
109
+ >
110
+ make sure its open
111
+ </Tooltip>
112
+ </div>
113
+ )
114
+ cy.findByText('should be visible').should('be.visible')
115
+ })
14
116
  })
package/dist/Tooltip.d.ts CHANGED
@@ -28,6 +28,11 @@ export interface TooltipProps {
28
28
  * If set, the tooltip will always respect the given placement
29
29
  */
30
30
  forcePlacement?: boolean;
31
+ /**
32
+ * Make sure the tooltip stays always open.
33
+ * This is useful for debugging.
34
+ */
35
+ forceOpen?: boolean;
31
36
  }
32
37
  export declare const Tooltip: React.FC<TooltipProps & React.HTMLProps<HTMLDivElement>>;
33
38
  export default Tooltip;
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.d.ts","sourceRoot":"./","sources":["Tooltip.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,SAAS,EAaV,MAAM,qCAAqC,CAAA;AAE5C,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AASD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAC5B,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAiL/C,CAAA;AAED,eAAe,OAAO,CAAA"}
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"./","sources":["Tooltip.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,SAAS,EAcV,MAAM,qCAAqC,CAAA;AAE5C,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AASD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAC5B,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CA4K/C,CAAA;AAED,eAAe,OAAO,CAAA"}
package/dist/index.es.mjs CHANGED
@@ -40,6 +40,16 @@ function __rest(s, e) {
40
40
  t[p[i]] = s[p[i]];
41
41
  }
42
42
  return t;
43
+ }
44
+
45
+ function __spreadArray(to, from, pack) {
46
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
47
+ if (ar || !(i in from)) {
48
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
49
+ ar[i] = from[i];
50
+ }
51
+ }
52
+ return to.concat(ar || Array.prototype.slice.call(from));
43
53
  }
44
54
 
45
55
  function getSide(placement) {
@@ -630,6 +640,88 @@ const offset = function (value) {
630
640
  };
631
641
  };
632
642
 
643
+ function getCrossAxis(axis) {
644
+ return axis === 'x' ? 'y' : 'x';
645
+ }
646
+
647
+ /**
648
+ * Shifts the floating element in order to keep it in view when it will overflow
649
+ * a clipping boundary.
650
+ * @see https://floating-ui.com/docs/shift
651
+ */
652
+ const shift = function (options) {
653
+ if (options === void 0) {
654
+ options = {};
655
+ }
656
+
657
+ return {
658
+ name: 'shift',
659
+ options,
660
+
661
+ async fn(middlewareArguments) {
662
+ const {
663
+ x,
664
+ y,
665
+ placement
666
+ } = middlewareArguments;
667
+ const {
668
+ mainAxis: checkMainAxis = true,
669
+ crossAxis: checkCrossAxis = false,
670
+ limiter = {
671
+ fn: _ref => {
672
+ let {
673
+ x,
674
+ y
675
+ } = _ref;
676
+ return {
677
+ x,
678
+ y
679
+ };
680
+ }
681
+ },
682
+ ...detectOverflowOptions
683
+ } = options;
684
+ const coords = {
685
+ x,
686
+ y
687
+ };
688
+ const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
689
+ const mainAxis = getMainAxisFromPlacement(getSide(placement));
690
+ const crossAxis = getCrossAxis(mainAxis);
691
+ let mainAxisCoord = coords[mainAxis];
692
+ let crossAxisCoord = coords[crossAxis];
693
+
694
+ if (checkMainAxis) {
695
+ const minSide = mainAxis === 'y' ? 'top' : 'left';
696
+ const maxSide = mainAxis === 'y' ? 'bottom' : 'right';
697
+ const min = mainAxisCoord + overflow[minSide];
698
+ const max = mainAxisCoord - overflow[maxSide];
699
+ mainAxisCoord = within(min, mainAxisCoord, max);
700
+ }
701
+
702
+ if (checkCrossAxis) {
703
+ const minSide = crossAxis === 'y' ? 'top' : 'left';
704
+ const maxSide = crossAxis === 'y' ? 'bottom' : 'right';
705
+ const min = crossAxisCoord + overflow[minSide];
706
+ const max = crossAxisCoord - overflow[maxSide];
707
+ crossAxisCoord = within(min, crossAxisCoord, max);
708
+ }
709
+
710
+ const limitedCoords = limiter.fn({ ...middlewareArguments,
711
+ [mainAxis]: mainAxisCoord,
712
+ [crossAxis]: crossAxisCoord
713
+ });
714
+ return { ...limitedCoords,
715
+ data: {
716
+ x: limitedCoords.x - x,
717
+ y: limitedCoords.y - y
718
+ }
719
+ };
720
+ }
721
+
722
+ };
723
+ };
724
+
633
725
  function isWindow(value) {
634
726
  return value && value.document && value.location && value.alert && value.setInterval;
635
727
  }
@@ -33435,21 +33527,15 @@ var ROTATE_MAP = {
33435
33527
  };
33436
33528
  var Tooltip = function (_a) {
33437
33529
  var _b;
33438
- var placement = _a.placement, _c = _a.color, color = _c === void 0 ? 'light' : _c, className = _a.className, children = _a.children, popper = _a.popper, disabled = _a.disabled, interactive = _a.interactive, forcePlacement = _a.forcePlacement, rest = __rest(_a, ["placement", "color", "className", "children", "popper", "disabled", "interactive", "forcePlacement"]);
33530
+ var placement = _a.placement, _c = _a.color, color = _c === void 0 ? 'light' : _c, className = _a.className, children = _a.children, popper = _a.popper, disabled = _a.disabled, interactive = _a.interactive, forcePlacement = _a.forcePlacement, _d = _a.forceOpen, forceOpen = _d === void 0 ? false : _d, rest = __rest(_a, ["placement", "color", "className", "children", "popper", "disabled", "interactive", "forcePlacement", "forceOpen"]);
33439
33531
  var arrowRef = React.useRef(null);
33440
- var _d = React.useState(false), open = _d[0], setOpen = _d[1];
33441
- var container = React.useState(function () {
33442
- // This will be executed only on the initial render
33443
- // https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
33444
- return document.createElement('div');
33445
- })[0];
33532
+ var _e = React.useState(false), open = _e[0], setOpen = _e[1];
33446
33533
  React.useEffect(function () {
33447
- document.body.appendChild(container);
33448
- return function () {
33449
- document.body.removeChild(container);
33450
- };
33451
- }, []);
33452
- var _e = useFloating({
33534
+ if (forceOpen) {
33535
+ setOpen(true);
33536
+ }
33537
+ }, [forceOpen]);
33538
+ var _f = useFloating({
33453
33539
  placement: placement,
33454
33540
  open: open,
33455
33541
  onOpenChange: setOpen,
@@ -33462,20 +33548,20 @@ var Tooltip = function (_a) {
33462
33548
  : flip(),
33463
33549
  offset(interactive ? 0 : 16),
33464
33550
  arrow({ element: arrowRef, padding: 24 }),
33551
+ shift({ padding: 16 }),
33465
33552
  ],
33466
33553
  whileElementsMounted: autoUpdate,
33467
- }), x = _e.x, y = _e.y, reference = _e.reference, floating = _e.floating, strategy = _e.strategy, calculatedPlacement = _e.placement, context = _e.context, _f = _e.middlewareData.arrow, _g = _f === void 0 ? {} : _f, arrowX = _g.x, arrowY = _g.y;
33468
- var _h = useInteractions([
33554
+ }), x = _f.x, y = _f.y, reference = _f.reference, floating = _f.floating, strategy = _f.strategy, calculatedPlacement = _f.placement, context = _f.context, _g = _f.middlewareData.arrow, _h = _g === void 0 ? {} : _g, arrowX = _h.x, arrowY = _h.y;
33555
+ var _j = useInteractions(__spreadArray([
33469
33556
  useHover(context, {
33470
33557
  handleClose: interactive ? safePolygon() : undefined,
33471
- enabled: !disabled,
33558
+ enabled: !disabled && !forceOpen,
33472
33559
  }),
33473
33560
  useFocus(context, {
33474
- enabled: !disabled,
33561
+ enabled: !disabled && !forceOpen,
33475
33562
  }),
33476
- useRole(context, { role: 'tooltip' }),
33477
- useDismiss(context),
33478
- ]), getReferenceProps = _h.getReferenceProps, getFloatingProps = _h.getFloatingProps;
33563
+ useRole(context, { role: 'tooltip' })
33564
+ ], (!forceOpen ? [useDismiss(context)] : []), true)), getReferenceProps = _j.getReferenceProps, getFloatingProps = _j.getFloatingProps;
33479
33565
  var placementSide = calculatedPlacement.split('-')[0];
33480
33566
  var arrowRotate = ROTATE_MAP[placementSide];
33481
33567
  var arrowXRule = 'left', arrowYRule = 'top';
@@ -33538,4 +33624,4 @@ var Tooltip = function (_a) {
33538
33624
  export { Tooltip as default };
33539
33625
  //# sourceMappingURL=index.es.mjs.map
33540
33626
 
33541
- /* <wind-keep class="container stroke-none fill-white block text-gray-900 shadow-gray-100 border-transparent bg-white fill-gray-900 text-white shadow-gray-800 bg-gray-900 rounded shadow border invisible absolute z-10 transform filter text-[16px] leading-[24px] min-w-[160px] text-center p-[8px] relative z-20 drop-shadow"> */
33627
+ /* <wind-keep class="stroke-none fill-white block text-gray-900 shadow-gray-100 border-transparent bg-white fill-gray-900 text-white shadow-gray-800 bg-gray-900 rounded shadow border invisible absolute z-10 transform filter text-[16px] leading-[24px] min-w-[160px] text-center p-[8px] relative z-20 drop-shadow"> */