Skip to content

Commit

Permalink
Merge branch 'release/v0.19.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
holtwick committed Apr 7, 2024
2 parents 97026e5 + 57c02a5 commit e2aa89e
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zeed",
"type": "module",
"version": "0.19.5",
"version": "0.19.6",
"description": "🌱 Simple foundation library",
"author": {
"name": "Dirk Holtwick",
Expand Down
1 change: 1 addition & 0 deletions src/common/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export * from './orderby'
export * from './path'
export * from './regexp'
export * from './rounding'
export * from './signal'
export * from './sortable'
export * from './sorted'
export * from './string-deburr'
Expand Down
53 changes: 53 additions & 0 deletions src/common/data/signal.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useSignal } from './signal'

describe('signal', () => {
it('should signal', async () => {
let copy: any // copy of "flag"
let count = 1 // counter for "name"

const [flag, setFlag] = useSignal(true, v => copy = v)
const name = useSignal('Henry')
const object = useSignal({
a: 1,
b: 2,
})

const off = name.on(v => ++count)

// Get values
expect(flag()).toEqual(true)
expect(name.get()).toEqual('Henry')
expect(copy).toEqual(undefined)
expect(object.get()).toEqual({
a: 1,
b: 2,
})

// Change values
setFlag(false)
name.set('Anna')
object.set({
a: 11,
b: 22,
})

// Check changed values
expect(flag()).toEqual(false)
expect(name.get()).toEqual('Anna')
expect(copy).toEqual(false)
expect(object.get()).toEqual({
a: 11,
b: 22,
})

// Skip setting same value
expect(count).toBe(2)
name.set('Anna')
expect(count).toBe(2)
name.set('Cloe')
expect(count).toBe(3)
off()
name.set('Diego')
expect(count).toBe(3)
})
})
52 changes: 52 additions & 0 deletions src/common/data/signal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { arrayRemoveElement } from './array'
import { objectPlain } from './object'

export type SignalWatcher<T> = (value: T, oldValue: T) => void

export type Signal<T> = [
() => T,
(value: T) => void,
(fn: SignalWatcher<T>) => () => void,
(fn: SignalWatcher<T>) => void,
] & {
get: () => T
set: (value: T) => void
on: (fn: SignalWatcher<T>) => () => void
off: (fn: SignalWatcher<T>) => void
}

/** Super simple signal implementation */
export function useSignal<T = any>(value: T, onChange?: SignalWatcher<T>): Signal<T> {
let signal = structuredClone(value)

const watchers: SignalWatcher<T>[] = []

function off(fn: SignalWatcher<T>) {
arrayRemoveElement(watchers, fn)
}

function on(fn: SignalWatcher<T>) {
watchers.push(fn)
return () => off(fn)
}

if (onChange)
watchers.push(onChange)

const get = () => structuredClone(signal)

const set = (value: T) => {
if (value !== signal) {
const oldValue = signal
signal = value
watchers.forEach(fn => fn(value, oldValue))
}
}

const obj: any = [get, set, on, off]
obj.get = get
obj.set = set
obj.on = on
obj.off = off
return obj
}

0 comments on commit e2aa89e

Please sign in to comment.