From 96a4ab62e7ee2a3b2ff18d14e80443f087d8a5b6 Mon Sep 17 00:00:00 2001 From: Nikita MIkhailov Date: Wed, 20 Jul 2022 14:43:05 +0400 Subject: [PATCH 1/6] feat(syncRef): added sync convertors. --- packages/shared/syncRef/demo.vue | 26 ++++++++ packages/shared/syncRef/index.md | 21 +++++++ packages/shared/syncRef/index.test.ts | 71 ++++++++++++++++++++++ packages/shared/syncRef/index.ts | 85 ++++++++++++++++++++++----- 4 files changed, 188 insertions(+), 15 deletions(-) diff --git a/packages/shared/syncRef/demo.vue b/packages/shared/syncRef/demo.vue index eb8331f8276..dc8cb2ac4a0 100644 --- a/packages/shared/syncRef/demo.vue +++ b/packages/shared/syncRef/demo.vue @@ -6,9 +6,35 @@ const a = ref('') const b = ref('') syncRef(a, b) + +const x = ref(1) +const y = ref(1) + +syncRef(x, y, { + syncConvertors: { + ltr: (left, _) => { + return left.value + Math.random() + }, + rtl: (_, right) => { + return right.value + Math.random() + }, + }, +}) diff --git a/packages/shared/syncRef/index.md b/packages/shared/syncRef/index.md index 34429a4d79b..6943d7bc48e 100644 --- a/packages/shared/syncRef/index.md +++ b/packages/shared/syncRef/index.md @@ -38,3 +38,24 @@ const b = ref('b') const stop = syncRef(a, b, { direction: 'rtl' }) ``` + +Sync convertors +```ts +import { syncRef } from '@vueuse/core' + +const a = ref(10) +const b = ref(2) + +const stop = syncRef(a, b, { + syncConvertors: { + ltr: left => left * 2, + rtl: (_, right) => right / 2 + } +}) + +console.log(b.value) // 20 + +b.value = 30 + +console.log(a.value) // 15 +``` diff --git a/packages/shared/syncRef/index.test.ts b/packages/shared/syncRef/index.test.ts index bfbe9f90122..8b8e991e413 100644 --- a/packages/shared/syncRef/index.test.ts +++ b/packages/shared/syncRef/index.test.ts @@ -47,4 +47,75 @@ describe('syncRef', () => { expect(left.value).toBe('foobar') expect(right.value).toBe('foobar') }) + + it('works with mutual convertors', () => { + const left = ref(10) + const right = ref(1) + + syncRef(left, right, { + syncConvertors: { + ltr: left => left.value * 2, + rtl: (_, right) => Math.round(right.value / 2), + }, + }) + + // check immediately sync + expect(right.value).toBe(20) + expect(left.value).toBe(10) + + left.value = 30 + expect(right.value).toBe(60) + expect(left.value).toBe(30) + + right.value = 10 + expect(right.value).toBe(10) + expect(left.value).toBe(5) + }) + + it('works with only rtl convertor', () => { + const left = ref(10) + const right = ref(2) + + syncRef(left, right, { + syncConvertors: { + rtl: (_, right) => Math.round(right.value / 2), + }, + }) + + // check immediately sync + expect(right.value).toBe(2) + expect(left.value).toBe(1) + + left.value = 10 + expect(right.value).toBe(2) + expect(left.value).toBe(10) + + right.value = 10 + + expect(right.value).toBe(10) + expect(left.value).toBe(5) + }) + + it('works with only ltr convertor', () => { + const right = ref(10) + const left = ref(2) + + syncRef(left, right, { + syncConvertors: { + ltr: left => Math.round(left.value / 2), + }, + }) + + // check immediately sync + expect(left.value).toBe(2) + expect(right.value).toBe(1) + + right.value = 10 + expect(left.value).toBe(2) + expect(right.value).toBe(10) + + left.value = 10 + expect(left.value).toBe(10) + expect(right.value).toBe(5) + }) }) diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 8a187a02316..997914aea21 100644 --- a/packages/shared/syncRef/index.ts +++ b/packages/shared/syncRef/index.ts @@ -1,8 +1,9 @@ -import type { Ref } from 'vue-demi' -import { watch } from 'vue-demi' +import type { WatchPausableReturn } from '@vueuse/shared' +import { pausableWatch } from '@vueuse/shared' +import type { Ref, UnwrapRef } from 'vue-demi' import type { ConfigurableFlushSync } from '../utils' -export interface SyncRefOptions extends ConfigurableFlushSync { +export interface SyncRefOptions extends ConfigurableFlushSync { /** * Watch deeply * @@ -17,11 +18,18 @@ export interface SyncRefOptions extends ConfigurableFlushSync { immediate?: boolean /** - * Direction of syncing + * Direction of syncing. Value will be redefined if you define syncConvertors * * @default 'both' */ direction?: 'ltr' | 'rtl' | 'both' + /** + * Sync function which converts values before sync. + */ + syncConvertors?: { + ltr?: (left: Ref, right: Ref) => T + rtl?: (left: Ref, right: Ref) => T + } } /** @@ -30,34 +38,81 @@ export interface SyncRefOptions extends ConfigurableFlushSync { * @param left * @param right */ -export function syncRef>(left: R, right: R, options: SyncRefOptions = {}) { +export function syncRef(left: R, right: R, options: SyncRefOptions> = {}) { const { flush = 'sync', deep = false, immediate = true, - direction = 'both', + syncConvertors = {}, } = options - let stop1: Function, stop2: Function + let watchLeft: WatchPausableReturn, watchRight: WatchPausableReturn + + let { direction = 'both' } = options + + if (syncConvertors.ltr || syncConvertors.rtl) { + if (syncConvertors.ltr && syncConvertors.rtl) + direction = 'both' + + else if (syncConvertors.ltr) + direction = 'ltr' + + else + direction = 'rtl' + } + + function sync() { + if (direction === 'ltr' || direction === 'both') + right.value = syncConvertors.ltr ? syncConvertors.ltr(left, right) : left.value + else + left.value = syncConvertors.rtl ? syncConvertors.rtl(left, right) : right.value + } + + if (immediate) + sync() if (direction === 'both' || direction === 'ltr') { - stop1 = watch( + watchLeft = pausableWatch( left, - newValue => right.value = newValue, - { flush, deep, immediate }, + (newValue) => { + if (!syncConvertors.ltr) { + right.value = newValue + + return + } + + watchRight?.pause() + + right.value = syncConvertors.ltr(left, right) + + watchRight?.resume() + }, + { flush, deep }, ) } if (direction === 'both' || direction === 'rtl') { - stop2 = watch( + watchRight = pausableWatch( right, - newValue => left.value = newValue, - { flush, deep, immediate }, + (newValue) => { + if (!syncConvertors.rtl) { + left.value = newValue + + return + } + + watchLeft?.pause() + + left.value = syncConvertors.rtl(left, right) + + watchLeft?.resume() + }, + { flush, deep }, ) } return () => { - stop1?.() - stop2?.() + watchLeft?.stop() + watchRight?.stop() } } From 2f9966fb2293a56caf4b769249c318da0cc1a7f1 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 24 Jul 2022 16:59:10 +0800 Subject: [PATCH 2/6] refactor --- packages/shared/syncRef/demo.vue | 2 +- packages/shared/syncRef/index.test.ts | 34 +++---------- packages/shared/syncRef/index.ts | 71 +++++++++------------------ 3 files changed, 29 insertions(+), 78 deletions(-) diff --git a/packages/shared/syncRef/demo.vue b/packages/shared/syncRef/demo.vue index dc8cb2ac4a0..36ad0d02857 100644 --- a/packages/shared/syncRef/demo.vue +++ b/packages/shared/syncRef/demo.vue @@ -11,7 +11,7 @@ const x = ref(1) const y = ref(1) syncRef(x, y, { - syncConvertors: { + transform: { ltr: (left, _) => { return left.value + Math.random() }, diff --git a/packages/shared/syncRef/index.test.ts b/packages/shared/syncRef/index.test.ts index 8b8e991e413..09b5802d1af 100644 --- a/packages/shared/syncRef/index.test.ts +++ b/packages/shared/syncRef/index.test.ts @@ -53,9 +53,9 @@ describe('syncRef', () => { const right = ref(1) syncRef(left, right, { - syncConvertors: { - ltr: left => left.value * 2, - rtl: (_, right) => Math.round(right.value / 2), + transform: { + ltr: left => left * 2, + rtl: right => Math.round(right / 2), }, }) @@ -77,8 +77,9 @@ describe('syncRef', () => { const right = ref(2) syncRef(left, right, { - syncConvertors: { - rtl: (_, right) => Math.round(right.value / 2), + direction: 'rtl', + transform: { + rtl: right => Math.round(right / 2), }, }) @@ -95,27 +96,4 @@ describe('syncRef', () => { expect(right.value).toBe(10) expect(left.value).toBe(5) }) - - it('works with only ltr convertor', () => { - const right = ref(10) - const left = ref(2) - - syncRef(left, right, { - syncConvertors: { - ltr: left => Math.round(left.value / 2), - }, - }) - - // check immediately sync - expect(left.value).toBe(2) - expect(right.value).toBe(1) - - right.value = 10 - expect(left.value).toBe(2) - expect(right.value).toBe(10) - - left.value = 10 - expect(left.value).toBe(10) - expect(right.value).toBe(5) - }) }) diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 997914aea21..8a540b24f18 100644 --- a/packages/shared/syncRef/index.ts +++ b/packages/shared/syncRef/index.ts @@ -1,6 +1,6 @@ -import type { WatchPausableReturn } from '@vueuse/shared' -import { pausableWatch } from '@vueuse/shared' -import type { Ref, UnwrapRef } from 'vue-demi' +import { resolveUnref } from '@vueuse/shared' +import type { Ref, UnwrapRef, WatchStopHandle } from 'vue-demi' +import { watch } from 'vue-demi' import type { ConfigurableFlushSync } from '../utils' export interface SyncRefOptions extends ConfigurableFlushSync { @@ -23,12 +23,13 @@ export interface SyncRefOptions extends ConfigurableFlushSync { * @default 'both' */ direction?: 'ltr' | 'rtl' | 'both' + /** - * Sync function which converts values before sync. + * Custom transform function */ - syncConvertors?: { - ltr?: (left: Ref, right: Ref) => T - rtl?: (left: Ref, right: Ref) => T + transform?: { + ltr?: (left: T) => T + rtl?: (right: T) => T } } @@ -43,76 +44,48 @@ export function syncRef(left: R, right: R, options: SyncRefOption flush = 'sync', deep = false, immediate = true, - syncConvertors = {}, + transform = {}, } = options - let watchLeft: WatchPausableReturn, watchRight: WatchPausableReturn - - let { direction = 'both' } = options + let watchLeft: WatchStopHandle + let watchRight: WatchStopHandle - if (syncConvertors.ltr || syncConvertors.rtl) { - if (syncConvertors.ltr && syncConvertors.rtl) - direction = 'both' - - else if (syncConvertors.ltr) - direction = 'ltr' - - else - direction = 'rtl' - } + const { direction = 'both' } = options + const transformLTR = transform.ltr ?? (v => v) + const transformRTL = transform.rtl ?? (v => v) function sync() { if (direction === 'ltr' || direction === 'both') - right.value = syncConvertors.ltr ? syncConvertors.ltr(left, right) : left.value + right.value = transformLTR(resolveUnref(left)) else - left.value = syncConvertors.rtl ? syncConvertors.rtl(left, right) : right.value + left.value = transformRTL(resolveUnref(right)) } if (immediate) sync() if (direction === 'both' || direction === 'ltr') { - watchLeft = pausableWatch( + watchLeft = watch( left, (newValue) => { - if (!syncConvertors.ltr) { - right.value = newValue - - return - } - - watchRight?.pause() - - right.value = syncConvertors.ltr(left, right) - - watchRight?.resume() + right.value = transformLTR(newValue) }, { flush, deep }, ) } if (direction === 'both' || direction === 'rtl') { - watchRight = pausableWatch( + watchRight = watch( right, (newValue) => { - if (!syncConvertors.rtl) { - left.value = newValue - - return - } - - watchLeft?.pause() - - left.value = syncConvertors.rtl(left, right) - - watchLeft?.resume() + left.value = transformRTL(newValue) }, { flush, deep }, ) } return () => { - watchLeft?.stop() - watchRight?.stop() + watchLeft?.() + watchRight?.() } } From d2189012437e0c408f58a5d9b4578e774d0d3513 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 24 Jul 2022 17:00:46 +0800 Subject: [PATCH 3/6] docs: update --- packages/shared/syncRef/demo.vue | 26 -------------------------- packages/shared/syncRef/index.md | 7 ++++--- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/packages/shared/syncRef/demo.vue b/packages/shared/syncRef/demo.vue index 36ad0d02857..eb8331f8276 100644 --- a/packages/shared/syncRef/demo.vue +++ b/packages/shared/syncRef/demo.vue @@ -6,35 +6,9 @@ const a = ref('') const b = ref('') syncRef(a, b) - -const x = ref(1) -const y = ref(1) - -syncRef(x, y, { - transform: { - ltr: (left, _) => { - return left.value + Math.random() - }, - rtl: (_, right) => { - return right.value + Math.random() - }, - }, -}) diff --git a/packages/shared/syncRef/index.md b/packages/shared/syncRef/index.md index 6943d7bc48e..9b67f6ad158 100644 --- a/packages/shared/syncRef/index.md +++ b/packages/shared/syncRef/index.md @@ -28,7 +28,7 @@ a.value = 'bar' console.log(b.value) // bar ``` -One directional +### One directional ```ts import { syncRef } from '@vueuse/core' @@ -39,7 +39,8 @@ const b = ref('b') const stop = syncRef(a, b, { direction: 'rtl' }) ``` -Sync convertors +### Custom Transform + ```ts import { syncRef } from '@vueuse/core' @@ -49,7 +50,7 @@ const b = ref(2) const stop = syncRef(a, b, { syncConvertors: { ltr: left => left * 2, - rtl: (_, right) => right / 2 + rtl: right => right / 2 } }) From 8075341813011855506b08cec359da715de4dc84 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 24 Jul 2022 17:02:19 +0800 Subject: [PATCH 4/6] chore: update --- packages/shared/syncRef/index.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 8a540b24f18..9f1a39afb44 100644 --- a/packages/shared/syncRef/index.ts +++ b/packages/shared/syncRef/index.ts @@ -1,4 +1,3 @@ -import { resolveUnref } from '@vueuse/shared' import type { Ref, UnwrapRef, WatchStopHandle } from 'vue-demi' import { watch } from 'vue-demi' import type { ConfigurableFlushSync } from '../utils' @@ -44,21 +43,21 @@ export function syncRef(left: R, right: R, options: SyncRefOption flush = 'sync', deep = false, immediate = true, + direction = 'both', transform = {}, } = options let watchLeft: WatchStopHandle let watchRight: WatchStopHandle - const { direction = 'both' } = options const transformLTR = transform.ltr ?? (v => v) const transformRTL = transform.rtl ?? (v => v) function sync() { if (direction === 'ltr' || direction === 'both') - right.value = transformLTR(resolveUnref(left)) + right.value = transformLTR(left.value) else - left.value = transformRTL(resolveUnref(right)) + left.value = transformRTL(right.value) } if (immediate) @@ -67,9 +66,7 @@ export function syncRef(left: R, right: R, options: SyncRefOption if (direction === 'both' || direction === 'ltr') { watchLeft = watch( left, - (newValue) => { - right.value = transformLTR(newValue) - }, + newValue => right.value = transformLTR(newValue), { flush, deep }, ) } @@ -77,9 +74,7 @@ export function syncRef(left: R, right: R, options: SyncRefOption if (direction === 'both' || direction === 'rtl') { watchRight = watch( right, - (newValue) => { - left.value = transformRTL(newValue) - }, + newValue => left.value = transformRTL(newValue), { flush, deep }, ) } From a7951891ff176107171e8df34428ea7fd24a6ea1 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 24 Jul 2022 17:04:45 +0800 Subject: [PATCH 5/6] chore: update --- packages/shared/syncRef/index.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 9f1a39afb44..10165e84cd9 100644 --- a/packages/shared/syncRef/index.ts +++ b/packages/shared/syncRef/index.ts @@ -53,21 +53,11 @@ export function syncRef(left: R, right: R, options: SyncRefOption const transformLTR = transform.ltr ?? (v => v) const transformRTL = transform.rtl ?? (v => v) - function sync() { - if (direction === 'ltr' || direction === 'both') - right.value = transformLTR(left.value) - else - left.value = transformRTL(right.value) - } - - if (immediate) - sync() - if (direction === 'both' || direction === 'ltr') { watchLeft = watch( left, newValue => right.value = transformLTR(newValue), - { flush, deep }, + { flush, deep, immediate }, ) } @@ -75,7 +65,7 @@ export function syncRef(left: R, right: R, options: SyncRefOption watchRight = watch( right, newValue => left.value = transformRTL(newValue), - { flush, deep }, + { flush, deep, immediate }, ) } From a8e56a0bfe897381669e382f10479780d15d9397 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 24 Jul 2022 17:07:22 +0800 Subject: [PATCH 6/6] chore: update --- packages/shared/syncRef/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 10165e84cd9..975c7126dde 100644 --- a/packages/shared/syncRef/index.ts +++ b/packages/shared/syncRef/index.ts @@ -1,8 +1,8 @@ -import type { Ref, UnwrapRef, WatchStopHandle } from 'vue-demi' +import type { Ref, WatchStopHandle } from 'vue-demi' import { watch } from 'vue-demi' import type { ConfigurableFlushSync } from '../utils' -export interface SyncRefOptions extends ConfigurableFlushSync { +export interface SyncRefOptions extends ConfigurableFlushSync { /** * Watch deeply * @@ -27,8 +27,8 @@ export interface SyncRefOptions extends ConfigurableFlushSync { * Custom transform function */ transform?: { - ltr?: (left: T) => T - rtl?: (right: T) => T + ltr?: (left: L) => R + rtl?: (right: R) => L } } @@ -38,7 +38,7 @@ export interface SyncRefOptions extends ConfigurableFlushSync { * @param left * @param right */ -export function syncRef(left: R, right: R, options: SyncRefOptions> = {}) { +export function syncRef(left: Ref, right: Ref, options: SyncRefOptions = {}) { const { flush = 'sync', deep = false, @@ -56,7 +56,7 @@ export function syncRef(left: R, right: R, options: SyncRefOption if (direction === 'both' || direction === 'ltr') { watchLeft = watch( left, - newValue => right.value = transformLTR(newValue), + newValue => right.value = transformLTR(newValue) as R, { flush, deep, immediate }, ) } @@ -64,7 +64,7 @@ export function syncRef(left: R, right: R, options: SyncRefOption if (direction === 'both' || direction === 'rtl') { watchRight = watch( right, - newValue => left.value = transformRTL(newValue), + newValue => left.value = transformRTL(newValue) as L, { flush, deep, immediate }, ) }