@phun-ky/speccer 9.0.13 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,8 +27,13 @@
27
27
  - [Curly brackets](#curly-brackets)
28
28
  - [Element typography](#element-typography)
29
29
  - [Mark elements](#mark-elements)
30
+ - [A11y notation](#a11y-notation)
31
+ - [Tab stops](#tab-stops)
32
+ - [Landmarks and regions](#landmarks-and-regions)
33
+ - [Keys and shortcut](#keys-and-shortcut)
30
34
  - [Customization](#customization)
31
35
  - [Contributing](#contributing)
36
+ - [Sponsor me](#sponsor-me)
32
37
 
33
38
  ## About
34
39
 
@@ -313,9 +318,37 @@ In your component examples, use the following attribute.
313
318
  <div data-speccer-mark …>…</div>
314
319
  ```
315
320
 
321
+ ### A11y notation
322
+
323
+ With speccer, you can also display accessibility notation, like [Accessibility Bluelines](https://dribbble.com/shots/6269661-Accessibility-Bluelines?utm_source=Clipboard_Shot&utm_campaign=jeremyelder&utm_content=Accessibility%20Bluelines&utm_medium=Social_Share&utm_source=Clipboard_Shot&utm_campaign=jeremyelder&utm_content=Accessibility%20Bluelines&utm_medium=Social_Share):
324
+
325
+ Prior art: [Jeremy Elder](https://twitter.com/JeremyElder)
326
+
327
+ #### Tab stops
328
+
329
+ ![Screenshot of speccer a11y tab stops in use](./public/a11y-tabstop.png)
330
+
331
+ If you want to display tab stops, append `data-speccer-a11y-tabstops` as an attribute to the container you want to display the tab stops in.
332
+
333
+ #### Landmarks and regions
334
+
335
+ ![Screenshot of speccer a11y landmarks in use](./public/a11y-landmark.png)
336
+
337
+ If you want to display landmarks and regions, append `data-speccer-a11y-landmark` as an attribute to the container you want to display the landmarks and regions in.
338
+
339
+ #### Keys and shortcut
340
+
341
+ ![Screenshot of speccer a11y shortcuts in use](./public/a11y-shortcut.png)
342
+
343
+ If you want to display the shortcut with keys used for elements, use `data-speccer-a11y-shortcut="<shortcut>"` on the element that uses this shortcut:
344
+
345
+ ```html
346
+ <button type="button" data-speccer-a11y-shortcut="ctrl + s">Save</button>
347
+ ```
348
+
316
349
  ## Customization
317
350
 
318
- ![Image of speccer dark mode](./public/darkmode.png)
351
+ ![Screenshot of speccer in a dark mode example](./public/darkmode.png)
319
352
 
320
353
  Allthough the styling works nicely with dark mode, you can use the provided CSS variables to customize the look and feel. If more control is needed, you can use CSS overrides :)
321
354
 
@@ -352,3 +385,11 @@ Allthough the styling works nicely with dark mode, you can use the provided CSS
352
385
  ## Contributing
353
386
 
354
387
  If you want to contribute, please read the [CONTRIBUTING.md](https://github.com/phun-ky/speccer/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/phun-ky/speccer/blob/main/CODE_OF_CONDUCT.md)
388
+
389
+ ## Sponsor me
390
+
391
+ I'm an Open Source evangelist, creating stuff that does not exist yet to help get rid of secondary activities and to enhance systems already in place, be it documentation or web sites.
392
+
393
+ The sponsorship is an unique opportunity to alleviate more hours for me to maintain my projects, create new ones and contribute to the large community we're all part of :)
394
+
395
+ [Support me with GitHub Sponsors](https://github.com/sponsors/phun-ky).
package/dist/speccer.css CHANGED
@@ -24,6 +24,8 @@
24
24
  --ph-speccer-line-width: 1px;
25
25
  --ph-speccer-line-width-negative: -1px;
26
26
  --ph-speccer-measure-size: 8px;
27
+ --ph-speccer-a11y-color-background: #1868b2;
28
+ --ph-speccer-a11y-landmark-color-background: #7e60c5;
27
29
  }
28
30
  svg.ph-speccer,
29
31
  .ph-speccer.speccer,
@@ -736,3 +738,116 @@ svg.ph-speccer .ph-speccer.path {
736
738
  border-style: solid;
737
739
  position: absolute;
738
740
  }
741
+ [data-speccer-a11y] {
742
+ counter-reset: speccer-a11y-tabstops;
743
+ }
744
+ .ph-speccer.speccer.a11y.tabstops {
745
+ position: absolute;
746
+ height: 48px;
747
+ width: 48px;
748
+ background-color: var(--ph-speccer-a11y-color-background);
749
+ border-radius: 0.5rem;
750
+ color: var(--ph-speccer-color-text-light);
751
+ font-family: var(--ph-speccer-font-family);
752
+ counter-increment: speccer-a11y-tabstops;
753
+ border: 3px solid var(--ph-speccer-a11y-color-background);
754
+ }
755
+ .ph-speccer.speccer.a11y.tabstops::before {
756
+ position: absolute;
757
+ top: calc(0.5rem - 2px);
758
+ left: calc(0.5rem - 2px);
759
+ content: counter(speccer-a11y-tabstops);
760
+ font-size: 12px;
761
+ text-align: left;
762
+ }
763
+ .ph-speccer.speccer.a11y.tabstops::after {
764
+ display: flex;
765
+ justify-content: flex-end;
766
+ align-items: flex-end;
767
+ position: absolute;
768
+ left: 0.5rem;
769
+ right: 0.5rem;
770
+ bottom: 0.5rem;
771
+ height: 2rem;
772
+ content: "⇥";
773
+ font-size: 2rem;
774
+ color: var(--ph-speccer-color-text-light);
775
+ font-family: var(--ph-speccer-font-family);
776
+ }
777
+ .ph-speccer.speccer.a11y.landmark {
778
+ position: absolute;
779
+ height: 48px;
780
+ width: 48px;
781
+ background-color: var(--ph-speccer-a11y-landmark-color-background);
782
+ border-radius: 0.5rem;
783
+ color: var(--ph-speccer-color-text-light);
784
+ font-family: var(--ph-speccer-font-family);
785
+ border: 3px solid var(--ph-speccer-a11y-landmark-color-background);
786
+ box-shadow: inset 0 0 0 2px var(--ph-speccer-color-text-light);
787
+ justify-content: center;
788
+ font-size: 1rem;
789
+ line-height: 100%;
790
+ align-items: center;
791
+ padding: 0.5rem;
792
+ pointer-events: auto;
793
+ }
794
+ .ph-speccer.speccer.a11y.landmark::after {
795
+ top: 100%;
796
+ left: 50%;
797
+ border: solid transparent;
798
+ content: "";
799
+ height: 0;
800
+ width: 0;
801
+ position: absolute;
802
+ pointer-events: none;
803
+ border-color: rgba(126,96,197,0);
804
+ border-top-color: var(--ph-speccer-a11y-landmark-color-background);
805
+ border-width: 12px;
806
+ margin-left: -12px;
807
+ }
808
+ .ph-speccer.speccer.a11y.region {
809
+ position: absolute;
810
+ outline: 2px solid var(--ph-speccer-a11y-landmark-color-background);
811
+ outline-offset: 2px;
812
+ }
813
+ .ph-speccer.speccer.a11y.shortcut-holder {
814
+ position: absolute;
815
+ height: 48px;
816
+ min-width: 120px;
817
+ display: flex;
818
+ flex-direction: row;
819
+ justify-content: flex-start;
820
+ align-items: center;
821
+ grid-gap: 0.5rem;
822
+ }
823
+ .ph-speccer.speccer.a11y.shortcut-holder kbd.ph-speccer.speccer.a11y.shortcut {
824
+ flex-shrink: 0;
825
+ position: relative;
826
+ background-color: var(--ph-speccer-a11y-color-background);
827
+ border-radius: 0.5rem;
828
+ color: var(--ph-speccer-color-text-light);
829
+ font-family: var(--ph-speccer-font-family);
830
+ display: inline-flex;
831
+ text-transform: uppercase;
832
+ height: 48px;
833
+ border: 3px solid var(--ph-speccer-a11y-color-background);
834
+ min-width: 48px;
835
+ font-size: 1.5rem;
836
+ justify-content: center;
837
+ align-items: center;
838
+ }
839
+ .ph-speccer.speccer.a11y.shortcut-holder kbd.ph-speccer.speccer.a11y.shortcut.modifier {
840
+ justify-content: flex-start;
841
+ align-items: flex-end;
842
+ padding: 0.25rem;
843
+ font-size: 1rem;
844
+ width: 80px;
845
+ text-transform: lowercase;
846
+ }
847
+ .ph-speccer.speccer.a11y.shortcut-holder kbd.ph-speccer.speccer.a11y.shortcut.physical {
848
+ justify-content: flex-start;
849
+ align-items: flex-end;
850
+ padding: 0.25rem;
851
+ font-size: 1rem;
852
+ text-transform: lowercase;
853
+ }
@@ -1,2 +1,28 @@
1
- var t,e,o;!function(t){t.Empty="",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top"}(t||(t={})),function(t){t.Outline="outline",t.Enclose="enclose",t.Full="full",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top",t.SVG="svg",t.Curly="curly"}(e||(e={})),function(t){t.Width="width",t.Height="height",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top"}(o||(o={}));const i=t=>t.split(" "),n=t=>i(t).includes(e.Right),r=t=>i(t).includes(e.Bottom),s=t=>i(t).includes(e.Full),a=t=>i(t).includes(e.Enclose),p=t=>t.includes(e.Curly)&&t.includes(e.Full),c=t=>"string"==typeof t,l=t=>!c(t),h=t=>"number"==typeof t,d=t=>!h(t),f=t=>void 0===t,m=()=>new Promise(requestAnimationFrame),u=t=>t.top,g=t=>t.left+t.width,y=t=>t.top+t.height,w=t=>t.left,x=t=>t.left+t.width/2,b=t=>t.top+t.height/2,E={center:t=>({x:x(t),y:b(t)}),top:t=>({x:x(t),y:u(t)}),right:t=>({x:g(t),y:b(t)}),bottom:t=>({x:x(t),y:y(t)}),left:t=>({x:w(t),y:b(t)}),"right-top":t=>({x:g(t),y:u(t)}),"right-bottom":t=>({x:g(t),y:y(t)}),"left-top":t=>({x:w(t),y:u(t)}),"left-bottom":t=>({x:w(t),y:y(t)}),"top-left":t=>({x:w(t),y:u(t)}),"top-right":t=>({x:g(t),y:u(t)}),"bottom-left":t=>({x:w(t),y:y(t)}),"bottom-right":t=>({x:g(t),y:y(t)}),"top-center":t=>({x:x(t),y:u(t)}),"right-center":t=>({x:g(t),y:b(t)}),"bottom-center":t=>({x:x(t),y:y(t)}),"left-center":t=>({x:w(t),y:b(t)})},$=async(t,e="center")=>{if(!e)throw Error("No position given");if(l(e))throw Error("The position given is not the required type: pos: "+typeof e);const o=["center","left","right","top","bottom","right-top","right-bottom","left-top","left-bottom","top-left","top-right","bottom-left","bottom-right","top-center","right-center","bottom-center","left-center"];if(!o.includes(e))throw Error(`The position given does not match allowed positions to use! Valid positions are: ${o.join(", ")}`);await m();const i=t.getBoundingClientRect();return E[e](i)},A=async(t,e,o="center",i="center")=>{if(!t||!e)throw Error("No element given");const{x:n,y:r}=await $(t,o),{x:s,y:a}=await $(e,i);return{x1:n,y1:r,x2:s,y2:a}},v=(t,e)=>{const{x1:o,x2:i,y1:n,y2:r}=t,{direct:s=!1,firstSet:a=!1,direction:p}=e;let c={x:o+(i-o)/2,y:n},l={x:o+(i-o)/2,y:r};return s&&(a?"west"===p?(c={x:o-32,y:n-8},l={x:i+32,y:r}):"south"===p?(c={x:o-8,y:n+32},l={x:i,y:r-32}):"east"===p?(c={x:o+32,y:n-8},l={x:i-32,y:r}):(c={x:o-8,y:n-32},l={x:i,y:r+32}):"west"===p?(c={x:o-32,y:n+8},l={x:i+32,y:r}):"south"===p?(c={x:o+8,y:n+32},l={x:i,y:r-32}):"east"===p?(c={x:o+32,y:n+8},l={x:i-32,y:r}):(c={x:o+8,y:n-32},l={x:i,y:r+32})),{firstPoint:{x:o,y:n},firstControl:c,lastPoint:{x:i,y:r},lastControl:l}},S=async(t,e,o)=>{const{pos1:i,pos2:n,firstSet:r=!1,direction:s}=o,{x1:a,y1:p,x2:c,y2:l}=await A(t,e,i,n);let h=0,d=0;"north"===s?d=8:"west"===s?h=8:"east"===s?h=-8:"south"===s&&(d=-8);const{firstPoint:f,firstControl:m,lastControl:u,lastPoint:g}=v({x1:a+0,x2:c+h,y1:p+0+document.documentElement.scrollTop,y2:l+d+document.documentElement.scrollTop},{direct:!0,firstSet:r,direction:s});return`M ${f.x} ${f.y}C ${m.x} ${m.y}, ${u.x} ${u.y}, ${g.x} ${g.y}`},P=async({start:t,stop:e,crude:o=!1})=>{const{x1:i,y1:n,x2:r,y2:s}=await A(t,e),a=((t,e,o,i,n=!0)=>{if(f(t)||f(e)||f(o)||f(i))throw new SyntaxError("Missing input for `angle`");if(d(t)||d(e)||d(o)||d(i))throw TypeError(`Parameters for \`angle\` do not have the required type. Requires number! Got: ${typeof t} ${typeof e} ${typeof o} ${typeof i}`);const r=i-e,s=o-t;let a=Math.atan2(r,s);return a*=180/Math.PI,n&&a<0&&(a+=360),a})(i,n,r,s);return o?(t=>{if(t>360)throw new RangeError("Parameter cannot exceed 360");if(t<0)throw new RangeError("Parameter cannot be lower than 0");return t>=45&&t<=135?"south":t>135&&t<=225?"west":t>225&&t<=315?"north":"east"})(a):(t=>{if(t>360)throw new RangeError("Parameter cannot exceed 360");if(t<0)throw new RangeError("Parameter cannot be lower than 0");return t>=0&&t<=22.5?"east":t>=22.5&&t<=67.5?"south-east":t>=67.5&&t<=112.5?"south":t>=112.5&&t<=157.5?"south-west":t>=157.5&&t<=202.5?"west":t>=202.5&&t<=247.5?"north-west":t>=247.5&&t<=292.5?"north":t>=292.5&&t<=337.5?"north-east":"east"})(a)},C=()=>"_"+Math.random().toString(36).substring(2,11),B=async(t,e)=>{var o;if(!(!t||!e||c(e)||h(e)||(o=e,"boolean"==typeof o)||Array.isArray(e)&&!e.length||!Object.keys(e).length&&e.constructor===Object))if(await m(),Array.isArray(e))for(const o of e)t.style[o.key]=o.value;else for(const o of Object.keys(e))t.style[o]=e[o]},R=async t=>(await m(),getComputedStyle(t,null));class L{#t;#e;startElement;stopElement;firstPathElement;secondPathElement;constructor(t,e){this.#o(t,e)}#o(t,e){if(!t||!e)throw new Error("Missing inputs startElement and stopElement");if(!document.body.contains(e))throw new Error("stopElement is not in the DOM");if(!document.body.contains(t))throw new Error("startElement is not in the DOM");if(this.startElement=t,this.stopElement=e,this.#t=document.getElementById("ph-speccer-svg"),this.#e=document.getElementById("ph-speccer-path"),!this.#e||!this.#t)throw new Error("Missing required SVG element to draw lines. Please see the documentation");B(this.#t,{height:`${document.body.scrollHeight}px`}),this.connect()}connect(){this.draw(this.#e)}#i(t){if(!t)throw new Error("No path given to #getPathElement!");const e=`ph_draw_path-path-${C()}`,o=t.cloneNode(!1),i=this.startElement.getAttribute("id")||C();return this.startElement.setAttribute("id",i),o.setAttribute("data-start-el",i),o.setAttribute("id",e),o.classList.remove("original"),o.classList.add("speccer"),o}async draw(t){if(!t)throw new Error("No path given to draw!");const e=this.#i(t),o=this.#i(t);if(!t.parentNode)throw new Error("No parentNode found for path");this.firstPathElement=t.parentNode.insertBefore(e,t.nextSibling),this.secondPathElement=t.parentNode.insertBefore(o,t.nextSibling);const i=await P({stop:this.stopElement,start:this.startElement,crude:!0}),{path1pos1:n,path1pos2:r,path2pos1:s,path2pos2:a}=(t=>{let e,o,i,n;switch(t){case"east":e="right-top",o="left-center",i="right-bottom",n="left-center";break;case"south":e="bottom-left",o="top-center",i="bottom-right",n="top-center";break;case"west":e="left-top",o="right-center",i="left-bottom",n="right-center";break;default:e="top-left",o="bottom-center",i="top-right",n="bottom-center"}return{path1pos1:e,path1pos2:o,path2pos1:i,path2pos2:n}})(i),p=await S(this.startElement,this.stopElement,{pos1:n,pos2:r,firstSet:!0,direction:i}),c=await S(this.startElement,this.stopElement,{pos1:s,pos2:a,direction:i});this.firstPathElement.setAttribute("data-direction",i),this.firstPathElement.setAttribute("data-pos1",n),this.firstPathElement.setAttribute("data-pos2",r),this.firstPathElement.setAttribute("d",p),this.secondPathElement.setAttribute("data-direction",i),this.secondPathElement.setAttribute("data-pos1",s),this.secondPathElement.setAttribute("data-pos2",a),this.secondPathElement.setAttribute("d",c)}}window.DrawSVGCurlyBracket=L;class T{#t;#e;startElement;stopElement;line;constructor(t,e){this.#o(t,e)}#o(t,e){if(!t||!e)throw new Error("Missing inputs startElement and stopElement");if(!document.body.contains(e))throw new Error("stopElement is not in the DOM");if(!document.body.contains(t))throw new Error("startElement is not in the DOM");if(this.startElement=t,this.stopElement=e,this.#t=document.getElementById("ph-speccer-svg"),this.#e=document.getElementById("ph-speccer-path"),!this.#e||!this.#t)throw new Error("Missing required SVG element to draw lines. Please see the documentation");B(this.#t,{height:`${document.body.scrollHeight}px`}),this.connect()}connect(){this.draw(this.#e)}async draw(t){if(!t)throw new Error("No path given to draw!");const e=`ph_draw_path-path-${C()}`,o=t.cloneNode(!1),i=this.startElement.getAttribute("id")||C();if(this.startElement.setAttribute("id",i),o.setAttribute("id",e),o.setAttribute("data-start-el",i),o.classList.remove("original"),o.classList.add("speccer"),!t.parentNode)throw new Error("No parentNode found for path");this.line=t.parentNode.insertBefore(o,t.nextSibling);const n=await P({start:this.startElement,stop:this.stopElement,crude:!0}),{pos1:r,pos2:s}=(t=>{let e,o;switch(t){case"east":e="right",o="left";break;case"south":e="bottom",o="top";break;case"west":e="left",o="right";break;default:e="top",o="bottom"}return{pos1:e,pos2:o}})(n),a=await(async(t,e,o)=>{const{pos1:i,pos2:n}=o,{x1:r,y1:s,x2:a,y2:p}=await A(t,e,i,n),{firstPoint:c,firstControl:l,lastControl:h,lastPoint:d}=v({x1:r,x2:a,y1:s,y2:p},{direction:""});return`M ${c.x} ${c.y}C ${l.x} ${l.y}, ${h.x} ${h.y}, ${d.x} ${d.y}`})(this.startElement,this.stopElement,{pos1:r,pos2:s});this.line.setAttribute("data-direction",n),this.line.setAttribute("data-pos1",r),this.line.setAttribute("data-pos2",s),this.line.setAttribute("d",a)}}window.DrawSVGLine=T;const N=(t,e,o="noop")=>{t&&(!e||e&&!e.length||e.trim().split(" ").filter((t=>t!==o)).forEach((e=>t.classList.add(e))))},I=(t,e)=>t?!e&&l(t)?Object.keys(t).filter((e=>t[e])).join(" ").trim():`${t.trim()} ${e?Object.keys(e).filter((t=>e[t])).join(" "):""}`.trim():"",M=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"],O=t=>parseInt(t,10),q=t=>t.includes("Top")?t.replace("Top"," top"):t.includes("Right")?t.replace("Right"," right"):t.includes("Bottom")?t.replace("Bottom"," bottom"):t.includes("Left")?t.replace("Left"," left"):"",H=t=>O(getComputedStyle(t).getPropertyValue("--ph-speccer-pin-space"))||48,k=(t,e,o)=>t-e.width/2+o.width/2,V=(t,e,o)=>t-e.height/2+o.height/2,W=async t=>{await m();const e=t.getBoundingClientRect(),o=e.top+window.scrollY,i=e.left+window.scrollX;return{height:e.height,width:e.width,top:o,left:i}},z=async(t,e)=>{await m();const o=t.getBoundingClientRect(),i=await W(e),n=await(async(t,e)=>{await m();const o=t.getBoundingClientRect(),i=e.getBoundingClientRect(),n=i.top+window.scrollY,r=i.left+window.scrollX;return{height:i.height,width:i.width,top:V(n,o,i),left:k(r,o,i)}})(t,e),r=i.height,s=i.width,a=o.height,p=o.width;return{absolute:()=>({top:i.top,left:i.left,height:r,width:s}),toTop:({center:t=!1,sourceHeight:e=a,modifier:o=0}={})=>({top:i.top+e+o,left:t?n.left:i.left,height:r,width:s}),fromTop:({center:t=!1,sourceHeight:e=a,modifier:o=0}={})=>({top:i.top-e-o,left:t?n.left:i.left,height:r,width:s}),toBottom:({center:t=!1,sourceHeight:e=a,targetHeight:o=r,modifier:p=0}={})=>({top:i.top+o-(e+p),left:t?n.left:i.left,height:r,width:s}),fromBottom:({center:t=!1,targetHeight:e=r,modifier:o=0}={})=>({top:i.top+e+o,left:t?n.left:i.left,height:r,width:s}),toLeft:({center:t=!1,sourceWidth:e=p,modifier:o=0}={})=>({top:t?n.top:i.top,left:i.left+e+o,height:r,width:s}),fromLeft:({center:t=!1,sourceWidth:e=p,modifier:o=0}={})=>({top:t?n.top:i.top,left:i.left-e-o,height:r,width:s}),toRight:({center:t=!1,sourceWidth:e=p,targetWidth:o=s,modifier:a=0}={})=>({top:t?n.top:i.top,left:i.left+o-(e+a),height:r,width:s}),fromRight:({center:t=!1,targetWidth:e=s,modifier:o=0}={})=>({top:t?n.top:i.top,left:i.left+e+o,height:r,width:s})}},j=async(t,o,p,c)=>{await m();const{isCurly:l=!1}=c||{},h=H(p),d=O(getComputedStyle(p).getPropertyValue("--ph-speccer-measure-size"))||8;const f=await z(p,o);if(a(t)){const{left:t,top:e,height:o,width:i}=f.absolute();return{left:`${t}px`,top:`${e}px`,height:`${o}px`,width:`${i}px`}}if(i(t).includes(e.Left)){if(s(t)&&!l){const{left:t,top:e,height:o}=f.fromLeft({sourceWidth:d});return{left:`${t}px`,top:`${e}px`,height:`${o}px`}}const{left:e,top:o}=f.fromLeft({center:!0,modifier:l?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(n(t)){if(s(t)&&!l){const{left:t,top:e,height:o}=f.fromRight({center:!1});return{left:`${t}px`,top:`${e}px`,height:`${o}px`}}const{left:e,top:o}=f.fromRight({center:!0,modifier:l?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(r(t)){if(s(t)&&!l){const{left:t,top:e,width:o}=f.fromBottom({center:!1});return{left:`${t}px`,top:`${e}px`,width:`${o}px`}}const{left:e,top:o}=f.fromBottom({center:!0,modifier:l?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(s(t)&&!l){const{left:t,top:e,width:o}=f.fromTop({center:!1});return{left:`${t}px`,top:`${e}px`,width:`${o}px`}}const{left:u,top:g}=f.fromTop({center:!0,modifier:l?h/1.5:h});return{left:`${u}px`,top:`${g}px`}},F=(t="",e,o="span")=>{const i=document.createElement(o),n=document.createTextNode(t),r={};null!==e&&""!==e&&(r[e]=!0),!s(e)&&!a(e)||s(e)&&p(e)?i.appendChild(n):(s(e)||a(e))&&i.setAttribute("data-dissection-counter",t);const c=I("ph-speccer speccer dissection",r);return N(i,c),i},D=async t=>{if(!t)return;const o=t.querySelectorAll("[data-anatomy]");if(o){let t=0;o.forEach((async(o,i)=>{if(!o)return;const n=o.getAttribute("data-anatomy")||"";if(!n||""===n||!n.includes(e.Outline))return;let r=M[i];r||(r=`${M[t]}${M[t].toLowerCase()}`,t++);const s=F(r,n);document.body.appendChild(s);const a=await j(n,o,s,{isCurly:p(n)});await B(s,a),n.includes(e.SVG)&&!p(n)?new T(o,s):p(n)&&new L(o,s)}))}},G=(t="",e="",o="span")=>{const i=document.createElement(o);return i.setAttribute("title",`${t}px`),i.setAttribute("data-measure",`${parseInt(`${t}`,10)}px`),N(i,`ph-speccer speccer measure ${e}`),i},_=async t=>{if(!t)return;const e=t.getAttribute("data-speccer-measure");if(""===e||!e)return;const s=await R(t);if("none"===s.display||"0"===s.opacity||"hidden"===s.visibility)return;await m();const a=t.getBoundingClientRect();if(i(e).includes(o.Width))if(r(e)){const o=G(a.width,e);document.body.appendChild(o);const i=await z(o,t),{left:n,top:r,width:s}=i.fromBottom({center:!1});await B(o,{left:`${n}px`,top:`${r}px`,width:`${s}px`})}else{const o=G(a.width,e);document.body.appendChild(o);const i=await z(o,t),{left:n,top:r,width:s}=i.fromTop({center:!1,modifier:-8});await B(o,{left:`${n}px`,top:`${r}px`,width:`${s}px`})}else if((t=>i(t).includes(o.Height))(e))if(n(e)){const o=G(a.height,e);document.body.appendChild(o);const i=await z(o,t),{left:n,top:r,height:s}=i.fromRight({center:!1});await B(o,{left:`${n}px`,top:`${r}px`,height:`${s}px`})}else{const o=G(a.height,e);document.body.appendChild(o);const i=await z(o,t),{left:n,top:r,height:s}=i.fromLeft({center:!1,modifier:-8});await B(o,{left:`${n}px`,top:`${r}px`,height:`${s}px`})}},X=async(t,e,o,i)=>{await m();const n=i.getBoundingClientRect(),r=await W(i);"marginTop"===t&&B(o,{height:`${e}px`,width:n.width+"px",left:r.left+"px",top:r.top-e+"px"}),"marginRight"===t&&B(o,{height:n.height+"px",width:`${e}px`,left:r.left+parseInt(n.width+"",10)+"px",top:r.top+"px"}),"marginBottom"===t&&B(o,{height:`${e}px`,width:n.width+"px",left:r.left+"px",top:r.top+parseInt(n.height+"",10)+"px"}),"marginLeft"===t&&B(o,{height:n.height+"px",width:`${e}px`,left:r.left-e+"px",top:r.top+"px"}),"paddingTop"===t&&B(o,{height:`${e}px`,width:n.width+"px",left:r.left+"px",top:r.top+"px"}),"paddingBottom"===t&&B(o,{height:`${e}px`,width:n.width+"px",left:r.left+"px",top:r.top+(parseInt(n.height+"",10)-e)+"px"}),"paddingRight"===t&&B(o,{height:n.height+"px",width:`${e}px`,left:r.left+(parseInt(n.width+"",10)-e)+"px",top:r.top+"px"}),"paddingLeft"===t&&B(o,{height:n.height+"px",width:`${e}px`,left:r.left+"px",top:r.top+"px"})},Y=(t="",e="span")=>{const o=document.createElement(e),i=document.createTextNode(`${t}`);return o.appendChild(i),o.setAttribute("title",`${t}px`),N(o,"ph-speccer speccer spacing"),o},J=async t=>{if(!t)return;const e=await R(t);if("none"===e.display||"0"===e.opacity||"hidden"===e.visibility)return;const o=(t=>{const{marginTop:e,marginBottom:o,marginLeft:i,marginRight:n,paddingTop:r,paddingBottom:s,paddingLeft:a,paddingRight:p}=t;return{marginTop:e,marginBottom:o,marginLeft:i,marginRight:n,paddingTop:r,paddingBottom:s,paddingLeft:a,paddingRight:p}})(e),i=Object.keys(o).filter((t=>"0px"!==o[t]));if(i.length)for(const e of i){const i=O(o[e]),n=Y(i),r=q(e);N(n,r),document.body.appendChild(n),t.classList.add("is-specced"),await X(e,i,n,t)}},K=t=>{const e=()=>((t,e,o=!1)=>{let i;return function(n,...r){const s=o&&!i;i&&clearTimeout(i),i=setTimeout((function(){i=null,o||t.apply(n,r)}),e),s&&t.apply(n,r)}})((()=>{t()}),300);window.removeEventListener("resize",e),window.addEventListener("resize",e)},Q=t=>{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",(()=>{t()})):t()},U=()=>{const t=new IntersectionObserver(((t,e)=>{for(const o of t)o.intersectionRatio>0&&(J(o.target),e.unobserve(o.target))}));for(const e of document.querySelectorAll("[data-speccer],[data-speccer] *:not(td):not(tr):not(th):not(tfoot):not(thead):not(tbody)"))t.observe(e);const e=new IntersectionObserver(((t,e)=>{for(const o of t)o.intersectionRatio>0&&(_(o.target),e.unobserve(o.target))}));for(const t of document.querySelectorAll("[data-speccer-measure]"))e.observe(t);const o=new IntersectionObserver((async(t,e)=>{for(const o of t)o.intersectionRatio>0&&(await D(o.target),e.unobserve(o.target))}));for(const t of document.querySelectorAll("[data-anatomy-section]"))o.observe(t)},Z=t=>{window.speccer=t},tt=t=>{const e=document.currentScript;if(e){const o=e.getAttribute("src");o&&o.includes("speccer.js")&&(e.hasAttribute("data-manual")?Z(t):e.hasAttribute("data-instant")?t():e.hasAttribute("data-dom")?Q(t):e.hasAttribute("data-lazy")?U():Q(t),e.hasAttribute("data-manual")||e.hasAttribute("data-lazy")||K(t))}},et=(t="span")=>{const e=document.createElement(t),o=I("ph-speccer speccer mark");return N(e,o),e},ot=async t=>{if(!t)return;const e=et();document.body.appendChild(e);const o=await z(e,t),{left:i,top:n,height:r,width:s}=o.absolute(),a={left:`${i}px`,top:`${n}px`,height:`${r}px`,width:`${s}px`};await B(e,a)},it=(t,e=3)=>parseFloat(t+"").toFixed(e),nt=(t,e)=>{const o=document.createElement("div"),i={};null!==e&&""!==e&&(i[e]=!0);const n=I("ph-speccer speccer typography",i);return o.innerHTML=t,N(o,n),o},rt=async e=>{if(!e)return;const o=e.getAttribute("data-speccer-typography"),i=await R(e);if("none"===i.display||"0"===i.opacity||"hidden"===i.visibility)return;e.classList.add("is-specced");const n=await(async t=>{const e=(t=>{const{lineHeight:e,letterSpacing:o,fontFamily:i,fontSize:n,fontStyle:r,fontVariationSettings:s,fontWeight:a}=t;return{lineHeight:e,letterSpacing:o,fontFamily:i,fontSize:n,fontStyle:r,fontVariationSettings:s,fontWeight:a}})(await R(t)),o="normal"!==e.lineHeight?parseInt(e.lineHeight,10)/16+"rem":"normal";return`\nfont-styles: {<ul class="speccer-styles"> <li><span class="property">font-family:</span> ${e.fontFamily};</li> <li><span class="property">font-size:</span> ${e.fontSize} / ${parseInt(e.fontSize,10)/16}rem;</li> <li><span class="property">font-weight:</span> ${e.fontWeight};</li> <li><span class="property">font-variation-settings:</span> ${e.fontVariationSettings};</li> <li><span class="property">line-height:</span> ${e.lineHeight} / ${o};</li> <li><span class="property">letter-spacing:</span> ${e.letterSpacing};</li> <li><span class="property">font-style:</span> ${e.fontStyle};</li></ul>}`})(e),r=nt(n,o);document.body.appendChild(r);const s=await(async(e,o,i)=>{const n=o.getBoundingClientRect(),r=H(i),s=i.getBoundingClientRect(),a=await W(o),p=a.left-s.width-r+"px",c=it(V(a.top,s,n))+"px",l=a.left+n.width+r+"px",h=it(V(a.top,s,n))+"px",d=it(k(a.left,s,n))+"px",f=a.top-s.height-r+"px",m=it(k(a.left,s,n))+"px",u=a.top+n.height+r+"px";let g={left:p,top:c};return e?.includes(t.Right)?g={left:l,top:h}:e?.includes(t.Top)?g={left:d,top:f}:e?.includes(t.Bottom)&&(g={left:m,top:u}),g})(o,e,r);B(r,s)},st={create:Y,element:J},at={create:F,element:D},pt={create:G,element:_},ct={create:et,element:ot},lt={create:nt,element:rt},ht={dom:Q,lazy:U,manual:Z,activate:tt},dt=()=>{((t,e=document)=>{[].forEach.call(e.querySelectorAll(t),(function(t){t.remove()}))})(".ph-speccer.speccer");const t=document.querySelectorAll("[data-speccer],[data-speccer] *:not(td):not(tr):not(th):not(tfoot):not(thead):not(tbody)"),e=document.querySelectorAll("[data-speccer-measure]"),o=document.querySelectorAll("[data-speccer-typography]"),i=document.querySelectorAll("[data-anatomy-section]"),n=document.querySelectorAll("[data-speccer-mark]");for(const t of n)ot(t);for(const e of t)J(e);for(const t of e)_(t);for(const t of o)rt(t);for(const t of i)D(t)};tt(dt);export{dt as default,at as dissect,ct as mark,pt as measure,ht as modes,st as spacing,lt as typography};
1
+ /**
2
+ * @phun-ky/speccer
3
+ * A script to annotate, show spacing specs and to display typography information in documentation/website on HTML elements
4
+ * @author Alexander Vassbotn Røyne-Helgesen <alexander@phun-ky.net>
5
+ * @version 9.1.1
6
+ * @license
7
+ * Copyright (c) 2018 Alexander Vassbotn Røyne-Helgesen
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ * of this software and associated documentation files (the "Software"), to deal
11
+ * in the Software without restriction, including without limitation the rights
12
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ * copies of the Software, and to permit persons to whom the Software is
14
+ * furnished to do so, subject to the following conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be included in all
17
+ * copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ * SOFTWARE.
26
+ */
27
+ var t,e,o;!function(t){t.Empty="",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top"}(t||(t={})),function(t){t.Outline="outline",t.Enclose="enclose",t.Full="full",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top",t.SVG="svg",t.Curly="curly"}(e||(e={})),function(t){t.Width="width",t.Height="height",t.Left="left",t.Right="right",t.Bottom="bottom",t.Top="top"}(o||(o={}));const n=t=>t.split(" "),i=t=>n(t).includes(e.Right),r=t=>n(t).includes(e.Bottom),s=t=>n(t).includes(e.Full),a=t=>n(t).includes(e.Enclose),c=t=>t.includes(e.Curly)&&t.includes(e.Full),l=t=>"string"==typeof t,p=t=>!l(t),h=t=>"number"==typeof t,d=t=>!h(t),f=t=>void 0===t,m=()=>new Promise(requestAnimationFrame),u=t=>t.top,g=t=>t.left+t.width,y=t=>t.top+t.height,w=t=>t.left,x=t=>t.left+t.width/2,b=t=>t.top+t.height/2,E={center:t=>({x:x(t),y:b(t)}),top:t=>({x:x(t),y:u(t)}),right:t=>({x:g(t),y:b(t)}),bottom:t=>({x:x(t),y:y(t)}),left:t=>({x:w(t),y:b(t)}),"right-top":t=>({x:g(t),y:u(t)}),"right-bottom":t=>({x:g(t),y:y(t)}),"left-top":t=>({x:w(t),y:u(t)}),"left-bottom":t=>({x:w(t),y:y(t)}),"top-left":t=>({x:w(t),y:u(t)}),"top-right":t=>({x:g(t),y:u(t)}),"bottom-left":t=>({x:w(t),y:y(t)}),"bottom-right":t=>({x:g(t),y:y(t)}),"top-center":t=>({x:x(t),y:u(t)}),"right-center":t=>({x:g(t),y:b(t)}),"bottom-center":t=>({x:x(t),y:y(t)}),"left-center":t=>({x:w(t),y:b(t)})},$=async(t,e="center")=>{if(!e)throw Error("No position given");if(p(e))throw Error("The position given is not the required type: pos: "+typeof e);const o=["center","left","right","top","bottom","right-top","right-bottom","left-top","left-bottom","top-left","top-right","bottom-left","bottom-right","top-center","right-center","bottom-center","left-center"];if(!o.includes(e))throw Error(`The position given does not match allowed positions to use! Valid positions are: ${o.join(", ")}`);await m();const n=t.getBoundingClientRect();return E[e](n)},A=async(t,e,o="center",n="center")=>{if(!t||!e)throw Error("No element given");const{x:i,y:r}=await $(t,o),{x:s,y:a}=await $(e,n);return{x1:i,y1:r,x2:s,y2:a}},v=(t,e)=>{const{x1:o,x2:n,y1:i,y2:r}=t,{direct:s=!1,firstSet:a=!1,direction:c}=e;let l={x:o+(n-o)/2,y:i},p={x:o+(n-o)/2,y:r};return s&&(a?"west"===c?(l={x:o-32,y:i-8},p={x:n+32,y:r}):"south"===c?(l={x:o-8,y:i+32},p={x:n,y:r-32}):"east"===c?(l={x:o+32,y:i-8},p={x:n-32,y:r}):(l={x:o-8,y:i-32},p={x:n,y:r+32}):"west"===c?(l={x:o-32,y:i+8},p={x:n+32,y:r}):"south"===c?(l={x:o+8,y:i+32},p={x:n,y:r-32}):"east"===c?(l={x:o+32,y:i+8},p={x:n-32,y:r}):(l={x:o+8,y:i-32},p={x:n,y:r+32})),{firstPoint:{x:o,y:i},firstControl:l,lastPoint:{x:n,y:r},lastControl:p}},S=async(t,e,o)=>{const{pos1:n,pos2:i,firstSet:r=!1,direction:s}=o,{x1:a,y1:c,x2:l,y2:p}=await A(t,e,n,i);let h=0,d=0;"north"===s?d=8:"west"===s?h=8:"east"===s?h=-8:"south"===s&&(d=-8);const{firstPoint:f,firstControl:m,lastControl:u,lastPoint:g}=v({x1:a+0,x2:l+h,y1:c+0+document.documentElement.scrollTop,y2:p+d+document.documentElement.scrollTop},{direct:!0,firstSet:r,direction:s});return`M ${f.x} ${f.y}C ${m.x} ${m.y}, ${u.x} ${u.y}, ${g.x} ${g.y}`},C=async({start:t,stop:e,crude:o=!1})=>{const{x1:n,y1:i,x2:r,y2:s}=await A(t,e),a=((t,e,o,n,i=!0)=>{if(f(t)||f(e)||f(o)||f(n))throw new SyntaxError("Missing input for `angle`");if(d(t)||d(e)||d(o)||d(n))throw TypeError(`Parameters for \`angle\` do not have the required type. Requires number! Got: ${typeof t} ${typeof e} ${typeof o} ${typeof n}`);const r=n-e,s=o-t;let a=Math.atan2(r,s);return a*=180/Math.PI,i&&a<0&&(a+=360),a})(n,i,r,s);return o?(t=>{if(t>360)throw new RangeError("Parameter cannot exceed 360");if(t<0)throw new RangeError("Parameter cannot be lower than 0");return t>=45&&t<=135?"south":t>135&&t<=225?"west":t>225&&t<=315?"north":"east"})(a):(t=>{if(t>360)throw new RangeError("Parameter cannot exceed 360");if(t<0)throw new RangeError("Parameter cannot be lower than 0");return t>=0&&t<=22.5?"east":t>=22.5&&t<=67.5?"south-east":t>=67.5&&t<=112.5?"south":t>=112.5&&t<=157.5?"south-west":t>=157.5&&t<=202.5?"west":t>=202.5&&t<=247.5?"north-west":t>=247.5&&t<=292.5?"north":t>=292.5&&t<=337.5?"north-east":"east"})(a)},L=()=>"_"+Math.random().toString(36).substring(2,11),P=async(t,e)=>{var o;if(!(!t||!e||l(e)||h(e)||(o=e,"boolean"==typeof o)||Array.isArray(e)&&!e.length||!Object.keys(e).length&&e.constructor===Object))if(await m(),Array.isArray(e))for(const o of e)t.style[o.key]=o.value;else for(const o of Object.keys(e))t.style[o]=e[o]},B=async t=>(await m(),getComputedStyle(t,null));class R{#t;#e;startElement;stopElement;firstPathElement;secondPathElement;constructor(t,e){this.#o(t,e)}#o(t,e){if(!t||!e)throw new Error("Missing inputs startElement and stopElement");if(!document.body.contains(e))throw new Error("stopElement is not in the DOM");if(!document.body.contains(t))throw new Error("startElement is not in the DOM");if(this.startElement=t,this.stopElement=e,this.#t=document.getElementById("ph-speccer-svg"),this.#e=document.getElementById("ph-speccer-path"),!this.#e||!this.#t)throw new Error("Missing required SVG element to draw lines. Please see the documentation");P(this.#t,{height:`${document.body.scrollHeight}px`}),this.connect()}connect(){this.draw(this.#e)}#n(t){if(!t)throw new Error("No path given to #getPathElement!");const e=`ph_draw_path-path-${L()}`,o=t.cloneNode(!1),n=this.startElement.getAttribute("id")||L();return this.startElement.setAttribute("id",n),o.setAttribute("data-start-el",n),o.setAttribute("id",e),o.classList.remove("original"),o.classList.add("speccer"),o}async draw(t){if(!t)throw new Error("No path given to draw!");const e=this.#n(t),o=this.#n(t);if(!t.parentNode)throw new Error("No parentNode found for path");this.firstPathElement=t.parentNode.insertBefore(e,t.nextSibling),this.secondPathElement=t.parentNode.insertBefore(o,t.nextSibling);const n=await C({stop:this.stopElement,start:this.startElement,crude:!0}),{path1pos1:i,path1pos2:r,path2pos1:s,path2pos2:a}=(t=>{let e,o,n,i;switch(t){case"east":e="right-top",o="left-center",n="right-bottom",i="left-center";break;case"south":e="bottom-left",o="top-center",n="bottom-right",i="top-center";break;case"west":e="left-top",o="right-center",n="left-bottom",i="right-center";break;default:e="top-left",o="bottom-center",n="top-right",i="bottom-center"}return{path1pos1:e,path1pos2:o,path2pos1:n,path2pos2:i}})(n),c=await S(this.startElement,this.stopElement,{pos1:i,pos2:r,firstSet:!0,direction:n}),l=await S(this.startElement,this.stopElement,{pos1:s,pos2:a,direction:n});this.firstPathElement.setAttribute("data-direction",n),this.firstPathElement.setAttribute("data-pos1",i),this.firstPathElement.setAttribute("data-pos2",r),this.firstPathElement.setAttribute("d",c),this.secondPathElement.setAttribute("data-direction",n),this.secondPathElement.setAttribute("data-pos1",s),this.secondPathElement.setAttribute("data-pos2",a),this.secondPathElement.setAttribute("d",l)}}window.DrawSVGCurlyBracket=R;class T{#t;#e;startElement;stopElement;line;constructor(t,e){this.#o(t,e)}#o(t,e){if(!t||!e)throw new Error("Missing inputs startElement and stopElement");if(!document.body.contains(e))throw new Error("stopElement is not in the DOM");if(!document.body.contains(t))throw new Error("startElement is not in the DOM");if(this.startElement=t,this.stopElement=e,this.#t=document.getElementById("ph-speccer-svg"),this.#e=document.getElementById("ph-speccer-path"),!this.#e||!this.#t)throw new Error("Missing required SVG element to draw lines. Please see the documentation");P(this.#t,{height:`${document.body.scrollHeight}px`}),this.connect()}connect(){this.draw(this.#e)}async draw(t){if(!t)throw new Error("No path given to draw!");const e=`ph_draw_path-path-${L()}`,o=t.cloneNode(!1),n=this.startElement.getAttribute("id")||L();if(this.startElement.setAttribute("id",n),o.setAttribute("id",e),o.setAttribute("data-start-el",n),o.classList.remove("original"),o.classList.add("speccer"),!t.parentNode)throw new Error("No parentNode found for path");this.line=t.parentNode.insertBefore(o,t.nextSibling);const i=await C({start:this.startElement,stop:this.stopElement,crude:!0}),{pos1:r,pos2:s}=(t=>{let e,o;switch(t){case"east":e="right",o="left";break;case"south":e="bottom",o="top";break;case"west":e="left",o="right";break;default:e="top",o="bottom"}return{pos1:e,pos2:o}})(i),a=await(async(t,e,o)=>{const{pos1:n,pos2:i}=o,{x1:r,y1:s,x2:a,y2:c}=await A(t,e,n,i),{firstPoint:l,firstControl:p,lastControl:h,lastPoint:d}=v({x1:r,x2:a,y1:s,y2:c},{direction:""});return`M ${l.x} ${l.y}C ${p.x} ${p.y}, ${h.x} ${h.y}, ${d.x} ${d.y}`})(this.startElement,this.stopElement,{pos1:r,pos2:s});this.line.setAttribute("data-direction",i),this.line.setAttribute("data-pos1",r),this.line.setAttribute("data-pos2",s),this.line.setAttribute("d",a)}}window.DrawSVGLine=T;const k=(t,e,o="noop")=>{t&&(!e||e&&!e.length||e.trim().split(" ").filter((t=>t!==o)).forEach((e=>t.classList.add(e))))},N=(t,e)=>t?!e&&p(t)?Object.keys(t).filter((e=>t[e])).join(" ").trim():`${t.trim()} ${e?Object.keys(e).filter((t=>e[t])).join(" "):""}`.trim():"",q=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"],I=t=>parseInt(t,10),M=t=>t.includes("Top")?t.replace("Top"," top"):t.includes("Right")?t.replace("Right"," right"):t.includes("Bottom")?t.replace("Bottom"," bottom"):t.includes("Left")?t.replace("Left"," left"):"",O=t=>I(getComputedStyle(t).getPropertyValue("--ph-speccer-pin-space"))||48,H=async(t,e,o)=>{await m();return getComputedStyle(t)[e]===o},V=async(t,e,o)=>{if(!t.parentElement)return null;return await H(t.parentElement,e,o)?t.parentElement:await V(t.parentElement,e,o)},W=(t,e,o)=>t-e.width/2+o.width/2,j=(t,e,o)=>t-e.height/2+o.height/2,z=async t=>{await m();let e=t.getBoundingClientRect(),o=e.top+window.scrollY;const n=e.left+window.scrollX,i=await(async t=>await V(t,"position","sticky"))(t),r=await(async t=>await H(t,"position","sticky"))(t);if(r){const n=t.style.position;await m(),t.style.position="relative",await m(),e=t.getBoundingClientRect(),o=e.top,t.style.position=n}else if(i){const n=i.style.position;await m(),i.style.position="relative",await m(),e=t.getBoundingClientRect(),o=e.top,i.style.position=n}return{height:e.height,width:e.width,top:o,left:n}},F=async(t,e)=>{await m();const o=t.getBoundingClientRect(),n=await z(e),i=await(async(t,e)=>{await m();const o=t.getBoundingClientRect(),n=e.getBoundingClientRect(),i=n.top+window.scrollY,r=n.left+window.scrollX;return{height:n.height,width:n.width,top:j(i,o,n),left:W(r,o,n)}})(t,e),r=n.height,s=n.width,a=o.height,c=o.width;return{absolute:()=>({top:n.top,left:n.left,height:r,width:s}),toTop:({center:t=!1,sourceHeight:e=a,modifier:o=0}={})=>({top:n.top+e+o,left:t?i.left:n.left,height:r,width:s}),fromTop:({center:t=!1,sourceHeight:e=a,modifier:o=0}={})=>({top:n.top-e-o,left:t?i.left:n.left,height:r,width:s}),toBottom:({center:t=!1,sourceHeight:e=a,targetHeight:o=r,modifier:c=0}={})=>({top:n.top+o-(e+c),left:t?i.left:n.left,height:r,width:s}),fromBottom:({center:t=!1,targetHeight:e=r,modifier:o=0}={})=>({top:n.top+e+o,left:t?i.left:n.left,height:r,width:s}),toLeft:({center:t=!1,sourceWidth:e=c,modifier:o=0}={})=>({top:t?i.top:n.top,left:n.left+e+o,height:r,width:s}),fromLeft:({center:t=!1,sourceWidth:e=c,modifier:o=0}={})=>({top:t?i.top:n.top,left:n.left-e-o,height:r,width:s}),toRight:({center:t=!1,sourceWidth:e=c,targetWidth:o=s,modifier:a=0}={})=>({top:t?i.top:n.top,left:n.left+o-(e+a),height:r,width:s}),fromRight:({center:t=!1,targetWidth:e=s,modifier:o=0}={})=>({top:t?i.top:n.top,left:n.left+e+o,height:r,width:s})}},D=async(t,o,c,l)=>{await m();const{isCurly:p=!1}=l||{},h=O(c),d=I(getComputedStyle(c).getPropertyValue("--ph-speccer-measure-size"))||8;const f=await F(c,o);if(a(t)){const{left:t,top:e,height:o,width:n}=f.absolute();return{left:`${t}px`,top:`${e}px`,height:`${o}px`,width:`${n}px`}}if(n(t).includes(e.Left)){if(s(t)&&!p){const{left:t,top:e,height:o}=f.fromLeft({sourceWidth:d});return{left:`${t}px`,top:`${e}px`,height:`${o}px`}}const{left:e,top:o}=f.fromLeft({center:!0,modifier:p?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(i(t)){if(s(t)&&!p){const{left:t,top:e,height:o}=f.fromRight({center:!1});return{left:`${t}px`,top:`${e}px`,height:`${o}px`}}const{left:e,top:o}=f.fromRight({center:!0,modifier:p?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(r(t)){if(s(t)&&!p){const{left:t,top:e,width:o}=f.fromBottom({center:!1});return{left:`${t}px`,top:`${e}px`,width:`${o}px`}}const{left:e,top:o}=f.fromBottom({center:!0,modifier:p?h/1.5:h});return{left:`${e}px`,top:`${o}px`}}if(s(t)&&!p){const{left:t,top:e,width:o}=f.fromTop({center:!1});return{left:`${t}px`,top:`${e}px`,width:`${o}px`}}const{left:u,top:g}=f.fromTop({center:!0,modifier:p?h/1.5:h});return{left:`${u}px`,top:`${g}px`}},G=(t="",e,o="span")=>{const n=document.createElement(o),i=document.createTextNode(t),r={};null!==e&&""!==e&&(r[e]=!0),!s(e)&&!a(e)||s(e)&&c(e)?n.appendChild(i):(s(e)||a(e))&&n.setAttribute("data-dissection-counter",t);const l=N("ph-speccer speccer dissection",r);return k(n,l),n},_=async t=>{if(!t)return;const o=t.querySelectorAll("[data-anatomy]");if(o){let t=0;o.forEach((async(o,n)=>{if(!o)return;const i=o.getAttribute("data-anatomy")||"";if(!i||""===i||!i.includes(e.Outline))return;let r=q[n];r||(r=`${q[t]}${q[t].toLowerCase()}`,t++);const s=G(r,i);document.body.appendChild(s);const a=await D(i,o,s,{isCurly:c(i)});await P(s,a),i.includes(e.SVG)&&!c(i)?new T(o,s):c(i)&&new R(o,s)}))}},X=(t="",e="",o="span")=>{const n=document.createElement(o);return n.setAttribute("title",`${t}px`),n.setAttribute("data-measure",`${parseInt(`${t}`,10)}px`),k(n,`ph-speccer speccer measure ${e}`),n},Y=async t=>{if(!t)return;const e=t.getAttribute("data-speccer-measure");if(""===e||!e)return;const s=await B(t);if("none"===s.display||"0"===s.opacity||"hidden"===s.visibility)return;await m();const a=t.getBoundingClientRect();if(n(e).includes(o.Width))if(r(e)){const o=X(a.width,e);document.body.appendChild(o);const n=await F(o,t),{left:i,top:r,width:s}=n.fromBottom({center:!1});await P(o,{left:`${i}px`,top:`${r}px`,width:`${s}px`})}else{const o=X(a.width,e);document.body.appendChild(o);const n=await F(o,t),{left:i,top:r,width:s}=n.fromTop({center:!1,modifier:-8});await P(o,{left:`${i}px`,top:`${r}px`,width:`${s}px`})}else if((t=>n(t).includes(o.Height))(e))if(i(e)){const o=X(a.height,e);document.body.appendChild(o);const n=await F(o,t),{left:i,top:r,height:s}=n.fromRight({center:!1});await P(o,{left:`${i}px`,top:`${r}px`,height:`${s}px`})}else{const o=X(a.height,e);document.body.appendChild(o);const n=await F(o,t),{left:i,top:r,height:s}=n.fromLeft({center:!1,modifier:-8});await P(o,{left:`${i}px`,top:`${r}px`,height:`${s}px`})}},J=async(t,e,o,n)=>{await m();const i=n.getBoundingClientRect(),r=await z(n);"marginTop"===t&&P(o,{height:`${e}px`,width:i.width+"px",left:r.left+"px",top:r.top-e+"px"}),"marginRight"===t&&P(o,{height:i.height+"px",width:`${e}px`,left:r.left+parseInt(i.width+"",10)+"px",top:r.top+"px"}),"marginBottom"===t&&P(o,{height:`${e}px`,width:i.width+"px",left:r.left+"px",top:r.top+parseInt(i.height+"",10)+"px"}),"marginLeft"===t&&P(o,{height:i.height+"px",width:`${e}px`,left:r.left-e+"px",top:r.top+"px"}),"paddingTop"===t&&P(o,{height:`${e}px`,width:i.width+"px",left:r.left+"px",top:r.top+"px"}),"paddingBottom"===t&&P(o,{height:`${e}px`,width:i.width+"px",left:r.left+"px",top:r.top+(parseInt(i.height+"",10)-e)+"px"}),"paddingRight"===t&&P(o,{height:i.height+"px",width:`${e}px`,left:r.left+(parseInt(i.width+"",10)-e)+"px",top:r.top+"px"}),"paddingLeft"===t&&P(o,{height:i.height+"px",width:`${e}px`,left:r.left+"px",top:r.top+"px"})},K=(t="",e="span")=>{const o=document.createElement(e),n=document.createTextNode(t+"");return o.appendChild(n),o.setAttribute("title",`${t}px`),k(o,"ph-speccer speccer spacing"),o},Q=async t=>{if(!t)return;const e=await B(t);if("none"===e.display||"0"===e.opacity||"hidden"===e.visibility)return;const o=(t=>{const{marginTop:e,marginBottom:o,marginLeft:n,marginRight:i,paddingTop:r,paddingBottom:s,paddingLeft:a,paddingRight:c}=t;return{marginTop:e,marginBottom:o,marginLeft:n,marginRight:i,paddingTop:r,paddingBottom:s,paddingLeft:a,paddingRight:c}})(e),n=Object.keys(o).filter((t=>"0px"!==o[t]));if(n.length)for(const e of n){const n=I(o[e]),i=K(n),r=M(e);k(i,r),document.body.appendChild(i),t.classList.add("is-specced"),await J(e,n,i,t)}},U=t=>{const e=()=>((t,e,o=!1)=>{let n;return function(i,...r){const s=o&&!n;n&&clearTimeout(n),n=setTimeout((function(){n=null,o||t.apply(i,r)}),e),s&&t.apply(i,r)}})((()=>{t()}),300);window.removeEventListener("resize",e),window.addEventListener("resize",e)},Z=t=>{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",(()=>{t()})):t()},tt=()=>{const t=new IntersectionObserver(((t,e)=>{for(const o of t)o.intersectionRatio>0&&(Q(o.target),e.unobserve(o.target))}));for(const e of document.querySelectorAll("[data-speccer],[data-speccer] *:not(td):not(tr):not(th):not(tfoot):not(thead):not(tbody)"))t.observe(e);const e=new IntersectionObserver(((t,e)=>{for(const o of t)o.intersectionRatio>0&&(Y(o.target),e.unobserve(o.target))}));for(const t of document.querySelectorAll("[data-speccer-measure]"))e.observe(t);const o=new IntersectionObserver((async(t,e)=>{for(const o of t)o.intersectionRatio>0&&(await _(o.target),e.unobserve(o.target))}));for(const t of document.querySelectorAll("[data-anatomy-section]"))o.observe(t)},et=t=>{window.speccer=t},ot=t=>{const e=document.currentScript;if(e){const o=e.getAttribute("src");o?.includes("speccer.js")&&(e.hasAttribute("data-manual")?et(t):e.hasAttribute("data-instant")?t():e.hasAttribute("data-dom")?Z(t):e.hasAttribute("data-lazy")?tt():Z(t),e.hasAttribute("data-manual")||e.hasAttribute("data-lazy")||U(t))}},nt=["alt","altgraph","capslock","control","fn","fnlock","hyper","meta","numlock","os","scrolllock","shift","super","symbol","command","ctrl","altgr","symbollock"],it=["escape","esc","enter","return","⏎","␛"],rt=async(t,e,o)=>{await m();const n=O(o),i=await F(o,e);if("tabstops"===t){let{left:t,top:e}=i.fromTop();return t-=32,t<=0&&(t=32),e<=0&&(e=32),{left:`${t}px`,top:`${e}px`}}if("landmark"===t){let{left:t,top:e}=i.fromTop();return t-=16,e-=16,t<=0&&(t=32),e<=0&&(e=32),{left:`${t}px`,top:`${e}px`}}if("region"===t){const{left:t,top:e,height:o,width:n}=i.fromTop();return{height:`${o}px`,width:`${n}px`,left:`${t}px`,top:`${e}px`}}if("shortcut"===t){const{left:t,top:e}=i.fromBottom();return{left:`${t}px`,top:`${e}px`}}const{left:r,top:s}=i.fromTop({center:!0,modifier:n});return{left:r-32+"px",top:s-32+"px"}},st=async(t,e,o)=>{if(!t||!t.checkVisibility())return;const n=((t="tabstops",e,o="span")=>{const n=document.createElement(o),i=N("ph-speccer speccer a11y",{tabstops:"tabstops"===t,landmark:"landmark"===t,region:"region"===t});if("landmark"===t&&e){const t=document.createTextNode(e+"");n.appendChild(t)}return k(n,i),n})(o,e);if("landmark"===o){n.setAttribute("data-speccer-nodename",t.nodeName);const e=t.role||`semantic role: ${t.nodeName.toLowerCase()}`,o=t.getAttribute("aria-label")||"unnamed";n.setAttribute("title",`${o}: ${e}`)}document.body.appendChild(n);const i=await rt(o,t,n);await P(n,i)},at=async(t,e)=>{const o=e.split(/\s\+\s/).map((t=>t.trim())),n=document.createElement("div");n.classList.add("ph-speccer"),n.classList.add("speccer"),n.classList.add("a11y"),n.classList.add("shortcut-holder");for(const t of o){const e=document.createElement("kbd"),o=document.createTextNode(t);e.classList.add("ph-speccer"),e.classList.add("speccer"),e.classList.add("a11y"),e.classList.add("shortcut"),nt.includes(t.toLowerCase())&&e.classList.add("modifier"),it.includes(t.toLowerCase())&&e.classList.add("physical"),e.appendChild(o),n.appendChild(e)}document.body.appendChild(n);const i=await rt("shortcut",t,n);await P(n,i)},ct=(t="span")=>{const e=document.createElement(t),o=N("ph-speccer speccer mark");return k(e,o),e},lt=async t=>{if(!t)return;const e=ct();document.body.appendChild(e);const o=await F(e,t),{left:n,top:i,height:r,width:s}=o.absolute(),a={left:`${n}px`,top:`${i}px`,height:`${r}px`,width:`${s}px`};await P(e,a)},pt=(t,e=3)=>parseFloat(t+"").toFixed(e),ht=(t,e)=>{const o=document.createElement("div"),n={};null!==e&&""!==e&&(n[e]=!0);const i=N("ph-speccer speccer typography",n);return o.innerHTML=t,k(o,i),o},dt=async e=>{if(!e)return;const o=e.getAttribute("data-speccer-typography"),n=await B(e);if("none"===n.display||"0"===n.opacity||"hidden"===n.visibility)return;e.classList.add("is-specced");const i=await(async t=>{const e=(t=>{const{lineHeight:e,letterSpacing:o,fontFamily:n,fontSize:i,fontStyle:r,fontVariationSettings:s,fontWeight:a}=t;return{lineHeight:e,letterSpacing:o,fontFamily:n,fontSize:i,fontStyle:r,fontVariationSettings:s,fontWeight:a}})(await B(t)),o="normal"!==e.lineHeight?parseInt(e.lineHeight,10)/16+"rem":"normal";return`\nfont-styles: {<ul class="speccer-styles"> <li><span class="property">font-family:</span> ${e.fontFamily};</li> <li><span class="property">font-size:</span> ${e.fontSize} / ${parseInt(e.fontSize,10)/16}rem;</li> <li><span class="property">font-weight:</span> ${e.fontWeight};</li> <li><span class="property">font-variation-settings:</span> ${e.fontVariationSettings};</li> <li><span class="property">line-height:</span> ${e.lineHeight} / ${o};</li> <li><span class="property">letter-spacing:</span> ${e.letterSpacing};</li> <li><span class="property">font-style:</span> ${e.fontStyle};</li></ul>}`})(e),r=ht(i,o);document.body.appendChild(r);const s=await(async(e,o,n)=>{const i=o.getBoundingClientRect(),r=O(n),s=n.getBoundingClientRect(),a=await z(o),c=a.left-s.width-r+"px",l=pt(j(a.top,s,i))+"px",p=a.left+i.width+r+"px",h=pt(j(a.top,s,i))+"px",d=pt(W(a.left,s,i))+"px",f=a.top-s.height-r+"px",m=pt(W(a.left,s,i))+"px",u=a.top+i.height+r+"px";let g={left:c,top:l};return e?.includes(t.Right)?g={left:p,top:h}:e?.includes(t.Top)?g={left:d,top:f}:e?.includes(t.Bottom)&&(g={left:m,top:u}),g})(o,e,r);P(r,s)},ft={create:K,element:Q},mt={create:G,element:_},ut={create:X,element:Y},gt={create:ct,element:lt},yt={create:ht,element:dt},wt={dom:Z,lazy:tt,manual:et,activate:ot},xt=()=>{((t,e=document)=>{[].forEach.call(e.querySelectorAll(t),(function(t){t.remove()}))})(".ph-speccer.speccer");const t=document.querySelectorAll("[data-speccer],[data-speccer] *:not(td):not(tr):not(th):not(tfoot):not(thead):not(tbody)"),e=document.querySelectorAll("[data-speccer-measure]"),o=document.querySelectorAll("[data-speccer-typography]"),n=document.querySelectorAll("[data-anatomy-section]"),i=document.querySelectorAll("[data-speccer-mark]");for(const t of i)lt(t);for(const e of t)Q(e);for(const t of e)Y(t);for(const t of o)dt(t);for(const t of n)_(t);(()=>{const t=document.querySelectorAll("[data-speccer-a11y-tabstops]"),e=document.querySelectorAll("[data-speccer-a11y-landmark]"),o=document.querySelectorAll("[data-speccer-a11y-shortcut]");if(o.length)for(const t of o){const e=t.getAttribute("data-speccer-a11y-shortcut");e&&""!==e&&at(t,e)}if(t.length)for(const e of t){const t=e.querySelectorAll("\n a[href], area[href], input:not([disabled]):not([tabindex='-1']),\n button:not([disabled]):not([tabindex='-1']),select:not([disabled]):not([tabindex='-1']),\n textarea:not([disabled]):not([tabindex='-1']),\n iframe, object, embed, *[tabindex]:not([tabindex='-1']), *[contenteditable=true]\n");for(const e of t)st(e,null,"tabstops")}if(e.length)for(const t of e){const e=t.querySelectorAll('\nheader, footer, section, main, nav, aside, [role="section"], [role="banner"],\n[role="complementary"], [role="contentinfo"], [role="form"], [role="main"],\n[role="navigation"], [role="region"], [role="search"]\n');for(const[t,o]of e.entries())st(o,t+1,"landmark"),st(o,null,"region")}})()};ot(xt);export{xt as default,mt as dissect,gt as mark,ut as measure,wt as modes,ft as spacing,yt as typography};
2
28
  //# sourceMappingURL=speccer.esm.js.map