diff --git a/packages/atom/src/Atom.ts b/packages/atom/src/Atom.ts index 4e2e11a..7a7fcf0 100644 --- a/packages/atom/src/Atom.ts +++ b/packages/atom/src/Atom.ts @@ -26,7 +26,9 @@ import * as MutableHashMap from "effect/MutableHashMap" import * as Option from "effect/Option" import { type Pipeable, pipeArguments } from "effect/Pipeable" import { hasProperty, isObject } from "effect/Predicate" +import * as Predicate from "effect/Predicate" import type { ReadonlyRecord } from "effect/Record" +import * as Record from "effect/Record" import * as Runtime from "effect/Runtime" import * as Schema from "effect/Schema" import * as Scope from "effect/Scope" @@ -1540,6 +1542,66 @@ export const map: { (self: Atom, f: (_: A) => B): Atom => transform(self, (get) => f(get(self))) ) +/** + * `Atom.slice` can be used to split up a structure atom into separate atoms + * for each property. This has the benefit of gating reactivity: if the source + * structure updates, but the target property does not, then any atom that + * depends on that property's slice atom will not update. + * + * @since 1.0.0 + * @category combinators + */ +export function slice>( + atom: A +): { readonly [K in keyof Type]: Atom[K]> } +/** + * `Atom.slice` can be used to split up a structure atom into separate atoms + * for each property. This has the benefit of gating reactivity: if the source + * structure updates, but the target property does not, then any atom that + * depends on that property's slice atom will not update. + * + * @since 1.0.0 + * @category combinators + */ +export function slice>( + family: (arg: Arg) => A +): { + readonly [K in keyof Type]: (arg: Arg) => Atom[K]> +} +export function slice>>( + input: A | ((arg: Arg) => A) +): + | Record> + | Record Atom> +{ + const isFamily = Predicate.isFunction(input) + + return new Proxy< + | Record> + | Record Atom> + >( + {}, + { + get(target, property, receiver) { + if ( + Record.has(target, property) || + Predicate.isSymbol(property) + ) { + return Reflect.get(target, property, receiver) + } + + const value = isFamily ? + family((arg: Arg) => readable((get) => get(input(arg))[property])) + : readable((get) => get(input)[property]) + + target[property] = value + + return value + } + } + ) +} + /** * @since 1.0.0 * @category combinators