Comparing version 0.0.4 to 0.1.0
@@ -15,2 +15,19 @@ import Stamp from '../src/stamp.js' | ||
</div> | ||
<div class="context common-context"> | ||
<template class="tpl-trap"> | ||
<p data-case="wrong">wrong</p> | ||
</template> | ||
</div> | ||
<div class="context alternate-context"> | ||
<template class="tpl-trap"> | ||
<p data-case="right">right</p> | ||
</template> | ||
</div> | ||
<div class="context-target"></div> | ||
<div class="context-target-alt"> | ||
<div class="context-target"></div> | ||
<div> | ||
` | ||
@@ -236,2 +253,68 @@ | ||
test('Can switch contexts between stamps', () => { | ||
const altContext = document.querySelector('.alternate-context') | ||
// Stamp in default context | ||
Stamp('.tpl-trap') | ||
.alias('outer') | ||
.stamp() | ||
.get('.tpl-trap', { context: altContext }) | ||
.alias('inner') | ||
.stamp() | ||
// Stringify results | ||
const results = Array.from(document.querySelectorAll('.context')) | ||
.map(context => context | ||
? context.querySelector('p').getAttribute('data-case') | ||
: 'empty') | ||
.join('-') | ||
expect(results).toEqual('wrong-right') | ||
}) | ||
test('Can switch contexts between stamps repeatedly', () => { | ||
const altContext = document.querySelector('.alternate-context') | ||
// Stamp in default context | ||
Stamp('.tpl-trap') | ||
.alias('outer') | ||
.clear() | ||
.stamp() | ||
.get('.tpl-trap', { context: altContext }) | ||
.alias('inner') | ||
.clear() | ||
.stamp() | ||
.get('outer', { override: true }) | ||
.stamp() | ||
.get('inner', { context: altContext }) | ||
.stamp() | ||
.context() | ||
// Stringify results | ||
const results = Array.from(document.querySelectorAll('.context')) | ||
.map(x => x.children.length) | ||
expect(results).toEqual([3, 3]) | ||
}) | ||
test('Can switch contexts without switching stamps', () => { | ||
const altContext = document.querySelector('.context-target-alt') | ||
// Stamp in default context | ||
Stamp('.tpl-trap') | ||
.target('.context-target') | ||
.stamp() | ||
.context(altContext) | ||
.target('.context-target') | ||
.stamp() | ||
// Stringify results | ||
const results = Array.from(document.querySelectorAll('.context-target')) | ||
.map(x => x.children.length) | ||
expect(results).toEqual([1, 1]) | ||
}) | ||
// window.onload = function () { | ||
@@ -265,1 +348,4 @@ // Stamp('#tpl-hello') | ||
// } | ||
//TODO teste get | ||
//TODO test override on get |
@@ -6,5 +6,5 @@ const stampData = {} | ||
function StampData (selector) { | ||
function StampData (selector, context) { | ||
this.selector = selector | ||
this.template = document.querySelector(selector) | ||
this.template = context.querySelector(selector) | ||
this.target = this.template.parentElement | ||
@@ -14,10 +14,11 @@ this.cap = Infinity | ||
this.mutator = identity | ||
this.context = context | ||
} | ||
function createNewStamp (selector) { | ||
stampData[selector] = new StampData(selector) | ||
function createNewStamp (selector, context) { | ||
stampData[selector] = new StampData(selector, context) | ||
} | ||
function Stamp (selector) { | ||
let data = {} | ||
function Stamp (selector, config={}) { | ||
let data = { context: config.context || document } | ||
@@ -38,10 +39,16 @@ function count () { | ||
const api = { | ||
get (selector) { | ||
const lookup = aliasData[selector] | ||
get (selector, config={}) { | ||
const context = config.context || document | ||
const override = config.override || false | ||
const originalSelector = aliasData[selector] | ||
? aliasData[selector] | ||
: selector | ||
if (!stampData[lookup]) { | ||
createNewStamp(lookup) | ||
if (!stampData[originalSelector] || override || config.context) { | ||
createNewStamp(originalSelector, context) | ||
} | ||
data = stampData[lookup] | ||
data = stampData[originalSelector] | ||
return this | ||
@@ -72,5 +79,9 @@ }, | ||
target (targetSelector) { | ||
data.target = document.querySelector(targetSelector) | ||
data.target = data.context.querySelector(targetSelector) | ||
return this | ||
}, | ||
context (element=document) { | ||
data.context = element | ||
return this | ||
}, | ||
keep (keepAmount) { | ||
@@ -106,3 +117,3 @@ data.keep = keepAmount | ||
if (selector) api.get(selector) | ||
if (selector) api.get(selector, config) | ||
return api | ||
@@ -109,0 +120,0 @@ } |
@@ -12,5 +12,5 @@ "use strict"; | ||
function StampData(selector) { | ||
function StampData(selector, context) { | ||
this.selector = selector; | ||
this.template = document.querySelector(selector); | ||
this.template = context.querySelector(selector); | ||
this.target = this.template.parentElement; | ||
@@ -20,10 +20,14 @@ this.cap = Infinity; | ||
this.mutator = identity; | ||
this.context = context; | ||
} | ||
function createNewStamp(selector) { | ||
stampData[selector] = new StampData(selector); | ||
function createNewStamp(selector, context) { | ||
stampData[selector] = new StampData(selector, context); | ||
} | ||
function Stamp(selector) { | ||
var data = {}; | ||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var data = { | ||
context: config.context || document | ||
}; | ||
@@ -45,9 +49,12 @@ function count() { | ||
get(selector) { | ||
var lookup = aliasData[selector] ? aliasData[selector] : selector; | ||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var context = config.context || document; | ||
var override = config.override || false; | ||
var originalSelector = aliasData[selector] ? aliasData[selector] : selector; | ||
if (!stampData[lookup]) { | ||
createNewStamp(lookup); | ||
if (!stampData[originalSelector] || override || config.context) { | ||
createNewStamp(originalSelector, context); | ||
} | ||
data = stampData[lookup]; | ||
data = stampData[originalSelector]; | ||
return this; | ||
@@ -84,6 +91,12 @@ }, | ||
target(targetSelector) { | ||
data.target = document.querySelector(targetSelector); | ||
data.target = data.context.querySelector(targetSelector); | ||
return this; | ||
}, | ||
context() { | ||
var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document; | ||
data.context = element; | ||
return this; | ||
}, | ||
keep(keepAmount) { | ||
@@ -124,3 +137,3 @@ data.keep = keepAmount; | ||
}; | ||
if (selector) api.get(selector); | ||
if (selector) api.get(selector, config); | ||
return api; | ||
@@ -127,0 +140,0 @@ } |
{ | ||
"name": "@dvo/stamp", | ||
"version": "0.0.4", | ||
"version": "0.1.0", | ||
"description": "Tool for lightweight componentization.", | ||
@@ -30,4 +30,4 @@ "main": "lib/stamp.js", | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.8.4", | ||
"@babel/preset-env": "^7.8.4", | ||
"@babel/core": "^7.8.7", | ||
"@babel/preset-env": "^7.8.7", | ||
"babel-jest": "^25.1.0", | ||
@@ -34,0 +34,0 @@ "jest": "^25.1.0", |
@@ -5,7 +5,7 @@ # STAMP | ||
Quite often components are lightweight. By that I mean they are reused in a single place and reflect static state (usually from an array and vaery little change once rendered). Stamp is a very simple way to deal with this lightweight componentization requirement, in a native and hassle-free way. | ||
Often components are lightweight — they are used in a single container and don't mutate a lot once applied. Stamp is a simple tool to manage these lightweight components. | ||
The concept is simple: | ||
- you write the lightweight component (or stamp), within a `<template>` tag, inside a wrapper element that will received them; | ||
- you write a mutator function that populates the stamp with the data you want. | ||
- you write the component (or stamp) within a `<template>` tag, right inside the container that will received them; | ||
- you give the stamp a "mutator" function that populates it with the data you want. | ||
- all methods are chainable, and when you're ready, just `stamp()` it! | ||
@@ -32,3 +32,3 @@ | ||
<section id="books"> | ||
<template id="tpl-book-card"> | ||
<template id="tpl-book-card"> <!-- See? The template is right inside the container! --> | ||
<div> | ||
@@ -48,3 +48,3 @@ <a target="_blank" href=""> | ||
Stamp('#tpl-book-card') | ||
// Define a mutator function | ||
// Define a mutator function to do the DOM manipulation | ||
.change(function (card) { | ||
@@ -74,2 +74,3 @@ card.querySelector('a') | ||
``` | ||
> It may be obvious, but the alias is just that: an alias. If you get a selector (eg. '.example'), than call it with an alias ('myExample'), any change you do to cap, target, context, etc will be in effect, regardless of being selected with the selector or alias. | ||
@@ -86,14 +87,76 @@ Clearing the components later is also a breeze: running `stamp.clear()` will clear all stamps from that template, while `stamp.clearAll()` will clear every single element that is not a `<template>`. Both functions affect items in the stamp's target (by default, the template's container). | ||
### Selectors and config | ||
A component is defined by the selector you use to get it. So if you change some properties of the stamp, such as `cap`, `keep`, `target` or `context`, those will be in effect the next time you `get()` the stamp or any aliases you added to him. | ||
You might want to reset those however, and to do so you'd use the second argument of the `get()` method: config. It is just an object holding the configuration you want — in ths case, 'override'. | ||
```javascript | ||
Stamp('#tpl-book-card', { override: true }) | ||
``` | ||
Currently, the only other config available is `context`, which is explained in detail below. Note that using `context` also automatically overrides the stamp because it assumes you're aiming at a different component with the same selector (a bad idea to begin with). | ||
### Contexts | ||
Out of necessity, an advanced feature was included: contexts. By default, Stamp will look for the selectors within the context of the document, but that can be overwritten. The reason has to do with the lifecycle of the component: | ||
1. Stamp will find the components template. | ||
1. Then clone it. By this time it is a document fragment, not attached to the DOM. | ||
1. Than manipulate the clone (in the document fragment) with your mutator function. | ||
1. Only then the component is added to the DOM. | ||
1. (A second mutator can be passed as an argument to the `stamp()` method — in that case, it will run after the component has been inserted into the DOM.) | ||
But as it happens, your component might have other components inside that needs stamping. Because **by the the time the mutator function runs your component is not attached to the DOM**, using `document.querySelector()` won't work. We need another context. | ||
The simplest way to provide a context is with the config argument. For example: | ||
```javascript | ||
Stamp('#tpl-foo') | ||
.change(el => { | ||
Stamp('#tpl-inner-bar', { context: el }) | ||
.stamp() | ||
}) | ||
.stamp() | ||
``` | ||
In the example above, the template foo had an inner template bar. The context of an inner component is the component itself, passed as the argument of the mutator function. Ommiting the context would cause Stamp to look for bar on the document. | ||
> Why isn't the context implied? So you can keep referencing templates outside your document fragment. | ||
There is another way to set a context: the `context()` method. You pass the new context as an argument so it will be used as the context for that stamp. It's main use is to stamp a temlate to a target in a different context. For example: | ||
```javascript | ||
Stamp('#tpl-foo') | ||
.change(el => { | ||
Stamp('#tpl-outer-baz') | ||
.context(el) | ||
.target('.inner-container') | ||
.stamp() | ||
.context() | ||
}) | ||
.stamp() | ||
``` | ||
In the example above, the baz template was on the document, outside of the context of the foo fragment. We selected it, changed the context and then selected the target inside the foo fragment. But noticed we then called `context()` without any arguments — **that will reset the context to document!** This is very important because other parts of the code could be expecting that to be the context for this template. Because of that pitfall, I'd recommend keeping the templates within the context they'll be used in. | ||
> The context is attached to the stamp, so setting it for one template won't interfere on the others. But beware that templates are defined by the selector you use. Two components with the same selector on different contexts will be seen as the same component. Avoiding this pitfall is super simple: don't use the same selector for different components. | ||
## API | ||
- `get()` <small>:string</small> Load a template by passing its selector. `Stamp('selector')` and `Stamp.get('selector')` are synonymous. | ||
- `alias()` <small>:string</small> Give the current stamp an alias, so it's easy to retrieve it later by calling `Stamp.get(alias)`. | ||
- `stamp()` <small>:function</small> Creates the component from the template, mutates it and appends to the target (by default, the template's container). If an argument function is passed, it will be run against the element *after* it is appended. | ||
- `alias()` <small>:string</small> Give the current stamp an alias, so it's easy to retrieve it later by calling `Stamp.get(alias)`. | ||
- `cap()` <small>:number</small> Set the maximum amount of this component the target may take. Additonal stamps (from the same template) will be ignored. | ||
- `change()` <small>:function</small> Defines a mutator function to be called just before stamping. The function receives the component instance **before** it is appended to the DOM, so manipulations on it are cheaper and you don't get FOUC. | ||
- `target()` <small>:string</small> Pass a selector to define a new target for the stamp. By default, the target is the template's parent element. | ||
- `keep()` <small>:number</small> Set the number of the component's instances you **do not** want to delete when calling `clear()` or `clearAll()`. This setting will spare the first *n* components found. | ||
- `cap()` <small>:number</small> Set the maximum amount of this component the target may take. Additonal stamps (from the same template) will be ignored. | ||
- `clear()` Deletes all stamps from the current template in the current target (by default, the template's parent element). | ||
- `clearAll()` Deletes all elements in the current target, except for `<template>` tags. This will target not only stamps, so use it carefully. | ||
- `debug()` <small>:bool</small> A minor tool that logs to the console the current stamp configuration. A truthy argument will cause debug() to return an object with the data instead of logging to console. | ||
- `execute()` <small>:function</small> Allows you to run a callback on any point in the chain. The function will receive the stamp object as an argument. Use it for side-effects or debugging. | ||
- `debug()` <small>:bool</small> A minor tool that logs to the console the current stamp configuration. A truthy argument will cause debug() to return an object with the data instead of logging to console. | ||
- `get()` <small>:string :obj</small> Loads a template by passing its selector — `Stamp('selector')` and `Stamp.get('selector')` are synonymous. The optional second arguments is a config object that may contain either the properties `override` and `context`. The first, `override` will discard any previous configuration made to the stamp, like mutator function or target. The second, `context` requires an object to be traversed intead of the document in search of selections. When setting context, the stamp is also overridden by default. | ||
- `keep()` <small>:number</small> Set the number of the component's instances you **do not** want to delete when calling `clear()` or `clearAll()`. This setting will spare the first *n* components found. | ||
- `stamp()` <small>:function</small> Creates the component from the template, mutates it and appends to the target (by default, the template's container). If an argument function is passed, it will be run against the element *after* it is appended. | ||
- `target()` <small>:string</small> Pass a selector to define a new target for the stamp. By default, the target is the template's parent element. |
@@ -6,5 +6,5 @@ const stampData = {} | ||
function StampData (selector) { | ||
function StampData (selector, context) { | ||
this.selector = selector | ||
this.template = document.querySelector(selector) | ||
this.template = context.querySelector(selector) | ||
this.target = this.template.parentElement | ||
@@ -14,10 +14,11 @@ this.cap = Infinity | ||
this.mutator = identity | ||
this.context = context | ||
} | ||
function createNewStamp (selector) { | ||
stampData[selector] = new StampData(selector) | ||
function createNewStamp (selector, context) { | ||
stampData[selector] = new StampData(selector, context) | ||
} | ||
function Stamp (selector) { | ||
let data = {} | ||
function Stamp (selector, config={}) { | ||
let data = { context: config.context || document } | ||
@@ -38,10 +39,16 @@ function count () { | ||
const api = { | ||
get (selector) { | ||
const lookup = aliasData[selector] | ||
get (selector, config={}) { | ||
const context = config.context || document | ||
const override = config.override || false | ||
const originalSelector = aliasData[selector] | ||
? aliasData[selector] | ||
: selector | ||
if (!stampData[lookup]) { | ||
createNewStamp(lookup) | ||
if (!stampData[originalSelector] || override || config.context) { | ||
createNewStamp(originalSelector, context) | ||
} | ||
data = stampData[lookup] | ||
data = stampData[originalSelector] | ||
return this | ||
@@ -72,5 +79,9 @@ }, | ||
target (targetSelector) { | ||
data.target = document.querySelector(targetSelector) | ||
data.target = data.context.querySelector(targetSelector) | ||
return this | ||
}, | ||
context (element=document) { | ||
data.context = element | ||
return this | ||
}, | ||
keep (keepAmount) { | ||
@@ -106,3 +117,3 @@ data.keep = keepAmount | ||
if (selector) api.get(selector) | ||
if (selector) api.get(selector, config) | ||
return api | ||
@@ -109,0 +120,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30460
618
158