-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #559 from studiometa/feature/mutation-observer
[Feature] Add mutation observer service and decorator
- Loading branch information
Showing
23 changed files
with
433 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# withMutation | ||
|
||
Use this decorator to add a `mutated(props)` hook managed by the [mutation](/api/services/useMutation.html) service. | ||
|
||
## Usage | ||
|
||
```js | ||
import { Base, withMutation } from '@studiometa/js-toolkit'; | ||
|
||
export default class Component extends withMutation(Base, { | ||
target: (instance) => instance.$el, | ||
}) { | ||
static config = { | ||
name: 'Component', | ||
}; | ||
|
||
mutated(props) { | ||
for (const mutation of props.mutations) { | ||
console.log(mutation); // MutationRecord | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Parameters | ||
|
||
- `BaseClass` (`Base`): the class to add mutation observation to | ||
- `options?` (`{ target?: (instance:Base) => Node } & MutationObserverInit`): define which element should be observed (defaults to the component's root element) and any options for the mutation observer | ||
|
||
### Return value | ||
|
||
- `Base`: a new class extending the given class with mutation observability enabled | ||
|
||
## API | ||
|
||
### Class methods | ||
|
||
#### `mutated` | ||
|
||
The `mutated` class method will be triggered when a DOM mutation occurs on the given target. | ||
|
||
**Arguments** | ||
|
||
- `props` (`MutationServiceProps`): the [mutation service props](/api/services/useMutation.md#props) | ||
|
||
## Examples | ||
|
||
### Update a component when its children have changed | ||
|
||
This decorator can be used to update a component when its inner HTML has changed to rebind refs and child components. | ||
|
||
```js | ||
import { Base, withMutation } from '@studiometa/js-toolkit'; | ||
|
||
export default class Component extends withMutation(Base, { | ||
childList: true, | ||
subtree: true, | ||
}) { | ||
static config = { | ||
name: 'Component', | ||
}; | ||
|
||
mutated(props) { | ||
this.$update(); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Mutation service | ||
|
||
The mutation service can be used to observe DOM mutations on a component with the MutationObserver API. | ||
|
||
## Usage | ||
|
||
```js | ||
import { useMutation } from '@studiometa/js-toolkit'; | ||
|
||
const { add, remove } = useMutation(); | ||
|
||
// Add a callback | ||
add('custom-id', ({ mutations }) => { | ||
console.log('Some attribute has changed!'); | ||
}); | ||
|
||
// Remove the callback | ||
remove('custom-id'); | ||
``` | ||
|
||
## Parameters | ||
|
||
### `target` | ||
|
||
- Type: `Node` | ||
|
||
The target element to observe, defaults to `document.documentElement`. | ||
|
||
**Example** | ||
|
||
Observe any attribute mutation on the `<body>` element: | ||
|
||
```js | ||
const service = useMutation(document.body); | ||
``` | ||
|
||
### `options` | ||
|
||
- Type: [`MutationObserverInit`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#options) | ||
|
||
Options for the mutation observer, defaults to `{ attributes: true }` only. | ||
|
||
**Example** | ||
|
||
Observe everything on the given element: | ||
|
||
```js | ||
const element = document.querySelector('#element'); | ||
const service = useMutation(element, { | ||
attributes: true, | ||
childList: true, | ||
subtree: true, | ||
}); | ||
``` | ||
|
||
## Props | ||
|
||
### `mutations` | ||
|
||
- Type: `MutationRecord[]` | ||
|
||
The list of `MutationRecord` that triggered the callback. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# cache | ||
|
||
Cache the result of a function with a list of keys. | ||
|
||
## Usage | ||
|
||
```js | ||
import { cache } from '@studiometa/js-toolkit/utils'; | ||
|
||
const keys = [document.body, Symbol('key')]; | ||
const callback = () => performance.now(); | ||
|
||
console.log(cache(keys, callback)); // 100 | ||
console.log(cache(keys, callback) === cache(keys, callback)); // true | ||
|
||
setTimeout(() => { | ||
console.log(cache(keys, callback)); // 100 | ||
}, 100); | ||
``` | ||
|
||
### Parameters | ||
|
||
- `keys` (`Array<any>`): a list of keys to be used to cache the result of the callback | ||
- `callback` (`() => any`): the callback executed to retrieve the value to cache | ||
|
||
### Return value | ||
|
||
The value returned by the `callback` function given as parameter. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { BaseDecorator, BaseInterface } from '../Base/types.js'; | ||
import type { Base, BaseProps, BaseConfig } from '../Base/index.js'; | ||
import type { MutationServiceOptions, MutationServiceProps } from '../services/index.js'; | ||
import { useMutation } from '../services/index.js'; | ||
|
||
export type MutationDecoratorOptions = MutationServiceOptions & { | ||
target?: (this: Base, instance: Base) => Node; | ||
}; | ||
|
||
export interface WithMutationInterface extends BaseInterface { | ||
mutated?(props: MutationServiceProps): void; | ||
} | ||
|
||
/** | ||
* Add a mutation observer to a component. | ||
*/ | ||
export function withMutation<S extends Base>( | ||
BaseClass: typeof Base, | ||
{ target = (instance) => instance.$el, ...options }: MutationDecoratorOptions = {}, | ||
): BaseDecorator<BaseInterface, S> { | ||
/** | ||
* Class. | ||
*/ | ||
class WithMutation<T extends BaseProps = BaseProps> extends BaseClass<T & WithMutationInterface> { | ||
/** | ||
* Config. | ||
*/ | ||
static config: BaseConfig = { | ||
...BaseClass.config, | ||
emits: ['mutated'], | ||
}; | ||
|
||
/** | ||
* Class constructor. | ||
*/ | ||
constructor(element: HTMLElement) { | ||
super(element); | ||
this.$on('mounted', () => { | ||
this.$services.register( | ||
'mutated', | ||
useMutation.bind(undefined, target.call(this, this), options), | ||
); | ||
this.$services.enable('mutated'); | ||
}); | ||
|
||
this.$on('destroyed', () => { | ||
this.$services.disable('mutated'); | ||
this.$services.unregister('mutated'); | ||
}); | ||
} | ||
} | ||
|
||
// @ts-ignore | ||
return WithMutation; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.