Compare commits
17 Commits
feat/vapor
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
2cda7bde09 | |
|
|
6255f1632c | |
|
|
ef51f7f1cc | |
|
|
252a0e2563 | |
|
|
bbb7670df1 | |
|
|
fcdda4a0be | |
|
|
79b63b41c6 | |
|
|
56d9b358f2 | |
|
|
b58e73d51a | |
|
|
e8ec520d9a | |
|
|
ce56f0c8f6 | |
|
|
723bb47a42 | |
|
|
57ea8a65d4 | |
|
|
7e5008080d | |
|
|
74b3018945 | |
|
|
28b1c4f62d | |
|
|
04f6ba33c7 |
|
|
@ -0,0 +1,36 @@
|
|||
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,
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
codecov:
|
||||
branch: master
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# 🎨 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
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
node_modules/
|
||||
**/*.spec.*
|
||||
**/style/
|
||||
*.html
|
||||
/components/test/*
|
||||
es/
|
||||
lib/
|
||||
_site/
|
||||
dist/
|
||||
site/dist/
|
||||
components/version/version.ts
|
||||
site/src/router/demoRoutes.js
|
||||
locale/
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
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',
|
||||
},
|
||||
};
|
||||
|
|
@ -12,6 +12,3 @@ contact_links:
|
|||
- name: Paypal
|
||||
url: https://www.paypal.me/tangjinzhou
|
||||
about: Love Ant Design Vue? Please consider supporting us via Paypal.
|
||||
- name: 支付宝/微信 赞助
|
||||
url: https://aliyuncdn.antdv.com/alipay-and-wechat.png
|
||||
about: Ant Design Vue 的健康持续发展需要您的支持,🙏
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
name: Build and Deploy to Cloudflare
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build Application
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --force
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-files
|
||||
path: site/dist/
|
||||
retention-days: 1
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
name: Deploy to Cloudflare
|
||||
needs: build
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
steps:
|
||||
- name: Checkout (for config files)
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
wrangler.jsonc
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-files
|
||||
path: site/dist/
|
||||
|
||||
- name: Deploy (Workers + Static Assets)
|
||||
uses: cloudflare/wrangler-action@v3.14.1
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: deploy --config wrangler.jsonc
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
- name: cache node_modules
|
||||
id: node_modules_cache_id
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
|
@ -52,13 +52,13 @@ jobs:
|
|||
# submodules: true
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: restore cache from node_modules
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
- name: cache node_modules
|
||||
id: node_modules_cache_id
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
|
@ -43,25 +43,25 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: restore cache from node_modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
||||
- name: cache lib
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: lib
|
||||
key: lib-${{ github.sha }}
|
||||
|
||||
- name: cache es
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: es
|
||||
key: es-${{ github.sha }}
|
||||
|
|
@ -77,13 +77,13 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: restore cache from node_modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
|
@ -99,13 +99,13 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: restore cache from node_modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ package-lock.json
|
|||
pnpm-lock.yaml
|
||||
/coverage
|
||||
|
||||
# 备份文件
|
||||
/components/test/*
|
||||
list.txt
|
||||
|
||||
site/dev.js
|
||||
|
||||
|
|
@ -74,39 +77,10 @@ vetur/
|
|||
|
||||
report.html
|
||||
|
||||
site/src/router/demoRoutes.js
|
||||
|
||||
|
||||
# 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/
|
||||
components/version/version.ts
|
||||
components/version/version.tsx
|
||||
components/version/token.json
|
||||
components/version/token-meta.json
|
||||
~component-api.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install pretty-quick --staged
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged",
|
||||
"pre-publish": "npm run lint",
|
||||
"commit-msg": "commitlint -x @commitlint/config-conventional -e $GIT_PARAMS"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
**/*.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/
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 100,
|
||||
"proseWrap": "never",
|
||||
"arrowParens": "avoid",
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ".prettierrc",
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
|
|
@ -1,9 +1,3 @@
|
|||
<p align="center">
|
||||
<a href="https://www.antdv.com/">
|
||||
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://www.antdv.com/" target="_blank">Ant Design Vue</a>
|
||||
</h1>
|
||||
|
|
@ -18,6 +12,14 @@
|
|||
|
||||
[](https://www.antdv.com/)
|
||||
|
||||
<div align="center">
|
||||
<sup><strong>赞助商</strong></sup>
|
||||
<br>
|
||||
<a href="https://mentorbook.ai/" target="_blank">
|
||||
<img src="/site/public/mentorbook_banner_zh.svg" alt="Mentorbook.AI - 你的 AI 导师,你的学习之旅" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
## 特性
|
||||
|
|
@ -88,14 +90,13 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
|
|||
- [Patreon](https://www.patreon.com/tangjinzhou)
|
||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||
|
||||
## 赞助商
|
||||
|
||||
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://www.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
|
||||
## 支持者
|
||||
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.antdv.com/">
|
||||
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
<img width="200" src="https://www.antdv.com/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
|
@ -18,6 +18,14 @@ An enterprise-class UI components based on Ant Design and Vue.
|
|||
|
||||
[](https://www.antdv.com/)
|
||||
|
||||
<div align="center">
|
||||
<sup><strong>Sponsored by</strong></sup>
|
||||
<br>
|
||||
<a href="https://mentorbook.ai/" target="_blank">
|
||||
<img src="/site/public/mentorbook_banner_en.svg" alt="Mentorbook.AI - Your AI Mentor, Your Learning Journey" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
English | [简体中文](./README-zh_CN.md)
|
||||
|
||||
## Features
|
||||
|
|
@ -82,14 +90,13 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
|
|||
- [Patreon](https://www.patreon.com/tangjinzhou)
|
||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||
|
||||
## Sponsors
|
||||
|
||||
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://www.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
|
||||
## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
@import '@ant-design-vue/tailwind-config';
|
||||
@source '../index.html';
|
||||
@source '../src/**/*.{vue,ts}';
|
||||
* {
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
export { default } from '@ant-design-vue/eslint-config/vue'
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<!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>
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"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/ui": "*",
|
||||
"@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",
|
||||
"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/typescript-config": "*",
|
||||
"@ant-design-vue/vite-config": "*",
|
||||
"@ant-design-vue/tailwind-config": "*",
|
||||
"@tailwindcss/vite": "^4.1.3",
|
||||
"@types/cookies": "^0.9.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
export { default } from "@ant-design-vue/prettier-config/tailwind";
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<template>
|
||||
<button @click="toggleTheme" class="fixed top-2 right-2">toggle {{ appearance }}</button>
|
||||
<a-theme :appearance="appearance">
|
||||
<RouterView />
|
||||
</a-theme>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const appearance = ref('light')
|
||||
|
||||
const toggleTheme = () => {
|
||||
appearance.value = appearance.value === 'light' ? 'dark' : 'light'
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<div class="flex h-screen" :class="pageClass">
|
||||
<TheNavbar v-if="!hideNavbar" :items="navs"></TheNavbar>
|
||||
<div class="flex-1 justify-center px-4 py-16" :class="contentClass">
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { provideLayoutOptions } from '@/composables/layout'
|
||||
import { computed, ref } from 'vue'
|
||||
import TheNavbar from './TheNavbar.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
navs: { name: string; path: string }[]
|
||||
hideNavbar?: boolean
|
||||
hideBreadcrumbs?: boolean
|
||||
}>()
|
||||
|
||||
const pageClass = ref<string>()
|
||||
const contentClass = ref<string>()
|
||||
|
||||
provideLayoutOptions({
|
||||
pageClass,
|
||||
contentClass,
|
||||
hideNavbar: computed(() => props.hideNavbar),
|
||||
hideBreadcrumbs: computed(() => props.hideBreadcrumbs),
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<template>
|
||||
<div class="flex flex-wrap gap-8 px-8">
|
||||
<RouterLink v-for="item in items" :key="item.path" :to="item.path">
|
||||
<div
|
||||
class="shadow-xs relative flex w-72 flex-col rounded-lg bg-primary capitalize text-primary-content transition-all hover:scale-105 hover:shadow-xl"
|
||||
>
|
||||
<div className="flex-col gap-2 flex flex-auto p-4 text-sm items-center text-center">
|
||||
<h2 className="font-semibold flex items-center gap-2 text-xl mb-1">
|
||||
{{ item.name }}
|
||||
</h2>
|
||||
<div className="flex flex-wrap items-start gap-2 justify-end">
|
||||
<ArrowRightIcon class="size-5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ArrowRightIcon } from '@heroicons/vue/20/solid'
|
||||
|
||||
defineProps<{
|
||||
items: { name: string; path: string }[]
|
||||
}>()
|
||||
</script>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<div class="max-w-full select-none overflow-x-auto px-4 py-2 text-sm">
|
||||
<ul class="flex min-h-min items-center whitespace-nowrap capitalize">
|
||||
<template v-for="(item, i) in items" :key="item.path">
|
||||
<li class="flex items-center">
|
||||
<template v-if="i > 0">
|
||||
<span
|
||||
class="ml-2 mr-3 block size-1.5 rotate-45 transform border-r-[1px] border-t-[1px] border-base-content/70 bg-transparent"
|
||||
></span>
|
||||
</template>
|
||||
<template v-if="item.path !== route.path">
|
||||
<RouterLink class="flex items-center hover:underline" :to="item.path">
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-base-content/70">{{ item.name }}</span>
|
||||
</template>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
defineProps<{ items: { name: string; path: string }[] }>()
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<template>
|
||||
<div class="bg-base-100/90 text-base-content border-base-content/10 border-r">
|
||||
<div class="flex min-h-16 w-full items-center p-2">
|
||||
<div class="justify-start">
|
||||
<div class="group relative inline-block">
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="bg-base-100 z-[1] mt-3 flex w-52 origin-top scale-95 flex-col flex-wrap rounded-lg p-2 text-sm capitalize"
|
||||
>
|
||||
<li v-for="item in items" :key="item.name">
|
||||
<RouterLink
|
||||
:aria-disabled="item.path === route.path"
|
||||
:to="item.path"
|
||||
@click.stop="$event.currentTarget.blur()"
|
||||
class="hover:bg-base-content/10 flex cursor-pointer flex-col rounded-lg px-3 py-2 transition duration-200"
|
||||
>
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
<ul v-if="item.children">
|
||||
<li v-for="child in item.children" :key="child.name">
|
||||
<RouterLink
|
||||
:to="child.path"
|
||||
@click.stop="$event.currentTarget.blur()"
|
||||
class="hover:bg-base-content/10 flex cursor-pointer flex-col rounded-lg px-3 py-2 text-xs opacity-80 transition duration-200"
|
||||
>
|
||||
{{ child.name }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
defineProps<{
|
||||
items: { name: string; path: string; children?: { name: string; path: string }[] }[]
|
||||
}>()
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { inject, InjectionKey, provide, Ref } from 'vue'
|
||||
|
||||
export interface LayoutOptions {
|
||||
pageClass: Ref<string | undefined>
|
||||
contentClass: Ref<string | undefined>
|
||||
hideNavbar: Ref<boolean>
|
||||
hideBreadcrumbs: Ref<boolean>
|
||||
}
|
||||
|
||||
const LayoutOptionsToken: InjectionKey<LayoutOptions> = Symbol()
|
||||
|
||||
export function provideLayoutOptions(options: LayoutOptions) {
|
||||
provide(LayoutOptionsToken, options)
|
||||
}
|
||||
|
||||
export function injectLayoutOptions() {
|
||||
const options = inject(LayoutOptionsToken)
|
||||
if (!options) {
|
||||
throw new Error('"injectLayoutOptions" must be called inside pages')
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import '~/tailwind.css'
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import App from './App.vue'
|
||||
import routes from './routes'
|
||||
import antd from '@ant-design-vue/ui'
|
||||
import '@ant-design-vue/ui/tailwind.css'
|
||||
import '@ant-design-vue/ui/style.css'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
createApp(App).use(router).use(antd).mount('#app')
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<template>
|
||||
<div class="flex h-[200vh] flex-col gap-2">
|
||||
<a-affix :offset-top="top" @change="onChange">
|
||||
<a-button type="primary" @click="top += 10">Affix top</a-button>
|
||||
</a-affix>
|
||||
<br />
|
||||
<a-affix :offset-bottom="bottom">
|
||||
<a-button type="primary" @click="bottom += 10">Affix bottom</a-button>
|
||||
</a-affix>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
const top = ref<number>(10)
|
||||
const bottom = ref<number>(10)
|
||||
const onChange = (lastAffix: boolean) => {
|
||||
console.log('onChange', lastAffix)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a-button variant="solid" size="lg">Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" disabled>Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" loading>Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" danger>Danger Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" danger disabled>Disabled Danger Solid Button</a-button>
|
||||
<br />
|
||||
<a-button variant="outlined" size="sm">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="md">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" disabled>Disabled Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" loading>Loading Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" danger>Danger Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" danger disabled>
|
||||
Disabled Danger Outlined Button
|
||||
</a-button>
|
||||
<br />
|
||||
<a-button variant="text" size="sm">Text Button</a-button>
|
||||
<a-button variant="text" size="md">Text Button</a-button>
|
||||
<a-button variant="text" size="lg">Text Button</a-button>
|
||||
<a-button variant="text" size="lg" disabled>Disabled Text Button</a-button>
|
||||
<a-button variant="text" size="lg" loading>Loading Text Button</a-button>
|
||||
<a-button variant="text" size="lg" danger>Danger Text Button</a-button>
|
||||
<a-button variant="text" size="lg" danger disabled>Disabled Danger Text Button</a-button>
|
||||
<br />
|
||||
<a-button variant="link" size="sm">Link Button</a-button>
|
||||
<a-button variant="link" size="md">Link Button</a-button>
|
||||
<a-button variant="link" size="lg">Link Button</a-button>
|
||||
<a-button variant="link" size="lg" disabled>Disabled Link Button</a-button>
|
||||
<a-button variant="link" size="lg" loading>Loading Link Button</a-button>
|
||||
<a-button variant="link" size="lg" danger>Danger Link Button</a-button>
|
||||
<a-button variant="link" size="lg" danger disabled>Disabled Danger Link Button</a-button>
|
||||
<br />
|
||||
<a-button variant="dashed" size="sm">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="md">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" disabled>Disabled Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" loading>Loading Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" danger>Danger Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" danger disabled>Disabled Danger Dashed Button</a-button>
|
||||
<br />
|
||||
<a-button variant="filled" size="sm">Filled Button</a-button>
|
||||
<a-button variant="filled" size="md">Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg">Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" disabled>Disabled Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" loading>Loading Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" danger>Danger Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" danger disabled>Disabled Danger Filled Button</a-button>
|
||||
|
||||
<a-button color="purple">Purple Button</a-button>
|
||||
<a-button color="blue">Blue Button</a-button>
|
||||
<a-button color="green">Green Button</a-button>
|
||||
<a-button color="red">Red Button</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<button class="btn btn-primary">Primary</button>
|
||||
<button class="btn btn-secondary">Default</button>
|
||||
<button class="btn btn-error">Danger</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-ghost">Ghost</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
<template>
|
||||
<a-flex gap="middle" vertical>
|
||||
<label>
|
||||
Select axis:
|
||||
<select v-model="axis">
|
||||
<option v-for="item in axisOptions" :key="item">{{ item }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<a-flex :vertical="axis === 'vertical'">
|
||||
<div
|
||||
v-for="(item, index) in new Array(4)"
|
||||
:key="item"
|
||||
:style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"
|
||||
/>
|
||||
</a-flex>
|
||||
<hr/>
|
||||
<label>
|
||||
Select justify:
|
||||
<select v-model="justify">
|
||||
<option v-for="item in justifyOptions" :key="item">{{ item }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Select align:
|
||||
<select v-model="align">
|
||||
<option v-for="item in alignOptions" :key="item">{{ item }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<a-flex :style="{ ...boxStyle }" :justify="justify" :align="align">
|
||||
<a-button variant="solid">Primary</a-button>
|
||||
<a-button variant="solid">Primary</a-button>
|
||||
<a-button variant="solid">Primary</a-button>
|
||||
<a-button variant="solid">Primary</a-button>
|
||||
</a-flex>
|
||||
<hr/>
|
||||
<a-flex gap="middle" vertical>
|
||||
<label>
|
||||
Select gap size:
|
||||
<select v-model="gapSize">
|
||||
<option v-for="item in gapSizeOptions" :key="item">{{ item }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<a-flex :gap="gapSize">
|
||||
<a-button variant="solid">Primary</a-button>
|
||||
<a-button>Default</a-button>
|
||||
<a-button variant="dashed">Dashed</a-button>
|
||||
<a-button variant="link">Link</a-button>
|
||||
</a-flex>
|
||||
</a-flex>
|
||||
<hr/>
|
||||
<label>
|
||||
Auto wrap:
|
||||
</label>
|
||||
<a-flex wrap="wrap" gap="small">
|
||||
<a-button v-for="item in new Array(24)" :key="item" variant="solid">Button</a-button>
|
||||
</a-flex>
|
||||
</a-flex>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { ref, reactive } from 'vue';
|
||||
|
||||
const baseStyle: CSSProperties = {
|
||||
width: '25%',
|
||||
height: '54px',
|
||||
};
|
||||
const boxStyle: CSSProperties = {
|
||||
width: '100%',
|
||||
height: '120px',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid #40a9ff',
|
||||
};
|
||||
|
||||
const axisOptions = reactive(['horizontal', 'vertical']);
|
||||
const axis = ref(axisOptions[0]);
|
||||
|
||||
const justifyOptions = reactive([
|
||||
'flex-start',
|
||||
'center',
|
||||
'flex-end',
|
||||
'space-between',
|
||||
'space-around',
|
||||
'space-evenly',
|
||||
]);
|
||||
const justify = ref(justifyOptions[0]);
|
||||
|
||||
const alignOptions = reactive(['flex-start', 'center', 'flex-end']);
|
||||
const align = ref(alignOptions[0]);
|
||||
|
||||
const gapSizeOptions = reactive(['small', 'middle', 'large']);
|
||||
const gapSize = ref(gapSizeOptions[0]);
|
||||
</script>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
import { RouteRecordRaw, RouterView } from 'vue-router'
|
||||
import BasicLayout from './components/BasicLayout.vue'
|
||||
import { Fragment, h } from 'vue'
|
||||
|
||||
// /pages/button/basic.vue
|
||||
const items = import.meta.glob('./pages/*/*.vue', { import: 'default', eager: true })
|
||||
|
||||
const categoryRoutes: Record<string, RouteRecordRaw[]> = {}
|
||||
|
||||
Object.keys(items).forEach(path => {
|
||||
const route = path.replace('./pages/', '').replace('.vue', '')
|
||||
const [category, demo] = route.split('/')
|
||||
|
||||
if (!categoryRoutes[category]) {
|
||||
categoryRoutes[category] = []
|
||||
}
|
||||
|
||||
categoryRoutes[category].push({
|
||||
path: demo,
|
||||
component: items[path],
|
||||
})
|
||||
})
|
||||
|
||||
const routes: RouteRecordRaw[] = Object.entries(categoryRoutes).map(([category, children]) => {
|
||||
const renderComponents = () =>
|
||||
h(
|
||||
'div',
|
||||
children.map(child => h(child.component)),
|
||||
)
|
||||
renderComponents.displayName = 'renderComponents'
|
||||
return {
|
||||
path: `/${category}`,
|
||||
component: RouterView,
|
||||
children: [
|
||||
...children,
|
||||
{
|
||||
path: ':demo*',
|
||||
component: renderComponents,
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const navs = Object.keys(categoryRoutes).map(category => ({
|
||||
name: category,
|
||||
path: `/${category}`,
|
||||
children: categoryRoutes[category].map(child => ({
|
||||
name: child.path,
|
||||
path: `/${category}/${child.path}`,
|
||||
})),
|
||||
}))
|
||||
routes.push({
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: h('div', 'demo not found'),
|
||||
})
|
||||
export default [
|
||||
{
|
||||
path: '/',
|
||||
component: BasicLayout,
|
||||
children: routes,
|
||||
props: {
|
||||
navs,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<Record<string, never>, Record<string, never>, any>
|
||||
export default component
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AButton: typeof import('@ant-design-vue/ui').Button
|
||||
AAffix: typeof import('@ant-design-vue/ui').Affix
|
||||
}
|
||||
}
|
||||
export {}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"extends": "@ant-design-vue/typescript-config/tsconfig.vue.json",
|
||||
"include": ["src/**/*.ts", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"~/*": ["./assets/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"extends": "@ant-design-vue/typescript-config/tsconfig.node.json",
|
||||
"include": ["vite.config.*"]
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import tailwindcss from '@tailwindcss/vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'node:path'
|
||||
import { defineConfig, Plugin } from 'vite'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue(), tailwindcss()],
|
||||
server: {
|
||||
watch: {
|
||||
ignored: ['!**/node_modules/@ant-design-vue/**'],
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src'),
|
||||
'~': resolve(__dirname, './assets'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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',
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
rm -rf dist
|
||||
mkdir dist
|
||||
./node_modules/.bin/webpack --config webpack.site.config.js
|
||||
cp dist/index.html index.html
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
export type KeyType = string | number;
|
||||
type ValueType = [number, any]; // [times, realValue]
|
||||
|
||||
const SPLIT = '%';
|
||||
|
||||
class Entity {
|
||||
instanceId: string;
|
||||
constructor(instanceId: string) {
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
|
||||
/** @private Internal cache map. Do not access this directly */
|
||||
cache = new Map<string, ValueType>();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export function createCache() {
|
|||
Array.from(styles).forEach(style => {
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = (style as any)[CSS_IN_JS_INSTANCE] || cssinjsInstanceId;
|
||||
|
||||
// Not force move if no head
|
||||
// Not force move if no head
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
|
||||
document.head.insertBefore(style, firstChild);
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
import type Cache from './Cache';
|
||||
import { extract as tokenExtractStyle, TOKEN_PREFIX } from './hooks/useCacheToken';
|
||||
import { CSS_VAR_PREFIX, extract as cssVarExtractStyle } from './hooks/useCSSVarRegister';
|
||||
import { extract as styleExtractStyle, STYLE_PREFIX } from './hooks/useStyleRegister';
|
||||
import { toStyleStr } from './util';
|
||||
import { ATTR_CACHE_MAP, serialize as serializeCacheMap } from './util/cacheMapUtil';
|
||||
|
||||
const ExtractStyleFns = {
|
||||
[STYLE_PREFIX]: styleExtractStyle,
|
||||
[TOKEN_PREFIX]: tokenExtractStyle,
|
||||
[CSS_VAR_PREFIX]: cssVarExtractStyle,
|
||||
};
|
||||
|
||||
type ExtractStyleType = keyof typeof ExtractStyleFns;
|
||||
|
||||
function isNotNull<T>(value: T | null): value is T {
|
||||
return value !== null;
|
||||
}
|
||||
|
||||
export default function extractStyle(
|
||||
cache: Cache,
|
||||
options?:
|
||||
| boolean
|
||||
| {
|
||||
plain?: boolean;
|
||||
types?: ExtractStyleType | ExtractStyleType[];
|
||||
},
|
||||
) {
|
||||
const { plain = false, types = ['style', 'token', 'cssVar'] } =
|
||||
typeof options === 'boolean' ? { plain: options } : options || {};
|
||||
|
||||
const matchPrefixRegexp = new RegExp(
|
||||
`^(${(typeof types === 'string' ? [types] : types).join('|')})%`,
|
||||
);
|
||||
|
||||
// prefix with `style` is used for `useStyleRegister` to cache style context
|
||||
const styleKeys = Array.from(cache.cache.keys()).filter(key => matchPrefixRegexp.test(key));
|
||||
|
||||
// Common effect styles like animation
|
||||
const effectStyles: Record<string, boolean> = {};
|
||||
|
||||
// Mapping of cachePath to style hash
|
||||
const cachePathMap: Record<string, string> = {};
|
||||
|
||||
let styleText = '';
|
||||
|
||||
styleKeys
|
||||
.map<[number, string] | null>(key => {
|
||||
const cachePath = key.replace(matchPrefixRegexp, '').replace(/%/g, '|');
|
||||
const [prefix] = key.split('%');
|
||||
const extractFn = ExtractStyleFns[prefix as keyof typeof ExtractStyleFns];
|
||||
const extractedStyle = extractFn(cache.cache.get(key)![1], effectStyles, {
|
||||
plain,
|
||||
});
|
||||
if (!extractedStyle) {
|
||||
return null;
|
||||
}
|
||||
const [order, styleId, styleStr] = extractedStyle;
|
||||
if (key.startsWith('style')) {
|
||||
cachePathMap[cachePath] = styleId;
|
||||
}
|
||||
return [order, styleStr];
|
||||
})
|
||||
.filter(isNotNull)
|
||||
.sort(([o1], [o2]) => o1 - o2)
|
||||
.forEach(([, style]) => {
|
||||
styleText += style;
|
||||
});
|
||||
|
||||
// ==================== Fill Cache Path ====================
|
||||
styleText += toStyleStr(
|
||||
`.${ATTR_CACHE_MAP}{content:"${serializeCacheMap(cachePathMap)}";}`,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
[ATTR_CACHE_MAP]: ATTR_CACHE_MAP,
|
||||
},
|
||||
plain,
|
||||
);
|
||||
|
||||
return styleText;
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
|
||||
import { ATTR_MARK, ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
|
||||
import { isClientSide, toStyleStr } from '../util';
|
||||
import type { TokenWithCSSVar } from '../util/css-variables';
|
||||
import { transformToken } from '../util/css-variables';
|
||||
import type { ExtractStyle } from './useGlobalCache';
|
||||
import useGlobalCache from './useGlobalCache';
|
||||
import { uniqueHash } from './useStyleRegister';
|
||||
import type { ComputedRef } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
export const CSS_VAR_PREFIX = 'cssVar';
|
||||
|
||||
type CSSVarCacheValue<V, T extends Record<string, V> = Record<string, V>> = [
|
||||
cssVarToken: TokenWithCSSVar<V, T>,
|
||||
cssVarStr: string,
|
||||
styleId: string,
|
||||
cssVarKey: string,
|
||||
];
|
||||
|
||||
const useCSSVarRegister = <V, T extends Record<string, V>>(
|
||||
config: ComputedRef<{
|
||||
path: string[];
|
||||
key: string;
|
||||
prefix?: string;
|
||||
unitless?: Record<string, boolean>;
|
||||
ignore?: Record<string, boolean>;
|
||||
scope?: string;
|
||||
token: any;
|
||||
}>,
|
||||
fn: () => T,
|
||||
) => {
|
||||
const styleContext = useStyleInject();
|
||||
|
||||
const stylePath = computed(() => {
|
||||
return [
|
||||
...config.value.path,
|
||||
config.value.key,
|
||||
config.value.scope || '',
|
||||
config.value.token?._tokenKey,
|
||||
];
|
||||
});
|
||||
|
||||
const cache = useGlobalCache<CSSVarCacheValue<V, T>>(
|
||||
CSS_VAR_PREFIX,
|
||||
stylePath,
|
||||
() => {
|
||||
const originToken = fn();
|
||||
const [mergedToken, cssVarsStr] = transformToken<V, T>(originToken, config.value.key, {
|
||||
prefix: config.value.prefix,
|
||||
unitless: config.value.unitless,
|
||||
ignore: config.value.ignore,
|
||||
scope: config.value.scope || '',
|
||||
});
|
||||
|
||||
const styleId = uniqueHash(stylePath.value, cssVarsStr);
|
||||
return [mergedToken, cssVarsStr, styleId, config.value.key];
|
||||
},
|
||||
([, , styleId]) => {
|
||||
if (isClientSide) {
|
||||
removeCSS(styleId, { mark: ATTR_MARK });
|
||||
}
|
||||
},
|
||||
([, cssVarsStr, styleId]) => {
|
||||
if (!cssVarsStr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const style = updateCSS(cssVarsStr, styleId, {
|
||||
mark: ATTR_MARK,
|
||||
prepend: 'queue',
|
||||
attachTo: styleContext.value.container,
|
||||
priority: -999,
|
||||
});
|
||||
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = styleContext.value.cache?.instanceId;
|
||||
|
||||
// Used for `useCacheToken` to remove on batch when token removed
|
||||
style.setAttribute(ATTR_TOKEN, config.value.key);
|
||||
},
|
||||
);
|
||||
|
||||
return cache;
|
||||
};
|
||||
|
||||
export const extract: ExtractStyle<CSSVarCacheValue<any>> = (cache, _effectStyles, options) => {
|
||||
const [, styleStr, styleId, cssVarKey] = cache;
|
||||
const { plain } = options || {};
|
||||
|
||||
if (!styleStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const order = -999;
|
||||
|
||||
// ====================== Style ======================
|
||||
// Used for rc-util
|
||||
const sharedAttrs = {
|
||||
'data-vc-order': 'prependQueue',
|
||||
'data-vc-priority': `${order}`,
|
||||
};
|
||||
|
||||
const styleText = toStyleStr(styleStr, cssVarKey, styleId, sharedAttrs, plain);
|
||||
|
||||
return [order, styleId, styleText];
|
||||
};
|
||||
|
||||
export default useCSSVarRegister;
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
import hash from '@emotion/hash';
|
||||
import { updateCSS } from '../../../vc-util/Dom/dynamicCSS';
|
||||
import { ATTR_MARK, ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
|
||||
import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
|
||||
import type Theme from '../theme/Theme';
|
||||
import { flattenToken, memoResult, token2key, toStyleStr } from '../util';
|
||||
import { transformToken } from '../util/css-variables';
|
||||
import type { ExtractStyle } from './useGlobalCache';
|
||||
import useGlobalCache from './useGlobalCache';
|
||||
import { flattenToken, token2key } from '../util';
|
||||
import type { Ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
const EMPTY_OVERRIDE = {};
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
// nuxt generate when NODE_ENV is prerender
|
||||
const isPrerender = process.env.NODE_ENV === 'prerender';
|
||||
|
||||
// Generate different prefix to make user selector break in production env.
|
||||
// This helps developer not to do style override directly on the hash id.
|
||||
const hashPrefix = process.env.NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css';
|
||||
const hashPrefix = !isProduction && !isPrerender ? 'css-dev-only-do-not-override' : 'css';
|
||||
|
||||
export interface Option<DerivativeToken, DesignToken> {
|
||||
/**
|
||||
|
|
@ -45,22 +46,6 @@ export interface Option<DerivativeToken, DesignToken> {
|
|||
override: object,
|
||||
theme: Theme<any, any>,
|
||||
) => DerivativeToken;
|
||||
|
||||
/**
|
||||
* Transform token to css variables.
|
||||
*/
|
||||
cssVar?: {
|
||||
/** Prefix for css variables */
|
||||
prefix?: string;
|
||||
/** Tokens that should not be appended with unit */
|
||||
unitless?: Record<string, boolean>;
|
||||
/** Tokens that should not be transformed to css variables */
|
||||
ignore?: Record<string, boolean>;
|
||||
/** Tokens that preserves origin value */
|
||||
preserve?: Record<string, boolean>;
|
||||
/** Key for current theme. Useful for customizing and should be unique */
|
||||
key?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const tokenKeys = new Map<string, number>();
|
||||
|
|
@ -109,7 +94,6 @@ export const getComputedToken = <DerivativeToken = object, DesignToken = Derivat
|
|||
format?: (token: DesignToken) => DerivativeToken,
|
||||
) => {
|
||||
const derivativeToken = theme.getDerivativeToken(originToken);
|
||||
|
||||
// Merge with override
|
||||
let mergedDerivativeToken = {
|
||||
...derivativeToken,
|
||||
|
|
@ -124,16 +108,6 @@ export const getComputedToken = <DerivativeToken = object, DesignToken = Derivat
|
|||
return mergedDerivativeToken;
|
||||
};
|
||||
|
||||
export const TOKEN_PREFIX = 'token';
|
||||
|
||||
type TokenCacheValue<DerivativeToken> = [
|
||||
token: DerivativeToken & { _tokenKey: string; _themeKey: string },
|
||||
hashId: string,
|
||||
realToken: DerivativeToken & { _tokenKey: string },
|
||||
cssVarStr: string,
|
||||
cssVarKey: string,
|
||||
];
|
||||
|
||||
/**
|
||||
* Cache theme derivative token as global shared one
|
||||
* @param theme Theme entity
|
||||
|
|
@ -145,27 +119,21 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
|
|||
theme: Ref<Theme<any, any>>,
|
||||
tokens: Ref<Partial<DesignToken>[]>,
|
||||
option: Ref<Option<DerivativeToken, DesignToken>> = ref({}),
|
||||
): Ref<TokenCacheValue<DerivativeToken>> {
|
||||
const styleContext = useStyleInject();
|
||||
) {
|
||||
const style = useStyleInject();
|
||||
|
||||
// Basic - We do basic cache here
|
||||
const mergedToken = computed(() =>
|
||||
memoResult(() => Object.assign({}, ...tokens.value), tokens.value),
|
||||
);
|
||||
|
||||
const mergedToken = computed(() => Object.assign({}, ...tokens.value));
|
||||
const tokenStr = computed(() => flattenToken(mergedToken.value));
|
||||
const overrideTokenStr = computed(() => flattenToken(option.value.override ?? EMPTY_OVERRIDE));
|
||||
const overrideTokenStr = computed(() => flattenToken(option.value.override || EMPTY_OVERRIDE));
|
||||
|
||||
const cssVarStr = computed(() => (option.value.cssVar ? flattenToken(option.value.cssVar) : ''));
|
||||
|
||||
const cachedToken = useGlobalCache<TokenCacheValue<DerivativeToken>>(
|
||||
TOKEN_PREFIX,
|
||||
const cachedToken = useGlobalCache<[DerivativeToken & { _tokenKey: string }, string]>(
|
||||
'token',
|
||||
computed(() => [
|
||||
option.value.salt ?? '',
|
||||
theme.value?.id,
|
||||
option.value.salt || '',
|
||||
theme.value.id,
|
||||
tokenStr.value,
|
||||
overrideTokenStr.value,
|
||||
cssVarStr.value,
|
||||
]),
|
||||
() => {
|
||||
const {
|
||||
|
|
@ -173,82 +141,25 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
|
|||
override = EMPTY_OVERRIDE,
|
||||
formatToken,
|
||||
getComputedToken: compute,
|
||||
cssVar,
|
||||
} = option.value;
|
||||
let mergedDerivativeToken = compute
|
||||
const mergedDerivativeToken = compute
|
||||
? compute(mergedToken.value, override, theme.value)
|
||||
: getComputedToken(mergedToken.value, override, theme.value, formatToken);
|
||||
|
||||
// Replace token value with css variables
|
||||
const actualToken = { ...mergedDerivativeToken };
|
||||
let cssVarsStr = '';
|
||||
if (!!cssVar) {
|
||||
[mergedDerivativeToken, cssVarsStr] = transformToken(mergedDerivativeToken, cssVar.key!, {
|
||||
prefix: cssVar.prefix,
|
||||
ignore: cssVar.ignore,
|
||||
unitless: cssVar.unitless,
|
||||
preserve: cssVar.preserve,
|
||||
});
|
||||
}
|
||||
|
||||
// Optimize for `useStyleRegister` performance
|
||||
const tokenKey = token2key(mergedDerivativeToken, salt);
|
||||
mergedDerivativeToken._tokenKey = tokenKey;
|
||||
actualToken._tokenKey = token2key(actualToken, salt);
|
||||
|
||||
const themeKey = cssVar?.key ?? tokenKey;
|
||||
mergedDerivativeToken._themeKey = themeKey;
|
||||
recordCleanToken(themeKey);
|
||||
recordCleanToken(tokenKey);
|
||||
|
||||
const hashId = `${hashPrefix}-${hash(tokenKey)}`;
|
||||
mergedDerivativeToken._hashId = hashId; // Not used
|
||||
|
||||
return [mergedDerivativeToken, hashId, actualToken, cssVarsStr, cssVar?.key || ''];
|
||||
return [mergedDerivativeToken, hashId];
|
||||
},
|
||||
cache => {
|
||||
// Remove token will remove all related style
|
||||
cleanTokenStyle(cache[0]._themeKey, styleContext.value?.cache?.instanceId);
|
||||
},
|
||||
([token, , , cssVarsStr]) => {
|
||||
const { cssVar } = option.value;
|
||||
if (cssVar && cssVarsStr) {
|
||||
const style = updateCSS(cssVarsStr, hash(`css-variables-${token._themeKey}`), {
|
||||
mark: ATTR_MARK,
|
||||
prepend: 'queue',
|
||||
attachTo: styleContext.value?.container,
|
||||
priority: -999,
|
||||
});
|
||||
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = styleContext.value?.cache?.instanceId;
|
||||
|
||||
// Used for `useCacheToken` to remove on batch when token removed
|
||||
style.setAttribute(ATTR_TOKEN, token._themeKey);
|
||||
}
|
||||
cleanTokenStyle(cache[0]._tokenKey, style.value?.cache.instanceId);
|
||||
},
|
||||
);
|
||||
|
||||
return cachedToken;
|
||||
}
|
||||
|
||||
export const extract: ExtractStyle<TokenCacheValue<any>> = (cache, _effectStyles, options) => {
|
||||
const [, , realToken, styleStr, cssVarKey] = cache;
|
||||
const { plain } = options || {};
|
||||
|
||||
if (!styleStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const styleId = realToken._tokenKey;
|
||||
const order = -999;
|
||||
|
||||
// ====================== Style ======================
|
||||
// Used for rc-util
|
||||
const sharedAttrs = {
|
||||
'data-vc-order': 'prependQueue',
|
||||
'data-vc-priority': `${order}`,
|
||||
};
|
||||
|
||||
const styleText = toStyleStr(styleStr, cssVarKey, styleId, sharedAttrs, plain);
|
||||
|
||||
return [order, styleId, styleText];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
// import canUseDom from 'rc-util/lib/Dom/canUseDom';
|
||||
import useLayoutEffect from '../../../_util/hooks/useLayoutEffect';
|
||||
import type { ShallowRef, WatchCallback } from 'vue';
|
||||
import { watch } from 'vue';
|
||||
|
||||
type UseCompatibleInsertionEffect = (
|
||||
renderEffect: WatchCallback,
|
||||
effect: (polyfill?: boolean) => ReturnType<WatchCallback>,
|
||||
deps: ShallowRef,
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Polyfill `useInsertionEffect` for React < 18
|
||||
* @param renderEffect will be executed in `useMemo`, and do not have callback
|
||||
* @param effect will be executed in `useLayoutEffect`
|
||||
* @param deps
|
||||
*/
|
||||
const useInsertionEffectPolyfill: UseCompatibleInsertionEffect = (renderEffect, effect, deps) => {
|
||||
watch(deps, renderEffect, { immediate: true });
|
||||
useLayoutEffect(() => effect(true), deps);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compatible `useInsertionEffect`
|
||||
* will use `useInsertionEffect` if React version >= 18,
|
||||
* otherwise use `useInsertionEffectPolyfill`.
|
||||
*/
|
||||
const useCompatibleInsertionEffect: UseCompatibleInsertionEffect = useInsertionEffectPolyfill;
|
||||
|
||||
export default useCompatibleInsertionEffect;
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
const useRun = () => {
|
||||
return function (fn: () => void) {
|
||||
fn();
|
||||
};
|
||||
};
|
||||
const useEffectCleanupRegister = useRun;
|
||||
|
||||
export default useEffectCleanupRegister;
|
||||
|
|
@ -1,37 +1,41 @@
|
|||
import { useStyleInject } from '../StyleContext';
|
||||
import type { KeyType } from '../Cache';
|
||||
import useCompatibleInsertionEffect from './useCompatibleInsertionEffect';
|
||||
import useHMR from './useHMR';
|
||||
import type { ShallowRef, Ref } from 'vue';
|
||||
import { onBeforeUnmount, watch, computed } from 'vue';
|
||||
|
||||
export type ExtractStyle<CacheValue> = (
|
||||
cache: CacheValue,
|
||||
effectStyles: Record<string, boolean>,
|
||||
options?: {
|
||||
plain?: boolean;
|
||||
},
|
||||
) => [order: number, styleId: string, style: string] | null;
|
||||
|
||||
export default function useGlobalCache<CacheType>(
|
||||
import { onBeforeUnmount, watch, watchEffect, shallowRef } from 'vue';
|
||||
export default function useClientCache<CacheType>(
|
||||
prefix: string,
|
||||
keyPath: Ref<KeyType[]>,
|
||||
cacheFn: () => CacheType,
|
||||
onCacheRemove?: (cache: CacheType, fromHMR: boolean) => void,
|
||||
// Add additional effect trigger by `useInsertionEffect`
|
||||
onCacheEffect?: (cachedValue: CacheType) => void,
|
||||
): ShallowRef<CacheType> {
|
||||
const styleContext = useStyleInject();
|
||||
const globalCache = computed(() => styleContext.value?.cache);
|
||||
const deps = computed(() => [prefix, ...keyPath.value].join('%'));
|
||||
|
||||
const fullPathStr = shallowRef('');
|
||||
const res = shallowRef<CacheType>();
|
||||
watchEffect(() => {
|
||||
fullPathStr.value = [prefix, ...keyPath.value].join('%');
|
||||
});
|
||||
const HMRUpdate = useHMR();
|
||||
const clearCache = (pathStr: string) => {
|
||||
styleContext.value.cache.update(pathStr, prevCache => {
|
||||
const [times = 0, cache] = prevCache || [];
|
||||
const nextCount = times - 1;
|
||||
if (nextCount === 0) {
|
||||
onCacheRemove?.(cache, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
type UpdaterArgs = [times: number, cache: CacheType];
|
||||
return [times - 1, cache];
|
||||
});
|
||||
};
|
||||
|
||||
const buildCache = (updater?: (data: UpdaterArgs) => UpdaterArgs) => {
|
||||
globalCache.value.update(deps.value, prevCache => {
|
||||
const [times = 0, cache] = prevCache || [undefined, undefined];
|
||||
watch(
|
||||
fullPathStr,
|
||||
(newStr, oldStr) => {
|
||||
if (oldStr) clearCache(oldStr);
|
||||
// Create cache
|
||||
styleContext.value.cache.update(newStr, prevCache => {
|
||||
const [times = 0, cache] = prevCache || [];
|
||||
|
||||
// HMR should always ignore cache since developer may change it
|
||||
let tmpCache = cache;
|
||||
|
|
@ -39,77 +43,16 @@ export default function useGlobalCache<CacheType>(
|
|||
onCacheRemove?.(tmpCache, HMRUpdate);
|
||||
tmpCache = null;
|
||||
}
|
||||
|
||||
const mergedCache = tmpCache || cacheFn();
|
||||
|
||||
const data: UpdaterArgs = [times, mergedCache];
|
||||
|
||||
// Call updater if need additional logic
|
||||
return updater ? updater(data) : data;
|
||||
return [times + 1, mergedCache];
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
deps,
|
||||
() => {
|
||||
buildCache();
|
||||
res.value = styleContext.value.cache.get(fullPathStr.value)![1];
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
let cacheEntity = globalCache.value.get(deps.value);
|
||||
|
||||
// HMR clean the cache but not trigger `useMemo` again
|
||||
// Let's fallback of this
|
||||
// ref https://github.com/ant-design/cssinjs/issues/127
|
||||
if (process.env.NODE_ENV !== 'production' && !cacheEntity) {
|
||||
buildCache();
|
||||
cacheEntity = globalCache.value.get(deps.value);
|
||||
}
|
||||
|
||||
const cacheContent = computed(
|
||||
() =>
|
||||
(globalCache.value.get(deps.value) && globalCache.value.get(deps.value)![1]) ||
|
||||
cacheEntity![1],
|
||||
);
|
||||
|
||||
// Remove if no need anymore
|
||||
useCompatibleInsertionEffect(
|
||||
() => {
|
||||
onCacheEffect?.(cacheContent.value);
|
||||
},
|
||||
polyfill => {
|
||||
// It's bad to call build again in effect.
|
||||
// But we have to do this since StrictMode will call effect twice
|
||||
// which will clear cache on the first time.
|
||||
buildCache(([times, cache]) => {
|
||||
if (polyfill && times === 0) {
|
||||
onCacheEffect?.(cacheContent.value);
|
||||
}
|
||||
return [times + 1, cache];
|
||||
});
|
||||
|
||||
return () => {
|
||||
globalCache.value.update(deps.value, prevCache => {
|
||||
const [times = 0, cache] = prevCache || [];
|
||||
const nextCount = times - 1;
|
||||
if (nextCount <= 0) {
|
||||
if (polyfill || !globalCache.value.get(deps.value)) {
|
||||
onCacheRemove?.(cache, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return [times - 1, cache];
|
||||
});
|
||||
};
|
||||
},
|
||||
deps,
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
buildCache();
|
||||
clearCache(fullPathStr.value);
|
||||
});
|
||||
|
||||
return cacheContent;
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import canUseDom from '../../canUseDom';
|
||||
import { ATTR_MARK } from '../StyleContext';
|
||||
import canUseDom from '../../../../_util/canUseDom';
|
||||
import { ATTR_MARK } from '../../StyleContext';
|
||||
|
||||
export const ATTR_CACHE_MAP = 'data-ant-cssinjs-cache-path';
|
||||
|
||||
|
|
@ -3,30 +3,38 @@ import type * as CSS from 'csstype';
|
|||
// @ts-ignore
|
||||
import unitless from '@emotion/unitless';
|
||||
import { compile, serialize, stringify } from 'stylis';
|
||||
import type { Theme, Transformer } from '..';
|
||||
import type Keyframes from '../Keyframes';
|
||||
import type { Linter } from '../linters';
|
||||
import { contentQuotesLinter, hashedAnimationLinter } from '../linters';
|
||||
import type { HashPriority } from '../StyleContext';
|
||||
import type { Theme, Transformer } from '../..';
|
||||
import type Cache from '../../Cache';
|
||||
import type Keyframes from '../../Keyframes';
|
||||
import type { Linter } from '../../linters';
|
||||
import { contentQuotesLinter, hashedAnimationLinter } from '../../linters';
|
||||
import type { HashPriority } from '../../StyleContext';
|
||||
import {
|
||||
useStyleInject,
|
||||
ATTR_CACHE_PATH,
|
||||
ATTR_MARK,
|
||||
ATTR_TOKEN,
|
||||
CSS_IN_JS_INSTANCE,
|
||||
} from '../StyleContext';
|
||||
import { isClientSide, supportLayer, toStyleStr } from '../util';
|
||||
import { CSS_FILE_STYLE, existPath, getStyleAndHash } from '../util/cacheMapUtil';
|
||||
import type { ExtractStyle } from './useGlobalCache';
|
||||
import useGlobalCache from './useGlobalCache';
|
||||
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
|
||||
} from '../../StyleContext';
|
||||
import { supportLayer } from '../../util';
|
||||
import useGlobalCache from '../useGlobalCache';
|
||||
import { removeCSS, updateCSS } from '../../../../vc-util/Dom/dynamicCSS';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import type { VueNode } from '../../type';
|
||||
import type { VueNode } from '../../../type';
|
||||
import canUseDom from '../../../../_util/canUseDom';
|
||||
|
||||
import {
|
||||
ATTR_CACHE_MAP,
|
||||
existPath,
|
||||
getStyleAndHash,
|
||||
serialize as serializeCacheMap,
|
||||
} from './cacheMapUtil';
|
||||
|
||||
const isClientSide = canUseDom();
|
||||
|
||||
const SKIP_CHECK = '_skip_check_';
|
||||
const MULTI_VALUE = '_multi_value_';
|
||||
|
||||
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
|
||||
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
|
||||
};
|
||||
|
|
@ -52,7 +60,6 @@ export type CSSInterpolation = InterpolationPrimitive | ArrayCSSInterpolation |
|
|||
|
||||
export type CSSOthersObject = Record<string, CSSInterpolation>;
|
||||
|
||||
// @ts-ignore
|
||||
export interface CSSObject extends CSSPropertiesWithMultiValues, CSSPseudos, CSSOthersObject {}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -107,6 +114,16 @@ export interface ParseInfo {
|
|||
parentSelectors: string[];
|
||||
}
|
||||
|
||||
// Global effect style will mount once and not removed
|
||||
// The effect will not save in SSR cache (e.g. keyframes)
|
||||
const globalEffectStyleKeys = new Set();
|
||||
|
||||
/**
|
||||
* @private Test only. Clear the global effect style keys.
|
||||
*/
|
||||
export const _cf =
|
||||
process.env.NODE_ENV !== 'production' ? () => globalEffectStyleKeys.clear() : undefined;
|
||||
|
||||
// Parse CSSObject to style content
|
||||
export const parseStyle = (
|
||||
interpolation: CSSInterpolation,
|
||||
|
|
@ -241,7 +258,6 @@ export const parseStyle = (
|
|||
|
||||
styleStr += `${styleName}:${formatValue};`;
|
||||
}
|
||||
|
||||
const actualValue = (value as any)?.value ?? value;
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
|
|
@ -279,7 +295,7 @@ export const parseStyle = (
|
|||
// ============================================================================
|
||||
// == Register ==
|
||||
// ============================================================================
|
||||
export function uniqueHash(path: (string | number)[], styleStr: string) {
|
||||
function uniqueHash(path: (string | number)[], styleStr: string) {
|
||||
return hash(`${path.join('%')}${styleStr}`);
|
||||
}
|
||||
|
||||
|
|
@ -287,17 +303,6 @@ export function uniqueHash(path: (string | number)[], styleStr: string) {
|
|||
// return null;
|
||||
// }
|
||||
|
||||
export const STYLE_PREFIX = 'style';
|
||||
|
||||
type StyleCacheValue = [
|
||||
styleStr: string,
|
||||
tokenKey: string,
|
||||
styleId: string,
|
||||
effectStyle: Record<string, string>,
|
||||
clientOnly: boolean | undefined,
|
||||
order: number,
|
||||
];
|
||||
|
||||
/**
|
||||
* Register a style to the global style sheet.
|
||||
*/
|
||||
|
|
@ -332,14 +337,22 @@ export default function useStyleRegister(
|
|||
}
|
||||
|
||||
// const [cacheStyle[0], cacheStyle[1], cacheStyle[2]]
|
||||
useGlobalCache<StyleCacheValue>(
|
||||
STYLE_PREFIX,
|
||||
useGlobalCache<
|
||||
[
|
||||
styleStr: string,
|
||||
tokenKey: string,
|
||||
styleId: string,
|
||||
effectStyle: Record<string, string>,
|
||||
clientOnly: boolean | undefined,
|
||||
order: number,
|
||||
]
|
||||
>(
|
||||
'style',
|
||||
fullPath,
|
||||
// Create cache if needed
|
||||
() => {
|
||||
const { path, hashId, layer, clientOnly, order = 0 } = info.value;
|
||||
const { path, hashId, layer, nonce, clientOnly, order = 0 } = info.value;
|
||||
const cachePath = fullPath.value.join('|');
|
||||
|
||||
// Get style from SSR inline style directly
|
||||
if (existPath(cachePath)) {
|
||||
const [inlineCacheStyleStr, styleHash] = getStyleAndHash(cachePath);
|
||||
|
|
@ -347,10 +360,8 @@ export default function useStyleRegister(
|
|||
return [inlineCacheStyleStr, tokenKey.value, styleHash, {}, clientOnly, order];
|
||||
}
|
||||
}
|
||||
|
||||
// Generate style
|
||||
const styleObj = styleFn();
|
||||
const { hashPriority, transformers, linters } = styleContext.value;
|
||||
const { hashPriority, container, transformers, linters, cache } = styleContext.value;
|
||||
|
||||
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
|
||||
hashId,
|
||||
|
|
@ -360,32 +371,18 @@ export default function useStyleRegister(
|
|||
transformers,
|
||||
linters,
|
||||
});
|
||||
|
||||
const styleStr = normalizeStyle(parsedStyle);
|
||||
const styleId = uniqueHash(fullPath.value, styleStr);
|
||||
|
||||
return [styleStr, tokenKey.value, styleId, effectStyle, clientOnly, order];
|
||||
},
|
||||
|
||||
// Remove cache if no need
|
||||
([, , styleId], fromHMR) => {
|
||||
if ((fromHMR || styleContext.value.autoClear) && isClientSide) {
|
||||
removeCSS(styleId, { mark: ATTR_MARK });
|
||||
}
|
||||
},
|
||||
|
||||
// Effect: Inject style here
|
||||
([styleStr, , styleId, effectStyle]) => {
|
||||
if (isMergedClientSide && styleStr !== CSS_FILE_STYLE) {
|
||||
if (isMergedClientSide) {
|
||||
const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
|
||||
mark: ATTR_MARK,
|
||||
prepend: 'queue',
|
||||
attachTo: styleContext.value.container,
|
||||
priority: info.value.order,
|
||||
attachTo: container,
|
||||
priority: order,
|
||||
};
|
||||
|
||||
const nonceStr =
|
||||
typeof info.value.nonce === 'function' ? info.value.nonce() : info.value.nonce;
|
||||
const nonceStr = typeof nonce === 'function' ? nonce() : nonce;
|
||||
|
||||
if (nonceStr) {
|
||||
mergedCSSConfig.csp = { nonce: nonceStr };
|
||||
|
|
@ -393,33 +390,45 @@ export default function useStyleRegister(
|
|||
|
||||
const style = updateCSS(styleStr, styleId, mergedCSSConfig);
|
||||
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = styleContext.value.cache.instanceId;
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
|
||||
|
||||
// Used for `useCacheToken` to remove on batch when token removed
|
||||
style.setAttribute(ATTR_TOKEN, tokenKey.value);
|
||||
|
||||
// Debug usage. Dev only
|
||||
// Dev usage to find which cache path made this easily
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
style.setAttribute(ATTR_CACHE_PATH, fullPath.value.join('|'));
|
||||
}
|
||||
|
||||
// Inject client side effect style
|
||||
Object.keys(effectStyle).forEach(effectKey => {
|
||||
updateCSS(
|
||||
normalizeStyle(effectStyle[effectKey]),
|
||||
`_effect-${effectKey}`,
|
||||
mergedCSSConfig,
|
||||
);
|
||||
if (!globalEffectStyleKeys.has(effectKey)) {
|
||||
globalEffectStyleKeys.add(effectKey);
|
||||
|
||||
// Inject
|
||||
updateCSS(normalizeStyle(effectStyle[effectKey]), `_effect-${effectKey}`, {
|
||||
mark: ATTR_MARK,
|
||||
prepend: 'queue',
|
||||
attachTo: container,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return [styleStr, tokenKey.value, styleId, effectStyle, clientOnly, order];
|
||||
},
|
||||
// Remove cache if no need
|
||||
([, , styleId], fromHMR) => {
|
||||
if ((fromHMR || styleContext.value.autoClear) && isClientSide) {
|
||||
removeCSS(styleId, { mark: ATTR_MARK });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return (node: VueNode) => {
|
||||
return node;
|
||||
// let styleNode: VueNode;
|
||||
|
||||
// if (!styleContext.value.ssrInline || isMergedClientSide || !styleContext.value.defaultCache) {
|
||||
// if (!styleContext.ssrInline || isMergedClientSide || !styleContext.defaultCache) {
|
||||
// styleNode = <Empty />;
|
||||
// } else {
|
||||
// styleNode = (
|
||||
|
|
@ -442,25 +451,78 @@ export default function useStyleRegister(
|
|||
};
|
||||
}
|
||||
|
||||
export const extract: ExtractStyle<StyleCacheValue> = (cache, effectStyles, options) => {
|
||||
const [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]: StyleCacheValue = cache;
|
||||
const { plain } = options || {};
|
||||
// ============================================================================
|
||||
// == SSR ==
|
||||
// ============================================================================
|
||||
export function extractStyle(cache: Cache, plain = false) {
|
||||
const matchPrefix = `style%`;
|
||||
|
||||
// prefix with `style` is used for `useStyleRegister` to cache style context
|
||||
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith(matchPrefix));
|
||||
|
||||
// Common effect styles like animation
|
||||
const effectStyles: Record<string, boolean> = {};
|
||||
|
||||
// Mapping of cachePath to style hash
|
||||
const cachePathMap: Record<string, string> = {};
|
||||
|
||||
let styleText = '';
|
||||
|
||||
function toStyleStr(
|
||||
style: string,
|
||||
tokenKey?: string,
|
||||
styleId?: string,
|
||||
customizeAttrs: Record<string, string> = {},
|
||||
) {
|
||||
const attrs: Record<string, string | undefined> = {
|
||||
...customizeAttrs,
|
||||
[ATTR_TOKEN]: tokenKey,
|
||||
[ATTR_MARK]: styleId,
|
||||
};
|
||||
|
||||
const attrStr = Object.keys(attrs)
|
||||
.map(attr => {
|
||||
const val = attrs[attr];
|
||||
return val ? `${attr}="${val}"` : null;
|
||||
})
|
||||
.filter(v => v)
|
||||
.join(' ');
|
||||
|
||||
return plain ? style : `<style ${attrStr}>${style}</style>`;
|
||||
}
|
||||
|
||||
// ====================== Fill Style ======================
|
||||
type OrderStyle = [order: number, style: string];
|
||||
|
||||
const orderStyles: OrderStyle[] = styleKeys
|
||||
.map(key => {
|
||||
const cachePath = key.slice(matchPrefix.length).replace(/%/g, '|');
|
||||
|
||||
const [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]: [
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
Record<string, string>,
|
||||
boolean,
|
||||
number,
|
||||
] = cache.cache.get(key)![1];
|
||||
|
||||
// Skip client only style
|
||||
if (clientOnly) {
|
||||
return null;
|
||||
return null! as OrderStyle;
|
||||
}
|
||||
|
||||
let keyStyleText = styleStr;
|
||||
|
||||
// ====================== Style ======================
|
||||
// Used for rc-util
|
||||
// Used for vc-util
|
||||
const sharedAttrs = {
|
||||
'data-vc-order': 'prependQueue',
|
||||
'data-vc-priority': `${order}`,
|
||||
};
|
||||
|
||||
keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs, plain);
|
||||
let keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs);
|
||||
|
||||
// Save cache path with hash mapping
|
||||
cachePathMap[cachePath] = styleId;
|
||||
|
||||
// =============== Create effect style ===============
|
||||
if (effectStyle) {
|
||||
|
|
@ -468,17 +530,37 @@ export const extract: ExtractStyle<StyleCacheValue> = (cache, effectStyles, opti
|
|||
// Effect style can be reused
|
||||
if (!effectStyles[effectKey]) {
|
||||
effectStyles[effectKey] = true;
|
||||
const effectStyleStr = normalizeStyle(effectStyle[effectKey]);
|
||||
keyStyleText += toStyleStr(
|
||||
effectStyleStr,
|
||||
normalizeStyle(effectStyle[effectKey]),
|
||||
tokenKey,
|
||||
`_effect-${effectKey}`,
|
||||
sharedAttrs,
|
||||
plain,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return [order, styleId, keyStyleText];
|
||||
};
|
||||
const ret: OrderStyle = [order, keyStyleText];
|
||||
|
||||
return ret;
|
||||
})
|
||||
.filter(o => o);
|
||||
|
||||
orderStyles
|
||||
.sort((o1, o2) => o1[0] - o2[0])
|
||||
.forEach(([, style]) => {
|
||||
styleText += style;
|
||||
});
|
||||
|
||||
// ==================== Fill Cache Path ====================
|
||||
styleText += toStyleStr(
|
||||
`.${ATTR_CACHE_MAP}{content:"${serializeCacheMap(cachePathMap)}";}`,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
[ATTR_CACHE_MAP]: ATTR_CACHE_MAP,
|
||||
},
|
||||
);
|
||||
|
||||
return styleText;
|
||||
}
|
||||
|
|
@ -1,37 +1,28 @@
|
|||
import extractStyle from './extractStyle';
|
||||
import useCacheToken, { getComputedToken } from './hooks/useCacheToken';
|
||||
import useCSSVarRegister from './hooks/useCSSVarRegister';
|
||||
import useCacheToken from './hooks/useCacheToken';
|
||||
import type { CSSInterpolation, CSSObject } from './hooks/useStyleRegister';
|
||||
import useStyleRegister from './hooks/useStyleRegister';
|
||||
import useStyleRegister, { extractStyle } from './hooks/useStyleRegister';
|
||||
import Keyframes from './Keyframes';
|
||||
import type { Linter } from './linters';
|
||||
import {
|
||||
legacyNotSelectorLinter,
|
||||
logicalPropertiesLinter,
|
||||
NaNLinter,
|
||||
parentSelectorLinter,
|
||||
} from './linters';
|
||||
import type { StyleProviderProps } from './StyleContext';
|
||||
import { createCache, StyleProvider } from './StyleContext';
|
||||
import { legacyNotSelectorLinter, logicalPropertiesLinter, parentSelectorLinter } from './linters';
|
||||
import type { StyleContextProps, StyleProviderProps } from './StyleContext';
|
||||
import { createCache, useStyleInject, useStyleProvider, StyleProvider } from './StyleContext';
|
||||
import type { DerivativeFunc, TokenType } from './theme';
|
||||
import { createTheme, Theme } from './theme';
|
||||
import type { Transformer } from './transformers/interface';
|
||||
import legacyLogicalPropertiesTransformer from './transformers/legacyLogicalProperties';
|
||||
import px2remTransformer from './transformers/px2rem';
|
||||
import { supportLogicProps, supportWhere, unit } from './util';
|
||||
import { token2CSSVar } from './util/css-variables';
|
||||
import { supportLogicProps, supportWhere } from './util';
|
||||
|
||||
export {
|
||||
const cssinjs = {
|
||||
Theme,
|
||||
createTheme,
|
||||
useStyleRegister,
|
||||
useCSSVarRegister,
|
||||
useCacheToken,
|
||||
createCache,
|
||||
StyleProvider,
|
||||
useStyleInject,
|
||||
useStyleProvider,
|
||||
Keyframes,
|
||||
extractStyle,
|
||||
getComputedToken,
|
||||
|
||||
// Transformer
|
||||
legacyLogicalPropertiesTransformer,
|
||||
|
|
@ -41,11 +32,32 @@ export {
|
|||
logicalPropertiesLinter,
|
||||
legacyNotSelectorLinter,
|
||||
parentSelectorLinter,
|
||||
NaNLinter,
|
||||
|
||||
// util
|
||||
token2CSSVar,
|
||||
unit,
|
||||
// cssinjs
|
||||
StyleProvider,
|
||||
};
|
||||
export {
|
||||
Theme,
|
||||
createTheme,
|
||||
useStyleRegister,
|
||||
useCacheToken,
|
||||
createCache,
|
||||
useStyleInject,
|
||||
useStyleProvider,
|
||||
Keyframes,
|
||||
extractStyle,
|
||||
|
||||
// Transformer
|
||||
legacyLogicalPropertiesTransformer,
|
||||
px2remTransformer,
|
||||
|
||||
// Linters
|
||||
logicalPropertiesLinter,
|
||||
legacyNotSelectorLinter,
|
||||
parentSelectorLinter,
|
||||
|
||||
// cssinjs
|
||||
StyleProvider,
|
||||
};
|
||||
export type {
|
||||
TokenType,
|
||||
|
|
@ -54,9 +66,12 @@ export type {
|
|||
DerivativeFunc,
|
||||
Transformer,
|
||||
Linter,
|
||||
StyleContextProps,
|
||||
StyleProviderProps,
|
||||
};
|
||||
|
||||
export const _experimental = {
|
||||
supportModernCSS: () => supportWhere() && supportLogicProps(),
|
||||
};
|
||||
|
||||
export default cssinjs;
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
import type { Linter } from './interface';
|
||||
import { lintWarning } from './utils';
|
||||
|
||||
const linter: Linter = (key, value, info) => {
|
||||
if ((typeof value === 'string' && /NaN/g.test(value)) || Number.isNaN(value)) {
|
||||
lintWarning(`Unexpected 'NaN' in property '${key}: ${value}'.`, info);
|
||||
}
|
||||
};
|
||||
|
||||
export default linter;
|
||||
|
|
@ -3,5 +3,4 @@ export { default as hashedAnimationLinter } from './hashedAnimationLinter';
|
|||
export type { Linter } from './interface';
|
||||
export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter';
|
||||
export { default as logicalPropertiesLinter } from './logicalPropertiesLinter';
|
||||
export { default as NaNLinter } from './NaNLinter';
|
||||
export { default as parentSelectorLinter } from './parentSelectorLinter';
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ export function lintWarning(message: string, info: LinterInfo) {
|
|||
|
||||
devWarning(
|
||||
false,
|
||||
`[Ant Design Vue CSS-in-JS] ${path ? `Error in ${path}: ` : ''}${message}${
|
||||
parentSelectors.length ? ` Selector: ${parentSelectors.join(' | ')}` : ''
|
||||
`[Ant Design Vue CSS-in-JS] ${path ? `Error in '${path}': ` : ''}${message}${
|
||||
parentSelectors.length ? ` Selector info: ${parentSelectors.join(' -> ')}` : ''
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,34 @@
|
|||
import type { CSSObject } from '..';
|
||||
import type { Transformer } from './interface';
|
||||
|
||||
function splitValues(value: string | number): [values: (string | number)[], important: boolean] {
|
||||
function splitValues(value: string | number) {
|
||||
if (typeof value === 'number') {
|
||||
return [[value], false];
|
||||
return [value];
|
||||
}
|
||||
|
||||
const rawStyle = String(value).trim();
|
||||
const importantCells = rawStyle.match(/(.*)(!important)/);
|
||||
|
||||
const splitStyle = (importantCells ? importantCells[1] : rawStyle).trim().split(/\s+/);
|
||||
const splitStyle = String(value).split(/\s+/);
|
||||
|
||||
// Combine styles split in brackets, like `calc(1px + 2px)`
|
||||
let temp = '';
|
||||
let brackets = 0;
|
||||
return [
|
||||
splitStyle.reduce<string[]>((list, item) => {
|
||||
if (item.includes('(') || item.includes(')')) {
|
||||
const left = item.split('(').length - 1;
|
||||
const right = item.split(')').length - 1;
|
||||
brackets += left - right;
|
||||
}
|
||||
if (brackets === 0) {
|
||||
list.push(temp + item);
|
||||
temp = '';
|
||||
} else if (brackets > 0) {
|
||||
return splitStyle.reduce<string[]>((list, item) => {
|
||||
if (item.includes('(')) {
|
||||
temp += item;
|
||||
brackets += item.split('(').length - 1;
|
||||
} else if (item.includes(')')) {
|
||||
temp += ` ${item}`;
|
||||
brackets -= item.split(')').length - 1;
|
||||
if (brackets === 0) {
|
||||
list.push(temp);
|
||||
temp = '';
|
||||
}
|
||||
} else if (brackets > 0) {
|
||||
temp += ` ${item}`;
|
||||
} else {
|
||||
list.push(item);
|
||||
}
|
||||
return list;
|
||||
}, []),
|
||||
!!importantCells,
|
||||
];
|
||||
}, []);
|
||||
}
|
||||
|
||||
type MatchValue = string[] & {
|
||||
|
|
@ -107,14 +105,8 @@ const keyMap: Record<string, MatchValue> = {
|
|||
borderEndEndRadius: ['borderBottomRightRadius'],
|
||||
};
|
||||
|
||||
function wrapImportantAndSkipCheck(value: string | number, important: boolean) {
|
||||
let parsedValue = value;
|
||||
|
||||
if (important) {
|
||||
parsedValue = `${parsedValue} !important`;
|
||||
}
|
||||
|
||||
return { _skip_check_: true, value: parsedValue };
|
||||
function skipCheck(value: string | number) {
|
||||
return { _skip_check_: true, value };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -135,28 +127,25 @@ const transform: Transformer = {
|
|||
const matchValue = keyMap[key];
|
||||
|
||||
if (matchValue && (typeof value === 'number' || typeof value === 'string')) {
|
||||
const [values, important] = splitValues(value);
|
||||
const values = splitValues(value);
|
||||
|
||||
if (matchValue.length && matchValue.notSplit) {
|
||||
// not split means always give same value like border
|
||||
matchValue.forEach(matchKey => {
|
||||
clone[matchKey] = wrapImportantAndSkipCheck(value, important);
|
||||
clone[matchKey] = skipCheck(value);
|
||||
});
|
||||
} else if (matchValue.length === 1) {
|
||||
// Handle like `marginBlockStart` => `marginTop`
|
||||
clone[matchValue[0]] = wrapImportantAndSkipCheck(value, important);
|
||||
clone[matchValue[0]] = skipCheck(value);
|
||||
} else if (matchValue.length === 2) {
|
||||
// Handle like `marginBlock` => `marginTop` & `marginBottom`
|
||||
matchValue.forEach((matchKey, index) => {
|
||||
clone[matchKey] = wrapImportantAndSkipCheck(values[index] ?? values[0], important);
|
||||
clone[matchKey] = skipCheck(values[index] ?? values[0]);
|
||||
});
|
||||
} else if (matchValue.length === 4) {
|
||||
// Handle like `inset` => `top` & `right` & `bottom` & `left`
|
||||
matchValue.forEach((matchKey, index) => {
|
||||
clone[matchKey] = wrapImportantAndSkipCheck(
|
||||
values[index] ?? values[index - 2] ?? values[0],
|
||||
important,
|
||||
);
|
||||
clone[matchKey] = skipCheck(values[index] ?? values[index - 2] ?? values[0]);
|
||||
});
|
||||
} else {
|
||||
clone[key] = value;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/**
|
||||
* respect https://github.com/cuth/postcss-pxtorem
|
||||
*/
|
||||
// @ts-ignore
|
||||
import unitless from '@emotion/unitless';
|
||||
import type { CSSObject } from '..';
|
||||
import type { Transformer } from './interface';
|
||||
|
|
|
|||
|
|
@ -1,37 +1,12 @@
|
|||
import hash from '@emotion/hash';
|
||||
import canUseDom from '../../canUseDom';
|
||||
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
|
||||
import { ATTR_MARK, ATTR_TOKEN } from '../StyleContext';
|
||||
import { Theme } from '../theme';
|
||||
import { removeCSS, updateCSS } from '../../vc-util/Dom/dynamicCSS';
|
||||
import canUseDom from '../canUseDom';
|
||||
|
||||
// Create a cache for memo concat
|
||||
type NestWeakMap<T> = WeakMap<object, NestWeakMap<T> | T>;
|
||||
const resultCache: NestWeakMap<object> = new WeakMap();
|
||||
const RESULT_VALUE = {};
|
||||
|
||||
export function memoResult<T extends object, R>(callback: () => R, deps: T[]): R {
|
||||
let current: WeakMap<any, any> = resultCache;
|
||||
for (let i = 0; i < deps.length; i += 1) {
|
||||
const dep = deps[i];
|
||||
if (!current.has(dep)) {
|
||||
current.set(dep, new WeakMap());
|
||||
}
|
||||
current = current.get(dep)!;
|
||||
}
|
||||
|
||||
if (!current.has(RESULT_VALUE)) {
|
||||
current.set(RESULT_VALUE, callback());
|
||||
}
|
||||
|
||||
return current.get(RESULT_VALUE);
|
||||
}
|
||||
import { Theme } from './theme';
|
||||
|
||||
// Create a cache here to avoid always loop generate
|
||||
const flattenTokenCache = new WeakMap<any, string>();
|
||||
|
||||
/**
|
||||
* Flatten token to string, this will auto cache the result when token not change
|
||||
*/
|
||||
export function flattenToken(token: any) {
|
||||
let str = flattenTokenCache.get(token) || '';
|
||||
|
||||
|
|
@ -141,39 +116,3 @@ export function supportLogicProps(): boolean {
|
|||
|
||||
return canLogic!;
|
||||
}
|
||||
|
||||
export const isClientSide = canUseDom();
|
||||
|
||||
export function unit(num: string | number) {
|
||||
if (typeof num === 'number') {
|
||||
return `${num}px`;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
export function toStyleStr(
|
||||
style: string,
|
||||
tokenKey?: string,
|
||||
styleId?: string,
|
||||
customizeAttrs: Record<string, string> = {},
|
||||
plain = false,
|
||||
) {
|
||||
if (plain) {
|
||||
return style;
|
||||
}
|
||||
const attrs: Record<string, string | undefined> = {
|
||||
...customizeAttrs,
|
||||
[ATTR_TOKEN]: tokenKey,
|
||||
[ATTR_MARK]: styleId,
|
||||
};
|
||||
|
||||
const attrStr = Object.keys(attrs)
|
||||
.map(attr => {
|
||||
const val = attrs[attr];
|
||||
return val ? `${attr}="${val}"` : null;
|
||||
})
|
||||
.filter(v => v)
|
||||
.join(' ');
|
||||
|
||||
return `<style ${attrStr}>${style}</style>`;
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
export const token2CSSVar = (token: string, prefix = '') => {
|
||||
return `--${prefix ? `${prefix}-` : ''}${token}`
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
||||
.replace(/([A-Z]+)([A-Z][a-z0-9]+)/g, '$1-$2')
|
||||
.replace(/([a-z])([A-Z0-9])/g, '$1-$2')
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
export const serializeCSSVar = <T extends Record<string, any>>(
|
||||
cssVars: T,
|
||||
hashId: string,
|
||||
options?: {
|
||||
scope?: string;
|
||||
},
|
||||
) => {
|
||||
if (!Object.keys(cssVars).length) {
|
||||
return '';
|
||||
}
|
||||
return `.${hashId}${options?.scope ? `.${options.scope}` : ''}{${Object.entries(cssVars)
|
||||
.map(([key, value]) => `${key}:${value};`)
|
||||
.join('')}}`;
|
||||
};
|
||||
|
||||
export type TokenWithCSSVar<V, T extends Record<string, V> = Record<string, V>> = {
|
||||
[key in keyof T]?: string | V;
|
||||
};
|
||||
|
||||
export const transformToken = <V, T extends Record<string, V> = Record<string, V>>(
|
||||
token: T,
|
||||
themeKey: string,
|
||||
config?: {
|
||||
prefix?: string;
|
||||
ignore?: {
|
||||
[key in keyof T]?: boolean;
|
||||
};
|
||||
unitless?: {
|
||||
[key in keyof T]?: boolean;
|
||||
};
|
||||
preserve?: {
|
||||
[key in keyof T]?: boolean;
|
||||
};
|
||||
scope?: string;
|
||||
},
|
||||
): [TokenWithCSSVar<V, T>, string] => {
|
||||
const cssVars: Record<string, string> = {};
|
||||
const result: TokenWithCSSVar<V, T> = {};
|
||||
Object.entries(token).forEach(([key, value]) => {
|
||||
if (config?.preserve?.[key]) {
|
||||
result[key as keyof T] = value;
|
||||
} else if ((typeof value === 'string' || typeof value === 'number') && !config?.ignore?.[key]) {
|
||||
const cssVar = token2CSSVar(key, config?.prefix);
|
||||
cssVars[cssVar] =
|
||||
typeof value === 'number' && !config?.unitless?.[key] ? `${value}px` : String(value);
|
||||
result[key as keyof T] = `var(${cssVar})`;
|
||||
}
|
||||
});
|
||||
return [result, serializeCSSVar(cssVars, themeKey, { scope: config?.scope })];
|
||||
};
|
||||
|
|
@ -2,31 +2,32 @@ export function isWindow(obj: any): obj is Window {
|
|||
return obj !== null && obj !== undefined && obj === obj.window;
|
||||
}
|
||||
|
||||
const getScroll = (target: HTMLElement | Window | Document | null): number => {
|
||||
export default function getScroll(
|
||||
target: HTMLElement | Window | Document | null,
|
||||
top: boolean,
|
||||
): number {
|
||||
if (typeof window === 'undefined') {
|
||||
return 0;
|
||||
}
|
||||
const method = top ? 'scrollTop' : 'scrollLeft';
|
||||
let result = 0;
|
||||
if (isWindow(target)) {
|
||||
result = target.pageYOffset;
|
||||
result = target[top ? 'scrollY' : 'scrollX'];
|
||||
} else if (target instanceof Document) {
|
||||
result = target.documentElement.scrollTop;
|
||||
result = target.documentElement[method];
|
||||
} else if (target instanceof HTMLElement) {
|
||||
result = target.scrollTop;
|
||||
result = target[method];
|
||||
} else if (target) {
|
||||
// According to the type inference, the `target` is `never` type.
|
||||
// Since we configured the loose mode type checking, and supports mocking the target with such shape below::
|
||||
// `{ documentElement: { scrollLeft: 200, scrollTop: 400 } }`,
|
||||
// the program may falls into this branch.
|
||||
// Check the corresponding tests for details. Don't sure what is the real scenario this happens.
|
||||
/* biome-ignore lint/complexity/useLiteralKeys: target is a never type */ /* eslint-disable-next-line dot-notation */
|
||||
result = target['scrollTop'];
|
||||
result = target[method];
|
||||
}
|
||||
|
||||
if (target && !isWindow(target) && typeof result !== 'number') {
|
||||
result = (target.ownerDocument ?? (target as Document)).documentElement?.scrollTop;
|
||||
result = ((target.ownerDocument ?? target) as any).documentElement?.[method];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export default getScroll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
import type { Ref, ShallowRef } from 'vue';
|
||||
|
||||
import { shallowRef, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
function useLayoutEffect(
|
||||
fn: (mount: boolean) => void | VoidFunction,
|
||||
deps?: Ref<any> | Ref<any>[] | ShallowRef<any> | ShallowRef<any>[],
|
||||
) {
|
||||
const firstMount = shallowRef(true);
|
||||
const cleanupFn = ref(null);
|
||||
let stopWatch = null;
|
||||
|
||||
stopWatch = watch(
|
||||
deps,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
if (cleanupFn.value) {
|
||||
cleanupFn.value();
|
||||
}
|
||||
cleanupFn.value = fn(firstMount.value);
|
||||
});
|
||||
},
|
||||
{ immediate: true, flush: 'post' },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
firstMount.value = false;
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (cleanupFn.value) {
|
||||
cleanupFn.value();
|
||||
}
|
||||
if (stopWatch) {
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const useLayoutUpdateEffect = (callback, deps) => {
|
||||
useLayoutEffect(firstMount => {
|
||||
if (!firstMount) {
|
||||
return callback();
|
||||
}
|
||||
}, deps);
|
||||
};
|
||||
|
||||
export default useLayoutEffect;
|
||||
|
|
@ -14,7 +14,7 @@ interface ScrollToOptions {
|
|||
export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||
const { getContainer = () => window, callback, duration = 450 } = options;
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container);
|
||||
const scrollTop = getScroll(container, true);
|
||||
const startTime = Date.now();
|
||||
|
||||
const frameFunc = () => {
|
||||
|
|
|
|||
|
|
@ -27,11 +27,10 @@ import useStyle from './style';
|
|||
function getDefaultTarget() {
|
||||
return typeof window !== 'undefined' ? window : null;
|
||||
}
|
||||
const AFFIX_STATUS_NONE = 0;
|
||||
const AFFIX_STATUS_PREPARE = 1;
|
||||
|
||||
type AffixStatus = typeof AFFIX_STATUS_NONE | typeof AFFIX_STATUS_PREPARE;
|
||||
|
||||
enum AffixStatus {
|
||||
None,
|
||||
Prepare,
|
||||
}
|
||||
export interface AffixState {
|
||||
affixStyle?: CSSProperties;
|
||||
placeholderStyle?: CSSProperties;
|
||||
|
|
@ -83,7 +82,7 @@ const Affix = defineComponent({
|
|||
const state = reactive({
|
||||
affixStyle: undefined,
|
||||
placeholderStyle: undefined,
|
||||
status: AFFIX_STATUS_NONE,
|
||||
status: AffixStatus.None,
|
||||
lastAffix: false,
|
||||
prevTarget: null,
|
||||
timeout: null,
|
||||
|
|
@ -99,12 +98,7 @@ const Affix = defineComponent({
|
|||
const measure = () => {
|
||||
const { status, lastAffix } = state;
|
||||
const { target } = props;
|
||||
if (
|
||||
status !== AFFIX_STATUS_PREPARE ||
|
||||
!fixedNode.value ||
|
||||
!placeholderNode.value ||
|
||||
!target
|
||||
) {
|
||||
if (status !== AffixStatus.Prepare || !fixedNode.value || !placeholderNode.value || !target) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +108,7 @@ const Affix = defineComponent({
|
|||
}
|
||||
|
||||
const newState = {
|
||||
status: AFFIX_STATUS_NONE,
|
||||
status: AffixStatus.None,
|
||||
} as AffixState;
|
||||
const placeholderRect = getTargetRect(placeholderNode.value as HTMLElement);
|
||||
|
||||
|
|
@ -178,7 +172,7 @@ const Affix = defineComponent({
|
|||
};
|
||||
const prepareMeasure = () => {
|
||||
Object.assign(state, {
|
||||
status: AFFIX_STATUS_PREPARE,
|
||||
status: AffixStatus.Prepare,
|
||||
affixStyle: undefined,
|
||||
placeholderStyle: undefined,
|
||||
});
|
||||
|
|
@ -259,13 +253,12 @@ const Affix = defineComponent({
|
|||
});
|
||||
|
||||
const { prefixCls } = useConfigInject('affix', props);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
return () => {
|
||||
const { affixStyle, placeholderStyle, status } = state;
|
||||
const className = classNames({
|
||||
[prefixCls.value]: affixStyle,
|
||||
[hashId.value]: true,
|
||||
[cssVarCls.value]: true,
|
||||
});
|
||||
const restProps = omit(props, [
|
||||
'prefixCls',
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import { FullToken, GenerateStyle, genStyleHooks, GetDefaultToken } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 弹出层的 z-index
|
||||
* @descEN z-index of popup
|
||||
*/
|
||||
zIndexPopup: number;
|
||||
}
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
|
||||
interface AffixToken extends FullToken<'Affix'> {
|
||||
//
|
||||
zIndexPopup: number;
|
||||
}
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
|
||||
const { componentCls } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
position: 'fixed',
|
||||
|
|
@ -24,9 +18,10 @@ const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
|
|||
};
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Affix'> = token => ({
|
||||
zIndexPopup: token.zIndexBase + 10,
|
||||
});
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genStyleHooks('Affix', genSharedAffixStyle, prepareComponentToken);
|
||||
export default genComponentStyleHook('Affix', token => {
|
||||
const affixToken = mergeToken<AffixToken>(token, {
|
||||
zIndexPopup: token.zIndexBase + 10,
|
||||
});
|
||||
return [genSharedAffixStyle(affixToken)];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,11 +9,8 @@ export function getTargetRect(target: BindElement): DOMRect {
|
|||
: ({ top: 0, bottom: window.innerHeight } as DOMRect);
|
||||
}
|
||||
|
||||
export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop?: number) {
|
||||
if (
|
||||
offsetTop !== undefined &&
|
||||
Math.round(targetRect.top) > Math.round(placeholderRect.top) - offsetTop
|
||||
) {
|
||||
export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop: number) {
|
||||
if (offsetTop !== undefined && targetRect.top > placeholderRect.top - offsetTop) {
|
||||
return `${offsetTop + targetRect.top}px`;
|
||||
}
|
||||
return undefined;
|
||||
|
|
@ -22,12 +19,9 @@ export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offse
|
|||
export function getFixedBottom(
|
||||
placeholderRect: DOMRect,
|
||||
targetRect: DOMRect,
|
||||
offsetBottom?: number,
|
||||
offsetBottom: number,
|
||||
) {
|
||||
if (
|
||||
offsetBottom !== undefined &&
|
||||
Math.round(targetRect.bottom) < Math.round(placeholderRect.bottom) + offsetBottom
|
||||
) {
|
||||
if (offsetBottom !== undefined && targetRect.bottom < placeholderRect.bottom + offsetBottom) {
|
||||
const targetBottomOffset = window.innerHeight - targetRect.bottom;
|
||||
return `${offsetBottom + targetBottomOffset}px`;
|
||||
}
|
||||
|
|
@ -35,7 +29,7 @@ export function getFixedBottom(
|
|||
}
|
||||
|
||||
// ======================== Observer ========================
|
||||
const TRIGGER_EVENTS: (keyof WindowEventMap)[] = [
|
||||
const TRIGGER_EVENTS = [
|
||||
'resize',
|
||||
'scroll',
|
||||
'touchstart',
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ const Alert = defineComponent({
|
|||
props: alertProps(),
|
||||
setup(props, { slots, emit, attrs, expose }) {
|
||||
const { prefixCls, direction } = useConfigInject('alert', props);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const closing = shallowRef(false);
|
||||
const closed = shallowRef(false);
|
||||
const alertNode = shallowRef();
|
||||
|
|
@ -134,7 +134,6 @@ const Alert = defineComponent({
|
|||
[`${prefixClsValue}-closable`]: closable,
|
||||
[`${prefixClsValue}-rtl`]: direction.value === 'rtl',
|
||||
[hashId.value]: true,
|
||||
[cssVarCls.value]: true,
|
||||
});
|
||||
|
||||
const closeIcon = closable ? (
|
||||
|
|
|
|||
|
|
@ -1,29 +1,13 @@
|
|||
import { CSSObject, unit } from '../../_util/cssinjs';
|
||||
import { FullToken, GenerateStyle, genStyleHooks, GetDefaultToken } from '../../theme/internal';
|
||||
import type { CSSInterpolation, CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent } from '../../style';
|
||||
import { CSSProperties } from 'vue';
|
||||
|
||||
export interface ComponentToken {
|
||||
// Component token here
|
||||
/**
|
||||
* @desc 默认内间距
|
||||
* @descEN Default padding
|
||||
*/
|
||||
defaultPadding: CSSProperties['padding'];
|
||||
/**
|
||||
* @desc 带有描述的内间距
|
||||
* @descEN Padding with description
|
||||
*/
|
||||
withDescriptionPadding: CSSProperties['padding'];
|
||||
/**
|
||||
* @desc 带有描述时的图标尺寸
|
||||
* @descEN Icon size with description
|
||||
*/
|
||||
withDescriptionIconSize: number;
|
||||
}
|
||||
export interface ComponentToken {}
|
||||
|
||||
type AlertToken = FullToken<'Alert'> & {
|
||||
// Custom token here
|
||||
alertIconSizeLG: number;
|
||||
alertPaddingHorizontal: number;
|
||||
};
|
||||
|
||||
const genAlertTypeStyle = (
|
||||
|
|
@ -33,8 +17,8 @@ const genAlertTypeStyle = (
|
|||
token: AlertToken,
|
||||
alertCls: string,
|
||||
): CSSObject => ({
|
||||
background: bgColor,
|
||||
border: `${unit(token.lineWidth)} ${token.lineType} ${borderColor}`,
|
||||
backgroundColor: bgColor,
|
||||
border: `${token.lineWidth}px ${token.lineType} ${borderColor}`,
|
||||
[`${alertCls}-icon`]: {
|
||||
color: iconColor,
|
||||
},
|
||||
|
|
@ -51,11 +35,12 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
|
|||
lineHeight,
|
||||
borderRadiusLG: borderRadius,
|
||||
motionEaseInOutCirc,
|
||||
withDescriptionIconSize,
|
||||
alertIconSizeLG,
|
||||
colorText,
|
||||
colorTextHeading,
|
||||
withDescriptionPadding,
|
||||
defaultPadding,
|
||||
paddingContentVerticalSM,
|
||||
alertPaddingHorizontal,
|
||||
paddingMD,
|
||||
paddingContentHorizontalLG,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
|
|
@ -64,7 +49,7 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
|
|||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: defaultPadding,
|
||||
padding: `${paddingContentVerticalSM}px ${alertPaddingHorizontal}px`, // Fixed horizontal padding here.
|
||||
wordWrap: 'break-word',
|
||||
borderRadius,
|
||||
|
||||
|
|
@ -82,14 +67,14 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
|
|||
lineHeight: 0,
|
||||
},
|
||||
|
||||
'&-description': {
|
||||
[`&-description`]: {
|
||||
display: 'none',
|
||||
fontSize,
|
||||
lineHeight,
|
||||
},
|
||||
|
||||
'&-message': {
|
||||
color: colorTextHeading,
|
||||
color: colorText,
|
||||
},
|
||||
|
||||
[`&${componentCls}-motion-leave`]: {
|
||||
|
|
@ -111,23 +96,24 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
|
|||
|
||||
[`${componentCls}-with-description`]: {
|
||||
alignItems: 'flex-start',
|
||||
padding: withDescriptionPadding,
|
||||
paddingInline: paddingContentHorizontalLG,
|
||||
paddingBlock: paddingMD,
|
||||
|
||||
[`${componentCls}-icon`]: {
|
||||
marginInlineEnd: marginSM,
|
||||
fontSize: withDescriptionIconSize,
|
||||
fontSize: alertIconSizeLG,
|
||||
lineHeight: 0,
|
||||
},
|
||||
|
||||
[`${componentCls}-message`]: {
|
||||
display: 'block',
|
||||
marginBottom: marginXS,
|
||||
color: colorTextHeading,
|
||||
color: colorText,
|
||||
fontSize: fontSizeLG,
|
||||
},
|
||||
|
||||
[`${componentCls}-description`]: {
|
||||
display: 'block',
|
||||
color: colorText,
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -201,7 +187,7 @@ export const genActionStyle: GenerateStyle<AlertToken> = (token: AlertToken): CS
|
|||
|
||||
return {
|
||||
[componentCls]: {
|
||||
'&-action': {
|
||||
[`&-action`]: {
|
||||
marginInlineStart: marginXS,
|
||||
},
|
||||
|
||||
|
|
@ -210,7 +196,7 @@ export const genActionStyle: GenerateStyle<AlertToken> = (token: AlertToken): CS
|
|||
padding: 0,
|
||||
overflow: 'hidden',
|
||||
fontSize: fontSizeIcon,
|
||||
lineHeight: unit(fontSizeIcon),
|
||||
lineHeight: `${fontSizeIcon}px`,
|
||||
backgroundColor: 'transparent',
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
|
|
@ -236,17 +222,19 @@ export const genActionStyle: GenerateStyle<AlertToken> = (token: AlertToken): CS
|
|||
};
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Alert'> = token => {
|
||||
const paddingHorizontal = 12; // Fixed value here.
|
||||
return {
|
||||
withDescriptionIconSize: token.fontSizeHeading3,
|
||||
defaultPadding: `${token.paddingContentVerticalSM}px ${paddingHorizontal}px`,
|
||||
withDescriptionPadding: `${token.paddingMD}px ${token.paddingContentHorizontalLG}px`,
|
||||
};
|
||||
};
|
||||
export const genAlertStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSInterpolation => [
|
||||
genBaseStyle(token),
|
||||
genTypeStyle(token),
|
||||
genActionStyle(token),
|
||||
];
|
||||
|
||||
export default genStyleHooks(
|
||||
'Alert',
|
||||
token => [genBaseStyle(token), genTypeStyle(token), genActionStyle(token)],
|
||||
prepareComponentToken,
|
||||
);
|
||||
export default genComponentStyleHook('Alert', token => {
|
||||
const { fontSizeHeading3 } = token;
|
||||
|
||||
const alertToken = mergeToken<AlertToken>(token, {
|
||||
alertIconSizeLG: fontSizeHeading3,
|
||||
alertPaddingHorizontal: 12, // Fixed value here.
|
||||
});
|
||||
|
||||
return [genAlertStyle(alertToken)];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import AnchorLink from './AnchorLink';
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import devWarning from '../vc-util/devWarning';
|
||||
import { arrayType } from '../_util/type';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
|
||||
|
||||
export type AnchorDirection = 'vertical' | 'horizontal';
|
||||
|
||||
|
|
@ -40,7 +39,8 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
|
|||
|
||||
if (rect.width || rect.height) {
|
||||
if (container === window) {
|
||||
return rect.top - element.ownerDocument!.documentElement!.clientTop;
|
||||
container = element.ownerDocument!.documentElement!;
|
||||
return rect.top - container.clientTop;
|
||||
}
|
||||
return rect.top - (container as HTMLElement).getBoundingClientRect().top;
|
||||
}
|
||||
|
|
@ -70,7 +70,6 @@ export const anchorProps = () => ({
|
|||
targetOffset: Number,
|
||||
items: arrayType<AnchorLinkItemProps[]>(),
|
||||
direction: PropTypes.oneOf(['vertical', 'horizontal'] as AnchorDirection[]).def('vertical'),
|
||||
replace: Boolean,
|
||||
onChange: Function as PropType<(currentActiveLink: string) => void>,
|
||||
onClick: Function as PropType<(e: MouseEvent, link: { title: any; href: string }) => void>,
|
||||
});
|
||||
|
|
@ -92,7 +91,7 @@ export default defineComponent({
|
|||
setup(props, { emit, attrs, slots, expose }) {
|
||||
const { prefixCls, getTargetContainer, direction } = useConfigInject('anchor', props);
|
||||
const anchorDirection = computed(() => props.direction ?? 'vertical');
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
devWarning(
|
||||
props.items && typeof slots.default !== 'function',
|
||||
|
|
@ -134,7 +133,7 @@ export default defineComponent({
|
|||
const target = document.getElementById(sharpLinkMatch[1]);
|
||||
if (target) {
|
||||
const top = getOffsetTop(target, container);
|
||||
if (top <= offsetTop + bounds) {
|
||||
if (top < offsetTop + bounds) {
|
||||
linkSections.push({
|
||||
link,
|
||||
top,
|
||||
|
|
@ -171,7 +170,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const container = getContainer.value();
|
||||
const scrollTop = getScroll(container);
|
||||
const scrollTop = getScroll(container, true);
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
let y = scrollTop + eleOffsetTop;
|
||||
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
|
||||
|
|
@ -278,7 +277,6 @@ export default defineComponent({
|
|||
title={title}
|
||||
customTitleProps={option}
|
||||
v-slots={{ customTitle: slots.customTitle }}
|
||||
replace={props.replace}
|
||||
>
|
||||
{anchorDirection.value === 'vertical' ? createNestedLink(children) : null}
|
||||
</AnchorLink>
|
||||
|
|
@ -286,7 +284,7 @@ export default defineComponent({
|
|||
})
|
||||
: null;
|
||||
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
|
||||
return () => {
|
||||
const { offsetTop, affix, showInkInFixed } = props;
|
||||
|
|
@ -298,8 +296,6 @@ export default defineComponent({
|
|||
const wrapperClass = classNames(hashId.value, props.wrapperClass, `${pre}-wrapper`, {
|
||||
[`${pre}-wrapper-horizontal`]: anchorDirection.value === 'horizontal',
|
||||
[`${pre}-rtl`]: direction.value === 'rtl',
|
||||
[rootCls.value]: true,
|
||||
[cssVarCls.value]: true,
|
||||
});
|
||||
|
||||
const anchorClass = classNames(pre, {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ export const anchorLinkProps = () => ({
|
|||
href: String,
|
||||
title: anyType<VueNode | ((item: any) => VueNode)>(),
|
||||
target: String,
|
||||
replace: Boolean,
|
||||
/* private use */
|
||||
customTitleProps: objectType<AnchorLinkItemProps>(),
|
||||
});
|
||||
|
|
@ -54,10 +53,6 @@ export default defineComponent({
|
|||
const { href } = props;
|
||||
contextHandleClick(e, { title: mergedTitle, href });
|
||||
scrollTo(href);
|
||||
if (props.replace) {
|
||||
e.preventDefault();
|
||||
window.location.replace(href);
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
|
|
|
|||
|
|
@ -1,55 +1,21 @@
|
|||
import { unit } from '../../_util/cssinjs';
|
||||
import {
|
||||
FullToken,
|
||||
GenerateStyle,
|
||||
genStyleHooks,
|
||||
GetDefaultToken,
|
||||
mergeToken,
|
||||
} from '../../theme/internal';
|
||||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent, textEllipsis } from '../../style';
|
||||
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 链接纵向内间距
|
||||
* @descEN Vertical padding of link
|
||||
*/
|
||||
linkPaddingBlock: number;
|
||||
/**
|
||||
* @desc 链接横向内间距
|
||||
* @descEN Horizontal padding of link
|
||||
*/
|
||||
linkPaddingInlineStart: number;
|
||||
}
|
||||
export interface ComponentToken {}
|
||||
|
||||
/**
|
||||
* @desc Anchor 组件的 Token
|
||||
* @descEN Token for Anchor component
|
||||
*/
|
||||
interface AnchorToken extends FullToken<'Anchor'> {
|
||||
/**
|
||||
* @desc 容器块偏移量
|
||||
* @descEN Holder block offset
|
||||
*/
|
||||
holderOffsetBlock: number;
|
||||
/**
|
||||
* @desc 次级锚点块内间距
|
||||
* @descEN Secondary anchor block padding
|
||||
*/
|
||||
anchorPaddingBlockSecondary: number | string;
|
||||
/**
|
||||
* @desc 锚点球大小
|
||||
* @descEN Anchor ball size
|
||||
*/
|
||||
anchorBallSize: number | string;
|
||||
/**
|
||||
* @desc 锚点标题块
|
||||
* @descEN Anchor title block
|
||||
*/
|
||||
anchorTitleBlock: number | string;
|
||||
anchorPaddingBlock: number;
|
||||
anchorPaddingBlockSecondary: number;
|
||||
anchorPaddingInline: number;
|
||||
anchorBallSize: number;
|
||||
anchorTitleBlock: number;
|
||||
}
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = token => {
|
||||
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||
const {
|
||||
componentCls,
|
||||
holderOffsetBlock,
|
||||
|
|
@ -58,25 +24,26 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = token => {
|
|||
colorPrimary,
|
||||
lineType,
|
||||
colorSplit,
|
||||
calc,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-wrapper`]: {
|
||||
marginBlockStart: calc(holderOffsetBlock).mul(-1).equal(),
|
||||
marginBlockStart: -holderOffsetBlock,
|
||||
paddingBlockStart: holderOffsetBlock,
|
||||
|
||||
// delete overflow: auto
|
||||
// overflow: 'auto',
|
||||
|
||||
backgroundColor: 'transparent',
|
||||
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
position: 'relative',
|
||||
paddingInlineStart: lineWidthBold,
|
||||
|
||||
[`${componentCls}-link`]: {
|
||||
paddingBlock: token.linkPaddingBlock,
|
||||
paddingInline: `${unit(token.linkPaddingInlineStart)} 0`,
|
||||
paddingBlock: token.anchorPaddingBlock,
|
||||
paddingInline: `${token.anchorPaddingInline}px 0`,
|
||||
|
||||
'&-title': {
|
||||
...textEllipsis,
|
||||
|
|
@ -106,21 +73,28 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = token => {
|
|||
[componentCls]: {
|
||||
'&::before': {
|
||||
position: 'absolute',
|
||||
insetInlineStart: 0,
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: 0,
|
||||
},
|
||||
top: 0,
|
||||
height: '100%',
|
||||
borderInlineStart: `${unit(lineWidthBold)} ${lineType} ${colorSplit}`,
|
||||
borderInlineStart: `${lineWidthBold}px ${lineType} ${colorSplit}`,
|
||||
content: '" "',
|
||||
},
|
||||
|
||||
[`${componentCls}-ink`]: {
|
||||
position: 'absolute',
|
||||
insetInlineStart: 0,
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: 0,
|
||||
},
|
||||
display: 'none',
|
||||
transform: 'translateY(-50%)',
|
||||
transition: `top ${motionDurationSlow} ease-in-out`,
|
||||
width: lineWidthBold,
|
||||
backgroundColor: colorPrimary,
|
||||
|
||||
[`&${componentCls}-ink-visible`]: {
|
||||
display: 'inline-block',
|
||||
},
|
||||
|
|
@ -135,7 +109,7 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = token => {
|
|||
};
|
||||
};
|
||||
|
||||
const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = token => {
|
||||
const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||
const { componentCls, motionDurationSlow, lineWidthBold, colorPrimary } = token;
|
||||
|
||||
return {
|
||||
|
|
@ -153,7 +127,7 @@ const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = token => {
|
|||
value: 0,
|
||||
},
|
||||
bottom: 0,
|
||||
borderBottom: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`,
|
||||
borderBottom: `1px ${token.lineType} ${token.colorSplit}`,
|
||||
content: '" "',
|
||||
},
|
||||
|
||||
|
|
@ -183,23 +157,17 @@ const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = token => {
|
|||
};
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Anchor'> = token => ({
|
||||
linkPaddingBlock: token.paddingXXS,
|
||||
linkPaddingInlineStart: token.padding,
|
||||
});
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genStyleHooks(
|
||||
'Anchor',
|
||||
token => {
|
||||
const { fontSize, fontSizeLG, paddingXXS, calc } = token;
|
||||
export default genComponentStyleHook('Anchor', token => {
|
||||
const { fontSize, fontSizeLG, padding, paddingXXS } = token;
|
||||
|
||||
const anchorToken = mergeToken<AnchorToken>(token, {
|
||||
holderOffsetBlock: paddingXXS,
|
||||
anchorPaddingBlockSecondary: calc(paddingXXS).div(2).equal(),
|
||||
anchorTitleBlock: calc(fontSize).div(14).mul(3).equal(),
|
||||
anchorBallSize: calc(fontSizeLG).div(2).equal(),
|
||||
anchorPaddingBlock: paddingXXS,
|
||||
anchorPaddingBlockSecondary: paddingXXS / 2,
|
||||
anchorPaddingInline: padding,
|
||||
anchorTitleBlock: (fontSize / 14) * 3,
|
||||
anchorBallSize: fontSizeLG / 2,
|
||||
});
|
||||
return [genSharedAnchorStyle(anchorToken), genSharedAnchorHorizontalStyle(anchorToken)];
|
||||
},
|
||||
prepareComponentToken,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import type { FullToken, GenerateStyle } from '../../theme/internal';
|
|||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { genPresetColor, resetComponent } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
interface BadgeToken extends FullToken<'Badge'> {
|
||||
badgeFontHeight: number;
|
||||
badgeZIndex: number | string;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import type { FullToken, GenerateStyle } from '../../theme/internal';
|
|||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { genFocusStyle, resetComponent } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
interface BreadcrumbToken extends FullToken<'Breadcrumb'> {
|
||||
breadcrumbBaseColor: string;
|
||||
breadcrumbFontSize: number;
|
||||
|
|
|
|||
|
|
@ -45,11 +45,7 @@ export default defineComponent({
|
|||
break;
|
||||
default:
|
||||
// eslint-disable-next-line no-console
|
||||
devWarning(
|
||||
!size || ['large', 'small', 'middle'].includes(size),
|
||||
'Button.Group',
|
||||
'Invalid prop `size`.',
|
||||
);
|
||||
devWarning(!size, 'Button.Group', 'Invalid prop `size`.');
|
||||
}
|
||||
return {
|
||||
[`${prefixCls.value}`]: true,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export default defineComponent({
|
|||
// emits: ['click', 'mousedown'],
|
||||
setup(props, { slots, attrs, emit, expose }) {
|
||||
const { prefixCls, autoInsertSpaceInButton, direction, size } = useConfigInject('btn', props);
|
||||
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const groupSizeContext = GroupSizeContext.useInject();
|
||||
const disabledContext = useInjectDisabled();
|
||||
const mergedDisabled = computed(() => props.disabled ?? disabledContext.value);
|
||||
|
|
@ -95,7 +95,6 @@ export default defineComponent({
|
|||
compactItemClassnames.value,
|
||||
{
|
||||
[hashId.value]: true,
|
||||
[cssVarCls.value]: true,
|
||||
[`${pre}`]: true,
|
||||
[`${pre}-${shape}`]: shape !== 'default' && shape,
|
||||
[`${pre}-${type}`]: type,
|
||||
|
|
@ -217,7 +216,7 @@ export default defineComponent({
|
|||
);
|
||||
|
||||
if (href !== undefined) {
|
||||
return wrapCSSVar(
|
||||
return wrapSSR(
|
||||
<a {...buttonProps} href={href} target={target} ref={buttonNodeRef}>
|
||||
{iconNode}
|
||||
{kids}
|
||||
|
|
@ -240,7 +239,7 @@ export default defineComponent({
|
|||
);
|
||||
}
|
||||
|
||||
return wrapCSSVar(buttonNode);
|
||||
return wrapSSR(buttonNode);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ If you want specific control over the positioning and placement of the `Icon`, t
|
|||
|
||||
<template>
|
||||
<a-space direction="vertical">
|
||||
<a-space warp>
|
||||
<a-space wrap>
|
||||
<a-tooltip title="search">
|
||||
<a-button type="primary" shape="circle" :icon="h(SearchOutlined)" />
|
||||
</a-tooltip>
|
||||
|
|
@ -32,7 +32,7 @@ If you want specific control over the positioning and placement of the `Icon`, t
|
|||
</a-tooltip>
|
||||
<a-button :icon="h(SearchOutlined)">Search</a-button>
|
||||
</a-space>
|
||||
<a-space warp>
|
||||
<a-space wrap>
|
||||
<a-tooltip title="search">
|
||||
<a-button shape="circle" :icon="h(SearchOutlined)" />
|
||||
</a-tooltip>
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
// Style as inline component
|
||||
import type { ButtonToken } from './token';
|
||||
import { prepareComponentToken, prepareToken } from './token';
|
||||
import { genCompactItemStyle } from '../../style/compact-item';
|
||||
import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import { genSubStyleComponent } from '../../theme/internal';
|
||||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import { unit } from '../../_util/cssinjs';
|
||||
|
||||
const genButtonCompactStyle: GenerateStyle<ButtonToken, CSSObject> = token => {
|
||||
const { componentCls, calc } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
// Special styles for Primary Button
|
||||
[`&-compact-item${componentCls}-primary`]: {
|
||||
[`&:not([disabled]) + ${componentCls}-compact-item${componentCls}-primary:not([disabled])`]:
|
||||
{
|
||||
position: 'relative',
|
||||
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
top: calc(token.lineWidth).mul(-1).equal(),
|
||||
insetInlineStart: calc(token.lineWidth).mul(-1).equal(),
|
||||
display: 'inline-block',
|
||||
width: token.lineWidth,
|
||||
height: `calc(100% + ${unit(token.lineWidth)} * 2)`,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Special styles for Primary Button
|
||||
'&-compact-vertical-item': {
|
||||
[`&${componentCls}-primary`]: {
|
||||
[`&:not([disabled]) + ${componentCls}-compact-vertical-item${componentCls}-primary:not([disabled])`]:
|
||||
{
|
||||
position: 'relative',
|
||||
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
top: calc(token.lineWidth).mul(-1).equal(),
|
||||
insetInlineStart: calc(token.lineWidth).mul(-1).equal(),
|
||||
display: 'inline-block',
|
||||
width: `calc(100% + ${unit(token.lineWidth)} * 2)`,
|
||||
height: token.lineWidth,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genSubStyleComponent(
|
||||
['Button', 'compact'],
|
||||
token => {
|
||||
const buttonToken = prepareToken(token);
|
||||
|
||||
return [
|
||||
// Space Compact
|
||||
genCompactItemStyle(buttonToken),
|
||||
genCompactItemVerticalStyle(buttonToken),
|
||||
genButtonCompactStyle(buttonToken),
|
||||
] as CSSObject[];
|
||||
},
|
||||
prepareComponentToken,
|
||||
);
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import type { ButtonToken } from './token';
|
||||
import type { ButtonToken } from '.';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genButtonBorderStyle = (buttonTypeCls: string, borderColor: string) => ({
|
||||
|
|
@ -23,8 +22,8 @@ const genButtonBorderStyle = (buttonTypeCls: string, borderColor: string) => ({
|
|||
},
|
||||
});
|
||||
|
||||
const genGroupStyle: GenerateStyle<ButtonToken, CSSObject> = token => {
|
||||
const { componentCls, fontSize, lineWidth, groupBorderColor, colorErrorHover } = token;
|
||||
const genGroupStyle: GenerateStyle<ButtonToken> = token => {
|
||||
const { componentCls, fontSize, lineWidth, colorPrimaryHover, colorErrorHover } = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-group`]: [
|
||||
|
|
@ -42,7 +41,7 @@ const genGroupStyle: GenerateStyle<ButtonToken, CSSObject> = token => {
|
|||
},
|
||||
|
||||
'&:not(:first-child)': {
|
||||
marginInlineStart: token.calc(lineWidth).mul(-1).equal(),
|
||||
marginInlineStart: -lineWidth,
|
||||
|
||||
[`&, & > ${componentCls}`]: {
|
||||
borderStartStartRadius: 0,
|
||||
|
|
@ -72,7 +71,7 @@ const genGroupStyle: GenerateStyle<ButtonToken, CSSObject> = token => {
|
|||
},
|
||||
|
||||
// Border Color
|
||||
genButtonBorderStyle(`${componentCls}-primary`, groupBorderColor),
|
||||
genButtonBorderStyle(`${componentCls}-primary`, colorPrimaryHover),
|
||||
genButtonBorderStyle(`${componentCls}-danger`, colorErrorHover),
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,59 +1,51 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import { unit } from '../../_util/cssinjs';
|
||||
|
||||
import { genFocusStyle } from '../../style';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import { genStyleHooks, mergeToken } from '../../theme/internal';
|
||||
import type { CSSInterpolation, CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genGroupStyle from './group';
|
||||
import type { ButtonToken, ComponentToken } from './token';
|
||||
import { prepareComponentToken, prepareToken } from './token';
|
||||
import { genFocusStyle } from '../../style';
|
||||
import { genCompactItemStyle } from '../../style/compact-item';
|
||||
import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical';
|
||||
|
||||
export type { ComponentToken };
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {}
|
||||
|
||||
export interface ButtonToken extends FullToken<'Button'> {
|
||||
// FIXME: should be removed
|
||||
colorOutlineDefault: string;
|
||||
buttonPaddingHorizontal: number;
|
||||
}
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSSObject => {
|
||||
const { componentCls, iconCls, fontWeight } = token;
|
||||
const { componentCls, iconCls } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
outline: 'none',
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
fontWeight,
|
||||
fontWeight: 400,
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
backgroundImage: 'none',
|
||||
background: 'transparent',
|
||||
border: `${unit(token.lineWidth)} ${token.lineType} transparent`,
|
||||
backgroundColor: 'transparent',
|
||||
border: `${token.lineWidth}px ${token.lineType} transparent`,
|
||||
cursor: 'pointer',
|
||||
transition: `all ${token.motionDurationMid} ${token.motionEaseInOut}`,
|
||||
userSelect: 'none',
|
||||
touchAction: 'manipulation',
|
||||
lineHeight: token.lineHeight,
|
||||
color: token.colorText,
|
||||
|
||||
'&:disabled > *': {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
|
||||
'> span': {
|
||||
display: 'inline-block',
|
||||
},
|
||||
|
||||
[`${componentCls}-icon`]: {
|
||||
lineHeight: 0,
|
||||
},
|
||||
|
||||
// Leave a space between icon and text.
|
||||
[`> ${iconCls} + span, > span + ${iconCls}`]: {
|
||||
marginInlineStart: token.marginXS,
|
||||
},
|
||||
|
||||
[`&:not(${componentCls}-icon-only) > ${componentCls}-icon`]: {
|
||||
[`&${componentCls}-loading-icon, &:not(:last-child)`]: {
|
||||
marginInlineEnd: token.marginXS,
|
||||
},
|
||||
},
|
||||
|
||||
'> a': {
|
||||
color: 'currentColor',
|
||||
},
|
||||
|
|
@ -62,29 +54,54 @@ const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSS
|
|||
...genFocusStyle(token),
|
||||
},
|
||||
|
||||
[`&${componentCls}-two-chinese-chars::first-letter`]: {
|
||||
letterSpacing: '0.34em',
|
||||
},
|
||||
|
||||
[`&${componentCls}-two-chinese-chars > *:not(${iconCls})`]: {
|
||||
marginInlineEnd: '-0.34em',
|
||||
letterSpacing: '0.34em',
|
||||
},
|
||||
|
||||
// make `btn-icon-only` not too narrow
|
||||
[`&-icon-only${componentCls}-compact-item`]: {
|
||||
flex: 'none',
|
||||
},
|
||||
// Special styles for Primary Button
|
||||
[`&-compact-item${componentCls}-primary`]: {
|
||||
[`&:not([disabled]) + ${componentCls}-compact-item${componentCls}-primary:not([disabled])`]:
|
||||
{
|
||||
position: 'relative',
|
||||
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
top: -token.lineWidth,
|
||||
insetInlineStart: -token.lineWidth,
|
||||
display: 'inline-block',
|
||||
width: token.lineWidth,
|
||||
height: `calc(100% + ${token.lineWidth * 2}px)`,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
content: '""',
|
||||
},
|
||||
} as CSSObject;
|
||||
},
|
||||
},
|
||||
// Special styles for Primary Button
|
||||
'&-compact-vertical-item': {
|
||||
[`&${componentCls}-primary`]: {
|
||||
[`&:not([disabled]) + ${componentCls}-compact-vertical-item${componentCls}-primary:not([disabled])`]:
|
||||
{
|
||||
position: 'relative',
|
||||
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
top: -token.lineWidth,
|
||||
insetInlineStart: -token.lineWidth,
|
||||
display: 'inline-block',
|
||||
width: `calc(100% + ${token.lineWidth * 2}px)`,
|
||||
height: token.lineWidth,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const genHoverActiveButtonStyle = (
|
||||
btnCls: string,
|
||||
hoverStyle: CSSObject,
|
||||
activeStyle: CSSObject,
|
||||
): CSSObject => ({
|
||||
[`&:not(:disabled):not(${btnCls}-disabled)`]: {
|
||||
const genHoverActiveButtonStyle = (hoverStyle: CSSObject, activeStyle: CSSObject): CSSObject => ({
|
||||
'&:not(:disabled)': {
|
||||
'&:hover': hoverStyle,
|
||||
'&:active': activeStyle,
|
||||
},
|
||||
|
|
@ -100,22 +117,21 @@ const genCircleButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
|
||||
const genRoundButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
borderRadius: token.controlHeight,
|
||||
paddingInlineStart: token.calc(token.controlHeight).div(2).equal(),
|
||||
paddingInlineEnd: token.calc(token.controlHeight).div(2).equal(),
|
||||
paddingInlineStart: token.controlHeight / 2,
|
||||
paddingInlineEnd: token.controlHeight / 2,
|
||||
});
|
||||
|
||||
// =============================== Type ===============================
|
||||
const genDisabledStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
cursor: 'not-allowed',
|
||||
borderColor: token.borderColorDisabled,
|
||||
borderColor: token.colorBorder,
|
||||
color: token.colorTextDisabled,
|
||||
background: token.colorBgContainerDisabled,
|
||||
backgroundColor: token.colorBgContainerDisabled,
|
||||
boxShadow: 'none',
|
||||
});
|
||||
|
||||
const genGhostButtonStyle = (
|
||||
btnCls: string,
|
||||
background: string,
|
||||
textColor: string | false,
|
||||
borderColor: string | false,
|
||||
textColorDisabled: string | false,
|
||||
|
|
@ -125,18 +141,17 @@ const genGhostButtonStyle = (
|
|||
): CSSObject => ({
|
||||
[`&${btnCls}-background-ghost`]: {
|
||||
color: textColor || undefined,
|
||||
background,
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: borderColor || undefined,
|
||||
boxShadow: 'none',
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
btnCls,
|
||||
{
|
||||
background,
|
||||
backgroundColor: 'transparent',
|
||||
...hoverStyle,
|
||||
},
|
||||
{
|
||||
background,
|
||||
backgroundColor: 'transparent',
|
||||
...activeStyle,
|
||||
},
|
||||
),
|
||||
|
|
@ -150,7 +165,7 @@ const genGhostButtonStyle = (
|
|||
});
|
||||
|
||||
const genSolidDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
[`&:disabled, &${token.componentCls}-disabled`]: {
|
||||
'&:disabled': {
|
||||
...genDisabledStyle(token),
|
||||
},
|
||||
});
|
||||
|
|
@ -160,7 +175,7 @@ const genSolidButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
});
|
||||
|
||||
const genPureDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
[`&:disabled, &${token.componentCls}-disabled`]: {
|
||||
'&:disabled': {
|
||||
cursor: 'not-allowed',
|
||||
color: token.colorTextDisabled,
|
||||
},
|
||||
|
|
@ -170,14 +185,12 @@ const genPureDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token
|
|||
const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
...genSolidButtonStyle(token),
|
||||
|
||||
background: token.defaultBg,
|
||||
borderColor: token.defaultBorderColor,
|
||||
color: token.defaultColor,
|
||||
backgroundColor: token.colorBgContainer,
|
||||
borderColor: token.colorBorder,
|
||||
|
||||
boxShadow: token.defaultShadow,
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorPrimaryHover,
|
||||
borderColor: token.colorPrimaryHover,
|
||||
|
|
@ -190,9 +203,8 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
|
||||
...genGhostButtonStyle(
|
||||
token.componentCls,
|
||||
token.ghostBg,
|
||||
token.defaultGhostColor,
|
||||
token.defaultGhostBorderColor,
|
||||
token.colorBgContainer,
|
||||
token.colorBgContainer,
|
||||
token.colorTextDisabled,
|
||||
token.colorBorder,
|
||||
),
|
||||
|
|
@ -202,7 +214,6 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
borderColor: token.colorError,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
borderColor: token.colorErrorBorderHover,
|
||||
|
|
@ -215,7 +226,6 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
|
||||
...genGhostButtonStyle(
|
||||
token.componentCls,
|
||||
token.ghostBg,
|
||||
token.colorError,
|
||||
token.colorError,
|
||||
token.colorTextDisabled,
|
||||
|
|
@ -229,26 +239,24 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
const genPrimaryButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
...genSolidButtonStyle(token),
|
||||
|
||||
color: token.primaryColor,
|
||||
background: token.colorPrimary,
|
||||
color: token.colorTextLightSolid,
|
||||
backgroundColor: token.colorPrimary,
|
||||
|
||||
boxShadow: token.primaryShadow,
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorTextLightSolid,
|
||||
background: token.colorPrimaryHover,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
},
|
||||
{
|
||||
color: token.colorTextLightSolid,
|
||||
background: token.colorPrimaryActive,
|
||||
backgroundColor: token.colorPrimaryActive,
|
||||
},
|
||||
),
|
||||
|
||||
...genGhostButtonStyle(
|
||||
token.componentCls,
|
||||
token.ghostBg,
|
||||
token.colorPrimary,
|
||||
token.colorPrimary,
|
||||
token.colorTextDisabled,
|
||||
|
|
@ -264,23 +272,20 @@ const genPrimaryButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
),
|
||||
|
||||
[`&${token.componentCls}-dangerous`]: {
|
||||
background: token.colorError,
|
||||
boxShadow: token.dangerShadow,
|
||||
color: token.dangerColor,
|
||||
backgroundColor: token.colorError,
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
background: token.colorErrorHover,
|
||||
backgroundColor: token.colorErrorHover,
|
||||
},
|
||||
{
|
||||
background: token.colorErrorActive,
|
||||
backgroundColor: token.colorErrorActive,
|
||||
},
|
||||
),
|
||||
|
||||
...genGhostButtonStyle(
|
||||
token.componentCls,
|
||||
token.ghostBg,
|
||||
token.colorError,
|
||||
token.colorError,
|
||||
token.colorTextDisabled,
|
||||
|
|
@ -309,10 +314,8 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
color: token.colorLink,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorLinkHover,
|
||||
background: token.linkHoverBg,
|
||||
},
|
||||
{
|
||||
color: token.colorLinkActive,
|
||||
|
|
@ -325,7 +328,6 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
color: token.colorError,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
},
|
||||
|
|
@ -341,14 +343,13 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
// Type: Text
|
||||
const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorText,
|
||||
background: token.textHoverBg,
|
||||
backgroundColor: token.colorBgTextHover,
|
||||
},
|
||||
{
|
||||
color: token.colorText,
|
||||
background: token.colorBgTextActive,
|
||||
backgroundColor: token.colorBgTextActive,
|
||||
},
|
||||
),
|
||||
|
||||
|
|
@ -359,19 +360,26 @@ const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
|||
|
||||
...genPureDisabledButtonStyle(token),
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
background: token.colorErrorBg,
|
||||
backgroundColor: token.colorErrorBg,
|
||||
},
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
background: token.colorErrorBg,
|
||||
backgroundColor: token.colorErrorBg,
|
||||
},
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
// Href and Disabled
|
||||
const genDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
|
||||
...genDisabledStyle(token),
|
||||
[`&${token.componentCls}:hover`]: {
|
||||
...genDisabledStyle(token),
|
||||
},
|
||||
});
|
||||
|
||||
const genTypeButtonStyle: GenerateStyle<ButtonToken> = token => {
|
||||
const { componentCls } = token;
|
||||
|
||||
|
|
@ -381,30 +389,26 @@ const genTypeButtonStyle: GenerateStyle<ButtonToken> = token => {
|
|||
[`${componentCls}-dashed`]: genDashedButtonStyle(token),
|
||||
[`${componentCls}-link`]: genLinkButtonStyle(token),
|
||||
[`${componentCls}-text`]: genTextButtonStyle(token),
|
||||
[`${componentCls}-ghost`]: genGhostButtonStyle(
|
||||
token.componentCls,
|
||||
token.ghostBg,
|
||||
token.colorBgContainer,
|
||||
token.colorBgContainer,
|
||||
token.colorTextDisabled,
|
||||
token.colorBorder,
|
||||
),
|
||||
[`${componentCls}-disabled`]: genDisabledButtonStyle(token),
|
||||
};
|
||||
};
|
||||
|
||||
// =============================== Size ===============================
|
||||
const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = '') => {
|
||||
const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSSInterpolation => {
|
||||
const {
|
||||
componentCls,
|
||||
iconCls,
|
||||
controlHeight,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
lineWidth,
|
||||
borderRadius,
|
||||
buttonPaddingHorizontal,
|
||||
iconCls,
|
||||
buttonPaddingVertical,
|
||||
} = token;
|
||||
|
||||
const paddingVertical = Math.max(0, (controlHeight - fontSize * lineHeight) / 2 - lineWidth);
|
||||
const paddingHorizontal = buttonPaddingHorizontal - lineWidth;
|
||||
|
||||
const iconOnlyCls = `${componentCls}-icon-only`;
|
||||
|
||||
return [
|
||||
|
|
@ -412,9 +416,8 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = '') => {
|
|||
{
|
||||
[`${componentCls}${sizePrefixCls}`]: {
|
||||
fontSize,
|
||||
lineHeight,
|
||||
height: controlHeight,
|
||||
padding: `${unit(buttonPaddingVertical!)} ${unit(buttonPaddingHorizontal!)}`,
|
||||
padding: `${paddingVertical}px ${paddingHorizontal}px`,
|
||||
borderRadius,
|
||||
|
||||
[`&${iconOnlyCls}`]: {
|
||||
|
|
@ -424,8 +427,8 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = '') => {
|
|||
[`&${componentCls}-round`]: {
|
||||
width: 'auto',
|
||||
},
|
||||
[iconCls]: {
|
||||
fontSize: token.buttonIconOnlyFontSize,
|
||||
'> span': {
|
||||
transform: 'scale(1.143)', // 14px -> 16px
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -438,6 +441,10 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = '') => {
|
|||
[`${componentCls}-loading-icon`]: {
|
||||
transition: `width ${token.motionDurationSlow} ${token.motionEaseInOut}, opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
|
||||
},
|
||||
|
||||
[`&:not(${iconOnlyCls}) ${componentCls}-loading-icon > ${iconCls}`]: {
|
||||
marginInlineEnd: token.marginXS,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -451,24 +458,14 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = '') => {
|
|||
];
|
||||
};
|
||||
|
||||
const genSizeBaseButtonStyle: GenerateStyle<ButtonToken> = token =>
|
||||
genSizeButtonStyle(
|
||||
mergeToken<ButtonToken>(token, {
|
||||
fontSize: token.contentFontSize,
|
||||
lineHeight: token.contentLineHeight,
|
||||
}),
|
||||
);
|
||||
const genSizeBaseButtonStyle: GenerateStyle<ButtonToken> = token => genSizeButtonStyle(token);
|
||||
|
||||
const genSizeSmallButtonStyle: GenerateStyle<ButtonToken> = token => {
|
||||
const smallToken = mergeToken<ButtonToken>(token, {
|
||||
controlHeight: token.controlHeightSM,
|
||||
fontSize: token.contentFontSizeSM,
|
||||
lineHeight: token.contentLineHeightSM,
|
||||
padding: token.paddingXS,
|
||||
buttonPaddingHorizontal: token.paddingInlineSM,
|
||||
buttonPaddingVertical: token.paddingBlockSM,
|
||||
buttonPaddingHorizontal: 8, // Fixed padding
|
||||
borderRadius: token.borderRadiusSM,
|
||||
buttonIconOnlyFontSize: token.onlyIconSizeSM,
|
||||
});
|
||||
|
||||
return genSizeButtonStyle(smallToken, `${token.componentCls}-sm`);
|
||||
|
|
@ -477,12 +474,8 @@ const genSizeSmallButtonStyle: GenerateStyle<ButtonToken> = token => {
|
|||
const genSizeLargeButtonStyle: GenerateStyle<ButtonToken> = token => {
|
||||
const largeToken = mergeToken<ButtonToken>(token, {
|
||||
controlHeight: token.controlHeightLG,
|
||||
fontSize: token.contentFontSizeLG,
|
||||
lineHeight: token.contentLineHeightLG,
|
||||
buttonPaddingHorizontal: token.paddingInlineLG,
|
||||
buttonPaddingVertical: token.paddingBlockLG,
|
||||
fontSize: token.fontSizeLG,
|
||||
borderRadius: token.borderRadiusLG,
|
||||
buttonIconOnlyFontSize: token.onlyIconSizeLG,
|
||||
});
|
||||
|
||||
return genSizeButtonStyle(largeToken, `${token.componentCls}-lg`);
|
||||
|
|
@ -500,10 +493,12 @@ const genBlockButtonStyle: GenerateStyle<ButtonToken> = token => {
|
|||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genStyleHooks(
|
||||
'Button',
|
||||
token => {
|
||||
const buttonToken = prepareToken(token);
|
||||
export default genComponentStyleHook('Button', token => {
|
||||
const { controlTmpOutline, paddingContentHorizontal } = token;
|
||||
const buttonToken = mergeToken<ButtonToken>(token, {
|
||||
colorOutlineDefault: controlTmpOutline,
|
||||
buttonPaddingHorizontal: paddingContentHorizontal,
|
||||
});
|
||||
|
||||
return [
|
||||
// Shared
|
||||
|
|
@ -517,20 +512,14 @@ export default genStyleHooks(
|
|||
// Block
|
||||
genBlockButtonStyle(buttonToken),
|
||||
|
||||
// Group (type, ghost, danger, loading)
|
||||
// Group (type, ghost, danger, disabled, loading)
|
||||
genTypeButtonStyle(buttonToken),
|
||||
|
||||
// Button Group
|
||||
genGroupStyle(buttonToken),
|
||||
|
||||
// Space Compact
|
||||
genCompactItemStyle(token, { focus: false }),
|
||||
genCompactItemVerticalStyle(token),
|
||||
];
|
||||
},
|
||||
prepareComponentToken,
|
||||
{
|
||||
unitless: {
|
||||
fontWeight: true,
|
||||
contentLineHeight: true,
|
||||
contentLineHeightSM: true,
|
||||
contentLineHeightLG: true,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,234 +0,0 @@
|
|||
import type { CSSProperties } from 'vue';
|
||||
import type { FullToken, GetDefaultToken } from '../../theme/internal';
|
||||
import { getLineHeight, mergeToken } from '../../theme/internal';
|
||||
import type { GenStyleFn } from '../../theme/util/genComponentStyleHook';
|
||||
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 文字字重
|
||||
* @descEN Font weight of text
|
||||
*/
|
||||
fontWeight: CSSProperties['fontWeight'];
|
||||
/**
|
||||
* @desc 默认按钮阴影
|
||||
* @descEN Shadow of default button
|
||||
*/
|
||||
defaultShadow: string;
|
||||
/**
|
||||
* @desc 主要按钮阴影
|
||||
* @descEN Shadow of primary button
|
||||
*/
|
||||
primaryShadow: string;
|
||||
/**
|
||||
* @desc 危险按钮阴影
|
||||
* @descEN Shadow of danger button
|
||||
*/
|
||||
dangerShadow: string;
|
||||
/**
|
||||
* @desc 主要按钮文本颜色
|
||||
* @descEN Text color of primary button
|
||||
*/
|
||||
primaryColor: string;
|
||||
/**
|
||||
* @desc 默认按钮文本颜色
|
||||
* @descEN Text color of default button
|
||||
*/
|
||||
defaultColor: string;
|
||||
/**
|
||||
* @desc 默认按钮背景色
|
||||
* @descEN Background color of default button
|
||||
*/
|
||||
defaultBg: string;
|
||||
/**
|
||||
* @desc 默认按钮边框颜色
|
||||
* @descEN Border color of default button
|
||||
*/
|
||||
defaultBorderColor: string;
|
||||
/**
|
||||
* @desc 危险按钮文本颜色
|
||||
* @descEN Text color of danger button
|
||||
*/
|
||||
dangerColor: string;
|
||||
/**
|
||||
* @desc 禁用状态边框颜色
|
||||
* @descEN Border color of disabled button
|
||||
*/
|
||||
borderColorDisabled: string;
|
||||
/**
|
||||
* @desc 默认幽灵按钮文本颜色
|
||||
* @descEN Text color of default ghost button
|
||||
*/
|
||||
defaultGhostColor: string;
|
||||
/**
|
||||
* @desc 幽灵按钮背景色
|
||||
* @descEN Background color of ghost button
|
||||
*/
|
||||
ghostBg: string;
|
||||
/**
|
||||
* @desc 默认幽灵按钮边框颜色
|
||||
* @descEN Border color of default ghost button
|
||||
*/
|
||||
defaultGhostBorderColor: string;
|
||||
/**
|
||||
* @desc 按钮横向内间距
|
||||
* @descEN Horizontal padding of button
|
||||
*/
|
||||
paddingInline: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 大号按钮横向内间距
|
||||
* @descEN Horizontal padding of large button
|
||||
*/
|
||||
paddingInlineLG: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 小号按钮横向内间距
|
||||
* @descEN Horizontal padding of small button
|
||||
*/
|
||||
paddingInlineSM: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 按钮横向内间距
|
||||
* @descEN Horizontal padding of button
|
||||
*/
|
||||
paddingBlock: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 大号按钮横向内间距
|
||||
* @descEN Horizontal padding of large button
|
||||
*/
|
||||
paddingBlockLG: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 小号按钮横向内间距
|
||||
* @descEN Horizontal padding of small button
|
||||
*/
|
||||
paddingBlockSM: CSSProperties['paddingInline'];
|
||||
/**
|
||||
* @desc 只有图标的按钮图标尺寸
|
||||
* @descEN Icon size of button which only contains icon
|
||||
*/
|
||||
onlyIconSize: number;
|
||||
/**
|
||||
* @desc 大号只有图标的按钮图标尺寸
|
||||
* @descEN Icon size of large button which only contains icon
|
||||
*/
|
||||
onlyIconSizeLG: number;
|
||||
/**
|
||||
* @desc 小号只有图标的按钮图标尺寸
|
||||
* @descEN Icon size of small button which only contains icon
|
||||
*/
|
||||
onlyIconSizeSM: number;
|
||||
/**
|
||||
* @desc 按钮组边框颜色
|
||||
* @descEN Border color of button group
|
||||
*/
|
||||
groupBorderColor: string;
|
||||
/**
|
||||
* @desc 链接按钮悬浮态背景色
|
||||
* @descEN Background color of link button when hover
|
||||
*/
|
||||
linkHoverBg: string;
|
||||
/**
|
||||
* @desc 文本按钮悬浮态背景色
|
||||
* @descEN Background color of text button when hover
|
||||
*/
|
||||
textHoverBg: string;
|
||||
/**
|
||||
* @desc 按钮内容字体大小
|
||||
* @descEN Font size of button content
|
||||
*/
|
||||
contentFontSize: number;
|
||||
/**
|
||||
* @desc 大号按钮内容字体大小
|
||||
* @descEN Font size of large button content
|
||||
*/
|
||||
contentFontSizeLG: number;
|
||||
/**
|
||||
* @desc 小号按钮内容字体大小
|
||||
* @descEN Font size of small button content
|
||||
*/
|
||||
contentFontSizeSM: number;
|
||||
/**
|
||||
* @desc 按钮内容字体行高
|
||||
* @descEN Line height of button content
|
||||
*/
|
||||
contentLineHeight: number;
|
||||
/**
|
||||
* @desc 大号按钮内容字体行高
|
||||
* @descEN Line height of large button content
|
||||
*/
|
||||
contentLineHeightLG: number;
|
||||
/**
|
||||
* @desc 小号按钮内容字体行高
|
||||
* @descEN Line height of small button content
|
||||
*/
|
||||
contentLineHeightSM: number;
|
||||
}
|
||||
|
||||
export interface ButtonToken extends FullToken<'Button'> {
|
||||
buttonPaddingHorizontal: CSSProperties['paddingInline'];
|
||||
buttonPaddingVertical: CSSProperties['paddingBlock'];
|
||||
buttonIconOnlyFontSize: number;
|
||||
}
|
||||
|
||||
export const prepareToken: (token: Parameters<GenStyleFn<'Button'>>[0]) => ButtonToken = token => {
|
||||
const { paddingInline, onlyIconSize, paddingBlock } = token;
|
||||
|
||||
const buttonToken = mergeToken<ButtonToken>(token, {
|
||||
buttonPaddingHorizontal: paddingInline,
|
||||
buttonPaddingVertical: paddingBlock,
|
||||
buttonIconOnlyFontSize: onlyIconSize,
|
||||
});
|
||||
|
||||
return buttonToken;
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Button'> = token => {
|
||||
const contentFontSize = token.contentFontSize ?? token.fontSize;
|
||||
const contentFontSizeSM = token.contentFontSizeSM ?? token.fontSize;
|
||||
const contentFontSizeLG = token.contentFontSizeLG ?? token.fontSizeLG;
|
||||
const contentLineHeight = token.contentLineHeight ?? getLineHeight(contentFontSize);
|
||||
const contentLineHeightSM = token.contentLineHeightSM ?? getLineHeight(contentFontSizeSM);
|
||||
const contentLineHeightLG = token.contentLineHeightLG ?? getLineHeight(contentFontSizeLG);
|
||||
|
||||
return {
|
||||
fontWeight: 400,
|
||||
defaultShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`,
|
||||
primaryShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`,
|
||||
dangerShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`,
|
||||
primaryColor: token.colorTextLightSolid,
|
||||
dangerColor: token.colorTextLightSolid,
|
||||
borderColorDisabled: token.colorBorder,
|
||||
defaultGhostColor: token.colorBgContainer,
|
||||
ghostBg: 'transparent',
|
||||
defaultGhostBorderColor: token.colorBgContainer,
|
||||
paddingInline: token.paddingContentHorizontal - token.lineWidth,
|
||||
paddingInlineLG: token.paddingContentHorizontal - token.lineWidth,
|
||||
paddingInlineSM: 8 - token.lineWidth,
|
||||
onlyIconSize: token.fontSizeLG,
|
||||
onlyIconSizeSM: token.fontSizeLG - 2,
|
||||
onlyIconSizeLG: token.fontSizeLG + 2,
|
||||
groupBorderColor: token.colorPrimaryHover,
|
||||
linkHoverBg: 'transparent',
|
||||
textHoverBg: token.colorBgTextHover,
|
||||
defaultColor: token.colorText,
|
||||
defaultBg: token.colorBgContainer,
|
||||
defaultBorderColor: token.colorBorder,
|
||||
defaultBorderColorDisabled: token.colorBorder,
|
||||
contentFontSize,
|
||||
contentFontSizeSM,
|
||||
contentFontSizeLG,
|
||||
contentLineHeight,
|
||||
contentLineHeightSM,
|
||||
contentLineHeightLG,
|
||||
paddingBlock: Math.max(
|
||||
(token.controlHeight - contentFontSize * contentLineHeight) / 2 - token.lineWidth,
|
||||
0,
|
||||
),
|
||||
paddingBlockSM: Math.max(
|
||||
(token.controlHeightSM - contentFontSizeSM * contentLineHeightSM) / 2 - token.lineWidth,
|
||||
0,
|
||||
),
|
||||
paddingBlockLG: Math.max(
|
||||
(token.controlHeightLG - contentFontSizeLG * contentLineHeightLG) / 2 - token.lineWidth,
|
||||
0,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
|
@ -57,18 +57,6 @@ export interface ThemeConfig {
|
|||
algorithm?: MappingAlgorithm | MappingAlgorithm[];
|
||||
hashed?: boolean;
|
||||
inherit?: boolean;
|
||||
cssVar?:
|
||||
| {
|
||||
/**
|
||||
* Prefix for css variable, default to `antd`.
|
||||
*/
|
||||
prefix?: string;
|
||||
/**
|
||||
* Unique key for theme, should be set manually < react@18.
|
||||
*/
|
||||
key?: string;
|
||||
}
|
||||
| boolean;
|
||||
}
|
||||
|
||||
export const configProviderProps = () => ({
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
import { useToken } from '../../theme/internal';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
/**
|
||||
* This hook is only for cssVar to add root className for components.
|
||||
* If root ClassName is needed, this hook could be refactored with `-root`
|
||||
* @param prefixCls
|
||||
*/
|
||||
const useCSSVarCls = (prefixCls: Ref<string>) => {
|
||||
const [, , , , cssVar] = useToken();
|
||||
|
||||
return computed(() => (cssVar.value ? `${prefixCls.value}-css-var` : ''));
|
||||
};
|
||||
|
||||
export default useCSSVarCls;
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
import type { SizeType } from '../SizeContext';
|
||||
import { useInjectSize } from '../SizeContext';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed, shallowRef, watch } from 'vue';
|
||||
|
||||
const useSize = <T>(customSize?: T | ((ctxSize: SizeType) => T)): Ref<T> => {
|
||||
const size = useInjectSize();
|
||||
|
||||
const mergedSize = shallowRef(null);
|
||||
|
||||
watch(
|
||||
computed(() => {
|
||||
return [customSize, size.value];
|
||||
}),
|
||||
() => {
|
||||
if (!customSize) {
|
||||
mergedSize.value = size.value as T;
|
||||
}
|
||||
if (typeof customSize === 'string') {
|
||||
mergedSize.value = customSize ?? (size.value as T);
|
||||
}
|
||||
if (customSize instanceof Function) {
|
||||
mergedSize.value = customSize(size.value) as T;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
return mergedSize;
|
||||
};
|
||||
|
||||
export default useSize;
|
||||
|
|
@ -2,26 +2,13 @@ import type { ThemeConfig } from '../context';
|
|||
import { defaultConfig } from '../../theme/internal';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import devWarning from '../../vc-util/warning';
|
||||
const themeKey = 'antdvtheme';
|
||||
|
||||
export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<ThemeConfig>) {
|
||||
const themeConfig = computed(() => theme?.value || {});
|
||||
const parentThemeConfig = computed<ThemeConfig>(() =>
|
||||
themeConfig.value.inherit === false || !parentTheme?.value ? defaultConfig : parentTheme.value,
|
||||
);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const cssVarEnabled = themeConfig.value.cssVar || parentThemeConfig.value.cssVar;
|
||||
const validKey = !!(
|
||||
(typeof themeConfig.value.cssVar === 'object' && themeConfig.value.cssVar?.key) ||
|
||||
themeKey
|
||||
);
|
||||
devWarning(
|
||||
!cssVarEnabled || validKey,
|
||||
'[Ant Design Vue ConfigProvider] Missing key in `cssVar` config. Please set `cssVar.key` manually in each ConfigProvider inside `cssVar` enabled ConfigProvider.',
|
||||
);
|
||||
}
|
||||
|
||||
const mergedTheme = computed(() => {
|
||||
if (!theme?.value) {
|
||||
return parentTheme?.value;
|
||||
|
|
@ -39,17 +26,6 @@ export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<The
|
|||
} as any;
|
||||
});
|
||||
|
||||
const cssVarKey = `css-var-${themeKey.replace(/:/g, '')}`;
|
||||
|
||||
const mergedCssVar = (themeConfig.value.cssVar ?? parentThemeConfig.value.cssVar) && {
|
||||
prefix: 'ant', // Default to ant
|
||||
...(typeof parentThemeConfig.value.cssVar === 'object' ? parentThemeConfig.value.cssVar : {}),
|
||||
...(typeof themeConfig.value.cssVar === 'object' ? themeConfig.value.cssVar : {}),
|
||||
key:
|
||||
(typeof themeConfig.value.cssVar === 'object' && themeConfig.value.cssVar?.key) ||
|
||||
cssVarKey,
|
||||
};
|
||||
|
||||
// Base token
|
||||
return {
|
||||
...parentThemeConfig.value,
|
||||
|
|
@ -60,7 +36,6 @@ export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<The
|
|||
...themeConfig.value.token,
|
||||
},
|
||||
components: mergedComponents,
|
||||
cssVar: mergedCssVar,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
let uid = 0;
|
||||
const useThemeKey = () => {
|
||||
return 'themekey' + uid++;
|
||||
};
|
||||
|
||||
export default useThemeKey;
|
||||
|
|
@ -15,7 +15,7 @@ import type { ValidateMessages } from '../form/interface';
|
|||
import useStyle from './style';
|
||||
import useTheme from './hooks/useTheme';
|
||||
import defaultSeedToken from '../theme/themes/seed';
|
||||
import type { ConfigProviderInnerProps, ConfigProviderProps, Theme, ThemeConfig } from './context';
|
||||
import type { ConfigProviderInnerProps, ConfigProviderProps, Theme } from './context';
|
||||
import {
|
||||
useConfigContextProvider,
|
||||
useConfigContextInject,
|
||||
|
|
@ -26,7 +26,7 @@ import {
|
|||
import { useProviderSize } from './SizeContext';
|
||||
import { useProviderDisabled } from './DisabledContext';
|
||||
import { createTheme } from '../_util/cssinjs';
|
||||
import { defaultTheme, DesignTokenProvider } from '../theme/context';
|
||||
import { DesignTokenProvider } from '../theme/internal';
|
||||
|
||||
export type {
|
||||
ConfigProviderProps,
|
||||
|
|
@ -226,47 +226,19 @@ const ConfigProvider = defineComponent({
|
|||
|
||||
// ================================ Dynamic theme ================================
|
||||
const memoTheme = computed(() => {
|
||||
const { algorithm, token, components, cssVar, ...rest } = mergedTheme.value || {};
|
||||
const { algorithm, token, ...rest } = mergedTheme.value || {};
|
||||
const themeObj =
|
||||
algorithm && (!Array.isArray(algorithm) || algorithm.length > 0)
|
||||
? createTheme(algorithm)
|
||||
: defaultTheme;
|
||||
|
||||
const parsedComponents: any = {};
|
||||
Object.entries(components || {}).forEach(([componentName, componentToken]) => {
|
||||
const parsedToken: typeof componentToken & { theme?: typeof defaultTheme } = {
|
||||
...componentToken,
|
||||
};
|
||||
if ('algorithm' in parsedToken) {
|
||||
if (parsedToken.algorithm === true) {
|
||||
parsedToken.theme = themeObj;
|
||||
} else if (
|
||||
Array.isArray(parsedToken.algorithm) ||
|
||||
typeof parsedToken.algorithm === 'function'
|
||||
) {
|
||||
parsedToken.theme = createTheme(parsedToken.algorithm as any);
|
||||
}
|
||||
delete parsedToken.algorithm;
|
||||
}
|
||||
parsedComponents[componentName] = parsedToken;
|
||||
});
|
||||
|
||||
const mergedToken = {
|
||||
...defaultSeedToken,
|
||||
...token,
|
||||
};
|
||||
|
||||
: undefined;
|
||||
return {
|
||||
...rest,
|
||||
theme: themeObj,
|
||||
|
||||
token: mergedToken,
|
||||
components: parsedComponents,
|
||||
override: {
|
||||
override: mergedToken,
|
||||
...parsedComponents,
|
||||
token: {
|
||||
...defaultSeedToken,
|
||||
...token,
|
||||
},
|
||||
cssVar: cssVar as Exclude<ThemeConfig['cssVar'], boolean>,
|
||||
};
|
||||
});
|
||||
const validateMessagesRef = computed(() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import { useStyleRegister } from '../../_util/cssinjs';
|
||||
import { resetIcon } from '../../style';
|
||||
import { useToken } from '../../theme/internal';
|
||||
|
|
@ -14,8 +13,7 @@ const useStyle = (iconPrefixCls: Ref<string>) => {
|
|||
hashId: '',
|
||||
path: ['ant-design-icons', iconPrefixCls.value],
|
||||
})),
|
||||
() =>
|
||||
[
|
||||
() => [
|
||||
{
|
||||
[`.${iconPrefixCls.value}`]: {
|
||||
...resetIcon(),
|
||||
|
|
@ -24,7 +22,7 @@ const useStyle = (iconPrefixCls: Ref<string>) => {
|
|||
},
|
||||
},
|
||||
},
|
||||
] as CSSObject[],
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
|
|||
import { resetComponent, roundedArrow, textEllipsis } from '../../style';
|
||||
import { genCompactItemStyle } from '../../style/compact-item';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
export interface ComponentToken {
|
||||
presetsWidth: number;
|
||||
presetsMaxWidth: number;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import type { FullToken, GenerateStyle } from '../../theme/internal';
|
|||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent, textEllipsis } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
interface DescriptionsToken extends FullToken<'Descriptions'> {
|
||||
descriptionsTitleMarginBottom: number;
|
||||
descriptionsExtraColor: string;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const BackTop = defineComponent({
|
|||
|
||||
const handleScroll = throttleByAnimationFrame((e: Event | { target: any }) => {
|
||||
const { visibilityHeight } = props;
|
||||
const scrollTop = getScroll(e.target);
|
||||
const scrollTop = getScroll(e.target, true);
|
||||
state.visible = scrollTop >= visibilityHeight;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
|||
import { resetComponent } from '../../style';
|
||||
import genFormValidateMotionStyle from './explain';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
export interface FormToken extends FullToken<'Form'> {
|
||||
formItemCls: string;
|
||||
rootPrefixCls: string;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import type { CSSObject } from '../../_util/cssinjs';
|
|||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
interface GridRowToken extends FullToken<'Grid'> {}
|
||||
|
||||
interface GridColToken extends FullToken<'Grid'> {
|
||||
|
|
|
|||
|
|
@ -58,13 +58,13 @@ exports[`renders ./components/image/demo/placeholder.vue correctly 1`] = `
|
|||
`;
|
||||
|
||||
exports[`renders ./components/image/demo/preview-group.vue correctly 1`] = `
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://aliyuncdn.antdv.com/vue.png">
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://www.antdv.com/vue.png">
|
||||
<!---->
|
||||
<div class="ant-image-mask">
|
||||
<div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://www.antdv.com/logo.png">
|
||||
<!---->
|
||||
<div class="ant-image-mask">
|
||||
<div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div>
|
||||
|
|
@ -106,7 +106,7 @@ exports[`renders ./components/image/demo/preview-group-visible.vue correctly 1`]
|
|||
`;
|
||||
|
||||
exports[`renders ./components/image/demo/preview-src.vue correctly 1`] = `
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
<div class="ant-image" style="width: 200px;"><img width="200" class="ant-image-img" src="https://www.antdv.com/logo.png">
|
||||
<!---->
|
||||
<div class="ant-image-mask">
|
||||
<div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Click the left and right switch buttons to preview multiple images.
|
|||
|
||||
<template>
|
||||
<a-image-preview-group>
|
||||
<a-image :width="200" src="https://aliyuncdn.antdv.com/vue.png" />
|
||||
<a-image :width="200" src="https://aliyuncdn.antdv.com/logo.png" />
|
||||
<a-image :width="200" src="https://www.antdv.com/vue.png" />
|
||||
<a-image :width="200" src="https://www.antdv.com/logo.png" />
|
||||
</a-image-preview-group>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ You can set different preview image.
|
|||
<template>
|
||||
<a-image
|
||||
:width="200"
|
||||
src="https://aliyuncdn.antdv.com/logo.png"
|
||||
src="https://www.antdv.com/logo.png"
|
||||
:preview="{
|
||||
src: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
}"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { App } from 'vue';
|
|||
|
||||
import * as components from './components';
|
||||
import { default as version } from './version';
|
||||
import * as cssinjs from './_util/cssinjs';
|
||||
import cssinjs from './_util/cssinjs';
|
||||
export * from './components';
|
||||
export * from './_util/cssinjs';
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue