atom.io 0.39.0 → 0.40.0
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/dist/data/index.js.map +1 -1
- package/dist/eslint-plugin/index.js +2 -1
- package/dist/eslint-plugin/index.js.map +1 -1
- package/dist/internal/index.d.ts +14 -8
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +129 -87
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts.map +1 -1
- package/dist/introspection/index.js.map +1 -1
- package/dist/json/index.d.ts.map +1 -1
- package/dist/json/index.js.map +1 -1
- package/dist/main/index.d.ts +8 -7
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js.map +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +43 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.d.ts.map +1 -1
- package/dist/react-devtools/index.js +12 -10
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
- package/dist/transceivers/set-rtx/index.js.map +1 -1
- package/dist/web/index.js.map +1 -1
- package/package.json +8 -8
- package/src/internal/events/ingest-selector-update.ts +13 -4
- package/src/internal/families/create-regular-atom-family.ts +3 -2
- package/src/internal/get-state/read-or-compute-value.ts +2 -1
- package/src/internal/get-state/reduce-reference.ts +15 -2
- package/src/internal/is-fn.ts +9 -0
- package/src/internal/operation.ts +3 -1
- package/src/internal/set-state/become.ts +11 -6
- package/src/internal/set-state/dispatch-state-update.ts +15 -12
- package/src/internal/set-state/operate-on-store.ts +3 -1
- package/src/internal/set-state/reset-atom-or-selector.ts +7 -7
- package/src/internal/set-state/set-atom-or-selector.ts +3 -2
- package/src/internal/set-state/set-atom.ts +4 -3
- package/src/internal/set-state/set-selector.ts +8 -7
- package/src/internal/timeline/create-timeline.ts +133 -98
- package/src/internal/timeline/time-travel.ts +42 -31
- package/src/internal/transaction/apply-transaction.ts +2 -2
- package/src/internal/transaction/build-transaction.ts +1 -1
- package/src/main/events.ts +8 -2
- package/src/main/logger.ts +1 -1
- package/src/main/timeline.ts +1 -7
- package/src/react-devtools/Updates.tsx +14 -9
- package/src/react-devtools/json-editor/editors-by-type/array-editor.tsx +1 -1
- package/src/react-devtools/json-editor/editors-by-type/object-editor.tsx +2 -3
- package/src/react-devtools/json-editor/editors-by-type/utilities/array-elements.ts +1 -1
- package/src/react-devtools/json-editor/editors-by-type/utilities/object-properties.ts +1 -1
- package/dist/use-o-DXPncKmZ.js +0 -47
- package/dist/use-o-DXPncKmZ.js.map +0 -1
|
@@ -4,13 +4,16 @@ import type {
|
|
|
4
4
|
AtomUpdateEvent,
|
|
5
5
|
StateCreationEvent,
|
|
6
6
|
StateDisposalEvent,
|
|
7
|
+
StateUpdate,
|
|
7
8
|
TimelineEvent,
|
|
8
9
|
TimelineManageable,
|
|
9
10
|
TimelineOptions,
|
|
11
|
+
TimelineSelectorUpdateEvent,
|
|
10
12
|
TimelineToken,
|
|
11
13
|
TransactionOutcomeEvent,
|
|
12
14
|
TransactionSubEvent,
|
|
13
15
|
TransactionToken,
|
|
16
|
+
WritablePureSelectorToken,
|
|
14
17
|
} from "atom.io"
|
|
15
18
|
|
|
16
19
|
import { reduceReference } from "../get-state/reduce-reference"
|
|
@@ -24,10 +27,6 @@ export type Timeline<ManagedAtom extends TimelineManageable> = {
|
|
|
24
27
|
type: `timeline`
|
|
25
28
|
key: string
|
|
26
29
|
at: number
|
|
27
|
-
shouldCapture?: (
|
|
28
|
-
update: TimelineEvent<ManagedAtom>,
|
|
29
|
-
timeline: Timeline<ManagedAtom>,
|
|
30
|
-
) => boolean
|
|
31
30
|
timeTraveling: `into_future` | `into_past` | null
|
|
32
31
|
history: TimelineEvent<ManagedAtom>[]
|
|
33
32
|
selectorTime: number | null
|
|
@@ -46,7 +45,6 @@ export function createTimeline<ManagedAtom extends TimelineManageable>(
|
|
|
46
45
|
type: `timeline`,
|
|
47
46
|
key: options.key,
|
|
48
47
|
at: 0,
|
|
49
|
-
|
|
50
48
|
timeTraveling: null,
|
|
51
49
|
selectorTime: null,
|
|
52
50
|
transactionKey: null,
|
|
@@ -56,9 +54,7 @@ export function createTimeline<ManagedAtom extends TimelineManageable>(
|
|
|
56
54
|
subject: new Subject(),
|
|
57
55
|
subscriptions: new Map(),
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
tl.shouldCapture = options.shouldCapture
|
|
61
|
-
}
|
|
57
|
+
|
|
62
58
|
const timelineKey = options.key
|
|
63
59
|
const target = newest(store)
|
|
64
60
|
for (const initialTopic of options.scope) {
|
|
@@ -182,93 +178,32 @@ function addAtomToTimeline(
|
|
|
182
178
|
if (txUpdateInProgress) {
|
|
183
179
|
joinTransaction(store, tl, txUpdateInProgress)
|
|
184
180
|
} else if (currentSelectorToken && currentSelectorTime) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
atomUpdates: [],
|
|
194
|
-
}
|
|
195
|
-
latestUpdate.atomUpdates.push({
|
|
196
|
-
type: `atom_update`,
|
|
197
|
-
token: atomToken,
|
|
198
|
-
update,
|
|
199
|
-
timestamp: Date.now(), // 👺 use store operation
|
|
200
|
-
})
|
|
201
|
-
if (tl.at !== tl.history.length) {
|
|
202
|
-
tl.history.splice(tl.at)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
tl.history.push(latestUpdate)
|
|
206
|
-
|
|
207
|
-
store.logger.info(
|
|
208
|
-
`⌛`,
|
|
209
|
-
`timeline`,
|
|
210
|
-
tl.key,
|
|
211
|
-
`got a selector_update "${currentSelectorToken.key}" with`,
|
|
212
|
-
latestUpdate.atomUpdates.map(
|
|
213
|
-
(atomUpdate) => atomUpdate.token.key,
|
|
214
|
-
),
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
tl.at = tl.history.length
|
|
218
|
-
tl.selectorTime = currentSelectorTime
|
|
219
|
-
} else {
|
|
220
|
-
if (latestUpdate?.type === `selector_update`) {
|
|
221
|
-
latestUpdate.atomUpdates.push({
|
|
222
|
-
type: `atom_update`,
|
|
223
|
-
token: atomToken,
|
|
224
|
-
update,
|
|
225
|
-
timestamp: Date.now(), // 👺 use store operation
|
|
226
|
-
})
|
|
227
|
-
store.logger.info(
|
|
228
|
-
`⌛`,
|
|
229
|
-
`timeline`,
|
|
230
|
-
tl.key,
|
|
231
|
-
`set selector_update "${currentSelectorToken.key}" to`,
|
|
232
|
-
latestUpdate?.atomUpdates.map(
|
|
233
|
-
(atomUpdate) => atomUpdate.token.key,
|
|
234
|
-
),
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (latestUpdate) {
|
|
239
|
-
const willCaptureSelectorUpdate =
|
|
240
|
-
tl.shouldCapture?.(latestUpdate, tl) ?? true
|
|
241
|
-
if (willCaptureSelectorUpdate) {
|
|
242
|
-
tl.subject.next(latestUpdate)
|
|
243
|
-
} else {
|
|
244
|
-
tl.history.pop()
|
|
245
|
-
tl.at = tl.history.length
|
|
246
|
-
}
|
|
247
|
-
}
|
|
181
|
+
buildSelectorUpdate(
|
|
182
|
+
store,
|
|
183
|
+
tl,
|
|
184
|
+
atomToken,
|
|
185
|
+
update,
|
|
186
|
+
currentSelectorToken,
|
|
187
|
+
currentSelectorTime,
|
|
188
|
+
)
|
|
248
189
|
} else {
|
|
249
190
|
const timestamp = Date.now()
|
|
250
191
|
tl.selectorTime = null
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const atomUpdate: AtomUpdateEvent<any> = {
|
|
192
|
+
|
|
193
|
+
const atomUpdate: AtomUpdateEvent<any> & TimelineEvent<any> = {
|
|
194
|
+
write: true,
|
|
255
195
|
type: `atom_update`,
|
|
256
196
|
token: deposit(atom),
|
|
257
197
|
update,
|
|
258
198
|
timestamp,
|
|
259
199
|
}
|
|
260
|
-
const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true
|
|
261
200
|
store.logger.info(
|
|
262
201
|
`⌛`,
|
|
263
202
|
`timeline`,
|
|
264
203
|
tl.key,
|
|
265
204
|
`got an atom_update to "${atom.key}"`,
|
|
266
205
|
)
|
|
267
|
-
|
|
268
|
-
tl.history.push(atomUpdate)
|
|
269
|
-
tl.at = tl.history.length
|
|
270
|
-
tl.subject.next(atomUpdate)
|
|
271
|
-
}
|
|
206
|
+
addToHistory(tl, atomUpdate)
|
|
272
207
|
}
|
|
273
208
|
}
|
|
274
209
|
},
|
|
@@ -322,10 +257,6 @@ function joinTransaction(
|
|
|
322
257
|
unsubscribe()
|
|
323
258
|
tl.transactionKey = null
|
|
324
259
|
if (tl.timeTraveling === null && currentTxInstanceId) {
|
|
325
|
-
if (tl.at !== tl.history.length) {
|
|
326
|
-
tl.history.splice(tl.at)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
260
|
// biome-ignore lint/style/noNonNullAssertion: we are in the context of this timeline
|
|
330
261
|
const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key)!
|
|
331
262
|
|
|
@@ -334,25 +265,99 @@ function joinTransaction(
|
|
|
334
265
|
timelineTopics,
|
|
335
266
|
)
|
|
336
267
|
|
|
337
|
-
const timelineTransactionUpdate:
|
|
338
|
-
TransactionToken<any
|
|
339
|
-
|
|
268
|
+
const timelineTransactionUpdate: TimelineEvent<any> &
|
|
269
|
+
TransactionOutcomeEvent<TransactionToken<any>> = {
|
|
270
|
+
write: true,
|
|
340
271
|
...transactionUpdate,
|
|
341
272
|
subEvents: subEventsFiltered,
|
|
342
273
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (willCapture) {
|
|
346
|
-
tl.history.push(timelineTransactionUpdate)
|
|
347
|
-
tl.at = tl.history.length
|
|
348
|
-
tl.subject.next(timelineTransactionUpdate)
|
|
349
|
-
}
|
|
274
|
+
|
|
275
|
+
addToHistory(tl, timelineTransactionUpdate)
|
|
350
276
|
}
|
|
351
277
|
},
|
|
352
278
|
)
|
|
353
279
|
}
|
|
354
280
|
}
|
|
355
281
|
|
|
282
|
+
function buildSelectorUpdate(
|
|
283
|
+
store: Store,
|
|
284
|
+
tl: Timeline<any>,
|
|
285
|
+
atomToken: AtomToken<any>,
|
|
286
|
+
eventOrUpdate: StateCreationEvent<any> | StateUpdate<any>,
|
|
287
|
+
currentSelectorToken: WritablePureSelectorToken<any>,
|
|
288
|
+
currentSelectorTime: number,
|
|
289
|
+
) {
|
|
290
|
+
let latestUpdate: TimelineEvent<any> | undefined = tl.history.at(-1)
|
|
291
|
+
if (currentSelectorTime !== tl.selectorTime) {
|
|
292
|
+
const selectorUpdate: TimelineEvent<any> & TimelineSelectorUpdateEvent<any> =
|
|
293
|
+
(latestUpdate = {
|
|
294
|
+
write: true,
|
|
295
|
+
type: `selector_update`,
|
|
296
|
+
timestamp: currentSelectorTime,
|
|
297
|
+
token: currentSelectorToken,
|
|
298
|
+
subEvents: [],
|
|
299
|
+
})
|
|
300
|
+
if (`type` in eventOrUpdate) {
|
|
301
|
+
latestUpdate.subEvents.push(eventOrUpdate)
|
|
302
|
+
} else {
|
|
303
|
+
latestUpdate.subEvents.push({
|
|
304
|
+
type: `atom_update`,
|
|
305
|
+
token: atomToken,
|
|
306
|
+
update: eventOrUpdate,
|
|
307
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
addToHistory(tl, latestUpdate)
|
|
312
|
+
tl.selectorTime = currentSelectorTime
|
|
313
|
+
|
|
314
|
+
store.logger.info(
|
|
315
|
+
`⌛`,
|
|
316
|
+
`timeline`,
|
|
317
|
+
tl.key,
|
|
318
|
+
`got a selector_update "${currentSelectorToken.key}" with`,
|
|
319
|
+
latestUpdate.subEvents.map((event) => event.token.key),
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
const operation = store.operation
|
|
323
|
+
const unsub = store.on.operationClose.subscribe(
|
|
324
|
+
`timeline:${tl.key} (needs to gather nested selector creations)`,
|
|
325
|
+
() => {
|
|
326
|
+
unsub()
|
|
327
|
+
if (operation.open) {
|
|
328
|
+
selectorUpdate.subEvents = [
|
|
329
|
+
...operation.subEvents,
|
|
330
|
+
...selectorUpdate.subEvents,
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
} else {
|
|
336
|
+
if (latestUpdate?.type === `selector_update`) {
|
|
337
|
+
if (`type` in eventOrUpdate) {
|
|
338
|
+
latestUpdate.subEvents.push(eventOrUpdate)
|
|
339
|
+
} else {
|
|
340
|
+
latestUpdate.subEvents.push({
|
|
341
|
+
type: `atom_update`,
|
|
342
|
+
token: atomToken,
|
|
343
|
+
update: eventOrUpdate,
|
|
344
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
345
|
+
})
|
|
346
|
+
}
|
|
347
|
+
store.logger.info(
|
|
348
|
+
`⌛`,
|
|
349
|
+
`timeline`,
|
|
350
|
+
tl.key,
|
|
351
|
+
`set selector_update "${currentSelectorToken.key}" to`,
|
|
352
|
+
latestUpdate?.subEvents.map((event) => event.token.key),
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (latestUpdate) {
|
|
357
|
+
tl.subject.next(latestUpdate)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
356
361
|
function filterTransactionSubEvents(
|
|
357
362
|
updates: TransactionSubEvent[],
|
|
358
363
|
timelineTopics: Set<string>,
|
|
@@ -402,6 +407,16 @@ function handleStateLifecycleEvent(
|
|
|
402
407
|
event: StateCreationEvent<any> | StateDisposalEvent<any>,
|
|
403
408
|
tl: Timeline<any>,
|
|
404
409
|
): void {
|
|
410
|
+
const currentSelectorToken =
|
|
411
|
+
store.operation.open &&
|
|
412
|
+
store.operation.token.type === `writable_pure_selector`
|
|
413
|
+
? store.operation.token
|
|
414
|
+
: null
|
|
415
|
+
const currentSelectorTime =
|
|
416
|
+
store.operation.open &&
|
|
417
|
+
store.operation.token.type === `writable_pure_selector`
|
|
418
|
+
? store.operation.timestamp
|
|
419
|
+
: null
|
|
405
420
|
if (!tl.timeTraveling) {
|
|
406
421
|
const target = newest(store)
|
|
407
422
|
if (isChildStore(target)) {
|
|
@@ -410,10 +425,21 @@ function handleStateLifecycleEvent(
|
|
|
410
425
|
const txUpdateInProgress = target.on.transactionApplying.state
|
|
411
426
|
if (txUpdateInProgress) {
|
|
412
427
|
joinTransaction(store, tl, txUpdateInProgress.update)
|
|
428
|
+
} else if (
|
|
429
|
+
currentSelectorToken &&
|
|
430
|
+
currentSelectorTime &&
|
|
431
|
+
event.type === `state_creation`
|
|
432
|
+
) {
|
|
433
|
+
buildSelectorUpdate(
|
|
434
|
+
store,
|
|
435
|
+
tl,
|
|
436
|
+
event.token,
|
|
437
|
+
event,
|
|
438
|
+
currentSelectorToken,
|
|
439
|
+
currentSelectorTime,
|
|
440
|
+
)
|
|
413
441
|
} else {
|
|
414
|
-
tl
|
|
415
|
-
tl.at = tl.history.length
|
|
416
|
-
tl.subject.next(event)
|
|
442
|
+
addToHistory(tl, event)
|
|
417
443
|
}
|
|
418
444
|
}
|
|
419
445
|
}
|
|
@@ -427,3 +453,12 @@ function handleStateLifecycleEvent(
|
|
|
427
453
|
break
|
|
428
454
|
}
|
|
429
455
|
}
|
|
456
|
+
|
|
457
|
+
function addToHistory(tl: Timeline<any>, event: TimelineEvent<any>): void {
|
|
458
|
+
if (tl.at !== tl.history.length) {
|
|
459
|
+
tl.history.splice(tl.at)
|
|
460
|
+
}
|
|
461
|
+
tl.history.push(event)
|
|
462
|
+
tl.at = tl.history.length
|
|
463
|
+
tl.subject.next(event)
|
|
464
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TimelineToken } from "atom.io"
|
|
1
|
+
import type { TimelineEvent, TimelineToken } from "atom.io"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ingestAtomUpdateEvent,
|
|
@@ -30,6 +30,7 @@ export const timeTravel = (
|
|
|
30
30
|
)
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
|
+
|
|
33
34
|
if (
|
|
34
35
|
(action === `redo` && timelineData.at === timelineData.history.length) ||
|
|
35
36
|
(action === `undo` && timelineData.at === 0)
|
|
@@ -46,46 +47,56 @@ export const timeTravel = (
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
timelineData.timeTraveling = action === `redo` ? `into_future` : `into_past`
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
let nextIndex = timelineData.at
|
|
51
|
+
let events: TimelineEvent<any>[]
|
|
52
|
+
switch (action) {
|
|
53
|
+
case `undo`:
|
|
54
|
+
--nextIndex
|
|
55
|
+
while (nextIndex !== 0 && timelineData.history[nextIndex].write !== true) {
|
|
56
|
+
--nextIndex
|
|
57
|
+
}
|
|
58
|
+
events = timelineData.history.slice(nextIndex, timelineData.at).reverse()
|
|
59
|
+
|
|
60
|
+
break
|
|
61
|
+
case `redo`:
|
|
62
|
+
++nextIndex
|
|
63
|
+
events = timelineData.history.slice(timelineData.at, nextIndex)
|
|
51
64
|
}
|
|
65
|
+
timelineData.at = nextIndex
|
|
52
66
|
|
|
53
|
-
const event = timelineData.history[timelineData.at]
|
|
54
67
|
const applying = action === `redo` ? `newValue` : `oldValue`
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
for (const event of events) {
|
|
70
|
+
switch (event.type) {
|
|
71
|
+
case `atom_update`: {
|
|
72
|
+
ingestAtomUpdateEvent(store, event, applying)
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
case `selector_update`: {
|
|
76
|
+
ingestSelectorUpdateEvent(store, event, applying)
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
case `transaction_outcome`: {
|
|
80
|
+
ingestTransactionOutcomeEvent(store, event, applying)
|
|
81
|
+
break
|
|
82
|
+
}
|
|
83
|
+
case `state_creation`: {
|
|
84
|
+
ingestCreationEvent(store, event, applying)
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
case `state_disposal`: {
|
|
88
|
+
ingestDisposalEvent(store, event, applying)
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
case `molecule_creation`:
|
|
92
|
+
case `molecule_disposal`:
|
|
72
93
|
}
|
|
73
|
-
case `state_disposal`: {
|
|
74
|
-
ingestDisposalEvent(store, event, applying)
|
|
75
|
-
break
|
|
76
|
-
}
|
|
77
|
-
case `molecule_creation`:
|
|
78
|
-
case `molecule_disposal`:
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (action === `redo`) {
|
|
82
|
-
++timelineData.at
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
timelineData.subject.next(action)
|
|
86
97
|
timelineData.timeTraveling = null
|
|
87
98
|
store.logger.info(
|
|
88
|
-
|
|
99
|
+
`⏸️`,
|
|
89
100
|
`timeline`,
|
|
90
101
|
token.key,
|
|
91
102
|
`"${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
|
|
@@ -34,7 +34,7 @@ export function applyTransaction<F extends Fn>(
|
|
|
34
34
|
`🛄`,
|
|
35
35
|
`transaction`,
|
|
36
36
|
child.transactionMeta.update.token.key,
|
|
37
|
-
`
|
|
37
|
+
`applying ${updates.length} subEvents:`,
|
|
38
38
|
updates,
|
|
39
39
|
)
|
|
40
40
|
|
|
@@ -55,7 +55,7 @@ export function applyTransaction<F extends Fn>(
|
|
|
55
55
|
`🛬`,
|
|
56
56
|
`transaction`,
|
|
57
57
|
child.transactionMeta.update.token.key,
|
|
58
|
-
`
|
|
58
|
+
`applied`,
|
|
59
59
|
)
|
|
60
60
|
} else if (isChildStore(parent)) {
|
|
61
61
|
parent.transactionMeta.update.subEvents.push(child.transactionMeta.update)
|
package/src/main/events.ts
CHANGED
|
@@ -23,10 +23,13 @@ export type AtomUpdateEvent<A extends AtomToken<any>> = {
|
|
|
23
23
|
timestamp: number
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export type SelectorUpdateSubEvent<A extends AtomToken<any>> =
|
|
27
|
+
| AtomUpdateEvent<A>
|
|
28
|
+
| StateCreationEvent<any>
|
|
26
29
|
export type TimelineSelectorUpdateEvent<A extends TimelineManageable> = {
|
|
27
30
|
type: `selector_update`
|
|
28
31
|
token: SelectorToken<any>
|
|
29
|
-
|
|
32
|
+
subEvents: SelectorUpdateSubEvent<AtomOnly<A>>[]
|
|
30
33
|
timestamp: number
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -110,7 +113,9 @@ export type TransactionOutcomeEvent<T extends TransactionToken<any>> = {
|
|
|
110
113
|
output: ReturnType<TokenType<T>>
|
|
111
114
|
}
|
|
112
115
|
|
|
113
|
-
export type TimelineEvent<ManagedAtom extends TimelineManageable> =
|
|
116
|
+
export type TimelineEvent<ManagedAtom extends TimelineManageable> = {
|
|
117
|
+
write?: true
|
|
118
|
+
} & (
|
|
114
119
|
| AtomUpdateEvent<AtomOnly<ManagedAtom>>
|
|
115
120
|
| MoleculeCreationEvent
|
|
116
121
|
| MoleculeDisposalEvent
|
|
@@ -118,3 +123,4 @@ export type TimelineEvent<ManagedAtom extends TimelineManageable> =
|
|
|
118
123
|
| StateDisposalEvent<AtomOnly<ManagedAtom>>
|
|
119
124
|
| TimelineSelectorUpdateEvent<ManagedAtom>
|
|
120
125
|
| TransactionOutcomeEvent<TransactionToken<any>>
|
|
126
|
+
)
|
package/src/main/logger.ts
CHANGED
|
@@ -37,7 +37,7 @@ const LOGGER_ICON_DICTIONARY = {
|
|
|
37
37
|
"⏭️": `Transaction redo`,
|
|
38
38
|
"⏮️": `Transaction undo`,
|
|
39
39
|
"⏳": `Timeline event partially captured`,
|
|
40
|
-
"
|
|
40
|
+
"⏸️": `Time-travel complete`,
|
|
41
41
|
// Problems
|
|
42
42
|
"💣": `Dangerous action likely to cause bad errors down the line`,
|
|
43
43
|
"❗": `Dangerous action unless in development mode`,
|
package/src/main/timeline.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { Timeline } from "atom.io/internal"
|
|
2
1
|
import { createTimeline, IMPLICIT, timeTravel } from "atom.io/internal"
|
|
3
2
|
|
|
4
|
-
import type { AtomFamilyToken, AtomToken,
|
|
3
|
+
import type { AtomFamilyToken, AtomToken, TimelineToken } from "."
|
|
5
4
|
|
|
6
5
|
export type TimelineManageable = AtomFamilyToken<any, any> | AtomToken<any>
|
|
7
6
|
export type AtomOnly<M extends TimelineManageable> = M extends AtomFamilyToken<
|
|
@@ -33,11 +32,6 @@ export type TimelineOptions<ManagedAtom extends TimelineManageable> = {
|
|
|
33
32
|
key: string
|
|
34
33
|
/** The managed atoms (and families of atoms) to record */
|
|
35
34
|
scope: ManagedAtom[]
|
|
36
|
-
/** A function that determines whether a given update should be recorded */
|
|
37
|
-
shouldCapture?: (
|
|
38
|
-
update: TimelineEvent<ManagedAtom>,
|
|
39
|
-
timeline: Timeline<TimelineManageable>,
|
|
40
|
-
) => boolean
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
/**
|
|
@@ -192,18 +192,23 @@ export const TimelineUpdateFC: React.FC<{
|
|
|
192
192
|
}
|
|
193
193
|
})
|
|
194
194
|
) : timelineUpdate.type === `selector_update` ? (
|
|
195
|
-
timelineUpdate.
|
|
195
|
+
timelineUpdate.subEvents
|
|
196
196
|
.filter(
|
|
197
197
|
(atomUpdateEvent) => !atomUpdateEvent.token.key.startsWith(`👁🗨`),
|
|
198
198
|
)
|
|
199
|
-
.map((
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
199
|
+
.map((event, index) => {
|
|
200
|
+
switch (event.type) {
|
|
201
|
+
case `atom_update`:
|
|
202
|
+
return (
|
|
203
|
+
<article.AtomUpdate
|
|
204
|
+
key={`${timelineUpdate.token.key}:${index}:${event.token.key}`}
|
|
205
|
+
serialNumber={index}
|
|
206
|
+
atomUpdate={event}
|
|
207
|
+
/>
|
|
208
|
+
)
|
|
209
|
+
case `state_creation`:
|
|
210
|
+
return null
|
|
211
|
+
}
|
|
207
212
|
})
|
|
208
213
|
) : timelineUpdate.type === `atom_update` ? (
|
|
209
214
|
<article.AtomUpdate
|
|
@@ -3,9 +3,9 @@ import { findInStore } from "atom.io/internal"
|
|
|
3
3
|
import type { Json, JsonTypes } from "atom.io/json"
|
|
4
4
|
import { JSON_DEFAULTS } from "atom.io/json"
|
|
5
5
|
import { useI, useO } from "atom.io/react"
|
|
6
|
-
import { DevtoolsContext } from "atom.io/react-devtools/store"
|
|
7
6
|
import { type ReactElement, useContext } from "react"
|
|
8
7
|
|
|
8
|
+
import { DevtoolsContext } from "../../store"
|
|
9
9
|
import type { JsonEditorComponents, SetterOrUpdater } from ".."
|
|
10
10
|
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
11
11
|
import { JsonEditor_INTERNAL } from "../json-editor-internal"
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import type { RegularAtomToken } from "atom.io"
|
|
2
2
|
import { findInStore } from "atom.io/internal"
|
|
3
3
|
import type { Json, JsonTypes } from "atom.io/json"
|
|
4
|
-
import { useI } from "atom.io/react
|
|
5
|
-
import { useO } from "atom.io/react/use-o"
|
|
6
|
-
import { DevtoolsContext } from "atom.io/react-devtools/store"
|
|
4
|
+
import { useI, useO } from "atom.io/react"
|
|
7
5
|
import type { FC, ReactElement } from "react"
|
|
8
6
|
import { useContext, useRef } from "react"
|
|
9
7
|
|
|
10
8
|
import { ElasticInput } from "../../elastic-input"
|
|
9
|
+
import { DevtoolsContext } from "../../store"
|
|
11
10
|
import type { SetterOrUpdater } from ".."
|
|
12
11
|
import type { JsonEditorComponents } from "../default-components"
|
|
13
12
|
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
@@ -10,7 +10,7 @@ export const makeElementSetters = <T extends Json.Tree.Array>(
|
|
|
10
10
|
data.map((value, index) => (newValue) => {
|
|
11
11
|
set((): T => {
|
|
12
12
|
const newData = [...data]
|
|
13
|
-
newData[index] = become(newValue
|
|
13
|
+
newData[index] = become(newValue, value)
|
|
14
14
|
return newData as unknown as T
|
|
15
15
|
})
|
|
16
16
|
})
|
|
@@ -14,7 +14,7 @@ export const makePropertySetters = <T extends Json.Tree.Object>(
|
|
|
14
14
|
toEntries(data).map(([key, value]) => [
|
|
15
15
|
key,
|
|
16
16
|
(newValue: unknown) => {
|
|
17
|
-
set({ ...data, [key]: become(newValue
|
|
17
|
+
set({ ...data, [key]: become(newValue, value) })
|
|
18
18
|
},
|
|
19
19
|
]),
|
|
20
20
|
)
|
package/dist/use-o-DXPncKmZ.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { IMPLICIT, findInStore, getFromStore, setIntoStore, subscribeToState } from "atom.io/internal";
|
|
2
|
-
import * as React$1 from "react";
|
|
3
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
5
|
-
//#region src/react/store-context.tsx
|
|
6
|
-
const StoreContext = React$1.createContext(IMPLICIT.STORE);
|
|
7
|
-
const StoreProvider = ({ children, store = IMPLICIT.STORE }) => /* @__PURE__ */ jsx(StoreContext.Provider, {
|
|
8
|
-
value: store,
|
|
9
|
-
children
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region src/react/parse-state-overloads.ts
|
|
14
|
-
function parseStateOverloads(store, ...rest) {
|
|
15
|
-
let token;
|
|
16
|
-
if (rest.length === 2) {
|
|
17
|
-
const family = rest[0];
|
|
18
|
-
const key = rest[1];
|
|
19
|
-
token = findInStore(store, family, key);
|
|
20
|
-
} else token = rest[0];
|
|
21
|
-
return token;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/react/use-i.ts
|
|
26
|
-
function useI(...params) {
|
|
27
|
-
const store = React$1.useContext(StoreContext);
|
|
28
|
-
const token = parseStateOverloads(store, ...params);
|
|
29
|
-
const setter = React$1.useRef(null);
|
|
30
|
-
setter.current ??= (next) => {
|
|
31
|
-
setIntoStore(store, token, next);
|
|
32
|
-
};
|
|
33
|
-
return setter.current;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/react/use-o.ts
|
|
38
|
-
function useO(...params) {
|
|
39
|
-
const store = React$1.useContext(StoreContext);
|
|
40
|
-
const token = parseStateOverloads(store, ...params);
|
|
41
|
-
const id = React$1.useId();
|
|
42
|
-
return React$1.useSyncExternalStore((dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch), () => getFromStore(store, token), () => getFromStore(store, token));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
export { StoreContext, StoreProvider, useI, useO };
|
|
47
|
-
//# sourceMappingURL=use-o-DXPncKmZ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-o-DXPncKmZ.js","names":["StoreContext: React.Context<Store>","React","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}>","token: ReadableToken<any>","React","setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t>","React"],"sources":["../src/react/store-context.tsx","../src/react/parse-state-overloads.ts","../src/react/use-i.ts","../src/react/use-o.ts"],"sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext: React.Context<Store> = React.createContext(\n\tIMPLICIT.STORE,\n)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import type {\n\tReadableFamilyToken,\n\tReadableToken,\n\tWritableFamilyToken,\n\tWritableToken,\n} from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [WritableFamilyToken<T, K>, K] | [WritableToken<T>]\n): WritableToken<T>\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): ReadableToken<T>\n\nexport function parseStateOverloads<T, K extends Canonical>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): ReadableToken<T> {\n\tlet token: ReadableToken<any>\n\tif (rest.length === 2) {\n\t\tconst family = rest[0]\n\t\tconst key = rest[1]\n\n\t\ttoken = findInStore(store, family, key)\n\t} else {\n\t\ttoken = rest[0]\n\t}\n\treturn token\n}\n","import type { WritableFamilyToken, WritableToken } from \"atom.io\"\nimport { setIntoStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: WritableToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical>(\n\ttoken: WritableFamilyToken<T, K>,\n\tkey: K,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical>(\n\t...params: [WritableFamilyToken<T, K>, K] | [WritableToken<T>]\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tsetter.current ??= (next) => {\n\t\tsetIntoStore(store, token, next)\n\t}\n\treturn setter.current\n}\n","import type { ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport { getFromStore, subscribeToState } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useO<T>(token: ReadableToken<T>): T\n\nexport function useO<T, K extends Canonical>(\n\ttoken: ReadableFamilyToken<T, K>,\n\tkey: K,\n): T\n\nexport function useO<T, K extends Canonical>(\n\t...params: [ReadableFamilyToken<T, K>, K] | [ReadableToken<T>]\n): T {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch),\n\t\t() => getFromStore(store, token),\n\t\t() => getFromStore(store, token),\n\t)\n}\n"],"mappings":";;;;;AAIA,MAAaA,eAAqCC,QAAM,cACvD,SAAS;AAGV,MAAaC,iBAGP,EAAE,UAAU,QAAQ,SAAS,OAAO,KACzC,oBAAC,aAAa;CAAS,OAAO;CAAQ;;;;;ACQvC,SAAgB,oBACf,OACA,GAAG,MACgB;CACnB,IAAIC;AACJ,KAAI,KAAK,WAAW,GAAG;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,KAAK;AAEjB,UAAQ,YAAY,OAAO,QAAQ;CACnC,MACA,SAAQ,KAAK;AAEd,QAAO;AACP;;;;ACjBD,SAAgB,KACf,GAAG,QACsD;CACzD,MAAM,QAAQC,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAMC,SAEFD,QAAM,OAAO;AACjB,QAAO,aAAa,SAAS;AAC5B,eAAa,OAAO,OAAO;CAC3B;AACD,QAAO,OAAO;AACd;;;;ACdD,SAAgB,KACf,GAAG,QACC;CACJ,MAAM,QAAQE,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAM,KAAKA,QAAM;AACjB,QAAOA,QAAM,sBACX,aAAa,iBAAiB,OAAO,OAAO,SAAS,MAAM,iBACtD,aAAa,OAAO,cACpB,aAAa,OAAO;AAE3B"}
|