@livestorm/ui-vue 2.0.2 → 2.0.4
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 +79 -93
- package/dist/{UiTimelineItem.vue_vue_type_style_index_0_lang-B0UKmlqE.mjs → UiTimelineItem.vue_vue_type_style_index_0_lang-BtG5oABt.mjs} +1595 -1594
- package/dist/components.mjs +1 -1
- package/dist/i18n-Cktw9hIu.mjs +49 -0
- package/dist/index.mjs +1 -1
- package/dist/integrations.mjs +10 -4
- package/dist/layouts.mjs +1 -1
- package/dist/types/src/components/Toast/ToastMessage.vue.d.ts +4 -4
- package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +2 -2
- package/dist/types/src/components/UiButton/UiButton.vue.d.ts +1 -1
- package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +1 -1
- package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +2 -2
- package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
- package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +1 -1
- package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +1 -1
- package/dist/types/src/components/UiForm/UiFormField.vue.d.ts +1 -1
- package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +5 -5
- package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +3 -3
- package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +3 -3
- package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +5 -5
- package/dist/types/src/composables/useButtonStyles.d.ts +1 -1
- package/dist/types/src/integrations/index.d.ts +1 -0
- package/dist/types/src/utils/i18n.d.ts +51 -0
- package/dist/ui-vue.css +1 -1
- package/dist/{useThemeAndModes-DY5SDC0a.mjs → useThemeAndModes-CUK56j0z.mjs} +20 -21
- package/dist/utils.mjs +55 -55
- package/integrations.d.ts +1 -0
- package/package.json +26 -19
- package/src/components/UiBanner/UiBanner.vue +4 -2
- package/src/components/UiDialog/UiDialogContent.vue +12 -4
- package/src/components/UiSideMenu/UiSideMenu.vue +4 -3
- package/src/composables/useThemeAndModes.ts +8 -4
- package/src/css/body.css +15 -7
- package/src/css/fonts.css +10 -0
- package/src/integrations/index.js +1 -0
- package/src/utils/clipboard.js +5 -2
- package/src/utils/i18n.ts +113 -0
|
@@ -1,58 +1,57 @@
|
|
|
1
|
-
import { useStorage as
|
|
2
|
-
import { ref as E, computed as d, watch as f } from "vue";
|
|
3
|
-
import { useRoute as b } from "vue-router";
|
|
1
|
+
import { useStorage as A } from "@vueuse/core";
|
|
2
|
+
import { ref as E, computed as d, watch as f, getCurrentInstance as b } from "vue";
|
|
4
3
|
const T = {
|
|
5
4
|
LIVESTORM: "Livestorm",
|
|
6
5
|
CUSTOMER1: "customer1",
|
|
7
6
|
CUSTOMER2: "customer2",
|
|
8
7
|
CUSTOMER3: "customer3"
|
|
9
|
-
},
|
|
8
|
+
}, p = {
|
|
10
9
|
LIGHT: "light",
|
|
11
10
|
DARK: "dark"
|
|
12
|
-
}, y = Object.values(T), C = Object.values(
|
|
11
|
+
}, y = Object.values(T), C = Object.values(p);
|
|
13
12
|
Object.fromEntries(
|
|
14
13
|
Object.entries(T).map(([e, t]) => [e.toLowerCase(), t])
|
|
15
14
|
);
|
|
16
15
|
const I = ["signup", "signin", "forgot-password", "reset-password"], R = {
|
|
17
16
|
theme: T.LIVESTORM,
|
|
18
|
-
mode:
|
|
19
|
-
contentMode:
|
|
20
|
-
}, i = E(/* @__PURE__ */ new Map()),
|
|
17
|
+
mode: p.DARK,
|
|
18
|
+
contentMode: p.LIGHT
|
|
19
|
+
}, i = E(/* @__PURE__ */ new Map()), v = E(/* @__PURE__ */ new Map()), o = A(
|
|
21
20
|
"themeAndMode",
|
|
22
21
|
R
|
|
23
22
|
);
|
|
24
|
-
function
|
|
23
|
+
function k({ themeOverride: e, modeOverride: t, contentModeOverride: n } = {}) {
|
|
25
24
|
const s = !!(e || t || n), a = e || o.value.theme, r = t || o.value.mode, S = n || o.value.contentMode;
|
|
26
25
|
function O() {
|
|
27
26
|
document.querySelector("body").setAttribute("data-colors-primitive", a), document.querySelector("body").setAttribute("data-colors-semantic", r), H();
|
|
28
27
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
28
|
+
function g() {
|
|
29
|
+
const l = () => t || o.value.mode, c = () => n || o.value.contentMode;
|
|
31
30
|
f(
|
|
32
31
|
() => Array.from(i.value.values()),
|
|
33
|
-
() => D({ mode:
|
|
32
|
+
() => D({ mode: l(), hasOverrides: s }),
|
|
34
33
|
{ immediate: !0 }
|
|
35
34
|
), f(
|
|
36
|
-
() => Array.from(
|
|
35
|
+
() => Array.from(v.value.values()),
|
|
37
36
|
() => M({ mode: c(), hasOverrides: s }),
|
|
38
37
|
{ immediate: !0 }
|
|
39
38
|
);
|
|
40
|
-
const
|
|
39
|
+
const m = b();
|
|
41
40
|
f(
|
|
42
|
-
() =>
|
|
41
|
+
() => m?.appContext.config.globalProperties.$route?.name,
|
|
43
42
|
(u) => {
|
|
44
43
|
u && I.includes(u.toString()) && M({ mode: c(), hasOverrides: s });
|
|
45
44
|
},
|
|
46
45
|
{ immediate: !0 }
|
|
47
46
|
);
|
|
48
47
|
}
|
|
49
|
-
function
|
|
50
|
-
(
|
|
48
|
+
function h(l, { selector: c, element: m, modeOverride: u }) {
|
|
49
|
+
(l === "mode" ? i : v).value.set(c, { element: m, modeOverride: u });
|
|
51
50
|
}
|
|
52
51
|
return {
|
|
53
52
|
initOnAppMounted: O,
|
|
54
|
-
registerWatchers:
|
|
55
|
-
addElementToWatch:
|
|
53
|
+
registerWatchers: g,
|
|
54
|
+
addElementToWatch: h,
|
|
56
55
|
updateContentMode: w,
|
|
57
56
|
updateTheme: L,
|
|
58
57
|
updateMode: _,
|
|
@@ -87,7 +86,7 @@ function D({ mode: e, hasOverrides: t = !1 }) {
|
|
|
87
86
|
}
|
|
88
87
|
function M({ mode: e, hasOverrides: t = !1, ignoreElementOverrides: n = !1 }) {
|
|
89
88
|
t || (o.value.contentMode = e);
|
|
90
|
-
for (const { element: s, modeOverride: a } of
|
|
89
|
+
for (const { element: s, modeOverride: a } of v.value.values()) {
|
|
91
90
|
const r = n ? e : a || e;
|
|
92
91
|
s.setAttribute("data-colors-semantic", r);
|
|
93
92
|
}
|
|
@@ -105,5 +104,5 @@ function H() {
|
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
export {
|
|
108
|
-
|
|
107
|
+
k as u
|
|
109
108
|
};
|
package/dist/utils.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { BREAKPOINT_2XL as F, BREAKPOINT_LG as N, BREAKPOINT_MD as X, BREAKPOINT_SM as D, BREAKPOINT_XL as Q, BREAKPOINT_XL_PLUS as U } from "./breakpoints.mjs";
|
|
2
2
|
import "./bus.mjs";
|
|
3
|
-
import { computed as h, createApp as _, h as
|
|
3
|
+
import { computed as h, createApp as _, h as f } from "vue";
|
|
4
4
|
import { useClipboard as g, usePermission as x } from "@vueuse/core";
|
|
5
|
-
import R from "
|
|
6
|
-
import { b as A, _ as C, c as
|
|
5
|
+
import { u as R } from "./i18n-Cktw9hIu.mjs";
|
|
6
|
+
import { b as A, _ as C, c as T, a as P } from "./a11y--y7uaY4j.mjs";
|
|
7
7
|
import { f as j, h as G, d as z, u as H } from "./a11y--y7uaY4j.mjs";
|
|
8
8
|
import { useResponsive as Y } from "./responsive.mjs";
|
|
9
9
|
import { useRoute as $, useRouter as S } from "vue-router";
|
|
10
10
|
import { RenderSlot as ee, getSlotAsComponent as te, unwrapFragments as oe, useSlotsAsComponents as ne } from "./slot.mjs";
|
|
11
11
|
let d = null;
|
|
12
|
-
function k(
|
|
12
|
+
function k(n, c) {
|
|
13
13
|
d && d();
|
|
14
|
-
const t =
|
|
15
|
-
document.body.appendChild(
|
|
16
|
-
const
|
|
17
|
-
render: () =>
|
|
18
|
-
|
|
14
|
+
const t = n.getBoundingClientRect(), s = document.createElement("div");
|
|
15
|
+
document.body.appendChild(s);
|
|
16
|
+
const a = _({
|
|
17
|
+
render: () => f(A, null, () => f(C, { open: !0, delayDuration: 0 }, () => [
|
|
18
|
+
f(T, { asChild: !0 }, () => f("span", {
|
|
19
19
|
"aria-hidden": "true",
|
|
20
20
|
style: {
|
|
21
21
|
position: "fixed",
|
|
@@ -26,11 +26,11 @@ function k(s, u) {
|
|
|
26
26
|
pointerEvents: "none"
|
|
27
27
|
}
|
|
28
28
|
})),
|
|
29
|
-
|
|
29
|
+
f(P, { side: "top" }, () => c),
|
|
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
|
+
f("span", {
|
|
34
34
|
role: "status",
|
|
35
35
|
style: {
|
|
36
36
|
position: "absolute",
|
|
@@ -39,81 +39,81 @@ function k(s, u) {
|
|
|
39
39
|
overflow: "hidden",
|
|
40
40
|
clipPath: "inset(50%)"
|
|
41
41
|
}
|
|
42
|
-
},
|
|
42
|
+
}, c)
|
|
43
43
|
]))
|
|
44
44
|
});
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
const
|
|
48
|
-
|
|
45
|
+
a.mount(s);
|
|
46
|
+
let p = !1;
|
|
47
|
+
const r = () => {
|
|
48
|
+
p || (p = !0, d === r && (d = null), a.unmount(), s.remove());
|
|
49
49
|
};
|
|
50
|
-
return d =
|
|
50
|
+
return d = r, r;
|
|
51
51
|
}
|
|
52
52
|
function O() {
|
|
53
|
-
const { isSupported:
|
|
54
|
-
async function
|
|
55
|
-
if (await
|
|
56
|
-
|
|
57
|
-
const
|
|
53
|
+
const { isSupported: n, copy: c } = g(), t = x("clipboard-write"), s = R(), a = h(() => n.value && t.value);
|
|
54
|
+
async function p(r, i, m = s("general_misc_copied-text")) {
|
|
55
|
+
if (await c(r), i) {
|
|
56
|
+
i.classList.add("copied");
|
|
57
|
+
const e = k(i, m);
|
|
58
58
|
setTimeout(() => {
|
|
59
|
-
|
|
59
|
+
i.classList.remove("copied"), e();
|
|
60
60
|
}, 600);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
return {
|
|
64
|
-
canCopy:
|
|
65
|
-
copy:
|
|
64
|
+
canCopy: a,
|
|
65
|
+
copy: p
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
-
function q(
|
|
69
|
-
const t = $(),
|
|
70
|
-
function
|
|
68
|
+
function q(n, c = !1) {
|
|
69
|
+
const t = $(), s = S(), a = `${n}-`;
|
|
70
|
+
function p() {
|
|
71
71
|
const e = [];
|
|
72
|
-
for (const
|
|
73
|
-
|
|
72
|
+
for (const o in t.query)
|
|
73
|
+
o.startsWith(a) && e.push(o);
|
|
74
74
|
return e;
|
|
75
75
|
}
|
|
76
|
-
function
|
|
76
|
+
function r(e) {
|
|
77
77
|
return e === "true" ? !0 : e === "false" ? !1 : e ?? !1;
|
|
78
78
|
}
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
const e =
|
|
79
|
+
const i = h(() => {
|
|
80
|
+
if (c) {
|
|
81
|
+
const e = p();
|
|
82
82
|
if (e.length === 0)
|
|
83
83
|
return !1;
|
|
84
|
-
const
|
|
85
|
-
for (const
|
|
86
|
-
|
|
87
|
-
return
|
|
84
|
+
const o = {};
|
|
85
|
+
for (const u of e)
|
|
86
|
+
o[u.substring(a.length)] = r(t.query[u]);
|
|
87
|
+
return o;
|
|
88
88
|
} else
|
|
89
|
-
return
|
|
90
|
-
}), m = !!
|
|
89
|
+
return r(t.query[n]);
|
|
90
|
+
}), m = !!i.value;
|
|
91
91
|
return h({
|
|
92
|
-
get: () =>
|
|
92
|
+
get: () => i.value,
|
|
93
93
|
set: (e) => {
|
|
94
|
-
if (e ===
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
|
|
94
|
+
if (e === i.value) return;
|
|
95
|
+
const o = e == null || e === !1;
|
|
96
|
+
if (o && !m)
|
|
97
|
+
s.back();
|
|
98
98
|
else {
|
|
99
|
-
let
|
|
100
|
-
if (
|
|
101
|
-
if (
|
|
102
|
-
const l =
|
|
99
|
+
let u;
|
|
100
|
+
if (c)
|
|
101
|
+
if (u = {}, o) {
|
|
102
|
+
const l = p();
|
|
103
103
|
for (const y of l)
|
|
104
|
-
|
|
104
|
+
u[y] = void 0;
|
|
105
105
|
} else
|
|
106
106
|
for (const l in e)
|
|
107
|
-
|
|
107
|
+
u[`${n}-${l}`] = e[l];
|
|
108
108
|
else
|
|
109
|
-
|
|
110
|
-
[
|
|
109
|
+
u = {
|
|
110
|
+
[n]: o ? void 0 : e
|
|
111
111
|
};
|
|
112
|
-
|
|
112
|
+
s[o ? "replace" : "push"]({
|
|
113
113
|
...t,
|
|
114
114
|
query: {
|
|
115
115
|
...t.query,
|
|
116
|
-
...
|
|
116
|
+
...u
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
119
|
}
|
package/integrations.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestorm/ui-vue",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "Livestorm UI components for Vue 3",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -37,21 +37,20 @@
|
|
|
37
37
|
"embla-carousel-vue": "^8.6.0",
|
|
38
38
|
"i18next": "^26.3.4",
|
|
39
39
|
"mitt": "^3.0.1",
|
|
40
|
-
"reka-ui": "2.9.10",
|
|
41
|
-
"
|
|
42
|
-
"@livestorm/ui-
|
|
43
|
-
"@livestorm/ui-icons": "^2.0.2"
|
|
40
|
+
"reka-ui": "^2.9.10",
|
|
41
|
+
"@livestorm/ui-tokens": "^2.0.4",
|
|
42
|
+
"@livestorm/ui-icons": "^2.0.4"
|
|
44
43
|
},
|
|
45
44
|
"devDependencies": {
|
|
46
45
|
"@chromatic-com/storybook": "^5.2.1",
|
|
47
|
-
"@storybook/addon-a11y": "^10.
|
|
48
|
-
"@storybook/addon-coverage": "^3.0.
|
|
49
|
-
"@storybook/addon-designs": "^11.1.
|
|
50
|
-
"@storybook/addon-docs": "^10.
|
|
51
|
-
"@storybook/addon-links": "^10.
|
|
52
|
-
"@storybook/addon-themes": "^10.
|
|
53
|
-
"@storybook/addon-vitest": "^10.
|
|
54
|
-
"@storybook/vue3-vite": "^10.
|
|
46
|
+
"@storybook/addon-a11y": "^10.5.5",
|
|
47
|
+
"@storybook/addon-coverage": "^3.0.2",
|
|
48
|
+
"@storybook/addon-designs": "^11.1.4",
|
|
49
|
+
"@storybook/addon-docs": "^10.5.5",
|
|
50
|
+
"@storybook/addon-links": "^10.5.5",
|
|
51
|
+
"@storybook/addon-themes": "^10.5.5",
|
|
52
|
+
"@storybook/addon-vitest": "^10.5.5",
|
|
53
|
+
"@storybook/vue3-vite": "^10.5.5",
|
|
55
54
|
"@tailwindcss/vite": "^4.3.2",
|
|
56
55
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
57
56
|
"@vitejs/plugin-vue-jsx": "^5.1.6",
|
|
@@ -60,25 +59,32 @@
|
|
|
60
59
|
"@vitest/coverage-v8": "^4.1.9",
|
|
61
60
|
"@vitest/ui": "^4.1.9",
|
|
62
61
|
"@vue/test-utils": "^2.4.11",
|
|
63
|
-
"chromatic": "^
|
|
62
|
+
"chromatic": "^18.1.0",
|
|
64
63
|
"eslint": "^9.39.4",
|
|
65
|
-
"eslint-plugin-storybook": "^10.
|
|
64
|
+
"eslint-plugin-storybook": "^10.5.5",
|
|
66
65
|
"happy-dom": "^20.10.6",
|
|
67
66
|
"playwright": "^1.61.1",
|
|
68
|
-
"storybook": "^10.
|
|
69
|
-
"
|
|
67
|
+
"storybook": "^10.5.5",
|
|
68
|
+
"tailwindcss": "^4.3.2",
|
|
69
|
+
"typescript": "^6.0.3",
|
|
70
70
|
"vite": "^7.3.6",
|
|
71
71
|
"vitest": "^4.1.9",
|
|
72
72
|
"vitest-browser-vue": "^2.1.0",
|
|
73
73
|
"vue": "^3.5.39",
|
|
74
74
|
"vue-router": "^5.1.0",
|
|
75
|
-
"vue-tsc": "^3.3.
|
|
75
|
+
"vue-tsc": "^3.3.8",
|
|
76
76
|
"@livestorm/dev-utils": "1.0.0"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
|
+
"tailwindcss": "^4.0.0",
|
|
79
80
|
"vue": "^3.5.30",
|
|
80
81
|
"vue-router": "^5.0.3"
|
|
81
82
|
},
|
|
83
|
+
"peerDependenciesMeta": {
|
|
84
|
+
"vue-router": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
82
88
|
"exports": {
|
|
83
89
|
".": {
|
|
84
90
|
"types": "./dist/types/index.d.ts",
|
|
@@ -88,6 +94,7 @@
|
|
|
88
94
|
"types": "./dist/types/src/theme.d.ts"
|
|
89
95
|
},
|
|
90
96
|
"./style": "./dist/ui-vue.css",
|
|
97
|
+
"./fonts": "./src/css/fonts.css",
|
|
91
98
|
"./components-vite": {
|
|
92
99
|
"types": "./components.d.ts",
|
|
93
100
|
"import": "./dist/components.mjs"
|
|
@@ -144,7 +151,7 @@
|
|
|
144
151
|
"test:vitest:updateSnapshots": "vitest -u",
|
|
145
152
|
"test:npm-package": "bash tests/npm-package/run.sh",
|
|
146
153
|
"npm-package:gallery": "bash tests/npm-package/run.sh --gallery",
|
|
147
|
-
"deploy:chromatic": "
|
|
154
|
+
"deploy:chromatic": "chromatic",
|
|
148
155
|
"setup-reka-paths": "node setup-reka-ui-paths.js",
|
|
149
156
|
"storybook:dev": "pnpm run setup-reka-paths && storybook dev -p 6006",
|
|
150
157
|
"storybook:build": "storybook build --stats-json"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, onMounted, ref } from 'vue'
|
|
3
3
|
import { useLocalStorage } from '@vueuse/core'
|
|
4
4
|
import UiButton from '../UiButton/UiButton.vue'
|
|
5
|
-
import
|
|
5
|
+
import { useTranslate } from '../../utils/i18n'
|
|
6
6
|
|
|
7
7
|
export interface UiBannerProps {
|
|
8
8
|
/**
|
|
@@ -60,6 +60,8 @@ export interface UiBannerProps {
|
|
|
60
60
|
closedExpirySeconds?: number
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
const translate = useTranslate()
|
|
64
|
+
|
|
63
65
|
const props = withDefaults(defineProps<UiBannerProps>(), {
|
|
64
66
|
color: 'primary',
|
|
65
67
|
variant: 'horizontal',
|
|
@@ -350,7 +352,7 @@ function handleAction () {
|
|
|
350
352
|
:class="closeButtonClasses"
|
|
351
353
|
>
|
|
352
354
|
<UiButton
|
|
353
|
-
:label="
|
|
355
|
+
:label="translate('general_close')"
|
|
354
356
|
variant="tertiary"
|
|
355
357
|
color="neutral"
|
|
356
358
|
icon="i-ls-x"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useMutationObserver, useThrottleFn } from '@vueuse/core'
|
|
3
|
-
import i18n from 'i18next'
|
|
4
3
|
import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
|
|
5
4
|
import {
|
|
6
5
|
DialogContent,
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
VisuallyHidden,
|
|
13
12
|
} from 'reka-ui'
|
|
14
13
|
import { computed, ref, useAttrs, watch } from 'vue'
|
|
14
|
+
import { useTranslate } from '../../utils/i18n'
|
|
15
15
|
import UiDialogClose from './UiDialogClose.vue'
|
|
16
16
|
|
|
17
17
|
interface UiDialogContentProps extends DialogContentProps {
|
|
@@ -32,7 +32,7 @@ const props = withDefaults(defineProps<UiDialogContentProps>(), {
|
|
|
32
32
|
title: undefined,
|
|
33
33
|
description: undefined,
|
|
34
34
|
hideClose: false,
|
|
35
|
-
closeButtonAriaLabel:
|
|
35
|
+
closeButtonAriaLabel: undefined,
|
|
36
36
|
overlayClass: '',
|
|
37
37
|
contentMode: 'light',
|
|
38
38
|
closeButtonMode: undefined,
|
|
@@ -69,12 +69,20 @@ function checkScroll () {
|
|
|
69
69
|
|
|
70
70
|
const throttledCheckScroll = useThrottleFn(checkScroll, 100)
|
|
71
71
|
|
|
72
|
+
const translate = useTranslate()
|
|
73
|
+
|
|
74
|
+
// Resolved at render time (not as a static prop default): the translation
|
|
75
|
+
// must follow the app-provided translator and the active locale.
|
|
76
|
+
const closeAriaLabel = computed(
|
|
77
|
+
() => props.closeButtonAriaLabel ?? translate('general_close'),
|
|
78
|
+
)
|
|
79
|
+
|
|
72
80
|
const attrs = useAttrs();
|
|
73
81
|
const accessibleTitle = computed(
|
|
74
82
|
() =>
|
|
75
83
|
props.title ||
|
|
76
84
|
(attrs['aria-label'] as string) ||
|
|
77
|
-
|
|
85
|
+
translate('general_dialog_title'),
|
|
78
86
|
);
|
|
79
87
|
const accessibleDescription = computed(
|
|
80
88
|
() =>
|
|
@@ -150,7 +158,7 @@ useMutationObserver(contentRef, () => {
|
|
|
150
158
|
|
|
151
159
|
<UiDialogClose
|
|
152
160
|
v-if="!hideClose"
|
|
153
|
-
:aria-label="
|
|
161
|
+
:aria-label="closeAriaLabel"
|
|
154
162
|
:mode="closeButtonMode ?? contentMode"
|
|
155
163
|
:class="{
|
|
156
164
|
'ml-4': !noPadding
|
|
@@ -8,11 +8,12 @@ import UiPopover from '../UiPopover/UiPopover.vue'
|
|
|
8
8
|
import UiPopoverTrigger from '../UiPopover/UiPopoverTrigger.vue'
|
|
9
9
|
import UiPopoverContent from '../UiPopover/UiPopoverContent.vue'
|
|
10
10
|
import { useMobileMenu } from '../../composables/useMobileMenu'
|
|
11
|
-
import
|
|
11
|
+
import { useTranslate } from '../../utils/i18n'
|
|
12
12
|
import { focusFirstMenuItem } from '../../utils'
|
|
13
13
|
import { computed, onBeforeUnmount, onMounted, provide, ref } from 'vue'
|
|
14
14
|
import { SIDE_MENU_LAYOUT_KEY } from './injection'
|
|
15
15
|
const { close, isOpen } = useMobileMenu()
|
|
16
|
+
const translate = useTranslate()
|
|
16
17
|
|
|
17
18
|
// State for the responsive (short-height) more menu popover, which surfaces
|
|
18
19
|
// the otherwise-hidden #bottom slot items.
|
|
@@ -287,7 +288,7 @@ function handleLogoClick (event: MouseEvent) {
|
|
|
287
288
|
<UiPopover v-model:open="isCollapsedMenuOpen">
|
|
288
289
|
<UiPopoverTrigger class="w-full cursor-pointer">
|
|
289
290
|
<UiSideMenuItem
|
|
290
|
-
:label="
|
|
291
|
+
:label="translate('room_bottom-bar_controls-label_more')"
|
|
291
292
|
icon="i-ls-more-horizontal"
|
|
292
293
|
:is-active="false"
|
|
293
294
|
:inside-interactive="true"
|
|
@@ -418,7 +419,7 @@ function handleLogoClick (event: MouseEvent) {
|
|
|
418
419
|
>
|
|
419
420
|
<UiPopoverTrigger class="cursor-pointer">
|
|
420
421
|
<UiSideMenuItem
|
|
421
|
-
:label="
|
|
422
|
+
:label="translate('room_bottom-bar_controls-label_more')"
|
|
422
423
|
icon="i-ls-more-vertical"
|
|
423
424
|
:is-active="false"
|
|
424
425
|
:inside-interactive="true"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useStorage } from '@vueuse/core'
|
|
2
|
-
import { computed, ref, watch } from 'vue'
|
|
3
|
-
import { useRoute } from 'vue-router'
|
|
2
|
+
import { computed, getCurrentInstance, ref, watch } from 'vue'
|
|
4
3
|
import {
|
|
5
4
|
THEME_LIST,
|
|
6
5
|
MODE_OPTIONS,
|
|
@@ -82,10 +81,15 @@ export default function useThemeAndModes (
|
|
|
82
81
|
{ immediate: true }
|
|
83
82
|
)
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
// vue-router is an optional peer: read the route from the app's global
|
|
85
|
+
// properties (which the router installs as $route) instead of importing
|
|
86
|
+
// vue-router, so the package resolves without it. Without a router the
|
|
87
|
+
// getter stays undefined and this watcher is simply inert. Same pattern
|
|
88
|
+
// as the $responsive fallback in UiPage/LayoutToasts.
|
|
89
|
+
const instance = getCurrentInstance()
|
|
86
90
|
|
|
87
91
|
watch(
|
|
88
|
-
() => route?.name,
|
|
92
|
+
() => instance?.appContext.config.globalProperties.$route?.name,
|
|
89
93
|
(routeName) => {
|
|
90
94
|
if (!routeName) { return }
|
|
91
95
|
if (ROUTES_TO_WATCH.includes(routeName.toString() as typeof ROUTES_TO_WATCH[number])) {
|
package/src/css/body.css
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
@reference '@livestorm/ui-tokens/output/supernova/index.css';
|
|
2
|
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
/*
|
|
4
|
+
Layered so the host app always wins: an unlayered rule (or the app's own
|
|
5
|
+
@layer base rules, declared after this import) overrides these defaults.
|
|
6
|
+
Without the layer, this body rule would beat a Tailwind v4 app's
|
|
7
|
+
`@layer base` typography no matter the import order.
|
|
8
|
+
The Inter font itself is NOT loaded here — see fonts.css.
|
|
9
|
+
*/
|
|
10
|
+
@layer base {
|
|
11
|
+
body {
|
|
12
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
13
|
+
font-size: 14px;
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
font-weight: 400;
|
|
16
|
+
color: var(--color-grey-700);
|
|
17
|
+
}
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
/*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Inter via Google Fonts — kept OUT of the base stylesheet (./style) on
|
|
3
|
+
purpose: a third-party font request must be the consumer's choice (GDPR,
|
|
4
|
+
self-hosting). Apps that want the quick path import this file once:
|
|
5
|
+
|
|
6
|
+
import '@livestorm/ui-vue/fonts'
|
|
7
|
+
|
|
8
|
+
The monorepo keeps loading it through ui-vue-legacy's style chain.
|
|
9
|
+
*/
|
|
10
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
|
package/src/utils/clipboard.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed, createApp, h } from 'vue'
|
|
2
2
|
import { useClipboard, usePermission } from '@vueuse/core'
|
|
3
|
-
import
|
|
3
|
+
import { useTranslate } from './i18n'
|
|
4
4
|
|
|
5
5
|
import UiTooltipProvider from '../components/UiTooltip/UiTooltipProvider.vue'
|
|
6
6
|
import UiTooltip from '../components/UiTooltip/UiTooltip.vue'
|
|
@@ -82,10 +82,13 @@ function flashTooltip (el, text) {
|
|
|
82
82
|
export function useCopyToClipboard () {
|
|
83
83
|
const { isSupported, copy: _copy } = useClipboard()
|
|
84
84
|
const permissionClipboardWrite = usePermission('clipboard-write')
|
|
85
|
+
// Captured at composable time so an app-provided UI_VUE_TRANSLATOR is
|
|
86
|
+
// honored; copy() itself runs later, in event handlers.
|
|
87
|
+
const translate = useTranslate()
|
|
85
88
|
|
|
86
89
|
const canCopy = computed(() => isSupported.value && permissionClipboardWrite.value)
|
|
87
90
|
|
|
88
|
-
async function copy (text, el, tooltipText =
|
|
91
|
+
async function copy (text, el, tooltipText = translate('general_misc_copied-text')) {
|
|
89
92
|
await _copy(text)
|
|
90
93
|
|
|
91
94
|
if (el) {
|