Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: merge initial options with action options #8

Merged
merged 3 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ Since Svelte automatically bundles all required dependencies, you only need to i

## Usage

`createPopperActions` returns a pair of actions to be used on the [reference and popper elements](https://popper.js.org/docs/v2/constructors/#usage).
`createPopperActions` takes an optional [options object](https://popper.js.org/docs/v2/constructors/#options) for configuring the popper instance, and returns a pair of actions to be used on the [reference and popper elements](https://popper.js.org/docs/v2/constructors/#usage).

The content action takes an [options object](https://popper.js.org/docs/v2/constructors/#options) for configuring the popper instance.
The content action also takes an [options object](https://popper.js.org/docs/v2/constructors/#options) for updating the options of the popper instance.

### Example

Expand Down Expand Up @@ -62,6 +62,22 @@ A Svelte version of the standard [tutorial](https://popper.js.org/docs/v2/tutori

## API

### Setting popper options

Popper options can be set statically when creating the popper actions, or dynamically on the content action.

If both are set, then the dynamic options will be merged with the initial options.

```svelte
<script>
// set once and no longer updated
const [popperRef, popperContent] = createPopperActions(initOptions);
</script>

<!-- will be merged with initOptions -->
<div use:popperContent={dynamicOptions}/>
```

### Accessing the Popper instance

If access is needed to the raw [Popper instance](https://popper.js.org/docs/v2/constructors/#instance) created by the actions, you can reference the third element returned by `createPopperActions`. The third element is a function that will return the current Popper instance used by the actions.
Expand All @@ -78,3 +94,4 @@ Using the raw Popper instance to [manually recompute the popper's position](http
}
</script>
```

6 changes: 5 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
roots: [
'./src',
'.',
],
testMatch: [
'**/__tests__/**/*.+(ts|js)',
Expand All @@ -9,5 +9,9 @@ module.exports = {
transform: {
'^.+\\.(ts)$': 'ts-jest',
},
coveragePathIgnorePatterns: [
'./node_modules/',
'./tests/helpers.ts',
],
};

150 changes: 0 additions & 150 deletions src/index.test.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ export function createPopperActions<
};
};

const contentAction: ContentAction<TModifier> = (node, initOptions?) => {
const contentAction: ContentAction<TModifier> = (node, contentOptions?) => {
contentNode = node;
options = initOptions;
options = { ...initOptions, ...contentOptions };
initPopper();
return {
update(newOptions: PopperOptions<TModifier>) {
options = newOptions;
update(newContentOptions: PopperOptions<TModifier>) {
options = { ...initOptions, ...newContentOptions };
if (popperInstance && options) {
popperInstance.setOptions(options);
}
Expand Down
24 changes: 24 additions & 0 deletions tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Action = (node: HTMLElement, params?: any) => ActionLifecycleHandlers;
export type ActionLifecycleHandlers = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
update?: (params: any) => void,
destroy? : () => void,
}

export const getElements = () => [
global.document.createElement('div'),
global.document.createElement('div'),
];

export const mountWithAction
// eslint-disable-next-line @typescript-eslint/no-explicit-any
= (node: HTMLElement, action: Action, params?: any) => action(node, params);

export const unmount = (_: HTMLElement, lifecycle: ActionLifecycleHandlers) => {
if (lifecycle.destroy) {
lifecycle.destroy();
}
};

61 changes: 61 additions & 0 deletions tests/init.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { createPopperActions } from '../src/index';
import { getElements, mountWithAction, unmount } from './helpers';

test('instance should init if and only if ref and content is mounted', () => {
// Arrange
const [refDiv, contentDiv] = getElements();
const [refAction, contentAction, getInstance] = createPopperActions();

// Act and Assert
expect(getInstance()).toBeNull();
mountWithAction(refDiv, refAction);

expect(getInstance()).toBeNull();
mountWithAction(contentDiv, contentAction);

expect(getInstance()).not.toBeNull();
});

test('instance should deinit if ref is unmounted', () => {
// Arrange
const [refDiv, contentDiv] = getElements();
const [refAction, contentAction, getInstance] = createPopperActions();
mountWithAction(contentDiv, contentAction);
const refLifecycle = mountWithAction(refDiv, refAction);

// Act
unmount(refDiv, refLifecycle);

// Assert
expect(getInstance()).toBeNull();
});

test('instance should deinit if content is unmounted', () => {
// Arrange
const [refDiv, contentDiv] = getElements();
const [refAction, contentAction, getInstance] = createPopperActions();
mountWithAction(refDiv, refAction);
const contentLifecycle = mountWithAction(contentDiv, contentAction);

// Act
unmount(contentDiv, contentLifecycle);

// Assert
expect(getInstance()).toBeNull();
});

test('instance should deinit if ref and content is unmounted', () => {
// Arrange
const [refDiv, contentDiv] = getElements();
const [refAction, contentAction, getInstance] = createPopperActions();
const refLifecycle = mountWithAction(refDiv, refAction);
const contentLifecycle = mountWithAction(contentDiv, contentAction);

// Act
unmount(refDiv, refLifecycle);
unmount(contentDiv, contentLifecycle);

// Assert
expect(getInstance()).toBeNull();
});