Skip to content

Commit

Permalink
feat: add useGlobalConfig, useLocale hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
yzh990918 committed Nov 21, 2022
1 parent 6bdb779 commit bb29895
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 1 deletion.
6 changes: 5 additions & 1 deletion packages/onu-ui/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import * as plugins from '@onu-ui/components'
import { provideGlobalConfig } from '@onu-ui/utils'
import { version } from '../package.json'
import type { InstallOptions } from '@onu-ui/utils'
import type { App, Plugin } from 'vue'

const INSTALLED_KEY = Symbol('OnuUI_Installed')

export const createInstaller = (components: Plugin[] = []) => {
const install = (app: App) => {
const install = (app: App, options?: InstallOptions) => {
if (app[INSTALLED_KEY]) return

app[INSTALLED_KEY] = true
components.forEach(c => app.use(c))

if (options) provideGlobalConfig(options, app, true)

// plugin install
app.config.globalProperties.$message = plugins.OMessage
}
Expand Down
1 change: 1 addition & 0 deletions packages/utils/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useGlobalConfig'
51 changes: 51 additions & 0 deletions packages/utils/hooks/useGlobalConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { configProviderContextKey } from '../tokens'
import { mergeObjects } from '../shared'
import type { InstallOptions } from '../tokens'
import type { App, Ref } from 'vue'
import type { MaybeRef } from '@vueuse/core'

const globalConfig = ref<InstallOptions>()

/**
* 获取全局配置 Hooks
* @param key
* @param defaultValue
*/
export function useGlobalConfig<T extends keyof InstallOptions, U extends InstallOptions[T]>(key: T, defaultValue?: U): Ref<Exclude<InstallOptions[T], undefined | U>>
export function useGlobalConfig(): Ref<InstallOptions>
export function useGlobalConfig(key?: keyof InstallOptions, defaultValue = undefined) {
const config = getCurrentInstance() ? inject(configProviderContextKey, globalConfig) : globalConfig

if (key)
return computed(() => config.value?.[key] ?? defaultValue)
else
return config
}

/**
* 注入配置
* @param config
* @param app
* @param global
*/
export function provideGlobalConfig(config: MaybeRef<InstallOptions>, app?: App, global = false) {
const sourceConfig = getCurrentInstance() ? useGlobalConfig() : undefined
const provideFn = app?.provide ?? (getCurrentInstance() ? provide : undefined)

if (!provideFn) return

const context = computed(() => {
const cfg = unref(config)
if (!sourceConfig?.value) return cfg

return mergeObjects(sourceConfig.value, cfg)
})

provideFn(configProviderContextKey, context)

// 初始化
if (global || !globalConfig.value)
globalConfig.value = context.value

return context
}
36 changes: 36 additions & 0 deletions packages/utils/hooks/useLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { deepGet } from '../shared'
import { en } from '../locale'
import { useGlobalConfig } from './useGlobalConfig'
import type { language } from '../locale'
import type { Ref } from 'vue'
import type { MaybeRef } from '@vueuse/core'

export type OnuTranslatorOption = Record<string, string | number>
export type OnuTranslator = (path: string, option?: OnuTranslatorOption) => string
export interface OnuLocaleContext {
locale: Ref<language>
lang: Ref<string>
t: OnuTranslator
}

export const translate = (path: string, option: OnuTranslatorOption | undefined, locale: language) => {
return (deepGet(locale, path, path) as string).replace(/\{(\w+)\}/g, (_, key) => `${option?.[key] ?? `{${key}}`}`)
}

export const buildTranslator = (locale: MaybeRef<language>): OnuTranslator => (path, option) => translate(path, option, unref(locale))

export const buildLocaleContext = (locale: MaybeRef<language>): OnuLocaleContext => {
const lang = computed(() => unref(locale).name)
const RefLocale = isRef(locale) ? locale : ref(locale)

return {
locale: RefLocale,
lang,
t: buildTranslator(locale),
}
}

export function useLocale() {
const locale = useGlobalConfig('locale')
return buildLocaleContext(computed(() => locale.value || en))
}
3 changes: 3 additions & 0 deletions packages/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export * from './vue'
export * from './shared'
export * from './locale'
export * from './tokens'
export * from './hooks'
5 changes: 5 additions & 0 deletions packages/utils/locale/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Locale guide

1. Define component locale, like `utils/locale/*`.
2. Add other language support? Add locale file in `locale`, then export it from `index.ts`.
3. Use i118n in component, please learn more about `useLocale`.
11 changes: 11 additions & 0 deletions packages/utils/locale/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export { default as en } from './lang/en'
export { default as zhCn } from './lang/zh-cn'

export interface TranslatePair {
[key: string]: string | string[] | TranslatePair
}

export interface language {
name: string
locales: TranslatePair
}
8 changes: 8 additions & 0 deletions packages/utils/locale/lang/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
name: 'en',
locales: {
empty: {
emptyText: 'No data',
},
},
}
8 changes: 8 additions & 0 deletions packages/utils/locale/lang/zh-cn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
name: 'zh-cn',
locales: {
empty: {
emptyText: '暂无数据',
},
},
}
37 changes: 37 additions & 0 deletions packages/utils/shared/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,40 @@ export function hash(str: string) {
* Generate random number in range [0, 1000]
*/
export const generateId = (): number => Math.floor(Math.random() * 10000)

/**
* Merge object from T & U
*/
export function mergeObjects<T extends Record<string, any>, U extends Record<string, any>>(sourceObj: T, targetObj: U) {
const keys = [...new Set([...(Object.keys(sourceObj)), ...(Object.keys(targetObj))])]
const newObj: Record<string, any> = {}

keys.forEach((key) => {
newObj[key] = targetObj[key] ?? sourceObj[key]
})

return newObj
}

export function deepGet(target: any, path: string | string[], defaultValue: any) {
if (!Array.isArray(path) && typeof path !== 'string')
throw new TypeError('path must be string or array')
if (target === null) return defaultValue

let pathArray = path
if (typeof path === 'string') {
path = path.replace(/\[(\w*)\]/g, '.$1')
path = path.startsWith('.') ? path.slice(1) : path

pathArray = path.split('.')
}

let index = 0
let levelPath: string
while (target !== null && index < pathArray.length) {
levelPath = pathArray[index++]
target = target[levelPath]
}

return index === pathArray.length ? target : defaultValue
}
12 changes: 12 additions & 0 deletions packages/utils/tokens/config-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { language } from '../locale'
import type { InjectionKey, Ref } from 'vue'
import type{ MaybeRef } from '@vueuse/core'

export interface InstallOptions {
prefix?: string
namespace?: MaybeRef<string>
locale?: MaybeRef<language>
zIndex?: MaybeRef<number>
}

export const configProviderContextKey: InjectionKey<Ref<InstallOptions>> = Symbol('__onu_config_provider')
1 change: 1 addition & 0 deletions packages/utils/tokens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './config-provider'

0 comments on commit bb29895

Please sign in to comment.