@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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +356 -2
  3. package/dist/_chunks/core.js +2314 -0
  4. package/dist/_chunks/core.js.map +1 -0
  5. package/dist/_chunks/index.d.ts +431 -0
  6. package/dist/core/index.cjs +67 -0
  7. package/dist/core/index.d.cts +2 -0
  8. package/dist/core/index.d.ts +2 -0
  9. package/dist/core/index.js +2 -0
  10. package/dist/element/index.cjs +47 -0
  11. package/dist/element/index.cjs.map +1 -0
  12. package/dist/element/index.d.cts +24 -0
  13. package/dist/element/index.d.ts +24 -0
  14. package/dist/element/index.js +46 -0
  15. package/dist/element/index.js.map +1 -0
  16. package/dist/index.cjs +512 -0
  17. package/dist/index.cjs.map +1 -0
  18. package/dist/index.d.cts +204 -0
  19. package/dist/index.d.ts +204 -0
  20. package/dist/index.js +441 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/nuxt/index.cjs +36 -0
  23. package/dist/nuxt/index.cjs.map +1 -0
  24. package/dist/nuxt/index.d.cts +30 -0
  25. package/dist/nuxt/index.d.ts +30 -0
  26. package/dist/nuxt/index.js +36 -0
  27. package/dist/nuxt/index.js.map +1 -0
  28. package/dist/resolver/index.cjs +26 -0
  29. package/dist/resolver/index.cjs.map +1 -0
  30. package/dist/resolver/index.d.cts +19 -0
  31. package/dist/resolver/index.d.ts +19 -0
  32. package/dist/resolver/index.js +26 -0
  33. package/dist/resolver/index.js.map +1 -0
  34. package/dist/styles.css +136 -0
  35. package/package.json +144 -3
  36. package/src/components/ASmartSkeleton.vue +228 -0
  37. package/src/components/ASmartSkeletonBox.vue +23 -0
  38. package/src/components/ASmartSkeletonProvider.vue +34 -0
  39. package/src/components/ASmartSkeletonSuspense.vue +142 -0
  40. package/src/composables/useSmartSkeleton.ts +20 -0
  41. package/src/composables/useStyles.ts +8 -0
  42. package/src/core/boot.ts +63 -0
  43. package/src/core/canvas.ts +7 -0
  44. package/src/core/constants.ts +76 -0
  45. package/src/core/debug.ts +154 -0
  46. package/src/core/dev.ts +53 -0
  47. package/src/core/fade.ts +490 -0
  48. package/src/core/ghost.ts +236 -0
  49. package/src/core/images.ts +28 -0
  50. package/src/core/index.ts +71 -0
  51. package/src/core/inline.generated.ts +9 -0
  52. package/src/core/measure.ts +571 -0
  53. package/src/core/memory.ts +146 -0
  54. package/src/core/motion.ts +12 -0
  55. package/src/core/plan.ts +368 -0
  56. package/src/core/reveal.ts +89 -0
  57. package/src/core/reveals.ts +39 -0
  58. package/src/core/shapes.ts +84 -0
  59. package/src/core/shimmer.ts +229 -0
  60. package/src/core/skeleton.ts +43 -0
  61. package/src/core/snapshot.ts +159 -0
  62. package/src/core/styles.ts +187 -0
  63. package/src/core/sweep.ts +203 -0
  64. package/src/core/theme.ts +162 -0
  65. package/src/element/index.ts +59 -0
  66. package/src/index.ts +27 -0
  67. package/src/nuxt/index.ts +59 -0
  68. package/src/resolver/index.ts +35 -0
  69. package/src/types.ts +100 -0
  70. package/src/vue/Skeleton.ts +275 -0
  71. package/src/vue/Suspense.ts +157 -0
  72. package/src/vue/config.ts +78 -0
  73. package/src/vue/index.ts +7 -0
  74. package/web-types.json +256 -0
package/dist/index.js ADDED
@@ -0,0 +1,441 @@
1
+ import { $ as ATTR_LOADING, A as DEFAULT_TEXT, B as themeVariables, C as smart, D as rectsOf, E as motionOf, F as DEFAULT_COLORS, G as addStyles, H as INLINE_STUB, I as DEFAULT_THEME, J as ATTR_BLOCK, K as removeStyles, L as applyTheme, M as checkNonce, N as debugging, O as shimmer, P as setDebug, Q as ATTR_LAYER, R as skeletonCSS, S as sequence, T as drawSkeleton, U as inlineScriptTag, V as INLINE_SCRIPT, W as SMART_SKELETON_CSS, X as ATTR_GHOST, Y as ATTR_DEBUG, Z as ATTR_IGNORE, _ as byPosition, a as exitDuration, at as ATTR_STATUS, b as planReveal, c as pendingImages, ct as DURATIONS, d as skeletonBoxStyle, dt as RESIZE_DURATION, et as ATTR_OWN, f as Memory, g as byContent, h as SKELETON_DELAY, i as fadeOut, it as ATTR_SNAPSHOT, j as measureSkeleton, k as prefersReducedMotion, l as DEFAULT_SKELETON_BOX_OPTIONS, lt as FADE_DURATION, m as forgetShapes, n as boxOf, nt as ATTR_RECT, o as sweep, ot as ATTR_XRAY, p as Ghost, q as ATTR_BAR, r as fadeIn, rt as ATTR_REVEAL, s as imageReady, st as CASCADE_SPREAD, t as Reveal, tt as ATTR_PANE, u as createSkeletonBox, ut as IMAGE_TIMEOUT, v as byRow, w as together, x as quickly, y as instant, z as themeStyleTag } from "./_chunks/core.js";
2
+ import { Fragment, Suspense, Transition, computed, createBlock, createCommentVNode, createElementBlock, defineComponent, getCurrentInstance, h, inject, mergeProps, onBeforeMount, onBeforeUnmount, onMounted, onUnmounted, openBlock, provide, ref, renderSlot, resolveDynamicComponent, toDisplayString, watch } from "vue";
3
+ //#region src/composables/useSmartSkeleton.ts
4
+ const SMART_SKELETON_CONFIG_KEY = Symbol("a-smart-skeleton");
5
+ /** Per server render: whether the full inline script has gone out yet, so the skeletons after it send a stub. */
6
+ const SMART_SKELETON_BOOT_KEY = Symbol("a-smart-skeleton.boot");
7
+ /** The provider settings in scope for this component. Empty outside a provider. */
8
+ const useSmartSkeleton = () => inject(SMART_SKELETON_CONFIG_KEY, {});
9
+ /** Whether this skeleton should send the stub — claiming the full script if it's the first. */
10
+ function claimStub() {
11
+ const boot = inject(SMART_SKELETON_BOOT_KEY, null);
12
+ const stub = !!boot?.sent;
13
+ if (boot) boot.sent = true;
14
+ return stub;
15
+ }
16
+ //#endregion
17
+ //#region src/composables/useStyles.ts
18
+ /** Adds the stylesheet on mount and removes it on unmount — reference counted, so siblings share one copy. */
19
+ function useStyles() {
20
+ onBeforeMount(addStyles);
21
+ onUnmounted(removeStyles);
22
+ }
23
+ //#endregion
24
+ //#region \0/plugin-vue/export-helper
25
+ var export_helper_default = (sfc, props) => {
26
+ const target = sfc.__vccOpts || sfc;
27
+ for (const [key, val] of props) target[key] = val;
28
+ return target;
29
+ };
30
+ //#endregion
31
+ //#region src/components/ASmartSkeleton.vue
32
+ /**
33
+ * The measured loading pane. Internal — `<ASmartSkeleton>` renders it.
34
+ *
35
+ * The ghost is laid out but never seen; the layer holds bones in a shadow root,
36
+ * so hydration never touches what was measured.
37
+ */
38
+ const Loading = defineComponent({
39
+ name: "ASmartSkeletonLoading",
40
+ props: {
41
+ id: String,
42
+ exact: Boolean,
43
+ refetch: Boolean,
44
+ label: String
45
+ },
46
+ setup(props, { slots }) {
47
+ const element = ref(null);
48
+ const config = useSmartSkeleton();
49
+ const script = claimStub() ? INLINE_STUB : INLINE_SCRIPT;
50
+ let ghost = null;
51
+ const optionsOf = () => ({
52
+ id: props.id,
53
+ exact: props.exact,
54
+ refetch: props.refetch
55
+ });
56
+ onMounted(() => {
57
+ checkNonce(config.nonce);
58
+ if (element.value) ghost = new Ghost(element.value, optionsOf());
59
+ });
60
+ watch(() => [
61
+ props.id,
62
+ props.exact,
63
+ props.refetch
64
+ ], () => ghost?.update(optionsOf()));
65
+ onBeforeUnmount(() => ghost?.destroy());
66
+ return () => [
67
+ props.label ? h("span", { [ATTR_STATUS]: "" }, props.label) : null,
68
+ h("div", {
69
+ ref: element,
70
+ [ATTR_LOADING]: "",
71
+ "aria-hidden": "true",
72
+ inert: ""
73
+ }, [
74
+ h("div", { [ATTR_GHOST]: "" }, slots.default?.()),
75
+ h("div", { [ATTR_SNAPSHOT]: "" }),
76
+ h("div", { [ATTR_LAYER]: "" })
77
+ ]),
78
+ h("script", {
79
+ nonce: config.nonce,
80
+ innerHTML: script
81
+ })
82
+ ];
83
+ }
84
+ });
85
+ const Content = defineComponent({
86
+ name: "ASmartSkeletonContent",
87
+ props: { memory: {
88
+ type: Object,
89
+ required: true
90
+ } },
91
+ setup(props, { slots }) {
92
+ const element = ref(null);
93
+ let memory = null;
94
+ onMounted(() => {
95
+ if (element.value) memory = new Memory(element.value, props.memory);
96
+ });
97
+ onBeforeUnmount(() => memory?.destroy());
98
+ return () => h("div", { ref: element }, slots.default?.());
99
+ }
100
+ });
101
+ var ASmartSkeleton_default = /* @__PURE__ */ export_helper_default(defineComponent({
102
+ name: "ASmartSkeleton",
103
+ props: {
104
+ /** Shows the skeleton, even over `data`. With `data`, it also shows while there is none. */
105
+ loading: {
106
+ type: Boolean,
107
+ default: void 0
108
+ },
109
+ /** Loading while `null` or `undefined`; handed to the default slot as `{ data }`. */
110
+ data: {
111
+ type: null,
112
+ required: false
113
+ },
114
+ /** Stands in for `data` to draw the skeleton before any has loaded. */
115
+ sample: {
116
+ type: null,
117
+ required: false
118
+ },
119
+ /** Remembers the shape under this key across visits. */
120
+ id: String,
121
+ /** Read to screen readers while loading, in place of the skeleton — "Loading profile". */
122
+ label: String,
123
+ empty: Boolean,
124
+ error: {
125
+ type: null,
126
+ required: false
127
+ },
128
+ /** Overrides the provider's reveal for this skeleton alone. */
129
+ reveal: [String, Object]
130
+ },
131
+ /** `reveal`: content has come in over a skeleton. */
132
+ emits: ["reveal"],
133
+ setup(props, { slots, emit }) {
134
+ const instance = getCurrentInstance();
135
+ const config = useSmartSkeleton();
136
+ let last = null;
137
+ let shown = null;
138
+ let from = null;
139
+ useStyles();
140
+ return () => {
141
+ const driven = !!instance?.vnode.props && "data" in instance.vnode.props;
142
+ const data = props.data;
143
+ if (data != null) last = {
144
+ id: props.id,
145
+ data
146
+ };
147
+ const show = (value) => driven ? value != null ? slots.default?.({ data: value }) : null : slots.default?.({ data: void 0 });
148
+ const loading = !!props.loading || driven && data == null && !props.error && !props.empty;
149
+ let key;
150
+ let content;
151
+ if (loading) {
152
+ const previous = last;
153
+ const real = data ?? (previous && previous.id === props.id ? previous.data : null);
154
+ key = "skeleton";
155
+ content = slots.skeleton ? h("div", {
156
+ [ATTR_OWN]: "",
157
+ "aria-hidden": "true"
158
+ }, slots.skeleton()) : h(Loading, {
159
+ id: props.id,
160
+ exact: real != null,
161
+ refetch: data != null,
162
+ label: props.label
163
+ }, () => show(real ?? props.sample));
164
+ } else if (props.error) {
165
+ key = "error";
166
+ content = slots.error?.({ error: props.error });
167
+ } else if (props.empty) {
168
+ key = "empty";
169
+ content = slots.empty?.() ?? show(data);
170
+ } else {
171
+ key = "content";
172
+ content = h(Content, { memory: {
173
+ id: props.id,
174
+ data,
175
+ rendered: driven,
176
+ sample: props.sample !== void 0
177
+ } }, () => show(data));
178
+ }
179
+ if (key !== shown) {
180
+ from = shown;
181
+ shown = key;
182
+ }
183
+ const revealing = key === "content" && from === "skeleton";
184
+ const reveal = props.reveal ?? config.reveal;
185
+ return h("div", {
186
+ [ATTR_REVEAL]: "",
187
+ "aria-busy": loading || void 0
188
+ }, [h(Transition, {
189
+ css: false,
190
+ appear: true,
191
+ onAppear: (el, done) => fadeIn(el, reveal, { initial: true }).then(done),
192
+ onEnter: (el, done) => fadeIn(el, reveal).then(() => {
193
+ done();
194
+ if (revealing) emit("reveal");
195
+ }),
196
+ onLeave: (el, done) => fadeOut(el).then(done)
197
+ }, () => h("div", {
198
+ key,
199
+ [ATTR_PANE]: ""
200
+ }, [content]))]);
201
+ };
202
+ }
203
+ }), [["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeleton.vue"]]);
204
+ //#endregion
205
+ //#region src/components/ASmartSkeletonBox.vue
206
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
207
+ name: "ASmartSkeletonBox",
208
+ __name: "ASmartSkeletonBox",
209
+ props: {
210
+ class: {
211
+ type: String,
212
+ required: false
213
+ },
214
+ style: {
215
+ type: Object,
216
+ required: false
217
+ },
218
+ height: {
219
+ type: [String, Number],
220
+ required: false
221
+ },
222
+ width: {
223
+ type: [String, Number],
224
+ required: false
225
+ },
226
+ radius: {
227
+ type: [String, Number],
228
+ required: false
229
+ }
230
+ },
231
+ setup(__props, { expose: __expose }) {
232
+ __expose();
233
+ const props = __props;
234
+ const element = ref(null);
235
+ useStyles();
236
+ onMounted(() => {
237
+ if (element.value) shimmer(element.value);
238
+ });
239
+ const __returned__ = {
240
+ props,
241
+ element,
242
+ get skeletonBoxStyle() {
243
+ return skeletonBoxStyle;
244
+ },
245
+ get ATTR_BAR() {
246
+ return ATTR_BAR;
247
+ }
248
+ };
249
+ Object.defineProperty(__returned__, "__isScriptSetup", {
250
+ enumerable: false,
251
+ value: true
252
+ });
253
+ return __returned__;
254
+ }
255
+ });
256
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
257
+ return openBlock(), createElementBlock("span", mergeProps({ ref: "element" }, { [$setup.ATTR_BAR]: "" }, { style: $setup.skeletonBoxStyle($setup.props) }), null, 16);
258
+ }
259
+ 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"]]);
260
+ //#endregion
261
+ //#region src/components/ASmartSkeletonSuspense.vue
262
+ const state = {
263
+ type: Object,
264
+ required: true
265
+ };
266
+ const Fallback = defineComponent({
267
+ name: "ASmartSkeletonFallback",
268
+ props: {
269
+ id: String,
270
+ label: String,
271
+ reveal: [String, Object],
272
+ state
273
+ },
274
+ setup(props, { slots }) {
275
+ const element = ref(null);
276
+ const config = useSmartSkeleton();
277
+ onMounted(() => {
278
+ const pane = element.value;
279
+ const reveal = pane?.parentElement;
280
+ if (!pane || !reveal) return;
281
+ props.state.waited = true;
282
+ fadeIn(pane, props.reveal ?? config.reveal, { initial: true });
283
+ reveal.setAttribute("aria-busy", "true");
284
+ });
285
+ onBeforeUnmount(() => {
286
+ const pane = element.value;
287
+ const reveal = pane?.parentElement;
288
+ if (!pane || !reveal) return;
289
+ reveal.removeAttribute("aria-busy");
290
+ const box = boxOf(pane);
291
+ const copy = pane.cloneNode(true);
292
+ props.state.exit = () => {
293
+ Object.assign(copy.style, {
294
+ position: "absolute",
295
+ top: `${box.top}px`,
296
+ left: `${box.left}px`,
297
+ width: `${box.width}px`
298
+ });
299
+ reveal.prepend(copy);
300
+ fadeOut(copy).then(() => copy.remove());
301
+ };
302
+ });
303
+ return () => h("div", {
304
+ ref: element,
305
+ [ATTR_PANE]: ""
306
+ }, h(Loading, {
307
+ id: props.id,
308
+ exact: false,
309
+ label: props.label
310
+ }, slots.default));
311
+ }
312
+ });
313
+ const BoundaryContent = defineComponent({
314
+ name: "ASmartSkeletonBoundaryContent",
315
+ props: {
316
+ id: String,
317
+ reveal: [String, Object],
318
+ state
319
+ },
320
+ emits: ["reveal"],
321
+ setup(props, { slots, emit }) {
322
+ const element = ref(null);
323
+ const config = useSmartSkeleton();
324
+ let memory = null;
325
+ onMounted(() => {
326
+ const pane = element.value;
327
+ if (!pane) return;
328
+ const waited = props.state.waited;
329
+ const arrival = fadeIn(pane, props.reveal ?? config.reveal, { initial: !waited });
330
+ if (waited) arrival.then(() => emit("reveal"));
331
+ props.state.exit?.();
332
+ props.state.exit = null;
333
+ memory = new Memory(pane, { id: props.id });
334
+ });
335
+ onBeforeUnmount(() => memory?.destroy());
336
+ return () => h("div", {
337
+ ref: element,
338
+ [ATTR_PANE]: ""
339
+ }, slots.default?.());
340
+ }
341
+ });
342
+ var ASmartSkeletonSuspense_default = /* @__PURE__ */ export_helper_default(defineComponent({
343
+ name: "ASmartSkeletonSuspense",
344
+ props: {
345
+ /** Remembers the shape under this key across visits. */
346
+ id: String,
347
+ /** Read to screen readers while suspended, in place of the skeleton. */
348
+ label: String,
349
+ /** Overrides the provider's reveal for this boundary alone. */
350
+ reveal: [String, Object]
351
+ },
352
+ /** `reveal`: content has come in over the skeleton. */
353
+ emits: ["reveal"],
354
+ setup(props, { slots, emit }) {
355
+ useStyles();
356
+ const shared = {
357
+ waited: false,
358
+ exit: null
359
+ };
360
+ return () => h("div", { [ATTR_REVEAL]: "" }, [h(Suspense, null, {
361
+ default: () => h(BoundaryContent, {
362
+ id: props.id,
363
+ reveal: props.reveal,
364
+ state: shared,
365
+ onReveal: () => emit("reveal")
366
+ }, slots.default),
367
+ fallback: () => h(Fallback, {
368
+ id: props.id,
369
+ label: props.label,
370
+ reveal: props.reveal,
371
+ state: shared
372
+ }, slots.skeleton)
373
+ })]);
374
+ }
375
+ }), [["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/ASmartSkeleton/src/components/ASmartSkeletonSuspense.vue"]]);
376
+ //#endregion
377
+ //#region src/components/ASmartSkeletonProvider.vue
378
+ const _sfc_main = /* @__PURE__ */ defineComponent({
379
+ name: "ASmartSkeletonProvider",
380
+ __name: "ASmartSkeletonProvider",
381
+ props: {
382
+ nonce: {
383
+ type: String,
384
+ required: false
385
+ },
386
+ theme: {
387
+ type: Object,
388
+ required: false
389
+ },
390
+ mode: {
391
+ type: String,
392
+ required: false
393
+ },
394
+ text: {
395
+ type: Object,
396
+ required: false
397
+ },
398
+ reveal: {
399
+ type: [String, Object],
400
+ required: false
401
+ },
402
+ debug: {
403
+ type: Boolean,
404
+ required: false
405
+ }
406
+ },
407
+ setup(__props, { expose: __expose }) {
408
+ __expose();
409
+ const props = __props;
410
+ provide(SMART_SKELETON_CONFIG_KEY, props);
411
+ provide(SMART_SKELETON_BOOT_KEY, { sent: false });
412
+ watch(() => props.debug, (debug) => {
413
+ if (debug !== void 0 && typeof window !== "undefined") setDebug(debug);
414
+ }, { immediate: true });
415
+ const __returned__ = {
416
+ props,
417
+ css: computed(() => skeletonCSS(props))
418
+ };
419
+ Object.defineProperty(__returned__, "__isScriptSetup", {
420
+ enumerable: false,
421
+ value: true
422
+ });
423
+ return __returned__;
424
+ }
425
+ });
426
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
427
+ return openBlock(), createElementBlock(Fragment, null, [
428
+ createCommentVNode(" eslint-disable-next-line vue/no-v-text-v-html-on-component "),
429
+ $setup.css ? (openBlock(), createBlock(resolveDynamicComponent("style"), {
430
+ key: 0,
431
+ nonce: $props.nonce,
432
+ textContent: toDisplayString($setup.css)
433
+ }, null, 8, ["nonce", "textContent"])) : createCommentVNode("v-if", true),
434
+ renderSlot(_ctx.$slots, "default")
435
+ ], 64);
436
+ }
437
+ 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"]]);
438
+ //#endregion
439
+ export { ASmartSkeleton_default as ASmartSkeleton, ASmartSkeletonBox_default as ASmartSkeletonBox, ASmartSkeletonProvider_default as ASmartSkeletonProvider, ASmartSkeletonSuspense_default as ASmartSkeletonSuspense, ATTR_BAR, ATTR_BLOCK, ATTR_DEBUG, ATTR_GHOST, ATTR_IGNORE, ATTR_LAYER, ATTR_LOADING, ATTR_OWN, ATTR_PANE, ATTR_RECT, ATTR_REVEAL, ATTR_SNAPSHOT, ATTR_STATUS, ATTR_XRAY, CASCADE_SPREAD, DEFAULT_COLORS, DEFAULT_SKELETON_BOX_OPTIONS, DEFAULT_TEXT, DEFAULT_THEME, DURATIONS, FADE_DURATION, Ghost, IMAGE_TIMEOUT, INLINE_SCRIPT, INLINE_STUB, Memory, RESIZE_DURATION, Reveal, SKELETON_DELAY, SMART_SKELETON_CSS, addStyles, applyTheme, boxOf, byContent, byPosition, byRow, checkNonce, createSkeletonBox, debugging, drawSkeleton, exitDuration, fadeIn, fadeOut, forgetShapes, imageReady, inlineScriptTag, instant, measureSkeleton, motionOf, pendingImages, planReveal, prefersReducedMotion, quickly, rectsOf, removeStyles, sequence, setDebug, shimmer, skeletonBoxStyle, skeletonCSS, smart, sweep, themeStyleTag, themeVariables, together, useSmartSkeleton, useStyles };
440
+
441
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"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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"}
@@ -0,0 +1,36 @@
1
+ let _nuxt_kit = require("@nuxt/kit");
2
+ //#region src/nuxt/index.ts
3
+ const COMPONENTS = {
4
+ ASmartSkeleton: "@alikhalilll/a-smart-skeleton",
5
+ ASmartSkeletonBox: "@alikhalilll/a-smart-skeleton",
6
+ ASmartSkeletonSuspense: "@alikhalilll/a-smart-skeleton",
7
+ ASmartSkeletonProvider: "@alikhalilll/a-smart-skeleton"
8
+ };
9
+ const STYLES = "@alikhalilll/a-smart-skeleton/styles.css";
10
+ const module$1 = (0, _nuxt_kit.defineNuxtModule)({
11
+ meta: {
12
+ name: "@alikhalilll/a-smart-skeleton",
13
+ configKey: "aSmartSkeleton",
14
+ compatibility: { nuxt: ">=3.0.0" }
15
+ },
16
+ defaults: {
17
+ prefix: "",
18
+ styles: true
19
+ },
20
+ setup(opts, nuxt) {
21
+ const prefix = opts.prefix ?? "";
22
+ for (const [exportName, from] of Object.entries(COMPONENTS)) {
23
+ const baseName = exportName.startsWith("A") ? exportName.slice(1) : exportName;
24
+ (0, _nuxt_kit.addComponent)({
25
+ name: `${prefix}${prefix ? baseName : exportName}`,
26
+ export: exportName,
27
+ filePath: from
28
+ });
29
+ }
30
+ if (opts.styles !== false && !nuxt.options.css.includes(STYLES)) nuxt.options.css.push(STYLES);
31
+ }
32
+ });
33
+ //#endregion
34
+ module.exports = module$1;
35
+
36
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["module"],"sources":["../../src/nuxt/index.ts"],"sourcesContent":["import { defineNuxtModule, addComponent } from '@nuxt/kit';\nimport type { NuxtModule } from '@nuxt/schema';\n\n/**\n * `@alikhalilll/a-smart-skeleton/nuxt` — registers the components for Nuxt\n * auto-import and adds the stylesheet to the app.\n *\n * modules: ['@alikhalilll/a-smart-skeleton/nuxt'],\n * aSmartSkeleton: { prefix: 'A', styles: true },\n *\n * Components registered natively:\n * <ASmartSkeleton> measured skeleton wrapper\n * <ASmartSkeletonBox> one shimmering bar\n * <ASmartSkeletonSuspense> Suspense boundary with a measured fallback\n * <ASmartSkeletonProvider> theme / nonce / reveal defaults\n *\n * The stylesheet is added to `nuxt.options.css` by default. It is also\n * injected at runtime, but shipping it in the page is what lets a\n * server-rendered skeleton be hidden before the first paint.\n */\n\nexport interface ModuleOptions {\n /** Optional prefix prepended to the registered component name. */\n prefix?: string;\n /** Add `@alikhalilll/a-smart-skeleton/styles.css` to the Nuxt css array. Default `true`. */\n styles?: boolean;\n}\n\nconst COMPONENTS: Record<string, string> = {\n ASmartSkeleton: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonBox: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonSuspense: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonProvider: '@alikhalilll/a-smart-skeleton',\n};\n\nconst STYLES = '@alikhalilll/a-smart-skeleton/styles.css';\n\nconst module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({\n meta: {\n name: '@alikhalilll/a-smart-skeleton',\n configKey: 'aSmartSkeleton',\n compatibility: { nuxt: '>=3.0.0' },\n },\n defaults: { prefix: '', styles: true },\n setup(opts, nuxt) {\n const prefix = opts.prefix ?? '';\n for (const [exportName, from] of Object.entries(COMPONENTS)) {\n const baseName = exportName.startsWith('A') ? exportName.slice(1) : exportName;\n const registeredName = `${prefix}${prefix ? baseName : exportName}`;\n addComponent({ name: registeredName, export: exportName, filePath: from });\n }\n\n if (opts.styles !== false && !nuxt.options.css.includes(STYLES)) {\n nuxt.options.css.push(STYLES);\n }\n },\n});\n\nexport default module;\n"],"mappings":";;AA4BA,MAAM,aAAqC;CACzC,gBAAgB;CAChB,mBAAmB;CACnB,wBAAwB;CACxB,wBAAwB;AAC1B;AAEA,MAAM,SAAS;AAEf,MAAMA,YAAAA,GAAAA,UAAAA,kBAAoE;CACxE,MAAM;EACJ,MAAM;EACN,WAAW;EACX,eAAe,EAAE,MAAM,UAAU;CACnC;CACA,UAAU;EAAE,QAAQ;EAAI,QAAQ;CAAK;CACrC,MAAM,MAAM,MAAM;EAChB,MAAM,SAAS,KAAK,UAAU;EAC9B,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,UAAU,GAAG;GAC3D,MAAM,WAAW,WAAW,WAAW,GAAG,IAAI,WAAW,MAAM,CAAC,IAAI;GAEpE,CAAA,GAAA,UAAA,cAAa;IAAE,MAAM,GADK,SAAS,SAAS,WAAW;IAClB,QAAQ;IAAY,UAAU;GAAK,CAAC;EAC3E;EAEA,IAAI,KAAK,WAAW,SAAS,CAAC,KAAK,QAAQ,IAAI,SAAS,MAAM,GAC5D,KAAK,QAAQ,IAAI,KAAK,MAAM;CAEhC;AACF,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { NuxtModule } from "@nuxt/schema";
2
+
3
+ //#region src/nuxt/index.d.ts
4
+ /**
5
+ * `@alikhalilll/a-smart-skeleton/nuxt` — registers the components for Nuxt
6
+ * auto-import and adds the stylesheet to the app.
7
+ *
8
+ * modules: ['@alikhalilll/a-smart-skeleton/nuxt'],
9
+ * aSmartSkeleton: { prefix: 'A', styles: true },
10
+ *
11
+ * Components registered natively:
12
+ * <ASmartSkeleton> measured skeleton wrapper
13
+ * <ASmartSkeletonBox> one shimmering bar
14
+ * <ASmartSkeletonSuspense> Suspense boundary with a measured fallback
15
+ * <ASmartSkeletonProvider> theme / nonce / reveal defaults
16
+ *
17
+ * The stylesheet is added to `nuxt.options.css` by default. It is also
18
+ * injected at runtime, but shipping it in the page is what lets a
19
+ * server-rendered skeleton be hidden before the first paint.
20
+ */
21
+ interface ModuleOptions {
22
+ /** Optional prefix prepended to the registered component name. */
23
+ prefix?: string;
24
+ /** Add `@alikhalilll/a-smart-skeleton/styles.css` to the Nuxt css array. Default `true`. */
25
+ styles?: boolean;
26
+ }
27
+ declare const module: NuxtModule<ModuleOptions>;
28
+ //#endregion
29
+ export { ModuleOptions, module as default };
30
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,30 @@
1
+ import { NuxtModule } from "@nuxt/schema";
2
+
3
+ //#region src/nuxt/index.d.ts
4
+ /**
5
+ * `@alikhalilll/a-smart-skeleton/nuxt` — registers the components for Nuxt
6
+ * auto-import and adds the stylesheet to the app.
7
+ *
8
+ * modules: ['@alikhalilll/a-smart-skeleton/nuxt'],
9
+ * aSmartSkeleton: { prefix: 'A', styles: true },
10
+ *
11
+ * Components registered natively:
12
+ * <ASmartSkeleton> measured skeleton wrapper
13
+ * <ASmartSkeletonBox> one shimmering bar
14
+ * <ASmartSkeletonSuspense> Suspense boundary with a measured fallback
15
+ * <ASmartSkeletonProvider> theme / nonce / reveal defaults
16
+ *
17
+ * The stylesheet is added to `nuxt.options.css` by default. It is also
18
+ * injected at runtime, but shipping it in the page is what lets a
19
+ * server-rendered skeleton be hidden before the first paint.
20
+ */
21
+ interface ModuleOptions {
22
+ /** Optional prefix prepended to the registered component name. */
23
+ prefix?: string;
24
+ /** Add `@alikhalilll/a-smart-skeleton/styles.css` to the Nuxt css array. Default `true`. */
25
+ styles?: boolean;
26
+ }
27
+ declare const module: NuxtModule<ModuleOptions>;
28
+ //#endregion
29
+ export { ModuleOptions, module as default };
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { addComponent, defineNuxtModule } from "@nuxt/kit";
2
+ //#region src/nuxt/index.ts
3
+ const COMPONENTS = {
4
+ ASmartSkeleton: "@alikhalilll/a-smart-skeleton",
5
+ ASmartSkeletonBox: "@alikhalilll/a-smart-skeleton",
6
+ ASmartSkeletonSuspense: "@alikhalilll/a-smart-skeleton",
7
+ ASmartSkeletonProvider: "@alikhalilll/a-smart-skeleton"
8
+ };
9
+ const STYLES = "@alikhalilll/a-smart-skeleton/styles.css";
10
+ const module = defineNuxtModule({
11
+ meta: {
12
+ name: "@alikhalilll/a-smart-skeleton",
13
+ configKey: "aSmartSkeleton",
14
+ compatibility: { nuxt: ">=3.0.0" }
15
+ },
16
+ defaults: {
17
+ prefix: "",
18
+ styles: true
19
+ },
20
+ setup(opts, nuxt) {
21
+ const prefix = opts.prefix ?? "";
22
+ for (const [exportName, from] of Object.entries(COMPONENTS)) {
23
+ const baseName = exportName.startsWith("A") ? exportName.slice(1) : exportName;
24
+ addComponent({
25
+ name: `${prefix}${prefix ? baseName : exportName}`,
26
+ export: exportName,
27
+ filePath: from
28
+ });
29
+ }
30
+ if (opts.styles !== false && !nuxt.options.css.includes(STYLES)) nuxt.options.css.push(STYLES);
31
+ }
32
+ });
33
+ //#endregion
34
+ export { module as default };
35
+
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/nuxt/index.ts"],"sourcesContent":["import { defineNuxtModule, addComponent } from '@nuxt/kit';\nimport type { NuxtModule } from '@nuxt/schema';\n\n/**\n * `@alikhalilll/a-smart-skeleton/nuxt` — registers the components for Nuxt\n * auto-import and adds the stylesheet to the app.\n *\n * modules: ['@alikhalilll/a-smart-skeleton/nuxt'],\n * aSmartSkeleton: { prefix: 'A', styles: true },\n *\n * Components registered natively:\n * <ASmartSkeleton> measured skeleton wrapper\n * <ASmartSkeletonBox> one shimmering bar\n * <ASmartSkeletonSuspense> Suspense boundary with a measured fallback\n * <ASmartSkeletonProvider> theme / nonce / reveal defaults\n *\n * The stylesheet is added to `nuxt.options.css` by default. It is also\n * injected at runtime, but shipping it in the page is what lets a\n * server-rendered skeleton be hidden before the first paint.\n */\n\nexport interface ModuleOptions {\n /** Optional prefix prepended to the registered component name. */\n prefix?: string;\n /** Add `@alikhalilll/a-smart-skeleton/styles.css` to the Nuxt css array. Default `true`. */\n styles?: boolean;\n}\n\nconst COMPONENTS: Record<string, string> = {\n ASmartSkeleton: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonBox: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonSuspense: '@alikhalilll/a-smart-skeleton',\n ASmartSkeletonProvider: '@alikhalilll/a-smart-skeleton',\n};\n\nconst STYLES = '@alikhalilll/a-smart-skeleton/styles.css';\n\nconst module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({\n meta: {\n name: '@alikhalilll/a-smart-skeleton',\n configKey: 'aSmartSkeleton',\n compatibility: { nuxt: '>=3.0.0' },\n },\n defaults: { prefix: '', styles: true },\n setup(opts, nuxt) {\n const prefix = opts.prefix ?? '';\n for (const [exportName, from] of Object.entries(COMPONENTS)) {\n const baseName = exportName.startsWith('A') ? exportName.slice(1) : exportName;\n const registeredName = `${prefix}${prefix ? baseName : exportName}`;\n addComponent({ name: registeredName, export: exportName, filePath: from });\n }\n\n if (opts.styles !== false && !nuxt.options.css.includes(STYLES)) {\n nuxt.options.css.push(STYLES);\n }\n },\n});\n\nexport default module;\n"],"mappings":";;AA4BA,MAAM,aAAqC;CACzC,gBAAgB;CAChB,mBAAmB;CACnB,wBAAwB;CACxB,wBAAwB;AAC1B;AAEA,MAAM,SAAS;AAEf,MAAM,SAAoC,iBAAgC;CACxE,MAAM;EACJ,MAAM;EACN,WAAW;EACX,eAAe,EAAE,MAAM,UAAU;CACnC;CACA,UAAU;EAAE,QAAQ;EAAI,QAAQ;CAAK;CACrC,MAAM,MAAM,MAAM;EAChB,MAAM,SAAS,KAAK,UAAU;EAC9B,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,UAAU,GAAG;GAC3D,MAAM,WAAW,WAAW,WAAW,GAAG,IAAI,WAAW,MAAM,CAAC,IAAI;GAEpE,aAAa;IAAE,MAAM,GADK,SAAS,SAAS,WAAW;IAClB,QAAQ;IAAY,UAAU;GAAK,CAAC;EAC3E;EAEA,IAAI,KAAK,WAAW,SAAS,CAAC,KAAK,QAAQ,IAAI,SAAS,MAAM,GAC5D,KAAK,QAAQ,IAAI,KAAK,MAAM;CAEhC;AACF,CAAC"}
@@ -0,0 +1,26 @@
1
+ //#region src/resolver/index.ts
2
+ const COMPONENT_TO_ENTRY = {
3
+ ASmartSkeleton: "@alikhalilll/a-smart-skeleton",
4
+ ASmartSkeletonBox: "@alikhalilll/a-smart-skeleton",
5
+ ASmartSkeletonSuspense: "@alikhalilll/a-smart-skeleton",
6
+ ASmartSkeletonProvider: "@alikhalilll/a-smart-skeleton"
7
+ };
8
+ function ASmartSkeletonResolver(opts = {}) {
9
+ const prefix = opts.prefix ?? "";
10
+ return {
11
+ type: "component",
12
+ resolve(name) {
13
+ const bare = prefix && name.startsWith(prefix) ? name.slice(prefix.length) : name;
14
+ const from = COMPONENT_TO_ENTRY[bare];
15
+ if (!from) return;
16
+ return {
17
+ name: bare,
18
+ from
19
+ };
20
+ }
21
+ };
22
+ }
23
+ //#endregion
24
+ module.exports = ASmartSkeletonResolver;
25
+
26
+ //# sourceMappingURL=index.cjs.map