@alfakit/vue 0.1.0 → 0.1.1
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/CHANGELOG.md +9 -0
- package/dist/components/cms/CmsLinkButton.vue.d.ts +1 -1
- package/dist/eject-manifest.json +2 -2
- package/dist/lib/Icon.js.map +1 -1
- package/dist/lib/Icon.vue.d.ts.map +1 -1
- package/dist/lib/Icon.vue_vue_type_script_setup_true_lang.js +18 -19
- package/dist/lib/Icon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/lib/hydration.d.ts +9 -0
- package/dist/lib/hydration.d.ts.map +1 -0
- package/dist/lib/hydration.js +17 -0
- package/dist/lib/hydration.js.map +1 -0
- package/dist/lib/icons.d.ts +3 -5
- package/dist/lib/icons.d.ts.map +1 -1
- package/dist/lib/icons.js +19 -22
- package/dist/lib/icons.js.map +1 -1
- package/dist/lib/lazy.d.ts +1 -1
- package/dist/lib/lazy.d.ts.map +1 -1
- package/dist/lib/lazy.js +12 -11
- package/dist/lib/lazy.js.map +1 -1
- package/package.json +2 -2
- package/src/lib/Icon.vue +6 -5
- package/src/lib/hydration.ts +35 -0
- package/src/lib/icons.ts +6 -11
- package/src/lib/lazy.ts +5 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @alfakit/vue
|
|
2
|
+
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Vue: icons and lazily loaded components no longer cause hydration mismatches when another app on the page already loaded them. Package READMEs show the Alfa Six logo on npm.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @alfakit/core@0.1.1
|
|
@@ -9,8 +9,8 @@ type __VLS_Props = {
|
|
|
9
9
|
class?: HTMLAttributes['class'];
|
|
10
10
|
};
|
|
11
11
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
12
|
-
class: string | false | Record<string, any> | import("vue").ClassValue[] | null;
|
|
13
12
|
size: "xs" | "sm" | "lg" | "icon" | "default" | "icon-sm" | "icon-xs" | null;
|
|
13
|
+
class: string | false | Record<string, any> | import("vue").ClassValue[] | null;
|
|
14
14
|
variant: "secondary" | "link" | "default" | "destructive" | "outline" | "ghost" | "plain" | null;
|
|
15
15
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
16
|
export default _default;
|
package/dist/eject-manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@alfakit/vue",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"adapter": "vue",
|
|
5
|
-
"generatedAt": "2026-10-19T06:
|
|
5
|
+
"generatedAt": "2026-10-19T06:40:49.122Z",
|
|
6
6
|
"components": {
|
|
7
7
|
"TextInput": {
|
|
8
8
|
"file": "src/components/fields/TextInputField.vue",
|
package/dist/lib/Icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.js","names":["_sfc_main","Icon_vue_vue_type_script_setup_true_lang_default","Icon_default"],"sources":["../../src/lib/Icon.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { iconAlias, iconAliasOverride, iconSource, isIconAlias } from '@alfakit/core'\nimport { computed,
|
|
1
|
+
{"version":3,"file":"Icon.js","names":["_sfc_main","Icon_vue_vue_type_script_setup_true_lang_default","Icon_default"],"sources":["../../src/lib/Icon.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { iconAlias, iconAliasOverride, iconSource, isIconAlias } from '@alfakit/core'\nimport { computed, type Component, type HTMLAttributes } from 'vue'\nimport { useOptionalRegistry } from '../context'\nimport { useAppMounted } from './hydration'\nimport { iconMap, resolveIcon } from './icons'\nimport { cn } from './utils'\n\n/**\n * Renders an icon resolved by the server (`Icons::resolve()`): a Lucide name (`users`,\n * `shopping-cart`), an image URL or sanitised `<svg>` markup. `alfakit::` aliases use the\n * app's replacement (`Icons::register()`) or `fallback`. Unknown Lucide names render the\n * `fallback` icon (if any) or nothing. `fallback` may also be a statically imported glyph\n * (`:fallback=\"SearchIcon\"`): renderer chrome uses it so an unreplaced alias draws at once,\n * without loading anything.\n */\nconst props = defineProps<{\n name?: string | null\n fallback?: string | Component | null\n class?: HTMLAttributes['class']\n}>()\n\n// `createAlfakit({ components: { 'panel:icon': MyIcon } })` renders every named icon with\n// another icon set; it receives `name`, `fallback` and `class`.\nconst custom = useOptionalRegistry()?.resolve('panel:icon')\n// Named icons render once this app has hydrated (the server render shows none).\nconst mounted = useAppMounted()\n\nconst fallbackName = computed(() =>\n typeof props.fallback === 'string' ? props.fallback : undefined,\n)\nconst glyph = computed(() =>\n props.fallback && typeof props.fallback !== 'string' ? props.fallback : null,\n)\n\n// Chrome icons (`<Icon name=\"alfakit::…\" :fallback=\"SearchIcon\" />`) draw their bundled glyph\n// synchronously unless the app replaced the alias with `Icons::register()`.\nconst useGlyph = computed(\n () =>\n glyph.value !== null &&\n !!props.name &&\n isIconAlias(props.name) &&\n iconAliasOverride(props.name) === undefined,\n)\n\nconst source = computed(() =>\n props.name && !useGlyph.value ? iconSource(iconAlias(props.name, fallbackName.value)) : null,\n)\n\nconst component = computed(() => {\n if (source.value?.type !== 'name' || custom) return null\n\n const icons = iconMap(mounted.value)\n\n // Nothing until the icon map has loaded (and during the server render and hydration).\n if (!icons) return null\n\n return (\n resolveIcon(source.value.name, icons) ??\n glyph.value ??\n (fallbackName.value ? resolveIcon(fallbackName.value, icons) : null)\n )\n})\n</script>\n\n<template>\n <component :is=\"glyph\" v-if=\"useGlyph && glyph\" :class=\"cn('size-4 shrink-0', props.class)\" />\n <!-- Sanitised on the server (SvgSanitizer): drawing elements only. -->\n <!-- eslint-disable vue/no-v-html -->\n <span\n v-else-if=\"source?.type === 'svg'\"\n aria-hidden=\"true\"\n data-slot=\"icon\"\n :class=\"cn('inline-flex size-4 shrink-0 [&>svg]:size-full', props.class)\"\n v-html=\"source.svg\"\n />\n <!-- eslint-enable vue/no-v-html -->\n <img\n v-else-if=\"source?.type === 'url'\"\n :src=\"source.url\"\n alt=\"\"\n aria-hidden=\"true\"\n data-slot=\"icon\"\n :class=\"cn('size-4 shrink-0 object-contain', props.class)\"\n />\n <component\n :is=\"custom\"\n v-else-if=\"custom && source?.type === 'name'\"\n :name=\"source.name\"\n :fallback=\"fallbackName\"\n :class=\"cn('size-4 shrink-0', props.class)\"\n />\n <component :is=\"component\" v-else-if=\"component\" :class=\"cn('size-4 shrink-0', props.class)\" />\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.vue.d.ts","sourceRoot":"","sources":["../../src/lib/Icon.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Icon.vue.d.ts","sourceRoot":"","sources":["../../src/lib/Icon.vue"],"names":[],"mappings":"AAiGA,OAAO,EAAY,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAMnE;;;;;;;GAOG;AACH,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IACpC,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAChC,CAAC;;AAuIF,wBAMG"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useOptionalRegistry as e } from "../context.js";
|
|
2
2
|
import { cn as t } from "./utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { useAppMounted as n } from "./hydration.js";
|
|
4
|
+
import { iconMap as r, resolveIcon as i } from "./icons.js";
|
|
4
5
|
import { iconAlias as a, iconAliasOverride as o, iconSource as s, isIconAlias as c } from "@alfakit/core";
|
|
5
|
-
import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, defineComponent as p, normalizeClass as m,
|
|
6
|
+
import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, defineComponent as p, normalizeClass as m, openBlock as h, resolveDynamicComponent as g, unref as _ } from "vue";
|
|
6
7
|
//#region src/lib/Icon.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
-
var
|
|
8
|
+
var v = ["innerHTML"], y = ["src"], b = /*@__PURE__*/ p({
|
|
8
9
|
__name: "Icon",
|
|
9
10
|
props: {
|
|
10
11
|
name: {},
|
|
@@ -18,45 +19,43 @@ var y = ["innerHTML"], b = ["src"], x = /*@__PURE__*/ p({
|
|
|
18
19
|
] }
|
|
19
20
|
},
|
|
20
21
|
setup(p) {
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (E.value?.type !== "name" || S) return null;
|
|
25
|
-
let e = n();
|
|
22
|
+
let b = p, x = e()?.resolve("panel:icon"), S = n(), C = l(() => typeof b.fallback == "string" ? b.fallback : void 0), w = l(() => b.fallback && typeof b.fallback != "string" ? b.fallback : null), T = l(() => w.value !== null && !!b.name && c(b.name) && o(b.name) === void 0), E = l(() => b.name && !T.value ? s(a(b.name, C.value)) : null), D = l(() => {
|
|
23
|
+
if (E.value?.type !== "name" || x) return null;
|
|
24
|
+
let e = r(S.value);
|
|
26
25
|
return e ? i(E.value.name, e) ?? w.value ?? (C.value ? i(C.value, e) : null) : null;
|
|
27
26
|
});
|
|
28
|
-
return (e, n) => T.value && w.value ? (
|
|
27
|
+
return (e, n) => T.value && w.value ? (h(), u(g(w.value), {
|
|
29
28
|
key: 0,
|
|
30
|
-
class: m(
|
|
31
|
-
}, null, 8, ["class"])) : E.value?.type === "svg" ? (
|
|
29
|
+
class: m(_(t)("size-4 shrink-0", b.class))
|
|
30
|
+
}, null, 8, ["class"])) : E.value?.type === "svg" ? (h(), f("span", {
|
|
32
31
|
key: 1,
|
|
33
32
|
"aria-hidden": "true",
|
|
34
33
|
"data-slot": "icon",
|
|
35
|
-
class: m(
|
|
34
|
+
class: m(_(t)("inline-flex size-4 shrink-0 [&>svg]:size-full", b.class)),
|
|
36
35
|
innerHTML: E.value.svg
|
|
37
|
-
}, null, 10,
|
|
36
|
+
}, null, 10, v)) : E.value?.type === "url" ? (h(), f("img", {
|
|
38
37
|
key: 2,
|
|
39
38
|
src: E.value.url,
|
|
40
39
|
alt: "",
|
|
41
40
|
"aria-hidden": "true",
|
|
42
41
|
"data-slot": "icon",
|
|
43
|
-
class: m(
|
|
44
|
-
}, null, 10,
|
|
42
|
+
class: m(_(t)("size-4 shrink-0 object-contain", b.class))
|
|
43
|
+
}, null, 10, y)) : _(x) && E.value?.type === "name" ? (h(), u(g(_(x)), {
|
|
45
44
|
key: 3,
|
|
46
45
|
name: E.value.name,
|
|
47
46
|
fallback: C.value,
|
|
48
|
-
class: m(
|
|
47
|
+
class: m(_(t)("size-4 shrink-0", b.class))
|
|
49
48
|
}, null, 8, [
|
|
50
49
|
"name",
|
|
51
50
|
"fallback",
|
|
52
51
|
"class"
|
|
53
|
-
])) : D.value ? (
|
|
52
|
+
])) : D.value ? (h(), u(g(D.value), {
|
|
54
53
|
key: 4,
|
|
55
|
-
class: m(
|
|
54
|
+
class: m(_(t)("size-4 shrink-0", b.class))
|
|
56
55
|
}, null, 8, ["class"])) : d("", !0);
|
|
57
56
|
}
|
|
58
57
|
});
|
|
59
58
|
//#endregion
|
|
60
|
-
export {
|
|
59
|
+
export { b as default };
|
|
61
60
|
|
|
62
61
|
//# sourceMappingURL=Icon.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_unref","_createElementBlock","_createCommentVNode","_hoisted_1","_hoisted_2","Icon_vue_vue_type_script_setup_true_lang_default","props","__props","custom","useOptionalRegistry","
|
|
1
|
+
{"version":3,"file":"Icon.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_unref","_createElementBlock","_createCommentVNode","_hoisted_1","_hoisted_2","Icon_vue_vue_type_script_setup_true_lang_default","props","__props","custom","useOptionalRegistry","mounted","useAppMounted","fallbackName","computed","glyph","useGlyph","isIconAlias","iconAliasOverride","source","iconSource","iconAlias","component","icons","iconMap","resolveIcon","openBlock","createBlock","resolveDynamicComponent","normalizeClass","unref","cn","createElementBlock","createCommentVNode"],"sources":["../../src/lib/Icon.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { iconAlias, iconAliasOverride, iconSource, isIconAlias } from '@alfakit/core'\nimport { computed, type Component, type HTMLAttributes } from 'vue'\nimport { useOptionalRegistry } from '../context'\nimport { useAppMounted } from './hydration'\nimport { iconMap, resolveIcon } from './icons'\nimport { cn } from './utils'\n\n/**\n * Renders an icon resolved by the server (`Icons::resolve()`): a Lucide name (`users`,\n * `shopping-cart`), an image URL or sanitised `<svg>` markup. `alfakit::` aliases use the\n * app's replacement (`Icons::register()`) or `fallback`. Unknown Lucide names render the\n * `fallback` icon (if any) or nothing. `fallback` may also be a statically imported glyph\n * (`:fallback=\"SearchIcon\"`): renderer chrome uses it so an unreplaced alias draws at once,\n * without loading anything.\n */\nconst props = defineProps<{\n name?: string | null\n fallback?: string | Component | null\n class?: HTMLAttributes['class']\n}>()\n\n// `createAlfakit({ components: { 'panel:icon': MyIcon } })` renders every named icon with\n// another icon set; it receives `name`, `fallback` and `class`.\nconst custom = useOptionalRegistry()?.resolve('panel:icon')\n// Named icons render once this app has hydrated (the server render shows none).\nconst mounted = useAppMounted()\n\nconst fallbackName = computed(() =>\n typeof props.fallback === 'string' ? props.fallback : undefined,\n)\nconst glyph = computed(() =>\n props.fallback && typeof props.fallback !== 'string' ? props.fallback : null,\n)\n\n// Chrome icons (`<Icon name=\"alfakit::…\" :fallback=\"SearchIcon\" />`) draw their bundled glyph\n// synchronously unless the app replaced the alias with `Icons::register()`.\nconst useGlyph = computed(\n () =>\n glyph.value !== null &&\n !!props.name &&\n isIconAlias(props.name) &&\n iconAliasOverride(props.name) === undefined,\n)\n\nconst source = computed(() =>\n props.name && !useGlyph.value ? iconSource(iconAlias(props.name, fallbackName.value)) : null,\n)\n\nconst component = computed(() => {\n if (source.value?.type !== 'name' || custom) return null\n\n const icons = iconMap(mounted.value)\n\n // Nothing until the icon map has loaded (and during the server render and hydration).\n if (!icons) return null\n\n return (\n resolveIcon(source.value.name, icons) ??\n glyph.value ??\n (fallbackName.value ? resolveIcon(fallbackName.value, icons) : null)\n )\n})\n</script>\n\n<template>\n <component :is=\"glyph\" v-if=\"useGlyph && glyph\" :class=\"cn('size-4 shrink-0', props.class)\" />\n <!-- Sanitised on the server (SvgSanitizer): drawing elements only. -->\n <!-- eslint-disable vue/no-v-html -->\n <span\n v-else-if=\"source?.type === 'svg'\"\n aria-hidden=\"true\"\n data-slot=\"icon\"\n :class=\"cn('inline-flex size-4 shrink-0 [&>svg]:size-full', props.class)\"\n v-html=\"source.svg\"\n />\n <!-- eslint-enable vue/no-v-html -->\n <img\n v-else-if=\"source?.type === 'url'\"\n :src=\"source.url\"\n alt=\"\"\n aria-hidden=\"true\"\n data-slot=\"icon\"\n :class=\"cn('size-4 shrink-0 object-contain', props.class)\"\n />\n <component\n :is=\"custom\"\n v-else-if=\"custom && source?.type === 'name'\"\n :name=\"source.name\"\n :fallback=\"fallbackName\"\n :class=\"cn('size-4 shrink-0', props.class)\"\n />\n <component :is=\"component\" v-else-if=\"component\" :class=\"cn('size-4 shrink-0', props.class)\" />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAgBA,IAAMU,IAAQC,GAQRC,IAASC,EAAoB,CAAC,EAAE,QAAQ,YAAY,GAEpDC,IAAUC,EAAc,GAExBC,IAAeC,QACnB,OAAOP,EAAM,YAAa,WAAWA,EAAM,WAAW,KAAA,CACxD,GACMQ,IAAQD,QACZP,EAAM,YAAY,OAAOA,EAAM,YAAa,WAAWA,EAAM,WAAW,IAC1E,GAIMS,IAAWF,QAEbC,EAAM,UAAU,QAChB,CAAC,CAACR,EAAM,QACRU,EAAYV,EAAM,IAAI,KACtBW,EAAkBX,EAAM,IAAI,MAAM,KAAA,CACtC,GAEMY,IAASL,QACbP,EAAM,QAAQ,CAACS,EAAS,QAAQI,EAAWC,EAAUd,EAAM,MAAMM,EAAa,KAAK,CAAC,IAAI,IAC1F,GAEMS,IAAYR,QAAe;GAC/B,IAAIK,EAAO,OAAO,SAAS,UAAUV,GAAQ,OAAO;GAEpD,IAAMc,IAAQC,EAAQb,EAAQ,KAAK;GAKnC,OAFKY,IAGHE,EAAYN,EAAO,MAAM,MAAMI,CAAK,KACpCR,EAAM,UACLF,EAAa,QAAQY,EAAYZ,EAAa,OAAOU,CAAK,IAAI,QAL9C;EAOrB,CAAC;mBAI8BP,EAAA,SAAYD,EAAA,SAAzClB,EAAA,GAAAC,EAA8FC,EAA9EgB,EAAA,KAAK,GAAA;;GAA4B,OAAKf,EAAEC,EAAA8B,CAAA,CAAE,CAAA,mBAAoBxB,EAAM,KAAK,CAAA;EAI5E,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,KAAAY,EAAA,OAAQ,SAAI,SADzBtB,EAAA,GAAAK,EAME,QAAA;;GAJA,eAAY;GACZ,aAAU;GACT,OAAKF,EAAEC,EAAA8B,CAAA,CAAE,CAAA,iDAAkDxB,EAAM,KAAK,CAAA;GACvE,WAAQY,EAAA,MAAO;EAIJ,GAAA,MAAA,IAAAf,CAAA,KAAAe,EAAA,OAAQ,SAAI,SADzBtB,EAAA,GAAAK,EAOE,OAAA;;GALC,KAAKiB,EAAA,MAAO;GACb,KAAI;GACJ,eAAY;GACZ,aAAU;GACT,OAAKnB,EAAEC,EAAA8B,CAAA,CAAE,CAAA,kCAAmCxB,EAAM,KAAK,CAAA;EAI7CN,GAAAA,MAAAA,IAAAA,CAAAA,KAAAA,EAAAQ,CAAA,KAAUU,EAAA,OAAQ,SAAI,UAFnCtB,EAAA,GAAAC,EAMEC,EALKE,EAAAQ,CAAA,CAAM,GAAA;;GAEV,MAAMU,EAAA,MAAO;GACb,UAAUN,EAAA;GACV,OAAKb,EAAEC,EAAA8B,CAAA,CAAE,CAAA,mBAAoBxB,EAAM,KAAK,CAAA;;;;;EAEL,CAAA,KAAAe,EAAA,SAAtCzB,EAAA,GAAAC,EAA+FC,EAA/EuB,EAAA,KAAS,GAAA;;GAAyB,OAAKtB,EAAEC,EAAA8B,CAAA,CAAE,CAAA,mBAAoBxB,EAAM,KAAK,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Call in a component's setup: `false` until the component's app has mounted (so during
|
|
4
|
+
* the server render and hydration), then `true` for every component in that app, so
|
|
5
|
+
* content rendered later draws at once (reactive). Lazily loaded parts (named icons, heavy
|
|
6
|
+
* fields) render their server markup until then, whatever has loaded already.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useAppMounted(): Ref<boolean>;
|
|
9
|
+
//# sourceMappingURL=hydration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydration.d.ts","sourceRoot":"","sources":["../../src/lib/hydration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,GAAG,EAAE,MAAM,KAAK,CAAA;AASnF;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,OAAO,CAAC,CAmB5C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getCurrentInstance as e, onMounted as t, ref as n } from "vue";
|
|
2
|
+
//#region src/lib/hydration.ts
|
|
3
|
+
var r = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function i() {
|
|
5
|
+
let i = e()?.appContext;
|
|
6
|
+
if (!i) return n(!0);
|
|
7
|
+
let a = r.get(i);
|
|
8
|
+
a || (a = n(!1), r.set(i, a));
|
|
9
|
+
let o = a;
|
|
10
|
+
return t(() => {
|
|
11
|
+
o.value = !0;
|
|
12
|
+
}), o;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { i as useAppMounted };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=hydration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydration.js","names":["mountedApps","useAppMounted","context","getCurrentInstance","ref","mounted","flag","onMounted"],"sources":["../../src/lib/hydration.ts"],"sourcesContent":["import { getCurrentInstance, onMounted, ref, type AppContext, type Ref } from 'vue'\n\n/**\n * Whether each app has mounted (hydrated). Kept per app, not per module: loaded icon chunks\n * and lazy components outlive an app, so a second app hydrating in the same page would\n * otherwise draw content its server markup does not contain.\n */\nconst mountedApps = new WeakMap<AppContext, Ref<boolean>>()\n\n/**\n * Call in a component's setup: `false` until the component's app has mounted (so during\n * the server render and hydration), then `true` for every component in that app, so\n * content rendered later draws at once (reactive). Lazily loaded parts (named icons, heavy\n * fields) render their server markup until then, whatever has loaded already.\n */\nexport function useAppMounted(): Ref<boolean> {\n const context = getCurrentInstance()?.appContext\n\n // Outside a component there is no hydration to wait for.\n if (!context) return ref(true)\n\n let mounted = mountedApps.get(context)\n\n if (!mounted) {\n mounted = ref(false)\n mountedApps.set(context, mounted)\n }\n\n const flag = mounted\n onMounted(() => {\n flag.value = true\n })\n\n return flag\n}\n"],"mappings":";;AAOA,IAAMA,oBAAc,IAAI,QAAkC;AAQ1D,SAAgBC,IAA8B;CAC5C,IAAMC,IAAUC,EAAmB,CAAC,EAAE;CAGtC,IAAI,CAACD,GAAS,OAAOE,EAAI,EAAI;CAE7B,IAAIC,IAAUL,EAAY,IAAIE,CAAO;CAErC,AAAKG,MACH,IAAUD,EAAI,EAAK,GACnBJ,EAAY,IAAIE,GAASG,CAAO;CAGlC,IAAMC,IAAOD;CAKb,OAJAE,QAAgB;EACd,EAAK,QAAQ;CACf,CAAC,GAEMD;AACT"}
|
package/dist/lib/icons.d.ts
CHANGED
|
@@ -12,13 +12,11 @@ import type * as IconModules from './icon-modules';
|
|
|
12
12
|
export type IconMap = typeof IconModules;
|
|
13
13
|
/** Start loading the icon map ahead of the first named icon (browser only). */
|
|
14
14
|
export declare function preloadIcons(): void;
|
|
15
|
-
/** `<Icon>`s call this once mounted: from then on named icons render (after hydration). */
|
|
16
|
-
export declare function markIconsMounted(): void;
|
|
17
15
|
/**
|
|
18
|
-
* The icon map once it has loaded in the browser and the
|
|
19
|
-
* (reactive). Starts loading it.
|
|
16
|
+
* The icon map once it has loaded in the browser and the `<Icon>`'s app has mounted
|
|
17
|
+
* (`useAppMounted()`), else `null` (reactive). Starts loading it.
|
|
20
18
|
*/
|
|
21
|
-
export declare function iconMap(): IconMap | null;
|
|
19
|
+
export declare function iconMap(mounted: boolean): IconMap | null;
|
|
22
20
|
/**
|
|
23
21
|
* The icon component for `name`, or `null` for unknown names (and while the icon map
|
|
24
22
|
* loads; the result is reactive).
|
package/dist/lib/icons.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/lib/icons.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/lib/icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,KAAK,CAAA;AACtE,OAAO,KAAK,KAAK,WAAW,MAAM,gBAAgB,CAAA;AAElD;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,WAAW,CAAA;AAsBxC,+EAA+E;AAC/E,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAuBhF;AAED,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/lib/icons.js
CHANGED
|
@@ -1,35 +1,32 @@
|
|
|
1
1
|
import { hasIcon as e } from "./icon-catalog.js";
|
|
2
2
|
import t from "./Icon.js";
|
|
3
|
-
import { defineAsyncComponent as n,
|
|
3
|
+
import { defineAsyncComponent as n, shallowRef as r } from "vue";
|
|
4
4
|
//#region src/lib/icons.ts
|
|
5
|
-
var
|
|
6
|
-
function
|
|
7
|
-
typeof window < "u" && (
|
|
8
|
-
throw
|
|
9
|
-
}),
|
|
5
|
+
var i = r(null), a, o = /* @__PURE__ */ new Map();
|
|
6
|
+
function s() {
|
|
7
|
+
typeof window < "u" && (a ??= import("./icon-modules.js").then((e) => i.value = e, (e) => {
|
|
8
|
+
throw a = void 0, e;
|
|
9
|
+
}), a.catch(() => void 0));
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
11
|
+
function c() {
|
|
12
|
+
s();
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
14
|
+
function l(e) {
|
|
15
|
+
return i.value || s(), e ? i.value : null;
|
|
16
16
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
function p(e, t) {
|
|
21
|
-
t === void 0 && l();
|
|
22
|
-
let r = t === void 0 ? a.value : t;
|
|
17
|
+
function u(e, t) {
|
|
18
|
+
t === void 0 && s();
|
|
19
|
+
let r = t === void 0 ? i.value : t;
|
|
23
20
|
if (!r) return null;
|
|
24
|
-
let
|
|
25
|
-
if (
|
|
26
|
-
let
|
|
27
|
-
loader: () =>
|
|
21
|
+
let a = o.get(e);
|
|
22
|
+
if (a !== void 0) return a;
|
|
23
|
+
let c = r.iconModules[r.iconPath(e, r.iconModules)], l = c ? n({
|
|
24
|
+
loader: () => c().then((e) => e.default),
|
|
28
25
|
suspensible: !1
|
|
29
26
|
}) : null;
|
|
30
|
-
return
|
|
27
|
+
return o.set(e, l), l;
|
|
31
28
|
}
|
|
32
29
|
//#endregion
|
|
33
|
-
export { t as Icon, e as hasIcon,
|
|
30
|
+
export { t as Icon, e as hasIcon, l as iconMap, c as preloadIcons, u as resolveIcon };
|
|
34
31
|
|
|
35
32
|
//# sourceMappingURL=icons.js.map
|
package/dist/lib/icons.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","names":["Icon_default","loadedMap","shallowRef","
|
|
1
|
+
{"version":3,"file":"icons.js","names":["Icon_default","loadedMap","shallowRef","pending","cache","loadIconMap","module","error","preloadIcons","iconMap","mounted","resolveIcon","map","icons","cached","name","loader","component","defineAsyncComponent","hasIcon"],"sources":["../../src/lib/icons.ts"],"sourcesContent":["import { defineAsyncComponent, shallowRef, type Component } from 'vue'\nimport type * as IconModules from './icon-modules'\n\n/**\n * Lazily loaded Lucide icons keyed by kebab-case name (`users`, `shopping-cart`). Each icon\n * becomes its own chunk, like `lucide-react/dynamic`, so the main bundle stays small.\n *\n * The name → chunk map (~2,000 entries, `./icon-modules`) is not part of any entry chunk\n * either: panels (`createAlfakit()`, starter kit pages) start loading it while they boot,\n * and elsewhere (a host's sidebar) it loads with the first icon. As in the other renderers,\n * named icons are drawn in the browser only: the server render and hydration show none.\n */\nexport type IconMap = typeof IconModules\n\nconst loadedMap = shallowRef<IconMap | null>(null)\n\nlet pending: Promise<IconMap> | undefined\n\nconst cache = new Map<string, Component | null>()\n\nfunction loadIconMap(): void {\n if (typeof window === 'undefined') return\n\n pending ??= import('./icon-modules').then(\n (module) => (loadedMap.value = module),\n (error: unknown) => {\n pending = undefined\n\n throw error\n },\n )\n pending.catch(() => undefined)\n}\n\n/** Start loading the icon map ahead of the first named icon (browser only). */\nexport function preloadIcons(): void {\n loadIconMap()\n}\n\n/**\n * The icon map once it has loaded in the browser and the `<Icon>`'s app has mounted\n * (`useAppMounted()`), else `null` (reactive). Starts loading it.\n */\nexport function iconMap(mounted: boolean): IconMap | null {\n if (!loadedMap.value) loadIconMap()\n\n return mounted ? loadedMap.value : null\n}\n\n/**\n * The icon component for `name`, or `null` for unknown names (and while the icon map\n * loads; the result is reactive).\n */\nexport function resolveIcon(name: string, map?: IconMap | null): Component | null {\n if (map === undefined) loadIconMap()\n\n const icons = map === undefined ? loadedMap.value : map\n\n if (!icons) return null\n\n const cached = cache.get(name)\n\n if (cached !== undefined) {\n return cached\n }\n\n const loader = icons.iconModules[icons.iconPath(name, icons.iconModules)]\n const component = loader\n ? defineAsyncComponent({\n loader: () => loader().then((module) => module.default),\n suspensible: false,\n })\n : null\n cache.set(name, component)\n\n return component\n}\n\nexport { hasIcon } from './icon-catalog'\nexport { default as Icon } from './Icon.vue'\n"],"mappings":";;;;AAcA,IAAMC,IAAYC,EAA2B,IAAI,GAE7CC,GAEEC,oBAAQ,IAAI,IAA8B;AAEhD,SAASC,IAAoB;CAC3B,AAAI,OAAO,SAAW,QAEtB,MAAY,OAAO,oBAAiB,CAAC,MAClC,MAAY,EAAU,QAAQC,IAC9B,MAAmB;EAGlB,MAFA,IAAU,KAAA,GAEJC;CACR,CACF,GACAJ,EAAQ,YAAY,KAAA,CAAS;AAC/B;AAGA,SAAgBK,IAAqB;CACnC,EAAY;AACd;AAMA,SAAgBC,EAAQ,GAAkC;CAGxD,OAFKR,EAAU,SAAOI,EAAY,GAE3BK,IAAUT,EAAU,QAAQ;AACrC;AAMA,SAAgBU,EAAY,GAAc,GAAwC;CAChF,AAAIC,MAAQ,KAAA,KAAWP,EAAY;CAEnC,IAAMQ,IAAQD,MAAQ,KAAA,IAAYX,EAAU,QAAQW;CAEpD,IAAI,CAACC,GAAO,OAAO;CAEnB,IAAMC,IAASV,EAAM,IAAIW,CAAI;CAE7B,IAAID,MAAW,KAAA,GACb,OAAOA;CAGT,IAAME,IAASH,EAAM,YAAYA,EAAM,SAASE,GAAMF,EAAM,WAAW,IACjEI,IAAYD,IACdE,EAAqB;EACnB,cAAcF,EAAO,CAAC,CAAC,MAAM,MAAWV,EAAO,OAAO;EACtD,aAAa;CACf,CAAC,IACD;CAGJ,OAFAF,EAAM,IAAIW,GAAME,CAAS,GAElBA;AACT"}
|
package/dist/lib/lazy.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Component } from 'vue';
|
|
|
2
2
|
/**
|
|
3
3
|
* A component whose code (and heavy dependencies such as Tiptap or Chart.js) loads on
|
|
4
4
|
* first use. The server render and hydration show `fallback` and never start the import;
|
|
5
|
-
* once
|
|
5
|
+
* once the app has mounted, a loaded component renders straight away.
|
|
6
6
|
*/
|
|
7
7
|
export declare function lazyComponent(name: string, load: () => Promise<Component>, fallback: Component): Component;
|
|
8
8
|
//# sourceMappingURL=lazy.d.ts.map
|
package/dist/lib/lazy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/lib/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/lib/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,KAAK,CAAA;AAG9E;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,EAC9B,QAAQ,EAAE,SAAS,GAClB,SAAS,CAuBX"}
|
package/dist/lib/lazy.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useAppMounted as e } from "./hydration.js";
|
|
2
|
+
import { defineAsyncComponent as t, defineComponent as n, h as r } from "vue";
|
|
2
3
|
//#region src/lib/lazy.ts
|
|
3
|
-
function
|
|
4
|
-
let
|
|
5
|
-
loader: () =>
|
|
6
|
-
loadingComponent:
|
|
4
|
+
function i(i, a, o) {
|
|
5
|
+
let s = null, c = t({
|
|
6
|
+
loader: () => a().then((e) => (s = e, e)),
|
|
7
|
+
loadingComponent: o,
|
|
7
8
|
delay: 0,
|
|
8
9
|
suspensible: !1
|
|
9
10
|
});
|
|
10
|
-
return
|
|
11
|
-
name:
|
|
11
|
+
return n({
|
|
12
|
+
name: i,
|
|
12
13
|
inheritAttrs: !1,
|
|
13
|
-
setup(
|
|
14
|
-
let
|
|
15
|
-
return
|
|
14
|
+
setup(t, { attrs: n }) {
|
|
15
|
+
let i = e();
|
|
16
|
+
return () => r(i.value ? s ?? c : o, n);
|
|
16
17
|
}
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
20
|
//#endregion
|
|
20
|
-
export {
|
|
21
|
+
export { i as lazyComponent };
|
|
21
22
|
|
|
22
23
|
//# sourceMappingURL=lazy.js.map
|
package/dist/lib/lazy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.js","names":["lazyComponent","loaded","Async","defineAsyncComponent","load","component","fallback","defineComponent","mounted","
|
|
1
|
+
{"version":3,"file":"lazy.js","names":["lazyComponent","loaded","Async","defineAsyncComponent","load","component","fallback","defineComponent","mounted","useAppMounted","h","attrs"],"sources":["../../src/lib/lazy.ts"],"sourcesContent":["import { defineAsyncComponent, defineComponent, h, type Component } from 'vue'\nimport { useAppMounted } from './hydration'\n\n/**\n * A component whose code (and heavy dependencies such as Tiptap or Chart.js) loads on\n * first use. The server render and hydration show `fallback` and never start the import;\n * once the app has mounted, a loaded component renders straight away.\n */\nexport function lazyComponent(\n name: string,\n load: () => Promise<Component>,\n fallback: Component,\n): Component {\n let loaded: Component | null = null\n const Async = defineAsyncComponent({\n loader: () =>\n load().then((component) => {\n loaded = component\n\n return component\n }),\n loadingComponent: fallback,\n delay: 0,\n suspensible: false,\n })\n\n return defineComponent({\n name,\n inheritAttrs: false,\n setup(_, { attrs }) {\n const mounted = useAppMounted()\n\n return () => h(mounted.value ? (loaded ?? Async) : fallback, attrs)\n },\n })\n}\n"],"mappings":";;;AAQA,SAAgBA,EACd,GACA,GACA,GACW;CACX,IAAIC,IAA2B,MACzBC,IAAQC,EAAqB;EACjC,cACEC,EAAK,CAAC,CAAC,MAAM,OACX,IAASC,GAEFA,EACR;EACH,kBAAkBC;EAClB,OAAO;EACP,aAAa;CACf,CAAC;CAED,OAAOC,EAAgB;EACrB;EACA,cAAc;EACd,MAAM,GAAG,EAAE,YAAS;GAClB,IAAMC,IAAUC,EAAc;GAE9B,aAAaC,EAAEF,EAAQ,QAASP,KAAUC,IAASI,GAAUK,CAAK;EACpE;CACF,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfakit/vue",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Vue 3 + shadcn-vue renderer for Alfakit, the Laravel admin panel builder by Alfa Six.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alfa Six (https://alfasixbh.com)",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"reka-ui": "^2.11.0",
|
|
97
97
|
"tailwind-merge": "^3.7.0",
|
|
98
98
|
"vue-sonner": "^2.0.9",
|
|
99
|
-
"@alfakit/core": "0.1.
|
|
99
|
+
"@alfakit/core": "0.1.1"
|
|
100
100
|
},
|
|
101
101
|
"peerDependencies": {
|
|
102
102
|
"@inertiajs/vue3": "^3.0.0",
|
package/src/lib/Icon.vue
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { iconAlias, iconAliasOverride, iconSource, isIconAlias } from '@alfakit/core'
|
|
3
|
-
import { computed,
|
|
3
|
+
import { computed, type Component, type HTMLAttributes } from 'vue'
|
|
4
4
|
import { useOptionalRegistry } from '../context'
|
|
5
|
-
import {
|
|
5
|
+
import { useAppMounted } from './hydration'
|
|
6
|
+
import { iconMap, resolveIcon } from './icons'
|
|
6
7
|
import { cn } from './utils'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -22,8 +23,8 @@ const props = defineProps<{
|
|
|
22
23
|
// `createAlfakit({ components: { 'panel:icon': MyIcon } })` renders every named icon with
|
|
23
24
|
// another icon set; it receives `name`, `fallback` and `class`.
|
|
24
25
|
const custom = useOptionalRegistry()?.resolve('panel:icon')
|
|
25
|
-
// Named icons render once
|
|
26
|
-
|
|
26
|
+
// Named icons render once this app has hydrated (the server render shows none).
|
|
27
|
+
const mounted = useAppMounted()
|
|
27
28
|
|
|
28
29
|
const fallbackName = computed(() =>
|
|
29
30
|
typeof props.fallback === 'string' ? props.fallback : undefined,
|
|
@@ -49,7 +50,7 @@ const source = computed(() =>
|
|
|
49
50
|
const component = computed(() => {
|
|
50
51
|
if (source.value?.type !== 'name' || custom) return null
|
|
51
52
|
|
|
52
|
-
const icons = iconMap()
|
|
53
|
+
const icons = iconMap(mounted.value)
|
|
53
54
|
|
|
54
55
|
// Nothing until the icon map has loaded (and during the server render and hydration).
|
|
55
56
|
if (!icons) return null
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getCurrentInstance, onMounted, ref, type AppContext, type Ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether each app has mounted (hydrated). Kept per app, not per module: loaded icon chunks
|
|
5
|
+
* and lazy components outlive an app, so a second app hydrating in the same page would
|
|
6
|
+
* otherwise draw content its server markup does not contain.
|
|
7
|
+
*/
|
|
8
|
+
const mountedApps = new WeakMap<AppContext, Ref<boolean>>()
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Call in a component's setup: `false` until the component's app has mounted (so during
|
|
12
|
+
* the server render and hydration), then `true` for every component in that app, so
|
|
13
|
+
* content rendered later draws at once (reactive). Lazily loaded parts (named icons, heavy
|
|
14
|
+
* fields) render their server markup until then, whatever has loaded already.
|
|
15
|
+
*/
|
|
16
|
+
export function useAppMounted(): Ref<boolean> {
|
|
17
|
+
const context = getCurrentInstance()?.appContext
|
|
18
|
+
|
|
19
|
+
// Outside a component there is no hydration to wait for.
|
|
20
|
+
if (!context) return ref(true)
|
|
21
|
+
|
|
22
|
+
let mounted = mountedApps.get(context)
|
|
23
|
+
|
|
24
|
+
if (!mounted) {
|
|
25
|
+
mounted = ref(false)
|
|
26
|
+
mountedApps.set(context, mounted)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const flag = mounted
|
|
30
|
+
onMounted(() => {
|
|
31
|
+
flag.value = true
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return flag
|
|
35
|
+
}
|
package/src/lib/icons.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAsyncComponent,
|
|
1
|
+
import { defineAsyncComponent, shallowRef, type Component } from 'vue'
|
|
2
2
|
import type * as IconModules from './icon-modules'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -13,7 +13,7 @@ import type * as IconModules from './icon-modules'
|
|
|
13
13
|
export type IconMap = typeof IconModules
|
|
14
14
|
|
|
15
15
|
const loadedMap = shallowRef<IconMap | null>(null)
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
let pending: Promise<IconMap> | undefined
|
|
18
18
|
|
|
19
19
|
const cache = new Map<string, Component | null>()
|
|
@@ -37,19 +37,14 @@ export function preloadIcons(): void {
|
|
|
37
37
|
loadIconMap()
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/** `<Icon>`s call this once mounted: from then on named icons render (after hydration). */
|
|
41
|
-
export function markIconsMounted(): void {
|
|
42
|
-
mounted.value = true
|
|
43
|
-
}
|
|
44
|
-
|
|
45
40
|
/**
|
|
46
|
-
* The icon map once it has loaded in the browser and the
|
|
47
|
-
* (reactive). Starts loading it.
|
|
41
|
+
* The icon map once it has loaded in the browser and the `<Icon>`'s app has mounted
|
|
42
|
+
* (`useAppMounted()`), else `null` (reactive). Starts loading it.
|
|
48
43
|
*/
|
|
49
|
-
export function iconMap(): IconMap | null {
|
|
44
|
+
export function iconMap(mounted: boolean): IconMap | null {
|
|
50
45
|
if (!loadedMap.value) loadIconMap()
|
|
51
46
|
|
|
52
|
-
return mounted
|
|
47
|
+
return mounted ? loadedMap.value : null
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
/**
|
package/src/lib/lazy.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { defineAsyncComponent, defineComponent, h,
|
|
1
|
+
import { defineAsyncComponent, defineComponent, h, type Component } from 'vue'
|
|
2
|
+
import { useAppMounted } from './hydration'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* A component whose code (and heavy dependencies such as Tiptap or Chart.js) loads on
|
|
5
6
|
* first use. The server render and hydration show `fallback` and never start the import;
|
|
6
|
-
* once
|
|
7
|
+
* once the app has mounted, a loaded component renders straight away.
|
|
7
8
|
*/
|
|
8
9
|
export function lazyComponent(
|
|
9
10
|
name: string,
|
|
@@ -27,11 +28,9 @@ export function lazyComponent(
|
|
|
27
28
|
name,
|
|
28
29
|
inheritAttrs: false,
|
|
29
30
|
setup(_, { attrs }) {
|
|
30
|
-
const mounted =
|
|
31
|
+
const mounted = useAppMounted()
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return () => h(loaded ?? (mounted.value ? Async : fallback), attrs)
|
|
33
|
+
return () => h(mounted.value ? (loaded ?? Async) : fallback, attrs)
|
|
35
34
|
},
|
|
36
35
|
})
|
|
37
36
|
}
|