mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-17 13:20:52 +08:00
refactor(mixins, utils, styles, index): typescript
This commit is contained in:
parent
187381b175
commit
a0921fab1b
@ -66,6 +66,7 @@
|
||||
"@rollup/plugin-node-resolve": "^10.0.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@vitejs/plugin-vue": "^1.0.4",
|
||||
"@vue/compiler-sfc": "^3.0.5",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
@ -93,7 +94,7 @@
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-vue": "^6.0.0-beta.11",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"typescript": "^4.0.5",
|
||||
"typescript": "^4.1.3",
|
||||
"vite": "^2.0.0-beta.23",
|
||||
"vue-jest": "^5.0.0-alpha.5",
|
||||
"vue-router": "^4.0.0-rc.1"
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { cB, c, cE } from '../../../../_utils/cssr'
|
||||
import createIconSwitchTransition from '../../../../_styles/transitions/icon-switch'
|
||||
|
||||
// vars:
|
||||
// --bezier
|
||||
// --color
|
||||
// --size
|
||||
// --color-hover
|
||||
// --color-pressed
|
||||
export default cB('base-clear', {
|
||||
flexShrink: 0,
|
||||
height: '1em',
|
||||
width: '1em',
|
||||
position: 'relative'
|
||||
}, [
|
||||
c('>', [
|
||||
cE('clear', {
|
||||
fontSize: 'var(--size)',
|
||||
cursor: 'pointer',
|
||||
color: 'var(--color)',
|
||||
transition: 'color .3s var(--bezier)'
|
||||
}, [
|
||||
c('&:hover', {
|
||||
color: 'var(--color-hover)!important'
|
||||
}),
|
||||
c('&:active', {
|
||||
color: 'var(--color-pressed)!important'
|
||||
})
|
||||
]),
|
||||
cE('placeholder', {
|
||||
display: 'flex'
|
||||
}),
|
||||
cE('clear, placeholder', {
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: 'translateX(-50%) translateY(-50%)'
|
||||
}, [
|
||||
createIconSwitchTransition({
|
||||
originalTransform: 'translateX(-50%) translateY(-50%)',
|
||||
left: '50%',
|
||||
top: '50%'
|
||||
})
|
||||
])
|
||||
])
|
||||
])
|
@ -1,14 +0,0 @@
|
||||
import { inject, computed } from 'vue'
|
||||
|
||||
export default function useConfig (props) {
|
||||
const NConfigProvider = inject('NConfigProvider', null)
|
||||
return {
|
||||
NConfigProvider,
|
||||
mergedBordered: computed(() => {
|
||||
const { bordered } = props
|
||||
if (bordered !== undefined) return bordered
|
||||
return NConfigProvider?.mergedBordered || true
|
||||
}),
|
||||
namespace: computed(() => NConfigProvider?.namespace)
|
||||
}
|
||||
}
|
19
src/_mixins/use-config.ts
Normal file
19
src/_mixins/use-config.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { inject, computed } from 'vue'
|
||||
import { ConfigProviderInjection } from '../config-provider'
|
||||
|
||||
interface UseConfigProps {
|
||||
bordered?: boolean
|
||||
}
|
||||
|
||||
export default function useConfig (props: UseConfigProps) {
|
||||
const NConfigProvider = inject<ConfigProviderInjection | null>('NConfigProvider', null)
|
||||
return {
|
||||
NConfigProvider,
|
||||
mergedBordered: computed(() => {
|
||||
const { bordered } = props
|
||||
if (bordered !== undefined) return bordered
|
||||
return NConfigProvider?.mergedBordered || true
|
||||
}),
|
||||
namespace: computed(() => NConfigProvider?.mergedNamespace)
|
||||
}
|
||||
}
|
@ -1,8 +1,26 @@
|
||||
import { computed, inject, provide, onBeforeUnmount } from 'vue'
|
||||
|
||||
export default function useFormItem (props, options = {}) {
|
||||
const { defaultSize = 'medium', mergedSize } = options
|
||||
const NFormItem = inject('NFormItem', null)
|
||||
interface UseFormItemOptions {
|
||||
defaultSize?: string
|
||||
mergedSize?: (formItem: FormItemInjection | null) => string
|
||||
}
|
||||
|
||||
interface FormItemInjection {
|
||||
size: string | undefined
|
||||
mergedSize: string
|
||||
restoreValidation: () => void
|
||||
handleContentBlur: () => void
|
||||
handleContentFocus: () => void
|
||||
handleContentInput: () => void
|
||||
handleContentChange: () => void
|
||||
}
|
||||
|
||||
interface UseFormItemProps {
|
||||
size?: string
|
||||
}
|
||||
|
||||
export default function useFormItem (props: UseFormItemProps, { defaultSize = 'medium', mergedSize }: UseFormItemOptions = {}) {
|
||||
const NFormItem = inject<FormItemInjection | null>('NFormItem', null)
|
||||
provide('NFormItem', null)
|
||||
const mergedSizeRef = computed(
|
||||
mergedSize
|
@ -1,18 +0,0 @@
|
||||
import { inject, getCurrentInstance, computed } from 'vue'
|
||||
import { warn } from '../_utils'
|
||||
|
||||
export default function useHljs (props) {
|
||||
const NConfigProvider = inject('NConfigProvider', {})
|
||||
const vm = getCurrentInstance().proxy
|
||||
if (
|
||||
__DEV__ &&
|
||||
!props.hljs &&
|
||||
!NConfigProvider.mergedHljs &&
|
||||
!vm.$naive.hljs
|
||||
) {
|
||||
warn('code', 'hljs is not set.')
|
||||
}
|
||||
return computed(() => {
|
||||
return props.hljs || NConfigProvider.mergedHljs || vm.$naive.hljs
|
||||
})
|
||||
}
|
23
src/_mixins/use-hljs.ts
Normal file
23
src/_mixins/use-hljs.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { inject, getCurrentInstance, computed } from 'vue'
|
||||
import { ConfigProviderInjection } from '../config-provider'
|
||||
import { warn } from '../_utils'
|
||||
|
||||
interface UseHljsProps {
|
||||
hljs?: any
|
||||
}
|
||||
|
||||
export default function useHljs (props: UseHljsProps) {
|
||||
const NConfigProvider = inject<ConfigProviderInjection | null>('NConfigProvider', null)
|
||||
const vm = getCurrentInstance()?.proxy as any
|
||||
if (
|
||||
__DEV__ &&
|
||||
!props.hljs &&
|
||||
!NConfigProvider?.mergedHljs &&
|
||||
!vm.$naive.hljs
|
||||
) {
|
||||
warn('code', 'hljs is not set.')
|
||||
}
|
||||
return computed(() => {
|
||||
return props.hljs || NConfigProvider?.mergedHljs || vm.$naive.hljs
|
||||
})
|
||||
}
|
@ -1,25 +1,26 @@
|
||||
import { inject, computed, getCurrentInstance } from 'vue'
|
||||
import { enUS, dateEnUS } from '../locales'
|
||||
import { ConfigProviderInjection } from '../config-provider'
|
||||
|
||||
export default function createLocaleMixin (ns) {
|
||||
const vm = getCurrentInstance().proxy
|
||||
const NConfigProvider = inject('NConfigProvider', {})
|
||||
export default function createLocaleMixin (ns: keyof typeof enUS) {
|
||||
const vm = getCurrentInstance()?.proxy
|
||||
const NConfigProvider = inject<ConfigProviderInjection | null>('NConfigProvider', null)
|
||||
const localeRef = computed(() => {
|
||||
const { mergedLocale } = NConfigProvider
|
||||
const { mergedLocale } = NConfigProvider || {}
|
||||
if (mergedLocale) return mergedLocale[ns]
|
||||
const { mergedLanguage } = NConfigProvider
|
||||
const { mergedLanguage } = NConfigProvider || {}
|
||||
if (mergedLanguage) {
|
||||
// legacy start
|
||||
const {
|
||||
$naive: { locales = [], fallbackLocale }
|
||||
} = vm
|
||||
} = vm as any
|
||||
return locales[mergedLanguage ?? fallbackLocale][ns]
|
||||
} else {
|
||||
return enUS[ns]
|
||||
}
|
||||
})
|
||||
const dateLocaleRef = computed(() => {
|
||||
const { mergedDateLocale } = NConfigProvider
|
||||
const { mergedDateLocale } = NConfigProvider || {}
|
||||
return mergedDateLocale ?? dateEnUS
|
||||
})
|
||||
return {
|
@ -1,3 +1,4 @@
|
||||
import { CNode } from 'css-render'
|
||||
import { onBeforeMount } from 'vue'
|
||||
import globalStyle from '../_styles/global/index.cssr.js'
|
||||
|
||||
@ -5,7 +6,7 @@ globalStyle.mount({
|
||||
id: 'naive-ui-global'
|
||||
})
|
||||
|
||||
export default function useStyle (mountId, style) {
|
||||
export default function useStyle (mountId: string, style: CNode) {
|
||||
onBeforeMount(() => {
|
||||
style.mount({
|
||||
id: mountId
|
@ -1,11 +1,20 @@
|
||||
import { inject, computed, onBeforeMount } from 'vue'
|
||||
import { merge } from 'lodash-es'
|
||||
import globalStyle from '../_styles/global/index.cssr.js'
|
||||
import { CNode } from 'css-render'
|
||||
import { ConfigProviderInjection, Theme, ThemeOverrides } from '../config-provider/index.js'
|
||||
|
||||
globalStyle.mount({
|
||||
id: 'naive-ui-global'
|
||||
})
|
||||
function useTheme (resolveId, mountId, style, defaultTheme, props) {
|
||||
|
||||
interface UseThemeProps {
|
||||
unstableTheme: Theme
|
||||
unstableThemeOverrides: ThemeOverrides
|
||||
builtinThemeOverrides: ThemeOverrides
|
||||
}
|
||||
|
||||
function useTheme (resolveId: string, mountId: string, style: CNode | undefined, defaultTheme: Theme, props: UseThemeProps) {
|
||||
if (style) {
|
||||
onBeforeMount(() => {
|
||||
style.mount({
|
||||
@ -13,7 +22,7 @@ function useTheme (resolveId, mountId, style, defaultTheme, props) {
|
||||
})
|
||||
})
|
||||
}
|
||||
const NConfigProvider = inject('NConfigProvider', {})
|
||||
const NConfigProvider = inject<ConfigProviderInjection | null>('NConfigProvider', null)
|
||||
const mergedThemeRef = computed(() => {
|
||||
// keep props to make theme overrideable
|
||||
const {
|
||||
@ -27,18 +36,18 @@ function useTheme (resolveId, mountId, style, defaultTheme, props) {
|
||||
} = selfOverrides
|
||||
const {
|
||||
mergedUnstableTheme: {
|
||||
common: injectedGlobalCommon,
|
||||
common: injectedGlobalCommon = undefined,
|
||||
[resolveId]: {
|
||||
common: injectedCommon,
|
||||
self: injectedSelf,
|
||||
common: injectedCommon = undefined,
|
||||
self: injectedSelf = undefined,
|
||||
peers: injectedPeers = {}
|
||||
} = {}
|
||||
} = {},
|
||||
mergedUnstableThemeOverrides: {
|
||||
common: injectedGlobalCommonOverrides,
|
||||
common: injectedGlobalCommonOverrides = undefined,
|
||||
[resolveId]: injectedSelfOverrides = {}
|
||||
} = {}
|
||||
} = NConfigProvider
|
||||
} = NConfigProvider || {}
|
||||
const {
|
||||
common: injectedCommonOverrides,
|
||||
peers: injectedPeersOverrides = {}
|
@ -16,7 +16,7 @@ const base = {
|
||||
alpha4: '0.38',
|
||||
alpha5: '0.28',
|
||||
|
||||
alphaClose: '0.52',
|
||||
alphaClose: 0.52,
|
||||
|
||||
alphaDisabled: '0.6',
|
||||
alphaDisabledInput: '0.06',
|
||||
@ -78,7 +78,7 @@ function overlay (alpha) {
|
||||
function neutral (alpha) {
|
||||
const overlayRgba = Array.from(baseInvertBackgroundRgb)
|
||||
overlayRgba[3] = Number(alpha)
|
||||
return composite(baseBackgroundRgb, overlayRgba)
|
||||
return composite(baseBackgroundRgb, overlayRgba as any)
|
||||
}
|
||||
const derived = {
|
||||
...commonVariables,
|
||||
@ -147,17 +147,17 @@ const derived = {
|
||||
borderColorOverlay: overlay(base.alphaBorder),
|
||||
|
||||
// close
|
||||
closeColorHover: neutral(base.alphaClose * 1.25),
|
||||
closeColorHoverOverlay: overlay(base.alphaClose * 1.25),
|
||||
closeColor: neutral(base.alphaClose),
|
||||
closeColorOverlay: overlay(base.alphaClose),
|
||||
closeColorPressed: neutral(base.alphaClose * 0.8),
|
||||
closeColorPressedOverlay: overlay(base.alphaClose * 0.8),
|
||||
closeColorHover: neutral(Number(base.alphaClose) * 1.25),
|
||||
closeColorHoverOverlay: overlay(Number(base.alphaClose) * 1.25),
|
||||
closeColor: neutral(Number(base.alphaClose)),
|
||||
closeColorOverlay: overlay(Number(base.alphaClose)),
|
||||
closeColorPressed: neutral(Number(base.alphaClose) * 0.8),
|
||||
closeColorPressedOverlay: overlay(Number(base.alphaClose) * 0.8),
|
||||
closeColorDisabled: neutral(base.alpha4),
|
||||
closeColorDisabledOverlay: overlay(base.alpha4),
|
||||
closeOpacity: base.alphaClose,
|
||||
closeOpacityHover: base.alphaClose * 1.25,
|
||||
closeOpacityPressed: base.alphaClose * 0.8,
|
||||
closeOpacity: Number(base.alphaClose),
|
||||
closeOpacityHover: Number(base.alphaClose) * 1.25,
|
||||
closeOpacityPressed: Number(base.alphaClose) * 0.8,
|
||||
|
||||
scrollbarColorOverlay: overlay(base.alphaScrollbar),
|
||||
scrollbarColorHoverOverlay: overlay(base.alphaScrollbarHover),
|
@ -80,7 +80,7 @@ function overlay (alpha) {
|
||||
function neutral (alpha) {
|
||||
const overlayRgba = Array.from(baseInvertBackgroundRgb)
|
||||
overlayRgba[3] = Number(alpha)
|
||||
return composite(baseBackgroundRgb, overlayRgba)
|
||||
return composite(baseBackgroundRgb, overlayRgba as any)
|
||||
}
|
||||
const derived = {
|
||||
...commonVariables,
|
||||
@ -149,17 +149,17 @@ const derived = {
|
||||
borderColorOverlay: overlay(base.alphaBorder),
|
||||
|
||||
// close
|
||||
closeColorHover: neutral(base.alphaClose * 0.8),
|
||||
closeColorHoverOverlay: overlay(base.alphaClose * 0.8),
|
||||
closeColor: neutral(base.alphaClose),
|
||||
closeColorOverlay: overlay(base.alphaClose),
|
||||
closeColorPressed: neutral(base.alphaClose * 1.25),
|
||||
closeColorPressedOverlay: overlay(base.alphaClose * 1.25),
|
||||
closeColorHover: neutral(Number(base.alphaClose) * 0.8),
|
||||
closeColorHoverOverlay: overlay(Number(base.alphaClose) * 0.8),
|
||||
closeColor: neutral(Number(base.alphaClose)),
|
||||
closeColorOverlay: overlay(Number(base.alphaClose)),
|
||||
closeColorPressed: neutral(Number(base.alphaClose) * 1.25),
|
||||
closeColorPressedOverlay: overlay(Number(base.alphaClose) * 1.25),
|
||||
closeColorDisabled: neutral(base.alpha4),
|
||||
closeColorDisabledOverlay: overlay(base.alpha4),
|
||||
closeOpacity: base.alphaClose,
|
||||
closeOpacityHover: base.alphaClose * 0.8,
|
||||
closeOpacityPressed: base.alphaClose * 1.25,
|
||||
closeOpacity: Number(base.alphaClose),
|
||||
closeOpacityHover: Number(base.alphaClose) * 0.8,
|
||||
closeOpacityPressed: Number(base.alphaClose) * 1.25,
|
||||
|
||||
scrollbarColorOverlay: overlay(base.alphaScrollbar),
|
||||
scrollbarColorHoverOverlay: overlay(base.alphaScrollbarHover),
|
@ -3,6 +3,15 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseInOut } = commonVariables
|
||||
|
||||
interface FadeDownTransitionOptions {
|
||||
name?: string
|
||||
fromOffset?: string
|
||||
enterDuration?: string
|
||||
leaveDuration?: string
|
||||
enterCubicBezier?: string
|
||||
leaveCubicBezier?: string
|
||||
}
|
||||
|
||||
export default function ({
|
||||
name = 'fade-down',
|
||||
fromOffset = '-4px',
|
||||
@ -10,7 +19,7 @@ export default function ({
|
||||
leaveDuration = '.3s',
|
||||
enterCubicBezier = cubicBezierEaseInOut,
|
||||
leaveCubicBezier = cubicBezierEaseInOut
|
||||
} = {}) {
|
||||
}: FadeDownTransitionOptions = {}) {
|
||||
return [
|
||||
c(
|
||||
`&.${namespace}-${name}-transition-enter-from, &.${namespace}-${name}-transition-leave-to`,
|
@ -7,6 +7,16 @@ const {
|
||||
cubicBezierEaseIn
|
||||
} = commonVariables
|
||||
|
||||
interface FadeInHeightExpandTransitionOption {
|
||||
overflow?: string
|
||||
duration?: string
|
||||
originalTransition?: string
|
||||
leavingDelay?: string
|
||||
foldPadding?: boolean
|
||||
enterToProps?: Record<string, string | number> | null
|
||||
leaveToProps?: Record<string, string | number> | null
|
||||
}
|
||||
|
||||
export default function ({
|
||||
overflow = 'hidden',
|
||||
duration = '.3s',
|
||||
@ -15,7 +25,7 @@ export default function ({
|
||||
foldPadding = false,
|
||||
enterToProps = null,
|
||||
leaveToProps = null
|
||||
} = {}) {
|
||||
}: FadeInHeightExpandTransitionOption = {}) {
|
||||
return [
|
||||
c(
|
||||
`&.${namespace}-fade-in-height-expand-transition-leave-from, &.${namespace}-fade-in-height-expand-transition-enter-to`,
|
@ -7,13 +7,21 @@ const {
|
||||
transformDebounceScale
|
||||
} = commonVariables
|
||||
|
||||
interface FadeInScaleUpTransitionOptions {
|
||||
transformOrigin?: string
|
||||
duration?: string
|
||||
enterScale?: string
|
||||
originalTransform?: string
|
||||
originalTransition?: string
|
||||
}
|
||||
|
||||
export default function ({
|
||||
transformOrigin = 'inherit',
|
||||
duration = '.2s',
|
||||
enterScale = '.9',
|
||||
originalTransform = '',
|
||||
originalTransition = ''
|
||||
} = {}) {
|
||||
}: FadeInScaleUpTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-fade-in-scale-up-transition-leave-active`, {
|
||||
transformOrigin,
|
@ -3,7 +3,12 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseInOut } = commonVariables
|
||||
|
||||
export default function ({ duration = '.2s', delay = '.1s' } = {}) {
|
||||
interface FadeInWidthExpandTransition {
|
||||
duration?: string
|
||||
delay?: string
|
||||
}
|
||||
|
||||
export default function ({ duration = '.2s', delay = '.1s' }: FadeInWidthExpandTransition = {}) {
|
||||
return [
|
||||
c(
|
||||
`&.${namespace}-fade-in-width-expand-transition-leave-from, &.${namespace}-fade-in-width-expand-transition-enter-to`,
|
@ -3,13 +3,21 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseInOut } = commonVariables
|
||||
|
||||
interface FadeInTransitionOptions {
|
||||
name?: string
|
||||
enterDuration?: string
|
||||
leaveDuration?: string
|
||||
enterCubicBezier?: string
|
||||
leaveCubicBezier?: string
|
||||
}
|
||||
|
||||
export default function ({
|
||||
name = 'fade-in',
|
||||
enterDuration = '0.2s',
|
||||
leaveDuration = '0.2s',
|
||||
enterCubicBezier = cubicBezierEaseInOut,
|
||||
leaveCubicBezier = cubicBezierEaseInOut
|
||||
} = {}) {
|
||||
}: FadeInTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-${name}-transition-enter-active`, {
|
||||
transition: `all ${enterDuration} ${enterCubicBezier}!important`
|
@ -3,7 +3,11 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseOut } = commonVariables
|
||||
|
||||
export default function fadeUpWidthExpandTransition ({ duration = '.2s' } = {}) {
|
||||
interface FadeUpWidthExpandTransition {
|
||||
duration?: string
|
||||
}
|
||||
|
||||
export default function fadeUpWidthExpandTransition ({ duration = '.2s' }: FadeUpWidthExpandTransition = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-fade-up-width-expand-transition-leave-active`, {
|
||||
transition: `
|
@ -1,12 +1,19 @@
|
||||
import { c, namespace } from '../../_utils/cssr'
|
||||
import commonVariables from '../new-common/_common'
|
||||
|
||||
interface IconSwitchTransitionOptions {
|
||||
originalTransform?: string
|
||||
left?: string | number
|
||||
top?: string | number
|
||||
transition?: string
|
||||
}
|
||||
|
||||
export default function ({
|
||||
originalTransform = '',
|
||||
left = 0,
|
||||
top = 0,
|
||||
transition = `all .3s ${commonVariables.cubicBezierEaseInOut} !important`
|
||||
} = {}) {
|
||||
}: IconSwitchTransitionOptions = {}) {
|
||||
return [
|
||||
c(
|
||||
`&.${namespace}-icon-switch-transition-enter-from, &.${namespace}-icon-switch-transition-leave-to`,
|
@ -3,11 +3,17 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseIn, cubicBezierEaseOut } = commonVariables
|
||||
|
||||
interface SlideInFromBottomTransitionOptions {
|
||||
duration?: string
|
||||
leaveDuration?: string
|
||||
name?: String
|
||||
}
|
||||
|
||||
export default function ({
|
||||
duration = '0.3s',
|
||||
leaveDuration = '0.2s',
|
||||
name = 'slide-in-from-bottom'
|
||||
} = {}) {
|
||||
}: SlideInFromBottomTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-${name}-transition-leave-active`, {
|
||||
transition: `transform ${leaveDuration} ${cubicBezierEaseIn}`
|
@ -3,11 +3,17 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseIn, cubicBezierEaseOut } = commonVariables
|
||||
|
||||
interface SlideInFromLeftTransitionOptions {
|
||||
duration?: string
|
||||
leaveDuration?: string
|
||||
name?: String
|
||||
}
|
||||
|
||||
export default function ({
|
||||
duration = '0.3s',
|
||||
leaveDuration = '0.2s',
|
||||
name = 'slide-in-from-left'
|
||||
} = {}) {
|
||||
}: SlideInFromLeftTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-${name}-transition-leave-active`, {
|
||||
transition: `transform ${leaveDuration} ${cubicBezierEaseIn}`
|
@ -3,11 +3,17 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseIn, cubicBezierEaseOut } = commonVariables
|
||||
|
||||
interface SlideInFromRightTransitionOptions {
|
||||
duration?: string
|
||||
leaveDuration?: string
|
||||
name?: String
|
||||
}
|
||||
|
||||
export default function ({
|
||||
duration = '0.3s',
|
||||
leaveDuration = '0.2s',
|
||||
name = 'slide-in-from-right'
|
||||
} = {}) {
|
||||
}: SlideInFromRightTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-${name}-transition-leave-active`, {
|
||||
transition: `transform ${leaveDuration} ${cubicBezierEaseIn}`
|
@ -3,11 +3,17 @@ import commonVariables from '../new-common/_common'
|
||||
|
||||
const { cubicBezierEaseIn, cubicBezierEaseOut } = commonVariables
|
||||
|
||||
interface SlideInFromTopTransitionOptions {
|
||||
duration?: string
|
||||
leaveDuration?: string
|
||||
name?: String
|
||||
}
|
||||
|
||||
export default function ({
|
||||
duration = '0.3s',
|
||||
leaveDuration = '0.2s',
|
||||
name = 'slide-in-from-top'
|
||||
} = {}) {
|
||||
}: SlideInFromTopTransitionOptions = {}) {
|
||||
return [
|
||||
c(`&.${namespace}-${name}-transition-leave-active`, {
|
||||
transition: `transform ${leaveDuration} ${cubicBezierEaseIn}`
|
@ -1,9 +1,9 @@
|
||||
import { composite } from 'seemly'
|
||||
|
||||
export function createHoverColor (rgb) {
|
||||
export function createHoverColor (rgb: string) {
|
||||
return composite(rgb, [255, 255, 255, 0.16])
|
||||
}
|
||||
|
||||
export function createPressedColor (rgb) {
|
||||
export function createPressedColor (rgb: string) {
|
||||
return composite(rgb, [0, 0, 0, 0.12])
|
||||
}
|
@ -3,43 +3,41 @@ import {
|
||||
watch,
|
||||
onMounted,
|
||||
inject,
|
||||
toRef,
|
||||
Ref,
|
||||
getCurrentInstance,
|
||||
onBeforeUnmount
|
||||
} from 'vue'
|
||||
|
||||
export function useInjectionRef (injectionName, key, fallback) {
|
||||
const injection = inject(injectionName)
|
||||
if (!injection && arguments.length > 2) return fallback
|
||||
return toRef(injection, key)
|
||||
}
|
||||
|
||||
// injection.collection {
|
||||
// key1: [insta, instb]
|
||||
// key2: [instc]
|
||||
// }
|
||||
export function useInjectionInstanceCollection (
|
||||
injectionName,
|
||||
collectionKey,
|
||||
registerKeyRef
|
||||
injectionName: string,
|
||||
collectionKey: string,
|
||||
registerKeyRef: Ref<any>
|
||||
) {
|
||||
const injection = inject(injectionName, null)
|
||||
const injection = inject<any | null>(injectionName, null)
|
||||
if (injection === null) return
|
||||
const vm = getCurrentInstance().proxy
|
||||
const vm = getCurrentInstance()?.proxy
|
||||
watch(registerKeyRef, registerInstance)
|
||||
registerInstance(registerKeyRef.value)
|
||||
onBeforeUnmount(() => {
|
||||
registerInstance(undefined, registerKeyRef.value)
|
||||
})
|
||||
function registerInstance (key, oldKey) {
|
||||
function registerInstance (key?: string, oldKey?: string) {
|
||||
const collection = injection[collectionKey]
|
||||
if (oldKey !== undefined) removeInstance(collection, oldKey)
|
||||
if (key !== undefined) addInstance(collection, key)
|
||||
}
|
||||
function removeInstance (collection, key) {
|
||||
function removeInstance (collection: Record<string, any[]>, key: string) {
|
||||
if (!collection[key]) collection[key] = []
|
||||
collection[key].splice(
|
||||
collection[key].findIndex((instance) => instance === vm),
|
||||
1
|
||||
)
|
||||
}
|
||||
function addInstance (collection, key) {
|
||||
function addInstance (collection: Record<string, any[]>, key: string) {
|
||||
if (!collection[key]) collection[key] = []
|
||||
if (!~collection[key].findIndex((instance) => instance === vm)) {
|
||||
collection[key].push(vm)
|
||||
@ -47,8 +45,12 @@ export function useInjectionInstanceCollection (
|
||||
}
|
||||
}
|
||||
|
||||
export function useInjectionCollection (injectionName, collectionKey, valueRef) {
|
||||
const injection = inject(injectionName, null)
|
||||
// injection.collection {
|
||||
// key1: [insta.value, instb.value]
|
||||
// key2: [instc.value]
|
||||
// }
|
||||
export function useInjectionCollection (injectionName: string, collectionKey: string, valueRef: Ref<any>) {
|
||||
const injection = inject<Record<any, any[]> | null>(injectionName, null)
|
||||
if (injection === null) return
|
||||
if (!(collectionKey in injection)) {
|
||||
injection[collectionKey] = []
|
||||
@ -71,23 +73,26 @@ export function useInjectionCollection (injectionName, collectionKey, valueRef)
|
||||
})
|
||||
}
|
||||
|
||||
// injection.collection {
|
||||
// key1: [insta.$el, instb.$el]
|
||||
// key2: [instc.$el]
|
||||
// }
|
||||
export function useInjectionElementCollection (
|
||||
injectionName,
|
||||
collectionKey,
|
||||
getElement
|
||||
injectionName: string,
|
||||
collectionKey: string,
|
||||
getElement: () => Element
|
||||
) {
|
||||
const injection = inject(injectionName)
|
||||
const injection = inject<Record<string, any[]> | null>(injectionName, null)
|
||||
if (injection === null) return
|
||||
if (!(collectionKey in injection)) {
|
||||
injection[collectionKey] = []
|
||||
}
|
||||
onMounted(() => {
|
||||
const currentInstance = getCurrentInstance().proxy
|
||||
injection[collectionKey].push(getElement(currentInstance))
|
||||
injection[collectionKey].push(getElement())
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
const collectionArray = injection[collectionKey]
|
||||
const currentInstance = getCurrentInstance().proxy
|
||||
const element = getElement(currentInstance)
|
||||
const element = getElement()
|
||||
const index = collectionArray.findIndex(
|
||||
(collectionElement) => collectionElement === element
|
||||
)
|
||||
@ -95,17 +100,17 @@ export function useInjectionElementCollection (
|
||||
})
|
||||
}
|
||||
|
||||
export function useDeferredTrue (valueRef, delay, shouldDelayRef) {
|
||||
export function useDeferredTrue (valueRef: Ref<any>, delay: number, shouldDelayRef: Ref<boolean>): Ref<boolean> {
|
||||
if (!delay) return valueRef
|
||||
const delayedRef = ref(valueRef.value)
|
||||
let timerId = null
|
||||
let timerId: number | null = null
|
||||
watch(valueRef, (value) => {
|
||||
if (timerId !== null) clearTimeout(timerId)
|
||||
if (timerId !== null) window.clearTimeout(timerId)
|
||||
if (value === true) {
|
||||
if (shouldDelayRef && shouldDelayRef.value === false) {
|
||||
delayedRef.value = true
|
||||
} else {
|
||||
timerId = setTimeout(() => {
|
||||
timerId = window.setTimeout(() => {
|
||||
delayedRef.value = true
|
||||
}, delay)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { useMemo } from 'vooks'
|
||||
import { inject } from 'vue'
|
||||
|
||||
export function useAdjustedTo (props) {
|
||||
const modal = inject('NModalBody', null)
|
||||
const drawer = inject('NDrawerBody', null)
|
||||
return useMemo(() => {
|
||||
const { to } = props
|
||||
if (to !== undefined) return to
|
||||
if (modal) return modal.bodyRef
|
||||
if (drawer) return drawer.bodyRef
|
||||
return to ?? 'body'
|
||||
})
|
||||
}
|
26
src/_utils/composable/use-adjusted-to.ts
Normal file
26
src/_utils/composable/use-adjusted-to.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { useMemo } from 'vooks'
|
||||
import { inject } from 'vue'
|
||||
|
||||
interface UseAdjustedToProps {
|
||||
to?: string
|
||||
}
|
||||
|
||||
interface ModalInjection {
|
||||
bodyRef: Element
|
||||
}
|
||||
|
||||
interface DrawerInjection {
|
||||
bodyRef: Element
|
||||
}
|
||||
|
||||
export function useAdjustedTo (props: UseAdjustedToProps) {
|
||||
const modal = inject<ModalInjection | null>('NModalBody', null)
|
||||
const drawer = inject<DrawerInjection | null>('NDrawerBody', null)
|
||||
return useMemo(() => {
|
||||
const { to } = props
|
||||
if (to !== undefined) return to
|
||||
if (modal) return modal.bodyRef
|
||||
if (drawer) return drawer.bodyRef
|
||||
return to ?? 'body'
|
||||
})
|
||||
}
|
@ -1,21 +1,19 @@
|
||||
const pureNumberRegex = /^(\d|\.)+$/
|
||||
const numberRegex = /(\d|\.)+/
|
||||
|
||||
export default function formatLength (length, options = {}) {
|
||||
const { c = 1, offset = 0, attachPx = true } = options
|
||||
const type = typeof length
|
||||
if (type === 'number') {
|
||||
export default function formatLength (length: number | string, { c = 1, offset = 0, attachPx = true } = {}): string {
|
||||
if (typeof length === 'number') {
|
||||
const result = (length + offset) * c
|
||||
if (result === 0) return '0'
|
||||
return `${result}px`
|
||||
} else if (type === 'string') {
|
||||
} else if (typeof length === 'string') {
|
||||
if (pureNumberRegex.test(length)) {
|
||||
const result = (Number(length) + offset) * c
|
||||
if (attachPx) {
|
||||
if (result === 0) return '0'
|
||||
return `${result}px`
|
||||
} else {
|
||||
return result
|
||||
return `${result}`
|
||||
}
|
||||
} else {
|
||||
const result = numberRegex.exec(length)
|
||||
@ -23,4 +21,5 @@ export default function formatLength (length, options = {}) {
|
||||
return length.replace(numberRegex, '' + (Number(result[0]) + offset) * c)
|
||||
}
|
||||
}
|
||||
return length
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import CSSRender from 'css-render'
|
||||
import CSSRender, { CNode } from 'css-render'
|
||||
import BEMPlugin from '@css-render/plugin-bem'
|
||||
|
||||
const namespace = 'n'
|
||||
@ -18,7 +18,7 @@ context.theme = null
|
||||
context.palette = null
|
||||
const { cB, cE, cM, cNotM } = plugin
|
||||
|
||||
function insideFormItem (status, style) {
|
||||
function insideFormItem (status: string | null, style: CNode) {
|
||||
if (status === null) return style
|
||||
return c(`${prefix}form-item`, [
|
||||
c(`${prefix}form-item-blank`, [
|
||||
@ -27,11 +27,11 @@ function insideFormItem (status, style) {
|
||||
])
|
||||
}
|
||||
|
||||
function insideModal (style) {
|
||||
function insideModal (style: CNode) {
|
||||
return c(`${prefix}modal, ${prefix}drawer`, [style])
|
||||
}
|
||||
|
||||
function createKey (keyPrefix, ...suffixs) {
|
||||
function createKey (keyPrefix: string, ...suffixs: string[]) {
|
||||
return (
|
||||
keyPrefix +
|
||||
suffixs
|
||||
@ -43,11 +43,11 @@ function createKey (keyPrefix, ...suffixs) {
|
||||
)
|
||||
}
|
||||
|
||||
function cRB (selector, ...rest) {
|
||||
return c(`${prefix}${selector}`, ...rest)
|
||||
function cRB (selector: string, ...rest: any[]): CNode {
|
||||
return (c as any)(`${prefix}${selector}`, ...rest)
|
||||
}
|
||||
|
||||
function withPrefix (selector) {
|
||||
function withPrefix (selector: string) {
|
||||
return `${prefix}${selector}`
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
const warnedMessages = new Set()
|
||||
|
||||
export function warnOnce (location, message) {
|
||||
export function warnOnce (location: string, message: string): void {
|
||||
const mergedMessage = `[naive/${location}]: ${message}`
|
||||
if (warnedMessages.has(mergedMessage)) return
|
||||
warnedMessages.add(mergedMessage)
|
||||
}
|
||||
|
||||
export function warn (location, message) {
|
||||
export function warn (location: string, message: string): void {
|
||||
console.error(`[naive/${location}]: ${message}`)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export function call (funcs, ...args) {
|
||||
export function call<A extends any[]> (funcs: Function[] | Function, ...args: A): void {
|
||||
if (Array.isArray(funcs)) funcs.forEach((func) => call(func, ...args))
|
||||
else return funcs(...args)
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { Fragment } from 'vue'
|
||||
|
||||
// o(n) flatten
|
||||
export function flatten (vNodes, result = []) {
|
||||
vNodes.forEach((vNode) => {
|
||||
if (vNode.type === Fragment) {
|
||||
flatten(vNode.children, result)
|
||||
} else {
|
||||
result.push(vNode)
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
26
src/_utils/vue/flatten.ts
Normal file
26
src/_utils/vue/flatten.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Fragment, VNodeChild } from 'vue'
|
||||
|
||||
// o(n) flatten
|
||||
export function flatten (vNodes: VNodeChild[], result: VNodeChild[] = []) {
|
||||
vNodes.forEach((vNode) => {
|
||||
if (vNode === null) return
|
||||
if (typeof vNode !== 'object') {
|
||||
result.push(vNode)
|
||||
return
|
||||
}
|
||||
if (Array.isArray(vNode)) {
|
||||
flatten(vNode, result)
|
||||
return
|
||||
}
|
||||
if (vNode.type === Fragment) {
|
||||
if (vNode.children === null) return
|
||||
if (Array.isArray(vNode.children)) {
|
||||
flatten(vNode.children, result)
|
||||
}
|
||||
// rawSlot
|
||||
} else {
|
||||
result.push(vNode)
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export function getSlot (instance, slotName = 'default', fallback = []) {
|
||||
const slots = instance.$slots
|
||||
return (slots[slotName] && slots[slotName]()) || fallback
|
||||
}
|
8
src/_utils/vue/get-slot.ts
Normal file
8
src/_utils/vue/get-slot.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ComponentPublicInstance, VNode } from "vue"
|
||||
|
||||
export function getSlot (instance: ComponentPublicInstance, slotName = 'default', fallback: VNode[] = []) {
|
||||
const slots = instance.$slots
|
||||
const slot = slots[slotName]
|
||||
if (slot === undefined) return fallback
|
||||
return slot()
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export function getVNodeChildren (vNode, slotName = 'default', fallback = []) {
|
||||
const children = vNode.children
|
||||
return (children[slotName] && children[slotName]()) || fallback
|
||||
}
|
12
src/_utils/vue/get-v-node-children.ts
Normal file
12
src/_utils/vue/get-v-node-children.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { VNode } from "vue"
|
||||
|
||||
export function getVNodeChildren (vNode: VNode, slotName = 'default', fallback: VNode[] = []): VNode[] {
|
||||
const { children } = vNode
|
||||
if (children !== null && typeof children === 'object' && !Array.isArray(children)) {
|
||||
const slot = children[slotName]
|
||||
if (typeof slot === 'function') {
|
||||
return slot()
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
export function keep (object, keys = [], rest = {}) {
|
||||
const keepedObject = {}
|
||||
keys.forEach((key) => {
|
||||
keepedObject[key] = object[key]
|
||||
})
|
||||
return Object.assign(keepedObject, rest)
|
||||
}
|
7
src/_utils/vue/keep.ts
Normal file
7
src/_utils/vue/keep.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export function keep<T, K extends keyof T, R> (object: T, keys: K[] = [], rest: R): Pick<T, K> & R {
|
||||
const keepedObject: any = {}
|
||||
keys.forEach((key) => {
|
||||
keepedObject[key] = object[key]
|
||||
})
|
||||
return Object.assign(keepedObject, rest)
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
export function omit (object, keys = [], rest = {}) {
|
||||
const omitedObject = {}
|
||||
const originalKeys = Object.getOwnPropertyNames(object)
|
||||
originalKeys.forEach((originalKey) => {
|
||||
if (!keys.includes(originalKey)) {
|
||||
omitedObject[originalKey] = object[originalKey]
|
||||
}
|
||||
})
|
||||
return Object.assign(omitedObject, rest)
|
||||
}
|
14
src/_utils/vue/omit.ts
Normal file
14
src/_utils/vue/omit.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export function omit <T, K extends keyof T, R> (
|
||||
object: T,
|
||||
keys: K[] = [],
|
||||
rest: R
|
||||
): Pick<T, Exclude<keyof T, K>> & R {
|
||||
const omitedObject: any = {}
|
||||
const originalKeys = Object.getOwnPropertyNames(object)
|
||||
originalKeys.forEach((originalKey) => {
|
||||
if (!(keys as string[]).includes(originalKey)) {
|
||||
omitedObject[originalKey] = object[originalKey as keyof T]
|
||||
}
|
||||
})
|
||||
return Object.assign(omitedObject, rest) as any
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
import { createTextVNode } from 'vue'
|
||||
import { defineComponent, createTextVNode, PropType, } from 'vue'
|
||||
|
||||
export const render = {
|
||||
export const render = defineComponent({
|
||||
name: 'Render',
|
||||
props: {
|
||||
render: {
|
||||
type: [String, Number, Function],
|
||||
default: () => {}
|
||||
type: [String, Number, Function] as PropType<string | number | null | undefined | Function>,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { render } = this
|
||||
if (render === undefined || render === null) return null
|
||||
if (typeof render === 'function') {
|
||||
return render()
|
||||
} else if (typeof render === 'string') {
|
||||
@ -19,4 +21,4 @@ export const render = {
|
||||
return JSON.stringify(render)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
@ -1,15 +1,38 @@
|
||||
import { App } from 'vue'
|
||||
import version from './version'
|
||||
import { warn } from './_utils'
|
||||
import { Hljs, NaiveLocale } from './config-provider'
|
||||
|
||||
function setHljs (hljs) {
|
||||
type ComponentType = any
|
||||
|
||||
interface NaiveUIInstance {
|
||||
version: string
|
||||
install (app: App): void
|
||||
use (plugin: { install: (naive: NaiveUIInstance) => void }): void
|
||||
componentPrefix: string
|
||||
hljs: any
|
||||
setHljs (hljs: any): void
|
||||
setHighlightjs (hljs: any): void
|
||||
locales: Record<string, NaiveLocale>
|
||||
fallbackLocale: NaiveLocale
|
||||
}
|
||||
|
||||
interface NaiveUICreateOptions {
|
||||
componentPrefix?: string
|
||||
components?: ComponentType[]
|
||||
locales?: NaiveLocale[]
|
||||
hljs?: Hljs
|
||||
}
|
||||
|
||||
function setHljs (this: NaiveUIInstance, hljs: any) {
|
||||
this.hljs = hljs
|
||||
}
|
||||
|
||||
function createLocalesObject (locales) {
|
||||
function createLocalesObject (locales: NaiveLocale[]) {
|
||||
return (
|
||||
locales &&
|
||||
locales.reduce((localeMap, locale) => {
|
||||
localeMap[locale._name] = locale
|
||||
localeMap[locale.name] = locale
|
||||
return localeMap
|
||||
}, {})
|
||||
)
|
||||
@ -19,14 +42,14 @@ function create ({
|
||||
componentPrefix = 'N',
|
||||
components = [],
|
||||
locales = [],
|
||||
hljs
|
||||
} = {}) {
|
||||
hljs = undefined
|
||||
}: NaiveUICreateOptions = {}) {
|
||||
const fallbackLocale = locales[0]
|
||||
if (!fallbackLocale) warn('create', '`locales` is empty.')
|
||||
const installTargets = []
|
||||
const naive = {
|
||||
const installTargets: App[] = []
|
||||
const naive: NaiveUIInstance = {
|
||||
version,
|
||||
use (plugin) {
|
||||
use (plugin: any) {
|
||||
plugin.install(naive)
|
||||
},
|
||||
install,
|
||||
@ -38,13 +61,13 @@ function create ({
|
||||
locales: createLocalesObject(locales),
|
||||
fallbackLocale
|
||||
}
|
||||
function registerComponent (app, name, component) {
|
||||
function registerComponent (app: App, name: string, component: ComponentType) {
|
||||
const registered = app.component(componentPrefix + name)
|
||||
if (!registered) {
|
||||
app.component(componentPrefix + name, component)
|
||||
}
|
||||
}
|
||||
function install (app) {
|
||||
function install (app: App) {
|
||||
if (installTargets.includes(app)) return
|
||||
installTargets.push(app)
|
||||
app.config.globalProperties.$naive = naive
|
||||
@ -52,7 +75,7 @@ function create ({
|
||||
const { name, alias } = component
|
||||
registerComponent(app, name, component)
|
||||
if (alias) {
|
||||
alias.forEach((aliasName) => {
|
||||
alias.forEach((aliasName: string) => {
|
||||
registerComponent(app, aliasName, component)
|
||||
})
|
||||
}
|
5
src/global.d.ts
vendored
Normal file
5
src/global.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
var __DEV__: boolean
|
||||
}
|
@ -3,17 +3,15 @@ import { enUS, zhCN } from './locales'
|
||||
|
||||
// deprecated
|
||||
import { NServiceLayout } from './_deprecated/nimbus-service-layout/index'
|
||||
import styleScheme from './_deprecated/style-scheme'
|
||||
|
||||
import create from './create'
|
||||
|
||||
export default create({
|
||||
components: [
|
||||
...Object.keys(components).map((key) => components[key]),
|
||||
...Object.keys(components).map((key) => components[key as keyof typeof components]),
|
||||
// Deprecated
|
||||
NServiceLayout
|
||||
],
|
||||
// deprecated
|
||||
locales: [enUS, zhCN],
|
||||
styleSchemes: styleScheme
|
||||
locales: [enUS, zhCN]
|
||||
})
|
5
src/shims-vue.d.ts
vendored
Normal file
5
src/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module "*.vue" {
|
||||
import { defineComponent } from "vue";
|
||||
const component: ReturnType<typeof defineComponent>;
|
||||
export default component;
|
||||
}
|
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/_deprecated/icons/**/*", "src/**/*.spec.js"],
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"module": "ES6",
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES6",
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user