Skip to content
This repository has been archived by the owner on Nov 9, 2024. It is now read-only.

Commit

Permalink
feat: add support for 'focusin' trigger (#689)
Browse files Browse the repository at this point in the history
* Add support for 'focusin' trigger to resolve #682

* Add tests for focusin trigger

* Fire mouseenter event prior to bubbling mouseLeave
  • Loading branch information
iansan5653 authored and atomiks committed Jan 28, 2020
1 parent f76fda6 commit 129366b
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/createTippy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,9 @@ export default function createTippy(
case 'focus':
on(isIE ? 'focusout' : 'blur', onBlur as EventListener);
break;
case 'focusin':
on('focusout', onBlur as EventListener);
break;
}
});
}
Expand Down
17 changes: 15 additions & 2 deletions test/integration/createTippy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('createTippy', () => {
it('adds correct listeners to the reference element based on `trigger` (`interactive`: false)', () => {
instance = createTippy(h(), {
...defaultProps,
trigger: 'mouseenter focus click',
trigger: 'mouseenter focus click focusin',
});

fireEvent.mouseEnter(instance.reference);
Expand All @@ -91,6 +91,12 @@ describe('createTippy', () => {
fireEvent.click(instance.reference);
expect(instance.state.isVisible).toBe(false);

fireEvent.focusIn(instance.reference);
expect(instance.state.isVisible).toBe(true);

fireEvent.focusOut(instance.reference);
expect(instance.state.isVisible).toBe(false);

// For completeness, it would seem to make sense to test that the tippy *is*
// hidden on clicking it's content (as this is a non-interactive instance);
// however, we use CSS pointer-events: none for non-interaction, so firing a
Expand All @@ -103,7 +109,7 @@ describe('createTippy', () => {
instance = createTippy(h(), {
...defaultProps,
interactive: true,
trigger: 'mouseenter focus click',
trigger: 'mouseenter focus click focusin',
});

fireEvent.mouseEnter(instance.reference);
Expand Down Expand Up @@ -136,9 +142,16 @@ describe('createTippy', () => {
fireEvent.click(instance.popperChildren.content);
expect(instance.state.isVisible).toBe(true);

fireEvent.focusIn(instance.reference);
expect(instance.state.isVisible).toBe(true);

fireEvent.focusOut(instance.reference);
expect(instance.state.isVisible).toBe(false);

// As above, bubble the mouseLeave event so the document.body handler
// invokes scheduleHide (but exits early and doesn't actually hide the tippy
// in this case).
fireEvent.mouseEnter(instance.reference);
fireEvent.mouseLeave(instance.popperChildren.content, {bubbles: true});
expect(instance.state.isVisible).toBe(true);
});
Expand Down
22 changes: 22 additions & 0 deletions test/integration/props.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,28 @@ describe('trigger', () => {
expect(instance.state.isVisible).toBe(true);
});

it('focusin', () => {
const instance = tippy(h(), {trigger: 'focusin'});

fireEvent.focusIn(instance.reference);
expect(instance.state.isVisible).toBe(true);

fireEvent.focusOut(instance.reference);
expect(instance.state.isVisible).toBe(false);
});

it('focusin + interactive: focus switching to inside popper does not hide tippy', () => {
const instance = tippy(h(), {interactive: true, trigger: 'focusin'});

fireEvent.focusIn(instance.reference);
expect(instance.state.isVisible).toBe(true);

fireEvent.focusOut(instance.reference, {
relatedTarget: instance.popper,
});
expect(instance.state.isVisible).toBe(true);
});

it('click', () => {
const instance = tippy(h(), {trigger: 'click'});

Expand Down
2 changes: 1 addition & 1 deletion website/src/pages/all-props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ index: 4
| **`sticky`** (available as a [plugin](/plugins/)) | `false` | **Ensures the tippy stays stuck to its reference element if it moves around or changes size while showing.** <br /><br /> Use `true` to check both `reference` and `popper` DOM rects, or use the strings `"reference"` or `"popper"` to check only one rect for improved performance (both are checked by default). <br /><br /> See the `updateDuration` prop to change the transition duration between position updates. |
| `theme` | `""` | **Themes added as classes (each separated by a space) to the tippy element's `classList`.** <br /><br /> See [Themes](/themes/) for details. |
| `touch` | `true` | **Determines if the tippy displays if the user is currently using touch input.** <br /><br /> Possible values: `boolean`, `"hold"`, `["hold", number]`. <br /><br /> Use `"hold"` to use `touch` listeners instead, and e.g. `["hold", 500]` to simulate "long press" behavior. |
| `trigger` | `"mouseenter focus"` | **The events (each separated by a space) which cause a tippy to show.** <br /><br /> Possible values: `"mouseenter"`, `"focus"`, `"click"`, `"manual"`. <br /><br /> Use `"manual"` to only trigger the tippy programmatically. |
| `trigger` | `"mouseenter focus"` | **The events (each separated by a space) which cause a tippy to show.** <br /><br /> Possible values: `"mouseenter"`, `"focus"`, `"focusin"`, `"click"`, `"manual"`. <br /><br /> Use `"manual"` to only trigger the tippy programmatically. |
| `triggerTarget` | `null` | **Which element(s) the `trigger` event listeners are applied to instead of the reference element.** <br /><br /> Possible values: `null`, `Element`, or `Element[]`. |
| `updateDuration` | `0` | **The transition duration between position updates of the popper element.** <br/><br /> Useful for the `sticky` and `flipOnUpdate` props. |
| `zIndex` | `9999` | **Determines the `z-index` of the tippy.** |

0 comments on commit 129366b

Please sign in to comment.