@fictjs/runtime 0.0.12 → 0.0.14

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.
Files changed (65) hide show
  1. package/dist/advanced.cjs +79 -0
  2. package/dist/advanced.cjs.map +1 -0
  3. package/dist/advanced.d.cts +50 -0
  4. package/dist/advanced.d.ts +50 -0
  5. package/dist/advanced.js +79 -0
  6. package/dist/advanced.js.map +1 -0
  7. package/dist/chunk-624QY53A.cjs +45 -0
  8. package/dist/chunk-624QY53A.cjs.map +1 -0
  9. package/dist/chunk-F3AIYQB7.js +45 -0
  10. package/dist/chunk-F3AIYQB7.js.map +1 -0
  11. package/dist/chunk-GJTYOFMO.cjs +109 -0
  12. package/dist/chunk-GJTYOFMO.cjs.map +1 -0
  13. package/dist/chunk-IUZXKAAY.js +109 -0
  14. package/dist/chunk-IUZXKAAY.js.map +1 -0
  15. package/dist/{slim.cjs → chunk-PMF6MWEV.cjs} +2557 -3110
  16. package/dist/chunk-PMF6MWEV.cjs.map +1 -0
  17. package/dist/{slim.js → chunk-RY4WDS6R.js} +2596 -3097
  18. package/dist/chunk-RY4WDS6R.js.map +1 -0
  19. package/dist/context-B7UYnfzM.d.ts +153 -0
  20. package/dist/context-UXySaqI_.d.cts +153 -0
  21. package/dist/effect-Auji1rz9.d.cts +350 -0
  22. package/dist/effect-Auji1rz9.d.ts +350 -0
  23. package/dist/index.cjs +108 -4441
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +5 -1492
  26. package/dist/index.d.ts +5 -1492
  27. package/dist/index.dev.js +1020 -2788
  28. package/dist/index.dev.js.map +1 -1
  29. package/dist/index.js +63 -4301
  30. package/dist/index.js.map +1 -1
  31. package/dist/internal.cjs +901 -0
  32. package/dist/internal.cjs.map +1 -0
  33. package/dist/internal.d.cts +158 -0
  34. package/dist/internal.d.ts +158 -0
  35. package/dist/internal.js +901 -0
  36. package/dist/internal.js.map +1 -0
  37. package/dist/{jsx-dev-runtime.d.ts → props-CrOMYbLv.d.cts} +107 -18
  38. package/dist/{jsx-dev-runtime.d.cts → props-ES0Ag_Wd.d.ts} +107 -18
  39. package/dist/scope-DKYzWfTn.d.cts +55 -0
  40. package/dist/scope-S6eAzBJZ.d.ts +55 -0
  41. package/package.json +10 -5
  42. package/src/advanced.ts +101 -0
  43. package/src/binding.ts +25 -422
  44. package/src/constants.ts +345 -344
  45. package/src/context.ts +300 -0
  46. package/src/cycle-guard.ts +124 -97
  47. package/src/delegated-events.ts +24 -0
  48. package/src/dom.ts +19 -25
  49. package/src/effect.ts +4 -0
  50. package/src/hooks.ts +9 -1
  51. package/src/index.ts +41 -130
  52. package/src/internal.ts +130 -0
  53. package/src/lifecycle.ts +13 -2
  54. package/src/list-helpers.ts +6 -65
  55. package/src/props.ts +48 -46
  56. package/src/signal.ts +59 -39
  57. package/src/store.ts +47 -7
  58. package/src/versioned-signal.ts +3 -3
  59. package/dist/jsx-runtime.d.cts +0 -671
  60. package/dist/jsx-runtime.d.ts +0 -671
  61. package/dist/slim.cjs.map +0 -1
  62. package/dist/slim.d.cts +0 -504
  63. package/dist/slim.d.ts +0 -504
  64. package/dist/slim.js.map +0 -1
  65. package/src/slim.ts +0 -69
package/src/signal.ts CHANGED
@@ -2,6 +2,11 @@ import { beginFlushGuard, beforeEffectRunGuard, endFlushGuard } from './cycle-gu
2
2
  import { getDevtoolsHook } from './devtools'
3
3
  import { registerRootCleanup } from './lifecycle'
4
4
 
5
+ const isDev =
6
+ typeof __DEV__ !== 'undefined'
7
+ ? __DEV__
8
+ : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'
9
+
5
10
  // ============================================================================
6
11
  // Type Definitions
7
12
  // ============================================================================
@@ -1177,21 +1182,28 @@ export function endBatch(): void {
1177
1182
  */
1178
1183
  export function batch<T>(fn: () => T): T {
1179
1184
  ++batchDepth
1180
- let _error: unknown
1181
- let hasError = false
1185
+ let result!: T
1186
+ let error: unknown
1182
1187
  try {
1183
- return fn()
1188
+ result = fn()
1184
1189
  } catch (e) {
1185
- _error = e
1186
- hasError = true
1187
- throw e
1190
+ error = e
1188
1191
  } finally {
1189
1192
  --batchDepth
1190
- // Only flush if no error occurred to avoid interfering with error propagation
1191
- if (!hasError && batchDepth === 0) {
1192
- flush()
1193
+ if (batchDepth === 0) {
1194
+ try {
1195
+ flush()
1196
+ } catch (flushErr) {
1197
+ if (error === undefined) {
1198
+ error = flushErr
1199
+ }
1200
+ }
1193
1201
  }
1194
1202
  }
1203
+ if (error !== undefined) {
1204
+ throw error
1205
+ }
1206
+ return result
1195
1207
  }
1196
1208
  /**
1197
1209
  * Get the current active subscriber
@@ -1335,43 +1347,51 @@ export default {
1335
1347
  }
1336
1348
  export const $state = signal as <T>(value: T) => T
1337
1349
 
1338
- let devtoolsSignalId = 0
1339
- let devtoolsEffectId = 0
1340
-
1341
1350
  interface DevtoolsIdentifiable {
1342
1351
  __id?: number
1343
1352
  }
1344
1353
 
1345
- function registerSignalDevtools(value: unknown, node: SignalNode): number | undefined {
1346
- const hook = getDevtoolsHook()
1347
- if (!hook) return undefined
1348
- const id = ++devtoolsSignalId
1349
- hook.registerSignal(id, value)
1350
- ;(node as SignalNode & DevtoolsIdentifiable).__id = id
1351
- return id
1352
- }
1354
+ let registerSignalDevtools: (value: unknown, node: SignalNode) => number | undefined = () =>
1355
+ undefined
1356
+ let updateSignalDevtools: (node: SignalNode, value: unknown) => void = () => {}
1357
+ let registerEffectDevtools: (node: EffectNode) => number | undefined = () => undefined
1358
+ let effectRunDevtools: (node: EffectNode) => void = () => {}
1359
+
1360
+ if (isDev) {
1361
+ let devtoolsSignalId = 0
1362
+ let devtoolsEffectId = 0
1363
+
1364
+ registerSignalDevtools = (value, node) => {
1365
+ const hook = getDevtoolsHook()
1366
+ if (!hook) return undefined
1367
+ const id = ++devtoolsSignalId
1368
+ hook.registerSignal(id, value)
1369
+ ;(node as SignalNode & DevtoolsIdentifiable).__id = id
1370
+ return id
1371
+ }
1353
1372
 
1354
- function updateSignalDevtools(node: SignalNode, value: unknown): void {
1355
- const hook = getDevtoolsHook()
1356
- if (!hook) return
1357
- const id = (node as SignalNode & DevtoolsIdentifiable).__id
1358
- if (id) hook.updateSignal(id, value)
1359
- }
1373
+ updateSignalDevtools = (node, value) => {
1374
+ const hook = getDevtoolsHook()
1375
+ if (!hook) return
1376
+ const id = (node as SignalNode & DevtoolsIdentifiable).__id
1377
+ if (id) hook.updateSignal(id, value)
1378
+ }
1360
1379
 
1361
- function registerEffectDevtools(node: EffectNode): number | undefined {
1362
- const hook = getDevtoolsHook()
1363
- if (!hook) return undefined
1364
- const id = ++devtoolsEffectId
1365
- hook.registerEffect(id)
1366
- ;(node as EffectNode & DevtoolsIdentifiable).__id = id
1367
- return id
1368
- }
1380
+ registerEffectDevtools = node => {
1381
+ const hook = getDevtoolsHook()
1382
+ if (!hook) return undefined
1383
+ const id = ++devtoolsEffectId
1384
+ hook.registerEffect(id)
1385
+ ;(node as EffectNode & DevtoolsIdentifiable).__id = id
1386
+ return id
1387
+ }
1369
1388
 
1370
- function effectRunDevtools(node: EffectNode): void {
1371
- const hook = getDevtoolsHook()
1372
- if (!hook) return
1373
- const id = (node as EffectNode & DevtoolsIdentifiable).__id
1374
- if (id) hook.effectRun(id)
1389
+ effectRunDevtools = node => {
1390
+ const hook = getDevtoolsHook()
1391
+ if (!hook) return
1392
+ const id = (node as EffectNode & DevtoolsIdentifiable).__id
1393
+ if (id) hook.effectRun(id)
1394
+ }
1375
1395
  }
1376
1396
 
1377
1397
  // ============================================================================
package/src/store.ts CHANGED
@@ -152,7 +152,13 @@ function getLastValue(target: any, prop: string | symbol) {
152
152
  */
153
153
  function reconcile(target: any, value: any) {
154
154
  if (target === value) return
155
- if (value === null || typeof value !== 'object') return // Should replace?
155
+ if (value === null || typeof value !== 'object') {
156
+ throw new Error(
157
+ `[Fict] Cannot replace store with primitive value: ${String(
158
+ value,
159
+ )}. setStore should return an object/array to merge.`,
160
+ )
161
+ }
156
162
 
157
163
  const realTarget = unwrap(target)
158
164
  const realValue = unwrap(value)
@@ -166,6 +172,11 @@ function reconcile(target: any, value: any) {
166
172
  target[key] = realValue[key] // Triggers proxy trap
167
173
  }
168
174
  }
175
+
176
+ // Fix array length if needed
177
+ if (Array.isArray(target) && target.length !== realValue.length) {
178
+ target.length = realValue.length
179
+ }
169
180
  }
170
181
 
171
182
  // ============================================================================
@@ -180,6 +191,29 @@ function reconcile(target: any, value: any) {
180
191
  export function createDiffingSignal<T extends object>(initialValue: T) {
181
192
  let currentValue = unwrap(initialValue)
182
193
  const signals = new Map<string | symbol, SignalAccessor<any>>()
194
+ let iterateSignal: SignalAccessor<number> | undefined
195
+
196
+ const getPropSignal = (prop: string | symbol) => {
197
+ let s = signals.get(prop)
198
+ if (!s) {
199
+ s = signal((currentValue as any)[prop])
200
+ signals.set(prop, s)
201
+ }
202
+ return s
203
+ }
204
+
205
+ const trackIterate = () => {
206
+ if (!iterateSignal) {
207
+ iterateSignal = signal(Reflect.ownKeys(currentValue).length)
208
+ }
209
+ iterateSignal()
210
+ }
211
+
212
+ const updateIterate = (value: T) => {
213
+ if (iterateSignal) {
214
+ iterateSignal(Reflect.ownKeys(value).length)
215
+ }
216
+ }
183
217
 
184
218
  // The stable proxy we return
185
219
  const proxy = new Proxy({} as T, {
@@ -188,17 +222,21 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
188
222
  if (prop === TARGET) return currentValue
189
223
 
190
224
  // Subscribe to property
191
- let s = signals.get(prop)
192
- if (!s) {
193
- // Initialize signal with current property value
194
- s = signal((currentValue as any)[prop])
195
- signals.set(prop, s)
196
- }
225
+ const s = getPropSignal(prop)
197
226
  return s()
198
227
  },
199
228
  ownKeys() {
229
+ trackIterate()
200
230
  return Reflect.ownKeys(currentValue)
201
231
  },
232
+ has(target, prop) {
233
+ getPropSignal(prop)()
234
+ return Reflect.has(currentValue, prop)
235
+ },
236
+ getOwnPropertyDescriptor(target, prop) {
237
+ getPropSignal(prop)()
238
+ return Reflect.getOwnPropertyDescriptor(currentValue, prop)
239
+ },
202
240
  })
203
241
 
204
242
  const read = () => proxy
@@ -215,6 +253,7 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
215
253
  const newVal = (next as any)[prop]
216
254
  s(newVal)
217
255
  }
256
+ updateIterate(next)
218
257
  return
219
258
  }
220
259
 
@@ -228,6 +267,7 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
228
267
  s(newVal)
229
268
  }
230
269
  }
270
+ updateIterate(next)
231
271
 
232
272
  // Note: If new properties appeared that weren't tracked, we don't care
233
273
  // because no one is listening.
@@ -1,4 +1,4 @@
1
- import { createSignal } from './signal'
1
+ import { createSignal, untrack } from './signal'
2
2
 
3
3
  export interface VersionedSignalOptions<T> {
4
4
  equals?: (prev: T, next: T) => boolean
@@ -52,7 +52,7 @@ export function createVersionedSignal<T>(
52
52
  force: () => {
53
53
  bumpVersion()
54
54
  },
55
- peekVersion: () => version(),
56
- peekValue: () => value(),
55
+ peekVersion: () => untrack(() => version()),
56
+ peekValue: () => untrack(() => value()),
57
57
  }
58
58
  }