@atom.io/spa-devtools 0.0.3 → 0.0.4

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/README.md CHANGED
@@ -33,7 +33,7 @@ Tsdown builds the package JavaScript and declarations. SPA's compiler transforms
33
33
 
34
34
  Breakage exercises the packed package in isolated, locked peer environments, including the coordinated atom.io workspace candidate. Until the first published release, Breakage reports a first-release baseline; these checks establish compatibility with the declared peers rather than a previous spa release. Coverage gates require 100% of statements, branches, functions, and lines across the package source.
35
35
 
36
- The serving recipe measures an interactive SPA app with the debugger: atom creation, render, useValue, useSetter, JSX, and AtomIODevtools. The combined browser bundle includes atom.io, SPA, and the debugger, with shared modules counted once and unused exports removed. SPA and atom.io remain peer dependencies of the debugger package; these consumer-app measurements include both. The required debugger stylesheet is imported but its bytes are excluded from the JavaScript total, as are application components, declarations, and source maps.
36
+ The serving recipe measures an interactive SPA app with the debugger: atom creation, render, useGetter, useSetter, JSX, and AtomIODevtools. The combined browser bundle includes atom.io, SPA, and the debugger, with shared modules counted once and unused exports removed. SPA and atom.io remain peer dependencies of the debugger package; these consumer-app measurements include both. The required debugger stylesheet is imported but its bytes are excluded from the JavaScript total, as are application components, declarations, and source maps.
37
37
 
38
38
  ## Browser serving size including SPA and atom.io
39
39
 
@@ -43,7 +43,7 @@ Sizes are exact minified and level-9 gzip JavaScript byte counts. Declarations,
43
43
 
44
44
  | Recipe | Entry | Minified JS | Gzip JS |
45
45
  | ----------------------------- | ----------------------------- | ----------: | -------: |
46
- | Interactive app with debugger | `tonnage-recipes/debugger.ts` | 87,864 B | 25,581 B |
46
+ | Interactive app with debugger | `tonnage-recipes/debugger.ts` | 87,866 B | 25,583 B |
47
47
 
48
48
  Report maintained with [tonnage](https://github.com/jeremybanka/tonnage).
49
49
 
package/README.mdx CHANGED
@@ -26,7 +26,7 @@ Tsdown builds the package JavaScript and declarations. SPA's compiler transforms
26
26
 
27
27
  Breakage exercises the packed package in isolated, locked peer environments, including the coordinated atom.io workspace candidate. Until the first published release, Breakage reports a first-release baseline; these checks establish compatibility with the declared peers rather than a previous spa release. Coverage gates require 100% of statements, branches, functions, and lines across the package source.
28
28
 
29
- The serving recipe measures an interactive SPA app with the debugger: atom creation, render, useValue, useSetter, JSX, and AtomIODevtools. The combined browser bundle includes atom.io, SPA, and the debugger, with shared modules counted once and unused exports removed. SPA and atom.io remain peer dependencies of the debugger package; these consumer-app measurements include both. The required debugger stylesheet is imported but its bytes are excluded from the JavaScript total, as are application components, declarations, and source maps.
29
+ The serving recipe measures an interactive SPA app with the debugger: atom creation, render, useGetter, useSetter, JSX, and AtomIODevtools. The combined browser bundle includes atom.io, SPA, and the debugger, with shared modules counted once and unused exports removed. SPA and atom.io remain peer dependencies of the debugger package; these consumer-app measurements include both. The required debugger stylesheet is imported but its bytes are excluded from the JavaScript total, as are application components, declarations, and source maps.
30
30
 
31
31
  <Tonnage config={config} />
32
32
 
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "@atom.io/spa/jsx-runtime";
2
- import { onCleanup, onMount, render, useId, useSetter, useTimeline, useValue } from "@atom.io/spa";
2
+ import { onCleanup, onMount, render, useGetter, useId, useSetter, useTimeline } from "@atom.io/spa";
3
3
  import { IMPLICIT, createRegularAtomFamily, disposeFromStore, findInStore, isReservedIntrospectionKey, setIntoStore } from "atom.io/internal";
4
4
  import { attachIntrospectionStates } from "atom.io/introspection";
5
5
  // src/store.ts
@@ -23,7 +23,7 @@ function ownedAtom(store, initial) {
23
23
  }
24
24
  function useLocal(store, initial) {
25
25
  const token = ownedAtom(store, initial);
26
- return [useValue(token), useSetter(token)];
26
+ return [useGetter(token), useSetter(token)];
27
27
  }
28
28
  function useSaved(store, key, fallback) {
29
29
  let initial = fallback;
@@ -31,11 +31,11 @@ function useSaved(store, key, fallback) {
31
31
  const saved = JSON.parse(localStorage.getItem(key) ?? `null`);
32
32
  if (saved !== null && typeof saved === typeof fallback) initial = saved;
33
33
  } catch {}
34
- const [value, set] = useLocal(store, initial);
35
- return [value, (next) => {
36
- set(next);
34
+ const [getValue, setValue] = useLocal(store, initial);
35
+ return [getValue, (next) => {
36
+ setValue(next);
37
37
  try {
38
- localStorage.setItem(key, JSON.stringify(value()));
38
+ localStorage.setItem(key, JSON.stringify(getValue()));
39
39
  } catch {}
40
40
  }];
41
41
  }
@@ -68,14 +68,14 @@ function useTools(store) {
68
68
  };
69
69
  }
70
70
  function useExpanded(tools, path, initial = false) {
71
- const value = useValue(tools.expanded);
72
- const set = useSetter(tools.expanded);
71
+ const getExpanded = useGetter(tools.expanded);
72
+ const setExpanded = useSetter(tools.expanded);
73
73
  const key = JSON.stringify(path);
74
74
  const group = `all:${JSON.stringify(path.slice(0, -1))}`;
75
- const read = () => value()[key] ?? value()[group] ?? initial;
75
+ const read = () => getExpanded()[key] ?? getExpanded()[group] ?? initial;
76
76
  return [read, (event) => {
77
77
  const next = !read();
78
- set((previous) => {
78
+ setExpanded((previous) => {
79
79
  const result = { ...previous };
80
80
  if (event.shiftKey) {
81
81
  const parent = JSON.stringify(path.slice(0, -1));
@@ -141,7 +141,7 @@ const TYPES = [
141
141
  `object`
142
142
  ];
143
143
  function JsonEditor(props) {
144
- const [expanded, toggle] = useExpanded(props.tools, props.path);
144
+ const [getExpanded, toggle] = useExpanded(props.tools, props.path);
145
145
  const circular = () => (props.ancestors?.includes(props.value) ?? false) || props.path.length > 50;
146
146
  const container = () => !circular() && (kind(props.value) === `object` || kind(props.value) === `array`);
147
147
  const entries = () => Object.entries(props.value);
@@ -157,12 +157,12 @@ function JsonEditor(props) {
157
157
  return `Expand ${props.path.at(-1)}`;
158
158
  },
159
159
  get "aria-expanded"() {
160
- return expanded();
160
+ return getExpanded();
161
161
  },
162
162
  get "onClick"() {
163
163
  return toggle;
164
164
  },
165
- children: () => expanded() ? `▾` : `▸`
165
+ children: () => getExpanded() ? `▾` : `▸`
166
166
  }) : jsx("span", { "class": "carat-spacer" }),
167
167
  jsx("span", {
168
168
  "class": "field-name",
@@ -212,7 +212,7 @@ function JsonEditor(props) {
212
212
  }
213
213
  }),
214
214
  () => props.actions
215
- ] }), () => container() && expanded() ? jsx("section", {
215
+ ] }), () => container() && getExpanded() ? jsx("section", {
216
216
  "class": "properties",
217
217
  children: [() => entries().map(([key]) => jsx(Property, {
218
218
  "key": key,
@@ -376,15 +376,15 @@ Primitive.spa = true;
376
376
  Property.spa = true;
377
377
  // src/Indexes.tsx
378
378
  function StateIndex(props) {
379
- const index = useValue(props.type === `atoms` ? props.tools.atomIndex : props.tools.selectorIndex);
379
+ const getStateIndex = useGetter(props.type === `atoms` ? props.tools.atomIndex : props.tools.selectorIndex);
380
380
  return jsx("article", {
381
381
  "class": "index",
382
382
  "data-testid": "state-index",
383
- children: () => index().size === 0 ? jsx("p", { children: [
383
+ children: () => getStateIndex().size === 0 ? jsx("p", { children: [
384
384
  "(no ",
385
385
  () => props.type,
386
386
  ")"
387
- ] }) : [...index().values()].map((node) => jsx(StateNode, {
387
+ ] }) : [...getStateIndex().values()].map((node) => jsx(StateNode, {
388
388
  "key": node.key,
389
389
  get "tools"() {
390
390
  return props.tools;
@@ -396,7 +396,7 @@ function StateIndex(props) {
396
396
  });
397
397
  }
398
398
  function StateNode(props) {
399
- const [open, toggle] = useExpanded(props.tools, [props.node.key]);
399
+ const [getOpen, toggle] = useExpanded(props.tools, [props.node.key]);
400
400
  return jsx("section", {
401
401
  "class": "node",
402
402
  get "data-testid"() {
@@ -406,7 +406,7 @@ function StateNode(props) {
406
406
  jsx("button", {
407
407
  "type": "button",
408
408
  get "aria-expanded"() {
409
- return open();
409
+ return getOpen();
410
410
  },
411
411
  get "data-testid"() {
412
412
  return `open-close-state-family-${props.node.key}`;
@@ -414,11 +414,11 @@ function StateNode(props) {
414
414
  get "onClick"() {
415
415
  return toggle;
416
416
  },
417
- children: () => open() ? `▾` : `▸`
417
+ children: () => getOpen() ? `▾` : `▸`
418
418
  }),
419
419
  jsx("h2", { children: () => props.node.key }),
420
420
  jsx("small", { children: "family" })
421
- ] }), () => open() ? [...props.node.familyMembers.values()].map((token) => jsx(StateLeaf, {
421
+ ] }), () => getOpen() ? [...props.node.familyMembers.values()].map((token) => jsx(StateLeaf, {
422
422
  "key": token.key,
423
423
  get "tools"() {
424
424
  return props.tools;
@@ -437,11 +437,11 @@ function StateNode(props) {
437
437
  });
438
438
  }
439
439
  function StateLeaf(props) {
440
- const read = useValue(props.token);
441
- const set = !props.token.type.startsWith(`readonly`) ? useSetter(props.token) : void 0;
440
+ const getValue = useGetter(props.token);
441
+ const setValue = !props.token.type.startsWith(`readonly`) ? useSetter(props.token) : void 0;
442
442
  const value = () => {
443
443
  try {
444
- return read();
444
+ return getValue();
445
445
  } catch (error) {
446
446
  return error;
447
447
  }
@@ -476,9 +476,9 @@ function StateLeaf(props) {
476
476
  return value();
477
477
  },
478
478
  get "change"() {
479
- return set ? (update) => {
480
- const next = update(read());
481
- set(() => next);
479
+ return setValue ? (update) => {
480
+ const next = update(getValue());
481
+ setValue(() => next);
482
482
  } : void 0;
483
483
  },
484
484
  get "path"() {
@@ -488,8 +488,8 @@ function StateLeaf(props) {
488
488
  });
489
489
  }
490
490
  function TransactionIndex(props) {
491
- const index = useValue(props.tools.transactionIndex);
492
- const visible = () => index().filter((token) => !isReservedIntrospectionKey(token.key));
491
+ const getTransactionIndex = useGetter(props.tools.transactionIndex);
492
+ const visible = () => getTransactionIndex().filter((token) => !isReservedIntrospectionKey(token.key));
493
493
  return jsx("article", {
494
494
  "class": "index",
495
495
  "data-testid": "transaction-index",
@@ -505,8 +505,8 @@ function TransactionIndex(props) {
505
505
  });
506
506
  }
507
507
  function TransactionLog(props) {
508
- const log = useValue(findInStore(props.tools.store, props.tools.transactionLogSelectors, props.token.key));
509
- const [open, toggle] = useExpanded(props.tools, [props.token.key]);
508
+ const getTransactionLog = useGetter(findInStore(props.tools.store, props.tools.transactionLogSelectors, props.token.key));
509
+ const [getOpen, toggle] = useExpanded(props.tools, [props.token.key]);
510
510
  return jsx("section", {
511
511
  "class": "node",
512
512
  get "data-testid"() {
@@ -516,7 +516,7 @@ function TransactionLog(props) {
516
516
  jsx("button", {
517
517
  "type": "button",
518
518
  get "aria-expanded"() {
519
- return open();
519
+ return getOpen();
520
520
  },
521
521
  get "data-testid"() {
522
522
  return `open-close-transaction-${props.token.key}`;
@@ -524,15 +524,15 @@ function TransactionLog(props) {
524
524
  get "onClick"() {
525
525
  return toggle;
526
526
  },
527
- children: () => open() ? `▾` : `▸`
527
+ children: () => getOpen() ? `▾` : `▸`
528
528
  }),
529
529
  jsx("h2", { children: () => props.token.key }),
530
530
  jsx("small", { children: [
531
531
  "(",
532
- () => log().length,
532
+ () => getTransactionLog().length,
533
533
  ")"
534
534
  ] })
535
- ] }), () => open() ? log().map((event, index) => jsx(EventView, {
535
+ ] }), () => getOpen() ? getTransactionLog().map((event, index) => jsx(EventView, {
536
536
  "key": index,
537
537
  get "tools"() {
538
538
  return props.tools;
@@ -547,7 +547,7 @@ function TransactionLog(props) {
547
547
  });
548
548
  }
549
549
  function EventView(props) {
550
- const [open, toggle] = useExpanded(props.tools, [
550
+ const [getOpen, toggle] = useExpanded(props.tools, [
551
551
  `event`,
552
552
  props.event.token?.key ?? ``,
553
553
  String(props.index)
@@ -561,16 +561,16 @@ function EventView(props) {
561
561
  jsx("button", {
562
562
  "type": "button",
563
563
  get "aria-expanded"() {
564
- return open();
564
+ return getOpen();
565
565
  },
566
566
  get "onClick"() {
567
567
  return toggle;
568
568
  },
569
- children: () => open() ? `▾` : `▸`
569
+ children: () => getOpen() ? `▾` : `▸`
570
570
  }),
571
571
  jsx("strong", { children: () => props.event.token?.key }),
572
572
  jsx("small", { children: () => props.event.type })
573
- ] }), () => open() ? props.event.type === `transaction_outcome` ? jsx(null, { children: [
573
+ ] }), () => getOpen() ? props.event.type === `transaction_outcome` ? jsx(null, { children: [
574
574
  jsx("p", { children: ["params: ", jsx("code", { children: () => describe(props.event.params) })] }),
575
575
  jsx("p", { children: ["output: ", jsx("code", { children: () => describe(props.event.output) })] }),
576
576
  jsx("section", {
@@ -597,10 +597,10 @@ function EventView(props) {
597
597
  });
598
598
  }
599
599
  function TimelineIndex(props) {
600
- const index = useValue(props.tools.timelineIndex);
600
+ const getTimelineIndex = useGetter(props.tools.timelineIndex);
601
601
  const groups = () => {
602
602
  const result = /* @__PURE__ */ new Map();
603
- for (const token of index()) {
603
+ for (const token of getTimelineIndex()) {
604
604
  if (isReservedIntrospectionKey(token.key) || token.key.startsWith(`👁‍🗨`)) continue;
605
605
  const key = token.family?.key ?? ``;
606
606
  const members = result.get(key) ?? [];
@@ -631,8 +631,8 @@ function TimelineIndex(props) {
631
631
  }
632
632
  function TimelineLog(props) {
633
633
  const controls = useTimeline(props.token);
634
- const log = useValue(findInStore(props.tools.store, props.tools.timelineSelectors, props.token.key));
635
- const [open, toggle] = useExpanded(props.tools, [props.token.key]);
634
+ const getTimeline = useGetter(findInStore(props.tools.store, props.tools.timelineSelectors, props.token.key));
635
+ const [getOpen, toggle] = useExpanded(props.tools, [props.token.key]);
636
636
  return jsx("section", {
637
637
  "class": "node",
638
638
  get "data-testid"() {
@@ -642,7 +642,7 @@ function TimelineLog(props) {
642
642
  jsx("button", {
643
643
  "type": "button",
644
644
  get "aria-expanded"() {
645
- return open();
645
+ return getOpen();
646
646
  },
647
647
  get "data-testid"() {
648
648
  return `open-close-timeline-${props.token.key}`;
@@ -650,39 +650,39 @@ function TimelineLog(props) {
650
650
  get "onClick"() {
651
651
  return toggle;
652
652
  },
653
- children: () => open() ? `▾` : `▸`
653
+ children: () => getOpen() ? `▾` : `▸`
654
654
  }),
655
655
  jsx("h2", { children: () => props.token.family?.subKey ?? props.token.key }),
656
656
  jsx("small", { children: [
657
657
  "(",
658
- () => controls().at,
658
+ () => controls.getCursor(),
659
659
  "/",
660
- () => controls().length,
660
+ () => controls.getLength(),
661
661
  ")"
662
662
  ] }),
663
663
  jsx("button", {
664
664
  "type": "button",
665
665
  get "disabled"() {
666
- return controls().at === 0;
666
+ return controls.getCursor() === 0;
667
667
  },
668
668
  "onClick": (() => {
669
- props.tools.attempt(controls().undo);
669
+ props.tools.attempt(controls.undo);
670
670
  }),
671
671
  children: "undo"
672
672
  }),
673
673
  jsx("button", {
674
674
  "type": "button",
675
675
  get "disabled"() {
676
- return controls().at === controls().length;
676
+ return controls.getCursor() === controls.getLength();
677
677
  },
678
678
  "onClick": (() => {
679
- props.tools.attempt(controls().redo);
679
+ props.tools.attempt(controls.redo);
680
680
  }),
681
681
  children: "redo"
682
682
  })
683
- ] }), () => open() ? jsx("section", { children: [() => log().history.map((event, index) => jsx("section", {
683
+ ] }), () => getOpen() ? jsx("section", { children: [() => getTimeline().history.map((event, index) => jsx("section", {
684
684
  "key": index,
685
- children: [() => index === log().at ? jsx("p", {
685
+ children: [() => index === getTimeline().at ? jsx("p", {
686
686
  "class": "you-are-here",
687
687
  children: "you are here"
688
688
  }) : null, jsx(EventView, {
@@ -696,7 +696,7 @@ function TimelineLog(props) {
696
696
  return index;
697
697
  }
698
698
  })]
699
- })), () => log().at === log().history.length ? jsx("p", {
699
+ })), () => getTimeline().at === getTimeline().history.length ? jsx("p", {
700
700
  "class": "you-are-here",
701
701
  children: "you are here"
702
702
  }) : null] }) : null]
@@ -741,15 +741,15 @@ const VIEWS = [
741
741
  ];
742
742
  function Panel(props) {
743
743
  const tools = useTools(props.store);
744
- const [hidden, setHidden] = useSaved(props.store, `🔍 Devtools Are Hidden`, props.hideByDefault);
745
- const [open, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true);
746
- const [selection, setSelection] = useSaved(props.store, `🔍 Devtools View`, `atoms`);
747
- const view = () => VIEWS.includes(selection()) ? selection() : `atoms`;
748
- const [position, setPosition] = useLocal(props.store, {
744
+ const [getHidden, setHidden] = useSaved(props.store, `🔍 Devtools Are Hidden`, props.hideByDefault);
745
+ const [getOpen, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true);
746
+ const [getSelection, setSelection] = useSaved(props.store, `🔍 Devtools View`, `atoms`);
747
+ const view = () => VIEWS.includes(getSelection()) ? getSelection() : `atoms`;
748
+ const [getPosition, setPosition] = useLocal(props.store, {
749
749
  x: 0,
750
750
  y: 0
751
751
  });
752
- const error = useValue(tools.error);
752
+ const getError = useGetter(tools.error);
753
753
  let panel = null;
754
754
  const attach = (element) => {
755
755
  panel = element;
@@ -782,13 +782,13 @@ function Panel(props) {
782
782
  "data-css": "spa-devtools",
783
783
  "data-testid": "atom-io-devtools",
784
784
  get "hidden"() {
785
- return hidden();
785
+ return getHidden();
786
786
  },
787
787
  get "data-open"() {
788
- return open();
788
+ return getOpen();
789
789
  },
790
790
  get "style"() {
791
- return `transform:translate(${position().x}px,${position().y}px)`;
791
+ return `transform:translate(${getPosition().x}px,${getPosition().y}px)`;
792
792
  },
793
793
  children: [jsx("header", {
794
794
  "class": "toolbar",
@@ -804,7 +804,7 @@ function Panel(props) {
804
804
  id: event.pointerId,
805
805
  startX: event.clientX,
806
806
  startY: event.clientY,
807
- ...position()
807
+ ...getPosition()
808
808
  };
809
809
  event.currentTarget.setPointerCapture(event.pointerId);
810
810
  }),
@@ -815,8 +815,8 @@ function Panel(props) {
815
815
  x: drag.x + event.clientX - drag.startX,
816
816
  y: drag.y + event.clientY - drag.startY
817
817
  };
818
- next.x = Math.max(position().x - rect.left, Math.min(next.x, position().x + window.innerWidth - rect.right));
819
- next.y = Math.max(position().y - rect.top, Math.min(next.y, position().y + window.innerHeight - rect.bottom));
818
+ next.x = Math.max(getPosition().x - rect.left, Math.min(next.x, getPosition().x + window.innerWidth - rect.right));
819
+ next.y = Math.max(getPosition().y - rect.top, Math.min(next.y, getPosition().y + window.innerHeight - rect.bottom));
820
820
  setPosition(next);
821
821
  }),
822
822
  "onPointerup": (() => {
@@ -843,7 +843,7 @@ function Panel(props) {
843
843
  children: "⠿"
844
844
  }),
845
845
  jsx("h1", { children: "atom.io" }),
846
- () => open() ? jsx("nav", {
846
+ () => getOpen() ? jsx("nav", {
847
847
  "aria-label": "Debugger views",
848
848
  children: () => VIEWS.map((name) => jsx("button", {
849
849
  "type": "button",
@@ -862,13 +862,13 @@ function Panel(props) {
862
862
  jsx("button", {
863
863
  "type": "button",
864
864
  get "aria-label"() {
865
- return open() ? `Minimize debugger` : `Open debugger`;
865
+ return getOpen() ? `Minimize debugger` : `Open debugger`;
866
866
  },
867
867
  "data-testid": "open-close-devtools",
868
868
  "onClick": (() => {
869
869
  setOpen((value) => !value);
870
870
  }),
871
- children: () => open() ? `−` : `🔍`
871
+ children: () => getOpen() ? `−` : `🔍`
872
872
  }),
873
873
  jsx("button", {
874
874
  "type": "button",
@@ -879,9 +879,9 @@ function Panel(props) {
879
879
  children: "×"
880
880
  })
881
881
  ]
882
- }), () => open() ? jsx(null, { children: [() => error() ? jsx("p", {
882
+ }), () => getOpen() ? jsx(null, { children: [() => getError() ? jsx("p", {
883
883
  "role": "alert",
884
- children: () => error()
884
+ children: () => getError()
885
885
  }) : null, () => view() === `atoms` || view() === `selectors` ? jsx(StateIndex, {
886
886
  "key": view(),
887
887
  get "tools"() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_spa","_spa","_spa"],"sources":["../src/store.ts","../src/value.ts","../src/JsonEditor.tsx","../src/Indexes.tsx","../src/AtomIODevtools.tsx"],"sourcesContent":["import type { Accessor } from \"@atom.io/spa\"\nimport { onCleanup, useId, useSetter, useValue } from \"@atom.io/spa\"\nimport type { RegularAtomFamilyToken, RegularAtomToken, Setter } from \"atom.io\"\nimport type { RootStore } from \"atom.io/internal\"\nimport {\n\tcreateRegularAtomFamily,\n\tdisposeFromStore,\n\tfindInStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { IntrospectionStates } from \"atom.io/introspection\"\nimport { attachIntrospectionStates } from \"atom.io/introspection\"\n\nconst locals = new WeakMap<RootStore, RegularAtomFamilyToken<unknown, string>>()\nconst introspection = new WeakMap<RootStore, IntrospectionStates>()\nexport type Path = readonly string[]\nexport interface Tools extends IntrospectionStates {\n\tstore: RootStore\n\texpanded: RegularAtomToken<Record<string, boolean>>\n\terror: RegularAtomToken<string>\n\tattempt(run: () => void): void\n}\n\nexport function ownedAtom<T>(store: RootStore, initial: T): RegularAtomToken<T> {\n\tlet family = locals.get(store)\n\tif (!family) {\n\t\tfamily = createRegularAtomFamily<unknown, string, never>(store, {\n\t\t\tkey: `🔍 spa devtools`,\n\t\t\tdefault: undefined,\n\t\t})\n\t\tlocals.set(store, family)\n\t}\n\tconst token = findInStore(store, family, useId()) as RegularAtomToken<T>\n\tsetIntoStore(store, token, initial)\n\tonCleanup(() => {\n\t\tdisposeFromStore(store, token)\n\t})\n\treturn token\n}\nexport function useLocal<T>(\n\tstore: RootStore,\n\tinitial: T,\n): [Accessor<T>, (next: T | Setter<T>) => void] {\n\tconst token = ownedAtom(store, initial)\n\treturn [useValue(token) as Accessor<T>, useSetter(token)]\n}\nexport function useSaved<T>(\n\tstore: RootStore,\n\tkey: string,\n\tfallback: T,\n): [Accessor<T>, (next: T | Setter<T>) => void] {\n\tlet initial = fallback\n\ttry {\n\t\tconst saved: unknown = JSON.parse(localStorage.getItem(key) ?? `null`)\n\t\tif (saved !== null && typeof saved === typeof fallback) initial = saved as T\n\t} catch {\n\t\t/* Storage may be unavailable. */\n\t}\n\tconst [value, set] = useLocal(store, initial)\n\treturn [\n\t\tvalue,\n\t\t(next) => {\n\t\t\tset(next)\n\t\t\ttry {\n\t\t\t\tlocalStorage.setItem(key, JSON.stringify(value()))\n\t\t\t} catch {\n\t\t\t\t/* Keep in-memory state when storage is unavailable. */\n\t\t\t}\n\t\t},\n\t]\n}\nexport function useTools(store: RootStore): Tools {\n\tlet states = introspection.get(store)\n\tif (!states) {\n\t\tstates = attachIntrospectionStates(store)\n\t\tintrospection.set(store, states)\n\t}\n\tlet expanded: Record<string, boolean> = {}\n\ttry {\n\t\tconst saved: unknown = JSON.parse(\n\t\t\tlocalStorage.getItem(`🔍 spa expanded`) ?? `{}`,\n\t\t)\n\t\tif (\n\t\t\tsaved &&\n\t\t\ttypeof saved === `object` &&\n\t\t\t!Array.isArray(saved) &&\n\t\t\tObject.values(saved).every((value) => typeof value === `boolean`)\n\t\t)\n\t\t\texpanded = saved as Record<string, boolean>\n\t} catch {\n\t\t/* Ignore corrupt or unavailable storage. */\n\t}\n\tconst error = ownedAtom(store, ``)\n\tconst setError = useSetter(error)\n\treturn {\n\t\t...states,\n\t\tstore,\n\t\terror,\n\t\texpanded: ownedAtom(store, expanded),\n\t\tattempt(run) {\n\t\t\ttry {\n\t\t\t\trun()\n\t\t\t\tsetError(``)\n\t\t\t} catch (caught) {\n\t\t\t\tsetError(caught instanceof Error ? caught.message : String(caught))\n\t\t\t}\n\t\t},\n\t}\n}\nexport function useExpanded(\n\ttools: Tools,\n\tpath: Path,\n\tinitial = false,\n): [Accessor<boolean>, (event: MouseEvent) => void] {\n\tconst value = useValue(tools.expanded)\n\tconst set = useSetter(tools.expanded)\n\tconst key = JSON.stringify(path)\n\tconst group = `all:${JSON.stringify(path.slice(0, -1))}`\n\tconst read = () => value()[key] ?? value()[group] ?? initial\n\treturn [\n\t\tread,\n\t\t(event) => {\n\t\t\tconst next = !read()\n\t\t\tset((previous) => {\n\t\t\t\tconst result = { ...previous }\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tconst parent = JSON.stringify(path.slice(0, -1))\n\t\t\t\t\tfor (const item of Object.keys(result)) {\n\t\t\t\t\t\tif (item.startsWith(`[`)) {\n\t\t\t\t\t\t\tconst candidate = JSON.parse(item) as string[]\n\t\t\t\t\t\t\tif (JSON.stringify(candidate.slice(0, -1)) === parent)\n\t\t\t\t\t\t\t\tReflect.deleteProperty(result, item)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresult[group] = next\n\t\t\t\t} else {\n\t\t\t\t\tresult[key] = next\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tlocalStorage.setItem(`🔍 spa expanded`, JSON.stringify(result))\n\t\t\t\t} catch {\n\t\t\t\t\t/* Keep in-memory expansion state. */\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t})\n\t\t},\n\t]\n}\n","export type Change = (update: (previous: unknown) => unknown) => void\nexport type JsonKind =\n\t| `string`\n\t| `number`\n\t| `boolean`\n\t| `null`\n\t| `array`\n\t| `object`\nexport function kind(value: unknown): JsonKind | `other` {\n\tif (value === null) return `null`\n\tif (Array.isArray(value)) return `array`\n\tif (\n\t\ttypeof value === `object` &&\n\t\t(Object.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null)\n\t)\n\t\treturn `object`\n\tif (\n\t\ttypeof value === `string` ||\n\t\ttypeof value === `number` ||\n\t\ttypeof value === `boolean`\n\t)\n\t\treturn typeof value as JsonKind\n\treturn `other`\n}\nexport function describe(value: unknown): string {\n\ttry {\n\t\tconst seen = new WeakSet<object>()\n\t\treturn (\n\t\t\tJSON.stringify(value, (_, item: unknown) => {\n\t\t\t\tif (typeof item === `bigint`) return `${item}n`\n\t\t\t\tif (item instanceof Error) return `${item.name}: ${item.message}`\n\t\t\t\tif (item instanceof Map) return { Map: [...item] }\n\t\t\t\tif (item instanceof Set) return { Set: [...item] }\n\t\t\t\tif (typeof item === `object` && item !== null) {\n\t\t\t\t\tif (seen.has(item)) return `[Circular]`\n\t\t\t\t\tseen.add(item)\n\t\t\t\t}\n\t\t\t\treturn item\n\t\t\t}) ?? String(value)\n\t\t)\n\t} catch {\n\t\treturn Object.prototype.toString.call(value)\n\t}\n}\nexport function convert(value: unknown, type: JsonKind): unknown {\n\tswitch (type) {\n\t\tcase `null`:\n\t\t\treturn null\n\t\tcase `string`:\n\t\t\treturn value == null\n\t\t\t\t? ``\n\t\t\t\t: typeof value === `string`\n\t\t\t\t\t? value\n\t\t\t\t\t: describe(value)\n\t\tcase `number`: {\n\t\t\tconst next = Array.isArray(value) ? value.length : Number(value)\n\t\t\treturn Number.isFinite(next) ? next : 0\n\t\t}\n\t\tcase `boolean`:\n\t\t\treturn typeof value === `string` ? value === `true` : Boolean(value)\n\t\tcase `array`:\n\t\t\treturn Array.isArray(value)\n\t\t\t\t? value\n\t\t\t\t: value == null\n\t\t\t\t\t? []\n\t\t\t\t\t: typeof value === `object`\n\t\t\t\t\t\t? Object.entries(value)\n\t\t\t\t\t\t: [value]\n\t\tcase `object`:\n\t\t\treturn kind(value) === `object`\n\t\t\t\t? value\n\t\t\t\t: Array.isArray(value)\n\t\t\t\t\t? Object.fromEntries(value.map((item, index) => [index, item]))\n\t\t\t\t\t: value == null\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { value }\n\t}\n}\n","import type { Child, VNode } from \"@atom.io/spa\"\n\nimport type { Path, Tools } from \"./store.ts\"\nimport { useExpanded } from \"./store.ts\"\nimport type { Change, JsonKind } from \"./value.ts\"\nimport { convert, describe, kind } from \"./value.ts\"\n\ninterface EditorProps {\n\ttools: Tools\n\tvalue: unknown\n\tchange?: Change | undefined\n\tpath: Path\n\tancestors?: readonly unknown[]\n\tlabel?: Child\n\tactions?: Child\n}\nconst TYPES: JsonKind[] = [\n\t`string`,\n\t`number`,\n\t`boolean`,\n\t`null`,\n\t`array`,\n\t`object`,\n]\nexport function JsonEditor(props: EditorProps): VNode {\n\tconst [expanded, toggle] = useExpanded(props.tools, props.path)\n\tconst circular = () =>\n\t\t(props.ancestors?.includes(props.value) ?? false) || props.path.length > 50\n\tconst container = () =>\n\t\t!circular() &&\n\t\t(kind(props.value) === `object` || kind(props.value) === `array`)\n\tconst entries = () => Object.entries(props.value as Record<string, unknown>)\n\treturn (\n\t\t<section\n\t\t\tclass=\"json-editor\"\n\t\t\tdata-testid={`${props.path.join(`.`)}-state-editor`}\n\t\t>\n\t\t\t<header>\n\t\t\t\t{container() ? (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label={`Expand ${props.path.at(-1)}`}\n\t\t\t\t\t\taria-expanded={expanded()}\n\t\t\t\t\t\tonClick={toggle}\n\t\t\t\t\t>\n\t\t\t\t\t\t{expanded() ? `▾` : `▸`}\n\t\t\t\t\t</button>\n\t\t\t\t) : (\n\t\t\t\t\t<span class=\"carat-spacer\" />\n\t\t\t\t)}\n\t\t\t\t<span class=\"field-name\">{props.label}</span>\n\t\t\t\t{props.change ? (\n\t\t\t\t\t<select\n\t\t\t\t\t\taria-label={`Type of ${props.path.at(-1)}`}\n\t\t\t\t\t\tvalue={kind(props.value)}\n\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\tconst type = event.currentTarget.value as JsonKind\n\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\tprops.change?.((previous) => convert(previous, type))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<option value=\"other\" disabled>\n\t\t\t\t\t\t\tother\n\t\t\t\t\t\t</option>\n\t\t\t\t\t\t{TYPES.map((type) => (\n\t\t\t\t\t\t\t<option value={type}>{type}</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t) : (\n\t\t\t\t\t<small>{kind(props.value)}</small>\n\t\t\t\t)}\n\t\t\t\t{container() ? (\n\t\t\t\t\t<code title={describe(props.value)}>{describe(props.value)}</code>\n\t\t\t\t) : circular() ? (\n\t\t\t\t\t<code>[Circular]</code>\n\t\t\t\t) : (\n\t\t\t\t\t<Primitive\n\t\t\t\t\t\tvalue={props.value}\n\t\t\t\t\t\tchange={props.change}\n\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\tlabel={props.path.at(-1) ?? `value`}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{props.actions}\n\t\t\t</header>\n\t\t\t{container() && expanded() ? (\n\t\t\t\t<section class=\"properties\">\n\t\t\t\t\t{entries().map(([key]) => (\n\t\t\t\t\t\t<Property key={key} name={key} editor={props} />\n\t\t\t\t\t))}\n\t\t\t\t\t{props.change ? (\n\t\t\t\t\t\t<footer>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\t\tprops.change?.((previous) => {\n\t\t\t\t\t\t\t\t\t\t\tif (Array.isArray(previous)) return [...previous, null]\n\t\t\t\t\t\t\t\t\t\t\tconst object = previous as Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\t\tlet name = `new`\n\t\t\t\t\t\t\t\t\t\t\twhile (Object.hasOwn(object, name)) name += `_`\n\t\t\t\t\t\t\t\t\t\t\treturn { ...object, [name]: null }\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tadd {Array.isArray(props.value) ? `item` : `property`}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t{Array.isArray(props.value) ? (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\t\t\tprops.change?.((previous) =>\n\t\t\t\t\t\t\t\t\t\t\t\t[...(previous as unknown[])].sort((a, b) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\ttypeof a === `number` && typeof b === `number`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? a - b\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: describe(a).localeCompare(describe(b)),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tsort\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</footer>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\nfunction Primitive(props: {\n\tvalue: unknown\n\tchange?: Change | undefined\n\ttools: Tools\n\tlabel: string\n}): VNode {\n\tconst set = (value: unknown) => {\n\t\tprops.tools.attempt(() => {\n\t\t\tprops.change?.(() => value)\n\t\t})\n\t}\n\treturn (\n\t\t<span class=\"primitive\">\n\t\t\t{kind(props.value) === `boolean` ? (\n\t\t\t\t<input\n\t\t\t\t\taria-label={props.label}\n\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\tchecked={Boolean(props.value)}\n\t\t\t\t\tdisabled={!props.change}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tset(event.currentTarget.checked)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : kind(props.value) === `string` || kind(props.value) === `number` ? (\n\t\t\t\t<input\n\t\t\t\t\taria-label={props.label}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tinputmode={kind(props.value) === `number` ? `decimal` : `text`}\n\t\t\t\t\tvalue={String(props.value)}\n\t\t\t\t\treadOnly={!props.change}\n\t\t\t\t\tonInput={(event) => {\n\t\t\t\t\t\tconst text = event.currentTarget.value\n\t\t\t\t\t\tif (kind(props.value) === `string`) set(text)\n\t\t\t\t\t\telse if (text.trim() && Number.isFinite(Number(text)))\n\t\t\t\t\t\t\tset(Number(text))\n\t\t\t\t\t}}\n\t\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t\tevent.currentTarget.value = String(props.value)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<code>{describe(props.value)}</code>\n\t\t\t)}\n\t\t</span>\n\t)\n}\nfunction Property(props: { name: string; editor: EditorProps }): VNode {\n\tconst parent = props.editor\n\tconst read = () => (parent.value as Record<string, unknown>)[props.name]\n\tconst change: Change = (update) => {\n\t\tparent.change?.((previous) => {\n\t\t\tif (Array.isArray(previous))\n\t\t\t\treturn previous.map((value, index) =>\n\t\t\t\t\tindex === Number(props.name) ? update(value) : value,\n\t\t\t\t)\n\t\t\tconst object = previous as Record<string, unknown>\n\t\t\treturn { ...object, [props.name]: update(object[props.name]) }\n\t\t})\n\t}\n\treturn (\n\t\t<section class=\"property\">\n\t\t\t<JsonEditor\n\t\t\t\tlabel={\n\t\t\t\t\tparent.change && !Array.isArray(parent.value) ? (\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\taria-label={`Rename ${props.name}`}\n\t\t\t\t\t\t\tstyle={`width:calc(${Math.max(1, props.name.length)}ch + 6px)`}\n\t\t\t\t\t\t\tvalue={props.name}\n\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\tconst input = event.currentTarget\n\t\t\t\t\t\t\t\tconst name = input.value\n\t\t\t\t\t\t\t\tparent.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tparent.change?.((previous) => {\n\t\t\t\t\t\t\t\t\t\tconst object = previous as Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\tif (name !== props.name && Object.hasOwn(object, name))\n\t\t\t\t\t\t\t\t\t\t\tthrow new Error(`Property \"${name}\" already exists`)\n\t\t\t\t\t\t\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\t\tObject.entries(object).map(([key, value]) => [\n\t\t\t\t\t\t\t\t\t\t\t\tkey === props.name ? name : key,\n\t\t\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\tinput.value = props.name\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<strong>{props.name}</strong>\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tactions={\n\t\t\t\t\tparent.change ? (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label={`Delete ${props.name}`}\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tparent.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tparent.change?.((previous) =>\n\t\t\t\t\t\t\t\t\t\tArray.isArray(previous)\n\t\t\t\t\t\t\t\t\t\t\t? previous.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t(_, index) => index !== Number(props.name),\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\t\t\t\tObject.entries(previous as object).filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t([key]) => key !== props.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t×\n\t\t\t\t\t\t</button>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t\ttools={parent.tools}\n\t\t\t\tpath={[...parent.path, props.name]}\n\t\t\t\tvalue={read()}\n\t\t\t\tchange={parent.change ? change : undefined}\n\t\t\t\tancestors={[...(parent.ancestors ?? []), parent.value]}\n\t\t\t/>\n\t\t</section>\n\t)\n}\n","import type { VNode } from \"@atom.io/spa\"\nimport { useSetter, useTimeline, useValue } from \"@atom.io/spa\"\nimport type {\n\tReadableToken,\n\tTimelineToken,\n\tTransactionToken,\n\tWritableToken,\n} from \"atom.io\"\nimport {\n\tdisposeFromStore,\n\tfindInStore,\n\tisReservedIntrospectionKey,\n} from \"atom.io/internal\"\nimport type { FamilyNode } from \"atom.io/introspection\"\n\nimport { JsonEditor } from \"./JsonEditor.tsx\"\nimport type { Tools } from \"./store.ts\"\nimport { useExpanded } from \"./store.ts\"\nimport { describe } from \"./value.ts\"\n\ntype Token = ReadableToken<unknown, any, any>\nexport function StateIndex(props: {\n\ttools: Tools\n\ttype: `atoms` | `selectors`\n}): VNode {\n\tconst index = useValue<Map<string, Token | FamilyNode<Token>>>(\n\t\tprops.type === `atoms` ? props.tools.atomIndex : props.tools.selectorIndex,\n\t)\n\treturn (\n\t\t<article class=\"index\" data-testid=\"state-index\">\n\t\t\t{index().size === 0 ? (\n\t\t\t\t<p>(no {props.type})</p>\n\t\t\t) : (\n\t\t\t\t[...index().values()].map((node) => (\n\t\t\t\t\t<StateNode key={node.key} tools={props.tools} node={node} />\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction StateNode(props: {\n\ttools: Tools\n\tnode: Token | FamilyNode<Token>\n}): VNode {\n\tconst [open, toggle] = useExpanded(props.tools, [props.node.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`state-${props.node.key}`}>\n\t\t\t{`familyMembers` in props.node ? (\n\t\t\t\t<>\n\t\t\t\t\t<header>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-expanded={open()}\n\t\t\t\t\t\t\tdata-testid={`open-close-state-family-${props.node.key}`}\n\t\t\t\t\t\t\tonClick={toggle}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{open() ? `▾` : `▸`}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<h2>{props.node.key}</h2>\n\t\t\t\t\t\t<small>family</small>\n\t\t\t\t\t</header>\n\t\t\t\t\t{open()\n\t\t\t\t\t\t? [...props.node.familyMembers.values()].map((token) => (\n\t\t\t\t\t\t\t\t<StateLeaf key={token.key} tools={props.tools} token={token} />\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t: null}\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<StateLeaf tools={props.tools} token={props.node} />\n\t\t\t)}\n\t\t</section>\n\t)\n}\nfunction StateLeaf(props: { tools: Tools; token: Token }): VNode {\n\tconst read = useValue(props.token)\n\tconst writable = !props.token.type.startsWith(`readonly`)\n\tconst set = writable\n\t\t? useSetter(props.token as WritableToken<unknown, any, any>)\n\t\t: undefined\n\tconst value = () => {\n\t\ttry {\n\t\t\treturn read()\n\t\t} catch (error) {\n\t\t\treturn error\n\t\t}\n\t}\n\treturn (\n\t\t<section class=\"state-leaf\" data-testid={`state-value-${props.token.key}`}>\n\t\t\t<JsonEditor\n\t\t\t\tlabel={<h3>{props.token.family?.subKey ?? props.token.key}</h3>}\n\t\t\t\tactions={\n\t\t\t\t\tprops.token.family ? (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label={`Dispose ${props.token.key}`}\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tdisposeFromStore(props.tools.store, props.token)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t×\n\t\t\t\t\t\t</button>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t\ttools={props.tools}\n\t\t\t\tvalue={value()}\n\t\t\t\tchange={\n\t\t\t\t\tset\n\t\t\t\t\t\t? (update) => {\n\t\t\t\t\t\t\t\t// Validate edits before opening an atom.io write operation.\n\t\t\t\t\t\t\t\tconst next = update(read())\n\t\t\t\t\t\t\t\tset(() => next)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tpath={\n\t\t\t\t\tprops.token.family\n\t\t\t\t\t\t? [props.token.family.key, props.token.family.subKey]\n\t\t\t\t\t\t: [props.token.key]\n\t\t\t\t}\n\t\t\t/>\n\t\t</section>\n\t)\n}\nexport function TransactionIndex(props: { tools: Tools }): VNode {\n\tconst index = useValue(props.tools.transactionIndex)\n\tconst visible = () =>\n\t\tindex().filter((token) => !isReservedIntrospectionKey(token.key))\n\treturn (\n\t\t<article class=\"index\" data-testid=\"transaction-index\">\n\t\t\t{visible().length === 0 ? (\n\t\t\t\t<p>(no transactions)</p>\n\t\t\t) : (\n\t\t\t\tvisible().map((token) => (\n\t\t\t\t\t<TransactionLog key={token.key} tools={props.tools} token={token} />\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction TransactionLog(props: {\n\ttools: Tools\n\ttoken: TransactionToken<any>\n}): VNode {\n\tconst log = useValue(\n\t\tfindInStore(\n\t\t\tprops.tools.store,\n\t\t\tprops.tools.transactionLogSelectors,\n\t\t\tprops.token.key,\n\t\t),\n\t)\n\tconst [open, toggle] = useExpanded(props.tools, [props.token.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`transaction-${props.token.key}`}>\n\t\t\t<header>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-expanded={open()}\n\t\t\t\t\tdata-testid={`open-close-transaction-${props.token.key}`}\n\t\t\t\t\tonClick={toggle}\n\t\t\t\t>\n\t\t\t\t\t{open() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<h2>{props.token.key}</h2>\n\t\t\t\t<small>({log().length})</small>\n\t\t\t</header>\n\t\t\t{open()\n\t\t\t\t? log().map((event, index) => (\n\t\t\t\t\t\t<EventView\n\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))\n\t\t\t\t: null}\n\t\t</section>\n\t)\n}\n// Events are recursive discriminated records, including user-defined transaction outputs.\nexport function EventView(props: {\n\ttools: Tools\n\tevent: any\n\tindex: number\n}): VNode {\n\tconst [open, toggle] = useExpanded(\n\t\tprops.tools,\n\t\t[`event`, props.event.token?.key ?? ``, String(props.index)],\n\t\ttrue,\n\t)\n\treturn (\n\t\t<section\n\t\t\tclass=\"event\"\n\t\t\tdata-testid={`${props.event.type === `transaction_outcome` ? `transaction` : `timeline`}-update-${props.event.token?.key}-${props.index}`}\n\t\t>\n\t\t\t<header>\n\t\t\t\t<button type=\"button\" aria-expanded={open()} onClick={toggle}>\n\t\t\t\t\t{open() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<strong>{props.event.token?.key}</strong>\n\t\t\t\t<small>{props.event.type}</small>\n\t\t\t</header>\n\t\t\t{open() ? (\n\t\t\t\tprops.event.type === `transaction_outcome` ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tparams: <code>{describe(props.event.params)}</code>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\toutput: <code>{describe(props.event.output)}</code>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<section class=\"impact\">\n\t\t\t\t\t\t\t{props.event.subEvents.map((event: any, index: number) => (\n\t\t\t\t\t\t\t\t<EventView\n\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</>\n\t\t\t\t) : props.event.update ? (\n\t\t\t\t\t<p>\n\t\t\t\t\t\t<del>{describe(props.event.update.oldValue)}</del> →{` `}\n\t\t\t\t\t\t<ins>{describe(props.event.update.newValue)}</ins>\n\t\t\t\t\t</p>\n\t\t\t\t) : (\n\t\t\t\t\t<code>{describe(props.event)}</code>\n\t\t\t\t)\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\nexport function TimelineIndex(props: { tools: Tools }): VNode {\n\tconst index = useValue(props.tools.timelineIndex)\n\tconst groups = () => {\n\t\tconst result = new Map<string, TimelineToken<any>[]>()\n\t\tfor (const token of index()) {\n\t\t\tif (isReservedIntrospectionKey(token.key) || token.key.startsWith(`👁‍🗨`))\n\t\t\t\tcontinue\n\t\t\tconst key = token.family?.key ?? ``\n\t\t\tconst members = result.get(key) ?? []\n\t\t\tmembers.push(token)\n\t\t\tresult.set(key, members)\n\t\t}\n\t\treturn [...result]\n\t}\n\treturn (\n\t\t<article class=\"index\" data-testid=\"timeline-index\">\n\t\t\t{groups().length === 0 ? (\n\t\t\t\t<p>(no timelines)</p>\n\t\t\t) : (\n\t\t\t\tgroups().map(([family, members]) => (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={family}\n\t\t\t\t\t\tdata-testid={family ? `timeline-family-${family}` : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t{family ? <h2>{family}</h2> : null}\n\t\t\t\t\t\t{members.map((token) => (\n\t\t\t\t\t\t\t<TimelineLog key={token.key} tools={props.tools} token={token} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</section>\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction TimelineLog(props: { tools: Tools; token: TimelineToken<any> }): VNode {\n\tconst controls = useTimeline(props.token)\n\tconst log = useValue(\n\t\tfindInStore(\n\t\t\tprops.tools.store,\n\t\t\tprops.tools.timelineSelectors,\n\t\t\tprops.token.key,\n\t\t),\n\t)\n\tconst [open, toggle] = useExpanded(props.tools, [props.token.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`timeline-${props.token.key}`}>\n\t\t\t<header>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-expanded={open()}\n\t\t\t\t\tdata-testid={`open-close-timeline-${props.token.key}`}\n\t\t\t\t\tonClick={toggle}\n\t\t\t\t>\n\t\t\t\t\t{open() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<h2>{props.token.family?.subKey ?? props.token.key}</h2>\n\t\t\t\t<small>\n\t\t\t\t\t({controls().at}/{controls().length})\n\t\t\t\t</small>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={controls().at === 0}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tprops.tools.attempt(controls().undo)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\tundo\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={controls().at === controls().length}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tprops.tools.attempt(controls().redo)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\tredo\n\t\t\t\t</button>\n\t\t\t</header>\n\t\t\t{open() ? (\n\t\t\t\t<section>\n\t\t\t\t\t{log().history.map((event, index) => (\n\t\t\t\t\t\t<section key={index}>\n\t\t\t\t\t\t\t{index === log().at ? (\n\t\t\t\t\t\t\t\t<p class=\"you-are-here\">you are here</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<EventView tools={props.tools} event={event} index={index} />\n\t\t\t\t\t\t</section>\n\t\t\t\t\t))}\n\t\t\t\t\t{log().at === log().history.length ? (\n\t\t\t\t\t\t<p class=\"you-are-here\">you are here</p>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\n","import type { VNode } from \"@atom.io/spa\"\nimport { onCleanup, onMount, render, useValue } from \"@atom.io/spa\"\nimport type { RootStore } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\n\nimport { StateIndex, TimelineIndex, TransactionIndex } from \"./Indexes.tsx\"\nimport { useLocal, useSaved, useTools } from \"./store.ts\"\n\nexport interface AtomIODevtoolsProps {\n\t/** Inspected store. Fixed for this component instance; change its key to replace it. */\n\tstore?: RootStore\n\thideByDefault?: boolean\n}\n/** Owns a rendering root in the inspected store, independently of its parent island. */\nexport function AtomIODevtools(props: AtomIODevtoolsProps): VNode {\n\tlet host: HTMLElement | null = null\n\tconst attach = (element: HTMLElement | null) => {\n\t\thost = element\n\t}\n\tonMount(() => {\n\t\tconst store = props.store ?? IMPLICIT.STORE\n\t\tconst root = render(\n\t\t\t() => <Panel store={store} hideByDefault={props.hideByDefault ?? false} />,\n\t\t\thost!,\n\t\t\t{ store },\n\t\t)\n\t\tonCleanup(root.dispose)\n\t})\n\treturn <spa-devtools ref={attach} />\n}\nconst VIEWS = [`atoms`, `selectors`, `transactions`, `timelines`] as const\ntype View = (typeof VIEWS)[number]\nfunction Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {\n\tconst tools = useTools(props.store)\n\tconst [hidden, setHidden] = useSaved(\n\t\tprops.store,\n\t\t`🔍 Devtools Are Hidden`,\n\t\tprops.hideByDefault,\n\t)\n\tconst [open, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true)\n\tconst [selection, setSelection] = useSaved<string>(\n\t\tprops.store,\n\t\t`🔍 Devtools View`,\n\t\t`atoms`,\n\t)\n\tconst view = () =>\n\t\tVIEWS.includes(selection() as View) ? (selection() as View) : `atoms`\n\tconst [position, setPosition] = useLocal(props.store, { x: 0, y: 0 })\n\tconst error = useValue(tools.error)\n\tlet panel: HTMLElement | null = null\n\tconst attach = (element: HTMLElement | null) => {\n\t\tpanel = element\n\t}\n\tlet drag:\n\t\t| { id: number; startX: number; startY: number; x: number; y: number }\n\t\t| undefined\n\tonMount(() => {\n\t\tconst shortcut = (event: KeyboardEvent) => {\n\t\t\tif (event.ctrlKey && event.shiftKey && event.code === `KeyA`) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tsetHidden((value) => !value)\n\t\t\t}\n\t\t}\n\t\tconst reset = () => {\n\t\t\tsetPosition({ x: 0, y: 0 })\n\t\t}\n\t\tdocument.addEventListener(`keydown`, shortcut)\n\t\twindow.addEventListener(`resize`, reset)\n\t\tonCleanup(() => {\n\t\t\tdocument.removeEventListener(`keydown`, shortcut)\n\t\t\twindow.removeEventListener(`resize`, reset)\n\t\t})\n\t})\n\treturn (\n\t\t<main\n\t\t\tref={attach}\n\t\t\tdata-css=\"spa-devtools\"\n\t\t\tdata-testid=\"atom-io-devtools\"\n\t\t\thidden={hidden()}\n\t\t\tdata-open={open()}\n\t\t\tstyle={`transform:translate(${position().x}px,${position().y}px)`}\n\t\t>\n\t\t\t<header class=\"toolbar\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"drag-handle\"\n\t\t\t\t\taria-label=\"Move debugger\"\n\t\t\t\t\ttitle=\"Drag to move; arrow keys to nudge\"\n\t\t\t\t\tonPointerdown={(event) => {\n\t\t\t\t\t\tif (event.button !== 0) return\n\t\t\t\t\t\tdrag = {\n\t\t\t\t\t\t\tid: event.pointerId,\n\t\t\t\t\t\t\tstartX: event.clientX,\n\t\t\t\t\t\t\tstartY: event.clientY,\n\t\t\t\t\t\t\t...position(),\n\t\t\t\t\t\t}\n\t\t\t\t\t\t;(event.currentTarget as HTMLElement).setPointerCapture(\n\t\t\t\t\t\t\tevent.pointerId,\n\t\t\t\t\t\t)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointermove={(event) => {\n\t\t\t\t\t\tif (!drag || drag.id !== event.pointerId || !panel) return\n\t\t\t\t\t\tconst rect = panel.getBoundingClientRect()\n\t\t\t\t\t\tconst next = {\n\t\t\t\t\t\t\tx: drag.x + event.clientX - drag.startX,\n\t\t\t\t\t\t\ty: drag.y + event.clientY - drag.startY,\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnext.x = Math.max(\n\t\t\t\t\t\t\tposition().x - rect.left,\n\t\t\t\t\t\t\tMath.min(next.x, position().x + window.innerWidth - rect.right),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tnext.y = Math.max(\n\t\t\t\t\t\t\tposition().y - rect.top,\n\t\t\t\t\t\t\tMath.min(next.y, position().y + window.innerHeight - rect.bottom),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsetPosition(next)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointerup={() => {\n\t\t\t\t\t\tdrag = undefined\n\t\t\t\t\t}}\n\t\t\t\t\tonPointercancel={() => {\n\t\t\t\t\t\tdrag = undefined\n\t\t\t\t\t}}\n\t\t\t\t\tonKeydown={(event) => {\n\t\t\t\t\t\tconst step = {\n\t\t\t\t\t\t\tArrowLeft: [-10, 0],\n\t\t\t\t\t\t\tArrowRight: [10, 0],\n\t\t\t\t\t\t\tArrowUp: [0, -10],\n\t\t\t\t\t\t\tArrowDown: [0, 10],\n\t\t\t\t\t\t}[event.key]\n\t\t\t\t\t\tif (step) {\n\t\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\t\tsetPosition(({ x, y }) => ({ x: x + step[0], y: y + step[1] }))\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t⠿\n\t\t\t\t</button>\n\t\t\t\t<h1>atom.io</h1>\n\t\t\t\t{open() ? (\n\t\t\t\t\t<nav aria-label=\"Debugger views\">\n\t\t\t\t\t\t{VIEWS.map((name) => (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\taria-pressed={view() === name}\n\t\t\t\t\t\t\t\tdata-testid={`view-${name}`}\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tsetSelection(name)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</nav>\n\t\t\t\t) : null}\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label={open() ? `Minimize debugger` : `Open debugger`}\n\t\t\t\t\tdata-testid=\"open-close-devtools\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetOpen((value) => !value)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{open() ? `−` : `🔍`}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide debugger (Ctrl+Shift+A)\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetHidden(true)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</header>\n\t\t\t{open() ? (\n\t\t\t\t<>\n\t\t\t\t\t{error() ? <p role=\"alert\">{error()}</p> : null}\n\t\t\t\t\t{view() === `atoms` || view() === `selectors` ? (\n\t\t\t\t\t\t<StateIndex\n\t\t\t\t\t\t\tkey={view()}\n\t\t\t\t\t\t\ttools={tools}\n\t\t\t\t\t\t\ttype={view() as `atoms` | `selectors`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : view() === `transactions` ? (\n\t\t\t\t\t\t<TransactionIndex tools={tools} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<TimelineIndex tools={tools} />\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t</main>\n\t)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_spa","_spa","_spa"],"sources":["../src/store.ts","../src/value.ts","../src/JsonEditor.tsx","../src/Indexes.tsx","../src/AtomIODevtools.tsx"],"sourcesContent":["import type { Accessor } from \"@atom.io/spa\"\nimport { onCleanup, useGetter, useId, useSetter } from \"@atom.io/spa\"\nimport type { RegularAtomFamilyToken, RegularAtomToken, Setter } from \"atom.io\"\nimport type { RootStore } from \"atom.io/internal\"\nimport {\n\tcreateRegularAtomFamily,\n\tdisposeFromStore,\n\tfindInStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport type { IntrospectionStates } from \"atom.io/introspection\"\nimport { attachIntrospectionStates } from \"atom.io/introspection\"\n\nconst locals = new WeakMap<RootStore, RegularAtomFamilyToken<unknown, string>>()\nconst introspection = new WeakMap<RootStore, IntrospectionStates>()\nexport type Path = readonly string[]\nexport interface Tools extends IntrospectionStates {\n\tstore: RootStore\n\texpanded: RegularAtomToken<Record<string, boolean>>\n\terror: RegularAtomToken<string>\n\tattempt(run: () => void): void\n}\n\nexport function ownedAtom<T>(store: RootStore, initial: T): RegularAtomToken<T> {\n\tlet family = locals.get(store)\n\tif (!family) {\n\t\tfamily = createRegularAtomFamily<unknown, string, never>(store, {\n\t\t\tkey: `🔍 spa devtools`,\n\t\t\tdefault: undefined,\n\t\t})\n\t\tlocals.set(store, family)\n\t}\n\tconst token = findInStore(store, family, useId()) as RegularAtomToken<T>\n\tsetIntoStore(store, token, initial)\n\tonCleanup(() => {\n\t\tdisposeFromStore(store, token)\n\t})\n\treturn token\n}\nexport function useLocal<T>(\n\tstore: RootStore,\n\tinitial: T,\n): [Accessor<T>, (next: T | Setter<T>) => void] {\n\tconst token = ownedAtom(store, initial)\n\treturn [useGetter(token) as Accessor<T>, useSetter(token)]\n}\nexport function useSaved<T>(\n\tstore: RootStore,\n\tkey: string,\n\tfallback: T,\n): [Accessor<T>, (next: T | Setter<T>) => void] {\n\tlet initial = fallback\n\ttry {\n\t\tconst saved: unknown = JSON.parse(localStorage.getItem(key) ?? `null`)\n\t\tif (saved !== null && typeof saved === typeof fallback) initial = saved as T\n\t} catch {\n\t\t/* Storage may be unavailable. */\n\t}\n\tconst [getValue, setValue] = useLocal(store, initial)\n\treturn [\n\t\tgetValue,\n\t\t(next) => {\n\t\t\tsetValue(next)\n\t\t\ttry {\n\t\t\t\tlocalStorage.setItem(key, JSON.stringify(getValue()))\n\t\t\t} catch {\n\t\t\t\t/* Keep in-memory state when storage is unavailable. */\n\t\t\t}\n\t\t},\n\t]\n}\nexport function useTools(store: RootStore): Tools {\n\tlet states = introspection.get(store)\n\tif (!states) {\n\t\tstates = attachIntrospectionStates(store)\n\t\tintrospection.set(store, states)\n\t}\n\tlet expanded: Record<string, boolean> = {}\n\ttry {\n\t\tconst saved: unknown = JSON.parse(\n\t\t\tlocalStorage.getItem(`🔍 spa expanded`) ?? `{}`,\n\t\t)\n\t\tif (\n\t\t\tsaved &&\n\t\t\ttypeof saved === `object` &&\n\t\t\t!Array.isArray(saved) &&\n\t\t\tObject.values(saved).every((value) => typeof value === `boolean`)\n\t\t)\n\t\t\texpanded = saved as Record<string, boolean>\n\t} catch {\n\t\t/* Ignore corrupt or unavailable storage. */\n\t}\n\tconst error = ownedAtom(store, ``)\n\tconst setError = useSetter(error)\n\treturn {\n\t\t...states,\n\t\tstore,\n\t\terror,\n\t\texpanded: ownedAtom(store, expanded),\n\t\tattempt(run) {\n\t\t\ttry {\n\t\t\t\trun()\n\t\t\t\tsetError(``)\n\t\t\t} catch (caught) {\n\t\t\t\tsetError(caught instanceof Error ? caught.message : String(caught))\n\t\t\t}\n\t\t},\n\t}\n}\nexport function useExpanded(\n\ttools: Tools,\n\tpath: Path,\n\tinitial = false,\n): [Accessor<boolean>, (event: MouseEvent) => void] {\n\tconst getExpanded = useGetter(tools.expanded)\n\tconst setExpanded = useSetter(tools.expanded)\n\tconst key = JSON.stringify(path)\n\tconst group = `all:${JSON.stringify(path.slice(0, -1))}`\n\tconst read = () => getExpanded()[key] ?? getExpanded()[group] ?? initial\n\treturn [\n\t\tread,\n\t\t(event) => {\n\t\t\tconst next = !read()\n\t\t\tsetExpanded((previous) => {\n\t\t\t\tconst result = { ...previous }\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tconst parent = JSON.stringify(path.slice(0, -1))\n\t\t\t\t\tfor (const item of Object.keys(result)) {\n\t\t\t\t\t\tif (item.startsWith(`[`)) {\n\t\t\t\t\t\t\tconst candidate = JSON.parse(item) as string[]\n\t\t\t\t\t\t\tif (JSON.stringify(candidate.slice(0, -1)) === parent)\n\t\t\t\t\t\t\t\tReflect.deleteProperty(result, item)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresult[group] = next\n\t\t\t\t} else {\n\t\t\t\t\tresult[key] = next\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tlocalStorage.setItem(`🔍 spa expanded`, JSON.stringify(result))\n\t\t\t\t} catch {\n\t\t\t\t\t/* Keep in-memory expansion state. */\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t})\n\t\t},\n\t]\n}\n","export type Change = (update: (previous: unknown) => unknown) => void\nexport type JsonKind =\n\t| `string`\n\t| `number`\n\t| `boolean`\n\t| `null`\n\t| `array`\n\t| `object`\nexport function kind(value: unknown): JsonKind | `other` {\n\tif (value === null) return `null`\n\tif (Array.isArray(value)) return `array`\n\tif (\n\t\ttypeof value === `object` &&\n\t\t(Object.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null)\n\t)\n\t\treturn `object`\n\tif (\n\t\ttypeof value === `string` ||\n\t\ttypeof value === `number` ||\n\t\ttypeof value === `boolean`\n\t)\n\t\treturn typeof value as JsonKind\n\treturn `other`\n}\nexport function describe(value: unknown): string {\n\ttry {\n\t\tconst seen = new WeakSet<object>()\n\t\treturn (\n\t\t\tJSON.stringify(value, (_, item: unknown) => {\n\t\t\t\tif (typeof item === `bigint`) return `${item}n`\n\t\t\t\tif (item instanceof Error) return `${item.name}: ${item.message}`\n\t\t\t\tif (item instanceof Map) return { Map: [...item] }\n\t\t\t\tif (item instanceof Set) return { Set: [...item] }\n\t\t\t\tif (typeof item === `object` && item !== null) {\n\t\t\t\t\tif (seen.has(item)) return `[Circular]`\n\t\t\t\t\tseen.add(item)\n\t\t\t\t}\n\t\t\t\treturn item\n\t\t\t}) ?? String(value)\n\t\t)\n\t} catch {\n\t\treturn Object.prototype.toString.call(value)\n\t}\n}\nexport function convert(value: unknown, type: JsonKind): unknown {\n\tswitch (type) {\n\t\tcase `null`:\n\t\t\treturn null\n\t\tcase `string`:\n\t\t\treturn value == null\n\t\t\t\t? ``\n\t\t\t\t: typeof value === `string`\n\t\t\t\t\t? value\n\t\t\t\t\t: describe(value)\n\t\tcase `number`: {\n\t\t\tconst next = Array.isArray(value) ? value.length : Number(value)\n\t\t\treturn Number.isFinite(next) ? next : 0\n\t\t}\n\t\tcase `boolean`:\n\t\t\treturn typeof value === `string` ? value === `true` : Boolean(value)\n\t\tcase `array`:\n\t\t\treturn Array.isArray(value)\n\t\t\t\t? value\n\t\t\t\t: value == null\n\t\t\t\t\t? []\n\t\t\t\t\t: typeof value === `object`\n\t\t\t\t\t\t? Object.entries(value)\n\t\t\t\t\t\t: [value]\n\t\tcase `object`:\n\t\t\treturn kind(value) === `object`\n\t\t\t\t? value\n\t\t\t\t: Array.isArray(value)\n\t\t\t\t\t? Object.fromEntries(value.map((item, index) => [index, item]))\n\t\t\t\t\t: value == null\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { value }\n\t}\n}\n","import type { Child, VNode } from \"@atom.io/spa\"\n\nimport type { Path, Tools } from \"./store.ts\"\nimport { useExpanded } from \"./store.ts\"\nimport type { Change, JsonKind } from \"./value.ts\"\nimport { convert, describe, kind } from \"./value.ts\"\n\ninterface EditorProps {\n\ttools: Tools\n\tvalue: unknown\n\tchange?: Change | undefined\n\tpath: Path\n\tancestors?: readonly unknown[]\n\tlabel?: Child\n\tactions?: Child\n}\nconst TYPES: JsonKind[] = [\n\t`string`,\n\t`number`,\n\t`boolean`,\n\t`null`,\n\t`array`,\n\t`object`,\n]\nexport function JsonEditor(props: EditorProps): VNode {\n\tconst [getExpanded, toggle] = useExpanded(props.tools, props.path)\n\tconst circular = () =>\n\t\t(props.ancestors?.includes(props.value) ?? false) || props.path.length > 50\n\tconst container = () =>\n\t\t!circular() &&\n\t\t(kind(props.value) === `object` || kind(props.value) === `array`)\n\tconst entries = () => Object.entries(props.value as Record<string, unknown>)\n\treturn (\n\t\t<section\n\t\t\tclass=\"json-editor\"\n\t\t\tdata-testid={`${props.path.join(`.`)}-state-editor`}\n\t\t>\n\t\t\t<header>\n\t\t\t\t{container() ? (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label={`Expand ${props.path.at(-1)}`}\n\t\t\t\t\t\taria-expanded={getExpanded()}\n\t\t\t\t\t\tonClick={toggle}\n\t\t\t\t\t>\n\t\t\t\t\t\t{getExpanded() ? `▾` : `▸`}\n\t\t\t\t\t</button>\n\t\t\t\t) : (\n\t\t\t\t\t<span class=\"carat-spacer\" />\n\t\t\t\t)}\n\t\t\t\t<span class=\"field-name\">{props.label}</span>\n\t\t\t\t{props.change ? (\n\t\t\t\t\t<select\n\t\t\t\t\t\taria-label={`Type of ${props.path.at(-1)}`}\n\t\t\t\t\t\tvalue={kind(props.value)}\n\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\tconst type = event.currentTarget.value as JsonKind\n\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\tprops.change?.((previous) => convert(previous, type))\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<option value=\"other\" disabled>\n\t\t\t\t\t\t\tother\n\t\t\t\t\t\t</option>\n\t\t\t\t\t\t{TYPES.map((type) => (\n\t\t\t\t\t\t\t<option value={type}>{type}</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t) : (\n\t\t\t\t\t<small>{kind(props.value)}</small>\n\t\t\t\t)}\n\t\t\t\t{container() ? (\n\t\t\t\t\t<code title={describe(props.value)}>{describe(props.value)}</code>\n\t\t\t\t) : circular() ? (\n\t\t\t\t\t<code>[Circular]</code>\n\t\t\t\t) : (\n\t\t\t\t\t<Primitive\n\t\t\t\t\t\tvalue={props.value}\n\t\t\t\t\t\tchange={props.change}\n\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\tlabel={props.path.at(-1) ?? `value`}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{props.actions}\n\t\t\t</header>\n\t\t\t{container() && getExpanded() ? (\n\t\t\t\t<section class=\"properties\">\n\t\t\t\t\t{entries().map(([key]) => (\n\t\t\t\t\t\t<Property key={key} name={key} editor={props} />\n\t\t\t\t\t))}\n\t\t\t\t\t{props.change ? (\n\t\t\t\t\t\t<footer>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\t\tprops.change?.((previous) => {\n\t\t\t\t\t\t\t\t\t\t\tif (Array.isArray(previous)) return [...previous, null]\n\t\t\t\t\t\t\t\t\t\t\tconst object = previous as Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\t\tlet name = `new`\n\t\t\t\t\t\t\t\t\t\t\twhile (Object.hasOwn(object, name)) name += `_`\n\t\t\t\t\t\t\t\t\t\t\treturn { ...object, [name]: null }\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tadd {Array.isArray(props.value) ? `item` : `property`}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t{Array.isArray(props.value) ? (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\t\t\tprops.change?.((previous) =>\n\t\t\t\t\t\t\t\t\t\t\t\t[...(previous as unknown[])].sort((a, b) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\ttypeof a === `number` && typeof b === `number`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? a - b\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: describe(a).localeCompare(describe(b)),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tsort\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</footer>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\nfunction Primitive(props: {\n\tvalue: unknown\n\tchange?: Change | undefined\n\ttools: Tools\n\tlabel: string\n}): VNode {\n\tconst set = (value: unknown) => {\n\t\tprops.tools.attempt(() => {\n\t\t\tprops.change?.(() => value)\n\t\t})\n\t}\n\treturn (\n\t\t<span class=\"primitive\">\n\t\t\t{kind(props.value) === `boolean` ? (\n\t\t\t\t<input\n\t\t\t\t\taria-label={props.label}\n\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\tchecked={Boolean(props.value)}\n\t\t\t\t\tdisabled={!props.change}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tset(event.currentTarget.checked)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : kind(props.value) === `string` || kind(props.value) === `number` ? (\n\t\t\t\t<input\n\t\t\t\t\taria-label={props.label}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tinputmode={kind(props.value) === `number` ? `decimal` : `text`}\n\t\t\t\t\tvalue={String(props.value)}\n\t\t\t\t\treadOnly={!props.change}\n\t\t\t\t\tonInput={(event) => {\n\t\t\t\t\t\tconst text = event.currentTarget.value\n\t\t\t\t\t\tif (kind(props.value) === `string`) set(text)\n\t\t\t\t\t\telse if (text.trim() && Number.isFinite(Number(text)))\n\t\t\t\t\t\t\tset(Number(text))\n\t\t\t\t\t}}\n\t\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t\tevent.currentTarget.value = String(props.value)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<code>{describe(props.value)}</code>\n\t\t\t)}\n\t\t</span>\n\t)\n}\nfunction Property(props: { name: string; editor: EditorProps }): VNode {\n\tconst parent = props.editor\n\tconst read = () => (parent.value as Record<string, unknown>)[props.name]\n\tconst change: Change = (update) => {\n\t\tparent.change?.((previous) => {\n\t\t\tif (Array.isArray(previous))\n\t\t\t\treturn previous.map((value, index) =>\n\t\t\t\t\tindex === Number(props.name) ? update(value) : value,\n\t\t\t\t)\n\t\t\tconst object = previous as Record<string, unknown>\n\t\t\treturn { ...object, [props.name]: update(object[props.name]) }\n\t\t})\n\t}\n\treturn (\n\t\t<section class=\"property\">\n\t\t\t<JsonEditor\n\t\t\t\tlabel={\n\t\t\t\t\tparent.change && !Array.isArray(parent.value) ? (\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\taria-label={`Rename ${props.name}`}\n\t\t\t\t\t\t\tstyle={`width:calc(${Math.max(1, props.name.length)}ch + 6px)`}\n\t\t\t\t\t\t\tvalue={props.name}\n\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\tconst input = event.currentTarget\n\t\t\t\t\t\t\t\tconst name = input.value\n\t\t\t\t\t\t\t\tparent.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tparent.change?.((previous) => {\n\t\t\t\t\t\t\t\t\t\tconst object = previous as Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\tif (name !== props.name && Object.hasOwn(object, name))\n\t\t\t\t\t\t\t\t\t\t\tthrow new Error(`Property \"${name}\" already exists`)\n\t\t\t\t\t\t\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\t\tObject.entries(object).map(([key, value]) => [\n\t\t\t\t\t\t\t\t\t\t\t\tkey === props.name ? name : key,\n\t\t\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\tinput.value = props.name\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<strong>{props.name}</strong>\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tactions={\n\t\t\t\t\tparent.change ? (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label={`Delete ${props.name}`}\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tparent.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tparent.change?.((previous) =>\n\t\t\t\t\t\t\t\t\t\tArray.isArray(previous)\n\t\t\t\t\t\t\t\t\t\t\t? previous.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t(_, index) => index !== Number(props.name),\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\t\t\t\tObject.entries(previous as object).filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t([key]) => key !== props.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t×\n\t\t\t\t\t\t</button>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t\ttools={parent.tools}\n\t\t\t\tpath={[...parent.path, props.name]}\n\t\t\t\tvalue={read()}\n\t\t\t\tchange={parent.change ? change : undefined}\n\t\t\t\tancestors={[...(parent.ancestors ?? []), parent.value]}\n\t\t\t/>\n\t\t</section>\n\t)\n}\n","import type { VNode } from \"@atom.io/spa\"\nimport { useGetter, useSetter, useTimeline } from \"@atom.io/spa\"\nimport type {\n\tReadableToken,\n\tTimelineToken,\n\tTransactionToken,\n\tWritableToken,\n} from \"atom.io\"\nimport {\n\tdisposeFromStore,\n\tfindInStore,\n\tisReservedIntrospectionKey,\n} from \"atom.io/internal\"\nimport type { FamilyNode } from \"atom.io/introspection\"\n\nimport { JsonEditor } from \"./JsonEditor.tsx\"\nimport type { Tools } from \"./store.ts\"\nimport { useExpanded } from \"./store.ts\"\nimport { describe } from \"./value.ts\"\n\ntype Token = ReadableToken<unknown, any, any>\nexport function StateIndex(props: {\n\ttools: Tools\n\ttype: `atoms` | `selectors`\n}): VNode {\n\tconst getStateIndex = useGetter<Map<string, Token | FamilyNode<Token>>>(\n\t\tprops.type === `atoms` ? props.tools.atomIndex : props.tools.selectorIndex,\n\t)\n\treturn (\n\t\t<article class=\"index\" data-testid=\"state-index\">\n\t\t\t{getStateIndex().size === 0 ? (\n\t\t\t\t<p>(no {props.type})</p>\n\t\t\t) : (\n\t\t\t\t[...getStateIndex().values()].map((node) => (\n\t\t\t\t\t<StateNode key={node.key} tools={props.tools} node={node} />\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction StateNode(props: {\n\ttools: Tools\n\tnode: Token | FamilyNode<Token>\n}): VNode {\n\tconst [getOpen, toggle] = useExpanded(props.tools, [props.node.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`state-${props.node.key}`}>\n\t\t\t{`familyMembers` in props.node ? (\n\t\t\t\t<>\n\t\t\t\t\t<header>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-expanded={getOpen()}\n\t\t\t\t\t\t\tdata-testid={`open-close-state-family-${props.node.key}`}\n\t\t\t\t\t\t\tonClick={toggle}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{getOpen() ? `▾` : `▸`}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<h2>{props.node.key}</h2>\n\t\t\t\t\t\t<small>family</small>\n\t\t\t\t\t</header>\n\t\t\t\t\t{getOpen()\n\t\t\t\t\t\t? [...props.node.familyMembers.values()].map((token) => (\n\t\t\t\t\t\t\t\t<StateLeaf key={token.key} tools={props.tools} token={token} />\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t: null}\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<StateLeaf tools={props.tools} token={props.node} />\n\t\t\t)}\n\t\t</section>\n\t)\n}\nfunction StateLeaf(props: { tools: Tools; token: Token }): VNode {\n\tconst getValue = useGetter(props.token)\n\tconst writable = !props.token.type.startsWith(`readonly`)\n\tconst setValue = writable\n\t\t? useSetter(props.token as WritableToken<unknown, any, any>)\n\t\t: undefined\n\tconst value = () => {\n\t\ttry {\n\t\t\treturn getValue()\n\t\t} catch (error) {\n\t\t\treturn error\n\t\t}\n\t}\n\treturn (\n\t\t<section class=\"state-leaf\" data-testid={`state-value-${props.token.key}`}>\n\t\t\t<JsonEditor\n\t\t\t\tlabel={<h3>{props.token.family?.subKey ?? props.token.key}</h3>}\n\t\t\t\tactions={\n\t\t\t\t\tprops.token.family ? (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label={`Dispose ${props.token.key}`}\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tprops.tools.attempt(() => {\n\t\t\t\t\t\t\t\t\tdisposeFromStore(props.tools.store, props.token)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t×\n\t\t\t\t\t\t</button>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t\ttools={props.tools}\n\t\t\t\tvalue={value()}\n\t\t\t\tchange={\n\t\t\t\t\tsetValue\n\t\t\t\t\t\t? (update) => {\n\t\t\t\t\t\t\t\t// Validate edits before opening an atom.io write operation.\n\t\t\t\t\t\t\t\tconst next = update(getValue())\n\t\t\t\t\t\t\t\tsetValue(() => next)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tpath={\n\t\t\t\t\tprops.token.family\n\t\t\t\t\t\t? [props.token.family.key, props.token.family.subKey]\n\t\t\t\t\t\t: [props.token.key]\n\t\t\t\t}\n\t\t\t/>\n\t\t</section>\n\t)\n}\nexport function TransactionIndex(props: { tools: Tools }): VNode {\n\tconst getTransactionIndex = useGetter(props.tools.transactionIndex)\n\tconst visible = () =>\n\t\tgetTransactionIndex().filter(\n\t\t\t(token) => !isReservedIntrospectionKey(token.key),\n\t\t)\n\treturn (\n\t\t<article class=\"index\" data-testid=\"transaction-index\">\n\t\t\t{visible().length === 0 ? (\n\t\t\t\t<p>(no transactions)</p>\n\t\t\t) : (\n\t\t\t\tvisible().map((token) => (\n\t\t\t\t\t<TransactionLog key={token.key} tools={props.tools} token={token} />\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction TransactionLog(props: {\n\ttools: Tools\n\ttoken: TransactionToken<any>\n}): VNode {\n\tconst getTransactionLog = useGetter(\n\t\tfindInStore(\n\t\t\tprops.tools.store,\n\t\t\tprops.tools.transactionLogSelectors,\n\t\t\tprops.token.key,\n\t\t),\n\t)\n\tconst [getOpen, toggle] = useExpanded(props.tools, [props.token.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`transaction-${props.token.key}`}>\n\t\t\t<header>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-expanded={getOpen()}\n\t\t\t\t\tdata-testid={`open-close-transaction-${props.token.key}`}\n\t\t\t\t\tonClick={toggle}\n\t\t\t\t>\n\t\t\t\t\t{getOpen() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<h2>{props.token.key}</h2>\n\t\t\t\t<small>({getTransactionLog().length})</small>\n\t\t\t</header>\n\t\t\t{getOpen()\n\t\t\t\t? getTransactionLog().map((event, index) => (\n\t\t\t\t\t\t<EventView\n\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))\n\t\t\t\t: null}\n\t\t</section>\n\t)\n}\n// Events are recursive discriminated records, including user-defined transaction outputs.\nexport function EventView(props: {\n\ttools: Tools\n\tevent: any\n\tindex: number\n}): VNode {\n\tconst [getOpen, toggle] = useExpanded(\n\t\tprops.tools,\n\t\t[`event`, props.event.token?.key ?? ``, String(props.index)],\n\t\ttrue,\n\t)\n\treturn (\n\t\t<section\n\t\t\tclass=\"event\"\n\t\t\tdata-testid={`${props.event.type === `transaction_outcome` ? `transaction` : `timeline`}-update-${props.event.token?.key}-${props.index}`}\n\t\t>\n\t\t\t<header>\n\t\t\t\t<button type=\"button\" aria-expanded={getOpen()} onClick={toggle}>\n\t\t\t\t\t{getOpen() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<strong>{props.event.token?.key}</strong>\n\t\t\t\t<small>{props.event.type}</small>\n\t\t\t</header>\n\t\t\t{getOpen() ? (\n\t\t\t\tprops.event.type === `transaction_outcome` ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tparams: <code>{describe(props.event.params)}</code>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\toutput: <code>{describe(props.event.output)}</code>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<section class=\"impact\">\n\t\t\t\t\t\t\t{props.event.subEvents.map((event: any, index: number) => (\n\t\t\t\t\t\t\t\t<EventView\n\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\ttools={props.tools}\n\t\t\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</>\n\t\t\t\t) : props.event.update ? (\n\t\t\t\t\t<p>\n\t\t\t\t\t\t<del>{describe(props.event.update.oldValue)}</del> →{` `}\n\t\t\t\t\t\t<ins>{describe(props.event.update.newValue)}</ins>\n\t\t\t\t\t</p>\n\t\t\t\t) : (\n\t\t\t\t\t<code>{describe(props.event)}</code>\n\t\t\t\t)\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\nexport function TimelineIndex(props: { tools: Tools }): VNode {\n\tconst getTimelineIndex = useGetter(props.tools.timelineIndex)\n\tconst groups = () => {\n\t\tconst result = new Map<string, TimelineToken<any>[]>()\n\t\tfor (const token of getTimelineIndex()) {\n\t\t\tif (isReservedIntrospectionKey(token.key) || token.key.startsWith(`👁‍🗨`))\n\t\t\t\tcontinue\n\t\t\tconst key = token.family?.key ?? ``\n\t\t\tconst members = result.get(key) ?? []\n\t\t\tmembers.push(token)\n\t\t\tresult.set(key, members)\n\t\t}\n\t\treturn [...result]\n\t}\n\treturn (\n\t\t<article class=\"index\" data-testid=\"timeline-index\">\n\t\t\t{groups().length === 0 ? (\n\t\t\t\t<p>(no timelines)</p>\n\t\t\t) : (\n\t\t\t\tgroups().map(([family, members]) => (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={family}\n\t\t\t\t\t\tdata-testid={family ? `timeline-family-${family}` : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t{family ? <h2>{family}</h2> : null}\n\t\t\t\t\t\t{members.map((token) => (\n\t\t\t\t\t\t\t<TimelineLog key={token.key} tools={props.tools} token={token} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</section>\n\t\t\t\t))\n\t\t\t)}\n\t\t</article>\n\t)\n}\nfunction TimelineLog(props: { tools: Tools; token: TimelineToken<any> }): VNode {\n\tconst controls = useTimeline(props.token)\n\tconst getTimeline = useGetter(\n\t\tfindInStore(\n\t\t\tprops.tools.store,\n\t\t\tprops.tools.timelineSelectors,\n\t\t\tprops.token.key,\n\t\t),\n\t)\n\tconst [getOpen, toggle] = useExpanded(props.tools, [props.token.key])\n\treturn (\n\t\t<section class=\"node\" data-testid={`timeline-${props.token.key}`}>\n\t\t\t<header>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-expanded={getOpen()}\n\t\t\t\t\tdata-testid={`open-close-timeline-${props.token.key}`}\n\t\t\t\t\tonClick={toggle}\n\t\t\t\t>\n\t\t\t\t\t{getOpen() ? `▾` : `▸`}\n\t\t\t\t</button>\n\t\t\t\t<h2>{props.token.family?.subKey ?? props.token.key}</h2>\n\t\t\t\t<small>\n\t\t\t\t\t({controls.getCursor()}/{controls.getLength()})\n\t\t\t\t</small>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={controls.getCursor() === 0}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tprops.tools.attempt(controls.undo)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\tundo\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={controls.getCursor() === controls.getLength()}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tprops.tools.attempt(controls.redo)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\tredo\n\t\t\t\t</button>\n\t\t\t</header>\n\t\t\t{getOpen() ? (\n\t\t\t\t<section>\n\t\t\t\t\t{getTimeline().history.map((event, index) => (\n\t\t\t\t\t\t<section key={index}>\n\t\t\t\t\t\t\t{index === getTimeline().at ? (\n\t\t\t\t\t\t\t\t<p class=\"you-are-here\">you are here</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<EventView tools={props.tools} event={event} index={index} />\n\t\t\t\t\t\t</section>\n\t\t\t\t\t))}\n\t\t\t\t\t{getTimeline().at === getTimeline().history.length ? (\n\t\t\t\t\t\t<p class=\"you-are-here\">you are here</p>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t) : null}\n\t\t</section>\n\t)\n}\n","import type { VNode } from \"@atom.io/spa\"\nimport { onCleanup, onMount, render, useGetter } from \"@atom.io/spa\"\nimport type { RootStore } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\n\nimport { StateIndex, TimelineIndex, TransactionIndex } from \"./Indexes.tsx\"\nimport { useLocal, useSaved, useTools } from \"./store.ts\"\n\nexport interface AtomIODevtoolsProps {\n\t/** Inspected store. Fixed for this component instance; change its key to replace it. */\n\tstore?: RootStore\n\thideByDefault?: boolean\n}\n/** Owns a rendering root in the inspected store, independently of its parent island. */\nexport function AtomIODevtools(props: AtomIODevtoolsProps): VNode {\n\tlet host: HTMLElement | null = null\n\tconst attach = (element: HTMLElement | null) => {\n\t\thost = element\n\t}\n\tonMount(() => {\n\t\tconst store = props.store ?? IMPLICIT.STORE\n\t\tconst root = render(\n\t\t\t() => <Panel store={store} hideByDefault={props.hideByDefault ?? false} />,\n\t\t\thost!,\n\t\t\t{ store },\n\t\t)\n\t\tonCleanup(root.dispose)\n\t})\n\treturn <spa-devtools ref={attach} />\n}\nconst VIEWS = [`atoms`, `selectors`, `transactions`, `timelines`] as const\ntype View = (typeof VIEWS)[number]\nfunction Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {\n\tconst tools = useTools(props.store)\n\tconst [getHidden, setHidden] = useSaved(\n\t\tprops.store,\n\t\t`🔍 Devtools Are Hidden`,\n\t\tprops.hideByDefault,\n\t)\n\tconst [getOpen, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true)\n\tconst [getSelection, setSelection] = useSaved<string>(\n\t\tprops.store,\n\t\t`🔍 Devtools View`,\n\t\t`atoms`,\n\t)\n\tconst view = () =>\n\t\tVIEWS.includes(getSelection() as View) ? (getSelection() as View) : `atoms`\n\tconst [getPosition, setPosition] = useLocal(props.store, { x: 0, y: 0 })\n\tconst getError = useGetter(tools.error)\n\tlet panel: HTMLElement | null = null\n\tconst attach = (element: HTMLElement | null) => {\n\t\tpanel = element\n\t}\n\tlet drag:\n\t\t| { id: number; startX: number; startY: number; x: number; y: number }\n\t\t| undefined\n\tonMount(() => {\n\t\tconst shortcut = (event: KeyboardEvent) => {\n\t\t\tif (event.ctrlKey && event.shiftKey && event.code === `KeyA`) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tsetHidden((value) => !value)\n\t\t\t}\n\t\t}\n\t\tconst reset = () => {\n\t\t\tsetPosition({ x: 0, y: 0 })\n\t\t}\n\t\tdocument.addEventListener(`keydown`, shortcut)\n\t\twindow.addEventListener(`resize`, reset)\n\t\tonCleanup(() => {\n\t\t\tdocument.removeEventListener(`keydown`, shortcut)\n\t\t\twindow.removeEventListener(`resize`, reset)\n\t\t})\n\t})\n\treturn (\n\t\t<main\n\t\t\tref={attach}\n\t\t\tdata-css=\"spa-devtools\"\n\t\t\tdata-testid=\"atom-io-devtools\"\n\t\t\thidden={getHidden()}\n\t\t\tdata-open={getOpen()}\n\t\t\tstyle={`transform:translate(${getPosition().x}px,${getPosition().y}px)`}\n\t\t>\n\t\t\t<header class=\"toolbar\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"drag-handle\"\n\t\t\t\t\taria-label=\"Move debugger\"\n\t\t\t\t\ttitle=\"Drag to move; arrow keys to nudge\"\n\t\t\t\t\tonPointerdown={(event) => {\n\t\t\t\t\t\tif (event.button !== 0) return\n\t\t\t\t\t\tdrag = {\n\t\t\t\t\t\t\tid: event.pointerId,\n\t\t\t\t\t\t\tstartX: event.clientX,\n\t\t\t\t\t\t\tstartY: event.clientY,\n\t\t\t\t\t\t\t...getPosition(),\n\t\t\t\t\t\t}\n\t\t\t\t\t\t;(event.currentTarget as HTMLElement).setPointerCapture(\n\t\t\t\t\t\t\tevent.pointerId,\n\t\t\t\t\t\t)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointermove={(event) => {\n\t\t\t\t\t\tif (!drag || drag.id !== event.pointerId || !panel) return\n\t\t\t\t\t\tconst rect = panel.getBoundingClientRect()\n\t\t\t\t\t\tconst next = {\n\t\t\t\t\t\t\tx: drag.x + event.clientX - drag.startX,\n\t\t\t\t\t\t\ty: drag.y + event.clientY - drag.startY,\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnext.x = Math.max(\n\t\t\t\t\t\t\tgetPosition().x - rect.left,\n\t\t\t\t\t\t\tMath.min(next.x, getPosition().x + window.innerWidth - rect.right),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tnext.y = Math.max(\n\t\t\t\t\t\t\tgetPosition().y - rect.top,\n\t\t\t\t\t\t\tMath.min(\n\t\t\t\t\t\t\t\tnext.y,\n\t\t\t\t\t\t\t\tgetPosition().y + window.innerHeight - rect.bottom,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tsetPosition(next)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointerup={() => {\n\t\t\t\t\t\tdrag = undefined\n\t\t\t\t\t}}\n\t\t\t\t\tonPointercancel={() => {\n\t\t\t\t\t\tdrag = undefined\n\t\t\t\t\t}}\n\t\t\t\t\tonKeydown={(event) => {\n\t\t\t\t\t\tconst step = {\n\t\t\t\t\t\t\tArrowLeft: [-10, 0],\n\t\t\t\t\t\t\tArrowRight: [10, 0],\n\t\t\t\t\t\t\tArrowUp: [0, -10],\n\t\t\t\t\t\t\tArrowDown: [0, 10],\n\t\t\t\t\t\t}[event.key]\n\t\t\t\t\t\tif (step) {\n\t\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\t\tsetPosition(({ x, y }) => ({ x: x + step[0], y: y + step[1] }))\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t⠿\n\t\t\t\t</button>\n\t\t\t\t<h1>atom.io</h1>\n\t\t\t\t{getOpen() ? (\n\t\t\t\t\t<nav aria-label=\"Debugger views\">\n\t\t\t\t\t\t{VIEWS.map((name) => (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\taria-pressed={view() === name}\n\t\t\t\t\t\t\t\tdata-testid={`view-${name}`}\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tsetSelection(name)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</nav>\n\t\t\t\t) : null}\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label={getOpen() ? `Minimize debugger` : `Open debugger`}\n\t\t\t\t\tdata-testid=\"open-close-devtools\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetOpen((value) => !value)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{getOpen() ? `−` : `🔍`}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide debugger (Ctrl+Shift+A)\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetHidden(true)\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</header>\n\t\t\t{getOpen() ? (\n\t\t\t\t<>\n\t\t\t\t\t{getError() ? <p role=\"alert\">{getError()}</p> : null}\n\t\t\t\t\t{view() === `atoms` || view() === `selectors` ? (\n\t\t\t\t\t\t<StateIndex\n\t\t\t\t\t\t\tkey={view()}\n\t\t\t\t\t\t\ttools={tools}\n\t\t\t\t\t\t\ttype={view() as `atoms` | `selectors`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : view() === `transactions` ? (\n\t\t\t\t\t\t<TransactionIndex tools={tools} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<TimelineIndex tools={tools} />\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t</main>\n\t)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atom.io/spa-devtools",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Atom.io's debugger, rendered with spa.",
5
5
  "homepage": "https://github.com/jeremybanka/atom.io/tree/main/packages/spa-devtools#readme",
6
6
  "repository": {
@@ -32,11 +32,11 @@
32
32
  "src"
33
33
  ],
34
34
  "devDependencies": {
35
- "@atom.io/spa": "0.0.3",
35
+ "@atom.io/spa": "0.0.4",
36
36
  "@breakage/changesets": "0.1.0",
37
37
  "@types/node": "26.6.6",
38
38
  "@vitest/coverage-v8": "5.1.0",
39
- "atom.io": "0.54.4",
39
+ "atom.io": "0.54.5",
40
40
  "breakage": "0.10.2",
41
41
  "eslint": "10.14.0",
42
42
  "happy-dom": "21.0.4",
@@ -45,7 +45,7 @@
45
45
  "vitest": "5.1.0"
46
46
  },
47
47
  "peerDependencies": {
48
- "@atom.io/spa": ">=0.0.0 <0.2.0",
48
+ "@atom.io/spa": ">=0.0.4 <0.2.0",
49
49
  "atom.io": "^0.54.1"
50
50
  },
51
51
  "publishConfig": {
@@ -1,5 +1,5 @@
1
1
  import type { VNode } from "@atom.io/spa"
2
- import { onCleanup, onMount, render, useValue } from "@atom.io/spa"
2
+ import { onCleanup, onMount, render, useGetter } from "@atom.io/spa"
3
3
  import type { RootStore } from "atom.io/internal"
4
4
  import { IMPLICIT } from "atom.io/internal"
5
5
 
@@ -32,21 +32,21 @@ const VIEWS = [`atoms`, `selectors`, `transactions`, `timelines`] as const
32
32
  type View = (typeof VIEWS)[number]
33
33
  function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
34
34
  const tools = useTools(props.store)
35
- const [hidden, setHidden] = useSaved(
35
+ const [getHidden, setHidden] = useSaved(
36
36
  props.store,
37
37
  `🔍 Devtools Are Hidden`,
38
38
  props.hideByDefault,
39
39
  )
40
- const [open, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true)
41
- const [selection, setSelection] = useSaved<string>(
40
+ const [getOpen, setOpen] = useSaved(props.store, `🔍 Devtools Are Open`, true)
41
+ const [getSelection, setSelection] = useSaved<string>(
42
42
  props.store,
43
43
  `🔍 Devtools View`,
44
44
  `atoms`,
45
45
  )
46
46
  const view = () =>
47
- VIEWS.includes(selection() as View) ? (selection() as View) : `atoms`
48
- const [position, setPosition] = useLocal(props.store, { x: 0, y: 0 })
49
- const error = useValue(tools.error)
47
+ VIEWS.includes(getSelection() as View) ? (getSelection() as View) : `atoms`
48
+ const [getPosition, setPosition] = useLocal(props.store, { x: 0, y: 0 })
49
+ const getError = useGetter(tools.error)
50
50
  let panel: HTMLElement | null = null
51
51
  const attach = (element: HTMLElement | null) => {
52
52
  panel = element
@@ -76,9 +76,9 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
76
76
  ref={attach}
77
77
  data-css="spa-devtools"
78
78
  data-testid="atom-io-devtools"
79
- hidden={hidden()}
80
- data-open={open()}
81
- style={`transform:translate(${position().x}px,${position().y}px)`}
79
+ hidden={getHidden()}
80
+ data-open={getOpen()}
81
+ style={`transform:translate(${getPosition().x}px,${getPosition().y}px)`}
82
82
  >
83
83
  <header class="toolbar">
84
84
  <button
@@ -92,7 +92,7 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
92
92
  id: event.pointerId,
93
93
  startX: event.clientX,
94
94
  startY: event.clientY,
95
- ...position(),
95
+ ...getPosition(),
96
96
  }
97
97
  ;(event.currentTarget as HTMLElement).setPointerCapture(
98
98
  event.pointerId,
@@ -106,12 +106,15 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
106
106
  y: drag.y + event.clientY - drag.startY,
107
107
  }
108
108
  next.x = Math.max(
109
- position().x - rect.left,
110
- Math.min(next.x, position().x + window.innerWidth - rect.right),
109
+ getPosition().x - rect.left,
110
+ Math.min(next.x, getPosition().x + window.innerWidth - rect.right),
111
111
  )
112
112
  next.y = Math.max(
113
- position().y - rect.top,
114
- Math.min(next.y, position().y + window.innerHeight - rect.bottom),
113
+ getPosition().y - rect.top,
114
+ Math.min(
115
+ next.y,
116
+ getPosition().y + window.innerHeight - rect.bottom,
117
+ ),
115
118
  )
116
119
  setPosition(next)
117
120
  }}
@@ -137,7 +140,7 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
137
140
  ⠿
138
141
  </button>
139
142
  <h1>atom.io</h1>
140
- {open() ? (
143
+ {getOpen() ? (
141
144
  <nav aria-label="Debugger views">
142
145
  {VIEWS.map((name) => (
143
146
  <button
@@ -155,13 +158,13 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
155
158
  ) : null}
156
159
  <button
157
160
  type="button"
158
- aria-label={open() ? `Minimize debugger` : `Open debugger`}
161
+ aria-label={getOpen() ? `Minimize debugger` : `Open debugger`}
159
162
  data-testid="open-close-devtools"
160
163
  onClick={() => {
161
164
  setOpen((value) => !value)
162
165
  }}
163
166
  >
164
- {open() ? `−` : `🔍`}
167
+ {getOpen() ? `−` : `🔍`}
165
168
  </button>
166
169
  <button
167
170
  type="button"
@@ -173,9 +176,9 @@ function Panel(props: { store: RootStore; hideByDefault: boolean }): VNode {
173
176
  ×
174
177
  </button>
175
178
  </header>
176
- {open() ? (
179
+ {getOpen() ? (
177
180
  <>
178
- {error() ? <p role="alert">{error()}</p> : null}
181
+ {getError() ? <p role="alert">{getError()}</p> : null}
179
182
  {view() === `atoms` || view() === `selectors` ? (
180
183
  <StateIndex
181
184
  key={view()}
package/src/Indexes.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { VNode } from "@atom.io/spa"
2
- import { useSetter, useTimeline, useValue } from "@atom.io/spa"
2
+ import { useGetter, useSetter, useTimeline } from "@atom.io/spa"
3
3
  import type {
4
4
  ReadableToken,
5
5
  TimelineToken,
@@ -23,15 +23,15 @@ export function StateIndex(props: {
23
23
  tools: Tools
24
24
  type: `atoms` | `selectors`
25
25
  }): VNode {
26
- const index = useValue<Map<string, Token | FamilyNode<Token>>>(
26
+ const getStateIndex = useGetter<Map<string, Token | FamilyNode<Token>>>(
27
27
  props.type === `atoms` ? props.tools.atomIndex : props.tools.selectorIndex,
28
28
  )
29
29
  return (
30
30
  <article class="index" data-testid="state-index">
31
- {index().size === 0 ? (
31
+ {getStateIndex().size === 0 ? (
32
32
  <p>(no {props.type})</p>
33
33
  ) : (
34
- [...index().values()].map((node) => (
34
+ [...getStateIndex().values()].map((node) => (
35
35
  <StateNode key={node.key} tools={props.tools} node={node} />
36
36
  ))
37
37
  )}
@@ -42,7 +42,7 @@ function StateNode(props: {
42
42
  tools: Tools
43
43
  node: Token | FamilyNode<Token>
44
44
  }): VNode {
45
- const [open, toggle] = useExpanded(props.tools, [props.node.key])
45
+ const [getOpen, toggle] = useExpanded(props.tools, [props.node.key])
46
46
  return (
47
47
  <section class="node" data-testid={`state-${props.node.key}`}>
48
48
  {`familyMembers` in props.node ? (
@@ -50,16 +50,16 @@ function StateNode(props: {
50
50
  <header>
51
51
  <button
52
52
  type="button"
53
- aria-expanded={open()}
53
+ aria-expanded={getOpen()}
54
54
  data-testid={`open-close-state-family-${props.node.key}`}
55
55
  onClick={toggle}
56
56
  >
57
- {open() ? `▾` : `▸`}
57
+ {getOpen() ? `▾` : `▸`}
58
58
  </button>
59
59
  <h2>{props.node.key}</h2>
60
60
  <small>family</small>
61
61
  </header>
62
- {open()
62
+ {getOpen()
63
63
  ? [...props.node.familyMembers.values()].map((token) => (
64
64
  <StateLeaf key={token.key} tools={props.tools} token={token} />
65
65
  ))
@@ -72,14 +72,14 @@ function StateNode(props: {
72
72
  )
73
73
  }
74
74
  function StateLeaf(props: { tools: Tools; token: Token }): VNode {
75
- const read = useValue(props.token)
75
+ const getValue = useGetter(props.token)
76
76
  const writable = !props.token.type.startsWith(`readonly`)
77
- const set = writable
77
+ const setValue = writable
78
78
  ? useSetter(props.token as WritableToken<unknown, any, any>)
79
79
  : undefined
80
80
  const value = () => {
81
81
  try {
82
- return read()
82
+ return getValue()
83
83
  } catch (error) {
84
84
  return error
85
85
  }
@@ -106,11 +106,11 @@ function StateLeaf(props: { tools: Tools; token: Token }): VNode {
106
106
  tools={props.tools}
107
107
  value={value()}
108
108
  change={
109
- set
109
+ setValue
110
110
  ? (update) => {
111
111
  // Validate edits before opening an atom.io write operation.
112
- const next = update(read())
113
- set(() => next)
112
+ const next = update(getValue())
113
+ setValue(() => next)
114
114
  }
115
115
  : undefined
116
116
  }
@@ -124,9 +124,11 @@ function StateLeaf(props: { tools: Tools; token: Token }): VNode {
124
124
  )
125
125
  }
126
126
  export function TransactionIndex(props: { tools: Tools }): VNode {
127
- const index = useValue(props.tools.transactionIndex)
127
+ const getTransactionIndex = useGetter(props.tools.transactionIndex)
128
128
  const visible = () =>
129
- index().filter((token) => !isReservedIntrospectionKey(token.key))
129
+ getTransactionIndex().filter(
130
+ (token) => !isReservedIntrospectionKey(token.key),
131
+ )
130
132
  return (
131
133
  <article class="index" data-testid="transaction-index">
132
134
  {visible().length === 0 ? (
@@ -143,30 +145,30 @@ function TransactionLog(props: {
143
145
  tools: Tools
144
146
  token: TransactionToken<any>
145
147
  }): VNode {
146
- const log = useValue(
148
+ const getTransactionLog = useGetter(
147
149
  findInStore(
148
150
  props.tools.store,
149
151
  props.tools.transactionLogSelectors,
150
152
  props.token.key,
151
153
  ),
152
154
  )
153
- const [open, toggle] = useExpanded(props.tools, [props.token.key])
155
+ const [getOpen, toggle] = useExpanded(props.tools, [props.token.key])
154
156
  return (
155
157
  <section class="node" data-testid={`transaction-${props.token.key}`}>
156
158
  <header>
157
159
  <button
158
160
  type="button"
159
- aria-expanded={open()}
161
+ aria-expanded={getOpen()}
160
162
  data-testid={`open-close-transaction-${props.token.key}`}
161
163
  onClick={toggle}
162
164
  >
163
- {open() ? `▾` : `▸`}
165
+ {getOpen() ? `▾` : `▸`}
164
166
  </button>
165
167
  <h2>{props.token.key}</h2>
166
- <small>({log().length})</small>
168
+ <small>({getTransactionLog().length})</small>
167
169
  </header>
168
- {open()
169
- ? log().map((event, index) => (
170
+ {getOpen()
171
+ ? getTransactionLog().map((event, index) => (
170
172
  <EventView
171
173
  key={index}
172
174
  tools={props.tools}
@@ -184,7 +186,7 @@ export function EventView(props: {
184
186
  event: any
185
187
  index: number
186
188
  }): VNode {
187
- const [open, toggle] = useExpanded(
189
+ const [getOpen, toggle] = useExpanded(
188
190
  props.tools,
189
191
  [`event`, props.event.token?.key ?? ``, String(props.index)],
190
192
  true,
@@ -195,13 +197,13 @@ export function EventView(props: {
195
197
  data-testid={`${props.event.type === `transaction_outcome` ? `transaction` : `timeline`}-update-${props.event.token?.key}-${props.index}`}
196
198
  >
197
199
  <header>
198
- <button type="button" aria-expanded={open()} onClick={toggle}>
199
- {open() ? `▾` : `▸`}
200
+ <button type="button" aria-expanded={getOpen()} onClick={toggle}>
201
+ {getOpen() ? `▾` : `▸`}
200
202
  </button>
201
203
  <strong>{props.event.token?.key}</strong>
202
204
  <small>{props.event.type}</small>
203
205
  </header>
204
- {open() ? (
206
+ {getOpen() ? (
205
207
  props.event.type === `transaction_outcome` ? (
206
208
  <>
207
209
  <p>
@@ -234,10 +236,10 @@ export function EventView(props: {
234
236
  )
235
237
  }
236
238
  export function TimelineIndex(props: { tools: Tools }): VNode {
237
- const index = useValue(props.tools.timelineIndex)
239
+ const getTimelineIndex = useGetter(props.tools.timelineIndex)
238
240
  const groups = () => {
239
241
  const result = new Map<string, TimelineToken<any>[]>()
240
- for (const token of index()) {
242
+ for (const token of getTimelineIndex()) {
241
243
  if (isReservedIntrospectionKey(token.key) || token.key.startsWith(`👁‍🗨`))
242
244
  continue
243
245
  const key = token.family?.key ?? ``
@@ -269,59 +271,59 @@ export function TimelineIndex(props: { tools: Tools }): VNode {
269
271
  }
270
272
  function TimelineLog(props: { tools: Tools; token: TimelineToken<any> }): VNode {
271
273
  const controls = useTimeline(props.token)
272
- const log = useValue(
274
+ const getTimeline = useGetter(
273
275
  findInStore(
274
276
  props.tools.store,
275
277
  props.tools.timelineSelectors,
276
278
  props.token.key,
277
279
  ),
278
280
  )
279
- const [open, toggle] = useExpanded(props.tools, [props.token.key])
281
+ const [getOpen, toggle] = useExpanded(props.tools, [props.token.key])
280
282
  return (
281
283
  <section class="node" data-testid={`timeline-${props.token.key}`}>
282
284
  <header>
283
285
  <button
284
286
  type="button"
285
- aria-expanded={open()}
287
+ aria-expanded={getOpen()}
286
288
  data-testid={`open-close-timeline-${props.token.key}`}
287
289
  onClick={toggle}
288
290
  >
289
- {open() ? `▾` : `▸`}
291
+ {getOpen() ? `▾` : `▸`}
290
292
  </button>
291
293
  <h2>{props.token.family?.subKey ?? props.token.key}</h2>
292
294
  <small>
293
- ({controls().at}/{controls().length})
295
+ ({controls.getCursor()}/{controls.getLength()})
294
296
  </small>
295
297
  <button
296
298
  type="button"
297
- disabled={controls().at === 0}
299
+ disabled={controls.getCursor() === 0}
298
300
  onClick={() => {
299
- props.tools.attempt(controls().undo)
301
+ props.tools.attempt(controls.undo)
300
302
  }}
301
303
  >
302
304
  undo
303
305
  </button>
304
306
  <button
305
307
  type="button"
306
- disabled={controls().at === controls().length}
308
+ disabled={controls.getCursor() === controls.getLength()}
307
309
  onClick={() => {
308
- props.tools.attempt(controls().redo)
310
+ props.tools.attempt(controls.redo)
309
311
  }}
310
312
  >
311
313
  redo
312
314
  </button>
313
315
  </header>
314
- {open() ? (
316
+ {getOpen() ? (
315
317
  <section>
316
- {log().history.map((event, index) => (
318
+ {getTimeline().history.map((event, index) => (
317
319
  <section key={index}>
318
- {index === log().at ? (
320
+ {index === getTimeline().at ? (
319
321
  <p class="you-are-here">you are here</p>
320
322
  ) : null}
321
323
  <EventView tools={props.tools} event={event} index={index} />
322
324
  </section>
323
325
  ))}
324
- {log().at === log().history.length ? (
326
+ {getTimeline().at === getTimeline().history.length ? (
325
327
  <p class="you-are-here">you are here</p>
326
328
  ) : null}
327
329
  </section>
@@ -23,7 +23,7 @@ const TYPES: JsonKind[] = [
23
23
  `object`,
24
24
  ]
25
25
  export function JsonEditor(props: EditorProps): VNode {
26
- const [expanded, toggle] = useExpanded(props.tools, props.path)
26
+ const [getExpanded, toggle] = useExpanded(props.tools, props.path)
27
27
  const circular = () =>
28
28
  (props.ancestors?.includes(props.value) ?? false) || props.path.length > 50
29
29
  const container = () =>
@@ -40,10 +40,10 @@ export function JsonEditor(props: EditorProps): VNode {
40
40
  <button
41
41
  type="button"
42
42
  aria-label={`Expand ${props.path.at(-1)}`}
43
- aria-expanded={expanded()}
43
+ aria-expanded={getExpanded()}
44
44
  onClick={toggle}
45
45
  >
46
- {expanded() ? `▾` : `▸`}
46
+ {getExpanded() ? `▾` : `▸`}
47
47
  </button>
48
48
  ) : (
49
49
  <span class="carat-spacer" />
@@ -84,7 +84,7 @@ export function JsonEditor(props: EditorProps): VNode {
84
84
  )}
85
85
  {props.actions}
86
86
  </header>
87
- {container() && expanded() ? (
87
+ {container() && getExpanded() ? (
88
88
  <section class="properties">
89
89
  {entries().map(([key]) => (
90
90
  <Property key={key} name={key} editor={props} />
package/src/store.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Accessor } from "@atom.io/spa"
2
- import { onCleanup, useId, useSetter, useValue } from "@atom.io/spa"
2
+ import { onCleanup, useGetter, useId, useSetter } from "@atom.io/spa"
3
3
  import type { RegularAtomFamilyToken, RegularAtomToken, Setter } from "atom.io"
4
4
  import type { RootStore } from "atom.io/internal"
5
5
  import {
@@ -42,7 +42,7 @@ export function useLocal<T>(
42
42
  initial: T,
43
43
  ): [Accessor<T>, (next: T | Setter<T>) => void] {
44
44
  const token = ownedAtom(store, initial)
45
- return [useValue(token) as Accessor<T>, useSetter(token)]
45
+ return [useGetter(token) as Accessor<T>, useSetter(token)]
46
46
  }
47
47
  export function useSaved<T>(
48
48
  store: RootStore,
@@ -56,13 +56,13 @@ export function useSaved<T>(
56
56
  } catch {
57
57
  /* Storage may be unavailable. */
58
58
  }
59
- const [value, set] = useLocal(store, initial)
59
+ const [getValue, setValue] = useLocal(store, initial)
60
60
  return [
61
- value,
61
+ getValue,
62
62
  (next) => {
63
- set(next)
63
+ setValue(next)
64
64
  try {
65
- localStorage.setItem(key, JSON.stringify(value()))
65
+ localStorage.setItem(key, JSON.stringify(getValue()))
66
66
  } catch {
67
67
  /* Keep in-memory state when storage is unavailable. */
68
68
  }
@@ -112,16 +112,16 @@ export function useExpanded(
112
112
  path: Path,
113
113
  initial = false,
114
114
  ): [Accessor<boolean>, (event: MouseEvent) => void] {
115
- const value = useValue(tools.expanded)
116
- const set = useSetter(tools.expanded)
115
+ const getExpanded = useGetter(tools.expanded)
116
+ const setExpanded = useSetter(tools.expanded)
117
117
  const key = JSON.stringify(path)
118
118
  const group = `all:${JSON.stringify(path.slice(0, -1))}`
119
- const read = () => value()[key] ?? value()[group] ?? initial
119
+ const read = () => getExpanded()[key] ?? getExpanded()[group] ?? initial
120
120
  return [
121
121
  read,
122
122
  (event) => {
123
123
  const next = !read()
124
- set((previous) => {
124
+ setExpanded((previous) => {
125
125
  const result = { ...previous }
126
126
  if (event.shiftKey) {
127
127
  const parent = JSON.stringify(path.slice(0, -1))