text-slicer 1.5.0-dev.0 → 1.5.0-dev.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/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.es.js +46 -49
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g={splitMode:"both",cssVariables:!1,dataAttributes:!1,keepWhitespaceNodes:!0,lockContainerHeight:!1},h=Object.freeze({word:"ts-word",char:"ts-char",whitespace:"ts-whitespace"}),o=" ",r=()=>typeof window<"u"&&typeof document<"u",c=t=>{const e=Intl.Segmenter;if(typeof e=="function"){const s=new e("en",{granularity:"grapheme"});return Array.from(s.segment(t),i=>i.segment)}return Array.from(t)},l=t=>t.split(o),a=t=>{const e={};return Object.keys(t).forEach(s=>{const i=t[s];i!==void 0&&(e[s]=i)}),e};exports.CLASSNAMES=h,exports.TextSlicer=class{el;original;opts;callbacks;charIndex;mounted;heightLocked=!1;lockedHeightPx=null;constructor(t={},e){const s=(i=t.container,r()&&i?typeof i=="string"?document.querySelector(i):i:null);var i;this.el=s,this.original=(n=>!!n&&typeof HTMLElement<"u"&&n instanceof HTMLElement)(s)?s.textContent?.toString()??"":"",this.opts={...g,...a(t)},this.callbacks=e,this.charIndex=0,this.mounted=!1}get metrics(){const t=this.original;return{wordTotal:t.length?l(t).length:0,charTotal:t.length,renderedAt:Date.now()}}init(){this.el&&(this.mounted=!0,this.opts.lockContainerHeight&&this.freezeHeight(),this.split())}reinit(t,e){if(this.el){if(typeof t=="string"&&(this.original=t),e){const s=this.opts.lockContainerHeight;this.opts={...this.opts,...a(e)},!s&&this.opts.lockContainerHeight?this.freezeHeight():s&&!this.opts.lockContainerHeight&&this.unfreezeHeight()}this.opts.lockContainerHeight&&this.freezeHeight(),this.split()}}clear(){this.el&&this.el.replaceChildren()}split(){if(!this.el)return;this.clear(),this.charIndex=0;const t=this.original,e=document.createDocumentFragment(),s=l(t);this.opts.splitMode==="chars"?this.appendChars(e,t):this.appendWords(e,s),this.el.appendChild(e),this.opts.cssVariables&&(this.el.style.setProperty("--word-total",String(s.length)),this.el.style.setProperty("--char-total",String(t.length))),this.callbacks?.onAfterRender?.(this.metrics)}destroy(){this.el&&(this.clear(),this.mounted=!1,this.unfreezeHeight())}updateOptions(t){const e=this.opts.lockContainerHeight;this.opts={...this.opts,...a(t)},!e&&this.opts.lockContainerHeight?this.freezeHeight():e&&!this.opts.lockContainerHeight&&this.unfreezeHeight(),this.mounted&&this.split()}freezeHeight(){if(!this.el||!r())return;const t=this.el.getBoundingClientRect(),e=Math.max(0,Math.round(t.height));e&&(this.heightLocked&&this.lockedHeightPx===e||(this.el.style.height=`${e}px`,this.el.style.overflow="hidden",this.heightLocked=!0,this.lockedHeightPx=e))}unfreezeHeight(){this.el&&r()&&(this.heightLocked&&(this.el.style.height="",this.el.style.overflow=""),this.heightLocked=!1,this.lockedHeightPx=null)}appendWords(t,e){e.forEach((s,i)=>{if(this.opts.splitMode==="both"){const n=this.createWordSpan(i,s);for(const d of c(s)){const p=this.createCharSpan(d);n.append(p)}t.append(n)}else{const n=this.createWordSpan(i);n.append(document.createTextNode(s)),t.append(n)}i<e.length-1&&t.append(this.createSpaceSpan())})}appendChars(t,e){for(const s of c(e)){const i=this.createCharSpan(s);t.append(i)}}createWordSpan(t,e=""){const s=document.createElement("span");return s.classList.add(h.word),this.opts.dataAttributes&&e&&s.setAttribute("data-word",e),this.opts.cssVariables&&s.style.setProperty("--word-index",String(t)),s}createCharSpan(t){const e=document.createElement("span");return e.textContent=t,this.opts.dataAttributes&&e.setAttribute("data-char",t),t===o?(e.classList.add(h.whitespace),this.opts.keepWhitespaceNodes||(e.textContent=o)):(e.classList.add(h.char),this.opts.cssVariables&&e.style.setProperty("--char-index",String(this.charIndex)),this.charIndex+=1),e}createSpaceSpan(){const t=document.createElement("span");return t.classList.add(h.whitespace),t.textContent=o,t}};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export interface TextSlicerOptions {
|
|
|
5
5
|
cssVariables?: boolean;
|
|
6
6
|
dataAttributes?: boolean;
|
|
7
7
|
keepWhitespaceNodes?: boolean;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/** При true фиксирует текущую высоту контейнера при init()/reinit(). */
|
|
9
|
+
lockContainerHeight?: boolean;
|
|
10
10
|
}
|
|
11
11
|
export interface TextSlicerMetrics {
|
|
12
12
|
wordTotal: number;
|
|
@@ -19,7 +19,6 @@ export interface TextSlicerCallbacks {
|
|
|
19
19
|
export declare const CLASSNAMES: Readonly<{
|
|
20
20
|
word: "ts-word";
|
|
21
21
|
char: "ts-char";
|
|
22
|
-
charWrap: "ts-char-wrap";
|
|
23
22
|
whitespace: "ts-whitespace";
|
|
24
23
|
}>;
|
|
25
24
|
export declare class TextSlicer {
|
|
@@ -29,6 +28,10 @@ export declare class TextSlicer {
|
|
|
29
28
|
private callbacks;
|
|
30
29
|
private charIndex;
|
|
31
30
|
private mounted;
|
|
31
|
+
/** Флаг, зафиксирована ли высота сейчас. */
|
|
32
|
+
private heightLocked;
|
|
33
|
+
/** Последнее зафиксированное значение высоты (в px). */
|
|
34
|
+
private lockedHeightPx;
|
|
32
35
|
constructor(options?: TextSlicerOptions, callbacks?: TextSlicerCallbacks);
|
|
33
36
|
get metrics(): TextSlicerMetrics;
|
|
34
37
|
init(): void;
|
|
@@ -37,10 +40,19 @@ export declare class TextSlicer {
|
|
|
37
40
|
split(): void;
|
|
38
41
|
destroy(): void;
|
|
39
42
|
updateOptions(next: Partial<TextSlicerOptions>): void;
|
|
43
|
+
/**
|
|
44
|
+
* Фиксирует текущую высоту контейнера (в px) и скрывает переполнение.
|
|
45
|
+
* Идемпотентно: повторный вызов без изменения высоты не трогает стили.
|
|
46
|
+
*/
|
|
47
|
+
freezeHeight(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Снимает фиксацию высоты контейнера.
|
|
50
|
+
* Возвращает инлайн-стили height/overflow к значениям по умолчанию.
|
|
51
|
+
*/
|
|
52
|
+
unfreezeHeight(): void;
|
|
40
53
|
private appendWords;
|
|
41
54
|
private appendChars;
|
|
42
55
|
private createWordSpan;
|
|
43
|
-
private
|
|
56
|
+
private createCharSpan;
|
|
44
57
|
private createSpaceSpan;
|
|
45
|
-
private applyIOSContainerSizeFix;
|
|
46
58
|
}
|
package/dist/index.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
const
|
|
1
|
+
const u = { splitMode: "both", cssVariables: !1, dataAttributes: !1, keepWhitespaceNodes: !0, lockContainerHeight: !1 }, o = Object.freeze({ word: "ts-word", char: "ts-char", whitespace: "ts-whitespace" }), r = " ", a = () => typeof window < "u" && typeof document < "u", l = (n) => {
|
|
2
2
|
const t = Intl.Segmenter;
|
|
3
3
|
if (typeof t == "function") {
|
|
4
4
|
const e = new t("en", { granularity: "grapheme" });
|
|
5
5
|
return Array.from(e.segment(n), (s) => s.segment);
|
|
6
6
|
}
|
|
7
7
|
return Array.from(n);
|
|
8
|
-
},
|
|
8
|
+
}, d = (n) => n.split(r), c = (n) => {
|
|
9
9
|
const t = {};
|
|
10
10
|
return Object.keys(n).forEach((e) => {
|
|
11
11
|
const s = n[e];
|
|
@@ -19,92 +19,89 @@ class f {
|
|
|
19
19
|
callbacks;
|
|
20
20
|
charIndex;
|
|
21
21
|
mounted;
|
|
22
|
+
heightLocked = !1;
|
|
23
|
+
lockedHeightPx = null;
|
|
22
24
|
constructor(t = {}, e) {
|
|
23
|
-
const s = (
|
|
24
|
-
var
|
|
25
|
-
this.el = s, this.original = ((
|
|
25
|
+
const s = (i = t.container, a() && i ? typeof i == "string" ? document.querySelector(i) : i : null);
|
|
26
|
+
var i;
|
|
27
|
+
this.el = s, this.original = ((h) => !!h && typeof HTMLElement < "u" && h instanceof HTMLElement)(s) ? s.textContent?.toString() ?? "" : "", this.opts = { ...u, ...c(t) }, this.callbacks = e, this.charIndex = 0, this.mounted = !1;
|
|
26
28
|
}
|
|
27
29
|
get metrics() {
|
|
28
30
|
const t = this.original;
|
|
29
|
-
return { wordTotal: t.length ?
|
|
31
|
+
return { wordTotal: t.length ? d(t).length : 0, charTotal: t.length, renderedAt: Date.now() };
|
|
30
32
|
}
|
|
31
33
|
init() {
|
|
32
|
-
this.el && (this.mounted = !0, this.split());
|
|
34
|
+
this.el && (this.mounted = !0, this.opts.lockContainerHeight && this.freezeHeight(), this.split());
|
|
33
35
|
}
|
|
34
36
|
reinit(t, e) {
|
|
35
|
-
|
|
37
|
+
if (this.el) {
|
|
38
|
+
if (typeof t == "string" && (this.original = t), e) {
|
|
39
|
+
const s = this.opts.lockContainerHeight;
|
|
40
|
+
this.opts = { ...this.opts, ...c(e) }, !s && this.opts.lockContainerHeight ? this.freezeHeight() : s && !this.opts.lockContainerHeight && this.unfreezeHeight();
|
|
41
|
+
}
|
|
42
|
+
this.opts.lockContainerHeight && this.freezeHeight(), this.split();
|
|
43
|
+
}
|
|
36
44
|
}
|
|
37
45
|
clear() {
|
|
38
|
-
this.el &&
|
|
46
|
+
this.el && this.el.replaceChildren();
|
|
39
47
|
}
|
|
40
48
|
split() {
|
|
41
49
|
if (!this.el) return;
|
|
42
50
|
this.clear(), this.charIndex = 0;
|
|
43
|
-
const t = this.original, e = document.createDocumentFragment(), s =
|
|
44
|
-
this.opts.splitMode === "chars" ? this.appendChars(e, t) : this.appendWords(e, s), this.el.appendChild(e), this.opts.cssVariables && (this.el.style.setProperty("--word-total", String(s.length)), this.el.style.setProperty("--char-total", String(t.length))), this.
|
|
45
|
-
if (!d()) return !1;
|
|
46
|
-
const r = navigator.userAgent || "", i = /iP(hone|ad|od)/.test(r), h = /WebKit/.test(r) && !/Chrome|CriOS|FxiOS|EdgiOS/.test(r);
|
|
47
|
-
return i && h;
|
|
48
|
-
})() && this.applyIOSContainerSizeFix(), this.callbacks?.onAfterRender?.(this.metrics);
|
|
51
|
+
const t = this.original, e = document.createDocumentFragment(), s = d(t);
|
|
52
|
+
this.opts.splitMode === "chars" ? this.appendChars(e, t) : this.appendWords(e, s), this.el.appendChild(e), this.opts.cssVariables && (this.el.style.setProperty("--word-total", String(s.length)), this.el.style.setProperty("--char-total", String(t.length))), this.callbacks?.onAfterRender?.(this.metrics);
|
|
49
53
|
}
|
|
50
54
|
destroy() {
|
|
51
|
-
this.el && (this.clear(), this.mounted = !1);
|
|
55
|
+
this.el && (this.clear(), this.mounted = !1, this.unfreezeHeight());
|
|
52
56
|
}
|
|
53
57
|
updateOptions(t) {
|
|
54
|
-
|
|
58
|
+
const e = this.opts.lockContainerHeight;
|
|
59
|
+
this.opts = { ...this.opts, ...c(t) }, !e && this.opts.lockContainerHeight ? this.freezeHeight() : e && !this.opts.lockContainerHeight && this.unfreezeHeight(), this.mounted && this.split();
|
|
60
|
+
}
|
|
61
|
+
freezeHeight() {
|
|
62
|
+
if (!this.el || !a()) return;
|
|
63
|
+
const t = this.el.getBoundingClientRect(), e = Math.max(0, Math.round(t.height));
|
|
64
|
+
e && (this.heightLocked && this.lockedHeightPx === e || (this.el.style.height = `${e}px`, this.el.style.overflow = "hidden", this.heightLocked = !0, this.lockedHeightPx = e));
|
|
65
|
+
}
|
|
66
|
+
unfreezeHeight() {
|
|
67
|
+
this.el && a() && (this.heightLocked && (this.el.style.height = "", this.el.style.overflow = ""), this.heightLocked = !1, this.lockedHeightPx = null);
|
|
55
68
|
}
|
|
56
69
|
appendWords(t, e) {
|
|
57
|
-
e.forEach((s,
|
|
70
|
+
e.forEach((s, i) => {
|
|
58
71
|
if (this.opts.splitMode === "both") {
|
|
59
|
-
const
|
|
60
|
-
for (const
|
|
61
|
-
const
|
|
62
|
-
|
|
72
|
+
const h = this.createWordSpan(i, s);
|
|
73
|
+
for (const p of l(s)) {
|
|
74
|
+
const g = this.createCharSpan(p);
|
|
75
|
+
h.append(g);
|
|
63
76
|
}
|
|
64
|
-
t.append(
|
|
77
|
+
t.append(h);
|
|
65
78
|
} else {
|
|
66
|
-
const
|
|
67
|
-
|
|
79
|
+
const h = this.createWordSpan(i);
|
|
80
|
+
h.append(document.createTextNode(s)), t.append(h);
|
|
68
81
|
}
|
|
69
|
-
|
|
82
|
+
i < e.length - 1 && t.append(this.createSpaceSpan());
|
|
70
83
|
});
|
|
71
84
|
}
|
|
72
85
|
appendChars(t, e) {
|
|
73
86
|
for (const s of l(e)) {
|
|
74
|
-
const
|
|
75
|
-
t.append(
|
|
87
|
+
const i = this.createCharSpan(s);
|
|
88
|
+
t.append(i);
|
|
76
89
|
}
|
|
77
90
|
}
|
|
78
91
|
createWordSpan(t, e = "") {
|
|
79
92
|
const s = document.createElement("span");
|
|
80
|
-
return s.classList.add(
|
|
93
|
+
return s.classList.add(o.word), this.opts.dataAttributes && e && s.setAttribute("data-word", e), this.opts.cssVariables && s.style.setProperty("--word-index", String(t)), s;
|
|
81
94
|
}
|
|
82
|
-
|
|
83
|
-
if (t === o) {
|
|
84
|
-
const s = document.createElement("span");
|
|
85
|
-
return s.classList.add(a.whitespace), s.textContent = o, s;
|
|
86
|
-
}
|
|
87
|
-
if (this.opts.extraCharWrapper) {
|
|
88
|
-
const s = document.createElement("span");
|
|
89
|
-
s.classList.add(a.charWrap);
|
|
90
|
-
const r = document.createElement("span");
|
|
91
|
-
return r.classList.add(a.char), r.textContent = t, this.opts.dataAttributes && r.setAttribute("data-char", t), this.opts.cssVariables && r.style.setProperty(p, String(this.charIndex)), this.charIndex += 1, s.appendChild(r), s;
|
|
92
|
-
}
|
|
95
|
+
createCharSpan(t) {
|
|
93
96
|
const e = document.createElement("span");
|
|
94
|
-
return e.
|
|
97
|
+
return e.textContent = t, this.opts.dataAttributes && e.setAttribute("data-char", t), t === r ? (e.classList.add(o.whitespace), this.opts.keepWhitespaceNodes || (e.textContent = r)) : (e.classList.add(o.char), this.opts.cssVariables && e.style.setProperty("--char-index", String(this.charIndex)), this.charIndex += 1), e;
|
|
95
98
|
}
|
|
96
99
|
createSpaceSpan() {
|
|
97
100
|
const t = document.createElement("span");
|
|
98
|
-
return t.classList.add(
|
|
99
|
-
}
|
|
100
|
-
applyIOSContainerSizeFix() {
|
|
101
|
-
if (!this.el) return;
|
|
102
|
-
this.el.style.minHeight = "", this.el.offsetHeight;
|
|
103
|
-
const t = this.el.getBoundingClientRect(), e = Math.ceil(t.height);
|
|
104
|
-
e > 0 && (this.el.style.minHeight = `${e}px`);
|
|
101
|
+
return t.classList.add(o.whitespace), t.textContent = r, t;
|
|
105
102
|
}
|
|
106
103
|
}
|
|
107
104
|
export {
|
|
108
|
-
|
|
105
|
+
o as CLASSNAMES,
|
|
109
106
|
f as TextSlicer
|
|
110
107
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(o,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):h((o=typeof globalThis<"u"?globalThis:o||self).TextSlicer={})})(this,function(o){"use strict";const h={splitMode:"both",cssVariables:!1,dataAttributes:!1,keepWhitespaceNodes:!0,lockContainerHeight:!1},r=Object.freeze({word:"ts-word",char:"ts-char",whitespace:"ts-whitespace"}),a=" ",c=()=>typeof window<"u"&&typeof document<"u",d=t=>{const e=Intl.Segmenter;if(typeof e=="function"){const s=new e("en",{granularity:"grapheme"});return Array.from(s.segment(t),i=>i.segment)}return Array.from(t)},p=t=>t.split(a),l=t=>{const e={};return Object.keys(t).forEach(s=>{const i=t[s];i!==void 0&&(e[s]=i)}),e};o.CLASSNAMES=r,o.TextSlicer=class{el;original;opts;callbacks;charIndex;mounted;heightLocked=!1;lockedHeightPx=null;constructor(t={},e){const s=(i=t.container,c()&&i?typeof i=="string"?document.querySelector(i):i:null);var i;this.el=s,this.original=(n=>!!n&&typeof HTMLElement<"u"&&n instanceof HTMLElement)(s)?s.textContent?.toString()??"":"",this.opts={...h,...l(t)},this.callbacks=e,this.charIndex=0,this.mounted=!1}get metrics(){const t=this.original;return{wordTotal:t.length?p(t).length:0,charTotal:t.length,renderedAt:Date.now()}}init(){this.el&&(this.mounted=!0,this.opts.lockContainerHeight&&this.freezeHeight(),this.split())}reinit(t,e){if(this.el){if(typeof t=="string"&&(this.original=t),e){const s=this.opts.lockContainerHeight;this.opts={...this.opts,...l(e)},!s&&this.opts.lockContainerHeight?this.freezeHeight():s&&!this.opts.lockContainerHeight&&this.unfreezeHeight()}this.opts.lockContainerHeight&&this.freezeHeight(),this.split()}}clear(){this.el&&this.el.replaceChildren()}split(){if(!this.el)return;this.clear(),this.charIndex=0;const t=this.original,e=document.createDocumentFragment(),s=p(t);this.opts.splitMode==="chars"?this.appendChars(e,t):this.appendWords(e,s),this.el.appendChild(e),this.opts.cssVariables&&(this.el.style.setProperty("--word-total",String(s.length)),this.el.style.setProperty("--char-total",String(t.length))),this.callbacks?.onAfterRender?.(this.metrics)}destroy(){this.el&&(this.clear(),this.mounted=!1,this.unfreezeHeight())}updateOptions(t){const e=this.opts.lockContainerHeight;this.opts={...this.opts,...l(t)},!e&&this.opts.lockContainerHeight?this.freezeHeight():e&&!this.opts.lockContainerHeight&&this.unfreezeHeight(),this.mounted&&this.split()}freezeHeight(){if(!this.el||!c())return;const t=this.el.getBoundingClientRect(),e=Math.max(0,Math.round(t.height));e&&(this.heightLocked&&this.lockedHeightPx===e||(this.el.style.height=`${e}px`,this.el.style.overflow="hidden",this.heightLocked=!0,this.lockedHeightPx=e))}unfreezeHeight(){this.el&&c()&&(this.heightLocked&&(this.el.style.height="",this.el.style.overflow=""),this.heightLocked=!1,this.lockedHeightPx=null)}appendWords(t,e){e.forEach((s,i)=>{if(this.opts.splitMode==="both"){const n=this.createWordSpan(i,s);for(const g of d(s)){const u=this.createCharSpan(g);n.append(u)}t.append(n)}else{const n=this.createWordSpan(i);n.append(document.createTextNode(s)),t.append(n)}i<e.length-1&&t.append(this.createSpaceSpan())})}appendChars(t,e){for(const s of d(e)){const i=this.createCharSpan(s);t.append(i)}}createWordSpan(t,e=""){const s=document.createElement("span");return s.classList.add(r.word),this.opts.dataAttributes&&e&&s.setAttribute("data-word",e),this.opts.cssVariables&&s.style.setProperty("--word-index",String(t)),s}createCharSpan(t){const e=document.createElement("span");return e.textContent=t,this.opts.dataAttributes&&e.setAttribute("data-char",t),t===a?(e.classList.add(r.whitespace),this.opts.keepWhitespaceNodes||(e.textContent=a)):(e.classList.add(r.char),this.opts.cssVariables&&e.style.setProperty("--char-index",String(this.charIndex)),this.charIndex+=1),e}createSpaceSpan(){const t=document.createElement("span");return t.classList.add(r.whitespace),t.textContent=a,t}},Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "text-slicer",
|
|
3
|
-
"version": "1.5.0-dev.
|
|
3
|
+
"version": "1.5.0-dev.1",
|
|
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",
|