smart-text-ellipsis 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 wurencaideli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ ## Introduction
2
+
3
+ [DEMO](https://wurencaideli.github.io/smart-text-ellipsis/demo.html)
4
+
5
+ #### install
6
+
7
+ ```javascript
8
+ npm install smart-text-ellipsis
9
+ ```
10
+
11
+ #### How to use
12
+
13
+ ```javascript
14
+
15
+ ```
@@ -0,0 +1,116 @@
1
+ /*!
2
+ * smart-text-ellipsis v0.0.2
3
+ * Copyright 2025 wuzhanggui https://github.com/wurencaideli
4
+ * Licensed under MIT
5
+ */
6
+ 'use strict';
7
+ function e(e) {
8
+ e && e.parentNode && e.parentNode.removeChild(e);
9
+ }
10
+ function t(e, t) {
11
+ e.classList.add(t);
12
+ }
13
+ function s(e, t) {
14
+ e.classList.remove(t);
15
+ }
16
+ exports.SmartTextEllipsis = class {
17
+ isDestroyed = !1;
18
+ maxLines = 0;
19
+ targetEl = void 0;
20
+ expandEl = void 0;
21
+ collapseEl = void 0;
22
+ placeholderEl = void 0;
23
+ isOpen = !1;
24
+ #e = 0;
25
+ constructor(e = {}) {
26
+ const s = e.targetEl,
27
+ i = e.isOpen,
28
+ l = e.maxLines,
29
+ n = document.createElement('span'),
30
+ p = document.createElement('div'),
31
+ h = document.createElement('div');
32
+ (n.innerText = e.expandElText || 'Expand'),
33
+ (p.innerText = e.collapseElText || 'Collapse'),
34
+ (n.onclick = () => {
35
+ this.#t();
36
+ }),
37
+ (p.onclick = () => {
38
+ this.#s();
39
+ }),
40
+ t(p, 'smart-text-ellipsis-collapse'),
41
+ t(n, 'smart-text-ellipsis-expand'),
42
+ t(h, 'smart-text-ellipsis-placeholder'),
43
+ s.prepend(n),
44
+ s.prepend(h),
45
+ s.appendChild(p),
46
+ (this.targetEl = s),
47
+ (this.isOpen = i),
48
+ (this.maxLines = l),
49
+ (this.expandEl = n),
50
+ (this.collapseEl = p),
51
+ (this.placeholderEl = h),
52
+ this.update();
53
+ }
54
+ destroy() {
55
+ (this.isOpen = !0),
56
+ e(this.expandEl),
57
+ e(this.collapseEl),
58
+ this.#i(),
59
+ (this.targetEl = void 0),
60
+ (this.expandEl = void 0),
61
+ (this.collapseEl = void 0),
62
+ (this.isDestroyed = !0);
63
+ }
64
+ update() {
65
+ this.isDestroyed || ((this.#e = this.#l()), this.#i(), this.#n(), this.#p());
66
+ }
67
+ #t() {
68
+ this.isDestroyed || ((this.isOpen = !0), this.update());
69
+ }
70
+ #s() {
71
+ this.isDestroyed || ((this.isOpen = !1), this.update());
72
+ }
73
+ #i() {
74
+ const e = this.targetEl;
75
+ e &&
76
+ (this.isDestroyed
77
+ ? e.style.setProperty('--max-lines', void 0)
78
+ : e.style.setProperty('--max-lines', `${this.maxLines}`),
79
+ 1 == this.maxLines
80
+ ? (t(e, 'smart-text-ellipsis-one'), s(e, 'smart-text-ellipsis-more'))
81
+ : (t(e, 'smart-text-ellipsis-more'), s(e, 'smart-text-ellipsis-one')),
82
+ this.isOpen && (s(e, 'smart-text-ellipsis-more'), s(e, 'smart-text-ellipsis-one')),
83
+ s(e, 'is-ellipsis'),
84
+ s(e, 'is-exceeded-max-line'));
85
+ }
86
+ #p() {
87
+ if (this.isDestroyed) return;
88
+ const e = this.targetEl;
89
+ e &&
90
+ (this.isOpen
91
+ ? this.#h() > this.maxLines && t(e, 'is-exceeded-max-line')
92
+ : this.#a() && t(e, 'is-ellipsis'));
93
+ }
94
+ #n() {
95
+ const e = this.#e,
96
+ t = this.placeholderEl,
97
+ s = this.targetEl;
98
+ t.style.height = s.clientHeight - e + 'px';
99
+ }
100
+ #l() {
101
+ const e = this.targetEl;
102
+ if (e) return parseFloat(getComputedStyle(e).lineHeight) || 24;
103
+ }
104
+ #a() {
105
+ const e = this.maxLines,
106
+ t = this.targetEl;
107
+ return 1 === e ? t.scrollWidth > t.clientWidth : t.scrollHeight > t.clientHeight;
108
+ }
109
+ #h() {
110
+ const e = this.targetEl,
111
+ t = this.collapseEl,
112
+ s = this.#e;
113
+ return Math.floor((e.clientHeight - t.clientHeight) / s);
114
+ }
115
+ };
116
+ //# sourceMappingURL=smart-text-ellipsis.cjs.js.map
@@ -0,0 +1,68 @@
1
+ {
2
+ "version": 3,
3
+ "file": "smart-text-ellipsis.cjs.js",
4
+ "sources": [
5
+ "../src/common.js",
6
+ "../src/index.js"
7
+ ],
8
+ "sourcesContent": [
9
+ "export function removeElement(element) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\nexport function addElementClass(el, className) {\n el.classList.add(className);\n}\nexport function removeElementClass(el, className) {\n el.classList.remove(className);\n}\n",
10
+ "import { addElementClass, removeElement, removeElementClass } from './common';\nexport class SmartTextEllipsis {\n isDestroyed = false;\n maxLines = 0;\n targetEl = undefined;\n expandEl = undefined;\n collapseEl = undefined;\n placeholderEl = undefined;\n isOpen = false;\n #lineHeight = 0;\n constructor(options = {}) {\n const targetEl = options.targetEl;\n const isOpen = options.isOpen;\n const maxLines = options.maxLines;\n const expandEl = document.createElement('span');\n const collapseEl = document.createElement('div');\n const placeholderEl = document.createElement('div');\n expandEl.innerText = options.expandElText || 'Expand';\n collapseEl.innerText = options.collapseElText || 'Collapse';\n expandEl.onclick = () => {\n this.#handleExpand();\n };\n collapseEl.onclick = () => {\n this.#handleCollapse();\n };\n addElementClass(collapseEl, 'smart-text-ellipsis-collapse');\n addElementClass(expandEl, 'smart-text-ellipsis-expand');\n addElementClass(placeholderEl, 'smart-text-ellipsis-placeholder');\n targetEl.prepend(expandEl);\n targetEl.prepend(placeholderEl);\n targetEl.appendChild(collapseEl);\n this.targetEl = targetEl;\n this.isOpen = isOpen;\n this.maxLines = maxLines;\n this.expandEl = expandEl;\n this.collapseEl = collapseEl;\n this.placeholderEl = placeholderEl;\n this.update();\n }\n /** 销毁实例 */\n destroy() {\n this.isOpen = true;\n removeElement(this.expandEl);\n removeElement(this.collapseEl);\n this.#setupClass();\n this.targetEl = undefined;\n this.expandEl = undefined;\n this.collapseEl = undefined;\n this.isDestroyed = true;\n }\n /** 更新样式 */\n update() {\n if (this.isDestroyed) return;\n this.#lineHeight = this.#getLineHeight();\n this.#setupClass();\n this.#setupPlaceholderStyle();\n this.#setupBtClass();\n }\n #handleExpand() {\n if (this.isDestroyed) return;\n this.isOpen = true;\n this.update();\n }\n #handleCollapse() {\n if (this.isDestroyed) return;\n this.isOpen = false;\n this.update();\n }\n /** 设置容器的类名 */\n #setupClass() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (!this.isDestroyed) {\n targetEl.style.setProperty('--max-lines', `${this.maxLines}`);\n } else {\n targetEl.style.setProperty('--max-lines', undefined);\n }\n if (this.maxLines == 1) {\n addElementClass(targetEl, 'smart-text-ellipsis-one');\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n } else {\n addElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n if (this.isOpen) {\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n removeElementClass(targetEl, 'is-ellipsis');\n removeElementClass(targetEl, 'is-exceeded-max-line');\n }\n /** 设置按钮的类名 */\n #setupBtClass() {\n if (this.isDestroyed) return;\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (this.isOpen) {\n // 如果行数超过了,显示收缩按钮\n if (this.#getActualLines() > this.maxLines) {\n addElementClass(targetEl, 'is-exceeded-max-line');\n }\n } else {\n // 如果字体省略了,显示展开按钮\n if (this.#isEllipsisActive()) {\n addElementClass(targetEl, 'is-ellipsis');\n }\n }\n }\n /** 设置占位元素的样式 */\n #setupPlaceholderStyle() {\n const lineHeight = this.#lineHeight;\n const placeholderEl = this.placeholderEl;\n const targetEl = this.targetEl;\n placeholderEl.style.height = `${targetEl.clientHeight - lineHeight}px`;\n }\n /** 获取一行文本的高度 */\n #getLineHeight() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n return parseFloat(getComputedStyle(targetEl).lineHeight) || 24;\n }\n /** 判断是否省略了 */\n #isEllipsisActive() {\n const maxLines = this.maxLines;\n const el = this.targetEl;\n if (maxLines === 1) {\n return el.scrollWidth > el.clientWidth;\n }\n return el.scrollHeight > el.clientHeight;\n }\n /** 获取文本视觉上的行数 */\n #getActualLines() {\n const targetEl = this.targetEl;\n const collapseEl = this.collapseEl;\n const lh = this.#lineHeight;\n return Math.floor((targetEl.clientHeight - collapseEl.clientHeight) / lh);\n }\n}\n"
11
+ ],
12
+ "names": [
13
+ "removeElement",
14
+ "element",
15
+ "parentNode",
16
+ "removeChild",
17
+ "addElementClass",
18
+ "el",
19
+ "className",
20
+ "classList",
21
+ "add",
22
+ "removeElementClass",
23
+ "remove",
24
+ "isDestroyed",
25
+ "maxLines",
26
+ "targetEl",
27
+ "undefined",
28
+ "expandEl",
29
+ "collapseEl",
30
+ "placeholderEl",
31
+ "isOpen",
32
+ "lineHeight",
33
+ "constructor",
34
+ "options",
35
+ "document",
36
+ "createElement",
37
+ "innerText",
38
+ "expandElText",
39
+ "collapseElText",
40
+ "onclick",
41
+ "this",
42
+ "handleExpand",
43
+ "handleCollapse",
44
+ "prepend",
45
+ "appendChild",
46
+ "update",
47
+ "destroy",
48
+ "setupClass",
49
+ "getLineHeight",
50
+ "setupPlaceholderStyle",
51
+ "setupBtClass",
52
+ "style",
53
+ "setProperty",
54
+ "getActualLines",
55
+ "isEllipsisActive",
56
+ "height",
57
+ "clientHeight",
58
+ "parseFloat",
59
+ "getComputedStyle",
60
+ "scrollWidth",
61
+ "clientWidth",
62
+ "scrollHeight",
63
+ "lh",
64
+ "Math",
65
+ "floor"
66
+ ],
67
+ "mappings": "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"
68
+ }
@@ -0,0 +1,63 @@
1
+ .smart-text-ellipsis-more {
2
+ display: -webkit-box;
3
+ -webkit-line-clamp: var(--max-lines);
4
+ -webkit-box-orient: vertical;
5
+ display: -moz-box;
6
+ line-clamp: var(--max-lines);
7
+ box-orient: vertical;
8
+ overflow: hidden;
9
+ }
10
+ .smart-text-ellipsis-one {
11
+ white-space: nowrap;
12
+ overflow: hidden;
13
+ text-overflow: ellipsis;
14
+ }
15
+ .is-ellipsis > .smart-text-ellipsis-expand {
16
+ display: inline;
17
+ display: initial;
18
+ }
19
+ .is-ellipsis > .smart-text-ellipsis-placeholder {
20
+ display: inline;
21
+ display: initial;
22
+ }
23
+ .is-exceeded-max-line > .smart-text-ellipsis-collapse {
24
+ display: -webkit-box;
25
+ display: -webkit-flex;
26
+ display: -moz-box;
27
+ display: -ms-flexbox;
28
+ display: flex;
29
+ }
30
+ .smart-text-ellipsis-expand {
31
+ display: none;
32
+ float: right;
33
+ clear: both;
34
+ cursor: pointer;
35
+ color: #1178d9;
36
+ position: relative;
37
+ z-index: 2;
38
+ }
39
+ .smart-text-ellipsis-collapse {
40
+ display: none;
41
+ -webkit-box-orient: horizontal;
42
+ -webkit-box-direction: normal;
43
+ -webkit-flex-direction: row;
44
+ -moz-box-orient: horizontal;
45
+ -moz-box-direction: normal;
46
+ -ms-flex-direction: row;
47
+ flex-direction: row;
48
+ -webkit-box-pack: end;
49
+ -webkit-justify-content: flex-end;
50
+ -moz-box-pack: end;
51
+ -ms-flex-pack: end;
52
+ justify-content: flex-end;
53
+ cursor: pointer;
54
+ color: #1178d9;
55
+ position: relative;
56
+ z-index: 2;
57
+ }
58
+ .smart-text-ellipsis-placeholder {
59
+ display: none;
60
+ float: right;
61
+ width: 0;
62
+ pointer-events: none;
63
+ }
@@ -0,0 +1,116 @@
1
+ /*!
2
+ * smart-text-ellipsis v0.0.2
3
+ * Copyright 2025 wuzhanggui https://github.com/wurencaideli
4
+ * Licensed under MIT
5
+ */
6
+ function e(e) {
7
+ e && e.parentNode && e.parentNode.removeChild(e);
8
+ }
9
+ function t(e, t) {
10
+ e.classList.add(t);
11
+ }
12
+ function s(e, t) {
13
+ e.classList.remove(t);
14
+ }
15
+ class i {
16
+ isDestroyed = !1;
17
+ maxLines = 0;
18
+ targetEl = void 0;
19
+ expandEl = void 0;
20
+ collapseEl = void 0;
21
+ placeholderEl = void 0;
22
+ isOpen = !1;
23
+ #e = 0;
24
+ constructor(e = {}) {
25
+ const s = e.targetEl,
26
+ i = e.isOpen,
27
+ l = e.maxLines,
28
+ n = document.createElement('span'),
29
+ p = document.createElement('div'),
30
+ h = document.createElement('div');
31
+ (n.innerText = e.expandElText || 'Expand'),
32
+ (p.innerText = e.collapseElText || 'Collapse'),
33
+ (n.onclick = () => {
34
+ this.#t();
35
+ }),
36
+ (p.onclick = () => {
37
+ this.#s();
38
+ }),
39
+ t(p, 'smart-text-ellipsis-collapse'),
40
+ t(n, 'smart-text-ellipsis-expand'),
41
+ t(h, 'smart-text-ellipsis-placeholder'),
42
+ s.prepend(n),
43
+ s.prepend(h),
44
+ s.appendChild(p),
45
+ (this.targetEl = s),
46
+ (this.isOpen = i),
47
+ (this.maxLines = l),
48
+ (this.expandEl = n),
49
+ (this.collapseEl = p),
50
+ (this.placeholderEl = h),
51
+ this.update();
52
+ }
53
+ destroy() {
54
+ (this.isOpen = !0),
55
+ e(this.expandEl),
56
+ e(this.collapseEl),
57
+ this.#i(),
58
+ (this.targetEl = void 0),
59
+ (this.expandEl = void 0),
60
+ (this.collapseEl = void 0),
61
+ (this.isDestroyed = !0);
62
+ }
63
+ update() {
64
+ this.isDestroyed || ((this.#e = this.#l()), this.#i(), this.#n(), this.#p());
65
+ }
66
+ #t() {
67
+ this.isDestroyed || ((this.isOpen = !0), this.update());
68
+ }
69
+ #s() {
70
+ this.isDestroyed || ((this.isOpen = !1), this.update());
71
+ }
72
+ #i() {
73
+ const e = this.targetEl;
74
+ e &&
75
+ (this.isDestroyed
76
+ ? e.style.setProperty('--max-lines', void 0)
77
+ : e.style.setProperty('--max-lines', `${this.maxLines}`),
78
+ 1 == this.maxLines
79
+ ? (t(e, 'smart-text-ellipsis-one'), s(e, 'smart-text-ellipsis-more'))
80
+ : (t(e, 'smart-text-ellipsis-more'), s(e, 'smart-text-ellipsis-one')),
81
+ this.isOpen && (s(e, 'smart-text-ellipsis-more'), s(e, 'smart-text-ellipsis-one')),
82
+ s(e, 'is-ellipsis'),
83
+ s(e, 'is-exceeded-max-line'));
84
+ }
85
+ #p() {
86
+ if (this.isDestroyed) return;
87
+ const e = this.targetEl;
88
+ e &&
89
+ (this.isOpen
90
+ ? this.#h() > this.maxLines && t(e, 'is-exceeded-max-line')
91
+ : this.#a() && t(e, 'is-ellipsis'));
92
+ }
93
+ #n() {
94
+ const e = this.#e,
95
+ t = this.placeholderEl,
96
+ s = this.targetEl;
97
+ t.style.height = s.clientHeight - e + 'px';
98
+ }
99
+ #l() {
100
+ const e = this.targetEl;
101
+ if (e) return parseFloat(getComputedStyle(e).lineHeight) || 24;
102
+ }
103
+ #a() {
104
+ const e = this.maxLines,
105
+ t = this.targetEl;
106
+ return 1 === e ? t.scrollWidth > t.clientWidth : t.scrollHeight > t.clientHeight;
107
+ }
108
+ #h() {
109
+ const e = this.targetEl,
110
+ t = this.collapseEl,
111
+ s = this.#e;
112
+ return Math.floor((e.clientHeight - t.clientHeight) / s);
113
+ }
114
+ }
115
+ export { i as SmartTextEllipsis };
116
+ //# sourceMappingURL=smart-text-ellipsis.esm.js.map
@@ -0,0 +1,69 @@
1
+ {
2
+ "version": 3,
3
+ "file": "smart-text-ellipsis.esm.js",
4
+ "sources": [
5
+ "../src/common.js",
6
+ "../src/index.js"
7
+ ],
8
+ "sourcesContent": [
9
+ "export function removeElement(element) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\nexport function addElementClass(el, className) {\n el.classList.add(className);\n}\nexport function removeElementClass(el, className) {\n el.classList.remove(className);\n}\n",
10
+ "import { addElementClass, removeElement, removeElementClass } from './common';\nexport class SmartTextEllipsis {\n isDestroyed = false;\n maxLines = 0;\n targetEl = undefined;\n expandEl = undefined;\n collapseEl = undefined;\n placeholderEl = undefined;\n isOpen = false;\n #lineHeight = 0;\n constructor(options = {}) {\n const targetEl = options.targetEl;\n const isOpen = options.isOpen;\n const maxLines = options.maxLines;\n const expandEl = document.createElement('span');\n const collapseEl = document.createElement('div');\n const placeholderEl = document.createElement('div');\n expandEl.innerText = options.expandElText || 'Expand';\n collapseEl.innerText = options.collapseElText || 'Collapse';\n expandEl.onclick = () => {\n this.#handleExpand();\n };\n collapseEl.onclick = () => {\n this.#handleCollapse();\n };\n addElementClass(collapseEl, 'smart-text-ellipsis-collapse');\n addElementClass(expandEl, 'smart-text-ellipsis-expand');\n addElementClass(placeholderEl, 'smart-text-ellipsis-placeholder');\n targetEl.prepend(expandEl);\n targetEl.prepend(placeholderEl);\n targetEl.appendChild(collapseEl);\n this.targetEl = targetEl;\n this.isOpen = isOpen;\n this.maxLines = maxLines;\n this.expandEl = expandEl;\n this.collapseEl = collapseEl;\n this.placeholderEl = placeholderEl;\n this.update();\n }\n /** 销毁实例 */\n destroy() {\n this.isOpen = true;\n removeElement(this.expandEl);\n removeElement(this.collapseEl);\n this.#setupClass();\n this.targetEl = undefined;\n this.expandEl = undefined;\n this.collapseEl = undefined;\n this.isDestroyed = true;\n }\n /** 更新样式 */\n update() {\n if (this.isDestroyed) return;\n this.#lineHeight = this.#getLineHeight();\n this.#setupClass();\n this.#setupPlaceholderStyle();\n this.#setupBtClass();\n }\n #handleExpand() {\n if (this.isDestroyed) return;\n this.isOpen = true;\n this.update();\n }\n #handleCollapse() {\n if (this.isDestroyed) return;\n this.isOpen = false;\n this.update();\n }\n /** 设置容器的类名 */\n #setupClass() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (!this.isDestroyed) {\n targetEl.style.setProperty('--max-lines', `${this.maxLines}`);\n } else {\n targetEl.style.setProperty('--max-lines', undefined);\n }\n if (this.maxLines == 1) {\n addElementClass(targetEl, 'smart-text-ellipsis-one');\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n } else {\n addElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n if (this.isOpen) {\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n removeElementClass(targetEl, 'is-ellipsis');\n removeElementClass(targetEl, 'is-exceeded-max-line');\n }\n /** 设置按钮的类名 */\n #setupBtClass() {\n if (this.isDestroyed) return;\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (this.isOpen) {\n // 如果行数超过了,显示收缩按钮\n if (this.#getActualLines() > this.maxLines) {\n addElementClass(targetEl, 'is-exceeded-max-line');\n }\n } else {\n // 如果字体省略了,显示展开按钮\n if (this.#isEllipsisActive()) {\n addElementClass(targetEl, 'is-ellipsis');\n }\n }\n }\n /** 设置占位元素的样式 */\n #setupPlaceholderStyle() {\n const lineHeight = this.#lineHeight;\n const placeholderEl = this.placeholderEl;\n const targetEl = this.targetEl;\n placeholderEl.style.height = `${targetEl.clientHeight - lineHeight}px`;\n }\n /** 获取一行文本的高度 */\n #getLineHeight() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n return parseFloat(getComputedStyle(targetEl).lineHeight) || 24;\n }\n /** 判断是否省略了 */\n #isEllipsisActive() {\n const maxLines = this.maxLines;\n const el = this.targetEl;\n if (maxLines === 1) {\n return el.scrollWidth > el.clientWidth;\n }\n return el.scrollHeight > el.clientHeight;\n }\n /** 获取文本视觉上的行数 */\n #getActualLines() {\n const targetEl = this.targetEl;\n const collapseEl = this.collapseEl;\n const lh = this.#lineHeight;\n return Math.floor((targetEl.clientHeight - collapseEl.clientHeight) / lh);\n }\n}\n"
11
+ ],
12
+ "names": [
13
+ "removeElement",
14
+ "element",
15
+ "parentNode",
16
+ "removeChild",
17
+ "addElementClass",
18
+ "el",
19
+ "className",
20
+ "classList",
21
+ "add",
22
+ "removeElementClass",
23
+ "remove",
24
+ "SmartTextEllipsis",
25
+ "isDestroyed",
26
+ "maxLines",
27
+ "targetEl",
28
+ "undefined",
29
+ "expandEl",
30
+ "collapseEl",
31
+ "placeholderEl",
32
+ "isOpen",
33
+ "lineHeight",
34
+ "constructor",
35
+ "options",
36
+ "document",
37
+ "createElement",
38
+ "innerText",
39
+ "expandElText",
40
+ "collapseElText",
41
+ "onclick",
42
+ "this",
43
+ "handleExpand",
44
+ "handleCollapse",
45
+ "prepend",
46
+ "appendChild",
47
+ "update",
48
+ "destroy",
49
+ "setupClass",
50
+ "getLineHeight",
51
+ "setupPlaceholderStyle",
52
+ "setupBtClass",
53
+ "style",
54
+ "setProperty",
55
+ "getActualLines",
56
+ "isEllipsisActive",
57
+ "height",
58
+ "clientHeight",
59
+ "parseFloat",
60
+ "getComputedStyle",
61
+ "scrollWidth",
62
+ "clientWidth",
63
+ "scrollHeight",
64
+ "lh",
65
+ "Math",
66
+ "floor"
67
+ ],
68
+ "mappings": "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"
69
+ }
@@ -0,0 +1,128 @@
1
+ /*!
2
+ * smart-text-ellipsis v0.0.2
3
+ * Copyright 2025 wuzhanggui https://github.com/wurencaideli
4
+ * Licensed under MIT
5
+ */
6
+ !(function (e, t) {
7
+ 'object' == typeof exports && 'undefined' != typeof module
8
+ ? t(exports)
9
+ : 'function' == typeof define && define.amd
10
+ ? define(['exports'], t)
11
+ : t(
12
+ ((e = 'undefined' != typeof globalThis ? globalThis : e || self)[
13
+ 'smart-text-ellipsis'
14
+ ] = {}),
15
+ );
16
+ })(this, function (e) {
17
+ 'use strict';
18
+ function t(e) {
19
+ e && e.parentNode && e.parentNode.removeChild(e);
20
+ }
21
+ function s(e, t) {
22
+ e.classList.add(t);
23
+ }
24
+ function i(e, t) {
25
+ e.classList.remove(t);
26
+ }
27
+ e.SmartTextEllipsis = class {
28
+ isDestroyed = !1;
29
+ maxLines = 0;
30
+ targetEl = void 0;
31
+ expandEl = void 0;
32
+ collapseEl = void 0;
33
+ placeholderEl = void 0;
34
+ isOpen = !1;
35
+ #e = 0;
36
+ constructor(e = {}) {
37
+ const t = e.targetEl,
38
+ i = e.isOpen,
39
+ l = e.maxLines,
40
+ n = document.createElement('span'),
41
+ p = document.createElement('div'),
42
+ h = document.createElement('div');
43
+ (n.innerText = e.expandElText || 'Expand'),
44
+ (p.innerText = e.collapseElText || 'Collapse'),
45
+ (n.onclick = () => {
46
+ this.#t();
47
+ }),
48
+ (p.onclick = () => {
49
+ this.#s();
50
+ }),
51
+ s(p, 'smart-text-ellipsis-collapse'),
52
+ s(n, 'smart-text-ellipsis-expand'),
53
+ s(h, 'smart-text-ellipsis-placeholder'),
54
+ t.prepend(n),
55
+ t.prepend(h),
56
+ t.appendChild(p),
57
+ (this.targetEl = t),
58
+ (this.isOpen = i),
59
+ (this.maxLines = l),
60
+ (this.expandEl = n),
61
+ (this.collapseEl = p),
62
+ (this.placeholderEl = h),
63
+ this.update();
64
+ }
65
+ destroy() {
66
+ (this.isOpen = !0),
67
+ t(this.expandEl),
68
+ t(this.collapseEl),
69
+ this.#i(),
70
+ (this.targetEl = void 0),
71
+ (this.expandEl = void 0),
72
+ (this.collapseEl = void 0),
73
+ (this.isDestroyed = !0);
74
+ }
75
+ update() {
76
+ this.isDestroyed || ((this.#e = this.#l()), this.#i(), this.#n(), this.#p());
77
+ }
78
+ #t() {
79
+ this.isDestroyed || ((this.isOpen = !0), this.update());
80
+ }
81
+ #s() {
82
+ this.isDestroyed || ((this.isOpen = !1), this.update());
83
+ }
84
+ #i() {
85
+ const e = this.targetEl;
86
+ e &&
87
+ (this.isDestroyed
88
+ ? e.style.setProperty('--max-lines', void 0)
89
+ : e.style.setProperty('--max-lines', `${this.maxLines}`),
90
+ 1 == this.maxLines
91
+ ? (s(e, 'smart-text-ellipsis-one'), i(e, 'smart-text-ellipsis-more'))
92
+ : (s(e, 'smart-text-ellipsis-more'), i(e, 'smart-text-ellipsis-one')),
93
+ this.isOpen && (i(e, 'smart-text-ellipsis-more'), i(e, 'smart-text-ellipsis-one')),
94
+ i(e, 'is-ellipsis'),
95
+ i(e, 'is-exceeded-max-line'));
96
+ }
97
+ #p() {
98
+ if (this.isDestroyed) return;
99
+ const e = this.targetEl;
100
+ e &&
101
+ (this.isOpen
102
+ ? this.#h() > this.maxLines && s(e, 'is-exceeded-max-line')
103
+ : this.#o() && s(e, 'is-ellipsis'));
104
+ }
105
+ #n() {
106
+ const e = this.#e,
107
+ t = this.placeholderEl,
108
+ s = this.targetEl;
109
+ t.style.height = s.clientHeight - e + 'px';
110
+ }
111
+ #l() {
112
+ const e = this.targetEl;
113
+ if (e) return parseFloat(getComputedStyle(e).lineHeight) || 24;
114
+ }
115
+ #o() {
116
+ const e = this.maxLines,
117
+ t = this.targetEl;
118
+ return 1 === e ? t.scrollWidth > t.clientWidth : t.scrollHeight > t.clientHeight;
119
+ }
120
+ #h() {
121
+ const e = this.targetEl,
122
+ t = this.collapseEl,
123
+ s = this.#e;
124
+ return Math.floor((e.clientHeight - t.clientHeight) / s);
125
+ }
126
+ };
127
+ });
128
+ //# sourceMappingURL=smart-text-ellipsis.umd.js.map
@@ -0,0 +1,68 @@
1
+ {
2
+ "version": 3,
3
+ "file": "smart-text-ellipsis.umd.js",
4
+ "sources": [
5
+ "../src/common.js",
6
+ "../src/index.js"
7
+ ],
8
+ "sourcesContent": [
9
+ "export function removeElement(element) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\nexport function addElementClass(el, className) {\n el.classList.add(className);\n}\nexport function removeElementClass(el, className) {\n el.classList.remove(className);\n}\n",
10
+ "import { addElementClass, removeElement, removeElementClass } from './common';\nexport class SmartTextEllipsis {\n isDestroyed = false;\n maxLines = 0;\n targetEl = undefined;\n expandEl = undefined;\n collapseEl = undefined;\n placeholderEl = undefined;\n isOpen = false;\n #lineHeight = 0;\n constructor(options = {}) {\n const targetEl = options.targetEl;\n const isOpen = options.isOpen;\n const maxLines = options.maxLines;\n const expandEl = document.createElement('span');\n const collapseEl = document.createElement('div');\n const placeholderEl = document.createElement('div');\n expandEl.innerText = options.expandElText || 'Expand';\n collapseEl.innerText = options.collapseElText || 'Collapse';\n expandEl.onclick = () => {\n this.#handleExpand();\n };\n collapseEl.onclick = () => {\n this.#handleCollapse();\n };\n addElementClass(collapseEl, 'smart-text-ellipsis-collapse');\n addElementClass(expandEl, 'smart-text-ellipsis-expand');\n addElementClass(placeholderEl, 'smart-text-ellipsis-placeholder');\n targetEl.prepend(expandEl);\n targetEl.prepend(placeholderEl);\n targetEl.appendChild(collapseEl);\n this.targetEl = targetEl;\n this.isOpen = isOpen;\n this.maxLines = maxLines;\n this.expandEl = expandEl;\n this.collapseEl = collapseEl;\n this.placeholderEl = placeholderEl;\n this.update();\n }\n /** 销毁实例 */\n destroy() {\n this.isOpen = true;\n removeElement(this.expandEl);\n removeElement(this.collapseEl);\n this.#setupClass();\n this.targetEl = undefined;\n this.expandEl = undefined;\n this.collapseEl = undefined;\n this.isDestroyed = true;\n }\n /** 更新样式 */\n update() {\n if (this.isDestroyed) return;\n this.#lineHeight = this.#getLineHeight();\n this.#setupClass();\n this.#setupPlaceholderStyle();\n this.#setupBtClass();\n }\n #handleExpand() {\n if (this.isDestroyed) return;\n this.isOpen = true;\n this.update();\n }\n #handleCollapse() {\n if (this.isDestroyed) return;\n this.isOpen = false;\n this.update();\n }\n /** 设置容器的类名 */\n #setupClass() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (!this.isDestroyed) {\n targetEl.style.setProperty('--max-lines', `${this.maxLines}`);\n } else {\n targetEl.style.setProperty('--max-lines', undefined);\n }\n if (this.maxLines == 1) {\n addElementClass(targetEl, 'smart-text-ellipsis-one');\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n } else {\n addElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n if (this.isOpen) {\n removeElementClass(targetEl, 'smart-text-ellipsis-more');\n removeElementClass(targetEl, 'smart-text-ellipsis-one');\n }\n removeElementClass(targetEl, 'is-ellipsis');\n removeElementClass(targetEl, 'is-exceeded-max-line');\n }\n /** 设置按钮的类名 */\n #setupBtClass() {\n if (this.isDestroyed) return;\n const targetEl = this.targetEl;\n if (!targetEl) return;\n if (this.isOpen) {\n // 如果行数超过了,显示收缩按钮\n if (this.#getActualLines() > this.maxLines) {\n addElementClass(targetEl, 'is-exceeded-max-line');\n }\n } else {\n // 如果字体省略了,显示展开按钮\n if (this.#isEllipsisActive()) {\n addElementClass(targetEl, 'is-ellipsis');\n }\n }\n }\n /** 设置占位元素的样式 */\n #setupPlaceholderStyle() {\n const lineHeight = this.#lineHeight;\n const placeholderEl = this.placeholderEl;\n const targetEl = this.targetEl;\n placeholderEl.style.height = `${targetEl.clientHeight - lineHeight}px`;\n }\n /** 获取一行文本的高度 */\n #getLineHeight() {\n const targetEl = this.targetEl;\n if (!targetEl) return;\n return parseFloat(getComputedStyle(targetEl).lineHeight) || 24;\n }\n /** 判断是否省略了 */\n #isEllipsisActive() {\n const maxLines = this.maxLines;\n const el = this.targetEl;\n if (maxLines === 1) {\n return el.scrollWidth > el.clientWidth;\n }\n return el.scrollHeight > el.clientHeight;\n }\n /** 获取文本视觉上的行数 */\n #getActualLines() {\n const targetEl = this.targetEl;\n const collapseEl = this.collapseEl;\n const lh = this.#lineHeight;\n return Math.floor((targetEl.clientHeight - collapseEl.clientHeight) / lh);\n }\n}\n"
11
+ ],
12
+ "names": [
13
+ "removeElement",
14
+ "element",
15
+ "parentNode",
16
+ "removeChild",
17
+ "addElementClass",
18
+ "el",
19
+ "className",
20
+ "classList",
21
+ "add",
22
+ "removeElementClass",
23
+ "remove",
24
+ "isDestroyed",
25
+ "maxLines",
26
+ "targetEl",
27
+ "undefined",
28
+ "expandEl",
29
+ "collapseEl",
30
+ "placeholderEl",
31
+ "isOpen",
32
+ "lineHeight",
33
+ "constructor",
34
+ "options",
35
+ "document",
36
+ "createElement",
37
+ "innerText",
38
+ "expandElText",
39
+ "collapseElText",
40
+ "onclick",
41
+ "this",
42
+ "handleExpand",
43
+ "handleCollapse",
44
+ "prepend",
45
+ "appendChild",
46
+ "update",
47
+ "destroy",
48
+ "setupClass",
49
+ "getLineHeight",
50
+ "setupPlaceholderStyle",
51
+ "setupBtClass",
52
+ "style",
53
+ "setProperty",
54
+ "getActualLines",
55
+ "isEllipsisActive",
56
+ "height",
57
+ "clientHeight",
58
+ "parseFloat",
59
+ "getComputedStyle",
60
+ "scrollWidth",
61
+ "clientWidth",
62
+ "scrollHeight",
63
+ "lh",
64
+ "Math",
65
+ "floor"
66
+ ],
67
+ "mappings": "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"
68
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "smart-text-ellipsis",
3
+ "version": "0.0.2",
4
+ "description": "A simple custom scrollbar plugin",
5
+ "author": "wuzhanggui",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "keywords": [
9
+ "ellipsis"
10
+ ],
11
+ "homepage": "https://wurencaideli.github.io/smart-text-ellipsis/demo.html",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/wurencaideli/smart-text-ellipsis"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/wurencaideli/smart-text-ellipsis/issues"
18
+ },
19
+ "jspm": {
20
+ "main": "dist/smart-text-ellipsis.cjs.js",
21
+ "registry": "jspm"
22
+ },
23
+ "main": "dist/smart-text-ellipsis.cjs.js",
24
+ "module": "dist/smart-text-ellipsis.esm.js",
25
+ "style": "dist/smart-text-ellipsis.css",
26
+ "files": [
27
+ "dist",
28
+ "src"
29
+ ],
30
+ "scripts": {
31
+ "dev": "rollup -c -w",
32
+ "build": "rollup -c",
33
+ "build-sass": "node ./build-sass.js"
34
+ },
35
+ "devDependencies": {
36
+ "@rollup/plugin-commonjs": "^28.0.6",
37
+ "@rollup/plugin-node-resolve": "^16.0.1",
38
+ "@rollup/plugin-terser": "^0.4.4",
39
+ "autoprefixer": "^10.4.21",
40
+ "clean-css": "^5.3.3",
41
+ "postcss": "^8.5.6",
42
+ "postcss-preset-env": "^10.2.3",
43
+ "rollup": "^3.29.5",
44
+ "sass": "^1.89.2"
45
+ }
46
+ }
package/src/common.js ADDED
@@ -0,0 +1,11 @@
1
+ export function removeElement(element) {
2
+ if (element && element.parentNode) {
3
+ element.parentNode.removeChild(element);
4
+ }
5
+ }
6
+ export function addElementClass(el, className) {
7
+ el.classList.add(className);
8
+ }
9
+ export function removeElementClass(el, className) {
10
+ el.classList.remove(className);
11
+ }
package/src/index.js ADDED
@@ -0,0 +1,138 @@
1
+ import { addElementClass, removeElement, removeElementClass } from './common';
2
+ export class SmartTextEllipsis {
3
+ isDestroyed = false;
4
+ maxLines = 0;
5
+ targetEl = undefined;
6
+ expandEl = undefined;
7
+ collapseEl = undefined;
8
+ placeholderEl = undefined;
9
+ isOpen = false;
10
+ #lineHeight = 0;
11
+ constructor(options = {}) {
12
+ const targetEl = options.targetEl;
13
+ const isOpen = options.isOpen;
14
+ const maxLines = options.maxLines;
15
+ const expandEl = document.createElement('span');
16
+ const collapseEl = document.createElement('div');
17
+ const placeholderEl = document.createElement('div');
18
+ expandEl.innerText = options.expandElText || 'Expand';
19
+ collapseEl.innerText = options.collapseElText || 'Collapse';
20
+ expandEl.onclick = () => {
21
+ this.#handleExpand();
22
+ };
23
+ collapseEl.onclick = () => {
24
+ this.#handleCollapse();
25
+ };
26
+ addElementClass(collapseEl, 'smart-text-ellipsis-collapse');
27
+ addElementClass(expandEl, 'smart-text-ellipsis-expand');
28
+ addElementClass(placeholderEl, 'smart-text-ellipsis-placeholder');
29
+ targetEl.prepend(expandEl);
30
+ targetEl.prepend(placeholderEl);
31
+ targetEl.appendChild(collapseEl);
32
+ this.targetEl = targetEl;
33
+ this.isOpen = isOpen;
34
+ this.maxLines = maxLines;
35
+ this.expandEl = expandEl;
36
+ this.collapseEl = collapseEl;
37
+ this.placeholderEl = placeholderEl;
38
+ this.update();
39
+ }
40
+ /** 销毁实例 */
41
+ destroy() {
42
+ this.isOpen = true;
43
+ removeElement(this.expandEl);
44
+ removeElement(this.collapseEl);
45
+ this.#setupClass();
46
+ this.targetEl = undefined;
47
+ this.expandEl = undefined;
48
+ this.collapseEl = undefined;
49
+ this.isDestroyed = true;
50
+ }
51
+ /** 更新样式 */
52
+ update() {
53
+ if (this.isDestroyed) return;
54
+ this.#lineHeight = this.#getLineHeight();
55
+ this.#setupClass();
56
+ this.#setupPlaceholderStyle();
57
+ this.#setupBtClass();
58
+ }
59
+ #handleExpand() {
60
+ if (this.isDestroyed) return;
61
+ this.isOpen = true;
62
+ this.update();
63
+ }
64
+ #handleCollapse() {
65
+ if (this.isDestroyed) return;
66
+ this.isOpen = false;
67
+ this.update();
68
+ }
69
+ /** 设置容器的类名 */
70
+ #setupClass() {
71
+ const targetEl = this.targetEl;
72
+ if (!targetEl) return;
73
+ if (!this.isDestroyed) {
74
+ targetEl.style.setProperty('--max-lines', `${this.maxLines}`);
75
+ } else {
76
+ targetEl.style.setProperty('--max-lines', undefined);
77
+ }
78
+ if (this.maxLines == 1) {
79
+ addElementClass(targetEl, 'smart-text-ellipsis-one');
80
+ removeElementClass(targetEl, 'smart-text-ellipsis-more');
81
+ } else {
82
+ addElementClass(targetEl, 'smart-text-ellipsis-more');
83
+ removeElementClass(targetEl, 'smart-text-ellipsis-one');
84
+ }
85
+ if (this.isOpen) {
86
+ removeElementClass(targetEl, 'smart-text-ellipsis-more');
87
+ removeElementClass(targetEl, 'smart-text-ellipsis-one');
88
+ }
89
+ removeElementClass(targetEl, 'is-ellipsis');
90
+ removeElementClass(targetEl, 'is-exceeded-max-line');
91
+ }
92
+ /** 设置按钮的类名 */
93
+ #setupBtClass() {
94
+ if (this.isDestroyed) return;
95
+ const targetEl = this.targetEl;
96
+ if (!targetEl) return;
97
+ if (this.isOpen) {
98
+ // 如果行数超过了,显示收缩按钮
99
+ if (this.#getActualLines() > this.maxLines) {
100
+ addElementClass(targetEl, 'is-exceeded-max-line');
101
+ }
102
+ } else {
103
+ // 如果字体省略了,显示展开按钮
104
+ if (this.#isEllipsisActive()) {
105
+ addElementClass(targetEl, 'is-ellipsis');
106
+ }
107
+ }
108
+ }
109
+ /** 设置占位元素的样式 */
110
+ #setupPlaceholderStyle() {
111
+ const lineHeight = this.#lineHeight;
112
+ const placeholderEl = this.placeholderEl;
113
+ const targetEl = this.targetEl;
114
+ placeholderEl.style.height = `${targetEl.clientHeight - lineHeight}px`;
115
+ }
116
+ /** 获取一行文本的高度 */
117
+ #getLineHeight() {
118
+ const targetEl = this.targetEl;
119
+ if (!targetEl) return;
120
+ return parseFloat(getComputedStyle(targetEl).lineHeight) || 24;
121
+ }
122
+ /** 判断是否省略了 */
123
+ #isEllipsisActive() {
124
+ const maxLines = this.maxLines;
125
+ const el = this.targetEl;
126
+ if (maxLines === 1) {
127
+ return el.scrollWidth > el.clientWidth;
128
+ }
129
+ return el.scrollHeight > el.clientHeight;
130
+ }
131
+ /** 获取文本视觉上的行数 */
132
+ #getActualLines() {
133
+ const targetEl = this.targetEl;
134
+ const collapseEl = this.collapseEl;
135
+ const lh = this.#lineHeight;
136
+ return Math.floor((targetEl.clientHeight - collapseEl.clientHeight) / lh);
137
+ }
138
+ }
package/src/index.scss ADDED
@@ -0,0 +1,51 @@
1
+ .smart-text-ellipsis-more {
2
+ display: -webkit-box;
3
+ -webkit-line-clamp: var(--max-lines);
4
+ -webkit-box-orient: vertical;
5
+ display: -moz-box; /* 旧 Firefox 私有(已废弃)可省略 */
6
+ line-clamp: var(--max-lines); /* 标准属性 */
7
+ box-orient: vertical;
8
+ overflow: hidden;
9
+ }
10
+ .smart-text-ellipsis-one {
11
+ white-space: nowrap;
12
+ overflow: hidden;
13
+ text-overflow: ellipsis;
14
+ }
15
+ .is-ellipsis {
16
+ > .smart-text-ellipsis-expand {
17
+ display: initial;
18
+ }
19
+ > .smart-text-ellipsis-placeholder {
20
+ display: initial;
21
+ }
22
+ }
23
+ .is-exceeded-max-line {
24
+ > .smart-text-ellipsis-collapse {
25
+ display: flex;
26
+ }
27
+ }
28
+ .smart-text-ellipsis-expand {
29
+ display: none;
30
+ float: right;
31
+ clear: both;
32
+ cursor: pointer;
33
+ color: #1178d9;
34
+ position: relative;
35
+ z-index: 2;
36
+ }
37
+ .smart-text-ellipsis-collapse {
38
+ display: none;
39
+ flex-direction: row;
40
+ justify-content: flex-end;
41
+ cursor: pointer;
42
+ color: #1178d9;
43
+ position: relative;
44
+ z-index: 2;
45
+ }
46
+ .smart-text-ellipsis-placeholder {
47
+ display: none;
48
+ float: right;
49
+ width: 0;
50
+ pointer-events: none;
51
+ }