Mutate is a library of helpers to maintain persistent modifications to the rendered DOM of a web page for implementation of temporary, experimental changes and features for rapid experimentation.
It is intended to be framework independent and equally effective for SPAs and traditionally rendered webpages.
$ npm install @evolv/mutate
Clone the repository and run the following commands.
$ npm install
$ npm run build
There is a demo site included.
Fair warning: It is hideous and may cause seizures :)
$ npm run demo
The API for Mutate is similar in a lot of ways to the API of jQuery
with a significant difference, that is selectors (Collectors
) refer
to all current and future matching Element
s, and the functions to modify
the DOM (Mutations
) are persistent.
This means that you don't need to worry about timing, or dynamic areas of the rendered page.
Mutate also provides the ability to "project" Element
s of the DOM into
other Element
s of the DOM, binding all interactions with the "projection"
back to the original Element
s.
As everyone building variants have learned the hard way, most Element
s
are dependent on their location in the DOM for both style and functionality.
Projection allows the implementer to "move" and restyle Element
s without
losing the position dependent functionality of the original Element
s.
import {collect, mutate} from '@evolv/mutate';
The basic flow when using Mutate is to first define a Collector.
collect('<selector>', '<collector name>');
Then to define a Mutator for the Collector.
mutate('<collector name>').hide();
Mutators allow for Mutations to be chained together, similar to jQuery which will be evaluated in order of invocation.
mutate('<collector name>').text('<new text value>').classes({'<new class>': true});
For updating instructions refer to the Update Process
collect(selector: string, name: string, parent?: string): Collector
Create a new named Collector.
note
If parent
is not specified, the library will attempt
to discover the closest non-volatile parents of any Element
that match the selector.
Name | Type | Description |
---|---|---|
selector |
string |
A CSS selector that the Collector should manage. |
name |
string |
The name of the collector of future reference from mutate. |
parent? |
string |
(Optional) An optional selector if the nearest non-volatile parent is known. |
The Collector instance created. This Collector can be retrieved by name as well.
mutate(collectorName: string, variantKey?: string): Mutator
Create a Mutator
associated with an named Collector
Name | Type |
---|---|
collectorName |
string |
variantKey? |
string |
The Collector
provides all functionality for creating persistent select Element
s currently
present or that will be present on the page at a future time.
A Collector
can have any number of Mutator
associated with it.
destroyed: boolean
True if the Collector
has been destroyed, otherwise False.
elements: Element[]
All Element
s the Collector
has collected.
id: string
The id of the Collector
.
isValid: boolean
True if all validation has been satisfied, otherwise False.
name: undefined | string
The name of the Collector
.
observedTargets: Element[]
All Element
s the Collector
is currently observing.
parentSelector: undefined | string
The current selector for parent Element
s if set.
paused: boolean
True if the Collector
is paused, otherwise False.
root: Element | Document
The outermost parent Element
to observe.
selector: undefined | string
The current selector for Element
s to be collected if set.
atLeast(count: number): Collector
Specify the minimum number of Element
s the Collector
must find before it is considered valid.
Name | Type | Description |
---|---|---|
count |
number |
The minimum number of Element s the Collector must match to be considered value. |
atMost(count: number): Collector
Specify the maximum number of Element
s the Collector
should find to be considered valid.
Name | Type | Description |
---|---|---|
count |
number |
The maximum number of Element s the Collector must match to be considered value. |
claim(): Promise<Element>
Permanently claim a collected Element
for modification.
Promise
<Element
>
destroy(): void
Permanently destroy this Collector
.
exactly(count): Collector
Specify the total number of Element
s the Collector
should find to be considered valid.
Name | Type | Description |
---|---|---|
count |
number |
The total number of Element s the Collector must match to be considered value. |
filter(predicate: Predicate): Collector
Add a Predicate
Element
s must satisfy to be included in the Collector
.
Name | Type | Description |
---|---|---|
predicate |
Predicate |
A Predicate Element s must satisfy to be included in the in the Collector
|
observeParent(parentSelector): Collector
Set a selector for the parent Element
s to be observed for matching Element
s.
Name | Type | Description |
---|---|---|
parentSelector |
string |
The selector for parent Element s. |
pause(): Collector
Pause collection and Element
related notifications for this Collector
.
subscribe(listener: ElementListener): Collector
Subscribe to notifications about the changing of Element
s within the Collector
.
Name | Type | Description |
---|---|---|
listener |
ElementListener |
A callback to be notified about changes in the Element s. |
subscribeState(listener: CollectorStateListener): Collector
Subscribe to notifications about the changing of state within the collector.
Name | Type | Description |
---|---|---|
listener |
CollectorStateListener |
A callback to be notified when the state of the Collector changes. |
unpause(): Collector
Unpause collection and Element
related notifications for this Collector
.
validate(predicate: Predicate): Collector
Add a Predicate
that the Collector
must satisfy before it is considered valid and ready to
apply Effect
s.
Name | Type | Description |
---|---|---|
predicate |
Predicate |
A Predicate the collector must meet before applying Effect s. |
within(`millis`: number): Collector
Specify the maximum amount of time in milliseconds that a Collector
has to satisfy all validation criteria.
Name | Type | Description |
---|---|---|
millis |
number |
The maximum amount of time the Collector has to satisfy validation criteria. |
Mutator
provides a collection of methods to persistently mutate the DOM.
with: Binder
Bind Effect
s to non-DOM related events or state changes.
The bound value will be available for use in Effect
s as well as triggering reapplication of
Effect
s.
Name | Type |
---|---|
attr |
(attrName : string , transform? : (v : any ) => any ) => Binder
|
content |
(transform? : (v : any ) => any ) => Binder
|
context |
(propertyName : string , transform? : (v : any ) => any ) => Binder
|
apply(transform): Mutator
WARNING! This function is experimental and should only be used in testing.
Name | Type | Description |
---|---|---|
transform |
(subject : Element ) => Element
|
A function that modifies the DOM of subject. |
attributes(attributes): Mutator
Set attributes on the Element
s in the Collector
.
Name | Type | Description |
---|---|---|
attributes |
object | Map <string , string | (state : Map <string , any >) => string > |
A {@type Map} of attribute names to {@type string} or {@type (() => string)} representing their desired state. |
classes(classes): Mutator
Set or remove classes on the Element
s in the Collector
.
Name | Type | Description |
---|---|---|
classes |
object | Map <string , boolean | (state : Map <string , any >) => boolean > |
A {@type Map} of class names to {@type boolean} or {@type (() => boolean)} representing their desired state. |
customEffect(initialize, modify, revert): Mutator
Create a custom Effect
that is persistently applied.
Name | Type | Description |
---|---|---|
initialize |
() => void
|
The function to be invoked to initialize the Effect . |
modify |
() => void
|
The function to be invoked when an Element is modified. |
revert |
() => void
|
The function to be invoked when the Effect should be reverted. |
hide(): Mutator
Hide all Element
s in the Collector
.
html(newHtml, clone?): Mutator
Replace the HTML content of the Element
s matched by the Collector
.
Name | Type | Default value | Description |
---|---|---|---|
newHtml |
string | Node [] |
undefined |
The new HTML or Node s to replace the content with. |
clone |
boolean |
true |
Whether or not a the nodes should be cloned before insertion. (Default: True) |
insert(nodes, clone?): Mutator
Insert one or more Node
s into all elements in the Collector
.
Name | Type | Default value | Description |
---|---|---|---|
nodes |
string | Node | Node [] |
undefined |
The Node s to insert, or a string containing the HTML to insert. |
clone |
boolean |
true |
Whether or not a the nodes should be cloned before insertion. (Default: True) |
once(): Mutator
Specify that the Effect
s be applied no more than once.
pause(): Mutator
Pause all Effect
s that are applied through this Mutator
.
project(to): Mutator
Clone and hide an Element
, mapping all events from the clone into the original elements. The clone is
then inserted into the DOM element that matches the {@param to} selector.
The purpose of the functionality is to avoid disabling or otherwise negatively impacting existing event listeners.
Name | Type | Description |
---|---|---|
to |
string |
The selector for an element into which the cloned Element should be projected. |
reevaluate(): Mutator
Reinitialize all Effect
s on the Element
s in the Collector
.
remove(nodes: Node[]): Mutator
Remove the specified Node
s from all elements in the Collector
.
Name | Type | Description |
---|---|---|
nodes |
string | Node | Node [] |
the Node s or a selector for Node s that should be removed. |
revert(subject?): Mutator
Revert all Effect
s applied through this Mutator
to all Element
s in the Collector
or the specified {@param subject}.
Name | Type | Description |
---|---|---|
subject? |
Element |
(Optional) The Element to revert the Effect s on. |
show(): Mutator
Show all Element
s in the Collector
.
styles(styles): Mutator
Set styles on the Element
s in the Collector
.
Name | Type | Description |
---|---|---|
styles |
object | Map <string , string | (state : Map <string , any >) => string > |
A {@type Map} of style names to {@type string} or {@type (() => string)} representing their desired state. |
text(newText: string): Mutator
Replace the text content of the Element
s matched by the Collector
.
Name | Type | Description |
---|---|---|
newText |
string | (state : default ) => string
|
The new text content. |
unpause(): Mutator
Unpause all Effect
s that are applied through this Mutator
.
interface CollectorStateListener
(collectorState
, collector
): void
Name | Type |
---|---|
collectorState |
CollectorState |
collector |
Collector |
interface ElementListener
(action
, element
, elementList
): void
Name | Type |
---|---|
action |
EventType |
element |
Element |
elementList |
Element [] |
interface Predicate
(element
): boolean
Name | Type |
---|---|
element |
HTMLElement |
boolean
- run npm start
- Create a simple website or use codesandbox
- Add a snippet to head
<script src="http://localhost:8080/index.js"></script>
(make sure that your local is running on 8080, otherwise update src) - Apply changes to the website in the console
evolv.collect('h1', 'l6aiigykj')
evolv.mutate("l6aiigykj").html("Test");