@buoy-gg/shared-ui 7.0.29 → 7.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/lib/commonjs/JsModal.js +18 -2
  2. package/lib/commonjs/JsModal.web.js +7 -4
  3. package/lib/commonjs/dataViewer/DataTreeActionDock.js +4 -2
  4. package/lib/commonjs/dataViewer/LiveExplorer.js +930 -0
  5. package/lib/commonjs/dataViewer/ValueEditModal.js +385 -0
  6. package/lib/commonjs/dataViewer/index.js +47 -0
  7. package/lib/commonjs/dataViewer/nestedPath.js +115 -0
  8. package/lib/commonjs/dataViewer/treeActions.js +3 -2
  9. package/lib/commonjs/dataViewer/useTreeDraft.js +125 -0
  10. package/lib/commonjs/dataViewer/useTreeEditor.js +105 -0
  11. package/lib/commonjs/env/EnvironmentIndicator.js +7 -1
  12. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  13. package/lib/commonjs/index.js +24 -0
  14. package/lib/commonjs/license/tierLimits.js +14 -0
  15. package/lib/commonjs/storage/devToolsStorageKeys.js +36 -0
  16. package/lib/commonjs/sync/toolActionRegistry.js +166 -0
  17. package/lib/commonjs/sync/toolUiBridge.js +74 -0
  18. package/lib/commonjs/ui/components/CompactRow.js +4 -0
  19. package/lib/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.js +9 -1
  20. package/lib/commonjs/ui/components/ExpandedInfoRow.js +3 -1
  21. package/lib/commonjs/ui/components/ModalHeader.js +7 -4
  22. package/lib/commonjs/ui/components/SearchBar.js +5 -109
  23. package/lib/commonjs/ui/components/ToolButton.js +5 -2
  24. package/lib/module/JsModal.js +18 -2
  25. package/lib/module/JsModal.web.js +7 -4
  26. package/lib/module/dataViewer/DataTreeActionDock.js +4 -2
  27. package/lib/module/dataViewer/LiveExplorer.js +925 -0
  28. package/lib/module/dataViewer/ValueEditModal.js +381 -0
  29. package/lib/module/dataViewer/index.js +10 -1
  30. package/lib/module/dataViewer/nestedPath.js +109 -0
  31. package/lib/module/dataViewer/treeActions.js +3 -2
  32. package/lib/module/dataViewer/useTreeDraft.js +121 -0
  33. package/lib/module/dataViewer/useTreeEditor.js +101 -0
  34. package/lib/module/env/EnvironmentIndicator.js +7 -1
  35. package/lib/module/hooks/safe-area-impl.js +1 -1
  36. package/lib/module/index.js +2 -0
  37. package/lib/module/license/tierLimits.js +14 -0
  38. package/lib/module/storage/devToolsStorageKeys.js +36 -0
  39. package/lib/module/sync/toolActionRegistry.js +154 -0
  40. package/lib/module/sync/toolUiBridge.js +68 -0
  41. package/lib/module/ui/components/CompactRow.js +4 -0
  42. package/lib/module/ui/components/EventHistoryViewer/DiffModeTabs.js +9 -1
  43. package/lib/module/ui/components/ExpandedInfoRow.js +3 -1
  44. package/lib/module/ui/components/ModalHeader.js +7 -4
  45. package/lib/module/ui/components/SearchBar.js +8 -112
  46. package/lib/module/ui/components/ToolButton.js +5 -2
  47. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/JsModal.web.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts +6 -1
  50. package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/dataViewer/LiveExplorer.d.ts +73 -0
  52. package/lib/typescript/commonjs/dataViewer/LiveExplorer.d.ts.map +1 -0
  53. package/lib/typescript/commonjs/dataViewer/ValueEditModal.d.ts +40 -0
  54. package/lib/typescript/commonjs/dataViewer/ValueEditModal.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/dataViewer/index.d.ts +5 -0
  56. package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/dataViewer/nestedPath.d.ts +20 -0
  58. package/lib/typescript/commonjs/dataViewer/nestedPath.d.ts.map +1 -0
  59. package/lib/typescript/commonjs/dataViewer/treeActions.d.ts +10 -0
  60. package/lib/typescript/commonjs/dataViewer/treeActions.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/dataViewer/useTreeDraft.d.ts +81 -0
  62. package/lib/typescript/commonjs/dataViewer/useTreeDraft.d.ts.map +1 -0
  63. package/lib/typescript/commonjs/dataViewer/useTreeEditor.d.ts +52 -0
  64. package/lib/typescript/commonjs/dataViewer/useTreeEditor.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/env/EnvironmentIndicator.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  67. package/lib/typescript/commonjs/index.d.ts +2 -0
  68. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/license/tierLimits.d.ts +10 -0
  70. package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +36 -0
  72. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/sync/toolActionRegistry.d.ts +85 -0
  74. package/lib/typescript/commonjs/sync/toolActionRegistry.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/sync/toolUiBridge.d.ts +39 -0
  76. package/lib/typescript/commonjs/sync/toolUiBridge.d.ts.map +1 -0
  77. package/lib/typescript/commonjs/ui/components/CompactRow.d.ts +5 -1
  78. package/lib/typescript/commonjs/ui/components/CompactRow.d.ts.map +1 -1
  79. package/lib/typescript/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts +6 -0
  81. package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/components/ExpandedInfoRow.d.ts +7 -1
  83. package/lib/typescript/commonjs/ui/components/ExpandedInfoRow.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/ui/components/SearchBar.d.ts +1 -3
  85. package/lib/typescript/commonjs/ui/components/SearchBar.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/ui/components/ToolButton.d.ts +5 -1
  87. package/lib/typescript/commonjs/ui/components/ToolButton.d.ts.map +1 -1
  88. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  89. package/lib/typescript/module/JsModal.web.d.ts.map +1 -1
  90. package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts +6 -1
  91. package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts.map +1 -1
  92. package/lib/typescript/module/dataViewer/LiveExplorer.d.ts +73 -0
  93. package/lib/typescript/module/dataViewer/LiveExplorer.d.ts.map +1 -0
  94. package/lib/typescript/module/dataViewer/ValueEditModal.d.ts +40 -0
  95. package/lib/typescript/module/dataViewer/ValueEditModal.d.ts.map +1 -0
  96. package/lib/typescript/module/dataViewer/index.d.ts +5 -0
  97. package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
  98. package/lib/typescript/module/dataViewer/nestedPath.d.ts +20 -0
  99. package/lib/typescript/module/dataViewer/nestedPath.d.ts.map +1 -0
  100. package/lib/typescript/module/dataViewer/treeActions.d.ts +10 -0
  101. package/lib/typescript/module/dataViewer/treeActions.d.ts.map +1 -1
  102. package/lib/typescript/module/dataViewer/useTreeDraft.d.ts +81 -0
  103. package/lib/typescript/module/dataViewer/useTreeDraft.d.ts.map +1 -0
  104. package/lib/typescript/module/dataViewer/useTreeEditor.d.ts +52 -0
  105. package/lib/typescript/module/dataViewer/useTreeEditor.d.ts.map +1 -0
  106. package/lib/typescript/module/env/EnvironmentIndicator.d.ts.map +1 -1
  107. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  108. package/lib/typescript/module/index.d.ts +2 -0
  109. package/lib/typescript/module/index.d.ts.map +1 -1
  110. package/lib/typescript/module/license/tierLimits.d.ts +10 -0
  111. package/lib/typescript/module/license/tierLimits.d.ts.map +1 -1
  112. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +36 -0
  113. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
  114. package/lib/typescript/module/sync/toolActionRegistry.d.ts +85 -0
  115. package/lib/typescript/module/sync/toolActionRegistry.d.ts.map +1 -0
  116. package/lib/typescript/module/sync/toolUiBridge.d.ts +39 -0
  117. package/lib/typescript/module/sync/toolUiBridge.d.ts.map +1 -0
  118. package/lib/typescript/module/ui/components/CompactRow.d.ts +5 -1
  119. package/lib/typescript/module/ui/components/CompactRow.d.ts.map +1 -1
  120. package/lib/typescript/module/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
  121. package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts +6 -0
  122. package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
  123. package/lib/typescript/module/ui/components/ExpandedInfoRow.d.ts +7 -1
  124. package/lib/typescript/module/ui/components/ExpandedInfoRow.d.ts.map +1 -1
  125. package/lib/typescript/module/ui/components/SearchBar.d.ts +1 -3
  126. package/lib/typescript/module/ui/components/SearchBar.d.ts.map +1 -1
  127. package/lib/typescript/module/ui/components/ToolButton.d.ts +5 -1
  128. package/lib/typescript/module/ui/components/ToolButton.d.ts.map +1 -1
  129. package/package.json +4 -4
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ValueEditModal = ValueEditModal;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _absoluteFill = require("../utils/absoluteFill.js");
10
+ var _index = require("../ui/gameUI/index.js");
11
+ var _nightTheme = require("../ui/night/nightTheme.js");
12
+ var _treeActions = require("./treeActions.js");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ /**
15
+ * Editing one value: a panel at the top of the screen, with Cancel and Save.
16
+ *
17
+ * This started as a pushed full screen and that was more ceremony than the task
18
+ * deserves — changing one string is the most ordinary thing in these tools, and
19
+ * it shouldn't cost a navigation. A modal is what people expect, and the reason
20
+ * it's pinned to the TOP rather than centred is the keyboard: a centred panel
21
+ * gets shoved up or covered the moment the field focuses, and a bottom sheet is
22
+ * simply underneath it. At the top it stays put and stays readable.
23
+ *
24
+ * The field is multiline for anything textual. Stored values are routinely
25
+ * tokens, URLs and serialized blobs, and a single line shows you roughly forty
26
+ * characters of them, scrolling sideways — which is how you edit the wrong part
27
+ * of a string without noticing.
28
+ *
29
+ * Type is preserved by construction: the ORIGINAL value's type picks the editor
30
+ * AND decides how the draft is read back, so editing a number can only produce
31
+ * a number. Raw JSON — the escape hatch for containers — re-checks the parsed
32
+ * result and refuses a different shape.
33
+ *
34
+ * Nothing here writes. `onSave` hands the value to whoever owns it.
35
+ *
36
+ * Hoisted from the Storage tool (which keeps its testIDs via `testIDPrefix`)
37
+ * so the Zustand store editor types values through the same rules.
38
+ */
39
+
40
+ /**
41
+ * How this value gets edited. Driven by the value's own type, which is also
42
+ * what makes the result type-safe without asking the user to declare anything.
43
+ */
44
+
45
+ function modeFor(value) {
46
+ if (typeof value === "boolean") return "boolean";
47
+ if (typeof value === "number") return "number";
48
+ if (value !== null && typeof value === "object") return "raw";
49
+ return "text";
50
+ }
51
+ function initialText(value, mode) {
52
+ if (mode === "raw") return JSON.stringify(value, null, 2);
53
+ if (value === null || value === undefined) return "";
54
+ return String(value);
55
+ }
56
+ function hintFor(mode, type) {
57
+ switch (mode) {
58
+ case "number":
59
+ return "Numeric only — anything else is refused, so this stays a number.";
60
+ case "raw":
61
+ return `Raw JSON. Must stay ${type === "array" ? "an array" : "an object"} — a different shape is refused.`;
62
+ default:
63
+ return "Saves as a string. The type never changes here.";
64
+ }
65
+ }
66
+ function ValueEditModal({
67
+ path,
68
+ value,
69
+ onSave,
70
+ onCancel,
71
+ saveLabel = "Save",
72
+ busy = false,
73
+ testIDPrefix = "buoy-data-value"
74
+ }) {
75
+ const mode = modeFor(value);
76
+ const type = (0, _treeActions.typeLabel)(value);
77
+ const [text, setText] = (0, _react.useState)(() => initialText(value, mode));
78
+
79
+ /**
80
+ * Advisory only — {@link commit} re-derives it, so a disabled button and a
81
+ * refused save can never disagree about what's valid.
82
+ */
83
+ const error = validate(text, mode, type);
84
+ const blocked = busy || error != null;
85
+ const commit = () => {
86
+ if (busy || validate(text, mode, type) != null) return;
87
+ onSave(parse(text, mode, value));
88
+ };
89
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
90
+ style: styles.overlay,
91
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
92
+ style: styles.scrim,
93
+ activeOpacity: 1,
94
+ onPress: busy ? undefined : onCancel,
95
+ testID: `${testIDPrefix}-scrim`,
96
+ accessibilityRole: "button",
97
+ accessibilityLabel: "Dismiss editor"
98
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
99
+ style: styles.panel,
100
+ pointerEvents: "box-none",
101
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
102
+ style: styles.card,
103
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
104
+ style: styles.headerRow,
105
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
106
+ style: styles.title,
107
+ children: "Edit value"
108
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
109
+ style: styles.typeBadge,
110
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
111
+ style: styles.typeBadgeText,
112
+ children: type
113
+ })
114
+ })]
115
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
116
+ style: styles.path,
117
+ numberOfLines: 1,
118
+ children: (0, _treeActions.breadcrumb)(path)
119
+ }), mode === "boolean" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(BooleanChoice, {
120
+ current: value === true,
121
+ onPick: onSave,
122
+ testIDPrefix: testIDPrefix
123
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
124
+ style: styles.fieldScroll,
125
+ keyboardShouldPersistTaps: "handled",
126
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
127
+ testID: `${testIDPrefix}-input`,
128
+ accessibilityLabel: "Value",
129
+ value: text,
130
+ onChangeText: setText,
131
+ autoFocus: true,
132
+ autoCapitalize: "none",
133
+ autoCorrect: false,
134
+ spellCheck: false,
135
+ editable: !busy
136
+ // Multiline for anything textual: stored values are long more
137
+ // often than they're short, and a single line hides that.
138
+ ,
139
+ multiline: mode !== "number"
140
+ // ASCII for raw JSON, because iOS Smart Punctuation is ON by
141
+ // default and rewrites the quotes you type as curly ones —
142
+ // which makes the text unparseable, disables Save, and leaves
143
+ // an "invalid JSON" message whose cause is invisible at a
144
+ // glance. An ASCII keyboard doesn't do the substitution.
145
+ ,
146
+ keyboardType: mode === "number" ? "numeric" : mode === "raw" ? "ascii-capable" : "default",
147
+ onSubmitEditing: mode === "number" ? commit : undefined,
148
+ placeholder: mode === "raw" ? "{ }" : "value",
149
+ placeholderTextColor: _nightTheme.night.color.placeholder,
150
+ style: [styles.input, mode === "raw" && styles.inputRaw, mode !== "number" && styles.inputMultiline, error != null && styles.inputInvalid]
151
+ })
152
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
153
+ style: error != null ? styles.error : styles.hint,
154
+ children: error ?? hintFor(mode, type)
155
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
156
+ style: styles.actions,
157
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
158
+ onPress: onCancel,
159
+ disabled: busy,
160
+ testID: `${testIDPrefix}-cancel`,
161
+ accessibilityRole: "button",
162
+ accessibilityLabel: "Cancel edit",
163
+ style: styles.cancelButton,
164
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
165
+ style: styles.cancelText,
166
+ children: "Cancel"
167
+ })
168
+ }), mode === "boolean" ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
169
+ onPress: commit,
170
+ disabled: blocked,
171
+ testID: `${testIDPrefix}-save`,
172
+ accessibilityRole: "button",
173
+ accessibilityLabel: saveLabel,
174
+ style: [styles.saveButton, blocked && styles.saveDisabled],
175
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
176
+ style: styles.saveText,
177
+ children: busy ? "Saving…" : saveLabel
178
+ })
179
+ })]
180
+ })]
181
+ })
182
+ })]
183
+ });
184
+ }
185
+ function BooleanChoice({
186
+ current,
187
+ onPick,
188
+ testIDPrefix
189
+ }) {
190
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
191
+ style: styles.boolRow,
192
+ children: [true, false].map(option => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
193
+ onPress: () => onPick(option),
194
+ testID: `${testIDPrefix}-${option}`,
195
+ accessibilityRole: "button",
196
+ accessibilityLabel: `Set ${option}`,
197
+ style: [styles.boolButton, current === option && styles.boolActive],
198
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
199
+ style: [styles.boolText, current === option && styles.boolTextActive],
200
+ children: String(option)
201
+ })
202
+ }, String(option)))
203
+ });
204
+ }
205
+
206
+ /** Null when the draft is applicable, else why it isn't. */
207
+ function validate(text, mode, type) {
208
+ if (mode === "number") {
209
+ if (text.trim() === "") return "Enter a number.";
210
+ if (Number.isNaN(Number(text))) return `"${text}" isn't a number.`;
211
+ return null;
212
+ }
213
+ if (mode === "raw") {
214
+ let parsed;
215
+ try {
216
+ parsed = JSON.parse(text);
217
+ } catch (e) {
218
+ return e instanceof Error ? e.message : "Invalid JSON.";
219
+ }
220
+ if ((0, _treeActions.typeLabel)(parsed) !== type) {
221
+ return `Must stay ${type} — that parses as ${(0, _treeActions.typeLabel)(parsed)}.`;
222
+ }
223
+ return null;
224
+ }
225
+ return null;
226
+ }
227
+ function parse(text, mode, original) {
228
+ if (mode === "number") return Number(text);
229
+ if (mode === "raw") return JSON.parse(text);
230
+ // An emptied field on a null keeps it null rather than silently minting an
231
+ // empty string, which would change the type this promised to preserve.
232
+ if (original === null && text === "") return null;
233
+ return text;
234
+ }
235
+ const styles = _reactNative.StyleSheet.create({
236
+ overlay: {
237
+ ..._absoluteFill.absoluteFill,
238
+ zIndex: 20
239
+ },
240
+ scrim: {
241
+ ..._absoluteFill.absoluteFill,
242
+ backgroundColor: "rgba(0,0,0,0.55)"
243
+ },
244
+ /** Pinned to the top so the keyboard can't reach it. */
245
+ panel: {
246
+ padding: 12
247
+ },
248
+ card: {
249
+ backgroundColor: _nightTheme.night.color.surface,
250
+ borderRadius: 14,
251
+ borderWidth: 1,
252
+ borderColor: _nightTheme.night.color.border,
253
+ padding: 14,
254
+ gap: 8
255
+ },
256
+ headerRow: {
257
+ flexDirection: "row",
258
+ alignItems: "center",
259
+ gap: 8
260
+ },
261
+ title: {
262
+ flex: 1,
263
+ color: _nightTheme.night.color.text,
264
+ fontSize: 14,
265
+ fontWeight: "700"
266
+ },
267
+ typeBadge: {
268
+ paddingHorizontal: 8,
269
+ paddingVertical: 2,
270
+ borderRadius: 6,
271
+ backgroundColor: _nightTheme.night.color.surfaceElevated
272
+ },
273
+ typeBadgeText: {
274
+ color: _index.macOSColors.semantic.warning,
275
+ fontSize: 10,
276
+ fontWeight: "700",
277
+ fontFamily: "monospace"
278
+ },
279
+ path: {
280
+ color: _nightTheme.night.color.textTertiary,
281
+ fontSize: 11,
282
+ fontFamily: "monospace"
283
+ },
284
+ /** Caps the panel's height so a huge blob can't push the buttons off-screen. */
285
+ fieldScroll: {
286
+ maxHeight: 240
287
+ },
288
+ input: {
289
+ color: _nightTheme.night.color.text,
290
+ backgroundColor: _nightTheme.night.color.surfaceElevated,
291
+ borderWidth: 1,
292
+ borderColor: _nightTheme.night.color.border,
293
+ borderRadius: 10,
294
+ paddingHorizontal: 12,
295
+ paddingVertical: 10,
296
+ fontSize: 14,
297
+ fontFamily: "monospace"
298
+ },
299
+ inputMultiline: {
300
+ minHeight: 110,
301
+ lineHeight: 20,
302
+ textAlignVertical: "top"
303
+ },
304
+ inputRaw: {
305
+ minHeight: 180,
306
+ fontSize: 12,
307
+ lineHeight: 18
308
+ },
309
+ inputInvalid: {
310
+ borderColor: _nightTheme.night.color.danger
311
+ },
312
+ hint: {
313
+ color: _nightTheme.night.color.textTertiary,
314
+ fontSize: 11,
315
+ lineHeight: 16
316
+ },
317
+ error: {
318
+ color: _nightTheme.night.color.danger,
319
+ fontSize: 11,
320
+ lineHeight: 16,
321
+ fontFamily: "monospace"
322
+ },
323
+ actions: {
324
+ flexDirection: "row",
325
+ gap: 8,
326
+ paddingTop: 2
327
+ },
328
+ cancelButton: {
329
+ flex: 1,
330
+ minHeight: 44,
331
+ alignItems: "center",
332
+ justifyContent: "center",
333
+ borderRadius: 10,
334
+ borderWidth: 1,
335
+ borderColor: _nightTheme.night.color.border
336
+ },
337
+ cancelText: {
338
+ color: _nightTheme.night.color.textSecondary,
339
+ fontSize: 14,
340
+ fontWeight: "600"
341
+ },
342
+ saveButton: {
343
+ flex: 1.4,
344
+ minHeight: 44,
345
+ alignItems: "center",
346
+ justifyContent: "center",
347
+ borderRadius: 10,
348
+ backgroundColor: _nightTheme.night.color.accent
349
+ },
350
+ saveDisabled: {
351
+ opacity: 0.35
352
+ },
353
+ saveText: {
354
+ color: _nightTheme.night.color.onAccent,
355
+ fontSize: 15,
356
+ fontWeight: "700"
357
+ },
358
+ boolRow: {
359
+ flexDirection: "row",
360
+ gap: 10
361
+ },
362
+ boolButton: {
363
+ flex: 1,
364
+ minHeight: 64,
365
+ alignItems: "center",
366
+ justifyContent: "center",
367
+ borderRadius: 12,
368
+ borderWidth: 1,
369
+ borderColor: _nightTheme.night.color.border,
370
+ backgroundColor: _nightTheme.night.color.surfaceElevated
371
+ },
372
+ boolActive: {
373
+ borderColor: _index.macOSColors.semantic.warning,
374
+ backgroundColor: _index.macOSColors.semantic.warning + "18"
375
+ },
376
+ boolText: {
377
+ color: _nightTheme.night.color.textTertiary,
378
+ fontSize: 16,
379
+ fontWeight: "700",
380
+ fontFamily: "monospace"
381
+ },
382
+ boolTextActive: {
383
+ color: _index.macOSColors.semantic.warning
384
+ }
385
+ });
@@ -69,6 +69,12 @@ Object.defineProperty(exports, "JsonStringNotice", {
69
69
  return _JsonStringNotice.JsonStringNotice;
70
70
  }
71
71
  });
72
+ Object.defineProperty(exports, "LiveExplorer", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _LiveExplorer.LiveExplorer;
76
+ }
77
+ });
72
78
  Object.defineProperty(exports, "SplitDiffViewer", {
73
79
  enumerable: true,
74
80
  get: function () {
@@ -99,6 +105,12 @@ Object.defineProperty(exports, "TypeLegend", {
99
105
  return _TypeLegend.TypeLegend;
100
106
  }
101
107
  });
108
+ Object.defineProperty(exports, "ValueEditModal", {
109
+ enumerable: true,
110
+ get: function () {
111
+ return _ValueEditModal.ValueEditModal;
112
+ }
113
+ });
102
114
  Object.defineProperty(exports, "VirtualizedDataExplorer", {
103
115
  enumerable: true,
104
116
  get: function () {
@@ -135,6 +147,12 @@ Object.defineProperty(exports, "decodeJsonStringPair", {
135
147
  return _jsonStringValue.decodeJsonStringPair;
136
148
  }
137
149
  });
150
+ Object.defineProperty(exports, "deleteNestedDataByPath", {
151
+ enumerable: true,
152
+ get: function () {
153
+ return _nestedPath.deleteNestedDataByPath;
154
+ }
155
+ });
138
156
  Object.defineProperty(exports, "describeTimestampDeltas", {
139
157
  enumerable: true,
140
158
  get: function () {
@@ -201,6 +219,12 @@ Object.defineProperty(exports, "jsonLikelyLargerThan", {
201
219
  return _objectDiff.jsonLikelyLargerThan;
202
220
  }
203
221
  });
222
+ Object.defineProperty(exports, "makeRootWriter", {
223
+ enumerable: true,
224
+ get: function () {
225
+ return _LiveExplorer.makeRootWriter;
226
+ }
227
+ });
204
228
  Object.defineProperty(exports, "objectDiff", {
205
229
  enumerable: true,
206
230
  get: function () {
@@ -249,6 +273,24 @@ Object.defineProperty(exports, "typeLabel", {
249
273
  return _treeActions.typeLabel;
250
274
  }
251
275
  });
276
+ Object.defineProperty(exports, "updateNestedDataByPath", {
277
+ enumerable: true,
278
+ get: function () {
279
+ return _nestedPath.updateNestedDataByPath;
280
+ }
281
+ });
282
+ Object.defineProperty(exports, "useTreeDraft", {
283
+ enumerable: true,
284
+ get: function () {
285
+ return _useTreeDraft.useTreeDraft;
286
+ }
287
+ });
288
+ Object.defineProperty(exports, "useTreeEditor", {
289
+ enumerable: true,
290
+ get: function () {
291
+ return _useTreeEditor.useTreeEditor;
292
+ }
293
+ });
252
294
  var _DataViewer = require("./DataViewer.js");
253
295
  var _VirtualizedDataExplorer = require("./VirtualizedDataExplorer.js");
254
296
  var _TypeLegend = require("./TypeLegend.js");
@@ -270,4 +312,9 @@ var _lineDiff = require("./lineDiff.js");
270
312
  var _diffThemes = require("./diffThemes.js");
271
313
  var _objectDiff = require("./objectDiff.js");
272
314
  var _ThemedSplitView = require("./ThemedSplitView.js");
315
+ var _useTreeDraft = require("./useTreeDraft.js");
316
+ var _useTreeEditor = require("./useTreeEditor.js");
317
+ var _ValueEditModal = require("./ValueEditModal.js");
318
+ var _LiveExplorer = require("./LiveExplorer.js");
319
+ var _nestedPath = require("./nestedPath.js");
273
320
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.updateNestedDataByPath = exports.deleteNestedDataByPath = void 0;
7
+ /**
8
+ * Immutable path writes over arbitrary JSON-ish data — the write kernel the
9
+ * live explorer edits through.
10
+ *
11
+ * Hoisted verbatim from @buoy-gg/react-query (utils/updateNestedDataByPath +
12
+ * utils/deleteNestedDataByPath), where the RQ Data Editor has run on them in
13
+ * production; react-query re-exports from here. Handles objects, arrays, and
14
+ * Map/Set (a Set edit round-trips through an array).
15
+ */
16
+
17
+ /**
18
+ * Returns a copy of `oldData` with the node at `updatePath` replaced by
19
+ * `value`. An empty path replaces the whole document.
20
+ */
21
+ const updateNestedDataByPath = (oldData, updatePath, value) => {
22
+ if (updatePath.length === 0) {
23
+ return value;
24
+ }
25
+ if (oldData instanceof Map) {
26
+ const newData = new Map(oldData);
27
+ if (updatePath.length === 1) {
28
+ newData.set(updatePath[0], value);
29
+ return newData;
30
+ }
31
+ const [head, ...tail] = updatePath;
32
+ const currentValue = newData.get(head);
33
+ newData.set(head, updateNestedDataByPath(currentValue ?? null, tail, value));
34
+ return newData;
35
+ }
36
+ if (oldData instanceof Set) {
37
+ const setAsArray = updateNestedDataByPath(Array.from(oldData), updatePath, value);
38
+ return new Set(Array.isArray(setAsArray) ? setAsArray : []);
39
+ }
40
+ if (Array.isArray(oldData)) {
41
+ const newData = [...oldData];
42
+ if (updatePath.length === 1) {
43
+ // @ts-expect-error NAS
44
+ newData[updatePath[0]] = value;
45
+ return newData;
46
+ }
47
+ const [head, ...tail] = updatePath;
48
+ // @ts-expect-error NAS
49
+ newData[head] = updateNestedDataByPath(newData[head], tail, value);
50
+ return newData;
51
+ }
52
+ if (oldData instanceof Object) {
53
+ const newData = {
54
+ ...oldData
55
+ };
56
+ if (updatePath.length === 1) {
57
+ // @ts-expect-error NAS
58
+ newData[updatePath[0]] = value;
59
+ return newData;
60
+ }
61
+ const [head, ...tail] = updatePath;
62
+ // @ts-expect-error NAS
63
+ newData[head] = updateNestedDataByPath(newData[head], tail, value);
64
+ return newData;
65
+ }
66
+ return oldData;
67
+ };
68
+
69
+ /**
70
+ * Returns a copy of `oldData` without the node at `deletePath`.
71
+ */
72
+ exports.updateNestedDataByPath = updateNestedDataByPath;
73
+ const deleteNestedDataByPath = (oldData, deletePath) => {
74
+ if (oldData instanceof Map) {
75
+ const newData = new Map(oldData);
76
+ if (deletePath.length === 1) {
77
+ newData.delete(deletePath[0]);
78
+ return newData;
79
+ }
80
+ const [head, ...tail] = deletePath;
81
+ newData.set(head, deleteNestedDataByPath(newData.get(head), tail));
82
+ return newData;
83
+ }
84
+ if (oldData instanceof Set) {
85
+ const setAsArray = deleteNestedDataByPath(Array.from(oldData), deletePath);
86
+ return new Set(setAsArray);
87
+ }
88
+ if (Array.isArray(oldData)) {
89
+ const newData = [...oldData];
90
+ if (deletePath.length === 1) {
91
+ return newData.filter((_, idx) => idx.toString() !== deletePath[0]);
92
+ }
93
+ const [head, ...tail] = deletePath;
94
+
95
+ // @ts-expect-error NAS
96
+ newData[head] = deleteNestedDataByPath(newData[head], tail);
97
+ return newData;
98
+ }
99
+ if (oldData instanceof Object) {
100
+ const newData = {
101
+ ...oldData
102
+ };
103
+ if (deletePath.length === 1) {
104
+ // @ts-expect-error NAS
105
+ delete newData[deletePath[0]];
106
+ return newData;
107
+ }
108
+ const [head, ...tail] = deletePath;
109
+ // @ts-expect-error NAS
110
+ newData[head] = deleteNestedDataByPath(newData[head], tail);
111
+ return newData;
112
+ }
113
+ return oldData;
114
+ };
115
+ exports.deleteNestedDataByPath = deleteNestedDataByPath;
@@ -75,6 +75,7 @@ function treeActionsFor(root, selection, options = {}) {
75
75
  const value = selection?.value;
76
76
  const has = selection != null;
77
77
  const isRoot = path.length === 0;
78
+ const removeLocked = options.rootEntriesLocked === true && path.length === 1;
78
79
  const parent = has && !isRoot ? (0, _jsonOps.getAtPath)(root, path.slice(0, -1)) : undefined;
79
80
  const parentIsArray = Array.isArray(parent);
80
81
  const index = parentIsArray ? Number(path[path.length - 1]) : -1;
@@ -158,8 +159,8 @@ function treeActionsFor(root, selection, options = {}) {
158
159
  id: "remove",
159
160
  label: "Remove",
160
161
  danger: true,
161
- enabled: has && !isRoot,
162
- op: has && !isRoot ? {
162
+ enabled: has && !isRoot && !removeLocked,
163
+ op: has && !isRoot && !removeLocked ? {
163
164
  kind: "remove",
164
165
  path
165
166
  } : null