vue#watchEffect TypeScript Examples
The following examples show how to use
vue#watchEffect.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useClickAway.ts From elenext with MIT License | 6 votes |
export default function useClickAway(
onClickAway: (event: EventType) => void,
targetRef: Ref<HTMLElement>,
eventName = 'click'
) {
const handler = (event: any) => {
if (!targetRef.value || targetRef.value.contains(event.target)) {
return
}
onClickAway(event)
}
watchEffect(onInvalidate => {
document.addEventListener(eventName, handler)
onInvalidate(() => {
document.removeEventListener(eventName, handler)
})
})
}
Example #2
Source File: useEventListener.ts From elenext with MIT License | 6 votes |
function useEventListener(
target: Ref<HTMLElement | Window | null>,
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): () => void {
let prevEle: HTMLElement | Window | null = null
const destroyWatcher = watchEffect(
() => {
target.value?.addEventListener(type, listener, options)
if (prevEle) {
prevEle.removeEventListener(type, listener)
}
prevEle = target?.value
},
{ flush: 'post' }
)
const removeListener = (isDestroyWatcher = true) => {
target.value?.removeEventListener(type, listener)
if (isDestroyWatcher) {
destroyWatcher()
}
}
onBeforeUnmount(() => {
removeListener(true)
})
return removeListener
}
Example #3
Source File: FormKitSchema.ts From formkit with MIT License | 6 votes |
/**
* Returns a reference as a placeholder to a specific location on an object.
* @param data - A reactive data object
* @param token - A dot-syntax string representing the object path
* @returns
*/
function getRef(token: string, data: Record<string, any>): Ref<unknown> {
const value = ref<any>(null)
if (token === 'get') {
const nodeRefs: Record<string, Ref<unknown>> = {}
value.value = get.bind(null, nodeRefs)
return value
}
const path = token.split('.')
watchEffect(() => (value.value = getValue(data, path)))
return value
}
Example #4
Source File: useEventListener.ts From hexon with GNU General Public License v3.0 | 6 votes |
useEventListener = (
ele: HTMLElement | Window,
type: keyof HTMLElementEventMap,
listener: (evt: Event) => void
) => {
watchEffect((onInvalidate) => {
ele.addEventListener(type, listener)
onInvalidate(() => {
ele.removeEventListener(type, listener)
})
})
}
Example #5
Source File: useResizeObserver.ts From hexon with GNU General Public License v3.0 | 6 votes |
useResizeObserver = (
ele: Ref<HTMLElement | undefined>,
cb: (entry: ResizeObserverEntry) => void
) => {
watchEffect((onInvalidate) => {
const ro = new ResizeObserver((entries) => {
for (let entry of entries) {
cb(entry)
}
})
if (ele.value) {
ro.observe(ele.value)
}
onInvalidate(() => {
ro.disconnect()
})
})
}
Example #6
Source File: legacy.test.ts From vue-i18n-next with MIT License | 6 votes |
test('tm', async () => {
const i18n = createVueI18n({
locale: 'ja',
messages: {
en: {},
ja: {
foo: {
bar: {
buz: 'hello'
},
codes: {
errors: ['error1', 'error2']
}
}
}
}
})
let messages1 = i18n.tm('foo.bar')
let messages2 = i18n.tm('foo.codes')
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
watchEffect(() => {
messages1 = i18n.tm('foo.bar')
messages2 = i18n.tm('foo.codes')
})
i18n.locale = 'en'
await nextTick()
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
})
Example #7
Source File: useTitle.ts From vhook with MIT License | 6 votes |
export function useTitle(title: string, restoreOnUnMount = false) {
const cache = document.title
const titleRef = ref(title)
watchEffect(() => {
document.title = titleRef.value
})
if (restoreOnUnMount) {
tryOnUnmounted(() => {
document.title = cache
})
}
const setTitle = (title: string) => {
titleRef.value = title
}
return setTitle
}
Example #8
Source File: FormKitSchema.ts From formkit with MIT License | 5 votes |
FormKitSchema = defineComponent({
name: 'FormKitSchema',
props: {
schema: {
type: [Array, Object] as PropType<
FormKitSchemaNode[] | FormKitSchemaCondition
>,
required: true,
},
data: {
type: Object as PropType<Record<string, any>>,
default: () => ({}),
},
library: {
type: Object as PropType<FormKitComponentLibrary>,
default: () => ({}),
},
},
setup(props, context) {
const instance = getCurrentInstance()
let instanceKey = Symbol(String(i++))
instanceScopes.set(instanceKey, [])
let provider = parseSchema(props.library, props.schema)
let render: RenderChildren
let data: Record<string, any>
// Re-parse the schema if it changes:
watch(
() => props.schema,
(newSchema, oldSchema) => {
instanceKey = Symbol(String(i++))
provider = parseSchema(props.library, props.schema)
render = createRenderFn(provider, data, instanceKey)
if (newSchema === oldSchema) {
// In this edge case, someone pushed/modified something in the schema
// and we've successfully re-parsed, but since the schema is not
// referenced in the render function it technically isnt a dependency
// and we need to force a re-render since we swapped out the render
// function completely.
;(instance?.proxy?.$forceUpdate as unknown as CallableFunction)()
}
},
{ deep: true }
)
// Watch the data object explicitly
watchEffect(() => {
data = Object.assign(reactive(props.data), {
slots: context.slots,
})
render = createRenderFn(provider, data, instanceKey)
})
return () => render()
},
})
Example #9
Source File: useEvent.ts From vhook with MIT License | 5 votes |
export function useEvent(
event: string,
cb: EventListenerOrEventListenerObject,
options?: HandlerOptions,
target: Target = window
) {
if (!event || !cb) {
return
}
let eventTarget: EventTarget | null = null
function register() {
eventTarget = registerEvent(target, event, cb, options)
}
function clear() {
if (eventTarget) {
eventTarget.removeEventListener(event, cb, options)
eventTarget = null
}
}
useLifecycles(
() => {
if (isRef(target)) {
watchEffect(
(onInvalidate) => {
register()
onInvalidate(() => {
clear()
})
},
{ flush: 'sync' }
)
} else {
register()
}
},
() => {
clear()
}
)
const targetDom = {
get value() {
return eventTarget
}
}
return [targetDom, clear]
}
Example #10
Source File: useLoadMore.ts From vue-request with MIT License | 4 votes |
function useLoadMore<R, P extends unknown[], FR, LR extends unknown[]>(
service: LoadMoreService<R, P, LR>,
options?: LoadMoreMixinOptions<R, P, FR>,
) {
if (!isFunction(service)) {
warning('useLoadMore only support function service');
}
const promiseQuery = generateService<R, P>(service as any);
const injectedGlobalOptions = inject<GlobalOptions>(
GLOBAL_OPTIONS_PROVIDE_KEY,
{},
);
const {
queryKey,
isNoMore,
listKey = 'list',
...restOptions
} = Object.assign(
{
listKey: injectedGlobalOptions.listKey ?? getGlobalOptions().listKey,
},
options ?? ({} as any),
);
if (queryKey) {
warning('useLoadMore does not support concurrent request');
}
const refreshing = ref(false);
const loadingMore = ref(false);
const reloading = ref(false);
const initailIncreaseQueryKey = 0;
const increaseQueryKey = ref(initailIncreaseQueryKey);
const {
data,
params,
queries,
run,
reset,
cancel: _cancel,
...rest
} = useAsyncQuery<R, P>(promiseQuery, {
...restOptions,
onSuccess: (...p) => {
loadingMore.value = false;
increaseQueryKey.value++;
restOptions?.onSuccess?.(...p);
},
onError: (...p) => {
loadingMore.value = false;
restOptions?.onError?.(...p);
},
queryKey: () => String(increaseQueryKey.value),
});
const latestData = ref(data.value) as Ref<R | undefined>;
watchEffect(() => {
if (data.value !== undefined) {
latestData.value = data.value;
}
});
const noMore = computed(() => {
return isNoMore && isFunction(isNoMore)
? isNoMore(latestData.value)
: false;
});
const dataList = computed(() => {
let list: any[] = [];
Object.values(queries).forEach(h => {
const dataList = get(h.data!, listKey);
if (dataList && Array.isArray(dataList)) {
list = list.concat(dataList);
}
});
return (list as unknown) as LR;
});
const loadMore = () => {
if (noMore.value) {
return;
}
loadingMore.value = true;
const [, ...restParams] = params.value;
const mergerParams = [
{ dataList: dataList.value, data: latestData.value },
...restParams,
] as P;
run(...mergerParams);
};
const unmountQueries = () => {
Object.keys(queries).forEach(key => {
if (key !== initailIncreaseQueryKey.toString()) {
queries[key].cancel();
queries[key].unmount();
delete queries[key];
}
});
};
const refresh = async () => {
refreshing.value = true;
const latestKey = increaseQueryKey.value - 1;
const key =
latestKey < initailIncreaseQueryKey ? initailIncreaseQueryKey : latestKey;
latestData.value = queries[key].data;
increaseQueryKey.value = initailIncreaseQueryKey;
const [, ...restParams] = params.value;
const mergerParams = [undefined, ...restParams] as any;
await run(...mergerParams);
unmountQueries();
refreshing.value = false;
};
const reload = async () => {
reloading.value = true;
reset();
increaseQueryKey.value = initailIncreaseQueryKey;
latestData.value = undefined;
const [, ...restParams] = params.value;
const mergerParams = [undefined, ...restParams] as any;
await run(...mergerParams);
reloading.value = false;
};
const cancel = () => {
_cancel();
loadingMore.value = false;
refreshing.value = false;
};
return {
data: latestData,
dataList: dataList,
params,
noMore,
loadingMore,
refreshing,
reloading,
run,
reload,
loadMore,
reset,
refresh,
cancel,
...omit(rest, ['refresh', 'mutate']),
};
}
Example #11
Source File: index.ts From elenext with MIT License | 4 votes |
usePopper = (props: UsePopperOptions) => {
const popperId = uniqueId('el-popper')
const { referenceRef, popperRef } = props
const timers: {
showTimer: any
hideTimer: any
} = { showTimer: undefined, hideTimer: undefined }
const state = reactive<usePopperState>({
instance: null,
popperId,
attrs: {
styles: {
popper: {
position: 'absolute',
left: '0',
top: '0',
},
arrow: {
position: 'absolute',
},
},
attributes: {},
},
})
const popperOptions = computed<PopperOptions>(() => {
return {
placement: props.placement || 'bottom-start',
strategy: 'absolute',
modifiers: [
{
name: 'updateState',
enabled: true,
phase: 'write',
fn: ({ state: popperState }: any) => {
const elements = Object.keys(popperState.elements)
state.attrs = {
styles: fromEntries(elements.map(element => [element, popperState.styles[element] || {}])),
attributes: fromEntries(elements.map(element => [element, popperState.attributes[element] || {}])),
}
},
requires: ['computeStyles'],
},
{ name: 'applyStyles', enabled: false },
{ name: 'offset', options: { offset: [0, props.offset || 0] } },
],
}
})
const clearScheduled = () => {
clearTimeout(timers.hideTimer)
clearTimeout(timers.showTimer)
}
let clickEvent: any = null
const togglePopper = (event: MouseEvent) => {
clickEvent = event
props.onTrigger(popperId)
}
const showPopper = () => {
clearScheduled()
timers.showTimer = setTimeout(() => {
props.onTrigger(popperId, true)
}, 0)
}
const hidePopper = () => {
clearScheduled()
timers.hideTimer = setTimeout(() => {
props.onTrigger(popperId, false)
}, props.hideDaly || 200)
}
const outSideClickHandler = (event: MouseEvent) => {
// outSideClick 和 togglePopper 冲突
if (event === clickEvent) {
return
}
if (popperRef.value && !popperRef.value.contains(event.target as Node)) {
if (
['hover', 'focus'].indexOf(props.trigger) !== -1 &&
referenceRef.value &&
referenceRef.value.contains(event.target as Node)
) {
return
} else {
hidePopper()
}
}
}
const eventRegOrUnReg = isReg => {
const referenceEl = referenceRef.value
const popperEl = popperRef.value
const event = isReg ? 'addEventListener' : 'removeEventListener'
if (referenceEl && popperEl) {
if (props.trigger === 'hover') {
referenceEl[event]('mouseenter', showPopper)
referenceEl[event]('mouseleave', hidePopper)
popperEl[event]('mouseenter', showPopper)
popperEl[event]('mouseleave', hidePopper)
}
if (props.trigger === 'click') {
referenceEl[event]('click', togglePopper)
// popperEl[event]('mouseenter', showPopper)
// popperEl[event]('mouseleave', hidePopper)
}
if (props.trigger === 'focus') {
referenceEl[event]('focus', showPopper)
referenceEl[event]('blur', hidePopper)
}
if (props.trigger !== 'manual') {
document[event]('click', outSideClickHandler)
}
}
}
watchEffect(() => {
if (state.instance) {
state.instance.setOptions(popperOptions.value)
}
})
watch([referenceRef, popperRef], () => {
const referenceEl = referenceRef.value
const popperEl = popperRef.value
if (referenceEl && popperEl) {
if (state.instance) {
state.instance.destroy()
}
state.instance = createPopper(referenceEl, popperEl as HTMLElement, popperOptions.value)
}
})
watchEffect(onInvalidate => {
const referenceEl = referenceRef.value
const popperEl = popperRef.value
onInvalidate(() => {
eventRegOrUnReg(false)
})
if (referenceEl && popperEl) {
eventRegOrUnReg(true)
}
})
onUnmounted(() => {
if (state.instance) {
state.instance.destroy()
}
})
return state
}
Example #12
Source File: useDraggable.ts From elenext with MIT License | 4 votes |
export default function useDraggable(
options: DraggableOptions
): [
Ref<HTMLElement | undefined>,
Ref<HTMLElement | undefined>,
{
dragging: Ref<boolean>
delta: Ref<{ x: number; y: number }>
style: Ref<CSSProperties>
limits: Ref<RectLimit | undefined>
}
] {
const targetRef = ref<HTMLElement>()
const handleRef = ref<HTMLElement>()
const dragging = ref(false)
const prev = ref<Point>({ x: 0, y: 0 })
const delta = ref<Point>({ x: 0, y: 0 })
const limits = ref<RectLimit | undefined>()
const handleSize = ref<Size>({ width: 0, height: 0 })
const style = computed<CSSProperties>(() => {
const direction = options.direction
const x = direction !== 'y' ? delta.value.x - handleSize.value.width / 2 : 0
const y = direction !== 'x' ? delta.value.y - handleSize.value.height / 2 : 0
return {
transform: `translate3D(${x}px,${y}px,0)`,
}
})
const startDragging = (event: TouchEvent) => {
event.preventDefault()
dragging.value = true
if (options.viewport) {
const { width, height } = targetRef.value!.getBoundingClientRect()
limits.value = {
minX: 0,
maxX: width,
minY: 0,
maxY: height,
}
}
}
const reposition = (event: TouchEvent) => {
if (dragging.value) {
const source = (event.changedTouches && event.changedTouches[0]) || (event.touches && event.touches[0]) || event
const { left, top } = targetRef.value!.getBoundingClientRect()
const { clientX, clientY } = source
const x = clientX - left
const y = clientY - top
const newDelta = calcDelta({
x,
y,
limits: limits.value,
})
delta.value = newDelta
return newDelta
}
return prev.value
}
const stopDragging = (event: TouchEvent) => {
event.preventDefault()
dragging.value = false
const newDelta = reposition(event)
prev.value = newDelta
}
watchEffect(() => {
if (targetRef.value && handleRef.value) {
const { width, height } = targetRef.value.getBoundingClientRect()
const { width: handleWidth, height: handleHeight } = handleRef.value.getBoundingClientRect()
handleSize.value = {
width: handleWidth,
height: handleHeight,
}
limits.value = {
minX: 0,
maxX: width,
minY: 0,
maxY: height,
}
const initPoint = options.onInit?.({ width, height })
if (initPoint) {
delta.value = initPoint
}
}
})
watchEffect(() => {
if (handleRef.value) {
const handle = handleRef.value
handle.addEventListener('mousedown', startDragging)
handle.addEventListener('touchstart', startDragging)
return () => {
handle.removeEventListener('mousedown', startDragging)
handle.removeEventListener('touchstart', startDragging)
}
}
})
watchEffect(() => {
if (targetRef.value) {
document.addEventListener('mousemove', reposition, { passive: true })
document.addEventListener('touchmove', reposition, { passive: true })
document.addEventListener('mouseup', stopDragging)
document.addEventListener('touchend', stopDragging)
return () => {
document.removeEventListener('mousemove', reposition)
document.removeEventListener('touchmove', reposition)
document.removeEventListener('mouseup', stopDragging)
document.removeEventListener('touchend', stopDragging)
}
}
})
return [targetRef, handleRef, { dragging, delta, style, limits }]
}
Example #13
Source File: useInput.ts From formkit with MIT License | 4 votes |
/**
* A composable for creating a new FormKit node.
* @param type - The type of node (input, group, list)
* @param attrs - The FormKit "props" — which is really the attrs list.
* @returns
* @public
*/
export function useInput(
props: FormKitComponentProps,
context: SetupContext<any>,
options: FormKitOptions = {}
): FormKitNode {
/**
* The configuration options, these are provided by either the plugin or by
* explicit props.
*/
const config = Object.assign({}, inject(optionsSymbol) || {}, options)
/**
* The current instance.
*/
const instance = getCurrentInstance()
/**
* Extracts the listeners.
*/
const listeners = onlyListeners(instance?.vnode.props)
/**
* Determines if the prop is v-modeled.
*/
const isVModeled = props.modelValue !== undefined
/**
* Determines if the object being passed as a v-model is reactive.
*/
// const isReactiveVModel = isVModeled && isReactive(props.modelValue)
/**
* Define the initial component
*/
const value: any =
props.modelValue !== undefined
? props.modelValue
: cloneAny(context.attrs.value)
/**
* Creates the node's initial props from the context, props, and definition
* @returns
*/
function createInitialProps(): Record<string, any> {
const initialProps: Record<string, any> = {
...nodeProps(props),
...listeners,
}
const attrs = except(nodeProps(context.attrs), pseudoProps)
initialProps.attrs = attrs
const propValues = only(nodeProps(context.attrs), pseudoProps)
for (const propName in propValues) {
initialProps[camel(propName)] = propValues[propName]
}
const classesProps = { props: {} }
classesToNodeProps(classesProps as FormKitNode, props)
Object.assign(initialProps, classesProps.props)
if (typeof initialProps.type !== 'string') {
initialProps.definition = initialProps.type
delete initialProps.type
}
return initialProps
}
/**
* Create the FormKitNode.
*/
const initialProps = createInitialProps()
/**
* The parent node.
*/
const parent = initialProps.ignore
? null
: props.parent || inject(parentSymbol, null)
const node = createNode(
extend(
config || {},
{
name: props.name || undefined,
value,
parent,
plugins: (config.plugins || []).concat(props.plugins),
config: props.config,
props: initialProps,
index: props.index,
},
false,
true
) as Partial<FormKitOptions>
) as FormKitNode
/**
* If no definition has been assigned at this point — we're out!
*/
if (!node.props.definition) error(600, node)
/**
* All props that are bound "late" (after node creation) — are added to a set
* which is used to watch the context.attrs object.
*/
const lateBoundProps = ref<Set<string | RegExp>>(
new Set(node.props.definition.props || [])
)
/**
* Any additional props added at a "later" time should also be part of the
* late bound props.
*/
node.on('added-props', ({ payload: lateProps }) => {
if (Array.isArray(lateProps))
lateProps.forEach((newProp) => lateBoundProps.value.add(newProp))
})
/**
* These prop names must be assigned.
*/
const pseudoPropNames = computed(() =>
pseudoProps.concat([...lateBoundProps.value]).reduce((names, prop) => {
if (typeof prop === 'string') {
names.push(camel(prop))
names.push(kebab(prop))
} else {
names.push(prop)
}
return names
}, [] as Array<string | RegExp>)
)
/* Splits Classes object into discrete props for each key */
watchEffect(() => classesToNodeProps(node, props))
/**
* The props object already has properties even if they start as "undefined"
* so we can loop over them and individual watchEffect to prevent responding
* inappropriately.
*/
const passThrough = nodeProps(props)
for (const prop in passThrough) {
watch(
() => props[prop as keyof FormKitComponentProps],
() => {
if (props[prop as keyof FormKitComponentProps] !== undefined) {
node.props[prop] = props[prop as keyof FormKitComponentProps]
}
}
)
}
/**
* Watch "pseudoProp" attributes explicitly.
*/
const attributeWatchers = new Set<WatchStopHandle>()
const possibleProps = nodeProps(context.attrs)
watchEffect(() => {
watchAttributes(only(possibleProps, pseudoPropNames.value))
})
/**
* Defines attributes that should be used as props.
* @param attrProps - Attributes that should be used as props instead
*/
function watchAttributes(attrProps: Record<string, any>) {
attributeWatchers.forEach((stop) => {
stop()
attributeWatchers.delete(stop)
})
for (const prop in attrProps) {
const camelName = camel(prop)
attributeWatchers.add(
watch(
() => context.attrs[prop],
() => {
node.props[camelName] = context.attrs[prop]
}
)
)
}
}
/**
* Watch and dynamically set attribute values, those values that are not
* props and are not pseudoProps
*/
watchEffect(() => {
const attrs = except(nodeProps(context.attrs), pseudoPropNames.value)
node.props.attrs = Object.assign({}, node.props.attrs || {}, attrs)
})
/**
* Add any/all "prop" errors to the store.
*/
watchEffect(() => {
const messages = props.errors.map((error) =>
createMessage({
key: slugify(error),
type: 'error',
value: error,
meta: { source: 'prop' },
})
)
node.store.apply(
messages,
(message) => message.type === 'error' && message.meta.source === 'prop'
)
})
/**
* Add input errors.
*/
if (node.type !== 'input') {
const sourceKey = `${node.name}-prop`
watchEffect(() => {
const keys = Object.keys(props.inputErrors)
const messages = keys.reduce((messages, key) => {
let value = props.inputErrors[key]
if (typeof value === 'string') value = [value]
if (Array.isArray(value)) {
messages[key] = value.map((error) =>
createMessage({
key: error,
type: 'error',
value: error,
meta: { source: sourceKey },
})
)
}
return messages
}, {} as Record<string, FormKitMessage[]>)
node.store.apply(
messages,
(message) =>
message.type === 'error' && message.meta.source === sourceKey
)
})
}
/**
* Watch the config prop for any changes.
*/
watchEffect(() => Object.assign(node.config, props.config))
/**
* Produce another parent object.
*/
if (node.type !== 'input') {
provide(parentSymbol, node)
}
let inputTimeout: number | undefined
// eslint-disable-next-line @typescript-eslint/ban-types
const mutex = new WeakSet<object>()
/**
* Explicitly watch the input value, and emit changes (lazy)
*/
node.on('modelUpdated', () => {
// Emit the values after commit
context.emit('inputRaw', node.context?.value, node)
clearTimeout(inputTimeout)
inputTimeout = setTimeout(
context.emit,
20,
'input',
node.context?.value,
node
) as unknown as number
if (isVModeled && node.context) {
const newValue = useRaw(node.context.value)
if (isObject(newValue) && useRaw(props.modelValue) !== newValue) {
// If this is an object that has been mutated inside FormKit core then
// we know when it is emitted it will "return" in the watchVerbose so
// we pro-actively add it to the mutex.
mutex.add(newValue)
}
context.emit('update:modelValue', newValue)
}
})
/**
* Enabled support for v-model, using this for groups/lists is not recommended
*/
if (isVModeled) {
watchVerbose(toRef(props, 'modelValue'), (path, value): void | boolean => {
const rawValue = useRaw(value)
if (isObject(rawValue) && mutex.has(rawValue)) {
return mutex.delete(rawValue)
}
if (!path.length) node.input(value, false)
else node.at(path)?.input(value, false)
})
}
/**
* When this input shuts down, we need to "delete" the node too.
*/
onUnmounted(() => node.destroy())
return node
}
Example #14
Source File: composer.test.ts From vue-i18n-next with MIT License | 4 votes |
describe('tm', () => {
test('basic', async () => {
const composer = createComposer({
locale: 'ja',
messages: {
en: {
foo: {
bar: {
buz: 'hello'
},
codes: {
errors: ['error1', 'error2']
}
}
},
ja: {
foo: {
bar: {
buz: 'こんにちは'
},
codes: {
errors: ['エラー1', 'エラー2']
}
}
}
}
})
let messages1 = composer.tm('foo.bar')
let messages2 = composer.tm('foo.codes')
expect(messages1).toEqual({ buz: 'こんにちは' })
expect(messages2).toEqual({ errors: ['エラー1', 'エラー2'] })
watchEffect(() => {
messages1 = composer.tm('foo.bar')
messages2 = composer.tm('foo.codes')
})
composer.locale.value = 'en'
await nextTick()
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
})
test('fallback to local locale', () => {
const composer = createComposer({
locale: 'en',
fallbackLocale: 'ja',
messages: {
ja: {
foo: {
bar: {
buz: 'hello'
}
}
}
}
})
const messages1 = composer.tm('foo')
expect(messages1).toEqual({ bar: { buz: 'hello' } })
})
test('fallback to global locale', () => {
const __root = createComposer({
locale: 'en',
fallbackLocale: 'ja',
messages: {
ja: {
foo: {
bar: {
buz: 'hello'
}
}
}
}
})
const child = createComposer({
inheritLocale: true,
__root
})
const messages1 = child.tm('foo')
expect(messages1).toEqual({ bar: { buz: 'hello' } })
})
test('resolved with rt', () => {
const { rt, tm } = createComposer({
locale: 'en',
messages: {
en: {
foo: {
bar: {
buz: 'hello, {name}!'
},
codes: {
errors: [() => 'error1', () => 'error2']
}
}
},
ja: {
foo: {
bar: {
buz: 'こんにちは、 {name}!'
},
codes: {
errors: [() => 'エラー1', () => 'エラー2']
}
}
}
}
})
expect(rt(tm('foo.bar').buz, { name: 'dio' })).toEqual('hello, dio!')
const errors = tm('foo.codes.errors')
for (const [index, err] of errors.entries()) {
expect(rt(err)).toEqual(`error${index + 1}`)
}
})
})