@leavepulse/ui 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/LpSkeleton-D7xU8IPV.css +29 -0
- package/dist/chunks/LpSkeleton-t5mMYl3a.js +29 -0
- package/dist/components/LpSkeleton.vue.d.ts +11 -1
- package/dist/components/LpSkeleton.vue.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/LpSkeleton.vue +81 -8
- package/dist/chunks/LpSkeleton-eSFIo4kD.js +0 -22
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
/*
|
|
3
|
+
* Unscoped: the items are written by the CONSUMER, inside the slot, so they
|
|
4
|
+
* carry no scope attribute of this component — a scoped rule could never reach
|
|
5
|
+
* them. Namespaced instead, and only ever applied under `.lp-skeleton`.
|
|
6
|
+
*
|
|
7
|
+
* One shared animation name means every item on the page pulses in phase: CSS
|
|
8
|
+
* animations are timed against the document, not against when each element
|
|
9
|
+
* mounted, so a skeleton that fills in progressively stays in step with itself.
|
|
10
|
+
*/
|
|
11
|
+
.lp-skeleton-item {
|
|
12
|
+
animation: lp-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Items nested anywhere inside a wrapper, at any depth. */
|
|
16
|
+
.lp-skeleton .lp-skeleton-item {
|
|
17
|
+
animation: lp-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
18
|
+
}
|
|
19
|
+
@keyframes lp-skeleton-pulse {
|
|
20
|
+
50% {
|
|
21
|
+
opacity: 0.5;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
@media (prefers-reduced-motion: reduce) {
|
|
25
|
+
.lp-skeleton-item {
|
|
26
|
+
animation: none;
|
|
27
|
+
opacity: 0.75;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineComponent, useSlots, computed, openBlock, createElementBlock, normalizeClass, renderSlot } from "vue";
|
|
2
|
+
import '../assets/LpSkeleton-D7xU8IPV.css';const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
3
|
+
__name: "LpSkeleton",
|
|
4
|
+
props: {
|
|
5
|
+
rounded: {}
|
|
6
|
+
},
|
|
7
|
+
setup(__props) {
|
|
8
|
+
const slots = useSlots();
|
|
9
|
+
const isBlock = computed(() => !slots.default);
|
|
10
|
+
return (_ctx, _cache) => {
|
|
11
|
+
return openBlock(), createElementBlock("div", {
|
|
12
|
+
"aria-hidden": "true",
|
|
13
|
+
class: normalizeClass(["lp-skeleton", [
|
|
14
|
+
isBlock.value ? "lp-skeleton-item bg-surface-soft" : "",
|
|
15
|
+
{
|
|
16
|
+
"rounded-control": isBlock.value && (__props.rounded === "control" || !__props.rounded),
|
|
17
|
+
"rounded-card": __props.rounded === "card",
|
|
18
|
+
"rounded-pill": __props.rounded === "pill"
|
|
19
|
+
}
|
|
20
|
+
]])
|
|
21
|
+
}, [
|
|
22
|
+
renderSlot(_ctx.$slots, "default")
|
|
23
|
+
], 2);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
export {
|
|
28
|
+
_sfc_main as _
|
|
29
|
+
};
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
2
|
rounded?: "control" | "card" | "pill";
|
|
3
3
|
};
|
|
4
|
-
declare
|
|
4
|
+
declare var __VLS_1: {};
|
|
5
|
+
type __VLS_Slots = {} & {
|
|
6
|
+
default?: (props: typeof __VLS_1) => any;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
5
10
|
declare const _default: typeof __VLS_export;
|
|
6
11
|
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ import { _ as _49 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
|
56
56
|
import { _ as _50 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
57
57
|
import { default as default3 } from "./components/LpShortcutsDialog.vue.js";
|
|
58
58
|
import { _ as _51 } from "./chunks/LpSidebar-7Vpy2IJc.js";
|
|
59
|
-
import { _ as _52 } from "./chunks/LpSkeleton-
|
|
59
|
+
import { _ as _52 } from "./chunks/LpSkeleton-t5mMYl3a.js";
|
|
60
60
|
import { _ as _53 } from "./chunks/LpSlider-B1SF3pRV.js";
|
|
61
61
|
import { _ as _54 } from "./chunks/LpSparkline-C6xQ2dwv.js";
|
|
62
62
|
import { _ as _55 } from "./chunks/LpStat-CDanpzU0.js";
|
package/package.json
CHANGED
|
@@ -1,16 +1,89 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
2
|
+
/*
|
|
3
|
+
* Loading placeholder, in two shapes.
|
|
4
|
+
*
|
|
5
|
+
* Bare, it is one pulsing block and the consumer's classes size it:
|
|
6
|
+
*
|
|
7
|
+
* <LpSkeleton class="h-4 w-40" />
|
|
8
|
+
*
|
|
9
|
+
* Given content, it becomes a WRAPPER instead: it stops pulsing itself and
|
|
10
|
+
* lends the pulse to any `.lp-skeleton-item` inside it, however deeply nested.
|
|
11
|
+
*
|
|
12
|
+
* <LpSkeleton class="space-y-3">
|
|
13
|
+
* <div class="flex items-center gap-3">
|
|
14
|
+
* <div class="lp-skeleton-item size-10 rounded-pill" />
|
|
15
|
+
* <div class="lp-skeleton-item h-4 w-32" />
|
|
16
|
+
* </div>
|
|
17
|
+
* </LpSkeleton>
|
|
18
|
+
*
|
|
19
|
+
* The second form exists because a real skeleton is a LAYOUT, not a stack of
|
|
20
|
+
* bars: a profile header is an avatar beside two lines of different widths
|
|
21
|
+
* above a button. Expressed as one component per block, that is a dozen
|
|
22
|
+
* <LpSkeleton> tags whose grid has to be rebuilt by hand and kept in step with
|
|
23
|
+
* the markup it stands in for. As a wrapper, the skeleton can be the real
|
|
24
|
+
* markup with its content swapped for plain divs — same flex, same gaps, same
|
|
25
|
+
* responsive classes — so it keeps matching the thing it is standing in for.
|
|
26
|
+
*
|
|
27
|
+
* Consumers had already arrived at this and built it themselves; it belongs
|
|
28
|
+
* here, where every app gets it.
|
|
29
|
+
*/
|
|
30
|
+
import { computed, useSlots } from "vue"
|
|
31
|
+
|
|
3
32
|
defineProps<{ rounded?: "control" | "card" | "pill" }>()
|
|
33
|
+
|
|
34
|
+
const slots = useSlots()
|
|
35
|
+
|
|
36
|
+
/* A wrapper must not pulse as a whole — the container would flash behind its
|
|
37
|
+
own items. Only the bare form is a placeholder in its own right. */
|
|
38
|
+
const isBlock = computed(() => !slots.default)
|
|
4
39
|
</script>
|
|
5
40
|
|
|
6
41
|
<template>
|
|
7
42
|
<div
|
|
8
43
|
aria-hidden="true"
|
|
9
|
-
class="
|
|
10
|
-
:class="
|
|
11
|
-
'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
44
|
+
class="lp-skeleton"
|
|
45
|
+
:class="[
|
|
46
|
+
isBlock ? 'lp-skeleton-item bg-surface-soft' : '',
|
|
47
|
+
{
|
|
48
|
+
'rounded-control': isBlock && (rounded === 'control' || !rounded),
|
|
49
|
+
'rounded-card': rounded === 'card',
|
|
50
|
+
'rounded-pill': rounded === 'pill',
|
|
51
|
+
},
|
|
52
|
+
]"
|
|
53
|
+
>
|
|
54
|
+
<slot />
|
|
55
|
+
</div>
|
|
16
56
|
</template>
|
|
57
|
+
|
|
58
|
+
<style>
|
|
59
|
+
/*
|
|
60
|
+
* Unscoped: the items are written by the CONSUMER, inside the slot, so they
|
|
61
|
+
* carry no scope attribute of this component — a scoped rule could never reach
|
|
62
|
+
* them. Namespaced instead, and only ever applied under `.lp-skeleton`.
|
|
63
|
+
*
|
|
64
|
+
* One shared animation name means every item on the page pulses in phase: CSS
|
|
65
|
+
* animations are timed against the document, not against when each element
|
|
66
|
+
* mounted, so a skeleton that fills in progressively stays in step with itself.
|
|
67
|
+
*/
|
|
68
|
+
.lp-skeleton-item {
|
|
69
|
+
animation: lp-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Items nested anywhere inside a wrapper, at any depth. */
|
|
73
|
+
.lp-skeleton .lp-skeleton-item {
|
|
74
|
+
animation: lp-skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@keyframes lp-skeleton-pulse {
|
|
78
|
+
50% {
|
|
79
|
+
opacity: 0.5;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (prefers-reduced-motion: reduce) {
|
|
84
|
+
.lp-skeleton-item {
|
|
85
|
+
animation: none;
|
|
86
|
+
opacity: 0.75;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
</style>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createElementBlock, normalizeClass } from "vue";
|
|
2
|
-
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
3
|
-
__name: "LpSkeleton",
|
|
4
|
-
props: {
|
|
5
|
-
rounded: {}
|
|
6
|
-
},
|
|
7
|
-
setup(__props) {
|
|
8
|
-
return (_ctx, _cache) => {
|
|
9
|
-
return openBlock(), createElementBlock("div", {
|
|
10
|
-
"aria-hidden": "true",
|
|
11
|
-
class: normalizeClass(["animate-pulse bg-surface-soft", {
|
|
12
|
-
"rounded-control": __props.rounded === "control" || !__props.rounded,
|
|
13
|
-
"rounded-card": __props.rounded === "card",
|
|
14
|
-
"rounded-pill": __props.rounded === "pill"
|
|
15
|
-
}])
|
|
16
|
-
}, null, 2);
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
export {
|
|
21
|
-
_sfc_main as _
|
|
22
|
-
};
|