@livestorm/ui-vue 2.0.4 → 3.0.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/README.md +8 -5
- package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-LpdvGf5X.mjs +6093 -0
- package/dist/a11y-BhF_nl7L.mjs +159 -0
- package/dist/components.mjs +105 -96
- package/dist/index.mjs +68 -64
- package/dist/layouts.mjs +16 -16
- package/dist/types/index.d.ts +5 -1
- package/dist/types/src/components/UiActionBar/UiActionBar.vue.d.ts +3 -1
- package/dist/types/src/components/UiActionBar/UiActionBarItem.vue.d.ts +18 -3
- package/dist/types/src/components/UiActionBar/types.d.ts +3 -1
- package/dist/types/src/components/UiButton/UiButton.vue.d.ts +17 -13
- package/dist/types/src/components/UiButtonGroup/UiButtonGroupItem.vue.d.ts +3 -0
- package/dist/types/src/components/UiButtonGroup/types.d.ts +1 -1
- package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +6 -4
- package/dist/types/src/components/UiInputEmoji/UiInputEmoji.vue.d.ts +45 -0
- package/dist/types/src/components/UiInputEmoji/index.d.ts +1 -0
- package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +67 -0
- package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +81 -0
- package/dist/types/src/components/UiInputRadio/index.d.ts +3 -0
- package/dist/types/src/components/UiInputRadio/types.d.ts +19 -0
- package/dist/types/src/components/UiLoader/UiLoader.vue.d.ts +6 -5
- package/dist/types/src/components/UiLogo/UiLogo.vue.d.ts +9 -3
- package/dist/types/src/components/UiPage/UiPage.vue.d.ts +34 -0
- package/dist/types/src/components/UiProgress/UiProgress.vue.d.ts +1 -1
- package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +109 -0
- package/dist/types/src/components/UiSwitch/index.d.ts +2 -0
- package/dist/types/src/components/UiSwitch/types.d.ts +3 -0
- package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +5 -2
- package/dist/types/src/composables/useContentMode.d.ts +25 -0
- package/dist/types/src/composables/useIconSize.d.ts +11 -0
- package/dist/types/src/constants/sizes.d.ts +1 -1
- package/dist/ui-vue.css +1 -1
- package/dist/{useThemeAndModes-CUK56j0z.mjs → useThemeAndModes-BzYwSOEv.mjs} +1 -1
- package/dist/utils.mjs +154 -99
- package/index.d.ts +4 -0
- package/index.js +8 -0
- package/package.json +11 -3
- package/src/components/Toast/ToastMessage.vue +6 -6
- package/src/components/UiActionBar/UiActionBar.vue +11 -2
- package/src/components/UiActionBar/UiActionBarItem.vue +56 -32
- package/src/components/UiActionBar/types.ts +3 -1
- package/src/components/UiAvatar/UiAvatar.vue +1 -1
- package/src/components/UiBanner/UiBanner.vue +7 -7
- package/src/components/UiButton/UiButton.vue +9 -9
- package/src/components/UiButtonGroup/UiButtonGroup.vue +4 -0
- package/src/components/UiButtonGroup/UiButtonGroupItem.vue +14 -0
- package/src/components/UiButtonGroup/types.ts +1 -1
- package/src/components/UiCarousel/UiCarousel.vue +2 -2
- package/src/components/UiColorPicker/UiColorPicker.vue +5 -5
- package/src/components/UiDialog/MarketplaceHeaderExample.vue +2 -2
- package/src/components/UiDialog/UiDialogClose.vue +1 -1
- package/src/components/UiDropdown/UiDropdownContent.vue +2 -2
- package/src/components/UiDropdown/UiDropdownItem.vue +8 -1
- package/src/components/UiDropdown/UiDropdownTrigger.vue +6 -7
- package/src/components/UiFieldWrapper/UiFieldWrapper.vue +1 -1
- package/src/components/UiInputCheckbox/UiInputCheckbox.vue +2 -2
- package/src/components/UiInputEmoji/UiInputEmoji.vue +173 -0
- package/src/components/UiInputEmoji/index.ts +1 -0
- package/src/components/UiInputRadio/UiInputRadio.vue +374 -0
- package/src/components/UiInputRadio/UiInputRadioGroup.vue +156 -0
- package/src/components/UiInputRadio/index.ts +3 -0
- package/src/components/UiInputRadio/types.ts +25 -0
- package/src/components/UiLoader/UiLoader.vue +8 -10
- package/src/components/UiLogo/UiLogo.vue +41 -7
- package/src/components/UiMenu/UiMenuContent.vue +1 -1
- package/src/components/UiMenu/UiMenuGroup.vue +1 -1
- package/src/components/UiMenu/UiMenuItem.vue +1 -1
- package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
- package/src/components/UiMenu/UiMenuSubTrigger.vue +2 -2
- package/src/components/UiPage/UiPage.vue +102 -29
- package/src/components/UiPageHeader/UiPageHeader.vue +29 -9
- package/src/components/UiRoomButton/UiRoomButton.vue +4 -4
- package/src/components/UiShell/UiShell.vue +1 -1
- package/src/components/UiSideMenu/UiSideMenu.vue +13 -10
- package/src/components/UiSideMenu/UiSideMenuItemContent.vue +2 -2
- package/src/components/UiStepper/UiStepperIndicator.vue +8 -11
- package/src/components/UiSwitch/UiSwitch.vue +359 -0
- package/src/components/UiSwitch/index.ts +2 -0
- package/src/components/UiSwitch/types.ts +5 -0
- package/src/components/UiTabs/UiTabs.vue +7 -4
- package/src/components/UiTextField/UiTextField.vue +6 -11
- package/src/components/UiTimeline/README.md +6 -6
- package/src/components/UiTimeline/UiTimelineItem.vue +3 -3
- package/src/composables/useContentMode.ts +53 -0
- package/src/composables/useIconSize.ts +28 -0
- package/src/constants/sizes.ts +1 -1
- package/src/global.d.ts +8 -0
- package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-BtG5oABt.mjs +0 -5454
- package/dist/a11y--y7uaY4j.mjs +0 -217
package/dist/utils.mjs
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { BREAKPOINT_2XL as
|
|
1
|
+
import { BREAKPOINT_2XL as Y, BREAKPOINT_LG as Z, BREAKPOINT_MD as ee, BREAKPOINT_SM as te, BREAKPOINT_XL as ne, BREAKPOINT_XL_PLUS as oe } from "./breakpoints.mjs";
|
|
2
2
|
import "./bus.mjs";
|
|
3
|
-
import { computed as
|
|
4
|
-
import { useClipboard as
|
|
5
|
-
import { u as
|
|
6
|
-
import { b as
|
|
7
|
-
import { f as
|
|
8
|
-
import { useResponsive as
|
|
9
|
-
import { useRoute as $, useRouter as
|
|
10
|
-
import { RenderSlot as
|
|
11
|
-
let
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
document.body.appendChild(
|
|
16
|
-
const
|
|
17
|
-
render: () =>
|
|
18
|
-
|
|
3
|
+
import { computed as l, createApp as g, h as y, ref as T, watch as x, onUnmounted as k, getCurrentInstance as S, onMounted as _, nextTick as w } from "vue";
|
|
4
|
+
import { useClipboard as b, usePermission as A, onKeyDown as C } from "@vueuse/core";
|
|
5
|
+
import { u as E } from "./i18n-Cktw9hIu.mjs";
|
|
6
|
+
import { b as I, _ as R, c as B, a as P } from "./a11y-BhF_nl7L.mjs";
|
|
7
|
+
import { f as ie } from "./a11y-BhF_nl7L.mjs";
|
|
8
|
+
import { useResponsive as ue } from "./responsive.mjs";
|
|
9
|
+
import { useRoute as $, useRouter as q } from "vue-router";
|
|
10
|
+
import { RenderSlot as ae, getSlotAsComponent as de, unwrapFragments as le, useSlotsAsComponents as fe } from "./slot.mjs";
|
|
11
|
+
let v = null;
|
|
12
|
+
function L(s, i) {
|
|
13
|
+
v && v();
|
|
14
|
+
const e = s.getBoundingClientRect(), t = document.createElement("div");
|
|
15
|
+
document.body.appendChild(t);
|
|
16
|
+
const f = g({
|
|
17
|
+
render: () => y(I, null, () => y(R, { open: !0, delayDuration: 0 }, () => [
|
|
18
|
+
y(B, { asChild: !0 }, () => y("span", {
|
|
19
19
|
"aria-hidden": "true",
|
|
20
20
|
style: {
|
|
21
21
|
position: "fixed",
|
|
22
|
-
left: `${
|
|
23
|
-
top: `${
|
|
24
|
-
width: `${
|
|
25
|
-
height: `${
|
|
22
|
+
left: `${e.left}px`,
|
|
23
|
+
top: `${e.top}px`,
|
|
24
|
+
width: `${e.width}px`,
|
|
25
|
+
height: `${e.height}px`,
|
|
26
26
|
pointerEvents: "none"
|
|
27
27
|
}
|
|
28
28
|
})),
|
|
29
|
-
|
|
29
|
+
y(P, { side: "top" }, () => i),
|
|
30
30
|
// The bubble lives in reka's portal where attrs like role are not
|
|
31
31
|
// forwardable; announce the feedback from a visually hidden live
|
|
32
32
|
// region instead so screen readers hear the copy confirmation.
|
|
33
|
-
|
|
33
|
+
y("span", {
|
|
34
34
|
role: "status",
|
|
35
35
|
style: {
|
|
36
36
|
position: "absolute",
|
|
@@ -39,108 +39,163 @@ function k(n, c) {
|
|
|
39
39
|
overflow: "hidden",
|
|
40
40
|
clipPath: "inset(50%)"
|
|
41
41
|
}
|
|
42
|
-
},
|
|
42
|
+
}, i)
|
|
43
43
|
]))
|
|
44
44
|
});
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
const
|
|
48
|
-
|
|
45
|
+
f.mount(t);
|
|
46
|
+
let a = !1;
|
|
47
|
+
const u = () => {
|
|
48
|
+
a || (a = !0, v === u && (v = null), f.unmount(), t.remove());
|
|
49
49
|
};
|
|
50
|
-
return
|
|
50
|
+
return v = u, u;
|
|
51
51
|
}
|
|
52
|
-
function
|
|
53
|
-
const { isSupported:
|
|
54
|
-
async function
|
|
55
|
-
if (await
|
|
56
|
-
|
|
57
|
-
const
|
|
52
|
+
function H() {
|
|
53
|
+
const { isSupported: s, copy: i } = b(), e = A("clipboard-write"), t = E(), f = l(() => s.value && e.value);
|
|
54
|
+
async function a(u, d, m = t("general_misc_copied-text")) {
|
|
55
|
+
if (await i(u), d) {
|
|
56
|
+
d.classList.add("copied");
|
|
57
|
+
const n = L(d, m);
|
|
58
58
|
setTimeout(() => {
|
|
59
|
-
|
|
59
|
+
d.classList.remove("copied"), n();
|
|
60
60
|
}, 600);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
return {
|
|
64
|
-
canCopy:
|
|
65
|
-
copy:
|
|
64
|
+
canCopy: f,
|
|
65
|
+
copy: a
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
-
function
|
|
69
|
-
const
|
|
70
|
-
function
|
|
71
|
-
const
|
|
72
|
-
for (const
|
|
73
|
-
|
|
74
|
-
return
|
|
68
|
+
function Q(s, i = !1) {
|
|
69
|
+
const e = $(), t = q(), f = `${s}-`;
|
|
70
|
+
function a() {
|
|
71
|
+
const n = [];
|
|
72
|
+
for (const r in e.query)
|
|
73
|
+
r.startsWith(f) && n.push(r);
|
|
74
|
+
return n;
|
|
75
75
|
}
|
|
76
|
-
function
|
|
77
|
-
return
|
|
76
|
+
function u(n) {
|
|
77
|
+
return n === "true" ? !0 : n === "false" ? !1 : n ?? !1;
|
|
78
78
|
}
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
79
|
+
const d = l(() => {
|
|
80
|
+
if (i) {
|
|
81
|
+
const n = a();
|
|
82
|
+
if (n.length === 0)
|
|
83
83
|
return !1;
|
|
84
|
-
const
|
|
85
|
-
for (const
|
|
86
|
-
|
|
87
|
-
return
|
|
84
|
+
const r = {};
|
|
85
|
+
for (const c of n)
|
|
86
|
+
r[c.substring(f.length)] = u(e.query[c]);
|
|
87
|
+
return r;
|
|
88
88
|
} else
|
|
89
|
-
return
|
|
90
|
-
}), m = !!
|
|
91
|
-
return
|
|
92
|
-
get: () =>
|
|
93
|
-
set: (
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
|
|
89
|
+
return u(e.query[s]);
|
|
90
|
+
}), m = !!d.value;
|
|
91
|
+
return l({
|
|
92
|
+
get: () => d.value,
|
|
93
|
+
set: (n) => {
|
|
94
|
+
if (n === d.value) return;
|
|
95
|
+
const r = n == null || n === !1;
|
|
96
|
+
if (r && !m)
|
|
97
|
+
t.back();
|
|
98
98
|
else {
|
|
99
|
-
let
|
|
100
|
-
if (
|
|
101
|
-
if (
|
|
102
|
-
const
|
|
103
|
-
for (const
|
|
104
|
-
|
|
99
|
+
let c;
|
|
100
|
+
if (i)
|
|
101
|
+
if (c = {}, r) {
|
|
102
|
+
const h = a();
|
|
103
|
+
for (const o of h)
|
|
104
|
+
c[o] = void 0;
|
|
105
105
|
} else
|
|
106
|
-
for (const
|
|
107
|
-
|
|
106
|
+
for (const h in n)
|
|
107
|
+
c[`${s}-${h}`] = n[h];
|
|
108
108
|
else
|
|
109
|
-
|
|
110
|
-
[
|
|
109
|
+
c = {
|
|
110
|
+
[s]: r ? void 0 : n
|
|
111
111
|
};
|
|
112
|
-
|
|
113
|
-
...
|
|
112
|
+
t[r ? "replace" : "push"]({
|
|
113
|
+
...e,
|
|
114
114
|
query: {
|
|
115
|
-
...
|
|
116
|
-
...
|
|
115
|
+
...e.query,
|
|
116
|
+
...c
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
-
let
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
let K = 0;
|
|
124
|
+
const p = T([]), O = l(() => p.value.length > 0);
|
|
125
|
+
function W(s, i) {
|
|
126
|
+
const e = K++, t = l(() => p.value.findIndex((o) => o.id === e));
|
|
127
|
+
function f() {
|
|
128
|
+
p.value.some((o) => o.id === e) || p.value.push({
|
|
129
|
+
id: e,
|
|
130
|
+
type: i
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function a() {
|
|
134
|
+
t.value !== -1 && p.value.splice(t.value, 1);
|
|
135
|
+
}
|
|
136
|
+
x(s, (o) => {
|
|
137
|
+
o ? f() : a();
|
|
138
|
+
}, {
|
|
139
|
+
immediate: !0
|
|
140
|
+
}), k(() => {
|
|
141
|
+
a();
|
|
142
|
+
});
|
|
143
|
+
const u = l(() => e === p.value[p.value.length - 1]?.id), d = l(() => t.value > 0), m = l(() => p.value.filter((o) => o.type === i)), n = l(() => m.value.findIndex((o) => o.id === e) < m.value.length - 1), r = l(() => m.value.findIndex((o) => o.id === e) > 0), c = [];
|
|
144
|
+
function h(o) {
|
|
145
|
+
c.push(o);
|
|
146
|
+
}
|
|
147
|
+
return C("Escape", () => {
|
|
148
|
+
u.value && c.forEach((o) => o());
|
|
149
|
+
}), {
|
|
150
|
+
isActiveStacked: u,
|
|
151
|
+
hasStackedBehind: d,
|
|
152
|
+
isBehindSameType: n,
|
|
153
|
+
hasStackedSameTypeBehind: r,
|
|
154
|
+
stackIndex: t,
|
|
155
|
+
onClose: h
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
typeof document < "u" && x(O, (s) => {
|
|
159
|
+
s ? document.documentElement.classList.add("overflow-hidden") : document.documentElement.classList.remove("overflow-hidden");
|
|
160
|
+
}, {
|
|
161
|
+
immediate: !0
|
|
162
|
+
});
|
|
163
|
+
function j() {
|
|
164
|
+
const s = S();
|
|
165
|
+
let i = null;
|
|
166
|
+
_(async () => {
|
|
167
|
+
await w();
|
|
168
|
+
const e = s.proxy.$el;
|
|
169
|
+
if (!e?.querySelector) return;
|
|
170
|
+
let t = e.querySelector("[data-stackview-autofocus]");
|
|
171
|
+
t ? ["INPUT", "A", "BUTTON", "TEXTAREA"].includes(t.tagName) || (t = t.querySelector("input, a, button, textarea") || t) : (t = e.querySelector('button[type="submit"]'), console.warn(
|
|
172
|
+
"%cDEV",
|
|
173
|
+
"background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;",
|
|
174
|
+
"A element should have the data-stackview-autofocus attribute in this component. Fallback to submit button."
|
|
175
|
+
)), clearTimeout(i), i = setTimeout(() => t?.focus(), 150);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
let U = 0;
|
|
179
|
+
function G() {
|
|
180
|
+
return ++U;
|
|
126
181
|
}
|
|
127
182
|
export {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
183
|
+
Y as BREAKPOINT_2XL,
|
|
184
|
+
Z as BREAKPOINT_LG,
|
|
185
|
+
ee as BREAKPOINT_MD,
|
|
186
|
+
te as BREAKPOINT_SM,
|
|
187
|
+
ne as BREAKPOINT_XL,
|
|
188
|
+
oe as BREAKPOINT_XL_PLUS,
|
|
189
|
+
ae as RenderSlot,
|
|
190
|
+
ie as focusFirstMenuItem,
|
|
191
|
+
de as getSlotAsComponent,
|
|
192
|
+
G as getUid,
|
|
193
|
+
O as hasStackedComponents,
|
|
194
|
+
le as unwrapFragments,
|
|
195
|
+
H as useCopyToClipboard,
|
|
196
|
+
ue as useResponsive,
|
|
197
|
+
Q as useRouteQueryModel,
|
|
198
|
+
fe as useSlotsAsComponents,
|
|
199
|
+
j as useStackAutofocus,
|
|
200
|
+
W as useStackedComponent
|
|
146
201
|
};
|
package/index.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export { default as UiFieldWrapper } from './src/components/UiFieldWrapper/UiFie
|
|
|
35
35
|
export { default as UiFormField } from './src/components/UiForm/UiFormField.vue'
|
|
36
36
|
export { default as UiHorizontalSeparator } from './src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue'
|
|
37
37
|
export { default as UiInputCheckbox } from './src/components/UiInputCheckbox/UiInputCheckbox.vue'
|
|
38
|
+
export { default as UiInputEmoji } from './src/components/UiInputEmoji/UiInputEmoji.vue'
|
|
39
|
+
export { default as UiInputRadio } from './src/components/UiInputRadio/UiInputRadio.vue'
|
|
40
|
+
export { default as UiInputRadioGroup } from './src/components/UiInputRadio/UiInputRadioGroup.vue'
|
|
38
41
|
export { default as UiInputSelect } from './src/components/UiInputSelect/UiInputSelect.vue'
|
|
39
42
|
export { default as UiInputTextarea } from './src/components/UiInputTextarea/UiInputTextarea.vue'
|
|
40
43
|
export { default as UiLabel } from './src/components/UiLabel/UiLabel.vue'
|
|
@@ -72,6 +75,7 @@ export { default as UiStepperIndicator } from './src/components/UiStepper/UiStep
|
|
|
72
75
|
export { default as UiStepperItem } from './src/components/UiStepper/UiStepperItem.vue'
|
|
73
76
|
export { default as UiStepperSeparator } from './src/components/UiStepper/UiStepperSeparator.vue'
|
|
74
77
|
export { default as UiStepperTitle } from './src/components/UiStepper/UiStepperTitle.vue'
|
|
78
|
+
export { default as UiSwitch } from './src/components/UiSwitch/UiSwitch.vue'
|
|
75
79
|
export { default as UiTable } from './src/components/UiTable/UiTable.vue'
|
|
76
80
|
export { default as UiTableBody } from './src/components/UiTable/UiTableBody.vue'
|
|
77
81
|
export { default as UiTableCell } from './src/components/UiTable/UiTableCell.vue'
|
package/index.js
CHANGED
|
@@ -37,6 +37,9 @@ import UiFieldWrapper from './src/components/UiFieldWrapper/UiFieldWrapper.vue'
|
|
|
37
37
|
import UiFormField from './src/components/UiForm/UiFormField.vue'
|
|
38
38
|
import UiHorizontalSeparator from './src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue'
|
|
39
39
|
import UiInputCheckbox from './src/components/UiInputCheckbox/UiInputCheckbox.vue'
|
|
40
|
+
import UiInputEmoji from './src/components/UiInputEmoji/UiInputEmoji.vue'
|
|
41
|
+
import UiInputRadio from './src/components/UiInputRadio/UiInputRadio.vue'
|
|
42
|
+
import UiInputRadioGroup from './src/components/UiInputRadio/UiInputRadioGroup.vue'
|
|
40
43
|
import UiInputSelect from './src/components/UiInputSelect/UiInputSelect.vue'
|
|
41
44
|
import UiInputTextarea from './src/components/UiInputTextarea/UiInputTextarea.vue'
|
|
42
45
|
import UiLabel from './src/components/UiLabel/UiLabel.vue'
|
|
@@ -74,6 +77,7 @@ import UiStepperIndicator from './src/components/UiStepper/UiStepperIndicator.vu
|
|
|
74
77
|
import UiStepperItem from './src/components/UiStepper/UiStepperItem.vue'
|
|
75
78
|
import UiStepperSeparator from './src/components/UiStepper/UiStepperSeparator.vue'
|
|
76
79
|
import UiStepperTitle from './src/components/UiStepper/UiStepperTitle.vue'
|
|
80
|
+
import UiSwitch from './src/components/UiSwitch/UiSwitch.vue'
|
|
77
81
|
import UiTable from './src/components/UiTable/UiTable.vue'
|
|
78
82
|
import UiTableBody from './src/components/UiTable/UiTableBody.vue'
|
|
79
83
|
import UiTableCell from './src/components/UiTable/UiTableCell.vue'
|
|
@@ -122,6 +126,9 @@ export {
|
|
|
122
126
|
UiFormField,
|
|
123
127
|
UiHorizontalSeparator,
|
|
124
128
|
UiInputCheckbox,
|
|
129
|
+
UiInputEmoji,
|
|
130
|
+
UiInputRadio,
|
|
131
|
+
UiInputRadioGroup,
|
|
125
132
|
UiInputSelect,
|
|
126
133
|
UiInputTextarea,
|
|
127
134
|
UiLabel,
|
|
@@ -159,6 +166,7 @@ export {
|
|
|
159
166
|
UiStepperItem,
|
|
160
167
|
UiStepperSeparator,
|
|
161
168
|
UiStepperTitle,
|
|
169
|
+
UiSwitch,
|
|
162
170
|
UiTable,
|
|
163
171
|
UiTableBody,
|
|
164
172
|
UiTableCell,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestorm/ui-vue",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Livestorm UI components for Vue 3",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
"main": "./dist/index.mjs",
|
|
12
12
|
"module": "./dist/index.mjs",
|
|
13
13
|
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"**/*.css",
|
|
16
|
+
"./index.js",
|
|
17
|
+
"./style.js"
|
|
18
|
+
],
|
|
14
19
|
"files": [
|
|
15
20
|
"dist",
|
|
16
21
|
"src",
|
|
@@ -38,11 +43,14 @@
|
|
|
38
43
|
"i18next": "^26.3.4",
|
|
39
44
|
"mitt": "^3.0.1",
|
|
40
45
|
"reka-ui": "^2.9.10",
|
|
41
|
-
"
|
|
42
|
-
"@livestorm/ui-
|
|
46
|
+
"vue-frimousse": "^0.1.4",
|
|
47
|
+
"@livestorm/ui-tokens": "^3.0.0",
|
|
48
|
+
"@livestorm/ui-icons": "^3.0.0"
|
|
43
49
|
},
|
|
44
50
|
"devDependencies": {
|
|
45
51
|
"@chromatic-com/storybook": "^5.2.1",
|
|
52
|
+
"@iconify-json/ph": "^1.2.2",
|
|
53
|
+
"@iconify/utils": "^3.1.4",
|
|
46
54
|
"@storybook/addon-a11y": "^10.5.5",
|
|
47
55
|
"@storybook/addon-coverage": "^3.0.2",
|
|
48
56
|
"@storybook/addon-designs": "^11.1.4",
|
|
@@ -31,13 +31,13 @@ const modalIcon = computed(() => {
|
|
|
31
31
|
|
|
32
32
|
switch (props.type) {
|
|
33
33
|
case 'alert':
|
|
34
|
-
return 'i-
|
|
34
|
+
return 'i-ph-x-circle !text-text-danger-base'
|
|
35
35
|
case 'warning':
|
|
36
|
-
return 'i-
|
|
36
|
+
return 'i-ph-warning !text-text-warning-base'
|
|
37
37
|
case 'info':
|
|
38
|
-
return 'i-
|
|
38
|
+
return 'i-ph-info text-text-primary-base'
|
|
39
39
|
case 'success':
|
|
40
|
-
return 'i-
|
|
40
|
+
return 'i-ph-check-circle text-text-success-base'
|
|
41
41
|
default:
|
|
42
42
|
return undefined
|
|
43
43
|
}
|
|
@@ -137,7 +137,7 @@ onMounted(() => {
|
|
|
137
137
|
<div class="shrink-0">
|
|
138
138
|
<div
|
|
139
139
|
v-if="modalIcon"
|
|
140
|
-
class="
|
|
140
|
+
class="size-5 mr-3 shrink-0 mb-2 sm:mb-0"
|
|
141
141
|
:class="modalIcon"
|
|
142
142
|
/>
|
|
143
143
|
</div>
|
|
@@ -167,7 +167,7 @@ onMounted(() => {
|
|
|
167
167
|
:data-testid="`toast-close-${String(props.id)}`"
|
|
168
168
|
color="neutral"
|
|
169
169
|
variant="tertiary"
|
|
170
|
-
icon="i-
|
|
170
|
+
icon="i-ph-x"
|
|
171
171
|
size="md"
|
|
172
172
|
aria-label="close"
|
|
173
173
|
class="-top-[10px] -right-[2px] sm:row-start-1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, provide } from 'vue'
|
|
3
|
-
import type { ActionBarOrientation, ActionBarPosition, ActionBarSize } from './types'
|
|
3
|
+
import type { ActionBarOrientation, ActionBarPosition, ActionBarSize, ActionBarTooltipSide } from './types'
|
|
4
4
|
import { ACTION_BAR_CONTEXT_KEY } from './types'
|
|
5
5
|
|
|
6
6
|
interface UiActionBarProps {
|
|
@@ -26,6 +26,7 @@ interface UiActionBarProps {
|
|
|
26
26
|
* Accessible label for the toolbar landmark. Defaults to "Actions".
|
|
27
27
|
*/
|
|
28
28
|
ariaLabel?: string
|
|
29
|
+
tooltipSide?: ActionBarTooltipSide
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const props = withDefaults(defineProps<UiActionBarProps>(), {
|
|
@@ -34,17 +35,25 @@ const props = withDefaults(defineProps<UiActionBarProps>(), {
|
|
|
34
35
|
position: undefined,
|
|
35
36
|
offset: 3,
|
|
36
37
|
ariaLabel: 'Actions',
|
|
38
|
+
tooltipSide: undefined,
|
|
37
39
|
})
|
|
38
40
|
|
|
39
41
|
provide(ACTION_BAR_CONTEXT_KEY, {
|
|
40
42
|
orientation: computed<ActionBarOrientation>(() => props.orientation),
|
|
41
43
|
size: computed<ActionBarSize>(() => props.size),
|
|
44
|
+
tooltipSide: computed<ActionBarTooltipSide | undefined>(() => props.tooltipSide),
|
|
42
45
|
})
|
|
43
46
|
|
|
44
47
|
const isVertical = computed(() => props.orientation === 'vertical')
|
|
45
48
|
|
|
46
49
|
// Inner padding follows the design tokens (space-0-5 = 2px).
|
|
47
|
-
const
|
|
50
|
+
const SIZE_CLASSES: Record<ActionBarSize, string> = {
|
|
51
|
+
xs: 'p-0.5 gap-0.5',
|
|
52
|
+
sm: 'p-0.5 gap-0.5',
|
|
53
|
+
md: 'p-1 gap-0.5',
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const sizeClasses = computed(() => SIZE_CLASSES[props.size])
|
|
48
57
|
|
|
49
58
|
// When `position` is set, anchor the bar to an edge of its positioned
|
|
50
59
|
// ancestor. Offsets are inline styles (rem) so any `offset` value works
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, inject } from 'vue'
|
|
2
|
+
import { computed, inject, useAttrs } from 'vue'
|
|
3
3
|
import {
|
|
4
4
|
TooltipProvider,
|
|
5
5
|
TooltipRoot,
|
|
@@ -9,16 +9,21 @@ import {
|
|
|
9
9
|
TooltipArrow,
|
|
10
10
|
} from 'reka-ui'
|
|
11
11
|
import type { RouteLocationRaw } from 'vue-router'
|
|
12
|
+
import { useIconSize } from '../../composables/useIconSize'
|
|
13
|
+
import type { ActionBarSize } from './types'
|
|
12
14
|
import { ACTION_BAR_CONTEXT_KEY } from './types'
|
|
13
15
|
|
|
14
16
|
interface UiActionBarItemProps {
|
|
15
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Icon class, e.g. `i-ph-trash`. Ignored when the `icon` slot is filled —
|
|
19
|
+
* use the slot for glyphs no icon class covers (emoji, an avatar, a dot).
|
|
20
|
+
*/
|
|
16
21
|
icon?: string
|
|
17
22
|
/** Visible/accessible label. Required so icon-only items stay accessible. */
|
|
18
23
|
label: string
|
|
19
24
|
/**
|
|
20
25
|
* Optional icon class rendered next to the label inside the hover tooltip —
|
|
21
|
-
* e.g. `i-
|
|
26
|
+
* e.g. `i-ph-arrow-square-out` to flag that the action opens in a new tab.
|
|
22
27
|
* Only shown for icon-only items (the tooltip is suppressed when
|
|
23
28
|
* `showLabel` is set).
|
|
24
29
|
*/
|
|
@@ -55,13 +60,20 @@ const props = withDefaults(defineProps<UiActionBarItemProps>(), {
|
|
|
55
60
|
|
|
56
61
|
const emit = defineEmits<{ click: [event: MouseEvent] }>()
|
|
57
62
|
|
|
63
|
+
// The trigger is rendered through `TooltipTrigger as-child`, which merges its
|
|
64
|
+
// own props over the child vnode — so normal attribute fallthrough never
|
|
65
|
+
// reaches the button. Read the consumer's `data-testid` explicitly, otherwise
|
|
66
|
+
// every item in a wrapped bar would share one indistinguishable test id.
|
|
67
|
+
const attrs = useAttrs()
|
|
68
|
+
const testId = computed(() => (attrs['data-testid'] as string | undefined) ?? 'ui-action-bar-item')
|
|
69
|
+
|
|
58
70
|
const ctx = inject(ACTION_BAR_CONTEXT_KEY, null)
|
|
59
71
|
const size = computed(() => ctx?.size.value ?? 'md')
|
|
60
72
|
const orientation = computed(() => ctx?.orientation.value ?? 'horizontal')
|
|
61
73
|
|
|
62
74
|
// Icon-only items get a tooltip; labeled items don't need one.
|
|
63
75
|
const showTooltip = computed(() => !props.showLabel)
|
|
64
|
-
const tooltipSide = computed(() => (orientation.value === 'vertical' ? 'right' : 'bottom'))
|
|
76
|
+
const tooltipSide = computed(() => ctx?.tooltipSide.value ?? (orientation.value === 'vertical' ? 'right' : 'bottom'))
|
|
65
77
|
|
|
66
78
|
const component = computed(() => {
|
|
67
79
|
if (props.disabled) return { is: 'button', props: { type: 'button', disabled: true } }
|
|
@@ -70,22 +82,30 @@ const component = computed(() => {
|
|
|
70
82
|
return { is: 'button', props: { type: 'button' } }
|
|
71
83
|
})
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
85
|
+
// Per-size layout classes. `square` sizes icon-only items; labeled items use
|
|
86
|
+
// `padded` and grow with their text instead of staying square. xs reuses the
|
|
87
|
+
// sm text style — the design system defines no xs one.
|
|
88
|
+
const SIZE_CLASSES: Record<ActionBarSize, { square: string, padded: string, text: string }> = {
|
|
89
|
+
xs: { square: 'size-6', padded: 'h-6 px-2 gap-1', text: 'text-action-button-sm' },
|
|
90
|
+
sm: { square: 'size-8', padded: 'h-8 px-2.5 gap-1', text: 'text-action-button-sm' },
|
|
91
|
+
md: { square: 'size-10', padded: 'h-10 px-3 gap-1.5', text: 'text-action-button-md' },
|
|
92
|
+
}
|
|
79
93
|
|
|
80
|
-
const
|
|
81
|
-
const
|
|
94
|
+
const sizeConfig = computed(() => SIZE_CLASSES[size.value])
|
|
95
|
+
const iconSizeClass = useIconSize(size)
|
|
82
96
|
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
// Everything bound on the item root: per-size layout and text classes, plus
|
|
98
|
+
// the persistent pressed background when the item is an active toggle (the
|
|
99
|
+
// dedicated neutral "active" token keeps an active-but-not-hovered toggle
|
|
100
|
+
// visually distinct from a merely hovered item).
|
|
101
|
+
const itemClasses = computed(() => [
|
|
102
|
+
props.showLabel ? sizeConfig.value.padded : sizeConfig.value.square,
|
|
103
|
+
sizeConfig.value.text,
|
|
104
|
+
{
|
|
105
|
+
'bg-actions-neutral-active-overlay': props.active === true,
|
|
106
|
+
'cursor-pointer': !props.disabled,
|
|
107
|
+
},
|
|
108
|
+
])
|
|
89
109
|
|
|
90
110
|
function onClick (event: MouseEvent) {
|
|
91
111
|
if (props.disabled) {
|
|
@@ -113,20 +133,22 @@ function onClick (event: MouseEvent) {
|
|
|
113
133
|
v-bind="component.props"
|
|
114
134
|
:aria-label="label"
|
|
115
135
|
:aria-pressed="active"
|
|
116
|
-
data-testid="
|
|
136
|
+
:data-testid="testId"
|
|
117
137
|
class="group inline-flex items-center justify-center rounded-lg shrink-0 outline-none transition-colors
|
|
118
138
|
text-actions-neutral-idle
|
|
119
139
|
hover:bg-actions-neutral-hover-overlay
|
|
120
140
|
focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus-ring
|
|
121
141
|
disabled:opacity-50 disabled:cursor-not-allowed"
|
|
122
|
-
:class="
|
|
142
|
+
:class="itemClasses"
|
|
123
143
|
@click="onClick"
|
|
124
144
|
>
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
<slot name="icon">
|
|
146
|
+
<span
|
|
147
|
+
v-if="icon"
|
|
148
|
+
:class="[icon, iconSizeClass]"
|
|
149
|
+
class="shrink-0"
|
|
150
|
+
/>
|
|
151
|
+
</slot>
|
|
130
152
|
</component>
|
|
131
153
|
</TooltipTrigger>
|
|
132
154
|
<TooltipPortal>
|
|
@@ -160,20 +182,22 @@ function onClick (event: MouseEvent) {
|
|
|
160
182
|
v-bind="component.props"
|
|
161
183
|
:aria-label="label"
|
|
162
184
|
:aria-pressed="active"
|
|
163
|
-
data-testid="
|
|
185
|
+
:data-testid="testId"
|
|
164
186
|
class="group inline-flex items-center justify-center rounded-lg shrink-0 outline-none transition-colors
|
|
165
187
|
text-actions-neutral-idle
|
|
166
188
|
hover:bg-actions-neutral-hover-overlay
|
|
167
189
|
focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus-ring
|
|
168
190
|
disabled:opacity-50 disabled:cursor-not-allowed"
|
|
169
|
-
:class="
|
|
191
|
+
:class="itemClasses"
|
|
170
192
|
@click="onClick"
|
|
171
193
|
>
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
194
|
+
<slot name="icon">
|
|
195
|
+
<span
|
|
196
|
+
v-if="icon"
|
|
197
|
+
:class="[icon, iconSizeClass]"
|
|
198
|
+
class="shrink-0"
|
|
199
|
+
/>
|
|
200
|
+
</slot>
|
|
177
201
|
<span class="whitespace-nowrap">{{ label }}</span>
|
|
178
202
|
</component>
|
|
179
203
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey } from 'vue'
|
|
2
2
|
|
|
3
3
|
export type ActionBarOrientation = 'horizontal' | 'vertical'
|
|
4
|
-
export type ActionBarSize = 'sm' | 'md'
|
|
4
|
+
export type ActionBarSize = 'xs' | 'sm' | 'md'
|
|
5
5
|
export type ActionBarPosition =
|
|
6
6
|
| 'top-left'
|
|
7
7
|
| 'top-right'
|
|
@@ -9,10 +9,12 @@ export type ActionBarPosition =
|
|
|
9
9
|
| 'center-right'
|
|
10
10
|
| 'bottom-left'
|
|
11
11
|
| 'bottom-right'
|
|
12
|
+
export type ActionBarTooltipSide = 'top' | 'right' | 'bottom' | 'left'
|
|
12
13
|
|
|
13
14
|
export interface ActionBarContext {
|
|
14
15
|
orientation: ComputedRef<ActionBarOrientation>
|
|
15
16
|
size: ComputedRef<ActionBarSize>
|
|
17
|
+
tooltipSide: ComputedRef<ActionBarTooltipSide | undefined>
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/**
|