├── .commitlintrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .vitepress
├── components
│ └── demo.vue
├── config.ts
├── config
│ ├── en-US
│ │ ├── index.ts
│ │ ├── nav.ts
│ │ └── sidebar.ts
│ ├── rewrites.ts
│ └── zh-CN
│ │ ├── index.ts
│ │ ├── nav.ts
│ │ └── sidebar.ts
└── theme
│ └── index.ts
├── README.md
├── components
├── _util
│ ├── hooks
│ │ ├── disabled.ts
│ │ ├── flex-gap-support.ts
│ │ └── size.ts
│ ├── style-checker.ts
│ ├── warning.ts
│ └── wave
│ │ ├── index.tsx
│ │ ├── style.ts
│ │ ├── use-wave.ts
│ │ ├── util.ts
│ │ └── wave-effect.tsx
├── button
│ ├── button-helper.tsx
│ ├── button.tsx
│ ├── demo
│ │ └── basic.vue
│ ├── index.md
│ ├── index.ts
│ ├── index.zh-CN.md
│ ├── interface.ts
│ ├── loading-icon.tsx
│ └── style
│ │ ├── group.ts
│ │ └── index.ts
├── components.ts
├── config-provider
│ ├── context.ts
│ ├── css-variables.ts
│ ├── default-render-empty.tsx
│ ├── hooks
│ │ └── config.ts
│ ├── index.md
│ ├── index.tsx
│ ├── index.zh-CN.md
│ └── style
│ │ └── index.ts
├── index.ts
├── space
│ ├── compact.tsx
│ ├── index.tsx
│ ├── item.tsx
│ └── style
│ │ ├── compact.tsx
│ │ └── index.tsx
├── style
│ ├── compact-item-vertical.ts
│ ├── compact-item.ts
│ ├── index.ts
│ ├── motion
│ │ ├── collapse.ts
│ │ ├── fade.ts
│ │ ├── index.ts
│ │ ├── motion.ts
│ │ ├── move.ts
│ │ ├── slide.ts
│ │ └── zoom.ts
│ ├── operationUnit.ts
│ ├── placementArrow.ts
│ ├── presetColor.tsx
│ ├── reset.css
│ └── roundedArrow.ts
├── theme
│ ├── index.ts
│ ├── interface
│ │ ├── alias.ts
│ │ ├── components.ts
│ │ ├── index.ts
│ │ ├── maps
│ │ │ ├── colors.ts
│ │ │ ├── font.ts
│ │ │ ├── index.ts
│ │ │ ├── size.ts
│ │ │ └── style.ts
│ │ ├── presetColors.ts
│ │ └── seeds.ts
│ ├── internal.ts
│ ├── themes
│ │ ├── ColorMap.ts
│ │ ├── compact
│ │ │ ├── genCompactSizeMapToken.ts
│ │ │ └── index.ts
│ │ ├── dark
│ │ │ ├── colorAlgorithm.ts
│ │ │ ├── colors.ts
│ │ │ └── index.ts
│ │ ├── default
│ │ │ ├── colorAlgorithm.ts
│ │ │ ├── colors.ts
│ │ │ └── index.ts
│ │ ├── seed.ts
│ │ └── shared
│ │ │ ├── genColorMapToken.ts
│ │ │ ├── genCommonMapToken.ts
│ │ │ ├── genControlHeight.ts
│ │ │ ├── genFontMapToken.ts
│ │ │ ├── genFontSizes.ts
│ │ │ ├── genRadius.ts
│ │ │ └── genSizeMapToken.ts
│ └── util
│ │ ├── alias.ts
│ │ ├── genComponentStyleHook.ts
│ │ ├── getAlphaColor.ts
│ │ └── statistic.ts
└── version.ts
├── package.json
├── pnpm-lock.yaml
├── site
├── components
│ ├── index.md
│ └── index.zh-CN.md
├── index.md
└── index.zh-CN.md
├── tests
└── demo.test.ts
├── tsconfig.json
├── vite.build.config.ts
└── vite.bundle.config.ts
/.commitlintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "@commitlint/config-conventional"
4 | ],
5 | "rules": {
6 | "type-enum": [
7 | 2,
8 | "always",
9 | [
10 | "feat",
11 | "fix",
12 | "refactor",
13 | "test",
14 | "build",
15 | "docs",
16 | "chore"
17 | ]
18 | ],
19 | "subject-max-length": [1,"always", 150]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | cache
2 | .temp
3 | *.log
4 | es
5 | lib
6 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@mistjs/eslint-config-vue-jsx"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | .vscode
4 | .DS_Store
5 | dist
6 | cache
7 | .temp
8 | es
9 | lib
10 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | pnpm exec commitlint -e "$1"
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | pnpm exec lint-staged
5 |
--------------------------------------------------------------------------------
/.vitepress/components/demo.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.vitepress/config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath } from 'url'
2 | import { resolve } from 'path'
3 | import { defineConfig } from 'vitepress'
4 | import vueJsxPlugin from '@vitejs/plugin-vue-jsx'
5 | import VitePluginVitepressDemo from 'vite-plugin-vitepress-demo'
6 | import getEnUSConfig from './config/en-US'
7 | import getZhCNConfig from './config/zh-CN'
8 | import { getRewrites } from './config/rewrites'
9 | const baseSrc = fileURLToPath(new URL('./', import.meta.url))
10 |
11 | export default defineConfig({
12 | rewrites: getRewrites(),
13 | lang: 'en-US',
14 | ignoreDeadLinks: true,
15 | locales: {
16 | 'zh-CN': {
17 | lang: 'zh-CN',
18 | title: 'Antd Tiny Vue',
19 | label: '简体中文',
20 | description: 'vue3组件库站点',
21 | themeConfig: getZhCNConfig()
22 | },
23 | root: {
24 | lang: 'en-US',
25 | title: 'Antd Tiny Vue',
26 | label: 'English',
27 | description: 'vue3 component library site',
28 | themeConfig: getEnUSConfig()
29 | }
30 | },
31 | vite: {
32 | plugins: [vueJsxPlugin(), VitePluginVitepressDemo()],
33 | resolve: {
34 | alias: {
35 | 'antd-tiny-vue': resolve(baseSrc, '../components')
36 | }
37 | },
38 | server: {
39 | port: 1199
40 | }
41 | }
42 | })
43 |
--------------------------------------------------------------------------------
/.vitepress/config/en-US/index.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 | import { getNav } from './nav'
3 | import { getSidebar } from './sidebar'
4 |
5 | export default (): DefaultTheme.Config => ({
6 | nav: getNav(),
7 | sidebar: getSidebar(),
8 | i18nRouting: true
9 | })
10 |
--------------------------------------------------------------------------------
/.vitepress/config/en-US/nav.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 |
3 | export const getNav = (): DefaultTheme.NavItem[] => {
4 | return [
5 | {
6 | text: 'Components',
7 | link: '/components/'
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.vitepress/config/en-US/sidebar.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 |
3 | const componentsDir = `/components/`
4 |
5 | export const getSidebar = (): DefaultTheme.Sidebar => {
6 | return {
7 | [componentsDir]: [
8 | {
9 | text: 'General',
10 | items: [
11 | {
12 | text: 'Button',
13 | link: `${componentsDir}button/`
14 | }
15 | ]
16 | },
17 | {
18 | text: 'Layout',
19 | items: []
20 | },
21 | {
22 | text: 'Navigation',
23 | items: []
24 | },
25 | {
26 | text: 'Data Entry',
27 | items: []
28 | },
29 | {
30 | text: 'Data Display',
31 | items: []
32 | },
33 | {
34 | text: 'Feedback',
35 | items: []
36 | },
37 | {
38 | text: 'Other',
39 | items: [
40 | {
41 | text: 'ConfigProvider',
42 | link: `${componentsDir}config-provider/`
43 | }
44 | ]
45 | }
46 | ]
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/.vitepress/config/rewrites.ts:
--------------------------------------------------------------------------------
1 | export const getRewrites = (): Record => {
2 | return {
3 | 'site/index.md': 'index.md',
4 | 'site/index.zh-CN.md': 'zh-CN/index.md',
5 | 'site/components/index.md': 'components/index.md',
6 | 'site/components/index.zh-CN.md': 'zh-CN/components/index.md',
7 | 'components/:comp/index.zh-CN.md': 'zh-CN/components/:comp/index.md'
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.vitepress/config/zh-CN/index.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 | import { getNav } from './nav'
3 | import { getSidebar } from './sidebar'
4 |
5 | export default (): DefaultTheme.Config => ({
6 | nav: getNav(),
7 | sidebar: getSidebar(),
8 | i18nRouting: true
9 | })
10 |
--------------------------------------------------------------------------------
/.vitepress/config/zh-CN/nav.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 |
3 | export const getNav = (): DefaultTheme.NavItem[] => {
4 | return [
5 | {
6 | text: '组件',
7 | link: '/zh-CN/components/'
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.vitepress/config/zh-CN/sidebar.ts:
--------------------------------------------------------------------------------
1 | import type { DefaultTheme } from 'vitepress'
2 | const componentsDir = `/zh-CN/components/`
3 |
4 | export const getSidebar = (): DefaultTheme.Sidebar => {
5 | return {
6 | [componentsDir]: [
7 | {
8 | text: '通用',
9 | items: [
10 | {
11 | text: 'Button 按钮',
12 | link: `${componentsDir}button/`
13 | }
14 | ]
15 | },
16 | {
17 | text: '布局',
18 | items: []
19 | },
20 | {
21 | text: '导航',
22 | items: []
23 | },
24 | {
25 | text: '数据入录',
26 | items: []
27 | },
28 | {
29 | text: '数据展示',
30 | items: []
31 | },
32 | {
33 | text: '反馈',
34 | items: []
35 | },
36 | {
37 | text: '其他',
38 | items: [
39 | {
40 | text: 'ConfigProvider',
41 | link: `${componentsDir}config-provider/`
42 | }
43 | ]
44 | }
45 | ]
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import type { Theme } from 'vitepress'
2 | // eslint-disable-next-line import/no-named-as-default
3 | import DefaultTheme from 'vitepress/theme'
4 | import AntdTheme from '../components/demo.vue'
5 | // import { AntdTheme } from 'vite-plugin-vitepress-demo/theme'
6 | export default {
7 | ...DefaultTheme,
8 | async enhanceApp(ctx) {
9 | DefaultTheme.enhanceApp?.(ctx)
10 | ctx.app.component('Demo', AntdTheme)
11 | // @ts-expect-error this is a local module
12 | if (!import.meta.env.SSR) {
13 | // @ts-expect-error this is a local module
14 | const Antd = (await import('antd-tiny-vue')).default
15 | ctx.app.use(Antd)
16 | }
17 | }
18 | } as Theme
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 学习ant-design设计规范
2 |
3 |
--------------------------------------------------------------------------------
/components/_util/hooks/disabled.ts:
--------------------------------------------------------------------------------
1 | import type { ComputedRef } from 'vue'
2 | import { computed } from 'vue'
3 | import { useProviderConfigState } from '../../config-provider/context'
4 |
5 | export const useDisabled = (props: Record) => {
6 | const { componentDisabled } = useProviderConfigState()
7 | return computed(() => props.disabled || componentDisabled.value) as ComputedRef
8 | }
9 |
--------------------------------------------------------------------------------
/components/_util/hooks/flex-gap-support.ts:
--------------------------------------------------------------------------------
1 | import { useState } from '@v-c/utils'
2 | import { onMounted } from 'vue'
3 | import { detectFlexGapSupported } from '../style-checker'
4 |
5 | export default () => {
6 | const [flexible, setFlexible] = useState(false)
7 |
8 | onMounted(() => {
9 | setFlexible(detectFlexGapSupported())
10 | })
11 | return flexible
12 | }
13 |
--------------------------------------------------------------------------------
/components/_util/hooks/size.ts:
--------------------------------------------------------------------------------
1 | import type { ComputedRef } from 'vue'
2 | import { computed } from 'vue'
3 | import type { SizeType } from '../../config-provider/context'
4 | import { useProviderConfigState } from '../../config-provider/context'
5 |
6 | export const useSize = (props: Record) => {
7 | const { componentSize } = useProviderConfigState()
8 | return computed(() => props.size || componentSize.value) as ComputedRef
9 | }
10 |
--------------------------------------------------------------------------------
/components/_util/style-checker.ts:
--------------------------------------------------------------------------------
1 | import { canUseDom } from '@v-c/utils'
2 |
3 | export const canUseDocElement = () =>
4 | canUseDom() && window.document.documentElement
5 |
6 | let flexGapSupported: boolean
7 | export const detectFlexGapSupported = () => {
8 | if (!canUseDocElement()) {
9 | return false
10 | }
11 |
12 | if (flexGapSupported !== undefined) {
13 | return flexGapSupported
14 | }
15 |
16 | // create flex container with row-gap set
17 | const flex = document.createElement('div')
18 | flex.style.display = 'flex'
19 | flex.style.flexDirection = 'column'
20 | flex.style.rowGap = '1px'
21 |
22 | // create two, elements inside it
23 | flex.appendChild(document.createElement('div'))
24 | flex.appendChild(document.createElement('div'))
25 |
26 | // append to the DOM (needed to obtain scrollHeight)
27 | document.body.appendChild(flex)
28 | flexGapSupported = flex.scrollHeight === 1 // flex container should be 1px high from the row-gap
29 | document.body.removeChild(flex)
30 |
31 | return flexGapSupported
32 | }
33 |
--------------------------------------------------------------------------------
/components/_util/warning.ts:
--------------------------------------------------------------------------------
1 | import { warning as rcWarning, resetWarned } from '@v-c/utils'
2 |
3 | export { resetWarned }
4 | export function noop() {}
5 |
6 | type Warning = (valid: boolean, component: string, message?: string) => void
7 |
8 | // eslint-disable-next-line import/no-mutable-exports
9 | let warning: Warning = noop
10 | if (process.env.NODE_ENV !== 'production') {
11 | warning = (valid, component, message) => {
12 | rcWarning(valid, `[antd: ${component}] ${message}`)
13 |
14 | // StrictMode will inject console which will not throw warning in React 17.
15 | if (process.env.NODE_ENV === 'test') {
16 | resetWarned()
17 | }
18 | }
19 | }
20 |
21 | export default warning
22 |
--------------------------------------------------------------------------------
/components/_util/wave/index.tsx:
--------------------------------------------------------------------------------
1 | import type { VNode } from 'vue'
2 | import { cloneVNode, computed, defineComponent, shallowRef } from 'vue'
3 | import { booleanType, classNames, filterEmpty, isVisible } from '@v-c/utils'
4 | import { useEventListener } from '@vueuse/core'
5 | import { useProviderConfigState } from '../../config-provider/context'
6 | import useStyle from './style'
7 | import useWave from './use-wave'
8 |
9 | const Wave = defineComponent({
10 | name: 'Wave',
11 | props: {
12 | disabled: booleanType()
13 | },
14 | setup(props, { slots }) {
15 | const { getPrefixCls } = useProviderConfigState()
16 | const containerRef = shallowRef()
17 |
18 | // ============================== Style ===============================
19 | const prefixCls = computed(() => getPrefixCls('wave'))
20 | const [, hashId] = useStyle(prefixCls)
21 | const showWave = useWave(
22 | containerRef,
23 | computed(() => classNames(prefixCls.value, hashId.value))
24 | )
25 |
26 | const onClick = (e: MouseEvent) => {
27 | const node = containerRef.value
28 | const { disabled } = props
29 | if (!node || node.nodeType !== 1 || disabled) {
30 | return
31 | }
32 | // Fix radio button click twice
33 | if (
34 | (e.target as HTMLElement).tagName === 'INPUT' ||
35 | !isVisible(e.target as HTMLElement) ||
36 | // No need wave
37 | !node.getAttribute ||
38 | node.getAttribute('disabled') ||
39 | (node as HTMLInputElement).disabled ||
40 | node.className.includes('disabled') ||
41 | node.className.includes('-leave')
42 | ) {
43 | return
44 | }
45 |
46 | showWave()
47 | }
48 |
49 | useEventListener(containerRef, 'click', onClick, true)
50 |
51 | return () => {
52 | const children = slots.default?.()
53 | const child = filterEmpty(children)[0]
54 | if (!child) return null
55 | return cloneVNode(child as VNode, { ref: containerRef })
56 | }
57 | }
58 | })
59 |
60 | export default Wave
61 |
--------------------------------------------------------------------------------
/components/_util/wave/style.ts:
--------------------------------------------------------------------------------
1 | import { genComponentStyleHook } from '../../theme/internal'
2 | import type { FullToken, GenerateStyle } from '../../theme/internal'
3 |
4 | export interface ComponentToken {}
5 |
6 | export interface WaveToken extends FullToken<'Wave'> {}
7 |
8 | const genWaveStyle: GenerateStyle = token => {
9 | const { componentCls, colorPrimary } = token
10 | return {
11 | [componentCls]: {
12 | position: 'absolute',
13 | background: 'transparent',
14 | pointerEvents: 'none',
15 | boxSizing: 'border-box',
16 | color: `var(--wave-color, ${colorPrimary})`,
17 |
18 | boxShadow: `0 0 0 0 currentcolor`,
19 | opacity: 0.2,
20 |
21 | // =================== Motion ===================
22 | '&.wave-motion-appear': {
23 | transition: [`box-shadow 0.4s ${token.motionEaseOutCirc}`, `opacity 2s ${token.motionEaseOutCirc}`].join(','),
24 |
25 | '&-active': {
26 | boxShadow: `0 0 0 6px currentcolor`,
27 | opacity: 0
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
34 | export default genComponentStyleHook('Wave', token => [genWaveStyle(token)])
35 |
--------------------------------------------------------------------------------
/components/_util/wave/use-wave.ts:
--------------------------------------------------------------------------------
1 | import type { ComputedRef, Ref } from 'vue'
2 | import showWaveEffect from './wave-effect'
3 |
4 | export default function useWave(nodeRef: Ref, className: ComputedRef): VoidFunction {
5 | function showWave() {
6 | // const node = nodeRef.va!
7 | showWaveEffect(nodeRef, className)
8 | }
9 |
10 | return showWave
11 | }
12 |
--------------------------------------------------------------------------------
/components/_util/wave/util.ts:
--------------------------------------------------------------------------------
1 | export function isNotGrey(color: string) {
2 | // eslint-disable-next-line no-useless-escape
3 | const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/)
4 | if (match && match[1] && match[2] && match[3]) {
5 | return !(match[1] === match[2] && match[2] === match[3])
6 | }
7 | return true
8 | }
9 |
10 | export function isValidWaveColor(color: string) {
11 | return (
12 | color &&
13 | color !== '#fff' &&
14 | color !== '#ffffff' &&
15 | color !== 'rgb(255, 255, 255)' &&
16 | color !== 'rgba(255, 255, 255, 1)' &&
17 | isNotGrey(color) &&
18 | !/rgba\((?:\d*, ){3}0\)/.test(color) && // any transparent rgba color
19 | color !== 'transparent'
20 | )
21 | }
22 |
23 | export function getTargetWaveColor(node: HTMLElement) {
24 | const { borderTopColor, borderColor, backgroundColor } = getComputedStyle(node)
25 | if (isValidWaveColor(borderTopColor)) {
26 | return borderTopColor
27 | }
28 | if (isValidWaveColor(borderColor)) {
29 | return borderColor
30 | }
31 | if (isValidWaveColor(backgroundColor)) {
32 | return backgroundColor
33 | }
34 | return null
35 | }
36 |
--------------------------------------------------------------------------------
/components/_util/wave/wave-effect.tsx:
--------------------------------------------------------------------------------
1 | import type { ComputedRef, Ref } from 'vue'
2 | import { unrefElement, useResizeObserver } from '@vueuse/core'
3 | import { computed, defineComponent, onMounted, render, shallowRef, toRef } from 'vue'
4 | import { classNames, delayTimer, objectType, safeNextick, useState } from '@v-c/utils'
5 | import { getTargetWaveColor } from './util'
6 | function validateNum(value: number) {
7 | return Number.isNaN(value) ? 0 : value
8 | }
9 | export const WaveEffect = defineComponent({
10 | name: 'WaveEffect',
11 | props: {
12 | target: objectType()
13 | },
14 | setup(props, { attrs }) {
15 | const divRef = shallowRef(undefined)
16 |
17 | const [color, setWaveColor] = useState(null)
18 | const [borderRadius, setBorderRadius] = useState([])
19 | const [left, setLeft] = useState(0)
20 | const [top, setTop] = useState(0)
21 | const [width, setWidth] = useState(0)
22 | const [height, setHeight] = useState(0)
23 | const [enabled, setEnabled] = useState(false)
24 | const [active, setActive] = useState(false)
25 | const waveStyle = computed(() => {
26 | const style: Record = {
27 | left: `${left.value}px`,
28 | top: `${top.value}px`,
29 | width: `${width.value}px`,
30 | height: `${height.value}px`,
31 | borderRadius: borderRadius.value.map(radius => `${radius}px`).join(' ')
32 | }
33 | if (color.value) {
34 | style['--wave-color'] = color.value
35 | }
36 | return style
37 | })
38 | function syncPos() {
39 | const { target } = props
40 | const nodeStyle = getComputedStyle(target)
41 |
42 | // Get wave color from target
43 | setWaveColor(getTargetWaveColor(target))
44 |
45 | const isStatic = nodeStyle.position === 'static'
46 |
47 | // Rect
48 | const { borderLeftWidth, borderTopWidth } = nodeStyle
49 | setLeft(isStatic ? target.offsetLeft : validateNum(-parseFloat(borderLeftWidth)))
50 | setTop(isStatic ? target.offsetTop : validateNum(-parseFloat(borderTopWidth)))
51 | setWidth(target.offsetWidth)
52 | setHeight(target.offsetHeight)
53 |
54 | // Get border radius
55 | const { borderTopLeftRadius, borderTopRightRadius, borderBottomLeftRadius, borderBottomRightRadius } = nodeStyle
56 |
57 | setBorderRadius([borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius].map(radius => validateNum(parseFloat(radius))))
58 | }
59 | onMounted(async () => {
60 | syncPos()
61 | setEnabled(true)
62 | await safeNextick()
63 | setActive(true)
64 | await delayTimer(5000)
65 | const holder = divRef.value?.parentElement
66 | holder!.parentElement?.removeChild(holder!)
67 | })
68 | const motionClassName = computed(() =>
69 | classNames({
70 | 'wave-motion-appear': enabled.value,
71 | 'wave-motion': true
72 | })
73 | )
74 | const motionClassNameActive = computed(() => ({
75 | 'wave-motion-appear-active': active.value
76 | }))
77 | useResizeObserver(toRef(props, 'target'), syncPos)
78 |
79 | return () => {
80 | if (!enabled.value) return null
81 | return (
82 |
87 | )
88 | }
89 | }
90 | })
91 |
92 | export default function showWaveEffect(nodeRef: Ref, className: ComputedRef) {
93 | const node = unrefElement(nodeRef)
94 | // Create holder
95 | const holder = document.createElement('div')
96 | holder.style.position = 'absolute'
97 | holder.style.left = `0px`
98 | holder.style.top = `0px`
99 | node?.insertBefore(holder, node?.firstChild)
100 |
101 | render(
102 | ,
106 | holder
107 | )
108 | }
109 |
--------------------------------------------------------------------------------
/components/button/button-helper.tsx:
--------------------------------------------------------------------------------
1 | // import type { VNode, VNodeChild } from 'vue'
2 | // import { isString } from '@v-c/utils'
3 | import { Text } from 'vue'
4 | import type { VNode } from 'vue'
5 |
6 | const rxTwoCNChar = /^[\u4E00-\u9FA5]{2}$/
7 | export const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar)
8 |
9 | export function isUnBorderedButtonType(type?: ButtonType) {
10 | return type === 'text' || type === 'link'
11 | }
12 | export const spaceChildren = (child: VNode, needInserted: boolean) => {
13 | const SPACE = needInserted ? ' ' : ''
14 | if (child.type === Text) {
15 | let text = (child.children as string).trim()
16 | if (isTwoCNChar(text)) {
17 | text = text.split('').join(SPACE)
18 | }
19 | return {text}
20 | }
21 | return child
22 | }
23 |
24 | //
25 | // function splitCNCharsBySpace(child: VNodeChild , needInserted: boolean) {
26 | // if (child === null || child === undefined) {
27 | // return;
28 | // }
29 | //
30 | // const SPACE = needInserted ? ' ' : '';
31 | //
32 | // if (
33 | // typeof child !== 'string' &&
34 | // typeof child !== 'number' &&
35 | // isString((child as VNode)) &&
36 | // isTwoCNChar((child as VNode).children)
37 | // ) {
38 | // return cloneVNode(child as , {
39 | // children: child.props.children.split('').join(SPACE),
40 | // });
41 | // }
42 | //
43 | // if (typeof child === 'string') {
44 | // return isTwoCNChar(child) ? {child.split('').join(SPACE)} : {child};
45 | // }
46 | //
47 | // if (isFragment(child)) {
48 | // return {child};
49 | // }
50 | //
51 | // return child;
52 | // }
53 | // export function spaceChildren(children: React.ReactNode, needInserted: boolean) {
54 | // let isPrevChildPure: boolean = false;
55 | // const childList: React.ReactNode[] = [];
56 | //
57 | // React.Children.forEach(children, (child) => {
58 | // const type = typeof child;
59 | // const isCurrentChildPure = type === 'string' || type === 'number';
60 | // if (isPrevChildPure && isCurrentChildPure) {
61 | // const lastIndex = childList.length - 1;
62 | // const lastChild = childList[lastIndex];
63 | // childList[lastIndex] = `${lastChild}${child}`;
64 | // } else {
65 | // childList.push(child);
66 | // }
67 | //
68 | // isPrevChildPure = isCurrentChildPure;
69 | // });
70 | //
71 | // return React.Children.map(childList, (child) =>
72 | // splitCNCharsBySpace(child as React.ReactElement | string | number, needInserted),
73 | // );
74 | // }
75 |
76 | const ButtonTypes = [
77 | 'default',
78 | 'primary',
79 | 'ghost',
80 | 'dashed',
81 | 'link',
82 | 'text'
83 | ] as const
84 | export type ButtonType = (typeof ButtonTypes)[number]
85 |
86 | const ButtonShapes = ['default', 'circle', 'round'] as const
87 | export type ButtonShape = (typeof ButtonShapes)[number]
88 |
89 | const ButtonHTMLTypes = ['submit', 'button', 'reset'] as const
90 | export type ButtonHTMLType = (typeof ButtonHTMLTypes)[number]
91 |
--------------------------------------------------------------------------------
/components/button/button.tsx:
--------------------------------------------------------------------------------
1 | import { computed, defineComponent, onMounted, shallowRef } from 'vue'
2 | import { tryOnBeforeUnmount } from '@vueuse/core'
3 | import {
4 | classNames,
5 | filterEmpty,
6 | getSlotsProps,
7 | runEvent,
8 | useState
9 | } from '@v-c/utils'
10 | import { useProviderConfigState } from '../config-provider/context'
11 | import warning from '../_util/warning'
12 | import Wave from '../_util/wave'
13 | import { useSize } from '../_util/hooks/size'
14 | import { useDisabled } from '../_util/hooks/disabled'
15 | import { useCompactItemContext } from '../space/compact'
16 | import useStyle from './style'
17 | import type { ButtonProps, LoadingConfigType } from './interface'
18 | import { buttonProps } from './interface'
19 | import {
20 | isTwoCNChar,
21 | isUnBorderedButtonType,
22 | spaceChildren
23 | } from './button-helper'
24 | import LoadingIcon from './loading-icon'
25 | type Loading = number | boolean
26 |
27 | function getLoadingConfig(loading: ButtonProps['loading']): LoadingConfigType {
28 | if (typeof loading === 'object' && loading) {
29 | const delay = loading?.delay
30 | const isDelay = !Number.isNaN(delay) && typeof delay === 'number'
31 | return {
32 | loading: false,
33 | delay: isDelay ? delay : 0
34 | }
35 | }
36 |
37 | return {
38 | loading,
39 | delay: 0
40 | }
41 | }
42 |
43 | const Button = defineComponent({
44 | name: 'AButton',
45 | inheritAttrs: false,
46 | __ANT_BUTTON: true,
47 | props: {
48 | ...buttonProps
49 | },
50 | setup(props, { slots, attrs }) {
51 | const { getPrefixCls, autoInsertSpaceInButton, direction } =
52 | useProviderConfigState()
53 | const prefixCls = computed(() => getPrefixCls('btn', props.prefixCls))
54 | const [wrapSSR, hashId] = useStyle(prefixCls)
55 | const size = useSize(props)
56 | const { compactSize, compactItemClassnames } = useCompactItemContext(
57 | prefixCls,
58 | direction
59 | )
60 | const sizeCls = computed(() => {
61 | const sizeClassNameMap: Record = {
62 | large: 'lg',
63 | small: 'sm',
64 | middle: undefined
65 | }
66 | const sizeFullName = compactSize?.value || size.value
67 | return sizeClassNameMap[sizeFullName]
68 | })
69 | const disabled = useDisabled(props)
70 | const buttonRef = shallowRef(null)
71 |
72 | const loadingOrDelay = computed(() => {
73 | return getLoadingConfig(props.loading)
74 | })
75 |
76 | const [innerLoading, setLoading] = useState(
77 | loadingOrDelay.value.loading
78 | )
79 | const [hasTwoCNChar, setHasTwoCNChar] = useState(false)
80 |
81 | let isNeedInserted = false
82 |
83 | const fixTwoCNChar = () => {
84 | // FIXME: for HOC usage like
85 | if (!buttonRef.value || autoInsertSpaceInButton.value === false) {
86 | return
87 | }
88 | const buttonText = buttonRef.value.textContent
89 | if (isNeedInserted && isTwoCNChar(buttonText as string)) {
90 | if (!hasTwoCNChar.value) {
91 | setHasTwoCNChar(true)
92 | }
93 | } else if (hasTwoCNChar.value) {
94 | setHasTwoCNChar(false)
95 | }
96 | }
97 |
98 | let delayTimer: number | null = null
99 |
100 | onMounted(() => {
101 | if (loadingOrDelay.value.delay > 0) {
102 | delayTimer = window.setTimeout(() => {
103 | delayTimer = null
104 | setLoading(true)
105 | }, loadingOrDelay.value.delay)
106 | } else {
107 | setLoading(loadingOrDelay.value.loading)
108 | }
109 | })
110 |
111 | function cleanupTimer() {
112 | if (delayTimer) {
113 | window.clearTimeout(delayTimer)
114 | delayTimer = null
115 | }
116 | }
117 | tryOnBeforeUnmount(() => {
118 | cleanupTimer()
119 | })
120 |
121 | const handleClick = (e: MouseEvent) => {
122 | // FIXME: https://github.com/ant-design/ant-design/issues/30207
123 | if (innerLoading.value || disabled.value) {
124 | e.preventDefault()
125 | return
126 | }
127 | runEvent(props, 'onClick', e)
128 | }
129 |
130 | const showError = () => {
131 | const { ghost, type } = props
132 |
133 | const icon = getSlotsProps(slots, props, 'icon')
134 |
135 | warning(
136 | !(typeof icon === 'string' && icon.length > 2),
137 | 'Button',
138 | `\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`
139 | )
140 |
141 | warning(
142 | !(ghost && isUnBorderedButtonType(type)),
143 | 'Button',
144 | "`link` or `text` button can't be a `ghost` button."
145 | )
146 | }
147 |
148 | return () => {
149 | const { shape, rootClassName, ghost, type, block, danger } = props
150 | const icon = getSlotsProps(slots, props, 'icon')
151 | const children = filterEmpty(slots.default?.() as any)
152 | isNeedInserted =
153 | children.length === 1 &&
154 | !slots.icon &&
155 | !isUnBorderedButtonType(props.type)
156 | fixTwoCNChar()
157 | showError()
158 | const iconType = innerLoading.value ? 'loading' : icon
159 |
160 | const autoInsertSpace = autoInsertSpaceInButton.value !== false
161 |
162 | const hrefAndDisabled = attrs.href !== undefined && disabled.value
163 |
164 | const classes = classNames(
165 | prefixCls.value,
166 | hashId.value,
167 | {
168 | [`${prefixCls.value}-${shape}`]: shape !== 'default' && shape,
169 | [`${prefixCls.value}-${type}`]: type,
170 | [`${prefixCls.value}-${sizeCls.value}`]: sizeCls.value,
171 | [`${prefixCls.value}-icon-only`]:
172 | !children && children !== 0 && !!iconType,
173 | [`${prefixCls.value}-background-ghost`]:
174 | ghost && !isUnBorderedButtonType(type),
175 | [`${prefixCls.value}-loading`]: innerLoading.value,
176 | [`${prefixCls.value}-two-chinese-chars`]:
177 | hasTwoCNChar.value && autoInsertSpace && !innerLoading.value,
178 | [`${prefixCls.value}-block`]: block,
179 | [`${prefixCls.value}-dangerous`]: !!danger,
180 | [`${prefixCls.value}-rtl`]: direction.value === 'rtl',
181 | [`${prefixCls.value}-disabled`]: hrefAndDisabled
182 | },
183 | attrs.class,
184 | compactItemClassnames.value,
185 | rootClassName
186 | )
187 | const iconNode =
188 | icon &&
189 | (!innerLoading.value ? (
190 | icon?.()
191 | ) : (
192 |
197 | ))
198 |
199 | const kids =
200 | children || children === 0
201 | ? spaceChildren(children[0] as any, isNeedInserted && autoInsertSpace)
202 | : undefined
203 | if (attrs.href !== undefined) {
204 | return wrapSSR(
205 |
212 | {iconNode}
213 | {kids}
214 |
215 | )
216 | }
217 | let buttonNode = (
218 |
227 | )
228 |
229 | if (!isUnBorderedButtonType(type)) {
230 | buttonNode = {buttonNode}
231 | }
232 |
233 | return wrapSSR(buttonNode)
234 | }
235 | }
236 | })
237 |
238 | export default Button
239 |
--------------------------------------------------------------------------------
/components/button/demo/basic.vue:
--------------------------------------------------------------------------------
1 |
2 | ---
3 | title: 按钮类型
4 | ---
5 |
6 | 按钮有五种类型:主按钮、次按钮、虚线按钮、文本按钮和链接按钮。主按钮在同一个操作区域最多出现一次。
7 |
8 |
9 |
10 | ---
11 | title: Type
12 | ---
13 |
14 | There are `primary` button, `default` button, `dashed` button, `text` button and `link` button in antd.
15 |
16 |
17 |
18 |
19 | Primary Button
20 | Default Button
21 | Dashed Button
22 | Text Button
23 | Link Button
24 |
25 |
26 |
--------------------------------------------------------------------------------
/components/button/index.md:
--------------------------------------------------------------------------------
1 | # Button
2 |
3 | To trigger an operation.
4 |
5 | ## When To Use
6 |
7 | A button means an operation (or a series of operations). Clicking a button will trigger corresponding business logic.
8 |
9 | In Ant Design we provide 5 types of button.
10 |
11 | - Primary button: indicate the main action, one primary button at most in one section.
12 | - Default button: indicate a series of actions without priority.
13 | - Dashed button: used for adding action commonly.
14 | - Text button: used for the most secondary action.
15 | - Link button: used for external links.
16 |
17 | And 4 other properties additionally.
18 |
19 | - `danger`: used for actions of risk, like deletion or authorization.
20 | - `ghost`: used in situations with complex background, home pages usually.
21 | - `disabled`: when actions are not available.
22 | - `loading`: add loading spinner in button, avoiding multiple submits too.
23 |
24 | ## Examples
25 |
26 |
27 |
28 | ## API
29 |
30 | Different button styles can be generated by setting Button properties. The recommended order is: `type` -> `shape` -> `size` -> `loading` -> `disabled`.
31 |
32 | | Property | Description | Type | Default | Version |
33 | | --- | --- | --- | --- | --- |
34 | | block | Option to fit button width to its parent width | boolean | false | |
35 | | danger | Set the danger status of button | boolean | false | |
36 | | disabled | Disabled state of button | boolean | false | |
37 | | ghost | Make background transparent and invert text and border colors | boolean | false | |
38 | | href | Redirect url of link button | string | - | |
39 | | htmlType | Set the original html `type` of `button`, see: [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type) | string | `button` | |
40 | | icon | Set the icon component of button | ReactNode | - | |
41 | | loading | Set the loading status of button | boolean \| { delay: number } | false | |
42 | | shape | Can be set button shape | `default` \| `circle` \| `round` | `default` | |
43 | | size | Set the size of button | `large` \| `middle` \| `small` | `middle` | |
44 | | target | Same as target attribute of a, works when href is specified | string | - | |
45 | | type | Can be set to `primary` `ghost` `dashed` `link` `text` `default` | string | `default` | |
46 | | onClick | Set the handler to handle `click` event | (event: MouseEvent) => void | - | |
47 |
48 | It accepts all props which native buttons support.
49 |
50 | ## Design Token
51 |
52 |
53 | ## FAQ
54 |
55 | ### How to remove space between 2 chinese characters?
56 |
57 | Following the Ant Design specification, we will add one space between if Button (exclude Text button and Link button) contains two Chinese characters only. If you don't need that, you can use [ConfigProvider](/components/config-provider/#api) to set `autoInsertSpaceInButton` as `false`.
58 |
59 |
60 |
61 |
67 |
--------------------------------------------------------------------------------
/components/button/index.ts:
--------------------------------------------------------------------------------
1 | import type { App } from 'vue'
2 | import Button from './button'
3 |
4 | Button.install = function (app: App) {
5 | app.component(Button.name, Button)
6 | }
7 |
8 | export default Button
9 |
--------------------------------------------------------------------------------
/components/button/index.zh-CN.md:
--------------------------------------------------------------------------------
1 | # Button 按钮
2 |
3 | 按钮用于开始一个即时操作。
4 |
5 | ## 何时使用
6 |
7 | 标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。
8 |
9 | 在 Ant Design 中我们提供了五种按钮。
10 |
11 | - 主按钮:用于主行动点,一个操作区域只能有一个主按钮。
12 | - 默认按钮:用于没有主次之分的一组行动点。
13 | - 虚线按钮:常用于添加操作。
14 | - 文本按钮:用于最次级的行动点。
15 | - 链接按钮:一般用于链接,即导航至某位置。
16 |
17 | 以及四种状态属性与上面配合使用。
18 |
19 | - 危险:删除/移动/修改权限等危险操作,一般需要二次确认。
20 | - 幽灵:用于背景色比较复杂的地方,常用在首页/产品页等展示场景。
21 | - 禁用:行动点不可用的时候,一般需要文案解释。
22 | - 加载中:用于异步操作等待反馈的时候,也可以避免多次提交。
23 |
24 | [完整设计指南](https://ant.design/docs/spec/buttons-cn)
25 |
26 | ## 代码演示
27 |
28 |
29 |
30 |
31 | ## API
32 |
33 | 通过设置 Button 的属性来产生不同的按钮样式,推荐顺序为:`type` -> `shape` -> `size` -> `loading` -> `disabled`。
34 |
35 | 按钮的属性说明如下:
36 |
37 | | 属性 | 说明 | 类型 | 默认值 | 版本 |
38 | | --- | --- | --- | --- | --- |
39 | | block | 将按钮宽度调整为其父宽度的选项 | boolean | false | |
40 | | danger | 设置危险按钮 | boolean | false | |
41 | | disabled | 设置按钮失效状态 | boolean | false | |
42 | | ghost | 幽灵属性,使按钮背景透明 | boolean | false | |
43 | | href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | |
44 | | htmlType | 设置 `button` 原生的 `type` 值,可选值请参考 [HTML 标准](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type) | string | `button` | |
45 | | icon | 设置按钮的图标组件 | ReactNode | - | |
46 | | loading | 设置按钮载入状态 | boolean \| { delay: number } | false | |
47 | | shape | 设置按钮形状 | `default` \| `circle` \| `round` | `default` | |
48 | | size | 设置按钮大小 | `large` \| `middle` \| `small` | `middle` | |
49 | | target | 相当于 a 链接的 target 属性,href 存在时生效 | string | - | |
50 | | type | 设置按钮类型 | `primary` \| `ghost` \| `dashed` \| `link` \| `text` \| `default` | `default` | |
51 | | onClick | 点击按钮时的回调 | (event: MouseEvent) => void | - | |
52 |
53 | 支持原生 button 的其他所有属性。
54 |
55 | ## Design Token
56 |
57 |
58 | ## FAQ
59 |
60 | ### 如何移除两个汉字之间的空格?
61 |
62 | 根据 Ant Design 设计规范要求,我们会在按钮内(文本按钮和链接按钮除外)只有两个汉字时自动添加空格,如果你不需要这个特性,可以设置 [ConfigProvider](/zh-CN/components/config-provider/#api) 的 `autoInsertSpaceInButton` 为 `false`。
63 |
64 |
65 |
66 |
72 |
73 | ## 设计指引
74 |
75 | - [我的按钮究竟该放哪儿!?| Ant Design 4.0 系列分享](https://zhuanlan.zhihu.com/p/109644406)
76 |
--------------------------------------------------------------------------------
/components/button/interface.ts:
--------------------------------------------------------------------------------
1 | import { booleanType, someType, stringType, vNodeType } from '@v-c/utils'
2 | import type { ExtractPropTypes } from 'vue'
3 | import type { SizeType } from '../config-provider/context'
4 | import type { ButtonHTMLType, ButtonShape, ButtonType } from './button-helper'
5 | export interface LoadingConfigType {
6 | loading: boolean
7 | delay: number
8 | }
9 |
10 | export const buttonProps = {
11 | type: stringType('default'),
12 | icon: vNodeType(),
13 | shape: stringType(),
14 | size: someType([String], 'default'),
15 | disabled: booleanType(),
16 | loading: someType(),
17 | prefixCls: stringType(),
18 | rootClassName: stringType(),
19 | ghost: booleanType(),
20 | danger: booleanType(),
21 | block: booleanType(),
22 | htmlType: stringType('button')
23 | }
24 |
25 | export type ButtonProps = ExtractPropTypes
26 |
--------------------------------------------------------------------------------
/components/button/loading-icon.tsx:
--------------------------------------------------------------------------------
1 | import { Transition, defineComponent, nextTick } from 'vue'
2 | import { booleanType, someType, stringType } from '@v-c/utils'
3 | import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'
4 |
5 | export interface LoadingIconProps {
6 | prefixCls: string
7 | existIcon: boolean
8 | loading?: boolean | object
9 | }
10 | export const loadingIconProps = {
11 | prefixCls: stringType(),
12 | existIcon: booleanType(),
13 | loading: someType([Boolean, Object])
14 | }
15 |
16 | const getCollapsedWidth = (el: Element) => {
17 | const node: HTMLElement = el as HTMLElement
18 | if (node) {
19 | node.style.width = '0'
20 | node.style.opacity = '0'
21 | node.style.transform = 'scale(0)'
22 | }
23 | }
24 |
25 | const getRealWidth = (el: Element) => {
26 | const node: HTMLElement = el as HTMLElement
27 | nextTick(() => {
28 | if (node) {
29 | node.style.width = `${node.scrollWidth}px`
30 | node.style.opacity = '1'
31 | node.style.transform = 'scale(1)'
32 | }
33 | }).then()
34 | }
35 |
36 | const LoadingIcon = defineComponent({
37 | name: 'LoadingIcon',
38 | props: loadingIconProps,
39 | setup(props) {
40 | return () => {
41 | const { loading, existIcon, prefixCls } = props
42 | const visible = !!loading
43 | if (existIcon) {
44 | return (
45 |
46 |
47 |
48 | )
49 | }
50 | return (
51 |
56 | {visible ? (
57 |
58 |
59 |
60 | ) : null}
61 |
62 | )
63 | }
64 | }
65 | })
66 |
67 | export default LoadingIcon
68 |
--------------------------------------------------------------------------------
/components/button/style/group.ts:
--------------------------------------------------------------------------------
1 | import type { GenerateStyle } from '../../theme/internal'
2 | import type { ButtonToken } from '.'
3 |
4 | const genButtonBorderStyle = (buttonTypeCls: string, borderColor: string) => ({
5 | // Border
6 | [`> span, > ${buttonTypeCls}`]: {
7 | '&:not(:last-child)': {
8 | [`&, & > ${buttonTypeCls}`]: {
9 | '&:not(:disabled)': {
10 | borderInlineEndColor: borderColor
11 | }
12 | }
13 | },
14 |
15 | '&:not(:first-child)': {
16 | [`&, & > ${buttonTypeCls}`]: {
17 | '&:not(:disabled)': {
18 | borderInlineStartColor: borderColor
19 | }
20 | }
21 | }
22 | }
23 | })
24 |
25 | const genGroupStyle: GenerateStyle = token => {
26 | const { componentCls, fontSize, lineWidth, colorPrimaryHover, colorErrorHover } = token
27 |
28 | return {
29 | [`${componentCls}-group`]: [
30 | {
31 | position: 'relative',
32 | display: 'inline-flex',
33 |
34 | // Border
35 | [`> span, > ${componentCls}`]: {
36 | '&:not(:last-child)': {
37 | [`&, & > ${componentCls}`]: {
38 | borderStartEndRadius: 0,
39 | borderEndEndRadius: 0
40 | }
41 | },
42 |
43 | '&:not(:first-child)': {
44 | marginInlineStart: -lineWidth,
45 |
46 | [`&, & > ${componentCls}`]: {
47 | borderStartStartRadius: 0,
48 | borderEndStartRadius: 0
49 | }
50 | }
51 | },
52 |
53 | [componentCls]: {
54 | position: 'relative',
55 | zIndex: 1,
56 |
57 | [`&:hover,
58 | &:focus,
59 | &:active`]: {
60 | zIndex: 2
61 | },
62 |
63 | '&[disabled]': {
64 | zIndex: 0
65 | }
66 | },
67 |
68 | [`${componentCls}-icon-only`]: {
69 | fontSize
70 | }
71 | },
72 |
73 | // Border Color
74 | genButtonBorderStyle(`${componentCls}-primary`, colorPrimaryHover),
75 | genButtonBorderStyle(`${componentCls}-danger`, colorErrorHover)
76 | ]
77 | }
78 | }
79 |
80 | export default genGroupStyle
81 |
--------------------------------------------------------------------------------
/components/button/style/index.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
2 | import type { FullToken, GenerateStyle } from '../../theme/internal'
3 | import { genComponentStyleHook, mergeToken } from '../../theme/internal'
4 | import { genFocusStyle } from '../../style'
5 | import { genCompactItemStyle } from '../../style/compact-item'
6 | import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical'
7 | import genGroupStyle from './group'
8 |
9 | /** Component only token. Which will handle additional calculation of alias token */
10 | export interface ComponentToken {}
11 |
12 | export interface ButtonToken extends FullToken<'Button'> {
13 | // FIXME: should be removed
14 | colorOutlineDefault: string
15 | buttonPaddingHorizontal: number
16 | }
17 |
18 | // ============================== Shared ==============================
19 | const genSharedButtonStyle: GenerateStyle = (
20 | token
21 | ): CSSObject => {
22 | const { componentCls, iconCls } = token
23 | return {
24 | [componentCls]: {
25 | outline: 'none',
26 | position: 'relative',
27 | display: 'inline-block',
28 | fontWeight: 400,
29 | whiteSpace: 'nowrap',
30 | textAlign: 'center',
31 | backgroundImage: 'none',
32 | backgroundColor: 'transparent',
33 | border: `${token.lineWidth}px ${token.lineType} transparent`,
34 | cursor: 'pointer',
35 | transition: `all ${token.motionDurationMid} ${token.motionEaseInOut}`,
36 | userSelect: 'none',
37 | touchAction: 'manipulation',
38 | lineHeight: token.lineHeight,
39 | color: token.colorText,
40 |
41 | '> span': {
42 | display: 'inline-block'
43 | },
44 |
45 | // Leave a space between icon and text.
46 | [`> ${iconCls} + span, > span + ${iconCls}`]: {
47 | marginInlineStart: token.marginXS
48 | },
49 |
50 | '> a': {
51 | color: 'currentColor'
52 | },
53 |
54 | '&:not(:disabled)': {
55 | ...genFocusStyle(token)
56 | },
57 |
58 | // make `btn-icon-only` not too narrow
59 | [`&-icon-only${componentCls}-compact-item`]: {
60 | flex: 'none'
61 | },
62 | // Special styles for Primary Button
63 | [`&-compact-item${componentCls}-primary`]: {
64 | [`&:not([disabled]) + ${componentCls}-compact-item${componentCls}-primary:not([disabled])`]:
65 | {
66 | position: 'relative',
67 |
68 | '&:before': {
69 | position: 'absolute',
70 | top: -token.lineWidth,
71 | insetInlineStart: -token.lineWidth,
72 | display: 'inline-block',
73 | width: token.lineWidth,
74 | height: `calc(100% + ${token.lineWidth * 2}px)`,
75 | backgroundColor: token.colorPrimaryHover,
76 | content: '""'
77 | }
78 | }
79 | },
80 | // Special styles for Primary Button
81 | '&-compact-vertical-item': {
82 | [`&${componentCls}-primary`]: {
83 | [`&:not([disabled]) + ${componentCls}-compact-vertical-item${componentCls}-primary:not([disabled])`]:
84 | {
85 | position: 'relative',
86 |
87 | '&:before': {
88 | position: 'absolute',
89 | top: -token.lineWidth,
90 | insetInlineStart: -token.lineWidth,
91 | display: 'inline-block',
92 | width: `calc(100% + ${token.lineWidth * 2}px)`,
93 | height: token.lineWidth,
94 | backgroundColor: token.colorPrimaryHover,
95 | content: '""'
96 | }
97 | }
98 | }
99 | }
100 | }
101 | }
102 | }
103 |
104 | const genHoverActiveButtonStyle = (
105 | hoverStyle: CSSObject,
106 | activeStyle: CSSObject
107 | ): CSSObject => ({
108 | '&:not(:disabled)': {
109 | '&:hover': hoverStyle,
110 | '&:active': activeStyle
111 | }
112 | })
113 |
114 | // ============================== Shape ===============================
115 | const genCircleButtonStyle: GenerateStyle = (
116 | token
117 | ) => ({
118 | minWidth: token.controlHeight,
119 | paddingInlineStart: 0,
120 | paddingInlineEnd: 0,
121 | borderRadius: '50%'
122 | })
123 |
124 | const genRoundButtonStyle: GenerateStyle = (token) => ({
125 | borderRadius: token.controlHeight,
126 | paddingInlineStart: token.controlHeight / 2,
127 | paddingInlineEnd: token.controlHeight / 2
128 | })
129 |
130 | // =============================== Type ===============================
131 | const genDisabledStyle: GenerateStyle = (token) => ({
132 | cursor: 'not-allowed',
133 | borderColor: token.colorBorder,
134 | color: token.colorTextDisabled,
135 | backgroundColor: token.colorBgContainerDisabled,
136 | boxShadow: 'none'
137 | })
138 |
139 | const genGhostButtonStyle = (
140 | btnCls: string,
141 | textColor: string | false,
142 | borderColor: string | false,
143 | textColorDisabled: string | false,
144 | borderColorDisabled: string | false,
145 | hoverStyle?: CSSObject,
146 | activeStyle?: CSSObject
147 | ): CSSObject => ({
148 | [`&${btnCls}-background-ghost`]: {
149 | color: textColor || undefined,
150 | backgroundColor: 'transparent',
151 | borderColor: borderColor || undefined,
152 | boxShadow: 'none',
153 |
154 | ...genHoverActiveButtonStyle(
155 | {
156 | backgroundColor: 'transparent',
157 | ...hoverStyle
158 | },
159 | {
160 | backgroundColor: 'transparent',
161 | ...activeStyle
162 | }
163 | ),
164 |
165 | '&:disabled': {
166 | cursor: 'not-allowed',
167 | color: textColorDisabled || undefined,
168 | borderColor: borderColorDisabled || undefined
169 | }
170 | }
171 | })
172 |
173 | const genSolidDisabledButtonStyle: GenerateStyle = (
174 | token
175 | ) => ({
176 | '&:disabled': {
177 | ...genDisabledStyle(token)
178 | }
179 | })
180 |
181 | const genSolidButtonStyle: GenerateStyle = (token) => ({
182 | ...genSolidDisabledButtonStyle(token)
183 | })
184 |
185 | const genPureDisabledButtonStyle: GenerateStyle = (
186 | token
187 | ) => ({
188 | '&:disabled': {
189 | cursor: 'not-allowed',
190 | color: token.colorTextDisabled
191 | }
192 | })
193 |
194 | // Type: Default
195 | const genDefaultButtonStyle: GenerateStyle = (
196 | token
197 | ) => ({
198 | ...genSolidButtonStyle(token),
199 |
200 | backgroundColor: token.colorBgContainer,
201 | borderColor: token.colorBorder,
202 |
203 | boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`,
204 |
205 | ...genHoverActiveButtonStyle(
206 | {
207 | color: token.colorPrimaryHover,
208 | borderColor: token.colorPrimaryHover
209 | },
210 | {
211 | color: token.colorPrimaryActive,
212 | borderColor: token.colorPrimaryActive
213 | }
214 | ),
215 |
216 | ...genGhostButtonStyle(
217 | token.componentCls,
218 | token.colorBgContainer,
219 | token.colorBgContainer,
220 | token.colorTextDisabled,
221 | token.colorBorder
222 | ),
223 |
224 | [`&${token.componentCls}-dangerous`]: {
225 | color: token.colorError,
226 | borderColor: token.colorError,
227 |
228 | ...genHoverActiveButtonStyle(
229 | {
230 | color: token.colorErrorHover,
231 | borderColor: token.colorErrorBorderHover
232 | },
233 | {
234 | color: token.colorErrorActive,
235 | borderColor: token.colorErrorActive
236 | }
237 | ),
238 |
239 | ...genGhostButtonStyle(
240 | token.componentCls,
241 | token.colorError,
242 | token.colorError,
243 | token.colorTextDisabled,
244 | token.colorBorder
245 | ),
246 | ...genSolidDisabledButtonStyle(token)
247 | }
248 | })
249 |
250 | // Type: Primary
251 | const genPrimaryButtonStyle: GenerateStyle = (
252 | token
253 | ) => ({
254 | ...genSolidButtonStyle(token),
255 |
256 | color: token.colorTextLightSolid,
257 | backgroundColor: token.colorPrimary,
258 |
259 | boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`,
260 |
261 | ...genHoverActiveButtonStyle(
262 | {
263 | color: token.colorTextLightSolid,
264 | backgroundColor: token.colorPrimaryHover
265 | },
266 | {
267 | color: token.colorTextLightSolid,
268 | backgroundColor: token.colorPrimaryActive
269 | }
270 | ),
271 |
272 | ...genGhostButtonStyle(
273 | token.componentCls,
274 | token.colorPrimary,
275 | token.colorPrimary,
276 | token.colorTextDisabled,
277 | token.colorBorder,
278 | {
279 | color: token.colorPrimaryHover,
280 | borderColor: token.colorPrimaryHover
281 | },
282 | {
283 | color: token.colorPrimaryActive,
284 | borderColor: token.colorPrimaryActive
285 | }
286 | ),
287 |
288 | [`&${token.componentCls}-dangerous`]: {
289 | backgroundColor: token.colorError,
290 | boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`,
291 |
292 | ...genHoverActiveButtonStyle(
293 | {
294 | backgroundColor: token.colorErrorHover
295 | },
296 | {
297 | backgroundColor: token.colorErrorActive
298 | }
299 | ),
300 |
301 | ...genGhostButtonStyle(
302 | token.componentCls,
303 | token.colorError,
304 | token.colorError,
305 | token.colorTextDisabled,
306 | token.colorBorder,
307 | {
308 | color: token.colorErrorHover,
309 | borderColor: token.colorErrorHover
310 | },
311 | {
312 | color: token.colorErrorActive,
313 | borderColor: token.colorErrorActive
314 | }
315 | ),
316 | ...genSolidDisabledButtonStyle(token)
317 | }
318 | })
319 |
320 | // Type: Dashed
321 | const genDashedButtonStyle: GenerateStyle = (
322 | token
323 | ) => ({
324 | ...genDefaultButtonStyle(token),
325 | borderStyle: 'dashed'
326 | })
327 |
328 | // Type: Link
329 | const genLinkButtonStyle: GenerateStyle = (token) => ({
330 | color: token.colorLink,
331 |
332 | ...genHoverActiveButtonStyle(
333 | {
334 | color: token.colorLinkHover
335 | },
336 | {
337 | color: token.colorLinkActive
338 | }
339 | ),
340 |
341 | ...genPureDisabledButtonStyle(token),
342 |
343 | [`&${token.componentCls}-dangerous`]: {
344 | color: token.colorError,
345 |
346 | ...genHoverActiveButtonStyle(
347 | {
348 | color: token.colorErrorHover
349 | },
350 | {
351 | color: token.colorErrorActive
352 | }
353 | ),
354 |
355 | ...genPureDisabledButtonStyle(token)
356 | }
357 | })
358 |
359 | // Type: Text
360 | const genTextButtonStyle: GenerateStyle = (token) => ({
361 | ...genHoverActiveButtonStyle(
362 | {
363 | color: token.colorText,
364 | backgroundColor: token.colorBgTextHover
365 | },
366 | {
367 | color: token.colorText,
368 | backgroundColor: token.colorBgTextActive
369 | }
370 | ),
371 |
372 | ...genPureDisabledButtonStyle(token),
373 |
374 | [`&${token.componentCls}-dangerous`]: {
375 | color: token.colorError,
376 |
377 | ...genPureDisabledButtonStyle(token),
378 | ...genHoverActiveButtonStyle(
379 | {
380 | color: token.colorErrorHover,
381 | backgroundColor: token.colorErrorBg
382 | },
383 | {
384 | color: token.colorErrorHover,
385 | backgroundColor: token.colorErrorBg
386 | }
387 | )
388 | }
389 | })
390 |
391 | // Href and Disabled
392 | const genDisabledButtonStyle: GenerateStyle = (
393 | token
394 | ) => ({
395 | ...genDisabledStyle(token),
396 | [`&${token.componentCls}:hover`]: {
397 | ...genDisabledStyle(token)
398 | }
399 | })
400 |
401 | const genTypeButtonStyle: GenerateStyle = (token) => {
402 | const { componentCls } = token
403 |
404 | return {
405 | [`${componentCls}-default`]: genDefaultButtonStyle(token),
406 | [`${componentCls}-primary`]: genPrimaryButtonStyle(token),
407 | [`${componentCls}-dashed`]: genDashedButtonStyle(token),
408 | [`${componentCls}-link`]: genLinkButtonStyle(token),
409 | [`${componentCls}-text`]: genTextButtonStyle(token),
410 | [`${componentCls}-disabled`]: genDisabledButtonStyle(token)
411 | }
412 | }
413 |
414 | // =============================== Size ===============================
415 | const genSizeButtonStyle = (
416 | token: ButtonToken,
417 | sizePrefixCls = ''
418 | ): CSSInterpolation => {
419 | const {
420 | componentCls,
421 | iconCls,
422 | controlHeight,
423 | fontSize,
424 | lineHeight,
425 | lineWidth,
426 | borderRadius,
427 | buttonPaddingHorizontal
428 | } = token
429 |
430 | const paddingVertical = Math.max(
431 | 0,
432 | (controlHeight - fontSize * lineHeight) / 2 - lineWidth
433 | )
434 | const paddingHorizontal = buttonPaddingHorizontal - lineWidth
435 |
436 | const iconOnlyCls = `${componentCls}-icon-only`
437 |
438 | return [
439 | // Size
440 | {
441 | [`${componentCls}${sizePrefixCls}`]: {
442 | fontSize,
443 | height: controlHeight,
444 | padding: `${paddingVertical}px ${paddingHorizontal}px`,
445 | borderRadius,
446 |
447 | [`&${iconOnlyCls}`]: {
448 | width: controlHeight,
449 | paddingInlineStart: 0,
450 | paddingInlineEnd: 0,
451 | [`&${componentCls}-round`]: {
452 | width: 'auto'
453 | },
454 | '> span': {
455 | transform: 'scale(1.143)' // 14px -> 16px
456 | }
457 | },
458 |
459 | // Loading
460 | [`&${componentCls}-loading`]: {
461 | opacity: token.opacityLoading,
462 | cursor: 'default'
463 | },
464 |
465 | [`${componentCls}-loading-icon`]: {
466 | transition: `width ${token.motionDurationSlow} ${token.motionEaseInOut}, opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`
467 | },
468 |
469 | [`&:not(${iconOnlyCls}) ${componentCls}-loading-icon > ${iconCls}`]: {
470 | marginInlineEnd: token.marginXS
471 | }
472 | }
473 | },
474 |
475 | // Shape - patch prefixCls again to override solid border radius style
476 | {
477 | [`${componentCls}${componentCls}-circle${sizePrefixCls}`]:
478 | genCircleButtonStyle(token)
479 | },
480 | {
481 | [`${componentCls}${componentCls}-round${sizePrefixCls}`]:
482 | genRoundButtonStyle(token)
483 | }
484 | ]
485 | }
486 |
487 | const genSizeBaseButtonStyle: GenerateStyle = (token) =>
488 | genSizeButtonStyle(token)
489 |
490 | const genSizeSmallButtonStyle: GenerateStyle = (token) => {
491 | const smallToken = mergeToken(token, {
492 | controlHeight: token.controlHeightSM,
493 | padding: token.paddingXS,
494 | buttonPaddingHorizontal: 8, // Fixed padding
495 | borderRadius: token.borderRadiusSM
496 | })
497 |
498 | return genSizeButtonStyle(smallToken, `${token.componentCls}-sm`)
499 | }
500 |
501 | const genSizeLargeButtonStyle: GenerateStyle = (token) => {
502 | const largeToken = mergeToken(token, {
503 | controlHeight: token.controlHeightLG,
504 | fontSize: token.fontSizeLG,
505 | borderRadius: token.borderRadiusLG
506 | })
507 |
508 | return genSizeButtonStyle(largeToken, `${token.componentCls}-lg`)
509 | }
510 |
511 | const genBlockButtonStyle: GenerateStyle = (token) => {
512 | const { componentCls } = token
513 | return {
514 | [componentCls]: {
515 | [`&${componentCls}-block`]: {
516 | width: '100%'
517 | }
518 | }
519 | }
520 | }
521 |
522 | // ============================== Export ==============================
523 | export default genComponentStyleHook('Button', (token) => {
524 | const { controlTmpOutline, paddingContentHorizontal } = token
525 |
526 | const buttonToken = mergeToken(token, {
527 | colorOutlineDefault: controlTmpOutline,
528 | buttonPaddingHorizontal: paddingContentHorizontal
529 | })
530 |
531 | return [
532 | // Shared
533 | genSharedButtonStyle(buttonToken),
534 |
535 | // Size
536 | genSizeSmallButtonStyle(buttonToken),
537 | genSizeBaseButtonStyle(buttonToken),
538 | genSizeLargeButtonStyle(buttonToken),
539 |
540 | // Block
541 | genBlockButtonStyle(buttonToken),
542 |
543 | // Group (type, ghost, danger, disabled, loading)
544 | genTypeButtonStyle(buttonToken),
545 |
546 | // Button Group
547 | genGroupStyle(buttonToken),
548 |
549 | // Space Compact
550 | genCompactItemStyle(token, { focus: false }),
551 | genCompactItemVerticalStyle(token)
552 | ]
553 | })
554 |
--------------------------------------------------------------------------------
/components/components.ts:
--------------------------------------------------------------------------------
1 | export { default as Button } from './button'
2 | export { default as ConfigProvider } from './config-provider'
3 | export { default as Space } from './space'
4 |
--------------------------------------------------------------------------------
/components/config-provider/context.ts:
--------------------------------------------------------------------------------
1 | import {
2 | booleanType,
3 | createInjectionState,
4 | functionType,
5 | objectType,
6 | someType,
7 | stringType
8 | } from '@v-c/utils'
9 | import type { ExtractPropTypes } from 'vue'
10 | import { computed } from 'vue'
11 | import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs'
12 | import type {
13 | AliasToken,
14 | MapToken,
15 | OverrideToken,
16 | SeedToken
17 | } from '../theme/interface'
18 | import type { RenderEmptyHandler } from './default-render-empty'
19 | import type { ConfigProviderProps } from './index'
20 |
21 | export type SizeType = 'small' | 'middle' | 'large' | undefined
22 |
23 | export interface Theme {
24 | primaryColor?: string
25 | infoColor?: string
26 | successColor?: string
27 | processingColor?: string
28 | errorColor?: string
29 | warningColor?: string
30 | }
31 |
32 | export interface CSPConfig {
33 | nonce?: string
34 | }
35 |
36 | export type DirectionType = 'ltr' | 'rtl' | undefined
37 |
38 | export type MappingAlgorithm = DerivativeFunc
39 |
40 | export interface ThemeConfig {
41 | token?: Partial
42 | components?: OverrideToken
43 | algorithm?: MappingAlgorithm | MappingAlgorithm[]
44 | hashed?: boolean
45 | inherit?: boolean
46 | }
47 | export const defaultIconPrefixCls = 'anticon'
48 |
49 | const defaultGetPrefixCls = (
50 | suffixCls?: string,
51 | customizePrefixCls?: string
52 | ) => {
53 | if (customizePrefixCls) return customizePrefixCls
54 |
55 | return suffixCls ? `ant-${suffixCls}` : 'ant'
56 | }
57 |
58 | export const configConsumerProps = {
59 | getTargetContainer: functionType<() => HTMLElement>(),
60 | getPopupContainer: functionType<(triggerNode?: HTMLElement) => HTMLElement>(),
61 | rootPrefixCls: stringType(),
62 | iconPrefixCls: stringType(defaultIconPrefixCls),
63 | getPrefixCls: functionType(defaultGetPrefixCls),
64 | renderEmpty: functionType(),
65 | csp: objectType(),
66 | autoInsertSpaceInButton: booleanType(),
67 | input: objectType<{
68 | autoComplete?: string
69 | }>(),
70 | pagination: objectType<{
71 | showSizeChanger?: boolean
72 | }>(),
73 | locale: objectType(),
74 | pageHeader: objectType<{
75 | ghost: boolean
76 | }>(),
77 | direction: someType([String]),
78 | space: objectType<{
79 | size?: SizeType | number
80 | }>(),
81 | virtual: booleanType(),
82 | dropdownMatchSelectWidth: booleanType(),
83 | form: objectType<{
84 | // requiredMark?: RequiredMark
85 | colon?: boolean
86 | // scrollToFirstError?: Options | boolean
87 | }>(),
88 | theme: objectType(),
89 | select: objectType<{
90 | showSearch?: boolean
91 | }>()
92 | }
93 |
94 | export type ConfigConsumerProps = ExtractPropTypes
95 |
96 | const configState = (props: ConfigProviderProps) => {
97 | const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {
98 | const { prefixCls, getPrefixCls } = props
99 | if (customizePrefixCls) return customizePrefixCls
100 | const mergedPrefixCls =
101 | prefixCls || getPrefixCls?.('') || defaultGetPrefixCls('')
102 | return suffixCls ? `${mergedPrefixCls}-${suffixCls}` : mergedPrefixCls
103 | }
104 | const iconPrefixCls = computed(
105 | () => props?.iconPrefixCls ?? defaultIconPrefixCls
106 | )
107 | const shouldWrapSSR = computed(
108 | () => iconPrefixCls.value !== defaultIconPrefixCls
109 | )
110 | const csp = computed(() => props?.csp)
111 | const componentSize = computed(() => props?.componentSize)
112 | const componentDisabled = computed(() => props?.componentDisabled)
113 | const autoInsertSpaceInButton = computed(() => props?.autoInsertSpaceInButton)
114 | const direction = computed(() => props?.direction)
115 | return {
116 | getPrefixCls,
117 | iconPrefixCls,
118 | shouldWrapSSR,
119 | csp,
120 | componentSize,
121 | componentDisabled,
122 | autoInsertSpaceInButton,
123 | direction
124 | }
125 | }
126 | const [useProviderConfigProvide, useProviderConfigInject] =
127 | createInjectionState(configState)
128 |
129 | export { useProviderConfigProvide }
130 | export const useProviderConfigState = (): ReturnType => {
131 | return (
132 | useProviderConfigInject() ??
133 | ({
134 | getPrefixCls: defaultGetPrefixCls,
135 | iconPrefixCls: computed(() => defaultIconPrefixCls),
136 | componentSize: computed(() => undefined),
137 | componentDisabled: computed(() => false),
138 | direction: computed(() => undefined),
139 | autoInsertSpaceInButton: computed(() => true)
140 | } as any)
141 | )
142 | }
143 |
--------------------------------------------------------------------------------
/components/config-provider/css-variables.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export, prefer-destructuring */
2 |
3 | import { generate } from '@ant-design/colors'
4 | import { TinyColor } from '@ctrl/tinycolor'
5 | import { canUseDom, updateCSS, warning } from '@v-c/utils'
6 | import type { Theme } from './context'
7 |
8 | const dynamicStyleMark = `-ant-${Date.now()}-${Math.random()}`
9 |
10 | export function getStyle(globalPrefixCls: string, theme: Theme) {
11 | const variables: Record = {}
12 |
13 | const formatColor = (color: TinyColor, updater?: (cloneColor: TinyColor) => TinyColor) => {
14 | let clone = color.clone()
15 | clone = updater?.(clone) || clone
16 | return clone.toRgbString()
17 | }
18 |
19 | const fillColor = (colorVal: string, type: string) => {
20 | const baseColor = new TinyColor(colorVal)
21 | const colorPalettes = generate(baseColor.toRgbString())
22 |
23 | variables[`${type}-color`] = formatColor(baseColor)
24 | variables[`${type}-color-disabled`] = colorPalettes[1]
25 | variables[`${type}-color-hover`] = colorPalettes[4]
26 | variables[`${type}-color-active`] = colorPalettes[6]
27 | variables[`${type}-color-outline`] = baseColor.clone().setAlpha(0.2).toRgbString()
28 | variables[`${type}-color-deprecated-bg`] = colorPalettes[0]
29 | variables[`${type}-color-deprecated-border`] = colorPalettes[2]
30 | }
31 |
32 | // ================ Primary Color ================
33 | if (theme.primaryColor) {
34 | fillColor(theme.primaryColor, 'primary')
35 |
36 | const primaryColor = new TinyColor(theme.primaryColor)
37 | const primaryColors = generate(primaryColor.toRgbString())
38 |
39 | // Legacy - We should use semantic naming standard
40 | primaryColors.forEach((color, index) => {
41 | variables[`primary-${index + 1}`] = color
42 | })
43 | // Deprecated
44 | variables['primary-color-deprecated-l-35'] = formatColor(primaryColor, c => c.lighten(35))
45 | variables['primary-color-deprecated-l-20'] = formatColor(primaryColor, c => c.lighten(20))
46 | variables['primary-color-deprecated-t-20'] = formatColor(primaryColor, c => c.tint(20))
47 | variables['primary-color-deprecated-t-50'] = formatColor(primaryColor, c => c.tint(50))
48 | variables['primary-color-deprecated-f-12'] = formatColor(primaryColor, c => c.setAlpha(c.getAlpha() * 0.12))
49 |
50 | const primaryActiveColor = new TinyColor(primaryColors[0])
51 | variables['primary-color-active-deprecated-f-30'] = formatColor(primaryActiveColor, c => c.setAlpha(c.getAlpha() * 0.3))
52 | variables['primary-color-active-deprecated-d-02'] = formatColor(primaryActiveColor, c => c.darken(2))
53 | }
54 |
55 | // ================ Success Color ================
56 | if (theme.successColor) {
57 | fillColor(theme.successColor, 'success')
58 | }
59 |
60 | // ================ Warning Color ================
61 | if (theme.warningColor) {
62 | fillColor(theme.warningColor, 'warning')
63 | }
64 |
65 | // ================= Error Color =================
66 | if (theme.errorColor) {
67 | fillColor(theme.errorColor, 'error')
68 | }
69 |
70 | // ================= Info Color ==================
71 | if (theme.infoColor) {
72 | fillColor(theme.infoColor, 'info')
73 | }
74 |
75 | // Convert to css variables
76 | const cssList = Object.keys(variables).map(key => `--${globalPrefixCls}-${key}: ${variables[key]};`)
77 |
78 | return `
79 | :root {
80 | ${cssList.join('\n')}
81 | }
82 | `.trim()
83 | }
84 |
85 | export function registerTheme(globalPrefixCls: string, theme: Theme) {
86 | const style = getStyle(globalPrefixCls, theme)
87 |
88 | if (canUseDom()) {
89 | updateCSS(style, `${dynamicStyleMark}-dynamic-theme`)
90 | } else {
91 | // @ts-expect-error this is ssr
92 | warning(false, 'ConfigProvider', 'SSR do not support dynamic theme with css variables.')
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/components/config-provider/default-render-empty.tsx:
--------------------------------------------------------------------------------
1 | import type { VNodeChild } from 'vue'
2 |
3 | export type RenderEmptyHandler = (componentName?: string) => VNodeChild
4 |
--------------------------------------------------------------------------------
/components/config-provider/hooks/config.ts:
--------------------------------------------------------------------------------
1 | import { useProviderConfigState } from '../context'
2 |
3 | export const useConfig = () => {
4 | const { componentDisabled, componentSize } = useProviderConfigState()
5 | return {
6 | componentDisabled,
7 | componentSize
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/components/config-provider/index.md:
--------------------------------------------------------------------------------
1 | # ConfigProvider
2 |
--------------------------------------------------------------------------------
/components/config-provider/index.tsx:
--------------------------------------------------------------------------------
1 | import { booleanType, objectType, someType, stringType } from '@v-c/utils'
2 | import type { App, ExtractPropTypes } from 'vue'
3 | import { computed, defineComponent } from 'vue'
4 | import { createTheme } from '@antd-tiny-vue/cssinjs'
5 | import defaultSeedToken from '../theme/themes/seed'
6 | import type { DesignTokenConfig } from '../theme/internal'
7 | import { DesignTokenProviderContext } from '../theme/internal'
8 | import type { CSPConfig, ConfigConsumerProps, DirectionType, SizeType, Theme, ThemeConfig } from './context'
9 | import { configConsumerProps, defaultIconPrefixCls, useProviderConfigProvide } from './context'
10 | import { registerTheme } from './css-variables'
11 | import type { RenderEmptyHandler } from './default-render-empty'
12 |
13 | import useStyle from './style'
14 | import { useConfig } from './hooks/config'
15 | export type { RenderEmptyHandler, CSPConfig, DirectionType, ConfigConsumerProps, ThemeConfig }
16 |
17 | export { defaultIconPrefixCls }
18 | export const configProviderProps = {
19 | ...configConsumerProps,
20 | prefixCls: stringType(),
21 | componentSize: someType([String]),
22 | componentDisabled: booleanType(),
23 | legacyLocale: objectType()
24 | }
25 |
26 | export type ConfigProviderProps = Partial>
27 |
28 | export const defaultPrefixCls = 'ant'
29 |
30 | // These props is used by `useContext` directly in sub component
31 | // const PASSED_PROPS: Exclude[] = [
32 | // 'getTargetContainer',
33 | // 'getPopupContainer',
34 | // 'renderEmpty',
35 | // 'pageHeader',
36 | // 'input',
37 | // 'pagination',
38 | // 'form',
39 | // 'select'
40 | // ]
41 |
42 | let globalPrefixCls: string
43 | let globalIconPrefixCls: string
44 |
45 | function getGlobalPrefixCls() {
46 | return globalPrefixCls || defaultPrefixCls
47 | }
48 |
49 | function getGlobalIconPrefixCls() {
50 | return globalIconPrefixCls || defaultIconPrefixCls
51 | }
52 |
53 | export const setGlobalConfig = ({ prefixCls, iconPrefixCls, theme }: Pick & { theme?: Theme }) => {
54 | if (prefixCls !== undefined) {
55 | globalPrefixCls = prefixCls
56 | }
57 | if (iconPrefixCls !== undefined) {
58 | globalIconPrefixCls = iconPrefixCls
59 | }
60 |
61 | if (theme) {
62 | registerTheme(getGlobalPrefixCls(), theme)
63 | }
64 | }
65 |
66 | export const globalConfig = () => ({
67 | getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
68 | if (customizePrefixCls) return customizePrefixCls
69 | return suffixCls ? `${getGlobalPrefixCls()}-${suffixCls}` : getGlobalPrefixCls()
70 | },
71 | getIconPrefixCls: getGlobalIconPrefixCls,
72 | getRootPrefixCls: () => {
73 | // If Global prefixCls provided, use this
74 | if (globalPrefixCls) {
75 | return globalPrefixCls
76 | }
77 |
78 | // Fallback to default prefixCls
79 | return getGlobalPrefixCls()
80 | }
81 | })
82 |
83 | const ConfigProvider = defineComponent({
84 | name: 'AConfigProvider',
85 | props: {
86 | ...configProviderProps
87 | },
88 | setup(props, { slots }) {
89 | // 依赖注入
90 | const { shouldWrapSSR, iconPrefixCls } = useProviderConfigProvide(props)
91 | const wrapSSR = useStyle(iconPrefixCls)
92 | const memoTheme = computed(() => {
93 | const { algorithm, token, ...rest } = props.theme || {}
94 | const themeObj = algorithm && (!Array.isArray(algorithm) || algorithm.length > 0) ? createTheme(algorithm) : undefined
95 | return {
96 | ...rest,
97 | theme: themeObj,
98 | token: {
99 | ...defaultSeedToken,
100 | ...token
101 | }
102 | }
103 | })
104 |
105 | return () => {
106 | const { locale, theme } = props
107 | const children = slots.default?.()
108 | let childNode = shouldWrapSSR.value ? wrapSSR(children) : children
109 |
110 | /**
111 | * Form
112 | */
113 | // const validateMessages = React.useMemo(
114 | // () =>
115 | // setValues(
116 | // {},
117 | // defaultLocale.Form?.defaultValidateMessages || {},
118 | // memoedConfig.locale?.Form?.defaultValidateMessages || {},
119 | // form?.validateMessages || {},
120 | // ),
121 | // [memoedConfig, form?.validateMessages],
122 | // );
123 | //
124 | // if (Object.keys(validateMessages).length > 0) {
125 | // childNode = {children};
126 | // }
127 | /**
128 | * 多语言实现部分
129 | */
130 | if (locale) {
131 | // 多语言部分
132 | // childNode = {childNode};
133 | }
134 |
135 | if (theme) {
136 | childNode = (
137 |
141 | {childNode}
142 |
143 | )
144 | }
145 |
146 | return childNode
147 | }
148 | }
149 | })
150 |
151 | ConfigProvider.install = (app: App) => {
152 | app.component(ConfigProvider.name, ConfigProvider)
153 | }
154 |
155 | ConfigProvider.config = setGlobalConfig
156 |
157 | ConfigProvider.useConfig = useConfig
158 | export default ConfigProvider as typeof ConfigProvider & {
159 | install(app: App): void
160 | config: typeof setGlobalConfig
161 | useConfig: typeof useConfig
162 | }
163 |
--------------------------------------------------------------------------------
/components/config-provider/index.zh-CN.md:
--------------------------------------------------------------------------------
1 | # ConfigProvider 全局配置
2 |
--------------------------------------------------------------------------------
/components/config-provider/style/index.ts:
--------------------------------------------------------------------------------
1 | import { useStyleRegister } from '@antd-tiny-vue/cssinjs'
2 | import type { Ref } from 'vue'
3 | import { computed } from 'vue'
4 | import { resetIcon } from '../../style'
5 | import { useToken } from '../../theme/internal'
6 |
7 | const useStyle = (iconPrefixCls: Ref) => {
8 | const [theme, token] = useToken()
9 | // Generate style for icons
10 | const info = computed(() => ({ theme: theme.value, token: token.value, hashId: '', path: ['ant-design-icons', iconPrefixCls.value] }))
11 | return useStyleRegister(info, () => [
12 | {
13 | [`.${iconPrefixCls.value}`]: {
14 | ...resetIcon(),
15 | [`.${iconPrefixCls.value} .${iconPrefixCls.value}-icon`]: {
16 | display: 'block'
17 | }
18 | }
19 | }
20 | ])
21 | }
22 |
23 | export default useStyle
24 |
--------------------------------------------------------------------------------
/components/index.ts:
--------------------------------------------------------------------------------
1 | import type { App } from 'vue'
2 | import * as components from './components'
3 | import version from './version'
4 |
5 | export default {
6 | install(app: App) {
7 | for (const componentsKey in components) {
8 | const component = (components as any)[componentsKey]
9 | if (component.install) {
10 | app.use(component)
11 | }
12 | }
13 | },
14 | version
15 | }
16 |
--------------------------------------------------------------------------------
/components/space/compact.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | anyType,
3 | booleanType,
4 | classNames,
5 | createInjectionState,
6 | filterEmpty,
7 | isObject,
8 | stringType
9 | } from '@v-c/utils'
10 | import type { Ref } from 'vue'
11 | import { computed, defineComponent } from 'vue'
12 | import type { DirectionType } from '../config-provider'
13 | import type { SizeType } from '../config-provider/context'
14 | import { useProviderConfigState } from '../config-provider/context'
15 | import useStyle from './style'
16 |
17 | const spaceCompactItem = (props: any) => {
18 | return {
19 | compactDirection: computed(() => props.compactDirection),
20 | isFirstItem: computed(() => props.isFirstItem),
21 | isLastItem: computed(() => props.isLastItem),
22 | compactSize: computed(() => props.compactSize)
23 | }
24 | }
25 |
26 | export const [useSpaceCompactProvider, useSpaceCompactInject] =
27 | createInjectionState(spaceCompactItem)
28 |
29 | export const useSpaceCompactItemState = ():
30 | | ReturnType
31 | | undefined => useSpaceCompactInject()
32 |
33 | export const useCompactItemContext = (
34 | prefixCls: Ref,
35 | direction: Ref
36 | ) => {
37 | const compactItemContext = useSpaceCompactItemState()
38 |
39 | const compactItemClassnames = computed(() => {
40 | if (!compactItemContext) return ''
41 |
42 | const { compactDirection, isFirstItem, isLastItem } = compactItemContext
43 | const separator = compactDirection.value === 'vertical' ? '-vertical-' : '-'
44 |
45 | return classNames({
46 | [`${prefixCls.value}-compact${separator}item`]: true,
47 | [`${prefixCls.value}-compact${separator}first-item`]: isFirstItem.value,
48 | [`${prefixCls.value}-compact${separator}last-item`]: isLastItem.value,
49 | [`${prefixCls.value}-compact${separator}item-rtl`]:
50 | direction.value === 'rtl'
51 | })
52 | })
53 |
54 | return {
55 | compactSize: compactItemContext?.compactSize,
56 | compactDirection: compactItemContext?.compactDirection,
57 | compactItemClassnames
58 | }
59 | }
60 |
61 | const CompactItem = defineComponent({
62 | name: 'CompactItem',
63 | inheritAttrs: false,
64 | props: {
65 | compactSize: anyType(),
66 | compactDirection: stringType<'horizontal' | 'vertical'>(),
67 | isFirstItem: booleanType(),
68 | isLastItem: booleanType()
69 | },
70 | setup(props, { slots }) {
71 | useSpaceCompactProvider(props)
72 | return () => slots.default?.()
73 | }
74 | })
75 |
76 | export const spaceCompactProps = {
77 | prefixCls: stringType(),
78 | size: anyType('middle'),
79 | direction: stringType<'horizontal' | 'vertical'>(),
80 | block: anyType(),
81 | rootClassName: stringType()
82 | }
83 |
84 | const Compact = defineComponent({
85 | name: 'Compact',
86 | inheritAttrs: false,
87 | props: spaceCompactProps,
88 | setup(props, { slots, attrs }) {
89 | const { getPrefixCls, direction: directionConfig } =
90 | useProviderConfigState()
91 | const prefixCls = computed(() =>
92 | getPrefixCls('space-compact', props.prefixCls)
93 | )
94 | const [wrapSSR, hashId] = useStyle(prefixCls)
95 | const compactItemContext = useSpaceCompactItemState()
96 | return () => {
97 | const childNodes = filterEmpty(slots.default?.())
98 | if (childNodes.length === 0) return null
99 | const { rootClassName, size, direction } = props
100 | const cls = classNames(
101 | prefixCls.value,
102 | hashId.value,
103 | {
104 | [`${prefixCls.value}-rtl`]: directionConfig.value === 'rtl',
105 | [`${prefixCls.value}-block`]: props.block,
106 | [`${prefixCls.value}-vertical`]: props.direction === 'vertical'
107 | },
108 | attrs.class,
109 | rootClassName
110 | )
111 | const nodes = childNodes.map((child, index) => {
112 | const key =
113 | (isObject(child) && (child as any).key) ||
114 | `${prefixCls.value}-item-${index}`
115 | return (
116 |
129 | {child}
130 |
131 | )
132 | })
133 | return wrapSSR(
134 |
135 | {nodes}
136 |
137 | )
138 | }
139 | }
140 | })
141 |
142 | export default Compact
143 |
--------------------------------------------------------------------------------
/components/space/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | anyType,
3 | booleanType,
4 | classNames,
5 | createInjectionState,
6 | filterEmpty,
7 | isObject,
8 | stringType,
9 | vNodeType
10 | } from '@v-c/utils'
11 | import type { App, CSSProperties } from 'vue'
12 | import { computed, defineComponent, shallowRef } from 'vue'
13 | import type { SizeType } from '../config-provider/context'
14 | import { useProviderConfigState } from '../config-provider/context'
15 | import useFlexGapSupport from '../_util/hooks/flex-gap-support'
16 | import useStyle from './style'
17 | import Item from './item'
18 | import Compact from './compact'
19 |
20 | export type SpaceSize = SizeType | number
21 |
22 | const spaceState = function ({ sizes, supportFlexGap, latestIndex }: any) {
23 | return {
24 | latestIndex: computed(() => latestIndex.value),
25 | horizontalSize: computed(() => sizes[0]),
26 | verticalSize: computed(() => sizes[1]),
27 | supportFlexGap: computed(() => supportFlexGap.value)
28 | }
29 | }
30 |
31 | export const [useSpaceProvider, useSpaceInject] =
32 | createInjectionState(spaceState)
33 |
34 | export const useSpaceContextState = () =>
35 | useSpaceInject() ?? {
36 | latestIndex: computed(() => 0),
37 | horizontalSize: computed(() => 0),
38 | verticalSize: computed(() => 0),
39 | supportFlexGap: computed(() => false)
40 | }
41 |
42 | export const spaceProps = {
43 | prefixCls: stringType(),
44 | rootClassName: stringType(),
45 | size: anyType('small'),
46 | direction: anyType<'horizontal' | 'vertical'>('horizontal'),
47 | align: stringType<'start' | 'end' | 'center' | 'baseline'>(),
48 | split: vNodeType(),
49 | wrap: booleanType(false)
50 | }
51 |
52 | const spaceSize = {
53 | small: 8,
54 | middle: 16,
55 | large: 24
56 | }
57 |
58 | function getNumberSize(size: SpaceSize) {
59 | return typeof size === 'string' ? spaceSize[size] : size || 0
60 | }
61 | const Space = defineComponent({
62 | name: 'ASpace',
63 | inheritAttrs: false,
64 | props: spaceProps,
65 | setup(props, { attrs, slots }) {
66 | const { getPrefixCls, direction: directionConfig } =
67 | useProviderConfigState()
68 | const supportFlexGap = useFlexGapSupport()
69 | const prefixCls = computed(() => getPrefixCls('space', props.prefixCls))
70 | const [wrapSSR, hashId] = useStyle(prefixCls)
71 | const sizes = computed<[SpaceSize, SpaceSize]>(() => {
72 | const { size } = props
73 | if (Array.isArray(size)) {
74 | return size.map(getNumberSize) as [SpaceSize, SpaceSize]
75 | }
76 | return [getNumberSize(size), getNumberSize(size)] as [
77 | SpaceSize,
78 | SpaceSize
79 | ]
80 | })
81 | const latestIndex = shallowRef(0)
82 |
83 | useSpaceProvider({ sizes, supportFlexGap, latestIndex })
84 |
85 | return () => {
86 | const { align, direction, rootClassName, split, wrap } = props
87 | const childNodes = filterEmpty(slots.default?.() as any)
88 | const mergedAlign =
89 | align === undefined && direction === 'horizontal' ? 'center' : align
90 | const cn = classNames(
91 | prefixCls.value,
92 | hashId.value,
93 | `${prefixCls.value}-${direction}`,
94 | {
95 | [`${prefixCls.value}-rtl`]: directionConfig.value === 'rtl',
96 | [`${prefixCls.value}-align-${mergedAlign}`]: mergedAlign
97 | },
98 | attrs.class,
99 | rootClassName
100 | )
101 | const itemClassName = `${prefixCls.value}-item`
102 | const marginDirection =
103 | directionConfig.value === 'rtl' ? 'marginLeft' : 'marginRight'
104 | const nodes = childNodes.map((child, i) => {
105 | if (child !== null && child !== undefined) {
106 | latestIndex.value = i
107 | }
108 | const key =
109 | (isObject(child) && (child as any).key) || `${itemClassName}-${i}`
110 | return (
111 | -
120 | {child}
121 |
122 | )
123 | })
124 |
125 | // =========================== Render ===========================
126 | if (childNodes.length === 0) {
127 | return null
128 | }
129 | const gapStyle: CSSProperties = {}
130 | if (wrap) {
131 | gapStyle.flexWrap = 'wrap'
132 | if (!supportFlexGap.value) {
133 | gapStyle.marginBottom = `-${sizes.value[1]}px`
134 | }
135 | }
136 | if (supportFlexGap.value) {
137 | gapStyle.columnGap = `${sizes.value[0]}px`
138 | gapStyle.rowGap = `${sizes.value[1]}px`
139 | }
140 | return wrapSSR(
141 |
142 | {nodes}
143 |
144 | )
145 | }
146 | }
147 | })
148 |
149 | Space.install = function (app: App) {
150 | app.component('ASpace', Space)
151 | }
152 |
153 | Space.Compact = Compact
154 | export default Space as typeof Space &
155 | Plugin & {
156 | readonly Compact: typeof Compact
157 | }
158 |
--------------------------------------------------------------------------------
/components/space/item.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | booleanType,
3 | filterEmpty,
4 | numberType,
5 | someType,
6 | stringType,
7 | vNodeType
8 | } from '@v-c/utils'
9 | import type { CSSProperties, ExtractPropTypes, VNodeChild } from 'vue'
10 | import { defineComponent } from 'vue'
11 | import { useSpaceContextState } from './index'
12 |
13 | export const itemProps = {
14 | className: stringType(),
15 | children: vNodeType(),
16 | index: numberType(),
17 | direction: stringType<'horizontal' | 'vertical'>(),
18 | marginDirection: stringType<'marginLeft' | 'marginRight'>(),
19 | split: someType VNodeChild) | VNodeChild>([
20 | String,
21 | Function,
22 | Object
23 | ]),
24 | wrap: booleanType()
25 | }
26 |
27 | export type ItemProps = ExtractPropTypes
28 |
29 | const Item = defineComponent({
30 | name: 'VcSpaceItem',
31 | props: itemProps,
32 | setup(props, { attrs, slots }) {
33 | const { supportFlexGap, latestIndex, verticalSize, horizontalSize } =
34 | useSpaceContextState()
35 | return () => {
36 | const { direction, index, marginDirection, split, wrap } = props
37 | const children = slots.default?.()
38 | if (!children || filterEmpty(children).length === 0) {
39 | return null
40 | }
41 | let style: CSSProperties = {}
42 | if (!supportFlexGap.value) {
43 | if (direction === 'vertical') {
44 | if (index < latestIndex.value) {
45 | style.marginBottom = `${horizontalSize.value / (split ? 2 : 1)}px`
46 | }
47 | } else {
48 | style = {
49 | ...(index < latestIndex.value &&
50 | ({
51 | [marginDirection]: `${horizontalSize.value / (split ? 2 : 1)}px`
52 | } as CSSProperties)),
53 | ...(wrap && { paddingBottom: `${verticalSize.value}px` })
54 | }
55 | }
56 | }
57 |
58 | return (
59 | <>
60 |
61 | {children}
62 |
63 | {index < latestIndex.value && split && (
64 |
65 | {split}
66 |
67 | )}
68 | >
69 | )
70 | }
71 | }
72 | })
73 |
74 | export default Item
75 |
--------------------------------------------------------------------------------
/components/space/style/compact.tsx:
--------------------------------------------------------------------------------
1 | import type { FullToken, GenerateStyle } from '../../theme/internal'
2 | /** Component only token. Which will handle additional calculation of alias token */
3 | export interface ComponentToken {
4 | // Component token here
5 | }
6 |
7 | interface SpaceToken extends FullToken<'Space'> {
8 | // Custom token here
9 | }
10 |
11 | const genSpaceCompactStyle: GenerateStyle = (token) => {
12 | const { componentCls } = token
13 |
14 | return {
15 | [componentCls]: {
16 | display: 'inline-flex',
17 | '&-block': {
18 | display: 'flex',
19 | width: '100%'
20 | },
21 | '&-vertical': {
22 | flexDirection: 'column'
23 | }
24 | }
25 | }
26 | }
27 |
28 | // ============================== Export ==============================
29 | export default genSpaceCompactStyle
30 |
--------------------------------------------------------------------------------
/components/space/style/index.tsx:
--------------------------------------------------------------------------------
1 | import type { FullToken, GenerateStyle } from '../../theme/internal'
2 | import { genComponentStyleHook } from '../../theme/internal'
3 | import genSpaceCompactStyle from './compact'
4 |
5 | /** Component only token. Which will handle additional calculation of alias token */
6 | export interface ComponentToken {
7 | // Component token here
8 | }
9 |
10 | interface SpaceToken extends FullToken<'Space'> {
11 | // Custom token here
12 | }
13 |
14 | const genSpaceStyle: GenerateStyle = (token) => {
15 | const { componentCls } = token
16 |
17 | return {
18 | [componentCls]: {
19 | display: 'inline-flex',
20 | '&-rtl': {
21 | direction: 'rtl'
22 | },
23 | '&-vertical': {
24 | flexDirection: 'column'
25 | },
26 | '&-align': {
27 | flexDirection: 'column',
28 | '&-center': {
29 | alignItems: 'center'
30 | },
31 | '&-start': {
32 | alignItems: 'flex-start'
33 | },
34 | '&-end': {
35 | alignItems: 'flex-end'
36 | },
37 | '&-baseline': {
38 | alignItems: 'baseline'
39 | }
40 | },
41 | [`${componentCls}-item`]: {
42 | '&:empty': {
43 | display: 'none'
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
50 | // ============================== Export ==============================
51 | export default genComponentStyleHook('Space', (token) => [
52 | genSpaceStyle(token),
53 | genSpaceCompactStyle(token)
54 | ])
55 |
--------------------------------------------------------------------------------
/components/style/compact-item-vertical.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
3 | import type { DerivativeToken, FullToken } from '../theme/internal'
4 | import type { OverrideComponent } from '../theme/util/genComponentStyleHook'
5 |
6 | function compactItemVerticalBorder(token: DerivativeToken, parentCls: string): CSSObject {
7 | return {
8 | // border collapse
9 | [`&-item:not(${parentCls}-last-item)`]: {
10 | marginBottom: -token.lineWidth
11 | },
12 |
13 | '&-item': {
14 | '&:hover,&:focus,&:active': {
15 | zIndex: 2
16 | },
17 |
18 | '&[disabled]': {
19 | zIndex: 0
20 | }
21 | }
22 | }
23 | }
24 |
25 | function compactItemBorderVerticalRadius(prefixCls: string, parentCls: string): CSSObject {
26 | return {
27 | [`&-item:not(${parentCls}-first-item):not(${parentCls}-last-item)`]: {
28 | borderRadius: 0
29 | },
30 |
31 | [`&-item${parentCls}-first-item:not(${parentCls}-last-item)`]: {
32 | [`&, &${prefixCls}-sm, &${prefixCls}-lg`]: {
33 | borderEndEndRadius: 0,
34 | borderEndStartRadius: 0
35 | }
36 | },
37 |
38 | [`&-item${parentCls}-last-item:not(${parentCls}-first-item)`]: {
39 | [`&, &${prefixCls}-sm, &${prefixCls}-lg`]: {
40 | borderStartStartRadius: 0,
41 | borderStartEndRadius: 0
42 | }
43 | }
44 | }
45 | }
46 |
47 | export function genCompactItemVerticalStyle(token: FullToken): CSSInterpolation {
48 | const compactCls = `${token.componentCls}-compact-vertical`
49 |
50 | return {
51 | [compactCls]: {
52 | ...compactItemVerticalBorder(token, compactCls),
53 | ...compactItemBorderVerticalRadius(token.componentCls, compactCls)
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/components/style/compact-item.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
3 | import type { DerivativeToken, FullToken } from '../theme/internal'
4 | import type { OverrideComponent } from '../theme/util/genComponentStyleHook'
5 |
6 | interface CompactItemOptions {
7 | focus?: boolean
8 | /**
9 | * Some component borders are implemented on child elements
10 | * like `Select`
11 | */
12 | borderElCls?: string
13 | /**
14 | * Some components have special `focus` className especially with popovers
15 | * like `Select` and `DatePicker`
16 | */
17 | focusElCls?: string
18 | }
19 |
20 | // handle border collapse
21 | function compactItemBorder(token: DerivativeToken, parentCls: string, options: CompactItemOptions): CSSObject {
22 | const { focusElCls, focus, borderElCls } = options
23 | const childCombinator = borderElCls ? '> *' : ''
24 | const hoverEffects = ['hover', focus ? 'focus' : null, 'active']
25 | .filter(Boolean)
26 | .map(n => `&:${n} ${childCombinator}`)
27 | .join(',')
28 | return {
29 | [`&-item:not(${parentCls}-last-item)`]: {
30 | marginInlineEnd: -token.lineWidth
31 | },
32 |
33 | '&-item': {
34 | [hoverEffects]: {
35 | zIndex: 2
36 | },
37 |
38 | ...(focusElCls
39 | ? {
40 | [`&${focusElCls}`]: {
41 | zIndex: 2
42 | }
43 | }
44 | : {}),
45 |
46 | [`&[disabled] ${childCombinator}`]: {
47 | zIndex: 0
48 | }
49 | }
50 | }
51 | }
52 |
53 | // handle border-radius
54 | function compactItemBorderRadius(prefixCls: string, parentCls: string, options: CompactItemOptions): CSSObject {
55 | const { borderElCls } = options
56 | const childCombinator = borderElCls ? `> ${borderElCls}` : ''
57 |
58 | return {
59 | [`&-item:not(${parentCls}-first-item):not(${parentCls}-last-item) ${childCombinator}`]: {
60 | borderRadius: 0
61 | },
62 |
63 | [`&-item:not(${parentCls}-last-item)${parentCls}-first-item`]: {
64 | [`& ${childCombinator}, &${prefixCls}-sm ${childCombinator}, &${prefixCls}-lg ${childCombinator}`]: {
65 | borderStartEndRadius: 0,
66 | borderEndEndRadius: 0
67 | }
68 | },
69 |
70 | [`&-item:not(${parentCls}-first-item)${parentCls}-last-item`]: {
71 | [`& ${childCombinator}, &${prefixCls}-sm ${childCombinator}, &${prefixCls}-lg ${childCombinator}`]: {
72 | borderStartStartRadius: 0,
73 | borderEndStartRadius: 0
74 | }
75 | }
76 | }
77 | }
78 |
79 | export function genCompactItemStyle(token: FullToken, options: CompactItemOptions = { focus: true }): CSSInterpolation {
80 | const { componentCls } = token
81 |
82 | const compactCls = `${componentCls}-compact`
83 |
84 | return {
85 | [compactCls]: {
86 | ...compactItemBorder(token, compactCls, options),
87 | ...compactItemBorderRadius(componentCls, compactCls, options)
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/components/style/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSObject } from '@antd-tiny-vue/cssinjs'
3 | import type { DerivativeToken } from '../theme/internal'
4 |
5 | export { operationUnit } from './operationUnit'
6 | export { roundedArrow } from './roundedArrow'
7 | export { genPresetColor } from './presetColor'
8 |
9 | export const textEllipsis: CSSObject = {
10 | overflow: 'hidden',
11 | whiteSpace: 'nowrap',
12 | textOverflow: 'ellipsis'
13 | }
14 |
15 | export const resetComponent = (token: DerivativeToken): CSSObject => ({
16 | boxSizing: 'border-box',
17 | margin: 0,
18 | padding: 0,
19 | color: token.colorText,
20 | fontSize: token.fontSize,
21 | // font-variant: @font-variant-base;
22 | lineHeight: token.lineHeight,
23 | listStyle: 'none',
24 | // font-feature-settings: @font-feature-settings-base;
25 | fontFamily: token.fontFamily
26 | })
27 |
28 | export const resetIcon = (): CSSObject => ({
29 | display: 'inline-flex',
30 | alignItems: 'center',
31 | color: 'inherit',
32 | fontStyle: 'normal',
33 | lineHeight: 0,
34 | textAlign: 'center',
35 | textTransform: 'none',
36 | // for SVG icon, see https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
37 | verticalAlign: '-0.125em',
38 | textRendering: 'optimizeLegibility',
39 | '-webkit-font-smoothing': 'antialiased',
40 | '-moz-osx-font-smoothing': 'grayscale',
41 |
42 | '> *': {
43 | lineHeight: 1
44 | },
45 |
46 | svg: {
47 | display: 'inline-block'
48 | }
49 | })
50 |
51 | export const clearFix = (): CSSObject => ({
52 | // https://github.com/ant-design/ant-design/issues/21301#issuecomment-583955229
53 | '&::before': {
54 | display: 'table',
55 | content: '""'
56 | },
57 |
58 | '&::after': {
59 | // https://github.com/ant-design/ant-design/issues/21864
60 | display: 'table',
61 | clear: 'both',
62 | content: '""'
63 | }
64 | })
65 |
66 | export const genLinkStyle = (token: DerivativeToken): CSSObject => ({
67 | a: {
68 | color: token.colorLink,
69 | textDecoration: token.linkDecoration,
70 | backgroundColor: 'transparent', // remove the gray background on active links in IE 10.
71 | outline: 'none',
72 | cursor: 'pointer',
73 | transition: `color ${token.motionDurationSlow}`,
74 | '-webkit-text-decoration-skip': 'objects', // remove gaps in links underline in iOS 8+ and Safari 8+.
75 |
76 | '&:hover': {
77 | color: token.colorLinkHover
78 | },
79 |
80 | '&:active': {
81 | color: token.colorLinkActive
82 | },
83 |
84 | [`&:active,
85 | &:hover`]: {
86 | textDecoration: token.linkHoverDecoration,
87 | outline: 0
88 | },
89 |
90 | // https://github.com/ant-design/ant-design/issues/22503
91 | '&:focus': {
92 | textDecoration: token.linkFocusDecoration,
93 | outline: 0
94 | },
95 |
96 | '&[disabled]': {
97 | color: token.colorTextDisabled,
98 | cursor: 'not-allowed'
99 | }
100 | }
101 | })
102 |
103 | export const genCommonStyle = (token: DerivativeToken, componentPrefixCls: string): CSSObject => {
104 | const { fontFamily, fontSize } = token
105 |
106 | const rootPrefixSelector = `[class^="${componentPrefixCls}"], [class*=" ${componentPrefixCls}"]`
107 |
108 | return {
109 | [rootPrefixSelector]: {
110 | fontFamily,
111 | fontSize,
112 | boxSizing: 'border-box',
113 |
114 | '&::before, &::after': {
115 | boxSizing: 'border-box'
116 | },
117 |
118 | [rootPrefixSelector]: {
119 | boxSizing: 'border-box',
120 |
121 | '&::before, &::after': {
122 | boxSizing: 'border-box'
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
129 | export const genFocusOutline = (token: DerivativeToken): CSSObject => ({
130 | outline: `${token.lineWidth * 4}px solid ${token.colorPrimaryBorder}`,
131 | outlineOffset: 1,
132 | transition: 'outline-offset 0s, outline 0s'
133 | })
134 |
135 | export const genFocusStyle = (token: DerivativeToken): CSSObject => ({
136 | '&:focus-visible': {
137 | ...genFocusOutline(token)
138 | }
139 | })
140 |
--------------------------------------------------------------------------------
/components/style/motion/collapse.ts:
--------------------------------------------------------------------------------
1 | import type { AliasToken, GenerateStyle } from '../../theme/internal'
2 | import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
3 |
4 | const genCollapseMotion: GenerateStyle> = (
5 | token
6 | ) => ({
7 | [token.componentCls]: {
8 | // For common/openAnimation
9 | [`${token.antCls}-motion-collapse-legacy`]: {
10 | overflow: 'hidden',
11 |
12 | '&-active': {
13 | transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
14 | opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`
15 | }
16 | },
17 |
18 | [`${token.antCls}-motion-collapse`]: {
19 | overflow: 'hidden',
20 | transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
21 | opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`
22 | }
23 | }
24 | })
25 |
26 | export default genCollapseMotion
27 |
--------------------------------------------------------------------------------
/components/style/motion/fade.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
2 | import { Keyframes } from '@antd-tiny-vue/cssinjs'
3 | import type { AliasToken } from '../../theme/internal'
4 | import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
5 | import { initMotion } from './motion'
6 |
7 | export const fadeIn = new Keyframes('antFadeIn', {
8 | '0%': {
9 | opacity: 0
10 | },
11 | '100%': {
12 | opacity: 1
13 | }
14 | })
15 |
16 | export const fadeOut = new Keyframes('antFadeOut', {
17 | '0%': {
18 | opacity: 1
19 | },
20 | '100%': {
21 | opacity: 0
22 | }
23 | })
24 |
25 | export const initFadeMotion = (token: TokenWithCommonCls, sameLevel = false): CSSInterpolation => {
26 | const { antCls } = token
27 | const motionCls = `${antCls}-fade`
28 | const sameLevelPrefix = sameLevel ? '&' : ''
29 |
30 | return [
31 | initMotion(motionCls, fadeIn, fadeOut, token.motionDurationMid, sameLevel),
32 | {
33 | [`
34 | ${sameLevelPrefix}${motionCls}-enter,
35 | ${sameLevelPrefix}${motionCls}-appear
36 | `]: {
37 | opacity: 0,
38 | animationTimingFunction: 'linear'
39 | },
40 |
41 | [`${sameLevelPrefix}${motionCls}-leave`]: {
42 | animationTimingFunction: 'linear'
43 | }
44 | }
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/components/style/motion/index.ts:
--------------------------------------------------------------------------------
1 | import { fadeIn, fadeOut, initFadeMotion } from './fade'
2 | import { initMoveMotion, moveDownIn, moveDownOut, moveLeftIn, moveLeftOut, moveRightIn, moveRightOut, moveUpIn, moveUpOut } from './move'
3 |
4 | import { initSlideMotion, slideDownIn, slideDownOut, slideLeftIn, slideLeftOut, slideRightIn, slideRightOut, slideUpIn, slideUpOut } from './slide'
5 | import { initZoomMotion, zoomBigIn, zoomBigOut, zoomDownIn, zoomDownOut, zoomIn, zoomLeftIn, zoomLeftOut, zoomOut, zoomRightIn, zoomRightOut, zoomUpIn, zoomUpOut } from './zoom'
6 | import genCollapseMotion from './collapse'
7 |
8 | export {
9 | initSlideMotion,
10 | slideUpIn,
11 | slideUpOut,
12 | slideDownIn,
13 | slideDownOut,
14 | slideLeftIn,
15 | slideLeftOut,
16 | slideRightIn,
17 | slideRightOut,
18 | zoomOut,
19 | zoomIn,
20 | zoomBigIn,
21 | zoomLeftOut,
22 | zoomBigOut,
23 | zoomLeftIn,
24 | zoomRightIn,
25 | zoomUpIn,
26 | zoomRightOut,
27 | zoomUpOut,
28 | zoomDownIn,
29 | zoomDownOut,
30 | initZoomMotion,
31 | fadeIn,
32 | fadeOut,
33 | initFadeMotion,
34 | moveRightOut,
35 | moveRightIn,
36 | moveLeftOut,
37 | moveLeftIn,
38 | moveDownOut,
39 | moveDownIn,
40 | moveUpIn,
41 | moveUpOut,
42 | initMoveMotion,
43 | genCollapseMotion
44 | }
45 |
--------------------------------------------------------------------------------
/components/style/motion/motion.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSObject, Keyframes } from '@antd-tiny-vue/cssinjs'
3 |
4 | const initMotionCommon = (duration: string): CSSObject => ({
5 | animationDuration: duration,
6 | animationFillMode: 'both'
7 | })
8 |
9 | // FIXME: origin less code seems same as initMotionCommon. Maybe we can safe remove
10 | const initMotionCommonLeave = (duration: string): CSSObject => ({
11 | animationDuration: duration,
12 | animationFillMode: 'both'
13 | })
14 |
15 | export const initMotion = (motionCls: string, inKeyframes: Keyframes, outKeyframes: Keyframes, duration: string, sameLevel = false): CSSObject => {
16 | const sameLevelPrefix = sameLevel ? '&' : ''
17 |
18 | return {
19 | [`
20 | ${sameLevelPrefix}${motionCls}-enter,
21 | ${sameLevelPrefix}${motionCls}-appear
22 | `]: {
23 | ...initMotionCommon(duration),
24 | animationPlayState: 'paused'
25 | },
26 |
27 | [`${sameLevelPrefix}${motionCls}-leave`]: {
28 | ...initMotionCommonLeave(duration),
29 | animationPlayState: 'paused'
30 | },
31 |
32 | [`
33 | ${sameLevelPrefix}${motionCls}-enter${motionCls}-enter-active,
34 | ${sameLevelPrefix}${motionCls}-appear${motionCls}-appear-active
35 | `]: {
36 | animationName: inKeyframes,
37 | animationPlayState: 'running'
38 | },
39 |
40 | [`${sameLevelPrefix}${motionCls}-leave${motionCls}-leave-active`]: {
41 | animationName: outKeyframes,
42 | animationPlayState: 'running',
43 | pointerEvents: 'none'
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/components/style/motion/move.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
2 | import { Keyframes } from '@antd-tiny-vue/cssinjs'
3 | import type { AliasToken } from '../../theme/internal'
4 | import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
5 | import { initMotion } from './motion'
6 |
7 | export const moveDownIn = new Keyframes('antMoveDownIn', {
8 | '0%': {
9 | transform: 'translate3d(0, 100%, 0)',
10 | transformOrigin: '0 0',
11 | opacity: 0
12 | },
13 |
14 | '100%': {
15 | transform: 'translate3d(0, 0, 0)',
16 | transformOrigin: '0 0',
17 | opacity: 1
18 | }
19 | })
20 |
21 | export const moveDownOut = new Keyframes('antMoveDownOut', {
22 | '0%': {
23 | transform: 'translate3d(0, 0, 0)',
24 | transformOrigin: '0 0',
25 | opacity: 1
26 | },
27 |
28 | '100%': {
29 | transform: 'translate3d(0, 100%, 0)',
30 | transformOrigin: '0 0',
31 | opacity: 0
32 | }
33 | })
34 |
35 | export const moveLeftIn = new Keyframes('antMoveLeftIn', {
36 | '0%': {
37 | transform: 'translate3d(-100%, 0, 0)',
38 | transformOrigin: '0 0',
39 | opacity: 0
40 | },
41 |
42 | '100%': {
43 | transform: 'translate3d(0, 0, 0)',
44 | transformOrigin: '0 0',
45 | opacity: 1
46 | }
47 | })
48 |
49 | export const moveLeftOut = new Keyframes('antMoveLeftOut', {
50 | '0%': {
51 | transform: 'translate3d(0, 0, 0)',
52 | transformOrigin: '0 0',
53 | opacity: 1
54 | },
55 |
56 | '100%': {
57 | transform: 'translate3d(-100%, 0, 0)',
58 | transformOrigin: '0 0',
59 | opacity: 0
60 | }
61 | })
62 |
63 | export const moveRightIn = new Keyframes('antMoveRightIn', {
64 | '0%': {
65 | transform: 'translate3d(100%, 0, 0)',
66 | transformOrigin: '0 0',
67 | opacity: 0
68 | },
69 |
70 | '100%': {
71 | transform: 'translate3d(0, 0, 0)',
72 | transformOrigin: '0 0',
73 | opacity: 1
74 | }
75 | })
76 |
77 | export const moveRightOut = new Keyframes('antMoveRightOut', {
78 | '0%': {
79 | transform: 'translate3d(0, 0, 0)',
80 | transformOrigin: '0 0',
81 | opacity: 1
82 | },
83 |
84 | '100%': {
85 | transform: 'translate3d(100%, 0, 0)',
86 | transformOrigin: '0 0',
87 | opacity: 0
88 | }
89 | })
90 |
91 | export const moveUpIn = new Keyframes('antMoveUpIn', {
92 | '0%': {
93 | transform: 'translate3d(0, -100%, 0)',
94 | transformOrigin: '0 0',
95 | opacity: 0
96 | },
97 |
98 | '100%': {
99 | transform: 'translate3d(0, 0, 0)',
100 | transformOrigin: '0 0',
101 | opacity: 1
102 | }
103 | })
104 |
105 | export const moveUpOut = new Keyframes('antMoveUpOut', {
106 | '0%': {
107 | transform: 'translate3d(0, 0, 0)',
108 | transformOrigin: '0 0',
109 | opacity: 1
110 | },
111 |
112 | '100%': {
113 | transform: 'translate3d(0, -100%, 0)',
114 | transformOrigin: '0 0',
115 | opacity: 0
116 | }
117 | })
118 |
119 | type MoveMotionTypes = 'move-up' | 'move-down' | 'move-left' | 'move-right'
120 | const moveMotion: Record = {
121 | 'move-up': {
122 | inKeyframes: moveUpIn,
123 | outKeyframes: moveUpOut
124 | },
125 | 'move-down': {
126 | inKeyframes: moveDownIn,
127 | outKeyframes: moveDownOut
128 | },
129 | 'move-left': {
130 | inKeyframes: moveLeftIn,
131 | outKeyframes: moveLeftOut
132 | },
133 | 'move-right': {
134 | inKeyframes: moveRightIn,
135 | outKeyframes: moveRightOut
136 | }
137 | }
138 |
139 | export const initMoveMotion = (token: TokenWithCommonCls, motionName: MoveMotionTypes): CSSInterpolation => {
140 | const { antCls } = token
141 | const motionCls = `${antCls}-${motionName}`
142 | const { inKeyframes, outKeyframes } = moveMotion[motionName]
143 |
144 | return [
145 | initMotion(motionCls, inKeyframes, outKeyframes, token.motionDurationMid),
146 | {
147 | [`
148 | ${motionCls}-enter,
149 | ${motionCls}-appear
150 | `]: {
151 | opacity: 0,
152 | animationTimingFunction: token.motionEaseOutCirc
153 | },
154 |
155 | [`${motionCls}-leave`]: {
156 | animationTimingFunction: token.motionEaseInOutCirc
157 | }
158 | }
159 | ]
160 | }
161 |
--------------------------------------------------------------------------------
/components/style/motion/slide.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
2 | import { Keyframes } from '@antd-tiny-vue/cssinjs'
3 | import type { AliasToken } from '../../theme/internal'
4 | import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
5 | import { initMotion } from './motion'
6 |
7 | export const slideUpIn = new Keyframes('antSlideUpIn', {
8 | '0%': {
9 | transform: 'scaleY(0.8)',
10 | transformOrigin: '0% 0%',
11 | opacity: 0
12 | },
13 |
14 | '100%': {
15 | transform: 'scaleY(1)',
16 | transformOrigin: '0% 0%',
17 | opacity: 1
18 | }
19 | })
20 |
21 | export const slideUpOut = new Keyframes('antSlideUpOut', {
22 | '0%': {
23 | transform: 'scaleY(1)',
24 | transformOrigin: '0% 0%',
25 | opacity: 1
26 | },
27 |
28 | '100%': {
29 | transform: 'scaleY(0.8)',
30 | transformOrigin: '0% 0%',
31 | opacity: 0
32 | }
33 | })
34 |
35 | export const slideDownIn = new Keyframes('antSlideDownIn', {
36 | '0%': {
37 | transform: 'scaleY(0.8)',
38 | transformOrigin: '100% 100%',
39 | opacity: 0
40 | },
41 |
42 | '100%': {
43 | transform: 'scaleY(1)',
44 | transformOrigin: '100% 100%',
45 | opacity: 1
46 | }
47 | })
48 |
49 | export const slideDownOut = new Keyframes('antSlideDownOut', {
50 | '0%': {
51 | transform: 'scaleY(1)',
52 | transformOrigin: '100% 100%',
53 | opacity: 1
54 | },
55 |
56 | '100%': {
57 | transform: 'scaleY(0.8)',
58 | transformOrigin: '100% 100%',
59 | opacity: 0
60 | }
61 | })
62 |
63 | export const slideLeftIn = new Keyframes('antSlideLeftIn', {
64 | '0%': {
65 | transform: 'scaleX(0.8)',
66 | transformOrigin: '0% 0%',
67 | opacity: 0
68 | },
69 |
70 | '100%': {
71 | transform: 'scaleX(1)',
72 | transformOrigin: '0% 0%',
73 | opacity: 1
74 | }
75 | })
76 |
77 | export const slideLeftOut = new Keyframes('antSlideLeftOut', {
78 | '0%': {
79 | transform: 'scaleX(1)',
80 | transformOrigin: '0% 0%',
81 | opacity: 1
82 | },
83 |
84 | '100%': {
85 | transform: 'scaleX(0.8)',
86 | transformOrigin: '0% 0%',
87 | opacity: 0
88 | }
89 | })
90 |
91 | export const slideRightIn = new Keyframes('antSlideRightIn', {
92 | '0%': {
93 | transform: 'scaleX(0.8)',
94 | transformOrigin: '100% 0%',
95 | opacity: 0
96 | },
97 |
98 | '100%': {
99 | transform: 'scaleX(1)',
100 | transformOrigin: '100% 0%',
101 | opacity: 1
102 | }
103 | })
104 |
105 | export const slideRightOut = new Keyframes('antSlideRightOut', {
106 | '0%': {
107 | transform: 'scaleX(1)',
108 | transformOrigin: '100% 0%',
109 | opacity: 1
110 | },
111 |
112 | '100%': {
113 | transform: 'scaleX(0.8)',
114 | transformOrigin: '100% 0%',
115 | opacity: 0
116 | }
117 | })
118 |
119 | type SlideMotionTypes = 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right'
120 | const slideMotion: Record = {
121 | 'slide-up': {
122 | inKeyframes: slideUpIn,
123 | outKeyframes: slideUpOut
124 | },
125 | 'slide-down': {
126 | inKeyframes: slideDownIn,
127 | outKeyframes: slideDownOut
128 | },
129 | 'slide-left': {
130 | inKeyframes: slideLeftIn,
131 | outKeyframes: slideLeftOut
132 | },
133 | 'slide-right': {
134 | inKeyframes: slideRightIn,
135 | outKeyframes: slideRightOut
136 | }
137 | }
138 |
139 | export const initSlideMotion = (token: TokenWithCommonCls, motionName: SlideMotionTypes): CSSInterpolation => {
140 | const { antCls } = token
141 | const motionCls = `${antCls}-${motionName}`
142 | const { inKeyframes, outKeyframes } = slideMotion[motionName]
143 |
144 | return [
145 | initMotion(motionCls, inKeyframes, outKeyframes, token.motionDurationMid),
146 |
147 | {
148 | [`
149 | ${motionCls}-enter,
150 | ${motionCls}-appear
151 | `]: {
152 | transform: 'scale(0)',
153 | transformOrigin: '0% 0%',
154 | opacity: 0,
155 | animationTimingFunction: token.motionEaseOutQuint
156 | },
157 |
158 | [`${motionCls}-leave`]: {
159 | animationTimingFunction: token.motionEaseInQuint
160 | }
161 | }
162 | ]
163 | }
164 |
--------------------------------------------------------------------------------
/components/style/motion/zoom.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
2 | import { Keyframes } from '@antd-tiny-vue/cssinjs'
3 | import type { AliasToken } from '../../theme/internal'
4 | import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
5 | import { initMotion } from './motion'
6 |
7 | export const zoomIn = new Keyframes('antZoomIn', {
8 | '0%': {
9 | transform: 'scale(0.2)',
10 | opacity: 0
11 | },
12 |
13 | '100%': {
14 | transform: 'scale(1)',
15 | opacity: 1
16 | }
17 | })
18 |
19 | export const zoomOut = new Keyframes('antZoomOut', {
20 | '0%': {
21 | transform: 'scale(1)'
22 | },
23 |
24 | '100%': {
25 | transform: 'scale(0.2)',
26 | opacity: 0
27 | }
28 | })
29 |
30 | export const zoomBigIn = new Keyframes('antZoomBigIn', {
31 | '0%': {
32 | transform: 'scale(0.8)',
33 | opacity: 0
34 | },
35 |
36 | '100%': {
37 | transform: 'scale(1)',
38 | opacity: 1
39 | }
40 | })
41 |
42 | export const zoomBigOut = new Keyframes('antZoomBigOut', {
43 | '0%': {
44 | transform: 'scale(1)'
45 | },
46 |
47 | '100%': {
48 | transform: 'scale(0.8)',
49 | opacity: 0
50 | }
51 | })
52 |
53 | export const zoomUpIn = new Keyframes('antZoomUpIn', {
54 | '0%': {
55 | transform: 'scale(0.8)',
56 | transformOrigin: '50% 0%',
57 | opacity: 0
58 | },
59 |
60 | '100%': {
61 | transform: 'scale(1)',
62 | transformOrigin: '50% 0%'
63 | }
64 | })
65 |
66 | export const zoomUpOut = new Keyframes('antZoomUpOut', {
67 | '0%': {
68 | transform: 'scale(1)',
69 | transformOrigin: '50% 0%'
70 | },
71 |
72 | '100%': {
73 | transform: 'scale(0.8)',
74 | transformOrigin: '50% 0%',
75 | opacity: 0
76 | }
77 | })
78 |
79 | export const zoomLeftIn = new Keyframes('antZoomLeftIn', {
80 | '0%': {
81 | transform: 'scale(0.8)',
82 | transformOrigin: '0% 50%',
83 | opacity: 0
84 | },
85 |
86 | '100%': {
87 | transform: 'scale(1)',
88 | transformOrigin: '0% 50%'
89 | }
90 | })
91 |
92 | export const zoomLeftOut = new Keyframes('antZoomLeftOut', {
93 | '0%': {
94 | transform: 'scale(1)',
95 | transformOrigin: '0% 50%'
96 | },
97 |
98 | '100%': {
99 | transform: 'scale(0.8)',
100 | transformOrigin: '0% 50%',
101 | opacity: 0
102 | }
103 | })
104 |
105 | export const zoomRightIn = new Keyframes('antZoomRightIn', {
106 | '0%': {
107 | transform: 'scale(0.8)',
108 | transformOrigin: '100% 50%',
109 | opacity: 0
110 | },
111 |
112 | '100%': {
113 | transform: 'scale(1)',
114 | transformOrigin: '100% 50%'
115 | }
116 | })
117 |
118 | export const zoomRightOut = new Keyframes('antZoomRightOut', {
119 | '0%': {
120 | transform: 'scale(1)',
121 | transformOrigin: '100% 50%'
122 | },
123 |
124 | '100%': {
125 | transform: 'scale(0.8)',
126 | transformOrigin: '100% 50%',
127 | opacity: 0
128 | }
129 | })
130 |
131 | export const zoomDownIn = new Keyframes('antZoomDownIn', {
132 | '0%': {
133 | transform: 'scale(0.8)',
134 | transformOrigin: '50% 100%',
135 | opacity: 0
136 | },
137 |
138 | '100%': {
139 | transform: 'scale(1)',
140 | transformOrigin: '50% 100%'
141 | }
142 | })
143 |
144 | export const zoomDownOut = new Keyframes('antZoomDownOut', {
145 | '0%': {
146 | transform: 'scale(1)',
147 | transformOrigin: '50% 100%'
148 | },
149 |
150 | '100%': {
151 | transform: 'scale(0.8)',
152 | transformOrigin: '50% 100%',
153 | opacity: 0
154 | }
155 | })
156 |
157 | type ZoomMotionTypes = 'zoom' | 'zoom-big' | 'zoom-big-fast' | 'zoom-left' | 'zoom-right' | 'zoom-up' | 'zoom-down'
158 | const zoomMotion: Record = {
159 | zoom: {
160 | inKeyframes: zoomIn,
161 | outKeyframes: zoomOut
162 | },
163 | 'zoom-big': {
164 | inKeyframes: zoomBigIn,
165 | outKeyframes: zoomBigOut
166 | },
167 | 'zoom-big-fast': {
168 | inKeyframes: zoomBigIn,
169 | outKeyframes: zoomBigOut
170 | },
171 | 'zoom-left': {
172 | inKeyframes: zoomLeftIn,
173 | outKeyframes: zoomLeftOut
174 | },
175 | 'zoom-right': {
176 | inKeyframes: zoomRightIn,
177 | outKeyframes: zoomRightOut
178 | },
179 | 'zoom-up': {
180 | inKeyframes: zoomUpIn,
181 | outKeyframes: zoomUpOut
182 | },
183 | 'zoom-down': {
184 | inKeyframes: zoomDownIn,
185 | outKeyframes: zoomDownOut
186 | }
187 | }
188 |
189 | export const initZoomMotion = (token: TokenWithCommonCls, motionName: ZoomMotionTypes): CSSInterpolation => {
190 | const { antCls } = token
191 | const motionCls = `${antCls}-${motionName}`
192 | const { inKeyframes, outKeyframes } = zoomMotion[motionName]
193 |
194 | return [
195 | initMotion(motionCls, inKeyframes, outKeyframes, motionName === 'zoom-big-fast' ? token.motionDurationFast : token.motionDurationMid),
196 | {
197 | [`
198 | ${motionCls}-enter,
199 | ${motionCls}-appear
200 | `]: {
201 | transform: 'scale(0)',
202 | opacity: 0,
203 | animationTimingFunction: token.motionEaseOutCirc,
204 |
205 | '&-prepare': {
206 | transform: 'none'
207 | }
208 | },
209 |
210 | [`${motionCls}-leave`]: {
211 | animationTimingFunction: token.motionEaseInOutCirc
212 | }
213 | }
214 | ]
215 | }
216 |
--------------------------------------------------------------------------------
/components/style/operationUnit.ts:
--------------------------------------------------------------------------------
1 | import type { CSSObject } from '@antd-tiny-vue/cssinjs'
2 | import type { DerivativeToken } from '../theme/internal'
3 |
4 | // eslint-disable-next-line import/prefer-default-export
5 | export const operationUnit = (token: DerivativeToken): CSSObject => ({
6 | // FIXME: This use link but is a operation unit. Seems should be a colorPrimary.
7 | // And Typography use this to generate link style which should not do this.
8 | color: token.colorLink,
9 | textDecoration: 'none',
10 | outline: 'none',
11 | cursor: 'pointer',
12 | transition: `color ${token.motionDurationSlow}`,
13 |
14 | '&:focus, &:hover': {
15 | color: token.colorLinkHover
16 | },
17 |
18 | '&:active': {
19 | color: token.colorLinkActive
20 | }
21 | })
22 |
--------------------------------------------------------------------------------
/components/style/placementArrow.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
2 | import type { AliasToken } from '../theme/internal'
3 | import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook'
4 | import { roundedArrow } from './roundedArrow'
5 |
6 | export const MAX_VERTICAL_CONTENT_RADIUS = 8
7 |
8 | export function getArrowOffset(options: { contentRadius: number; limitVerticalRadius?: boolean }) {
9 | const maxVerticalContentRadius = MAX_VERTICAL_CONTENT_RADIUS
10 | const { contentRadius, limitVerticalRadius } = options
11 | const dropdownArrowOffset = contentRadius > 12 ? contentRadius + 2 : 12
12 | const dropdownArrowOffsetVertical = limitVerticalRadius ? maxVerticalContentRadius : dropdownArrowOffset
13 | return { dropdownArrowOffset, dropdownArrowOffsetVertical }
14 | }
15 |
16 | function isInject(valid: boolean, code: CSSObject): CSSObject {
17 | if (!valid) return {}
18 | return code
19 | }
20 |
21 | export default function getArrowStyle>(
22 | token: Token,
23 | options: {
24 | colorBg: string
25 | showArrowCls?: string
26 | contentRadius?: number
27 | limitVerticalRadius?: boolean
28 | arrowDistance?: number
29 | arrowPlacement?: {
30 | left?: boolean
31 | right?: boolean
32 | top?: boolean
33 | bottom?: boolean
34 | }
35 | }
36 | ): CSSInterpolation {
37 | const { componentCls, sizePopupArrow, borderRadiusXS, borderRadiusOuter, boxShadowPopoverArrow } = token
38 |
39 | const {
40 | colorBg,
41 | contentRadius = token.borderRadiusLG,
42 | limitVerticalRadius,
43 | arrowDistance = 0,
44 | arrowPlacement = {
45 | left: true,
46 | right: true,
47 | top: true,
48 | bottom: true
49 | }
50 | } = options
51 |
52 | const { dropdownArrowOffsetVertical, dropdownArrowOffset } = getArrowOffset({
53 | contentRadius,
54 | limitVerticalRadius
55 | })
56 |
57 | return {
58 | [componentCls]: {
59 | // ============================ Basic ============================
60 | [`${componentCls}-arrow`]: [
61 | {
62 | position: 'absolute',
63 | zIndex: 1, // lift it up so the menu wouldn't cask shadow on it
64 | display: 'block',
65 |
66 | ...roundedArrow(sizePopupArrow, borderRadiusXS, borderRadiusOuter, colorBg, boxShadowPopoverArrow),
67 |
68 | '&:before': {
69 | background: colorBg
70 | }
71 | }
72 | ],
73 |
74 | // ========================== Placement ==========================
75 | // Here handle the arrow position and rotate stuff
76 | // >>>>> Top
77 | ...isInject(!!arrowPlacement.top, {
78 | [[`&-placement-top ${componentCls}-arrow`, `&-placement-topLeft ${componentCls}-arrow`, `&-placement-topRight ${componentCls}-arrow`].join(',')]: {
79 | bottom: arrowDistance,
80 | transform: 'translateY(100%) rotate(180deg)'
81 | },
82 |
83 | [`&-placement-top ${componentCls}-arrow`]: {
84 | left: {
85 | _skip_check_: true,
86 | value: '50%'
87 | },
88 | transform: 'translateX(-50%) translateY(100%) rotate(180deg)'
89 | },
90 |
91 | [`&-placement-topLeft ${componentCls}-arrow`]: {
92 | left: {
93 | _skip_check_: true,
94 | value: dropdownArrowOffset
95 | }
96 | },
97 |
98 | [`&-placement-topRight ${componentCls}-arrow`]: {
99 | right: {
100 | _skip_check_: true,
101 | value: dropdownArrowOffset
102 | }
103 | }
104 | }),
105 |
106 | // >>>>> Bottom
107 | ...isInject(!!arrowPlacement.bottom, {
108 | [[`&-placement-bottom ${componentCls}-arrow`, `&-placement-bottomLeft ${componentCls}-arrow`, `&-placement-bottomRight ${componentCls}-arrow`].join(',')]: {
109 | top: arrowDistance,
110 | transform: `translateY(-100%)`
111 | },
112 |
113 | [`&-placement-bottom ${componentCls}-arrow`]: {
114 | left: {
115 | _skip_check_: true,
116 | value: '50%'
117 | },
118 | transform: `translateX(-50%) translateY(-100%)`
119 | },
120 |
121 | [`&-placement-bottomLeft ${componentCls}-arrow`]: {
122 | left: {
123 | _skip_check_: true,
124 | value: dropdownArrowOffset
125 | }
126 | },
127 |
128 | [`&-placement-bottomRight ${componentCls}-arrow`]: {
129 | right: {
130 | _skip_check_: true,
131 | value: dropdownArrowOffset
132 | }
133 | }
134 | }),
135 |
136 | // >>>>> Left
137 | ...isInject(!!arrowPlacement.left, {
138 | [[`&-placement-left ${componentCls}-arrow`, `&-placement-leftTop ${componentCls}-arrow`, `&-placement-leftBottom ${componentCls}-arrow`].join(',')]: {
139 | right: {
140 | _skip_check_: true,
141 | value: arrowDistance
142 | },
143 | transform: 'translateX(100%) rotate(90deg)'
144 | },
145 |
146 | [`&-placement-left ${componentCls}-arrow`]: {
147 | top: {
148 | _skip_check_: true,
149 | value: '50%'
150 | },
151 | transform: 'translateY(-50%) translateX(100%) rotate(90deg)'
152 | },
153 |
154 | [`&-placement-leftTop ${componentCls}-arrow`]: {
155 | top: dropdownArrowOffsetVertical
156 | },
157 |
158 | [`&-placement-leftBottom ${componentCls}-arrow`]: {
159 | bottom: dropdownArrowOffsetVertical
160 | }
161 | }),
162 |
163 | // >>>>> Right
164 | ...isInject(!!arrowPlacement.right, {
165 | [[`&-placement-right ${componentCls}-arrow`, `&-placement-rightTop ${componentCls}-arrow`, `&-placement-rightBottom ${componentCls}-arrow`].join(',')]: {
166 | left: {
167 | _skip_check_: true,
168 | value: arrowDistance
169 | },
170 | transform: 'translateX(-100%) rotate(-90deg)'
171 | },
172 |
173 | [`&-placement-right ${componentCls}-arrow`]: {
174 | top: {
175 | _skip_check_: true,
176 | value: '50%'
177 | },
178 | transform: 'translateY(-50%) translateX(-100%) rotate(-90deg)'
179 | },
180 |
181 | [`&-placement-rightTop ${componentCls}-arrow`]: {
182 | top: dropdownArrowOffsetVertical
183 | },
184 |
185 | [`&-placement-rightBottom ${componentCls}-arrow`]: {
186 | bottom: dropdownArrowOffsetVertical
187 | }
188 | })
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/components/style/presetColor.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSObject } from '@antd-tiny-vue/cssinjs'
3 | import type { AliasToken, PresetColorKey } from '../theme/internal'
4 | import { PresetColors } from '../theme/internal'
5 | import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook'
6 |
7 | interface CalcColor {
8 | /** token[`${colorKey}-1`] */
9 | lightColor: string
10 | /** token[`${colorKey}-3`] */
11 | lightBorderColor: string
12 | /** token[`${colorKey}-6`] */
13 | darkColor: string
14 | /** token[`${colorKey}-7`] */
15 | textColor: string
16 | }
17 |
18 | type GenCSS = (colorKey: PresetColorKey, calcColor: CalcColor) => CSSObject
19 |
20 | export function genPresetColor>(token: Token, genCss: GenCSS): CSSObject {
21 | return PresetColors.reduce((prev: CSSObject, colorKey: PresetColorKey) => {
22 | const lightColor = token[`${colorKey}-1`]
23 | const lightBorderColor = token[`${colorKey}-3`]
24 | const darkColor = token[`${colorKey}-6`]
25 | const textColor = token[`${colorKey}-7`]
26 |
27 | return {
28 | ...prev,
29 | ...genCss(colorKey, { lightColor, lightBorderColor, darkColor, textColor })
30 | }
31 | }, {} as CSSObject)
32 | }
33 |
--------------------------------------------------------------------------------
/components/style/reset.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable */
2 | html,
3 | body {
4 | width: 100%;
5 | height: 100%;
6 | }
7 | input::-ms-clear,
8 | input::-ms-reveal {
9 | display: none;
10 | }
11 | *,
12 | *::before,
13 | *::after {
14 | box-sizing: border-box;
15 | }
16 | html {
17 | font-family: sans-serif;
18 | line-height: 1.15;
19 | -webkit-text-size-adjust: 100%;
20 | -ms-text-size-adjust: 100%;
21 | -ms-overflow-style: scrollbar;
22 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
23 | }
24 | @-ms-viewport {
25 | width: device-width;
26 | }
27 | body {
28 | margin: 0;
29 | }
30 | [tabindex='-1']:focus {
31 | outline: none;
32 | }
33 | hr {
34 | box-sizing: content-box;
35 | height: 0;
36 | overflow: visible;
37 | }
38 | h1,
39 | h2,
40 | h3,
41 | h4,
42 | h5,
43 | h6 {
44 | margin-top: 0;
45 | margin-bottom: 0.5em;
46 | font-weight: 500;
47 | }
48 | p {
49 | margin-top: 0;
50 | margin-bottom: 1em;
51 | }
52 | abbr[title],
53 | abbr[data-original-title] {
54 | -webkit-text-decoration: underline dotted;
55 | text-decoration: underline;
56 | text-decoration: underline dotted;
57 | border-bottom: 0;
58 | cursor: help;
59 | }
60 | address {
61 | margin-bottom: 1em;
62 | font-style: normal;
63 | line-height: inherit;
64 | }
65 | input[type='text'],
66 | input[type='password'],
67 | input[type='number'],
68 | textarea {
69 | -webkit-appearance: none;
70 | }
71 | ol,
72 | ul,
73 | dl {
74 | margin-top: 0;
75 | margin-bottom: 1em;
76 | }
77 | ol ol,
78 | ul ul,
79 | ol ul,
80 | ul ol {
81 | margin-bottom: 0;
82 | }
83 | dt {
84 | font-weight: 500;
85 | }
86 | dd {
87 | margin-bottom: 0.5em;
88 | margin-left: 0;
89 | }
90 | blockquote {
91 | margin: 0 0 1em;
92 | }
93 | dfn {
94 | font-style: italic;
95 | }
96 | b,
97 | strong {
98 | font-weight: bolder;
99 | }
100 | small {
101 | font-size: 80%;
102 | }
103 | sub,
104 | sup {
105 | position: relative;
106 | font-size: 75%;
107 | line-height: 0;
108 | vertical-align: baseline;
109 | }
110 | sub {
111 | bottom: -0.25em;
112 | }
113 | sup {
114 | top: -0.5em;
115 | }
116 | pre,
117 | code,
118 | kbd,
119 | samp {
120 | font-size: 1em;
121 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
122 | }
123 | pre {
124 | margin-top: 0;
125 | margin-bottom: 1em;
126 | overflow: auto;
127 | }
128 | figure {
129 | margin: 0 0 1em;
130 | }
131 | img {
132 | vertical-align: middle;
133 | border-style: none;
134 | }
135 | a,
136 | area,
137 | button,
138 | [role='button'],
139 | input:not([type='range']),
140 | label,
141 | select,
142 | summary,
143 | textarea {
144 | touch-action: manipulation;
145 | }
146 | table {
147 | border-collapse: collapse;
148 | }
149 | caption {
150 | padding-top: 0.75em;
151 | padding-bottom: 0.3em;
152 | text-align: left;
153 | caption-side: bottom;
154 | }
155 | input,
156 | button,
157 | select,
158 | optgroup,
159 | textarea {
160 | margin: 0;
161 | color: inherit;
162 | font-size: inherit;
163 | font-family: inherit;
164 | line-height: inherit;
165 | }
166 | button,
167 | input {
168 | overflow: visible;
169 | }
170 | button,
171 | select {
172 | text-transform: none;
173 | }
174 | button,
175 | html [type='button'],
176 | [type='reset'],
177 | [type='submit'] {
178 | -webkit-appearance: button;
179 | }
180 | button::-moz-focus-inner,
181 | [type='button']::-moz-focus-inner,
182 | [type='reset']::-moz-focus-inner,
183 | [type='submit']::-moz-focus-inner {
184 | padding: 0;
185 | border-style: none;
186 | }
187 | input[type='radio'],
188 | input[type='checkbox'] {
189 | box-sizing: border-box;
190 | padding: 0;
191 | }
192 | input[type='date'],
193 | input[type='time'],
194 | input[type='datetime-local'],
195 | input[type='month'] {
196 | -webkit-appearance: listbox;
197 | }
198 | textarea {
199 | overflow: auto;
200 | resize: vertical;
201 | }
202 | fieldset {
203 | min-width: 0;
204 | margin: 0;
205 | padding: 0;
206 | border: 0;
207 | }
208 | legend {
209 | display: block;
210 | width: 100%;
211 | max-width: 100%;
212 | margin-bottom: 0.5em;
213 | padding: 0;
214 | color: inherit;
215 | font-size: 1.5em;
216 | line-height: inherit;
217 | white-space: normal;
218 | }
219 | progress {
220 | vertical-align: baseline;
221 | }
222 | [type='number']::-webkit-inner-spin-button,
223 | [type='number']::-webkit-outer-spin-button {
224 | height: auto;
225 | }
226 | [type='search'] {
227 | outline-offset: -2px;
228 | -webkit-appearance: none;
229 | }
230 | [type='search']::-webkit-search-cancel-button,
231 | [type='search']::-webkit-search-decoration {
232 | -webkit-appearance: none;
233 | }
234 | ::-webkit-file-upload-button {
235 | font: inherit;
236 | -webkit-appearance: button;
237 | }
238 | output {
239 | display: inline-block;
240 | }
241 | summary {
242 | display: list-item;
243 | }
244 | template {
245 | display: none;
246 | }
247 | [hidden] {
248 | display: none !important;
249 | }
250 | mark {
251 | padding: 0.2em;
252 | background-color: #feffe6;
253 | }
254 |
--------------------------------------------------------------------------------
/components/style/roundedArrow.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import type { CSSObject } from '@antd-tiny-vue/cssinjs'
3 |
4 | export const roundedArrow = (width: number, innerRadius: number, outerRadius: number, bgColor: string, boxShadow: string): CSSObject => {
5 | const unitWidth = width / 2
6 |
7 | const ax = 0
8 | const ay = unitWidth
9 | const bx = (outerRadius * 1) / Math.sqrt(2)
10 | const by = unitWidth - outerRadius * (1 - 1 / Math.sqrt(2))
11 | const cx = unitWidth - innerRadius * (1 / Math.sqrt(2))
12 | const cy = outerRadius * (Math.sqrt(2) - 1) + innerRadius * (1 / Math.sqrt(2))
13 | const dx = 2 * unitWidth - cx
14 | const dy = cy
15 | const ex = 2 * unitWidth - bx
16 | const ey = by
17 | const fx = 2 * unitWidth - ax
18 | const fy = ay
19 |
20 | const shadowWidth = unitWidth * Math.sqrt(2) + outerRadius * (Math.sqrt(2) - 2)
21 |
22 | return {
23 | pointerEvents: 'none',
24 | width,
25 | height: width,
26 | overflow: 'hidden',
27 |
28 | '&::before': {
29 | position: 'absolute',
30 | bottom: 0,
31 | insetInlineStart: 0,
32 | width,
33 | height: width / 2,
34 | background: bgColor,
35 | clipPath: `path('M ${ax} ${ay} A ${outerRadius} ${outerRadius} 0 0 0 ${bx} ${by} L ${cx} ${cy} A ${innerRadius} ${innerRadius} 0 0 1 ${dx} ${dy} L ${ex} ${ey} A ${outerRadius} ${outerRadius} 0 0 0 ${fx} ${fy} Z')`,
36 | content: '""'
37 | },
38 |
39 | '&::after': {
40 | content: '""',
41 | position: 'absolute',
42 | width: shadowWidth,
43 | height: shadowWidth,
44 | bottom: 0,
45 | insetInline: 0,
46 | margin: 'auto',
47 | borderRadius: {
48 | _skip_check_: true,
49 | value: `0 0 ${innerRadius}px 0`
50 | },
51 | transform: 'translateY(50%) rotate(-135deg)',
52 | boxShadow,
53 | zIndex: 0,
54 | background: 'transparent'
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/components/theme/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import { defaultConfig, useToken as useInternalToken } from './internal'
3 | import type { GlobalToken } from './interface'
4 | import defaultAlgorithm from './themes/default'
5 | import darkAlgorithm from './themes/dark'
6 | import compactAlgorithm from './themes/compact'
7 |
8 | // ZombieJ: We export as object to user but array in internal.
9 | // This is used to minimize the bundle size for antd package but safe to refactor as object also.
10 | // Please do not export internal `useToken` directly to avoid something export unexpected.
11 | /** Get current context Design Token. Will be different if you are using nest theme config. */
12 | function useToken() {
13 | const [theme, token, hashId] = useInternalToken()
14 |
15 | return { theme, token, hashId }
16 | }
17 |
18 | export { type GlobalToken }
19 |
20 | export default {
21 | /** @private Test Usage. Do not use in production. */
22 | defaultConfig,
23 |
24 | /** Default seedToken */
25 | defaultSeed: defaultConfig.token,
26 |
27 | useToken,
28 | defaultAlgorithm,
29 | darkAlgorithm,
30 | compactAlgorithm
31 | }
32 |
--------------------------------------------------------------------------------
/components/theme/interface/alias.ts:
--------------------------------------------------------------------------------
1 | import type { CSSProperties } from 'vue'
2 | import type { MapToken } from './maps'
3 |
4 | // ======================================================================
5 | // == Alias Token ==
6 | // ======================================================================
7 | // 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
8 |
9 | export interface AliasToken extends MapToken {
10 | // Background
11 | colorFillContentHover: string
12 | colorFillAlter: string
13 | colorFillContent: string
14 |
15 | colorBgContainerDisabled: string
16 | colorBgTextHover: string
17 | colorBgTextActive: string
18 |
19 | // Border
20 | colorBorderBg: string
21 | /**
22 | * @nameZH 分割线颜色
23 | * @desc 用于作为分割线的颜色,此颜色和 colorBorderSecondary 的颜色一致,但是用的是透明色。
24 | */
25 | colorSplit: string
26 |
27 | // Text
28 | colorTextPlaceholder: string
29 | colorTextDisabled: string
30 | colorTextHeading: string
31 | colorTextLabel: string
32 | colorTextDescription: string
33 | colorTextLightSolid: string
34 |
35 | /** Weak action. Such as `allowClear` or Alert close button */
36 | colorIcon: string
37 | /** Weak action hover color. Such as `allowClear` or Alert close button */
38 | colorIconHover: string
39 |
40 | colorLink: string
41 | colorLinkHover: string
42 | colorLinkActive: string
43 |
44 | colorHighlight: string
45 |
46 | controlOutline: string
47 | colorWarningOutline: string
48 | colorErrorOutline: string
49 |
50 | // Font
51 | /** Operation icon in Select, Cascader, etc. icon fontSize. Normal is same as fontSizeSM */
52 | fontSizeIcon: number
53 |
54 | /** For heading like h1, h2, h3 or option selected item */
55 | fontWeightStrong: number
56 |
57 | // Control
58 | controlOutlineWidth: number
59 | controlItemBgHover: string // Note. It also is a color
60 | controlItemBgActive: string // Note. It also is a color
61 | controlItemBgActiveHover: string // Note. It also is a color
62 | controlInteractiveSize: number
63 | controlItemBgActiveDisabled: string // Note. It also is a color
64 |
65 | // Padding
66 | paddingXXS: number
67 | paddingXS: number
68 | paddingSM: number
69 | padding: number
70 | paddingMD: number
71 | paddingLG: number
72 | paddingXL: number
73 |
74 | // Padding Content
75 | paddingContentHorizontalLG: number
76 | paddingContentHorizontal: number
77 | paddingContentHorizontalSM: number
78 | paddingContentVerticalLG: number
79 | paddingContentVertical: number
80 | paddingContentVerticalSM: number
81 |
82 | // Margin
83 | marginXXS: number
84 | marginXS: number
85 | marginSM: number
86 | margin: number
87 | marginMD: number
88 | marginLG: number
89 | marginXL: number
90 | marginXXL: number
91 |
92 | // =============== Legacy: should be remove ===============
93 | opacityLoading: number
94 |
95 | boxShadow: string
96 | boxShadowSecondary: string
97 | boxShadowTertiary: string
98 |
99 | linkDecoration: CSSProperties['textDecoration']
100 | linkHoverDecoration: CSSProperties['textDecoration']
101 | linkFocusDecoration: CSSProperties['textDecoration']
102 |
103 | controlPaddingHorizontal: number
104 | controlPaddingHorizontalSM: number
105 |
106 | // Media queries breakpoints
107 | screenXS: number
108 | screenXSMin: number
109 | screenXSMax: number
110 | screenSM: number
111 | screenSMMin: number
112 | screenSMMax: number
113 | screenMD: number
114 | screenMDMin: number
115 | screenMDMax: number
116 | screenLG: number
117 | screenLGMin: number
118 | screenLGMax: number
119 | screenXL: number
120 | screenXLMin: number
121 | screenXLMax: number
122 | screenXXL: number
123 | screenXXLMin: number
124 |
125 | /** Used for DefaultButton, Switch which has default outline */
126 | controlTmpOutline: string
127 |
128 | // FIXME: component box-shadow, should be removed
129 | /** @internal */
130 | boxShadowPopoverArrow: string
131 | /** @internal */
132 | boxShadowCard: string
133 | /** @internal */
134 | boxShadowDrawerRight: string
135 | /** @internal */
136 | boxShadowDrawerLeft: string
137 | /** @internal */
138 | boxShadowDrawerUp: string
139 | /** @internal */
140 | boxShadowDrawerDown: string
141 | /** @internal */
142 | boxShadowTabsOverflowLeft: string
143 | /** @internal */
144 | boxShadowTabsOverflowRight: string
145 | /** @internal */
146 | boxShadowTabsOverflowTop: string
147 | /** @internal */
148 | boxShadowTabsOverflowBottom: string
149 | }
150 |
--------------------------------------------------------------------------------
/components/theme/interface/components.ts:
--------------------------------------------------------------------------------
1 | // import type { ComponentToken as AlertComponentToken } from '../../alert/style'
2 | // import type { ComponentToken as AnchorComponentToken } from '../../anchor/style'
3 | // import type { ComponentToken as AvatarComponentToken } from '../../avatar/style'
4 | // import type { ComponentToken as BackTopComponentToken } from '../../back-top/style'
5 | import type { ComponentToken as ButtonComponentToken } from '../../button/style'
6 | // import type { ComponentToken as FloatButtonComponentToken } from '../../floats-button/style'
7 | // import type { ComponentToken as CalendarComponentToken } from '../../calendar/style'
8 | // import type { ComponentToken as CardComponentToken } from '../../card/style'
9 | // import type { ComponentToken as CarouselComponentToken } from '../../carousel/style'
10 | // import type { ComponentToken as CascaderComponentToken } from '../../cascader/style'
11 | // import type { ComponentToken as CheckboxComponentToken } from '../../checkbox/style'
12 | // import type { ComponentToken as CollapseComponentToken } from '../../collapse/style'
13 | // import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style'
14 | // import type { ComponentToken as DividerComponentToken } from '../../divider/style'
15 | // import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style'
16 | // import type { ComponentToken as DrawerComponentToken } from '../../drawer/style'
17 | // import type { ComponentToken as EmptyComponentToken } from '../../empty/style'
18 | // import type { ComponentToken as ImageComponentToken } from '../../image/style'
19 | // import type { ComponentToken as InputNumberComponentToken } from '../../input-number/style'
20 | // import type { ComponentToken as LayoutComponentToken } from '../../layout/style'
21 | // import type { ComponentToken as ListComponentToken } from '../../list/style'
22 | // import type { ComponentToken as MentionsComponentToken } from '../../mentions/style'
23 | // import type { ComponentToken as MenuComponentToken } from '../../menu/style'
24 | // import type { ComponentToken as MessageComponentToken } from '../../message/style'
25 | // import type { ComponentToken as ModalComponentToken } from '../../modal/style'
26 | // import type { ComponentToken as NotificationComponentToken } from '../../notification/style'
27 | // import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style'
28 | // import type { ComponentToken as PopoverComponentToken } from '../../popover/style'
29 | // import type { ComponentToken as ProgressComponentToken } from '../../progress/style'
30 | // import type { ComponentToken as RadioComponentToken } from '../../radio/style'
31 | // import type { ComponentToken as RateComponentToken } from '../../rate/style'
32 | // import type { ComponentToken as ResultComponentToken } from '../../result/style'
33 | // import type { ComponentToken as SegmentedComponentToken } from '../../segmented/style'
34 | // import type { ComponentToken as SelectComponentToken } from '../../select/style'
35 | // import type { ComponentToken as SkeletonComponentToken } from '../../skeleton/style'
36 | // import type { ComponentToken as SliderComponentToken } from '../../slider/style'
37 | import type { ComponentToken as SpaceComponentToken } from '../../space/style'
38 | // import type { ComponentToken as SpinComponentToken } from '../../spin/style'
39 | // import type { ComponentToken as StepsComponentToken } from '../../steps/style'
40 | // import type { ComponentToken as TableComponentToken } from '../../table/style'
41 | // import type { ComponentToken as TabsComponentToken } from '../../tabs/style'
42 | // import type { ComponentToken as TagComponentToken } from '../../tag/style'
43 | // import type { ComponentToken as TimelineComponentToken } from '../../timeline/style'
44 | // import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style'
45 | // import type { ComponentToken as TransferComponentToken } from '../../transfer/style'
46 | // import type { ComponentToken as TypographyComponentToken } from '../../typography/style'
47 | // import type { ComponentToken as UploadComponentToken } from '../../upload/style'
48 | // import type { ComponentToken as TourComponentToken } from '../../tour/style'
49 | // import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style'
50 | // import type { ComponentToken as AppComponentToken } from '../../app/style'
51 | import type { ComponentToken as WaveToken } from '../../_util/wave/style'
52 |
53 | export interface ComponentTokenMap {
54 | Affix?: {}
55 | // Alert?: AlertComponentToken
56 | // Anchor?: AnchorComponentToken
57 | // Avatar?: AvatarComponentToken
58 | // BackTop?: BackTopComponentToken
59 | // Badge?: {}
60 | Button?: ButtonComponentToken
61 | // Breadcrumb?: {}
62 | // Card?: CardComponentToken
63 | // Carousel?: CarouselComponentToken
64 | // Cascader?: CascaderComponentToken
65 | // Checkbox?: CheckboxComponentToken
66 | // Collapse?: CollapseComponentToken
67 | // DatePicker?: DatePickerComponentToken
68 | // Descriptions?: {}
69 | // Divider?: DividerComponentToken
70 | // Drawer?: DrawerComponentToken
71 | // Dropdown?: DropdownComponentToken
72 | // Empty?: EmptyComponentToken
73 | // FloatButton?: FloatButtonComponentToken
74 | // Form?: {}
75 | // Grid?: {}
76 | // Image?: ImageComponentToken
77 | // Input?: {}
78 | // InputNumber?: InputNumberComponentToken
79 | // Layout?: LayoutComponentToken
80 | // List?: ListComponentToken
81 | // Mentions?: MentionsComponentToken
82 | // Notification?: NotificationComponentToken
83 | // Pagination?: {}
84 | // Popover?: PopoverComponentToken
85 | // Popconfirm?: PopconfirmComponentToken
86 | // Rate?: RateComponentToken
87 | // Radio?: RadioComponentToken
88 | // Result?: ResultComponentToken
89 | // Segmented?: SegmentedComponentToken
90 | // Select?: SelectComponentToken
91 | // Skeleton?: SkeletonComponentToken
92 | // Slider?: SliderComponentToken
93 | // Spin?: SpinComponentToken
94 | // Statistic?: {}
95 | // Switch?: {}
96 | // Tag?: TagComponentToken
97 | // Tree?: {}
98 | // TreeSelect?: {}
99 | // Typography?: TypographyComponentToken
100 | // Timeline?: TimelineComponentToken
101 | // Transfer?: TransferComponentToken
102 | // Tabs?: TabsComponentToken
103 | // Calendar?: CalendarComponentToken
104 | // Steps?: StepsComponentToken
105 | // Menu?: MenuComponentToken
106 | // Modal?: ModalComponentToken
107 | // Message?: MessageComponentToken
108 | // Upload?: UploadComponentToken
109 | // Tooltip?: TooltipComponentToken
110 | // Table?: TableComponentToken
111 | Space?: SpaceComponentToken
112 | // Progress?: ProgressComponentToken
113 | // Tour?: TourComponentToken
114 | // QRCode?: QRCodeComponentToken
115 | // App?: AppComponentToken
116 | //
117 | // /** @private Internal TS definition. Do not use. */
118 | Wave?: WaveToken
119 | }
120 |
--------------------------------------------------------------------------------
/components/theme/interface/index.ts:
--------------------------------------------------------------------------------
1 | import type { ComponentTokenMap } from './components'
2 | import type { AliasToken } from './alias'
3 |
4 | export type OverrideToken = {
5 | [key in keyof ComponentTokenMap]: Partial & Partial
6 | }
7 |
8 | /** Final token which contains the components level override */
9 | export type GlobalToken = AliasToken & ComponentTokenMap
10 |
11 | export { PresetColors } from './presetColors'
12 | export type { PresetColorType, ColorPalettes, PresetColorKey } from './presetColors'
13 | export type { SeedToken } from './seeds'
14 | export type { MapToken, ColorMapToken, ColorNeutralMapToken, CommonMapToken, HeightMapToken, SizeMapToken, FontMapToken, StyleMapToken } from './maps'
15 | export type { AliasToken } from './alias'
16 | export type { ComponentTokenMap } from './components'
17 |
--------------------------------------------------------------------------------
/components/theme/interface/maps/colors.ts:
--------------------------------------------------------------------------------
1 | export interface ColorNeutralMapToken {
2 | /**
3 | * @internal
4 | */
5 | colorTextBase: string
6 |
7 | /**
8 | * @internal
9 | */
10 | colorBgBase: string
11 |
12 | // ---------- Text ---------- //
13 |
14 | /**
15 | * @nameZH 一级文本色
16 | * @desc 最深的文本色。为了符合W3C标准,默认的文本颜色使用了该色,同时这个颜色也是最深的中性色。
17 | */
18 | colorText: string
19 |
20 | /**
21 | * @nameZH 二级文本色
22 | * @desc 作为第二梯度的文本色,一般用在不那么需要强化文本颜色的场景,例如 Label 文本、Menu 的文本选中态等场景。
23 | */
24 | colorTextSecondary: string
25 |
26 | /**
27 | * @nameZH 三级文本色
28 | * @desc 第三级文本色一般用于描述性文本,例如表单的中的补充说明文本、列表的描述性文本等场景。
29 | */
30 | colorTextTertiary: string
31 |
32 | /**
33 | * @nameZH 四级文本色
34 | * @desc 第四级文本色是最浅的文本色,例如表单的输入提示文本、禁用色文本等。
35 | */
36 | colorTextQuaternary: string
37 |
38 | // ---------- Border ---------- //
39 |
40 | /**
41 | * @nameZH 一级边框色
42 | * @nameEN Default Border Color
43 | * @desc 默认使用的边框颜色, 用于分割不同的元素,例如:表单的分割线、卡片的分割线等。
44 | * @descEN Default border color, used to separate different elements, such as: form separator, card separator, etc.
45 | */
46 | colorBorder: string
47 |
48 | /**
49 | * @nameZH 二级边框色
50 | * @nameEN Secondary Border Color
51 | * @desc 比默认使用的边框色要浅一级,此颜色和 colorSplit 的颜色一致。使用的是实色。
52 | * @descEN Slightly lighter than the default border color, this color is the same as `colorSplit`. Solid color is used.
53 | */
54 | colorBorderSecondary: string
55 |
56 | // ---------- Fill ---------- //
57 |
58 | /**
59 | * @nameZH 一级填充色
60 | * @desc 最深的填充色,用于拉开与二、三级填充色的区分度,目前只用在 Slider 的 hover 效果。
61 | */
62 | colorFill: string
63 |
64 | /**
65 | * @nameZH 二级填充色
66 | * @desc 二级填充色可以较为明显地勾勒出元素形体,如 Rate、Skeleton 等。也可以作为三级填充色的 Hover 状态,如 Table 等。
67 | */
68 | colorFillSecondary: string
69 |
70 | /**
71 | * @nameZH 三级填充色
72 | * @desc 三级填充色用于勾勒出元素形体的场景,如 Slider、Segmented 等。如无强调需求的情况下,建议使用三级填色作为默认填色。
73 | */
74 | colorFillTertiary: string
75 |
76 | /**
77 | * @nameZH 四级填充色
78 | * @desc 最弱一级的填充色,适用于不易引起注意的色块,例如斑马纹、区分边界的色块等。
79 | */
80 | colorFillQuaternary: string
81 |
82 | // ---------- Surface ---------- //
83 |
84 | /**
85 | * @nameZH 布局背景色
86 | * @desc 该色用于页面整体布局的背景色,只有需要在页面中处于 B1 的视觉层级时才会使用该 token,其他用法都是错误的
87 | */
88 | colorBgLayout: string
89 |
90 | /**
91 | * @nameZH 组件容器背景色
92 | * @desc 组件的容器背景色,例如:默认按钮、输入框等。务必不要将其与 `colorBgElevated` 混淆。
93 | */
94 | colorBgContainer: string
95 |
96 | /**
97 | * @nameZH 浮层容器背景色
98 | * @desc 浮层容器背景色,在暗色模式下该 token 的色值会比 `colorBgContainer` 要亮一些。例如:模态框、弹出框、菜单等。
99 | */
100 | colorBgElevated: string
101 |
102 | /**
103 | * @nameZH 引起注意的背景色
104 | * @desc 该色用于引起用户强烈关注注意的背景色,目前只用在 Tooltip 的背景色上。
105 | */
106 | colorBgSpotlight: string
107 | }
108 |
109 | /**
110 | * 品牌色梯度变量
111 | */
112 | interface ColorPrimaryMapToken {
113 | /**
114 | * @nameZH 品牌主色
115 | * @desc 品牌色是体现产品特性和传播理念最直观的视觉元素之一,用于产品的主色调、主按钮、主图标、主文本等 */
116 | colorPrimary: string // 6
117 |
118 | /**
119 | * @nameZH 主色浅色背景色
120 | * @nameEN Light Background Color of Primary Color
121 | * @desc 主色浅色背景颜色,一般用于视觉层级较弱的选中状态。
122 | * @descEN Light background color of primary color, usually used for weak visual level selection state.
123 | */
124 | colorPrimaryBg: string // 1
125 |
126 | /**
127 | * @nameZH 主色浅色背景悬浮态
128 | * @desc 与主色浅色背景颜色相对应的悬浮态颜色。
129 | */
130 | colorPrimaryBgHover: string // 2
131 |
132 | /**
133 | * @nameZH 主色描边色
134 | * @desc 主色梯度下的描边用色,用在 Slider 组件的描边上
135 | */
136 | colorPrimaryBorder: string // 3
137 |
138 | /**
139 | * @nameZH 主色描边色悬浮态
140 | * @desc 主色梯度下的描边用色的悬浮态,Slider 、Button 等组件的描边 Hover 时会使用
141 | */
142 | colorPrimaryBorderHover: string // 4
143 |
144 | /**
145 | * @nameZH 主色悬浮态
146 | * @desc 主色梯度下的悬浮态,使用频率很高
147 | */
148 | colorPrimaryHover: string // 5
149 |
150 | /**
151 | * @nameZH 主色激活态
152 | * @desc 主色梯度下的深色激活态
153 | */
154 | colorPrimaryActive: string // 7
155 |
156 | /**
157 | * @nameZH 主色文本悬浮态
158 | * @desc 主色梯度下的文本悬浮态
159 | */
160 | colorPrimaryTextHover: string // 8
161 |
162 | /**
163 | * @nameZH 主色文本
164 | * @desc 主色梯度下的文本颜色
165 | */
166 | colorPrimaryText: string // 9
167 |
168 | /**
169 | * @nameZH 主色文本
170 | * @desc 主色梯度下的文本激活态
171 | */
172 | colorPrimaryTextActive: string // 10
173 | }
174 |
175 | interface ColorSuccessMapToken {
176 | /**
177 | * @nameZH 成功色的浅色背景颜色
178 | * @nameEN Light Background Color of Success Color
179 | * @desc 成功色的浅色背景颜色,用于 Tag 和 Alert 的成功态背景色
180 | * @descEN Light background color of success color, used for Tag and Alert success state background color
181 | */
182 | colorSuccessBg: string // 1
183 |
184 | /**
185 | * @nameZH 成功色的浅色背景色悬浮态
186 | * @nameEN Hover State Color of Light Success Background
187 | * @desc 成功色浅色背景颜色,一般用于视觉层级较弱的选中状态,不过 antd 目前没有使用到该 token
188 | * @descEN Light background color of success color, but antd does not use this token currently
189 | */
190 | colorSuccessBgHover: string // 2
191 |
192 | /**
193 | * @nameZH 成功色的描边色
194 | * @desc 成功色的描边色,用于 Tag 和 Alert 的成功态描边色
195 | */
196 | colorSuccessBorder: string // 3
197 |
198 | /**
199 | * @nameZH 成功色的描边色悬浮态
200 | * @desc 成功色的描边色悬浮态
201 | */
202 | colorSuccessBorderHover: string // 4
203 |
204 | /**
205 | * @nameZH 成功色的深色悬浮态
206 | * @desc 成功色的深色悬浮态
207 | */
208 | colorSuccessHover: string // 5
209 |
210 | /**
211 | * @nameZH 成功色
212 | * @desc 默认的成功色,如 Result、Progress 等组件中都有使用该颜色
213 | */
214 | colorSuccess: string // 6
215 |
216 | /**
217 | * @nameZH 成功色的深色激活态
218 | * @desc 成功色的深色激活态
219 | */
220 | colorSuccessActive: string // 7
221 |
222 | /**
223 | * @nameZH 成功色的文本悬浮态
224 | * @desc 成功色的文本悬浮态
225 | */
226 | colorSuccessTextHover: string // 8
227 |
228 | /**
229 | * @nameZH 成功色的文本默认态
230 | * @desc 成功色的文本默认态
231 | */
232 | colorSuccessText: string // 9
233 |
234 | /**
235 | * @nameZH 成功色的文本激活态
236 | * @desc 成功色的文本激活态
237 | */
238 | colorSuccessTextActive: string // 10
239 | }
240 |
241 | interface ColorWarningMapToken {
242 | /**
243 | * @nameZH 警戒色的浅色背景颜色
244 | */
245 | colorWarningBg: string // 1
246 |
247 | /**
248 | * @nameZH 警戒色的浅色背景色悬浮态
249 | * @desc 警戒色的浅色背景色悬浮态
250 | */
251 | colorWarningBgHover: string // 2
252 |
253 | /**
254 | * @nameZH 警戒色的描边色
255 | * @desc 警戒色的描边色
256 | */
257 | colorWarningBorder: string // 3
258 |
259 | /**
260 | * @nameZH 警戒色的描边色悬浮态
261 | * @desc 警戒色的描边色悬浮态
262 | */
263 | colorWarningBorderHover: string // 4
264 |
265 | /**
266 | * @nameZH 警戒色的深色悬浮态
267 | * @desc 警戒色的深色悬浮态
268 | */
269 | colorWarningHover: string // 5
270 |
271 | /**
272 | * @nameZH 警戒色
273 | * @desc 最常用的警戒色,例如 Notification、 Alert等警告类组件或 Input 输入类等组件会使用该颜色
274 | */
275 | colorWarning: string // 6
276 |
277 | /**
278 | * @nameZH 警戒色的深色激活态
279 | * @desc 警戒色的深色激活态
280 | */
281 | colorWarningActive: string // 7
282 |
283 | /**
284 | * @nameZH 警戒色的文本悬浮态
285 | * @desc 警戒色的文本悬浮态
286 | */
287 | colorWarningTextHover: string // 8
288 |
289 | /**
290 | * @nameZH 警戒色的文本默认态
291 | * @desc 警戒色的文本默认态
292 | */
293 | colorWarningText: string // 9
294 |
295 | /**
296 | * @nameZH 警戒色的文本激活态
297 | * @desc 警戒色的文本激活态
298 | */
299 | colorWarningTextActive: string // 10
300 | }
301 |
302 | interface ColorInfoMapToken {
303 | /**
304 | * @nameZH 信息色的浅色背景颜色
305 | * @desc 信息色的浅色背景颜色
306 | */
307 | colorInfoBg: string // 1
308 |
309 | /**
310 | * @nameZH 信息色的浅色背景色悬浮态
311 | * @desc 信息色的浅色背景色悬浮态
312 | */
313 | colorInfoBgHover: string // 2
314 |
315 | /**
316 | * @nameZH 信息色的描边色
317 | */
318 | colorInfoBorder: string // 3
319 |
320 | /**
321 | * @nameZH 信息色的描边色悬浮态
322 | */
323 | colorInfoBorderHover: string // 4
324 |
325 | /**
326 | * @nameZH 信息色的深色悬浮态
327 | */
328 | colorInfoHover: string // 5
329 |
330 | /**
331 | * @nameZH 信息色
332 | */
333 | colorInfo: string // 6
334 |
335 | /**
336 | * @nameZH 信息色的深色激活态
337 | */
338 | colorInfoActive: string // 7
339 |
340 | /**
341 | * @nameZH 信息色的文本悬浮态
342 | */
343 | colorInfoTextHover: string // 8
344 |
345 | /**
346 | * @nameZH 信息色的文本默认态
347 | */
348 | colorInfoText: string // 9
349 |
350 | /**
351 | * @nameZH 信息色的文本激活态
352 | */
353 | colorInfoTextActive: string // 10
354 | }
355 |
356 | interface ColorErrorMapToken {
357 | /**
358 | * @nameZH 错误色的浅色背景颜色
359 | */
360 | colorErrorBg: string // 1
361 |
362 | /**
363 | * @nameZH 错误色的浅色背景色悬浮态
364 | */
365 | colorErrorBgHover: string // 2
366 |
367 | /**
368 | * @nameZH 错误色的描边色
369 | */
370 | colorErrorBorder: string // 3
371 |
372 | /**
373 | * @nameZH 错误色的描边色悬浮态
374 | */
375 | colorErrorBorderHover: string // 4
376 |
377 | /**
378 | * @nameZH 错误色的深色悬浮态
379 | */
380 | colorErrorHover: string // 5
381 |
382 | /**
383 | * @nameZH 错误色
384 | */
385 | colorError: string // 6
386 |
387 | /**
388 | * @nameZH 错误色的深色激活态
389 | */
390 | colorErrorActive: string // 7
391 |
392 | /**
393 | * @nameZH 错误色的文本悬浮态
394 | */
395 | colorErrorTextHover: string // 8
396 |
397 | /**
398 | * @nameZH 错误色的文本默认态
399 | */
400 | colorErrorText: string // 9
401 |
402 | /**
403 | * @nameZH 错误色的文本激活态
404 | */
405 | colorErrorTextActive: string // 10
406 | }
407 |
408 | export interface ColorMapToken extends ColorNeutralMapToken, ColorPrimaryMapToken, ColorSuccessMapToken, ColorWarningMapToken, ColorErrorMapToken, ColorInfoMapToken {
409 | /**
410 | * @nameZH 纯白色
411 | * @desc 不随主题变化的纯白色
412 | * @descEN Pure white color don't changed by theme
413 | * @default #FFFFFF
414 | */
415 | colorWhite: string
416 |
417 | /**
418 | * @nameZH 浮层的背景蒙层颜色
419 | * @nameEN Background color of the mask
420 | * @desc 浮层的背景蒙层颜色,用于遮罩浮层下面的内容,Modal、Drawer 等组件的蒙层使用的是该 token
421 | * @descEN The background color of the mask, used to cover the content below the mask, Modal, Drawer and other components use this token
422 | */
423 | colorBgMask: string
424 |
425 | /**
426 | * @nameZH 纯黑色
427 | * @desc 不随主题变化的纯黑色
428 | * @default #0000
429 | */
430 | // colorBlack: string;
431 | }
432 |
--------------------------------------------------------------------------------
/components/theme/interface/maps/font.ts:
--------------------------------------------------------------------------------
1 | export interface FontMapToken {
2 | // Font Size
3 | fontSizeSM: number
4 | fontSize: number
5 | fontSizeLG: number
6 | fontSizeXL: number
7 |
8 | /**
9 | * @nameZH 一级标题字号
10 | * @desc H1 标签所使用的字号
11 | * @default 38
12 | */
13 | fontSizeHeading1: number
14 | /**
15 | * @nameZH 二级标题字号
16 | * @desc h2 标签所使用的字号
17 | * @default 30
18 | */
19 | fontSizeHeading2: number
20 | /**
21 | * @nameZH 三级标题字号
22 | * @desc h3 标签使用的字号
23 | * @default 24
24 | */
25 | fontSizeHeading3: number
26 | /**
27 | * @nameZH 四级标题字号
28 | * @desc h4 标签使用的字号
29 | * @default 20
30 | */
31 | fontSizeHeading4: number
32 | /**
33 | * @nameZH 五级标题字号
34 | * @desc h5 标签使用的字号
35 | * @default 16
36 | */
37 | fontSizeHeading5: number
38 |
39 | // LineHeight
40 | lineHeight: number
41 | lineHeightLG: number
42 | lineHeightSM: number
43 |
44 | lineHeightHeading1: number
45 | lineHeightHeading2: number
46 | lineHeightHeading3: number
47 | lineHeightHeading4: number
48 | lineHeightHeading5: number
49 | }
50 |
--------------------------------------------------------------------------------
/components/theme/interface/maps/index.ts:
--------------------------------------------------------------------------------
1 | import type { ColorPalettes } from '../presetColors'
2 | import type { SeedToken } from '../seeds'
3 | import type { HeightMapToken, SizeMapToken } from './size'
4 | import type { ColorMapToken } from './colors'
5 | import type { StyleMapToken } from './style'
6 | import type { FontMapToken } from './font'
7 |
8 | export * from './colors'
9 | export * from './style'
10 | export * from './size'
11 | export * from './font'
12 |
13 | export interface CommonMapToken extends StyleMapToken {
14 | // Motion
15 | motionDurationFast: string
16 | motionDurationMid: string
17 | motionDurationSlow: string
18 | }
19 |
20 | // ======================================================================
21 | // == Map Token ==
22 | // ======================================================================
23 | // 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
24 |
25 | export interface MapToken extends SeedToken, ColorPalettes, ColorMapToken, SizeMapToken, HeightMapToken, StyleMapToken, FontMapToken, CommonMapToken {}
26 |
--------------------------------------------------------------------------------
/components/theme/interface/maps/size.ts:
--------------------------------------------------------------------------------
1 | export interface SizeMapToken {
2 | /**
3 | * @nameZH XXL
4 | * @default 48
5 | */
6 | sizeXXL: number
7 | /**
8 | * @nameZH XL
9 | * @default 32
10 | */
11 | sizeXL: number
12 | /**
13 | * @nameZH LG
14 | * @default 24
15 | */
16 | sizeLG: number
17 | /**
18 | * @nameZH MD
19 | * @default 20
20 | */
21 | sizeMD: number
22 | /** Same as size by default, but could be larger in compact mode */
23 | sizeMS: number
24 | /**
25 | * @nameZH 默认
26 | * @desc 默认尺寸
27 | * @default 16
28 | */
29 | size: number
30 | /**
31 | * @nameZH SM
32 | * @default 12
33 | */
34 | sizeSM: number
35 | /**
36 | * @nameZH XS
37 | * @default 8
38 | */
39 | sizeXS: number
40 | /**
41 | * @nameZH XXS
42 | * @default 4
43 | */
44 | sizeXXS: number
45 | }
46 |
47 | export interface HeightMapToken {
48 | // Control
49 | /** Only Used for control inside component like Multiple Select inner selection item */
50 |
51 | /**
52 | * @nameZH 更小的组件高度
53 | * @nameEN XS component height
54 | */
55 | controlHeightXS: number
56 |
57 | /**
58 | * @nameZH 较小的组件高度
59 | * @nameEN SM component height
60 | */
61 | controlHeightSM: number
62 |
63 | /**
64 | * @nameZH 较高的组件高度
65 | * @nameEN LG component height
66 | */
67 | controlHeightLG: number
68 | }
69 |
--------------------------------------------------------------------------------
/components/theme/interface/maps/style.ts:
--------------------------------------------------------------------------------
1 | export interface StyleMapToken {
2 | /**
3 | * @nameZH 线宽
4 | * @nameEN Line Width
5 | * @desc 描边类组件的默认线宽,如 Button、Input、Select 等输入类控件。
6 | * @descEN The default line width of the outline class components, such as Button, Input, Select, etc.
7 | * @default 1
8 | */
9 | lineWidthBold: number
10 |
11 | /**
12 | * @nameZH XS号圆角
13 | * @desc XS号圆角,用于组件中的一些小圆角,如 Segmented 、Arrow 等一些内部圆角的组件样式中。
14 | * @descEN XS size border radius, used in some small border radius components, such as Segmented, Arrow and other components.
15 | * @default 2
16 | */
17 | borderRadiusXS: number
18 | /**
19 | * @nameZH SM号圆角
20 | * @nameEN SM Border Radius
21 | * @desc SM号圆角,用于组件小尺寸下的圆角,如 Button、Input、Select 等输入类控件在 small size 下的圆角
22 | * @descEN SM size border radius, used in small size components, such as Button, Input, Select and other input components in small size
23 | * @default 4
24 | */
25 | borderRadiusSM: number
26 | /**
27 | * @nameZH LG号圆角
28 | * @nameEN LG Border Radius
29 | * @desc LG号圆角,用于组件中的一些大圆角,如 Card、Modal 等一些组件样式。
30 | * @descEN LG size border radius, used in some large border radius components, such as Card, Modal and other components.
31 | * @default 8
32 | */
33 | borderRadiusLG: number
34 | /**
35 | * @default 4
36 | */
37 | borderRadiusOuter: number
38 | }
39 |
--------------------------------------------------------------------------------
/components/theme/interface/presetColors.ts:
--------------------------------------------------------------------------------
1 | export const PresetColors = ['blue', 'purple', 'cyan', 'green', 'magenta', 'pink', 'red', 'orange', 'yellow', 'volcano', 'geekblue', 'lime', 'gold'] as const
2 |
3 | export type PresetColorKey = (typeof PresetColors)[number]
4 |
5 | export type PresetColorType = Record
6 |
7 | type ColorPaletteKeyIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
8 |
9 | export type ColorPalettes = {
10 | [key in `${keyof PresetColorType}-${ColorPaletteKeyIndex}`]: string
11 | }
12 |
--------------------------------------------------------------------------------
/components/theme/interface/seeds.ts:
--------------------------------------------------------------------------------
1 | import type { PresetColorType } from './presetColors'
2 | // ======================================================================
3 | // == Seed Token ==
4 | // ======================================================================
5 | // 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
6 |
7 | export interface SeedToken extends PresetColorType {
8 | // ---------- Color ---------- //
9 |
10 | /**
11 | * @nameZH 品牌主色
12 | * @nameEN Brand Color
13 | * @desc 品牌色是体现产品特性和传播理念最直观的视觉元素之一。在你完成品牌主色的选取之后,我们会自动帮你生成一套完整的色板,并赋予它们有效的设计语义
14 | * @descEN Brand color is one of the most direct visual elements to reflect the characteristics and communication of the product. After you have selected the brand color, we will automatically generate a complete color palette and assign it effective design semantics.
15 | */
16 | colorPrimary: string
17 |
18 | /**
19 | * @nameZH 成功色
20 | * @nameEN Success Color
21 | * @desc 用于表示操作成功的 Token 序列,如 Result、Progress 等组件会使用该组梯度变量。
22 | * @descEN Used to represent the token sequence of operation success, such as Result, Progress and other components will use these map tokens.
23 | */
24 | colorSuccess: string
25 |
26 | /**
27 | * @nameZH 警戒色
28 | * @nameEN Warning Color
29 | * @desc 用于表示操作警告的 Token 序列,如 Notification、 Alert等警告类组件或 Input 输入类等组件会使用该组梯度变量。
30 | * @descEN Used to represent the warning map token, such as Notification, Alert, etc. Alert or Control component(like Input) will use these map tokens.
31 | */
32 | colorWarning: string
33 |
34 | /**
35 | * @nameZH 错误色
36 | * @nameEN Error Color
37 | * @desc 用于表示操作失败的 Token 序列,如失败按钮、错误状态提示(Result)组件等。
38 | * @descEN Used to represent the visual elements of the operation failure, such as the error Button, error Result component, etc.
39 | */
40 | colorError: string
41 |
42 | /**
43 | * @nameZH 信息色
44 | * @nameEN Info Color
45 | * @desc 用于表示操作信息的 Token 序列,如 Alert 、Tag、 Progress 等组件都有用到该组梯度变量。
46 | * @descEN Used to represent the operation information of the Token sequence, such as Alert, Tag, Progress, and other components use these map tokens.
47 | */
48 | colorInfo: string
49 |
50 | /**
51 | * @nameZH 基础文本色
52 | * @nameEN Seed Text Color
53 | * @desc 用于派生文本色梯度的基础变量,v5 中我们添加了一层文本色的派生算法可以产出梯度明确的文本色的梯度变量。但请不要在代码中直接使用该 Seed Token !
54 | * @descEN Used to derive the base variable of the text color gradient. In v5, we added a layer of text color derivation algorithm to produce gradient variables of text color gradient. But please do not use this Seed Token directly in the code!
55 | */
56 | colorTextBase: string
57 |
58 | /**
59 | * @nameZH 基础背景色
60 | * @nameEN Seed Background Color
61 | * @desc 用于派生背景色梯度的基础变量,v5 中我们添加了一层背景色的派生算法可以产出梯度明确的背景色的梯度变量。但请不要在代码中直接使用该 Seed Token !
62 | * @descEN Used to derive the base variable of the background color gradient. In v5, we added a layer of background color derivation algorithm to produce map token of background color. But PLEASE DO NOT USE this Seed Token directly in the code!
63 | */
64 | colorBgBase: string
65 |
66 | // ---------- Font ---------- //
67 |
68 | /**
69 | * @nameZH 字体
70 | * @nameEN Font family for default text
71 | * @desc Ant Design 的字体家族中优先使用系统默认的界面字体,同时提供了一套利于屏显的备用字体库,来维护在不同平台以及浏览器的显示下,字体始终保持良好的易读性和可读性,体现了友好、稳定和专业的特性。
72 | */
73 | fontFamily: string
74 |
75 | /**
76 | * @nameZH 代码字体
77 | * @nameEN Font family for code text
78 | * @desc 代码字体,用于 Typography 内的 code、pre 和 kbd 类型的元素
79 | */
80 | fontFamilyCode: string
81 |
82 | /**
83 | * @nameZH 默认字号
84 | * @nameEN Default Font Size
85 | * @desc 设计系统中使用最广泛的字体大小,文本梯度也将基于该字号进行派生。
86 | * @default 14
87 | */
88 | fontSize: number
89 |
90 | // ---------- Line ---------- //
91 |
92 | /**
93 | * @nameZH 基础线宽
94 | * @nameEN Base Line Width
95 | * @desc 用于控制组件边框、分割线等的宽度
96 | * @descEN Border width of base components
97 | */
98 | lineWidth: number
99 |
100 | /**
101 | * @nameZH 线条样式
102 | * @nameEN Line Style
103 | * @desc 用于控制组件边框、分割线等的样式,默认是实线
104 | * @descEN Border style of base components
105 | */
106 | lineType: string
107 |
108 | // ---------- BorderRadius ---------- //
109 |
110 | /**
111 | * @nameZH 基础圆角
112 | * @nameEN Base Border Radius
113 | * @descEN Border radius of base components
114 | * @desc 基础组件的圆角大小,例如按钮、输入框、卡片等
115 | */
116 | borderRadius: number
117 |
118 | // ---------- Size ---------- //
119 |
120 | /**
121 | * @nameZH 尺寸变化单位
122 | * @nameEN Size Change Unit
123 | * @desc 用于控制组件尺寸的变化单位,在 Ant Design 中我们的基础单位为 4 ,便于更加细致地控制尺寸梯度
124 | * @descEN The unit of size change, in Ant Design, our base unit is 4, which is more fine-grained control of the size step
125 | * @default 4
126 | */
127 | sizeUnit: number
128 |
129 | /**
130 | * @nameZH 尺寸步长
131 | * @nameEN Size Base Step
132 | * @desc 用于控制组件尺寸的基础步长,尺寸步长结合尺寸变化单位,就可以派生各种尺寸梯度。通过调整步长即可得到不同的布局模式,例如 V5 紧凑模式下的尺寸步长为 2
133 | * @descEN The base step of size change, the size step combined with the size change unit, can derive various size steps. By adjusting the step, you can get different layout modes, such as the size step of the compact mode of V5 is 2
134 | * @default 4
135 | */
136 | sizeStep: number
137 |
138 | /**
139 | * @nameZH 组件箭头尺寸
140 | */
141 | sizePopupArrow: number
142 |
143 | /**
144 | * @nameZH 基础高度
145 | * @nameEN Base Control Height
146 | * @desc Ant Design 中按钮和输入框等基础控件的高度
147 | * @descEN The height of the basic controls such as buttons and input boxes in Ant Design
148 | * @default 32
149 | */
150 | controlHeight: number
151 |
152 | // ---------- zIndex ---------- //
153 |
154 | /**
155 | * @nameZH 基础 zIndex
156 | * @nameEN Base zIndex
157 | * @desc 所有组件的基础 Z 轴值,用于一些悬浮类的组件的可以基于该值 Z 轴控制层级,例如 BackTop、 Affix 等
158 | * @descEN The base Z axis value of all components, which can be used to control the level of some floating components based on the Z axis value, such as BackTop, Affix, etc.
159 | *
160 | * @default 0
161 | */
162 | zIndexBase: number
163 |
164 | /**
165 | * @nameZH 浮层基础 zIndex
166 | * @nameEN popup base zIndex
167 | * @desc 浮层类组件的基础 Z 轴值,用于一些悬浮类的组件的可以基于该值 Z 轴控制层级,例如 FloatButton、 Affix、Modal 等
168 | * @descEN Base zIndex of component like FloatButton, Affix which can be cover by large popup
169 | * @default 1000
170 | */
171 | zIndexPopupBase: number
172 |
173 | // ---------- Opacity ---------- //
174 |
175 | /**
176 | * @nameZH 图片不透明度
177 | * @nameEN Define default Image opacity. Useful when in dark-like theme
178 | */
179 | opacityImage: number
180 |
181 | // ---------- motion ---------- //
182 | // TODO: 缺一个懂 motion 的人来收敛 Motion 相关的 Token
183 |
184 | /**
185 | * @nameZH 动画时长变化单位
186 | * @nameEN Animation Duration Unit
187 | * @desc 用于控制动画时长的变化单位
188 | * @descEN The unit of animation duration change
189 | * @default 100ms
190 | */
191 | motionUnit: number
192 |
193 | /**
194 | * @nameZH 动画基础时长
195 | */
196 | motionBase: number
197 |
198 | motionEaseOutCirc: string
199 |
200 | motionEaseInOutCirc: string
201 |
202 | motionEaseInOut: string
203 |
204 | motionEaseOutBack: string
205 |
206 | motionEaseInBack: string
207 |
208 | motionEaseInQuint: string
209 |
210 | motionEaseOutQuint: string
211 |
212 | motionEaseOut: string
213 |
214 | // ---------- Style ---------- //
215 |
216 | /**
217 | * @nameZH 线框风格
218 | * @nameEN Wireframe Style
219 | * @desc 用于将组件的视觉效果变为线框化,如果需要使用 V4 的效果,需要开启配置项
220 | * @default false
221 | */
222 | wireframe: boolean
223 | }
224 |
--------------------------------------------------------------------------------
/components/theme/internal.ts:
--------------------------------------------------------------------------------
1 | import type { CSSInterpolation, Theme } from '@antd-tiny-vue/cssinjs'
2 | import { createTheme, useCacheToken, useStyleRegister } from '@antd-tiny-vue/cssinjs'
3 | import { createInjectionState, objectType, someType } from '@v-c/utils'
4 | import type { ComputedRef, VNodeChild } from 'vue'
5 | import { computed, defineComponent } from 'vue'
6 | import version from '../version'
7 | import type { AliasToken, GlobalToken, MapToken, OverrideToken, PresetColorKey, PresetColorType, SeedToken } from './interface'
8 | import { PresetColors } from './interface'
9 | import defaultDerivative from './themes/default'
10 | import defaultSeedToken from './themes/seed'
11 | import formatToken from './util/alias'
12 | import type { FullToken } from './util/genComponentStyleHook'
13 | import genComponentStyleHook from './util/genComponentStyleHook'
14 | import statisticToken, { merge as mergeToken, statistic } from './util/statistic'
15 |
16 | const defaultTheme = createTheme(defaultDerivative)
17 |
18 | export {
19 | // colors
20 | PresetColors,
21 | // Statistic
22 | statistic,
23 | statisticToken,
24 | mergeToken,
25 | // hooks
26 | useStyleRegister,
27 | genComponentStyleHook
28 | }
29 | export type {
30 | SeedToken,
31 | AliasToken,
32 | PresetColorType,
33 | PresetColorKey,
34 | // FIXME: Remove this type
35 | FullToken,
36 | AliasToken as DerivativeToken
37 | }
38 |
39 | // ================================ Context =================================
40 | // To ensure snapshot stable. We disable hashed in test env.
41 | export const defaultConfig: DesignTokenConfig = {
42 | token: defaultSeedToken,
43 | hashed: true
44 | }
45 |
46 | export interface DesignTokenConfig {
47 | token: Partial
48 | theme?: Theme
49 | components?: OverrideToken
50 | hashed?: string | boolean
51 | }
52 |
53 | const [useDesignTokenProvider, useDesignTokenInject] = createInjectionState((token: DesignTokenConfig) => {
54 | return token
55 | })
56 |
57 | export const DesignTokenProviderContext = defineComponent({
58 | props: {
59 | token: objectType(),
60 | theme: objectType>(),
61 | components: objectType(),
62 | hashed: someType([String, Boolean])
63 | },
64 | setup(props, { slots }) {
65 | useDesignTokenProvider(props)
66 | return () => {
67 | return slots.default?.()
68 | }
69 | }
70 | })
71 |
72 | export { useDesignTokenProvider }
73 | export const useDesignTokenState = () => useDesignTokenInject() ?? defaultConfig
74 |
75 | // ================================== Hook ==================================
76 | export function useToken(): [ComputedRef>, ComputedRef, ComputedRef] {
77 | const designTokenContext = useDesignTokenState()
78 | const salt = computed(() => `${version}-${designTokenContext.hashed || ''}`)
79 |
80 | const mergedTheme = computed(() => designTokenContext.theme || defaultTheme)
81 | const tokens = computed(() => [defaultSeedToken, designTokenContext.token])
82 | const opt = computed(() => {
83 | return {
84 | salt: salt.value,
85 | override: { override: designTokenContext.token, ...designTokenContext.components },
86 | formatToken
87 | }
88 | })
89 |
90 | const cacheToken = useCacheToken(mergedTheme, tokens, opt)
91 |
92 | return [mergedTheme, computed(() => cacheToken.value?.[0]), computed(() => (designTokenContext.hashed ? cacheToken.value?.[1] : ''))]
93 | }
94 |
95 | export type UseComponentStyleResult = [(node: VNodeChild) => VNodeChild, ComputedRef]
96 |
97 | export type GenerateStyle = (token: ComponentToken) => ReturnType
98 |
--------------------------------------------------------------------------------
/components/theme/themes/ColorMap.ts:
--------------------------------------------------------------------------------
1 | import type { ColorNeutralMapToken } from '../interface'
2 |
3 | export interface ColorMap {
4 | 1: string
5 | 2: string
6 | 3: string
7 | 4: string
8 | 5: string
9 | 6: string
10 | 7: string
11 | 8: string
12 | 9: string
13 | 10: string
14 | }
15 |
16 | export type GenerateColorMap = (baseColor: string) => ColorMap
17 | export type GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => ColorNeutralMapToken
18 |
--------------------------------------------------------------------------------
/components/theme/themes/compact/genCompactSizeMapToken.ts:
--------------------------------------------------------------------------------
1 | import type { SeedToken, SizeMapToken } from '../../interface'
2 |
3 | export default function genSizeMapToken(token: SeedToken): SizeMapToken {
4 | const { sizeUnit, sizeStep } = token
5 |
6 | const compactSizeStep = sizeStep - 2
7 |
8 | return {
9 | sizeXXL: sizeUnit * (compactSizeStep + 10),
10 | sizeXL: sizeUnit * (compactSizeStep + 6),
11 | sizeLG: sizeUnit * (compactSizeStep + 2),
12 | sizeMD: sizeUnit * (compactSizeStep + 2),
13 | sizeMS: sizeUnit * (compactSizeStep + 1),
14 | size: sizeUnit * compactSizeStep,
15 | sizeSM: sizeUnit * compactSizeStep,
16 | sizeXS: sizeUnit * (compactSizeStep - 1),
17 | sizeXXS: sizeUnit * (compactSizeStep - 1)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/components/theme/themes/compact/index.ts:
--------------------------------------------------------------------------------
1 | import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs'
2 | import genControlHeight from '../shared/genControlHeight'
3 | import type { MapToken, SeedToken } from '../../interface'
4 | import defaultAlgorithm from '../default'
5 | import genFontMapToken from '../shared/genFontMapToken'
6 | import genCompactSizeMapToken from './genCompactSizeMapToken'
7 |
8 | const derivative: DerivativeFunc = (token, mapToken) => {
9 | const mergedMapToken = mapToken ?? defaultAlgorithm(token)
10 |
11 | const fontSize = mergedMapToken.fontSizeSM // Smaller size font-size as base
12 | const controlHeight = mergedMapToken.controlHeight - 4
13 |
14 | return {
15 | ...mergedMapToken,
16 | ...genCompactSizeMapToken(mapToken ?? token),
17 |
18 | // font
19 | ...genFontMapToken(fontSize),
20 |
21 | // controlHeight
22 | controlHeight,
23 | ...genControlHeight({ ...mergedMapToken, controlHeight })
24 | }
25 | }
26 |
27 | export default derivative
28 |
--------------------------------------------------------------------------------
/components/theme/themes/dark/colorAlgorithm.ts:
--------------------------------------------------------------------------------
1 | import { TinyColor } from '@ctrl/tinycolor'
2 |
3 | export const getAlphaColor = (baseColor: string, alpha: number) => new TinyColor(baseColor).setAlpha(alpha).toRgbString()
4 |
5 | export const getSolidColor = (baseColor: string, brightness: number) => {
6 | const instance = new TinyColor(baseColor)
7 | return instance.lighten(brightness).toHexString()
8 | }
9 |
--------------------------------------------------------------------------------
/components/theme/themes/dark/colors.ts:
--------------------------------------------------------------------------------
1 | import { generate } from '@ant-design/colors'
2 | import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
3 | import { getAlphaColor, getSolidColor } from './colorAlgorithm'
4 |
5 | export const generateColorPalettes: GenerateColorMap = (baseColor: string) => {
6 | const colors = generate(baseColor, { theme: 'dark' })
7 | return {
8 | 1: colors[0],
9 | 2: colors[1],
10 | 3: colors[2],
11 | 4: colors[3],
12 | 5: colors[6],
13 | 6: colors[5],
14 | 7: colors[4],
15 | 8: colors[6],
16 | 9: colors[5],
17 | 10: colors[4]
18 | // 8: colors[9],
19 | // 9: colors[8],
20 | // 10: colors[7],
21 | }
22 | }
23 |
24 | export const generateNeutralColorPalettes: GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => {
25 | const colorBgBase = bgBaseColor || '#000'
26 | const colorTextBase = textBaseColor || '#fff'
27 |
28 | return {
29 | colorBgBase,
30 | colorTextBase,
31 |
32 | colorText: getAlphaColor(colorTextBase, 0.85),
33 | colorTextSecondary: getAlphaColor(colorTextBase, 0.65),
34 | colorTextTertiary: getAlphaColor(colorTextBase, 0.45),
35 | colorTextQuaternary: getAlphaColor(colorTextBase, 0.25),
36 |
37 | colorFill: getAlphaColor(colorTextBase, 0.18),
38 | colorFillSecondary: getAlphaColor(colorTextBase, 0.12),
39 | colorFillTertiary: getAlphaColor(colorTextBase, 0.08),
40 | colorFillQuaternary: getAlphaColor(colorTextBase, 0.04),
41 |
42 | colorBgElevated: getSolidColor(colorBgBase, 12),
43 | colorBgContainer: getSolidColor(colorBgBase, 8),
44 | colorBgLayout: getSolidColor(colorBgBase, 0),
45 | colorBgSpotlight: getSolidColor(colorBgBase, 26),
46 |
47 | colorBorder: getSolidColor(colorBgBase, 26),
48 | colorBorderSecondary: getSolidColor(colorBgBase, 19)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/components/theme/themes/dark/index.ts:
--------------------------------------------------------------------------------
1 | import { generate } from '@ant-design/colors'
2 | import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs'
3 | import type { ColorPalettes, MapToken, PresetColorType, SeedToken } from '../../interface'
4 | import { defaultPresetColors } from '../seed'
5 | import genColorMapToken from '../shared/genColorMapToken'
6 | import defaultAlgorithm from '../default'
7 | import { generateColorPalettes, generateNeutralColorPalettes } from './colors'
8 |
9 | const derivative: DerivativeFunc = (token, mapToken) => {
10 | const colorPalettes = Object.keys(defaultPresetColors)
11 | // @ts-expect-error this is a bug of typescript
12 | .map((colorKey: keyof PresetColorType) => {
13 | const colors = generate(token[colorKey], { theme: 'dark' })
14 |
15 | return new Array(10).fill(1).reduce((prev, _, i) => {
16 | prev[`${colorKey}-${i + 1}`] = colors[i]
17 | return prev
18 | }, {}) as ColorPalettes
19 | })
20 | .reduce((prev, cur) => {
21 | prev = {
22 | ...prev,
23 | ...cur
24 | }
25 | return prev
26 | }, {} as ColorPalettes)
27 |
28 | const mergedMapToken = mapToken ?? defaultAlgorithm(token)
29 |
30 | return {
31 | ...mergedMapToken,
32 |
33 | // Dark tokens
34 | ...colorPalettes,
35 | // Colors
36 | ...genColorMapToken(token, {
37 | generateColorPalettes,
38 | generateNeutralColorPalettes
39 | })
40 | }
41 | }
42 |
43 | export default derivative
44 |
--------------------------------------------------------------------------------
/components/theme/themes/default/colorAlgorithm.ts:
--------------------------------------------------------------------------------
1 | import { TinyColor } from '@ctrl/tinycolor'
2 |
3 | export const getAlphaColor = (baseColor: string, alpha: number) => new TinyColor(baseColor).setAlpha(alpha).toRgbString()
4 |
5 | export const getSolidColor = (baseColor: string, brightness: number) => {
6 | const instance = new TinyColor(baseColor)
7 | return instance.darken(brightness).toHexString()
8 | }
9 |
--------------------------------------------------------------------------------
/components/theme/themes/default/colors.ts:
--------------------------------------------------------------------------------
1 | import { generate } from '@ant-design/colors'
2 | import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
3 | import { getAlphaColor, getSolidColor } from './colorAlgorithm'
4 |
5 | export const generateColorPalettes: GenerateColorMap = (baseColor: string) => {
6 | const colors = generate(baseColor)
7 | return {
8 | 1: colors[0],
9 | 2: colors[1],
10 | 3: colors[2],
11 | 4: colors[3],
12 | 5: colors[4],
13 | 6: colors[5],
14 | 7: colors[6],
15 | 8: colors[4],
16 | 9: colors[5],
17 | 10: colors[6]
18 | // 8: colors[7],
19 | // 9: colors[8],
20 | // 10: colors[9],
21 | }
22 | }
23 |
24 | export const generateNeutralColorPalettes: GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => {
25 | const colorBgBase = bgBaseColor || '#fff'
26 | const colorTextBase = textBaseColor || '#000'
27 |
28 | return {
29 | colorBgBase,
30 | colorTextBase,
31 |
32 | colorText: getAlphaColor(colorTextBase, 0.88),
33 | colorTextSecondary: getAlphaColor(colorTextBase, 0.65),
34 | colorTextTertiary: getAlphaColor(colorTextBase, 0.45),
35 | colorTextQuaternary: getAlphaColor(colorTextBase, 0.25),
36 |
37 | colorFill: getAlphaColor(colorTextBase, 0.15),
38 | colorFillSecondary: getAlphaColor(colorTextBase, 0.06),
39 | colorFillTertiary: getAlphaColor(colorTextBase, 0.04),
40 | colorFillQuaternary: getAlphaColor(colorTextBase, 0.02),
41 |
42 | colorBgLayout: getSolidColor(colorBgBase, 4),
43 | colorBgContainer: getSolidColor(colorBgBase, 0),
44 | colorBgElevated: getSolidColor(colorBgBase, 0),
45 | colorBgSpotlight: getAlphaColor(colorTextBase, 0.85),
46 |
47 | colorBorder: getSolidColor(colorBgBase, 15),
48 | colorBorderSecondary: getSolidColor(colorBgBase, 6)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/components/theme/themes/default/index.ts:
--------------------------------------------------------------------------------
1 | import { generate } from '@ant-design/colors'
2 | import genControlHeight from '../shared/genControlHeight'
3 | import genSizeMapToken from '../shared/genSizeMapToken'
4 | import type {
5 | ColorPalettes,
6 | MapToken,
7 | PresetColorType,
8 | SeedToken
9 | } from '../../interface'
10 | import { defaultPresetColors } from '../seed'
11 | import genColorMapToken from '../shared/genColorMapToken'
12 | import genCommonMapToken from '../shared/genCommonMapToken'
13 | import genFontMapToken from '../shared/genFontMapToken'
14 | import { generateColorPalettes, generateNeutralColorPalettes } from './colors'
15 |
16 | export default function derivative(token: SeedToken): MapToken {
17 | const colorPalettes = Object.keys(defaultPresetColors)
18 | .map((value) => {
19 | const colorKey = value as keyof PresetColorType
20 | const colors = generate(token[colorKey])
21 |
22 | return new Array(10).fill(1).reduce((prev, _, i) => {
23 | prev[`${colorKey}-${i + 1}`] = colors[i]
24 | return prev
25 | }, {}) as ColorPalettes
26 | })
27 | .reduce((prev, cur) => {
28 | prev = {
29 | ...prev,
30 | ...cur
31 | }
32 | return prev
33 | }, {} as ColorPalettes)
34 |
35 | return {
36 | ...token,
37 | ...colorPalettes,
38 | // Colors
39 | ...genColorMapToken(token, {
40 | generateColorPalettes,
41 | generateNeutralColorPalettes
42 | }),
43 | // Font
44 | ...genFontMapToken(token.fontSize),
45 | // Size
46 | ...genSizeMapToken(token),
47 | // Height
48 | ...genControlHeight(token),
49 | // Others
50 | ...genCommonMapToken(token)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/components/theme/themes/seed.ts:
--------------------------------------------------------------------------------
1 | import type { PresetColorType, SeedToken } from '../internal'
2 |
3 | export const defaultPresetColors: PresetColorType = {
4 | blue: '#1677ff',
5 | purple: '#722ED1',
6 | cyan: '#13C2C2',
7 | green: '#52C41A',
8 | magenta: '#EB2F96',
9 | pink: '#eb2f96',
10 | red: '#F5222D',
11 | orange: '#FA8C16',
12 | yellow: '#FADB14',
13 | volcano: '#FA541C',
14 | geekblue: '#2F54EB',
15 | gold: '#FAAD14',
16 | lime: '#A0D911'
17 | }
18 |
19 | const seedToken: SeedToken = {
20 | // preset color palettes
21 | ...defaultPresetColors,
22 |
23 | // Color
24 | colorPrimary: '#1677ff',
25 | colorSuccess: '#52c41a',
26 | colorWarning: '#faad14',
27 | colorError: '#ff4d4f',
28 | colorInfo: '#1677ff',
29 | colorTextBase: '',
30 |
31 | colorBgBase: '',
32 |
33 | // Font
34 | fontFamily: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
35 | 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
36 | 'Noto Color Emoji'`,
37 | fontFamilyCode: `'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace`,
38 | fontSize: 14,
39 |
40 | // Line
41 | lineWidth: 1,
42 | lineType: 'solid',
43 |
44 | // Motion
45 | motionUnit: 0.1,
46 | motionBase: 0,
47 | motionEaseOutCirc: 'cubic-bezier(0.08, 0.82, 0.17, 1)',
48 | motionEaseInOutCirc: 'cubic-bezier(0.78, 0.14, 0.15, 0.86)',
49 | motionEaseOut: 'cubic-bezier(0.215, 0.61, 0.355, 1)',
50 | motionEaseInOut: 'cubic-bezier(0.645, 0.045, 0.355, 1)',
51 | motionEaseOutBack: 'cubic-bezier(0.12, 0.4, 0.29, 1.46)',
52 | motionEaseInBack: 'cubic-bezier(0.71, -0.46, 0.88, 0.6)',
53 | motionEaseInQuint: 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
54 | motionEaseOutQuint: 'cubic-bezier(0.23, 1, 0.32, 1)',
55 |
56 | // Radius
57 | borderRadius: 6,
58 |
59 | // Size
60 | sizeUnit: 4,
61 | sizeStep: 4,
62 | sizePopupArrow: 16,
63 |
64 | // Control Base
65 | controlHeight: 32,
66 |
67 | // zIndex
68 | zIndexBase: 0,
69 | zIndexPopupBase: 1000,
70 |
71 | // Image
72 | opacityImage: 1,
73 |
74 | // Wireframe
75 | wireframe: false
76 | }
77 | export default seedToken
78 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genColorMapToken.ts:
--------------------------------------------------------------------------------
1 | import { TinyColor } from '@ctrl/tinycolor'
2 | import type { ColorMapToken, SeedToken } from '../../interface'
3 | import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
4 |
5 | interface PaletteGenerators {
6 | generateColorPalettes: GenerateColorMap
7 | generateNeutralColorPalettes: GenerateNeutralColorMap
8 | }
9 |
10 | export default function genColorMapToken(seed: SeedToken, { generateColorPalettes, generateNeutralColorPalettes }: PaletteGenerators): ColorMapToken {
11 | const { colorSuccess: colorSuccessBase, colorWarning: colorWarningBase, colorError: colorErrorBase, colorInfo: colorInfoBase, colorPrimary: colorPrimaryBase, colorBgBase, colorTextBase } = seed
12 |
13 | const primaryColors = generateColorPalettes(colorPrimaryBase)
14 | const successColors = generateColorPalettes(colorSuccessBase)
15 | const warningColors = generateColorPalettes(colorWarningBase)
16 | const errorColors = generateColorPalettes(colorErrorBase)
17 | const infoColors = generateColorPalettes(colorInfoBase)
18 | const neutralColors = generateNeutralColorPalettes(colorBgBase, colorTextBase)
19 |
20 | return {
21 | ...neutralColors,
22 |
23 | colorPrimaryBg: primaryColors[1],
24 | colorPrimaryBgHover: primaryColors[2],
25 | colorPrimaryBorder: primaryColors[3],
26 | colorPrimaryBorderHover: primaryColors[4],
27 | colorPrimaryHover: primaryColors[5],
28 | colorPrimary: primaryColors[6],
29 | colorPrimaryActive: primaryColors[7],
30 | colorPrimaryTextHover: primaryColors[8],
31 | colorPrimaryText: primaryColors[9],
32 | colorPrimaryTextActive: primaryColors[10],
33 |
34 | colorSuccessBg: successColors[1],
35 | colorSuccessBgHover: successColors[2],
36 | colorSuccessBorder: successColors[3],
37 | colorSuccessBorderHover: successColors[4],
38 | colorSuccessHover: successColors[4],
39 | colorSuccess: successColors[6],
40 | colorSuccessActive: successColors[7],
41 | colorSuccessTextHover: successColors[8],
42 | colorSuccessText: successColors[9],
43 | colorSuccessTextActive: successColors[10],
44 |
45 | colorErrorBg: errorColors[1],
46 | colorErrorBgHover: errorColors[2],
47 | colorErrorBorder: errorColors[3],
48 | colorErrorBorderHover: errorColors[4],
49 | colorErrorHover: errorColors[5],
50 | colorError: errorColors[6],
51 | colorErrorActive: errorColors[7],
52 | colorErrorTextHover: errorColors[8],
53 | colorErrorText: errorColors[9],
54 | colorErrorTextActive: errorColors[10],
55 |
56 | colorWarningBg: warningColors[1],
57 | colorWarningBgHover: warningColors[2],
58 | colorWarningBorder: warningColors[3],
59 | colorWarningBorderHover: warningColors[4],
60 | colorWarningHover: warningColors[4],
61 | colorWarning: warningColors[6],
62 | colorWarningActive: warningColors[7],
63 | colorWarningTextHover: warningColors[8],
64 | colorWarningText: warningColors[9],
65 | colorWarningTextActive: warningColors[10],
66 |
67 | colorInfoBg: infoColors[1],
68 | colorInfoBgHover: infoColors[2],
69 | colorInfoBorder: infoColors[3],
70 | colorInfoBorderHover: infoColors[4],
71 | colorInfoHover: infoColors[4],
72 | colorInfo: infoColors[6],
73 | colorInfoActive: infoColors[7],
74 | colorInfoTextHover: infoColors[8],
75 | colorInfoText: infoColors[9],
76 | colorInfoTextActive: infoColors[10],
77 |
78 | colorBgMask: new TinyColor('#000').setAlpha(0.45).toRgbString(),
79 | colorWhite: '#fff'
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genCommonMapToken.ts:
--------------------------------------------------------------------------------
1 | import type { CommonMapToken, SeedToken } from '../../interface'
2 | import genRadius from './genRadius'
3 |
4 | export default function genCommonMapToken(token: SeedToken): CommonMapToken {
5 | const { motionUnit, motionBase, borderRadius, lineWidth } = token
6 |
7 | return {
8 | // motion
9 | motionDurationFast: `${(motionBase + motionUnit).toFixed(1)}s`,
10 | motionDurationMid: `${(motionBase + motionUnit * 2).toFixed(1)}s`,
11 | motionDurationSlow: `${(motionBase + motionUnit * 3).toFixed(1)}s`,
12 |
13 | // line
14 | lineWidthBold: lineWidth + 1,
15 |
16 | // radius
17 | ...genRadius(borderRadius)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genControlHeight.ts:
--------------------------------------------------------------------------------
1 | import type { HeightMapToken, SeedToken } from '../../interface'
2 |
3 | const genControlHeight = (token: SeedToken): HeightMapToken => {
4 | const { controlHeight } = token
5 |
6 | return {
7 | controlHeightSM: controlHeight * 0.75,
8 | controlHeightXS: controlHeight * 0.5,
9 | controlHeightLG: controlHeight * 1.25
10 | }
11 | }
12 |
13 | export default genControlHeight
14 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genFontMapToken.ts:
--------------------------------------------------------------------------------
1 | import type { FontMapToken } from '../../interface'
2 | import genFontSizes from './genFontSizes'
3 |
4 | const genFontMapToken = (fontSize: number): FontMapToken => {
5 | const fontSizePairs = genFontSizes(fontSize)
6 | const fontSizes = fontSizePairs.map(pair => pair.size)
7 | const lineHeights = fontSizePairs.map(pair => pair.lineHeight)
8 |
9 | return {
10 | fontSizeSM: fontSizes[0],
11 | fontSize: fontSizes[1],
12 | fontSizeLG: fontSizes[2],
13 | fontSizeXL: fontSizes[3],
14 |
15 | fontSizeHeading1: fontSizes[6],
16 | fontSizeHeading2: fontSizes[5],
17 | fontSizeHeading3: fontSizes[4],
18 | fontSizeHeading4: fontSizes[3],
19 | fontSizeHeading5: fontSizes[2],
20 |
21 | lineHeight: lineHeights[1],
22 | lineHeightLG: lineHeights[2],
23 | lineHeightSM: lineHeights[0],
24 |
25 | lineHeightHeading1: lineHeights[6],
26 | lineHeightHeading2: lineHeights[5],
27 | lineHeightHeading3: lineHeights[4],
28 | lineHeightHeading4: lineHeights[3],
29 | lineHeightHeading5: lineHeights[2]
30 | }
31 | }
32 |
33 | export default genFontMapToken
34 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genFontSizes.ts:
--------------------------------------------------------------------------------
1 | // https://zhuanlan.zhihu.com/p/32746810
2 | export default function getFontSizes(base: number) {
3 | const fontSizes = new Array(10).fill(null).map((_, index) => {
4 | const i = index - 1
5 | const baseSize = base * 2.71828 ** (i / 5)
6 | const intSize = index > 1 ? Math.floor(baseSize) : Math.ceil(baseSize)
7 |
8 | // Convert to even
9 | return Math.floor(intSize / 2) * 2
10 | })
11 |
12 | fontSizes[1] = base
13 |
14 | return fontSizes.map(size => {
15 | const height = size + 8
16 |
17 | return {
18 | size,
19 | lineHeight: height / size
20 | }
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genRadius.ts:
--------------------------------------------------------------------------------
1 | import type { MapToken } from '../../interface'
2 |
3 | const genRadius = (radiusBase: number): Pick => {
4 | let radiusLG = radiusBase
5 | let radiusSM = radiusBase
6 | let radiusXS = radiusBase
7 | let radiusOuter = radiusBase
8 |
9 | // radiusLG
10 | if (radiusBase < 6 && radiusBase >= 5) {
11 | radiusLG = radiusBase + 1
12 | } else if (radiusBase < 16 && radiusBase >= 6) {
13 | radiusLG = radiusBase + 2
14 | } else if (radiusBase >= 16) {
15 | radiusLG = 16
16 | }
17 |
18 | // radiusSM
19 | if (radiusBase < 7 && radiusBase >= 5) {
20 | radiusSM = 4
21 | } else if (radiusBase < 8 && radiusBase >= 7) {
22 | radiusSM = 5
23 | } else if (radiusBase < 14 && radiusBase >= 8) {
24 | radiusSM = 6
25 | } else if (radiusBase < 16 && radiusBase >= 14) {
26 | radiusSM = 7
27 | } else if (radiusBase >= 16) {
28 | radiusSM = 8
29 | }
30 |
31 | // radiusXS
32 | if (radiusBase < 6 && radiusBase >= 2) {
33 | radiusXS = 1
34 | } else if (radiusBase >= 6) {
35 | radiusXS = 2
36 | }
37 |
38 | // radiusOuter
39 | if (radiusBase > 4 && radiusBase < 8) {
40 | radiusOuter = 4
41 | } else if (radiusBase >= 8) {
42 | radiusOuter = 6
43 | }
44 |
45 | return {
46 | borderRadius: radiusBase > 16 ? 16 : radiusBase,
47 | borderRadiusXS: radiusXS,
48 | borderRadiusSM: radiusSM,
49 | borderRadiusLG: radiusLG,
50 | borderRadiusOuter: radiusOuter
51 | }
52 | }
53 |
54 | export default genRadius
55 |
--------------------------------------------------------------------------------
/components/theme/themes/shared/genSizeMapToken.ts:
--------------------------------------------------------------------------------
1 | import type { SeedToken, SizeMapToken } from '../../interface'
2 |
3 | export default function genSizeMapToken(token: SeedToken): SizeMapToken {
4 | const { sizeUnit, sizeStep } = token
5 |
6 | return {
7 | sizeXXL: sizeUnit * (sizeStep + 8), // 48
8 | sizeXL: sizeUnit * (sizeStep + 4), // 32
9 | sizeLG: sizeUnit * (sizeStep + 2), // 24
10 | sizeMD: sizeUnit * (sizeStep + 1), // 20
11 | sizeMS: sizeUnit * sizeStep, // 16
12 | size: sizeUnit * sizeStep, // 16
13 | sizeSM: sizeUnit * (sizeStep - 1), // 12
14 | sizeXS: sizeUnit * (sizeStep - 2), // 8
15 | sizeXXS: sizeUnit * (sizeStep - 3) // 4
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/components/theme/util/alias.ts:
--------------------------------------------------------------------------------
1 | import { TinyColor } from '@ctrl/tinycolor'
2 | import type { AliasToken, MapToken, OverrideToken, SeedToken } from '../interface'
3 | import seedToken from '../themes/seed'
4 | import getAlphaColor from './getAlphaColor'
5 |
6 | /** Raw merge of `@antd-tiny-vue/cssinjs` token. Which need additional process */
7 | type RawMergedToken = MapToken & OverrideToken & { override: Partial }
8 |
9 | /**
10 | * Seed (designer) > Derivative (designer) > Alias (developer).
11 | *
12 | * Merge seed & derivative & override token and generate alias token for developer.
13 | */
14 | export default function formatToken(derivativeToken: RawMergedToken): AliasToken {
15 | const { override, ...restToken } = derivativeToken
16 | const overrideTokens = { ...override }
17 |
18 | Object.keys(seedToken).forEach(token => {
19 | delete overrideTokens[token as keyof SeedToken]
20 | })
21 |
22 | const mergedToken = {
23 | ...restToken,
24 | ...overrideTokens
25 | }
26 |
27 | const screenXS = 480
28 | const screenSM = 576
29 | const screenMD = 768
30 | const screenLG = 992
31 | const screenXL = 1200
32 | const screenXXL = 1600
33 |
34 | // Generate alias token
35 | const aliasToken: AliasToken = {
36 | ...mergedToken,
37 |
38 | colorLink: mergedToken.colorInfoText,
39 | colorLinkHover: mergedToken.colorInfoHover,
40 | colorLinkActive: mergedToken.colorInfoActive,
41 |
42 | // ============== Background ============== //
43 | colorFillContent: mergedToken.colorFillSecondary,
44 | colorFillContentHover: mergedToken.colorFill,
45 | colorFillAlter: mergedToken.colorFillQuaternary,
46 | colorBgContainerDisabled: mergedToken.colorFillTertiary,
47 |
48 | // ============== Split ============== //
49 | colorBorderBg: mergedToken.colorBgContainer,
50 | colorSplit: getAlphaColor(mergedToken.colorBorderSecondary, mergedToken.colorBgContainer),
51 |
52 | // ============== Text ============== //
53 | colorTextPlaceholder: mergedToken.colorTextQuaternary,
54 | colorTextDisabled: mergedToken.colorTextQuaternary,
55 | colorTextHeading: mergedToken.colorText,
56 | colorTextLabel: mergedToken.colorTextSecondary,
57 | colorTextDescription: mergedToken.colorTextTertiary,
58 | colorTextLightSolid: mergedToken.colorWhite,
59 | colorHighlight: mergedToken.colorError,
60 | colorBgTextHover: mergedToken.colorFillSecondary,
61 | colorBgTextActive: mergedToken.colorFill,
62 |
63 | colorIcon: mergedToken.colorTextTertiary,
64 | colorIconHover: mergedToken.colorText,
65 |
66 | colorErrorOutline: getAlphaColor(mergedToken.colorErrorBg, mergedToken.colorBgContainer),
67 | colorWarningOutline: getAlphaColor(mergedToken.colorWarningBg, mergedToken.colorBgContainer),
68 |
69 | // Font
70 | fontSizeIcon: mergedToken.fontSizeSM,
71 |
72 | // Control
73 | lineWidth: mergedToken.lineWidth,
74 | controlOutlineWidth: mergedToken.lineWidth * 2,
75 | // Checkbox size and expand icon size
76 | controlInteractiveSize: mergedToken.controlHeight / 2,
77 |
78 | controlItemBgHover: mergedToken.colorFillTertiary,
79 | controlItemBgActive: mergedToken.colorPrimaryBg,
80 | controlItemBgActiveHover: mergedToken.colorPrimaryBgHover,
81 | controlItemBgActiveDisabled: mergedToken.colorFill,
82 | controlTmpOutline: mergedToken.colorFillQuaternary,
83 | controlOutline: getAlphaColor(mergedToken.colorPrimaryBg, mergedToken.colorBgContainer),
84 |
85 | lineType: mergedToken.lineType,
86 | borderRadius: mergedToken.borderRadius,
87 | borderRadiusXS: mergedToken.borderRadiusXS,
88 | borderRadiusSM: mergedToken.borderRadiusSM,
89 | borderRadiusLG: mergedToken.borderRadiusLG,
90 |
91 | fontWeightStrong: 600,
92 |
93 | opacityLoading: 0.65,
94 |
95 | linkDecoration: 'none',
96 | linkHoverDecoration: 'none',
97 | linkFocusDecoration: 'none',
98 |
99 | controlPaddingHorizontal: 12,
100 | controlPaddingHorizontalSM: 8,
101 |
102 | paddingXXS: mergedToken.sizeXXS,
103 | paddingXS: mergedToken.sizeXS,
104 | paddingSM: mergedToken.sizeSM,
105 | padding: mergedToken.size,
106 | paddingMD: mergedToken.sizeMD,
107 | paddingLG: mergedToken.sizeLG,
108 | paddingXL: mergedToken.sizeXL,
109 |
110 | paddingContentHorizontalLG: mergedToken.sizeLG,
111 | paddingContentVerticalLG: mergedToken.sizeMS,
112 | paddingContentHorizontal: mergedToken.sizeMS,
113 | paddingContentVertical: mergedToken.sizeSM,
114 | paddingContentHorizontalSM: mergedToken.size,
115 | paddingContentVerticalSM: mergedToken.sizeXS,
116 |
117 | marginXXS: mergedToken.sizeXXS,
118 | marginXS: mergedToken.sizeXS,
119 | marginSM: mergedToken.sizeSM,
120 | margin: mergedToken.size,
121 | marginMD: mergedToken.sizeMD,
122 | marginLG: mergedToken.sizeLG,
123 | marginXL: mergedToken.sizeXL,
124 | marginXXL: mergedToken.sizeXXL,
125 |
126 | boxShadow: `
127 | 0 6px 16px 0 rgba(0, 0, 0, 0.08),
128 | 0 3px 6px -4px rgba(0, 0, 0, 0.12),
129 | 0 9px 28px 8px rgba(0, 0, 0, 0.05)
130 | `,
131 | boxShadowSecondary: `
132 | 0 6px 16px 0 rgba(0, 0, 0, 0.08),
133 | 0 3px 6px -4px rgba(0, 0, 0, 0.12),
134 | 0 9px 28px 8px rgba(0, 0, 0, 0.05)
135 | `,
136 | boxShadowTertiary: `
137 | 0 1px 2px 0 rgba(0, 0, 0, 0.03),
138 | 0 1px 6px -1px rgba(0, 0, 0, 0.02),
139 | 0 2px 4px 0 rgba(0, 0, 0, 0.02)
140 | `,
141 |
142 | screenXS,
143 | screenXSMin: screenXS,
144 | screenXSMax: screenSM - 1,
145 | screenSM,
146 | screenSMMin: screenSM,
147 | screenSMMax: screenMD - 1,
148 | screenMD,
149 | screenMDMin: screenMD,
150 | screenMDMax: screenLG - 1,
151 | screenLG,
152 | screenLGMin: screenLG,
153 | screenLGMax: screenXL - 1,
154 | screenXL,
155 | screenXLMin: screenXL,
156 | screenXLMax: screenXXL - 1,
157 | screenXXL,
158 | screenXXLMin: screenXXL,
159 |
160 | boxShadowPopoverArrow: '2px 2px 5px rgba(0, 0, 0, 0.05)',
161 | boxShadowCard: `
162 | 0 1px 2px -2px ${new TinyColor('rgba(0, 0, 0, 0.16)').toRgbString()},
163 | 0 3px 6px 0 ${new TinyColor('rgba(0, 0, 0, 0.12)').toRgbString()},
164 | 0 5px 12px 4px ${new TinyColor('rgba(0, 0, 0, 0.09)').toRgbString()}
165 | `,
166 | boxShadowDrawerRight: `
167 | -6px 0 16px 0 rgba(0, 0, 0, 0.08),
168 | -3px 0 6px -4px rgba(0, 0, 0, 0.12),
169 | -9px 0 28px 8px rgba(0, 0, 0, 0.05)
170 | `,
171 | boxShadowDrawerLeft: `
172 | 6px 0 16px 0 rgba(0, 0, 0, 0.08),
173 | 3px 0 6px -4px rgba(0, 0, 0, 0.12),
174 | 9px 0 28px 8px rgba(0, 0, 0, 0.05)
175 | `,
176 | boxShadowDrawerUp: `
177 | 0 6px 16px 0 rgba(0, 0, 0, 0.08),
178 | 0 3px 6px -4px rgba(0, 0, 0, 0.12),
179 | 0 9px 28px 8px rgba(0, 0, 0, 0.05)
180 | `,
181 | boxShadowDrawerDown: `
182 | 0 -6px 16px 0 rgba(0, 0, 0, 0.08),
183 | 0 -3px 6px -4px rgba(0, 0, 0, 0.12),
184 | 0 -9px 28px 8px rgba(0, 0, 0, 0.05)
185 | `,
186 | boxShadowTabsOverflowLeft: 'inset 10px 0 8px -8px rgba(0, 0, 0, 0.08)',
187 | boxShadowTabsOverflowRight: 'inset -10px 0 8px -8px rgba(0, 0, 0, 0.08)',
188 | boxShadowTabsOverflowTop: 'inset 0 10px 8px -8px rgba(0, 0, 0, 0.08)',
189 | boxShadowTabsOverflowBottom: 'inset 0 -10px 8px -8px rgba(0, 0, 0, 0.08)',
190 |
191 | // Override AliasToken
192 | ...overrideTokens
193 | }
194 |
195 | return aliasToken
196 | }
197 |
--------------------------------------------------------------------------------
/components/theme/util/genComponentStyleHook.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-redeclare */
2 | import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
3 | import { useStyleRegister } from '@antd-tiny-vue/cssinjs'
4 | import type { Ref } from 'vue'
5 | import { computed } from 'vue'
6 | import { genCommonStyle, genLinkStyle } from '../../style'
7 | import { useProviderConfigState } from '../../config-provider/context'
8 | import type { UseComponentStyleResult } from '../internal'
9 | import { mergeToken, statisticToken, useToken } from '../internal'
10 | import type { ComponentTokenMap, GlobalToken } from '../interface'
11 |
12 | export type OverrideTokenWithoutDerivative = ComponentTokenMap
13 | export type OverrideComponent = keyof OverrideTokenWithoutDerivative
14 | export type GlobalTokenWithComponent = GlobalToken & ComponentTokenMap[ComponentName]
15 |
16 | export interface StyleInfo {
17 | hashId: string
18 | prefixCls: string
19 | rootPrefixCls: string
20 | iconPrefixCls: string
21 | overrideComponentToken: ComponentTokenMap[ComponentName]
22 | }
23 |
24 | export type TokenWithCommonCls = T & {
25 | /** Wrap component class with `.` prefix */
26 | componentCls: string
27 | /** Origin prefix which do not have `.` prefix */
28 | prefixCls: string
29 | /** Wrap icon class with `.` prefix */
30 | iconCls: string
31 | /** Wrap ant prefixCls class with `.` prefix */
32 | antCls: string
33 | }
34 | export type FullToken = TokenWithCommonCls>
35 |
36 | export default function genComponentStyleHook(
37 | component: ComponentName,
38 | styleFn: (token: FullToken, info: StyleInfo) => CSSInterpolation,
39 | getDefaultToken?: OverrideTokenWithoutDerivative[ComponentName] | ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName])
40 | ) {
41 | return (prefixCls: Ref): UseComponentStyleResult => {
42 | const [theme, token, hashId] = useToken()
43 | const { getPrefixCls, iconPrefixCls } = useProviderConfigState()
44 | const rootPrefixCls = computed(() => getPrefixCls())
45 | const sharedInfo = computed(() => {
46 | return {
47 | theme: theme.value,
48 | token: token.value,
49 | hashId: hashId.value,
50 | path: ['Shared', rootPrefixCls.value]
51 | }
52 | })
53 | // Generate style for all a tags in antd component.
54 | useStyleRegister(sharedInfo, () => [
55 | {
56 | // Link
57 | '&': genLinkStyle(token.value)
58 | }
59 | ])
60 | const componentInfo = computed(() => ({
61 | theme: theme.value,
62 | token: token.value,
63 | hashId: hashId.value,
64 | path: [component, prefixCls.value, iconPrefixCls.value]
65 | }))
66 | return [
67 | useStyleRegister(componentInfo, () => {
68 | const { token: proxyToken, flush } = statisticToken(token.value)
69 |
70 | const defaultComponentToken = typeof getDefaultToken === 'function' ? getDefaultToken(proxyToken) : getDefaultToken
71 | const mergedComponentToken = { ...defaultComponentToken, ...token.value[component] }
72 |
73 | const componentCls = `.${prefixCls.value}`
74 | const mergedToken = mergeToken>>(
75 | proxyToken,
76 | {
77 | componentCls,
78 | prefixCls: prefixCls.value,
79 | iconCls: `.${iconPrefixCls.value}`,
80 | antCls: `.${rootPrefixCls.value}`
81 | },
82 | mergedComponentToken
83 | )
84 |
85 | const styleInterpolation = styleFn(mergedToken as unknown as FullToken, {
86 | hashId: hashId.value,
87 | prefixCls: prefixCls.value,
88 | rootPrefixCls: rootPrefixCls.value,
89 | iconPrefixCls: iconPrefixCls.value,
90 | overrideComponentToken: token.value[component]
91 | })
92 | flush(component, mergedComponentToken)
93 | return [genCommonStyle(token.value, prefixCls.value), styleInterpolation]
94 | }),
95 | hashId
96 | ]
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/components/theme/util/getAlphaColor.ts:
--------------------------------------------------------------------------------
1 | import { TinyColor } from '@ctrl/tinycolor'
2 |
3 | function isStableColor(color: number): boolean {
4 | return color >= 0 && color <= 255
5 | }
6 |
7 | function getAlphaColor(frontColor: string, backgroundColor: string): string {
8 | const { r: fR, g: fG, b: fB, a: originAlpha } = new TinyColor(frontColor).toRgb()
9 | if (originAlpha < 1) {
10 | return frontColor
11 | }
12 |
13 | const { r: bR, g: bG, b: bB } = new TinyColor(backgroundColor).toRgb()
14 |
15 | for (let fA = 0.01; fA <= 1; fA += 0.01) {
16 | const r = Math.round((fR - bR * (1 - fA)) / fA)
17 | const g = Math.round((fG - bG * (1 - fA)) / fA)
18 | const b = Math.round((fB - bB * (1 - fA)) / fA)
19 | if (isStableColor(r) && isStableColor(g) && isStableColor(b)) {
20 | return new TinyColor({ r, g, b, a: Math.round(fA * 100) / 100 }).toRgbString()
21 | }
22 | }
23 |
24 | // fallback
25 | /* istanbul ignore next */
26 | return new TinyColor({ r: fR, g: fG, b: fB, a: 1 }).toRgbString()
27 | }
28 |
29 | export default getAlphaColor
30 |
--------------------------------------------------------------------------------
/components/theme/util/statistic.ts:
--------------------------------------------------------------------------------
1 | declare const CSSINJS_STATISTIC: any
2 |
3 | const enableStatistic = process.env.NODE_ENV !== 'production' || typeof CSSINJS_STATISTIC !== 'undefined'
4 | let recording = true
5 |
6 | /**
7 | * This function will do as `Object.assign` in production. But will use Object.defineProperty:get to
8 | * pass all value access in development. To support statistic field usage with alias token.
9 | */
10 | export function merge(...objs: Partial[]): T {
11 | /* istanbul ignore next */
12 | if (!enableStatistic) {
13 | return Object.assign({}, ...objs)
14 | }
15 |
16 | recording = false
17 |
18 | const ret = {} as T
19 |
20 | objs.forEach(obj => {
21 | const keys = Object.keys(obj)
22 |
23 | keys.forEach(key => {
24 | Object.defineProperty(ret, key, {
25 | configurable: true,
26 | enumerable: true,
27 | get: () => (obj as any)[key]
28 | })
29 | })
30 | })
31 |
32 | recording = true
33 | return ret
34 | }
35 |
36 | /** @private Internal Usage. Not use in your production. */
37 | export const statistic: Record }> = {}
38 |
39 | /** @private Internal Usage. Not use in your production. */
40 | // eslint-disable-next-line camelcase
41 | export const _statistic_build_: typeof statistic = {}
42 |
43 | /* istanbul ignore next */
44 | function noop() {}
45 |
46 | /** Statistic token usage case. Should use `merge` function if you do not want spread record. */
47 | export default function statisticToken(token: T) {
48 | let tokenKeys: Set | undefined
49 | let proxy = token
50 | let flush: (componentName: string, componentToken: Record) => void = noop
51 |
52 | if (enableStatistic) {
53 | tokenKeys = new Set()
54 |
55 | proxy = new Proxy(token, {
56 | get(obj: any, prop: any) {
57 | if (recording) {
58 | tokenKeys!.add(prop)
59 | }
60 | return obj[prop]
61 | }
62 | })
63 |
64 | flush = (componentName, componentToken) => {
65 | statistic[componentName] = { global: Array.from(tokenKeys!), component: componentToken }
66 | }
67 | }
68 |
69 | return { token: proxy, keys: tokenKeys, flush }
70 | }
71 |
--------------------------------------------------------------------------------
/components/version.ts:
--------------------------------------------------------------------------------
1 | export default '0.0.1'
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "antd-tiny-vue",
3 | "version": "1.0.0",
4 | "packageManager": "pnpm@8.2.0",
5 | "description": "this is a tiny antd components for vue3",
6 | "keywords": [
7 | "antd",
8 | "ant-design-vue",
9 | "ant-design",
10 | "vue3",
11 | "vue3-components",
12 | "components"
13 | ],
14 | "license": "MIT",
15 | "author": "aibayanyu",
16 | "main": "lib/index.js",
17 | "module": "es/index.js",
18 | "types": "lib/index.d.ts",
19 | "files": [
20 | "lib",
21 | "es",
22 | "dist",
23 | "README.md"
24 | ],
25 | "scripts": {
26 | "test": "vitest",
27 | "prepare": "husky install",
28 | "dev": "vitepress dev",
29 | "build:site": "vitepress build",
30 | "build:lib": "vite build --config vite.build.config.ts",
31 | "build:umd": "vite build --config vite.bundle.config.ts",
32 | "copy:css": "cpx \"components/style/*.css\" dist",
33 | "preview": "vitepress preview"
34 | },
35 | "dependencies": {
36 | "@ant-design/colors": "^7.0.0",
37 | "@ant-design/icons-vue": "^6.1.0",
38 | "@antd-tiny-vue/cssinjs": "0.0.8",
39 | "@ctrl/tinycolor": "^3.6.0",
40 | "@v-c/utils": "^0.0.22",
41 | "@vueuse/core": "^9.13.0",
42 | "vue": "^3.3.0-beta.2"
43 | },
44 | "devDependencies": {
45 | "@commitlint/cli": "^17.5.0",
46 | "@commitlint/config-conventional": "^17.4.4",
47 | "@mistjs/eslint-config-vue-jsx": "^0.0.7",
48 | "@mistjs/tsconfig": "^1.1.1",
49 | "@mistjs/tsconfig-vue": "^1.1.2",
50 | "@types/node": "^18.15.10",
51 | "@vitejs/plugin-vue-jsx": "^3.0.1",
52 | "cpx": "^1.5.0",
53 | "eslint": "^8.36.0",
54 | "husky": "^8.0.3",
55 | "lint-staged": "^13.2.0",
56 | "prettier": "^2.8.7",
57 | "typescript": "^5.0.4",
58 | "unbuild": "^1.1.2",
59 | "vite": "^4.3.3",
60 | "vite-plugin-dts": "^2.3.0",
61 | "vite-plugin-vitepress-demo": "2.0.0-beta.29",
62 | "vitepress": "1.0.0-alpha.74",
63 | "vitest": "^0.28.5"
64 | },
65 | "pnpm": {
66 | "peerDependencyRules": {
67 | "ignoreMissing": [
68 | "@algolia/client-search"
69 | ]
70 | },
71 | "overrides": {
72 | "vue": "3.3.0-beta.2"
73 | }
74 | },
75 | "lint-staged": {
76 | "*.{js,jsx,ts,tsx,vue}": "eslint --fix"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/site/components/index.md:
--------------------------------------------------------------------------------
1 | # Components
2 |
--------------------------------------------------------------------------------
/site/components/index.zh-CN.md:
--------------------------------------------------------------------------------
1 | # 组件
2 |
--------------------------------------------------------------------------------
/site/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: Antd Tiny Vue
5 | titleTemplate: Vite & Vue Powered Static Site Generator
6 |
7 | hero:
8 | name: Antd Tiny Vue
9 | text: Vite & Vue Powered Static Site Generator
10 | tagline: Simple, powerful, and performant. Meet the modern SSG framework you've always wanted.
11 | actions:
12 | - theme: brand
13 | text: Components
14 | link: /components/
15 | - theme: alt
16 | text: View on GitHub
17 | link: https://github.com/antd-tiny-vue/antd-tiny-vue
18 |
19 | features:
20 | - title: "Vite: The DX that can't be beat"
21 | details: Feel the speed of Vite. Instant server start and lightning fast HMR that stays fast regardless of the app size.
22 | - title: Designed to be simplicity first
23 | details: With Markdown-centered content, it's built to help you focus on writing and deployed with minimum configuration.
24 | - title: Power of Vue meets Markdown
25 | details: Enhance your content with all the features of Vue in Markdown, while being able to customize your site with Vue.
26 | - title: Fully static yet still dynamic
27 | details: Go wild with true SSG + SPA architecture. Static on page load, but engage users with 100% interactivity from there.
28 | ---
29 |
--------------------------------------------------------------------------------
/site/index.zh-CN.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | title: Antd Tiny Vue
5 | titleTemplate: Vite & Vue Powered Static Site Generator
6 |
7 | hero:
8 | name: Antd Tiny Vue
9 | text: Vite & Vue Powered Static Site Generator
10 | tagline: Simple, powerful, and performant. Meet the modern SSG framework you've always wanted.
11 | actions:
12 | - theme: brand
13 | text: 组件
14 | link: /zh-CN/components/
15 | - theme: alt
16 | text: View on GitHub
17 | link: https://github.com/antd-tiny-vue/antd-tiny-vue
18 |
19 | features:
20 | - title: "Vite: The DX that can't be beat"
21 | details: Feel the speed of Vite. Instant server start and lightning fast HMR that stays fast regardless of the app size.
22 | - title: Designed to be simplicity first
23 | details: With Markdown-centered content, it's built to help you focus on writing and deployed with minimum configuration.
24 | - title: Power of Vue meets Markdown
25 | details: Enhance your content with all the features of Vue in Markdown, while being able to customize your site with Vue.
26 | - title: Fully static yet still dynamic
27 | details: Go wild with true SSG + SPA architecture. Static on page load, but engage users with 100% interactivity from there.
28 | ---
29 |
--------------------------------------------------------------------------------
/tests/demo.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest'
2 |
3 | describe('demo', () => {
4 | it('should pass', () => {
5 | expect(1).toBe(1)
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@mistjs/tsconfig-vue",
3 | "compilerOptions": {
4 | "moduleResolution": "bundler"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/vite.build.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vueJsx from '@vitejs/plugin-vue-jsx'
3 | import dts from 'vite-plugin-dts'
4 | export default defineConfig({
5 | plugins: [
6 | vueJsx(),
7 | dts({
8 | outputDir: ['es', 'lib'],
9 | include: ['components/**/*.ts', 'components/**/*.tsx']
10 | })
11 | ],
12 | build: {
13 | minify: false,
14 | rollupOptions: {
15 | external: [
16 | '@ant-design/colors',
17 | /^@ant-design\/icons-vue/,
18 | '@antd-tiny-vue/cssinjs',
19 | '@ctrl/tinycolor',
20 | '@v-c/utils',
21 | '@vueuse/core',
22 | 'vue'
23 | ],
24 | output: [
25 | {
26 | format: 'es',
27 | dir: 'es',
28 | entryFileNames: '[name].js',
29 | preserveModules: true,
30 | preserveModulesRoot: 'components'
31 | },
32 | {
33 | format: 'cjs',
34 | dir: 'lib',
35 | entryFileNames: '[name].js',
36 | preserveModules: true,
37 | preserveModulesRoot: 'components',
38 | exports: 'named'
39 | }
40 | ]
41 | },
42 | lib: {
43 | entry: 'components/index.ts',
44 | formats: ['es', 'cjs']
45 | }
46 | }
47 | })
48 |
--------------------------------------------------------------------------------
/vite.bundle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vueJsx from '@vitejs/plugin-vue-jsx'
3 | export default defineConfig({
4 | plugins: [vueJsx()],
5 | build: {
6 | lib: {
7 | entry: 'components/index.ts',
8 | name: 'Antd',
9 | fileName: () => `antd.js`,
10 | formats: ['umd']
11 | }
12 | }
13 | })
14 |
--------------------------------------------------------------------------------