feat:组件框架
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated by Umi automatically
|
||||
// DO NOT CHANGE IT MANUALLY!
|
||||
export const components = {};
|
||||
@@ -0,0 +1,194 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated by Umi automatically
|
||||
// DO NOT CHANGE IT MANUALLY!
|
||||
import { filesMeta, tabsMeta } from '.';
|
||||
import type { IDemoData, IRouteMeta } from 'dumi/dist/client/theme-api/types';
|
||||
|
||||
// Copy from React official demo.
|
||||
type ReactPromise<T> = Promise<T> & {
|
||||
status?: 'pending' | 'fulfilled' | 'rejected';
|
||||
value?: T;
|
||||
reason?: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private Internal usage. Safe to remove
|
||||
*/
|
||||
export function use<T>(promise: ReactPromise<T>): T {
|
||||
if (promise.status === 'fulfilled') {
|
||||
return promise.value!;
|
||||
} else if (promise.status === 'rejected') {
|
||||
throw promise.reason;
|
||||
} else if (promise.status === 'pending') {
|
||||
throw promise;
|
||||
} else {
|
||||
promise.status = 'pending';
|
||||
promise.then(
|
||||
(result) => {
|
||||
promise.status = 'fulfilled';
|
||||
promise.value = result;
|
||||
},
|
||||
(reason) => {
|
||||
promise.status = 'rejected';
|
||||
promise.reason = reason;
|
||||
},
|
||||
);
|
||||
throw promise;
|
||||
}
|
||||
}
|
||||
|
||||
const demoIdMap = Object.keys(filesMeta).reduce((total, current) => {
|
||||
if (filesMeta[current].demoIndex) {
|
||||
const { ids, getter } = filesMeta[current].demoIndex;
|
||||
|
||||
ids.forEach((id) => {
|
||||
total[id] = getter;
|
||||
});
|
||||
}
|
||||
|
||||
return total;
|
||||
}, {});
|
||||
|
||||
const demosCache = new Map<string, Promise<IDemoData | undefined>>();
|
||||
|
||||
/**
|
||||
* expand context for source omit extension
|
||||
* why not do this in compile-time?
|
||||
* asset metadata also has extension and for reduce bundle size
|
||||
*/
|
||||
function expandDemoContext(context?: IDemoData['context']) {
|
||||
if (context) {
|
||||
Object.keys(context).forEach((src) => {
|
||||
const withoutExt = src.match(/^(.+)\.(js|jsx|ts|tsx|json)$/)?.[1];
|
||||
|
||||
if (withoutExt && !context[withoutExt]) {
|
||||
context[withoutExt] = context[src];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* use demo data by id
|
||||
*/
|
||||
export function useDemo(id: string): IDemoData | undefined {
|
||||
if (!demosCache.get(id)) {
|
||||
demosCache.set(
|
||||
id,
|
||||
demoIdMap[id]?.().then(({ demos }) => {
|
||||
// expand context for omit ext
|
||||
expandDemoContext(demos[id].context);
|
||||
return demos[id];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return use(demosCache.get(id)!);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all demos
|
||||
*/
|
||||
export async function getFullDemos() {
|
||||
const demoFilesMeta = Object.entries(filesMeta).filter(
|
||||
([_id, meta]) => meta.demoIndex,
|
||||
);
|
||||
|
||||
return Promise.all(
|
||||
demoFilesMeta.map(async ([id, meta]) => ({
|
||||
id,
|
||||
demos: (await meta.demoIndex.getter()).demos as Record<string, IDemoData>,
|
||||
})),
|
||||
).then((ret) =>
|
||||
ret.reduce<Record<string, IDemoData>>((total, { id, demos }) => {
|
||||
Object.values(demos).forEach((demo) => {
|
||||
// set route id in runtime for reduce bundle size
|
||||
demo.routeId = id;
|
||||
|
||||
// expand context for omit ext
|
||||
expandDemoContext(demo.context);
|
||||
});
|
||||
Object.assign(total, demos);
|
||||
return total;
|
||||
}, {}),
|
||||
);
|
||||
}
|
||||
|
||||
type ITab = NonNullable<IRouteMeta['tabs']>[0];
|
||||
|
||||
/**
|
||||
* generate final data for tab
|
||||
*/
|
||||
function genTab(id: string, meta?: ITab['meta']): ITab {
|
||||
return {
|
||||
...tabsMeta[id],
|
||||
meta: meta ?? {
|
||||
frontmatter: { title: tabsMeta[id].title },
|
||||
toc: [],
|
||||
texts: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* get route meta by id
|
||||
*/
|
||||
export function getRouteMetaById<T extends { syncOnly?: boolean }>(
|
||||
id: string,
|
||||
opts?: T,
|
||||
): T extends { syncOnly: true }
|
||||
? IRouteMeta | undefined
|
||||
: Promise<IRouteMeta> | undefined {
|
||||
|
||||
if (filesMeta[id]) {
|
||||
const { frontmatter, toc, textGetter, tabs } = filesMeta[id];
|
||||
const routeMeta: IRouteMeta = {
|
||||
frontmatter,
|
||||
toc,
|
||||
texts: [],
|
||||
};
|
||||
|
||||
if (opts?.syncOnly) {
|
||||
if (tabs) {
|
||||
routeMeta.tabs = tabs.map((tabId) =>
|
||||
genTab(tabId, getRouteMetaById(tabId, opts)),
|
||||
);
|
||||
}
|
||||
return routeMeta;
|
||||
} else {
|
||||
return new Promise(async (resolve) => {
|
||||
if (textGetter) {
|
||||
({ texts: routeMeta.texts } = await textGetter());
|
||||
}
|
||||
if (tabs) {
|
||||
routeMeta.tabs = await Promise.all(
|
||||
tabs.map(async (tabId) =>
|
||||
genTab(tabId, await getRouteMetaById(tabId, opts)),
|
||||
),
|
||||
);
|
||||
}
|
||||
resolve(routeMeta);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get all routes meta
|
||||
*/
|
||||
export async function getFullRoutesMeta(): Promise<Record<string, IRouteMeta>> {
|
||||
return await Promise.all(
|
||||
Object.keys(filesMeta).map(async (id) => ({
|
||||
id,
|
||||
meta: await getRouteMetaById(id),
|
||||
})),
|
||||
).then((ret) =>
|
||||
ret.reduce(
|
||||
(total, { id, meta }) => {
|
||||
total[id] = meta;
|
||||
return total;
|
||||
},
|
||||
{},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated by Umi automatically
|
||||
// DO NOT CHANGE IT MANUALLY!
|
||||
import { frontmatter as fm0, toc as t0 } from '/Users/donghym/Desktop/day/UI/Nova/docs/guide/getting-started.md?type=frontmatter';
|
||||
import { demoIndex as dmi0 } from '/Users/donghym/Desktop/day/UI/Nova/docs/guide/getting-started.md?type=demo-index';
|
||||
import { frontmatter as fm1, toc as t1 } from '/Users/donghym/Desktop/day/UI/Nova/docs/components/index.md?type=frontmatter';
|
||||
import { demoIndex as dmi1 } from '/Users/donghym/Desktop/day/UI/Nova/docs/components/index.md?type=demo-index';
|
||||
import { frontmatter as fm2, toc as t2 } from '/Users/donghym/Desktop/day/UI/Nova/docs/index.md?type=frontmatter';
|
||||
import { demoIndex as dmi2 } from '/Users/donghym/Desktop/day/UI/Nova/docs/index.md?type=demo-index';
|
||||
import { frontmatter as fm3, toc as t3 } from '/Users/donghym/Desktop/day/UI/Nova/src/components/Button/index.md?type=frontmatter';
|
||||
import { demoIndex as dmi3 } from '/Users/donghym/Desktop/day/UI/Nova/src/components/Button/index.md?type=demo-index';
|
||||
|
||||
export const filesMeta = {
|
||||
'docs/guide/getting-started': {
|
||||
frontmatter: fm0,
|
||||
toc: t0,
|
||||
demoIndex: dmi0,
|
||||
textGetter: () => import(/* webpackChunkName: "meta__docs" */'/Users/donghym/Desktop/day/UI/Nova/docs/guide/getting-started.md?type=text'),
|
||||
},
|
||||
'docs/components/index': {
|
||||
frontmatter: fm1,
|
||||
toc: t1,
|
||||
demoIndex: dmi1,
|
||||
textGetter: () => import(/* webpackChunkName: "meta__docs" */'/Users/donghym/Desktop/day/UI/Nova/docs/components/index.md?type=text'),
|
||||
},
|
||||
'docs/index': {
|
||||
frontmatter: fm2,
|
||||
toc: t2,
|
||||
demoIndex: dmi2,
|
||||
textGetter: () => import(/* webpackChunkName: "meta__docs" */'/Users/donghym/Desktop/day/UI/Nova/docs/index.md?type=text'),
|
||||
},
|
||||
'components/Button/index': {
|
||||
frontmatter: fm3,
|
||||
toc: t3,
|
||||
demoIndex: dmi3,
|
||||
textGetter: () => import(/* webpackChunkName: "meta__components" */'/Users/donghym/Desktop/day/UI/Nova/src/components/Button/index.md?type=text'),
|
||||
},
|
||||
}
|
||||
|
||||
export { tabs as tabsMeta } from './tabs';
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated by Umi automatically
|
||||
// DO NOT CHANGE IT MANUALLY!
|
||||
import { warning } from '/Users/donghym/Desktop/day/UI/Nova/node_modules/.pnpm/rc-util@5.44.4_react-dom@19.2.6_react@19.2.6__react@19.2.6/node_modules/rc-util';
|
||||
import deepmerge from '/Users/donghym/Desktop/day/UI/Nova/node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge';
|
||||
import { getRouteMetaById } from './exports';
|
||||
|
||||
// Proxy do not warning since `Object.keys` will get nothing to loop
|
||||
function wrapEmpty(meta, fieldName, defaultValue) {
|
||||
Object.defineProperty(meta, fieldName, {
|
||||
get: () => {
|
||||
warning(false, `'${fieldName}' return empty in latest version, please use \`useRouteMeta\` instead.`);
|
||||
return defaultValue;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const patchRoutes = ({ routes }) => {
|
||||
Object.values(routes).forEach((route) => {
|
||||
const routeMeta = getRouteMetaById(route.id, { syncOnly: true });
|
||||
|
||||
if (routeMeta) {
|
||||
if (process.env.NODE_ENV === 'production' && (route.meta?.frontmatter?.debug || routeMeta.frontmatter?.debug)) {
|
||||
// hide route in production which set hide frontmatter
|
||||
delete routes[route.id];
|
||||
} else {
|
||||
// merge meta to route object
|
||||
route.meta = deepmerge(route.meta, routeMeta);
|
||||
|
||||
wrapEmpty(route.meta, 'toc', []);
|
||||
wrapEmpty(route.meta, 'texts', []);
|
||||
|
||||
route.meta.tabs?.forEach((tab) => {
|
||||
wrapEmpty(tab, 'toc', []);
|
||||
wrapEmpty(tab, 'texts', []);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated by Umi automatically
|
||||
// DO NOT CHANGE IT MANUALLY!
|
||||
export const tabs = {
|
||||
}
|
||||
Reference in New Issue
Block a user