@holyer-lib/ui 0.0.9 → 0.0.10

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/ui.cjs.js CHANGED
@@ -14,6 +14,318 @@ function __$styleInject(css) {
14
14
  return css;
15
15
  }
16
16
 
17
+ function __$styleInject$1(css) {
18
+ if (!css) return;
19
+
20
+ if (typeof window == 'undefined') return;
21
+ var style = document.createElement('style');
22
+ style.setAttribute('media', 'screen');
23
+
24
+ style.innerHTML = css;
25
+ document.head.appendChild(style);
26
+ return css;
27
+ }
28
+
29
+ __$styleInject$1(".hi-expand-text {\n display: flex;\n width: 100%;\n line-height: 1.5;\n}\n.hi-expand-text--content {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-word;\n -webkit-line-clamp: var(--hi-expand-text-line-clamp);\n line-clamp: var(--hi-expand-text-line-clamp);\n}\n.hi-expand-text--content.hi-expand-text--content__show-toggle::before {\n content: '';\n float: right;\n height: 100%;\n margin-bottom: calc(-1em * 1.5);\n}\n.hi-expand-text--content__expanded {\n display: block;\n overflow: visible;\n -webkit-line-clamp: unset;\n line-clamp: unset;\n}\n.hi-expand-text--toggle {\n color: var(--td-brand-color);\n float: right;\n clear: both;\n cursor: pointer;\n}\n");
30
+
31
+ //
32
+
33
+ var script$1 = {
34
+ name: 'HiExpandText',
35
+ props: {
36
+ content: {
37
+ type: String,
38
+ default: ''
39
+ },
40
+
41
+ /**
42
+ * [0]: 展开时显示的文本,[1]: 收起时显示的文本
43
+ */
44
+ label: {
45
+ type: Array,
46
+ default: () => ['展开', '收起'],
47
+ validator: arr => {
48
+ return arr.length === 2 && arr.every(s => typeof s === 'string');
49
+ }
50
+ },
51
+
52
+ lineClamp: {
53
+ type: Number,
54
+ default: 2
55
+ }
56
+ },
57
+ data() {
58
+ return {
59
+ showToggle: false,
60
+ isExpanded: false,
61
+ resizeTimer: null,
62
+ resizeObserver: null
63
+ };
64
+ },
65
+ computed: {
66
+ expandText() {
67
+ return this.isExpanded ? this.label[1] : this.label[0];
68
+ },
69
+
70
+ textClass() {
71
+ return {
72
+ 'hi-expand-text--content': true,
73
+ 'hi-expand-text--content__show-toggle': this.showToggle,
74
+ 'hi-expand-text--content__expanded': this.isExpanded
75
+ };
76
+ }
77
+ },
78
+
79
+ watch: {
80
+ content() {
81
+ this.$nextTick(this.checkEllipsis);
82
+ }
83
+ },
84
+ mounted() {
85
+ this.checkEllipsis();
86
+ window.addEventListener('resize', this.handleResize);
87
+ if (window.ResizeObserver && this.$el) {
88
+ this.resizeObserver = new ResizeObserver(() => {
89
+ this.handleResize();
90
+ });
91
+ this.resizeObserver.observe(this.$el);
92
+ }
93
+ },
94
+ beforeDestroy() {
95
+ window.removeEventListener('resize', this.handleResize);
96
+ if (this.resizeObserver) this.resizeObserver.disconnect();
97
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
98
+ },
99
+
100
+ methods: {
101
+ handleResize() {
102
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
103
+ this.resizeTimer = setTimeout(() => {
104
+ this.checkEllipsis();
105
+ }, 100);
106
+ },
107
+
108
+ /**
109
+ * @Description 检查是否存在溢出情况,兼容展开和收起两种状态
110
+ * @Author holyer
111
+ * @Date 2026/02/08 17:01:51
112
+ */
113
+ checkEllipsis() {
114
+ const textEl = this.$refs.textRef;
115
+ if (!textEl || !textEl.offsetParent) {
116
+ this.showToggle = false;
117
+ return;
118
+ }
119
+
120
+ if (this.isExpanded) {
121
+ // 展开状态下:模拟收起状态,检测是否需要 toggle
122
+ this.showToggle = this.wouldOverflowIfCollapsed(textEl);
123
+ } else {
124
+ // 收起状态下:直接检测是否溢出
125
+ this.showToggle = textEl.scrollHeight - textEl.clientHeight > 2;
126
+ }
127
+ },
128
+
129
+ /**
130
+ * 模拟收起状态,检测内容是否会溢出
131
+ */
132
+ wouldOverflowIfCollapsed(el) {
133
+ // 1. 保存原始状态
134
+ const originalDisplay = el.style.display;
135
+ const originalWebkitLineClamp = el.style.webkitLineClamp;
136
+ const originalClassList = el.className;
137
+
138
+ try {
139
+ // 2. 临时应用“收起”样式,移除 --expanded 和 --show-toggle
140
+ el.className = 'hi-expand-text--content';
141
+ el.style.display = '-webkit-box';
142
+ el.style.webkitBoxOrient = 'vertical';
143
+ el.style.overflow = 'hidden';
144
+ el.style.webkitLineClamp = this.lineClamp;
145
+
146
+ // 3. 强制 reflow(触发 layout)
147
+ const { scrollHeight, clientHeight } = el;
148
+
149
+ // 4. 判断是否溢出
150
+ return scrollHeight - clientHeight > 2;
151
+ } finally {
152
+ // 5. 恢复原始状态(确保无副作用)
153
+ el.className = originalClassList;
154
+ el.style.display = originalDisplay;
155
+ el.style.webkitLineClamp = originalWebkitLineClamp;
156
+ }
157
+ },
158
+
159
+ handleToggle() {
160
+ this.isExpanded = !this.isExpanded;
161
+ this.$emit('toggle', this.isExpanded);
162
+ },
163
+
164
+ // 供外部手动更新
165
+ update() {
166
+ this.$nextTick(this.checkEllipsis);
167
+ }
168
+ }
169
+ };
170
+
171
+ function normalizeComponent$1(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
172
+ if (typeof shadowMode !== 'boolean') {
173
+ createInjectorSSR = createInjector;
174
+ createInjector = shadowMode;
175
+ shadowMode = false;
176
+ }
177
+ // Vue.extend constructor export interop.
178
+ const options = typeof script === 'function' ? script.options : script;
179
+ // render functions
180
+ if (template && template.render) {
181
+ options.render = template.render;
182
+ options.staticRenderFns = template.staticRenderFns;
183
+ options._compiled = true;
184
+ // functional template
185
+ if (isFunctionalTemplate) {
186
+ options.functional = true;
187
+ }
188
+ }
189
+ // scopedId
190
+ if (scopeId) {
191
+ options._scopeId = scopeId;
192
+ }
193
+ let hook;
194
+ if (moduleIdentifier) {
195
+ // server build
196
+ hook = function (context) {
197
+ // 2.3 injection
198
+ context =
199
+ context || // cached call
200
+ (this.$vnode && this.$vnode.ssrContext) || // stateful
201
+ (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
202
+ // 2.2 with runInNewContext: true
203
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
204
+ context = __VUE_SSR_CONTEXT__;
205
+ }
206
+ // inject component styles
207
+ if (style) {
208
+ style.call(this, createInjectorSSR(context));
209
+ }
210
+ // register component module identifier for async chunk inference
211
+ if (context && context._registeredComponents) {
212
+ context._registeredComponents.add(moduleIdentifier);
213
+ }
214
+ };
215
+ // used by ssr in case component is cached and beforeCreate
216
+ // never gets called
217
+ options._ssrRegister = hook;
218
+ }
219
+ else if (style) {
220
+ hook = shadowMode
221
+ ? function (context) {
222
+ style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
223
+ }
224
+ : function (context) {
225
+ style.call(this, createInjector(context));
226
+ };
227
+ }
228
+ if (hook) {
229
+ if (options.functional) {
230
+ // register for functional component in vue file
231
+ const originalRender = options.render;
232
+ options.render = function renderWithStyleInjection(h, context) {
233
+ hook.call(context);
234
+ return originalRender(h, context);
235
+ };
236
+ }
237
+ else {
238
+ // inject component registration as beforeCreate hook
239
+ const existing = options.beforeCreate;
240
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
241
+ }
242
+ }
243
+ return script;
244
+ }
245
+
246
+ /* script */
247
+ const __vue_script__$1 = script$1;
248
+
249
+ /* template */
250
+ var __vue_render__$1 = function () {
251
+ var _vm = this;
252
+ var _h = _vm.$createElement;
253
+ var _c = _vm._self._c || _h;
254
+ return _c(
255
+ "div",
256
+ {
257
+ staticClass: "hi-expand-text",
258
+ style: { "--hi-expand-text-line-clamp": _vm.lineClamp },
259
+ },
260
+ [
261
+ _c(
262
+ "div",
263
+ { ref: "textRef", class: _vm.textClass },
264
+ [
265
+ _vm.showToggle
266
+ ? _c(
267
+ "div",
268
+ {
269
+ staticClass: "hi-expand-text--toggle",
270
+ on: { click: _vm.handleToggle },
271
+ },
272
+ [
273
+ _vm._t("toggleText", function () {
274
+ return [_vm._v(_vm._s(_vm.expandText))]
275
+ }),
276
+ ],
277
+ 2
278
+ )
279
+ : _vm._e(),
280
+ _vm._v(" "),
281
+ _vm._t("default", function () {
282
+ return [_vm._v(_vm._s(_vm.content))]
283
+ }),
284
+ ],
285
+ 2
286
+ ),
287
+ ]
288
+ )
289
+ };
290
+ var __vue_staticRenderFns__$1 = [];
291
+ __vue_render__$1._withStripped = true;
292
+
293
+ /* style */
294
+ const __vue_inject_styles__$1 = undefined;
295
+ /* scoped */
296
+ const __vue_scope_id__$1 = undefined;
297
+ /* module identifier */
298
+ const __vue_module_identifier__$1 = undefined;
299
+ /* functional template */
300
+ const __vue_is_functional_template__$1 = false;
301
+ /* style inject */
302
+
303
+ /* style inject SSR */
304
+
305
+ /* style inject shadow dom */
306
+
307
+
308
+
309
+ const __vue_component__$1 = /*#__PURE__*/normalizeComponent$1(
310
+ { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
311
+ __vue_inject_styles__$1,
312
+ __vue_script__$1,
313
+ __vue_scope_id__$1,
314
+ __vue_is_functional_template__$1,
315
+ __vue_module_identifier__$1,
316
+ false,
317
+ undefined,
318
+ undefined,
319
+ undefined
320
+ );
321
+
322
+ __vue_component__$1.name = 'HiExpandText';
323
+
324
+ // 添加 install
325
+ __vue_component__$1.install = Vue => {
326
+ Vue.component(__vue_component__$1.name, __vue_component__$1);
327
+ };
328
+
17
329
  function __$styleInject(css) {
18
330
  if (!css) return;
19
331
 
@@ -298,7 +610,11 @@ __vue_component__.install = Vue => {
298
610
  Vue.component(__vue_component__.name, __vue_component__);
299
611
  };
300
612
 
301
- const components = [__vue_component__];
613
+ // eslint-disable-next-line prettier/prettier
614
+ const components = [
615
+ __vue_component__$1,
616
+ __vue_component__
617
+ ];
302
618
 
303
619
  const install = function (Vue) {
304
620
  components.forEach(component => {
@@ -306,6 +622,10 @@ const install = function (Vue) {
306
622
  });
307
623
  };
308
624
 
309
- var index = { install, HiTitle: __vue_component__ };
625
+ var index = {
626
+ install,
627
+ HiExpandText: __vue_component__$1,
628
+ HiTitle: __vue_component__
629
+ };
310
630
 
311
631
  module.exports = index;
package/dist/ui.esm.js CHANGED
@@ -10,6 +10,318 @@ function __$styleInject(css) {
10
10
  return css;
11
11
  }
12
12
 
13
+ function __$styleInject$1(css) {
14
+ if (!css) return;
15
+
16
+ if (typeof window == 'undefined') return;
17
+ var style = document.createElement('style');
18
+ style.setAttribute('media', 'screen');
19
+
20
+ style.innerHTML = css;
21
+ document.head.appendChild(style);
22
+ return css;
23
+ }
24
+
25
+ __$styleInject$1(".hi-expand-text {\n display: flex;\n width: 100%;\n line-height: 1.5;\n}\n.hi-expand-text--content {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-word;\n -webkit-line-clamp: var(--hi-expand-text-line-clamp);\n line-clamp: var(--hi-expand-text-line-clamp);\n}\n.hi-expand-text--content.hi-expand-text--content__show-toggle::before {\n content: '';\n float: right;\n height: 100%;\n margin-bottom: calc(-1em * 1.5);\n}\n.hi-expand-text--content__expanded {\n display: block;\n overflow: visible;\n -webkit-line-clamp: unset;\n line-clamp: unset;\n}\n.hi-expand-text--toggle {\n color: var(--td-brand-color);\n float: right;\n clear: both;\n cursor: pointer;\n}\n");
26
+
27
+ //
28
+
29
+ var script$1 = {
30
+ name: 'HiExpandText',
31
+ props: {
32
+ content: {
33
+ type: String,
34
+ default: ''
35
+ },
36
+
37
+ /**
38
+ * [0]: 展开时显示的文本,[1]: 收起时显示的文本
39
+ */
40
+ label: {
41
+ type: Array,
42
+ default: () => ['展开', '收起'],
43
+ validator: arr => {
44
+ return arr.length === 2 && arr.every(s => typeof s === 'string');
45
+ }
46
+ },
47
+
48
+ lineClamp: {
49
+ type: Number,
50
+ default: 2
51
+ }
52
+ },
53
+ data() {
54
+ return {
55
+ showToggle: false,
56
+ isExpanded: false,
57
+ resizeTimer: null,
58
+ resizeObserver: null
59
+ };
60
+ },
61
+ computed: {
62
+ expandText() {
63
+ return this.isExpanded ? this.label[1] : this.label[0];
64
+ },
65
+
66
+ textClass() {
67
+ return {
68
+ 'hi-expand-text--content': true,
69
+ 'hi-expand-text--content__show-toggle': this.showToggle,
70
+ 'hi-expand-text--content__expanded': this.isExpanded
71
+ };
72
+ }
73
+ },
74
+
75
+ watch: {
76
+ content() {
77
+ this.$nextTick(this.checkEllipsis);
78
+ }
79
+ },
80
+ mounted() {
81
+ this.checkEllipsis();
82
+ window.addEventListener('resize', this.handleResize);
83
+ if (window.ResizeObserver && this.$el) {
84
+ this.resizeObserver = new ResizeObserver(() => {
85
+ this.handleResize();
86
+ });
87
+ this.resizeObserver.observe(this.$el);
88
+ }
89
+ },
90
+ beforeDestroy() {
91
+ window.removeEventListener('resize', this.handleResize);
92
+ if (this.resizeObserver) this.resizeObserver.disconnect();
93
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
94
+ },
95
+
96
+ methods: {
97
+ handleResize() {
98
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
99
+ this.resizeTimer = setTimeout(() => {
100
+ this.checkEllipsis();
101
+ }, 100);
102
+ },
103
+
104
+ /**
105
+ * @Description 检查是否存在溢出情况,兼容展开和收起两种状态
106
+ * @Author holyer
107
+ * @Date 2026/02/08 17:01:51
108
+ */
109
+ checkEllipsis() {
110
+ const textEl = this.$refs.textRef;
111
+ if (!textEl || !textEl.offsetParent) {
112
+ this.showToggle = false;
113
+ return;
114
+ }
115
+
116
+ if (this.isExpanded) {
117
+ // 展开状态下:模拟收起状态,检测是否需要 toggle
118
+ this.showToggle = this.wouldOverflowIfCollapsed(textEl);
119
+ } else {
120
+ // 收起状态下:直接检测是否溢出
121
+ this.showToggle = textEl.scrollHeight - textEl.clientHeight > 2;
122
+ }
123
+ },
124
+
125
+ /**
126
+ * 模拟收起状态,检测内容是否会溢出
127
+ */
128
+ wouldOverflowIfCollapsed(el) {
129
+ // 1. 保存原始状态
130
+ const originalDisplay = el.style.display;
131
+ const originalWebkitLineClamp = el.style.webkitLineClamp;
132
+ const originalClassList = el.className;
133
+
134
+ try {
135
+ // 2. 临时应用“收起”样式,移除 --expanded 和 --show-toggle
136
+ el.className = 'hi-expand-text--content';
137
+ el.style.display = '-webkit-box';
138
+ el.style.webkitBoxOrient = 'vertical';
139
+ el.style.overflow = 'hidden';
140
+ el.style.webkitLineClamp = this.lineClamp;
141
+
142
+ // 3. 强制 reflow(触发 layout)
143
+ const { scrollHeight, clientHeight } = el;
144
+
145
+ // 4. 判断是否溢出
146
+ return scrollHeight - clientHeight > 2;
147
+ } finally {
148
+ // 5. 恢复原始状态(确保无副作用)
149
+ el.className = originalClassList;
150
+ el.style.display = originalDisplay;
151
+ el.style.webkitLineClamp = originalWebkitLineClamp;
152
+ }
153
+ },
154
+
155
+ handleToggle() {
156
+ this.isExpanded = !this.isExpanded;
157
+ this.$emit('toggle', this.isExpanded);
158
+ },
159
+
160
+ // 供外部手动更新
161
+ update() {
162
+ this.$nextTick(this.checkEllipsis);
163
+ }
164
+ }
165
+ };
166
+
167
+ function normalizeComponent$1(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
168
+ if (typeof shadowMode !== 'boolean') {
169
+ createInjectorSSR = createInjector;
170
+ createInjector = shadowMode;
171
+ shadowMode = false;
172
+ }
173
+ // Vue.extend constructor export interop.
174
+ const options = typeof script === 'function' ? script.options : script;
175
+ // render functions
176
+ if (template && template.render) {
177
+ options.render = template.render;
178
+ options.staticRenderFns = template.staticRenderFns;
179
+ options._compiled = true;
180
+ // functional template
181
+ if (isFunctionalTemplate) {
182
+ options.functional = true;
183
+ }
184
+ }
185
+ // scopedId
186
+ if (scopeId) {
187
+ options._scopeId = scopeId;
188
+ }
189
+ let hook;
190
+ if (moduleIdentifier) {
191
+ // server build
192
+ hook = function (context) {
193
+ // 2.3 injection
194
+ context =
195
+ context || // cached call
196
+ (this.$vnode && this.$vnode.ssrContext) || // stateful
197
+ (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
198
+ // 2.2 with runInNewContext: true
199
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
200
+ context = __VUE_SSR_CONTEXT__;
201
+ }
202
+ // inject component styles
203
+ if (style) {
204
+ style.call(this, createInjectorSSR(context));
205
+ }
206
+ // register component module identifier for async chunk inference
207
+ if (context && context._registeredComponents) {
208
+ context._registeredComponents.add(moduleIdentifier);
209
+ }
210
+ };
211
+ // used by ssr in case component is cached and beforeCreate
212
+ // never gets called
213
+ options._ssrRegister = hook;
214
+ }
215
+ else if (style) {
216
+ hook = shadowMode
217
+ ? function (context) {
218
+ style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
219
+ }
220
+ : function (context) {
221
+ style.call(this, createInjector(context));
222
+ };
223
+ }
224
+ if (hook) {
225
+ if (options.functional) {
226
+ // register for functional component in vue file
227
+ const originalRender = options.render;
228
+ options.render = function renderWithStyleInjection(h, context) {
229
+ hook.call(context);
230
+ return originalRender(h, context);
231
+ };
232
+ }
233
+ else {
234
+ // inject component registration as beforeCreate hook
235
+ const existing = options.beforeCreate;
236
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
237
+ }
238
+ }
239
+ return script;
240
+ }
241
+
242
+ /* script */
243
+ const __vue_script__$1 = script$1;
244
+
245
+ /* template */
246
+ var __vue_render__$1 = function () {
247
+ var _vm = this;
248
+ var _h = _vm.$createElement;
249
+ var _c = _vm._self._c || _h;
250
+ return _c(
251
+ "div",
252
+ {
253
+ staticClass: "hi-expand-text",
254
+ style: { "--hi-expand-text-line-clamp": _vm.lineClamp },
255
+ },
256
+ [
257
+ _c(
258
+ "div",
259
+ { ref: "textRef", class: _vm.textClass },
260
+ [
261
+ _vm.showToggle
262
+ ? _c(
263
+ "div",
264
+ {
265
+ staticClass: "hi-expand-text--toggle",
266
+ on: { click: _vm.handleToggle },
267
+ },
268
+ [
269
+ _vm._t("toggleText", function () {
270
+ return [_vm._v(_vm._s(_vm.expandText))]
271
+ }),
272
+ ],
273
+ 2
274
+ )
275
+ : _vm._e(),
276
+ _vm._v(" "),
277
+ _vm._t("default", function () {
278
+ return [_vm._v(_vm._s(_vm.content))]
279
+ }),
280
+ ],
281
+ 2
282
+ ),
283
+ ]
284
+ )
285
+ };
286
+ var __vue_staticRenderFns__$1 = [];
287
+ __vue_render__$1._withStripped = true;
288
+
289
+ /* style */
290
+ const __vue_inject_styles__$1 = undefined;
291
+ /* scoped */
292
+ const __vue_scope_id__$1 = undefined;
293
+ /* module identifier */
294
+ const __vue_module_identifier__$1 = undefined;
295
+ /* functional template */
296
+ const __vue_is_functional_template__$1 = false;
297
+ /* style inject */
298
+
299
+ /* style inject SSR */
300
+
301
+ /* style inject shadow dom */
302
+
303
+
304
+
305
+ const __vue_component__$1 = /*#__PURE__*/normalizeComponent$1(
306
+ { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
307
+ __vue_inject_styles__$1,
308
+ __vue_script__$1,
309
+ __vue_scope_id__$1,
310
+ __vue_is_functional_template__$1,
311
+ __vue_module_identifier__$1,
312
+ false,
313
+ undefined,
314
+ undefined,
315
+ undefined
316
+ );
317
+
318
+ __vue_component__$1.name = 'HiExpandText';
319
+
320
+ // 添加 install
321
+ __vue_component__$1.install = Vue => {
322
+ Vue.component(__vue_component__$1.name, __vue_component__$1);
323
+ };
324
+
13
325
  function __$styleInject(css) {
14
326
  if (!css) return;
15
327
 
@@ -294,7 +606,11 @@ __vue_component__.install = Vue => {
294
606
  Vue.component(__vue_component__.name, __vue_component__);
295
607
  };
296
608
 
297
- const components = [__vue_component__];
609
+ // eslint-disable-next-line prettier/prettier
610
+ const components = [
611
+ __vue_component__$1,
612
+ __vue_component__
613
+ ];
298
614
 
299
615
  const install = function (Vue) {
300
616
  components.forEach(component => {
@@ -302,6 +618,10 @@ const install = function (Vue) {
302
618
  });
303
619
  };
304
620
 
305
- var index = { install, HiTitle: __vue_component__ };
621
+ var index = {
622
+ install,
623
+ HiExpandText: __vue_component__$1,
624
+ HiTitle: __vue_component__
625
+ };
306
626
 
307
627
  export { index as default };
package/dist/ui.umd.js CHANGED
@@ -16,6 +16,318 @@
16
16
  return css;
17
17
  }
18
18
 
19
+ function __$styleInject$1(css) {
20
+ if (!css) return;
21
+
22
+ if (typeof window == 'undefined') return;
23
+ var style = document.createElement('style');
24
+ style.setAttribute('media', 'screen');
25
+
26
+ style.innerHTML = css;
27
+ document.head.appendChild(style);
28
+ return css;
29
+ }
30
+
31
+ __$styleInject$1(".hi-expand-text {\n display: flex;\n width: 100%;\n line-height: 1.5;\n}\n.hi-expand-text--content {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-word;\n -webkit-line-clamp: var(--hi-expand-text-line-clamp);\n line-clamp: var(--hi-expand-text-line-clamp);\n}\n.hi-expand-text--content.hi-expand-text--content__show-toggle::before {\n content: '';\n float: right;\n height: 100%;\n margin-bottom: calc(-1em * 1.5);\n}\n.hi-expand-text--content__expanded {\n display: block;\n overflow: visible;\n -webkit-line-clamp: unset;\n line-clamp: unset;\n}\n.hi-expand-text--toggle {\n color: var(--td-brand-color);\n float: right;\n clear: both;\n cursor: pointer;\n}\n");
32
+
33
+ //
34
+
35
+ var script$1 = {
36
+ name: 'HiExpandText',
37
+ props: {
38
+ content: {
39
+ type: String,
40
+ default: ''
41
+ },
42
+
43
+ /**
44
+ * [0]: 展开时显示的文本,[1]: 收起时显示的文本
45
+ */
46
+ label: {
47
+ type: Array,
48
+ default: () => ['展开', '收起'],
49
+ validator: arr => {
50
+ return arr.length === 2 && arr.every(s => typeof s === 'string');
51
+ }
52
+ },
53
+
54
+ lineClamp: {
55
+ type: Number,
56
+ default: 2
57
+ }
58
+ },
59
+ data() {
60
+ return {
61
+ showToggle: false,
62
+ isExpanded: false,
63
+ resizeTimer: null,
64
+ resizeObserver: null
65
+ };
66
+ },
67
+ computed: {
68
+ expandText() {
69
+ return this.isExpanded ? this.label[1] : this.label[0];
70
+ },
71
+
72
+ textClass() {
73
+ return {
74
+ 'hi-expand-text--content': true,
75
+ 'hi-expand-text--content__show-toggle': this.showToggle,
76
+ 'hi-expand-text--content__expanded': this.isExpanded
77
+ };
78
+ }
79
+ },
80
+
81
+ watch: {
82
+ content() {
83
+ this.$nextTick(this.checkEllipsis);
84
+ }
85
+ },
86
+ mounted() {
87
+ this.checkEllipsis();
88
+ window.addEventListener('resize', this.handleResize);
89
+ if (window.ResizeObserver && this.$el) {
90
+ this.resizeObserver = new ResizeObserver(() => {
91
+ this.handleResize();
92
+ });
93
+ this.resizeObserver.observe(this.$el);
94
+ }
95
+ },
96
+ beforeDestroy() {
97
+ window.removeEventListener('resize', this.handleResize);
98
+ if (this.resizeObserver) this.resizeObserver.disconnect();
99
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
100
+ },
101
+
102
+ methods: {
103
+ handleResize() {
104
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
105
+ this.resizeTimer = setTimeout(() => {
106
+ this.checkEllipsis();
107
+ }, 100);
108
+ },
109
+
110
+ /**
111
+ * @Description 检查是否存在溢出情况,兼容展开和收起两种状态
112
+ * @Author holyer
113
+ * @Date 2026/02/08 17:01:51
114
+ */
115
+ checkEllipsis() {
116
+ const textEl = this.$refs.textRef;
117
+ if (!textEl || !textEl.offsetParent) {
118
+ this.showToggle = false;
119
+ return;
120
+ }
121
+
122
+ if (this.isExpanded) {
123
+ // 展开状态下:模拟收起状态,检测是否需要 toggle
124
+ this.showToggle = this.wouldOverflowIfCollapsed(textEl);
125
+ } else {
126
+ // 收起状态下:直接检测是否溢出
127
+ this.showToggle = textEl.scrollHeight - textEl.clientHeight > 2;
128
+ }
129
+ },
130
+
131
+ /**
132
+ * 模拟收起状态,检测内容是否会溢出
133
+ */
134
+ wouldOverflowIfCollapsed(el) {
135
+ // 1. 保存原始状态
136
+ const originalDisplay = el.style.display;
137
+ const originalWebkitLineClamp = el.style.webkitLineClamp;
138
+ const originalClassList = el.className;
139
+
140
+ try {
141
+ // 2. 临时应用“收起”样式,移除 --expanded 和 --show-toggle
142
+ el.className = 'hi-expand-text--content';
143
+ el.style.display = '-webkit-box';
144
+ el.style.webkitBoxOrient = 'vertical';
145
+ el.style.overflow = 'hidden';
146
+ el.style.webkitLineClamp = this.lineClamp;
147
+
148
+ // 3. 强制 reflow(触发 layout)
149
+ const { scrollHeight, clientHeight } = el;
150
+
151
+ // 4. 判断是否溢出
152
+ return scrollHeight - clientHeight > 2;
153
+ } finally {
154
+ // 5. 恢复原始状态(确保无副作用)
155
+ el.className = originalClassList;
156
+ el.style.display = originalDisplay;
157
+ el.style.webkitLineClamp = originalWebkitLineClamp;
158
+ }
159
+ },
160
+
161
+ handleToggle() {
162
+ this.isExpanded = !this.isExpanded;
163
+ this.$emit('toggle', this.isExpanded);
164
+ },
165
+
166
+ // 供外部手动更新
167
+ update() {
168
+ this.$nextTick(this.checkEllipsis);
169
+ }
170
+ }
171
+ };
172
+
173
+ function normalizeComponent$1(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
174
+ if (typeof shadowMode !== 'boolean') {
175
+ createInjectorSSR = createInjector;
176
+ createInjector = shadowMode;
177
+ shadowMode = false;
178
+ }
179
+ // Vue.extend constructor export interop.
180
+ const options = typeof script === 'function' ? script.options : script;
181
+ // render functions
182
+ if (template && template.render) {
183
+ options.render = template.render;
184
+ options.staticRenderFns = template.staticRenderFns;
185
+ options._compiled = true;
186
+ // functional template
187
+ if (isFunctionalTemplate) {
188
+ options.functional = true;
189
+ }
190
+ }
191
+ // scopedId
192
+ if (scopeId) {
193
+ options._scopeId = scopeId;
194
+ }
195
+ let hook;
196
+ if (moduleIdentifier) {
197
+ // server build
198
+ hook = function (context) {
199
+ // 2.3 injection
200
+ context =
201
+ context || // cached call
202
+ (this.$vnode && this.$vnode.ssrContext) || // stateful
203
+ (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
204
+ // 2.2 with runInNewContext: true
205
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
206
+ context = __VUE_SSR_CONTEXT__;
207
+ }
208
+ // inject component styles
209
+ if (style) {
210
+ style.call(this, createInjectorSSR(context));
211
+ }
212
+ // register component module identifier for async chunk inference
213
+ if (context && context._registeredComponents) {
214
+ context._registeredComponents.add(moduleIdentifier);
215
+ }
216
+ };
217
+ // used by ssr in case component is cached and beforeCreate
218
+ // never gets called
219
+ options._ssrRegister = hook;
220
+ }
221
+ else if (style) {
222
+ hook = shadowMode
223
+ ? function (context) {
224
+ style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
225
+ }
226
+ : function (context) {
227
+ style.call(this, createInjector(context));
228
+ };
229
+ }
230
+ if (hook) {
231
+ if (options.functional) {
232
+ // register for functional component in vue file
233
+ const originalRender = options.render;
234
+ options.render = function renderWithStyleInjection(h, context) {
235
+ hook.call(context);
236
+ return originalRender(h, context);
237
+ };
238
+ }
239
+ else {
240
+ // inject component registration as beforeCreate hook
241
+ const existing = options.beforeCreate;
242
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
243
+ }
244
+ }
245
+ return script;
246
+ }
247
+
248
+ /* script */
249
+ const __vue_script__$1 = script$1;
250
+
251
+ /* template */
252
+ var __vue_render__$1 = function () {
253
+ var _vm = this;
254
+ var _h = _vm.$createElement;
255
+ var _c = _vm._self._c || _h;
256
+ return _c(
257
+ "div",
258
+ {
259
+ staticClass: "hi-expand-text",
260
+ style: { "--hi-expand-text-line-clamp": _vm.lineClamp },
261
+ },
262
+ [
263
+ _c(
264
+ "div",
265
+ { ref: "textRef", class: _vm.textClass },
266
+ [
267
+ _vm.showToggle
268
+ ? _c(
269
+ "div",
270
+ {
271
+ staticClass: "hi-expand-text--toggle",
272
+ on: { click: _vm.handleToggle },
273
+ },
274
+ [
275
+ _vm._t("toggleText", function () {
276
+ return [_vm._v(_vm._s(_vm.expandText))]
277
+ }),
278
+ ],
279
+ 2
280
+ )
281
+ : _vm._e(),
282
+ _vm._v(" "),
283
+ _vm._t("default", function () {
284
+ return [_vm._v(_vm._s(_vm.content))]
285
+ }),
286
+ ],
287
+ 2
288
+ ),
289
+ ]
290
+ )
291
+ };
292
+ var __vue_staticRenderFns__$1 = [];
293
+ __vue_render__$1._withStripped = true;
294
+
295
+ /* style */
296
+ const __vue_inject_styles__$1 = undefined;
297
+ /* scoped */
298
+ const __vue_scope_id__$1 = undefined;
299
+ /* module identifier */
300
+ const __vue_module_identifier__$1 = undefined;
301
+ /* functional template */
302
+ const __vue_is_functional_template__$1 = false;
303
+ /* style inject */
304
+
305
+ /* style inject SSR */
306
+
307
+ /* style inject shadow dom */
308
+
309
+
310
+
311
+ const __vue_component__$1 = /*#__PURE__*/normalizeComponent$1(
312
+ { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
313
+ __vue_inject_styles__$1,
314
+ __vue_script__$1,
315
+ __vue_scope_id__$1,
316
+ __vue_is_functional_template__$1,
317
+ __vue_module_identifier__$1,
318
+ false,
319
+ undefined,
320
+ undefined,
321
+ undefined
322
+ );
323
+
324
+ __vue_component__$1.name = 'HiExpandText';
325
+
326
+ // 添加 install
327
+ __vue_component__$1.install = Vue => {
328
+ Vue.component(__vue_component__$1.name, __vue_component__$1);
329
+ };
330
+
19
331
  function __$styleInject(css) {
20
332
  if (!css) return;
21
333
 
@@ -300,7 +612,11 @@
300
612
  Vue.component(__vue_component__.name, __vue_component__);
301
613
  };
302
614
 
303
- const components = [__vue_component__];
615
+ // eslint-disable-next-line prettier/prettier
616
+ const components = [
617
+ __vue_component__$1,
618
+ __vue_component__
619
+ ];
304
620
 
305
621
  const install = function (Vue) {
306
622
  components.forEach(component => {
@@ -308,7 +624,11 @@
308
624
  });
309
625
  };
310
626
 
311
- var index = { install, HiTitle: __vue_component__ };
627
+ var index = {
628
+ install,
629
+ HiExpandText: __vue_component__$1,
630
+ HiTitle: __vue_component__
631
+ };
312
632
 
313
633
  return index;
314
634
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holyer-lib/ui",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "main": "dist/ui.cjs.js",
5
5
  "module": "dist/ui.esm.js",
6
6
  "unpkg": "dist/ui.umd.js",
@@ -9,11 +9,5 @@
9
9
  ],
10
10
  "publishConfig": {
11
11
  "access": "public"
12
- },
13
- "dependencies": {
14
- "@holyer-lib/title": "1.0.2"
15
- },
16
- "peerDependencies": {
17
- "vue": "2.6.14"
18
12
  }
19
13
  }