@poupe/vue
Version:
Vue component library for Poupe UI framework with theme customization and accessibility support
425 lines (424 loc) • 14.6 kB
JavaScript
import { defineComponent as g, computed as _, ref as w, watch as T, onMounted as R, onUnmounted as P, provide as B, createElementBlock as c, openBlock as l, createElementVNode as i, createCommentVNode as h, renderSlot as y, createTextVNode as N, normalizeClass as k, Fragment as A, renderList as j, toDisplayString as v, createBlock as b, resolveDynamicComponent as q, createVNode as S, unref as z, h as C, withCtx as x, normalizeProps as E, guardReactiveProps as I } from "vue";
import { I as L } from "./iconify-C52eJ6S7.js";
import { _ as O } from "./_plugin-vue_export-helper-CHgC5LLL.js";
const V = { class: "flex flex-col min-h-screen" }, D = { class: "lg:hidden surface-container-high shadow-z1 sticky top-0 z-20" }, F = { class: "p-4 flex items-center justify-between" }, G = { class: "text-lg font-bold" }, H = ["aria-label"], J = {
class: "w-6 h-6",
fill: "none",
stroke: "currentColor",
viewBox: "0 0 24 24"
}, U = {
key: 0,
"stroke-linecap": "round",
"stroke-linejoin": "round",
"stroke-width": "2",
d: "M4 6h16M4 12h16M4 18h16"
}, W = {
key: 1,
"stroke-linecap": "round",
"stroke-linejoin": "round",
"stroke-width": "2",
d: "M6 18L18 6M6 6l12 12"
}, K = { class: "flex flex-1" }, Q = { class: "hidden lg:block p-4 border-b border-outline-variant" }, X = { class: "text-xl font-bold" }, Y = { class: "flex-1 p-2 overflow-y-auto" }, Z = ["onClick"], ee = { class: "flex-1 flex flex-col lg:ml-0" }, te = {
key: 0,
class: "surface-container p-4 lg:p-6 border-b border-outline-variant"
}, oe = { class: "text-xl lg:text-2xl font-bold mb-1" }, se = {
key: 0,
class: "text-on-surface-variant text-sm lg:text-base"
}, re = { class: "flex-1 surface overflow-y-auto" }, ne = { class: "container m-auto max-w-6xl p-4 lg:p-6" }, Pe = /* @__PURE__ */ g({
__name: "viewer",
props: {
stories: {},
defaultStory: { default: void 0 },
useRouter: { default: void 0 }
},
setup(s) {
const e = s, t = (o) => o.toLowerCase().replaceAll(/\s+/g, "-"), r = (o) => {
const a = e.stories.find((d) => t(d.name) === o);
return (a == null ? void 0 : a.name) || "";
}, n = _(
() => e.useRouter ? {
// Vue Router navigation
getCurrentStory: () => {
var a;
const o = e.useRouter.route.query.story;
if (o) {
const d = r(o);
if (d) return d;
}
return e.defaultStory || ((a = e.stories[0]) == null ? void 0 : a.name) || "";
},
setStory: (o) => {
const a = t(o);
e.useRouter.router.push({
query: { ...e.useRouter.route.query, story: a }
});
},
init: () => {
if (!e.useRouter.route.query.story && p.value) {
const o = t(p.value.name);
e.useRouter.router.replace({
query: { ...e.useRouter.route.query, story: o }
});
}
}
} : {
// Hash-based navigation
getCurrentStory: () => {
var o;
if (globalThis.location !== void 0) {
const a = globalThis.location.hash.slice(1);
if (a) {
const d = r(a);
if (d) return d;
}
}
return e.defaultStory || ((o = e.stories[0]) == null ? void 0 : o.name) || "";
},
setStory: (o) => {
globalThis.location !== void 0 && (globalThis.location.hash = t(o));
},
init: () => {
globalThis.location !== void 0 && !globalThis.location.hash && p.value && (globalThis.location.hash = t(p.value.name));
}
}
), u = w((() => {
var o;
return globalThis.location === void 0 || !globalThis.location.hash ? e.defaultStory || ((o = e.stories[0]) == null ? void 0 : o.name) || "" : n.value.getCurrentStory();
})()), p = _(() => e.stories.find((o) => o.name === u.value));
T(() => [e.stories, e.defaultStory], () => {
const o = n.value.getCurrentStory();
o !== u.value && (u.value = o);
});
const M = (o) => {
u.value = o, n.value.setStory(o);
};
let $;
e.useRouter ? T(() => e.useRouter.route.query.story, (o) => {
if (o) {
const a = r(o);
a && a !== u.value && (u.value = a);
}
}) : (R(() => {
$ = () => {
const o = n.value.getCurrentStory();
o !== u.value && (u.value = o);
}, typeof globalThis.addEventListener == "function" && globalThis.addEventListener("hashchange", $);
}), P(() => {
$ && typeof globalThis.removeEventListener == "function" && globalThis.removeEventListener("hashchange", $);
})), R(() => {
(e.useRouter || globalThis.location !== void 0) && n.value.init();
});
const m = w(!1);
return B("storyViewer", {
currentStory: u
}), (o, a) => (l(), c("div", V, [
i("div", D, [
i("div", F, [
i("h1", G, [
y(o.$slots, "title", {}, () => [
a[2] || (a[2] = N(" Component Stories "))
])
]),
i("button", {
class: "p-2 rounded-md hover:bg-surface-container-highest",
"aria-label": m.value ? "Close menu" : "Open menu",
onClick: a[0] || (a[0] = (d) => m.value = !m.value)
}, [
(l(), c("svg", J, [
m.value ? (l(), c("path", W)) : (l(), c("path", U))
]))
], 8, H)
])
]),
m.value ? (l(), c("div", {
key: 0,
class: "lg:hidden fixed inset-0 z-10 bg-scrim/50",
onClick: a[1] || (a[1] = (d) => m.value = !1)
})) : h("", !0),
i("div", K, [
i("div", {
class: k([
"fixed lg:static inset-y-0 left-0 z-20 w-64",
"surface-container-high shadow-z2 lg:shadow-z1",
"transform transition-transform duration-200 lg:translate-x-0",
"flex flex-col h-full lg:h-auto",
m.value ? "translate-x-0" : "-translate-x-full"
])
}, [
i("div", Q, [
i("h1", X, [
y(o.$slots, "title", {}, () => [
a[3] || (a[3] = N(" Component Stories "))
])
])
]),
i("nav", Y, [
(l(!0), c(A, null, j(o.stories, (d) => (l(), c("button", {
key: d.name,
class: k([
"w-full text-left px-4 py-2 mb-1 rounded-md transition-colors",
"text-sm font-medium",
u.value === d.name ? "bg-primary text-on-primary" : "hover:bg-surface-container-highest text-on-surface"
]),
onClick: (qe) => {
M(d.name), m.value = !1;
}
}, v(d.name), 11, Z))), 128))
])
], 2),
i("div", ee, [
p.value ? (l(), c("div", te, [
i("h2", oe, v(p.value.name), 1),
p.value.description ? (l(), c("p", se, v(p.value.description), 1)) : h("", !0)
])) : h("", !0),
i("div", re, [
i("div", ne, [
y(o.$slots, "story", { story: p.value }, () => {
var d;
return [
p.value ? (l(), b(q((d = p.value) == null ? void 0 : d.component), { key: 0 })) : h("", !0)
];
})
])
])
])
])
]));
}
}), ae = { class: "mb-8" }, le = { class: "mb-4" }, ie = { class: "text-2xl font-bold text-on-surface" }, ce = {
key: 0,
class: "text-on-surface-variant mt-1"
}, ue = { class: "space-y-4" }, de = /* @__PURE__ */ g({
__name: "section",
props: {
title: {},
description: {}
},
setup(s) {
return (e, t) => (l(), c("section", ae, [
i("header", le, [
i("h2", ie, v(e.title), 1),
e.description ? (l(), c("p", ce, v(e.description), 1)) : h("", !0)
]),
i("div", ue, [
y(e.$slots, "default")
])
]));
}
}), pe = /* @__PURE__ */ g({
__name: "showcase",
props: {
gap: { default: "base" },
wrap: { type: Boolean, default: !0 },
center: { type: Boolean, default: !1 }
},
setup(s) {
return (e, t) => (l(), c("div", {
class: k([
"flex",
{
"flex-wrap": e.wrap,
"items-center": e.center,
"gap-2": e.gap === "xs",
"gap-3": e.gap === "sm",
"gap-4": e.gap === "base",
"gap-6": e.gap === "lg",
"gap-8": e.gap === "xl"
}
])
}, [
y(e.$slots, "default")
], 2));
}
}), fe = { class: "story-code-block surface-container-high on-surface rounded-lg overflow-hidden" }, he = { class: "flex items-center justify-between px-3 py-2 border-b border-outline-variant" }, me = { class: "text-xs on-surface-variant" }, ve = ["title"], ge = { class: "overflow-x-auto p-4 text-sm font-mono" }, ye = /* @__PURE__ */ g({
__name: "code-block",
props: {
code: {},
language: { default: "vue" }
},
setup(s) {
const e = s, t = w(!1), r = _(() => e.code.trim());
async function n() {
try {
await globalThis.navigator.clipboard.writeText(r.value), t.value = !0, globalThis.setTimeout(() => {
t.value = !1;
}, 2e3);
} catch (f) {
globalThis.console.error("Failed to copy:", f);
}
}
return (f, u) => (l(), c("div", fe, [
i("div", he, [
i("span", me, v(f.language || "code"), 1),
i("button", {
class: "p-1 -mr-1 surface-container-highest on-surface rounded hover:surface-container transition-colors",
title: t.value ? "Copied!" : "Copy code",
onClick: n
}, [
S(z(L), {
icon: t.value ? "mdi:check" : "mdi:content-copy",
class: "w-4 h-4"
}, null, 8, ["icon"])
], 8, ve)
]),
i("pre", ge, [
i("code", null, v(r.value), 1)
])
]));
}
}), _e = /* @__PURE__ */ O(ye, [["__scopeId", "data-v-2af731f9"]]), be = { class: "story-showcase-item" }, $e = {
key: 0,
class: "mb-2 flex items-center justify-between"
}, we = {
key: 0,
class: "text-sm font-medium on-surface-variant"
}, Se = ["title"], Ce = { class: "story-showcase-content" }, ke = {
key: 1,
class: "mt-4"
}, xe = /* @__PURE__ */ g({
__name: "showcase-item",
props: {
code: { default: void 0 },
language: { default: "vue" },
title: { default: void 0 }
},
setup(s) {
const e = w(!1);
return (t, r) => (l(), c("div", be, [
t.title || t.code ? (l(), c("div", $e, [
t.title ? (l(), c("h4", we, v(t.title), 1)) : h("", !0),
t.code ? (l(), c("button", {
key: 1,
class: "ml-auto p-1.5 -mr-1.5 surface-container-highest on-surface rounded hover:surface-container transition-colors",
title: e.value ? "Hide code" : "Show code",
onClick: r[0] || (r[0] = (n) => e.value = !e.value)
}, [
S(z(L), {
icon: e.value ? "mdi:code-off" : "mdi:code-tags",
class: "w-4 h-4"
}, null, 8, ["icon"])
], 8, Se)) : h("", !0)
])) : h("", !0),
i("div", Ce, [
y(t.$slots, "default")
]),
e.value && t.code ? (l(), c("div", ke, [
S(_e, {
code: t.code,
language: t.language
}, null, 8, ["code", "language"])
])) : h("", !0)
]));
}
});
function Te(s, e = {}) {
const { componentPrefix: t = "P" } = e;
if (!s.component)
return "";
const r = Re(s.component, t), n = Ne(s.props || {}), f = s.slots ? Ae(s.slots) : "";
let u = f ? `<${r}${n}>
${f}
</${r}>` : `<${r}${n} />`;
return s.wrapperClass && (u = `<div class="${s.wrapperClass}">${u}</div>`), u;
}
function Re(s, e) {
if (typeof s == "string")
return s;
const t = s.name || s.__name;
return !t || typeof t != "string" ? "Component" : t.startsWith(e) ? t : `${e}${t}`;
}
function Ne(s) {
const e = Object.entries(s).filter(([, r]) => r != null);
return e.length === 0 ? "" : " " + e.map(([r, n]) => {
if (n === !0) return r;
if (n === !1) return `:${r}="false"`;
if (typeof n == "string") {
const f = n.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
return `${r}="${f}"`;
}
return `:${r}="${JSON.stringify(n).replaceAll('"', """)}"`;
}).join(" ");
}
function Ae(s) {
return Object.entries(s).map(([t, r]) => {
const n = typeof r == "function" ? "Dynamic content" : r;
return t === "default" ? ` ${n}` : ` <template #${t}>
${n}
</template>`;
}).join(`
`);
}
function Be(s) {
return s;
}
function Ee(s, e, t) {
return { title: s, description: e, stories: t };
}
const je = /* @__PURE__ */ g({
__name: "renderer",
props: {
story: {},
options: { default: void 0 }
},
setup(s) {
const e = s, t = _(() => Te(e.story, e.options)), r = _(() => {
if (!e.story.component)
return () => C("div", { class: "text-on-surface-variant" }, "No preview available");
const n = {};
if (e.story.slots)
for (const [u, p] of Object.entries(e.story.slots))
n[u] = typeof p == "function" ? p : () => p;
const f = () => C(e.story.component, e.story.props || {}, n);
return e.story.wrapperClass ? () => C("div", { class: e.story.wrapperClass }, [f()]) : f;
});
return (n, f) => (l(), b(xe, {
title: n.story.title,
code: t.value,
language: "vue"
}, {
default: x(() => [
(l(), b(q(r.value)))
]),
_: 1
}, 8, ["title", "code"]));
}
}), Ie = /* @__PURE__ */ g({
__name: "group-renderer",
props: {
group: {},
options: { default: void 0 },
showcaseProps: { default: () => ({ gap: "lg" }) }
},
setup(s) {
return (e, t) => (l(), b(de, {
title: e.group.title,
description: e.group.description
}, {
default: x(() => [
S(pe, E(I(e.showcaseProps)), {
default: x(() => [
(l(!0), c(A, null, j(e.group.stories, (r, n) => (l(), b(je, {
key: `${r.title}-${n}`,
story: r,
options: e.options
}, null, 8, ["story", "options"]))), 128))
]),
_: 1
}, 16)
]),
_: 1
}, 8, ["title", "description"]));
}
});
export {
_e as StoryCodeBlock,
Ie as StoryGroupRenderer,
je as StoryRenderer,
de as StorySection,
pe as StoryShowcase,
xe as StoryShowcaseItem,
Pe as StoryViewer,
Be as createStory,
Ee as createStoryGroup,
Te as generateCode
};