@livestorm/ui-vue 2.0.0 → 2.0.2
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 +16 -14
- package/dist/{UiTimelineItem.vue_vue_type_style_index_0_lang-DOLFRKcb.mjs → UiTimelineItem.vue_vue_type_style_index_0_lang-B0UKmlqE.mjs} +1158 -1270
- package/dist/a11y--y7uaY4j.mjs +217 -0
- package/dist/components.mjs +73 -72
- package/dist/index.mjs +28 -27
- package/dist/layouts.mjs +27 -26
- package/dist/responsive.mjs +33 -19
- package/dist/types/src/components/UiButton/UiButton.vue.d.ts +31 -0
- package/dist/types/src/components/UiDropdown/UiDropdown.vue.d.ts +2 -2
- package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +4 -4
- package/dist/types/src/components/UiTooltip/UiTooltip.vue.d.ts +28 -5
- package/dist/types/src/utils/responsive.d.ts +9 -1
- package/dist/ui-vue.css +1 -1
- package/dist/utils.mjs +117 -82
- package/package.json +3 -5
- package/src/components/Toast/LayoutToasts.vue +4 -1
- package/src/components/UiButton/UiButton.vue +49 -46
- package/src/components/UiFieldWrapper/UiFieldWrapper.vue +7 -5
- package/src/components/UiInputCheckbox/UiInputCheckbox.vue +14 -10
- package/src/components/UiLabel/UiLabel.vue +11 -9
- package/src/components/UiPage/UiPage.vue +4 -1
- package/src/components/UiTooltip/UiTooltip.vue +56 -4
- package/src/utils/clipboard.js +80 -13
- package/src/utils/responsive.js +70 -16
- package/dist/a11y-DIdrv5Mn.mjs +0 -66
package/src/utils/clipboard.js
CHANGED
|
@@ -1,7 +1,83 @@
|
|
|
1
|
-
import { computed } from 'vue'
|
|
1
|
+
import { computed, createApp, h } from 'vue'
|
|
2
2
|
import { useClipboard, usePermission } from '@vueuse/core'
|
|
3
3
|
import i18n from 'i18next'
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import UiTooltipProvider from '../components/UiTooltip/UiTooltipProvider.vue'
|
|
6
|
+
import UiTooltip from '../components/UiTooltip/UiTooltip.vue'
|
|
7
|
+
import UiTooltipTrigger from '../components/UiTooltip/UiTooltipTrigger.vue'
|
|
8
|
+
import UiTooltipContent from '../components/UiTooltip/UiTooltipContent.vue'
|
|
9
|
+
|
|
10
|
+
let hideActiveFlash = null
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Transient "Copied!" flash above an element, rendered with the design
|
|
14
|
+
* system's own UiTooltip family so the bubble, arrow and positioning stay
|
|
15
|
+
* identical to every other tooltip. The copy() API is imperative and
|
|
16
|
+
* receives a raw DOM element, so the tooltip cannot wrap the caller's
|
|
17
|
+
* markup: instead a throwaway Vue app drives a controlled-open tooltip
|
|
18
|
+
* whose invisible trigger is overlaid on the element's current rect.
|
|
19
|
+
*/
|
|
20
|
+
function flashTooltip (el, text) {
|
|
21
|
+
// A copy triggered before the previous flash ended replaces it instead of
|
|
22
|
+
// stacking a second bubble on top.
|
|
23
|
+
if (hideActiveFlash) {
|
|
24
|
+
hideActiveFlash()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const rect = el.getBoundingClientRect()
|
|
28
|
+
const host = document.createElement('div')
|
|
29
|
+
document.body.appendChild(host)
|
|
30
|
+
|
|
31
|
+
const app = createApp({
|
|
32
|
+
render: () => h(UiTooltipProvider, null, () =>
|
|
33
|
+
h(UiTooltip, { open: true, delayDuration: 0 }, () => [
|
|
34
|
+
h(UiTooltipTrigger, { asChild: true }, () =>
|
|
35
|
+
h('span', {
|
|
36
|
+
'aria-hidden': 'true',
|
|
37
|
+
style: {
|
|
38
|
+
position: 'fixed',
|
|
39
|
+
left: `${rect.left}px`,
|
|
40
|
+
top: `${rect.top}px`,
|
|
41
|
+
width: `${rect.width}px`,
|
|
42
|
+
height: `${rect.height}px`,
|
|
43
|
+
pointerEvents: 'none',
|
|
44
|
+
},
|
|
45
|
+
})),
|
|
46
|
+
h(UiTooltipContent, { side: 'top' }, () => text),
|
|
47
|
+
// The bubble lives in reka's portal where attrs like role are not
|
|
48
|
+
// forwardable; announce the feedback from a visually hidden live
|
|
49
|
+
// region instead so screen readers hear the copy confirmation.
|
|
50
|
+
h('span', {
|
|
51
|
+
role: 'status',
|
|
52
|
+
style: {
|
|
53
|
+
position: 'absolute',
|
|
54
|
+
width: '1px',
|
|
55
|
+
height: '1px',
|
|
56
|
+
overflow: 'hidden',
|
|
57
|
+
clipPath: 'inset(50%)',
|
|
58
|
+
},
|
|
59
|
+
}, text),
|
|
60
|
+
])),
|
|
61
|
+
})
|
|
62
|
+
app.mount(host)
|
|
63
|
+
|
|
64
|
+
// Idempotent: the replace-guard above may spend a flash's hide before its
|
|
65
|
+
// own copy() timer fires it a second time.
|
|
66
|
+
let hidden = false
|
|
67
|
+
const hide = () => {
|
|
68
|
+
if (hidden) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
hidden = true
|
|
72
|
+
if (hideActiveFlash === hide) {
|
|
73
|
+
hideActiveFlash = null
|
|
74
|
+
}
|
|
75
|
+
app.unmount()
|
|
76
|
+
host.remove()
|
|
77
|
+
}
|
|
78
|
+
hideActiveFlash = hide
|
|
79
|
+
return hide
|
|
80
|
+
}
|
|
5
81
|
|
|
6
82
|
export function useCopyToClipboard () {
|
|
7
83
|
const { isSupported, copy: _copy } = useClipboard()
|
|
@@ -14,19 +90,10 @@ export function useCopyToClipboard () {
|
|
|
14
90
|
|
|
15
91
|
if (el) {
|
|
16
92
|
el.classList.add('copied')
|
|
17
|
-
const
|
|
18
|
-
triggers: [],
|
|
19
|
-
content: tooltipText,
|
|
20
|
-
delay: 0,
|
|
21
|
-
})
|
|
22
|
-
tooltip.show()
|
|
93
|
+
const hideTooltip = flashTooltip(el, tooltipText)
|
|
23
94
|
setTimeout(() => {
|
|
24
95
|
el.classList.remove('copied')
|
|
25
|
-
|
|
26
|
-
// Transition
|
|
27
|
-
setTimeout(() => {
|
|
28
|
-
destroyTooltip(el)
|
|
29
|
-
}, 400)
|
|
96
|
+
hideTooltip()
|
|
30
97
|
}, 600)
|
|
31
98
|
}
|
|
32
99
|
}
|
package/src/utils/responsive.js
CHANGED
|
@@ -1,9 +1,75 @@
|
|
|
1
1
|
import { reactive, computed } from 'vue'
|
|
2
2
|
import generateFlags from './devices'
|
|
3
|
+
import { BREAKPOINT_MD, BREAKPOINT_LG, BREAKPOINT_XL_PLUS } from './breakpoints'
|
|
3
4
|
|
|
4
5
|
let responsive
|
|
5
6
|
|
|
7
|
+
// Under SSR there is no viewport: the server renders a desktop-sized static
|
|
8
|
+
// snapshot. To keep hydration safe, the client's lazy singleton starts from
|
|
9
|
+
// the SAME snapshot (identical trees during the hydration pass) and syncs to
|
|
10
|
+
// the real viewport in a microtask, which runs after hydration completes but
|
|
11
|
+
// before the first paint.
|
|
12
|
+
const SSR_WIDTH = 1280
|
|
13
|
+
const SSR_HEIGHT = 800
|
|
14
|
+
|
|
15
|
+
// Default flags, derived from the design system breakpoints. An app installing
|
|
16
|
+
// the Responsive plugin can override any of them via `options.computed`.
|
|
17
|
+
const DEFAULT_FLAGS = {
|
|
18
|
+
mobile: state => state.width < BREAKPOINT_MD,
|
|
19
|
+
tablet: state => state.width < BREAKPOINT_LG,
|
|
20
|
+
smallDesktop: state => state.width < BREAKPOINT_XL_PLUS,
|
|
21
|
+
desktop: state => state.width >= BREAKPOINT_LG,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function createResponsive (customComputed = {}, { deferViewportSync = false } = {}) {
|
|
25
|
+
const isClient = typeof window !== 'undefined'
|
|
26
|
+
const readViewportNow = isClient && !deferViewportSync
|
|
27
|
+
|
|
28
|
+
const state = reactive({
|
|
29
|
+
width: readViewportNow ? window.innerWidth : SSR_WIDTH,
|
|
30
|
+
height: readViewportNow ? window.innerHeight : SSR_HEIGHT,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const derived = { ...DEFAULT_FLAGS, ...customComputed }
|
|
34
|
+
for (const key in derived) {
|
|
35
|
+
// Assigning a computed ref onto a reactive object stores it unwrapped:
|
|
36
|
+
// consumers read plain booleans while reactivity is preserved.
|
|
37
|
+
state[key] = computed(() => derived[key](state))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isClient) {
|
|
41
|
+
const sync = () => {
|
|
42
|
+
state.width = window.innerWidth
|
|
43
|
+
state.height = window.innerHeight
|
|
44
|
+
}
|
|
45
|
+
if (deferViewportSync) {
|
|
46
|
+
// Runs after the synchronous hydration pass but before the first
|
|
47
|
+
// paint: server HTML and client hydration tree stay identical, then a
|
|
48
|
+
// normal reactive update applies the real viewport with no visible
|
|
49
|
+
// flash for client-only apps either.
|
|
50
|
+
queueMicrotask(sync)
|
|
51
|
+
}
|
|
52
|
+
window.addEventListener('resize', sync)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return state
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Viewport state shared by the whole app. Lazily created on first use, so
|
|
60
|
+
* components work with no plugin registration: installing the Responsive
|
|
61
|
+
* plugin is only needed to customize the flags or to read `$responsive`
|
|
62
|
+
* in templates.
|
|
63
|
+
*
|
|
64
|
+
* @returns {import('./responsive.types').ResponsiveGlobalComponentProperty}
|
|
65
|
+
*/
|
|
6
66
|
export function useResponsive () {
|
|
67
|
+
if (!responsive) {
|
|
68
|
+
// Deferred viewport sync keeps SSR hydration safe; the plugin path below
|
|
69
|
+
// keeps its historical immediate initialization (it installs client-side
|
|
70
|
+
// at app boot, before anything rendered).
|
|
71
|
+
responsive = createResponsive({}, { deferViewportSync: true })
|
|
72
|
+
}
|
|
7
73
|
return responsive
|
|
8
74
|
}
|
|
9
75
|
|
|
@@ -13,11 +79,6 @@ export default {
|
|
|
13
79
|
computed: {},
|
|
14
80
|
}, options)
|
|
15
81
|
|
|
16
|
-
const computedProps = {}
|
|
17
|
-
for (const key in finalOptions.computed) {
|
|
18
|
-
computedProps[key] = computed(() => finalOptions.computed[key](responsive))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
82
|
if (import.meta.env.RESPONSIVE_V2) {
|
|
22
83
|
let device
|
|
23
84
|
const defaultUserAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.39 Safari/537.36'
|
|
@@ -44,18 +105,11 @@ export default {
|
|
|
44
105
|
}
|
|
45
106
|
app.config.globalProperties.$responsive = responsive
|
|
46
107
|
} else {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
52
|
-
|
|
108
|
+
// The plugin-created instance replaces the lazy singleton so that
|
|
109
|
+
// useResponsive() and $responsive stay the same object, with the
|
|
110
|
+
// app's custom computed applied on top of the default flags.
|
|
111
|
+
responsive = createResponsive(finalOptions.computed)
|
|
53
112
|
app.config.globalProperties.$responsive = responsive
|
|
54
|
-
|
|
55
|
-
window.addEventListener('resize', () => {
|
|
56
|
-
responsive.width = window.innerWidth
|
|
57
|
-
responsive.height = window.innerHeight
|
|
58
|
-
})
|
|
59
113
|
}
|
|
60
114
|
},
|
|
61
115
|
}
|
package/dist/a11y-DIdrv5Mn.mjs
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { ref as k, computed as u, watch as r, onUnmounted as S, getCurrentInstance as y, onMounted as g, nextTick as x } from "vue";
|
|
2
|
-
import { onKeyDown as w } from "@vueuse/core";
|
|
3
|
-
let T = 0;
|
|
4
|
-
const a = k([]), b = u(() => a.value.length > 0);
|
|
5
|
-
function A(o, s) {
|
|
6
|
-
const n = T++, t = u(() => a.value.findIndex((e) => e.id === n));
|
|
7
|
-
function f() {
|
|
8
|
-
a.value.some((e) => e.id === n) || a.value.push({
|
|
9
|
-
id: n,
|
|
10
|
-
type: s
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
function i() {
|
|
14
|
-
t.value !== -1 && a.value.splice(t.value, 1);
|
|
15
|
-
}
|
|
16
|
-
r(o, (e) => {
|
|
17
|
-
e ? f() : i();
|
|
18
|
-
}, {
|
|
19
|
-
immediate: !0
|
|
20
|
-
}), S(() => {
|
|
21
|
-
i();
|
|
22
|
-
});
|
|
23
|
-
const d = u(() => n === a.value[a.value.length - 1]?.id), m = u(() => t.value > 0), c = u(() => a.value.filter((e) => e.type === s)), p = u(() => c.value.findIndex((e) => e.id === n) < c.value.length - 1), h = u(() => c.value.findIndex((e) => e.id === n) > 0), l = [];
|
|
24
|
-
function v(e) {
|
|
25
|
-
l.push(e);
|
|
26
|
-
}
|
|
27
|
-
return w("Escape", () => {
|
|
28
|
-
d.value && l.forEach((e) => e());
|
|
29
|
-
}), {
|
|
30
|
-
isActiveStacked: d,
|
|
31
|
-
hasStackedBehind: m,
|
|
32
|
-
isBehindSameType: p,
|
|
33
|
-
hasStackedSameTypeBehind: h,
|
|
34
|
-
stackIndex: t,
|
|
35
|
-
onClose: v
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
typeof document < "u" && r(b, (o) => {
|
|
39
|
-
o ? document.documentElement.classList.add("overflow-hidden") : document.documentElement.classList.remove("overflow-hidden");
|
|
40
|
-
}, {
|
|
41
|
-
immediate: !0
|
|
42
|
-
});
|
|
43
|
-
function C() {
|
|
44
|
-
const o = y();
|
|
45
|
-
let s = null;
|
|
46
|
-
g(async () => {
|
|
47
|
-
await x();
|
|
48
|
-
const n = o.proxy.$el;
|
|
49
|
-
if (!n?.querySelector) return;
|
|
50
|
-
let t = n.querySelector("[data-stackview-autofocus]");
|
|
51
|
-
t ? ["INPUT", "A", "BUTTON", "TEXTAREA"].includes(t.tagName) || (t = t.querySelector("input, a, button, textarea") || t) : (t = n.querySelector('button[type="submit"]'), console.warn(
|
|
52
|
-
"%cDEV",
|
|
53
|
-
"background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;",
|
|
54
|
-
"A element should have the data-stackview-autofocus attribute in this component. Fallback to submit button."
|
|
55
|
-
)), clearTimeout(s), s = setTimeout(() => t?.focus(), 150);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
function q(o) {
|
|
59
|
-
o.preventDefault(), (o.target.closest('[role="menu"]') || o.target).querySelector("a")?.focus();
|
|
60
|
-
}
|
|
61
|
-
export {
|
|
62
|
-
C as a,
|
|
63
|
-
q as f,
|
|
64
|
-
b as h,
|
|
65
|
-
A as u
|
|
66
|
-
};
|