feat: stronger theme types

This commit is contained in:
07akioni 2021-02-01 15:45:53 +08:00
parent 7d84bb4d4a
commit 06e78b19bd
6 changed files with 55 additions and 77 deletions

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/consistent-type-assertions */
import { inject, computed, onBeforeMount, ComputedRef, PropType } from 'vue'
import { merge } from 'lodash-es'
import globalStyle from '../_styles/global/index.cssr'
@ -9,23 +10,34 @@ globalStyle.mount({
id: 'naive-ui-global'
})
type ThemeOverrides = any
export interface Theme<T = undefined, R = any> {
export interface Theme<T = {}, R = any> {
name: string
common?: ThemeCommonVars
peers?: R
self?: (vars: ThemeCommonVars) => T
}
export type ExtractThemeVars<T> = T extends Theme<infer U, unknown> ? U : {}
export type ExtractPeerOverrides<T> = T extends Theme<unknown, infer V>
? {
peers?: {
[k in keyof V]?: ExtractThemeVars<V[k]>
}
}
: T
export type ExtractThemeOverrides<T> = Partial<ExtractThemeVars<T>> &
ExtractPeerOverrides<T> & { common?: ThemeCommonVars }
export function createTheme<T, R> (theme: Theme<T, R>): Theme<T, R> {
return theme
}
type UseThemeProps<T> = Readonly<{
unstableTheme?: Theme<T> | undefined
unstableThemeOverrides?: ThemeOverrides
builtinThemeOverrides?: ThemeOverrides
unstableTheme?: T | undefined
unstableThemeOverrides?: ExtractThemeOverrides<T>
builtinThemeOverrides?: ExtractThemeOverrides<T>
}>
export type MergedTheme<T> = T extends Theme<infer V, infer W>
@ -42,7 +54,7 @@ function useTheme<T, R> (
mountId: string,
style: CNode | undefined,
defaultTheme: Theme<T, R>,
props: UseThemeProps<T>
props: UseThemeProps<Theme<T, R>>
): ComputedRef<MergedTheme<Theme<T, R>>> {
if (style) {
onBeforeMount(() => {
@ -59,13 +71,14 @@ function useTheme<T, R> (
// keep props to make theme overrideable
const {
unstableTheme: { common, self, peers = {} } = {},
unstableThemeOverrides: selfOverrides = {},
builtinThemeOverrides: builtinOverrides = {}
unstableThemeOverrides: selfOverrides = {} as ExtractThemeOverrides<
Theme<T, R>
>,
builtinThemeOverrides: builtinOverrides = {} as ExtractThemeOverrides<
Theme<T, R>
>
} = props
const {
common: commonOverrides,
peers: peersOverrides = {}
} = selfOverrides
const { common: commonOverrides, peers: peersOverrides } = selfOverrides
const {
mergedUnstableTheme: {
common: injectedGlobalCommon = undefined,
@ -108,39 +121,21 @@ function useTheme<T, R> (
}
useTheme.props = {
unstableTheme: {
type: Object,
default: undefined
},
unstableThemeOverrides: {
type: Object,
default: undefined
},
builtinThemeOverrides: {
type: Object,
default: undefined
}
unstableTheme: Object,
unstableThemeOverrides: Object,
builtinThemeOverrides: Object
} as const
export interface ThemeProps<T> {
unstableTheme: {
type: PropType<T | undefined>
default: undefined
}
unstableThemeOverrides: {
type: ObjectConstructor
default: undefined
}
builtinThemeOverrides: {
type: ObjectConstructor
default: undefined
}
unstableTheme: PropType<T>
unstableThemeOverrides: PropType<ExtractThemeOverrides<T>>
builtinThemeOverrides: PropType<ExtractThemeOverrides<T>>
}
export interface ThemePropsReactive<T> {
unstableTheme?: T
unstableThemeOverrides?: Record<string, any>
builtinThemeOverrides?: Record<string, any>
unstableThemeOverrides?: ExtractThemeOverrides<T>
builtinThemeOverrides?: ExtractThemeOverrides<T>
}
/**

View File

@ -168,9 +168,9 @@ export default defineComponent({
class="n-cascader-menu"
autoPending
unstableThemeOverrides={
NCascader.mergedTheme.peers.BaseSelectMenu
NCascader.mergedTheme.overrides.BaseSelectMenu
}
unstableTheme={NCascader.mergedTheme.overrides.BaseSelectMenu}
unstableTheme={NCascader.mergedTheme.peers.BaseSelectMenu}
treeMate={this.selectTreeMate}
multiple={this.multiple}
value={this.value}

View File

@ -26,47 +26,26 @@ export default defineComponent({
default: false
},
bordered: {
type: Boolean,
type: Boolean as PropType<boolean | undefined>,
default: undefined
},
locale: Object as PropType<NaiveLocale>,
dateLocale: Object as PropType<NaiveDateLocale>,
namespace: {
type: String,
default: undefined
},
namespace: String,
tag: {
type: String,
default: 'div'
},
hljs: {
type: Object as PropType<Hljs>,
default: undefined
},
hljs: Object as PropType<Hljs>,
// wip, unstable
unstableTheme: {
type: Object as PropType<Theme>,
default: undefined
},
unstableThemeOverrides: {
type: Object as PropType<ThemeOverrides>,
default: undefined
},
unstableTheme: Object as PropType<Theme>,
unstableThemeOverrides: Object as PropType<ThemeOverrides>,
// deprecated
theme: {
type: String,
default: undefined
},
language: {
type: String,
default: undefined
},
lang: {
type: String,
default: undefined
},
theme: String,
language: String,
lang: String,
as: {
type: Object as PropType<string>,
type: Object as PropType<string | undefined>,
validator: () => {
warn('config-provider', '`as` is deprecated, please use `tag` instead.')
return true
@ -74,7 +53,7 @@ export default defineComponent({
default: undefined
},
themeEnvironment: {
type: Object as PropType<unknown>,
type: Object as PropType<unknown | undefined>,
validator: () => {
warn('config-provider', '`theme-environment` is deprecated.')
return true
@ -82,7 +61,7 @@ export default defineComponent({
default: undefined
},
themeEnvironments: {
type: Object as PropType<unknown>,
type: Object as PropType<unknown | undefined>,
validator: () => {
warn('config-provider', '`theme-environments` is deprecated.')
return true

View File

@ -247,8 +247,12 @@ export default defineComponent({
}
}
function handleMouseDown (e: MouseEvent): void {
if (addButtonInstRef.value?.$el.contains(e.target as Node)) { e.preventDefault() }
if (minusButtonInstRef.value?.$el.contains(e.target as Node)) { e.preventDefault() }
if (addButtonInstRef.value?.$el.contains(e.target as Node)) {
e.preventDefault()
}
if (minusButtonInstRef.value?.$el.contains(e.target as Node)) {
e.preventDefault()
}
inputInstRef.value?.activate()
}
const handleAddClick = doAdd
@ -303,7 +307,7 @@ export default defineComponent({
const [r, g, b, a] = rgba(iconColorDisabled)
return {
textColorTextDisabled: `rgb(${r}, ${g}, ${b})`,
opacityDisabled: a
opacityDisabled: `${a}`
}
})
}

View File

@ -412,7 +412,7 @@
- [ ] getKey select & autocomplete type safe & input event interface? onInput value | null or value
- [x] vshow (maybe create a vue pr)
- [x] jsx focusin out (waiting for vue update)
- [ ] inject key & value in type
- [x] inject key & value in type (I should use InjectionKey...)
- [x] form item no label css
- [x] unify treemate ignored
- [ ] fix menu extra