feat: add ant-design theme

This commit is contained in:
aibayanyu 2023-03-06 07:30:21 +08:00
commit 74bb3d43c2
52 changed files with 3805 additions and 5 deletions

View File

@ -0,0 +1,28 @@
import { createInjectionState } from '@vueuse/core'
import { computed } from 'vue'
export const defaultIconPrefixCls = 'anticon'
const defaultGetPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls
return suffixCls ? `ant-${suffixCls}` : 'ant'
}
const [useProviderConfigProvide, useProviderConfigInject] = createInjectionState(() => {
const getPrefixCls = defaultGetPrefixCls
const iconPrefixCls = computed(() => defaultIconPrefixCls)
return {
getPrefixCls,
iconPrefixCls
}
})
export { useProviderConfigProvide }
export const useProviderConfigState = () => {
return (
useProviderConfigInject() ?? {
getPrefixCls: defaultGetPrefixCls,
iconPrefixCls: computed(() => defaultIconPrefixCls)
}
)
}

View File

@ -0,0 +1,56 @@
/* eslint-disable import/prefer-default-export */
import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
import type { DerivativeToken, FullToken } from '../theme/internal'
import type { OverrideComponent } from '../theme/util/genComponentStyleHook'
function compactItemVerticalBorder(token: DerivativeToken, parentCls: string): CSSObject {
return {
// border collapse
[`&-item:not(${parentCls}-last-item)`]: {
marginBottom: -token.lineWidth
},
'&-item': {
'&:hover,&:focus,&:active': {
zIndex: 2
},
'&[disabled]': {
zIndex: 0
}
}
}
}
function compactItemBorderVerticalRadius(prefixCls: string, parentCls: string): CSSObject {
return {
[`&-item:not(${parentCls}-first-item):not(${parentCls}-last-item)`]: {
borderRadius: 0
},
[`&-item${parentCls}-first-item:not(${parentCls}-last-item)`]: {
[`&, &${prefixCls}-sm, &${prefixCls}-lg`]: {
borderEndEndRadius: 0,
borderEndStartRadius: 0
}
},
[`&-item${parentCls}-last-item:not(${parentCls}-first-item)`]: {
[`&, &${prefixCls}-sm, &${prefixCls}-lg`]: {
borderStartStartRadius: 0,
borderStartEndRadius: 0
}
}
}
}
export function genCompactItemVerticalStyle<T extends OverrideComponent>(token: FullToken<T>): CSSInterpolation {
const compactCls = `${token.componentCls}-compact-vertical`
return {
[compactCls]: {
...compactItemVerticalBorder(token, compactCls),
...compactItemBorderVerticalRadius(token.componentCls, compactCls)
}
}
}

View File

@ -0,0 +1,90 @@
/* eslint-disable import/prefer-default-export */
import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
import type { DerivativeToken, FullToken } from '../theme/internal'
import type { OverrideComponent } from '../theme/util/genComponentStyleHook'
interface CompactItemOptions {
focus?: boolean
/**
* Some component borders are implemented on child elements
* like `Select`
*/
borderElCls?: string
/**
* Some components have special `focus` className especially with popovers
* like `Select` and `DatePicker`
*/
focusElCls?: string
}
// handle border collapse
function compactItemBorder(token: DerivativeToken, parentCls: string, options: CompactItemOptions): CSSObject {
const { focusElCls, focus, borderElCls } = options
const childCombinator = borderElCls ? '> *' : ''
const hoverEffects = ['hover', focus ? 'focus' : null, 'active']
.filter(Boolean)
.map(n => `&:${n} ${childCombinator}`)
.join(',')
return {
[`&-item:not(${parentCls}-last-item)`]: {
marginInlineEnd: -token.lineWidth
},
'&-item': {
[hoverEffects]: {
zIndex: 2
},
...(focusElCls
? {
[`&${focusElCls}`]: {
zIndex: 2
}
}
: {}),
[`&[disabled] ${childCombinator}`]: {
zIndex: 0
}
}
}
}
// handle border-radius
function compactItemBorderRadius(prefixCls: string, parentCls: string, options: CompactItemOptions): CSSObject {
const { borderElCls } = options
const childCombinator = borderElCls ? `> ${borderElCls}` : ''
return {
[`&-item:not(${parentCls}-first-item):not(${parentCls}-last-item) ${childCombinator}`]: {
borderRadius: 0
},
[`&-item:not(${parentCls}-last-item)${parentCls}-first-item`]: {
[`& ${childCombinator}, &${prefixCls}-sm ${childCombinator}, &${prefixCls}-lg ${childCombinator}`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0
}
},
[`&-item:not(${parentCls}-first-item)${parentCls}-last-item`]: {
[`& ${childCombinator}, &${prefixCls}-sm ${childCombinator}, &${prefixCls}-lg ${childCombinator}`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0
}
}
}
}
export function genCompactItemStyle<T extends OverrideComponent>(token: FullToken<T>, options: CompactItemOptions = { focus: true }): CSSInterpolation {
const { componentCls } = token
const compactCls = `${componentCls}-compact`
return {
[compactCls]: {
...compactItemBorder(token, compactCls, options),
...compactItemBorderRadius(componentCls, compactCls, options)
}
}
}

139
components/style/index.ts Normal file
View File

@ -0,0 +1,139 @@
/* eslint-disable import/prefer-default-export */
import type { CSSObject } from '@antd-tiny-vue/cssinjs'
import type { DerivativeToken } from '../theme/internal'
export { operationUnit } from './operationUnit'
export { roundedArrow } from './roundedArrow'
export { genPresetColor } from './presetColor'
export const textEllipsis: CSSObject = {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
}
export const resetComponent = (token: DerivativeToken): CSSObject => ({
boxSizing: 'border-box',
margin: 0,
padding: 0,
color: token.colorText,
fontSize: token.fontSize,
// font-variant: @font-variant-base;
lineHeight: token.lineHeight,
listStyle: 'none',
// font-feature-settings: @font-feature-settings-base;
fontFamily: token.fontFamily
})
export const resetIcon = (): CSSObject => ({
display: 'inline-flex',
alignItems: 'center',
color: 'inherit',
fontStyle: 'normal',
lineHeight: 0,
textAlign: 'center',
textTransform: 'none',
// for SVG icon, see https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
verticalAlign: '-0.125em',
textRendering: 'optimizeLegibility',
'-webkit-font-smoothing': 'antialiased',
'-moz-osx-font-smoothing': 'grayscale',
'> *': {
lineHeight: 1
},
svg: {
display: 'inline-block'
}
})
export const clearFix = (): CSSObject => ({
// https://github.com/ant-design/ant-design/issues/21301#issuecomment-583955229
'&::before': {
display: 'table',
content: '""'
},
'&::after': {
// https://github.com/ant-design/ant-design/issues/21864
display: 'table',
clear: 'both',
content: '""'
}
})
export const genLinkStyle = (token: DerivativeToken): CSSObject => ({
a: {
color: token.colorLink,
textDecoration: token.linkDecoration,
backgroundColor: 'transparent', // remove the gray background on active links in IE 10.
outline: 'none',
cursor: 'pointer',
transition: `color ${token.motionDurationSlow}`,
'-webkit-text-decoration-skip': 'objects', // remove gaps in links underline in iOS 8+ and Safari 8+.
'&:hover': {
color: token.colorLinkHover
},
'&:active': {
color: token.colorLinkActive
},
[`&:active,
&:hover`]: {
textDecoration: token.linkHoverDecoration,
outline: 0
},
// https://github.com/ant-design/ant-design/issues/22503
'&:focus': {
textDecoration: token.linkFocusDecoration,
outline: 0
},
'&[disabled]': {
color: token.colorTextDisabled,
cursor: 'not-allowed'
}
}
})
export const genCommonStyle = (token: DerivativeToken, componentPrefixCls: string): CSSObject => {
const { fontFamily, fontSize } = token
const rootPrefixSelector = `[class^="${componentPrefixCls}"], [class*=" ${componentPrefixCls}"]`
return {
[rootPrefixSelector]: {
fontFamily,
fontSize,
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box'
},
[rootPrefixSelector]: {
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box'
}
}
}
}
}
export const genFocusOutline = (token: DerivativeToken): CSSObject => ({
outline: `${token.lineWidth * 4}px solid ${token.colorPrimaryBorder}`,
outlineOffset: 1,
transition: 'outline-offset 0s, outline 0s'
})
export const genFocusStyle = (token: DerivativeToken): CSSObject => ({
'&:focus-visible': {
...genFocusOutline(token)
}
})

View File

@ -0,0 +1,24 @@
import type { AliasToken, GenerateStyle } from '../../theme/internal'
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
const genCollapseMotion: GenerateStyle<TokenWithCommonCls<AliasToken>> = token => ({
[token.componentCls]: {
// For common/openAnimation
[`${token.antCls}-motion-collapse-legacy`]: {
overflow: 'hidden',
'&-active': {
transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`
}
},
[`${token.antCls}-motion-collapse`]: {
overflow: 'hidden',
transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`
}
}
})
export default genCollapseMotion

View File

@ -0,0 +1,46 @@
import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
import { Keyframes } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../../theme/internal'
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
import { initMotion } from './motion'
export const fadeIn = new Keyframes('antFadeIn', {
'0%': {
opacity: 0
},
'100%': {
opacity: 1
}
})
export const fadeOut = new Keyframes('antFadeOut', {
'0%': {
opacity: 1
},
'100%': {
opacity: 0
}
})
export const initFadeMotion = (token: TokenWithCommonCls<AliasToken>, sameLevel = false): CSSInterpolation => {
const { antCls } = token
const motionCls = `${antCls}-fade`
const sameLevelPrefix = sameLevel ? '&' : ''
return [
initMotion(motionCls, fadeIn, fadeOut, token.motionDurationMid, sameLevel),
{
[`
${sameLevelPrefix}${motionCls}-enter,
${sameLevelPrefix}${motionCls}-appear
`]: {
opacity: 0,
animationTimingFunction: 'linear'
},
[`${sameLevelPrefix}${motionCls}-leave`]: {
animationTimingFunction: 'linear'
}
}
]
}

View File

@ -0,0 +1,44 @@
import { fadeIn, fadeOut, initFadeMotion } from './fade'
import { initMoveMotion, moveDownIn, moveDownOut, moveLeftIn, moveLeftOut, moveRightIn, moveRightOut, moveUpIn, moveUpOut } from './move'
import { initSlideMotion, slideDownIn, slideDownOut, slideLeftIn, slideLeftOut, slideRightIn, slideRightOut, slideUpIn, slideUpOut } from './slide'
import { initZoomMotion, zoomBigIn, zoomBigOut, zoomDownIn, zoomDownOut, zoomIn, zoomLeftIn, zoomLeftOut, zoomOut, zoomRightIn, zoomRightOut, zoomUpIn, zoomUpOut } from './zoom'
import genCollapseMotion from './collapse'
export {
initSlideMotion,
slideUpIn,
slideUpOut,
slideDownIn,
slideDownOut,
slideLeftIn,
slideLeftOut,
slideRightIn,
slideRightOut,
zoomOut,
zoomIn,
zoomBigIn,
zoomLeftOut,
zoomBigOut,
zoomLeftIn,
zoomRightIn,
zoomUpIn,
zoomRightOut,
zoomUpOut,
zoomDownIn,
zoomDownOut,
initZoomMotion,
fadeIn,
fadeOut,
initFadeMotion,
moveRightOut,
moveRightIn,
moveLeftOut,
moveLeftIn,
moveDownOut,
moveDownIn,
moveUpIn,
moveUpOut,
initMoveMotion,
genCollapseMotion
}

View File

@ -0,0 +1,46 @@
/* eslint-disable import/prefer-default-export */
import type { CSSObject, Keyframes } from '@antd-tiny-vue/cssinjs'
const initMotionCommon = (duration: string): CSSObject => ({
animationDuration: duration,
animationFillMode: 'both'
})
// FIXME: origin less code seems same as initMotionCommon. Maybe we can safe remove
const initMotionCommonLeave = (duration: string): CSSObject => ({
animationDuration: duration,
animationFillMode: 'both'
})
export const initMotion = (motionCls: string, inKeyframes: Keyframes, outKeyframes: Keyframes, duration: string, sameLevel = false): CSSObject => {
const sameLevelPrefix = sameLevel ? '&' : ''
return {
[`
${sameLevelPrefix}${motionCls}-enter,
${sameLevelPrefix}${motionCls}-appear
`]: {
...initMotionCommon(duration),
animationPlayState: 'paused'
},
[`${sameLevelPrefix}${motionCls}-leave`]: {
...initMotionCommonLeave(duration),
animationPlayState: 'paused'
},
[`
${sameLevelPrefix}${motionCls}-enter${motionCls}-enter-active,
${sameLevelPrefix}${motionCls}-appear${motionCls}-appear-active
`]: {
animationName: inKeyframes,
animationPlayState: 'running'
},
[`${sameLevelPrefix}${motionCls}-leave${motionCls}-leave-active`]: {
animationName: outKeyframes,
animationPlayState: 'running',
pointerEvents: 'none'
}
}
}

View File

@ -0,0 +1,160 @@
import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
import { Keyframes } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../../theme/internal'
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
import { initMotion } from './motion'
export const moveDownIn = new Keyframes('antMoveDownIn', {
'0%': {
transform: 'translate3d(0, 100%, 0)',
transformOrigin: '0 0',
opacity: 0
},
'100%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
}
})
export const moveDownOut = new Keyframes('antMoveDownOut', {
'0%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
},
'100%': {
transform: 'translate3d(0, 100%, 0)',
transformOrigin: '0 0',
opacity: 0
}
})
export const moveLeftIn = new Keyframes('antMoveLeftIn', {
'0%': {
transform: 'translate3d(-100%, 0, 0)',
transformOrigin: '0 0',
opacity: 0
},
'100%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
}
})
export const moveLeftOut = new Keyframes('antMoveLeftOut', {
'0%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
},
'100%': {
transform: 'translate3d(-100%, 0, 0)',
transformOrigin: '0 0',
opacity: 0
}
})
export const moveRightIn = new Keyframes('antMoveRightIn', {
'0%': {
transform: 'translate3d(100%, 0, 0)',
transformOrigin: '0 0',
opacity: 0
},
'100%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
}
})
export const moveRightOut = new Keyframes('antMoveRightOut', {
'0%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
},
'100%': {
transform: 'translate3d(100%, 0, 0)',
transformOrigin: '0 0',
opacity: 0
}
})
export const moveUpIn = new Keyframes('antMoveUpIn', {
'0%': {
transform: 'translate3d(0, -100%, 0)',
transformOrigin: '0 0',
opacity: 0
},
'100%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
}
})
export const moveUpOut = new Keyframes('antMoveUpOut', {
'0%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1
},
'100%': {
transform: 'translate3d(0, -100%, 0)',
transformOrigin: '0 0',
opacity: 0
}
})
type MoveMotionTypes = 'move-up' | 'move-down' | 'move-left' | 'move-right'
const moveMotion: Record<MoveMotionTypes, { inKeyframes: Keyframes; outKeyframes: Keyframes }> = {
'move-up': {
inKeyframes: moveUpIn,
outKeyframes: moveUpOut
},
'move-down': {
inKeyframes: moveDownIn,
outKeyframes: moveDownOut
},
'move-left': {
inKeyframes: moveLeftIn,
outKeyframes: moveLeftOut
},
'move-right': {
inKeyframes: moveRightIn,
outKeyframes: moveRightOut
}
}
export const initMoveMotion = (token: TokenWithCommonCls<AliasToken>, motionName: MoveMotionTypes): CSSInterpolation => {
const { antCls } = token
const motionCls = `${antCls}-${motionName}`
const { inKeyframes, outKeyframes } = moveMotion[motionName]
return [
initMotion(motionCls, inKeyframes, outKeyframes, token.motionDurationMid),
{
[`
${motionCls}-enter,
${motionCls}-appear
`]: {
opacity: 0,
animationTimingFunction: token.motionEaseOutCirc
},
[`${motionCls}-leave`]: {
animationTimingFunction: token.motionEaseInOutCirc
}
}
]
}

View File

@ -0,0 +1,163 @@
import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
import { Keyframes } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../../theme/internal'
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
import { initMotion } from './motion'
export const slideUpIn = new Keyframes('antSlideUpIn', {
'0%': {
transform: 'scaleY(0.8)',
transformOrigin: '0% 0%',
opacity: 0
},
'100%': {
transform: 'scaleY(1)',
transformOrigin: '0% 0%',
opacity: 1
}
})
export const slideUpOut = new Keyframes('antSlideUpOut', {
'0%': {
transform: 'scaleY(1)',
transformOrigin: '0% 0%',
opacity: 1
},
'100%': {
transform: 'scaleY(0.8)',
transformOrigin: '0% 0%',
opacity: 0
}
})
export const slideDownIn = new Keyframes('antSlideDownIn', {
'0%': {
transform: 'scaleY(0.8)',
transformOrigin: '100% 100%',
opacity: 0
},
'100%': {
transform: 'scaleY(1)',
transformOrigin: '100% 100%',
opacity: 1
}
})
export const slideDownOut = new Keyframes('antSlideDownOut', {
'0%': {
transform: 'scaleY(1)',
transformOrigin: '100% 100%',
opacity: 1
},
'100%': {
transform: 'scaleY(0.8)',
transformOrigin: '100% 100%',
opacity: 0
}
})
export const slideLeftIn = new Keyframes('antSlideLeftIn', {
'0%': {
transform: 'scaleX(0.8)',
transformOrigin: '0% 0%',
opacity: 0
},
'100%': {
transform: 'scaleX(1)',
transformOrigin: '0% 0%',
opacity: 1
}
})
export const slideLeftOut = new Keyframes('antSlideLeftOut', {
'0%': {
transform: 'scaleX(1)',
transformOrigin: '0% 0%',
opacity: 1
},
'100%': {
transform: 'scaleX(0.8)',
transformOrigin: '0% 0%',
opacity: 0
}
})
export const slideRightIn = new Keyframes('antSlideRightIn', {
'0%': {
transform: 'scaleX(0.8)',
transformOrigin: '100% 0%',
opacity: 0
},
'100%': {
transform: 'scaleX(1)',
transformOrigin: '100% 0%',
opacity: 1
}
})
export const slideRightOut = new Keyframes('antSlideRightOut', {
'0%': {
transform: 'scaleX(1)',
transformOrigin: '100% 0%',
opacity: 1
},
'100%': {
transform: 'scaleX(0.8)',
transformOrigin: '100% 0%',
opacity: 0
}
})
type SlideMotionTypes = 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right'
const slideMotion: Record<SlideMotionTypes, { inKeyframes: Keyframes; outKeyframes: Keyframes }> = {
'slide-up': {
inKeyframes: slideUpIn,
outKeyframes: slideUpOut
},
'slide-down': {
inKeyframes: slideDownIn,
outKeyframes: slideDownOut
},
'slide-left': {
inKeyframes: slideLeftIn,
outKeyframes: slideLeftOut
},
'slide-right': {
inKeyframes: slideRightIn,
outKeyframes: slideRightOut
}
}
export const initSlideMotion = (token: TokenWithCommonCls<AliasToken>, motionName: SlideMotionTypes): CSSInterpolation => {
const { antCls } = token
const motionCls = `${antCls}-${motionName}`
const { inKeyframes, outKeyframes } = slideMotion[motionName]
return [
initMotion(motionCls, inKeyframes, outKeyframes, token.motionDurationMid),
{
[`
${motionCls}-enter,
${motionCls}-appear
`]: {
transform: 'scale(0)',
transformOrigin: '0% 0%',
opacity: 0,
animationTimingFunction: token.motionEaseOutQuint
},
[`${motionCls}-leave`]: {
animationTimingFunction: token.motionEaseInQuint
}
}
]
}

View File

@ -0,0 +1,215 @@
import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
import { Keyframes } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../../theme/internal'
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook'
import { initMotion } from './motion'
export const zoomIn = new Keyframes('antZoomIn', {
'0%': {
transform: 'scale(0.2)',
opacity: 0
},
'100%': {
transform: 'scale(1)',
opacity: 1
}
})
export const zoomOut = new Keyframes('antZoomOut', {
'0%': {
transform: 'scale(1)'
},
'100%': {
transform: 'scale(0.2)',
opacity: 0
}
})
export const zoomBigIn = new Keyframes('antZoomBigIn', {
'0%': {
transform: 'scale(0.8)',
opacity: 0
},
'100%': {
transform: 'scale(1)',
opacity: 1
}
})
export const zoomBigOut = new Keyframes('antZoomBigOut', {
'0%': {
transform: 'scale(1)'
},
'100%': {
transform: 'scale(0.8)',
opacity: 0
}
})
export const zoomUpIn = new Keyframes('antZoomUpIn', {
'0%': {
transform: 'scale(0.8)',
transformOrigin: '50% 0%',
opacity: 0
},
'100%': {
transform: 'scale(1)',
transformOrigin: '50% 0%'
}
})
export const zoomUpOut = new Keyframes('antZoomUpOut', {
'0%': {
transform: 'scale(1)',
transformOrigin: '50% 0%'
},
'100%': {
transform: 'scale(0.8)',
transformOrigin: '50% 0%',
opacity: 0
}
})
export const zoomLeftIn = new Keyframes('antZoomLeftIn', {
'0%': {
transform: 'scale(0.8)',
transformOrigin: '0% 50%',
opacity: 0
},
'100%': {
transform: 'scale(1)',
transformOrigin: '0% 50%'
}
})
export const zoomLeftOut = new Keyframes('antZoomLeftOut', {
'0%': {
transform: 'scale(1)',
transformOrigin: '0% 50%'
},
'100%': {
transform: 'scale(0.8)',
transformOrigin: '0% 50%',
opacity: 0
}
})
export const zoomRightIn = new Keyframes('antZoomRightIn', {
'0%': {
transform: 'scale(0.8)',
transformOrigin: '100% 50%',
opacity: 0
},
'100%': {
transform: 'scale(1)',
transformOrigin: '100% 50%'
}
})
export const zoomRightOut = new Keyframes('antZoomRightOut', {
'0%': {
transform: 'scale(1)',
transformOrigin: '100% 50%'
},
'100%': {
transform: 'scale(0.8)',
transformOrigin: '100% 50%',
opacity: 0
}
})
export const zoomDownIn = new Keyframes('antZoomDownIn', {
'0%': {
transform: 'scale(0.8)',
transformOrigin: '50% 100%',
opacity: 0
},
'100%': {
transform: 'scale(1)',
transformOrigin: '50% 100%'
}
})
export const zoomDownOut = new Keyframes('antZoomDownOut', {
'0%': {
transform: 'scale(1)',
transformOrigin: '50% 100%'
},
'100%': {
transform: 'scale(0.8)',
transformOrigin: '50% 100%',
opacity: 0
}
})
type ZoomMotionTypes = 'zoom' | 'zoom-big' | 'zoom-big-fast' | 'zoom-left' | 'zoom-right' | 'zoom-up' | 'zoom-down'
const zoomMotion: Record<ZoomMotionTypes, { inKeyframes: Keyframes; outKeyframes: Keyframes }> = {
zoom: {
inKeyframes: zoomIn,
outKeyframes: zoomOut
},
'zoom-big': {
inKeyframes: zoomBigIn,
outKeyframes: zoomBigOut
},
'zoom-big-fast': {
inKeyframes: zoomBigIn,
outKeyframes: zoomBigOut
},
'zoom-left': {
inKeyframes: zoomLeftIn,
outKeyframes: zoomLeftOut
},
'zoom-right': {
inKeyframes: zoomRightIn,
outKeyframes: zoomRightOut
},
'zoom-up': {
inKeyframes: zoomUpIn,
outKeyframes: zoomUpOut
},
'zoom-down': {
inKeyframes: zoomDownIn,
outKeyframes: zoomDownOut
}
}
export const initZoomMotion = (token: TokenWithCommonCls<AliasToken>, motionName: ZoomMotionTypes): CSSInterpolation => {
const { antCls } = token
const motionCls = `${antCls}-${motionName}`
const { inKeyframes, outKeyframes } = zoomMotion[motionName]
return [
initMotion(motionCls, inKeyframes, outKeyframes, motionName === 'zoom-big-fast' ? token.motionDurationFast : token.motionDurationMid),
{
[`
${motionCls}-enter,
${motionCls}-appear
`]: {
transform: 'scale(0)',
opacity: 0,
animationTimingFunction: token.motionEaseOutCirc,
'&-prepare': {
transform: 'none'
}
},
[`${motionCls}-leave`]: {
animationTimingFunction: token.motionEaseInOutCirc
}
}
]
}

View File

@ -0,0 +1,21 @@
import type { CSSObject } from '@antd-tiny-vue/cssinjs'
import type { DerivativeToken } from '../theme/internal'
// eslint-disable-next-line import/prefer-default-export
export const operationUnit = (token: DerivativeToken): CSSObject => ({
// FIXME: This use link but is a operation unit. Seems should be a colorPrimary.
// And Typography use this to generate link style which should not do this.
color: token.colorLink,
textDecoration: 'none',
outline: 'none',
cursor: 'pointer',
transition: `color ${token.motionDurationSlow}`,
'&:focus, &:hover': {
color: token.colorLinkHover
},
'&:active': {
color: token.colorLinkActive
}
})

View File

@ -0,0 +1,191 @@
import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../theme/internal'
import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook'
import { roundedArrow } from './roundedArrow'
export const MAX_VERTICAL_CONTENT_RADIUS = 8
export function getArrowOffset(options: { contentRadius: number; limitVerticalRadius?: boolean }) {
const maxVerticalContentRadius = MAX_VERTICAL_CONTENT_RADIUS
const { contentRadius, limitVerticalRadius } = options
const dropdownArrowOffset = contentRadius > 12 ? contentRadius + 2 : 12
const dropdownArrowOffsetVertical = limitVerticalRadius ? maxVerticalContentRadius : dropdownArrowOffset
return { dropdownArrowOffset, dropdownArrowOffsetVertical }
}
function isInject(valid: boolean, code: CSSObject): CSSObject {
if (!valid) return {}
return code
}
export default function getArrowStyle<Token extends TokenWithCommonCls<AliasToken>>(
token: Token,
options: {
colorBg: string
showArrowCls?: string
contentRadius?: number
limitVerticalRadius?: boolean
arrowDistance?: number
arrowPlacement?: {
left?: boolean
right?: boolean
top?: boolean
bottom?: boolean
}
}
): CSSInterpolation {
const { componentCls, sizePopupArrow, borderRadiusXS, borderRadiusOuter, boxShadowPopoverArrow } = token
const {
colorBg,
contentRadius = token.borderRadiusLG,
limitVerticalRadius,
arrowDistance = 0,
arrowPlacement = {
left: true,
right: true,
top: true,
bottom: true
}
} = options
const { dropdownArrowOffsetVertical, dropdownArrowOffset } = getArrowOffset({
contentRadius,
limitVerticalRadius
})
return {
[componentCls]: {
// ============================ Basic ============================
[`${componentCls}-arrow`]: [
{
position: 'absolute',
zIndex: 1, // lift it up so the menu wouldn't cask shadow on it
display: 'block',
...roundedArrow(sizePopupArrow, borderRadiusXS, borderRadiusOuter, colorBg, boxShadowPopoverArrow),
'&:before': {
background: colorBg
}
}
],
// ========================== Placement ==========================
// Here handle the arrow position and rotate stuff
// >>>>> Top
...isInject(!!arrowPlacement.top, {
[[`&-placement-top ${componentCls}-arrow`, `&-placement-topLeft ${componentCls}-arrow`, `&-placement-topRight ${componentCls}-arrow`].join(',')]: {
bottom: arrowDistance,
transform: 'translateY(100%) rotate(180deg)'
},
[`&-placement-top ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: '50%'
},
transform: 'translateX(-50%) translateY(100%) rotate(180deg)'
},
[`&-placement-topLeft ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: dropdownArrowOffset
}
},
[`&-placement-topRight ${componentCls}-arrow`]: {
right: {
_skip_check_: true,
value: dropdownArrowOffset
}
}
}),
// >>>>> Bottom
...isInject(!!arrowPlacement.bottom, {
[[`&-placement-bottom ${componentCls}-arrow`, `&-placement-bottomLeft ${componentCls}-arrow`, `&-placement-bottomRight ${componentCls}-arrow`].join(',')]: {
top: arrowDistance,
transform: `translateY(-100%)`
},
[`&-placement-bottom ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: '50%'
},
transform: `translateX(-50%) translateY(-100%)`
},
[`&-placement-bottomLeft ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: dropdownArrowOffset
}
},
[`&-placement-bottomRight ${componentCls}-arrow`]: {
right: {
_skip_check_: true,
value: dropdownArrowOffset
}
}
}),
// >>>>> Left
...isInject(!!arrowPlacement.left, {
[[`&-placement-left ${componentCls}-arrow`, `&-placement-leftTop ${componentCls}-arrow`, `&-placement-leftBottom ${componentCls}-arrow`].join(',')]: {
right: {
_skip_check_: true,
value: arrowDistance
},
transform: 'translateX(100%) rotate(90deg)'
},
[`&-placement-left ${componentCls}-arrow`]: {
top: {
_skip_check_: true,
value: '50%'
},
transform: 'translateY(-50%) translateX(100%) rotate(90deg)'
},
[`&-placement-leftTop ${componentCls}-arrow`]: {
top: dropdownArrowOffsetVertical
},
[`&-placement-leftBottom ${componentCls}-arrow`]: {
bottom: dropdownArrowOffsetVertical
}
}),
// >>>>> Right
...isInject(!!arrowPlacement.right, {
[[`&-placement-right ${componentCls}-arrow`, `&-placement-rightTop ${componentCls}-arrow`, `&-placement-rightBottom ${componentCls}-arrow`].join(',')]: {
left: {
_skip_check_: true,
value: arrowDistance
},
transform: 'translateX(-100%) rotate(-90deg)'
},
[`&-placement-right ${componentCls}-arrow`]: {
top: {
_skip_check_: true,
value: '50%'
},
transform: 'translateY(-50%) translateX(-100%) rotate(-90deg)'
},
[`&-placement-rightTop ${componentCls}-arrow`]: {
top: dropdownArrowOffsetVertical
},
[`&-placement-rightBottom ${componentCls}-arrow`]: {
bottom: dropdownArrowOffsetVertical
}
})
}
}
}

View File

@ -0,0 +1,32 @@
/* eslint-disable import/prefer-default-export */
import type { CSSObject } from '@antd-tiny-vue/cssinjs'
import type { AliasToken, PresetColorKey } from '../theme/internal'
import { PresetColors } from '../theme/internal'
import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook'
interface CalcColor {
/** token[`${colorKey}-1`] */
lightColor: string
/** token[`${colorKey}-3`] */
lightBorderColor: string
/** token[`${colorKey}-6`] */
darkColor: string
/** token[`${colorKey}-7`] */
textColor: string
}
type GenCSS = (colorKey: PresetColorKey, calcColor: CalcColor) => CSSObject
export function genPresetColor<Token extends TokenWithCommonCls<AliasToken>>(token: Token, genCss: GenCSS): CSSObject {
return PresetColors.reduce((prev: CSSObject, colorKey: PresetColorKey) => {
const lightColor = token[`${colorKey}-1`]
const lightBorderColor = token[`${colorKey}-3`]
const darkColor = token[`${colorKey}-6`]
const textColor = token[`${colorKey}-7`]
return {
...prev,
...genCss(colorKey, { lightColor, lightBorderColor, darkColor, textColor })
}
}, {} as CSSObject)
}

253
components/style/reset.css Normal file
View File

@ -0,0 +1,253 @@
/* stylelint-disable */
html,
body {
width: 100%;
height: 100%;
}
input::-ms-clear,
input::-ms-reveal {
display: none;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
body {
margin: 0;
}
[tabindex='-1']:focus {
outline: none;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5em;
font-weight: 500;
}
p {
margin-top: 0;
margin-bottom: 1em;
}
abbr[title],
abbr[data-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline;
text-decoration: underline dotted;
border-bottom: 0;
cursor: help;
}
address {
margin-bottom: 1em;
font-style: normal;
line-height: inherit;
}
input[type='text'],
input[type='password'],
input[type='number'],
textarea {
-webkit-appearance: none;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1em;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 500;
}
dd {
margin-bottom: 0.5em;
margin-left: 0;
}
blockquote {
margin: 0 0 1em;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
pre,
code,
kbd,
samp {
font-size: 1em;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
}
pre {
margin-top: 0;
margin-bottom: 1em;
overflow: auto;
}
figure {
margin: 0 0 1em;
}
img {
vertical-align: middle;
border-style: none;
}
a,
area,
button,
[role='button'],
input:not([type='range']),
label,
select,
summary,
textarea {
touch-action: manipulation;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75em;
padding-bottom: 0.3em;
text-align: left;
caption-side: bottom;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
color: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type='button']::-moz-focus-inner,
[type='reset']::-moz-focus-inner,
[type='submit']::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type='radio'],
input[type='checkbox'] {
box-sizing: border-box;
padding: 0;
}
input[type='date'],
input[type='time'],
input[type='datetime-local'],
input[type='month'] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
margin: 0;
padding: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
margin-bottom: 0.5em;
padding: 0;
color: inherit;
font-size: 1.5em;
line-height: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button {
height: auto;
}
[type='search'] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type='search']::-webkit-search-cancel-button,
[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
mark {
padding: 0.2em;
background-color: #feffe6;
}

View File

@ -0,0 +1,57 @@
/* eslint-disable import/prefer-default-export */
import type { CSSObject } from '@antd-tiny-vue/cssinjs'
export const roundedArrow = (width: number, innerRadius: number, outerRadius: number, bgColor: string, boxShadow: string): CSSObject => {
const unitWidth = width / 2
const ax = 0
const ay = unitWidth
const bx = (outerRadius * 1) / Math.sqrt(2)
const by = unitWidth - outerRadius * (1 - 1 / Math.sqrt(2))
const cx = unitWidth - innerRadius * (1 / Math.sqrt(2))
const cy = outerRadius * (Math.sqrt(2) - 1) + innerRadius * (1 / Math.sqrt(2))
const dx = 2 * unitWidth - cx
const dy = cy
const ex = 2 * unitWidth - bx
const ey = by
const fx = 2 * unitWidth - ax
const fy = ay
const shadowWidth = unitWidth * Math.sqrt(2) + outerRadius * (Math.sqrt(2) - 2)
return {
pointerEvents: 'none',
width,
height: width,
overflow: 'hidden',
'&::before': {
position: 'absolute',
bottom: 0,
insetInlineStart: 0,
width,
height: width / 2,
background: bgColor,
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')`,
content: '""'
},
'&::after': {
content: '""',
position: 'absolute',
width: shadowWidth,
height: shadowWidth,
bottom: 0,
insetInline: 0,
margin: 'auto',
borderRadius: {
_skip_check_: true,
value: `0 0 ${innerRadius}px 0`
},
transform: 'translateY(50%) rotate(-135deg)',
boxShadow,
zIndex: 0,
background: 'transparent'
}
}
}

31
components/theme/index.ts Normal file
View File

@ -0,0 +1,31 @@
/* eslint-disable import/prefer-default-export */
import { defaultConfig, useToken as useInternalToken } from './internal'
import type { GlobalToken } from './interface'
import defaultAlgorithm from './themes/default'
import darkAlgorithm from './themes/dark'
import compactAlgorithm from './themes/compact'
// ZombieJ: We export as object to user but array in internal.
// This is used to minimize the bundle size for antd package but safe to refactor as object also.
// Please do not export internal `useToken` directly to avoid something export unexpected.
/** Get current context Design Token. Will be different if you are using nest theme config. */
function useToken() {
const [theme, token, hashId] = useInternalToken()
return { theme, token, hashId }
}
export { type GlobalToken }
export default {
/** @private Test Usage. Do not use in production. */
defaultConfig,
/** Default seedToken */
defaultSeed: defaultConfig.token,
useToken,
defaultAlgorithm,
darkAlgorithm,
compactAlgorithm
}

View File

@ -0,0 +1,149 @@
import type { CSSProperties } from 'vue'
import type { MapToken } from './maps'
// ======================================================================
// == Alias Token ==
// ======================================================================
// 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
export interface AliasToken extends MapToken {
// Background
colorFillContentHover: string
colorFillAlter: string
colorFillContent: string
colorBgContainerDisabled: string
colorBgTextHover: string
colorBgTextActive: string
// Border
colorBorderBg: string
/**
* @nameZH 线
* @desc 线 colorBorderSecondary
*/
colorSplit: string
// Text
colorTextPlaceholder: string
colorTextDisabled: string
colorTextHeading: string
colorTextLabel: string
colorTextDescription: string
colorTextLightSolid: string
/** Weak action. Such as `allowClear` or Alert close button */
colorIcon: string
/** Weak action hover color. Such as `allowClear` or Alert close button */
colorIconHover: string
colorLink: string
colorLinkHover: string
colorLinkActive: string
colorHighlight: string
controlOutline: string
colorWarningOutline: string
colorErrorOutline: string
// Font
/** Operation icon in Select, Cascader, etc. icon fontSize. Normal is same as fontSizeSM */
fontSizeIcon: number
/** For heading like h1, h2, h3 or option selected item */
fontWeightStrong: number
// Control
controlOutlineWidth: number
controlItemBgHover: string // Note. It also is a color
controlItemBgActive: string // Note. It also is a color
controlItemBgActiveHover: string // Note. It also is a color
controlInteractiveSize: number
controlItemBgActiveDisabled: string // Note. It also is a color
// Padding
paddingXXS: number
paddingXS: number
paddingSM: number
padding: number
paddingMD: number
paddingLG: number
paddingXL: number
// Padding Content
paddingContentHorizontalLG: number
paddingContentHorizontal: number
paddingContentHorizontalSM: number
paddingContentVerticalLG: number
paddingContentVertical: number
paddingContentVerticalSM: number
// Margin
marginXXS: number
marginXS: number
marginSM: number
margin: number
marginMD: number
marginLG: number
marginXL: number
marginXXL: number
// =============== Legacy: should be remove ===============
opacityLoading: number
boxShadow: string
boxShadowSecondary: string
boxShadowTertiary: string
linkDecoration: CSSProperties['textDecoration']
linkHoverDecoration: CSSProperties['textDecoration']
linkFocusDecoration: CSSProperties['textDecoration']
controlPaddingHorizontal: number
controlPaddingHorizontalSM: number
// Media queries breakpoints
screenXS: number
screenXSMin: number
screenXSMax: number
screenSM: number
screenSMMin: number
screenSMMax: number
screenMD: number
screenMDMin: number
screenMDMax: number
screenLG: number
screenLGMin: number
screenLGMax: number
screenXL: number
screenXLMin: number
screenXLMax: number
screenXXL: number
screenXXLMin: number
/** Used for DefaultButton, Switch which has default outline */
controlTmpOutline: string
// FIXME: component box-shadow, should be removed
/** @internal */
boxShadowPopoverArrow: string
/** @internal */
boxShadowCard: string
/** @internal */
boxShadowDrawerRight: string
/** @internal */
boxShadowDrawerLeft: string
/** @internal */
boxShadowDrawerUp: string
/** @internal */
boxShadowDrawerDown: string
/** @internal */
boxShadowTabsOverflowLeft: string
/** @internal */
boxShadowTabsOverflowRight: string
/** @internal */
boxShadowTabsOverflowTop: string
/** @internal */
boxShadowTabsOverflowBottom: string
}

View File

@ -0,0 +1,119 @@
// import type { ComponentToken as AlertComponentToken } from '../../alert/style'
// import type { ComponentToken as AnchorComponentToken } from '../../anchor/style'
// import type { ComponentToken as AvatarComponentToken } from '../../avatar/style'
// import type { ComponentToken as BackTopComponentToken } from '../../back-top/style'
// import type { ComponentToken as ButtonComponentToken } from '../../button/style'
// import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style'
// import type { ComponentToken as CalendarComponentToken } from '../../calendar/style'
// import type { ComponentToken as CardComponentToken } from '../../card/style'
// import type { ComponentToken as CarouselComponentToken } from '../../carousel/style'
// import type { ComponentToken as CascaderComponentToken } from '../../cascader/style'
// import type { ComponentToken as CheckboxComponentToken } from '../../checkbox/style'
// import type { ComponentToken as CollapseComponentToken } from '../../collapse/style'
// import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style'
// import type { ComponentToken as DividerComponentToken } from '../../divider/style'
// import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style'
// import type { ComponentToken as DrawerComponentToken } from '../../drawer/style'
// import type { ComponentToken as EmptyComponentToken } from '../../empty/style'
// import type { ComponentToken as ImageComponentToken } from '../../image/style'
// import type { ComponentToken as InputNumberComponentToken } from '../../input-number/style'
// import type { ComponentToken as LayoutComponentToken } from '../../layout/style'
// import type { ComponentToken as ListComponentToken } from '../../list/style'
// import type { ComponentToken as MentionsComponentToken } from '../../mentions/style'
// import type { ComponentToken as MenuComponentToken } from '../../menu/style'
// import type { ComponentToken as MessageComponentToken } from '../../message/style'
// import type { ComponentToken as ModalComponentToken } from '../../modal/style'
// import type { ComponentToken as NotificationComponentToken } from '../../notification/style'
// import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style'
// import type { ComponentToken as PopoverComponentToken } from '../../popover/style'
// import type { ComponentToken as ProgressComponentToken } from '../../progress/style'
// import type { ComponentToken as RadioComponentToken } from '../../radio/style'
// import type { ComponentToken as RateComponentToken } from '../../rate/style'
// import type { ComponentToken as ResultComponentToken } from '../../result/style'
// import type { ComponentToken as SegmentedComponentToken } from '../../segmented/style'
// import type { ComponentToken as SelectComponentToken } from '../../select/style'
// import type { ComponentToken as SkeletonComponentToken } from '../../skeleton/style'
// import type { ComponentToken as SliderComponentToken } from '../../slider/style'
// import type { ComponentToken as SpaceComponentToken } from '../../space/style'
// import type { ComponentToken as SpinComponentToken } from '../../spin/style'
// import type { ComponentToken as StepsComponentToken } from '../../steps/style'
// import type { ComponentToken as TableComponentToken } from '../../table/style'
// import type { ComponentToken as TabsComponentToken } from '../../tabs/style'
// import type { ComponentToken as TagComponentToken } from '../../tag/style'
// import type { ComponentToken as TimelineComponentToken } from '../../timeline/style'
// import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style'
// import type { ComponentToken as TransferComponentToken } from '../../transfer/style'
// import type { ComponentToken as TypographyComponentToken } from '../../typography/style'
// import type { ComponentToken as UploadComponentToken } from '../../upload/style'
// import type { ComponentToken as TourComponentToken } from '../../tour/style'
// import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style'
// import type { ComponentToken as AppComponentToken } from '../../app/style'
// import type { ComponentToken as WaveToken } from '../../_util/wave/style'
export interface ComponentTokenMap {
Affix?: {}
// Alert?: AlertComponentToken
// Anchor?: AnchorComponentToken
// Avatar?: AvatarComponentToken
// BackTop?: BackTopComponentToken
// Badge?: {}
// Button?: ButtonComponentToken
// Breadcrumb?: {}
// Card?: CardComponentToken
// Carousel?: CarouselComponentToken
// Cascader?: CascaderComponentToken
// Checkbox?: CheckboxComponentToken
// Collapse?: CollapseComponentToken
// DatePicker?: DatePickerComponentToken
// Descriptions?: {}
// Divider?: DividerComponentToken
// Drawer?: DrawerComponentToken
// Dropdown?: DropdownComponentToken
// Empty?: EmptyComponentToken
// FloatButton?: FloatButtonComponentToken
// Form?: {}
// Grid?: {}
// Image?: ImageComponentToken
// Input?: {}
// InputNumber?: InputNumberComponentToken
// Layout?: LayoutComponentToken
// List?: ListComponentToken
// Mentions?: MentionsComponentToken
// Notification?: NotificationComponentToken
// Pagination?: {}
// Popover?: PopoverComponentToken
// Popconfirm?: PopconfirmComponentToken
// Rate?: RateComponentToken
// Radio?: RadioComponentToken
// Result?: ResultComponentToken
// Segmented?: SegmentedComponentToken
// Select?: SelectComponentToken
// Skeleton?: SkeletonComponentToken
// Slider?: SliderComponentToken
// Spin?: SpinComponentToken
// Statistic?: {}
// Switch?: {}
// Tag?: TagComponentToken
// Tree?: {}
// TreeSelect?: {}
// Typography?: TypographyComponentToken
// Timeline?: TimelineComponentToken
// Transfer?: TransferComponentToken
// Tabs?: TabsComponentToken
// Calendar?: CalendarComponentToken
// Steps?: StepsComponentToken
// Menu?: MenuComponentToken
// Modal?: ModalComponentToken
// Message?: MessageComponentToken
// Upload?: UploadComponentToken
// Tooltip?: TooltipComponentToken
// Table?: TableComponentToken
// Space?: SpaceComponentToken
// Progress?: ProgressComponentToken
// Tour?: TourComponentToken
// QRCode?: QRCodeComponentToken
// App?: AppComponentToken
//
// /** @private Internal TS definition. Do not use. */
// Wave?: WaveToken
}

View File

@ -0,0 +1,16 @@
import type { ComponentTokenMap } from './components'
import type { AliasToken } from './alias'
export type OverrideToken = {
[key in keyof ComponentTokenMap]: Partial<ComponentTokenMap[key]> & Partial<AliasToken>
}
/** Final token which contains the components level override */
export type GlobalToken = AliasToken & ComponentTokenMap
export { PresetColors } from './presetColors'
export type { PresetColorType, ColorPalettes, PresetColorKey } from './presetColors'
export type { SeedToken } from './seeds'
export type { MapToken, ColorMapToken, ColorNeutralMapToken, CommonMapToken, HeightMapToken, SizeMapToken, FontMapToken, StyleMapToken } from './maps'
export type { AliasToken } from './alias'
export type { ComponentTokenMap } from './components'

View File

@ -0,0 +1,431 @@
export interface ColorNeutralMapToken {
/**
* @internal
*/
colorTextBase: string
/**
* @internal
*/
colorBgBase: string
// ---------- Text ---------- //
/**
* @nameZH
* @desc W3C标准使
*/
colorText: string
/**
* @nameZH
* @desc Label Menu
*/
colorTextSecondary: string
/**
* @nameZH
* @desc
*/
colorTextTertiary: string
/**
* @nameZH
* @desc
*/
colorTextQuaternary: string
// ---------- Border ---------- //
/**
* @nameZH
* @nameEN Default Border Color
* @desc 使, 线线
* @descEN Default border color, used to separate different elements, such as: form separator, card separator, etc.
*/
colorBorder: string
/**
* @nameZH
* @nameEN Secondary Border Color
* @desc 使 colorSplit 使
* @descEN Slightly lighter than the default border color, this color is the same as `colorSplit`. Solid color is used.
*/
colorBorderSecondary: string
// ---------- Fill ---------- //
/**
* @nameZH
* @desc Slider hover
*/
colorFill: string
/**
* @nameZH
* @desc RateSkeleton Hover Table
*/
colorFillSecondary: string
/**
* @nameZH
* @desc SliderSegmented 使
*/
colorFillTertiary: string
/**
* @nameZH
* @desc
*/
colorFillQuaternary: string
// ---------- Surface ---------- //
/**
* @nameZH
* @desc B1 使 token
*/
colorBgLayout: string
/**
* @nameZH
* @desc `colorBgElevated`
*/
colorBgContainer: string
/**
* @nameZH
* @desc token `colorBgContainer`
*/
colorBgElevated: string
/**
* @nameZH
* @desc Tooltip
*/
colorBgSpotlight: string
}
/**
*
*/
interface ColorPrimaryMapToken {
/**
* @nameZH
* @desc */
colorPrimary: string // 6
/**
* @nameZH
* @nameEN Light Background Color of Primary Color
* @desc
* @descEN Light background color of primary color, usually used for weak visual level selection state.
*/
colorPrimaryBg: string // 1
/**
* @nameZH
* @desc
*/
colorPrimaryBgHover: string // 2
/**
* @nameZH
* @desc Slider
*/
colorPrimaryBorder: string // 3
/**
* @nameZH
* @desc Slider Button Hover 使
*/
colorPrimaryBorderHover: string // 4
/**
* @nameZH
* @desc 使
*/
colorPrimaryHover: string // 5
/**
* @nameZH
* @desc
*/
colorPrimaryActive: string // 7
/**
* @nameZH
* @desc
*/
colorPrimaryTextHover: string // 8
/**
* @nameZH
* @desc
*/
colorPrimaryText: string // 9
/**
* @nameZH
* @desc
*/
colorPrimaryTextActive: string // 10
}
interface ColorSuccessMapToken {
/**
* @nameZH
* @nameEN Light Background Color of Success Color
* @desc Tag Alert
* @descEN Light background color of success color, used for Tag and Alert success state background color
*/
colorSuccessBg: string // 1
/**
* @nameZH
* @nameEN Hover State Color of Light Success Background
* @desc antd 使 token
* @descEN Light background color of success color, but antd does not use this token currently
*/
colorSuccessBgHover: string // 2
/**
* @nameZH
* @desc Tag Alert
*/
colorSuccessBorder: string // 3
/**
* @nameZH
* @desc
*/
colorSuccessBorderHover: string // 4
/**
* @nameZH
* @desc
*/
colorSuccessHover: string // 5
/**
* @nameZH
* @desc ResultProgress 使
*/
colorSuccess: string // 6
/**
* @nameZH
* @desc
*/
colorSuccessActive: string // 7
/**
* @nameZH
* @desc
*/
colorSuccessTextHover: string // 8
/**
* @nameZH
* @desc
*/
colorSuccessText: string // 9
/**
* @nameZH
* @desc
*/
colorSuccessTextActive: string // 10
}
interface ColorWarningMapToken {
/**
* @nameZH
*/
colorWarningBg: string // 1
/**
* @nameZH
* @desc
*/
colorWarningBgHover: string // 2
/**
* @nameZH
* @desc
*/
colorWarningBorder: string // 3
/**
* @nameZH
* @desc
*/
colorWarningBorderHover: string // 4
/**
* @nameZH
* @desc
*/
colorWarningHover: string // 5
/**
* @nameZH
* @desc Notification Alert等警告类组件或 Input 使
*/
colorWarning: string // 6
/**
* @nameZH
* @desc
*/
colorWarningActive: string // 7
/**
* @nameZH
* @desc
*/
colorWarningTextHover: string // 8
/**
* @nameZH
* @desc
*/
colorWarningText: string // 9
/**
* @nameZH
* @desc
*/
colorWarningTextActive: string // 10
}
interface ColorInfoMapToken {
/**
* @nameZH
* @desc
*/
colorInfoBg: string // 1
/**
* @nameZH
* @desc
*/
colorInfoBgHover: string // 2
/**
* @nameZH
*/
colorInfoBorder: string // 3
/**
* @nameZH
*/
colorInfoBorderHover: string // 4
/**
* @nameZH
*/
colorInfoHover: string // 5
/**
* @nameZH
*/
colorInfo: string // 6
/**
* @nameZH
*/
colorInfoActive: string // 7
/**
* @nameZH
*/
colorInfoTextHover: string // 8
/**
* @nameZH
*/
colorInfoText: string // 9
/**
* @nameZH
*/
colorInfoTextActive: string // 10
}
interface ColorErrorMapToken {
/**
* @nameZH
*/
colorErrorBg: string // 1
/**
* @nameZH
*/
colorErrorBgHover: string // 2
/**
* @nameZH
*/
colorErrorBorder: string // 3
/**
* @nameZH
*/
colorErrorBorderHover: string // 4
/**
* @nameZH
*/
colorErrorHover: string // 5
/**
* @nameZH
*/
colorError: string // 6
/**
* @nameZH
*/
colorErrorActive: string // 7
/**
* @nameZH
*/
colorErrorTextHover: string // 8
/**
* @nameZH
*/
colorErrorText: string // 9
/**
* @nameZH
*/
colorErrorTextActive: string // 10
}
export interface ColorMapToken extends ColorNeutralMapToken, ColorPrimaryMapToken, ColorSuccessMapToken, ColorWarningMapToken, ColorErrorMapToken, ColorInfoMapToken {
/**
* @nameZH
* @desc
* @descEN Pure white color don't changed by theme
* @default #FFFFFF
*/
colorWhite: string
/**
* @nameZH
* @nameEN Background color of the mask
* @desc ModalDrawer 使 token
* @descEN The background color of the mask, used to cover the content below the mask, Modal, Drawer and other components use this token
*/
colorBgMask: string
/**
* @nameZH
* @desc
* @default #0000
*/
// colorBlack: string;
}

View File

@ -0,0 +1,49 @@
export interface FontMapToken {
// Font Size
fontSizeSM: number
fontSize: number
fontSizeLG: number
fontSizeXL: number
/**
* @nameZH
* @desc H1 使
* @default 38
*/
fontSizeHeading1: number
/**
* @nameZH
* @desc h2 使
* @default 30
*/
fontSizeHeading2: number
/**
* @nameZH
* @desc h3 使
* @default 24
*/
fontSizeHeading3: number
/**
* @nameZH
* @desc h4 使
* @default 20
*/
fontSizeHeading4: number
/**
* @nameZH
* @desc h5 使
* @default 16
*/
fontSizeHeading5: number
// LineHeight
lineHeight: number
lineHeightLG: number
lineHeightSM: number
lineHeightHeading1: number
lineHeightHeading2: number
lineHeightHeading3: number
lineHeightHeading4: number
lineHeightHeading5: number
}

View File

@ -0,0 +1,25 @@
import type { ColorPalettes } from '../presetColors'
import type { SeedToken } from '../seeds'
import type { HeightMapToken, SizeMapToken } from './size'
import type { ColorMapToken } from './colors'
import type { StyleMapToken } from './style'
import type { FontMapToken } from './font'
export * from './colors'
export * from './style'
export * from './size'
export * from './font'
export interface CommonMapToken extends StyleMapToken {
// Motion
motionDurationFast: string
motionDurationMid: string
motionDurationSlow: string
}
// ======================================================================
// == Map Token ==
// ======================================================================
// 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
export interface MapToken extends SeedToken, ColorPalettes, ColorMapToken, SizeMapToken, HeightMapToken, StyleMapToken, FontMapToken, CommonMapToken {}

View File

@ -0,0 +1,68 @@
export interface SizeMapToken {
/**
* @nameZH XXL
* @default 48
*/
sizeXXL: number
/**
* @nameZH XL
* @default 32
*/
sizeXL: number
/**
* @nameZH LG
* @default 24
*/
sizeLG: number
/**
* @nameZH MD
* @default 20
*/
sizeMD: number
/** Same as size by default, but could be larger in compact mode */
sizeMS: number
/**
* @nameZH
* @desc
* @default 16
*/
size: number
/**
* @nameZH SM
* @default 12
*/
sizeSM: number
/**
* @nameZH XS
* @default 8
*/
sizeXS: number
/**
* @nameZH XXS
* @default 4
*/
sizeXXS: number
}
export interface HeightMapToken {
// Control
/** Only Used for control inside component like Multiple Select inner selection item */
/**
* @nameZH
* @nameEN XS component height
*/
controlHeightXS: number
/**
* @nameZH
* @nameEN SM component height
*/
controlHeightSM: number
/**
* @nameZH
* @nameEN LG component height
*/
controlHeightLG: number
}

View File

@ -0,0 +1,38 @@
export interface StyleMapToken {
/**
* @nameZH 线
* @nameEN Line Width
* @desc 线 ButtonInputSelect
* @descEN The default line width of the outline class components, such as Button, Input, Select, etc.
* @default 1
*/
lineWidthBold: number
/**
* @nameZH XS号圆角
* @desc XS号圆角 Segmented Arrow
* @descEN XS size border radius, used in some small border radius components, such as Segmented, Arrow and other components.
* @default 2
*/
borderRadiusXS: number
/**
* @nameZH SM号圆角
* @nameEN SM Border Radius
* @desc SM号圆角 ButtonInputSelect small size
* @descEN SM size border radius, used in small size components, such as Button, Input, Select and other input components in small size
* @default 4
*/
borderRadiusSM: number
/**
* @nameZH LG号圆角
* @nameEN LG Border Radius
* @desc LG号圆角 CardModal
* @descEN LG size border radius, used in some large border radius components, such as Card, Modal and other components.
* @default 8
*/
borderRadiusLG: number
/**
* @default 4
*/
borderRadiusOuter: number
}

View File

@ -0,0 +1,11 @@
export const PresetColors = ['blue', 'purple', 'cyan', 'green', 'magenta', 'pink', 'red', 'orange', 'yellow', 'volcano', 'geekblue', 'lime', 'gold'] as const
export type PresetColorKey = (typeof PresetColors)[number]
export type PresetColorType = Record<PresetColorKey, string>
type ColorPaletteKeyIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
export type ColorPalettes = {
[key in `${keyof PresetColorType}-${ColorPaletteKeyIndex}`]: string
}

View File

@ -0,0 +1,223 @@
import type { PresetColorType } from './presetColors'
// ======================================================================
// == Seed Token ==
// ======================================================================
// 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥
export interface SeedToken extends PresetColorType {
// ---------- Color ---------- //
/**
* @nameZH
* @nameEN Brand Color
* @desc
* @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.
*/
colorPrimary: string
/**
* @nameZH
* @nameEN Success Color
* @desc Token ResultProgress 使
* @descEN Used to represent the token sequence of operation success, such as Result, Progress and other components will use these map tokens.
*/
colorSuccess: string
/**
* @nameZH
* @nameEN Warning Color
* @desc Token Notification Alert等警告类组件或 Input 使
* @descEN Used to represent the warning map token, such as Notification, Alert, etc. Alert or Control component(like Input) will use these map tokens.
*/
colorWarning: string
/**
* @nameZH
* @nameEN Error Color
* @desc Token Result
* @descEN Used to represent the visual elements of the operation failure, such as the error Button, error Result component, etc.
*/
colorError: string
/**
* @nameZH
* @nameEN Info Color
* @desc Token Alert Tag Progress
* @descEN Used to represent the operation information of the Token sequence, such as Alert, Tag, Progress, and other components use these map tokens.
*/
colorInfo: string
/**
* @nameZH
* @nameEN Seed Text Color
* @desc v5 使 Seed Token
* @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!
*/
colorTextBase: string
/**
* @nameZH
* @nameEN Seed Background Color
* @desc v5 使 Seed Token
* @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!
*/
colorBgBase: string
// ---------- Font ---------- //
/**
* @nameZH
* @nameEN Font family for default text
* @desc Ant Design 使
*/
fontFamily: string
/**
* @nameZH
* @nameEN Font family for code text
* @desc Typography codepre kbd
*/
fontFamilyCode: string
/**
* @nameZH
* @nameEN Default Font Size
* @desc 使广
* @default 14
*/
fontSize: number
// ---------- Line ---------- //
/**
* @nameZH 线
* @nameEN Base Line Width
* @desc 线
* @descEN Border width of base components
*/
lineWidth: number
/**
* @nameZH 线
* @nameEN Line Style
* @desc 线线
* @descEN Border style of base components
*/
lineType: string
// ---------- BorderRadius ---------- //
/**
* @nameZH
* @nameEN Base Border Radius
* @descEN Border radius of base components
* @desc
*/
borderRadius: number
// ---------- Size ---------- //
/**
* @nameZH
* @nameEN Size Change Unit
* @desc Ant Design 4 便
* @descEN The unit of size change, in Ant Design, our base unit is 4, which is more fine-grained control of the size step
* @default 4
*/
sizeUnit: number
/**
* @nameZH
* @nameEN Size Base Step
* @desc V5 2
* @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
* @default 4
*/
sizeStep: number
/**
* @nameZH
*/
sizePopupArrow: number
/**
* @nameZH
* @nameEN Base Control Height
* @desc Ant Design
* @descEN The height of the basic controls such as buttons and input boxes in Ant Design
* @default 32
*/
controlHeight: number
// ---------- zIndex ---------- //
/**
* @nameZH zIndex
* @nameEN Base zIndex
* @desc Z Z BackTop Affix
* @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.
*
* @default 0
*/
zIndexBase: number
/**
* @nameZH zIndex
* @nameEN popup base zIndex
* @desc Z Z FloatButton AffixModal
* @descEN Base zIndex of component like FloatButton, Affix which can be cover by large popup
* @default 1000
*/
zIndexPopupBase: number
// ---------- Opacity ---------- //
/**
* @nameZH
* @nameEN Define default Image opacity. Useful when in dark-like theme
*/
opacityImage: number
// ---------- motion ---------- //
// TODO: 缺一个懂 motion 的人来收敛 Motion 相关的 Token
/**
* @nameZH
* @nameEN Animation Duration Unit
* @desc
* @descEN The unit of animation duration change
* @default 100ms
*/
motionUnit: number
/**
* @nameZH
*/
motionBase: number
motionEaseOutCirc: string
motionEaseInOutCirc: string
motionEaseInOut: string
motionEaseOutBack: string
motionEaseInBack: string
motionEaseInQuint: string
motionEaseOutQuint: string
motionEaseOut: string
// ---------- Style ---------- //
/**
* @nameZH 线
* @nameEN Wireframe Style
* @desc 线使 V4
* @default false
*/
wireframe: boolean
}

View File

@ -0,0 +1,82 @@
import type { CSSInterpolation, Theme } from '@antd-tiny-vue/cssinjs'
import { createTheme, useCacheToken, useStyleRegister } from '@antd-tiny-vue/cssinjs'
import { createInjectionState } from '@vueuse/core'
import type { ComputedRef, VNodeChild } from 'vue'
import { computed } from 'vue'
import version from '../version'
import type { AliasToken, GlobalToken, MapToken, OverrideToken, PresetColorKey, PresetColorType, SeedToken } from './interface'
import { PresetColors } from './interface'
import defaultDerivative from './themes/default'
import defaultSeedToken from './themes/seed'
import formatToken from './util/alias'
import type { FullToken } from './util/genComponentStyleHook'
import genComponentStyleHook from './util/genComponentStyleHook'
import statisticToken, { merge as mergeToken, statistic } from './util/statistic'
const defaultTheme = createTheme(defaultDerivative)
export {
// colors
PresetColors,
// Statistic
statistic,
statisticToken,
mergeToken,
// hooks
useStyleRegister,
genComponentStyleHook
}
export type {
SeedToken,
AliasToken,
PresetColorType,
PresetColorKey,
// FIXME: Remove this type
FullToken,
AliasToken as DerivativeToken
}
// ================================ Context =================================
// To ensure snapshot stable. We disable hashed in test env.
export const defaultConfig: DesignTokenConfig = {
token: defaultSeedToken,
hashed: true
}
export interface DesignTokenConfig {
token: Partial<AliasToken>
theme?: Theme<SeedToken, MapToken>
components?: OverrideToken
hashed?: string | boolean
}
const [useDesignTokenProvider, useDesignTokenInject] = createInjectionState((token: DesignTokenConfig) => {
return token
})
export { useDesignTokenProvider }
export const useDesignTokenState = () => useDesignTokenInject() ?? defaultConfig
// ================================== Hook ==================================
export function useToken(): [ComputedRef<Theme<SeedToken, MapToken>>, ComputedRef<GlobalToken>, ComputedRef<string>] {
const designTokenContext = useDesignTokenState()
const salt = computed(() => `${version}-${designTokenContext.hashed || ''}`)
const mergedTheme = computed(() => designTokenContext.theme || defaultTheme)
const tokens = computed(() => [defaultSeedToken, designTokenContext.token])
const opt = computed(() => {
return {
salt: salt.value,
override: { override: designTokenContext.token, ...designTokenContext.components },
formatToken
}
})
const cacheToken = useCacheToken<GlobalToken, SeedToken>(mergedTheme, tokens, opt)
return [mergedTheme, computed(() => cacheToken.value?.[0]), computed(() => (designTokenContext.hashed ? cacheToken.value?.[1] : ''))]
}
export type UseComponentStyleResult = [(node: VNodeChild) => VNodeChild, string]
export type GenerateStyle<ComponentToken extends object = AliasToken, ReturnType = CSSInterpolation> = (token: ComponentToken) => ReturnType

View File

@ -0,0 +1,17 @@
import type { ColorNeutralMapToken } from '../interface'
export interface ColorMap {
1: string
2: string
3: string
4: string
5: string
6: string
7: string
8: string
9: string
10: string
}
export type GenerateColorMap = (baseColor: string) => ColorMap
export type GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => ColorNeutralMapToken

View File

@ -0,0 +1,19 @@
import type { SeedToken, SizeMapToken } from '../../interface'
export default function genSizeMapToken(token: SeedToken): SizeMapToken {
const { sizeUnit, sizeStep } = token
const compactSizeStep = sizeStep - 2
return {
sizeXXL: sizeUnit * (compactSizeStep + 10),
sizeXL: sizeUnit * (compactSizeStep + 6),
sizeLG: sizeUnit * (compactSizeStep + 2),
sizeMD: sizeUnit * (compactSizeStep + 2),
sizeMS: sizeUnit * (compactSizeStep + 1),
size: sizeUnit * compactSizeStep,
sizeSM: sizeUnit * compactSizeStep,
sizeXS: sizeUnit * (compactSizeStep - 1),
sizeXXS: sizeUnit * (compactSizeStep - 1)
}
}

View File

@ -0,0 +1,27 @@
import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs'
import genControlHeight from '../shared/genControlHeight'
import type { MapToken, SeedToken } from '../../interface'
import defaultAlgorithm from '../default'
import genFontMapToken from '../shared/genFontMapToken'
import genCompactSizeMapToken from './genCompactSizeMapToken'
const derivative: DerivativeFunc<SeedToken, MapToken> = (token, mapToken) => {
const mergedMapToken = mapToken ?? defaultAlgorithm(token)
const fontSize = mergedMapToken.fontSizeSM // Smaller size font-size as base
const controlHeight = mergedMapToken.controlHeight - 4
return {
...mergedMapToken,
...genCompactSizeMapToken(mapToken ?? token),
// font
...genFontMapToken(fontSize),
// controlHeight
controlHeight,
...genControlHeight({ ...mergedMapToken, controlHeight })
}
}
export default derivative

View File

@ -0,0 +1,8 @@
import { TinyColor } from '@ctrl/tinycolor'
export const getAlphaColor = (baseColor: string, alpha: number) => new TinyColor(baseColor).setAlpha(alpha).toRgbString()
export const getSolidColor = (baseColor: string, brightness: number) => {
const instance = new TinyColor(baseColor)
return instance.lighten(brightness).toHexString()
}

View File

@ -0,0 +1,50 @@
import { generate } from '@ant-design/colors'
import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
import { getAlphaColor, getSolidColor } from './colorAlgorithm'
export const generateColorPalettes: GenerateColorMap = (baseColor: string) => {
const colors = generate(baseColor, { theme: 'dark' })
return {
1: colors[0],
2: colors[1],
3: colors[2],
4: colors[3],
5: colors[6],
6: colors[5],
7: colors[4],
8: colors[6],
9: colors[5],
10: colors[4]
// 8: colors[9],
// 9: colors[8],
// 10: colors[7],
}
}
export const generateNeutralColorPalettes: GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => {
const colorBgBase = bgBaseColor || '#000'
const colorTextBase = textBaseColor || '#fff'
return {
colorBgBase,
colorTextBase,
colorText: getAlphaColor(colorTextBase, 0.85),
colorTextSecondary: getAlphaColor(colorTextBase, 0.65),
colorTextTertiary: getAlphaColor(colorTextBase, 0.45),
colorTextQuaternary: getAlphaColor(colorTextBase, 0.25),
colorFill: getAlphaColor(colorTextBase, 0.18),
colorFillSecondary: getAlphaColor(colorTextBase, 0.12),
colorFillTertiary: getAlphaColor(colorTextBase, 0.08),
colorFillQuaternary: getAlphaColor(colorTextBase, 0.04),
colorBgElevated: getSolidColor(colorBgBase, 12),
colorBgContainer: getSolidColor(colorBgBase, 8),
colorBgLayout: getSolidColor(colorBgBase, 0),
colorBgSpotlight: getSolidColor(colorBgBase, 26),
colorBorder: getSolidColor(colorBgBase, 26),
colorBorderSecondary: getSolidColor(colorBgBase, 19)
}
}

View File

@ -0,0 +1,43 @@
import { generate } from '@ant-design/colors'
import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs'
import type { ColorPalettes, MapToken, PresetColorType, SeedToken } from '../../interface'
import { defaultPresetColors } from '../seed'
import genColorMapToken from '../shared/genColorMapToken'
import defaultAlgorithm from '../default'
import { generateColorPalettes, generateNeutralColorPalettes } from './colors'
const derivative: DerivativeFunc<SeedToken, MapToken> = (token, mapToken) => {
const colorPalettes = Object.keys(defaultPresetColors)
// @ts-expect-error this is a bug of typescript
.map((colorKey: keyof PresetColorType) => {
const colors = generate(token[colorKey], { theme: 'dark' })
return new Array(10).fill(1).reduce((prev, _, i) => {
prev[`${colorKey}-${i + 1}`] = colors[i]
return prev
}, {}) as ColorPalettes
})
.reduce((prev, cur) => {
prev = {
...prev,
...cur
}
return prev
}, {} as ColorPalettes)
const mergedMapToken = mapToken ?? defaultAlgorithm(token)
return {
...mergedMapToken,
// Dark tokens
...colorPalettes,
// Colors
...genColorMapToken(token, {
generateColorPalettes,
generateNeutralColorPalettes
})
}
}
export default derivative

View File

@ -0,0 +1,8 @@
import { TinyColor } from '@ctrl/tinycolor'
export const getAlphaColor = (baseColor: string, alpha: number) => new TinyColor(baseColor).setAlpha(alpha).toRgbString()
export const getSolidColor = (baseColor: string, brightness: number) => {
const instance = new TinyColor(baseColor)
return instance.darken(brightness).toHexString()
}

View File

@ -0,0 +1,50 @@
import { generate } from '@ant-design/colors'
import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
import { getAlphaColor, getSolidColor } from './colorAlgorithm'
export const generateColorPalettes: GenerateColorMap = (baseColor: string) => {
const colors = generate(baseColor)
return {
1: colors[0],
2: colors[1],
3: colors[2],
4: colors[3],
5: colors[4],
6: colors[5],
7: colors[6],
8: colors[4],
9: colors[5],
10: colors[6]
// 8: colors[7],
// 9: colors[8],
// 10: colors[9],
}
}
export const generateNeutralColorPalettes: GenerateNeutralColorMap = (bgBaseColor: string, textBaseColor: string) => {
const colorBgBase = bgBaseColor || '#fff'
const colorTextBase = textBaseColor || '#000'
return {
colorBgBase,
colorTextBase,
colorText: getAlphaColor(colorTextBase, 0.88),
colorTextSecondary: getAlphaColor(colorTextBase, 0.65),
colorTextTertiary: getAlphaColor(colorTextBase, 0.45),
colorTextQuaternary: getAlphaColor(colorTextBase, 0.25),
colorFill: getAlphaColor(colorTextBase, 0.15),
colorFillSecondary: getAlphaColor(colorTextBase, 0.06),
colorFillTertiary: getAlphaColor(colorTextBase, 0.04),
colorFillQuaternary: getAlphaColor(colorTextBase, 0.02),
colorBgLayout: getSolidColor(colorBgBase, 4),
colorBgContainer: getSolidColor(colorBgBase, 0),
colorBgElevated: getSolidColor(colorBgBase, 0),
colorBgSpotlight: getAlphaColor(colorTextBase, 0.85),
colorBorder: getSolidColor(colorBgBase, 15),
colorBorderSecondary: getSolidColor(colorBgBase, 6)
}
}

View File

@ -0,0 +1,46 @@
import { generate } from '@ant-design/colors'
import genControlHeight from '../shared/genControlHeight'
import genSizeMapToken from '../shared/genSizeMapToken'
import type { ColorPalettes, MapToken, PresetColorType, SeedToken } from '../../interface'
import { defaultPresetColors } from '../seed'
import genColorMapToken from '../shared/genColorMapToken'
import genCommonMapToken from '../shared/genCommonMapToken'
import genFontMapToken from '../shared/genFontMapToken'
import { generateColorPalettes, generateNeutralColorPalettes } from './colors'
export default function derivative(token: SeedToken): MapToken {
const colorPalettes = Object.keys(defaultPresetColors)
.map((colorKey: keyof PresetColorType) => {
const colors = generate(token[colorKey])
return new Array(10).fill(1).reduce((prev, _, i) => {
prev[`${colorKey}-${i + 1}`] = colors[i]
return prev
}, {}) as ColorPalettes
})
.reduce((prev, cur) => {
prev = {
...prev,
...cur
}
return prev
}, {} as ColorPalettes)
return {
...token,
...colorPalettes,
// Colors
...genColorMapToken(token, {
generateColorPalettes,
generateNeutralColorPalettes
}),
// Font
...genFontMapToken(token.fontSize),
// Size
...genSizeMapToken(token),
// Height
...genControlHeight(token),
// Others
...genCommonMapToken(token)
}
}

View File

@ -0,0 +1,77 @@
import type { PresetColorType, SeedToken } from '../internal'
export const defaultPresetColors: PresetColorType = {
blue: '#1677ff',
purple: '#722ED1',
cyan: '#13C2C2',
green: '#52C41A',
magenta: '#EB2F96',
pink: '#eb2f96',
red: '#F5222D',
orange: '#FA8C16',
yellow: '#FADB14',
volcano: '#FA541C',
geekblue: '#2F54EB',
gold: '#FAAD14',
lime: '#A0D911'
}
const seedToken: SeedToken = {
// preset color palettes
...defaultPresetColors,
// Color
colorPrimary: '#1677ff',
colorSuccess: '#52c41a',
colorWarning: '#faad14',
colorError: '#ff4d4f',
colorInfo: '#1677ff',
colorTextBase: '',
colorBgBase: '',
// Font
fontFamily: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji'`,
fontFamilyCode: `'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace`,
fontSize: 14,
// Line
lineWidth: 1,
lineType: 'solid',
// Motion
motionUnit: 0.1,
motionBase: 0,
motionEaseOutCirc: 'cubic-bezier(0.08, 0.82, 0.17, 1)',
motionEaseInOutCirc: 'cubic-bezier(0.78, 0.14, 0.15, 0.86)',
motionEaseOut: 'cubic-bezier(0.215, 0.61, 0.355, 1)',
motionEaseInOut: 'cubic-bezier(0.645, 0.045, 0.355, 1)',
motionEaseOutBack: 'cubic-bezier(0.12, 0.4, 0.29, 1.46)',
motionEaseInBack: 'cubic-bezier(0.71, -0.46, 0.88, 0.6)',
motionEaseInQuint: 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
motionEaseOutQuint: 'cubic-bezier(0.23, 1, 0.32, 1)',
// Radius
borderRadius: 6,
// Size
sizeUnit: 4,
sizeStep: 4,
sizePopupArrow: 16,
// Control Base
controlHeight: 32,
// zIndex
zIndexBase: 0,
zIndexPopupBase: 1000,
// Image
opacityImage: 1,
// Wireframe
wireframe: false
}
export default seedToken

View File

@ -0,0 +1,81 @@
import { TinyColor } from '@ctrl/tinycolor'
import type { ColorMapToken, SeedToken } from '../../interface'
import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'
interface PaletteGenerators {
generateColorPalettes: GenerateColorMap
generateNeutralColorPalettes: GenerateNeutralColorMap
}
export default function genColorMapToken(seed: SeedToken, { generateColorPalettes, generateNeutralColorPalettes }: PaletteGenerators): ColorMapToken {
const { colorSuccess: colorSuccessBase, colorWarning: colorWarningBase, colorError: colorErrorBase, colorInfo: colorInfoBase, colorPrimary: colorPrimaryBase, colorBgBase, colorTextBase } = seed
const primaryColors = generateColorPalettes(colorPrimaryBase)
const successColors = generateColorPalettes(colorSuccessBase)
const warningColors = generateColorPalettes(colorWarningBase)
const errorColors = generateColorPalettes(colorErrorBase)
const infoColors = generateColorPalettes(colorInfoBase)
const neutralColors = generateNeutralColorPalettes(colorBgBase, colorTextBase)
return {
...neutralColors,
colorPrimaryBg: primaryColors[1],
colorPrimaryBgHover: primaryColors[2],
colorPrimaryBorder: primaryColors[3],
colorPrimaryBorderHover: primaryColors[4],
colorPrimaryHover: primaryColors[5],
colorPrimary: primaryColors[6],
colorPrimaryActive: primaryColors[7],
colorPrimaryTextHover: primaryColors[8],
colorPrimaryText: primaryColors[9],
colorPrimaryTextActive: primaryColors[10],
colorSuccessBg: successColors[1],
colorSuccessBgHover: successColors[2],
colorSuccessBorder: successColors[3],
colorSuccessBorderHover: successColors[4],
colorSuccessHover: successColors[4],
colorSuccess: successColors[6],
colorSuccessActive: successColors[7],
colorSuccessTextHover: successColors[8],
colorSuccessText: successColors[9],
colorSuccessTextActive: successColors[10],
colorErrorBg: errorColors[1],
colorErrorBgHover: errorColors[2],
colorErrorBorder: errorColors[3],
colorErrorBorderHover: errorColors[4],
colorErrorHover: errorColors[5],
colorError: errorColors[6],
colorErrorActive: errorColors[7],
colorErrorTextHover: errorColors[8],
colorErrorText: errorColors[9],
colorErrorTextActive: errorColors[10],
colorWarningBg: warningColors[1],
colorWarningBgHover: warningColors[2],
colorWarningBorder: warningColors[3],
colorWarningBorderHover: warningColors[4],
colorWarningHover: warningColors[4],
colorWarning: warningColors[6],
colorWarningActive: warningColors[7],
colorWarningTextHover: warningColors[8],
colorWarningText: warningColors[9],
colorWarningTextActive: warningColors[10],
colorInfoBg: infoColors[1],
colorInfoBgHover: infoColors[2],
colorInfoBorder: infoColors[3],
colorInfoBorderHover: infoColors[4],
colorInfoHover: infoColors[4],
colorInfo: infoColors[6],
colorInfoActive: infoColors[7],
colorInfoTextHover: infoColors[8],
colorInfoText: infoColors[9],
colorInfoTextActive: infoColors[10],
colorBgMask: new TinyColor('#000').setAlpha(0.45).toRgbString(),
colorWhite: '#fff'
}
}

View File

@ -0,0 +1,19 @@
import type { CommonMapToken, SeedToken } from '../../interface'
import genRadius from './genRadius'
export default function genCommonMapToken(token: SeedToken): CommonMapToken {
const { motionUnit, motionBase, borderRadius, lineWidth } = token
return {
// motion
motionDurationFast: `${(motionBase + motionUnit).toFixed(1)}s`,
motionDurationMid: `${(motionBase + motionUnit * 2).toFixed(1)}s`,
motionDurationSlow: `${(motionBase + motionUnit * 3).toFixed(1)}s`,
// line
lineWidthBold: lineWidth + 1,
// radius
...genRadius(borderRadius)
}
}

View File

@ -0,0 +1,13 @@
import type { HeightMapToken, SeedToken } from '../../interface'
const genControlHeight = (token: SeedToken): HeightMapToken => {
const { controlHeight } = token
return {
controlHeightSM: controlHeight * 0.75,
controlHeightXS: controlHeight * 0.5,
controlHeightLG: controlHeight * 1.25
}
}
export default genControlHeight

View File

@ -0,0 +1,33 @@
import type { FontMapToken } from '../../interface'
import genFontSizes from './genFontSizes'
const genFontMapToken = (fontSize: number): FontMapToken => {
const fontSizePairs = genFontSizes(fontSize)
const fontSizes = fontSizePairs.map(pair => pair.size)
const lineHeights = fontSizePairs.map(pair => pair.lineHeight)
return {
fontSizeSM: fontSizes[0],
fontSize: fontSizes[1],
fontSizeLG: fontSizes[2],
fontSizeXL: fontSizes[3],
fontSizeHeading1: fontSizes[6],
fontSizeHeading2: fontSizes[5],
fontSizeHeading3: fontSizes[4],
fontSizeHeading4: fontSizes[3],
fontSizeHeading5: fontSizes[2],
lineHeight: lineHeights[1],
lineHeightLG: lineHeights[2],
lineHeightSM: lineHeights[0],
lineHeightHeading1: lineHeights[6],
lineHeightHeading2: lineHeights[5],
lineHeightHeading3: lineHeights[4],
lineHeightHeading4: lineHeights[3],
lineHeightHeading5: lineHeights[2]
}
}
export default genFontMapToken

View File

@ -0,0 +1,22 @@
// https://zhuanlan.zhihu.com/p/32746810
export default function getFontSizes(base: number) {
const fontSizes = new Array(10).fill(null).map((_, index) => {
const i = index - 1
const baseSize = base * 2.71828 ** (i / 5)
const intSize = index > 1 ? Math.floor(baseSize) : Math.ceil(baseSize)
// Convert to even
return Math.floor(intSize / 2) * 2
})
fontSizes[1] = base
return fontSizes.map(size => {
const height = size + 8
return {
size,
lineHeight: height / size
}
})
}

View File

@ -0,0 +1,54 @@
import type { MapToken } from '../../interface'
const genRadius = (radiusBase: number): Pick<MapToken, 'borderRadiusXS' | 'borderRadiusSM' | 'borderRadiusLG' | 'borderRadius' | 'borderRadiusOuter'> => {
let radiusLG = radiusBase
let radiusSM = radiusBase
let radiusXS = radiusBase
let radiusOuter = radiusBase
// radiusLG
if (radiusBase < 6 && radiusBase >= 5) {
radiusLG = radiusBase + 1
} else if (radiusBase < 16 && radiusBase >= 6) {
radiusLG = radiusBase + 2
} else if (radiusBase >= 16) {
radiusLG = 16
}
// radiusSM
if (radiusBase < 7 && radiusBase >= 5) {
radiusSM = 4
} else if (radiusBase < 8 && radiusBase >= 7) {
radiusSM = 5
} else if (radiusBase < 14 && radiusBase >= 8) {
radiusSM = 6
} else if (radiusBase < 16 && radiusBase >= 14) {
radiusSM = 7
} else if (radiusBase >= 16) {
radiusSM = 8
}
// radiusXS
if (radiusBase < 6 && radiusBase >= 2) {
radiusXS = 1
} else if (radiusBase >= 6) {
radiusXS = 2
}
// radiusOuter
if (radiusBase > 4 && radiusBase < 8) {
radiusOuter = 4
} else if (radiusBase >= 8) {
radiusOuter = 6
}
return {
borderRadius: radiusBase > 16 ? 16 : radiusBase,
borderRadiusXS: radiusXS,
borderRadiusSM: radiusSM,
borderRadiusLG: radiusLG,
borderRadiusOuter: radiusOuter
}
}
export default genRadius

View File

@ -0,0 +1,17 @@
import type { SeedToken, SizeMapToken } from '../../interface'
export default function genSizeMapToken(token: SeedToken): SizeMapToken {
const { sizeUnit, sizeStep } = token
return {
sizeXXL: sizeUnit * (sizeStep + 8), // 48
sizeXL: sizeUnit * (sizeStep + 4), // 32
sizeLG: sizeUnit * (sizeStep + 2), // 24
sizeMD: sizeUnit * (sizeStep + 1), // 20
sizeMS: sizeUnit * sizeStep, // 16
size: sizeUnit * sizeStep, // 16
sizeSM: sizeUnit * (sizeStep - 1), // 12
sizeXS: sizeUnit * (sizeStep - 2), // 8
sizeXXS: sizeUnit * (sizeStep - 3) // 4
}
}

View File

@ -0,0 +1,196 @@
import { TinyColor } from '@ctrl/tinycolor'
import type { AliasToken, MapToken, OverrideToken, SeedToken } from '../interface'
import seedToken from '../themes/seed'
import getAlphaColor from './getAlphaColor'
/** Raw merge of `@antd-tiny-vue/cssinjs` token. Which need additional process */
type RawMergedToken = MapToken & OverrideToken & { override: Partial<AliasToken> }
/**
* Seed (designer) > Derivative (designer) > Alias (developer).
*
* Merge seed & derivative & override token and generate alias token for developer.
*/
export default function formatToken(derivativeToken: RawMergedToken): AliasToken {
const { override, ...restToken } = derivativeToken
const overrideTokens = { ...override }
Object.keys(seedToken).forEach(token => {
delete overrideTokens[token as keyof SeedToken]
})
const mergedToken = {
...restToken,
...overrideTokens
}
const screenXS = 480
const screenSM = 576
const screenMD = 768
const screenLG = 992
const screenXL = 1200
const screenXXL = 1600
// Generate alias token
const aliasToken: AliasToken = {
...mergedToken,
colorLink: mergedToken.colorInfoText,
colorLinkHover: mergedToken.colorInfoHover,
colorLinkActive: mergedToken.colorInfoActive,
// ============== Background ============== //
colorFillContent: mergedToken.colorFillSecondary,
colorFillContentHover: mergedToken.colorFill,
colorFillAlter: mergedToken.colorFillQuaternary,
colorBgContainerDisabled: mergedToken.colorFillTertiary,
// ============== Split ============== //
colorBorderBg: mergedToken.colorBgContainer,
colorSplit: getAlphaColor(mergedToken.colorBorderSecondary, mergedToken.colorBgContainer),
// ============== Text ============== //
colorTextPlaceholder: mergedToken.colorTextQuaternary,
colorTextDisabled: mergedToken.colorTextQuaternary,
colorTextHeading: mergedToken.colorText,
colorTextLabel: mergedToken.colorTextSecondary,
colorTextDescription: mergedToken.colorTextTertiary,
colorTextLightSolid: mergedToken.colorWhite,
colorHighlight: mergedToken.colorError,
colorBgTextHover: mergedToken.colorFillSecondary,
colorBgTextActive: mergedToken.colorFill,
colorIcon: mergedToken.colorTextTertiary,
colorIconHover: mergedToken.colorText,
colorErrorOutline: getAlphaColor(mergedToken.colorErrorBg, mergedToken.colorBgContainer),
colorWarningOutline: getAlphaColor(mergedToken.colorWarningBg, mergedToken.colorBgContainer),
// Font
fontSizeIcon: mergedToken.fontSizeSM,
// Control
lineWidth: mergedToken.lineWidth,
controlOutlineWidth: mergedToken.lineWidth * 2,
// Checkbox size and expand icon size
controlInteractiveSize: mergedToken.controlHeight / 2,
controlItemBgHover: mergedToken.colorFillTertiary,
controlItemBgActive: mergedToken.colorPrimaryBg,
controlItemBgActiveHover: mergedToken.colorPrimaryBgHover,
controlItemBgActiveDisabled: mergedToken.colorFill,
controlTmpOutline: mergedToken.colorFillQuaternary,
controlOutline: getAlphaColor(mergedToken.colorPrimaryBg, mergedToken.colorBgContainer),
lineType: mergedToken.lineType,
borderRadius: mergedToken.borderRadius,
borderRadiusXS: mergedToken.borderRadiusXS,
borderRadiusSM: mergedToken.borderRadiusSM,
borderRadiusLG: mergedToken.borderRadiusLG,
fontWeightStrong: 600,
opacityLoading: 0.65,
linkDecoration: 'none',
linkHoverDecoration: 'none',
linkFocusDecoration: 'none',
controlPaddingHorizontal: 12,
controlPaddingHorizontalSM: 8,
paddingXXS: mergedToken.sizeXXS,
paddingXS: mergedToken.sizeXS,
paddingSM: mergedToken.sizeSM,
padding: mergedToken.size,
paddingMD: mergedToken.sizeMD,
paddingLG: mergedToken.sizeLG,
paddingXL: mergedToken.sizeXL,
paddingContentHorizontalLG: mergedToken.sizeLG,
paddingContentVerticalLG: mergedToken.sizeMS,
paddingContentHorizontal: mergedToken.sizeMS,
paddingContentVertical: mergedToken.sizeSM,
paddingContentHorizontalSM: mergedToken.size,
paddingContentVerticalSM: mergedToken.sizeXS,
marginXXS: mergedToken.sizeXXS,
marginXS: mergedToken.sizeXS,
marginSM: mergedToken.sizeSM,
margin: mergedToken.size,
marginMD: mergedToken.sizeMD,
marginLG: mergedToken.sizeLG,
marginXL: mergedToken.sizeXL,
marginXXL: mergedToken.sizeXXL,
boxShadow: `
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowSecondary: `
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowTertiary: `
0 1px 2px 0 rgba(0, 0, 0, 0.03),
0 1px 6px -1px rgba(0, 0, 0, 0.02),
0 2px 4px 0 rgba(0, 0, 0, 0.02)
`,
screenXS,
screenXSMin: screenXS,
screenXSMax: screenSM - 1,
screenSM,
screenSMMin: screenSM,
screenSMMax: screenMD - 1,
screenMD,
screenMDMin: screenMD,
screenMDMax: screenLG - 1,
screenLG,
screenLGMin: screenLG,
screenLGMax: screenXL - 1,
screenXL,
screenXLMin: screenXL,
screenXLMax: screenXXL - 1,
screenXXL,
screenXXLMin: screenXXL,
boxShadowPopoverArrow: '2px 2px 5px rgba(0, 0, 0, 0.05)',
boxShadowCard: `
0 1px 2px -2px ${new TinyColor('rgba(0, 0, 0, 0.16)').toRgbString()},
0 3px 6px 0 ${new TinyColor('rgba(0, 0, 0, 0.12)').toRgbString()},
0 5px 12px 4px ${new TinyColor('rgba(0, 0, 0, 0.09)').toRgbString()}
`,
boxShadowDrawerRight: `
-6px 0 16px 0 rgba(0, 0, 0, 0.08),
-3px 0 6px -4px rgba(0, 0, 0, 0.12),
-9px 0 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowDrawerLeft: `
6px 0 16px 0 rgba(0, 0, 0, 0.08),
3px 0 6px -4px rgba(0, 0, 0, 0.12),
9px 0 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowDrawerUp: `
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowDrawerDown: `
0 -6px 16px 0 rgba(0, 0, 0, 0.08),
0 -3px 6px -4px rgba(0, 0, 0, 0.12),
0 -9px 28px 8px rgba(0, 0, 0, 0.05)
`,
boxShadowTabsOverflowLeft: 'inset 10px 0 8px -8px rgba(0, 0, 0, 0.08)',
boxShadowTabsOverflowRight: 'inset -10px 0 8px -8px rgba(0, 0, 0, 0.08)',
boxShadowTabsOverflowTop: 'inset 0 10px 8px -8px rgba(0, 0, 0, 0.08)',
boxShadowTabsOverflowBottom: 'inset 0 -10px 8px -8px rgba(0, 0, 0, 0.08)',
// Override AliasToken
...overrideTokens
}
return aliasToken
}

View File

@ -0,0 +1,98 @@
/* eslint-disable no-redeclare */
import type { CSSInterpolation } from '@antd-tiny-vue/cssinjs'
import { useStyleRegister } from '@antd-tiny-vue/cssinjs'
import type { Ref } from 'vue'
import { computed } from 'vue'
import { genCommonStyle, genLinkStyle } from '../../style'
import { useProviderConfigState } from '../../config-provider/context'
import type { UseComponentStyleResult } from '../internal'
import { mergeToken, statisticToken, useToken } from '../internal'
import type { ComponentTokenMap, GlobalToken } from '../interface'
export type OverrideTokenWithoutDerivative = ComponentTokenMap
export type OverrideComponent = keyof OverrideTokenWithoutDerivative
export type GlobalTokenWithComponent<ComponentName extends OverrideComponent> = GlobalToken & ComponentTokenMap[ComponentName]
export interface StyleInfo<ComponentName extends OverrideComponent> {
hashId: string
prefixCls: string
rootPrefixCls: string
iconPrefixCls: string
overrideComponentToken: ComponentTokenMap[ComponentName]
}
export type TokenWithCommonCls<T> = T & {
/** Wrap component class with `.` prefix */
componentCls: string
/** Origin prefix which do not have `.` prefix */
prefixCls: string
/** Wrap icon class with `.` prefix */
iconCls: string
/** Wrap ant prefixCls class with `.` prefix */
antCls: string
}
export type FullToken<ComponentName extends OverrideComponent> = TokenWithCommonCls<GlobalTokenWithComponent<ComponentName>>
export default function genComponentStyleHook<ComponentName extends OverrideComponent>(
component: ComponentName,
styleFn: (token: FullToken<ComponentName>, info: StyleInfo<ComponentName>) => CSSInterpolation,
getDefaultToken?: OverrideTokenWithoutDerivative[ComponentName] | ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName])
) {
return (prefixCls: Ref<string>): UseComponentStyleResult => {
const [theme, token, hashId] = useToken()
const { getPrefixCls, iconPrefixCls } = useProviderConfigState()
const rootPrefixCls = computed(() => getPrefixCls())
const sharedInfo = computed(() => {
return {
theme: theme.value,
token: token.value,
hashId: hashId.value,
path: ['Shared', rootPrefixCls.value]
}
})
// Generate style for all a tags in antd component.
useStyleRegister(sharedInfo, () => [
{
// Link
'&': genLinkStyle(token.value)
}
])
const componentInfo = computed(() => ({
theme: theme.value,
token: token.value,
hashId: hashId.value,
path: [component, prefixCls.value, iconPrefixCls.value]
}))
return [
useStyleRegister(componentInfo, () => {
const { token: proxyToken, flush } = statisticToken(token.value)
const defaultComponentToken = typeof getDefaultToken === 'function' ? getDefaultToken(proxyToken) : getDefaultToken
const mergedComponentToken = { ...defaultComponentToken, ...token.value[component] }
const componentCls = `.${prefixCls.value}`
const mergedToken = mergeToken<TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>>(
proxyToken,
{
componentCls,
prefixCls: prefixCls.value,
iconCls: `.${iconPrefixCls.value}`,
antCls: `.${rootPrefixCls.value}`
},
mergedComponentToken
)
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
hashId: hashId.value,
prefixCls: prefixCls.value,
rootPrefixCls: rootPrefixCls.value,
iconPrefixCls: iconPrefixCls.value,
overrideComponentToken: token.value[component]
})
flush(component, mergedComponentToken)
return [genCommonStyle(token.value, prefixCls.value), styleInterpolation]
}),
hashId.value
]
}
}

View File

@ -0,0 +1,29 @@
import { TinyColor } from '@ctrl/tinycolor'
function isStableColor(color: number): boolean {
return color >= 0 && color <= 255
}
function getAlphaColor(frontColor: string, backgroundColor: string): string {
const { r: fR, g: fG, b: fB, a: originAlpha } = new TinyColor(frontColor).toRgb()
if (originAlpha < 1) {
return frontColor
}
const { r: bR, g: bG, b: bB } = new TinyColor(backgroundColor).toRgb()
for (let fA = 0.01; fA <= 1; fA += 0.01) {
const r = Math.round((fR - bR * (1 - fA)) / fA)
const g = Math.round((fG - bG * (1 - fA)) / fA)
const b = Math.round((fB - bB * (1 - fA)) / fA)
if (isStableColor(r) && isStableColor(g) && isStableColor(b)) {
return new TinyColor({ r, g, b, a: Math.round(fA * 100) / 100 }).toRgbString()
}
}
// fallback
/* istanbul ignore next */
return new TinyColor({ r: fR, g: fG, b: fB, a: 1 }).toRgbString()
}
export default getAlphaColor

View File

@ -0,0 +1,70 @@
declare const CSSINJS_STATISTIC: any
const enableStatistic = process.env.NODE_ENV !== 'production' || typeof CSSINJS_STATISTIC !== 'undefined'
let recording = true
/**
* This function will do as `Object.assign` in production. But will use Object.defineProperty:get to
* pass all value access in development. To support statistic field usage with alias token.
*/
export function merge<T extends object>(...objs: Partial<T>[]): T {
/* istanbul ignore next */
if (!enableStatistic) {
return Object.assign({}, ...objs)
}
recording = false
const ret = {} as T
objs.forEach(obj => {
const keys = Object.keys(obj)
keys.forEach(key => {
Object.defineProperty(ret, key, {
configurable: true,
enumerable: true,
get: () => (obj as any)[key]
})
})
})
recording = true
return ret
}
/** @private Internal Usage. Not use in your production. */
export const statistic: Record<string, { global: string[]; component: Record<string, string | number> }> = {}
/** @private Internal Usage. Not use in your production. */
// eslint-disable-next-line camelcase
export const _statistic_build_: typeof statistic = {}
/* istanbul ignore next */
function noop() {}
/** Statistic token usage case. Should use `merge` function if you do not want spread record. */
export default function statisticToken<T extends object>(token: T) {
let tokenKeys: Set<string> | undefined
let proxy = token
let flush: (componentName: string, componentToken: Record<string, string | number>) => void = noop
if (enableStatistic) {
tokenKeys = new Set<string>()
proxy = new Proxy(token, {
get(obj: any, prop: any) {
if (recording) {
tokenKeys!.add(prop)
}
return obj[prop]
}
})
flush = (componentName, componentToken) => {
statistic[componentName] = { global: Array.from(tokenKeys!), component: componentToken }
}
}
return { token: proxy, keys: tokenKeys, flush }
}

1
components/version.ts Normal file
View File

@ -0,0 +1 @@
export default '0.0.1'

View File

@ -14,7 +14,10 @@
"preview": "vitepress preview site"
},
"dependencies": {
"@ant-design/colors": "^7.0.0",
"@antd-tiny-vue/cssinjs": "^0.0.4",
"@ctrl/tinycolor": "^3.6.0",
"@vueuse/core": "^9.13.0",
"vue": "^3.2.0"
},
"devDependencies": {

View File

@ -1,14 +1,17 @@
lockfileVersion: 5.4
specifiers:
'@ant-design/colors': ^7.0.0
'@antd-tiny-vue/cssinjs': ^0.0.4
'@commitlint/cli': ^17.4.3
'@commitlint/config-conventional': ^17.4.3
'@ctrl/tinycolor': ^3.6.0
'@mistjs/eslint-config-vue-jsx': ^0.0.3
'@mistjs/tsconfig': ^1.0.0
'@mistjs/tsconfig-vue': ^0.0.3
'@types/node': ^18.13.0
'@vitejs/plugin-vue-jsx': ^3.0.0
'@vueuse/core': ^9.13.0
eslint: ^8.34.0
husky: ^8.0.3
lint-staged: ^13.1.2
@ -21,7 +24,10 @@ specifiers:
vue: ^3.2.0
dependencies:
'@ant-design/colors': 7.0.0
'@antd-tiny-vue/cssinjs': 0.0.4_vue@3.2.47
'@ctrl/tinycolor': 3.6.0
'@vueuse/core': 9.13.0_vue@3.2.47
vue: 3.2.47
devDependencies:
@ -165,6 +171,12 @@ packages:
'@jridgewell/trace-mapping': 0.3.9
dev: true
/@ant-design/colors/7.0.0:
resolution: {integrity: sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==}
dependencies:
'@ctrl/tinycolor': 3.6.0
dev: false
/@antd-tiny-vue/cssinjs/0.0.4_vue@3.2.47:
resolution: {integrity: sha512-o6eU9IN+nfzaeCLHaQ94FqgvZV7eHeyY/Qw0p7ETMOyEQup13LBb4feOQKHGtBKLRkeoTugpY6EhAuMhn10SYw==}
peerDependencies:
@ -642,6 +654,11 @@ packages:
'@jridgewell/trace-mapping': 0.3.9
dev: true
/@ctrl/tinycolor/3.6.0:
resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==}
engines: {node: '>=10'}
dev: false
/@docsearch/css/3.3.3:
resolution: {integrity: sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==}
dev: true
@ -1130,7 +1147,6 @@ packages:
/@types/web-bluetooth/0.0.16:
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
dev: true
/@typescript-eslint/eslint-plugin/5.51.0_z4swst3wuuqk4hlme4ajzslgh4:
resolution: {integrity: sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==}
@ -1441,11 +1457,9 @@ packages:
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/@vueuse/metadata/9.13.0:
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
dev: true
/@vueuse/shared/9.13.0_vue@3.2.47:
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
@ -1454,7 +1468,6 @@ packages:
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/JSONStream/1.3.5:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
@ -4841,7 +4854,6 @@ packages:
optional: true
dependencies:
vue: 3.2.47
dev: true
/vue-eslint-parser/9.1.0_eslint@8.34.0:
resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}