feat(button): unstable rtl (#74)

This commit is contained in:
07akioni 2021-06-11 16:22:06 +08:00 committed by GitHub
parent ae4b44dfb5
commit 6177b96e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 8 deletions

51
src/_mixins/use-rtl.ts Normal file
View File

@ -0,0 +1,51 @@
import { Ref, onBeforeMount, inject, watchEffect, computed } from 'vue'
import { ssrInjectionKey } from '../ssr/context'
import {
RtlEnabledState,
RtlItem
} from '../config-provider/src/internal-interface'
// The current implemention will take extra perf & memory usage. I just want to
// make it work now. If we can determine whether the style is already mounted,
// we won't need to watch effect. However, we need to make css-render support
// it. We need to refactor ssrAdapter and expose a exists function
export default function useRtl (
mountId: string,
rtlStateRef: Ref<RtlEnabledState | undefined> | undefined,
clsPrefixRef: Ref<string>
): Ref<RtlItem | undefined> | undefined {
if (!rtlStateRef) return undefined
const ssrAdapter = inject(ssrInjectionKey, undefined)
const componentRtlStateRef = computed(() => {
const { value: rtlState } = rtlStateRef
if (!rtlState) {
return undefined
}
const componentRtlState = rtlState[mountId as keyof RtlEnabledState]
if (!componentRtlState) {
return undefined
}
return componentRtlState
})
const mountStyle = (): void => {
watchEffect(() => {
const { value: clsPrefix } = clsPrefixRef
const { value: componentRtlState } = componentRtlStateRef
if (!componentRtlState) return
componentRtlState.style.mount({
id: `${clsPrefix}${mountId}Rtl`,
head: true,
props: {
bPrefix: clsPrefix ? `.${clsPrefix}-` : undefined
},
ssr: ssrAdapter
})
})
}
if (ssrAdapter) {
mountStyle()
} else {
onBeforeMount(mountStyle)
}
return componentRtlStateRef
}

View File

@ -18,6 +18,7 @@ ghost
loading
color
group
rtl-debug
debug
```

View File

@ -0,0 +1,24 @@
# Rtl Debug
```html
<n-space vertical>
<n-space><n-switch v-model:value="rtlEnabled" />Rtl</n-space>
<n-config-provider :rtl="rtlEnabled ? rtlStyles : undefined">
<n-button>Rtl Test</n-button>
</n-config-provider>
</n-space>
```
```js
import { defineComponent, ref } from 'vue'
import { unstableButtonRtl } from 'naive-ui'
export default defineComponent({
setup () {
return {
rtlEnabled: ref(false),
rtlStyles: [unstableButtonRtl]
}
}
})
```

View File

@ -28,6 +28,7 @@ import type { ButtonTheme } from '../styles'
import { buttonGroupInjectionKey } from './ButtonGroup'
import type { Type, Size } from './interface'
import style from './styles/button.cssr'
import useRtl from '../../_mixins/use-rtl'
const buttonProps = {
...(useTheme.props as ThemeProps<ButtonTheme>),
@ -157,7 +158,7 @@ const Button = defineComponent({
const handleBlur = (): void => {
enterPressedRef.value = false
}
const { mergedClsPrefixRef } = useConfig(props)
const { mergedClsPrefixRef, NConfigProvider } = useConfig(props)
const themeRef = useTheme(
'Button',
'Button',
@ -166,6 +167,11 @@ const Button = defineComponent({
props,
mergedClsPrefixRef
)
const rtlEnabledRef = useRtl(
'Button',
NConfigProvider?.mergedRtlRef,
mergedClsPrefixRef
)
return {
selfRef,
waveRef,
@ -174,6 +180,7 @@ const Button = defineComponent({
mergedSize: mergedSizeRef,
showBorder: showBorderRef,
enterPressed: enterPressedRef,
rtlEnabled: rtlEnabledRef,
handleMouseDown,
handleKeyDown,
handleBlur,
@ -390,6 +397,7 @@ const Button = defineComponent({
`${mergedClsPrefix}-button`,
`${mergedClsPrefix}-button--${this.type}-type`,
{
[`${mergedClsPrefix}-button--rtl`]: this.rtlEnabled,
[`${mergedClsPrefix}-button--disabled`]: this.disabled,
[`${mergedClsPrefix}-button--block`]: this.block,
[`${mergedClsPrefix}-button--pressed`]: this.enterPressed,

View File

@ -0,0 +1,7 @@
import { cB, cM } from '../../../_utils/cssr'
export default cB('button', [
cM('rtl', `
direction: rtl;
`)
])

View File

@ -1,3 +1,4 @@
export { default as buttonDark } from './dark'
export { default as buttonLight } from './light'
export { default as buttonRtl } from './rtl'
export type { ButtonThemeVars, ButtonTheme } from './light'

6
src/button/styles/rtl.ts Normal file
View File

@ -0,0 +1,6 @@
import rtlStyle from '../src/styles/button-rtl.cssr'
export default {
name: 'Button',
style: rtlStyle
}

View File

@ -6,7 +6,9 @@ import {
PropType,
provide,
InjectionKey,
renderSlot
renderSlot,
ComputedRef,
markRaw
} from 'vue'
import { useMemo } from 'vooks'
import { merge } from 'lodash-es'
@ -18,17 +20,18 @@ import type {
GlobalComponentConfig,
GlobalIconConfig
} from './interface'
import type { ConfigProviderInjection } from './internal-interface'
import type {
ConfigProviderInjection,
RtlProp,
RtlEnabledState
} from './internal-interface'
import { NDateLocale, NLocale } from '../../locales'
export const configProviderInjectionKey: InjectionKey<ConfigProviderInjection> =
Symbol('configProviderInjection')
export const configProviderProps = {
abstract: {
type: Boolean,
default: false
},
abstract: Boolean,
bordered: {
type: Boolean as PropType<boolean | undefined>,
default: undefined
@ -37,6 +40,7 @@ export const configProviderProps = {
locale: Object as PropType<NLocale | null>,
dateLocale: Object as PropType<NDateLocale | null>,
namespace: String,
rtl: Array as PropType<RtlProp>,
tag: {
type: String,
default: 'div'
@ -160,7 +164,21 @@ export default defineComponent({
const { clsPrefix } = props
return NConfigProvider?.mergedClsPrefixRef.value ?? clsPrefix
})
const mergedRtlRef: ComputedRef<RtlEnabledState | undefined> = computed(
() => {
const { rtl } = props
if (rtl === undefined) {
return NConfigProvider?.mergedRtlRef.value
}
const rtlEnabledState: RtlEnabledState = {}
for (const rtlInfo of rtl) {
rtlEnabledState[rtlInfo.name] = markRaw(rtlInfo)
}
return rtlEnabledState
}
)
provide(configProviderInjectionKey, {
mergedRtlRef,
mergedIconsRef,
mergedComponentPropsRef,
mergedBorderedRef,

View File

@ -1,4 +1,5 @@
import { VNodeChild, Ref } from 'vue'
import { CNode } from 'css-render'
import type { AlertTheme } from '../../alert/styles'
import type { AnchorTheme } from '../../anchor/styles'
import type { AutoCompleteTheme } from '../../auto-complete/styles'
@ -200,6 +201,16 @@ export interface GlobalIconConfig {
zoomOut?: () => VNodeChild
}
export interface RtlItem {
name: keyof GlobalThemeWithoutCommon
style: CNode
}
export type RtlProp = RtlItem[]
export type RtlEnabledState = Partial<
Record<keyof GlobalThemeWithoutCommon, RtlItem>
>
export interface ConfigProviderInjection {
mergedClsPrefixRef: Ref<string | undefined>
mergedBorderedRef: Ref<boolean | undefined>
@ -211,6 +222,7 @@ export interface ConfigProviderInjection {
mergedIconsRef: Ref<GlobalIconConfig | undefined>
mergedThemeRef: Ref<GlobalTheme | undefined>
mergedThemeOverridesRef: Ref<GlobalThemeOverrides | undefined>
mergedRtlRef: Ref<RtlEnabledState | undefined>
// deprecated
/** @deprecated */
mergedLegacyThemeRef: Ref<string | undefined>

View File

@ -6,7 +6,7 @@ export { avatarDark } from './avatar/styles'
export { backTopDark } from './back-top/styles'
export { badgeDark } from './badge/styles'
export { breadcrumbDark } from './breadcrumb/styles'
export { buttonDark } from './button/styles'
export { buttonDark, buttonRtl as unstableButtonRtl } from './button/styles'
export { cardDark } from './card/styles'
export { cascaderDark } from './cascader/styles'
export { checkboxDark } from './checkbox/styles'