@7pmlabs/design-system 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/design-system.css +1 -1
- package/dist/design-system.js +24 -16
- package/dist/design-system177.js +29 -326
- package/dist/design-system177.js.map +1 -1
- package/dist/design-system179.js +1 -1
- package/dist/design-system179.js.map +1 -1
- package/dist/design-system180.js +73 -85
- package/dist/design-system180.js.map +1 -1
- package/dist/design-system182.js +1 -1
- package/dist/design-system182.js.map +1 -1
- package/dist/design-system183.js +32 -105
- package/dist/design-system183.js.map +1 -1
- package/dist/design-system185.js +4 -5
- package/dist/design-system185.js.map +1 -1
- package/dist/design-system186.js +26 -104
- package/dist/design-system186.js.map +1 -1
- package/dist/design-system188.js +4 -5
- package/dist/design-system188.js.map +1 -1
- package/dist/design-system189.js +23 -727
- package/dist/design-system189.js.map +1 -1
- package/dist/design-system191.js +1 -1
- package/dist/design-system191.js.map +1 -1
- package/dist/design-system192.js +31 -11
- package/dist/design-system192.js.map +1 -1
- package/dist/design-system194.js +8 -0
- package/dist/design-system194.js.map +1 -0
- package/dist/design-system195.js +332 -5
- package/dist/design-system195.js.map +1 -1
- package/dist/design-system197.js +5 -46
- package/dist/design-system197.js.map +1 -1
- package/dist/design-system198.js +100 -4
- package/dist/design-system198.js.map +1 -1
- package/dist/design-system200.js +8 -0
- package/dist/design-system200.js.map +1 -0
- package/dist/design-system201.js +19 -5
- package/dist/design-system201.js.map +1 -1
- package/dist/design-system202.js +4 -119
- package/dist/design-system202.js.map +1 -1
- package/dist/design-system203.js +6 -0
- package/dist/design-system203.js.map +1 -0
- package/dist/design-system204.js +419 -5
- package/dist/design-system204.js.map +1 -1
- package/dist/design-system206.js +8 -0
- package/dist/design-system206.js.map +1 -0
- package/dist/design-system207.js +108 -5
- package/dist/design-system207.js.map +1 -1
- package/dist/design-system209.js +6 -4
- package/dist/design-system209.js.map +1 -1
- package/dist/design-system210.js +90 -154
- package/dist/design-system210.js.map +1 -1
- package/dist/design-system212.js +5 -4
- package/dist/design-system212.js.map +1 -1
- package/dist/design-system213.js +737 -7
- package/dist/design-system213.js.map +1 -1
- package/dist/design-system215.js +8 -0
- package/dist/design-system215.js.map +1 -0
- package/dist/design-system216.js +11 -5
- package/dist/design-system216.js.map +1 -1
- package/dist/design-system217.js +451 -506
- package/dist/design-system217.js.map +1 -1
- package/dist/design-system219.js +4 -5
- package/dist/design-system219.js.map +1 -1
- package/dist/design-system220.js +3 -7
- package/dist/design-system220.js.map +1 -1
- package/dist/design-system221.js +41 -369
- package/dist/design-system221.js.map +1 -1
- package/dist/design-system222.js +7 -0
- package/dist/design-system222.js.map +1 -0
- package/dist/design-system223.js +283 -6
- package/dist/design-system223.js.map +1 -1
- package/dist/design-system225.js +8 -0
- package/dist/design-system225.js.map +1 -0
- package/dist/design-system226.js +122 -0
- package/dist/design-system226.js.map +1 -0
- package/dist/design-system228.js +8 -0
- package/dist/design-system228.js.map +1 -0
- package/dist/{design-system205.js → design-system229.js} +1 -1
- package/dist/{design-system205.js.map → design-system229.js.map} +1 -1
- package/dist/design-system231.js +8 -0
- package/dist/design-system231.js.map +1 -0
- package/dist/{design-system208.js → design-system232.js} +1 -1
- package/dist/{design-system208.js.map → design-system232.js.map} +1 -1
- package/dist/design-system233.js +7 -0
- package/dist/design-system233.js.map +1 -0
- package/dist/design-system234.js +173 -0
- package/dist/design-system234.js.map +1 -0
- package/dist/design-system236.js +8 -0
- package/dist/design-system236.js.map +1 -0
- package/dist/design-system237.js +10 -0
- package/dist/design-system237.js.map +1 -0
- package/dist/{design-system214.js → design-system238.js} +2 -2
- package/dist/{design-system214.js.map → design-system238.js.map} +1 -1
- package/dist/design-system240.js +8 -0
- package/dist/design-system240.js.map +1 -0
- package/dist/design-system241.js +583 -0
- package/dist/design-system241.js.map +1 -0
- package/dist/design-system243.js +9 -0
- package/dist/design-system243.js.map +1 -0
- package/dist/design-system244.js +10 -0
- package/dist/design-system244.js.map +1 -0
- package/dist/design-system245.js +377 -0
- package/dist/design-system245.js.map +1 -0
- package/dist/design-system247.js +9 -0
- package/dist/design-system247.js.map +1 -0
- package/dist/types/components/BSkeleton/BSkeleton.spec.d.ts +1 -0
- package/dist/types/components/BSkeleton/BSkeleton.vue.d.ts +46 -0
- package/dist/types/components/BSkeleton/BSkeletonAvatar.vue.d.ts +12 -0
- package/dist/types/components/BSkeleton/BSkeletonButton.vue.d.ts +14 -0
- package/dist/types/components/BSkeleton/BSkeletonImage.vue.d.ts +7 -0
- package/dist/types/components/BSkeleton/BSkeletonInput.vue.d.ts +12 -0
- package/dist/types/components/BSkeleton/BSkeletonNode.vue.d.ts +19 -0
- package/dist/types/components/BSkeleton/index.d.ts +7 -0
- package/dist/types/components/BSkeleton/types.d.ts +20 -0
- package/dist/types/components/BSplitter/BSplitter.spec.d.ts +1 -0
- package/dist/types/components/BSplitter/BSplitter.vue.d.ts +45 -0
- package/dist/types/components/BSplitter/BSplitterPanel.vue.d.ts +40 -0
- package/dist/types/components/BSplitter/index.d.ts +3 -0
- package/dist/types/components/BSplitter/types.d.ts +42 -0
- package/dist/types/components/index.d.ts +2 -0
- package/package.json +1 -1
- package/dist/design-system193.js +0 -528
- package/dist/design-system193.js.map +0 -1
- package/dist/design-system196.js +0 -6
- package/dist/design-system196.js.map +0 -1
- package/dist/design-system199.js +0 -286
- package/dist/design-system199.js.map +0 -1
package/dist/design-system223.js
CHANGED
|
@@ -1,9 +1,286 @@
|
|
|
1
|
-
import e from "./design-
|
|
2
|
-
import t from "
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { BTabsContextKey as e } from "./design-system220.js";
|
|
2
|
+
import { Fragment as t, KeepAlive as n, computed as r, createBlock as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, defineComponent as l, h as ee, nextTick as u, normalizeClass as d, normalizeStyle as f, onMounted as p, openBlock as m, provide as h, ref as g, renderList as _, renderSlot as v, resolveDynamicComponent as y, toDisplayString as b, useId as x, vShow as S, watch as C, withDirectives as w, withModifiers as te } from "vue";
|
|
3
|
+
//#region src/components/BTabs/BTabs.vue?vue&type=script&setup=true&lang.ts
|
|
4
|
+
var ne = { class: "b-tabs__header" }, re = {
|
|
5
|
+
key: 0,
|
|
6
|
+
class: "b-tabs__extra b-tabs__extra--left"
|
|
7
|
+
}, ie = ["aria-orientation"], ae = [
|
|
8
|
+
"data-tab-key",
|
|
9
|
+
"aria-selected",
|
|
10
|
+
"aria-disabled",
|
|
11
|
+
"aria-controls",
|
|
12
|
+
"id",
|
|
13
|
+
"tabindex",
|
|
14
|
+
"onClick"
|
|
15
|
+
], T = { class: "b-tabs__tab-label" }, oe = ["onClick"], se = {
|
|
16
|
+
key: 2,
|
|
17
|
+
class: "b-tabs__extra b-tabs__extra--right"
|
|
18
|
+
}, ce = {
|
|
19
|
+
key: 0,
|
|
20
|
+
"aria-hidden": "true",
|
|
21
|
+
style: { display: "none" }
|
|
22
|
+
}, E = { class: "b-tabs__content" }, D = [
|
|
23
|
+
"id",
|
|
24
|
+
"aria-labelledby",
|
|
25
|
+
"tabindex",
|
|
26
|
+
"aria-hidden"
|
|
27
|
+
], O = [
|
|
28
|
+
"id",
|
|
29
|
+
"aria-labelledby",
|
|
30
|
+
"tabindex",
|
|
31
|
+
"aria-hidden"
|
|
32
|
+
], k = /* @__PURE__ */ l({
|
|
33
|
+
__name: "BTabs",
|
|
34
|
+
props: {
|
|
35
|
+
activeKey: {},
|
|
36
|
+
defaultActiveKey: {},
|
|
37
|
+
items: { default: () => [] },
|
|
38
|
+
type: { default: "line" },
|
|
39
|
+
placement: { default: "top" },
|
|
40
|
+
size: { default: "middle" },
|
|
41
|
+
centered: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: !1
|
|
44
|
+
},
|
|
45
|
+
animated: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: !0
|
|
48
|
+
},
|
|
49
|
+
hideAdd: {
|
|
50
|
+
type: Boolean,
|
|
51
|
+
default: !1
|
|
52
|
+
},
|
|
53
|
+
destroyOnHidden: {
|
|
54
|
+
type: Boolean,
|
|
55
|
+
default: !1
|
|
56
|
+
},
|
|
57
|
+
keepAlive: {
|
|
58
|
+
type: Boolean,
|
|
59
|
+
default: !1
|
|
60
|
+
},
|
|
61
|
+
tabBarGutter: {}
|
|
62
|
+
},
|
|
63
|
+
emits: [
|
|
64
|
+
"update:activeKey",
|
|
65
|
+
"change",
|
|
66
|
+
"tabClick",
|
|
67
|
+
"edit"
|
|
68
|
+
],
|
|
69
|
+
setup(k, { emit: A }) {
|
|
70
|
+
let j = A, M = x(), N = (e) => `${M}-tab-${e}`, P = (e) => `${M}-tabpanel-${e}`, F = g(/* @__PURE__ */ new Map()), I = g([]);
|
|
71
|
+
function L(e) {
|
|
72
|
+
F.value.set(e.key, e), I.value.includes(e.key) || (I.value = [...I.value, e.key]);
|
|
73
|
+
}
|
|
74
|
+
function R(e) {
|
|
75
|
+
F.value.delete(e), I.value = I.value.filter((t) => t !== e);
|
|
76
|
+
}
|
|
77
|
+
function z(e, t) {
|
|
78
|
+
F.value.set(e, t);
|
|
79
|
+
}
|
|
80
|
+
let B = r(() => k.items && k.items.length > 0), V = r(() => B.value ? k.items : I.value.map((e) => F.value.get(e)).filter((e) => e !== void 0).map((e) => ({
|
|
81
|
+
key: e.key,
|
|
82
|
+
label: e.label,
|
|
83
|
+
disabled: e.disabled,
|
|
84
|
+
closable: e.closable,
|
|
85
|
+
destroyOnHidden: e.destroyOnHidden,
|
|
86
|
+
forceRender: e.forceRender,
|
|
87
|
+
keepAlive: e.keepAlive
|
|
88
|
+
}))), H = r(() => k.activeKey !== void 0), U = r(() => V.value.find((e) => !e.disabled)?.key ?? V.value[0]?.key ?? ""), W = g(k.activeKey ?? k.defaultActiveKey ?? U.value);
|
|
89
|
+
C(() => k.activeKey, (e) => {
|
|
90
|
+
e !== void 0 && (W.value = e);
|
|
91
|
+
}), C(V, () => {
|
|
92
|
+
(W.value === void 0 || !V.value.find((e) => e.key === W.value)) && (W.value = U.value);
|
|
93
|
+
});
|
|
94
|
+
let G = r(() => H.value ? k.activeKey : W.value);
|
|
95
|
+
h(e, {
|
|
96
|
+
activeKey: G,
|
|
97
|
+
type: r(() => k.type),
|
|
98
|
+
size: r(() => k.size),
|
|
99
|
+
placement: r(() => k.placement),
|
|
100
|
+
keepAlive: r(() => k.keepAlive),
|
|
101
|
+
destroyOnHidden: r(() => k.destroyOnHidden),
|
|
102
|
+
register: L,
|
|
103
|
+
unregister: R,
|
|
104
|
+
update: z
|
|
105
|
+
});
|
|
106
|
+
function K(e, t) {
|
|
107
|
+
let n = V.value.find((t) => t.key === e);
|
|
108
|
+
!n || n.disabled || (t && j("tabClick", e, t), e !== G.value && (H.value || (W.value = e), j("update:activeKey", e), j("change", e)));
|
|
109
|
+
}
|
|
110
|
+
function le() {
|
|
111
|
+
j("edit", null, "add");
|
|
112
|
+
}
|
|
113
|
+
function ue(e, t) {
|
|
114
|
+
t.stopPropagation(), j("edit", e, "remove");
|
|
115
|
+
}
|
|
116
|
+
let q = g(null), J = g({});
|
|
117
|
+
function Y() {
|
|
118
|
+
if (!q.value || k.type !== "line") return;
|
|
119
|
+
let e = q.value.querySelector(".b-tabs__tab--active");
|
|
120
|
+
e && (k.placement === "left" || k.placement === "right" ? J.value = {
|
|
121
|
+
top: `${e.offsetTop}px`,
|
|
122
|
+
height: `${e.offsetHeight}px`
|
|
123
|
+
} : J.value = {
|
|
124
|
+
left: `${e.offsetLeft}px`,
|
|
125
|
+
width: `${e.offsetWidth}px`
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
C(G, async () => {
|
|
129
|
+
await u(), Y();
|
|
130
|
+
}), p(() => {
|
|
131
|
+
Y();
|
|
132
|
+
});
|
|
133
|
+
function de(e) {
|
|
134
|
+
let t = k.placement === "left" || k.placement === "right", n = t ? ["ArrowDown"] : ["ArrowRight"], r = t ? ["ArrowUp"] : ["ArrowLeft"];
|
|
135
|
+
if (e.key === "Delete" && k.type === "editable-card") {
|
|
136
|
+
let t = V.value.find((e) => e.key === G.value);
|
|
137
|
+
t && t.closable !== !1 && (e.preventDefault(), j("edit", G.value, "remove"));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if ([
|
|
141
|
+
...n,
|
|
142
|
+
...r,
|
|
143
|
+
"Home",
|
|
144
|
+
"End"
|
|
145
|
+
].includes(e.key)) {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
let t = V.value.filter((e) => !e.disabled);
|
|
148
|
+
if (t.length === 0) return;
|
|
149
|
+
let i = t.findIndex((e) => e.key === G.value), a;
|
|
150
|
+
a = n.includes(e.key) ? (i + 1) % t.length : r.includes(e.key) ? (i - 1 + t.length) % t.length : e.key === "Home" ? 0 : t.length - 1;
|
|
151
|
+
let o = t[a].key;
|
|
152
|
+
K(o), u(() => {
|
|
153
|
+
q.value && q.value.querySelector(`[data-tab-key="${o}"]`)?.focus();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
let X = g(new Set([G.value]));
|
|
158
|
+
C(G, (e) => {
|
|
159
|
+
X.value.add(e);
|
|
160
|
+
});
|
|
161
|
+
function Z(e) {
|
|
162
|
+
return e.destroyOnHidden ? !1 : e.keepAlive === void 0 ? k.destroyOnHidden ? !1 : k.keepAlive : e.keepAlive;
|
|
163
|
+
}
|
|
164
|
+
function fe(e) {
|
|
165
|
+
return e.forceRender || Z(e) ? !0 : e.destroyOnHidden ?? k.destroyOnHidden ? e.key === G.value : X.value.has(e.key);
|
|
166
|
+
}
|
|
167
|
+
let Q = r(() => {
|
|
168
|
+
let e = {};
|
|
169
|
+
for (let t of V.value) Z(t) && (e[t.key] = l({
|
|
170
|
+
name: `BTabPanel_${t.key}`,
|
|
171
|
+
setup() {
|
|
172
|
+
return () => {
|
|
173
|
+
let e = F.value.get(t.key);
|
|
174
|
+
return e ? e.renderContent() : null;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}));
|
|
178
|
+
return e;
|
|
179
|
+
});
|
|
180
|
+
function pe(e) {
|
|
181
|
+
return F.value.get(e)?.renderContent() ?? [];
|
|
182
|
+
}
|
|
183
|
+
function $(e) {
|
|
184
|
+
return F.value.get(e)?.renderLabel?.();
|
|
185
|
+
}
|
|
186
|
+
let me = r(() => [
|
|
187
|
+
"b-tabs",
|
|
188
|
+
`b-tabs--${k.type}`,
|
|
189
|
+
`b-tabs--${k.placement}`,
|
|
190
|
+
`b-tabs--${k.size}`,
|
|
191
|
+
{ "b-tabs--centered": k.centered }
|
|
192
|
+
]), he = r(() => k.tabBarGutter === void 0 ? void 0 : { gap: `${k.tabBarGutter}px` });
|
|
193
|
+
return (e, r) => (m(), o("div", { class: d(me.value) }, [
|
|
194
|
+
s("div", ne, [
|
|
195
|
+
e.$slots.leftExtra ? (m(), o("div", re, [v(e.$slots, "leftExtra")])) : a("", !0),
|
|
196
|
+
s("div", {
|
|
197
|
+
ref_key: "tabListRef",
|
|
198
|
+
ref: q,
|
|
199
|
+
class: "b-tabs__list",
|
|
200
|
+
role: "tablist",
|
|
201
|
+
"aria-orientation": k.placement === "left" || k.placement === "right" ? "vertical" : "horizontal",
|
|
202
|
+
style: f(he.value)
|
|
203
|
+
}, [(m(!0), o(t, null, _(V.value, (n) => (m(), o("div", {
|
|
204
|
+
key: n.key,
|
|
205
|
+
"data-tab-key": n.key,
|
|
206
|
+
class: d(["b-tabs__tab", {
|
|
207
|
+
"b-tabs__tab--active": n.key === G.value,
|
|
208
|
+
"b-tabs__tab--disabled": n.disabled
|
|
209
|
+
}]),
|
|
210
|
+
role: "tab",
|
|
211
|
+
"aria-selected": n.key === G.value,
|
|
212
|
+
"aria-disabled": n.disabled || void 0,
|
|
213
|
+
"aria-controls": P(n.key),
|
|
214
|
+
id: N(n.key),
|
|
215
|
+
tabindex: n.key === G.value ? 0 : -1,
|
|
216
|
+
onClick: (e) => !n.disabled && K(n.key, e),
|
|
217
|
+
onKeydown: de
|
|
218
|
+
}, [s("span", T, [B.value ? v(e.$slots, "label", {
|
|
219
|
+
key: 0,
|
|
220
|
+
item: n,
|
|
221
|
+
active: n.key === G.value
|
|
222
|
+
}, () => [c(b(n.label), 1)]) : (m(), o(t, { key: 1 }, [$(n.key) ? (m(), i(y(() => ee("span", $(n.key))), { key: 0 })) : (m(), o(t, { key: 1 }, [c(b(n.label), 1)], 64))], 64))]), k.type === "editable-card" && n.closable !== !1 ? (m(), o("span", {
|
|
223
|
+
key: 0,
|
|
224
|
+
class: "b-tabs__tab-remove",
|
|
225
|
+
"aria-hidden": "true",
|
|
226
|
+
onClick: te((e) => ue(n.key, e), ["stop"])
|
|
227
|
+
}, [v(e.$slots, "removeIcon", { item: n }, () => [r[0] ||= s("svg", {
|
|
228
|
+
viewBox: "0 0 16 16",
|
|
229
|
+
fill: "currentColor",
|
|
230
|
+
class: "b-tabs__close-icon"
|
|
231
|
+
}, [s("path", { d: "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" })], -1)])], 8, oe)) : a("", !0)], 42, ae))), 128)), k.type === "line" ? (m(), o("div", {
|
|
232
|
+
key: 0,
|
|
233
|
+
class: "b-tabs__ink-bar",
|
|
234
|
+
"aria-hidden": "true",
|
|
235
|
+
style: f(J.value)
|
|
236
|
+
}, null, 4)) : a("", !0)], 12, ie),
|
|
237
|
+
k.type === "editable-card" && !k.hideAdd ? (m(), o("button", {
|
|
238
|
+
key: 1,
|
|
239
|
+
class: "b-tabs__add",
|
|
240
|
+
"aria-label": "Add tab",
|
|
241
|
+
onClick: le
|
|
242
|
+
}, [v(e.$slots, "addIcon", {}, () => [r[1] ||= s("svg", {
|
|
243
|
+
viewBox: "0 0 16 16",
|
|
244
|
+
fill: "currentColor",
|
|
245
|
+
"aria-hidden": "true",
|
|
246
|
+
class: "b-tabs__add-icon"
|
|
247
|
+
}, [s("path", { d: "M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" })], -1)])])) : a("", !0),
|
|
248
|
+
e.$slots.rightExtra ? (m(), o("div", se, [v(e.$slots, "rightExtra")])) : a("", !0)
|
|
249
|
+
]),
|
|
250
|
+
B.value ? a("", !0) : w((m(), o("div", ce, [v(e.$slots, "default")], 512)), [[S, !1]]),
|
|
251
|
+
s("div", E, [(m(!0), o(t, null, _(V.value, (r) => (m(), o(t, { key: r.key }, [Z(r) ? w((m(), o("div", {
|
|
252
|
+
key: 0,
|
|
253
|
+
id: P(r.key),
|
|
254
|
+
class: d(["b-tabs__panel", {
|
|
255
|
+
"b-tabs__panel--active": r.key === G.value,
|
|
256
|
+
"b-tabs__panel--animated": k.animated
|
|
257
|
+
}]),
|
|
258
|
+
role: "tabpanel",
|
|
259
|
+
"aria-labelledby": N(r.key),
|
|
260
|
+
tabindex: r.key === G.value ? 0 : -1,
|
|
261
|
+
"aria-hidden": r.key !== G.value
|
|
262
|
+
}, [B.value ? a("", !0) : (m(), i(n, { key: 0 }, [r.key === G.value ? (m(), i(y(Q.value[r.key] ?? (() => null)), { key: r.key })) : a("", !0)], 1024)), B.value ? v(e.$slots, "default", {
|
|
263
|
+
key: 1,
|
|
264
|
+
item: r
|
|
265
|
+
}) : a("", !0)], 10, D)), [[S, r.key === G.value]]) : fe(r) ? w((m(), o("div", {
|
|
266
|
+
key: 1,
|
|
267
|
+
id: P(r.key),
|
|
268
|
+
class: d(["b-tabs__panel", {
|
|
269
|
+
"b-tabs__panel--active": r.key === G.value,
|
|
270
|
+
"b-tabs__panel--animated": k.animated
|
|
271
|
+
}]),
|
|
272
|
+
role: "tabpanel",
|
|
273
|
+
"aria-labelledby": N(r.key),
|
|
274
|
+
tabindex: r.key === G.value ? 0 : -1,
|
|
275
|
+
"aria-hidden": r.key !== G.value
|
|
276
|
+
}, [B.value ? v(e.$slots, "default", {
|
|
277
|
+
key: 0,
|
|
278
|
+
item: r
|
|
279
|
+
}) : (m(), i(y(() => pe(r.key)), { key: 1 }))], 10, O)), [[S, r.key === G.value]]) : a("", !0)], 64))), 128))])
|
|
280
|
+
], 2));
|
|
281
|
+
}
|
|
282
|
+
});
|
|
6
283
|
//#endregion
|
|
7
|
-
export {
|
|
284
|
+
export { k as default };
|
|
8
285
|
|
|
9
286
|
//# sourceMappingURL=design-system223.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-system223.js","names":[],"sources":["../src/components/BUpload/BUpload.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { ref, computed, watch, onMounted, useAttrs } from 'vue';\nimport { useComponentId } from '@/composables/useComponentId';\nimport {\n BUploadListType,\n BUploadFileStatus,\n type BUploadFile,\n type BUploadChangeInfo,\n type BUploadRequestOption,\n type BUploadShowUploadList,\n} from './types';\n\ndefineOptions({ inheritAttrs: false });\n\nconst attrs = useAttrs();\n\n//#region Props\nconst {\n accept = '',\n action = '',\n multiple = false,\n disabled = false,\n directory = false,\n maxCount,\n listType = BUploadListType.Text,\n method = 'POST',\n name: fieldName = 'file',\n headers,\n data,\n withCredentials = false,\n openFileDialogOnClick = true,\n showUploadList = true,\n defaultFileList = [],\n beforeUpload,\n customRequest,\n} = defineProps<{\n /** File types that can be accepted (MIME types or extensions). */\n accept?: string;\n /** Uploading URL. */\n action?: string | ((file: File) => Promise<string>);\n /** Whether to support multiple file selection. */\n multiple?: boolean;\n /** Whether to disable the upload button. */\n disabled?: boolean;\n /** Support uploading directories. */\n directory?: boolean;\n /** Limit the number of uploaded files. */\n maxCount?: number;\n /** Built-in style of the upload list. */\n listType?: BUploadListType | `${BUploadListType}`;\n /** HTTP method for upload request. */\n method?: string;\n /** The name of the file field in the upload request. */\n name?: string;\n /** Custom request headers for upload. */\n headers?: Record<string, string>;\n /** Extra data to include with the upload request. */\n data?: Record<string, unknown> | ((file: BUploadFile) => Record<string, unknown>);\n /** Whether to send cookies with the request. */\n withCredentials?: boolean;\n /** Whether clicking the component opens the file dialog. */\n openFileDialogOnClick?: boolean;\n /** Whether to show the upload list. */\n showUploadList?: boolean | BUploadShowUploadList;\n /** Initial file list for uncontrolled usage. */\n defaultFileList?: BUploadFile[];\n /** Hook before uploading. Return false or a rejected Promise to stop. */\n beforeUpload?: (file: File, fileList: File[]) => boolean | Promise<File | Blob | boolean | void>;\n /** Override the default upload behavior. */\n customRequest?: (options: BUploadRequestOption) => void;\n}>();\n//#endregion\n\n//#region Model & Events\nconst model = defineModel<BUploadFile[]>('fileList', { default: undefined });\n\nconst emit = defineEmits<{\n change: [info: BUploadChangeInfo];\n remove: [file: BUploadFile];\n preview: [file: BUploadFile];\n download: [file: BUploadFile];\n drop: [event: DragEvent];\n}>();\n//#endregion\n\n//#region Internal State\nconst { componentUID } = useComponentId();\nconst inputRef = ref<HTMLInputElement | null>(null);\nconst dragOver = ref(false);\nconst internalFileList = ref<BUploadFile[]>(Array.isArray(defaultFileList) ? [...defaultFileList] : []);\n\nconst fileList = computed<BUploadFile[]>({\n get: () => (model.value !== undefined ? model.value : internalFileList.value),\n set: (val) => {\n internalFileList.value = val;\n if (model.value !== undefined) {\n model.value = val;\n }\n },\n});\n\nonMounted(() => {\n if (model.value === undefined && defaultFileList.length > 0) {\n internalFileList.value = [...defaultFileList];\n }\n});\n\nwatch(\n () => model.value,\n (val) => {\n if (val !== undefined) {\n internalFileList.value = val;\n }\n },\n);\n\nconst isPictureCard = computed(\n () =>\n listType === BUploadListType.PictureCard ||\n listType === BUploadListType.PictureCircle,\n);\n\nconst showListConfig = computed<BUploadShowUploadList | false>(() => {\n if (showUploadList === false) return false;\n if (showUploadList === true) {\n return { showPreviewIcon: true, showRemoveIcon: true, showDownloadIcon: false };\n }\n return showUploadList;\n});\n\nconst atMaxCount = computed(() => maxCount !== undefined && maxCount !== 1 && fileList.value.length >= maxCount);\n//#endregion\n\n//#region Upload Logic\nlet fileUidCounter = 0;\n\nfunction genUid(): string {\n fileUidCounter += 1;\n return `b-upload-${componentUID.value}-${fileUidCounter}-${Date.now()}`;\n}\n\nfunction fileToUploadFile(file: File): BUploadFile {\n return {\n uid: genUid(),\n name: file.name,\n size: file.size,\n type: file.type,\n status: BUploadFileStatus.Uploading,\n percent: 0,\n originFileObj: file,\n };\n}\n\nfunction triggerChange(file: BUploadFile, newFileList: BUploadFile[], event?: ProgressEvent) {\n fileList.value = newFileList;\n emit('change', { file, fileList: newFileList, event });\n}\n\nfunction defaultUpload(options: BUploadRequestOption) {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable && options.onProgress) {\n options.onProgress({ percent: Math.round((e.loaded / e.total) * 100) });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n options.onSuccess?.(xhr.response);\n } else {\n options.onError?.(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n options.onError?.(new Error('Upload network error'));\n });\n\n xhr.open(options.method || 'POST', options.action, true);\n\n if (options.withCredentials) {\n xhr.withCredentials = true;\n }\n\n if (options.headers) {\n Object.entries(options.headers).forEach(([key, val]) => {\n xhr.setRequestHeader(key, val);\n });\n }\n\n const formData = new FormData();\n if (options.data) {\n Object.entries(options.data).forEach(([key, val]) => {\n formData.append(key, val as string);\n });\n }\n formData.append(options.filename, options.file);\n\n xhr.send(formData);\n}\n\nasync function uploadFile(file: File, rawFiles: File[]) {\n if (beforeUpload) {\n try {\n const result = await beforeUpload(file, rawFiles);\n if (result === false) return;\n if (result instanceof Blob) {\n const transformed = result instanceof File ? result : new File([result], file.name, { type: result.type });\n processUpload(transformed);\n return;\n }\n } catch {\n return;\n }\n }\n processUpload(file);\n}\n\nfunction processUpload(file: File) {\n const uploadFile = fileToUploadFile(file);\n let newList: BUploadFile[];\n\n if (maxCount === 1) {\n newList = [uploadFile];\n } else if (maxCount !== undefined) {\n newList = [...fileList.value, uploadFile].slice(-maxCount);\n } else {\n newList = [...fileList.value, uploadFile];\n }\n\n triggerChange(uploadFile, newList);\n\n const resolvedAction = typeof action === 'function' ? action(file) : Promise.resolve(action);\n\n resolvedAction.then((url: string) => {\n const requestFn = customRequest || defaultUpload;\n const extraData = typeof data === 'function' ? data(uploadFile) : (data || {});\n\n requestFn({\n action: url,\n file,\n filename: fieldName,\n headers,\n data: extraData,\n withCredentials,\n method,\n onProgress: (e) => {\n const updatedFile = { ...uploadFile, percent: e.percent };\n const updatedList = fileList.value.map((f) =>\n f.uid === uploadFile.uid ? updatedFile : f,\n );\n triggerChange(updatedFile, updatedList);\n },\n onSuccess: (response) => {\n const updatedFile = {\n ...uploadFile,\n status: BUploadFileStatus.Done,\n percent: 100,\n response,\n };\n const updatedList = fileList.value.map((f) =>\n f.uid === uploadFile.uid ? updatedFile : f,\n );\n triggerChange(updatedFile, updatedList);\n },\n onError: (error) => {\n const updatedFile = {\n ...uploadFile,\n status: BUploadFileStatus.Error,\n error,\n };\n const updatedList = fileList.value.map((f) =>\n f.uid === uploadFile.uid ? updatedFile : f,\n );\n triggerChange(updatedFile, updatedList);\n },\n });\n });\n}\n\nfunction handleFiles(files: FileList | null) {\n if (!files || files.length === 0) return;\n\n const rawFiles = Array.from(files);\n let filesToUpload: File[];\n\n if (maxCount === 1) {\n filesToUpload = rawFiles.slice(0, 1);\n } else if (maxCount !== undefined) {\n const remaining = maxCount - fileList.value.length;\n filesToUpload = remaining > 0 ? rawFiles.slice(0, remaining) : [];\n } else {\n filesToUpload = rawFiles;\n }\n\n filesToUpload.forEach((file) => uploadFile(file, rawFiles));\n}\n//#endregion\n\n//#region Event Handlers\nfunction handleClick() {\n if (disabled || !openFileDialogOnClick || atMaxCount.value) return;\n inputRef.value?.click();\n}\n\nfunction handleKeyDown(event: KeyboardEvent) {\n if (disabled || atMaxCount.value) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n inputRef.value?.click();\n }\n}\n\nfunction handleInputChange(event: Event) {\n const input = event.target as HTMLInputElement;\n handleFiles(input.files);\n input.value = '';\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault();\n if (disabled) return;\n dragOver.value = true;\n}\n\nfunction handleDragLeave(event: DragEvent) {\n event.preventDefault();\n dragOver.value = false;\n}\n\nfunction handleDrop(event: DragEvent) {\n event.preventDefault();\n dragOver.value = false;\n if (disabled) return;\n emit('drop', event);\n handleFiles(event.dataTransfer?.files ?? null);\n}\n\nfunction handleRemove(file: BUploadFile) {\n emit('remove', file);\n const newList = fileList.value.filter((f) => f.uid !== file.uid);\n triggerChange({ ...file, status: BUploadFileStatus.Removed }, newList);\n}\n\nfunction handlePreview(file: BUploadFile) {\n emit('preview', file);\n}\n\nfunction handleDownload(file: BUploadFile) {\n emit('download', file);\n}\n//#endregion\n\n//#region Expose\ndefineExpose({\n /** Open the native file dialog programmatically. */\n openFileDialog: () => inputRef.value?.click(),\n});\n//#endregion\n</script>\n\n<template>\n <div\n class=\"b-upload\"\n :class=\"{\n 'b-upload--disabled': disabled,\n 'b-upload--drag-over': dragOver,\n [`b-upload--${listType}`]: true,\n }\"\n >\n <!-- Upload trigger area -->\n <div\n v-if=\"!isPictureCard || !atMaxCount\"\n class=\"b-upload__trigger\"\n role=\"button\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-disabled=\"disabled || undefined\"\n :aria-label=\"(attrs['aria-label'] as string) || 'Upload file'\"\n @click=\"handleClick\"\n @keydown=\"handleKeyDown\"\n @dragover=\"handleDragOver\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop\"\n >\n <slot>\n <div v-if=\"isPictureCard\" class=\"b-upload__card-trigger\">\n <span class=\"b-upload__plus-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </span>\n <span class=\"b-upload__card-text\">Upload</span>\n </div>\n <span v-else class=\"b-upload__default-text\">Click to Upload</span>\n </slot>\n </div>\n\n <!-- Hidden file input -->\n <input\n ref=\"inputRef\"\n class=\"b-upload__input\"\n type=\"file\"\n :accept=\"accept || undefined\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n :webkitdirectory=\"directory || undefined\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n @change=\"handleInputChange\"\n />\n\n <!-- File list -->\n <div\n v-if=\"showListConfig !== false && fileList.length > 0\"\n class=\"b-upload__list\"\n :class=\"`b-upload__list--${listType}`\"\n role=\"list\"\n aria-label=\"Uploaded files\"\n >\n <div\n v-for=\"file in fileList\"\n :key=\"file.uid\"\n class=\"b-upload__item\"\n :class=\"{\n 'b-upload__item--error': file.status === BUploadFileStatus.Error,\n 'b-upload__item--done': file.status === BUploadFileStatus.Done,\n 'b-upload__item--uploading': file.status === BUploadFileStatus.Uploading,\n }\"\n role=\"listitem\"\n >\n <!-- Thumbnail for picture types -->\n <span\n v-if=\"listType !== BUploadListType.Text\"\n class=\"b-upload__item-thumbnail\"\n aria-hidden=\"true\"\n >\n <img\n v-if=\"file.thumbUrl || file.url\"\n :src=\"file.thumbUrl || file.url\"\n :alt=\"file.name\"\n class=\"b-upload__item-image\"\n />\n <span v-else class=\"b-upload__item-file-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z\" />\n <polyline points=\"14,2 14,8 20,8\" />\n </svg>\n </span>\n </span>\n\n <!-- File info -->\n <span class=\"b-upload__item-info\">\n <span class=\"b-upload__item-name\" :title=\"file.name\">\n {{ file.name }}\n </span>\n </span>\n\n <!-- Actions -->\n <span class=\"b-upload__item-actions\">\n <button\n v-if=\"showListConfig && showListConfig.showPreviewIcon && (file.url || file.thumbUrl)\"\n class=\"b-upload__action-btn\"\n type=\"button\"\n aria-label=\"Preview file\"\n @click.stop=\"handlePreview(file)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n </button>\n <button\n v-if=\"showListConfig && showListConfig.showDownloadIcon && file.status === BUploadFileStatus.Done\"\n class=\"b-upload__action-btn\"\n type=\"button\"\n aria-label=\"Download file\"\n @click.stop=\"handleDownload(file)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\" />\n <polyline points=\"7,10 12,15 17,10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n <button\n v-if=\"showListConfig && showListConfig.showRemoveIcon\"\n class=\"b-upload__action-btn b-upload__action-btn--remove\"\n type=\"button\"\n aria-label=\"Remove file\"\n :disabled=\"disabled\"\n @click.stop=\"handleRemove(file)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </span>\n\n <!-- Progress bar -->\n <div\n v-if=\"file.status === BUploadFileStatus.Uploading\"\n class=\"b-upload__progress\"\n role=\"progressbar\"\n :aria-valuenow=\"file.percent ?? 0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n :aria-label=\"`Uploading ${file.name}`\"\n >\n <div\n class=\"b-upload__progress-bar\"\n :style=\"{ width: `${file.percent ?? 0}%` }\"\n />\n </div>\n </div>\n </div>\n\n <!-- Hint slot -->\n <div v-if=\"$slots.hint\" class=\"b-upload__hint\">\n <slot name=\"hint\" />\n </div>\n </div>\n</template>\n\n<style scoped>\n.b-upload {\n --b-upload-actions-color: rgba(0, 0, 0, 0.45);\n --b-upload-card-size: 102px;\n --b-upload-color-primary: #1677ff;\n --b-upload-color-error: #d32f2f;\n --b-upload-color-success: #52c41a;\n --b-upload-color-border: #d9d9d9;\n --b-upload-color-bg: #fafafa;\n --b-upload-color-bg-hover: #f0f0f0;\n --b-upload-color-text: rgba(0, 0, 0, 0.88);\n --b-upload-color-text-secondary: rgba(0, 0, 0, 0.6);\n --b-upload-border-radius: 8px;\n --b-upload-line-height: 1.5715;\n --b-upload-font-size: 14px;\n --b-upload-progress-stroke-width: 2px;\n\n position: relative;\n font-size: var(--b-upload-font-size);\n line-height: var(--b-upload-line-height);\n color: var(--b-upload-color-text);\n}\n\n/* Picture-card/circle layout: root becomes flex container */\n.b-upload--picture-card,\n.b-upload--picture-circle {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n align-items: flex-start;\n}\n\n/* Hidden file input */\n.b-upload__input {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n/* Trigger */\n.b-upload__trigger {\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n outline: none;\n border-radius: var(--b-upload-border-radius);\n}\n\n.b-upload__trigger:focus-visible {\n outline: 2px solid var(--b-upload-color-primary);\n outline-offset: 2px;\n}\n\n.b-upload--disabled .b-upload__trigger {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Default text trigger */\n.b-upload__default-text {\n padding: 4px 15px;\n border: 1px solid var(--b-upload-color-border);\n border-radius: var(--b-upload-border-radius);\n background: #fff;\n color: var(--b-upload-color-text);\n transition: border-color 0.2s, color 0.2s;\n}\n\n.b-upload__trigger:hover .b-upload__default-text {\n color: var(--b-upload-color-primary);\n border-color: var(--b-upload-color-primary);\n}\n\n/* Picture card trigger */\n.b-upload--picture-card .b-upload__trigger,\n.b-upload--picture-circle .b-upload__trigger {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: var(--b-upload-card-size);\n height: var(--b-upload-card-size);\n border: 1px dashed var(--b-upload-color-border);\n border-radius: var(--b-upload-border-radius);\n background: var(--b-upload-color-bg);\n transition: border-color 0.2s;\n}\n\n.b-upload--picture-circle .b-upload__trigger {\n border-radius: 50%;\n}\n\n.b-upload--picture-card .b-upload__trigger:hover,\n.b-upload--picture-circle .b-upload__trigger:hover {\n border-color: var(--b-upload-color-primary);\n}\n\n.b-upload__card-trigger {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n color: var(--b-upload-color-text-secondary);\n}\n\n.b-upload__plus-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.b-upload__plus-icon svg {\n width: 20px;\n height: 20px;\n}\n\n.b-upload__card-text {\n font-size: var(--b-upload-font-size);\n}\n\n/* Drag states */\n.b-upload--drag-over .b-upload__trigger {\n border-color: var(--b-upload-color-primary);\n background: color-mix(in srgb, var(--b-upload-color-primary) 5%, transparent);\n}\n\n/* File list - text type */\n.b-upload__list {\n margin-top: 8px;\n}\n\n.b-upload__list--text .b-upload__item,\n.b-upload__list--picture .b-upload__item {\n display: flex;\n align-items: center;\n padding: 4px 8px;\n border-radius: var(--b-upload-border-radius);\n transition: background-color 0.2s;\n position: relative;\n}\n\n.b-upload__list--text .b-upload__item:hover,\n.b-upload__list--picture .b-upload__item:hover {\n background: var(--b-upload-color-bg);\n}\n\n/* File list - picture-card type */\n.b-upload__list--picture-card,\n.b-upload__list--picture-circle {\n display: contents;\n}\n\n.b-upload__list--picture-card .b-upload__item,\n.b-upload__list--picture-circle .b-upload__item {\n position: relative;\n width: var(--b-upload-card-size);\n height: var(--b-upload-card-size);\n border: 1px solid var(--b-upload-color-border);\n border-radius: var(--b-upload-border-radius);\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.b-upload__list--picture-circle .b-upload__item {\n border-radius: 50%;\n}\n\n/* Thumbnails */\n.b-upload__item-thumbnail {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n margin-right: 8px;\n}\n\n.b-upload__list--picture-card .b-upload__item-thumbnail,\n.b-upload__list--picture-circle .b-upload__item-thumbnail {\n width: 100%;\n height: 100%;\n margin-right: 0;\n}\n\n.b-upload__item-image {\n max-width: 100%;\n max-height: 100%;\n object-fit: cover;\n}\n\n.b-upload__item-file-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--b-upload-color-text-secondary);\n}\n\n.b-upload__item-file-icon svg {\n width: 24px;\n height: 24px;\n}\n\n/* File info */\n.b-upload__item-info {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.b-upload__item-name {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--b-upload-color-text);\n transition: color 0.2s;\n}\n\n.b-upload__item--error .b-upload__item-name {\n color: var(--b-upload-color-error);\n}\n\n/* For card mode, hide file info text */\n.b-upload__list--picture-card .b-upload__item-info,\n.b-upload__list--picture-circle .b-upload__item-info {\n display: none;\n}\n\n/* Actions */\n.b-upload__item-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-left: 8px;\n}\n\n.b-upload__list--picture-card .b-upload__item-actions,\n.b-upload__list--picture-circle .b-upload__item-actions {\n position: absolute;\n inset: 0;\n margin-left: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s;\n}\n\n.b-upload__list--picture-card .b-upload__item:hover .b-upload__item-actions,\n.b-upload__list--picture-circle .b-upload__item:hover .b-upload__item-actions {\n opacity: 1;\n}\n\n.b-upload__action-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--b-upload-actions-color);\n transition: color 0.2s;\n}\n\n.b-upload__action-btn:hover {\n color: var(--b-upload-color-primary);\n}\n\n.b-upload__action-btn--remove:hover {\n color: var(--b-upload-color-error);\n}\n\n.b-upload__action-btn:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.b-upload__action-btn svg {\n width: 16px;\n height: 16px;\n}\n\n.b-upload__list--picture-card .b-upload__action-btn,\n.b-upload__list--picture-circle .b-upload__action-btn {\n color: rgba(255, 255, 255, 0.85);\n}\n\n.b-upload__list--picture-card .b-upload__action-btn svg,\n.b-upload__list--picture-circle .b-upload__action-btn svg {\n width: 24px;\n height: 24px;\n}\n\n.b-upload__list--picture-card .b-upload__action-btn:hover,\n.b-upload__list--picture-circle .b-upload__action-btn:hover {\n color: #fff;\n}\n\n/* Progress bar */\n.b-upload__progress {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: var(--b-upload-progress-stroke-width);\n background: var(--b-upload-color-bg-hover);\n overflow: hidden;\n}\n\n.b-upload__progress-bar {\n height: 100%;\n background: var(--b-upload-color-primary);\n transition: width 0.2s;\n}\n\n/* Hint */\n.b-upload__hint {\n margin-top: 8px;\n color: var(--b-upload-color-text-secondary);\n font-size: 12px;\n}\n\n/* Dark mode - explicit */\n[data-prefers-color='dark'] .b-upload {\n --b-upload-actions-color: rgba(255, 255, 255, 0.45);\n --b-upload-color-border: #424242;\n --b-upload-color-bg: #1f1f1f;\n --b-upload-color-bg-hover: #2f2f2f;\n --b-upload-color-text: rgba(255, 255, 255, 0.85);\n --b-upload-color-text-secondary: rgba(255, 255, 255, 0.6);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-upload {\n --b-upload-actions-color: rgba(255, 255, 255, 0.45);\n --b-upload-color-border: #424242;\n --b-upload-color-bg: #1f1f1f;\n --b-upload-color-bg-hover: #2f2f2f;\n --b-upload-color-text: rgba(255, 255, 255, 0.85);\n --b-upload-color-text-secondary: rgba(255, 255, 255, 0.6);\n }\n}\n\n/* Dark mode - follow system (only when no explicit preference is set) */\n@media (prefers-color-scheme: dark) {\n :root:not([data-prefers-color]) .b-upload {\n --b-upload-actions-color: rgba(255, 255, 255, 0.45);\n --b-upload-color-border: #424242;\n --b-upload-color-bg: #1f1f1f;\n --b-upload-color-bg-hover: #2f2f2f;\n --b-upload-color-text: rgba(255, 255, 255, 0.85);\n --b-upload-color-text-secondary: rgba(255, 255, 255, 0.6);\n }\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n .b-upload__trigger,\n .b-upload__default-text,\n .b-upload__item-name,\n .b-upload__action-btn,\n .b-upload__progress-bar,\n .b-upload__item-actions,\n .b-upload__list--text .b-upload__item,\n .b-upload__list--picture .b-upload__item {\n transition: none;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"design-system223.js","names":[],"sources":["../src/components/BTabs/BTabs.vue?vue&type=script&setup=true&lang.ts"],"sourcesContent":["import { defineComponent as _defineComponent } from 'vue'\nimport { renderSlot as _renderSlot, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, renderList as _renderList, Fragment as _Fragment, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, resolveDynamicComponent as _resolveDynamicComponent, createBlock as _createBlock, createElementVNode as _createElementVNode, withModifiers as _withModifiers, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, vShow as _vShow, withDirectives as _withDirectives, KeepAlive as _KeepAlive } from \"vue\"\n\nconst _hoisted_1 = { class: \"b-tabs__header\" }\nconst _hoisted_2 = {\n key: 0,\n class: \"b-tabs__extra b-tabs__extra--left\"\n}\nconst _hoisted_3 = [\"aria-orientation\"]\nconst _hoisted_4 = [\"data-tab-key\", \"aria-selected\", \"aria-disabled\", \"aria-controls\", \"id\", \"tabindex\", \"onClick\"]\nconst _hoisted_5 = { class: \"b-tabs__tab-label\" }\nconst _hoisted_6 = [\"onClick\"]\nconst _hoisted_7 = {\n key: 2,\n class: \"b-tabs__extra b-tabs__extra--right\"\n}\nconst _hoisted_8 = {\n key: 0,\n \"aria-hidden\": \"true\",\n style: {\"display\":\"none\"}\n}\nconst _hoisted_9 = { class: \"b-tabs__content\" }\nconst _hoisted_10 = [\"id\", \"aria-labelledby\", \"tabindex\", \"aria-hidden\"]\nconst _hoisted_11 = [\"id\", \"aria-labelledby\", \"tabindex\", \"aria-hidden\"]\n\nimport type { Component, VNode } from 'vue';\nimport { computed, defineComponent, h, nextTick, onMounted, provide, ref, useId, watch } from 'vue';\n\nimport type {\n BTabItem,\n BTabPaneRegistration,\n BTabsContext,\n BTabsPlacement,\n BTabsSize,\n BTabsType,\n} from './types';\nimport { BTabsContextKey } from './types';\n\n// ─────────────────────────────────────────────\n// Props\n// ─────────────────────────────────────────────\n\nexport default /*@__PURE__*/_defineComponent({\n __name: 'BTabs',\n props: {\n activeKey: {},\n defaultActiveKey: {},\n items: { default: () => ([]) },\n type: { default: 'line' },\n placement: { default: 'top' },\n size: { default: 'middle' },\n centered: { type: Boolean, default: false },\n animated: { type: Boolean, default: true },\n hideAdd: { type: Boolean, default: false },\n destroyOnHidden: { type: Boolean, default: false },\n keepAlive: { type: Boolean, default: false },\n tabBarGutter: {}\n },\n emits: [\"update:activeKey\", \"change\", \"tabClick\", \"edit\"],\n setup(__props: any, { emit: __emit }) {\n\n\n\n// ─────────────────────────────────────────────\n// Emits\n// ─────────────────────────────────────────────\nconst emit = __emit;\n\n// ─────────────────────────────────────────────\n// Slots\n// ─────────────────────────────────────────────\n\n\n// ─────────────────────────────────────────────\n// Instance-scoped ID prefix (prevents duplicate IDs when multiple BTabs on page)\n// ─────────────────────────────────────────────\nconst uid = useId();\nconst tabId = (key: string) => `${uid}-tab-${key}`;\nconst panelId = (key: string) => `${uid}-tabpanel-${key}`;\n\n// ─────────────────────────────────────────────\n// Pane registry (for BTabPane child component API)\n// ─────────────────────────────────────────────\nconst paneRegistry = ref(new Map<string, BTabPaneRegistration>());\nconst paneOrder = ref<string[]>([]);\n\nfunction registerPane(pane: BTabPaneRegistration) {\n paneRegistry.value.set(pane.key, pane);\n if (!paneOrder.value.includes(pane.key)) {\n paneOrder.value = [...paneOrder.value, pane.key];\n }\n}\n\nfunction unregisterPane(key: string) {\n paneRegistry.value.delete(key);\n paneOrder.value = paneOrder.value.filter((k) => k !== key);\n}\n\nfunction updatePane(key: string, pane: BTabPaneRegistration) {\n paneRegistry.value.set(key, pane);\n}\n\n// ─────────────────────────────────────────────\n// Mode detection + effective items\n// ─────────────────────────────────────────────\nconst isItemsMode = computed(() => __props.items && __props.items.length > 0);\n\nconst effectiveItems = computed<BTabItem[]>(() => {\n if (isItemsMode.value) return __props.items;\n return paneOrder.value\n .map((key) => paneRegistry.value.get(key))\n .filter((p): p is BTabPaneRegistration => p !== undefined)\n .map((pane) => ({\n key: pane.key,\n label: pane.label,\n disabled: pane.disabled,\n closable: pane.closable,\n destroyOnHidden: pane.destroyOnHidden,\n forceRender: pane.forceRender,\n keepAlive: pane.keepAlive,\n }));\n});\n\n// ─────────────────────────────────────────────\n// Internal state\n// ─────────────────────────────────────────────\nconst isControlled = computed(() => __props.activeKey !== undefined);\n\nconst firstEnabledKey = computed(\n () => effectiveItems.value.find((i) => !i.disabled)?.key ?? effectiveItems.value[0]?.key ?? '',\n);\n\nconst internalKey = ref<string>(__props.activeKey ?? __props.defaultActiveKey ?? firstEnabledKey.value);\n\nwatch(\n () => __props.activeKey,\n (val) => {\n if (val !== undefined) internalKey.value = val;\n },\n);\n\nwatch(effectiveItems, () => {\n if (\n internalKey.value === undefined ||\n !effectiveItems.value.find((i) => i.key === internalKey.value)\n ) {\n internalKey.value = firstEnabledKey.value;\n }\n});\n\nconst currentKey = computed(() => (isControlled.value ? __props.activeKey! : internalKey.value));\n\n// ─────────────────────────────────────────────\n// Provide context to BTabPane children\n// ─────────────────────────────────────────────\nconst context: BTabsContext = {\n activeKey: currentKey,\n type: computed(() => __props.type),\n size: computed(() => __props.size),\n placement: computed(() => __props.placement),\n keepAlive: computed(() => __props.keepAlive),\n destroyOnHidden: computed(() => __props.destroyOnHidden),\n register: registerPane,\n unregister: unregisterPane,\n update: updatePane,\n};\n\nprovide(BTabsContextKey, context);\n\n// ─────────────────────────────────────────────\n// Tab activation\n// ─────────────────────────────────────────────\nfunction activateTab(key: string, event?: MouseEvent) {\n const item = effectiveItems.value.find((i) => i.key === key);\n if (!item || item.disabled) return;\n\n if (event) {\n emit('tabClick', key, event);\n }\n\n if (key === currentKey.value) return;\n\n if (!isControlled.value) {\n internalKey.value = key;\n }\n emit('update:activeKey', key);\n emit('change', key);\n}\n\n// ─────────────────────────────────────────────\n// Editable-card actions\n// ─────────────────────────────────────────────\nfunction onAdd() {\n emit('edit', null, 'add');\n}\n\nfunction onRemove(key: string, event: MouseEvent) {\n event.stopPropagation();\n emit('edit', key, 'remove');\n}\n\n// ─────────────────────────────────────────────\n// Ink bar positioning\n// ─────────────────────────────────────────────\nconst tabListRef = ref<HTMLElement | null>(null);\nconst inkBarStyle = ref<Record<string, string>>({});\n\nfunction updateInkBar() {\n if (!tabListRef.value || __props.type !== 'line') return;\n const activeEl = tabListRef.value.querySelector<HTMLElement>('.b-tabs__tab--active');\n if (!activeEl) return;\n\n const isVertical = __props.placement === 'left' || __props.placement === 'right';\n\n if (isVertical) {\n inkBarStyle.value = {\n top: `${activeEl.offsetTop}px`,\n height: `${activeEl.offsetHeight}px`,\n };\n } else {\n inkBarStyle.value = {\n left: `${activeEl.offsetLeft}px`,\n width: `${activeEl.offsetWidth}px`,\n };\n }\n}\n\nwatch(currentKey, async () => {\n await nextTick();\n updateInkBar();\n});\n\nonMounted(() => {\n updateInkBar();\n});\n\n// ─────────────────────────────────────────────\n// Keyboard navigation (roving tabindex)\n// ─────────────────────────────────────────────\nfunction onKeydown(event: KeyboardEvent) {\n const isVertical = __props.placement === 'left' || __props.placement === 'right';\n const nextKeys = isVertical ? ['ArrowDown'] : ['ArrowRight'];\n const prevKeys = isVertical ? ['ArrowUp'] : ['ArrowLeft'];\n\n // Delete key closes the active tab in editable-card mode\n if (event.key === 'Delete' && __props.type === 'editable-card') {\n const item = effectiveItems.value.find((i) => i.key === currentKey.value);\n if (item && item.closable !== false) {\n event.preventDefault();\n emit('edit', currentKey.value, 'remove');\n }\n return;\n }\n\n if ([...nextKeys, ...prevKeys, 'Home', 'End'].includes(event.key)) {\n event.preventDefault();\n const enabledItems = effectiveItems.value.filter((i) => !i.disabled);\n if (enabledItems.length === 0) return;\n\n const currentIdx = enabledItems.findIndex((i) => i.key === currentKey.value);\n\n let targetIdx: number;\n if (nextKeys.includes(event.key)) {\n targetIdx = (currentIdx + 1) % enabledItems.length;\n } else if (prevKeys.includes(event.key)) {\n targetIdx = (currentIdx - 1 + enabledItems.length) % enabledItems.length;\n } else if (event.key === 'Home') {\n targetIdx = 0;\n } else {\n targetIdx = enabledItems.length - 1;\n }\n\n const targetKey = enabledItems[targetIdx].key;\n activateTab(targetKey);\n\n nextTick(() => {\n if (!tabListRef.value) return;\n const targetEl = tabListRef.value.querySelector<HTMLElement>(`[data-tab-key=\"${targetKey}\"]`);\n targetEl?.focus();\n });\n }\n}\n\n// ─────────────────────────────────────────────\n// KeepAlive + content visibility\n// ─────────────────────────────────────────────\nconst renderedKeys = ref<Set<string>>(new Set([currentKey.value]));\n\nwatch(currentKey, (key) => {\n renderedKeys.value.add(key);\n});\n\nfunction shouldUseKeepAlive(item: BTabItem): boolean {\n if (item.destroyOnHidden) return false;\n if (item.keepAlive !== undefined) return item.keepAlive;\n if (__props.destroyOnHidden) return false;\n return __props.keepAlive;\n}\n\nfunction shouldRender(item: BTabItem): boolean {\n if (item.forceRender) return true;\n if (shouldUseKeepAlive(item)) return true;\n const itemDestroy = item.destroyOnHidden ?? __props.destroyOnHidden;\n if (itemDestroy) return item.key === currentKey.value;\n return renderedKeys.value.has(item.key);\n}\n\n// ─────────────────────────────────────────────\n// KeepAlive panel wrapper components\n// ─────────────────────────────────────────────\nconst panelWrappers = computed<Record<string, Component>>(() => {\n const wrappers: Record<string, Component> = {};\n for (const item of effectiveItems.value) {\n if (!shouldUseKeepAlive(item)) continue;\n wrappers[item.key] = defineComponent({\n name: `BTabPanel_${item.key}`,\n setup() {\n return () => {\n const pane = paneRegistry.value.get(item.key);\n if (pane) {\n return pane.renderContent();\n }\n return null;\n };\n },\n });\n }\n return wrappers;\n});\n\nfunction getPaneContent(key: string): VNode[] {\n const pane = paneRegistry.value.get(key);\n return pane?.renderContent() ?? [];\n}\n\nfunction getPaneLabel(key: string): VNode[] | undefined {\n const pane = paneRegistry.value.get(key);\n return pane?.renderLabel?.();\n}\n\n// ─────────────────────────────────────────────\n// Computed classes\n// ─────────────────────────────────────────────\nconst rootClasses = computed(() => [\n 'b-tabs',\n `b-tabs--${__props.type}`,\n `b-tabs--${__props.placement}`,\n `b-tabs--${__props.size}`,\n { 'b-tabs--centered': __props.centered },\n]);\n\nconst tabBarGutterStyle = computed(() =>\n __props.tabBarGutter !== undefined ? { gap: `${__props.tabBarGutter}px` } : undefined,\n);\n\nreturn (_ctx: any,_cache: any) => {\n return (_openBlock(), _createElementBlock(\"div\", {\n class: _normalizeClass(rootClasses.value)\n }, [\n _createElementVNode(\"div\", _hoisted_1, [\n (_ctx.$slots.leftExtra)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_2, [\n _renderSlot(_ctx.$slots, \"leftExtra\")\n ]))\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", {\n ref_key: \"tabListRef\",\n ref: tabListRef,\n class: \"b-tabs__list\",\n role: \"tablist\",\n \"aria-orientation\": \n __props.placement === 'left' || __props.placement === 'right' ? 'vertical' : 'horizontal'\n ,\n style: _normalizeStyle(tabBarGutterStyle.value)\n }, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(effectiveItems.value, (item) => {\n return (_openBlock(), _createElementBlock(\"div\", {\n key: item.key,\n \"data-tab-key\": item.key,\n class: _normalizeClass([\"b-tabs__tab\", {\n 'b-tabs__tab--active': item.key === currentKey.value,\n 'b-tabs__tab--disabled': item.disabled,\n }]),\n role: \"tab\",\n \"aria-selected\": item.key === currentKey.value,\n \"aria-disabled\": item.disabled || undefined,\n \"aria-controls\": panelId(item.key),\n id: tabId(item.key),\n tabindex: item.key === currentKey.value ? 0 : -1,\n onClick: ($event: any) => (!item.disabled && activateTab(item.key, $event)),\n onKeydown: onKeydown\n }, [\n _createElementVNode(\"span\", _hoisted_5, [\n (isItemsMode.value)\n ? _renderSlot(_ctx.$slots, \"label\", {\n key: 0,\n item: item,\n active: item.key === currentKey.value\n }, () => [\n _createTextVNode(_toDisplayString(item.label), 1)\n ])\n : (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [\n (getPaneLabel(item.key))\n ? (_openBlock(), _createBlock(_resolveDynamicComponent(() => h('span', getPaneLabel(item.key)!)), { key: 0 }))\n : (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [\n _createTextVNode(_toDisplayString(item.label), 1)\n ], 64))\n ], 64))\n ]),\n (__props.type === 'editable-card' && item.closable !== false)\n ? (_openBlock(), _createElementBlock(\"span\", {\n key: 0,\n class: \"b-tabs__tab-remove\",\n \"aria-hidden\": \"true\",\n onClick: _withModifiers(($event: any) => (onRemove(item.key, $event)), [\"stop\"])\n }, [\n _renderSlot(_ctx.$slots, \"removeIcon\", { item: item }, () => [\n _cache[0] || (_cache[0] = _createElementVNode(\"svg\", {\n viewBox: \"0 0 16 16\",\n fill: \"currentColor\",\n class: \"b-tabs__close-icon\"\n }, [\n _createElementVNode(\"path\", { d: \"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\" })\n ], -1))\n ])\n ], 8, _hoisted_6))\n : _createCommentVNode(\"\", true)\n ], 42, _hoisted_4))\n }), 128)),\n (__props.type === 'line')\n ? (_openBlock(), _createElementBlock(\"div\", {\n key: 0,\n class: \"b-tabs__ink-bar\",\n \"aria-hidden\": \"true\",\n style: _normalizeStyle(inkBarStyle.value)\n }, null, 4))\n : _createCommentVNode(\"\", true)\n ], 12, _hoisted_3),\n (__props.type === 'editable-card' && !__props.hideAdd)\n ? (_openBlock(), _createElementBlock(\"button\", {\n key: 1,\n class: \"b-tabs__add\",\n \"aria-label\": \"Add tab\",\n onClick: onAdd\n }, [\n _renderSlot(_ctx.$slots, \"addIcon\", {}, () => [\n _cache[1] || (_cache[1] = _createElementVNode(\"svg\", {\n viewBox: \"0 0 16 16\",\n fill: \"currentColor\",\n \"aria-hidden\": \"true\",\n class: \"b-tabs__add-icon\"\n }, [\n _createElementVNode(\"path\", { d: \"M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z\" })\n ], -1))\n ])\n ]))\n : _createCommentVNode(\"\", true),\n (_ctx.$slots.rightExtra)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_7, [\n _renderSlot(_ctx.$slots, \"rightExtra\")\n ]))\n : _createCommentVNode(\"\", true)\n ]),\n (!isItemsMode.value)\n ? _withDirectives((_openBlock(), _createElementBlock(\"div\", _hoisted_8, [\n _renderSlot(_ctx.$slots, \"default\")\n ], 512)), [\n [_vShow, false]\n ])\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", _hoisted_9, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(effectiveItems.value, (item) => {\n return (_openBlock(), _createElementBlock(_Fragment, {\n key: item.key\n }, [\n (shouldUseKeepAlive(item))\n ? _withDirectives((_openBlock(), _createElementBlock(\"div\", {\n key: 0,\n id: panelId(item.key),\n class: _normalizeClass([\"b-tabs__panel\", {\n 'b-tabs__panel--active': item.key === currentKey.value,\n 'b-tabs__panel--animated': __props.animated,\n }]),\n role: \"tabpanel\",\n \"aria-labelledby\": tabId(item.key),\n tabindex: item.key === currentKey.value ? 0 : -1,\n \"aria-hidden\": item.key !== currentKey.value\n }, [\n (!isItemsMode.value)\n ? (_openBlock(), _createBlock(_KeepAlive, { key: 0 }, [\n (item.key === currentKey.value)\n ? (_openBlock(), _createBlock(_resolveDynamicComponent(panelWrappers.value[item.key] ?? (() => null)), {\n key: item.key\n }))\n : _createCommentVNode(\"\", true)\n ], 1024))\n : _createCommentVNode(\"\", true),\n (isItemsMode.value)\n ? _renderSlot(_ctx.$slots, \"default\", {\n key: 1,\n item: item\n })\n : _createCommentVNode(\"\", true)\n ], 10, _hoisted_10)), [\n [_vShow, item.key === currentKey.value]\n ])\n : (shouldRender(item))\n ? _withDirectives((_openBlock(), _createElementBlock(\"div\", {\n key: 1,\n id: panelId(item.key),\n class: _normalizeClass([\"b-tabs__panel\", {\n 'b-tabs__panel--active': item.key === currentKey.value,\n 'b-tabs__panel--animated': __props.animated,\n }]),\n role: \"tabpanel\",\n \"aria-labelledby\": tabId(item.key),\n tabindex: item.key === currentKey.value ? 0 : -1,\n \"aria-hidden\": item.key !== currentKey.value\n }, [\n (isItemsMode.value)\n ? _renderSlot(_ctx.$slots, \"default\", {\n key: 0,\n item: item\n })\n : (_openBlock(), _createBlock(_resolveDynamicComponent(() => getPaneContent(item.key)), { key: 1 }))\n ], 10, _hoisted_11)), [\n [_vShow, item.key === currentKey.value]\n ])\n : _createCommentVNode(\"\", true)\n ], 64))\n }), 128))\n ])\n ], 2))\n}\n}\n\n})"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-system225.js","names":[],"sources":["../src/components/BTabs/BTabs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Component, VNode } from 'vue';\nimport { computed, defineComponent, h, nextTick, onMounted, provide, ref, useId, watch } from 'vue';\n\nimport type {\n BTabItem,\n BTabPaneRegistration,\n BTabsContext,\n BTabsPlacement,\n BTabsSize,\n BTabsType,\n} from './types';\nimport { BTabsContextKey } from './types';\n\n// ─────────────────────────────────────────────\n// Props\n// ─────────────────────────────────────────────\nconst {\n activeKey,\n defaultActiveKey,\n items = [],\n type = 'line',\n placement = 'top',\n size = 'middle',\n centered = false,\n animated = true,\n hideAdd = false,\n destroyOnHidden = false,\n keepAlive = false,\n tabBarGutter,\n} = defineProps<{\n /** Current active tab key (controlled via v-model:activeKey). */\n activeKey?: string;\n /** Initial active tab key for uncontrolled mode. @default first non-disabled tab */\n defaultActiveKey?: string;\n /** Tab items configuration. When provided and non-empty, BTabPane children are ignored. */\n items?: BTabItem[];\n /** Visual style of the tabs. @default 'line' */\n type?: BTabsType;\n /** Position of the tab bar. @default 'top' */\n placement?: BTabsPlacement;\n /** Size preset for the tab bar. @default 'middle' */\n size?: BTabsSize;\n /** Whether to center the tab items. @default false */\n centered?: boolean;\n /** Whether content switching is animated. @default true */\n animated?: boolean;\n /** Whether to hide the add button in editable-card mode. @default false */\n hideAdd?: boolean;\n /** Whether to destroy inactive tab content globally. @default false */\n destroyOnHidden?: boolean;\n /** Whether to keep component state alive when switching tabs globally. @default false */\n keepAlive?: boolean;\n /** Gap between tabs in pixels. */\n tabBarGutter?: number;\n}>();\n\n// ─────────────────────────────────────────────\n// Emits\n// ─────────────────────────────────────────────\nconst emit = defineEmits<{\n /** Fires when the active tab changes. */\n (e: 'update:activeKey', key: string): void;\n /** Fires when the active tab changes (alias for update:activeKey). */\n (e: 'change', key: string): void;\n /** Fires when a tab is clicked. */\n (e: 'tabClick', key: string, event: MouseEvent): void;\n /** Fires when a tab is added or removed (editable-card only). */\n (e: 'edit', key: string | null, action: 'add' | 'remove'): void;\n}>();\n\n// ─────────────────────────────────────────────\n// Slots\n// ─────────────────────────────────────────────\ndefineSlots<{\n /** Items mode: receives { item } scoped prop. Pane mode: contains BTabPane children (no props). */\n default?: (props: { item?: BTabItem }) => unknown;\n /** Custom label renderer for each tab (items mode). */\n label?: (props: { item: BTabItem; active: boolean }) => unknown;\n /** Extra content on the left side of the tab bar. */\n leftExtra?: () => unknown;\n /** Extra content on the right side of the tab bar. */\n rightExtra?: () => unknown;\n /** Custom add button (editable-card type). */\n addIcon?: () => unknown;\n /** Custom remove/close icon (editable-card type). */\n removeIcon?: (props: { item: BTabItem }) => unknown;\n}>();\n\n// ─────────────────────────────────────────────\n// Instance-scoped ID prefix (prevents duplicate IDs when multiple BTabs on page)\n// ─────────────────────────────────────────────\nconst uid = useId();\nconst tabId = (key: string) => `${uid}-tab-${key}`;\nconst panelId = (key: string) => `${uid}-tabpanel-${key}`;\n\n// ─────────────────────────────────────────────\n// Pane registry (for BTabPane child component API)\n// ─────────────────────────────────────────────\nconst paneRegistry = ref(new Map<string, BTabPaneRegistration>());\nconst paneOrder = ref<string[]>([]);\n\nfunction registerPane(pane: BTabPaneRegistration) {\n paneRegistry.value.set(pane.key, pane);\n if (!paneOrder.value.includes(pane.key)) {\n paneOrder.value = [...paneOrder.value, pane.key];\n }\n}\n\nfunction unregisterPane(key: string) {\n paneRegistry.value.delete(key);\n paneOrder.value = paneOrder.value.filter((k) => k !== key);\n}\n\nfunction updatePane(key: string, pane: BTabPaneRegistration) {\n paneRegistry.value.set(key, pane);\n}\n\n// ─────────────────────────────────────────────\n// Mode detection + effective items\n// ─────────────────────────────────────────────\nconst isItemsMode = computed(() => items && items.length > 0);\n\nconst effectiveItems = computed<BTabItem[]>(() => {\n if (isItemsMode.value) return items;\n return paneOrder.value\n .map((key) => paneRegistry.value.get(key))\n .filter((p): p is BTabPaneRegistration => p !== undefined)\n .map((pane) => ({\n key: pane.key,\n label: pane.label,\n disabled: pane.disabled,\n closable: pane.closable,\n destroyOnHidden: pane.destroyOnHidden,\n forceRender: pane.forceRender,\n keepAlive: pane.keepAlive,\n }));\n});\n\n// ─────────────────────────────────────────────\n// Internal state\n// ─────────────────────────────────────────────\nconst isControlled = computed(() => activeKey !== undefined);\n\nconst firstEnabledKey = computed(\n () => effectiveItems.value.find((i) => !i.disabled)?.key ?? effectiveItems.value[0]?.key ?? '',\n);\n\nconst internalKey = ref<string>(activeKey ?? defaultActiveKey ?? firstEnabledKey.value);\n\nwatch(\n () => activeKey,\n (val) => {\n if (val !== undefined) internalKey.value = val;\n },\n);\n\nwatch(effectiveItems, () => {\n if (\n internalKey.value === undefined ||\n !effectiveItems.value.find((i) => i.key === internalKey.value)\n ) {\n internalKey.value = firstEnabledKey.value;\n }\n});\n\nconst currentKey = computed(() => (isControlled.value ? activeKey! : internalKey.value));\n\n// ─────────────────────────────────────────────\n// Provide context to BTabPane children\n// ─────────────────────────────────────────────\nconst context: BTabsContext = {\n activeKey: currentKey,\n type: computed(() => type),\n size: computed(() => size),\n placement: computed(() => placement),\n keepAlive: computed(() => keepAlive),\n destroyOnHidden: computed(() => destroyOnHidden),\n register: registerPane,\n unregister: unregisterPane,\n update: updatePane,\n};\n\nprovide(BTabsContextKey, context);\n\n// ─────────────────────────────────────────────\n// Tab activation\n// ─────────────────────────────────────────────\nfunction activateTab(key: string, event?: MouseEvent) {\n const item = effectiveItems.value.find((i) => i.key === key);\n if (!item || item.disabled) return;\n\n if (event) {\n emit('tabClick', key, event);\n }\n\n if (key === currentKey.value) return;\n\n if (!isControlled.value) {\n internalKey.value = key;\n }\n emit('update:activeKey', key);\n emit('change', key);\n}\n\n// ─────────────────────────────────────────────\n// Editable-card actions\n// ─────────────────────────────────────────────\nfunction onAdd() {\n emit('edit', null, 'add');\n}\n\nfunction onRemove(key: string, event: MouseEvent) {\n event.stopPropagation();\n emit('edit', key, 'remove');\n}\n\n// ─────────────────────────────────────────────\n// Ink bar positioning\n// ─────────────────────────────────────────────\nconst tabListRef = ref<HTMLElement | null>(null);\nconst inkBarStyle = ref<Record<string, string>>({});\n\nfunction updateInkBar() {\n if (!tabListRef.value || type !== 'line') return;\n const activeEl = tabListRef.value.querySelector<HTMLElement>('.b-tabs__tab--active');\n if (!activeEl) return;\n\n const isVertical = placement === 'left' || placement === 'right';\n\n if (isVertical) {\n inkBarStyle.value = {\n top: `${activeEl.offsetTop}px`,\n height: `${activeEl.offsetHeight}px`,\n };\n } else {\n inkBarStyle.value = {\n left: `${activeEl.offsetLeft}px`,\n width: `${activeEl.offsetWidth}px`,\n };\n }\n}\n\nwatch(currentKey, async () => {\n await nextTick();\n updateInkBar();\n});\n\nonMounted(() => {\n updateInkBar();\n});\n\n// ─────────────────────────────────────────────\n// Keyboard navigation (roving tabindex)\n// ─────────────────────────────────────────────\nfunction onKeydown(event: KeyboardEvent) {\n const isVertical = placement === 'left' || placement === 'right';\n const nextKeys = isVertical ? ['ArrowDown'] : ['ArrowRight'];\n const prevKeys = isVertical ? ['ArrowUp'] : ['ArrowLeft'];\n\n // Delete key closes the active tab in editable-card mode\n if (event.key === 'Delete' && type === 'editable-card') {\n const item = effectiveItems.value.find((i) => i.key === currentKey.value);\n if (item && item.closable !== false) {\n event.preventDefault();\n emit('edit', currentKey.value, 'remove');\n }\n return;\n }\n\n if ([...nextKeys, ...prevKeys, 'Home', 'End'].includes(event.key)) {\n event.preventDefault();\n const enabledItems = effectiveItems.value.filter((i) => !i.disabled);\n if (enabledItems.length === 0) return;\n\n const currentIdx = enabledItems.findIndex((i) => i.key === currentKey.value);\n\n let targetIdx: number;\n if (nextKeys.includes(event.key)) {\n targetIdx = (currentIdx + 1) % enabledItems.length;\n } else if (prevKeys.includes(event.key)) {\n targetIdx = (currentIdx - 1 + enabledItems.length) % enabledItems.length;\n } else if (event.key === 'Home') {\n targetIdx = 0;\n } else {\n targetIdx = enabledItems.length - 1;\n }\n\n const targetKey = enabledItems[targetIdx].key;\n activateTab(targetKey);\n\n nextTick(() => {\n if (!tabListRef.value) return;\n const targetEl = tabListRef.value.querySelector<HTMLElement>(`[data-tab-key=\"${targetKey}\"]`);\n targetEl?.focus();\n });\n }\n}\n\n// ─────────────────────────────────────────────\n// KeepAlive + content visibility\n// ─────────────────────────────────────────────\nconst renderedKeys = ref<Set<string>>(new Set([currentKey.value]));\n\nwatch(currentKey, (key) => {\n renderedKeys.value.add(key);\n});\n\nfunction shouldUseKeepAlive(item: BTabItem): boolean {\n if (item.destroyOnHidden) return false;\n if (item.keepAlive !== undefined) return item.keepAlive;\n if (destroyOnHidden) return false;\n return keepAlive;\n}\n\nfunction shouldRender(item: BTabItem): boolean {\n if (item.forceRender) return true;\n if (shouldUseKeepAlive(item)) return true;\n const itemDestroy = item.destroyOnHidden ?? destroyOnHidden;\n if (itemDestroy) return item.key === currentKey.value;\n return renderedKeys.value.has(item.key);\n}\n\n// ─────────────────────────────────────────────\n// KeepAlive panel wrapper components\n// ─────────────────────────────────────────────\nconst panelWrappers = computed<Record<string, Component>>(() => {\n const wrappers: Record<string, Component> = {};\n for (const item of effectiveItems.value) {\n if (!shouldUseKeepAlive(item)) continue;\n wrappers[item.key] = defineComponent({\n name: `BTabPanel_${item.key}`,\n setup() {\n return () => {\n const pane = paneRegistry.value.get(item.key);\n if (pane) {\n return pane.renderContent();\n }\n return null;\n };\n },\n });\n }\n return wrappers;\n});\n\nfunction getPaneContent(key: string): VNode[] {\n const pane = paneRegistry.value.get(key);\n return pane?.renderContent() ?? [];\n}\n\nfunction getPaneLabel(key: string): VNode[] | undefined {\n const pane = paneRegistry.value.get(key);\n return pane?.renderLabel?.();\n}\n\n// ─────────────────────────────────────────────\n// Computed classes\n// ─────────────────────────────────────────────\nconst rootClasses = computed(() => [\n 'b-tabs',\n `b-tabs--${type}`,\n `b-tabs--${placement}`,\n `b-tabs--${size}`,\n { 'b-tabs--centered': centered },\n]);\n\nconst tabBarGutterStyle = computed(() =>\n tabBarGutter !== undefined ? { gap: `${tabBarGutter}px` } : undefined,\n);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <!-- Tab bar -->\n <div class=\"b-tabs__header\">\n <div v-if=\"$slots.leftExtra\" class=\"b-tabs__extra b-tabs__extra--left\">\n <slot name=\"leftExtra\" />\n </div>\n\n <div\n ref=\"tabListRef\"\n class=\"b-tabs__list\"\n role=\"tablist\"\n :aria-orientation=\"\n placement === 'left' || placement === 'right' ? 'vertical' : 'horizontal'\n \"\n :style=\"tabBarGutterStyle\"\n >\n <div\n v-for=\"item in effectiveItems\"\n :key=\"item.key\"\n :data-tab-key=\"item.key\"\n class=\"b-tabs__tab\"\n :class=\"{\n 'b-tabs__tab--active': item.key === currentKey,\n 'b-tabs__tab--disabled': item.disabled,\n }\"\n role=\"tab\"\n :aria-selected=\"item.key === currentKey\"\n :aria-disabled=\"item.disabled || undefined\"\n :aria-controls=\"panelId(item.key)\"\n :id=\"tabId(item.key)\"\n :tabindex=\"item.key === currentKey ? 0 : -1\"\n @click=\"!item.disabled && activateTab(item.key, $event)\"\n @keydown=\"onKeydown\"\n >\n <span class=\"b-tabs__tab-label\">\n <!-- Items mode: use label slot or item.label -->\n <template v-if=\"isItemsMode\">\n <slot name=\"label\" :item=\"item\" :active=\"item.key === currentKey\">\n {{ item.label }}\n </slot>\n </template>\n <!-- Pane mode: use pane's renderLabel or label string -->\n <template v-else>\n <component\n v-if=\"getPaneLabel(item.key)\"\n :is=\"() => h('span', getPaneLabel(item.key)!)\"\n />\n <template v-else>{{ item.label }}</template>\n </template>\n </span>\n <span\n v-if=\"type === 'editable-card' && item.closable !== false\"\n class=\"b-tabs__tab-remove\"\n aria-hidden=\"true\"\n @click.stop=\"onRemove(item.key, $event)\"\n >\n <slot name=\"removeIcon\" :item=\"item\">\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"b-tabs__close-icon\">\n <path\n d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"\n />\n </svg>\n </slot>\n </span>\n </div>\n\n <!-- Ink bar (line type only) -->\n <div\n v-if=\"type === 'line'\"\n class=\"b-tabs__ink-bar\"\n aria-hidden=\"true\"\n :style=\"inkBarStyle\"\n />\n </div>\n\n <!-- Add button (outside tablist to avoid aria-required-children violation) -->\n <button\n v-if=\"type === 'editable-card' && !hideAdd\"\n class=\"b-tabs__add\"\n aria-label=\"Add tab\"\n @click=\"onAdd\"\n >\n <slot name=\"addIcon\">\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\" class=\"b-tabs__add-icon\">\n <path\n d=\"M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z\"\n />\n </svg>\n </slot>\n </button>\n\n <div v-if=\"$slots.rightExtra\" class=\"b-tabs__extra b-tabs__extra--right\">\n <slot name=\"rightExtra\" />\n </div>\n </div>\n\n <!-- Hidden slot area for BTabPane registration (pane mode only) -->\n <div v-if=\"!isItemsMode\" v-show=\"false\" aria-hidden=\"true\" style=\"display: none\">\n <slot />\n </div>\n\n <!-- Tab panels -->\n <div class=\"b-tabs__content\">\n <template v-for=\"item in effectiveItems\" :key=\"item.key\">\n <!-- KeepAlive panels -->\n <div\n v-if=\"shouldUseKeepAlive(item)\"\n :id=\"panelId(item.key)\"\n class=\"b-tabs__panel\"\n :class=\"{\n 'b-tabs__panel--active': item.key === currentKey,\n 'b-tabs__panel--animated': animated,\n }\"\n role=\"tabpanel\"\n :aria-labelledby=\"tabId(item.key)\"\n :tabindex=\"item.key === currentKey ? 0 : -1\"\n :aria-hidden=\"item.key !== currentKey\"\n v-show=\"item.key === currentKey\"\n >\n <!-- Pane mode: KeepAlive caches wrapper component instances -->\n <KeepAlive v-if=\"!isItemsMode\">\n <component\n v-if=\"item.key === currentKey\"\n :is=\"panelWrappers[item.key] ?? (() => null)\"\n :key=\"item.key\"\n />\n </KeepAlive>\n <!-- Items mode: always render slot content; v-show on parent preserves state -->\n <template v-if=\"isItemsMode\">\n <slot :item=\"item\" />\n </template>\n </div>\n\n <!-- Standard panels (no KeepAlive) -->\n <div\n v-else-if=\"shouldRender(item)\"\n v-show=\"item.key === currentKey\"\n :id=\"panelId(item.key)\"\n class=\"b-tabs__panel\"\n :class=\"{\n 'b-tabs__panel--active': item.key === currentKey,\n 'b-tabs__panel--animated': animated,\n }\"\n role=\"tabpanel\"\n :aria-labelledby=\"tabId(item.key)\"\n :tabindex=\"item.key === currentKey ? 0 : -1\"\n :aria-hidden=\"item.key !== currentKey\"\n >\n <!-- Items mode: scoped slot -->\n <template v-if=\"isItemsMode\">\n <slot :item=\"item\" />\n </template>\n <!-- Pane mode: render registered content -->\n <component v-else :is=\"() => getPaneContent(item.key)\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style>\n/* ─────────────────────────────────────────────\n BTabs - Design tokens (scoped to .b-tabs)\n ───────────────────────────────────────────── */\n.b-tabs {\n --b-tabs-ink-bar-color: oklch(54.6% 0.245 262.881);\n --b-tabs-item-active-color: oklch(35% 0.2 260);\n --b-tabs-item-color: oklch(30% 0.02 260 / 88%);\n --b-tabs-item-hover-color: oklch(54.6% 0.245 262.881);\n --b-tabs-item-selected-color: oklch(54.6% 0.245 262.881);\n --b-tabs-item-disabled-color: oklch(30% 0.02 260 / 25%);\n --b-tabs-title-font-size: 14px;\n --b-tabs-title-font-size-lg: 16px;\n --b-tabs-title-font-size-sm: 14px;\n --b-tabs-card-bg: oklch(97% 0.003 260 / 50%);\n --b-tabs-card-height: 40px;\n --b-tabs-card-height-lg: 48px;\n --b-tabs-card-height-sm: 32px;\n --b-tabs-card-padding: 8px 16px;\n --b-tabs-card-padding-lg: 11px 16px;\n --b-tabs-card-padding-sm: 4px 8px;\n --b-tabs-card-gutter: 2px;\n --b-tabs-card-border-radius: 8px 8px 0 0;\n --b-tabs-horizontal-item-gutter: 32px;\n --b-tabs-horizontal-item-padding: 12px 0;\n --b-tabs-horizontal-item-padding-lg: 16px 0;\n --b-tabs-horizontal-item-padding-sm: 8px 0;\n --b-tabs-horizontal-margin: 0 0 16px 0;\n --b-tabs-vertical-item-margin: 16px 0 0 0;\n --b-tabs-vertical-item-padding: 8px 24px;\n --b-tabs-border-color: oklch(80% 0.005 260);\n --b-tabs-content-min-height: 0;\n --b-tabs-focus-ring: 0 0 0 2px oklch(54.6% 0.245 262.881 / 20%);\n --b-tabs-transition-duration: 200ms;\n\n display: flex;\n flex-direction: column;\n font-size: var(--b-tabs-title-font-size);\n line-height: 1.5;\n}\n\n/* ── Placement layouts ── */\n.b-tabs--left {\n flex-direction: row;\n}\n\n.b-tabs--right {\n flex-direction: row-reverse;\n}\n\n.b-tabs--bottom {\n flex-direction: column-reverse;\n}\n\n/* ── Size variants ── */\n.b-tabs--large {\n --b-tabs-title-font-size: var(--b-tabs-title-font-size-lg);\n}\n\n.b-tabs--small {\n --b-tabs-title-font-size: var(--b-tabs-title-font-size-sm);\n}\n\n/* ─────────────────────────────────────────────\n Header\n ───────────────────────────────────────────── */\n.b-tabs__header {\n display: flex;\n align-items: center;\n position: relative;\n flex-shrink: 0;\n}\n\n.b-tabs--top .b-tabs__header,\n.b-tabs--bottom .b-tabs__header {\n border-bottom: 1px solid var(--b-tabs-border-color);\n margin: var(--b-tabs-horizontal-margin);\n}\n\n.b-tabs--bottom .b-tabs__header {\n border-bottom: none;\n border-top: 1px solid var(--b-tabs-border-color);\n margin: 0;\n}\n\n.b-tabs--left .b-tabs__header,\n.b-tabs--right .b-tabs__header {\n flex-direction: column;\n align-items: stretch;\n border-right: 1px solid var(--b-tabs-border-color);\n margin: 0;\n}\n\n.b-tabs--right .b-tabs__header {\n border-right: none;\n border-left: 1px solid var(--b-tabs-border-color);\n}\n\n/* Card type removes border from header */\n.b-tabs--card .b-tabs__header,\n.b-tabs--editable-card .b-tabs__header {\n border-bottom: 1px solid var(--b-tabs-border-color);\n}\n\n/* ─────────────────────────────────────────────\n Tab list (roving tabindex container)\n ───────────────────────────────────────────── */\n.b-tabs__list {\n display: flex;\n position: relative;\n flex: 1;\n gap: var(--b-tabs-horizontal-item-gutter);\n}\n\n.b-tabs--centered .b-tabs__list {\n justify-content: center;\n}\n\n.b-tabs--left .b-tabs__list,\n.b-tabs--right .b-tabs__list {\n flex-direction: column;\n gap: 0;\n}\n\n/* ─────────────────────────────────────────────\n Individual tab\n ───────────────────────────────────────────── */\n.b-tabs__tab {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n position: relative;\n padding: var(--b-tabs-horizontal-item-padding);\n border: none;\n background: none;\n color: var(--b-tabs-item-color);\n font-size: inherit;\n font-family: inherit;\n cursor: pointer;\n white-space: nowrap;\n outline: none;\n transition: color var(--b-tabs-transition-duration);\n line-height: 1.5;\n}\n\n.b-tabs__tab:hover:not(.b-tabs__tab--disabled) {\n color: var(--b-tabs-item-hover-color);\n}\n\n.b-tabs__tab--active {\n color: var(--b-tabs-item-selected-color);\n font-weight: 500;\n}\n\n.b-tabs__tab--active:hover {\n color: var(--b-tabs-item-active-color);\n}\n\n.b-tabs__tab--disabled {\n color: var(--b-tabs-item-disabled-color);\n cursor: not-allowed;\n}\n\n.b-tabs__tab:focus-visible {\n box-shadow: var(--b-tabs-focus-ring);\n border-radius: 4px;\n}\n\n/* Large size - tab padding */\n.b-tabs--large .b-tabs__tab {\n padding: var(--b-tabs-horizontal-item-padding-lg);\n}\n\n/* Small size - tab padding */\n.b-tabs--small .b-tabs__tab {\n padding: var(--b-tabs-horizontal-item-padding-sm);\n}\n\n/* Vertical tabs */\n.b-tabs--left .b-tabs__tab,\n.b-tabs--right .b-tabs__tab {\n padding: var(--b-tabs-vertical-item-padding);\n justify-content: flex-start;\n}\n\n.b-tabs--left .b-tabs__tab:not(:first-child),\n.b-tabs--right .b-tabs__tab:not(:first-child) {\n margin: var(--b-tabs-vertical-item-margin);\n}\n\n/* ─────────────────────────────────────────────\n Card-type tab\n ───────────────────────────────────────────── */\n.b-tabs--card .b-tabs__list,\n.b-tabs--editable-card .b-tabs__list {\n gap: var(--b-tabs-card-gutter);\n}\n\n.b-tabs--card .b-tabs__tab,\n.b-tabs--editable-card .b-tabs__tab {\n padding: var(--b-tabs-card-padding);\n background: var(--b-tabs-card-bg);\n border: 1px solid var(--b-tabs-border-color);\n border-bottom: none;\n border-radius: var(--b-tabs-card-border-radius);\n height: var(--b-tabs-card-height);\n margin-bottom: -1px;\n}\n\n.b-tabs--card .b-tabs__tab--active,\n.b-tabs--editable-card .b-tabs__tab--active {\n background: white;\n border-bottom-color: white;\n}\n\n.b-tabs--large.b-tabs--card .b-tabs__tab,\n.b-tabs--large.b-tabs--editable-card .b-tabs__tab {\n padding: var(--b-tabs-card-padding-lg);\n height: var(--b-tabs-card-height-lg);\n}\n\n.b-tabs--small.b-tabs--card .b-tabs__tab,\n.b-tabs--small.b-tabs--editable-card .b-tabs__tab {\n padding: var(--b-tabs-card-padding-sm);\n height: var(--b-tabs-card-height-sm);\n}\n\n/* ─────────────────────────────────────────────\n Ink bar (line type indicator)\n ───────────────────────────────────────────── */\n.b-tabs__ink-bar {\n position: absolute;\n background: var(--b-tabs-ink-bar-color);\n transition:\n left var(--b-tabs-transition-duration) cubic-bezier(0.645, 0.045, 0.355, 1),\n width var(--b-tabs-transition-duration) cubic-bezier(0.645, 0.045, 0.355, 1),\n top var(--b-tabs-transition-duration) cubic-bezier(0.645, 0.045, 0.355, 1),\n height var(--b-tabs-transition-duration) cubic-bezier(0.645, 0.045, 0.355, 1);\n pointer-events: none;\n}\n\n.b-tabs--top .b-tabs__ink-bar,\n.b-tabs--bottom .b-tabs__ink-bar {\n bottom: 0;\n height: 2px;\n}\n\n.b-tabs--bottom .b-tabs__ink-bar {\n bottom: auto;\n top: 0;\n}\n\n.b-tabs--left .b-tabs__ink-bar {\n right: 0;\n width: 2px;\n}\n\n.b-tabs--right .b-tabs__ink-bar {\n left: 0;\n width: 2px;\n}\n\n/* ─────────────────────────────────────────────\n Close / Remove button\n ───────────────────────────────────────────── */\n.b-tabs__tab-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n cursor: pointer;\n opacity: 0.6;\n transition:\n opacity var(--b-tabs-transition-duration),\n background var(--b-tabs-transition-duration);\n}\n\n.b-tabs__tab-remove:hover {\n opacity: 1;\n background: oklch(0% 0 0 / 8%);\n}\n\n.b-tabs__close-icon {\n width: 12px;\n height: 12px;\n}\n\n/* ─────────────────────────────────────────────\n Add button\n ───────────────────────────────────────────── */\n.b-tabs__add {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: var(--b-tabs-card-padding);\n background: var(--b-tabs-card-bg);\n border: 1px solid var(--b-tabs-border-color);\n border-bottom: none;\n border-radius: var(--b-tabs-card-border-radius);\n height: var(--b-tabs-card-height);\n margin-bottom: -1px;\n cursor: pointer;\n color: var(--b-tabs-item-color);\n transition: color var(--b-tabs-transition-duration);\n}\n\n.b-tabs__add:hover {\n color: var(--b-tabs-item-hover-color);\n}\n\n.b-tabs__add:focus-visible {\n box-shadow: var(--b-tabs-focus-ring);\n}\n\n.b-tabs__add-icon {\n width: 16px;\n height: 16px;\n}\n\n/* ─────────────────────────────────────────────\n Extra content slots\n ───────────────────────────────────────────── */\n.b-tabs__extra {\n display: flex;\n align-items: center;\n padding: 0 8px;\n flex-shrink: 0;\n}\n\n/* ─────────────────────────────────────────────\n Content area\n ───────────────────────────────────────────── */\n.b-tabs__content {\n flex: 1;\n min-height: var(--b-tabs-content-min-height);\n}\n\n.b-tabs__panel {\n outline: none;\n}\n\n.b-tabs__panel--animated {\n animation: b-tabs-fade-in var(--b-tabs-transition-duration) ease-in-out;\n}\n\n@keyframes b-tabs-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ─────────────────────────────────────────────\n Dark mode\n ───────────────────────────────────────────── */\n[data-prefers-color='dark'] .b-tabs {\n --b-tabs-ink-bar-color: oklch(70% 0.18 262.881);\n --b-tabs-item-active-color: oklch(80% 0.14 262.881);\n --b-tabs-item-color: oklch(85% 0.01 260 / 88%);\n --b-tabs-item-hover-color: oklch(70% 0.18 262.881);\n --b-tabs-item-selected-color: oklch(70% 0.18 262.881);\n --b-tabs-item-disabled-color: oklch(85% 0.01 260 / 25%);\n --b-tabs-card-bg: oklch(25% 0.015 260 / 50%);\n --b-tabs-border-color: oklch(35% 0.01 260);\n}\n\n[data-prefers-color='dark'] .b-tabs--card .b-tabs__tab--active,\n[data-prefers-color='dark'] .b-tabs--editable-card .b-tabs__tab--active {\n background: oklch(20% 0.015 260);\n border-bottom-color: oklch(20% 0.015 260);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-tabs {\n --b-tabs-ink-bar-color: oklch(70% 0.18 262.881);\n --b-tabs-item-active-color: oklch(80% 0.14 262.881);\n --b-tabs-item-color: oklch(85% 0.01 260 / 88%);\n --b-tabs-item-hover-color: oklch(70% 0.18 262.881);\n --b-tabs-item-selected-color: oklch(70% 0.18 262.881);\n --b-tabs-item-disabled-color: oklch(85% 0.01 260 / 25%);\n --b-tabs-card-bg: oklch(25% 0.015 260 / 50%);\n --b-tabs-border-color: oklch(35% 0.01 260);\n }\n [data-prefers-color='system'] .b-tabs--editable-card .b-tabs__tab--active {\n background: oklch(20% 0.015 260);\n border-bottom-color: oklch(20% 0.015 260);\n }\n}\n\n/* ─────────────────────────────────────────────\n Reduced motion\n ───────────────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .b-tabs {\n --b-tabs-transition-duration: 0ms;\n }\n\n .b-tabs__panel--animated {\n animation: none;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Transition as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, defineComponent as s, normalizeClass as c, normalizeStyle as l, openBlock as u, ref as d, renderSlot as f, toDisplayString as p, watch as m, withCtx as h, withModifiers as g } from "vue";
|
|
2
|
+
//#region src/components/BTag/BTag.vue?vue&type=script&setup=true&lang.ts
|
|
3
|
+
var _ = ["aria-hidden"], v = { class: "b-tag__content" }, y = ["data-icon"], b = {
|
|
4
|
+
key: 1,
|
|
5
|
+
class: "b-tag__close-icon",
|
|
6
|
+
viewBox: "0 0 12 12",
|
|
7
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
8
|
+
"aria-hidden": "true",
|
|
9
|
+
focusable: "false"
|
|
10
|
+
}, x = /* @__PURE__ */ s({
|
|
11
|
+
__name: "BTag",
|
|
12
|
+
props: {
|
|
13
|
+
color: {},
|
|
14
|
+
variant: { default: "filled" },
|
|
15
|
+
size: { default: "default" },
|
|
16
|
+
closable: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: !1
|
|
19
|
+
},
|
|
20
|
+
closeIcon: {},
|
|
21
|
+
visible: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: () => void 0
|
|
24
|
+
},
|
|
25
|
+
bordered: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: !0
|
|
28
|
+
},
|
|
29
|
+
icon: {}
|
|
30
|
+
},
|
|
31
|
+
emits: [
|
|
32
|
+
"close",
|
|
33
|
+
"afterClose",
|
|
34
|
+
"update:visible"
|
|
35
|
+
],
|
|
36
|
+
setup(s, { emit: x }) {
|
|
37
|
+
let S = x, C = [
|
|
38
|
+
"default",
|
|
39
|
+
"success",
|
|
40
|
+
"processing",
|
|
41
|
+
"error",
|
|
42
|
+
"warning",
|
|
43
|
+
"magenta",
|
|
44
|
+
"red",
|
|
45
|
+
"volcano",
|
|
46
|
+
"orange",
|
|
47
|
+
"gold",
|
|
48
|
+
"lime",
|
|
49
|
+
"green",
|
|
50
|
+
"cyan",
|
|
51
|
+
"blue",
|
|
52
|
+
"geekblue",
|
|
53
|
+
"purple"
|
|
54
|
+
], w = t(() => s.color === void 0 || C.includes(s.color)), T = t(() => w.value ? s.color ?? "default" : "default"), E = t(() => s.visible !== void 0), D = d(!0);
|
|
55
|
+
m(() => s.visible, (e) => {
|
|
56
|
+
e !== void 0 && (D.value = e);
|
|
57
|
+
});
|
|
58
|
+
let O = t(() => E.value ? s.visible : D.value);
|
|
59
|
+
function k(e) {
|
|
60
|
+
S("close", e), E.value ? S("update:visible", !1) : D.value = !1;
|
|
61
|
+
}
|
|
62
|
+
function A(e) {
|
|
63
|
+
k(e);
|
|
64
|
+
}
|
|
65
|
+
function j(e) {
|
|
66
|
+
(e.key === "Enter" || e.key === " " || e.key === "Escape") && (e.preventDefault(), k(e));
|
|
67
|
+
}
|
|
68
|
+
function M() {
|
|
69
|
+
S("afterClose");
|
|
70
|
+
}
|
|
71
|
+
let N = t(() => [
|
|
72
|
+
"b-tag",
|
|
73
|
+
`b-tag--${T.value}`,
|
|
74
|
+
`b-tag--${s.variant}`,
|
|
75
|
+
{
|
|
76
|
+
"b-tag--borderless": !s.bordered,
|
|
77
|
+
"b-tag--closable": s.closable,
|
|
78
|
+
"b-tag--small": s.size === "small",
|
|
79
|
+
"b-tag--large": s.size === "large",
|
|
80
|
+
"b-tag--custom-color": !w.value
|
|
81
|
+
}
|
|
82
|
+
]), P = t(() => {
|
|
83
|
+
if (!w.value) return { "--b-tag-custom-color": s.color };
|
|
84
|
+
});
|
|
85
|
+
return (t, d) => (u(), n(e, {
|
|
86
|
+
name: "b-tag-fade",
|
|
87
|
+
onAfterLeave: M
|
|
88
|
+
}, {
|
|
89
|
+
default: h(() => [O.value ? (u(), i("span", {
|
|
90
|
+
key: 0,
|
|
91
|
+
class: c(N.value),
|
|
92
|
+
style: l(P.value)
|
|
93
|
+
}, [
|
|
94
|
+
t.$slots.icon || s.icon ? (u(), i("span", {
|
|
95
|
+
key: 0,
|
|
96
|
+
class: "b-tag__icon",
|
|
97
|
+
"aria-hidden": t.$slots.icon ? void 0 : "true"
|
|
98
|
+
}, [f(t.$slots, "icon", {}, () => [o(p(s.icon), 1)])], 8, _)) : r("", !0),
|
|
99
|
+
a("span", v, [f(t.$slots, "default")]),
|
|
100
|
+
s.closable ? (u(), i("button", {
|
|
101
|
+
key: 1,
|
|
102
|
+
type: "button",
|
|
103
|
+
class: "b-tag__close",
|
|
104
|
+
"aria-label": "Remove tag",
|
|
105
|
+
tabindex: "0",
|
|
106
|
+
onClick: g(A, ["stop"]),
|
|
107
|
+
onKeydown: j
|
|
108
|
+
}, [f(t.$slots, "closeIcon", {}, () => [s.closeIcon ? (u(), i("span", {
|
|
109
|
+
key: 0,
|
|
110
|
+
class: "b-tag__close-label",
|
|
111
|
+
"aria-hidden": "true",
|
|
112
|
+
"data-icon": s.closeIcon
|
|
113
|
+
}, null, 8, y)) : (u(), i("svg", b, [...d[0] ||= [a("path", { d: "M9.5 3.205 8.795 2.5 6 5.295 3.205 2.5 2.5 3.205 5.295 6 2.5 8.795 3.205 9.5 6 6.705 8.795 9.5 9.5 8.795 6.705 6z" }, null, -1)]]))])], 32)) : r("", !0)
|
|
114
|
+
], 6)) : r("", !0)]),
|
|
115
|
+
_: 3
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
//#endregion
|
|
120
|
+
export { x as default };
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=design-system226.js.map
|