@gullerya/spotlight
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -5,7 +5,12 @@ const | ||
SHAPE_KEY = Symbol('shape.key'), | ||
TD_KEY = Symbol('td.key'), | ||
RENDER_KEY = Symbol('render.key'), | ||
COORDS_EXTRACTOR_KEY = Symbol('coords.extractor.key'), | ||
RENDER_KEY = Symbol('render.key'), | ||
SHAPES = Object.freeze({ circle: 'circle', oval: 'oval', box: 'box' }), | ||
DEFAULT_SHAPE = SHAPES.circle, | ||
DEFAULT_TD = 333, | ||
DEFAULT_OPTIONS = Object.freeze({ | ||
shape: SHAPES.circle | ||
shape: SHAPES.circle, | ||
transitionDuration: DEFAULT_TD | ||
}); | ||
@@ -26,2 +31,3 @@ | ||
sls.shape = opts.shape; | ||
sls[TD_KEY] = opts.transitionDuration; | ||
@@ -44,3 +50,2 @@ // setting the target last | ||
bottom: 0; | ||
color: #000; | ||
z-index: 999; | ||
@@ -51,4 +56,7 @@ overflow: hidden; | ||
:host(.shown) .spotlight { | ||
opacity: 0.4; | ||
border-color: rgba(0, 0, 0, 0.5); | ||
} | ||
:host(.shown) .inner-fence { | ||
border-color: rgba(255, 255, 0, 1); | ||
} | ||
@@ -58,21 +66,30 @@ .spotlight { | ||
border: 200vmax solid; | ||
border-color: rgba(0, 0, 0, 0); | ||
transform: translate(-50%, -50%); | ||
opacity: 0; | ||
transition: all 333ms; | ||
transition: all var(--t-d); | ||
} | ||
:host .spotlight.border { | ||
border: 3px solid #ff0; | ||
opacity: 1; | ||
.inner-fence { | ||
position: absolute; | ||
top: -2px; | ||
left: -2px; | ||
right: -2px; | ||
bottom: -2px; | ||
border: 3px solid; | ||
border-color: rgba(255, 255, 0, 0); | ||
transition: all var(--t-d); | ||
} | ||
:host(.box) .spotlight { | ||
.box, | ||
.box > .inner-fence { | ||
border-radius: calc(200vmax + 24px); | ||
} | ||
:host(.oval) .spotlight { | ||
.oval, | ||
.oval > .inner-fence { | ||
border-radius: 50%; | ||
} | ||
:host(.circle) .spotlight { | ||
.circle, | ||
.circle > .inner-fence { | ||
border-radius: 50%; | ||
@@ -82,4 +99,5 @@ } | ||
<div class="spotlight shadow"></div> | ||
<div class="spotlight border"></div> | ||
<div class="spotlight"> | ||
<div class="inner-fence"></div> | ||
</div> | ||
`; | ||
@@ -95,2 +113,3 @@ | ||
connectedCallback() { | ||
this.shadowRoot.host.style.setProperty('--t-d', this[TD_KEY] + 'ms'); | ||
if (typeof this.offsetWidth === 'number') { | ||
@@ -116,2 +135,15 @@ this.classList.add('shown'); | ||
get transitionDuration() { | ||
return this[TD_KEY]; | ||
} | ||
set transitionDuration(td) { | ||
if (td && typeof td === 'number') { | ||
this[TD_KEY] = td; | ||
this.shadowRoot.host.style.setProperty('--t-d', this[TD_KEY] + 'ms'); | ||
} else { | ||
console.error('invalid transition duration (' + td + '), staying on the present value (' + this[TD_KEY] + ')'); | ||
} | ||
} | ||
get target() { | ||
@@ -122,2 +154,6 @@ return this[TARGET_KEY]; | ||
set target(target) { | ||
this.moveTo(target); | ||
} | ||
moveTo(target) { | ||
if (this[TARGET_KEY] === target) { | ||
@@ -135,11 +171,13 @@ return; | ||
this[TARGET_KEY] = target; | ||
this[RENDER_KEY](); | ||
return this[RENDER_KEY](); | ||
} | ||
close() { | ||
const sl = this.shadowRoot.querySelector('.spotlight'); | ||
sl.addEventListener('transitionend', () => { | ||
this[PARENT_KEY].removeChild(this); | ||
this.classList.remove('shown'); | ||
return new Promise(resolve => { | ||
setTimeout(() => { | ||
this[PARENT_KEY].removeChild(this); | ||
resolve(); | ||
}, this[TD_KEY]); | ||
}); | ||
this.classList.remove('shown'); | ||
} | ||
@@ -170,15 +208,14 @@ | ||
} | ||
const sle = this.shadowRoot.querySelectorAll('.spotlight'); | ||
sle.forEach(e => { | ||
e.style.top = coords.y + coords.height / 2 + 'px'; | ||
e.style.left = coords.x + coords.width / 2 + 'px'; | ||
e.style.width = w + 'px'; | ||
e.style.height = h + 'px'; | ||
const sle = this.shadowRoot.querySelector('.spotlight'); | ||
return new Promise(resolve => { | ||
sle.className = 'spotlight ' + s; | ||
Object.assign(sle.style, { | ||
top: coords.y + coords.height / 2 + 'px', | ||
left: coords.x + coords.width / 2 + 'px', | ||
width: w + 'px', | ||
height: h + 'px' | ||
}); | ||
setTimeout(resolve, this[TD_KEY]); | ||
}); | ||
Object.keys(SHAPES).forEach(sk => { | ||
if (SHAPES[sk] !== s) { | ||
this.classList.remove(SHAPES[sk]); | ||
} | ||
}); | ||
this.classList.add(s); | ||
} | ||
@@ -203,5 +240,9 @@ | ||
if (!opts.shape || !(opts.shape in SHAPES)) { | ||
console.error('invalid shape (' + opts.shape + '), falling back to the default (circle)'); | ||
opts.shape = SHAPES.circle; | ||
console.error('invalid shape (' + opts.shape + '), falling back to the default (' + DEFAULT_SHAPE + ')'); | ||
opts.shape = DEFAULT_SHAPE; | ||
} | ||
if (!opts.transitionDuration || typeof opts.transitionDuration !== 'number') { | ||
console.error('invalid transition duration (' + opts.transitionDuration + '), falling back to the default (' + DEFAULT_TD + ')'); | ||
opts.transitionDuration = DEFAULT_TD; | ||
} | ||
} |
@@ -1,1 +0,1 @@ | ||
const t=Symbol("parent.key"),e=Symbol("target.key"),n=Symbol("shape.key"),o=Symbol("coords.extractor.key"),s=Symbol("render.key"),r=Object.freeze({circle:"circle",oval:"oval",box:"box"}),i=Object.freeze({shape:r.circle});export{r as SHAPES,a as spotlight};function a(e,n,o){const s=Object.assign({},i,o,{target:e,parent:n||document.body});!function(t){if(!t.target||t.target.nodeType!==Node.ELEMENT_NODE||t.target===document.body)throw new Error("invalid target ("+t.target+")");if(!t.parent||t.parent.nodeType!==Node.ELEMENT_NODE)throw new Error("invalid parent ("+t.parent+")");if(!t.parent.contains(t.target)||t.parent===t.target)throw new Error("target MUST be a child of a given parent; they MAY NOT be the same element");t.shape&&t.shape in r||(console.error("invalid shape ("+t.shape+"), falling back to the default (circle)"),t.shape=r.circle)}(s);const a=document.createElement("spotlight-scene");return a[t]=s.parent,a.shape=s.shape,a.target=s.target,a[t].appendChild(a),a}const h=document.createElement("template");h.innerHTML='\n\t<style>\n\t\t:host {\n\t\t\tposition: absolute;\n\t\t\ttop: 0;\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\tbottom: 0;\n\t\t\tcolor: #000;\n\t\t\tz-index: 999;\n\t\t\toverflow: hidden;\n\t\t}\n\n\t\t:host(.shown) .spotlight {\n\t\t\topacity: 0.4;\n\t\t}\n\n\t\t.spotlight {\n\t\t\tposition: absolute;\n\t\t\tborder: 200vmax solid;\n\t\t\ttransform: translate(-50%, -50%);\n\t\t\topacity: 0;\n\t\t\ttransition: all 333ms;\n\t\t}\n\n\t\t:host .spotlight.border {\n\t\t\tborder: 3px solid #ff0;\n\t\t\topacity: 1;\n\t\t}\n\n\t\t:host(.box) .spotlight {\n\t\t\tborder-radius: calc(200vmax + 24px);\n\t\t}\n\n\t\t:host(.oval) .spotlight {\n\t\t\tborder-radius: 50%;\n\t\t}\n\n\t\t:host(.circle) .spotlight {\n\t\t\tborder-radius: 50%;\n\t\t}\n\t</style>\n\n\t<div class="spotlight shadow"></div>\n\t<div class="spotlight border"></div>\n',customElements.define("spotlight-scene",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).appendChild(h.content.cloneNode(!0))}connectedCallback(){"number"==typeof this.offsetWidth&&this.classList.add("shown")}get parent(){return this[t]}get shape(){return this[n]}set shape(t){this[n]!==t&&(this[n]=t,this[s]())}get target(){return this[e]}set target(n){if(this[e]!==n){if(!n||n.nodeType!==Node.ELEMENT_NODE||n===document.body)throw new Error("invalid target");if(!this[t].contains(n)||this[t]===n)throw new Error("target MUST be a child of a given parent; they MAY NOT be the same element");this[e]=n,this[s]()}}close(){this.shadowRoot.querySelector(".spotlight").addEventListener("transitionend",()=>{this[t].removeChild(this)}),this.classList.remove("shown")}[s](){if(!this[e])return;const t=this[o](this[e]);let s,i,a;switch(this[n]){case r.box:s=t.width+24,i=t.height+24,a=r.box;break;case r.oval:s=t.width*Math.pow(2,.5),i=t.height*Math.pow(2,.5),a=r.oval;break;case r.circle:default:s=i=Math.pow(Math.pow(t.width,2)+Math.pow(t.height,2),.5)+12,a=r.circle}this.shadowRoot.querySelectorAll(".spotlight").forEach(e=>{e.style.top=t.y+t.height/2+"px",e.style.left=t.x+t.width/2+"px",e.style.width=s+"px",e.style.height=i+"px"}),Object.keys(r).forEach(t=>{r[t]!==a&&this.classList.remove(r[t])}),this.classList.add(a)}[o](t){return t.getBoundingClientRect()}}); | ||
const t=Symbol("parent.key"),e=Symbol("target.key"),n=Symbol("shape.key"),o=Symbol("td.key"),r=Symbol("render.key"),i=Symbol("coords.extractor.key"),s=Object.freeze({circle:"circle",oval:"oval",box:"box"}),a=s.circle,h=333,l=Object.freeze({shape:s.circle,transitionDuration:h});export{s as SHAPES,c as spotlight};function c(e,n,r){const i=Object.assign({},l,r,{target:e,parent:n||document.body});!function(t){if(!t.target||t.target.nodeType!==Node.ELEMENT_NODE||t.target===document.body)throw new Error("invalid target ("+t.target+")");if(!t.parent||t.parent.nodeType!==Node.ELEMENT_NODE)throw new Error("invalid parent ("+t.parent+")");if(!t.parent.contains(t.target)||t.parent===t.target)throw new Error("target MUST be a child of a given parent; they MAY NOT be the same element");t.shape&&t.shape in s||(console.error("invalid shape ("+t.shape+"), falling back to the default ("+a+")"),t.shape=a);t.transitionDuration&&"number"==typeof t.transitionDuration||(console.error("invalid transition duration ("+t.transitionDuration+"), falling back to the default ("+h+")"),t.transitionDuration=h)}(i);const c=document.createElement("spotlight-scene");return c[t]=i.parent,c.shape=i.shape,c[o]=i.transitionDuration,c.target=i.target,c[t].appendChild(c),c}const d=document.createElement("template");d.innerHTML='\n\t<style>\n\t\t:host {\n\t\t\tposition: absolute;\n\t\t\ttop: 0;\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\tbottom: 0;\n\t\t\tz-index: 999;\n\t\t\toverflow: hidden;\n\t\t}\n\n\t\t:host(.shown) .spotlight {\n\t\t\tborder-color: rgba(0, 0, 0, 0.5);\n\t\t}\n\t\t:host(.shown) .inner-fence {\n\t\t\tborder-color: rgba(255, 255, 0, 1);\n\t\t}\n\n\t\t.spotlight {\n\t\t\tposition: absolute;\n\t\t\tborder: 200vmax solid;\n\t\t\tborder-color: rgba(0, 0, 0, 0);\n\t\t\ttransform: translate(-50%, -50%);\n\t\t\ttransition: all var(--t-d);\n\t\t}\n\n\t\t.inner-fence {\n\t\t\tposition: absolute;\n\t\t\ttop: -2px;\n\t\t\tleft: -2px;\n\t\t\tright: -2px;\n\t\t\tbottom: -2px;\n\t\t\tborder: 3px solid;\n\t\t\tborder-color: rgba(255, 255, 0, 0);\n\t\t\ttransition: all var(--t-d);\n\t\t}\n\n\t\t.box,\n\t\t.box > .inner-fence {\n\t\t\tborder-radius: calc(200vmax + 24px);\n\t\t}\n\n\t\t.oval,\n\t\t.oval > .inner-fence {\n\t\t\tborder-radius: 50%;\n\t\t}\n\n\t\t.circle,\n\t\t.circle > .inner-fence {\n\t\t\tborder-radius: 50%;\n\t\t}\n\t</style>\n\n\t<div class="spotlight">\n\t\t<div class="inner-fence"></div>\n\t</div>\n',customElements.define("spotlight-scene",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).appendChild(d.content.cloneNode(!0))}connectedCallback(){this.shadowRoot.host.style.setProperty("--t-d",this[o]+"ms"),"number"==typeof this.offsetWidth&&this.classList.add("shown")}get parent(){return this[t]}get shape(){return this[n]}set shape(t){this[n]!==t&&(this[n]=t,this[r]())}get transitionDuration(){return this[o]}set transitionDuration(t){t&&"number"==typeof t?(this[o]=t,this.shadowRoot.host.style.setProperty("--t-d",this[o]+"ms")):console.error("invalid transition duration ("+t+"), staying on the present value ("+this[o]+")")}get target(){return this[e]}set target(t){this.moveTo(t)}moveTo(n){if(this[e]!==n){if(!n||n.nodeType!==Node.ELEMENT_NODE||n===document.body)throw new Error("invalid target");if(!this[t].contains(n)||this[t]===n)throw new Error("target MUST be a child of a given parent; they MAY NOT be the same element");return this[e]=n,this[r]()}}close(){return this.classList.remove("shown"),new Promise(e=>{setTimeout(()=>{this[t].removeChild(this),e()},this[o])})}[r](){if(!this[e])return;const t=this[i](this[e]);let r,a,h;switch(this[n]){case s.box:r=t.width+24,a=t.height+24,h=s.box;break;case s.oval:r=t.width*Math.pow(2,.5),a=t.height*Math.pow(2,.5),h=s.oval;break;case s.circle:default:r=a=Math.pow(Math.pow(t.width,2)+Math.pow(t.height,2),.5)+12,h=s.circle}const l=this.shadowRoot.querySelector(".spotlight");return new Promise(e=>{l.className="spotlight "+h,Object.assign(l.style,{top:t.y+t.height/2+"px",left:t.x+t.width/2+"px",width:r+"px",height:a+"px"}),setTimeout(e,this[o])})}[i](t){return t.getBoundingClientRect()}}); |
{ | ||
"name": "@gullerya/spotlight", | ||
"version": "1.1.0", | ||
"description": "spotlight an abitrary DOM element or viewport area while fading out the rest of the content", | ||
"version": "1.2.0", | ||
"description": "spotlight an abitrary DOM element while fading out the rest of the content", | ||
"keywords": [ | ||
"spotlight", | ||
"highlight", | ||
"focus", | ||
"emphasize", | ||
"callout", | ||
@@ -9,0 +11,0 @@ "shading", |
@@ -18,3 +18,8 @@ [![GitHub](https://img.shields.io/github/license/gullerya/spotlight.svg)](https://github.com/gullerya/spotlight) | ||
* __1.0.1__ | ||
* __1.2.0__ | ||
* added customizable transition duration | ||
* added API `moveTo` (same as setting the target, but returns `Promise`, resolved when finished) | ||
* `close` API also returns `Promise`, resolved when all done | ||
* __1.1.0__ | ||
* initial release | ||
@@ -57,3 +62,4 @@ | ||
* `options` <small>[optional]</small> | ||
- TBD | ||
- `shape` - see `shape property definition of the `spotlight-scene` API below | ||
- `transition-duration` - see `transition-duration` property definition of the `spotlight-scene` below | ||
@@ -77,7 +83,6 @@ # `spotlight-scene` component APIs | ||
#### properties: | ||
* `sls.container` <small>[read only]</small> | ||
* `sls.container` <small>[DOM element] [read only]</small> | ||
- returns the `container` element that the component was initialized with (see base API above) | ||
- `container` MAY NOT be changed | ||
* `sls.target` | ||
- returns the currently 'spotlighted' element (the current `target`) | ||
* `sls.target` <small>[DOM element]</small> - 'spotted' element | ||
- setting this property will move the 'spotlight' to another `target` | ||
@@ -87,14 +92,19 @@ - acceptible values are subject to the same constraints as in the main API | ||
- MUST be a descendend of the `container` | ||
* `sls.shape` | ||
- returns the currently used shape | ||
* `sls.shape` <small>[enum]</small> - shape of the spotlight, defaults to `circle` | ||
- setting this property on a 'living' component will be immediatelly applied | ||
- acceptible values: | ||
- `circle` <small>[default]</small> | ||
- `circle` | ||
- `oval` | ||
- `box` | ||
- values better to be taken from the `SHAPES` enum, like `SHAPES.circle` | ||
* `transition-duration` <small>[number]</small> - duration in millis of spotlight's transitions (move from target to target, shape change, etc); defaults to 333 | ||
- setting this property will be effective from the next transition forth | ||
#### methods: | ||
* `sls.close()` | ||
- returns `Promise`, resolved when all done | ||
- removes the `spotlight-scene` component and performs all relevant cleanups | ||
* `sls.moveTo(targetElement)` | ||
- returns `Promise`, resolved when move it finished | ||
- `targetElement` subject to the same constraints `target` property above | ||
@@ -106,2 +116,3 @@ # Typical usage example | ||
const t2 = <... another one>; | ||
const t3 = <... another one>; | ||
@@ -118,3 +129,7 @@ const sl = spotlight(t1); // the spotlight is shown now | ||
sl.remove(); | ||
sl.transitionDuration = 500; // slow it down a bit | ||
sl.moveTo(t3) | ||
.then(() => console.log('spotlight moved, do something...')); | ||
sl.close(); | ||
``` |
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
18296
203
130