diff --git a/.prettierrc.js b/.prettierrc.js index 5b52bed2..5f5d0dda 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -5,4 +5,4 @@ module.exports = { tabWidth: 4, useTabs: false, printWidth: 80, -} \ No newline at end of file +}; diff --git a/.stylelintrc.js b/.stylelintrc.js index 8b69a928..e7a21793 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -4,16 +4,14 @@ module.exports = { 'stylelint-config-rational-order', 'stylelint-config-prettier', // 排除与 prettier 冲突的 rule ], - plugins: [ - 'stylelint-declaration-block-no-ignored-properties' - ], + plugins: ['stylelint-declaration-block-no-ignored-properties'], // https://stylelint.docschina.org/user-guide/rules/ rules: { - "indentation": 4, - "no-empty-source": null, - "max-empty-lines": 2, - "no-duplicate-selectors": null, - "at-rule-no-unknown": null, + indentation: 4, + 'no-empty-source': null, + 'max-empty-lines': 2, + 'no-duplicate-selectors': null, + 'at-rule-no-unknown': null, 'comment-empty-line-before': null, 'no-invalid-double-slash-comments': null, 'no-descending-specificity': null, @@ -28,9 +26,9 @@ module.exports = { // https://github.com/stylelint/stylelint/blob/main/docs/migration-guide/to-14.md overrides: [ { - files: ["**/*.less"], - customSyntax: "postcss-less" - } + files: ['**/*.less'], + customSyntax: 'postcss-less', + }, ], ignoreFiles: [], -} \ No newline at end of file +}; diff --git a/docs/.vitepress/components/tag/index.md b/docs/.vitepress/components/tag/index.md index 1732198e..55586838 100644 --- a/docs/.vitepress/components/tag/index.md +++ b/docs/.vitepress/components/tag/index.md @@ -14,45 +14,59 @@ app.use(FTag); ### 基础用法 ---BASIC +:::demo +basic.vue +::: ### 可移除标签 设置 `closable` 属性可以定义一个标签是否可移除。 ---CLOSABLE +:::demo +closable.vue +::: ### 动态编辑标签 动态编辑标签可以通过点击标签关闭按钮后触发的 `close` 事件来实现 ---EDIT +:::demo +edit.vue +::: ### 不同尺寸 Tag 组件提供了以下几种尺寸,可以在不同场景下选择合适的尺寸。 ---SIZE +:::demo +size.vue +::: ### 不同主题 Tag 组件提供了三个不同的主题。 ---THEME +:::demo +theme.vue +::: ### 带图标 ---WITHICON +:::demo +withIcon.vue +::: ### 结合 Form 组件 ---WITHFORM +:::demo +withForm.vue +::: ### 超长省略 ---TOOLTIP - ---CODE +:::demo +tooltip.vue +::: ## Tag Props diff --git a/docs/.vitepress/scripts/constants.js b/docs/.vitepress/scripts/constants.js index 2be71643..17ed94e6 100644 --- a/docs/.vitepress/scripts/constants.js +++ b/docs/.vitepress/scripts/constants.js @@ -1,12 +1,6 @@ exports.SCRIPT_TEMPLATE = ` - `; diff --git a/docs/.vitepress/scripts/genComponentDoc.js b/docs/.vitepress/scripts/genComponentDoc.js index da9caebb..71836cb5 100644 --- a/docs/.vitepress/scripts/genComponentDoc.js +++ b/docs/.vitepress/scripts/genComponentDoc.js @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ const path = require('path'); -const fs = require('fs'); const fse = require('fs-extra'); const shiki = require('shiki'); @@ -12,8 +11,8 @@ const CODE_PATH = path.join( ); function getDemoCode() { - if (fs.existsSync(CODE_PATH)) { - return JSON.parse(fs.readFileSync(CODE_PATH, 'utf-8')); + if (fse.existsSync(CODE_PATH)) { + return JSON.parse(fse.readFileSync(CODE_PATH, 'utf-8')); } return { @@ -65,14 +64,14 @@ const highlight = async (code, lang = 'vue') => { .replace(/^
'); }; -async function genComponent(dir, name) { +async function genComponentExample(dir, name) { const output = genOutputPath(name); const indexPath = path.join(dir, 'index.md'); - if (!fs.existsSync(indexPath)) return; + if (!fse.existsSync(indexPath)) return; - let fileContent = fs.readFileSync(indexPath, 'utf-8'); + let fileContent = fse.readFileSync(indexPath, 'utf-8'); - const demos = fs.readdirSync(dir); + const demos = fse.readdirSync(dir); const demoMDStrs = []; const scriptCode = { imports: [], @@ -82,7 +81,7 @@ async function genComponent(dir, name) { for (const filename of demos) { const fullPath = path.join(dir, filename); if ( - fs.statSync(fullPath).isFile() && + fse.statSync(fullPath).isFile() && path.extname(fullPath) === '.vue' ) { const demoContent = []; @@ -100,7 +99,7 @@ async function genComponent(dir, name) { fse.outputFileSync( tempCompPath, handleCompDoc( - fs.readFileSync(fullPath, 'utf-8'), + fse.readFileSync(fullPath, 'utf-8'), name, demoName, ), @@ -109,19 +108,23 @@ async function genComponent(dir, name) { demoContent.push(`<${compName} />`); - const rawCode = fs.readFileSync(fullPath, 'utf-8'); + const rawCode = fse.readFileSync(fullPath, 'utf-8'); tempCode[`${name}.${demoName}`] = rawCode; tempCode[`${name}.${demoName}-code`] = await highlight(rawCode); - const matchStr = new RegExp( - `--${demoName.toLocaleUpperCase()}\\s`, - 'i', + const dashMatchRegExp = new RegExp(`--${demoName}`, 'ig'); + const colonMatchRegExp = new RegExp( + `:::demo[\\s]*${demoName}\.vue[\\s]*:::`, + 'g', ); - if (matchStr.test(fileContent)) { - fileContent = fileContent.replace( - matchStr, - demoContent.join('\n\n\n'), - ); + + if ( + dashMatchRegExp.test(fileContent) || + colonMatchRegExp.test(fileContent) + ) { + fileContent = fileContent + .replace(dashMatchRegExp, demoContent.join('\n\n\n')) + .replace(colonMatchRegExp, demoContent.join('\n\n\n')); } else { demoMDStrs.push(...demoContent); } @@ -131,13 +134,26 @@ async function genComponent(dir, name) { const scriptStr = SCRIPT_TEMPLATE.replace( 'IMPORT_EXPRESSION', scriptCode.imports.join('\n'), - ).replace('COMPONENTS', scriptCode.components.join(',\n')); + ); demoMDStrs.push(scriptStr); + const dashCodeMatchRegExp = new RegExp(`--CODE`); + const colonCodeMatchRegExp = new RegExp(`:::code[\\s\\S]*:::`); + if ( + !( + dashCodeMatchRegExp.test(fileContent) || + colonCodeMatchRegExp.test(fileContent) + ) + ) { + const appendContent = '\n\n:::code:::\n\n'; + fileContent = fileContent + appendContent; + } fse.outputFileSync( output, - fileContent.replace('--CODE', demoMDStrs.join('\n\n')), + fileContent + .replace(dashCodeMatchRegExp, demoMDStrs.join('\n\n')) + .replace(colonCodeMatchRegExp, demoMDStrs.join('\n\n')), ); if (Object.keys(tempCode).length) { @@ -149,9 +165,9 @@ async function genComponent(dir, name) { } async function genComponents(src) { - const components = fs.readdirSync(src); + const components = fse.readdirSync(src); for (const name of components) { - await genComponent(path.join(src, name), name); + await genComponentExample(path.join(src, name), name); } } @@ -160,14 +176,15 @@ async function watch(src) { dir: src, debounce: 50, }); + await watcher.init(); - const gen = (data) => { - const fullPath = path.join(src, data.path); + + const handleGen = (data) => { // 只监听目录变更 - if (fs.statSync(fullPath).isDirectory()) { + if (data.stats.isDirectory()) { const pathSeps = data.path.split(path.sep); - const componentName = pathSeps[0]; - genComponent(path.join(src, componentName), componentName); + const pkgName = pathSeps[0]; + genComponentExample(path.join(src, pkgName), pkgName); } }; const handleDelete = (data) => { @@ -185,26 +202,25 @@ async function watch(src) { }); if (hasDeleteCode) { - fs.writeFileSync(CODE_PATH, JSON.stringify(code, null, 2)); + fse.writeFileSync(CODE_PATH, JSON.stringify(code, null, 2)); } const outputPath = genOutputPath(name); - if (fs.existsSync(outputPath)) { - fs.unlinkSync(outputPath); + if (fse.existsSync(outputPath)) { + fse.unlinkSync(outputPath); } } else if (data.stats.isFile() && path.extname(data.path) === '.vue') { + const pkgName = pathSeps[0]; // 删除组件属性 - const codekey = `${pathSeps[0]}.${path.basename( - data.path, - '.vue', - )}`; + const codekey = `${pkgName}.${path.basename(data.path, '.vue')}`; if (code[codekey]) { delete code[codekey]; - fs.writeFileSync(CODE_PATH, JSON.stringify(code, null, 2)); + fse.writeFileSync(CODE_PATH, JSON.stringify(code, null, 2)); } - genComponent(path.join(src, pathSeps[0]), pathSeps[0]); + genComponentExample(path.join(src, pkgName), pkgName); } }; - watcher.on('+', gen); + + watcher.on('+', handleGen); watcher.on('-', handleDelete); } diff --git a/docs/.vitepress/scripts/transform.js b/docs/.vitepress/scripts/transform.js deleted file mode 100644 index 0e074cbf..00000000 --- a/docs/.vitepress/scripts/transform.js +++ /dev/null @@ -1,68 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const path = require('path'); -const fs = require('fs'); -const fse = require('fs-extra'); - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function genComponent(dir, name) { - const indexPath = path.join(dir, 'index.md'); - if (!fs.existsSync(indexPath)) return; - - let fileContent = fs.readFileSync(indexPath, 'utf-8'); - - const demos = fs.readdirSync(dir); - const demoMDStrs = []; - for (const demoName of demos) { - const fullPath = path.join(dir, demoName); - if (fs.statSync(fullPath).isDirectory(fullPath)) { - const codePath = path.join(fullPath, 'index.vue'); - const textPath = path.join(fullPath, 'index.md'); - const demoContent = []; - if (fs.existsSync(textPath)) { - demoContent.push(fs.readFileSync(textPath, 'utf-8')); - } - - if (fs.existsSync(codePath)) { - fs.writeFileSync( - fullPath + '.vue', - fs.readFileSync(codePath, 'utf-8'), - ); - demoContent.push(`--${demoName.toLocaleUpperCase()}`); - } - if ( - demoContent.length && - fileContent.indexOf( - `PREVIEW_${demoName.toLocaleUpperCase()}`, - ) !== -1 - ) { - fileContent = fileContent.replace( - `PREVIEW_${demoName.toLocaleUpperCase()}`, - demoContent.join('\n\n'), - ); - } else { - demoMDStrs.push(...demoContent); - } - - fse.removeSync(fullPath); - } - } - - demoMDStrs.push('--CODE'); - - fs.writeFileSync( - indexPath, - fileContent.replace('PREVIEW_CODE', demoMDStrs.join('\n\n')), - ); -} - -function genComponents(src) { - const components = fs.readdirSync(src); - for (const name of components) { - genComponent(path.join(src, name), name); - } -} - -(() => { - const src = path.join(process.cwd(), './docs/.vitepress/components'); - genComponents(src); -})(); diff --git a/jest.setup.js b/jest.setup.js index c6df8e11..f66f6239 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1 +1 @@ -import { config } from '@vue/test-utils'; +// import { config } from '@vue/test-utils';