@alikhalilll/a-smart-skeleton 0.0.0-stage → 2.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/LICENSE +21 -0
- package/README.md +356 -2
- package/dist/_chunks/core.js +2314 -0
- package/dist/_chunks/core.js.map +1 -0
- package/dist/_chunks/index.d.ts +431 -0
- package/dist/core/index.cjs +67 -0
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/element/index.cjs +47 -0
- package/dist/element/index.cjs.map +1 -0
- package/dist/element/index.d.cts +24 -0
- package/dist/element/index.d.ts +24 -0
- package/dist/element/index.js +46 -0
- package/dist/element/index.js.map +1 -0
- package/dist/index.cjs +512 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +204 -0
- package/dist/index.d.ts +204 -0
- package/dist/index.js +441 -0
- package/dist/index.js.map +1 -0
- package/dist/nuxt/index.cjs +36 -0
- package/dist/nuxt/index.cjs.map +1 -0
- package/dist/nuxt/index.d.cts +30 -0
- package/dist/nuxt/index.d.ts +30 -0
- package/dist/nuxt/index.js +36 -0
- package/dist/nuxt/index.js.map +1 -0
- package/dist/resolver/index.cjs +26 -0
- package/dist/resolver/index.cjs.map +1 -0
- package/dist/resolver/index.d.cts +19 -0
- package/dist/resolver/index.d.ts +19 -0
- package/dist/resolver/index.js +26 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/styles.css +136 -0
- package/package.json +144 -3
- package/src/components/ASmartSkeleton.vue +228 -0
- package/src/components/ASmartSkeletonBox.vue +23 -0
- package/src/components/ASmartSkeletonProvider.vue +34 -0
- package/src/components/ASmartSkeletonSuspense.vue +142 -0
- package/src/composables/useSmartSkeleton.ts +20 -0
- package/src/composables/useStyles.ts +8 -0
- package/src/core/boot.ts +63 -0
- package/src/core/canvas.ts +7 -0
- package/src/core/constants.ts +76 -0
- package/src/core/debug.ts +154 -0
- package/src/core/dev.ts +53 -0
- package/src/core/fade.ts +490 -0
- package/src/core/ghost.ts +236 -0
- package/src/core/images.ts +28 -0
- package/src/core/index.ts +71 -0
- package/src/core/inline.generated.ts +9 -0
- package/src/core/measure.ts +571 -0
- package/src/core/memory.ts +146 -0
- package/src/core/motion.ts +12 -0
- package/src/core/plan.ts +368 -0
- package/src/core/reveal.ts +89 -0
- package/src/core/reveals.ts +39 -0
- package/src/core/shapes.ts +84 -0
- package/src/core/shimmer.ts +229 -0
- package/src/core/skeleton.ts +43 -0
- package/src/core/snapshot.ts +159 -0
- package/src/core/styles.ts +187 -0
- package/src/core/sweep.ts +203 -0
- package/src/core/theme.ts +162 -0
- package/src/element/index.ts +59 -0
- package/src/index.ts +27 -0
- package/src/nuxt/index.ts +59 -0
- package/src/resolver/index.ts +35 -0
- package/src/types.ts +100 -0
- package/src/vue/Skeleton.ts +275 -0
- package/src/vue/Suspense.ts +157 -0
- package/src/vue/config.ts +78 -0
- package/src/vue/index.ts +7 -0
- package/web-types.json +256 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { t as Reveal } from "../_chunks/core.js";
|
|
2
|
+
//#region src/element/index.ts
|
|
3
|
+
const Base = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
|
|
4
|
+
/** A reveal in plain HTML: its children start as a skeleton with `loading`, as content without. */
|
|
5
|
+
var ASmartSkeletonReveal = class extends Base {
|
|
6
|
+
reveal = null;
|
|
7
|
+
started = false;
|
|
8
|
+
connectedCallback() {
|
|
9
|
+
if (this.started) return;
|
|
10
|
+
this.started = true;
|
|
11
|
+
const content = document.createDocumentFragment();
|
|
12
|
+
content.append(...this.childNodes);
|
|
13
|
+
this.reveal = new Reveal(this, {
|
|
14
|
+
id: this.id || void 0,
|
|
15
|
+
reveal: this.getAttribute("reveal") ?? void 0,
|
|
16
|
+
label: this.getAttribute("label") ?? void 0,
|
|
17
|
+
onReveal: () => this.dispatchEvent(new Event("reveal"))
|
|
18
|
+
});
|
|
19
|
+
if (this.hasAttribute("loading")) this.reveal.load(content);
|
|
20
|
+
else this.reveal.show(content);
|
|
21
|
+
}
|
|
22
|
+
disconnectedCallback() {
|
|
23
|
+
queueMicrotask(() => {
|
|
24
|
+
if (this.isConnected) return;
|
|
25
|
+
this.reveal?.destroy();
|
|
26
|
+
this.reveal = null;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** Shows a skeleton measured from `content`, rendered from sample data, or else the shape last shown. */
|
|
30
|
+
load(content) {
|
|
31
|
+
this.setAttribute("loading", "");
|
|
32
|
+
this.reveal?.load(content);
|
|
33
|
+
}
|
|
34
|
+
show(content) {
|
|
35
|
+
this.removeAttribute("loading");
|
|
36
|
+
this.reveal?.show(content);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (typeof customElements !== "undefined" && !customElements.get("a-smart-skeleton-reveal")) {
|
|
40
|
+
customElements.define("a-smart-skeleton-reveal", ASmartSkeletonReveal);
|
|
41
|
+
if (!customElements.get("ask-reveal")) customElements.define("ask-reveal", class extends ASmartSkeletonReveal {});
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { ASmartSkeletonReveal };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/element/index.ts"],"sourcesContent":["import { Reveal, type RevealMode } from '../core';\n\n// Importable on a server, where there's no HTMLElement to extend\nconst Base = typeof HTMLElement === 'undefined' ? (class {} as typeof HTMLElement) : HTMLElement;\n\n/** A reveal in plain HTML: its children start as a skeleton with `loading`, as content without. */\nexport class ASmartSkeletonReveal extends Base {\n private reveal: Reveal | null = null;\n private started = false;\n\n connectedCallback() {\n if (this.started) return;\n this.started = true;\n const content = document.createDocumentFragment();\n content.append(...this.childNodes);\n this.reveal = new Reveal(this, {\n id: this.id || undefined,\n reveal: (this.getAttribute('reveal') as RevealMode | null) ?? undefined,\n label: this.getAttribute('label') ?? undefined,\n onReveal: () => this.dispatchEvent(new Event('reveal')),\n });\n if (this.hasAttribute('loading')) this.reveal.load(content);\n else this.reveal.show(content);\n }\n\n disconnectedCallback() {\n // A move reconnects within the task; only a removal stays out\n queueMicrotask(() => {\n if (this.isConnected) return;\n this.reveal?.destroy();\n this.reveal = null;\n });\n }\n\n /** Shows a skeleton measured from `content`, rendered from sample data, or else the shape last shown. */\n load(content?: Node | string) {\n this.setAttribute('loading', '');\n this.reveal?.load(content);\n }\n\n show(content: Node | string) {\n this.removeAttribute('loading');\n this.reveal?.show(content);\n }\n}\n\nif (typeof customElements !== 'undefined' && !customElements.get('a-smart-skeleton-reveal')) {\n customElements.define('a-smart-skeleton-reveal', ASmartSkeletonReveal);\n if (!customElements.get('ask-reveal')) {\n customElements.define('ask-reveal', class extends ASmartSkeletonReveal {});\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'a-smart-skeleton-reveal': ASmartSkeletonReveal;\n 'ask-reveal': ASmartSkeletonReveal;\n }\n}\n"],"mappings":";;AAGA,MAAM,OAAO,OAAO,gBAAgB,cAAe,MAAM,CAAC,IAA2B;;AAGrF,IAAa,uBAAb,cAA0C,KAAK;CAC7C,SAAgC;CAChC,UAAkB;CAElB,oBAAoB;EAClB,IAAI,KAAK,SAAS;EAClB,KAAK,UAAU;EACf,MAAM,UAAU,SAAS,uBAAuB;EAChD,QAAQ,OAAO,GAAG,KAAK,UAAU;EACjC,KAAK,SAAS,IAAI,OAAO,MAAM;GAC7B,IAAI,KAAK,MAAM,KAAA;GACf,QAAS,KAAK,aAAa,QAAQ,KAA2B,KAAA;GAC9D,OAAO,KAAK,aAAa,OAAO,KAAK,KAAA;GACrC,gBAAgB,KAAK,cAAc,IAAI,MAAM,QAAQ,CAAC;EACxD,CAAC;EACD,IAAI,KAAK,aAAa,SAAS,GAAG,KAAK,OAAO,KAAK,OAAO;OACrD,KAAK,OAAO,KAAK,OAAO;CAC/B;CAEA,uBAAuB;EAErB,qBAAqB;GACnB,IAAI,KAAK,aAAa;GACtB,KAAK,QAAQ,QAAQ;GACrB,KAAK,SAAS;EAChB,CAAC;CACH;;CAGA,KAAK,SAAyB;EAC5B,KAAK,aAAa,WAAW,EAAE;EAC/B,KAAK,QAAQ,KAAK,OAAO;CAC3B;CAEA,KAAK,SAAwB;EAC3B,KAAK,gBAAgB,SAAS;EAC9B,KAAK,QAAQ,KAAK,OAAO;CAC3B;AACF;AAEA,IAAI,OAAO,mBAAmB,eAAe,CAAC,eAAe,IAAI,yBAAyB,GAAG;CAC3F,eAAe,OAAO,2BAA2B,oBAAoB;CACrE,IAAI,CAAC,eAAe,IAAI,YAAY,GAClC,eAAe,OAAO,cAAc,cAAc,qBAAqB,CAAC,CAAC;AAE7E"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_core = require("./_chunks/core.js");
|
|
3
|
+
let vue = require("vue");
|
|
4
|
+
//#region src/composables/useSmartSkeleton.ts
|
|
5
|
+
const SMART_SKELETON_CONFIG_KEY = Symbol("a-smart-skeleton");
|
|
6
|
+
/** Per server render: whether the full inline script has gone out yet, so the skeletons after it send a stub. */
|
|
7
|
+
const SMART_SKELETON_BOOT_KEY = Symbol("a-smart-skeleton.boot");
|
|
8
|
+
/** The provider settings in scope for this component. Empty outside a provider. */
|
|
9
|
+
const useSmartSkeleton = () => (0, vue.inject)(SMART_SKELETON_CONFIG_KEY, {});
|
|
10
|
+
/** Whether this skeleton should send the stub — claiming the full script if it's the first. */
|
|
11
|
+
function claimStub() {
|
|
12
|
+
const boot = (0, vue.inject)(SMART_SKELETON_BOOT_KEY, null);
|
|
13
|
+
const stub = !!boot?.sent;
|
|
14
|
+
if (boot) boot.sent = true;
|
|
15
|
+
return stub;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/composables/useStyles.ts
|
|
19
|
+
/** Adds the stylesheet on mount and removes it on unmount — reference counted, so siblings share one copy. */
|
|
20
|
+
function useStyles() {
|
|
21
|
+
(0, vue.onBeforeMount)(require_core.addStyles);
|
|
22
|
+
(0, vue.onUnmounted)(require_core.removeStyles);
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region \0/plugin-vue/export-helper
|
|
26
|
+
var export_helper_default = (sfc, props) => {
|
|
27
|
+
const target = sfc.__vccOpts || sfc;
|
|
28
|
+
for (const [key, val] of props) target[key] = val;
|
|
29
|
+
return target;
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/components/ASmartSkeleton.vue
|
|
33
|
+
/**
|
|
34
|
+
* The measured loading pane. Internal — `<ASmartSkeleton>` renders it.
|
|
35
|
+
*
|
|
36
|
+
* The ghost is laid out but never seen; the layer holds bones in a shadow root,
|
|
37
|
+
* so hydration never touches what was measured.
|
|
38
|
+
*/
|
|
39
|
+
const Loading = (0, vue.defineComponent)({
|
|
40
|
+
name: "ASmartSkeletonLoading",
|
|
41
|
+
props: {
|
|
42
|
+
id: String,
|
|
43
|
+
exact: Boolean,
|
|
44
|
+
refetch: Boolean,
|
|
45
|
+
label: String
|
|
46
|
+
},
|
|
47
|
+
setup(props, { slots }) {
|
|
48
|
+
const element = (0, vue.ref)(null);
|
|
49
|
+
const config = useSmartSkeleton();
|
|
50
|
+
const script = claimStub() ? require_core.INLINE_STUB : require_core.INLINE_SCRIPT;
|
|
51
|
+
let ghost = null;
|
|
52
|
+
const optionsOf = () => ({
|
|
53
|
+
id: props.id,
|
|
54
|
+
exact: props.exact,
|
|
55
|
+
refetch: props.refetch
|
|
56
|
+
});
|
|
57
|
+
(0, vue.onMounted)(() => {
|
|
58
|
+
require_core.checkNonce(config.nonce);
|
|
59
|
+
if (element.value) ghost = new require_core.Ghost(element.value, optionsOf());
|
|
60
|
+
});
|
|
61
|
+
(0, vue.watch)(() => [
|
|
62
|
+
props.id,
|
|
63
|
+
props.exact,
|
|
64
|
+
props.refetch
|
|
65
|
+
], () => ghost?.update(optionsOf()));
|
|
66
|
+
(0, vue.onBeforeUnmount)(() => ghost?.destroy());
|
|
67
|
+
return () => [
|
|
68
|
+
props.label ? (0, vue.h)("span", { [require_core.ATTR_STATUS]: "" }, props.label) : null,
|
|
69
|
+
(0, vue.h)("div", {
|
|
70
|
+
ref: element,
|
|
71
|
+
[require_core.ATTR_LOADING]: "",
|
|
72
|
+
"aria-hidden": "true",
|
|
73
|
+
inert: ""
|
|
74
|
+
}, [
|
|
75
|
+
(0, vue.h)("div", { [require_core.ATTR_GHOST]: "" }, slots.default?.()),
|
|
76
|
+
(0, vue.h)("div", { [require_core.ATTR_SNAPSHOT]: "" }),
|
|
77
|
+
(0, vue.h)("div", { [require_core.ATTR_LAYER]: "" })
|
|
78
|
+
]),
|
|
79
|
+
(0, vue.h)("script", {
|
|
80
|
+
nonce: config.nonce,
|
|
81
|
+
innerHTML: script
|
|
82
|
+
})
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
const Content = (0, vue.defineComponent)({
|
|
87
|
+
name: "ASmartSkeletonContent",
|
|
88
|
+
props: { memory: {
|
|
89
|
+
type: Object,
|
|
90
|
+
required: true
|
|
91
|
+
} },
|
|
92
|
+
setup(props, { slots }) {
|
|
93
|
+
const element = (0, vue.ref)(null);
|
|
94
|
+
let memory = null;
|
|
95
|
+
(0, vue.onMounted)(() => {
|
|
96
|
+
if (element.value) memory = new require_core.Memory(element.value, props.memory);
|
|
97
|
+
});
|
|
98
|
+
(0, vue.onBeforeUnmount)(() => memory?.destroy());
|
|
99
|
+
return () => (0, vue.h)("div", { ref: element }, slots.default?.());
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
var ASmartSkeleton_default = /* @__PURE__ */ export_helper_default((0, vue.defineComponent)({
|
|
103
|
+
name: "ASmartSkeleton",
|
|
104
|
+
props: {
|
|
105
|
+
/** Shows the skeleton, even over `data`. With `data`, it also shows while there is none. */
|
|
106
|
+
loading: {
|
|
107
|
+
type: Boolean,
|
|
108
|
+
default: void 0
|
|
109
|
+
},
|
|
110
|
+
/** Loading while `null` or `undefined`; handed to the default slot as `{ data }`. */
|
|
111
|
+
data: {
|
|
112
|
+
type: null,
|
|
113
|
+
required: false
|
|
114
|
+
},
|
|
115
|
+
/** Stands in for `data` to draw the skeleton before any has loaded. */
|
|
116
|
+
sample: {
|
|
117
|
+
type: null,
|
|
118
|
+
required: false
|
|
119
|
+
},
|
|
120
|
+
/** Remembers the shape under this key across visits. */
|
|
121
|
+
id: String,
|
|
122
|
+
/** Read to screen readers while loading, in place of the skeleton — "Loading profile". */
|
|
123
|
+
label: String,
|
|
124
|
+
empty: Boolean,
|
|
125
|
+
error: {
|
|
126
|
+
type: null,
|
|
127
|
+
required: false
|
|
128
|
+
},
|
|
129
|
+
/** Overrides the provider's reveal for this skeleton alone. */
|
|
130
|
+
reveal: [String, Object]
|
|
131
|
+
},
|
|
132
|
+
/** `reveal`: content has come in over a skeleton. */
|
|
133
|
+
emits: ["reveal"],
|
|
134
|
+
setup(props, { slots, emit }) {
|
|
135
|
+
const instance = (0, vue.getCurrentInstance)();
|
|
136
|
+
const config = useSmartSkeleton();
|
|
137
|
+
let last = null;
|
|
138
|
+
let shown = null;
|
|
139
|
+
let from = null;
|
|
140
|
+
useStyles();
|
|
141
|
+
return () => {
|
|
142
|
+
const driven = !!instance?.vnode.props && "data" in instance.vnode.props;
|
|
143
|
+
const data = props.data;
|
|
144
|
+
if (data != null) last = {
|
|
145
|
+
id: props.id,
|
|
146
|
+
data
|
|
147
|
+
};
|
|
148
|
+
const show = (value) => driven ? value != null ? slots.default?.({ data: value }) : null : slots.default?.({ data: void 0 });
|
|
149
|
+
const loading = !!props.loading || driven && data == null && !props.error && !props.empty;
|
|
150
|
+
let key;
|
|
151
|
+
let content;
|
|
152
|
+
if (loading) {
|
|
153
|
+
const previous = last;
|
|
154
|
+
const real = data ?? (previous && previous.id === props.id ? previous.data : null);
|
|
155
|
+
key = "skeleton";
|
|
156
|
+
content = slots.skeleton ? (0, vue.h)("div", {
|
|
157
|
+
[require_core.ATTR_OWN]: "",
|
|
158
|
+
"aria-hidden": "true"
|
|
159
|
+
}, slots.skeleton()) : (0, vue.h)(Loading, {
|
|
160
|
+
id: props.id,
|
|
161
|
+
exact: real != null,
|
|
162
|
+
refetch: data != null,
|
|
163
|
+
label: props.label
|
|
164
|
+
}, () => show(real ?? props.sample));
|
|
165
|
+
} else if (props.error) {
|
|
166
|
+
key = "error";
|
|
167
|
+
content = slots.error?.({ error: props.error });
|
|
168
|
+
} else if (props.empty) {
|
|
169
|
+
key = "empty";
|
|
170
|
+
content = slots.empty?.() ?? show(data);
|
|
171
|
+
} else {
|
|
172
|
+
key = "content";
|
|
173
|
+
content = (0, vue.h)(Content, { memory: {
|
|
174
|
+
id: props.id,
|
|
175
|
+
data,
|
|
176
|
+
rendered: driven,
|
|
177
|
+
sample: props.sample !== void 0
|
|
178
|
+
} }, () => show(data));
|
|
179
|
+
}
|
|
180
|
+
if (key !== shown) {
|
|
181
|
+
from = shown;
|
|
182
|
+
shown = key;
|
|
183
|
+
}
|
|
184
|
+
const revealing = key === "content" && from === "skeleton";
|
|
185
|
+
const reveal = props.reveal ?? config.reveal;
|
|
186
|
+
return (0, vue.h)("div", {
|
|
187
|
+
[require_core.ATTR_REVEAL]: "",
|
|
188
|
+
"aria-busy": loading || void 0
|
|
189
|
+
}, [(0, vue.h)(vue.Transition, {
|
|
190
|
+
css: false,
|
|
191
|
+
appear: true,
|
|
192
|
+
onAppear: (el, done) => require_core.fadeIn(el, reveal, { initial: true }).then(done),
|
|
193
|
+
onEnter: (el, done) => require_core.fadeIn(el, reveal).then(() => {
|
|
194
|
+
done();
|
|
195
|
+
if (revealing) emit("reveal");
|
|
196
|
+
}),
|
|
197
|
+
onLeave: (el, done) => require_core.fadeOut(el).then(done)
|
|
198
|
+
}, () => (0, vue.h)("div", {
|
|
199
|
+
key,
|
|
200
|
+
[require_core.ATTR_PANE]: ""
|
|
201
|
+
}, [content]))]);
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}), [["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeleton.vue"]]);
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/components/ASmartSkeletonBox.vue
|
|
207
|
+
const _sfc_main$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
208
|
+
name: "ASmartSkeletonBox",
|
|
209
|
+
__name: "ASmartSkeletonBox",
|
|
210
|
+
props: {
|
|
211
|
+
class: {
|
|
212
|
+
type: String,
|
|
213
|
+
required: false
|
|
214
|
+
},
|
|
215
|
+
style: {
|
|
216
|
+
type: Object,
|
|
217
|
+
required: false
|
|
218
|
+
},
|
|
219
|
+
height: {
|
|
220
|
+
type: [String, Number],
|
|
221
|
+
required: false
|
|
222
|
+
},
|
|
223
|
+
width: {
|
|
224
|
+
type: [String, Number],
|
|
225
|
+
required: false
|
|
226
|
+
},
|
|
227
|
+
radius: {
|
|
228
|
+
type: [String, Number],
|
|
229
|
+
required: false
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
setup(__props, { expose: __expose }) {
|
|
233
|
+
__expose();
|
|
234
|
+
const props = __props;
|
|
235
|
+
const element = (0, vue.ref)(null);
|
|
236
|
+
useStyles();
|
|
237
|
+
(0, vue.onMounted)(() => {
|
|
238
|
+
if (element.value) require_core.shimmer(element.value);
|
|
239
|
+
});
|
|
240
|
+
const __returned__ = {
|
|
241
|
+
props,
|
|
242
|
+
element,
|
|
243
|
+
get skeletonBoxStyle() {
|
|
244
|
+
return require_core.skeletonBoxStyle;
|
|
245
|
+
},
|
|
246
|
+
get ATTR_BAR() {
|
|
247
|
+
return require_core.ATTR_BAR;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
Object.defineProperty(__returned__, "__isScriptSetup", {
|
|
251
|
+
enumerable: false,
|
|
252
|
+
value: true
|
|
253
|
+
});
|
|
254
|
+
return __returned__;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
|
|
258
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("span", (0, vue.mergeProps)({ ref: "element" }, { [$setup.ATTR_BAR]: "" }, { style: $setup.skeletonBoxStyle($setup.props) }), null, 16);
|
|
259
|
+
}
|
|
260
|
+
var ASmartSkeletonBox_default = /* @__PURE__ */ export_helper_default(_sfc_main$2, [["render", _sfc_render$1], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeletonBox.vue"]]);
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/components/ASmartSkeletonSuspense.vue
|
|
263
|
+
const state = {
|
|
264
|
+
type: Object,
|
|
265
|
+
required: true
|
|
266
|
+
};
|
|
267
|
+
const Fallback = (0, vue.defineComponent)({
|
|
268
|
+
name: "ASmartSkeletonFallback",
|
|
269
|
+
props: {
|
|
270
|
+
id: String,
|
|
271
|
+
label: String,
|
|
272
|
+
reveal: [String, Object],
|
|
273
|
+
state
|
|
274
|
+
},
|
|
275
|
+
setup(props, { slots }) {
|
|
276
|
+
const element = (0, vue.ref)(null);
|
|
277
|
+
const config = useSmartSkeleton();
|
|
278
|
+
(0, vue.onMounted)(() => {
|
|
279
|
+
const pane = element.value;
|
|
280
|
+
const reveal = pane?.parentElement;
|
|
281
|
+
if (!pane || !reveal) return;
|
|
282
|
+
props.state.waited = true;
|
|
283
|
+
require_core.fadeIn(pane, props.reveal ?? config.reveal, { initial: true });
|
|
284
|
+
reveal.setAttribute("aria-busy", "true");
|
|
285
|
+
});
|
|
286
|
+
(0, vue.onBeforeUnmount)(() => {
|
|
287
|
+
const pane = element.value;
|
|
288
|
+
const reveal = pane?.parentElement;
|
|
289
|
+
if (!pane || !reveal) return;
|
|
290
|
+
reveal.removeAttribute("aria-busy");
|
|
291
|
+
const box = require_core.boxOf(pane);
|
|
292
|
+
const copy = pane.cloneNode(true);
|
|
293
|
+
props.state.exit = () => {
|
|
294
|
+
Object.assign(copy.style, {
|
|
295
|
+
position: "absolute",
|
|
296
|
+
top: `${box.top}px`,
|
|
297
|
+
left: `${box.left}px`,
|
|
298
|
+
width: `${box.width}px`
|
|
299
|
+
});
|
|
300
|
+
reveal.prepend(copy);
|
|
301
|
+
require_core.fadeOut(copy).then(() => copy.remove());
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
return () => (0, vue.h)("div", {
|
|
305
|
+
ref: element,
|
|
306
|
+
[require_core.ATTR_PANE]: ""
|
|
307
|
+
}, (0, vue.h)(Loading, {
|
|
308
|
+
id: props.id,
|
|
309
|
+
exact: false,
|
|
310
|
+
label: props.label
|
|
311
|
+
}, slots.default));
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
const BoundaryContent = (0, vue.defineComponent)({
|
|
315
|
+
name: "ASmartSkeletonBoundaryContent",
|
|
316
|
+
props: {
|
|
317
|
+
id: String,
|
|
318
|
+
reveal: [String, Object],
|
|
319
|
+
state
|
|
320
|
+
},
|
|
321
|
+
emits: ["reveal"],
|
|
322
|
+
setup(props, { slots, emit }) {
|
|
323
|
+
const element = (0, vue.ref)(null);
|
|
324
|
+
const config = useSmartSkeleton();
|
|
325
|
+
let memory = null;
|
|
326
|
+
(0, vue.onMounted)(() => {
|
|
327
|
+
const pane = element.value;
|
|
328
|
+
if (!pane) return;
|
|
329
|
+
const waited = props.state.waited;
|
|
330
|
+
const arrival = require_core.fadeIn(pane, props.reveal ?? config.reveal, { initial: !waited });
|
|
331
|
+
if (waited) arrival.then(() => emit("reveal"));
|
|
332
|
+
props.state.exit?.();
|
|
333
|
+
props.state.exit = null;
|
|
334
|
+
memory = new require_core.Memory(pane, { id: props.id });
|
|
335
|
+
});
|
|
336
|
+
(0, vue.onBeforeUnmount)(() => memory?.destroy());
|
|
337
|
+
return () => (0, vue.h)("div", {
|
|
338
|
+
ref: element,
|
|
339
|
+
[require_core.ATTR_PANE]: ""
|
|
340
|
+
}, slots.default?.());
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
var ASmartSkeletonSuspense_default = /* @__PURE__ */ export_helper_default((0, vue.defineComponent)({
|
|
344
|
+
name: "ASmartSkeletonSuspense",
|
|
345
|
+
props: {
|
|
346
|
+
/** Remembers the shape under this key across visits. */
|
|
347
|
+
id: String,
|
|
348
|
+
/** Read to screen readers while suspended, in place of the skeleton. */
|
|
349
|
+
label: String,
|
|
350
|
+
/** Overrides the provider's reveal for this boundary alone. */
|
|
351
|
+
reveal: [String, Object]
|
|
352
|
+
},
|
|
353
|
+
/** `reveal`: content has come in over the skeleton. */
|
|
354
|
+
emits: ["reveal"],
|
|
355
|
+
setup(props, { slots, emit }) {
|
|
356
|
+
useStyles();
|
|
357
|
+
const shared = {
|
|
358
|
+
waited: false,
|
|
359
|
+
exit: null
|
|
360
|
+
};
|
|
361
|
+
return () => (0, vue.h)("div", { [require_core.ATTR_REVEAL]: "" }, [(0, vue.h)(vue.Suspense, null, {
|
|
362
|
+
default: () => (0, vue.h)(BoundaryContent, {
|
|
363
|
+
id: props.id,
|
|
364
|
+
reveal: props.reveal,
|
|
365
|
+
state: shared,
|
|
366
|
+
onReveal: () => emit("reveal")
|
|
367
|
+
}, slots.default),
|
|
368
|
+
fallback: () => (0, vue.h)(Fallback, {
|
|
369
|
+
id: props.id,
|
|
370
|
+
label: props.label,
|
|
371
|
+
reveal: props.reveal,
|
|
372
|
+
state: shared
|
|
373
|
+
}, slots.skeleton)
|
|
374
|
+
})]);
|
|
375
|
+
}
|
|
376
|
+
}), [["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeletonSuspense.vue"]]);
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/components/ASmartSkeletonProvider.vue
|
|
379
|
+
const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
380
|
+
name: "ASmartSkeletonProvider",
|
|
381
|
+
__name: "ASmartSkeletonProvider",
|
|
382
|
+
props: {
|
|
383
|
+
nonce: {
|
|
384
|
+
type: String,
|
|
385
|
+
required: false
|
|
386
|
+
},
|
|
387
|
+
theme: {
|
|
388
|
+
type: Object,
|
|
389
|
+
required: false
|
|
390
|
+
},
|
|
391
|
+
mode: {
|
|
392
|
+
type: String,
|
|
393
|
+
required: false
|
|
394
|
+
},
|
|
395
|
+
text: {
|
|
396
|
+
type: Object,
|
|
397
|
+
required: false
|
|
398
|
+
},
|
|
399
|
+
reveal: {
|
|
400
|
+
type: [String, Object],
|
|
401
|
+
required: false
|
|
402
|
+
},
|
|
403
|
+
debug: {
|
|
404
|
+
type: Boolean,
|
|
405
|
+
required: false
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
setup(__props, { expose: __expose }) {
|
|
409
|
+
__expose();
|
|
410
|
+
const props = __props;
|
|
411
|
+
(0, vue.provide)(SMART_SKELETON_CONFIG_KEY, props);
|
|
412
|
+
(0, vue.provide)(SMART_SKELETON_BOOT_KEY, { sent: false });
|
|
413
|
+
(0, vue.watch)(() => props.debug, (debug) => {
|
|
414
|
+
if (debug !== void 0 && typeof window !== "undefined") require_core.setDebug(debug);
|
|
415
|
+
}, { immediate: true });
|
|
416
|
+
const __returned__ = {
|
|
417
|
+
props,
|
|
418
|
+
css: (0, vue.computed)(() => require_core.skeletonCSS(props))
|
|
419
|
+
};
|
|
420
|
+
Object.defineProperty(__returned__, "__isScriptSetup", {
|
|
421
|
+
enumerable: false,
|
|
422
|
+
value: true
|
|
423
|
+
});
|
|
424
|
+
return __returned__;
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
428
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [
|
|
429
|
+
(0, vue.createCommentVNode)(" eslint-disable-next-line vue/no-v-text-v-html-on-component "),
|
|
430
|
+
$setup.css ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)("style"), {
|
|
431
|
+
key: 0,
|
|
432
|
+
nonce: $props.nonce,
|
|
433
|
+
textContent: (0, vue.toDisplayString)($setup.css)
|
|
434
|
+
}, null, 8, ["nonce", "textContent"])) : (0, vue.createCommentVNode)("v-if", true),
|
|
435
|
+
(0, vue.renderSlot)(_ctx.$slots, "default")
|
|
436
|
+
], 64);
|
|
437
|
+
}
|
|
438
|
+
var ASmartSkeletonProvider_default = /* @__PURE__ */ export_helper_default(_sfc_main, [["render", _sfc_render], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeletonProvider.vue"]]);
|
|
439
|
+
//#endregion
|
|
440
|
+
exports.ASmartSkeleton = ASmartSkeleton_default;
|
|
441
|
+
exports.ASmartSkeletonBox = ASmartSkeletonBox_default;
|
|
442
|
+
exports.ASmartSkeletonProvider = ASmartSkeletonProvider_default;
|
|
443
|
+
exports.ASmartSkeletonSuspense = ASmartSkeletonSuspense_default;
|
|
444
|
+
exports.ATTR_BAR = require_core.ATTR_BAR;
|
|
445
|
+
exports.ATTR_BLOCK = require_core.ATTR_BLOCK;
|
|
446
|
+
exports.ATTR_DEBUG = require_core.ATTR_DEBUG;
|
|
447
|
+
exports.ATTR_GHOST = require_core.ATTR_GHOST;
|
|
448
|
+
exports.ATTR_IGNORE = require_core.ATTR_IGNORE;
|
|
449
|
+
exports.ATTR_LAYER = require_core.ATTR_LAYER;
|
|
450
|
+
exports.ATTR_LOADING = require_core.ATTR_LOADING;
|
|
451
|
+
exports.ATTR_OWN = require_core.ATTR_OWN;
|
|
452
|
+
exports.ATTR_PANE = require_core.ATTR_PANE;
|
|
453
|
+
exports.ATTR_RECT = require_core.ATTR_RECT;
|
|
454
|
+
exports.ATTR_REVEAL = require_core.ATTR_REVEAL;
|
|
455
|
+
exports.ATTR_SNAPSHOT = require_core.ATTR_SNAPSHOT;
|
|
456
|
+
exports.ATTR_STATUS = require_core.ATTR_STATUS;
|
|
457
|
+
exports.ATTR_XRAY = require_core.ATTR_XRAY;
|
|
458
|
+
exports.CASCADE_SPREAD = require_core.CASCADE_SPREAD;
|
|
459
|
+
exports.DEFAULT_COLORS = require_core.DEFAULT_COLORS;
|
|
460
|
+
exports.DEFAULT_SKELETON_BOX_OPTIONS = require_core.DEFAULT_SKELETON_BOX_OPTIONS;
|
|
461
|
+
exports.DEFAULT_TEXT = require_core.DEFAULT_TEXT;
|
|
462
|
+
exports.DEFAULT_THEME = require_core.DEFAULT_THEME;
|
|
463
|
+
exports.DURATIONS = require_core.DURATIONS;
|
|
464
|
+
exports.FADE_DURATION = require_core.FADE_DURATION;
|
|
465
|
+
exports.Ghost = require_core.Ghost;
|
|
466
|
+
exports.IMAGE_TIMEOUT = require_core.IMAGE_TIMEOUT;
|
|
467
|
+
exports.INLINE_SCRIPT = require_core.INLINE_SCRIPT;
|
|
468
|
+
exports.INLINE_STUB = require_core.INLINE_STUB;
|
|
469
|
+
exports.Memory = require_core.Memory;
|
|
470
|
+
exports.RESIZE_DURATION = require_core.RESIZE_DURATION;
|
|
471
|
+
exports.Reveal = require_core.Reveal;
|
|
472
|
+
exports.SKELETON_DELAY = require_core.SKELETON_DELAY;
|
|
473
|
+
exports.SMART_SKELETON_CSS = require_core.SMART_SKELETON_CSS;
|
|
474
|
+
exports.addStyles = require_core.addStyles;
|
|
475
|
+
exports.applyTheme = require_core.applyTheme;
|
|
476
|
+
exports.boxOf = require_core.boxOf;
|
|
477
|
+
exports.byContent = require_core.byContent;
|
|
478
|
+
exports.byPosition = require_core.byPosition;
|
|
479
|
+
exports.byRow = require_core.byRow;
|
|
480
|
+
exports.checkNonce = require_core.checkNonce;
|
|
481
|
+
exports.createSkeletonBox = require_core.createSkeletonBox;
|
|
482
|
+
exports.debugging = require_core.debugging;
|
|
483
|
+
exports.drawSkeleton = require_core.drawSkeleton;
|
|
484
|
+
exports.exitDuration = require_core.exitDuration;
|
|
485
|
+
exports.fadeIn = require_core.fadeIn;
|
|
486
|
+
exports.fadeOut = require_core.fadeOut;
|
|
487
|
+
exports.forgetShapes = require_core.forgetShapes;
|
|
488
|
+
exports.imageReady = require_core.imageReady;
|
|
489
|
+
exports.inlineScriptTag = require_core.inlineScriptTag;
|
|
490
|
+
exports.instant = require_core.instant;
|
|
491
|
+
exports.measureSkeleton = require_core.measureSkeleton;
|
|
492
|
+
exports.motionOf = require_core.motionOf;
|
|
493
|
+
exports.pendingImages = require_core.pendingImages;
|
|
494
|
+
exports.planReveal = require_core.planReveal;
|
|
495
|
+
exports.prefersReducedMotion = require_core.prefersReducedMotion;
|
|
496
|
+
exports.quickly = require_core.quickly;
|
|
497
|
+
exports.rectsOf = require_core.rectsOf;
|
|
498
|
+
exports.removeStyles = require_core.removeStyles;
|
|
499
|
+
exports.sequence = require_core.sequence;
|
|
500
|
+
exports.setDebug = require_core.setDebug;
|
|
501
|
+
exports.shimmer = require_core.shimmer;
|
|
502
|
+
exports.skeletonBoxStyle = require_core.skeletonBoxStyle;
|
|
503
|
+
exports.skeletonCSS = require_core.skeletonCSS;
|
|
504
|
+
exports.smart = require_core.smart;
|
|
505
|
+
exports.sweep = require_core.sweep;
|
|
506
|
+
exports.themeStyleTag = require_core.themeStyleTag;
|
|
507
|
+
exports.themeVariables = require_core.themeVariables;
|
|
508
|
+
exports.together = require_core.together;
|
|
509
|
+
exports.useSmartSkeleton = useSmartSkeleton;
|
|
510
|
+
exports.useStyles = useStyles;
|
|
511
|
+
|
|
512
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["addStyles","removeStyles"],"sources":["../src/composables/useSmartSkeleton.ts","../src/composables/useStyles.ts","../src/components/ASmartSkeleton.vue","../src/components/ASmartSkeletonBox.vue","../src/components/ASmartSkeletonSuspense.vue","../src/components/ASmartSkeletonProvider.vue"],"sourcesContent":["import { inject, type InjectionKey } from 'vue';\nimport type { SmartSkeletonConfig } from '../types';\n\nexport const SMART_SKELETON_CONFIG_KEY: InjectionKey<SmartSkeletonConfig> =\n Symbol('a-smart-skeleton');\n\n/** Per server render: whether the full inline script has gone out yet, so the skeletons after it send a stub. */\nexport const SMART_SKELETON_BOOT_KEY: InjectionKey<{ sent: boolean }> =\n Symbol('a-smart-skeleton.boot');\n\n/** The provider settings in scope for this component. Empty outside a provider. */\nexport const useSmartSkeleton = (): SmartSkeletonConfig => inject(SMART_SKELETON_CONFIG_KEY, {});\n\n/** Whether this skeleton should send the stub — claiming the full script if it's the first. */\nexport function claimStub(): boolean {\n const boot = inject(SMART_SKELETON_BOOT_KEY, null);\n const stub = !!boot?.sent;\n if (boot) boot.sent = true;\n return stub;\n}\n","import { onBeforeMount, onUnmounted } from 'vue';\nimport { addStyles, removeStyles } from '../core';\n\n/** Adds the stylesheet on mount and removes it on unmount — reference counted, so siblings share one copy. */\nexport function useStyles(): void {\n onBeforeMount(addStyles);\n onUnmounted(removeStyles);\n}\n","<script lang=\"ts\">\nimport {\n defineComponent,\n getCurrentInstance,\n h,\n onBeforeUnmount,\n onMounted,\n ref,\n Transition,\n watch,\n type PropType,\n type VNodeChild,\n} from 'vue';\nimport {\n ATTR_GHOST,\n ATTR_LAYER,\n ATTR_LOADING,\n ATTR_OWN,\n ATTR_PANE,\n ATTR_REVEAL,\n ATTR_SNAPSHOT,\n ATTR_STATUS,\n checkNonce,\n fadeIn,\n fadeOut,\n Ghost,\n INLINE_SCRIPT,\n INLINE_STUB,\n Memory,\n type MemoryOptions,\n type RevealMode,\n} from '../core';\nimport { claimStub, useSmartSkeleton } from '../composables/useSmartSkeleton';\nimport { useStyles } from '../composables/useStyles';\n\n/**\n * The measured loading pane. Internal — `<ASmartSkeleton>` renders it.\n *\n * The ghost is laid out but never seen; the layer holds bones in a shadow root,\n * so hydration never touches what was measured.\n */\nexport const Loading = defineComponent({\n name: 'ASmartSkeletonLoading',\n props: {\n id: String,\n exact: Boolean,\n refetch: Boolean,\n label: String,\n },\n setup(props, { slots }) {\n const element = ref<HTMLElement | null>(null);\n const config = useSmartSkeleton();\n const script = claimStub() ? INLINE_STUB : INLINE_SCRIPT;\n let ghost: Ghost | null = null;\n\n const optionsOf = () => ({ id: props.id, exact: props.exact, refetch: props.refetch });\n onMounted(() => {\n checkNonce(config.nonce);\n if (element.value) ghost = new Ghost(element.value, optionsOf());\n });\n // Options-only changes update the live ghost in place; the observers and shadow sheet\n // outlive a prop flip, which happens every data arrival in data-driven mode.\n watch(\n () => [props.id, props.exact, props.refetch],\n () => ghost?.update(optionsOf())\n );\n onBeforeUnmount(() => ghost?.destroy());\n\n return () => [\n props.label ? h('span', { [ATTR_STATUS]: '' }, props.label) : null,\n h(\n 'div',\n {\n ref: element,\n [ATTR_LOADING]: '',\n 'aria-hidden': 'true',\n inert: '',\n },\n [\n h('div', { [ATTR_GHOST]: '' }, slots.default?.()),\n h('div', { [ATTR_SNAPSHOT]: '' }),\n h('div', { [ATTR_LAYER]: '' }),\n ]\n ),\n h('script', { nonce: config.nonce, innerHTML: script }),\n ];\n },\n});\n\nexport const Content = defineComponent({\n name: 'ASmartSkeletonContent',\n props: {\n memory: { type: Object as PropType<MemoryOptions>, required: true },\n },\n setup(props, { slots }) {\n const element = ref<HTMLElement | null>(null);\n let memory: Memory | null = null;\n\n onMounted(() => {\n if (element.value) memory = new Memory(element.value, props.memory);\n });\n onBeforeUnmount(() => memory?.destroy());\n\n return () => h('div', { ref: element }, slots.default?.());\n },\n});\n\n/**\n * Shows a skeleton measured from the content it wraps, then reveals the content.\n *\n * ```vue\n * <ASmartSkeleton :data=\"user\" :sample=\"SAMPLE_USER\">\n * <template #default=\"{ data }\">\n * <UserCard :user=\"data\" />\n * </template>\n * </ASmartSkeleton>\n * ```\n */\nexport default defineComponent({\n name: 'ASmartSkeleton',\n props: {\n /** Shows the skeleton, even over `data`. With `data`, it also shows while there is none. */\n loading: { type: Boolean, default: undefined },\n /** Loading while `null` or `undefined`; handed to the default slot as `{ data }`. */\n data: { type: null as unknown as PropType<unknown>, required: false },\n /** Stands in for `data` to draw the skeleton before any has loaded. */\n sample: { type: null as unknown as PropType<unknown>, required: false },\n /** Remembers the shape under this key across visits. */\n id: String,\n /** Read to screen readers while loading, in place of the skeleton — \"Loading profile\". */\n label: String,\n empty: Boolean,\n error: { type: null as unknown as PropType<unknown>, required: false },\n /** Overrides the provider's reveal for this skeleton alone. */\n reveal: [String, Object] as PropType<RevealMode>,\n },\n /** `reveal`: content has come in over a skeleton. */\n emits: ['reveal'],\n setup(props, { slots, emit }) {\n const instance = getCurrentInstance();\n const config = useSmartSkeleton();\n let last: { id?: string; data: unknown } | null = null;\n let shown: string | null = null;\n let from: string | null = null;\n useStyles();\n\n return () => {\n const driven = !!instance?.vnode.props && 'data' in instance.vnode.props;\n const data = props.data;\n if (data != null) last = { id: props.id, data };\n\n const show = (value: unknown): VNodeChild =>\n driven\n ? value != null\n ? slots.default?.({ data: value })\n : null\n : slots.default?.({ data: undefined });\n\n const loading = !!props.loading || (driven && data == null && !props.error && !props.empty);\n\n let key: string;\n let content: VNodeChild;\n if (loading) {\n const previous = last as { id?: string; data: unknown } | null;\n const real = data ?? (previous && previous.id === props.id ? previous.data : null);\n key = 'skeleton';\n content = slots.skeleton\n ? h('div', { [ATTR_OWN]: '', 'aria-hidden': 'true' }, slots.skeleton())\n : h(\n Loading,\n {\n id: props.id,\n exact: real != null,\n refetch: data != null,\n label: props.label,\n },\n () => show(real ?? props.sample)\n );\n } else if (props.error) {\n key = 'error';\n content = slots.error?.({ error: props.error });\n } else if (props.empty) {\n key = 'empty';\n content = slots.empty?.() ?? show(data);\n } else {\n key = 'content';\n content = h(\n Content,\n {\n memory: {\n id: props.id,\n data,\n rendered: driven,\n sample: props.sample !== undefined,\n },\n },\n () => show(data)\n );\n }\n\n if (key !== shown) {\n from = shown;\n shown = key;\n }\n const revealing = key === 'content' && from === 'skeleton';\n\n const reveal = props.reveal ?? config.reveal;\n return h('div', { [ATTR_REVEAL]: '', 'aria-busy': loading || undefined }, [\n h(\n Transition,\n {\n css: false,\n appear: true,\n onAppear: (el, done) => fadeIn(el as HTMLElement, reveal, { initial: true }).then(done),\n onEnter: (el, done) =>\n fadeIn(el as HTMLElement, reveal).then(() => {\n done();\n if (revealing) emit('reveal');\n }),\n onLeave: (el, done) => fadeOut(el as HTMLElement).then(done),\n },\n () => h('div', { key, [ATTR_PANE]: '' }, [content])\n ),\n ]);\n };\n },\n});\n</script>\n","<script setup lang=\"ts\">\nimport { ref, onMounted } from 'vue';\nimport { shimmer, skeletonBoxStyle, ATTR_BAR } from '../core';\nimport { useStyles } from '../composables/useStyles';\nimport type { ASmartSkeletonBoxProps } from '../types';\n\ndefineOptions({\n name: 'ASmartSkeletonBox',\n});\n\nconst props = defineProps<ASmartSkeletonBoxProps>();\n\nconst element = ref<HTMLElement | null>(null);\nuseStyles();\n\nonMounted(() => {\n if (element.value) shimmer(element.value);\n});\n</script>\n\n<template>\n <span ref=\"element\" v-bind=\"{ [ATTR_BAR]: '' }\" :style=\"skeletonBoxStyle(props)\" />\n</template>\n","<script lang=\"ts\">\nimport { defineComponent, h, onBeforeUnmount, onMounted, ref, Suspense, type PropType } from 'vue';\nimport { ATTR_PANE, ATTR_REVEAL, boxOf, fadeIn, fadeOut, Memory, type RevealMode } from '../core';\nimport { useSmartSkeleton } from '../composables/useSmartSkeleton';\nimport { useStyles } from '../composables/useStyles';\nimport { Loading } from './ASmartSkeleton.vue';\n\ntype State = { waited: boolean; exit: (() => void) | null };\nconst state = { type: Object as PropType<State>, required: true } as const;\n\nexport const Fallback = defineComponent({\n name: 'ASmartSkeletonFallback',\n props: { id: String, label: String, reveal: [String, Object] as PropType<RevealMode>, state },\n setup(props, { slots }) {\n const element = ref<HTMLElement | null>(null);\n const config = useSmartSkeleton();\n\n onMounted(() => {\n const pane = element.value;\n const reveal = pane?.parentElement;\n if (!pane || !reveal) return;\n // eslint-disable-next-line vue/no-mutating-props\n props.state.waited = true;\n fadeIn(pane, props.reveal ?? config.reveal, { initial: true });\n reveal.setAttribute('aria-busy', 'true');\n });\n\n onBeforeUnmount(() => {\n const pane = element.value;\n const reveal = pane?.parentElement;\n if (!pane || !reveal) return;\n reveal.removeAttribute('aria-busy');\n\n const box = boxOf(pane);\n const copy = pane.cloneNode(true) as HTMLElement;\n // eslint-disable-next-line vue/no-mutating-props\n props.state.exit = () => {\n Object.assign(copy.style, {\n position: 'absolute',\n top: `${box.top}px`,\n left: `${box.left}px`,\n width: `${box.width}px`,\n });\n reveal.prepend(copy);\n fadeOut(copy).then(() => copy.remove());\n };\n });\n\n return () =>\n h(\n 'div',\n { ref: element, [ATTR_PANE]: '' },\n h(Loading, { id: props.id, exact: false, label: props.label }, slots.default)\n );\n },\n});\n\nexport const BoundaryContent = defineComponent({\n name: 'ASmartSkeletonBoundaryContent',\n props: { id: String, reveal: [String, Object] as PropType<RevealMode>, state },\n emits: ['reveal'],\n setup(props, { slots, emit }) {\n const element = ref<HTMLElement | null>(null);\n const config = useSmartSkeleton();\n let memory: Memory | null = null;\n\n onMounted(() => {\n const pane = element.value;\n if (!pane) return;\n const waited = props.state.waited;\n const arrival = fadeIn(pane, props.reveal ?? config.reveal, {\n initial: !waited,\n });\n if (waited) arrival.then(() => emit('reveal'));\n\n props.state.exit?.();\n // eslint-disable-next-line vue/no-mutating-props\n props.state.exit = null;\n memory = new Memory(pane, { id: props.id });\n });\n onBeforeUnmount(() => memory?.destroy());\n\n return () => h('div', { ref: element, [ATTR_PANE]: '' }, slots.default?.());\n },\n});\n\n/**\n * A Suspense boundary whose fallback is a measured skeleton, crossfading into the content.\n *\n * ```vue\n * <ASmartSkeletonSuspense>\n * <LoadedQuote />\n * <template #skeleton><Quote :quote=\"SAMPLE_QUOTE\" /></template>\n * </ASmartSkeletonSuspense>\n * ```\n */\nexport default defineComponent({\n name: 'ASmartSkeletonSuspense',\n props: {\n /** Remembers the shape under this key across visits. */\n id: String,\n /** Read to screen readers while suspended, in place of the skeleton. */\n label: String,\n /** Overrides the provider's reveal for this boundary alone. */\n reveal: [String, Object] as PropType<RevealMode>,\n },\n /** `reveal`: content has come in over the skeleton. */\n emits: ['reveal'],\n setup(props, { slots, emit }) {\n useStyles();\n const shared: State = { waited: false, exit: null };\n\n return () =>\n h('div', { [ATTR_REVEAL]: '' }, [\n h(Suspense, null, {\n default: () =>\n h(\n BoundaryContent,\n {\n id: props.id,\n reveal: props.reveal,\n state: shared,\n onReveal: () => emit('reveal'),\n },\n slots.default\n ),\n fallback: () =>\n h(\n Fallback,\n {\n id: props.id,\n label: props.label,\n reveal: props.reveal,\n state: shared,\n },\n slots.skeleton\n ),\n }),\n ]);\n },\n});\n</script>\n","<script setup lang=\"ts\">\nimport { computed, provide, watch } from 'vue';\nimport { setDebug, skeletonCSS } from '../core';\nimport {\n SMART_SKELETON_CONFIG_KEY,\n SMART_SKELETON_BOOT_KEY,\n} from '../composables/useSmartSkeleton';\nimport type { ASmartSkeletonProviderProps } from '../types';\n\ndefineOptions({\n name: 'ASmartSkeletonProvider',\n});\n\nconst props = defineProps<ASmartSkeletonProviderProps>();\n\nprovide(SMART_SKELETON_CONFIG_KEY, props);\nprovide(SMART_SKELETON_BOOT_KEY, { sent: false });\n\nwatch(\n () => props.debug,\n (debug) => {\n if (debug !== undefined && typeof window !== 'undefined') setDebug(debug);\n },\n { immediate: true }\n);\n\nconst css = computed(() => skeletonCSS(props));\n</script>\n\n<template>\n <!-- eslint-disable-next-line vue/no-v-text-v-html-on-component -->\n <component :is=\"'style'\" v-if=\"css\" :nonce=\"nonce\" v-text=\"css\" />\n <slot />\n</template>\n"],"mappings":"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"}
|