feat(@vben/docs): preview components are supported within documents (#4250)
parent
d47d051b19
commit
cbf601581d
|
@ -0,0 +1,43 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import PreviewGroup from './preview-group.vue';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
files?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), { files: '() => []' });
|
||||||
|
|
||||||
|
const parsedFiles = computed(() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(decodeURIComponent(props.files ?? ''));
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="border-border shadow-float relative rounded-xl border">
|
||||||
|
<div
|
||||||
|
class="not-prose relative w-full overflow-x-auto rounded-t-lg px-4 py-6"
|
||||||
|
>
|
||||||
|
<div class="flex w-full max-w-[700px] px-2">
|
||||||
|
<slot v-if="parsedFiles.length > 0"></slot>
|
||||||
|
<div v-else class="text-destructive text-sm">
|
||||||
|
<span class="bg-destructive text-foreground rounded-sm px-1 py-1">
|
||||||
|
ERROR:
|
||||||
|
</span>
|
||||||
|
The preview directory does not exist. Please check the 'dir'
|
||||||
|
parameter.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<PreviewGroup v-if="parsedFiles.length > 0" :files="parsedFiles">
|
||||||
|
<template v-for="file in parsedFiles" #[file]>
|
||||||
|
<slot :name="file"></slot>
|
||||||
|
</template>
|
||||||
|
</PreviewGroup>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as DemoPreview } from './demo-preview.vue';
|
|
@ -0,0 +1,108 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, useSlots } from 'vue';
|
||||||
|
|
||||||
|
import { VbenTooltip } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
|
import { Code } from 'lucide-vue-next';
|
||||||
|
import {
|
||||||
|
TabsContent,
|
||||||
|
TabsIndicator,
|
||||||
|
TabsList,
|
||||||
|
TabsRoot,
|
||||||
|
TabsTrigger,
|
||||||
|
} from 'radix-vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
files?: string[];
|
||||||
|
}>(),
|
||||||
|
{ files: () => [] },
|
||||||
|
);
|
||||||
|
|
||||||
|
const open = ref(false);
|
||||||
|
|
||||||
|
const slots = useSlots();
|
||||||
|
|
||||||
|
const tabs = computed(() => {
|
||||||
|
return props.files.map((file) => {
|
||||||
|
return {
|
||||||
|
component: slots[file],
|
||||||
|
label: file,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentTab = ref('index.vue');
|
||||||
|
|
||||||
|
const toggleOpen = () => {
|
||||||
|
open.value = !open.value;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TabsRoot
|
||||||
|
v-model="currentTab"
|
||||||
|
class="bg-background-deep border-border overflow-hidden rounded-b-xl border-t"
|
||||||
|
@update:model-value="open = true"
|
||||||
|
>
|
||||||
|
<div class="border-border bg-background flex border-b-2 pr-2">
|
||||||
|
<div class="flex w-full items-center justify-between text-[13px]">
|
||||||
|
<TabsList class="relative flex">
|
||||||
|
<template v-if="open">
|
||||||
|
<TabsIndicator
|
||||||
|
class="absolute bottom-0 left-0 h-[2px] w-[--radix-tabs-indicator-size] translate-x-[--radix-tabs-indicator-position] rounded-full transition-[width,transform] duration-300"
|
||||||
|
>
|
||||||
|
<div class="size-full bg-[var(--vp-c-indigo-1)]"></div>
|
||||||
|
</TabsIndicator>
|
||||||
|
<TabsTrigger
|
||||||
|
v-for="(tab, index) in tabs"
|
||||||
|
:key="index"
|
||||||
|
:value="tab.label"
|
||||||
|
class="border-box text-foreground px-4 py-3 data-[state=active]:text-[var(--vp-c-indigo-1)]"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
{{ tab.label }}
|
||||||
|
</TabsTrigger>
|
||||||
|
</template>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:class="{
|
||||||
|
'py-2': !open,
|
||||||
|
}"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<VbenTooltip side="top">
|
||||||
|
<template #trigger>
|
||||||
|
<Code
|
||||||
|
class="hover:bg-accent size-6.5 cursor-pointer rounded-full p-1.5"
|
||||||
|
@click="toggleOpen"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
{{ open ? 'Collapse code' : 'Expand code' }}
|
||||||
|
</VbenTooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:class="`${open ? 'h-[unset] max-h-[80vh]' : 'h-0'}`"
|
||||||
|
class="block overflow-y-scroll bg-[var(--vp-code-block-bg)] transition-all duration-300"
|
||||||
|
>
|
||||||
|
<TabsContent
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.label"
|
||||||
|
:value="tab.label"
|
||||||
|
as-child
|
||||||
|
class="rounded-xl"
|
||||||
|
>
|
||||||
|
<div class="text-foreground relative rounded-xl">
|
||||||
|
<component :is="tab.component" class="border-0" />
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
</div>
|
||||||
|
</TabsRoot>
|
||||||
|
</template>
|
|
@ -203,7 +203,7 @@ function nav(): DefaultTheme.NavItem[] {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
link: '/commercial/technical-support',
|
link: '/commercial/technical-support',
|
||||||
text: '🦄 Technical Support',
|
text: '🦄 Tech Support',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
link: '/sponsor/personal',
|
link: '/sponsor/personal',
|
||||||
|
|
|
@ -2,12 +2,12 @@ import { withPwa } from '@vite-pwa/vitepress';
|
||||||
import { defineConfigWithTheme } from 'vitepress';
|
import { defineConfigWithTheme } from 'vitepress';
|
||||||
|
|
||||||
import { en } from './en.mts';
|
import { en } from './en.mts';
|
||||||
import { shard } from './shard.mts';
|
import { shared } from './shared.mts';
|
||||||
import { zh } from './zh.mts';
|
import { zh } from './zh.mts';
|
||||||
|
|
||||||
export default withPwa(
|
export default withPwa(
|
||||||
defineConfigWithTheme({
|
defineConfigWithTheme({
|
||||||
...shard,
|
...shared,
|
||||||
locales: {
|
locales: {
|
||||||
en: {
|
en: {
|
||||||
label: 'English',
|
label: 'English',
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
import type { MarkdownEnv, MarkdownRenderer } from 'vitepress';
|
||||||
|
|
||||||
|
import crypto from 'node:crypto';
|
||||||
|
import { readdirSync } from 'node:fs';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
export const rawPathRegexp =
|
||||||
|
// eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/strict
|
||||||
|
/^(.+?(?:\.([\da-z]+))?)(#[\w-]+)?(?: ?{(\d+(?:[,-]\d+)*)? ?(\S+)?})? ?(?:\[(.+)])?$/;
|
||||||
|
|
||||||
|
function rawPathToToken(rawPath: string) {
|
||||||
|
const [
|
||||||
|
filepath = '',
|
||||||
|
extension = '',
|
||||||
|
region = '',
|
||||||
|
lines = '',
|
||||||
|
lang = '',
|
||||||
|
rawTitle = '',
|
||||||
|
] = (rawPathRegexp.exec(rawPath) || []).slice(1);
|
||||||
|
|
||||||
|
const title = rawTitle || filepath.split('/').pop() || '';
|
||||||
|
|
||||||
|
return { extension, filepath, lang, lines, region, title };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const demoPreviewPlugin = (md: MarkdownRenderer) => {
|
||||||
|
md.core.ruler.after('inline', 'demo-preview', (state) => {
|
||||||
|
const insertComponentImport = (importString: string) => {
|
||||||
|
const index = state.tokens.findIndex(
|
||||||
|
(i) => i.type === 'html_block' && i.content.match(/<script setup>/g),
|
||||||
|
);
|
||||||
|
if (index === -1) {
|
||||||
|
const importComponent = new state.Token('html_block', '', 0);
|
||||||
|
importComponent.content = `<script setup>\n${importString}\n</script>\n`;
|
||||||
|
state.tokens.splice(0, 0, importComponent);
|
||||||
|
} else {
|
||||||
|
if (state.tokens[index]) {
|
||||||
|
const content = state.tokens[index].content;
|
||||||
|
state.tokens[index].content = content.replace(
|
||||||
|
'</script>',
|
||||||
|
`${importString}\n</script>`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Define the regular expression to match the desired pattern
|
||||||
|
const regex = /<DemoPreview[^>]*\sdir="([^"]*)"/g;
|
||||||
|
// Iterate through the Markdown content and replace the pattern
|
||||||
|
state.src = state.src.replaceAll(regex, (_match, dir) => {
|
||||||
|
const componentDir = join(process.cwd(), 'src', dir);
|
||||||
|
|
||||||
|
let childFiles: string[] = [];
|
||||||
|
let dirExists = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
childFiles =
|
||||||
|
readdirSync(componentDir, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
recursive: false,
|
||||||
|
withFileTypes: false,
|
||||||
|
}) || [];
|
||||||
|
} catch {
|
||||||
|
dirExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dirExists) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueWord = generateContentHash(componentDir);
|
||||||
|
|
||||||
|
const ComponentName = `DemoComponent_${uniqueWord}`;
|
||||||
|
insertComponentImport(
|
||||||
|
`import ${ComponentName} from '${componentDir}/index.vue'`,
|
||||||
|
);
|
||||||
|
const { path: _path } = state.env as MarkdownEnv;
|
||||||
|
|
||||||
|
const index = state.tokens.findIndex((i) => i.content.match(regex));
|
||||||
|
|
||||||
|
if (!state.tokens[index]) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
state.tokens[index].content =
|
||||||
|
`<DemoPreview files="${encodeURIComponent(JSON.stringify(childFiles))}" ><${ComponentName}/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const _dummyToken = new state.Token('', '', 0);
|
||||||
|
const tokenArray: Array<typeof _dummyToken> = [];
|
||||||
|
childFiles.forEach((filename) => {
|
||||||
|
// const slotName = filename.replace(extname(filename), '');
|
||||||
|
|
||||||
|
const templateStart = new state.Token('html_inline', '', 0);
|
||||||
|
templateStart.content = `<template #${filename}>`;
|
||||||
|
tokenArray.push(templateStart);
|
||||||
|
|
||||||
|
const resolvedPath = join(componentDir, filename);
|
||||||
|
|
||||||
|
const { extension, filepath, lang, lines, title } =
|
||||||
|
rawPathToToken(resolvedPath);
|
||||||
|
// Add code tokens for each line
|
||||||
|
const token = new state.Token('fence', 'code', 0);
|
||||||
|
token.info = `${lang || extension}${lines ? `{${lines}}` : ''}${
|
||||||
|
title ? `[${title}]` : ''
|
||||||
|
}`;
|
||||||
|
|
||||||
|
token.content = `<<< ${filepath}`;
|
||||||
|
(token as any).src = [resolvedPath];
|
||||||
|
tokenArray.push(token);
|
||||||
|
|
||||||
|
const templateEnd = new state.Token('html_inline', '', 0);
|
||||||
|
templateEnd.content = '</template>';
|
||||||
|
tokenArray.push(templateEnd);
|
||||||
|
});
|
||||||
|
const endTag = new state.Token('html_inline', '', 0);
|
||||||
|
endTag.content = '</DemoPreview>';
|
||||||
|
tokenArray.push(endTag);
|
||||||
|
|
||||||
|
state.tokens.splice(index + 1, 0, ...tokenArray);
|
||||||
|
|
||||||
|
// console.log(
|
||||||
|
// state.md.renderer.render(state.tokens, state?.options ?? [], state.env),
|
||||||
|
// );
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateContentHash(input: string, length: number = 10): string {
|
||||||
|
// 使用 SHA-256 生成哈希值
|
||||||
|
const hash = crypto.createHash('sha256').update(input).digest('hex');
|
||||||
|
|
||||||
|
// 将哈希值转换为 Base36 编码,并取指定长度的字符作为结果
|
||||||
|
return Number.parseInt(hash, 16).toString(36).slice(0, length);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import type { PwaOptions } from '@vite-pwa/vitepress';
|
import type { PwaOptions } from '@vite-pwa/vitepress';
|
||||||
|
import type { HeadConfig } from 'vitepress';
|
||||||
|
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
@ -6,12 +7,20 @@ import {
|
||||||
GitChangelog,
|
GitChangelog,
|
||||||
GitChangelogMarkdownSection,
|
GitChangelogMarkdownSection,
|
||||||
} from '@nolebase/vitepress-plugin-git-changelog/vite';
|
} from '@nolebase/vitepress-plugin-git-changelog/vite';
|
||||||
import { defineConfig, type HeadConfig } from 'vitepress';
|
import tailwind from 'tailwindcss';
|
||||||
|
import { defineConfig, postcssIsolateStyles } from 'vitepress';
|
||||||
|
|
||||||
|
import { demoPreviewPlugin } from './plugins/demo-preview';
|
||||||
import { search as zhSearch } from './zh.mts';
|
import { search as zhSearch } from './zh.mts';
|
||||||
|
|
||||||
export const shard = defineConfig({
|
export const shared = defineConfig({
|
||||||
|
appearance: 'dark',
|
||||||
head: head(),
|
head: head(),
|
||||||
|
markdown: {
|
||||||
|
preConfig(md) {
|
||||||
|
md.use(demoPreviewPlugin);
|
||||||
|
},
|
||||||
|
},
|
||||||
pwa: pwa(),
|
pwa: pwa(),
|
||||||
srcDir: 'src',
|
srcDir: 'src',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
|
@ -36,11 +45,34 @@ export const shard = defineConfig({
|
||||||
chunkSizeWarningLimit: Infinity,
|
chunkSizeWarningLimit: Infinity,
|
||||||
minify: 'terser',
|
minify: 'terser',
|
||||||
},
|
},
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [
|
||||||
|
tailwind(),
|
||||||
|
postcssIsolateStyles({ includeFiles: [/vp-doc\.css/] }),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
json: {
|
json: {
|
||||||
stringify: true,
|
stringify: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
GitChangelog({
|
GitChangelog({
|
||||||
|
mapAuthors: [
|
||||||
|
{
|
||||||
|
mapByNameAliases: ['Vben'],
|
||||||
|
name: 'vben',
|
||||||
|
username: 'anncwb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'vince',
|
||||||
|
username: 'vince292007',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Li Kui',
|
||||||
|
username: 'likui628',
|
||||||
|
},
|
||||||
|
],
|
||||||
repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',
|
repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',
|
||||||
}),
|
}),
|
||||||
GitChangelogMarkdownSection(),
|
GitChangelogMarkdownSection(),
|
|
@ -38,6 +38,7 @@ export const zh = defineConfig({
|
||||||
|
|
||||||
sidebar: {
|
sidebar: {
|
||||||
'/commercial/': { base: '/commercial/', items: sidebarCommercial() },
|
'/commercial/': { base: '/commercial/', items: sidebarCommercial() },
|
||||||
|
'/components/': { base: '/components/', items: sidebarComponents() },
|
||||||
'/guide/': { base: '/guide/', items: sidebarGuide() },
|
'/guide/': { base: '/guide/', items: sidebarGuide() },
|
||||||
},
|
},
|
||||||
sidebarMenuLabel: '菜单',
|
sidebarMenuLabel: '菜单',
|
||||||
|
@ -60,6 +61,11 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
||||||
},
|
},
|
||||||
{ link: 'introduction/quick-start', text: '快速开始' },
|
{ link: 'introduction/quick-start', text: '快速开始' },
|
||||||
{ link: 'introduction/thin', text: '精简版本' },
|
{ link: 'introduction/thin', text: '精简版本' },
|
||||||
|
{
|
||||||
|
base: '/',
|
||||||
|
link: 'components/introduction',
|
||||||
|
text: '组件文档',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -117,7 +123,7 @@ function sidebarCommercial(): DefaultTheme.SidebarItem[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
link: 'community',
|
link: 'community',
|
||||||
text: '社区交流',
|
text: '社区',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
link: 'technical-support',
|
link: 'technical-support',
|
||||||
|
@ -130,6 +136,30 @@ function sidebarCommercial(): DefaultTheme.SidebarItem[] {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sidebarComponents(): DefaultTheme.SidebarItem[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: '组件',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
link: 'introduction',
|
||||||
|
text: '介绍',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
collapsed: false,
|
||||||
|
text: '通用组件',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
link: 'common-ui/vben-modal',
|
||||||
|
text: 'Modal 弹窗',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function nav(): DefaultTheme.NavItem[] {
|
function nav(): DefaultTheme.NavItem[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -138,28 +168,10 @@ function nav(): DefaultTheme.NavItem[] {
|
||||||
{
|
{
|
||||||
link: '/guide/introduction/vben',
|
link: '/guide/introduction/vben',
|
||||||
text: '指南',
|
text: '指南',
|
||||||
// items: [
|
},
|
||||||
// {
|
{
|
||||||
// link: '/guide/introduction/vben',
|
link: '/components/introduction',
|
||||||
// text: '简介',
|
text: '组件',
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// link: '/guide/essentials/concept',
|
|
||||||
// text: '基础',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// link: '/guide/in-depth/layout',
|
|
||||||
// text: '深入',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// link: '/guide/project/standard',
|
|
||||||
// text: '工程',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// link: '/guide/other/project-update',
|
|
||||||
// text: '其他',
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '历史版本',
|
text: '历史版本',
|
||||||
|
@ -234,7 +246,7 @@ function nav(): DefaultTheme.NavItem[] {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
link: '/commercial/community',
|
link: '/commercial/community',
|
||||||
text: '👨👦👦 社区交流',
|
text: '👨👦👦 社区',
|
||||||
// items: [
|
// items: [
|
||||||
// {
|
// {
|
||||||
// link: 'https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=22ySzj7pKiw&businessType=9&from=246610&biz=ka&mainSourceId=share&subSourceId=others&jumpsource=shorturl#/pc',
|
// link: 'https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=22ySzj7pKiw&businessType=9&from=246610&biz=ka&mainSourceId=share&subSourceId=others&jumpsource=shorturl#/pc',
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// https://vitepress.dev/guide/custom-theme
|
// https://vitepress.dev/guide/custom-theme
|
||||||
import type { Theme } from 'vitepress';
|
import type { EnhanceAppContext, Theme } from 'vitepress';
|
||||||
|
|
||||||
import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client';
|
import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client';
|
||||||
import DefaultTheme from 'vitepress/theme';
|
import DefaultTheme from 'vitepress/theme';
|
||||||
|
|
||||||
|
import { DemoPreview } from '../components';
|
||||||
import SiteLayout from './components/site-layout.vue';
|
import SiteLayout from './components/site-layout.vue';
|
||||||
import VbenContributors from './components/vben-contributors.vue';
|
import VbenContributors from './components/vben-contributors.vue';
|
||||||
import { initHmPlugin } from './plugins/hm';
|
import { initHmPlugin } from './plugins/hm';
|
||||||
|
@ -13,9 +14,10 @@ import './styles';
|
||||||
import '@nolebase/vitepress-plugin-git-changelog/client/style.css';
|
import '@nolebase/vitepress-plugin-git-changelog/client/style.css';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
enhanceApp({ app }) {
|
enhanceApp(ctx: EnhanceAppContext) {
|
||||||
// ...
|
const { app } = ctx;
|
||||||
app.component('VbenContributors', VbenContributors);
|
app.component('VbenContributors', VbenContributors);
|
||||||
|
app.component('DemoPreview', DemoPreview);
|
||||||
app.use(NolebaseGitChangelogPlugin);
|
app.use(NolebaseGitChangelogPlugin);
|
||||||
// 百度统计
|
// 百度统计
|
||||||
initHmPlugin();
|
initHmPlugin();
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
import './variables.css';
|
import './variables.css';
|
||||||
import './base.css';
|
import './base.css';
|
||||||
|
import '@vben/styles';
|
||||||
|
|
|
@ -8,10 +8,18 @@
|
||||||
"docs:preview": "vitepress preview"
|
"docs:preview": "vitepress preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"medium-zoom": "^1.1.0"
|
"@vben-core/shadcn-ui": "workspace:*",
|
||||||
|
"@vben/common-ui": "workspace:*",
|
||||||
|
"@vben/styles": "workspace:*",
|
||||||
|
"@vueuse/core": "^11.0.3",
|
||||||
|
"lucide-vue-next": "^0.436.0",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
|
"medium-zoom": "^1.1.0",
|
||||||
|
"radix-vue": "^1.9.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nolebase/vitepress-plugin-git-changelog": "^2.4.0",
|
"@nolebase/vitepress-plugin-git-changelog": "^2.4.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
"@vite-pwa/vitepress": "^0.5.0",
|
"@vite-pwa/vitepress": "^0.5.0",
|
||||||
"vitepress": "^1.3.4",
|
"vitepress": "^1.3.4",
|
||||||
"vue": "^3.4.38"
|
"vue": "^3.4.38"
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# vben-modal
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
|
||||||
|
文档还在完善中,敬请期待。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
框架提供的模态框组件,支持`拖拽`、`全屏`、`自定义`等功能。
|
||||||
|
|
||||||
|
## 基础用法
|
||||||
|
|
||||||
|
使用 `useVbenModal` 创建最基于的模态框。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-modal/basic" />
|
||||||
|
|
||||||
|
## 组件抽离
|
||||||
|
|
||||||
|
modal 内的内容一般业务中,会比较复杂,所以我们可以将 modal 内的内容抽离出来。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-modal/extra" />
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### 属性
|
||||||
|
|
||||||
|
| 属性名 | 描述 | 类型 | 默认值 |
|
||||||
|
| ------ | ----- | -------- | ------ |
|
||||||
|
| title | 标题. | `string` | — |
|
||||||
|
|
||||||
|
### 事件
|
||||||
|
|
||||||
|
| 事件名 | 描述 | 类型 |
|
||||||
|
| ------ | ---- | ---- |
|
||||||
|
| TODO | TODO | TODO |
|
||||||
|
|
||||||
|
### 插槽
|
||||||
|
|
||||||
|
| 插槽名 | 描述 |
|
||||||
|
| ------- | ---- |
|
||||||
|
| default | xx. |
|
|
@ -0,0 +1,11 @@
|
||||||
|
# 介绍
|
||||||
|
|
||||||
|
::: tip README
|
||||||
|
|
||||||
|
该文档介绍的是框架组件的使用方法、属性、事件等。如果你觉得组件封装的不好,或者不符合你的需求,你可以直接使用原生的组件,或者自己封装一个组件,不需要拘泥于框架提供的组件。我们只是提供了一些常用的组件,方便你快速开发。是否使用,取决于你的需求。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 通用组件
|
||||||
|
|
||||||
|
通用组件是一些常用的组件,比如弹窗、抽屉、表单等。大部分基于 `Tailwind CSS` 实现,可适用于不同 UI 组件库的应用。
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<VbenButton @click="() => modalApi.open()">打开弹窗</VbenButton>
|
||||||
|
<Modal title="基础示例"> modal content </Modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import ExtraModal from './modal.vue';
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
// 链接抽离的组件
|
||||||
|
connectedComponent: ExtraModal,
|
||||||
|
});
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
modalApi.open();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Modal />
|
||||||
|
|
||||||
|
<VbenButton @click="openModal">打开弹窗</VbenButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const [Modal] = useVbenModal();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Modal title="基础示例"> extra modal content </Modal>
|
||||||
|
</template>
|
|
@ -42,3 +42,5 @@ VITE_INJECT_APP_LOADING=false
|
||||||
<div class="title"><%= VITE_APP_TITLE %></div>
|
<div class="title"><%= VITE_APP_TITLE %></div>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import tailwindcssConfig from '@vben/tailwind-config';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...tailwindcssConfig,
|
||||||
|
content: [
|
||||||
|
...tailwindcssConfig.content,
|
||||||
|
'.vitepress/**/*.{js,mts,ts,vue}',
|
||||||
|
'src/demos/**/*.{js,mts,ts,vue}',
|
||||||
|
'src/**/*.md',
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,6 +1,13 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"extends": "@vben/tsconfig/web.json",
|
"extends": "@vben/tsconfig/web.json",
|
||||||
"include": [".vitepress/*.mts", ".vitepress/**/*.ts", ".vitepress/**/*.vue"],
|
"include": [
|
||||||
|
".vitepress/*.mts",
|
||||||
|
".vitepress/**/*.ts",
|
||||||
|
".vitepress/**/*.vue",
|
||||||
|
"src/*.mts",
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.vue"
|
||||||
|
],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
"node": ">=20",
|
"node": ">=20",
|
||||||
"pnpm": ">=9"
|
"pnpm": ">=9"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.7.1",
|
"packageManager": "pnpm@9.9.0",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"peerDependencyRules": {
|
"peerDependencyRules": {
|
||||||
"allowedVersions": {
|
"allowedVersions": {
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface Props {
|
||||||
contentClass?: any;
|
contentClass?: any;
|
||||||
contentStyle?: StyleValue;
|
contentStyle?: StyleValue;
|
||||||
delayDuration?: number;
|
delayDuration?: number;
|
||||||
side: TooltipContentProps['side'];
|
side?: TooltipContentProps['side'];
|
||||||
}
|
}
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
withDefaults(defineProps<Props>(), {
|
||||||
|
@ -33,7 +33,7 @@ withDefaults(defineProps<Props>(), {
|
||||||
:class="contentClass"
|
:class="contentClass"
|
||||||
:side="side"
|
:side="side"
|
||||||
:style="contentStyle"
|
:style="contentStyle"
|
||||||
class="side-content text-popover-foreground bg-popover"
|
class="side-content text-popover-foreground bg-accent rounded-md"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
export * from './ellipsis-text';
|
export * from './ellipsis-text';
|
||||||
export * from './page';
|
export * from './page';
|
||||||
export * from '@vben-core/popup-ui';
|
export * from '@vben-core/popup-ui';
|
||||||
|
|
||||||
|
export { VbenButton } from '@vben-core/shadcn-ui';
|
||||||
|
|
|
@ -322,13 +322,37 @@ importers:
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@vben-core/shadcn-ui':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../packages/@core/ui-kit/shadcn-ui
|
||||||
|
'@vben/common-ui':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../packages/effects/common-ui
|
||||||
|
'@vben/styles':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../packages/styles
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: ^11.0.3
|
||||||
|
version: 11.0.3(vue@3.4.38(typescript@5.5.4))
|
||||||
|
lucide-vue-next:
|
||||||
|
specifier: ^0.436.0
|
||||||
|
version: 0.436.0(vue@3.4.38(typescript@5.5.4))
|
||||||
|
markdown-it:
|
||||||
|
specifier: ^14.1.0
|
||||||
|
version: 14.1.0
|
||||||
medium-zoom:
|
medium-zoom:
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
|
radix-vue:
|
||||||
|
specifier: ^1.9.4
|
||||||
|
version: 1.9.4(vue@3.4.38(typescript@5.5.4))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nolebase/vitepress-plugin-git-changelog':
|
'@nolebase/vitepress-plugin-git-changelog':
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.0(@algolia/client-search@4.24.0)(@types/node@22.5.0)(async-validator@4.2.5)(axios@1.7.5)(nprogress@0.2.0)(postcss@8.4.41)(qrcode@1.5.4)(sass@1.77.8)(search-insights@2.16.3)(sortablejs@1.15.2)(terser@5.31.6)(typescript@5.5.4)
|
version: 2.4.0(@algolia/client-search@4.24.0)(@types/node@22.5.0)(async-validator@4.2.5)(axios@1.7.5)(nprogress@0.2.0)(postcss@8.4.41)(qrcode@1.5.4)(sass@1.77.8)(search-insights@2.16.3)(sortablejs@1.15.2)(terser@5.31.6)(typescript@5.5.4)
|
||||||
|
'@types/markdown-it':
|
||||||
|
specifier: ^14.1.2
|
||||||
|
version: 14.1.2
|
||||||
'@vite-pwa/vitepress':
|
'@vite-pwa/vitepress':
|
||||||
specifier: ^0.5.0
|
specifier: ^0.5.0
|
||||||
version: 0.5.0(vite-plugin-pwa@0.20.1(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(terser@5.31.6))(workbox-build@7.1.1)(workbox-window@7.1.0))
|
version: 0.5.0(vite-plugin-pwa@0.20.1(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(terser@5.31.6))(workbox-build@7.1.1)(workbox-window@7.1.0))
|
||||||
|
@ -3438,7 +3462,6 @@ packages:
|
||||||
|
|
||||||
'@ls-lint/ls-lint@2.2.3':
|
'@ls-lint/ls-lint@2.2.3':
|
||||||
resolution: {integrity: sha512-ekM12jNm/7O2I/hsRv9HvYkRdfrHpiV1epVuI2NP+eTIcEgdIdKkKCs9KgQydu/8R5YXTov9aHdOgplmCHLupw==}
|
resolution: {integrity: sha512-ekM12jNm/7O2I/hsRv9HvYkRdfrHpiV1epVuI2NP+eTIcEgdIdKkKCs9KgQydu/8R5YXTov9aHdOgplmCHLupw==}
|
||||||
cpu: [x64, arm64, s390x]
|
|
||||||
os: [darwin, linux, win32]
|
os: [darwin, linux, win32]
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
@ -6958,6 +6981,9 @@ packages:
|
||||||
lines-and-columns@1.2.4:
|
lines-and-columns@1.2.4:
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
|
|
||||||
|
linkify-it@5.0.0:
|
||||||
|
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
||||||
|
|
||||||
lint-staged@15.2.9:
|
lint-staged@15.2.9:
|
||||||
resolution: {integrity: sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==}
|
resolution: {integrity: sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==}
|
||||||
engines: {node: '>=18.12.0'}
|
engines: {node: '>=18.12.0'}
|
||||||
|
@ -7137,6 +7163,10 @@ packages:
|
||||||
mark.js@8.11.1:
|
mark.js@8.11.1:
|
||||||
resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
|
resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
|
||||||
|
|
||||||
|
markdown-it@14.1.0:
|
||||||
|
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
mathml-tag-names@2.1.3:
|
mathml-tag-names@2.1.3:
|
||||||
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
||||||
|
|
||||||
|
@ -7146,6 +7176,9 @@ packages:
|
||||||
mdn-data@2.0.30:
|
mdn-data@2.0.30:
|
||||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||||
|
|
||||||
|
mdurl@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
|
||||||
|
|
||||||
medium-zoom@1.1.0:
|
medium-zoom@1.1.0:
|
||||||
resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==}
|
resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==}
|
||||||
|
|
||||||
|
@ -8304,6 +8337,10 @@ packages:
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
punycode.js@2.3.1:
|
||||||
|
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -9310,6 +9347,9 @@ packages:
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
uc.micro@2.1.0:
|
||||||
|
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||||
|
|
||||||
ufo@1.5.4:
|
ufo@1.5.4:
|
||||||
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
|
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
|
||||||
|
|
||||||
|
@ -16391,6 +16431,10 @@ snapshots:
|
||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
|
linkify-it@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
uc.micro: 2.1.0
|
||||||
|
|
||||||
lint-staged@15.2.9:
|
lint-staged@15.2.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 5.3.0
|
chalk: 5.3.0
|
||||||
|
@ -16607,12 +16651,23 @@ snapshots:
|
||||||
|
|
||||||
mark.js@8.11.1: {}
|
mark.js@8.11.1: {}
|
||||||
|
|
||||||
|
markdown-it@14.1.0:
|
||||||
|
dependencies:
|
||||||
|
argparse: 2.0.1
|
||||||
|
entities: 4.5.0
|
||||||
|
linkify-it: 5.0.0
|
||||||
|
mdurl: 2.0.0
|
||||||
|
punycode.js: 2.3.1
|
||||||
|
uc.micro: 2.1.0
|
||||||
|
|
||||||
mathml-tag-names@2.1.3: {}
|
mathml-tag-names@2.1.3: {}
|
||||||
|
|
||||||
mdn-data@2.0.28: {}
|
mdn-data@2.0.28: {}
|
||||||
|
|
||||||
mdn-data@2.0.30: {}
|
mdn-data@2.0.30: {}
|
||||||
|
|
||||||
|
mdurl@2.0.0: {}
|
||||||
|
|
||||||
medium-zoom@1.1.0: {}
|
medium-zoom@1.1.0: {}
|
||||||
|
|
||||||
memoize-one@6.0.0: {}
|
memoize-one@6.0.0: {}
|
||||||
|
@ -17781,6 +17836,8 @@ snapshots:
|
||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
sade: 1.8.1
|
sade: 1.8.1
|
||||||
|
|
||||||
|
punycode.js@2.3.1: {}
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
pupa@3.1.0:
|
pupa@3.1.0:
|
||||||
|
@ -18908,6 +18965,8 @@ snapshots:
|
||||||
|
|
||||||
typescript@5.5.4: {}
|
typescript@5.5.4: {}
|
||||||
|
|
||||||
|
uc.micro@2.1.0: {}
|
||||||
|
|
||||||
ufo@1.5.4: {}
|
ufo@1.5.4: {}
|
||||||
|
|
||||||
unbox-primitive@1.0.2:
|
unbox-primitive@1.0.2:
|
||||||
|
|
Loading…
Reference in New Issue