@katabatic/runtime 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,19 +1,27 @@
1
1
  {
2
- "name": "@katabatic/runtime",
3
- "license": "MIT",
4
- "version": "1.1.0",
5
- "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/katabatic-js/katabatic.git",
9
- "directory": "packages/runtime"
10
- },
11
- "exports": {
12
- ".": {
13
- "import": "./src/index.js"
14
- }
15
- },
16
- "dependencies": {
17
- "@katabatic/signals": "^1.0.0"
2
+ "name": "@katabatic/runtime",
3
+ "license": "MIT",
4
+ "version": "1.1.1",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/katabatic-js/katabatic.git",
9
+ "directory": "packages/runtime"
10
+ },
11
+ "files": ["/src"],
12
+ "exports": {
13
+ ".": {
14
+ "import": "./src/index.js"
18
15
  }
16
+ },
17
+ "dependencies": {
18
+ "@katabatic/signals": "^1.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@vitest/browser": "^4.1.0",
22
+ "@vitest/browser-preview": "^4.1.0"
23
+ },
24
+ "scripts": {
25
+ "test": "vitest"
26
+ }
19
27
  }
package/src/animate.js CHANGED
@@ -42,7 +42,7 @@ export class Animate {
42
42
  }
43
43
  }
44
44
 
45
- run(direction) {
45
+ play(direction) {
46
46
  if (this.direction === 'both') {
47
47
  this.#build({ direction: 'both' })
48
48
  this.#direction(direction)
@@ -53,7 +53,7 @@ export class Animate {
53
53
  this.#build({ direction })
54
54
  }
55
55
  }
56
- return this
56
+ return this.animation
57
57
  }
58
58
 
59
59
  dispose() {
package/src/client.js CHANGED
@@ -3,11 +3,29 @@ import { Animate } from './animate.js'
3
3
 
4
4
  export class Client extends Set {
5
5
  effect(fn) {
6
- const effect = new Effect(fn, { orphaned: true, async: false }).run()
6
+ const effect = new Effect(fn, { orphaned: true, async: true }).run()
7
7
  this.add(effect)
8
8
  return effect
9
9
  }
10
10
 
11
+ in() {}
12
+
13
+ out(callback) {
14
+ callback()
15
+ }
16
+
17
+ run() {
18
+ for (const entry of this) {
19
+ entry.run?.()
20
+ }
21
+ }
22
+
23
+ pause() {
24
+ for (const entry of this) {
25
+ entry.pause?.()
26
+ }
27
+ }
28
+
11
29
  dispose() {
12
30
  for (const entry of cleared(this)) {
13
31
  entry.dispose?.()
@@ -22,22 +40,59 @@ export class AnimatedClient extends Client {
22
40
  return animate
23
41
  }
24
42
 
25
- runAnimate(direction, callback) {
26
- const promises = []
27
- for (const entry of this) {
28
- if (entry instanceof Animate) {
29
- promises.push(entry.run(direction).animation?.finished)
43
+ in() {
44
+ if (!this.playingIn) {
45
+ const playingIn = this.#playAnimates('in')?.then(() => {
46
+ if (this.playingIn === playingIn) {
47
+ this.playingIn = undefined
48
+ }
49
+ })
50
+
51
+ if (this.playingOut) {
52
+ this.run()
30
53
  }
54
+
55
+ this.playingIn = playingIn
56
+ this.playingOut = undefined
31
57
  }
58
+ }
32
59
 
33
- const finished = Promise.all(promises)
34
- .catch(() => {})
35
- .finally(() => {
36
- if (this.finished === finished) {
37
- callback?.()
60
+ out(callback) {
61
+ if (!this.playingOut) {
62
+ const playingOut = this.#playAnimates('out')?.then((completed) => {
63
+ if (this.playingOut === playingOut) {
64
+ if (completed) {
65
+ callback()
66
+ }
67
+ this.playingOut = undefined
38
68
  }
39
69
  })
40
- this.finished = finished
70
+
71
+ if (playingOut) {
72
+ this.pause()
73
+ } else {
74
+ callback()
75
+ }
76
+
77
+ this.playingOut = playingOut
78
+ this.playingIn = undefined
79
+ }
80
+ }
81
+
82
+ #playAnimates(direction) {
83
+ const playingPromises = []
84
+ for (const entry of this) {
85
+ const animation = entry.play?.(direction)
86
+ if (animation) {
87
+ playingPromises.push(animation.finished)
88
+ }
89
+ }
90
+
91
+ if (playingPromises.length > 0) {
92
+ return Promise.all(playingPromises)
93
+ .then(() => true)
94
+ .catch(() => false)
95
+ }
41
96
  }
42
97
  }
43
98
 
package/src/eachBlock.js CHANGED
@@ -66,39 +66,53 @@ export class EachBlock extends Map {
66
66
  }
67
67
 
68
68
  init() {
69
- this.#effect ??= new Effect(() => {
70
- const iterable = this.getIterable()
71
-
72
- for (const block of this.#getRemovedBlocks(iterable)) {
73
- this.#removeBlock(block)
74
- }
75
-
76
- let tail = this.#head
77
- let index = 0
78
- for (const item of iterable) {
79
- const key = this.getKey(item, index)
80
- let block = this.get(key)
81
-
82
- if (block) {
83
- if (tail.nextBlock === block) {
84
- tail = updateBlock(block, item)
69
+ this.#effect = new Effect(
70
+ () => {
71
+ const iterable = this.getIterable()
72
+
73
+ for (const block of this.#getRemovedBlocks(iterable)) {
74
+ this.#removeBlock(block)
75
+ }
76
+
77
+ let tail = this.#head
78
+ let index = 0
79
+ for (const item of iterable) {
80
+ const key = this.getKey(item, index)
81
+ let block = this.get(key)
82
+
83
+ if (block) {
84
+ if (tail.nextBlock === block) {
85
+ tail = updateBlock(block, item)
86
+ } else {
87
+ tail = updateBlock(this.#moveBlockAfter(block, tail), item)
88
+ }
85
89
  } else {
86
- tail = updateBlock(this.#moveBlockAfter(block, tail), item)
90
+ tail = this.#insertBlockAfter(new Block(key, item), tail)
91
+ if (this.#effect) tail.in()
87
92
  }
88
- } else {
89
- tail = this.#insertBlockAfter(new Block(key, item), tail)
90
- if (this.#effect) tail.runAnimate('in')
91
- }
92
93
 
93
- index++
94
- }
95
- }, { orphaned: true, async: false }).run()
94
+ index++
95
+ }
96
+ },
97
+ { orphaned: true, async: true }
98
+ ).run()
96
99
 
97
100
  return this
98
101
  }
99
102
 
103
+ run() {
104
+ this.#effect.run()
105
+ }
106
+
107
+ pause() {
108
+ this.#effect.pause()
109
+ for (const entry of this) {
110
+ entry.pause()
111
+ }
112
+ }
113
+
100
114
  dispose() {
101
- this.#effect?.dispose()
115
+ this.#effect.dispose()
102
116
  for (const entry of cleared(this)) {
103
117
  entry.dispose()
104
118
  }
package/src/ifBlock.js CHANGED
@@ -1,9 +1,9 @@
1
- import { Effect } from '@katabatic/signals'
1
+ import { compute, Effect } from '@katabatic/signals'
2
2
  import { AnimatedClient } from './client.js'
3
3
 
4
4
  export class IfBlock {
5
5
  constructor(anchor, getCondition, concequent, alternate) {
6
- this.getCondition = getCondition
6
+ this.getCondition = compute(getCondition)
7
7
  this.concequent = concequent
8
8
  this.alternate = alternate
9
9
  this.#headBlock = createHeadBlock(anchor)
@@ -44,36 +44,40 @@ export class IfBlock {
44
44
  }
45
45
 
46
46
  init() {
47
- let previousCondition
48
-
49
- this.#effect ??= new Effect(
47
+ this.#effect = new Effect(
50
48
  () => {
51
- const condition = this.getCondition()
52
-
53
- if (condition === previousCondition) return
54
- previousCondition = condition
55
-
56
- if (condition) {
57
- this.#altBlock?.runAnimate('out', () => this.#removeBlock(this.#altBlock))
49
+ if (this.getCondition()) {
50
+ this.#altBlock?.out(() => this.#removeBlock(this.#altBlock))
58
51
  this.#condBlock ??= this.#insertBlock(new Block(), this.concequent)
59
- if (this.#effect) this.#condBlock.runAnimate('in')
52
+ if (this.#effect) this.#condBlock.in()
60
53
  } else {
61
- this.#condBlock?.runAnimate('out', () => this.#removeBlock(this.#condBlock))
54
+ this.#condBlock?.out(() => this.#removeBlock(this.#condBlock))
62
55
  if (this.alternate) {
63
56
  this.#altBlock ??= this.#insertBlock(new Block(), this.alternate)
64
- if (this.#effect) this.#altBlock.runAnimate('in')
57
+ if (this.#effect) this.#altBlock.in()
65
58
  }
66
59
  }
67
60
  },
68
- { orphaned: true, async: false }
61
+ { orphaned: true, async: true }
69
62
  ).run()
70
63
 
71
64
  return this
72
65
  }
73
66
 
67
+ run() {
68
+ this.#effect.run()
69
+ }
70
+
71
+ pause() {
72
+ this.#effect.pause()
73
+ this.#condBlock?.pause()
74
+ this.#altBlock?.pause()
75
+ }
76
+
74
77
  dispose() {
75
- this.#effect?.dispose()
78
+ this.#effect.dispose()
76
79
  this.#condBlock?.dispose()
80
+ this.#altBlock?.dispose()
77
81
  }
78
82
  }
79
83
 
@@ -89,7 +93,9 @@ class Block extends AnimatedClient {
89
93
 
90
94
  function createHeadBlock(anchor) {
91
95
  const block = new Block()
92
- block.anchor = anchor.previousSibling
93
- block.parentAnchor = block.anchor ? undefined : anchor.parentNode
96
+
97
+ block.anchor = document.createComment('')
98
+ anchor.parentNode.insertBefore(block.anchor, anchor)
99
+
94
100
  return block
95
101
  }
package/src/index.js CHANGED
@@ -102,30 +102,6 @@ export function $$(customElement) {
102
102
  }
103
103
  }
104
104
 
105
- client.getBindingProp = function (object, property, fn) {
106
- if (
107
- !!Object.getOwnPropertyDescriptor(object, property)?.get ||
108
- !!Object.getOwnPropertyDescriptor(Object.getPrototypeOf(object), property)?.get
109
- ) {
110
- this.locked = true
111
- fn(object[property])
112
- this.locked = false
113
- return true
114
- }
115
- return false
116
- }
117
-
118
- client.setBindingProp = function (object, property, value) {
119
- if (
120
- !!Object.getOwnPropertyDescriptor(object, property)?.set ||
121
- !!Object.getOwnPropertyDescriptor(Object.getPrototypeOf(object), property)?.set
122
- ) {
123
- if (!this.locked) object[property] = value
124
- return true
125
- }
126
- return false
127
- }
128
-
129
105
  return client
130
106
  }
131
107
 
package/src/rootBlock.js CHANGED
@@ -1,12 +1,7 @@
1
1
  import { Client } from './client.js'
2
2
 
3
- export function rootBlock(body) {
3
+ export function rootBlock(fn) {
4
4
  const block = new Client()
5
- body(block)
6
-
7
- return {
8
- dispose() {
9
- block.dispose()
10
- }
11
- }
5
+ fn(block)
6
+ return block
12
7
  }