atom.io 0.33.12 → 0.33.13

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.
@@ -1,22 +1,25 @@
1
1
  import { useI, useO } from "../use-o-BrXc7Qro.js";
2
- import { IMPLICIT, become, createAtomFamily, createStandaloneAtom, findInStore } from "atom.io/internal";
2
+ import { IMPLICIT, actUponStore, arbitrary, become, createAtomFamily, createStandaloneAtom, createTransaction, findInStore, getFromStore } from "atom.io/internal";
3
3
  import { JSON_DEFAULTS, fromEntries, isJson, stringifyJson, toEntries } from "atom.io/json";
4
- import { getState, redo, undo } from "atom.io";
4
+ import { redo, undo } from "atom.io";
5
5
  import { Component, Fragment, createContext, forwardRef, useContext, useId, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
6
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { StoreContext, useI as useI$1, useO as useO$1 } from "atom.io/react";
8
8
  import { LayoutGroup, motion } from "motion/react";
9
- import { attachIntrospectionStates, discoverType, jsonRefinery, prettyJson, primitiveRefinery } from "atom.io/introspection";
9
+ import { attachIntrospectionStates, discoverType, isPlainObject, jsonRefinery, prettyJson, primitiveRefinery } from "atom.io/introspection";
10
10
  import { persistSync } from "atom.io/web";
11
11
 
12
12
  //#region src/react-devtools/Button.tsx
13
- const OpenClose = ({ isOpen, setIsOpen, disabled, testid }) => {
13
+ const OpenClose = ({ isOpen, setIsOpen, onShiftClick, disabled, testid }) => {
14
14
  return /* @__PURE__ */ jsx("button", {
15
15
  type: "button",
16
16
  "data-testid": testid,
17
17
  className: `carat ${isOpen ? `open` : `closed`}`,
18
- onClick: () => {
19
- setIsOpen((prev) => !prev);
18
+ onClick: (event) => {
19
+ if (onShiftClick && event.shiftKey) {
20
+ if (!onShiftClick(event)) return;
21
+ }
22
+ setIsOpen?.((prev) => !prev);
20
23
  },
21
24
  disabled,
22
25
  children: /* @__PURE__ */ jsx("span", {
@@ -189,7 +192,52 @@ function attachDevtoolsStates(store) {
189
192
  const viewIsOpenAtoms = createAtomFamily(store, {
190
193
  key: `🔍 Devtools View Is Open`,
191
194
  default: false,
192
- effects: (key) => typeof window === `undefined` ? [] : [persistSync(window.localStorage, JSON, key + `:view-is-open`)]
195
+ effects: (key) => typeof window === `undefined` ? [] : [persistSync(window.localStorage, JSON, `view-is-open:${key.join()}`)]
196
+ });
197
+ const openCloseAllTX = createTransaction(store, {
198
+ key: `openCloseMultiView`,
199
+ do: ({ get, set }, path, current) => {
200
+ const currentView = get(devtoolsViewSelectionState);
201
+ let states;
202
+ switch (currentView) {
203
+ case `atoms`:
204
+ states = get(introspectionStates.atomIndex);
205
+ break;
206
+ case `selectors`:
207
+ states = get(introspectionStates.selectorIndex);
208
+ break;
209
+ case `transactions`:
210
+ case `timelines`: return;
211
+ }
212
+ switch (path.length) {
213
+ case 1:
214
+ for (const [key] of states) set(viewIsOpenAtoms, [key], !current);
215
+ break;
216
+ default: {
217
+ const item = states.get(path[0]);
218
+ let value;
219
+ let segments;
220
+ if (item) {
221
+ if (`familyMembers` in item) {
222
+ if (path.length === 2) {
223
+ for (const [subKey] of item.familyMembers) set(viewIsOpenAtoms, [path[0], subKey], !current);
224
+ return;
225
+ }
226
+ const token = item.familyMembers.get(path[1]);
227
+ value = get(token);
228
+ segments = path.slice(2, -1);
229
+ } else {
230
+ value = get(item);
231
+ segments = path.slice(1, -1);
232
+ }
233
+ for (const segment of segments) if (value && typeof value === `object`) value = value[segment];
234
+ const head = path.slice(0, -1);
235
+ if (Array.isArray(value)) for (let i = 0; i < value.length; i++) set(viewIsOpenAtoms, [...head, i], !current);
236
+ else if (isPlainObject(value)) for (const key of Object.keys(value)) set(viewIsOpenAtoms, [...head, key], !current);
237
+ }
238
+ }
239
+ }
240
+ }
193
241
  });
194
242
  return {
195
243
  ...introspectionStates,
@@ -197,6 +245,7 @@ function attachDevtoolsStates(store) {
197
245
  devtoolsViewSelectionState,
198
246
  devtoolsViewOptionsState,
199
247
  viewIsOpenAtoms,
248
+ openCloseAllTX,
200
249
  store
201
250
  };
202
251
  }
@@ -410,6 +459,7 @@ const NonJsonEditor = ({ data, testid }) => {
410
459
  //#endregion
411
460
  //#region src/react-devtools/json-editor/json-editor-internal.tsx
412
461
  const JsonEditor_INTERNAL = ({ data, set, name, rename, remove, recast, path = [], isReadonly = () => false, isHidden = () => false, className, style, Components, isOpen, setIsOpen, testid }) => {
462
+ const { openCloseAllTX, store } = useContext(DevtoolsContext);
413
463
  const dataIsJson = isJson(data);
414
464
  const refined = jsonRefinery.refine(data) ?? {
415
465
  type: `non-json`,
@@ -418,23 +468,21 @@ const JsonEditor_INTERNAL = ({ data, set, name, rename, remove, recast, path = [
418
468
  const SubEditor = dataIsJson ? SubEditors[refined.type] : NonJsonEditor;
419
469
  const disabled = isReadonly(path);
420
470
  const dataIsTree = refined.type === `array` || refined.type === `object`;
471
+ const dataIsExpandable = dataIsTree && isOpen !== void 0 && setIsOpen;
421
472
  return isHidden(path) ? null : /* @__PURE__ */ jsx(Components.ErrorBoundary, { children: /* @__PURE__ */ jsxs(Components.EditorWrapper, {
422
473
  className,
423
474
  style,
424
475
  testid,
425
- children: [/* @__PURE__ */ jsxs("header", { children: [
426
- remove ? /* @__PURE__ */ jsx(Components.Button, {
427
- disabled,
428
- onClick: () => {
429
- remove();
430
- },
431
- testid: `${testid}-delete`,
432
- children: /* @__PURE__ */ jsx(Components.DeleteIcon, {})
433
- }) : null,
434
- dataIsTree && isOpen !== void 0 && setIsOpen ? /* @__PURE__ */ jsx(button.OpenClose, {
435
- isOpen,
476
+ children: [/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsxs("main", { children: [
477
+ remove || dataIsExpandable ? /* @__PURE__ */ jsx(button.OpenClose, {
478
+ isOpen: isOpen ?? false,
436
479
  testid: `${testid}-open-close`,
437
- setIsOpen
480
+ onShiftClick: () => {
481
+ actUponStore(store, openCloseAllTX, arbitrary())(path, isOpen);
482
+ return false;
483
+ },
484
+ setIsOpen,
485
+ disabled: !dataIsExpandable
438
486
  }) : null,
439
487
  rename && /* @__PURE__ */ jsx(Components.KeyWrapper, { children: /* @__PURE__ */ jsx(ElasticInput, {
440
488
  value: name,
@@ -444,7 +492,10 @@ const JsonEditor_INTERNAL = ({ data, set, name, rename, remove, recast, path = [
444
492
  disabled,
445
493
  "data-testid": `${testid}-rename`
446
494
  }) }),
447
- dataIsTree ? /* @__PURE__ */ jsxs(Fragment$1, { children: [recast ? /* @__PURE__ */ jsx("select", {
495
+ dataIsTree ? /* @__PURE__ */ jsxs(Fragment$1, { children: [isOpen !== void 0 && setIsOpen ? /* @__PURE__ */ jsx("span", {
496
+ className: "json_viewer",
497
+ children: JSON.stringify(data)
498
+ }) : null, recast ? /* @__PURE__ */ jsx("select", {
448
499
  onChange: (e) => {
449
500
  recast(e.target.value);
450
501
  },
@@ -455,9 +506,6 @@ const JsonEditor_INTERNAL = ({ data, set, name, rename, remove, recast, path = [
455
506
  value: type,
456
507
  children: type
457
508
  }, type))
458
- }) : null, isOpen !== void 0 && setIsOpen ? /* @__PURE__ */ jsx("span", {
459
- className: "json_viewer",
460
- children: JSON.stringify(data)
461
509
  }) : null] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(SubEditor, {
462
510
  data: refined.data,
463
511
  set,
@@ -480,7 +528,14 @@ const JsonEditor_INTERNAL = ({ data, set, name, rename, remove, recast, path = [
480
528
  children: type
481
529
  }, type))
482
530
  }) : null] })
483
- ] }), dataIsTree && isOpen !== false ? /* @__PURE__ */ jsx(SubEditor, {
531
+ ] }), remove ? /* @__PURE__ */ jsx(Components.Button, {
532
+ disabled,
533
+ onClick: () => {
534
+ remove();
535
+ },
536
+ testid: `${testid}-delete`,
537
+ children: /* @__PURE__ */ jsx(Components.DeleteIcon, {})
538
+ }) : null] }), dataIsTree && isOpen !== false ? /* @__PURE__ */ jsx(SubEditor, {
484
539
  data: refined.data,
485
540
  set,
486
541
  remove,
@@ -775,12 +830,12 @@ const ArrayEditor = ({ path = [], isReadonly = () => false, isHidden = () => fal
775
830
  const setElement = makeElementSetters(data, set);
776
831
  const removeElement = makePropertyRemovers(data, set);
777
832
  const recastElement = makePropertyRecasters(data, set);
778
- return /* @__PURE__ */ jsxs(Components.ArrayWrapper, { children: [/* @__PURE__ */ jsx("div", {
833
+ return /* @__PURE__ */ jsxs(Components.ArrayWrapper, { children: [/* @__PURE__ */ jsx("main", {
779
834
  className: `json_editor_elements${disabled ? ` readonly` : ``}`,
780
835
  children: data.map((element, index) => {
781
836
  const elementPath = [...path, index];
782
837
  const pathKey = elementPath.join(`,`);
783
- const viewIsOpenAtom = findInStore(store, viewIsOpenAtoms, `${testid}__${pathKey}`);
838
+ const viewIsOpenAtom = findInStore(store, viewIsOpenAtoms, [...path, index]);
784
839
  return /* @__PURE__ */ jsx(ArrayElement, {
785
840
  path: elementPath,
786
841
  isReadonly,
@@ -794,7 +849,7 @@ const ArrayEditor = ({ path = [], isReadonly = () => false, isHidden = () => fal
794
849
  viewIsOpenAtom
795
850
  }, pathKey);
796
851
  })
797
- }), /* @__PURE__ */ jsx(Components.Button, {
852
+ }), !disabled ? /* @__PURE__ */ jsx("footer", { children: /* @__PURE__ */ jsx(Components.Button, {
798
853
  testid: `${testid}-add-element`,
799
854
  disabled,
800
855
  onClick: () => {
@@ -804,7 +859,7 @@ const ArrayEditor = ({ path = [], isReadonly = () => false, isHidden = () => fal
804
859
  });
805
860
  },
806
861
  children: /* @__PURE__ */ jsx(Components.AddIcon, {})
807
- })] });
862
+ }) }) : null] });
808
863
  };
809
864
 
810
865
  //#endregion
@@ -850,7 +905,7 @@ const ObjectEditor = ({ path = [], isReadonly = () => false, isHidden = () => fa
850
905
  const propertyPath = [...path, key];
851
906
  const originalPropertyPath = [...path, originalKey];
852
907
  const stablePathKey = originalPropertyPath.join(`.`);
853
- const viewIsOpenAtom = findInStore(store, viewIsOpenAtoms, `${testid}__${stablePathKey}`);
908
+ const viewIsOpenAtom = findInStore(store, viewIsOpenAtoms, [...path, key]);
854
909
  return /* @__PURE__ */ jsx(ObjectProperty, {
855
910
  path: propertyPath,
856
911
  isReadonly,
@@ -865,7 +920,7 @@ const ObjectEditor = ({ path = [], isReadonly = () => false, isHidden = () => fa
865
920
  viewIsOpenAtom
866
921
  }, stablePathKey);
867
922
  })
868
- }), disabled ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Components.Button, {
923
+ }), disabled ? null : /* @__PURE__ */ jsxs("footer", { children: [/* @__PURE__ */ jsx(Components.Button, {
869
924
  disabled,
870
925
  testid: `${testid}-add-property`,
871
926
  onClick: () => {
@@ -923,7 +978,7 @@ const SubEditors = {
923
978
  object: ObjectEditor,
924
979
  string: StringEditor
925
980
  };
926
- const JsonEditor = ({ data, set, name, rename, remove, isReadonly = () => false, isHidden = () => false, className, Header, style, Components: CustomComponents = {}, testid }) => {
981
+ const JsonEditor = ({ data, set, name, rename, remove, path = [], isReadonly = () => false, isHidden = () => false, className, Header, style, Components: CustomComponents = {}, testid }) => {
927
982
  const Components = {
928
983
  ...DEFAULT_JSON_EDITOR_COMPONENTS,
929
984
  ...CustomComponents
@@ -934,7 +989,7 @@ const JsonEditor = ({ data, set, name, rename, remove, isReadonly = () => false,
934
989
  name,
935
990
  rename,
936
991
  remove,
937
- path: [],
992
+ path,
938
993
  isReadonly,
939
994
  isHidden,
940
995
  className,
@@ -950,19 +1005,23 @@ const JsonEditor = ({ data, set, name, rename, remove, isReadonly = () => false,
950
1005
  const StateEditor = ({ token }) => {
951
1006
  const set = useI$1(token);
952
1007
  const data = useO$1(token);
1008
+ const metaPath = token.family ? [token.family.key, token.family.subKey] : [token.key];
953
1009
  return /* @__PURE__ */ jsx(JsonEditor, {
954
1010
  testid: `${token.key}-state-editor`,
955
1011
  data,
956
- set
1012
+ set,
1013
+ path: metaPath
957
1014
  });
958
1015
  };
959
1016
  const ReadonlySelectorViewer = ({ token }) => {
960
1017
  const data = useO$1(token);
1018
+ const metaPath = token.family ? [token.family.key, token.family.subKey] : [token.key];
961
1019
  return /* @__PURE__ */ jsx(JsonEditor, {
962
1020
  testid: `${token.key}-state-editor`,
963
1021
  data,
964
1022
  set: () => null,
965
- isReadonly: () => true
1023
+ isReadonly: () => true,
1024
+ path: metaPath
966
1025
  });
967
1026
  };
968
1027
  const StoreEditor = ({ token }) => {
@@ -979,59 +1038,73 @@ const StoreEditor = ({ token }) => {
979
1038
  //#endregion
980
1039
  //#region src/react-devtools/StateIndex.tsx
981
1040
  const StateIndexLeafNode = ({ node, isOpenState, typeState }) => {
1041
+ const { openCloseAllTX, store } = useContext(DevtoolsContext);
982
1042
  const setIsOpen = useI$1(isOpenState);
983
1043
  const isOpen = useO$1(isOpenState);
984
1044
  const state = useO$1(node);
985
1045
  const stateTypeLoadable = useO$1(typeState);
986
1046
  const stateType = stateTypeLoadable instanceof Promise ? `Promise` : stateTypeLoadable;
987
1047
  const isPrimitive = Boolean(primitiveRefinery.refine(state));
988
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("header", { children: [
989
- /* @__PURE__ */ jsx(button.OpenClose, {
990
- isOpen: isOpen && !isPrimitive,
991
- testid: `open-close-state-${node.key}`,
992
- setIsOpen,
993
- disabled: isPrimitive
994
- }),
995
- /* @__PURE__ */ jsxs("main", {
996
- onClick: () => {
997
- console.log(node, getState(node));
998
- },
999
- onKeyUp: () => {
1000
- console.log(node, getState(node));
1001
- },
1002
- children: [/* @__PURE__ */ jsx("h2", { children: node.family?.subKey ?? node.key }), /* @__PURE__ */ jsxs("span", {
1048
+ const path = node.family ? [node.family.key, node.family.subKey] : [node.key];
1049
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsxs("main", {
1050
+ onClick: () => {
1051
+ console.log(node, getFromStore(store, node));
1052
+ },
1053
+ onKeyUp: () => {
1054
+ console.log(node, getFromStore(store, node));
1055
+ },
1056
+ children: [
1057
+ /* @__PURE__ */ jsx(button.OpenClose, {
1058
+ isOpen: isOpen && !isPrimitive,
1059
+ testid: `open-close-state-${node.key}`,
1060
+ onShiftClick: () => {
1061
+ actUponStore(store, openCloseAllTX, arbitrary())(path, isOpen);
1062
+ return false;
1063
+ },
1064
+ setIsOpen,
1065
+ disabled: isPrimitive
1066
+ }),
1067
+ /* @__PURE__ */ jsx("h2", { children: node.family?.subKey ?? node.key }),
1068
+ /* @__PURE__ */ jsxs("span", {
1003
1069
  className: "type detail",
1004
1070
  children: [
1005
1071
  "(",
1006
1072
  stateType,
1007
1073
  ")"
1008
1074
  ]
1009
- })]
1010
- }),
1011
- isPrimitive ? /* @__PURE__ */ jsx(StoreEditor, { token: node }) : /* @__PURE__ */ jsx("div", {
1012
- className: "json_viewer",
1013
- children: JSON.stringify(state)
1014
- })
1015
- ] }), isOpen && !isPrimitive ? /* @__PURE__ */ jsx("main", { children: /* @__PURE__ */ jsx(StoreEditor, { token: node }) }) : null] });
1075
+ })
1076
+ ]
1077
+ }), isPrimitive ? /* @__PURE__ */ jsx(StoreEditor, { token: node }) : /* @__PURE__ */ jsx("div", {
1078
+ className: "json_viewer",
1079
+ children: JSON.stringify(state)
1080
+ })] }), isOpen && !isPrimitive ? /* @__PURE__ */ jsx("main", { children: /* @__PURE__ */ jsx(StoreEditor, { token: node }) }) : null] });
1016
1081
  };
1017
1082
  const StateIndexTreeNode = ({ node, isOpenState }) => {
1018
1083
  const setIsOpen = useI$1(isOpenState);
1019
1084
  const isOpen = useO$1(isOpenState);
1020
- const { typeSelectors, viewIsOpenAtoms, store } = useContext(DevtoolsContext);
1085
+ const { typeSelectors, viewIsOpenAtoms, openCloseAllTX, store } = useContext(DevtoolsContext);
1021
1086
  for (const [key, childNode] of node.familyMembers) {
1022
- findInStore(store, viewIsOpenAtoms, key);
1087
+ findInStore(store, viewIsOpenAtoms, [key]);
1023
1088
  findInStore(store, typeSelectors, childNode.key);
1024
1089
  }
1025
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsx(button.OpenClose, {
1026
- isOpen,
1027
- testid: `open-close-state-family-${node.key}`,
1028
- setIsOpen
1029
- }), /* @__PURE__ */ jsxs("main", { children: [/* @__PURE__ */ jsx("h2", { children: node.key }), /* @__PURE__ */ jsx("span", {
1030
- className: "type detail",
1031
- children: " (family)"
1032
- })] })] }), isOpen ? [...node.familyMembers.entries()].map(([key, childNode]) => /* @__PURE__ */ jsx(StateIndexNode, {
1090
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("header", { children: /* @__PURE__ */ jsxs("main", { children: [
1091
+ /* @__PURE__ */ jsx(button.OpenClose, {
1092
+ isOpen,
1093
+ testid: `open-close-state-family-${node.key}`,
1094
+ onShiftClick: () => {
1095
+ actUponStore(store, openCloseAllTX, arbitrary())([node.key], isOpen);
1096
+ return false;
1097
+ },
1098
+ setIsOpen
1099
+ }),
1100
+ /* @__PURE__ */ jsx("h2", { children: node.key }),
1101
+ /* @__PURE__ */ jsx("span", {
1102
+ className: "type detail",
1103
+ children: " (family)"
1104
+ })
1105
+ ] }) }), isOpen ? [...node.familyMembers.entries()].map(([key, childNode]) => /* @__PURE__ */ jsx(StateIndexNode, {
1033
1106
  node: childNode,
1034
- isOpenState: findInStore(store, viewIsOpenAtoms, childNode.key),
1107
+ isOpenState: findInStore(store, viewIsOpenAtoms, [node.key, key]),
1035
1108
  typeState: findInStore(store, typeSelectors, childNode.key)
1036
1109
  }, key)) : null] });
1037
1110
  };
@@ -1052,14 +1125,13 @@ const StateIndexNode = ({ node, isOpenState, typeState }) => {
1052
1125
  const StateIndex = ({ tokenIndex }) => {
1053
1126
  const tokenIds = useO$1(tokenIndex);
1054
1127
  const { typeSelectors, viewIsOpenAtoms, store } = useContext(DevtoolsContext);
1055
- console.log(tokenIds);
1056
1128
  return /* @__PURE__ */ jsx("article", {
1057
1129
  className: "index state_index",
1058
1130
  "data-testid": "state-index",
1059
1131
  children: [...tokenIds.entries()].map(([key, node]) => {
1060
1132
  return /* @__PURE__ */ jsx(StateIndexNode, {
1061
1133
  node,
1062
- isOpenState: findInStore(store, viewIsOpenAtoms, node.key),
1134
+ isOpenState: findInStore(store, viewIsOpenAtoms, [node.key]),
1063
1135
  typeState: findInStore(store, typeSelectors, node.key)
1064
1136
  }, key);
1065
1137
  })
@@ -1270,7 +1342,7 @@ const TimelineIndex = () => {
1270
1342
  children: tokenIds.filter((token) => !token.key.startsWith(`👁‍🗨`)).map((token) => {
1271
1343
  return /* @__PURE__ */ jsx(TimelineLog, {
1272
1344
  token,
1273
- isOpenState: findInStore(store, viewIsOpenAtoms, token.key),
1345
+ isOpenState: findInStore(store, viewIsOpenAtoms, [token.key]),
1274
1346
  timelineState: findInStore(store, timelineSelectors, token.key)
1275
1347
  }, token.key);
1276
1348
  })
@@ -1312,7 +1384,7 @@ const TransactionIndex = () => {
1312
1384
  children: tokenIds.filter((token) => !token.key.startsWith(`🔍`)).map((token) => {
1313
1385
  return /* @__PURE__ */ jsx(TransactionLog, {
1314
1386
  token,
1315
- isOpenState: findInStore(store, viewIsOpenAtoms, token.key),
1387
+ isOpenState: findInStore(store, viewIsOpenAtoms, [token.key]),
1316
1388
  logState: findInStore(store, transactionLogSelectors, token.key)
1317
1389
  }, token.key);
1318
1390
  })