@holyer-lib/ui 0.0.8 → 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.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
 
@@ -28,19 +340,90 @@
28
340
  return css;
29
341
  }
30
342
 
31
- __$styleInject(".hi-title {\n font-size: 24px;\n font-weight: bold;\n margin: 16px 0;\n border-left: 4px solid var(--td-brand-color);\n padding-left: 12px;\n}\n");
343
+ __$styleInject(".hi-title {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.hi-title--small {\n gap: 2px;\n}\n.hi-title--large {\n gap: 6px;\n}\n.hi-title__header {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.hi-title__prefix {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n}\n.hi-title__bar {\n width: 4px;\n background-color: var(--td-brand-color);\n flex-shrink: 0;\n}\n.hi-title__icon {\n flex-shrink: 0;\n line-height: 1;\n}\n.hi-title__text {\n margin: 0;\n font-weight: 600;\n color: var(--td-text-color-primary);\n}\n.hi-title__description {\n margin: 0;\n font-size: 12px;\n color: var(--td-text-color-secondary);\n}\n");
32
344
 
33
345
  //
346
+ const TITILE_SIZE_MAP = {
347
+ small: '14px',
348
+ medium: '16px',
349
+ large: '18px'
350
+ };
34
351
  var script = {
35
352
  name: 'HiTitle',
353
+ inheritAttrs: false,
36
354
  props: {
355
+ // 自定义图标类名
356
+ iconClass: {
357
+ type: String,
358
+ default: ''
359
+ },
360
+ // 主标题文本(优先级低于 default slot)
37
361
  content: {
38
362
  type: String,
39
- default: '标题'
363
+ default: ''
364
+ },
365
+ // 描述文本(优先级低于 description slot)
366
+ description: {
367
+ type: String,
368
+ default: ''
369
+ },
370
+ // 尺寸:控制整体大小(影响文字、图标、bar 高度)
371
+ size: {
372
+ type: String,
373
+ default: 'medium',
374
+ validator: val => ['small', 'medium', 'large'].includes(val)
375
+ },
376
+ // 主标题颜色(支持自定义)
377
+ color: {
378
+ type: String,
379
+ default: ''
380
+ },
381
+ // 自定义前缀图标组件
382
+ prefixIcon: {
383
+ type: [Object, Function],
384
+ default: null
385
+ },
386
+ // 自定义 bar 类名(用于覆盖样式)
387
+ barClass: {
388
+ type: String,
389
+ default: ''
390
+ },
391
+ // 自定义标题文字类名
392
+ textClass: {
393
+ type: String,
394
+ default: ''
395
+ },
396
+ // 自定义描述文字类名
397
+ descClass: {
398
+ type: String,
399
+ default: ''
40
400
  }
41
401
  },
42
- data() {
43
- return {};
402
+ computed: {
403
+ titleClass() {
404
+ return ['hi-title', `hi-title--${this.size}`, { 'hi-title--has-desc': this.hasDescription }];
405
+ },
406
+ // 根据 size 计算文字大小
407
+ textSize() {
408
+ return TITILE_SIZE_MAP[this.size] || TITILE_SIZE_MAP.medium;
409
+ },
410
+ // 图标大小 = 文字大小(保持视觉一致)
411
+ iconSize() {
412
+ return this.textSize;
413
+ },
414
+ // 装饰条高度 = 文字行高 ≈ 文字大小 * 1.2~1.5
415
+ barHeight() {
416
+ const base = parseFloat(TITILE_SIZE_MAP[this.size] || '16');
417
+ return `${base * 1.2}px`;
418
+ },
419
+ // 主标题颜色(props 优先,否则继承)
420
+ textColor() {
421
+ return this.color || 'inherit';
422
+ },
423
+ // 是否存在描述内容(用于控制布局)
424
+ hasDescription() {
425
+ return this.description || this.$slots.description;
426
+ }
44
427
  }
45
428
  };
46
429
 
@@ -129,13 +512,64 @@
129
512
  var _c = _vm._self._c || _h;
130
513
  return _c(
131
514
  "div",
132
- { staticClass: "hi-title" },
515
+ _vm._b({ class: _vm.titleClass }, "div", _vm.$attrs, false),
133
516
  [
134
- _vm._t("default", function () {
135
- return [_vm._v(_vm._s(_vm.content))]
136
- }),
137
- ],
138
- 2
517
+ _c("div", { staticClass: "hi-title__header" }, [
518
+ _c(
519
+ "div",
520
+ { staticClass: "hi-title__prefix" },
521
+ [
522
+ _vm._t("prefix", function () {
523
+ return [
524
+ _vm.prefixIcon
525
+ ? _c(_vm.prefixIcon, {
526
+ tag: "component",
527
+ class: ["hi-title__icon", _vm.iconClass],
528
+ style: { fontSize: _vm.iconSize },
529
+ })
530
+ : _c("div", {
531
+ class: ["hi-title__bar", _vm.barClass],
532
+ style: { height: _vm.barHeight },
533
+ }),
534
+ ]
535
+ }),
536
+ ],
537
+ 2
538
+ ),
539
+ _vm._v(" "),
540
+ _vm.content || _vm.$slots.default
541
+ ? _c(
542
+ "div",
543
+ {
544
+ class: ["hi-title__text", _vm.textClass],
545
+ style: {
546
+ color: _vm.textColor,
547
+ fontSize: _vm.textSize,
548
+ },
549
+ },
550
+ [
551
+ _vm._t("default", function () {
552
+ return [_vm._v(_vm._s(_vm.content))]
553
+ }),
554
+ ],
555
+ 2
556
+ )
557
+ : _vm._e(),
558
+ ]),
559
+ _vm._v(" "),
560
+ _vm.hasDescription
561
+ ? _c(
562
+ "p",
563
+ { class: ["hi-title__description", _vm.descClass] },
564
+ [
565
+ _vm._t("description", function () {
566
+ return [_vm._v(_vm._s(_vm.description))]
567
+ }),
568
+ ],
569
+ 2
570
+ )
571
+ : _vm._e(),
572
+ ]
139
573
  )
140
574
  };
141
575
  var __vue_staticRenderFns__ = [];
@@ -174,11 +608,15 @@
174
608
  __vue_component__.name = 'HiTitle';
175
609
 
176
610
  // 添加 install
177
- __vue_component__.install = (Vue) => {
611
+ __vue_component__.install = Vue => {
178
612
  Vue.component(__vue_component__.name, __vue_component__);
179
613
  };
180
614
 
181
- const components = [__vue_component__];
615
+ // eslint-disable-next-line prettier/prettier
616
+ const components = [
617
+ __vue_component__$1,
618
+ __vue_component__
619
+ ];
182
620
 
183
621
  const install = function (Vue) {
184
622
  components.forEach(component => {
@@ -186,7 +624,11 @@
186
624
  });
187
625
  };
188
626
 
189
- var index = { install, HiTitle: __vue_component__ };
627
+ var index = {
628
+ install,
629
+ HiExpandText: __vue_component__$1,
630
+ HiTitle: __vue_component__
631
+ };
190
632
 
191
633
  return index;
192
634
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holyer-lib/ui",
3
- "version": "0.0.8",
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.1"
15
- },
16
- "peerDependencies": {
17
- "vue": "2.6.14"
18
12
  }
19
13
  }