vue-clean-tabs 1.0.0 → 1.1.0

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.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { defineComponent as D, useCssVars as F, ref as S, computed as v, onMounted as L, onUnmounted as W, nextTick as E, openBlock as b, createElementBlock as f, normalizeClass as k, normalizeStyle as m, createElementVNode as x, Fragment as I, renderList as N, createCommentVNode as w, toDisplayString as V } from "vue";
1
+ import { defineComponent as A, useCssVars as D, ref as T, computed as p, onMounted as L, onUnmounted as W, nextTick as E, openBlock as b, createElementBlock as f, normalizeClass as m, normalizeStyle as x, createElementVNode as y, Fragment as I, renderList as N, createCommentVNode as w, toDisplayString as V } from "vue";
2
2
  const U = {
3
3
  activeTextColor: "rgb(20, 23, 26)",
4
4
  inactiveTextColor: "rgb(76, 82, 89)",
@@ -44,44 +44,44 @@ const U = {
44
44
  gap: "16px"
45
45
  }
46
46
  }, P = {
47
- line: (n, o) => ({
47
+ line: (a, o) => ({
48
48
  position: "absolute",
49
49
  bottom: "0",
50
50
  left: "12px",
51
51
  right: "12px",
52
52
  height: o,
53
- backgroundColor: n,
53
+ backgroundColor: a,
54
54
  borderRadius: "0"
55
55
  }),
56
- underline: (n, o) => ({
56
+ underline: (a, o) => ({
57
57
  position: "absolute",
58
58
  bottom: "0",
59
59
  left: "0",
60
60
  right: "0",
61
61
  height: o,
62
- backgroundColor: n,
62
+ backgroundColor: a,
63
63
  borderRadius: "0"
64
64
  }),
65
- dot: (n, o) => ({
65
+ dot: (a, o) => ({
66
66
  position: "absolute",
67
67
  bottom: "4px",
68
68
  left: "50%",
69
69
  transform: "translateX(-50%)",
70
70
  width: o,
71
71
  height: o,
72
- backgroundColor: n,
72
+ backgroundColor: a,
73
73
  borderRadius: "50%"
74
74
  }),
75
- pill: (n, o) => ({
75
+ pill: (a, o) => ({
76
76
  position: "absolute",
77
77
  bottom: "4px",
78
78
  left: "8px",
79
79
  right: "8px",
80
80
  height: o,
81
- backgroundColor: n,
81
+ backgroundColor: a,
82
82
  borderRadius: o
83
83
  })
84
- }, X = (n, o, l) => P[n](o, l), y = (n, o) => ({ ...n, ...o }), G = (n, o, l) => !n || !l ? o : { ...o, ...l }, J = ["disabled", "onClick", "onMouseenter", "onMouseleave"], K = ["innerHTML"], Q = { class: "tab-text" }, Y = /* @__PURE__ */ D({
84
+ }, X = (a, o, l) => P[a](o, l), h = (a, o) => ({ ...a, ...o }), G = (a, o, l) => !a || !l ? o : { ...o, ...l }, J = ["disabled", "onClick", "onMouseenter", "onMouseleave"], K = ["innerHTML"], Q = { class: "tab-text" }, Y = /* @__PURE__ */ A({
85
85
  __name: "ConfigurableSimpleTabs",
86
86
  props: {
87
87
  tabs: {},
@@ -98,83 +98,84 @@ const U = {
98
98
  scrollable: { type: Boolean, default: !1 }
99
99
  },
100
100
  emits: ["tab-change", "tab-click", "tab-hover", "tab-leave"],
101
- setup(n, { expose: o, emit: l }) {
101
+ setup(a, { expose: o, emit: l }) {
102
102
  var z;
103
- F((e) => ({
104
- "4e65487a": i.value.indicatorColor,
105
- "25a898f4": i.value.backgroundColor
103
+ D((e) => ({
104
+ "001f7dcf": i.value.inactiveTextColor,
105
+ "78d6cd4f": i.value.fontFamily,
106
+ "37ab6550": i.value.indicatorColor,
107
+ "10278ad8": i.value.activeTextColor,
108
+ "6a0edb99": i.value.backgroundColor
106
109
  }));
107
- const t = n, r = l, d = S(t.defaultActive || ((z = t.tabs[0]) == null ? void 0 : z.id) || ""), p = S(!1), h = S(null), i = v(
108
- () => y(U, t.theme)
109
- ), c = v(
110
- () => y(q, t.animation)
111
- ), g = v(
112
- () => y(O, t.responsive)
113
- ), R = v(
114
- () => y(j[t.size], t.style)
115
- ), u = v(
110
+ const t = a, d = l, s = T(t.defaultActive || ((z = t.tabs[0]) == null ? void 0 : z.id) || ""), v = T(!1), C = T(null), i = p(() => h(U, t.theme)), c = p(
111
+ () => h(q, t.animation)
112
+ ), g = p(
113
+ () => h(O, t.responsive)
114
+ ), R = p(
115
+ () => h(j[t.size], t.style)
116
+ ), u = p(
116
117
  () => G(
117
- p.value && g.value.enabled,
118
+ v.value && g.value.enabled,
118
119
  R.value,
119
120
  g.value.mobileStyle
120
121
  )
121
- ), T = () => {
122
- g.value.enabled && (p.value = window.innerWidth <= g.value.mobileBreakpoint);
123
- }, M = (e) => e.disabled ? i.value.inactiveTextColor : d.value === e.id ? i.value.activeTextColor : h.value === e.id ? i.value.hoverTextColor : i.value.inactiveTextColor, B = () => X(
122
+ ), k = () => {
123
+ g.value.enabled && (v.value = window.innerWidth <= g.value.mobileBreakpoint);
124
+ }, M = (e) => e.disabled ? i.value.inactiveTextColor : s.value === e.id ? i.value.activeTextColor : C.value === e.id ? i.value.hoverTextColor : i.value.inactiveTextColor, H = () => X(
124
125
  u.value.indicatorStyle,
125
126
  i.value.indicatorColor,
126
127
  u.value.indicatorHeight
127
- ), H = (e, s) => {
128
- e.disabled || (d.value = e.id, r("tab-change", e.id, e), r("tab-click", e.id, e, s), e.route && console.log("Navigate to:", e.route));
128
+ ), B = (e, r) => {
129
+ e.disabled || (s.value = e.id, d("tab-change", e.id, e), d("tab-click", e.id, e, r), e.route && console.log("Navigate to:", e.route));
129
130
  }, $ = (e) => {
130
- e.disabled || (h.value = e.id, r("tab-hover", e.id, e));
131
- }, A = (e) => {
132
- e.disabled || (h.value = null, r("tab-leave", e.id, e));
131
+ e.disabled || (C.value = e.id, d("tab-hover", e.id, e));
132
+ }, F = (e) => {
133
+ e.disabled || (C.value = null, d("tab-leave", e.id, e));
133
134
  }, _ = () => {
134
- T();
135
+ k();
135
136
  };
136
137
  return L(() => {
137
- T(), window.addEventListener("resize", _);
138
+ k(), window.addEventListener("resize", _);
138
139
  }), W(() => {
139
140
  window.removeEventListener("resize", _);
140
141
  }), o({
141
- activeTab: d,
142
+ activeTab: s,
142
143
  setActiveTab: (e) => {
143
- const s = t.tabs.find((a) => a.id === e);
144
- s && !s.disabled && (d.value = e, r("tab-change", e, s));
144
+ const r = t.tabs.find((n) => n.id === e);
145
+ r && !r.disabled && (s.value = e, d("tab-change", e, r));
145
146
  },
146
- getActiveTab: () => t.tabs.find((e) => e.id === d.value),
147
+ getActiveTab: () => t.tabs.find((e) => e.id === s.value),
147
148
  scrollToTab: (e) => {
148
149
  t.scrollable && E(() => {
149
- const s = document.querySelector(`[data-tab-id="${e}"]`);
150
- s && s.scrollIntoView({ behavior: "smooth", inline: "center" });
150
+ const r = document.querySelector(`[data-tab-id="${e}"]`);
151
+ r && r.scrollIntoView({ behavior: "smooth", inline: "center" });
151
152
  });
152
153
  }
153
- }), (e, s) => (b(), f("div", {
154
- class: k(["simple-tabs-container", [
154
+ }), (e, r) => (b(), f("div", {
155
+ class: m(["simple-tabs-container", [
155
156
  `size-${t.size}`,
156
157
  {
157
158
  "tabs-block": t.block,
158
159
  "tabs-centered": t.centered,
159
160
  "tabs-scrollable": t.scrollable,
160
- "is-mobile": p.value
161
+ "is-mobile": v.value
161
162
  },
162
163
  t.className
163
164
  ]]),
164
- style: m({
165
+ style: x({
165
166
  backgroundColor: i.value.backgroundColor,
166
167
  boxShadow: i.value.boxShadow,
167
168
  flexShrink: 0,
168
169
  ...t.customStyle
169
170
  })
170
171
  }, [
171
- x("nav", null, [
172
- x("ul", {
173
- class: k(["tabs-list", {
174
- "flex-wrap": t.scrollable && !p.value,
175
- "overflow-x-auto": t.scrollable && p.value
172
+ y("nav", null, [
173
+ y("ul", {
174
+ class: m(["tabs-list", {
175
+ "flex-wrap": t.scrollable && !v.value,
176
+ "overflow-x-auto": t.scrollable && v.value
176
177
  }]),
177
- style: m({
178
+ style: x({
178
179
  display: "flex",
179
180
  gap: u.value.gap,
180
181
  justifyContent: t.centered ? "center" : "flex-start",
@@ -183,39 +184,43 @@ const U = {
183
184
  listStyle: "none"
184
185
  })
185
186
  }, [
186
- (b(!0), f(I, null, N(t.tabs, (a) => (b(), f("li", {
187
- key: a.id,
188
- class: k(["tab-item", {
189
- "tab-active": d.value === a.id,
190
- "tab-disabled": a.disabled
187
+ (b(!0), f(I, null, N(t.tabs, (n) => (b(), f("li", {
188
+ key: n.id,
189
+ class: m(["tab-item", {
190
+ "tab-active": s.value === n.id,
191
+ "tab-disabled": n.disabled
191
192
  }])
192
193
  }, [
193
- x("button", {
194
- class: "tab-button",
195
- disabled: a.disabled,
196
- style: m({
194
+ y("button", {
195
+ class: m(["tab-button", {
196
+ "tab-button-active": s.value === n.id,
197
+ "tab-button-disabled": n.disabled
198
+ }]),
199
+ disabled: n.disabled,
200
+ style: x({
197
201
  position: "relative",
198
202
  display: "flex",
199
203
  alignItems: "center",
200
204
  background: "none",
201
205
  border: "none",
202
- cursor: a.disabled ? "not-allowed" : "pointer",
206
+ cursor: n.disabled ? "not-allowed" : "pointer",
203
207
  textDecoration: "none",
204
208
  transition: c.value.enabled ? `color ${c.value.transitionDuration} ${c.value.easing}` : "none",
205
209
  padding: u.value.padding,
206
210
  fontSize: u.value.fontSize,
207
- fontWeight: u.value.fontWeight,
211
+ fontWeight: s.value === n.id ? "500" : u.value.fontWeight,
208
212
  fontFamily: i.value.fontFamily,
209
- color: M(a),
210
- opacity: a.disabled ? 0.5 : 1,
213
+ color: M(n),
214
+ opacity: n.disabled ? 0.5 : 1,
211
215
  borderRadius: u.value.borderRadius || "0",
212
- whiteSpace: "nowrap"
216
+ whiteSpace: "nowrap",
217
+ lineHeight: 1.25
213
218
  }),
214
- onClick: (C) => H(a, C),
215
- onMouseenter: (C) => $(a),
216
- onMouseleave: (C) => A(a)
219
+ onClick: (S) => B(n, S),
220
+ onMouseenter: (S) => $(n),
221
+ onMouseleave: (S) => F(n)
217
222
  }, [
218
- a.icon ? (b(), f("span", {
223
+ n.icon ? (b(), f("span", {
219
224
  key: 0,
220
225
  class: "tab-icon",
221
226
  style: {
@@ -223,30 +228,30 @@ const U = {
223
228
  fontSize: "1em",
224
229
  lineHeight: 1
225
230
  },
226
- innerHTML: a.icon
231
+ innerHTML: n.icon
227
232
  }, null, 8, K)) : w("", !0),
228
- x("span", Q, V(a.name), 1),
229
- d.value === a.id ? (b(), f("span", {
233
+ y("span", Q, V(n.name), 1),
234
+ s.value === n.id ? (b(), f("span", {
230
235
  key: 1,
231
236
  class: "tab-indicator",
232
- style: m({
233
- ...B(),
237
+ style: x({
238
+ ...H(),
234
239
  transition: c.value.enabled ? `all ${c.value.indicatorTransition || c.value.transitionDuration} ${c.value.easing}` : "none"
235
240
  })
236
241
  }, null, 4)) : w("", !0)
237
- ], 44, J)
242
+ ], 46, J)
238
243
  ], 2))), 128))
239
244
  ], 6)
240
245
  ])
241
246
  ], 6));
242
247
  }
243
248
  });
244
- const Z = (n, o) => {
245
- const l = n.__vccOpts || n;
246
- for (const [t, r] of o)
247
- l[t] = r;
249
+ const Z = (a, o) => {
250
+ const l = a.__vccOpts || a;
251
+ for (const [t, d] of o)
252
+ l[t] = d;
248
253
  return l;
249
- }, te = /* @__PURE__ */ Z(Y, [["__scopeId", "data-v-166844ee"]]);
254
+ }, te = /* @__PURE__ */ Z(Y, [["__scopeId", "data-v-28fbd600"]]);
250
255
  export {
251
256
  te as ConfigurableSimpleTabs,
252
257
  te as default,
@@ -256,7 +261,7 @@ export {
256
261
  X as getIndicatorStyle,
257
262
  G as getResponsiveStyle,
258
263
  P as indicatorStyles,
259
- y as mergeConfig,
264
+ h as mergeConfig,
260
265
  j as sizeConfigs
261
266
  };
262
267
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n \r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n \r\n // 尺寸\r\n size?: TabSize;\r\n \r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n \r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n \r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n \r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n \r\n // 自定义类名\r\n className?: string;\r\n \r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n \r\n // 是否显示为块级元素\r\n block?: boolean;\r\n \r\n // 居中对齐\r\n centered?: boolean;\r\n \r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n \r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle, \r\n color: string, \r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n \r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n \r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from '../types';\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from '../types';\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: 'medium',\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || '');\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => \r\n mergeConfig(defaultTheme, props.theme)\r\n);\r\n\r\nconst computedAnimation = computed(() => \r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() => \r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() => \r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() => \r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value = window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n \r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n \r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n \r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n \r\n activeTab.value = tab.id;\r\n emit('tab-change', tab.id, tab);\r\n emit('tab-click', tab.id, tab, event);\r\n \r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log('Navigate to:', tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit('tab-hover', tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit('tab-leave', tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener('resize', handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find(t => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit('tab-change', tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find(t => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: 'smooth', inline: 'center' });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind('computedTheme.indicatorColor');\r\n outline-offset: 2px;\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(to right, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(to left, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n \r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n\r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n\r\n // 尺寸\r\n size?: TabSize;\r\n\r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n\r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n\r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n\r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n\r\n // 自定义类名\r\n className?: string;\r\n\r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n\r\n // 是否显示为块级元素\r\n block?: boolean;\r\n\r\n // 居中对齐\r\n centered?: boolean;\r\n\r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n\r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle,\r\n color: string,\r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :class=\"{\r\n 'tab-button-active': activeTab === tab.id,\r\n 'tab-button-disabled': tab.disabled,\r\n }\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: activeTab === tab.id ? '500' : computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n lineHeight: 1.25,\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n\r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n\r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from \"vue\";\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from \"../types\";\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from \"../types\";\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: \"medium\",\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || \"\");\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => mergeConfig(defaultTheme, props.theme));\r\n\r\nconst computedAnimation = computed(() =>\r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() =>\r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() =>\r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() =>\r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value =\r\n window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n\r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n\r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n\r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n\r\n activeTab.value = tab.id;\r\n emit(\"tab-change\", tab.id, tab);\r\n emit(\"tab-click\", tab.id, tab, event);\r\n\r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log(\"Navigate to:\", tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit(\"tab-hover\", tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit(\"tab-leave\", tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener(\"resize\", handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener(\"resize\", handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find((t) => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit(\"tab-change\", tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find((t) => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: \"smooth\", inline: \"center\" });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n text-decoration: none;\r\n background: transparent;\r\n border: 0px;\r\n font-size: 16px;\r\n font-weight: 400;\r\n line-height: 1.25;\r\n padding: 14px 12px;\r\n position: relative;\r\n color: v-bind(\"computedTheme.inactiveTextColor\");\r\n font-family: v-bind(\"computedTheme.fontFamily\");\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind(\"computedTheme.indicatorColor\");\r\n outline-offset: 2px;\r\n}\r\n\r\n.tab-button-active {\r\n color: v-bind(\"computedTheme.activeTextColor\");\r\n font-weight: 500;\r\n}\r\n\r\n.tab-button-active::before {\r\n position: absolute;\r\n background: v-bind(\"computedTheme.indicatorColor\");\r\n height: 2px;\r\n inset: auto 12px 0px;\r\n content: \"\";\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-button {\r\n padding: 14px 0;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-button-active::before {\r\n inset: auto 0px 0px;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(\r\n to right,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(\r\n to left,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n\r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(l,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(l=typeof globalThis<"u"?globalThis:l||self,e(l.VueSimpleTabs={},l.Vue))})(this,function(l,e){"use strict";const h={activeTextColor:"rgb(20, 23, 26)",inactiveTextColor:"rgb(76, 82, 89)",hoverTextColor:"rgb(55, 65, 81)",backgroundColor:"#ffffff",indicatorColor:"rgb(20, 23, 26)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", "SF Pro Display", "Inter", sans-serif'},x={small:{padding:"8px 10px",fontSize:"14px",fontWeight:"500",indicatorHeight:"2px",indicatorStyle:"line",gap:"16px"},medium:{padding:"14px 12px",fontSize:"16px",fontWeight:"600",indicatorHeight:"2px",indicatorStyle:"line",gap:"20px"},large:{padding:"16px 16px",fontSize:"18px",fontWeight:"700",indicatorHeight:"3px",indicatorStyle:"line",gap:"24px"}},S={transitionDuration:"0.2s",easing:"ease",enabled:!0,indicatorTransition:"0.3s ease"},C={mobileBreakpoint:768,enabled:!0,mobileStyle:{padding:"14px 0",gap:"16px"}},k={line:(i,n)=>({position:"absolute",bottom:"0",left:"12px",right:"12px",height:n,backgroundColor:i,borderRadius:"0"}),underline:(i,n)=>({position:"absolute",bottom:"0",left:"0",right:"0",height:n,backgroundColor:i,borderRadius:"0"}),dot:(i,n)=>({position:"absolute",bottom:"4px",left:"50%",transform:"translateX(-50%)",width:n,height:n,backgroundColor:i,borderRadius:"50%"}),pill:(i,n)=>({position:"absolute",bottom:"4px",left:"8px",right:"8px",height:n,backgroundColor:i,borderRadius:n})},T=(i,n,s)=>k[i](n,s),m=(i,n)=>({...i,...n}),_=(i,n,s)=>!i||!s?n:{...n,...s},E=["disabled","onClick","onMouseenter","onMouseleave"],M=["innerHTML"],V={class:"tab-text"},N=e.defineComponent({__name:"ConfigurableSimpleTabs",props:{tabs:{},defaultActive:{},size:{default:"medium"},theme:{},style:{},animation:{},responsive:{},className:{},customStyle:{},block:{type:Boolean,default:!1},centered:{type:Boolean,default:!1},scrollable:{type:Boolean,default:!1}},emits:["tab-change","tab-click","tab-hover","tab-leave"],setup(i,{expose:n,emit:s}){var R;e.useCssVars(t=>({"4e65487a":r.value.indicatorColor,"25a898f4":r.value.backgroundColor}));const o=i,c=s,u=e.ref(o.defaultActive||((R=o.tabs[0])==null?void 0:R.id)||""),b=e.ref(!1),v=e.ref(null),r=e.computed(()=>m(h,o.theme)),p=e.computed(()=>m(S,o.animation)),g=e.computed(()=>m(C,o.responsive)),H=e.computed(()=>m(x[o.size],o.style)),f=e.computed(()=>_(b.value&&g.value.enabled,H.value,g.value.mobileStyle)),B=()=>{g.value.enabled&&(b.value=window.innerWidth<=g.value.mobileBreakpoint)},$=t=>t.disabled?r.value.inactiveTextColor:u.value===t.id?r.value.activeTextColor:v.value===t.id?r.value.hoverTextColor:r.value.inactiveTextColor,A=()=>T(f.value.indicatorStyle,r.value.indicatorColor,f.value.indicatorHeight),D=(t,d)=>{t.disabled||(u.value=t.id,c("tab-change",t.id,t),c("tab-click",t.id,t,d),t.route&&console.log("Navigate to:",t.route))},F=t=>{t.disabled||(v.value=t.id,c("tab-hover",t.id,t))},I=t=>{t.disabled||(v.value=null,c("tab-leave",t.id,t))},w=()=>{B()};return e.onMounted(()=>{B(),window.addEventListener("resize",w)}),e.onUnmounted(()=>{window.removeEventListener("resize",w)}),n({activeTab:u,setActiveTab:t=>{const d=o.tabs.find(a=>a.id===t);d&&!d.disabled&&(u.value=t,c("tab-change",t,d))},getActiveTab:()=>o.tabs.find(t=>t.id===u.value),scrollToTab:t=>{o.scrollable&&e.nextTick(()=>{const d=document.querySelector(`[data-tab-id="${t}"]`);d&&d.scrollIntoView({behavior:"smooth",inline:"center"})})}}),(t,d)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["simple-tabs-container",[`size-${o.size}`,{"tabs-block":o.block,"tabs-centered":o.centered,"tabs-scrollable":o.scrollable,"is-mobile":b.value},o.className]]),style:e.normalizeStyle({backgroundColor:r.value.backgroundColor,boxShadow:r.value.boxShadow,flexShrink:0,...o.customStyle})},[e.createElementVNode("nav",null,[e.createElementVNode("ul",{class:e.normalizeClass(["tabs-list",{"flex-wrap":o.scrollable&&!b.value,"overflow-x-auto":o.scrollable&&b.value}]),style:e.normalizeStyle({display:"flex",gap:f.value.gap,justifyContent:o.centered?"center":"flex-start",margin:0,padding:0,listStyle:"none"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.tabs,a=>(e.openBlock(),e.createElementBlock("li",{key:a.id,class:e.normalizeClass(["tab-item",{"tab-active":u.value===a.id,"tab-disabled":a.disabled}])},[e.createElementVNode("button",{class:"tab-button",disabled:a.disabled,style:e.normalizeStyle({position:"relative",display:"flex",alignItems:"center",background:"none",border:"none",cursor:a.disabled?"not-allowed":"pointer",textDecoration:"none",transition:p.value.enabled?`color ${p.value.transitionDuration} ${p.value.easing}`:"none",padding:f.value.padding,fontSize:f.value.fontSize,fontWeight:f.value.fontWeight,fontFamily:r.value.fontFamily,color:$(a),opacity:a.disabled?.5:1,borderRadius:f.value.borderRadius||"0",whiteSpace:"nowrap"}),onClick:y=>D(a,y),onMouseenter:y=>F(a),onMouseleave:y=>I(a)},[a.icon?(e.openBlock(),e.createElementBlock("span",{key:0,class:"tab-icon",style:{marginRight:"8px",fontSize:"1em",lineHeight:1},innerHTML:a.icon},null,8,M)):e.createCommentVNode("",!0),e.createElementVNode("span",V,e.toDisplayString(a.name),1),u.value===a.id?(e.openBlock(),e.createElementBlock("span",{key:1,class:"tab-indicator",style:e.normalizeStyle({...A(),transition:p.value.enabled?`all ${p.value.indicatorTransition||p.value.transitionDuration} ${p.value.easing}`:"none"})},null,4)):e.createCommentVNode("",!0)],44,E)],2))),128))],6)])],6))}}),L="",z=((i,n)=>{const s=i.__vccOpts||i;for(const[o,c]of n)s[o]=c;return s})(N,[["__scopeId","data-v-166844ee"]]);l.ConfigurableSimpleTabs=z,l.default=z,l.defaultAnimation=S,l.defaultResponsive=C,l.defaultTheme=h,l.getIndicatorStyle=T,l.getResponsiveStyle=_,l.indicatorStyles=k,l.mergeConfig=m,l.sizeConfigs=x,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(a,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(a=typeof globalThis<"u"?globalThis:a||self,e(a.VueSimpleTabs={},a.Vue))})(this,function(a,e){"use strict";const h={activeTextColor:"rgb(20, 23, 26)",inactiveTextColor:"rgb(76, 82, 89)",hoverTextColor:"rgb(55, 65, 81)",backgroundColor:"#ffffff",indicatorColor:"rgb(20, 23, 26)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", "SF Pro Display", "Inter", sans-serif'},x={small:{padding:"8px 10px",fontSize:"14px",fontWeight:"500",indicatorHeight:"2px",indicatorStyle:"line",gap:"16px"},medium:{padding:"14px 12px",fontSize:"16px",fontWeight:"600",indicatorHeight:"2px",indicatorStyle:"line",gap:"20px"},large:{padding:"16px 16px",fontSize:"18px",fontWeight:"700",indicatorHeight:"3px",indicatorStyle:"line",gap:"24px"}},C={transitionDuration:"0.2s",easing:"ease",enabled:!0,indicatorTransition:"0.3s ease"},S={mobileBreakpoint:768,enabled:!0,mobileStyle:{padding:"14px 0",gap:"16px"}},k={line:(l,n)=>({position:"absolute",bottom:"0",left:"12px",right:"12px",height:n,backgroundColor:l,borderRadius:"0"}),underline:(l,n)=>({position:"absolute",bottom:"0",left:"0",right:"0",height:n,backgroundColor:l,borderRadius:"0"}),dot:(l,n)=>({position:"absolute",bottom:"4px",left:"50%",transform:"translateX(-50%)",width:n,height:n,backgroundColor:l,borderRadius:"50%"}),pill:(l,n)=>({position:"absolute",bottom:"4px",left:"8px",right:"8px",height:n,backgroundColor:l,borderRadius:n})},T=(l,n,r)=>k[l](n,r),m=(l,n)=>({...l,...n}),_=(l,n,r)=>!l||!r?n:{...n,...r},E=["disabled","onClick","onMouseenter","onMouseleave"],M=["innerHTML"],V={class:"tab-text"},H=e.defineComponent({__name:"ConfigurableSimpleTabs",props:{tabs:{},defaultActive:{},size:{default:"medium"},theme:{},style:{},animation:{},responsive:{},className:{},customStyle:{},block:{type:Boolean,default:!1},centered:{type:Boolean,default:!1},scrollable:{type:Boolean,default:!1}},emits:["tab-change","tab-click","tab-hover","tab-leave"],setup(l,{expose:n,emit:r}){var R;e.useCssVars(t=>({"001f7dcf":s.value.inactiveTextColor,"78d6cd4f":s.value.fontFamily,"37ab6550":s.value.indicatorColor,"10278ad8":s.value.activeTextColor,"6a0edb99":s.value.backgroundColor}));const o=l,u=r,d=e.ref(o.defaultActive||((R=o.tabs[0])==null?void 0:R.id)||""),b=e.ref(!1),v=e.ref(null),s=e.computed(()=>m(h,o.theme)),p=e.computed(()=>m(C,o.animation)),g=e.computed(()=>m(S,o.responsive)),N=e.computed(()=>m(x[o.size],o.style)),f=e.computed(()=>_(b.value&&g.value.enabled,N.value,g.value.mobileStyle)),B=()=>{g.value.enabled&&(b.value=window.innerWidth<=g.value.mobileBreakpoint)},$=t=>t.disabled?s.value.inactiveTextColor:d.value===t.id?s.value.activeTextColor:v.value===t.id?s.value.hoverTextColor:s.value.inactiveTextColor,A=()=>T(f.value.indicatorStyle,s.value.indicatorColor,f.value.indicatorHeight),F=(t,c)=>{t.disabled||(d.value=t.id,u("tab-change",t.id,t),u("tab-click",t.id,t,c),t.route&&console.log("Navigate to:",t.route))},D=t=>{t.disabled||(v.value=t.id,u("tab-hover",t.id,t))},I=t=>{t.disabled||(v.value=null,u("tab-leave",t.id,t))},w=()=>{B()};return e.onMounted(()=>{B(),window.addEventListener("resize",w)}),e.onUnmounted(()=>{window.removeEventListener("resize",w)}),n({activeTab:d,setActiveTab:t=>{const c=o.tabs.find(i=>i.id===t);c&&!c.disabled&&(d.value=t,u("tab-change",t,c))},getActiveTab:()=>o.tabs.find(t=>t.id===d.value),scrollToTab:t=>{o.scrollable&&e.nextTick(()=>{const c=document.querySelector(`[data-tab-id="${t}"]`);c&&c.scrollIntoView({behavior:"smooth",inline:"center"})})}}),(t,c)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["simple-tabs-container",[`size-${o.size}`,{"tabs-block":o.block,"tabs-centered":o.centered,"tabs-scrollable":o.scrollable,"is-mobile":b.value},o.className]]),style:e.normalizeStyle({backgroundColor:s.value.backgroundColor,boxShadow:s.value.boxShadow,flexShrink:0,...o.customStyle})},[e.createElementVNode("nav",null,[e.createElementVNode("ul",{class:e.normalizeClass(["tabs-list",{"flex-wrap":o.scrollable&&!b.value,"overflow-x-auto":o.scrollable&&b.value}]),style:e.normalizeStyle({display:"flex",gap:f.value.gap,justifyContent:o.centered?"center":"flex-start",margin:0,padding:0,listStyle:"none"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.tabs,i=>(e.openBlock(),e.createElementBlock("li",{key:i.id,class:e.normalizeClass(["tab-item",{"tab-active":d.value===i.id,"tab-disabled":i.disabled}])},[e.createElementVNode("button",{class:e.normalizeClass(["tab-button",{"tab-button-active":d.value===i.id,"tab-button-disabled":i.disabled}]),disabled:i.disabled,style:e.normalizeStyle({position:"relative",display:"flex",alignItems:"center",background:"none",border:"none",cursor:i.disabled?"not-allowed":"pointer",textDecoration:"none",transition:p.value.enabled?`color ${p.value.transitionDuration} ${p.value.easing}`:"none",padding:f.value.padding,fontSize:f.value.fontSize,fontWeight:d.value===i.id?"500":f.value.fontWeight,fontFamily:s.value.fontFamily,color:$(i),opacity:i.disabled?.5:1,borderRadius:f.value.borderRadius||"0",whiteSpace:"nowrap",lineHeight:1.25}),onClick:y=>F(i,y),onMouseenter:y=>D(i),onMouseleave:y=>I(i)},[i.icon?(e.openBlock(),e.createElementBlock("span",{key:0,class:"tab-icon",style:{marginRight:"8px",fontSize:"1em",lineHeight:1},innerHTML:i.icon},null,8,M)):e.createCommentVNode("",!0),e.createElementVNode("span",V,e.toDisplayString(i.name),1),d.value===i.id?(e.openBlock(),e.createElementBlock("span",{key:1,class:"tab-indicator",style:e.normalizeStyle({...A(),transition:p.value.enabled?`all ${p.value.indicatorTransition||p.value.transitionDuration} ${p.value.easing}`:"none"})},null,4)):e.createCommentVNode("",!0)],46,E)],2))),128))],6)])],6))}}),L="",z=((l,n)=>{const r=l.__vccOpts||l;for(const[o,u]of n)r[o]=u;return r})(H,[["__scopeId","data-v-28fbd600"]]);a.ConfigurableSimpleTabs=z,a.default=z,a.defaultAnimation=C,a.defaultResponsive=S,a.defaultTheme=h,a.getIndicatorStyle=T,a.getResponsiveStyle=_,a.indicatorStyles=k,a.mergeConfig=m,a.sizeConfigs=x,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
2
2
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n \r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n \r\n // 尺寸\r\n size?: TabSize;\r\n \r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n \r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n \r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n \r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n \r\n // 自定义类名\r\n className?: string;\r\n \r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n \r\n // 是否显示为块级元素\r\n block?: boolean;\r\n \r\n // 居中对齐\r\n centered?: boolean;\r\n \r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n \r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n \r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle, \r\n color: string, \r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n \r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n \r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from '../types';\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from '../types';\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: 'medium',\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || '');\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => \r\n mergeConfig(defaultTheme, props.theme)\r\n);\r\n\r\nconst computedAnimation = computed(() => \r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() => \r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() => \r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() => \r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value = window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n \r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n \r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n \r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n \r\n activeTab.value = tab.id;\r\n emit('tab-change', tab.id, tab);\r\n emit('tab-click', tab.id, tab, event);\r\n \r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log('Navigate to:', tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit('tab-hover', tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit('tab-leave', tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener('resize', handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find(t => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit('tab-change', tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find(t => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: 'smooth', inline: 'center' });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind('computedTheme.indicatorColor');\r\n outline-offset: 2px;\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(to right, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(to left, v-bind('computedTheme.backgroundColor'), transparent);\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n \r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/types.ts","../src/components/ConfigurableSimpleTabs.vue"],"sourcesContent":["// 简洁标签页组件的类型定义\r\n\r\n// 标签项接口\r\nexport interface TabItem {\r\n id: string;\r\n name: string;\r\n disabled?: boolean; // 是否禁用\r\n route?: string; // 可选路由地址\r\n icon?: string; // 可选图标\r\n}\r\n\r\n// 尺寸类型\r\nexport type TabSize = 'small' | 'medium' | 'large';\r\n\r\n// 指示器样式类型\r\nexport type IndicatorStyle = 'line' | 'dot' | 'pill' | 'underline';\r\n\r\n// 主题配置接口\r\nexport interface SimpleTabsTheme {\r\n // 激活状态文字颜色\r\n activeTextColor: string;\r\n // 非激活状态文字颜色\r\n inactiveTextColor: string;\r\n // 悬浮状态文字颜色\r\n hoverTextColor: string;\r\n // 背景色\r\n backgroundColor: string;\r\n // 激活指示器颜色\r\n indicatorColor: string;\r\n // 字体系列\r\n fontFamily: string;\r\n // 边框颜色(如果需要)\r\n borderColor?: string;\r\n // 阴影(如果需要)\r\n boxShadow?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n // 内边距\r\n padding: string;\r\n // 字体大小\r\n fontSize: string;\r\n // 字体粗细\r\n fontWeight: string;\r\n // 指示器高度\r\n indicatorHeight: string;\r\n // 指示器样式\r\n indicatorStyle: IndicatorStyle;\r\n // 圆角大小\r\n borderRadius?: string;\r\n // 标签间距\r\n gap?: string;\r\n}\r\n\r\n// 动画配置接口\r\nexport interface AnimationConfig {\r\n // 过渡时长\r\n transitionDuration: string;\r\n // 缓动函数\r\n easing: string;\r\n // 是否启用动画\r\n enabled: boolean;\r\n // 指示器动画时长\r\n indicatorTransition?: string;\r\n}\r\n\r\n// 响应式配置接口\r\nexport interface ResponsiveConfig {\r\n // 移动端断点\r\n mobileBreakpoint: number;\r\n // 移动端样式\r\n mobileStyle?: Partial<StyleConfig>;\r\n // 是否启用响应式\r\n enabled: boolean;\r\n}\r\n\r\n// 主组件Props接口\r\nexport interface SimpleTabsProps {\r\n // 标签页数据\r\n tabs: TabItem[];\r\n\r\n // 默认激活的标签ID\r\n defaultActive?: string;\r\n\r\n // 尺寸\r\n size?: TabSize;\r\n\r\n // 主题配置\r\n theme?: Partial<SimpleTabsTheme>;\r\n\r\n // 样式配置\r\n style?: Partial<StyleConfig>;\r\n\r\n // 动画配置\r\n animation?: Partial<AnimationConfig>;\r\n\r\n // 响应式配置\r\n responsive?: Partial<ResponsiveConfig>;\r\n\r\n // 自定义类名\r\n className?: string;\r\n\r\n // 自定义内联样式\r\n customStyle?: Record<string, any>;\r\n\r\n // 是否显示为块级元素\r\n block?: boolean;\r\n\r\n // 居中对齐\r\n centered?: boolean;\r\n\r\n // 是否可滚动(当标签过多时)\r\n scrollable?: boolean;\r\n}\r\n\r\n// 事件接口\r\nexport interface SimpleTabsEvents {\r\n 'tab-change': [tabId: string, tab: TabItem];\r\n 'tab-click': [tabId: string, tab: TabItem, event: Event];\r\n 'tab-hover': [tabId: string, tab: TabItem];\r\n 'tab-leave': [tabId: string, tab: TabItem];\r\n}\r\n\r\n// 默认主题\r\nexport const defaultTheme: SimpleTabsTheme = {\r\n activeTextColor: 'rgb(20, 23, 26)',\r\n inactiveTextColor: 'rgb(76, 82, 89)',\r\n hoverTextColor: 'rgb(55, 65, 81)',\r\n backgroundColor: '#ffffff',\r\n indicatorColor: 'rgb(20, 23, 26)',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"SF Pro Display\", \"Inter\", sans-serif',\r\n};\r\n\r\n// 尺寸配置\r\nexport const sizeConfigs: Record<TabSize, StyleConfig> = {\r\n small: {\r\n padding: '8px 10px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '16px',\r\n },\r\n medium: {\r\n padding: '14px 12px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n indicatorHeight: '2px',\r\n indicatorStyle: 'line',\r\n gap: '20px',\r\n },\r\n large: {\r\n padding: '16px 16px',\r\n fontSize: '18px',\r\n fontWeight: '700',\r\n indicatorHeight: '3px',\r\n indicatorStyle: 'line',\r\n gap: '24px',\r\n },\r\n};\r\n\r\n// 默认动画配置\r\nexport const defaultAnimation: AnimationConfig = {\r\n transitionDuration: '0.2s',\r\n easing: 'ease',\r\n enabled: true,\r\n indicatorTransition: '0.3s ease',\r\n};\r\n\r\n// 默认响应式配置\r\nexport const defaultResponsive: ResponsiveConfig = {\r\n mobileBreakpoint: 768,\r\n enabled: true,\r\n mobileStyle: {\r\n padding: '14px 0',\r\n gap: '16px',\r\n },\r\n};\r\n\r\n// 指示器样式映射\r\nexport const indicatorStyles: Record<IndicatorStyle, (color: string, height: string) => Record<string, string>> = {\r\n line: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '12px',\r\n right: '12px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n underline: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '0',\r\n left: '0',\r\n right: '0',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '0',\r\n }),\r\n\r\n dot: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n width: height,\r\n height,\r\n backgroundColor: color,\r\n borderRadius: '50%',\r\n }),\r\n\r\n pill: (color: string, height: string) => ({\r\n position: 'absolute',\r\n bottom: '4px',\r\n left: '8px',\r\n right: '8px',\r\n height,\r\n backgroundColor: color,\r\n borderRadius: height,\r\n }),\r\n};\r\n\r\n// 工具函数:获取指示器样式\r\nexport const getIndicatorStyle = (\r\n style: IndicatorStyle,\r\n color: string,\r\n height: string\r\n): Record<string, string> => {\r\n return indicatorStyles[style](color, height);\r\n};\r\n\r\n// 工具函数:合并配置\r\nexport const mergeConfig = <T extends Record<string, any>>(\r\n defaultConfig: T,\r\n userConfig?: Partial<T>\r\n): T => {\r\n return { ...defaultConfig, ...userConfig };\r\n};\r\n\r\n// 工具函数:获取响应式样式\r\nexport const getResponsiveStyle = (\r\n isMobile: boolean,\r\n baseStyle: StyleConfig,\r\n mobileStyle?: Partial<StyleConfig>\r\n): StyleConfig => {\r\n if (!isMobile || !mobileStyle) return baseStyle;\r\n return { ...baseStyle, ...mobileStyle };\r\n};\r\n\r\n","<template>\r\n <div\r\n class=\"simple-tabs-container\"\r\n :class=\"[\r\n `size-${props.size}`,\r\n {\r\n 'tabs-block': props.block,\r\n 'tabs-centered': props.centered,\r\n 'tabs-scrollable': props.scrollable,\r\n 'is-mobile': isMobile,\r\n },\r\n props.className,\r\n ]\"\r\n :style=\"{\r\n backgroundColor: computedTheme.backgroundColor,\r\n boxShadow: computedTheme.boxShadow,\r\n flexShrink: 0,\r\n ...props.customStyle,\r\n }\"\r\n >\r\n <nav>\r\n <ul\r\n class=\"tabs-list\"\r\n :class=\"{\r\n 'flex-wrap': props.scrollable && !isMobile,\r\n 'overflow-x-auto': props.scrollable && isMobile,\r\n }\"\r\n :style=\"{\r\n display: 'flex',\r\n gap: computedStyleConfig.gap,\r\n justifyContent: props.centered ? 'center' : 'flex-start',\r\n margin: 0,\r\n padding: 0,\r\n listStyle: 'none',\r\n }\"\r\n >\r\n <li\r\n v-for=\"tab in props.tabs\"\r\n :key=\"tab.id\"\r\n class=\"tab-item\"\r\n :class=\"{\r\n 'tab-active': activeTab === tab.id,\r\n 'tab-disabled': tab.disabled,\r\n }\"\r\n >\r\n <button\r\n class=\"tab-button\"\r\n :class=\"{\r\n 'tab-button-active': activeTab === tab.id,\r\n 'tab-button-disabled': tab.disabled,\r\n }\"\r\n :disabled=\"tab.disabled\"\r\n :style=\"{\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center',\r\n background: 'none',\r\n border: 'none',\r\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\r\n textDecoration: 'none',\r\n transition: computedAnimation.enabled\r\n ? `color ${computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n padding: computedStyleConfig.padding,\r\n fontSize: computedStyleConfig.fontSize,\r\n fontWeight: activeTab === tab.id ? '500' : computedStyleConfig.fontWeight,\r\n fontFamily: computedTheme.fontFamily,\r\n color: getTabTextColor(tab),\r\n opacity: tab.disabled ? 0.5 : 1,\r\n borderRadius: computedStyleConfig.borderRadius || '0',\r\n whiteSpace: 'nowrap',\r\n lineHeight: 1.25,\r\n }\"\r\n @click=\"handleTabClick(tab, $event)\"\r\n @mouseenter=\"handleTabHover(tab)\"\r\n @mouseleave=\"handleTabLeave(tab)\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"tab.icon\"\r\n class=\"tab-icon\"\r\n :style=\"{\r\n marginRight: '8px',\r\n fontSize: '1em',\r\n lineHeight: 1,\r\n }\"\r\n v-html=\"tab.icon\"\r\n />\r\n\r\n <!-- 标签文本 -->\r\n <span class=\"tab-text\">{{ tab.name }}</span>\r\n\r\n <!-- 激活指示器 -->\r\n <span\r\n v-if=\"activeTab === tab.id\"\r\n class=\"tab-indicator\"\r\n :style=\"{\r\n ...getIndicatorStyleComputed(),\r\n transition: computedAnimation.enabled\r\n ? `all ${computedAnimation.indicatorTransition || computedAnimation.transitionDuration} ${computedAnimation.easing}`\r\n : 'none',\r\n }\"\r\n />\r\n </button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted, onUnmounted, nextTick } from \"vue\";\r\nimport type { SimpleTabsProps, SimpleTabsEvents, TabItem } from \"../types\";\r\nimport {\r\n defaultTheme,\r\n sizeConfigs,\r\n defaultAnimation,\r\n defaultResponsive,\r\n mergeConfig,\r\n getResponsiveStyle,\r\n getIndicatorStyle,\r\n} from \"../types\";\r\n\r\n// Props定义\r\nconst props = withDefaults(defineProps<SimpleTabsProps>(), {\r\n size: \"medium\",\r\n block: false,\r\n centered: false,\r\n scrollable: false,\r\n});\r\n\r\n// Events定义\r\nconst emit = defineEmits<SimpleTabsEvents>();\r\n\r\n// 响应式状态\r\nconst activeTab = ref(props.defaultActive || props.tabs[0]?.id || \"\");\r\nconst isMobile = ref(false);\r\nconst hoveredTab = ref<string | null>(null);\r\n\r\n// 计算属性\r\nconst computedTheme = computed(() => mergeConfig(defaultTheme, props.theme));\r\n\r\nconst computedAnimation = computed(() =>\r\n mergeConfig(defaultAnimation, props.animation)\r\n);\r\n\r\nconst computedResponsive = computed(() =>\r\n mergeConfig(defaultResponsive, props.responsive)\r\n);\r\n\r\nconst baseStyleConfig = computed(() =>\r\n mergeConfig(sizeConfigs[props.size], props.style)\r\n);\r\n\r\nconst computedStyleConfig = computed(() =>\r\n getResponsiveStyle(\r\n isMobile.value && computedResponsive.value.enabled,\r\n baseStyleConfig.value,\r\n computedResponsive.value.mobileStyle\r\n )\r\n);\r\n\r\n// 工具方法\r\nconst checkMobile = () => {\r\n if (computedResponsive.value.enabled) {\r\n isMobile.value =\r\n window.innerWidth <= computedResponsive.value.mobileBreakpoint;\r\n }\r\n};\r\n\r\nconst getTabTextColor = (tab: TabItem): string => {\r\n if (tab.disabled) {\r\n return computedTheme.value.inactiveTextColor;\r\n }\r\n\r\n if (activeTab.value === tab.id) {\r\n return computedTheme.value.activeTextColor;\r\n }\r\n\r\n if (hoveredTab.value === tab.id) {\r\n return computedTheme.value.hoverTextColor;\r\n }\r\n\r\n return computedTheme.value.inactiveTextColor;\r\n};\r\n\r\nconst getIndicatorStyleComputed = () => {\r\n return getIndicatorStyle(\r\n computedStyleConfig.value.indicatorStyle,\r\n computedTheme.value.indicatorColor,\r\n computedStyleConfig.value.indicatorHeight\r\n );\r\n};\r\n\r\n// 事件处理\r\nconst handleTabClick = (tab: TabItem, event: Event) => {\r\n if (tab.disabled) return;\r\n\r\n activeTab.value = tab.id;\r\n emit(\"tab-change\", tab.id, tab);\r\n emit(\"tab-click\", tab.id, tab, event);\r\n\r\n // 路由跳转逻辑(如果需要)\r\n if (tab.route) {\r\n console.log(\"Navigate to:\", tab.route);\r\n // 这里可以集成 vue-router\r\n }\r\n};\r\n\r\nconst handleTabHover = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = tab.id;\r\n emit(\"tab-hover\", tab.id, tab);\r\n};\r\n\r\nconst handleTabLeave = (tab: TabItem) => {\r\n if (tab.disabled) return;\r\n hoveredTab.value = null;\r\n emit(\"tab-leave\", tab.id, tab);\r\n};\r\n\r\n// 窗口尺寸变化监听\r\nconst handleResize = () => {\r\n checkMobile();\r\n};\r\n\r\n// 生命周期\r\nonMounted(() => {\r\n checkMobile();\r\n window.addEventListener(\"resize\", handleResize);\r\n});\r\n\r\nonUnmounted(() => {\r\n window.removeEventListener(\"resize\", handleResize);\r\n});\r\n\r\n// 暴露给父组件\r\ndefineExpose({\r\n activeTab,\r\n setActiveTab: (tabId: string) => {\r\n const tab = props.tabs.find((t) => t.id === tabId);\r\n if (tab && !tab.disabled) {\r\n activeTab.value = tabId;\r\n emit(\"tab-change\", tabId, tab);\r\n }\r\n },\r\n getActiveTab: () => {\r\n return props.tabs.find((t) => t.id === activeTab.value);\r\n },\r\n scrollToTab: (tabId: string) => {\r\n if (!props.scrollable) return;\r\n nextTick(() => {\r\n const tabElement = document.querySelector(`[data-tab-id=\"${tabId}\"]`);\r\n if (tabElement) {\r\n tabElement.scrollIntoView({ behavior: \"smooth\", inline: \"center\" });\r\n }\r\n });\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.simple-tabs-container {\r\n width: 100%;\r\n}\r\n\r\n.simple-tabs-container.tabs-block {\r\n display: block;\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list {\r\n overflow-x: auto;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n}\r\n\r\n.simple-tabs-container.tabs-scrollable .tabs-list::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n}\r\n\r\n.tab-item {\r\n flex-shrink: 0;\r\n position: relative;\r\n}\r\n\r\n.tab-button {\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n text-decoration: none;\r\n background: transparent;\r\n border: 0px;\r\n font-size: 16px;\r\n font-weight: 400;\r\n line-height: 1.25;\r\n padding: 14px 12px;\r\n position: relative;\r\n color: v-bind(\"computedTheme.inactiveTextColor\");\r\n font-family: v-bind(\"computedTheme.fontFamily\");\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.tab-button:focus {\r\n outline: none;\r\n}\r\n\r\n.tab-button:focus-visible {\r\n outline: 2px solid v-bind(\"computedTheme.indicatorColor\");\r\n outline-offset: 2px;\r\n}\r\n\r\n.tab-button-active {\r\n color: v-bind(\"computedTheme.activeTextColor\");\r\n font-weight: 500;\r\n}\r\n\r\n.tab-button-active::before {\r\n position: absolute;\r\n background: v-bind(\"computedTheme.indicatorColor\");\r\n height: 2px;\r\n inset: auto 12px 0px;\r\n content: \"\";\r\n}\r\n\r\n/* 移动端优化 */\r\n.simple-tabs-container.is-mobile .tab-button {\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* 禁用状态样式 */\r\n.tab-disabled .tab-button {\r\n cursor: not-allowed;\r\n}\r\n\r\n/* 响应式样式 */\r\n@media (max-width: 768px) {\r\n .simple-tabs-container.is-mobile .tab-button {\r\n padding: 14px 0;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-button-active::before {\r\n inset: auto 0px 0px;\r\n }\r\n\r\n .simple-tabs-container.is-mobile .tab-indicator {\r\n left: 0 !important;\r\n right: 0 !important;\r\n }\r\n}\r\n\r\n/* 滚动优化 */\r\n.tabs-scrollable {\r\n position: relative;\r\n}\r\n\r\n.tabs-scrollable::before,\r\n.tabs-scrollable::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n width: 20px;\r\n pointer-events: none;\r\n z-index: 1;\r\n}\r\n\r\n.tabs-scrollable::before {\r\n left: 0;\r\n background: linear-gradient(\r\n to right,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n.tabs-scrollable::after {\r\n right: 0;\r\n background: linear-gradient(\r\n to left,\r\n v-bind(\"computedTheme.backgroundColor\"),\r\n transparent\r\n );\r\n}\r\n\r\n/* 不同尺寸的样式 */\r\n.size-small .tab-button {\r\n min-height: 32px;\r\n}\r\n\r\n.size-medium .tab-button {\r\n min-height: 40px;\r\n}\r\n\r\n.size-large .tab-button {\r\n min-height: 48px;\r\n}\r\n\r\n/* 居中对齐样式 */\r\n.tabs-centered .tabs-list {\r\n justify-content: center;\r\n}\r\n\r\n/* 图标样式 */\r\n.tab-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.tab-icon svg {\r\n width: 1em;\r\n height: 1em;\r\n fill: currentColor;\r\n}\r\n\r\n/* 指示器样式基类 */\r\n.tab-indicator {\r\n pointer-events: none;\r\n}\r\n\r\n/* 动画性能优化 */\r\n.tab-button,\r\n.tab-indicator {\r\n will-change: color, background-color, transform;\r\n}\r\n\r\n/* 高对比度模式支持 */\r\n@media (prefers-contrast: high) {\r\n .tab-button {\r\n border: 1px solid currentColor;\r\n }\r\n\r\n .tab-indicator {\r\n border: 2px solid currentColor;\r\n }\r\n}\r\n\r\n/* 减少动画模式支持 */\r\n@media (prefers-reduced-motion: reduce) {\r\n .tab-button,\r\n .tab-indicator {\r\n transition: none !important;\r\n }\r\n}\r\n</style>\r\n\r\n"],"names":["defaultTheme","sizeConfigs","defaultAnimation","defaultResponsive","indicatorStyles","color","height","getIndicatorStyle","style","mergeConfig","defaultConfig","userConfig","getResponsiveStyle","isMobile","baseStyle","mobileStyle","props","__props","emit","__emit","activeTab","ref","_a","hoveredTab","computedTheme","computed","computedAnimation","computedResponsive","baseStyleConfig","computedStyleConfig","checkMobile","getTabTextColor","tab","getIndicatorStyleComputed","handleTabClick","event","handleTabHover","handleTabLeave","handleResize","onMounted","onUnmounted","__expose","tabId","t","nextTick","tabElement","_createElementBlock","_normalizeStyle","_createElementVNode","_openBlock","_Fragment","_renderList","$event","_hoisted_3","_toDisplayString"],"mappings":"kQA6HO,MAAMA,EAAgC,CACzC,gBAAiB,kBACjB,kBAAmB,kBACnB,eAAgB,kBAChB,gBAAiB,UACjB,eAAgB,kBAChB,WAAY,sFAChB,EAGaC,EAA4C,CACrD,MAAO,CACH,QAAS,WACT,SAAU,OACV,WAAY,MACZ,gBAAiB,MACjB,eAAgB,OAChB,IAAK,MACT,EACA,OAAQ,CACJ,QAAS,YACT,SAAU,OACV,WAAY,MACZ,gBAAiB,MACjB,eAAgB,OAChB,IAAK,MACT,EACA,MAAO,CACH,QAAS,YACT,SAAU,OACV,WAAY,MACZ,gBAAiB,MACjB,eAAgB,OAChB,IAAK,MACT,CACJ,EAGaC,EAAoC,CAC7C,mBAAoB,OACpB,OAAQ,OACR,QAAS,GACT,oBAAqB,WACzB,EAGaC,EAAsC,CAC/C,iBAAkB,IAClB,QAAS,GACT,YAAa,CACT,QAAS,SACT,IAAK,MACT,CACJ,EAGaC,EAAqG,CAC9G,KAAM,CAACC,EAAeC,KAAoB,CACtC,SAAU,WACV,OAAQ,IACR,KAAM,OACN,MAAO,OACP,OAAAA,EACA,gBAAiBD,EACjB,aAAc,GAAA,GAGlB,UAAW,CAACA,EAAeC,KAAoB,CAC3C,SAAU,WACV,OAAQ,IACR,KAAM,IACN,MAAO,IACP,OAAAA,EACA,gBAAiBD,EACjB,aAAc,GAAA,GAGlB,IAAK,CAACA,EAAeC,KAAoB,CACrC,SAAU,WACV,OAAQ,MACR,KAAM,MACN,UAAW,mBACX,MAAOA,EACP,OAAAA,EACA,gBAAiBD,EACjB,aAAc,KAAA,GAGlB,KAAM,CAACA,EAAeC,KAAoB,CACtC,SAAU,WACV,OAAQ,MACR,KAAM,MACN,MAAO,MACP,OAAAA,EACA,gBAAiBD,EACjB,aAAcC,CAAA,EAEtB,EAGaC,EAAoB,CAC7BC,EACAH,EACAC,IAEOF,EAAgBI,CAAK,EAAEH,EAAOC,CAAM,EAIlCG,EAAc,CACvBC,EACAC,KAEO,CAAE,GAAGD,EAAe,GAAGC,IAIrBC,EAAqB,CAC9BC,EACAC,EACAC,IAEI,CAACF,GAAY,CAACE,EAAoBD,EAC/B,CAAE,GAAGA,EAAW,GAAGC,wpBC5H9B,MAAMC,EAAQC,EAQRC,EAAOC,EAGPC,EAAYC,EAAAA,IAAIL,EAAM,iBAAiBM,EAAAN,EAAM,KAAK,CAAC,IAAZ,YAAAM,EAAe,KAAM,EAAE,EAC9DT,EAAWQ,MAAI,EAAK,EACpBE,EAAaF,MAAmB,IAAI,EAGpCG,EAAgBC,EAAAA,SAAS,IAAMhB,EAAYT,EAAcgB,EAAM,KAAK,CAAC,EAErEU,EAAoBD,EAAA,SAAS,IACjChB,EAAYP,EAAkBc,EAAM,SAAS,CAAA,EAGzCW,EAAqBF,EAAA,SAAS,IAClChB,EAAYN,EAAmBa,EAAM,UAAU,CAAA,EAG3CY,EAAkBH,EAAA,SAAS,IAC/BhB,EAAYR,EAAYe,EAAM,IAAI,EAAGA,EAAM,KAAK,CAAA,EAG5Ca,EAAsBJ,EAAA,SAAS,IACnCb,EACEC,EAAS,OAASc,EAAmB,MAAM,QAC3CC,EAAgB,MAChBD,EAAmB,MAAM,WAC3B,CAAA,EAIIG,EAAc,IAAM,CACpBH,EAAmB,MAAM,UAC3Bd,EAAS,MACP,OAAO,YAAcc,EAAmB,MAAM,iBAClD,EAGII,EAAmBC,GACnBA,EAAI,SACCR,EAAc,MAAM,kBAGzBJ,EAAU,QAAUY,EAAI,GACnBR,EAAc,MAAM,gBAGzBD,EAAW,QAAUS,EAAI,GACpBR,EAAc,MAAM,eAGtBA,EAAc,MAAM,kBAGvBS,EAA4B,IACzB1B,EACLsB,EAAoB,MAAM,eAC1BL,EAAc,MAAM,eACpBK,EAAoB,MAAM,eAAA,EAKxBK,EAAiB,CAACF,EAAcG,IAAiB,CACjDH,EAAI,WAERZ,EAAU,MAAQY,EAAI,GACjBd,EAAA,aAAcc,EAAI,GAAIA,CAAG,EAC9Bd,EAAK,YAAac,EAAI,GAAIA,EAAKG,CAAK,EAGhCH,EAAI,OACE,QAAA,IAAI,eAAgBA,EAAI,KAAK,EAEvC,EAGII,EAAkBJ,GAAiB,CACnCA,EAAI,WACRT,EAAW,MAAQS,EAAI,GAClBd,EAAA,YAAac,EAAI,GAAIA,CAAG,EAAA,EAGzBK,EAAkBL,GAAiB,CACnCA,EAAI,WACRT,EAAW,MAAQ,KACdL,EAAA,YAAac,EAAI,GAAIA,CAAG,EAAA,EAIzBM,EAAe,IAAM,CACbR,GAAA,EAIdS,OAAAA,EAAAA,UAAU,IAAM,CACFT,IACL,OAAA,iBAAiB,SAAUQ,CAAY,CAAA,CAC/C,EAEDE,EAAAA,YAAY,IAAM,CACT,OAAA,oBAAoB,SAAUF,CAAY,CAAA,CAClD,EAGYG,EAAA,CACX,UAAArB,EACA,aAAesB,GAAkB,CACzB,MAAAV,EAAMhB,EAAM,KAAK,KAAM2B,GAAMA,EAAE,KAAOD,CAAK,EAC7CV,GAAO,CAACA,EAAI,WACdZ,EAAU,MAAQsB,EACbxB,EAAA,aAAcwB,EAAOV,CAAG,EAEjC,EACA,aAAc,IACLhB,EAAM,KAAK,KAAM,GAAM,EAAE,KAAOI,EAAU,KAAK,EAExD,YAAcsB,GAAkB,CACzB1B,EAAM,YACX4B,EAAAA,SAAS,IAAM,CACb,MAAMC,EAAa,SAAS,cAAc,iBAAiBH,CAAK,IAAI,EAChEG,GACFA,EAAW,eAAe,CAAE,SAAU,SAAU,OAAQ,SAAU,CACpE,CACD,CACH,CAAA,CACD,wBAjQCC,EAAA,mBA0GM,MAAA,CAzGJ,wBAAM,wBAAuB,CACJ,QAAA9B,EAAM,IAAI,IAAoC,aAAAA,EAAM,MAAiC,gBAAAA,EAAM,SAAsC,kBAAAA,EAAM,uBAAkCH,EAAQ,OAAmBG,EAAM,SAAA,IAUlO,MAAK+B,EAAAA,eAAA,CAA4B,gBAAAvB,EAAA,MAAc,gBAAmC,UAAAA,EAAA,MAAc,uBAA2C,GAAAR,EAAM,WAAA,KAOlJgC,EAAA,mBAsFM,MAAA,KAAA,CArFJA,EAAAA,mBAoFK,KAAA,CAnFH,wBAAM,YAAW,aACiBhC,EAAM,YAAU,CAAKH,EAAQ,wBAAgCG,EAAM,YAAcH,EAAQ,KAAA,IAI1H,MAAKkC,EAAAA,eAAA,gBAAgD,IAAAlB,EAAA,MAAoB,IAAgC,eAAAb,EAAM,SAAQ,SAAA,sDASxHiC,YAAA,EAAA,EAAAH,EAAAA,mBAoEKI,EAAA,SAnEW,KAAAC,EAAAA,WAAAnC,EAAM,KAAbgB,kBADTc,EAAA,mBAoEK,KAAA,CAlEF,IAAKd,EAAI,GACV,wBAAM,WAAU,cACqBZ,EAAS,QAAKY,EAAI,GAAiC,eAAAA,EAAI,QAAA,MAK5FgB,EAAAA,mBA0DS,SAAA,CAzDP,wBAAM,aAAY,qBAC4B5B,EAAS,QAAKY,EAAI,GAA0C,sBAAAA,EAAI,QAAA,IAI7G,SAAUA,EAAI,SACd,MAAKe,EAAAA,eAAA,wFAAuM,OAAAf,EAAI,SAAQ,cAAA,gCAAgG,WAAAN,EAAA,MAAkB,QAAoC,SAAAA,EAAA,MAAkB,kBAAkB,IAAIA,EAAA,MAAkB,MAAM,UAAsD,QAAAG,EAAA,MAAoB,QAAkC,SAAAA,EAAA,MAAoB,SAAqC,WAAAT,EAAA,QAAcY,EAAI,GAAa,MAAAH,EAAA,MAAoB,WAAuC,WAAAL,EAAA,MAAc,WAAkC,MAAAO,EAAgBC,CAAG,EAA2B,QAAAA,EAAI,SAAQ,GAAA,EAAyC,aAAAH,EAAA,MAAoB,cAAY,0CAqBh2B,QAAOuB,GAAAlB,EAAeF,EAAKoB,CAAM,EACjC,aAAUA,GAAEhB,EAAeJ,CAAG,EAC9B,aAAUoB,GAAEf,EAAeL,CAAG,CAAA,GAIvBA,EAAI,oBADZc,EAAAA,mBASE,OAAA,OAPA,MAAM,WACL,MAAO,8CAIP,EACD,UAAQd,EAAI,IAAA,yCAIdgB,qBAA4C,OAA5CK,EAA0BC,EAAAA,gBAAAtB,EAAI,IAAI,EAAA,CAAA,EAI1BZ,EAAS,QAAKY,EAAI,kBAD1Bc,qBASE,OAAA,OAPA,MAAM,gBACL,MAAKC,EAAAA,eAAA,IAAwBd,EAAyB,EAAiC,WAAAP,EAAA,MAAkB,eAAoCA,EAAiB,MAAC,qBAAuBA,EAAA,MAAkB,kBAAkB,IAAIA,EAAiB,MAAC,MAAM"}
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .simple-tabs-container[data-v-166844ee]{width:100%}.simple-tabs-container.tabs-block[data-v-166844ee]{display:block}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-166844ee]{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-166844ee]::-webkit-scrollbar{display:none}.tab-item[data-v-166844ee]{flex-shrink:0;position:relative}.tab-button[data-v-166844ee]{outline:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.tab-button[data-v-166844ee]:focus{outline:none}.tab-button[data-v-166844ee]:focus-visible{outline:2px solid var(--4e65487a);outline-offset:2px}.simple-tabs-container.is-mobile .tab-button[data-v-166844ee]{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tab-disabled .tab-button[data-v-166844ee]{cursor:not-allowed}@media (max-width: 768px){.simple-tabs-container.is-mobile .tab-indicator[data-v-166844ee]{left:0!important;right:0!important}}.tabs-scrollable[data-v-166844ee]{position:relative}.tabs-scrollable[data-v-166844ee]:before,.tabs-scrollable[data-v-166844ee]:after{content:"";position:absolute;top:0;bottom:0;width:20px;pointer-events:none;z-index:1}.tabs-scrollable[data-v-166844ee]:before{left:0;background:linear-gradient(to right,var(--25a898f4),transparent)}.tabs-scrollable[data-v-166844ee]:after{right:0;background:linear-gradient(to left,var(--25a898f4),transparent)}.size-small .tab-button[data-v-166844ee]{min-height:32px}.size-medium .tab-button[data-v-166844ee]{min-height:40px}.size-large .tab-button[data-v-166844ee]{min-height:48px}.tabs-centered .tabs-list[data-v-166844ee]{justify-content:center}.tab-icon[data-v-166844ee]{display:inline-flex;align-items:center;justify-content:center}.tab-icon svg[data-v-166844ee]{width:1em;height:1em;fill:currentColor}.tab-indicator[data-v-166844ee]{pointer-events:none}.tab-button[data-v-166844ee],.tab-indicator[data-v-166844ee]{will-change:color,background-color,transform}@media (prefers-contrast: high){.tab-button[data-v-166844ee]{border:1px solid currentColor}.tab-indicator[data-v-166844ee]{border:2px solid currentColor}}@media (prefers-reduced-motion: reduce){.tab-button[data-v-166844ee],.tab-indicator[data-v-166844ee]{transition:none!important}}
1
+ .simple-tabs-container[data-v-28fbd600]{width:100%}.simple-tabs-container.tabs-block[data-v-28fbd600]{display:block}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-28fbd600]{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.simple-tabs-container.tabs-scrollable .tabs-list[data-v-28fbd600]::-webkit-scrollbar{display:none}.tab-item[data-v-28fbd600]{flex-shrink:0;position:relative}.tab-button[data-v-28fbd600]{outline:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;cursor:pointer;display:flex;align-items:center;text-decoration:none;background:transparent;border:0px;font-size:16px;font-weight:400;line-height:1.25;padding:14px 12px;position:relative;color:var(--001f7dcf);font-family:var(--78d6cd4f);transition:color .2s ease}.tab-button[data-v-28fbd600]:focus{outline:none}.tab-button[data-v-28fbd600]:focus-visible{outline:2px solid var(--37ab6550);outline-offset:2px}.tab-button-active[data-v-28fbd600]{color:var(--10278ad8);font-weight:500}.tab-button-active[data-v-28fbd600]:before{position:absolute;background:var(--37ab6550);height:2px;inset:auto 12px 0px;content:""}.simple-tabs-container.is-mobile .tab-button[data-v-28fbd600]{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tab-disabled .tab-button[data-v-28fbd600]{cursor:not-allowed}@media (max-width: 768px){.simple-tabs-container.is-mobile .tab-button[data-v-28fbd600]{padding:14px 0}.simple-tabs-container.is-mobile .tab-button-active[data-v-28fbd600]:before{inset:auto 0px 0px}.simple-tabs-container.is-mobile .tab-indicator[data-v-28fbd600]{left:0!important;right:0!important}}.tabs-scrollable[data-v-28fbd600]{position:relative}.tabs-scrollable[data-v-28fbd600]:before,.tabs-scrollable[data-v-28fbd600]:after{content:"";position:absolute;top:0;bottom:0;width:20px;pointer-events:none;z-index:1}.tabs-scrollable[data-v-28fbd600]:before{left:0;background:linear-gradient(to right,var(--6a0edb99),transparent)}.tabs-scrollable[data-v-28fbd600]:after{right:0;background:linear-gradient(to left,var(--6a0edb99),transparent)}.size-small .tab-button[data-v-28fbd600]{min-height:32px}.size-medium .tab-button[data-v-28fbd600]{min-height:40px}.size-large .tab-button[data-v-28fbd600]{min-height:48px}.tabs-centered .tabs-list[data-v-28fbd600]{justify-content:center}.tab-icon[data-v-28fbd600]{display:inline-flex;align-items:center;justify-content:center}.tab-icon svg[data-v-28fbd600]{width:1em;height:1em;fill:currentColor}.tab-indicator[data-v-28fbd600]{pointer-events:none}.tab-button[data-v-28fbd600],.tab-indicator[data-v-28fbd600]{will-change:color,background-color,transform}@media (prefers-contrast: high){.tab-button[data-v-28fbd600]{border:1px solid currentColor}.tab-indicator[data-v-28fbd600]{border:2px solid currentColor}}@media (prefers-reduced-motion: reduce){.tab-button[data-v-28fbd600],.tab-indicator[data-v-28fbd600]{transition:none!important}}