mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-07 13:48:31 +08:00
refactor(avatar, base icon, base close): ts
This commit is contained in:
parent
05690562fd
commit
37dff9426e
60
.eslintrc.js
60
.eslintrc.js
@ -1,31 +1,51 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'@vue/standard',
|
||||
'@vue/typescript/recommended',
|
||||
'plugin:markdown/recommended'
|
||||
],
|
||||
extends: ['plugin:markdown/recommended'],
|
||||
rules: {
|
||||
'vue/max-attributes-per-line': [
|
||||
2,
|
||||
{
|
||||
singleline: 20,
|
||||
multiline: {
|
||||
max: 1,
|
||||
allowFirstLine: false
|
||||
}
|
||||
}
|
||||
],
|
||||
'vue/no-multiple-template-root': 0,
|
||||
'vue/no-lone-template': 0,
|
||||
'vue/no-v-model-argument': 0,
|
||||
'no-void': 0
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: 'src/**/*.vue',
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'@vue/standard',
|
||||
'@vue/typescript/recommended'
|
||||
],
|
||||
rules: {
|
||||
'vue/max-attributes-per-line': [
|
||||
2,
|
||||
{
|
||||
singleline: 20,
|
||||
multiline: {
|
||||
max: 1,
|
||||
allowFirstLine: false
|
||||
}
|
||||
}
|
||||
],
|
||||
'vue/no-multiple-template-root': 0,
|
||||
'vue/no-lone-template': 0,
|
||||
'vue/no-v-model-argument': 0
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.ts', '*.js', '*.tsx'],
|
||||
extends: ['standard-with-typescript'],
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/strict-boolean-expressions': 0,
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 0
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['light.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-module-boundary-types': 0
|
||||
'@typescript-eslint/explicit-module-boundary-types': 0,
|
||||
'@typescript-eslint/explicit-function-return-type': 0
|
||||
}
|
||||
},
|
||||
{
|
||||
|
10
package.json
10
package.json
@ -49,6 +49,10 @@
|
||||
"prettier --write",
|
||||
"eslint --fix"
|
||||
],
|
||||
"*.tsx": [
|
||||
"prettier --write",
|
||||
"eslint --fix"
|
||||
],
|
||||
"*.vue": [
|
||||
"prettier --parser=vue --write",
|
||||
"eslint --fix"
|
||||
@ -83,12 +87,14 @@
|
||||
"babel-jest": "^26.6.2",
|
||||
"cross-env": "^5.2.1",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^7.0.0",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-config-standard-with-typescript": "^19.0.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-markdown": "^2.0.0-rc.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.2",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"husky": "^4.3.5",
|
||||
|
@ -1 +0,0 @@
|
||||
export { default } from './src/Close.vue'
|
1
src/_base/close/index.ts
Normal file
1
src/_base/close/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './src/Close'
|
@ -1,16 +1,4 @@
|
||||
<template>
|
||||
<n-base-icon
|
||||
class="n-base-close"
|
||||
:class="{
|
||||
'n-base-close--disabled': disabled
|
||||
}"
|
||||
>
|
||||
<close-icon />
|
||||
</n-base-icon>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
import { h, defineComponent } from 'vue'
|
||||
import { useStyle } from '../../../_mixins'
|
||||
import NBaseIcon from '../../icon'
|
||||
import { CloseIcon } from '../../icons'
|
||||
@ -18,10 +6,6 @@ import style from './styles/index.cssr.js'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BaseClose',
|
||||
components: {
|
||||
NBaseIcon,
|
||||
CloseIcon
|
||||
},
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
@ -30,6 +14,17 @@ export default defineComponent({
|
||||
},
|
||||
setup (props) {
|
||||
useStyle('BaseClose', style)
|
||||
return (
|
||||
<NBaseIcon
|
||||
class={[
|
||||
'n-base-close',
|
||||
{
|
||||
'n-base-close--disabled': props.disabled
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CloseIcon />
|
||||
</NBaseIcon>
|
||||
)
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,22 +0,0 @@
|
||||
import { cB, cM, c } from '../../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --close-color
|
||||
// --close-color-hover
|
||||
// --close-color-pressed
|
||||
// --close-color-disabled
|
||||
export default cB('base-close', `
|
||||
cursor: pointer;
|
||||
color: var(--close-color);
|
||||
`, [
|
||||
c('&:hover', {
|
||||
color: 'var(--close-color-hover)'
|
||||
}),
|
||||
c('&:active', {
|
||||
color: 'var(--close-color-pressed)'
|
||||
}),
|
||||
cM('disabled', {
|
||||
cursor: 'not-allowed!important',
|
||||
color: 'var(--close-color-disabled)'
|
||||
})
|
||||
])
|
26
src/_base/close/src/styles/index.cssr.ts
Normal file
26
src/_base/close/src/styles/index.cssr.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { cB, cM, c } from '../../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --close-color
|
||||
// --close-color-hover
|
||||
// --close-color-pressed
|
||||
// --close-color-disabled
|
||||
export default cB(
|
||||
'base-close',
|
||||
`
|
||||
cursor: pointer;
|
||||
color: var(--close-color);
|
||||
`,
|
||||
[
|
||||
c('&:hover', {
|
||||
color: 'var(--close-color-hover)'
|
||||
}),
|
||||
c('&:active', {
|
||||
color: 'var(--close-color-pressed)'
|
||||
}),
|
||||
cM('disabled', {
|
||||
cursor: 'not-allowed!important',
|
||||
color: 'var(--close-color-disabled)'
|
||||
})
|
||||
]
|
||||
)
|
@ -1 +0,0 @@
|
||||
export { default } from './src/Icon.vue'
|
1
src/_base/icon/index.ts
Normal file
1
src/_base/icon/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './src/Icon'
|
@ -1,9 +1,4 @@
|
||||
<template>
|
||||
<i class="n-base-icon"><slot /></i>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
import { h, defineComponent, renderSlot } from 'vue'
|
||||
import { useStyle } from '../../../_mixins'
|
||||
import style from './styles/index.cssr.js'
|
||||
|
||||
@ -11,6 +6,8 @@ export default defineComponent({
|
||||
name: 'BaseIcon',
|
||||
setup () {
|
||||
useStyle('BaseIcon', style)
|
||||
},
|
||||
render () {
|
||||
return <i class="n-base-icon">{renderSlot(this.$slots, 'default')}</i>
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,6 +1,8 @@
|
||||
import { c, cB } from '../../../../_utils/cssr'
|
||||
|
||||
export default cB('base-icon', `
|
||||
export default cB(
|
||||
'base-icon',
|
||||
`
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
line-height: 1em;
|
||||
@ -9,9 +11,11 @@ export default cB('base-icon', `
|
||||
position: relative;
|
||||
fill: currentColor;
|
||||
transform: translateZ(0);
|
||||
`, [
|
||||
c('svg', {
|
||||
height: '1em',
|
||||
width: '1em'
|
||||
})
|
||||
])
|
||||
`,
|
||||
[
|
||||
c('svg', {
|
||||
height: '1em',
|
||||
width: '1em'
|
||||
})
|
||||
]
|
||||
)
|
12
src/_base/index.ts
Normal file
12
src/_base/index.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export { default as NIconSwitchTransition } from './icon-switch-transition'
|
||||
export { default as NFadeInExpandTransition } from './fade-in-expand-transition'
|
||||
export { default as NBaseClose } from './close'
|
||||
export { default as NBaseIcon } from './icon'
|
||||
export { default as NBaseFocusDetector } from './focus-detector'
|
||||
export { default as NBaseLoading } from './loading'
|
||||
export { default as NBaseSelectMenu } from './select-menu'
|
||||
export { default as NBaseWave } from './wave'
|
||||
export { default as NBaseMenuMask } from './menu-mask'
|
||||
export { default as NBaseSelection } from './selection'
|
||||
export { default as NBaseSlotMachine } from './slot-machine'
|
||||
export { default as NBaseClear } from './clear'
|
@ -1,2 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
export { default as NAvatar } from './src/Avatar.vue'
|
2
src/avatar/index.ts
Normal file
2
src/avatar/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
/* istanbul ignore file */
|
||||
export { default as NAvatar } from './src/Avatar'
|
118
src/avatar/src/Avatar.tsx
Normal file
118
src/avatar/src/Avatar.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import {
|
||||
h,
|
||||
ref,
|
||||
computed,
|
||||
onUpdated,
|
||||
onMounted,
|
||||
defineComponent,
|
||||
PropType
|
||||
} from 'vue'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { avatarLight } from '../styles'
|
||||
import type { AvatarTheme } from '../styles'
|
||||
import { createKey } from '../../_utils'
|
||||
import style from './styles/index.cssr'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Avatar',
|
||||
props: {
|
||||
...(useTheme.props as ThemeProps<AvatarTheme>),
|
||||
size: {
|
||||
type: [String, Number] as PropType<
|
||||
number | 'tiny' | 'small' | 'medium' | 'large' | 'huge'
|
||||
>,
|
||||
default: 'medium'
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
circle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
round: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
let memoedTextHtml: string | null = null
|
||||
const textRef = ref<HTMLElement | null>(null)
|
||||
const selfRef = ref<HTMLElement | null>(null)
|
||||
const adjustText = (): void => {
|
||||
const { value: textEl } = textRef
|
||||
if (textEl) {
|
||||
if (memoedTextHtml === null || memoedTextHtml !== textEl.innerHTML) {
|
||||
memoedTextHtml = textEl.innerHTML
|
||||
const { value: selfEl } = selfRef
|
||||
if (selfEl) {
|
||||
const { offsetWidth: elWidth, offsetHeight: elHeight } = selfEl
|
||||
const { offsetWidth: textWidth, offsetHeight: textHeight } = textEl
|
||||
const radix = 0.9
|
||||
const ratio = Math.min(
|
||||
(elWidth / textWidth) * radix,
|
||||
(elHeight / textHeight) * radix,
|
||||
1
|
||||
)
|
||||
textEl.style.transform = `translateX(-50%) translateY(-50%) scale(${ratio})`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not Good Impl
|
||||
onMounted(() => adjustText())
|
||||
onUpdated(() => {
|
||||
console.log('updated')
|
||||
adjustText()
|
||||
})
|
||||
const themeRef = useTheme('Avatar', 'Avatar', style, avatarLight, props)
|
||||
return {
|
||||
textRef,
|
||||
selfRef,
|
||||
cssVars: computed(() => {
|
||||
const { size, round, circle } = props
|
||||
const {
|
||||
self: { borderRadius, fontSize, color },
|
||||
common: { cubicBezierEaseInOut }
|
||||
} = themeRef.value
|
||||
let height: string
|
||||
if (typeof size === 'number') {
|
||||
height = `${size}px`
|
||||
} else {
|
||||
height = themeRef.value.self[createKey('height', size)]
|
||||
}
|
||||
return {
|
||||
'--font-size': fontSize,
|
||||
'--border-radius': round || circle ? '50%' : borderRadius,
|
||||
'--color': color,
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--size': height
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { $slots, src } = this
|
||||
return (
|
||||
<span ref="selfRef" class="n-avatar" style={this.cssVars as any}>
|
||||
{!$slots.default && src ? (
|
||||
<img src={src} />
|
||||
) : (
|
||||
<span
|
||||
ref="textRef"
|
||||
class="n-avatar__text"
|
||||
style={{ background: this.color }}
|
||||
>
|
||||
{$slots}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})
|
@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<span ref="selfRef" class="n-avatar" :style="cssVars">
|
||||
<img v-if="!$slots.default && src" :src="src">
|
||||
<slot v-else-if="$slots.icon" name="icon" />
|
||||
<span
|
||||
v-else
|
||||
ref="textRef"
|
||||
class="n-avatar__text"
|
||||
:style="{
|
||||
background: color
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, onUpdated, onMounted, defineComponent } from 'vue'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import { avatarLight } from '../styles'
|
||||
import { createKey } from '../../_utils'
|
||||
import { validSize } from './config'
|
||||
import style from './styles/index.cssr.js'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Avatar',
|
||||
props: {
|
||||
...useTheme.props,
|
||||
size: {
|
||||
validator (value) {
|
||||
return validSize.includes(value) || typeof value === 'number'
|
||||
},
|
||||
default: 'medium'
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
circle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
round: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
let memoedTextHtml = null
|
||||
const textRef = ref(null)
|
||||
const selfRef = ref(null)
|
||||
const adjustText = () => {
|
||||
const { value: textEl } = textRef
|
||||
if (textEl) {
|
||||
if (memoedTextHtml === null || memoedTextHtml !== textEl.innerHTML) {
|
||||
memoedTextHtml = textEl.innerHTML
|
||||
const { value: selfEl } = selfRef
|
||||
const { offsetWidth: elWidth, offsetHeight: elHeight } = selfEl
|
||||
const { offsetWidth: textWidth, offsetHeight: textHeight } = textEl
|
||||
const radix = 0.9
|
||||
const ratio = Math.min(
|
||||
(elWidth / textWidth) * radix,
|
||||
(elHeight / textHeight) * radix,
|
||||
1
|
||||
)
|
||||
textEl.style.transform = `translateX(-50%) translateY(-50%) scale(${ratio})`
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not Good Impl
|
||||
onMounted(() => adjustText())
|
||||
onUpdated(() => {
|
||||
console.log('updated')
|
||||
adjustText()
|
||||
})
|
||||
const themeRef = useTheme('Avatar', 'Avatar', style, avatarLight, props)
|
||||
return {
|
||||
textRef,
|
||||
selfRef,
|
||||
cssVars: computed(() => {
|
||||
const { size, round, circle } = props
|
||||
const {
|
||||
self: {
|
||||
borderRadius,
|
||||
fontSize,
|
||||
color,
|
||||
[createKey('height', String(size))]: height
|
||||
},
|
||||
common: { cubicBezierEaseInOut }
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--font-size': fontSize,
|
||||
'--border-radius': round || circle ? '50%' : borderRadius,
|
||||
'--color': color,
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--size': height || `${size}px`
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1 +0,0 @@
|
||||
export const validSize = ['tiny', 'small', 'medium', 'large', 'huge']
|
@ -6,7 +6,9 @@ import { c, cE, cB } from '../../../_utils/cssr'
|
||||
// --color
|
||||
// --bezier
|
||||
// --size
|
||||
export default cB('avatar', `
|
||||
export default cB(
|
||||
'avatar',
|
||||
`
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
color: #FFF;
|
||||
@ -20,23 +22,28 @@ export default cB('avatar', `
|
||||
transition:
|
||||
background-color .3s var(--bezier),
|
||||
color .3s var(--bezier);
|
||||
`, [
|
||||
c('img', {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}),
|
||||
cE('text', `
|
||||
`,
|
||||
[
|
||||
c('img', {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}),
|
||||
cE(
|
||||
'text',
|
||||
`
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
`),
|
||||
cB('icon', {
|
||||
verticalAlign: 'bottom',
|
||||
fontSize: 'var(--size)'
|
||||
}),
|
||||
cE('text', {
|
||||
lineHeight: 1.25
|
||||
})
|
||||
])
|
||||
`
|
||||
),
|
||||
cB('icon', {
|
||||
verticalAlign: 'bottom',
|
||||
fontSize: 'var(--size)'
|
||||
}),
|
||||
cE('text', {
|
||||
lineHeight: 1.25
|
||||
})
|
||||
]
|
||||
)
|
@ -1,6 +1,7 @@
|
||||
import { commonDark } from '../../_styles/new-common'
|
||||
import { AvatarTheme } from './light'
|
||||
|
||||
export default {
|
||||
const avatarDark: AvatarTheme = {
|
||||
name: 'Avatar',
|
||||
common: commonDark,
|
||||
self (vars) {
|
||||
@ -26,3 +27,5 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default avatarDark
|
@ -1,2 +0,0 @@
|
||||
export { default as avatarDark } from './dark.js'
|
||||
export { default as avatarLight } from './light.js'
|
3
src/avatar/styles/index.ts
Normal file
3
src/avatar/styles/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as avatarDark } from './dark'
|
||||
export { default as avatarLight } from './light'
|
||||
export type { AvatarThemeVars, AvatarTheme } from './light'
|
@ -1,28 +0,0 @@
|
||||
import { commonLight } from '../../_styles/new-common'
|
||||
|
||||
export default {
|
||||
name: 'Avatar',
|
||||
common: commonLight,
|
||||
self (vars) {
|
||||
const {
|
||||
borderRadius,
|
||||
avatarColorOverlay,
|
||||
fontSize,
|
||||
heightTiny,
|
||||
heightSmall,
|
||||
heightMedium,
|
||||
heightLarge,
|
||||
heightHuge
|
||||
} = vars
|
||||
return {
|
||||
borderRadius,
|
||||
fontSize,
|
||||
heightTiny,
|
||||
heightSmall,
|
||||
heightMedium,
|
||||
heightLarge,
|
||||
heightHuge,
|
||||
color: avatarColorOverlay
|
||||
}
|
||||
}
|
||||
}
|
37
src/avatar/styles/light.ts
Normal file
37
src/avatar/styles/light.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { commonLight } from '../../_styles/new-common'
|
||||
import type { ThemeCommonVars } from '../../_styles/new-common'
|
||||
import type { Theme } from '../../_mixins'
|
||||
|
||||
const self = (vars: ThemeCommonVars) => {
|
||||
const {
|
||||
borderRadius,
|
||||
avatarColorOverlay,
|
||||
fontSize,
|
||||
heightTiny,
|
||||
heightSmall,
|
||||
heightMedium,
|
||||
heightLarge,
|
||||
heightHuge
|
||||
} = vars
|
||||
return {
|
||||
borderRadius,
|
||||
fontSize,
|
||||
heightTiny,
|
||||
heightSmall,
|
||||
heightMedium,
|
||||
heightLarge,
|
||||
heightHuge,
|
||||
color: avatarColorOverlay
|
||||
}
|
||||
}
|
||||
|
||||
export type AvatarThemeVars = ReturnType<typeof self>
|
||||
|
||||
const avatarLight: Theme<AvatarThemeVars> = {
|
||||
name: 'Avatar',
|
||||
common: commonLight,
|
||||
self
|
||||
}
|
||||
|
||||
export default avatarLight
|
||||
export type AvatarTheme = typeof avatarLight
|
@ -6,6 +6,9 @@
|
||||
"strictNullChecks": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment",
|
||||
"module": "ES6",
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES6",
|
||||
|
@ -36,5 +36,9 @@ module.exports = {
|
||||
})
|
||||
]
|
||||
}
|
||||
},
|
||||
esbuild: {
|
||||
jsxFactory: 'h',
|
||||
jsxFragment: 'Fragment'
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user