text-slicer 1.4.0-dev.4 → 1.4.0-dev.6
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/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.es.js +26 -30
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";class
|
|
1
|
+
"use strict";class r{textElement;originalText;splitMode;cssVariables;dataAttributes;waitForFonts;fontReadyTimeout;stabilizeLayout;nowrapWords;innerWrapper;charIndexCounter;destroyed;constructor(t={}){const{container:e=".text-slicer",splitMode:s="both",cssVariables:a=!1,dataAttributes:n=!1,waitForFonts:o=!1,fontReadyTimeout:l=1500,stabilizeLayout:h=!1,nowrapWords:c=!1,innerWrapper:i=!0}=t;this.textElement=typeof e=="string"?document.querySelector(e):e??null,this.originalText="",this.splitMode=s,this.cssVariables=a,this.dataAttributes=n,this.waitForFonts=o,this.fontReadyTimeout=l,this.stabilizeLayout=h,this.nowrapWords=c,this.innerWrapper=i,this.charIndexCounter=0,this.destroyed=!1,this.textElement&&(this.originalText=(this.textElement.textContent??"").trim(),this.originalText.length>0&&this.textElement.setAttribute("aria-label",this.originalText))}async init(){this.textElement&&(this.waitForFonts&&await r.waitFontsForElement(this.textElement,this.fontReadyTimeout).catch(()=>{}),await r.nextFrame(),this.split())}destroy(){this.textElement&&!this.destroyed&&(this.textElement.innerHTML="",this.textElement.textContent=this.originalText,this.textElement.removeAttribute("aria-hidden"),this.destroyed=!0)}split(){if(!this.textElement)return;this.clear(),this.charIndexCounter=0;const t=document.createDocumentFragment(),e=this.originalText.split(" "),s=this.originalText.length;this.splitMode==="words"||this.splitMode==="both"?this.splitWords(t,e):this.splitChars(t),this.textElement.appendChild(t),r.forceReflow(this.textElement),this.cssVariables&&(this.textElement.style.setProperty("--word-total",String(e.length)),this.textElement.style.setProperty("--char-total",String(s))),this.textElement.setAttribute("aria-hidden","false")}splitWords(t,e){e.forEach((s,a)=>{if(this.splitMode==="both"){const n=this.createWordSpan(a,s);for(const o of s)n.append(this.createCharSpan(o));t.append(n)}else{const n=this.createWordSpan(a);n.append(document.createTextNode(s)),t.append(n)}a<e.length-1&&t.append(r.createSpaceSpan())})}splitChars(t){for(const e of this.originalText)t.append(this.createCharSpan(e))}createWordSpan(t,e=""){const s=document.createElement("span");return s.classList.add("word"),this.dataAttributes&&s.setAttribute("data-word",e),this.cssVariables&&s.style.setProperty("--word-index",String(t)),this.stabilizeLayout&&(r.applyStableInlineBox(s),this.nowrapWords&&(s.style.whiteSpace="nowrap")),s}createCharSpan(t){const e=document.createElement("span");if(t===" ")return e.classList.add("whitespace"),e.textContent=" ",e;if(e.classList.add("char"),e.textContent=t,e.style.position="relative",e.style.color="transparent",this.cssVariables&&e.style.setProperty("--char-index",String(this.charIndexCounter)),this.dataAttributes&&e.setAttribute("data-char",t),this.stabilizeLayout&&r.applyStableInlineBox(e),this.innerWrapper){const s=document.createElement("span");s.classList.add("char-inner"),s.textContent=t,s.style.position="absolute",s.style.left="0",s.style.top="0",s.style.right="auto",s.style.bottom="auto",e.appendChild(s)}return this.charIndexCounter+=1,e}static createSpaceSpan(){const t=document.createElement("span");return t.classList.add("whitespace"),t.textContent=" ",t}clear(){this.textElement&&(this.textElement.innerHTML="")}static applyStableInlineBox(t){t.style.display="inline-block",t.style.verticalAlign="baseline",t.style.lineHeight="1em",t.style.backfaceVisibility="hidden",t.style.willChange="transform"}static forceReflow(t){t.offsetHeight}static nextFrame(){return new Promise(t=>requestAnimationFrame(()=>t()))}static getFontFaceSet(){const t=document;return typeof t.fonts=="object"&&t.fonts?t.fonts:null}static async waitFontsForElement(t,e){const s=r.getFontFaceSet();if(!s)return;const a=getComputedStyle(t),n=a.fontFamily.split(",").map(i=>i.trim().replace(/^['"]|['"]$/g,"")).filter(i=>i.length>0),o=a.fontStyle||"normal",l=a.fontWeight||"400",h=a.fontStretch||"normal",c=n.map(i=>`${o} ${l} ${h} 1em ${i}`).map(i=>s.load(i));await Promise.race([Promise.all(c).then(()=>{}),new Promise(i=>window.setTimeout(i,e))])}}module.exports=r;
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ declare class TextSlicer {
|
|
|
37
37
|
private static forceReflow;
|
|
38
38
|
private static nextFrame;
|
|
39
39
|
private static getFontFaceSet;
|
|
40
|
-
|
|
40
|
+
/** Ждём именно те шрифты, что применяются к элементу */
|
|
41
|
+
private static waitFontsForElement;
|
|
41
42
|
}
|
|
42
43
|
export default TextSlicer;
|
package/dist/index.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class r {
|
|
2
2
|
textElement;
|
|
3
3
|
originalText;
|
|
4
4
|
splitMode;
|
|
@@ -9,16 +9,15 @@ class n {
|
|
|
9
9
|
stabilizeLayout;
|
|
10
10
|
nowrapWords;
|
|
11
11
|
innerWrapper;
|
|
12
|
-
charIndexCounter
|
|
13
|
-
destroyed
|
|
12
|
+
charIndexCounter;
|
|
13
|
+
destroyed;
|
|
14
14
|
constructor(t = {}) {
|
|
15
|
-
const { container: e = ".text-slicer", splitMode: s = "both", cssVariables:
|
|
16
|
-
|
|
17
|
-
this.originalText = (this.textElement.textContent ?? "").trim(), this.splitMode = s, this.cssVariables = a, this.dataAttributes = i, this.waitForFonts = r, this.fontReadyTimeout = o, this.stabilizeLayout = l, this.nowrapWords = h, this.innerWrapper = d, this.originalText.length > 0 && this.textElement.setAttribute("aria-label", this.originalText);
|
|
15
|
+
const { container: e = ".text-slicer", splitMode: s = "both", cssVariables: n = !1, dataAttributes: a = !1, waitForFonts: o = !1, fontReadyTimeout: l = 1500, stabilizeLayout: h = !1, nowrapWords: c = !1, innerWrapper: i = !0 } = t;
|
|
16
|
+
this.textElement = typeof e == "string" ? document.querySelector(e) : e ?? null, this.originalText = "", this.splitMode = s, this.cssVariables = n, this.dataAttributes = a, this.waitForFonts = o, this.fontReadyTimeout = l, this.stabilizeLayout = h, this.nowrapWords = c, this.innerWrapper = i, this.charIndexCounter = 0, this.destroyed = !1, this.textElement && (this.originalText = (this.textElement.textContent ?? "").trim(), this.originalText.length > 0 && this.textElement.setAttribute("aria-label", this.originalText));
|
|
18
17
|
}
|
|
19
18
|
async init() {
|
|
20
|
-
this.textElement && (this.waitForFonts && await
|
|
21
|
-
}), await
|
|
19
|
+
this.textElement && (this.waitForFonts && await r.waitFontsForElement(this.textElement, this.fontReadyTimeout).catch(() => {
|
|
20
|
+
}), await r.nextFrame(), this.split());
|
|
22
21
|
}
|
|
23
22
|
destroy() {
|
|
24
23
|
this.textElement && !this.destroyed && (this.textElement.innerHTML = "", this.textElement.textContent = this.originalText, this.textElement.removeAttribute("aria-hidden"), this.destroyed = !0);
|
|
@@ -27,19 +26,19 @@ class n {
|
|
|
27
26
|
if (!this.textElement) return;
|
|
28
27
|
this.clear(), this.charIndexCounter = 0;
|
|
29
28
|
const t = document.createDocumentFragment(), e = this.originalText.split(" "), s = this.originalText.length;
|
|
30
|
-
this.splitMode === "words" || this.splitMode === "both" ? this.splitWords(t, e) : this.
|
|
29
|
+
this.splitMode === "words" || this.splitMode === "both" ? this.splitWords(t, e) : this.splitChars(t), this.textElement.appendChild(t), r.forceReflow(this.textElement), this.cssVariables && (this.textElement.style.setProperty("--word-total", String(e.length)), this.textElement.style.setProperty("--char-total", String(s))), this.textElement.setAttribute("aria-hidden", "false");
|
|
31
30
|
}
|
|
32
31
|
splitWords(t, e) {
|
|
33
|
-
e.forEach((s,
|
|
32
|
+
e.forEach((s, n) => {
|
|
34
33
|
if (this.splitMode === "both") {
|
|
35
|
-
const
|
|
36
|
-
for (const
|
|
37
|
-
t.append(
|
|
34
|
+
const a = this.createWordSpan(n, s);
|
|
35
|
+
for (const o of s) a.append(this.createCharSpan(o));
|
|
36
|
+
t.append(a);
|
|
38
37
|
} else {
|
|
39
|
-
const
|
|
40
|
-
|
|
38
|
+
const a = this.createWordSpan(n);
|
|
39
|
+
a.append(document.createTextNode(s)), t.append(a);
|
|
41
40
|
}
|
|
42
|
-
|
|
41
|
+
n < e.length - 1 && t.append(r.createSpaceSpan());
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
44
|
splitChars(t) {
|
|
@@ -47,15 +46,15 @@ class n {
|
|
|
47
46
|
}
|
|
48
47
|
createWordSpan(t, e = "") {
|
|
49
48
|
const s = document.createElement("span");
|
|
50
|
-
return s.classList.add("word"), this.dataAttributes && s.setAttribute("data-word", e), this.cssVariables && s.style.setProperty("--word-index", String(t)), this.stabilizeLayout && (
|
|
49
|
+
return s.classList.add("word"), this.dataAttributes && s.setAttribute("data-word", e), this.cssVariables && s.style.setProperty("--word-index", String(t)), this.stabilizeLayout && (r.applyStableInlineBox(s), this.nowrapWords && (s.style.whiteSpace = "nowrap")), s;
|
|
51
50
|
}
|
|
52
51
|
createCharSpan(t) {
|
|
53
52
|
const e = document.createElement("span");
|
|
54
53
|
if (t === " ") return e.classList.add("whitespace"), e.textContent = " ", e;
|
|
55
|
-
if (e.classList.add("char"), this.cssVariables && e.style.setProperty("--char-index", String(this.charIndexCounter)), this.dataAttributes && e.setAttribute("data-char", t), this.stabilizeLayout &&
|
|
54
|
+
if (e.classList.add("char"), e.textContent = t, e.style.position = "relative", e.style.color = "transparent", this.cssVariables && e.style.setProperty("--char-index", String(this.charIndexCounter)), this.dataAttributes && e.setAttribute("data-char", t), this.stabilizeLayout && r.applyStableInlineBox(e), this.innerWrapper) {
|
|
56
55
|
const s = document.createElement("span");
|
|
57
|
-
s.classList.add("char-inner"), s.textContent = t, e.appendChild(s);
|
|
58
|
-
}
|
|
56
|
+
s.classList.add("char-inner"), s.textContent = t, s.style.position = "absolute", s.style.left = "0", s.style.top = "0", s.style.right = "auto", s.style.bottom = "auto", e.appendChild(s);
|
|
57
|
+
}
|
|
59
58
|
return this.charIndexCounter += 1, e;
|
|
60
59
|
}
|
|
61
60
|
static createSpaceSpan() {
|
|
@@ -78,17 +77,14 @@ class n {
|
|
|
78
77
|
const t = document;
|
|
79
78
|
return typeof t.fonts == "object" && t.fonts ? t.fonts : null;
|
|
80
79
|
}
|
|
81
|
-
static
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
88
|
-
e.ready.then(() => i()).catch(() => i()), t > 0 && window.setTimeout(() => i(), t);
|
|
89
|
-
}) : Promise.resolve();
|
|
80
|
+
static async waitFontsForElement(t, e) {
|
|
81
|
+
const s = r.getFontFaceSet();
|
|
82
|
+
if (!s) return;
|
|
83
|
+
const n = getComputedStyle(t), a = n.fontFamily.split(",").map((i) => i.trim().replace(/^['"]|['"]$/g, "")).filter((i) => i.length > 0), o = n.fontStyle || "normal", l = n.fontWeight || "400", h = n.fontStretch || "normal", c = a.map((i) => `${o} ${l} ${h} 1em ${i}`).map((i) => s.load(i));
|
|
84
|
+
await Promise.race([Promise.all(c).then(() => {
|
|
85
|
+
}), new Promise((i) => window.setTimeout(i, e))]);
|
|
90
86
|
}
|
|
91
87
|
}
|
|
92
88
|
export {
|
|
93
|
-
|
|
89
|
+
r as default
|
|
94
90
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(s,
|
|
1
|
+
(function(s,l){typeof exports=="object"&&typeof module<"u"?module.exports=l():typeof define=="function"&&define.amd?define(l):(s=typeof globalThis<"u"?globalThis:s||self).TextSlicer=l()})(this,function(){"use strict";class s{textElement;originalText;splitMode;cssVariables;dataAttributes;waitForFonts;fontReadyTimeout;stabilizeLayout;nowrapWords;innerWrapper;charIndexCounter;destroyed;constructor(t={}){const{container:e=".text-slicer",splitMode:i="both",cssVariables:a=!1,dataAttributes:r=!1,waitForFonts:o=!1,fontReadyTimeout:h=1500,stabilizeLayout:c=!1,nowrapWords:d=!1,innerWrapper:n=!0}=t;this.textElement=typeof e=="string"?document.querySelector(e):e??null,this.originalText="",this.splitMode=i,this.cssVariables=a,this.dataAttributes=r,this.waitForFonts=o,this.fontReadyTimeout=h,this.stabilizeLayout=c,this.nowrapWords=d,this.innerWrapper=n,this.charIndexCounter=0,this.destroyed=!1,this.textElement&&(this.originalText=(this.textElement.textContent??"").trim(),this.originalText.length>0&&this.textElement.setAttribute("aria-label",this.originalText))}async init(){this.textElement&&(this.waitForFonts&&await s.waitFontsForElement(this.textElement,this.fontReadyTimeout).catch(()=>{}),await s.nextFrame(),this.split())}destroy(){this.textElement&&!this.destroyed&&(this.textElement.innerHTML="",this.textElement.textContent=this.originalText,this.textElement.removeAttribute("aria-hidden"),this.destroyed=!0)}split(){if(!this.textElement)return;this.clear(),this.charIndexCounter=0;const t=document.createDocumentFragment(),e=this.originalText.split(" "),i=this.originalText.length;this.splitMode==="words"||this.splitMode==="both"?this.splitWords(t,e):this.splitChars(t),this.textElement.appendChild(t),s.forceReflow(this.textElement),this.cssVariables&&(this.textElement.style.setProperty("--word-total",String(e.length)),this.textElement.style.setProperty("--char-total",String(i))),this.textElement.setAttribute("aria-hidden","false")}splitWords(t,e){e.forEach((i,a)=>{if(this.splitMode==="both"){const r=this.createWordSpan(a,i);for(const o of i)r.append(this.createCharSpan(o));t.append(r)}else{const r=this.createWordSpan(a);r.append(document.createTextNode(i)),t.append(r)}a<e.length-1&&t.append(s.createSpaceSpan())})}splitChars(t){for(const e of this.originalText)t.append(this.createCharSpan(e))}createWordSpan(t,e=""){const i=document.createElement("span");return i.classList.add("word"),this.dataAttributes&&i.setAttribute("data-word",e),this.cssVariables&&i.style.setProperty("--word-index",String(t)),this.stabilizeLayout&&(s.applyStableInlineBox(i),this.nowrapWords&&(i.style.whiteSpace="nowrap")),i}createCharSpan(t){const e=document.createElement("span");if(t===" ")return e.classList.add("whitespace"),e.textContent=" ",e;if(e.classList.add("char"),e.textContent=t,e.style.position="relative",e.style.color="transparent",this.cssVariables&&e.style.setProperty("--char-index",String(this.charIndexCounter)),this.dataAttributes&&e.setAttribute("data-char",t),this.stabilizeLayout&&s.applyStableInlineBox(e),this.innerWrapper){const i=document.createElement("span");i.classList.add("char-inner"),i.textContent=t,i.style.position="absolute",i.style.left="0",i.style.top="0",i.style.right="auto",i.style.bottom="auto",e.appendChild(i)}return this.charIndexCounter+=1,e}static createSpaceSpan(){const t=document.createElement("span");return t.classList.add("whitespace"),t.textContent=" ",t}clear(){this.textElement&&(this.textElement.innerHTML="")}static applyStableInlineBox(t){t.style.display="inline-block",t.style.verticalAlign="baseline",t.style.lineHeight="1em",t.style.backfaceVisibility="hidden",t.style.willChange="transform"}static forceReflow(t){t.offsetHeight}static nextFrame(){return new Promise(t=>requestAnimationFrame(()=>t()))}static getFontFaceSet(){const t=document;return typeof t.fonts=="object"&&t.fonts?t.fonts:null}static async waitFontsForElement(t,e){const i=s.getFontFaceSet();if(!i)return;const a=getComputedStyle(t),r=a.fontFamily.split(",").map(n=>n.trim().replace(/^['"]|['"]$/g,"")).filter(n=>n.length>0),o=a.fontStyle||"normal",h=a.fontWeight||"400",c=a.fontStretch||"normal",d=r.map(n=>`${o} ${h} ${c} 1em ${n}`).map(n=>i.load(n));await Promise.race([Promise.all(d).then(()=>{}),new Promise(n=>window.setTimeout(n,e))])}}return s});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "text-slicer",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.6",
|
|
4
4
|
"description": "TextSlicer is designed to split text within an HTML element into separate words and/or characters, wrapping each word and/or character in separate span elements.",
|
|
5
5
|
"author": "ux-ui.pro",
|
|
6
6
|
"license": "MIT",
|