Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
refactor: file structure
Browse files Browse the repository at this point in the history
  • Loading branch information
sheepbox8646 committed Jun 25, 2024
1 parent e27bea0 commit f6b70f5
Show file tree
Hide file tree
Showing 28 changed files with 322 additions and 301 deletions.
103 changes: 0 additions & 103 deletions packages/core/src/animation.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { CanvasKit } from 'canvaskit-wasm'
import { isUndefined } from '@newcar/utils'
import type { Widget } from './widget'
import type { Ref } from './prop'
import type { MaybeArray } from './utils'
import { normalize } from './utils'

// TODO: Rebuild needed!

Expand Down Expand Up @@ -98,102 +94,3 @@ export function useAnimate<T extends Widget, A>(anim: Animate<T, A>) {
}
})
}

export function withHook<T extends Widget, A>({
before,
animate,
after,
}: {
before?: Animate<T, A>
animate: Animate<T, A>
after?: Animate<T, A>
}) {
let called = false
return useAnimate<T, A>((ctx) => {
if (!called) {
if (before)
before(ctx)
called = true
}
animate(ctx)
if (ctx.process >= 1) {
if (after)
after(ctx)
}
})
}

export function changeProperty<T extends Widget>(
propsToChange: (widget: T) => MaybeArray<Ref<number>>,
) {
let called = false
let a: {
original: number[]
}

return useAnimate<T, {
changed: Ref<number>[]
original: number[]
from?: MaybeArray<number>
to: MaybeArray<number>
}>((ctx) => {
const from = !isUndefined(ctx.from) ? normalize(ctx.from) : ctx.original
const rto = normalize(ctx.to)
for (const index in ctx.changed) {
ctx.changed[index].value = from[index] + ctx.process * (rto[index] - from[index])
}
})
.with<{ original: number[], changed: Ref<number>[] }>((ctx) => {
if (!called) {
a = {
original: normalize(propsToChange(ctx.widget)).map(x => x.value),
}
called = true
}

return Object.assign(a, { changed: normalize(propsToChange(ctx.widget)) })
})
}

export function parallel<T extends Widget>(...anims: Anim<T>[]) {
return depend<() => boolean, AnimationContext<T>>((ctx) => {
return () => {
const res = anims.map(a => a.build(ctx)())
anims = res
.map((r, i) => [r, i])
.filter(([r, _]) => !r)
.map(([_, i]) => anims[i as any])

return res.reduce((x, xs) => x || xs)
}
})
}

export function sequence<T extends Widget>(...anims: Anim<T>[]) {
return depend<() => boolean, AnimationContext<T>>((ctx) => {
return () => {
if (anims[0].build(ctx)()) {
anims.shift()
if (anims.length === 0) {
return true
}
}

return false
}
})
}
export function delay<T extends Widget>(duration: number) {
return useAnimate<T, unknown>((_) => { }).withAttr({ duration })
}
export function timeline<T extends Widget>(...lines: [
number,
number,
WithDep<() => boolean, { duration: number } & AnimationContext<T>>,
][]) {
return parallel(
...lines.map(([d, duration, a]) =>
sequence(delay(d), a.withAttr({ duration }) as any),
),
)
}
13 changes: 13 additions & 0 deletions packages/core/src/apis/bind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { changed } from './changed'
import type { Reactive } from './reactive'
import type { Ref } from './ref'
import { ref } from './ref'

export function bind<T, K extends keyof T>(r: Reactive<T>, k: K): Ref<T[K]> {
const res = ref(r[k])
changed(res, (n) => {
r[k] = n.value
})

return res
}
19 changes: 19 additions & 0 deletions packages/core/src/apis/change-many.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { changed } from './changed'
import type { Listener, Reactive } from './reactive'

export function changedMany<T extends [Reactive<any>]>(
targets: T,
listener: Listener<T>,
) {
for (const [i, target] of targets.entries()) {
changed(target, (v) => {
const newValue = Array.of(...targets.entries()).map(([ix, nv]) => {
if (ix === i)
return v
else return nv
})

listener(newValue as any)
})
}
}
38 changes: 38 additions & 0 deletions packages/core/src/apis/change-property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { isUndefined } from '@newcar/utils'
import { useAnimate } from '../animation'
import type { MaybeArray } from '../utils'
import type { Widget } from '../widget'
import { normalize } from './normalize'
import type { Ref } from './ref'

export function changeProperty<T extends Widget>(
propsToChange: (widget: T) => MaybeArray<Ref<number>>,
) {
let called = false
let a: {
original: number[]
}

return useAnimate<T, {
changed: Ref<number>[]
original: number[]
from?: MaybeArray<number>
to: MaybeArray<number>
}>((ctx) => {
const from = !isUndefined(ctx.from) ? normalize(ctx.from) : ctx.original
const rto = normalize(ctx.to)
for (const index in ctx.changed) {
ctx.changed[index].value = from[index] + ctx.process * (rto[index] - from[index])
}
})
.with<{ original: number[], changed: Ref<number>[] }>((ctx) => {
if (!called) {
a = {
original: normalize(propsToChange(ctx.widget)).map((x: Ref<number>) => x.value),
}
called = true
}

return Object.assign(a, { changed: normalize(propsToChange(ctx.widget)) })
})
}
26 changes: 26 additions & 0 deletions packages/core/src/apis/changed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { isUndefined } from '@newcar/utils'
import type { Listener, PropertyWithChange, Reactive } from './reactive'

export function changed<T>(
target: Reactive<T>,
listener: Listener<T> | {
preChanged?: Listener<T>
postChanged?: Listener<T>
},
) {
const withChanged = target as PropertyWithChange<T>

if (!isUndefined(target)) {
if (typeof listener === 'function') {
withChanged.$onPostChanged(listener)
}
else {
if (listener.postChanged) {
withChanged.$onPostChanged(listener.postChanged)
}
if (listener.preChanged) {
withChanged.$onPreChanged(listener.preChanged)
}
}
}
}
6 changes: 6 additions & 0 deletions packages/core/src/apis/delay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useAnimate } from '../animation'
import type { Widget } from '../widget'

export function delay<T extends Widget>(duration: number) {
return useAnimate<T, unknown>((_) => { }).withAttr({ duration })
}
4 changes: 4 additions & 0 deletions packages/core/src/apis/get-reactive-tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { Reactive } from './reactive'
import { REACTIVE_TAG } from './reactive'

export const getReactiveTag = <T>(r: Reactive<T>): undefined | number => (r as any)[REACTIVE_TAG]
23 changes: 23 additions & 0 deletions packages/core/src/apis/normalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getReactiveTag } from './get-reactive-tag'

export function normalize(obj: any) {
if (typeof obj !== 'object')
return obj

const normalized: any = {}
const keys = Object.keys(obj)

for (const key of keys) {
if (typeof obj[key] !== 'object') {
normalized[key] = obj[key]
}
else if (getReactiveTag(obj[key]) === 2) {
normalized[key] = obj[key].value
}
else {
normalized[key] = obj[key]
}
}

return normalized
}
17 changes: 17 additions & 0 deletions packages/core/src/apis/parallel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Anim, AnimationContext } from '../animation'
import { depend } from '../animation'
import type { Widget } from '../widget'

export function parallel<T extends Widget>(...anims: Anim<T>[]) {
return depend<() => boolean, AnimationContext<T>>((ctx) => {
return () => {
const res = anims.map(a => a.build(ctx)())
anims = res
.map((r, i) => [r, i])
.filter(([r, _]) => !r)
.map(([_, i]) => anims[i as any])

return res.reduce((x, xs) => x || xs)
}
})
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { App } from './app'
import type { App } from '../app'

export type LengthUnitType = 'raw' | 'percent'

Expand Down
60 changes: 60 additions & 0 deletions packages/core/src/apis/reactive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export interface PropertyWithChange<T> {
$onPostChanged: (listener: Listener<T>) => void
$onPreChanged: (listener: Listener<T>) => void
}

export type Listener<T> = (newValue: Reactive<T>) => void

export const REACTIVE_TAG = Symbol('reactive')
export function _reactive<T>(value: T, listener?: Listener<T>, reactType: number = 1) {
if (value === undefined)
return
if (typeof value !== 'object')
return
if (REACTIVE_TAG in (value as any))
return value
const postListeners: Listener<T>[] = listener ? [listener] : []
const preListeners: Listener<T>[] = []

Object.defineProperty(value, '$onPostChanged', {
value: (listener: Listener<T>) => {
postListeners.push(listener)
},
writable: false,
configurable: false,
})
Object.defineProperty(value, '$onPreChanged', {
value: (listener: Listener<T>) => {
preListeners.push(listener)
},
writable: false,
configurable: false,
})
Object.defineProperty(value, REACTIVE_TAG, {
value: reactType,
writable: false,
configurable: false,
})

return new Proxy(value, {
get(target, prop) {
return (target as Record<string, any>)[prop as string]
},
set(target, prop, newValue) {
for (const preListener of preListeners) {
preListener(Object.seal(target) as any)
}
(target as Record<string, any>)[prop as string] = newValue
for (const postListener of postListeners) {
postListener(Object.seal(target) as any)
}

return true
},
})
}

export type Reactive<T> = T
export function reactive<T>(value: T, listener?: Listener<T>) {
return _reactive(value, listener, 1)
}
7 changes: 7 additions & 0 deletions packages/core/src/apis/ref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Listener, Reactive } from './reactive'
import { _reactive } from './reactive'

export type Ref<T> = Reactive<{ value: T }>
export function ref<T>(value: T, listener?: Listener<{ value: T }>) {
return _reactive({ value }, listener, 2)
}
18 changes: 18 additions & 0 deletions packages/core/src/apis/sequence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Anim, AnimationContext } from '../animation'
import { depend } from '../animation'
import type { Widget } from '../widget'

export function sequence<T extends Widget>(...anims: Anim<T>[]) {
return depend<() => boolean, AnimationContext<T>>((ctx) => {
return () => {
if (anims[0].build(ctx)()) {
anims.shift()
if (anims.length === 0) {
return true
}
}

return false
}
})
}
17 changes: 17 additions & 0 deletions packages/core/src/apis/timeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { AnimationContext, WithDep } from '../animation'
import type { Widget } from '../widget'
import { delay } from './delay'
import { parallel } from './parallel'
import { sequence } from './sequence'

export function timeline<T extends Widget>(...lines: [
number,
number,
WithDep<() => boolean, { duration: number } & AnimationContext<T>>,
][]) {
return parallel(
...lines.map(([d, duration, a]) =>
sequence(delay(d), a.withAttr({ duration }) as any),
),
)
}
7 changes: 7 additions & 0 deletions packages/core/src/apis/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Reactive } from './reactive'
import type { Ref } from './ref'

export type ArrayOrPrimitive = Record<number, any> | string | number | null | undefined | boolean | symbol
export type ConvertToProp<T> = {
[K in keyof T]: T[K] extends ArrayOrPrimitive ? Ref<T[K]> : Reactive<T[K]>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $source } from './global'
import { $source } from '../global'

/**
* Preloading a font file.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $source } from './global'
import { $source } from '../global'

/**
* Preloading a image.
Expand Down
Loading

0 comments on commit f6b70f5

Please sign in to comment.