Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
196 lines
3.9 KiB
Markdown
196 lines
3.9 KiB
Markdown
---
|
|
category: Reactivity
|
|
related: syncRefs
|
|
---
|
|
|
|
# syncRef
|
|
|
|
Two-way refs synchronization.
|
|
|
|
## Usage
|
|
|
|
```ts
|
|
import { syncRef } from '@vueuse/core'
|
|
|
|
const a = ref('a')
|
|
const b = ref('b')
|
|
|
|
const stop = syncRef(a, b)
|
|
|
|
console.log(a.value) // a
|
|
|
|
b.value = 'foo'
|
|
|
|
console.log(a.value) // foo
|
|
|
|
a.value = 'bar'
|
|
|
|
console.log(b.value) // bar
|
|
```
|
|
|
|
### One directional
|
|
|
|
```ts
|
|
import { syncRef } from '@vueuse/core'
|
|
|
|
const a = ref('a')
|
|
const b = ref('b')
|
|
|
|
const stop = syncRef(a, b, { direction: 'rtl' })
|
|
```
|
|
|
|
### Custom Transform
|
|
|
|
```ts
|
|
import { syncRef } from '@vueuse/core'
|
|
|
|
const a = ref(10)
|
|
const b = ref(2)
|
|
|
|
const stop = syncRef(a, b, {
|
|
transform: {
|
|
ltr: left => left * 2,
|
|
rtl: right => right / 2
|
|
}
|
|
})
|
|
|
|
console.log(b.value) // 20
|
|
|
|
b.value = 30
|
|
|
|
console.log(a.value) // 15
|
|
```
|
|
|
|
## Type Declarations
|
|
|
|
```ts
|
|
type Direction = "ltr" | "rtl" | "both"
|
|
type SpecificFieldPartial<T, K extends keyof T> = Partial<Pick<T, K>> &
|
|
Omit<T, K>
|
|
/**
|
|
* A = B
|
|
*/
|
|
type Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false
|
|
/**
|
|
* A ∩ B ≠ ∅
|
|
*/
|
|
type IntersectButNotEqual<A, B> =
|
|
Equal<A, B> extends true ? false : A & B extends never ? false : true
|
|
/**
|
|
* A ⊆ B
|
|
*/
|
|
type IncludeButNotEqual<A, B> =
|
|
Equal<A, B> extends true ? false : A extends B ? true : false
|
|
/**
|
|
* A ∩ B = ∅
|
|
*/
|
|
type NotIntersect<A, B> =
|
|
Equal<A, B> extends true ? false : A & B extends never ? true : false
|
|
interface EqualType<
|
|
D extends Direction,
|
|
L,
|
|
R,
|
|
O extends keyof Transform<L, R> = D extends "both" ? "ltr" | "rtl" : D,
|
|
> {
|
|
transform?: SpecificFieldPartial<Pick<Transform<L, R>, O>, O>
|
|
}
|
|
type StrictIncludeMap<
|
|
IncludeType extends "LR" | "RL",
|
|
D extends Exclude<Direction, "both">,
|
|
L,
|
|
R,
|
|
> = Equal<[IncludeType, D], ["LR", "ltr"]> &
|
|
Equal<[IncludeType, D], ["RL", "rtl"]> extends true
|
|
? {
|
|
transform?: SpecificFieldPartial<Pick<Transform<L, R>, D>, D>
|
|
}
|
|
: {
|
|
transform: Pick<Transform<L, R>, D>
|
|
}
|
|
type StrictIncludeType<
|
|
IncludeType extends "LR" | "RL",
|
|
D extends Direction,
|
|
L,
|
|
R,
|
|
> = D extends "both"
|
|
? {
|
|
transform: SpecificFieldPartial<
|
|
Transform<L, R>,
|
|
IncludeType extends "LR" ? "ltr" : "rtl"
|
|
>
|
|
}
|
|
: D extends Exclude<Direction, "both">
|
|
? StrictIncludeMap<IncludeType, D, L, R>
|
|
: never
|
|
type IntersectButNotEqualType<D extends Direction, L, R> = D extends "both"
|
|
? {
|
|
transform: Transform<L, R>
|
|
}
|
|
: D extends Exclude<Direction, "both">
|
|
? {
|
|
transform: Pick<Transform<L, R>, D>
|
|
}
|
|
: never
|
|
type NotIntersectType<D extends Direction, L, R> = IntersectButNotEqualType<
|
|
D,
|
|
L,
|
|
R
|
|
>
|
|
interface Transform<L, R> {
|
|
ltr: (left: L) => R
|
|
rtl: (right: R) => L
|
|
}
|
|
type TransformType<D extends Direction, L, R> =
|
|
Equal<L, R> extends true
|
|
? EqualType<D, L, R>
|
|
: IncludeButNotEqual<L, R> extends true
|
|
? StrictIncludeType<"LR", D, L, R>
|
|
: IncludeButNotEqual<R, L> extends true
|
|
? StrictIncludeType<"RL", D, L, R>
|
|
: IntersectButNotEqual<L, R> extends true
|
|
? IntersectButNotEqualType<D, L, R>
|
|
: NotIntersect<L, R> extends true
|
|
? NotIntersectType<D, L, R>
|
|
: never
|
|
export type SyncRefOptions<
|
|
L,
|
|
R,
|
|
D extends Direction,
|
|
> = ConfigurableFlushSync & {
|
|
/**
|
|
* Watch deeply
|
|
*
|
|
* @default false
|
|
*/
|
|
deep?: boolean
|
|
/**
|
|
* Sync values immediately
|
|
*
|
|
* @default true
|
|
*/
|
|
immediate?: boolean
|
|
/**
|
|
* Direction of syncing. Value will be redefined if you define syncConvertors
|
|
*
|
|
* @default 'both'
|
|
*/
|
|
direction?: D
|
|
} & TransformType<D, L, R>
|
|
/**
|
|
* Two-way refs synchronization.
|
|
* From the set theory perspective to restrict the option's type
|
|
* Check in the following order:
|
|
* 1. L = R
|
|
* 2. L ∩ R ≠ ∅
|
|
* 3. L ⊆ R
|
|
* 4. L ∩ R = ∅
|
|
*/
|
|
export declare function syncRef<L, R, D extends Direction = "both">(
|
|
left: Ref<L>,
|
|
right: Ref<R>,
|
|
...[options]: Equal<L, R> extends true
|
|
? [options?: SyncRefOptions<L, R, D>]
|
|
: [options: SyncRefOptions<L, R, D>]
|
|
): () => void
|
|
```
|