chore: use monorepo

feat/vapor
tangjinzhou 2025-07-24 22:06:11 +08:00
parent f5560db05d
commit c49a9aa6c3
532 changed files with 1088 additions and 28774 deletions

View File

@ -1,36 +0,0 @@
const fs = require('fs');
const path = require('path');
const restCssPath = path.join(process.cwd(), 'components', 'style', 'reset.css');
const tokenStatisticPath = path.join(process.cwd(), 'components', 'version', 'token.json');
const tokenMetaPath = path.join(process.cwd(), 'components', 'version', 'token-meta.json');
function finalizeCompile() {
if (fs.existsSync(path.join(__dirname, './es'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'es', 'style', 'reset.css'));
fs.copyFileSync(tokenStatisticPath, path.join(process.cwd(), 'es', 'version', 'token.json'));
fs.copyFileSync(tokenMetaPath, path.join(process.cwd(), 'es', 'version', 'token-meta.json'));
}
if (fs.existsSync(path.join(__dirname, './lib'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'lib', 'style', 'reset.css'));
fs.copyFileSync(tokenStatisticPath, path.join(process.cwd(), 'lib', 'version', 'token.json'));
fs.copyFileSync(tokenMetaPath, path.join(process.cwd(), 'lib', 'version', 'token-meta.json'));
}
}
function finalizeDist() {
if (fs.existsSync(path.join(__dirname, './dist'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'dist', 'reset.css'));
}
}
module.exports = {
compile: {
finalize: finalizeCompile,
},
dist: {
finalize: finalizeDist,
},
bail: true,
};

View File

@ -1,2 +0,0 @@
codecov:
branch: master

View File

@ -1,11 +0,0 @@
# 🎨 editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -1,13 +0,0 @@
node_modules/
**/*.spec.*
**/style/
*.html
/components/test/*
es/
lib/
_site/
dist/
site/dist/
components/version/version.ts
site/src/router/demoRoutes.js
locale/

View File

@ -1,112 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
jasmine: true,
jest: true,
es6: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
parser: 'babel-eslint',
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'@vue/typescript/recommended',
'@vue/prettier',
// 'prettier',
],
// extends: [
// 'eslint:recommended',
// 'plugin:vue/vue3-recommended',
// '@vue/typescript/recommended',
// '@vue/prettier',
// ],
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
globals: {
h: true,
defineProps: 'readonly',
},
overrides: [
{
files: ['*.md'],
processor: 'markdown/markdown',
rules: {
'no-console': 'off',
},
},
{
files: ['*.ts', '*.tsx'],
// extends: ['@vue/typescript/recommended', '@vue/prettier'],
parserOptions: {
project: './tsconfig.json',
},
rules: {
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
],
'@typescript-eslint/ban-ts-comment': 0,
},
},
{
files: ['*.vue'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2021,
},
rules: {
'no-console': 'off',
'vue/no-reserved-component-names': 'off',
},
},
],
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true, argsIgnorePattern: '^_' },
],
'import/no-named-as-default': 'off',
'import/namespace': [2, { allowComputed: true }],
'import/no-named-as-default-member': 'off',
'import/no-unresolved': [2, { ignore: ['ant-design-vue'] }],
'comma-dangle': [2, 'always-multiline'],
'no-var': 'error',
'no-console': [2, { allow: ['warn', 'error'] }],
'object-shorthand': 2,
'no-unused-vars': [2, { ignoreRestSiblings: true, argsIgnorePattern: '^_' }],
'no-undef': 2,
camelcase: 'off',
'no-extra-boolean-cast': 'off',
semi: ['error', 'always'],
'vue/no-v-html': 'off',
'vue/require-explicit-emits': 'off',
'vue/require-prop-types': 'off',
'vue/require-default-prop': 'off',
'vue/no-reserved-keys': 'off',
'vue/comment-directive': 'off',
'vue/prop-name-casing': 'off',
'vue/one-component-per-file': 'off',
'vue/custom-event-name-casing': 'off',
'vue/v-on-event-hyphenation': 'off',
'vue/max-attributes-per-line': [
2,
{
singleline: 20,
multiline: 1,
},
],
'vue/multi-word-component-names': 'off',
},
};

44
.gitignore vendored
View File

@ -66,9 +66,6 @@ package-lock.json
pnpm-lock.yaml
/coverage
# 备份文件
/components/test/*
list.txt
site/dev.js
@ -77,10 +74,39 @@ vetur/
report.html
site/src/router/demoRoutes.js
components/version/version.ts
components/version/version.tsx
components/version/token.json
components/version/token-meta.json
~component-api.json
# Local env files
.env
.env.*
!.env.template
# Testing
coverage
# Turbo
.turbo
# Vercel
.vercel
# Build Outputs
.next/
out/
build/
dist/
storybook-static/
# Debug
npm-debug.log*
# Misc
.DS_Store
*.pem
vite.config.*.timestamp*
*.tsbuildinfo
*.log
.npmrc
.tsup/

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install pretty-quick --staged

View File

@ -1,7 +0,0 @@
{
"hooks": {
"pre-commit": "pretty-quick --staged",
"pre-publish": "npm run lint",
"commit-msg": "commitlint -x @commitlint/config-conventional -e $GIT_PARAMS"
}
}

View File

@ -1,60 +0,0 @@
const libDir = process.env.LIB_DIR;
const transformIgnorePatterns = [
'/dist/',
// Ignore modules without es dir.
// Update: @babel/runtime should also be transformed
// 'node_modules/(?!.*(@babel|lodash-es))',
'node_modules/(?!@ant-design/icons-vue|@ant-design/icons-svg|lodash-es)/',
];
const testPathIgnorePatterns = ['/node_modules/', 'node'];
function getTestRegex(libDir) {
if (libDir === 'dist') {
return 'demo\\.test\\.js$';
}
return '.*\\.test\\.(j|t)sx?$';
}
module.exports = {
verbose: true,
setupFiles: ['./tests/setup.js'],
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'vue', 'md', 'jpg'],
modulePathIgnorePatterns: ['/_site/'],
testPathIgnorePatterns: testPathIgnorePatterns,
transform: {
'\\.(vue|md)$': '<rootDir>/node_modules/@vue/vue3-jest',
'\\.(js|jsx)$': '<rootDir>/node_modules/babel-jest',
'\\.(ts|tsx)$': '<rootDir>/node_modules/ts-jest',
'\\.svg$': '<rootDir>/node_modules/jest-transform-stub',
},
testRegex: getTestRegex(libDir),
moduleNameMapper: {
'^@/(.*)$/': '<rootDir>/$1',
'^ant-design-vue$': '<rootDir>/components/index',
'^ant-design-vue/es/(.*)$': '<rootDir>/components/$1',
},
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
collectCoverage: process.env.COVERAGE === 'true',
collectCoverageFrom: [
'components/**/*.{js,jsx,vue}',
'!components/*/__tests__/**/type.{js,jsx}',
'!components/vc-*/**/*',
'!components/*/demo/**/*',
'!components/_util/**/*',
'!components/align/**/*',
'!components/trigger/**/*',
'!**/node_modules/**',
],
testEnvironment: 'jsdom',
testEnvironmentOptions: {
url: 'http://localhost',
customExportConditions: ['node', 'node-addons'],
},
transformIgnorePatterns,
globals: {
'ts-jest': {
babelConfig: true,
},
},
};

View File

@ -1,31 +0,0 @@
**/*.svg
lib/
es/
dist/
_site/
coverage/
CNAME
LICENSE
yarn.lock
netlify.toml
yarn-error.log
*.sh
*.snap
.gitignore
.npmignore
.prettierignore
.DS_Store
.editorconfig
.eslintignore
**/*.yml
**/assets
.gitattributes
.stylelintrc
.vcmrc
.png
.npmrc.template
.huskyrc
.gitmodules
*.png
v2-doc/

View File

@ -1,17 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"printWidth": 100,
"proseWrap": "never",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}

View File

@ -1,23 +0,0 @@
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
"rules": {
"comment-empty-line-before": null,
"declaration-empty-line-before": null,
"function-comma-newline-after": null,
"function-name-case": null,
"function-parentheses-newline-inside": null,
"function-max-empty-lines": null,
"function-whitespace-after": null,
"indentation": null,
"number-leading-zero": null,
"number-no-trailing-zeros": null,
"rule-empty-line-before": null,
"selector-combinator-space-after": null,
"selector-list-comma-newline-after": null,
"selector-pseudo-element-colon-notation": null,
"unit-no-unknown": null,
"value-list-max-empty-lines": null,
"font-family-no-missing-generic-family-keyword": null,
"no-descending-specificity": null
}
}

View File

@ -1,43 +0,0 @@
{
"extends": [
"stylelint-config-standard",
"stylelint-config-rational-order",
"stylelint-config-prettier"
],
"customSyntax": "postcss-less",
"plugins": ["stylelint-declaration-block-no-ignored-properties"],
"rules": {
"function-name-case": ["lower"],
"function-no-unknown": [
true,
{
"ignoreFunctions": [
"fade",
"fadeout",
"tint",
"darken",
"ceil",
"fadein",
"floor",
"unit",
"shade",
"lighten",
"percentage",
"-"
]
}
],
"import-notation": null,
"no-descending-specificity": null,
"no-invalid-position-at-import-rule": null,
"declaration-empty-line-before": null,
"keyframes-name-pattern": null,
"custom-property-pattern": null,
"number-max-precision": 8,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"selector-class-pattern": null,
"selector-id-pattern": null,
"selector-not-notation": null
}
}

17
.vcmrc
View File

@ -1,17 +0,0 @@
{
"helpMessage": "\nPlease fix your commit message (and consider using https://www.npmjs.com/package/commitizen)\n",
"types": [
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"chore",
"revert",
"ci"
],
"warnOnFail": false,
"autoFix": false
}

View File

@ -0,0 +1,17 @@
@import '@ant-design-vue/tailwind-config';
@source '../index.html';
@source '../src/**/*.{vue,ts}';
@source '../../../node_modules/ant-design-vue/dist/lib.mjs';
* {
scrollbar-width: thin;
scrollbar-color: var(--color-base-300) transparent;
}
*:focus-visible {
outline: none;
}
.shiki.github-dark,
.dark-scrollbar {
scrollbar-color: rgba(121, 121, 121, 0.4) transparent;
}

View File

@ -0,0 +1,3 @@
// @ts-check
export { default } from '@ant-design-vue/eslint-config/vue'

View File

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Playground</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -0,0 +1,50 @@
{
"name": "playground",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite",
"lint": "eslint . --fix",
"preview": "vite preview",
"tsc": "vue-tsc --noEmit"
},
"dependencies": {
"@floating-ui/vue": "^1.1.5",
"@heroicons/vue": "^2.1.5",
"ant-design-vue": "*",
"@simonwep/pickr": "^1.9.1",
"@trpc/client": "^11.0.0",
"@trpc/server": "^11.0.0",
"@wdns/vue-code-block": "^2.3.3",
"clsx": "^2.1.1",
"cookies": "^0.9.1",
"react": "18",
"react-dom": "18",
"uuid": "^10.0.0",
"vue": "^3.4.34",
"vue-router": "^4.4.0"
},
"devDependencies": {
"@ant-design-vue/eslint-config": "*",
"@ant-design-vue/prettier-config": "*",
"@ant-design-vue/tailwind-config": "*",
"@ant-design-vue/typescript-config": "*",
"@ant-design-vue/vite-config": "*",
"@tailwindcss/vite": "^4.1.3",
"@types/cookies": "^0.9.0",
"@types/node": "^20.0.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-vue": "^5.1.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"tailwindcss": "^4.1.3",
"typescript": "^5.8.2",
"vite": "^5.3.5",
"vite-plugin-dts": "^3.9.1",
"vite-svg-loader": "^5.1.0",
"vue-tsc": "^3.0.3"
}
}

View File

@ -0,0 +1,3 @@
// @ts-check
export { default } from "@ant-design-vue/prettier-config/tailwind";

View File

@ -0,0 +1,3 @@
<template>
<RouterView></RouterView>
</template>

View File

@ -0,0 +1,12 @@
import '~/tailwind.css'
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import routes from './routes'
const router = createRouter({
history: createWebHistory(),
routes,
})
createApp(App).use(router).mount('#app')

View File

@ -0,0 +1,4 @@
import { RouteRecordRaw } from 'vue-router'
const items = import.meta.glob('./pages/*/index.ts', { import: 'default', eager: true })
export default Object.values(items) as RouteRecordRaw[]

5
apps/playground/src/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<Record<string, never>, Record<string, never>, any>
export default component
}

View File

@ -0,0 +1,99 @@
import { RouteRecordRaw } from 'vue-router'
export function globRoutes(
baseName: string,
globs: Record<string, () => Promise<unknown>>,
): RouteRecordRaw {
const items = Object.entries(globs).map(([path, component]) => {
const match = path.match(/^\.\/pages\/(.+)\/index\.ts$/)
if (!match) {
throw new Error('invalid glob')
}
return {
name: match[1],
component,
}
})
const home: RouteRecordRaw = {
path: '',
components: {
default: () => import('@/components/HomePage.vue'),
breadcrumbs: () => import('@/components/TheBreadcrumbs.vue'),
},
props: {
default: {
items: items.map(item => {
return {
name: item.name,
path: `/${baseName}/${item.name}`,
}
}),
},
breadcrumbs: {
items: [
{
name: 'home',
path: '/',
},
{
name: baseName,
path: `/${baseName}`,
},
],
},
},
meta: {
name: baseName,
title: baseName,
},
}
const pages: RouteRecordRaw[] = items.map(item => {
return {
path: item.name,
components: {
default: item.component,
breadcrumbs: () => import('@/components/TheBreadcrumbs.vue'),
},
props: {
breadcrumbs: {
items: [
{
name: 'home',
path: '/',
},
{
name: baseName,
path: `/${baseName}`,
},
{
name: item.name,
path: `/${baseName}/${item.name}`,
},
],
},
},
meta: {
name: item.name,
title: `${baseName} - ${item.name}`,
},
}
})
return {
path: `/${baseName}`,
component: () => import('@/components/BasicLayout.vue'),
props: {
navs: [
{
name: 'home',
path: '/',
},
],
hideNavbar: true,
hideBreadcrumbs: true,
},
children: [home, ...pages],
} as RouteRecordRaw
}

View File

@ -0,0 +1,70 @@
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path'
import { defineConfig, Plugin } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
appType: 'mpa',
plugins: [
vue(),
react(),
tailwindcss(),
],
build: {
rollupOptions: {
input: {
main: resolve(__dirname, './index.html'),
},
},
},
server: {
watch: {
ignored: ['!**/node_modules/@ant-design-vue/**'],
},
},
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'~': resolve(__dirname, './assets'),
},
},
})
interface ImportmapOptions {
imports: Record<string, string>
}
function importmapPlugin(options: ImportmapOptions): Plugin {
return {
name: 'vite-plugin-importmap',
apply: 'build',
config() {
return {
build: {
rollupOptions: {
external: Object.keys(options.imports),
},
},
}
},
transformIndexHtml: {
order: 'pre',
handler(html) {
return {
html,
tags: [
{
tag: 'script',
attrs: {
type: 'importmap',
},
children: JSON.stringify(options),
injectTo: 'head-prepend',
},
],
}
},
},
}
}

View File

@ -1,19 +0,0 @@
module.exports = {
env: {
test: {
presets: [['@babel/preset-env']],
plugins: [
['@vue/babel-plugin-jsx', { mergeProps: false, enableObjectSlots: false }],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-runtime',
'transform-require-context',
],
},
},
};

View File

@ -1,5 +0,0 @@
#!/usr/bin/env bash
rm -rf dist
mkdir dist
./node_modules/.bin/webpack --config webpack.site.config.js
cp dist/index.html index.html

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
export default '4.2.6';

13
eslint.config.js Normal file
View File

@ -0,0 +1,13 @@
// @ts-check
import typescript from '@ant-design-vue/eslint-config/typescript'
/**
* @type {import('eslint').Linter.Config[]}
*/
export default [
...typescript,
{
ignores: ['apps/**', 'packages/**', 'packages-*/**'],
},
]

View File

@ -1,316 +1,34 @@
{
"name": "ant-design-vue",
"version": "4.2.6",
"name": "@ant-design-vue/ant-design-vue",
"private": true,
"version": "5.0.0-alpha.1",
"title": "Ant Design Vue",
"description": "An enterprise-class UI design language and Vue-based implementation",
"keywords": [
"vue",
"vue3",
"ant",
"design",
"antd",
"vueComponent",
"component",
"components",
"ui",
"framework",
"frontend"
],
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/antd.min.js",
"typings": "es/index.d.ts",
"files": [
"dist",
"lib",
"es",
"scripts",
"vetur",
"typings/global.d.ts",
"locale"
"description": "An enterprise-class UI design language and Vue-based implementation for Ant Design",
"type": "module",
"workspaces": [
"apps/*",
"packages/*",
"packages-*/*"
],
"scripts": {
"collect-token-statistic": "tsx scripts/collect-token-statistic.js",
"token-meta": "node scripts/generate-token-meta.js",
"predev": "npm run version & npm run collect-token-statistic & npm run token-meta && node node_modules/esbuild/install.js",
"precompile": "npm run version & npm run collect-token-statistic & npm run token-meta",
"pretest": "npm run version",
"predist": "npm run version",
"presite": "npm run version & npm run routes & npm run collect-token-statistic & npm run token-meta",
"dev": "npm run routes && vite serve site",
"fast-dev": "npm run routes && vite serve site",
"test": "cross-env NODE_ENV=test jest --config .jest.js",
"compile": "node antd-tools/cli/run.js compile",
"generator-webtypes": "tsc -p antd-tools/generator-types/tsconfig.json && node antd-tools/generator-types/index.js",
"pub": "npm run version & npm run collect-token-statistic & npm run token-meta && node --max_old_space_size=8192 antd-tools/cli/run.js pub",
"pub-with-ci": "npm run version & npm run collect-token-statistic & npm run token-meta && node antd-tools/cli/run.js pub-with-ci",
"prepublishOnly": "node antd-tools/cli/run.js guard",
"pre-publish": "npm run generator-webtypes",
"prettier": "prettier -c --write **/*",
"pretty-quick": "pretty-quick",
"dist": "node --max_old_space_size=8192 antd-tools/cli/run.js dist",
"lint": "npm run tsc && npm run lint:demo && npm run lint:md && npm run lint:script && npm run lint:site",
"lint:components": "eslint --fix --ext .jsx,.js,.ts,.tsx ./components",
"lint:demo": "eslint --fix components/*/demo/*.vue",
"lint:md": "eslint --fix *.md",
"lint:script": "eslint . --ext '.js,.jsx,.ts,.tsx'",
"lint:site": "eslint --fix -c ./.eslintrc.js --ext .jsx,.js,.ts,.tsx,vue ./site",
"lint:style": "stylelint \"{site,components}/**/*.less\" --syntax less",
"codecov": "codecov",
"routes": "node site/scripts/genrateRoutes.js",
"tsc": "tsc --noEmit",
"vue-tsc": "vue-tsc --noEmit",
"site": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build site --base=https://next.antdv.com/",
"pub:site": "npm run site && node site/scripts/pushToOSS.js",
"prepare": "husky install",
"version": "node ./scripts/generate-version",
"sort-api": "node antd-tools/cli/run.js sort-api-table"
},
"browserslist": [
"> 0.5%",
"last 2 versions",
"Firefox ESR",
"not dead"
],
"repository": {
"type": "git",
"url": "https://github.com/vueComponent/ant-design-vue.git"
},
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ant-design-vue"
},
"bugs": {
"url": "https://github.com/vueComponent/ant-design-vue/issues"
},
"homepage": "https://www.antdv.com/",
"peerDependencies": {
"vue": ">=3.2.0"
},
"engines": {
"node": ">=12.22.0"
"build": "turbo build",
"dev": "turbo dev",
"dev:apps": "turbo dev --filter=\"./apps/*\"",
"lint": "turbo lint"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.10.5",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-export-default-from": "^7.8.3",
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
"@babel/plugin-proposal-object-rest-spread": "^7.9.6",
"@babel/plugin-proposal-optional-chaining": "^7.10.1",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-member-expression-literals": "^7.8.3",
"@babel/plugin-transform-object-assign": "^7.8.3",
"@babel/plugin-transform-property-literals": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.10.5",
"@babel/plugin-transform-template-literals": "^7.8.3",
"@babel/plugin-transform-typescript": "^7.12.1",
"@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.9.6",
"@babel/preset-typescript": "^7.10.4",
"@commitlint/cli": "^12.0.0",
"@commitlint/config-conventional": "^12.0.0",
"@octokit/rest": "^18.0.0",
"@rollup/plugin-babel": "^5.3.0",
"@types/compression": "^1.7.0",
"@types/fs-extra": "^9.0.8",
"@types/jest": "^28.1.4",
"@types/koa": "^2.11.6",
"@types/lodash-es": "^4.17.3",
"@types/lru-cache": "^5.1.0",
"@types/markdown-it": "^10.0.2",
"@types/node": "^14.0.0",
"@types/postcss-load-config": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vitejs/plugin-legacy": "^2.2.0",
"@vitejs/plugin-vue": "^3.0.0",
"@vitejs/plugin-vue-jsx": "^2.0.0",
"@vue/babel-plugin-jsx": "^1.0.0",
"@vue/cli-plugin-eslint": "^5.0.0",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/test-utils": "^2.0.2",
"@vue/vue3-jest": "28",
"@vueuse/core": "^8.3.1",
"@webpack-cli/serve": "^1.3.1",
"acorn": "^8.0.0",
"ali-oss": "^6.16.0",
"autoprefixer": "^10.2.0",
"axios": "^0.22.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^28.1.2",
"babel-loader": "^8.0.0",
"babel-plugin-import": "^1.1.1",
"babel-plugin-inline-import-data-uri": "^1.0.1",
"babel-plugin-istanbul": "^6.0.0",
"babel-plugin-transform-require-context": "^0.1.1",
"case-sensitive-paths-webpack-plugin": "^2.1.2",
"chalk": "^4.1.1",
"cheerio": "^1.0.0-rc.2",
"codecov": "^3.0.0",
"codesandbox": "^2.2.3",
"colorful": "^2.1.0",
"commander": "^6.1.0",
"compare-versions": "^3.3.0",
"cross-env": "^7.0.0",
"css-loader": "^5.0.0",
"css-minimizer-webpack-plugin": "^3.0.0",
"cz-git": "^1.3.8",
"date-fns": "^2.24.0",
"diacritics": "^1.3.0",
"docsearch.js": "^2.6.3",
"duplicate-package-checker-webpack-plugin": "^3.0.0",
"enquire-js": "^0.2.1",
"esbuild": "~0.12.29",
"esbuild-loader": "^3.0.0",
"escape-html": "^1.0.3",
"eslint": "^8.3.0",
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-html": "^6.0.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-markdown": "^2.0.0",
"eslint-plugin-no-explicit-type-exports": "^0.12.0",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-vue": "^9.17.0",
"fast-glob": "^3.2.7",
"fetch-jsonp": "^1.1.3",
"fs-extra": "^10.0.0",
"glob": "^7.1.2",
"globby": "^11.1.0",
"gray-matter": "^4.0.3",
"gulp": "^4.0.1",
"gulp-babel": "^8.0.0",
"gulp-strip-code": "^0.1.4",
"gulp-typescript": "^6.0.0-alpha.1",
"html-webpack-plugin": "^5.3.1",
"husky": "^6.0.0",
"ignore-emit-webpack-plugin": "^2.0.6",
"is-windows": "^1.0.2",
"jest": "^28.1.2",
"jest-environment-jsdom": "^28.0.0",
"jest-environment-node": "^28.0.2",
"jest-serializer-vue": "^2.0.0",
"jest-transform-stub": "^2.0.0",
"js-base64": "^3.0.0",
"json-templater": "^1.2.0",
"jsonp": "^0.2.1",
"less": "^4.0.0",
"less-loader": "^10.0.0",
"less-plugin-npm-import": "^2.1.0",
"less-vars-to-js": "^1.3.0",
"lint-staged": "^11.0.0",
"majo": "^0.10.1",
"markdown-it": "^8.4.2",
"markdown-it-anchor": "^8.0.4",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0",
"markdown-it-table-of-contents": "^0.5.2",
"marked": "0.3.18",
"merge2": "^1.2.1",
"mini-css-extract-plugin": "^2.4.5",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"mockdate": "^2.0.2",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"postcss": "^8.2.12",
"postcss-loader": "^6.0.0",
"prettier": "^2.2.0",
"pretty-quick": "^3.0.0",
"prismjs": "^1.23.0",
"progress": "^2.0.3",
"raw-loader": "^4.0.2",
"remark-frontmatter": "^2.0.0",
"remark-parse": "^8.0.0",
"remark-stringify": "^8.0.0",
"remark-yaml-config": "^4.1.0",
"remove-files-webpack-plugin": "^1.5.0",
"reqwest": "^2.0.5",
"rimraf": "^3.0.0",
"rucksack-css": "^1.0.2",
"selenium-server": "^3.0.1",
"semver": "^7.0.0",
"slash": "^3.0.0",
"string-replace-loader": "^3.1.0",
"style-loader": "^3.0.0",
"stylelint": "^14.0.0",
"stylelint-config-prettier": "^9.0.0",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-standard": "^25.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^5.0.0",
"terser-webpack-plugin": "^5.1.1",
"through2": "^3.0.0",
"tinycolor2": "^1.6.0",
"ts-jest": "^28.0.5",
"ts-loader": "^9.1.0",
"tsx": "^4.0.0",
"typedoc": "^0.23.25",
"typescript": "~4.9.3",
"umi-request": "^1.3.5",
"unified": "9.2.2",
"url-loader": "^3.0.0",
"vanilla-jsoneditor": "^0.15.1",
"vite": "^3.0.0",
"vue": "^3.2.0",
"vue-clipboard2": "0.3.3",
"vue-drag-resize": "^2.0.3",
"vue-eslint-parser": "^9.3.1",
"vue-i18n": "^9.1.7",
"vue-infinite-scroll": "^2.0.2",
"vue-loader": "^17.0.0",
"vue-request": "^2.0.4",
"vue-router": "^4.0.0",
"vue-style-loader": "^4.1.2",
"vue-tsc": "^1.0.6",
"vuex": "^4.0.0",
"webpack": "^5.0.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^4.0.0",
"webpack-merge": "^5.0.0",
"webpackbar": "^5.0.2",
"xhr-mock": "^2.5.1"
"@ant-design-vue/eslint-config": "*",
"@ant-design-vue/prettier-config": "*",
"@ant-design-vue/typescript-config": "*",
"@types/node": "^20.0.0",
"eslint": "^8.56.0",
"prettier": "^3.3.3",
"esbuild": "^0.25.8",
"turbo": "^2.4.4",
"typescript": "^5.8.2"
},
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^7.0.0",
"@babel/runtime": "^7.10.5",
"@ctrl/tinycolor": "^3.5.0",
"@emotion/hash": "^0.9.0",
"@emotion/unitless": "^0.8.0",
"@simonwep/pickr": "~1.8.0",
"array-tree-filter": "^2.1.0",
"async-validator": "^4.0.0",
"csstype": "^3.1.3",
"dayjs": "^1.10.5",
"dom-align": "^1.12.1",
"dom-scroll-into-view": "^2.0.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.15",
"resize-observer-polyfill": "^1.5.1",
"scroll-into-view-if-needed": "^2.2.25",
"shallow-equal": "^1.0.0",
"stylis": "^4.1.3",
"throttle-debounce": "^5.0.0",
"vue-types": "^3.0.0",
"warning": "^4.0.0"
},
"sideEffects": [
"site/*",
"*.vue",
"*.md",
"dist/*",
"*.css"
],
"config": {
"commitizen": {
"path": "node_modules/cz-git",
"czConfig": "./scripts/commitizen.js"
}
},
"web-types": "vetur/web-types.json"
"packageManager": "npm@10.8.2",
"engines": {
"node": ">=20"
}
}

View File

@ -0,0 +1,5 @@
import { Linter } from 'eslint'
declare const e: Linter.Config[]
export default e

View File

@ -0,0 +1,21 @@
// @ts-check
/**
* @type {Pick<import('eslint').Linter.Config, 'rules'>}
*/
export default {
rules: {
'no-redeclare': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: true,
argsIgnorePattern: '^_',
},
],
},
}

View File

@ -0,0 +1,20 @@
// @ts-check
/**
* @type {Pick<import('eslint').Linter.Config, 'ignores'>}
*/
export default {
ignores: [
'**/node_modules/',
'**/dist/',
'**/public/',
'**/assets/',
'**/*.js',
'**/.turbo/',
'**/.next/',
'**/*.html',
'.github/',
'.vscode/',
'**/.tsup/',
],
}

View File

@ -0,0 +1,31 @@
// @ts-check
import eslint from '@eslint/js'
import prettier from 'eslint-config-prettier'
import checkFile from 'eslint-plugin-check-file'
import tseslint from 'typescript-eslint'
import base from './eslint.config.base.js'
import ignore from './eslint.config.ignore.js'
export default tseslint.config(
ignore,
eslint.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/src/**/*.{ts}'],
plugins: {
'check-file': checkFile,
},
rules: {
'check-file/filename-naming-convention': [
'warn',
{
'**/*.ts': 'KEBAB_CASE',
},
{ ignoreMiddleExtensions: true },
],
},
},
base,
prettier,
)

View File

@ -0,0 +1,77 @@
// @ts-check
import eslint from '@eslint/js';
import prettier from 'eslint-config-prettier';
import checkFile from 'eslint-plugin-check-file';
import pluginVue from 'eslint-plugin-vue';
import tseslint from 'typescript-eslint';
import base from './eslint.config.base.js';
import ignore from './eslint.config.ignore.js';
export default tseslint.config(
ignore,
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: {
parser: tseslint.parser,
sourceType: 'module',
},
},
},
{
files: ['**/src/**/*.{ts,vue}'],
plugins: {
'check-file': checkFile,
},
rules: {
'check-file/filename-naming-convention': [
'warn',
{
'**/*.vue': 'PASCAL_CASE',
'**/*.ts': 'KEBAB_CASE',
},
{ ignoreMiddleExtensions: true },
],
},
},
{
files: ['**/*.vue'],
rules: {
'check-file/no-index': 'warn',
},
},
eslint.configs.recommended,
...tseslint.configs.recommended,
// @ts-ignore
...pluginVue.configs['flat/recommended'],
base,
{
rules: {
'vue/require-default-prop': 'off',
'vue/no-mutating-props': 'off',
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'off',
semi: ['error', 'always'],
quotes: [
2,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true,
},
],
'vue/require-prop-types': 0,
'vue/v-on-event-hyphenation': 0,
'import/no-unresolved': [2, { ignore: ['^@ant-design-vue/table'] }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/consistent-type-imports': 'error',
},
},
prettier,
);

View File

@ -0,0 +1,27 @@
{
"name": "@ant-design-vue/eslint-config",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
"./typescript": {
"import": "./eslint.config.typescript.js",
"types": "./config.d.ts"
},
"./vue": {
"import": "./eslint.config.vue.js",
"types": "./config.d.ts"
}
},
"devDependencies": {
"@eslint/js": "^8.56.0",
"@types/eslint__js": "^8.42.3",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-check-file": "^2.8.0",
"eslint-plugin-vue": "^9.27.0",
"typescript": "^5.8.2",
"typescript-eslint": "^7.17.0",
"globby": "^14.1.0"
}
}

View File

@ -0,0 +1,5 @@
import { Config } from 'prettier'
declare const e: Config
export default e

View File

@ -0,0 +1,22 @@
{
"name": "@ant-design-vue/prettier-config",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"import": "./prettier.config.base.js",
"types": "./config.d.ts"
},
"./tailwind": {
"import": "./prettier.config.tailwind.js",
"types": "./config.d.ts"
}
},
"devDependencies": {
"prettier": "^3.3.3"
},
"peerDependencies": {
"prettier-plugin-tailwindcss": "*"
}
}

View File

@ -0,0 +1,15 @@
// @ts-check
/**
* @type {import('prettier').Config}
*/
export default {
semi: false,
tabWidth: 2,
singleQuote: true,
printWidth: 100,
trailingComma: 'all',
proseWrap: 'never',
arrowParens: 'avoid',
htmlWhitespaceSensitivity: 'ignore',
}

View File

@ -0,0 +1,11 @@
// @ts-check
import base from './prettier.config.base.js'
/**
* @type {import('prettier').Config}
*/
export default {
...base,
plugins: ['prettier-plugin-tailwindcss'],
}

View File

@ -0,0 +1,21 @@
{
"name": "@ant-design-vue/tailwind-config",
"version": "0.0.0",
"private": true,
"exports": {
".": {
"default": "./tailwind.css"
},
"./themes/*": {
"default": "./themes/*.css"
}
},
"devDependencies": {
"tailwindcss": "^4.0.9",
"@tailwindcss/typography": "^0.5.16"
},
"peerDependencies": {
"tailwindcss": "^4",
"@tailwindcss/typography": "^0.5.16"
}
}

View File

@ -0,0 +1,35 @@
@import 'tailwindcss' source(none);
@import './themes/light.css';
@plugin '@tailwindcss/typography';
@utility text-tint-* {
color: color-mix(in srgb, --value(--color- *, [ *]), white calc(--modifier(integer) * 1%));
}
@utility text-shade-* {
color: color-mix(in srgb, --value(--color- *, [ *]), black calc(--modifier(integer) * 1%));
}
@utility bg-tint-* {
background-color: color-mix(
in srgb,
--value(--color- *, [ *]),
white calc(--modifier(integer) * 1%)
);
}
@utility bg-shade-* {
background-color: color-mix(
in srgb,
--value(--color- *, [ *]),
black calc(--modifier(integer) * 1%)
);
}
@utility border-tint-* {
border-color: color-mix(in srgb, --value(--color- *, [ *]), white calc(--modifier(integer) * 1%));
}
@utility border-shade-* {
border-color: color-mix(in srgb, --value(--color- *, [ *]), black calc(--modifier(integer) * 1%));
}

View File

@ -0,0 +1,22 @@
@theme {
--color-base-100: #ffffff;
--color-base-200: #f7f7f7;
--color-base-300: #ededed;
--color-base-content: #222222;
--color-primary: #151415;
--color-primary-content: #ffffff;
--color-secondary: #0d58fc;
--color-secondary-content: #ffffff;
--color-accent: #0289ff;
--color-accent-content: #ffffff;
--color-neutral: #666666;
--color-neutral-content: #ffffff;
--color-info: #0d58fc;
--color-info-content: #ffffff;
--color-success: #00c573;
--color-success-content: #ffffff;
--color-warning: #ff9900;
--color-warning-content: #ffffff;
--color-error: #ff3333;
--color-error-content: #ffffff;
}

View File

@ -0,0 +1,5 @@
{
"name": "@ant-design-vue/typescript-config",
"version": "0.0.0",
"private": true
}

View File

@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "bundler"
}
}

View File

@ -0,0 +1,22 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"allowImportingTsExtensions": true,
"allowJs": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": false,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": false,
"target": "ES2020",
"types": ["vite/client"]
}
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.vite.json",
"compilerOptions": {
"types": ["vite/client"]
}
}

View File

@ -0,0 +1,5 @@
import { GetUserConfig } from './index.d'
declare const e: GetUserConfig
export default e

View File

@ -0,0 +1,8 @@
import { UserConfig, UserConfigFnObject } from 'vite'
export type GetUserConfig = (dirname: string) => UserConfig | UserConfigFnObject
export declare function extendsConfig(
base: UserConfig | UserConfigFnObject,
overwrite: UserConfig | UserConfigFnObject,
): UserConfigFnObject

View File

@ -0,0 +1,14 @@
// @ts-check
import { mergeConfig } from 'vite'
/**
* @type {typeof import('./index.d.ts').extendsConfig}
*/
export function extendsConfig(base, overwrite) {
return env =>
mergeConfig(
typeof base === 'function' ? base(env) : base,
typeof overwrite === 'function' ? overwrite(env) : overwrite,
)
}

View File

@ -0,0 +1,32 @@
{
"name": "@ant-design-vue/vite-config",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"import": "./index.js",
"types": "./index.d.ts"
},
"./typescript": {
"import": "./vite.config.typescript.js",
"types": "./config.d.ts"
},
"./vue": {
"import": "./vite.config.vue.js",
"types": "./config.d.ts"
}
},
"devDependencies": {
"@types/node": "^20.0.0",
"@vitejs/plugin-vue": "^5.1.3",
"vite": "^5.3.5",
"vite-plugin-dts": "^4.5.4"
},
"peerDependencies": {
"@vitejs/plugin-vue": "*",
"typescript": "*",
"vite": "5",
"vite-plugin-dts": "*"
}
}

View File

@ -0,0 +1,67 @@
// @ts-nocheck
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
/**
* @type {import('./index.d.ts').GetUserConfig}
*/
export default dirname =>
defineConfig(({ mode }) => {
const pkg = JSON.parse(readFileSync(resolve(dirname, './package.json'), 'utf-8'));
const isDev = mode === 'development';
return {
plugins: [
dts({
outDir: 'dist',
compilerOptions: { declarationMap: isDev },
include: ['src/**/*.ts', 'src/**/*.vue', 'src/**/*.d.ts'],
insertTypesEntry: true,
skipDiagnostics: false,
}),
],
build: {
cssCodeSplit: true,
lib: {
entry: {
lib: resolve(dirname, 'src/index.ts'),
},
lib: {
entry: {
lib: resolve(dirname, 'src/index.ts'),
},
formats: ['es', 'cjs'],
fileName: (format, entryName) => `${entryName}.${format === 'es' ? 'mjs' : 'cjs'}`,
},
},
rollupOptions: {
external: isDev
? id => {
if (pkg.peerDependencies && id in pkg.peerDependencies) {
return true;
}
if (/^@(ant-design-vue)\//.test(id) || id === 'ant-design-vue') {
return true;
}
return false;
}
: pkg.peerDependencies && Object.keys(pkg.peerDependencies),
},
sourcemap: isDev ? 'inline' : undefined,
minify: !isDev,
emptyOutDir: !isDev,
watch: process.argv.includes('--watch')
? {
buildDelay: 300,
}
: null,
},
resolve: {
alias: {
'@': resolve(dirname, './src'),
},
},
};
});

View File

@ -0,0 +1,16 @@
// @ts-check
import { defineConfig } from 'vite'
import { extendsConfig } from './index.js'
import lib from './vite.config.lib.js'
/**
* @type {import('./index.d.ts').GetUserConfig}
*/
export default dirname =>
extendsConfig(
lib(dirname),
defineConfig({
plugins: [],
}),
)

View File

@ -0,0 +1,28 @@
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import { extendsConfig } from './index.js'
import lib from './vite.config.lib.js'
/**
* @type {import('./index.d.ts').GetUserConfig}
*/
export default dirname =>
extendsConfig(
lib(dirname),
defineConfig(({ mode }) => {
return {
plugins: [vue()],
build: {
cssCodeSplit: true,
rollupOptions: {
output: {
exports: 'named',
globals: {
vue: 'Vue',
},
},
},
},
}
}),
)

0
packages/ui/README.md Normal file
View File

View File

@ -0,0 +1,4 @@
// @ts-check
export { default } from '@ant-design-vue/eslint-config/vue';

88
packages/ui/package.json Normal file
View File

@ -0,0 +1,88 @@
{
"name": "ant-design-vue",
"version": "5.0.0-alpha.1",
"title": "Ant Design Vue",
"description": "An enterprise-class UI design language and Vue-based implementation",
"keywords": [
"vue",
"vue3",
"ant",
"design",
"antd",
"vueComponent",
"component",
"components",
"ui",
"framework",
"frontend"
],
"scripts": {
"build": "vite build",
"build:dev": "vite build --mode development",
"dev": "vite build --watch --mode development",
"lint": "eslint . --fix",
"tsc": "tsc --noEmit",
"tsg": "tsc --declaration --declarationMap --emitDeclarationOnly --noEmit false --outDir dist/types"
},
"type": "module",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.umd.js"
},
"./style.css": {
"import": "./dist/index.css",
"require": "./dist/index.css"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/ant-design-vue/core.git"
},
"bugs": {
"url": "https://github.com/ant-design-vue/table/issues"
},
"license": "MIT",
"main": "./dist/index.umd.js",
"module": "./dist/index.esm.js",
"types": "./dist/src/index.d.ts",
"files": [
"dist",
"src/style",
"typings"
],
"sideEffects": [
"dist/*",
"*.less"
],
"peerDependencies": {
"vue": "^3.2.34"
},
"dependencies": {
"@ant-design/colors": "^7.0.0",
"@ant-design/icons-vue": "^6.0.1",
"@floating-ui/dom": "^1.6.13",
"@floating-ui/vue": "^1.1.6",
"lodash-es": "^4.17.21",
"resize-observer-polyfill": "^1.5.1"
},
"devDependencies": {
"@ant-design-vue/eslint-config": "*",
"@ant-design-vue/prettier-config": "*",
"@ant-design-vue/tailwind-config": "*",
"@ant-design-vue/typescript-config": "*",
"@ant-design-vue/vite-config": "*",
"@tailwindcss/vite": "^4.1.3",
"@vitejs/plugin-vue": "^5.1.3",
"@vueuse/core": "^12.0.0",
"@types/node": "^20.19.7",
"prettier-plugin-tailwindcss": "^0.6.11",
"tailwindcss": "^4.0.14",
"typescript": "^5.8.2",
"vite": "^5.3.5",
"vite-plugin-dts": "^4.5.4",
"vite-svg-loader": "^5.1.0",
"vue": "^3.4.34",
"vue-tsc": "^3.0.3"
}
}

View File

@ -0,0 +1,3 @@
// @ts-check
export { default } from "@ant-design-vue/prettier-config/tailwind";

24
packages/ui/src/index.ts Normal file
View File

@ -0,0 +1,24 @@
import { App } from 'vue'
const components = {} as any
export const install = function (app: App) {
Object.keys(components).forEach(key => {
const component = components[key]
if (component.install) {
app.use(component)
}
})
app.config.globalProperties.$message = components.message
app.config.globalProperties.$notification = components.notification
app.config.globalProperties.$info = components.Modal.info
app.config.globalProperties.$success = components.Modal.success
app.config.globalProperties.$error = components.Modal.error
app.config.globalProperties.$warning = components.Modal.warning
app.config.globalProperties.$confirm = components.Modal.confirm
app.config.globalProperties.$destroyAll = components.Modal.destroyAll
return app
}
export default {
install,
}

5
packages/ui/src/shims-app.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

11
packages/ui/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"extends": "@ant-design-vue/typescript-config/tsconfig.vue.json",
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.d.ts"],
"references": [{ "path": "./tsconfig.node.json" }],
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"~/*": ["./assets/*"]
}
}
}

View File

@ -0,0 +1,4 @@
{
"extends": "@ant-design-vue/typescript-config/tsconfig.node.json",
"include": ["vite.config.*"]
}

5
packages/ui/typings/global.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */
declare module 'vue' {
export interface GlobalComponents {}
}
export {}

View File

@ -0,0 +1,23 @@
import { extendsConfig } from '@ant-design-vue/vite-config';
import vue from '@ant-design-vue/vite-config/vue';
import { resolve } from 'node:path';
import tailwindcss from '@tailwindcss/vite';
export default extendsConfig(vue(__dirname), {
resolve: {
alias: {
'~': resolve(__dirname, './assets'),
},
},
plugins: [tailwindcss()],
build: {
lib: {
name: 'antd',
entry: {
lib: resolve(__dirname, 'src/index.ts'),
},
formats: ['umd'],
fileName: (format, entryName) => `${entryName}.${format}.js`,
},
},
})

View File

@ -1,3 +0,0 @@
module.exports = {
plugins: [require('autoprefixer')],
};

3
prettier.config.js Normal file
View File

@ -0,0 +1,3 @@
// @ts-check
export { default } from '@ant-design-vue/prettier-config'

View File

@ -1,102 +0,0 @@
const TypeDoc = require('typedoc');
const fs = require('fs-extra');
const getTokenList = (list, source) =>
list
.filter(
item =>
!item.comment?.blockTags.some(tag => tag.tag === '@internal' || tag.tag === '@private'),
)
.map(item => ({
source,
token: item.name,
type: item.type.toString(),
desc:
item.comment?.blockTags
?.find(tag => tag.tag === '@desc')
?.content.reduce((result, str) => result.concat(str.text), '') || '',
descEn:
item.comment?.blockTags
?.find(tag => tag.tag === '@descEN')
?.content.reduce((result, str) => result.concat(str.text), '') || '',
name:
item.comment?.blockTags
?.find(tag => tag.tag === '@nameZH')
?.content.reduce((result, str) => result.concat(str.text), '') || '',
nameEn:
item.comment?.blockTags
?.find(tag => tag.tag === '@nameEN')
?.content.reduce((result, str) => result.concat(str.text), '') || '',
}));
function main() {
const app = new TypeDoc.Application();
// If you want TypeDoc to load tsconfig.json / typedoc.json files
app.options.addReader(new TypeDoc.TSConfigReader());
app.options.addReader(new TypeDoc.TypeDocReader());
app.bootstrap({
// typedoc options here
entryPoints: ['components/theme/interface/index.ts'],
skipErrorChecking: true,
});
const project = app.convert();
if (project) {
// Project may not have converted correctly
const output = 'components/version/token-meta.json';
const tokenMeta = {};
let presetColors = [];
project.children.forEach(type => {
if (type.name === 'SeedToken') {
tokenMeta.seed = getTokenList(type.children, 'seed');
} else if (type.name === 'MapToken') {
tokenMeta.map = getTokenList(type.children, 'map');
} else if (type.name === 'AliasToken') {
tokenMeta.alias = getTokenList(type.children, 'alias');
} else if (type.name === 'PresetColors') {
presetColors = type.type.target.elements.map(item => item.value);
}
});
// Exclude preset colors
tokenMeta.seed = tokenMeta.seed.filter(
item => !presetColors.some(color => item.token.startsWith(color)),
);
tokenMeta.map = tokenMeta.map.filter(
item => !presetColors.some(color => item.token.startsWith(color)),
);
tokenMeta.alias = tokenMeta.alias.filter(
item => !presetColors.some(color => item.token.startsWith(color)),
);
tokenMeta.alias = tokenMeta.alias.filter(
item => !tokenMeta.map.some(mapItem => mapItem.token === item.token),
);
tokenMeta.map = tokenMeta.map.filter(
item => !tokenMeta.seed.some(seedItem => seedItem.token === item.token),
);
const finalMeta = Object.entries(tokenMeta).reduce((acc, [key, value]) => {
value.forEach(item => {
acc[item.token] = {
name: item.name,
nameEn: item.nameEn,
desc: item.desc,
descEn: item.descEn,
type: item.type,
source: key,
};
});
return acc;
}, {});
fs.writeJsonSync(output, finalMeta, 'utf8');
// eslint-disable-next-line no-console
console.log(`✅ Token Meta has been written to ${output}`);
}
}
main();

View File

@ -1,102 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta
name="description"
content="An enterprise-class UI components based on Ant Design and Vue"
/>
<title>Ant Design Vue</title>
<link rel="icon" type="image/x-icon" href="//aliyuncdn.antdv.com/favicon.ico" />
<style id="nprogress-style">
#page-404 {
background-image: url('https://os.alipayobjects.com/rmsportal/NOAjOBbnYCrNzrW.jpg');
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
background-size: 100%;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
}
section {
position: absolute;
top: 48%;
left: 55%;
margin: -103px 0 0 -120px;
text-align: center;
}
h1 {
color: #1890ff;
font-size: 120px;
font-weight: 500;
}
p {
color: #314659;
font-size: 18px;
}
</style>
<script>
if (location.host === 'ant-design-vue.gitee.io' || location.host === 'vue.ant.design') {
location.replace(location.href.replace(location.host, 'www.antdv.com'));
}
var _hmt = _hmt || [];
var srcMap = {
'ant-design-vue.gitee.io': 'https://hm.baidu.com/hm.js?1e30265f06f76fabfcdb7ed272017441',
'www.antdv.com': 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22',
};
var src =
srcMap[location.host] || 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22';
(function () {
var hm = document.createElement('script');
hm.src = src;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="app">
<div id="page-404" data-reactroot="">
<section>
<h1>404</h1>
<p>
你要找的页面不存在
<a href="/">返回首页</a>
</p>
</section>
<style>
#app {
height: 100%;
background-color: #fff;
}
</style>
</div>
</div>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-151755889-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-151755889-1');
</script>
</body>
</html>

View File

@ -1,17 +0,0 @@
<template>
<a-button type="primary">Tooltip will show when mouse enter.</a-button>
<a-config-provider
:theme="{
cssVar: {
key: 'test',
},
components: {
Button: {
colorPrimary: '#123456',
},
},
}"
>
<a-button type="primary">Tooltip will show when mouse enter.</a-button>
</a-config-provider>
</template>

View File

@ -1,10 +0,0 @@
// debugger tsx
// import Demo from '../../components/select/demo/field-names.vue';
import Demo from './demo/demo.vue';
export default {
setup() {},
render() {
return <Demo />;
},
};

View File

@ -1,81 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta
name="description"
content="An enterprise-class UI components based on Ant Design and Vue"
/>
<title>Ant Design Vue — An enterprise-class UI components based on Ant Design and Vue.js</title>
<meta
name="keywords"
content="ant design vue,ant-design-vue,ant-design-vue admin,ant design pro,vue ant design,vue ant design pro,vue ant design admin,ant design vue官网,ant design vue中文文档,ant design vue文档"
/>
<link rel="shortcut icon" type="image/x-icon" href="//aliyuncdn.antdv.com/favicon.ico" />
<style id="nprogress-style">
#nprogress {
display: none;
}
</style>
<script>
if (location.host === 'ant-design-vue.gitee.io' || location.host === 'vue.ant.design') {
location.replace(location.href.replace(location.host, 'www.antdv.com'));
}
var _hmt = _hmt || [];
var srcMap = {
'ant-design-vue.gitee.io': 'https://hm.baidu.com/hm.js?1e30265f06f76fabfcdb7ed272017441',
'vue.ant.design': 'https://hm.baidu.com/hm.js?f0ba868f114e674b816b4880f7525811',
'www.antdv.com': 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22',
};
var src =
srcMap[location.host] || 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22';
(function () {
var hm = document.createElement('script');
hm.src = src;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="app"></div>
<script src="https://aliyuncdn.antdv.com/common/docsearch.min_2.6.3.js"></script>
<script type="module" src="/src/main.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-151755889-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-151755889-1');
</script>
<script type="text/javascript" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
<!-- <div
class="surveybyantdv"
data-sf-id="63ad5912f3e10066"
data-sf-mode="popover"
data-sf-button-color="#3a3939"
data-sf-text-color="#ffffff"
data-sf-button-radius="50"
data-sf-button-icon="form-outlined"
data-sf-default-open="false"
data-sf-allow-repeat-submit="true"
data-sf-close-after-submit="false"
data-sf-hide-after-submit="false"
data-sf-delay-visible="false"
data-sf-preload="true"
data-sf-width="368px"
data-sf-height="407px"
></div>
<script async src="https://aliyuncdn.antdv.com/form/static/embed/runtime.js"></script> -->
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,40 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const globby = require('globby');
const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const { ESLint } = require('eslint');
(async () => {
const paths = await globby('components/*/index.*.md');
const components = {};
paths.forEach(path => {
const content = fs.readFileSync(path).toString();
const componentName = path.split('/')[1];
const { data } = matter(content);
components[componentName] = { ...components[componentName], ...data };
});
const TEMPLATE = `
export default [
${Object.keys(components).map(
component => `
{
path: '${component}:lang(-cn)?',
meta: ${JSON.stringify(components[component])},
component: () => import('../../../components/${component}/demo/index.vue'),
}`,
)}
];`;
const engine = new ESLint({
fix: true,
useEslintrc: false,
baseConfig: require(path.join(process.cwd(), '.eslintrc.js')),
});
const report = await engine.lintText(TEMPLATE);
fs.writeFileSync('site/src/router/demoRoutes.js', report[0].output);
})();

View File

@ -1,59 +0,0 @@
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-var-requires */
const OSS = require('ali-oss');
const path = require('path');
const fs = require('fs');
const accessKeyId = process.env.ALI_OSS_ACCESSKEY;
const accessKeySecret = process.env.ALI_OSS_SECRETKEY;
const client = new OSS({
bucket: '4x-antdv',
cname: 'true',
endpoint: '4x-antdv.oss-cn-beijing.aliyuncs.com',
region: 'oss-cn-beijing',
accessKeyId,
accessKeySecret,
});
const assetsPath = path.join(process.cwd(), 'site', 'dist', 'assets');
const put = (target, source) => {
return new Promise((reslove, reject) => {
client
.put(target, source)
.then(res => {
if (res.res.status !== 200) {
console.log(`${res.name} upload failed!`);
reject();
process.exit(500);
} else {
console.log(`${res.name} upload success!`);
reslove();
}
})
.catch(err => {
if (err) {
err && console.log(err);
process.exit(500);
}
});
});
};
async function upload() {
try {
const files = await fs.promises.readdir(assetsPath, {
withFileTypes: true,
});
for (const file of files) {
if (file.isFile()) {
await put(`assets/${file.name}`, path.join(assetsPath, file.name));
}
}
await put('index.html', path.join(process.cwd(), 'site', 'dist', 'index.html'));
} catch (err) {
console.error(err);
}
}
upload();

View File

@ -1,148 +0,0 @@
<template>
<a-style-provider :hash-priority="hashPriority">
<a-config-provider :locale="locale" :theme="themeConfig">
<SiteToken>
<router-view />
</SiteToken>
</a-config-provider>
</a-style-provider>
</template>
<script lang="ts">
import { computed, defineComponent, provide, watch, ref } from 'vue';
import type { Ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import useMediaQuery from './hooks/useMediaQuery';
import { GLOBAL_CONFIG } from './SymbolKey';
import enUS from '../../components/locale/en_US';
import zhCN from '../../components/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import { theme as antdTheme } from 'ant-design-vue';
import type { ThemeConfig } from '../../components/config-provider/context';
import SiteToken from './SiteToken.vue';
function isZhCN(name: string) {
return /-cn\/?$/.test(name);
}
export interface GlobalConfig {
isMobile: Ref<boolean>;
lang: Ref<'zh-CN' | 'en-US'>;
isZhCN: Ref<boolean>;
responsive: Ref<null | 'narrow' | 'crowded'>;
blocked: Ref<boolean>;
}
export type ThemeName = '' | 'light' | 'dark' | 'compact';
const getAlgorithm = (themes: ThemeName[] = []) =>
themes
.filter(theme => !!theme)
.map(theme => {
if (theme === 'dark') {
return antdTheme.darkAlgorithm;
}
if (theme === 'compact') {
return antdTheme.compactAlgorithm;
}
return antdTheme.defaultAlgorithm;
});
export default defineComponent({
components: {
SiteToken,
},
setup() {
const route = useRoute();
const i18n = useI18n();
const colSize = useMediaQuery();
const isMobile = computed(() => colSize.value === 'sm' || colSize.value === 'xs');
const theme = ref<ThemeName>((localStorage.getItem('theme') as ThemeName) || 'light');
const compactTheme = ref<ThemeName>((localStorage.getItem('compactTheme') as ThemeName) || '');
const themeConfig = computed(() => {
return {
algorithm: getAlgorithm([...new Set([theme.value, compactTheme.value])]),
cssVar: true,
} as ThemeConfig;
});
const hashPriority = ref('low' as const);
watch(hashPriority, () => {
location.reload();
});
// useSiteToken();
const responsive = computed(() => {
if (colSize.value === 'xs') {
return 'crowded';
} else if (colSize.value === 'sm') {
return 'narrow';
}
return null;
});
const globalConfig: GlobalConfig = {
isMobile,
responsive,
lang: computed<any>(() => i18n.locale.value),
isZhCN: computed(() => i18n.locale.value === 'zh-CN'),
blocked: ref(false),
};
const changeTheme = (t: ThemeName) => {
theme.value = t;
localStorage.setItem('theme', t);
};
const changeCompactTheme = (t: ThemeName) => {
compactTheme.value = t;
localStorage.setItem('compactTheme', t);
};
provide('themeMode', {
theme,
compactTheme,
changeTheme,
changeCompactTheme,
});
provide(GLOBAL_CONFIG, globalConfig);
watch(
() => route.path,
val => {
i18n.locale.value = isZhCN(val) ? 'zh-CN' : 'en-US';
},
{ immediate: true },
);
watch(
globalConfig.isZhCN,
val => {
if (val) {
dayjs.locale(zhCN.locale);
} else {
dayjs.locale(enUS.locale);
}
},
{ immediate: true },
);
const locale = computed(() => {
return globalConfig.isZhCN.value ? zhCN : enUS;
});
setTimeout(() => {
const div = document.createElement('div');
div.className = 'adsbox';
document.body.appendChild(div);
globalConfig.blocked.value = 'none' === getComputedStyle(div).display;
}, 300);
watch(
theme,
() => {
if (theme.value === 'dark') {
document.getElementsByTagName('html')[0].setAttribute('data-doc-theme', 'dark');
document.getElementsByTagName('body')[0].setAttribute('data-theme', 'dark');
document.getElementsByTagName('html')[0].style.colorScheme = 'dark';
} else {
document.getElementsByTagName('html')[0].setAttribute('data-doc-theme', 'light');
document.getElementsByTagName('body')[0].setAttribute('data-theme', 'light');
document.getElementsByTagName('html')[0].style.colorScheme = 'light';
}
},
{ immediate: true },
);
return { globalConfig, locale, themeConfig, hashPriority };
},
});
</script>

View File

@ -1,7 +0,0 @@
<template>
<slot></slot>
</template>
<script lang="ts" setup>
import useSiteToken from './hooks/useSiteToken';
useSiteToken();
</script>

View File

@ -1 +0,0 @@
export const GLOBAL_CONFIG = Symbol('globalConfig');

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->
<title>Vue</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="69.644116%" y1="0%" x2="69.644116%" y2="100%" id="linearGradient-1">
<stop stop-color="#29CDFF" offset="0%"></stop>
<stop stop-color="#148EFF" offset="37.8600687%"></stop>
<stop stop-color="#0A60FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-19.8191553%" y1="-36.7931464%" x2="138.57919%" y2="157.637507%" id="linearGradient-2">
<stop stop-color="#29CDFF" offset="0%"></stop>
<stop stop-color="#0F78FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-3">
<stop stop-color="#FA8E7D" offset="0%"></stop>
<stop stop-color="#F74A5C" offset="51.2635191%"></stop>
<stop stop-color="#F51D2C" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Vue" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" transform="translate(19.000000, 9.000000)">
<path d="M89.96,90.48 C78.58,93.48 68.33,83.36 67.62,82.48 L46.6604487,62.2292258 C45.5023849,61.1103236 44.8426845,59.5728835 44.8296987,57.9626396 L44.5035564,17.5209948 C44.4948861,16.4458744 44.0537714,15.4195095 43.2796864,14.6733517 L29.6459999,1.53153737 C28.055475,-0.00160504005 25.5232423,0.0449126588 23.9900999,1.63543756 C23.2715121,2.38092066 22.87,3.37600834 22.87,4.41143746 L22.87,64.3864751 C22.87,67.0807891 23.9572233,69.6611067 25.885409,71.5429748 L63.6004615,108.352061 C65.9466323,110.641873 69.6963584,110.624605 72.0213403,108.313281" id="Path-Copy" fill="url(#linearGradient-1)" fill-rule="nonzero" transform="translate(56.415000, 54.831157) scale(-1, 1) translate(-56.415000, -54.831157) "></path>
<path d="M68,90.1163122 C56.62,93.1163122 45.46,83.36 44.75,82.48 L23.7904487,62.2292258 C22.6323849,61.1103236 21.9726845,59.5728835 21.9596987,57.9626396 L21.6335564,17.5209948 C21.6248861,16.4458744 21.1837714,15.4195095 20.4096864,14.6733517 L6.7759999,1.53153737 C5.185475,-0.00160504005 2.65324232,0.0449126588 1.12009991,1.63543756 C0.401512125,2.38092066 3.90211878e-13,3.37600834 3.90798505e-13,4.41143746 L3.94351218e-13,64.3864751 C3.94681177e-13,67.0807891 1.08722326,69.6611067 3.01540903,71.5429748 L40.7807092,108.401101 C43.1069304,110.671444 46.8180151,110.676525 49.1504445,108.412561" id="Path" fill="url(#linearGradient-2)" fill-rule="nonzero"></path>
<path d="M43.2983488,19.0991931 L27.5566079,3.88246244 C26.7624281,3.11476967 26.7409561,1.84862177 27.5086488,1.05444194 C27.8854826,0.664606611 28.4044438,0.444472651 28.9466386,0.444472651 L60.3925021,0.444472651 C61.4970716,0.444472651 62.3925021,1.33990315 62.3925021,2.44447265 C62.3925021,2.9858375 62.1730396,3.50407742 61.7842512,3.88079942 L46.0801285,19.0975301 C45.3051579,19.8484488 44.0742167,19.8491847 43.2983488,19.0991931 Z" id="Path" fill="url(#linearGradient-3)"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,56 +0,0 @@
import { defineComponent, toRefs, computed } from 'vue';
import type { CSSProperties, PropType } from 'vue';
import { TinyColor, type ColorInput } from '@ctrl/tinycolor';
import useSiteToken from '../../hooks/useSiteToken';
const ColorChunk = defineComponent({
props: {
color: {
type: String as PropType<ColorInput>,
default: '#000',
},
},
setup(props, { attrs, slots }) {
const SiteToken = useSiteToken();
const token = computed(() => SiteToken.value.token);
const { color } = toRefs(props);
const dotColor = computed(() => {
const _color = new TinyColor(color.value).toHex8String();
return _color.endsWith('ff') ? _color.slice(0, -2) : _color;
});
return () => {
return (
<span
{...attrs}
style={{
padding: '0.2em 0.4em',
fontSize: '0.9em',
background: token.value.siteMarkdownCodeBg,
borderRadius: `${token.value.borderRadius}px`,
fontFamily: 'monospace',
...(attrs.style as CSSProperties),
}}
>
<span
style={{
display: 'inline-block',
width: '6px',
height: '6px',
borderRadius: `${token.value.borderRadiusSM}px`,
marginRight: '4px',
border: `1px solid ${token.value.colorSplit}`,
backgroundColor: dotColor.value,
}}
/>
{slots.default ? slots.default() : dotColor.value}
</span>
);
};
},
});
export default ColorChunk;

View File

@ -1,205 +0,0 @@
import { defineComponent, toRefs, computed } from 'vue';
import type { PropType } from 'vue';
import { ConfigProvider, Table } from 'ant-design-vue';
import { getDesignToken } from '../antdv-token-previewer';
import tokenMeta from 'ant-design-vue/es/version/token-meta.json';
import tokenData from 'ant-design-vue/es/version/token.json';
import { useLocale } from '../../i18n';
import useSiteToken from '../../hooks/useSiteToken';
import { useColumns } from '../TokenTable';
import ColorChunk from '../ColorChunk';
const defaultToken = getDesignToken();
const locales = {
cn: {
token: 'Token 名称',
description: '描述',
type: '类型',
value: '默认值',
},
en: {
token: 'Token Name',
description: 'Description',
type: 'Type',
value: 'Default Value',
},
};
interface SubTokenTableProps {
defaultOpen?: boolean;
title: string;
tokens: string[];
}
const SubTokenTable = defineComponent({
props: {
defaultOpen: {
type: Boolean as PropType<SubTokenTableProps['defaultOpen']>,
},
title: {
type: String as PropType<SubTokenTableProps['title']>,
},
tokens: {
type: Array as PropType<SubTokenTableProps['tokens']>,
},
},
setup(props) {
const { defaultOpen, title, tokens } = toRefs(props);
const [, lang] = useLocale(locales);
const siteToken = useSiteToken();
const token = computed(() => siteToken.value.token);
const columns = useColumns();
return () => {
if (!tokens.value.length) {
return null;
}
const data = tokens.value
.sort((token1, token2) => {
const hasColor1 = token1.toLowerCase().includes('color');
const hasColor2 = token2.toLowerCase().includes('color');
if (hasColor1 && !hasColor2) {
return -1;
}
if (!hasColor1 && hasColor2) {
return 1;
}
return token1 < token2 ? -1 : 1;
})
.map(name => {
const meta = tokenMeta[name];
if (!meta) {
return null;
}
return {
name,
desc: lang.value === 'cn' ? meta.desc : meta.descEn,
type: meta.type,
value: (defaultToken as any)[name],
};
})
.filter(info => info);
return (
// Reuse `.markdown` style
<details class="markdown" open={defaultOpen.value || process.env.NODE_ENV !== 'production'}>
<summary>
<h3 style={{ display: 'inline' }}>{title.value}</h3>
</summary>
<ConfigProvider
theme={{
token: {
borderRadius: 0,
},
}}
>
<Table
size="middle"
columns={columns}
bordered
dataSource={data}
style={{ marginBottom: token.value.margin }}
pagination={false}
rowKey={record => record.name}
v-slots={{
bodyCell: ({ text, record, column }) => {
if (column.key === 'type') {
return (
<span
style={{
margin: '0 1px',
padding: '0.2em 0.4em',
fontSize: '0.9em',
background: `${token.value.siteMarkdownCodeBg}`,
border: `1px solid ${token.value.colorSplit}`,
borderRadius: '3px',
fontFamily: 'monospace',
}}
>
{record.type}
</span>
);
}
if (column.key === 'value') {
const isColor =
typeof record.value === 'string' &&
(record.value.startsWith('#') || record.value.startsWith('rgb'));
if (isColor) {
return <ColorChunk color={record.value}>{record.value}</ColorChunk>;
}
return (
<span>
{typeof record.value !== 'string'
? JSON.stringify(record.value)
: record.value}
</span>
);
}
return <span>{text} </span>;
},
}}
/>
</ConfigProvider>
</details>
);
};
},
});
export interface ComponentTokenTableProps {
component: string;
}
const ComponentTokenTable = defineComponent({
props: {
component: {
type: String as PropType<ComponentTokenTableProps['component']>,
},
},
setup(props) {
const { component } = toRefs(props);
const mergedTokens = computed(() => {
const globalTokenSet = new Set<string>();
let componentTokens: Record<string, string> = {};
component.value.split(',').forEach(comp => {
const { global: globalTokens = [], component: singleComponentTokens = [] } =
tokenData[comp] || {};
globalTokens.forEach((token: string) => {
globalTokenSet.add(token);
});
componentTokens = {
...componentTokens,
...singleComponentTokens,
};
});
return {
mergedGlobalTokens: Array.from(globalTokenSet),
mergedComponentTokens: componentTokens,
};
});
return () => {
return (
<>
{/* Component Token 先不展示 */}
{/* <SubTokenTable title="Component Token" tokens={mergedComponentTokens} defaultOpen /> */}
<SubTokenTable title="Global Token" tokens={mergedTokens.value.mergedGlobalTokens} />
</>
);
};
},
});
export default ComponentTokenTable;

View File

@ -1,4 +0,0 @@
export const REPO_OWNER = 'VueComponent';
export const REPO_NAME = 'ant-design-vue';
export const REPO_PATH = `${REPO_OWNER}/${REPO_NAME}`;
export const REPO_BRANCH = 'main';

View File

@ -1,112 +0,0 @@
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
import { useRoute } from 'vue-router';
import { REPO_PATH } from './constants';
import dayjs from 'dayjs';
defineProps({
isZn: Boolean,
});
const route = useRoute();
const contributors = ref([]);
const lastCommitTime = ref(0);
const filterData = data => {
const arr = [];
data.forEach(item => {
if (!!item.author?.login || !!item.author?.html_url || !!item.author?.avatar_url) {
lastCommitTime.value = Math.max(lastCommitTime.value, +new Date(item.commit.author.date));
arr.push({
login: item.author.login,
url: item.author.html_url,
avatar: item.author.avatar_url,
});
}
});
contributors.value = arr.reduce((acc, curr) => {
if (!acc.find(item => item.login === curr.login)) {
acc.push(curr);
}
return acc;
}, []);
};
const getContributors = async () => {
const path = route.path;
const parts = path.split('/');
const name = parts[2];
const componentName = name.includes('-') ? name.replace('-cn', '') : name;
const url = `https://api.github.com/repos/${REPO_PATH}/commits?path=/components/${componentName}`;
try {
const req = await fetch(url);
const res = await req.json();
filterData(res);
} catch (e) {
return null;
}
};
watchEffect(() => {
getContributors();
});
</script>
<template>
<div v-if="contributors.length > 0" class="contributors-list">
<ul class="acss-1ppw8kl">
<li v-for="item in contributors" :key="item.login">
<a-tooltip :title="`${isZn ? '文档贡献者:' : 'Contributor: '}${item.login}`">
<a :href="item.url" target="_blank">
<a-avatar :src="item.avatar" size="small" />
</a>
</a-tooltip>
</li>
</ul>
<span>
{{ isZn ? '最后更新' : 'Last updated' }} : {{ dayjs(lastCommitTime).format('YYYY/MM/DD') }}
</span>
</div>
</template>
<style scoped>
.contributors-list {
margin-top: 120px !important;
display: flex;
gap: 8px;
}
.contributors-list span {
color: var(--primary-color);
}
.acss-1ppw8kl {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
clear: both;
flex: 1;
}
.acss-1ppw8kl li {
height: 24px;
}
.acss-1ppw8kl li,
.acss-1ppw8kl .ant-avatar + .ant-avatar {
-webkit-transition: all 0.3s;
transition: all 0.3s;
-webkit-margin-end: -8px;
margin-inline-end: -8px;
}
.acss-1ppw8kl:hover li,
.acss-1ppw8kl:hover .ant-avatar {
-webkit-margin-end: 0;
margin-inline-end: 0;
}
</style>

View File

@ -1,265 +0,0 @@
<template>
<template v-if="inIframe">
<div :id="sectionId"><slot /></div>
</template>
<section v-else :id="sectionId" class="code-box">
<section class="code-box-demo">
<template v-if="iframeDemo[iframeDemoKey]">
<div class="browser-mockup with-url">
<iframe :src="iframeDemo[iframeDemoKey]" :height="iframeHeight" />
</div>
</template>
<template v-else>
<slot />
</template>
</section>
<section class="code-box-meta markdown">
<div class="code-box-title">
<a :href="`#${sectionId}`">{{ title }}</a>
</div>
<div class="code-box-description" v-html="docHtml"></div>
<div class="code-box-actions">
<a-tooltip :title="$t('app.demo.codesandbox')">
<CodeSandboxOutlined
class="code-box-code-copy code-box-code-action"
@click="handleCodeSandbox"
/>
</a-tooltip>
<a-tooltip :title="$t(`app.demo.type.${type === 'JS' ? 'js' : 'ts'}`)">
<span
class="code-expand-icon code-box-code-action"
style="width: auto"
@click="handleChangeType"
>
{{ type }}
</span>
</a-tooltip>
<a-tooltip
v-if="!blocked"
:title="$t(`app.demo.${copied ? 'copied' : 'copy'}`)"
:open="copyTooltipVisible"
@openChange="onCopyTooltipVisibleChange"
>
<component
:is="copied && copyTooltipVisible ? 'CheckOutlined' : 'SnippetsOutlined'"
key="copy"
v-clipboard:copy="type === 'TS' ? sourceCode : jsSourceCode"
v-clipboard:success="handleCodeCopied"
class="code-box-code-copy code-box-code-action"
/>
</a-tooltip>
<a-tooltip v-else :title="$t('app.demo.copy')">
<SnippetsOutlined class="code-box-code-copy code-box-code-action" @click="warning" />
</a-tooltip>
<a-tooltip :title="$t(`app.demo.code.${codeExpand ? 'hide' : 'show'}`)">
<span class="code-expand-icon code-box-code-action">
<img
alt="expand code"
:src="
theme === 'dark'
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
"
:class="codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'"
@click="handleCodeExpand"
/>
<img
alt="expand code"
:src="
theme === 'dark'
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
"
:class="codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'"
@click="handleCodeExpand"
/>
</span>
</a-tooltip>
</div>
</section>
<section :class="highlightClass">
<div ref="codeRef" class="highlight">
<slot v-if="type === 'TS'" name="htmlCode" />
<slot v-else name="jsVersionHtml" />
</div>
<div class="code-box-actions code-box-actions-bottom">
<a-tooltip :title="$t(`app.demo.code.hide`)">
<span class="code-expand-icon code-box-code-action">
<img
alt="expand code"
:src="
theme === 'dark'
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
"
:class="'code-expand-icon-show'"
@click="handleCodeExpand($event, sectionId)"
/>
</span>
</a-tooltip>
</div>
</section>
</section>
</template>
<script lang="ts">
import type { GlobalConfig } from '../App.vue';
import { GLOBAL_CONFIG } from '../SymbolKey';
import { computed, defineComponent, inject, onMounted, ref } from 'vue';
import { CheckOutlined, SnippetsOutlined, CodeSandboxOutlined } from '@ant-design/icons-vue';
import { getCodeSandboxParams } from '../utils/generateOnlineDemo';
import packageInfo from '../../../package.json';
// import { Modal } from 'ant-design-vue';
export default defineComponent({
name: 'DemoBox',
components: {
CheckOutlined,
SnippetsOutlined,
CodeSandboxOutlined,
},
props: {
jsfiddle: Object,
},
setup(props) {
const codeExpand = ref(false);
const type = ref('TS');
const copyTooltipVisible = ref(false);
const copied = ref(false);
const codeRef = ref<HTMLDivElement>();
const sectionId = computed(() => {
const relativePath = props.jsfiddle?.relativePath || '';
return `${relativePath.split('/').join('-').replace('.vue', '')}`.toLocaleLowerCase();
});
const inIframe = inject('inIframe', false);
const iframeHeight = computed(() => props.jsfiddle?.iframe);
// eslint-disable-next-line @typescript-eslint/no-empty-function
const addDemosInfo: any = inject('addDemosInfo', () => {});
const globalConfig = inject<GlobalConfig>(GLOBAL_CONFIG);
const title = computed(
() =>
props.jsfiddle &&
props.jsfiddle.title &&
props.jsfiddle?.title[globalConfig.isZhCN.value ? 'zh-CN' : 'en-US'],
);
const warning = () => {
// Modal.warning({
// content: globalConfig.isZhCN
// ? '使 AdBlock Adblock Plus Ant Design Vue 便'
// : 'We have detected that you may have used AdBlock or Adblock Plus, which will affect functions such as copying and expanding code. You can add Ant Design Vue to the whitelist so that we can provide better services.',
// });
};
const iframeDemoKey = computed(() => {
return (
props.jsfiddle &&
props.jsfiddle.title &&
props.jsfiddle?.title['en-US'] &&
String(props.jsfiddle?.title['en-US']).split(' ').join('-').toLowerCase()
);
});
const onCopyTooltipVisibleChange = (visible: boolean) => {
if (visible) {
copyTooltipVisible.value = visible;
copied.value = false;
} else {
copyTooltipVisible.value = visible;
}
};
const docHtml = computed(() =>
props.jsfiddle && props.jsfiddle.docHtml
? (
props.jsfiddle.docHtml.replace(
`<h2 id="zh-cn">zh-CN <a class="header-anchor" href="#zh-cn">
<span aria-hidden="true" class="anchor">#</span>
</a></h2>`,
'',
).split(`<h2 id="en-us">en-US <a class="header-anchor" href="#en-us">
<span aria-hidden="true" class="anchor">#</span>
</a></h2>`)[globalConfig.isZhCN.value ? 0 : 1] || ''
).trim()
: '',
);
const handleCodeExpand = (_, sectionId?) => {
if (globalConfig.blocked.value) {
warning();
return;
}
if (sectionId) {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView();
}
}
codeExpand.value = !codeExpand.value;
};
const handleCodeCopied = () => {
copied.value = true;
};
const handleChangeType = () => {
if (globalConfig.blocked.value) {
warning();
return;
}
type.value = type.value === 'TS' ? 'JS' : 'TS';
};
const handleCodeSandbox = () => {
const code = codeRef.value.innerText;
const params = getCodeSandboxParams(code, {
title: `${title.value} - ant-design-vue@${packageInfo.version}`,
});
const div = document.createElement('div');
div.style.display = 'none';
div.innerHTML = `<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank">
<input type="hidden" name="parameters" value="${params}" />
<input type="submit" value="Open in sandbox" />
</form>`;
document.body.appendChild(div);
(div.firstElementChild as HTMLFormElement).submit();
document.body.removeChild(div);
};
const highlightClass = computed(() => {
return {
'highlight-wrapper': true,
'highlight-wrapper-expand': codeExpand.value,
};
});
const iframeDemo = inject('iframeDemo', {});
onMounted(() => {
addDemosInfo({
href: `#${sectionId.value}`,
title,
});
});
const theme = computed(() => inject('themeMode', { theme: ref('light') }).theme.value);
return {
docHtml,
iframeDemo,
iframeDemoKey,
iframeHeight,
inIframe,
theme,
type,
warning,
blocked: globalConfig.blocked,
isZhCN: globalConfig.isZhCN,
sectionId,
title,
codeExpand,
copyTooltipVisible,
copied,
onCopyTooltipVisibleChange,
handleCodeExpand,
handleCodeCopied,
handleChangeType,
highlightClass,
sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))),
jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))),
codeRef,
handleCodeSandbox,
};
},
});
</script>
<style></style>

View File

@ -1,5 +0,0 @@
<template>
<div>
<router-view></router-view>
</div>
</template>

View File

@ -1,143 +0,0 @@
import { defineComponent, toRefs, computed } from 'vue';
import type { PropType } from 'vue';
import type { TableProps } from 'ant-design-vue';
import { Table } from 'ant-design-vue';
import { getDesignToken } from '../antdv-token-previewer';
import tokenMeta from 'ant-design-vue/es/version/token-meta.json';
import { useLocale } from '../../i18n';
import useSiteToken from '../../hooks/useSiteToken';
import ColorChunk from '../ColorChunk';
type TokenTableProps = {
type: 'seed' | 'map' | 'alias';
lang: 'zh' | 'en';
};
type TokenData = {
name: string;
desc: string;
type: string;
value: any;
};
const defaultToken = getDesignToken();
const locales = {
cn: {
token: 'Token 名称',
description: '描述',
type: '类型',
value: '默认值',
},
en: {
token: 'Token Name',
description: 'Description',
type: 'Type',
value: 'Default Value',
},
};
export function useColumns(): Exclude<TableProps<TokenData>['columns'], undefined> {
const [locale] = useLocale(locales);
return [
{
title: locale.value.token,
key: 'name',
dataIndex: 'name',
},
{
title: locale.value.description,
key: 'desc',
dataIndex: 'desc',
},
{
title: locale.value.type,
key: 'type',
dataIndex: 'type',
},
{
title: locale.value.value,
key: 'value',
dataIndex: 'value',
},
];
}
const TokenTable = defineComponent({
props: {
type: {
type: String as PropType<TokenTableProps['type']>,
},
lang: {
type: String as PropType<TokenTableProps['lang']>,
},
},
setup(props, { attrs }) {
const { type } = toRefs(props);
const SiteToken = useSiteToken();
const token = computed(() => SiteToken.value.token);
const [, lang] = useLocale(locales);
const columns = useColumns();
const data = computed<TokenData[]>(() => {
return Object.entries(tokenMeta)
.filter(([, meta]: any) => meta.source === type.value)
.map(([token, meta]: any) => ({
name: token,
desc: lang.value === 'cn' ? meta.desc : meta.descEn,
type: meta.type,
value: (defaultToken as any)[token],
}));
});
return () => {
return (
<Table
dataSource={data.value}
columns={columns}
pagination={false}
bordered
{...attrs}
v-slots={{
bodyCell: ({ text, record, column }) => {
if (column.key === 'type') {
return (
<span
style={{
margin: '0 1px',
padding: '0.2em 0.4em',
fontSize: '0.9em',
background: `${token.value.siteMarkdownCodeBg}`,
border: `1px solid ${token.value.colorSplit}`,
borderRadius: '3px',
fontFamily: 'monospace',
}}
>
{record.type}
</span>
);
}
if (column.key === 'value') {
const isColor =
typeof record.value === 'string' &&
(record.value.startsWith('#') || record.value.startsWith('rgb'));
if (isColor) {
return <ColorChunk color={record.value}>{record.value}</ColorChunk>;
}
return (
<span>
{typeof record.value !== 'string' ? JSON.stringify(record.value) : record.value}
</span>
);
}
return <span>{text} </span>;
},
}}
></Table>
);
};
},
});
export default TokenTable;

View File

@ -1,364 +0,0 @@
import type { InputProps } from 'ant-design-vue';
import { ConfigProvider, Input, InputNumber, Select, theme } from 'ant-design-vue';
import classNames from 'ant-design-vue/es/_util/classNames';
import type { PropType } from 'vue';
import { defineComponent, watchEffect, computed, toRefs, ref } from 'vue';
import { HexColorPicker, RgbaColorPicker } from '../vue-colorful';
import tinycolor from 'tinycolor2';
import makeStyle from './utils/makeStyle';
import type { ValueType } from 'ant-design-vue/es/input-number/src/utils/MiniDecimal';
const { useToken } = theme;
const useStyle = makeStyle('ColorPanel', token => ({
'.color-panel': {
padding: 12,
backgroundColor: '#fff',
borderRadius: 12,
border: '1px solid rgba(0, 0, 0, 0.06)',
boxShadow: token.boxShadow,
width: 224,
boxSizing: 'border-box',
'.color-panel-mode': {
display: 'flex',
alignItems: 'center',
marginBottom: 6,
},
'.color-panel-preview': {
width: 24,
height: 24,
borderRadius: 4,
boxShadow: '0 2px 3px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.09)',
flex: 'none',
overflow: 'hidden',
background:
'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAFpJREFUWAntljEKADAIA23p6v//qQ+wfUEcCu1yriEgp0FHRJSJcnehmmWm1Dv/lO4HIg1AAAKjTqm03ea88zMCCEDgO4HV5bS757f+7wRoAAIQ4B9gByAAgQ3pfiDmXmAeEwAAAABJRU5ErkJggg==) 0% 0% / 32px',
},
'.color-panel-preset-colors': {
paddingTop: 12,
display: 'flex',
flexWrap: 'wrap',
width: 200,
},
'.color-panel-preset-color-btn': {
borderRadius: 4,
width: 20,
height: 20,
border: 'none',
outline: 'none',
margin: 4,
cursor: 'pointer',
boxShadow: '0 2px 3px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.09)',
},
'.color-panel-mode-title': {
color: token.colorTextPlaceholder,
marginTop: 2,
fontSize: 12,
textAlign: 'center',
},
'.color-panel-rgba-input': {
display: 'flex',
alignItems: 'center',
'&-part': {
flex: 1,
width: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
'&-title': {
color: token.colorTextPlaceholder,
marginTop: 2,
fontSize: 12,
},
'&:not(:last-child)': {
marginRight: 4,
},
[`${token.rootCls}-input-number`]: {
width: '100%',
input: {
fontSize: 12,
padding: '0 4px',
},
},
},
},
},
}));
export type HexColorInputProps = {
value: string;
onChange?: (value: string) => void;
alpha?: boolean;
};
const getHexValue = (value: string, alpha = false) => {
return alpha ? tinycolor(value).toHex8() : tinycolor(value).toHex();
};
const HexColorInput = defineComponent({
name: 'HexColorInput',
props: {
value: { type: String },
alpha: { type: Boolean },
onChange: { type: Function as PropType<(value: string) => void> },
},
setup(props) {
const { value, alpha } = toRefs(props);
const hexValue = ref<string>(value.value);
const focusRef = ref<boolean>(false);
const handleChange: InputProps['onChange'] = e => {
hexValue.value = e.target.value;
props.onChange(getHexValue(e.target.value, alpha.value));
};
const handleBlur: InputProps['onBlur'] = (e: any) => {
focusRef.value = false;
hexValue.value = getHexValue(e.target.value, alpha.value);
};
const handleFocus = () => {
focusRef.value = true;
};
watchEffect(() => {
if (!focusRef.value) {
hexValue.value = getHexValue(value.value, alpha.value);
}
});
return () => {
return (
<div>
<Input
size="small"
value={hexValue.value}
onFocus={handleFocus}
onChange={handleChange}
onBlur={handleBlur}
v-slots={{
prefix: () => '#',
}}
/>
<div class="color-panel-mode-title">HEX{alpha.value ? '8' : ''}</div>
</div>
);
};
},
});
type RgbaColor = tinycolor.ColorFormats.RGBA;
export type RgbColorInputProps = {
value?: RgbaColor;
onChange?: (value: RgbaColor) => void;
alpha?: boolean;
};
const RgbColorInput = defineComponent({
name: 'RgbColorInput',
props: {
value: { type: Object as PropType<RgbaColor>, default: () => ({ r: 0, g: 0, b: 0, a: 1 }) },
onChange: { type: Function as PropType<(value: RgbaColor) => void> },
alpha: { type: Boolean },
},
setup(props) {
const { value, alpha } = toRefs(props);
const handleChange = (val: ValueType, key: 'r' | 'g' | 'b' | 'a') => {
value.value[key] = val;
props.onChange(value.value);
};
return () => {
return (
<div class="color-panel-rgba-input">
<ConfigProvider theme={{ components: { InputNumber: { handleWidth: 12 } } }}>
<div class="color-panel-rgba-input-part">
<InputNumber
min={0}
max={255}
size="small"
value={value.value.r}
onChange={val => handleChange(val, 'r')}
/>
<div class="color-panel-mode-title">R</div>
</div>
<div class="color-panel-rgba-input-part">
<InputNumber
min={0}
max={255}
size="small"
value={value.value.g}
onChange={val => handleChange(val, 'g')}
/>
<div class="color-panel-mode-title">G</div>
</div>
<div class="color-panel-rgba-input-part">
<InputNumber
min={0}
max={255}
size="small"
value={value.value.b}
onChange={val => handleChange(val, 'b')}
/>
<div class="color-panel-mode-title">B</div>
</div>
{alpha.value && (
<div class="color-panel-rgba-input-part">
<InputNumber
min={0}
max={1}
step={0.01}
size="small"
value={value.value.a}
onChange={val => handleChange(val, 'a')}
/>
<div class="color-panel-mode-title">A</div>
</div>
)}
</ConfigProvider>
</div>
);
};
},
});
export type ColorPanelProps = {
color: string;
onChange: (color: string) => void;
alpha?: boolean;
};
const colorModes = ['HEX', 'HEX8', 'RGB', 'RGBA'] as const;
type ColorMode = (typeof colorModes)[number];
const getColorStr = (color: any, mode: ColorMode) => {
switch (mode) {
case 'HEX':
return tinycolor(color).toHexString();
case 'HEX8':
return tinycolor(color).toHex8String();
case 'RGBA':
case 'RGB':
default:
return tinycolor(color).toRgbString();
}
};
const ColorPanel = defineComponent({
name: 'ColorPanel',
inheritAttrs: false,
props: {
color: { type: String },
onChange: { type: Function as PropType<(color: string) => void> },
alpha: { type: Boolean },
},
setup(props, { attrs }) {
const { color, alpha } = toRefs(props);
const { token } = useToken();
const [wrapSSR, hashId] = useStyle();
const colorMode = ref<ColorMode>('HEX');
const presetColors = computed(() => {
return [
token.value.blue,
token.value.purple,
token.value.cyan,
token.value.green,
token.value.magenta,
token.value.pink,
token.value.red,
token.value.orange,
token.value.yellow,
token.value.volcano,
token.value.geekblue,
token.value.gold,
token.value.lime,
'#000',
];
});
const handleColorModeChange = (value: ColorMode) => {
colorMode.value = value;
props.onChange(getColorStr(color.value, value));
};
return () => {
return wrapSSR(
<div {...attrs} class={classNames(hashId.value, 'color-panel')}>
{(colorMode.value === 'HEX' || colorMode.value === 'RGB') && (
<HexColorPicker
style={{ height: '160px' }}
color={tinycolor(color.value).toHex()}
onChange={value => {
props.onChange(getColorStr(value, colorMode.value));
}}
/>
)}
{(colorMode.value === 'RGBA' || colorMode.value === 'HEX8') && (
<RgbaColorPicker
style={{ height: '160px' }}
color={tinycolor(color.value).toRgb()}
onChange={value => {
props.onChange(getColorStr(value, colorMode.value));
}}
/>
)}
<div style={{ marginTop: '12px' }}>
<div class="color-panel-mode">
<div class="color-panel-preview">
<div style={{ backgroundColor: color.value, width: '100%', height: '100%' }} />
</div>
<Select
value={colorMode.value}
onChange={handleColorModeChange}
options={colorModes
.filter(item => alpha.value || item === 'HEX' || item === 'RGB')
.map(item => ({ value: item, key: item }))}
size="small"
bordered={false}
dropdownMatchSelectWidth={false}
/>
</div>
{colorMode.value === 'HEX' && (
<HexColorInput
value={tinycolor(color.value).toHex()}
onChange={v => props.onChange(tinycolor(v).toHexString())}
/>
)}
{colorMode.value === 'HEX8' && (
<HexColorInput
alpha
value={tinycolor(color.value).toHex8()}
onChange={v => props.onChange(tinycolor(v).toHex8String())}
/>
)}
{(colorMode.value === 'RGBA' || colorMode.value === 'RGB') && (
<RgbColorInput
alpha={colorMode.value === 'RGBA'}
value={tinycolor(color.value).toRgb()}
onChange={v => props.onChange(tinycolor(v).toRgbString())}
/>
)}
</div>
<div class="color-panel-preset-colors">
{presetColors.value.map(presetColor => (
<button
key={presetColor}
class="color-panel-preset-color-btn"
style={{ backgroundColor: presetColor }}
onClick={() => props.onChange(presetColor)}
/>
))}
</div>
</div>,
);
};
},
});
export default ColorPanel;

View File

@ -1,80 +0,0 @@
import { defineComponent, toRefs } from 'vue';
import type { CSSProperties } from 'vue';
import classNames from 'ant-design-vue/es/_util/classNames';
import makeStyle from './utils/makeStyle';
import getColorBgImg from './utils/getColorBgImg';
export type ColorPreviewProps = {
color: string;
dark?: boolean;
};
const useStyle = makeStyle('ColorPreview', () => ({
'.previewer-color-preview': {
width: '20px',
height: '20px',
position: 'relative',
borderRadius: '50%',
padding: 0,
display: 'inline-block',
'&::before': {
content: '""',
width: '100%',
height: '100%',
borderRadius: '50%',
top: 0,
insetInlineStart: 0,
position: 'absolute',
zIndex: 2,
backgroundColor: 'var(--antd-token-previewer-color-preview)',
boxShadow: '0 2px 3px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.09)',
},
},
}));
const ColorPreview = defineComponent({
name: 'ColorPreview',
inheritAttrs: false,
props: {
color: { type: String },
dark: { type: Boolean },
},
setup(props, { attrs }) {
const { color, dark } = toRefs(props);
const [warpSSR, hashId] = useStyle();
return () => {
return warpSSR(
<div
{...attrs}
class={classNames('previewer-color-preview', attrs.class, hashId.value)}
style={[
{
// @ts-ignore
['--antd-token-previewer-color-preview']: color.value,
...(attrs.style as CSSProperties),
},
]}
>
<div
style={{
content: '""',
width: '18px',
height: '18px',
borderRadius: '50%',
top: '1px',
insetInlineStart: '1px',
position: 'absolute',
zIndex: 1,
background: `${getColorBgImg(dark.value)} 0% 0% / 20px`,
}}
/>
</div>,
);
};
},
});
export default ColorPreview;

View File

@ -1,133 +0,0 @@
import type { CSSProperties, PropType } from 'vue';
import { defineComponent, toRefs, ref } from 'vue';
import makeStyle from './utils/makeStyle';
import classNames from 'ant-design-vue/es/_util/classNames';
import { Segmented, Tag } from 'ant-design-vue';
const useStyle = makeStyle('FilterPanel', token => ({
'.previewer-filter-panel': {
// boxShadow:
// '0 2px 4px 0 rgba(0,0,0,0.05), 0 1px 2px 0 rgba(25,15,15,0.07), 0 0 1px 0 rgba(0,0,0,0.08)',
// backgroundColor: '#fff',
// borderRadius: 6,
// padding: '8px 12px',
overflow: 'hidden',
display: 'flex',
alignItems: 'start',
'.component-tree-head': {
display: 'flex',
alignItems: 'center',
flex: 'none',
marginInlineEnd: 20,
'.component-tree-filter-type': {
color: token.colorTextSecondary,
marginInlineEnd: token.marginXS,
fontSize: token.fontSizeSM,
},
'.component-tree-filter-segmented': {
fontSize: token.fontSizeSM,
},
},
'.preview-panel-subtitle': {
fontSize: token.fontSizeSM,
color: token.colorTextSecondary,
},
[`${token.rootCls}-tag.previewer-token-filter-tag`]: {
color: token.colorPrimary,
backgroundColor: 'rgba(22,119,255,0.10)',
border: 'none',
borderRadius: 4,
'> .anticon': {
color: token.colorPrimary,
},
},
},
}));
export type FilterMode = 'highlight' | 'filter';
export type FilterPanelProps = {
filterMode?: FilterMode;
onFilterModeChange?: (mode: FilterMode) => void;
selectedTokens: string[];
onSelectedTokensChange?: (newTokens: string[]) => void;
onTokenClick?: (token: string) => void;
className?: string;
style?: CSSProperties;
};
const FilterPanel = defineComponent({
name: 'FilterPanel',
inheritAttrs: false,
props: {
filterMode: { type: String as PropType<FilterMode> },
onFilterModeChange: { type: Function as PropType<(mode: FilterMode) => void> },
selectedTokens: { type: Array as PropType<string[]> },
onSelectedTokensChange: { type: Function as PropType<(newTokens: string[]) => void> },
onTokenClick: { type: Function as PropType<(token: string) => void> },
},
setup(props, { attrs }) {
const { filterMode: customFilterMode, selectedTokens } = toRefs(props);
const [wrapSSR, hashId] = useStyle();
const filterMode = ref<FilterMode>(customFilterMode.value || 'filter');
return () => {
if (selectedTokens.value.length === 0) {
return null;
}
return wrapSSR(
<div {...attrs} class={classNames('previewer-filter-panel', hashId.value, attrs.class)}>
{selectedTokens.value && selectedTokens.value.length > 0 && (
<>
<div class="component-tree-head">
<div class="component-tree-filter-type">筛选方式</div>
<Segmented
class="component-tree-filter-segmented"
size="small"
value={filterMode.value}
onChange={value => {
props.onFilterModeChange?.(value as any);
filterMode.value = value as any;
}}
options={[
{ label: '过滤', value: 'filter' },
{ label: '高亮', value: 'highlight' },
]}
/>
</div>
<div>
<span class="preview-panel-subtitle">已选中</span>
{selectedTokens.value.map(token => (
<Tag
key={token}
closable
onClose={() =>
props.onSelectedTokensChange?.(
selectedTokens.value?.filter(item => item !== token),
)
}
style={{ marginBlock: '2px', cursor: 'pointer' }}
class="previewer-token-filter-tag"
onClick={() => props.onTokenClick?.(token)}
>
{token}
</Tag>
))}
</div>
</>
)}
</div>,
);
};
},
});
export default FilterPanel;

View File

@ -1,102 +0,0 @@
import classNames from 'ant-design-vue/es/_util/classNames';
import makeStyle from './utils/makeStyle';
import type { PropType } from 'vue';
import { defineComponent, toRefs } from 'vue';
const useStyle = makeStyle('IconSwitch', () => {
const activeBackground = '#314659';
return {
'.theme-editor-icon-switch': {
display: 'inline-block',
'.holder': {
position: 'relative',
display: 'inline-flex',
background: '#ebedf0',
borderRadius: '100vw',
cursor: 'pointer',
transition: 'all 0.3s',
'&::before': {
position: 'absolute',
top: 0,
left: 'calc(100% - 32px)',
width: 32,
height: 32,
background: activeBackground,
borderRadius: '100vw',
transition: 'all 0.3s',
content: '""',
},
'&.leftChecked::before': {
left: 0,
},
'&:hover': {
boxShadow: '0 0 3px fade(@active-background, 40%)',
},
},
'.icon': {
position: 'relative',
width: 32,
height: 32,
color: '#a3b1bf',
lineHeight: '32px',
textAlign: 'center',
transition: 'all 0.3s',
fontSize: 16,
'.anticon': {
fontSize: 14,
},
'&:first-child': {
marginInlineEnd: -4,
},
'&.active': {
color: '#fff',
},
},
},
};
});
export interface IconSwitchProps {
leftChecked?: boolean;
onChange?: (leftChecked: boolean) => void;
}
const IconSwitch = defineComponent({
name: 'IconSwitch',
props: {
leftChecked: { type: Boolean },
onChange: { type: Function as PropType<(leftChecked: boolean) => void> },
},
setup(props, { attrs, slots }) {
const { leftChecked } = toRefs(props);
const [wrapSSR, hashId] = useStyle();
return () => {
return wrapSSR(
<div {...attrs} class={classNames('theme-editor-icon-switch', attrs.class, hashId.value)}>
<div
class={classNames('holder', leftChecked.value && 'leftChecked')}
onClick={() => {
props.onChange(!leftChecked.value);
}}
>
<span class={classNames('icon', leftChecked.value && 'active')}>
{slots.leftIcon && slots.leftIcon()}
</span>
<span class={classNames('icon', !leftChecked.value && 'active')}>
{slots.rightIcon && slots.rightIcon()}
</span>
</div>
</div>,
);
};
},
});
export default IconSwitch;

View File

@ -1,35 +0,0 @@
import type { CSSProperties, PropType } from 'vue';
import { defineComponent, toRefs } from 'vue';
import { antdComponents } from './component-panel';
import type { Theme } from './interface';
import ComponentDemoPro from './token-panel-pro/ComponentDemoPro';
export type PreviewDemoProps = {
theme: Theme;
};
const PreviewDemo = defineComponent({
name: 'PreviewDemo',
props: {
theme: { type: Object as PropType<Theme> },
},
setup(props, { attrs }) {
const { theme } = toRefs(props);
return () => {
return (
<div {...attrs} style={{ ...(attrs.style as CSSProperties), overflow: 'auto' }}>
<ComponentDemoPro
theme={theme.value}
components={antdComponents}
componentDrawer={false}
showAll
style={{ minHeight: '100%' }}
/>
</div>
);
};
},
});
export default PreviewDemo;

View File

@ -1,168 +0,0 @@
import type { PropType } from 'vue';
import { defineComponent, toRefs, ref, computed } from 'vue';
import type { DerivativeFunc } from 'ant-design-vue/es/_util/cssinjs';
import classNames from 'ant-design-vue/es/_util/classNames';
import type { SelectedToken, Theme } from './interface';
import type { Locale } from './locale';
import { useProvideLocaleContext, zhCN } from './locale';
import { mapRelatedAlias, seedRelatedAlias, seedRelatedMap } from './meta/TokenRelation';
import { getRelatedComponents } from './utils/statistic';
import makeStyle from './utils/makeStyle';
import useControlledTheme from './hooks/useControlledTheme';
import type { TokenPanelProProps } from './token-panel-pro';
import TokenPanelPro from './token-panel-pro';
import ComponentDemoPro from './token-panel-pro/ComponentDemoPro';
import { antdComponents } from './component-panel';
const useStyle = makeStyle('ThemeEditor', token => ({
'.antd-theme-editor': {
backgroundColor: token.colorBgLayout,
display: 'flex',
},
}));
const defaultTheme: Theme = {
name: '默认主题',
key: 'default',
config: {},
};
export type ThemeEditorProps = {
/**
* @deprecated
* @default true
*/
simple?: boolean;
theme?: Theme;
onThemeChange?: (theme: Theme) => void;
darkAlgorithm?: DerivativeFunc<any, any>;
locale?: Locale;
};
const ThemeEditor = defineComponent({
name: 'ThemeEditor',
inheritAttrs: false,
props: {
simple: { type: Boolean },
theme: { type: Object as PropType<Theme> },
onThemeChange: { type: Function as PropType<(theme: Theme) => void> },
darkAlgorithm: { type: Function as PropType<DerivativeFunc<any, any>> },
locale: { type: Object as PropType<Locale>, default: zhCN },
},
setup(props, { attrs, expose }) {
const { theme: customTheme, darkAlgorithm, locale } = toRefs(props);
const [wrapSSR, hashId] = useStyle();
const selectedTokens = ref<SelectedToken>({
seed: ['colorPrimary'],
});
const aliasOpen = ref<boolean>(false);
const { theme, infoFollowPrimary, onInfoFollowPrimaryChange, updateRef } = useControlledTheme({
theme: customTheme,
defaultTheme,
onChange: props.onThemeChange,
darkAlgorithm,
});
const handleTokenSelect: TokenPanelProProps['onTokenSelect'] = (token, type) => {
const tokens = typeof token === 'string' ? (token ? [token] : []) : token;
if (type === 'seed') {
return {
seed: tokens,
};
}
let newSelectedTokens = { ...selectedTokens.value };
tokens.forEach(newToken => {
newSelectedTokens = {
...selectedTokens.value,
[type]: selectedTokens.value[type]?.includes(newToken)
? selectedTokens.value[type]?.filter(t => t !== newToken)
: [...(selectedTokens.value[type] ?? []), newToken],
};
});
if (type === 'map') {
delete newSelectedTokens.alias;
}
selectedTokens.value = newSelectedTokens;
};
const computedSelectedTokens = computed(() => {
if (
selectedTokens.value.seed?.length &&
!selectedTokens.value.map?.length &&
!selectedTokens.value.alias?.length
) {
return [
...selectedTokens.value.seed,
...((seedRelatedMap as any)[selectedTokens.value.seed[0]] ?? []),
...((seedRelatedAlias as any)[selectedTokens.value.seed[0]] ?? []),
];
}
if (selectedTokens.value.map?.length && !selectedTokens.value.alias?.length) {
return [
...selectedTokens.value.map,
...selectedTokens.value.map.reduce((result, item) => {
return result.concat((mapRelatedAlias as any)[item]);
}, []),
];
}
if (selectedTokens.value.alias?.length) {
return [...selectedTokens.value.alias];
}
return [];
});
const relatedComponents = computed(() => {
return computedSelectedTokens.value ? getRelatedComponents(computedSelectedTokens.value) : [];
});
expose({
updateRef,
});
useProvideLocaleContext(locale);
return () => {
return wrapSSR(
<div {...attrs} class={classNames(hashId.value, 'antd-theme-editor', attrs.class)}>
<div
style={{
flex: aliasOpen.value ? '0 0 860px' : `0 0 ${860 - 320}px`,
height: '100%',
backgroundColor: '#F7F8FA',
backgroundImage: 'linear-gradient(180deg, #FFFFFF 0%, rgba(246,247,249,0.00) 100%)',
display: 'flex',
transition: 'all 0.3s',
}}
>
<TokenPanelPro
aliasOpen={aliasOpen.value}
onAliasOpenChange={open => (aliasOpen.value = open)}
theme={theme.value}
style={{ flex: 1 }}
selectedTokens={selectedTokens.value}
onTokenSelect={handleTokenSelect}
infoFollowPrimary={infoFollowPrimary.value}
onInfoFollowPrimaryChange={onInfoFollowPrimaryChange}
/>
</div>
<ComponentDemoPro
theme={theme.value}
components={antdComponents}
activeComponents={relatedComponents.value}
selectedTokens={computedSelectedTokens.value}
style={{ flex: 1, overflow: 'auto' }}
componentDrawer
/>
</div>,
);
};
},
});
export default ThemeEditor;

View File

@ -1,240 +0,0 @@
import type { PropType } from 'vue';
import { defineComponent, toRefs, computed } from 'vue';
import makeStyle from './utils/makeStyle';
import classNames from 'ant-design-vue/es/_util/classNames';
import { Button, Dropdown, Menu } from 'ant-design-vue';
import { CloseOutlined, PlusOutlined } from '@ant-design/icons-vue';
import type { Theme } from './interface';
interface ThemeItem extends Theme {
icon?: any;
closable?: boolean;
fixed?: boolean;
}
export type ThemeSelectProps = {
onEnabledThemeChange: (themes: string[]) => void;
onShownThemeChange: (
themes: string[],
selectTheme: string,
info: { type: 'select' | 'deselect' },
) => void;
enabledThemes: string[];
shownThemes: string[];
themes: ThemeItem[];
showAddTheme?: boolean;
};
const useStyle = makeStyle('ThemeSelect', token => ({
'.previewer-theme-select': {
padding: `${token.paddingXXS}px ${token.paddingXS}px`,
borderRadius: 4,
backgroundColor: 'rgba(0, 0, 0, 0.02)',
height: token.controlHeight,
display: 'flex',
alignItems: 'center',
overflow: 'hidden',
[`${token.rootCls}-btn.previewer-theme-select-add-btn`]: {
minWidth: 0,
width: 16,
height: 16,
fontSize: 8,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
marginInlineStart: token.marginSM,
boxShadow: 'none',
},
'.previewer-theme-select-tag': {
height: 22,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
boxSizing: 'border-box',
borderRadius: 4,
backgroundColor: token.colorBgContainer,
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
paddingInline: 10,
fontSize: token.fontSizeSM,
position: 'relative',
cursor: 'pointer',
// transition: `all ${token.motionDurationMid}`,
'&:not(:last-child)': {
marginInlineEnd: token.marginXS,
},
'&.previewer-theme-select-tag-active': {
border: `${token.lineWidth}px ${token.lineType} ${token['blue-1']}`,
backgroundColor: 'rgba(22,119,255,0.10)',
color: token.colorPrimary,
'&::after': {
content: '""',
borderStartEndRadius: 2,
position: 'absolute',
insetInlineEnd: 2,
top: 2,
width: 6,
height: 6,
background: `linear-gradient(to right top, transparent, transparent 50%, ${token.colorPrimary} 50%, ${token.colorPrimary} 100%)`,
},
},
'.previewer-theme-select-tag-close-btn': {
position: 'absolute',
top: -2,
insetInlineEnd: -2,
width: 12,
height: 12,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: token.colorBgContainer,
boxShadow:
'0 2px 8px -2px rgba(0,0,0,0.05), 0 1px 4px -1px rgba(25,15,15,0.07), 0 0 1px 0 rgba(0,0,0,0.08)',
borderRadius: '50%',
opacity: 0,
pointerEvents: 'none',
zIndex: 2,
color: token.colorIcon,
'> .anticon': {
fontSize: 6,
},
},
'&:hover': {
'.previewer-theme-select-tag-close-btn': {
opacity: 1,
pointerEvents: 'initial',
},
},
},
},
'.previewer-theme-select-dropdown': {
'.previewer-theme-select-dropdown-title': {
[`${token.rootCls}-dropdown-menu-item-group-title`]: {
fontSize: token.fontSizeSM,
paddingBottom: token.padding,
paddingTop: 10,
},
},
},
}));
const ThemeSelect = defineComponent({
name: 'ThemeSelect',
inheritAttrs: false,
props: {
onEnabledThemeChange: { type: Function as PropType<(themes: string[]) => void> },
onShownThemeChange: {
type: Function as PropType<
(themes: string[], selectTheme: string, info: { type: 'select' | 'deselect' }) => void
>,
},
enabledThemes: { type: Array as PropType<string[]> },
shownThemes: { type: Array as PropType<string[]> },
themes: { type: Array as PropType<ThemeItem[]> },
showAddTheme: { type: Boolean },
},
setup(props, { attrs }) {
const { enabledThemes, shownThemes, themes, showAddTheme } = toRefs(props);
const [wrapSSR, hashId] = useStyle();
const dropdownItems = computed(() => [
{
disabled: true,
label: '添加主题即可预览',
className: 'previewer-theme-select-dropdown-title',
type: 'group',
key: 'add-theme-to-preview',
},
...themes.value
.filter(theme => !shownThemes.value.includes(theme.key))
.map(theme => ({
icon: theme.icon,
value: theme.key,
label: theme.name,
key: theme.key,
onClick: () => {
props.onShownThemeChange([...shownThemes.value, theme.key], theme.key, {
type: 'select',
});
},
})),
]);
const shownThemeEntities = computed(() =>
themes.value.filter(theme => shownThemes.value.includes(theme.key)),
);
return () => {
return wrapSSR(
<div {...attrs} class={classNames('previewer-theme-select', hashId.value, attrs.class)}>
{shownThemeEntities.value.map(theme => (
<span
onClick={() => {
if (theme.fixed) {
return;
}
props.onEnabledThemeChange(
enabledThemes.value.includes(theme.key)
? enabledThemes.value.filter(item => item !== theme.key)
: [...enabledThemes.value, theme.key],
);
}}
key={theme.key}
class={classNames('previewer-theme-select-tag', {
'previewer-theme-select-tag-active': enabledThemes.value.includes(theme.key),
})}
>
{theme.name}
{theme.closable && (
<span
class="previewer-theme-select-tag-close-btn"
onClick={e => {
e.stopPropagation();
props.onEnabledThemeChange(
enabledThemes.value.filter(item => item !== theme.key),
);
props.onShownThemeChange(
shownThemes.value.filter(item => item !== theme.key),
theme.key,
{ type: 'deselect' },
);
}}
>
<CloseOutlined />
</span>
)}
</span>
))}
{showAddTheme.value && (
<Dropdown
placement="bottomRight"
trigger={['click']}
overlayClassName={classNames('previewer-theme-select-dropdown', hashId.value)}
v-slots={{
overlay: () => <Menu items={dropdownItems.value} />,
}}
>
<Button
type="primary"
shape="circle"
class="previewer-theme-select-add-btn"
icon={<PlusOutlined />}
/>
</Dropdown>
)}
</div>,
);
};
},
});
export default ThemeSelect;

View File

@ -1,250 +0,0 @@
import { Button, Popover, Input, InputNumber } from 'ant-design-vue';
import classNames from 'ant-design-vue/es/_util/classNames';
import type { PropType } from 'vue';
import { defineComponent, toRefs, computed, ref, watch } from 'vue';
import { debounce } from 'lodash';
import ColorPanel from './ColorPanel';
import ColorPreview from './ColorPreview';
import type { MutableTheme } from './interface';
import { useInjectLocaleContext } from './locale';
import isColor from './utils/isColor';
import makeStyle from './utils/makeStyle';
const useStyle = makeStyle('TokenInput', token => ({
'.previewer-token-input': {
[`${token.rootCls}-input-group-addon, ${token.rootCls}-input-number-group-addon`]: {
border: '0 !important',
color: `rgba(0, 0, 0, 0.25) !important`,
fontSize: `${token.fontSizeSM}px !important`,
padding: '0 !important',
backgroundColor: 'transparent !important',
'&:first-child': {
paddingInlineStart: 0,
},
'&:last-child': {
paddingInlineEnd: 0,
},
},
[`${token.rootCls}-input-group-wrapper, ${token.rootCls}-input-number-group-wrapper`]: {
padding: 0,
height: 24,
width: '100%',
input: {
fontSize: token.fontSizeSM,
lineHeight: token.lineHeightSM,
padding: `2px ${token.paddingXS}px`,
height: 24,
},
},
[`${token.rootCls}-input-group-wrapper ${token.rootCls}-input, ${token.rootCls}-input-number-group-wrapper ${token.rootCls}-input-number`]:
{
background: 'white',
borderRadius: `${token.borderRadiusLG}px !important`,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
'&&-light': {
[`${token.rootCls}-input-group-addon, ${token.rootCls}-input-number-group-addon`]: {
backgroundColor: token.colorBgContainer,
},
[`${token.rootCls}-input-group-wrapper ${token.rootCls}-input,
${token.rootCls}-input-number-group-wrapper ${token.rootCls}-input-number-input`]: {
background: token.colorFillAlter,
},
},
'&&-readonly': {
input: {
cursor: 'text',
color: token.colorText,
},
},
},
}));
export type TokenInputProps = {
theme?: MutableTheme;
value?: string | number;
onChange?: (value: string | number) => void;
light?: boolean;
readonly?: boolean;
onReset?: () => void;
canReset?: boolean;
hideTheme?: boolean;
};
const TokenInput = defineComponent({
name: 'TokenInput',
inheritAttrs: false,
props: {
theme: { type: Object as PropType<MutableTheme> },
value: { type: [String, Number] },
onChange: { type: Function as PropType<(value: string | number) => void> },
light: { type: Boolean },
readonly: { type: Boolean },
onReset: { type: Function as PropType<() => void> },
canReset: { type: Boolean },
hideTheme: { type: Boolean },
},
setup(props, { attrs }) {
const { value, theme, light, readonly, canReset: customCanReset, hideTheme } = toRefs(props);
const valueRef = ref<number | string>(value.value || '');
const tokenValue = ref<string | number>(value.value || '');
const canReset = computed(() => customCanReset.value ?? valueRef.value !== tokenValue.value);
const locale = useInjectLocaleContext();
const [wrapSSR, hashId] = useStyle();
watch(
value,
val => {
if (val !== undefined) {
tokenValue.value = val;
}
},
{ immediate: true },
);
const debouncedOnChange = debounce((newValue: number | string) => {
props.onChange?.(newValue);
}, 500);
const handleTokenChange = (newValue: number | string) => {
if (!readonly.value) {
tokenValue.value = newValue;
debouncedOnChange(newValue);
}
};
const handleReset = () => {
if (props.onReset) {
props.onReset();
} else {
handleTokenChange(valueRef.value);
}
};
return () => {
const addonAfter = !readonly.value && (
<span
style={{
display: 'flex',
alignItems: 'center',
minWidth: hideTheme.value ? '' : '80px',
}}
>
{canReset.value || hideTheme.value ? (
<Button
style={{
fontSize: '12px',
}}
onClick={handleReset}
type="link"
size="small"
disabled={!canReset.value}
>
{locale.value.reset}
</Button>
) : (
<span style={{ padding: '0 8px' }}>{theme.value?.name}</span>
)}
</span>
);
let inputNode;
if (typeof valueRef.value === 'string' && isColor(valueRef.value)) {
inputNode = (
<Input
bordered={false}
addonAfter={addonAfter}
value={String(tokenValue.value)}
disabled={readonly.value}
addonBefore={
<Popover
trigger="click"
placement="bottomRight"
arrow-point-at-center
overlayInnerStyle={{ padding: 0 }}
v-slots={{
content: () => (
<ColorPanel
alpha
color={String(tokenValue.value)}
style={{ border: 'none' }}
onChange={(v: string) => {
handleTokenChange(v);
}}
/>
),
}}
>
<ColorPreview
color={String(tokenValue.value)}
dark={theme.value?.key === 'dark'}
style={{
cursor: 'pointer',
marginInlineEnd: '8px',
verticalAlign: 'top',
}}
/>
</Popover>
}
onChange={e => {
handleTokenChange(e.target.value);
}}
/>
);
} else if (typeof valueRef.value === 'number') {
inputNode = (
<InputNumber
addonAfter={addonAfter}
bordered={false}
value={tokenValue.value}
disabled={readonly.value}
onChange={newValue => {
handleTokenChange(Number(newValue));
}}
/>
);
} else {
inputNode = (
<Input
addonAfter={addonAfter}
bordered={false}
value={String(tokenValue.value)}
disabled={readonly.value}
onChange={e => {
handleTokenChange(
typeof value.value === 'number' ? Number(e.target.value) : e.target.value,
);
}}
/>
);
}
return wrapSSR(
<div
{...attrs}
class={classNames('previewer-token-input', hashId.value, attrs.class, {
'previewer-token-input-light': light.value,
'previewer-token-input-readonly': readonly.value,
})}
>
{inputNode}
</div>,
);
};
},
});
export default TokenInput;

View File

@ -1,24 +0,0 @@
import { defineComponent } from 'vue';
import { Alert, Space } from 'ant-design-vue';
import type { ComponentDemo } from '../../interface';
const Demo = defineComponent({
setup() {
return () => (
<Space direction={'vertical'}>
<Alert message="Success Tips" type="success" showIcon />
<Alert message="Informational Notes" type="info" showIcon />
<Alert message="Warning" type="warning" showIcon closable />
<Alert message="Error" type="error" showIcon />
</Space>
);
},
});
const componentDemo: ComponentDemo = {
demo: <Demo />,
tokens: ['colorIconHover', 'colorIcon', 'colorText'],
key: 'alert',
};
export default componentDemo;

View File

@ -1,28 +0,0 @@
import { defineComponent } from 'vue';
import { Alert, Space } from 'ant-design-vue';
import type { ComponentDemo } from '../../interface';
const Demo = defineComponent({
setup() {
return () => (
<Space direction={'vertical'}>
<Alert message="Error" type="error" showIcon />
<Alert
message="Error"
description="This is an error message about copywriting."
type="error"
showIcon
/>
</Space>
);
},
});
const componentDemo: ComponentDemo = {
demo: <Demo />,
tokens: ['colorErrorBg', 'colorErrorBorder', 'colorError'],
key: 'error',
};
export default componentDemo;

Some files were not shown because too many files have changed in this diff Show More