@buoy-gg/time-machine 7.0.40 → 7.0.42

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 (173) hide show
  1. package/README.md +4 -0
  2. package/lib/commonjs/components/HeaderActions.js +1 -91
  3. package/lib/commonjs/components/HeaderReloadButton.js +1 -58
  4. package/lib/commonjs/components/TimeMachineBody.js +1 -282
  5. package/lib/commonjs/components/TimeMachineModal.js +1 -74
  6. package/lib/commonjs/components/confirm.js +2 -38
  7. package/lib/commonjs/components/floating/NamePromptModal.js +1 -193
  8. package/lib/commonjs/components/floating/TimeMachineFloatingTool.js +1 -715
  9. package/lib/commonjs/components/floating/armedPoint.js +1 -92
  10. package/lib/commonjs/components/floating/barSettings.js +1 -66
  11. package/lib/commonjs/components/format.js +1 -24
  12. package/lib/commonjs/components/list/CaptureBar.js +1 -97
  13. package/lib/commonjs/components/list/RestoreOutcomeCard.js +1 -175
  14. package/lib/commonjs/components/list/SnapshotRow.js +1 -170
  15. package/lib/commonjs/components/list/SourcesStrip.js +1 -172
  16. package/lib/commonjs/components/list/UndoDeleteBar.js +1 -85
  17. package/lib/commonjs/components/list/WipeAllRow.js +1 -46
  18. package/lib/commonjs/components/preview/ItemDiffPanel.js +1 -79
  19. package/lib/commonjs/components/preview/PreviewFlow.js +1 -51
  20. package/lib/commonjs/components/preview/RestorePointNameRow.js +1 -83
  21. package/lib/commonjs/components/preview/RestorePreviewScreen.js +1 -1010
  22. package/lib/commonjs/components/preview/verdictMeta.js +1 -58
  23. package/lib/commonjs/components/sources.js +1 -83
  24. package/lib/commonjs/hooks/useTimeMachine.js +1 -24
  25. package/lib/commonjs/index.js +1 -161
  26. package/lib/commonjs/preset.js +1 -56
  27. package/lib/commonjs/store/routeRestore.js +1 -188
  28. package/lib/commonjs/store/snapshotVault.js +1 -186
  29. package/lib/commonjs/store/sourceIds.js +1 -9
  30. package/lib/commonjs/store/sourceSettings.js +1 -79
  31. package/lib/commonjs/store/timeMachineStore.js +1 -848
  32. package/lib/commonjs/sync/timeMachineSyncAdapter.js +1 -258
  33. package/lib/commonjs/ui/SwipeActionsRow.js +1 -178
  34. package/lib/commonjs/ui/primitives.js +1 -172
  35. package/lib/commonjs/ui/tmTheme.js +1 -118
  36. package/lib/module/components/HeaderActions.js +1 -85
  37. package/lib/module/components/HeaderReloadButton.js +1 -53
  38. package/lib/module/components/TimeMachineBody.js +1 -277
  39. package/lib/module/components/TimeMachineModal.js +1 -68
  40. package/lib/module/components/confirm.js +2 -33
  41. package/lib/module/components/floating/NamePromptModal.js +1 -188
  42. package/lib/module/components/floating/TimeMachineFloatingTool.js +1 -708
  43. package/lib/module/components/floating/armedPoint.js +1 -82
  44. package/lib/module/components/floating/barSettings.js +1 -57
  45. package/lib/module/components/format.js +1 -19
  46. package/lib/module/components/list/CaptureBar.js +1 -92
  47. package/lib/module/components/list/RestoreOutcomeCard.js +1 -169
  48. package/lib/module/components/list/SnapshotRow.js +1 -167
  49. package/lib/module/components/list/SourcesStrip.js +1 -169
  50. package/lib/module/components/list/UndoDeleteBar.js +1 -82
  51. package/lib/module/components/list/WipeAllRow.js +1 -41
  52. package/lib/module/components/preview/ItemDiffPanel.js +1 -74
  53. package/lib/module/components/preview/PreviewFlow.js +1 -46
  54. package/lib/module/components/preview/RestorePointNameRow.js +1 -78
  55. package/lib/module/components/preview/RestorePreviewScreen.js +1 -1005
  56. package/lib/module/components/preview/verdictMeta.js +1 -54
  57. package/lib/module/components/sources.js +1 -73
  58. package/lib/module/hooks/useTimeMachine.js +1 -19
  59. package/lib/module/index.js +1 -46
  60. package/lib/module/preset.js +1 -51
  61. package/lib/module/store/routeRestore.js +1 -176
  62. package/lib/module/store/snapshotVault.js +1 -170
  63. package/lib/module/store/sourceIds.js +1 -5
  64. package/lib/module/store/sourceSettings.js +1 -69
  65. package/lib/module/store/timeMachineStore.js +1 -839
  66. package/lib/module/sync/timeMachineSyncAdapter.js +1 -253
  67. package/lib/module/ui/SwipeActionsRow.js +1 -173
  68. package/lib/module/ui/primitives.js +1 -164
  69. package/lib/module/ui/tmTheme.js +1 -114
  70. package/lib/web/index.mjs +3 -0
  71. package/package.json +43 -10
  72. package/lib/commonjs/components/HeaderActions.js.map +0 -1
  73. package/lib/commonjs/components/HeaderReloadButton.js.map +0 -1
  74. package/lib/commonjs/components/TimeMachineBody.js.map +0 -1
  75. package/lib/commonjs/components/TimeMachineModal.js.map +0 -1
  76. package/lib/commonjs/components/confirm.js.map +0 -1
  77. package/lib/commonjs/components/floating/NamePromptModal.js.map +0 -1
  78. package/lib/commonjs/components/floating/TimeMachineFloatingTool.js.map +0 -1
  79. package/lib/commonjs/components/floating/armedPoint.js.map +0 -1
  80. package/lib/commonjs/components/floating/barSettings.js.map +0 -1
  81. package/lib/commonjs/components/format.js.map +0 -1
  82. package/lib/commonjs/components/list/CaptureBar.js.map +0 -1
  83. package/lib/commonjs/components/list/RestoreOutcomeCard.js.map +0 -1
  84. package/lib/commonjs/components/list/SnapshotRow.js.map +0 -1
  85. package/lib/commonjs/components/list/SourcesStrip.js.map +0 -1
  86. package/lib/commonjs/components/list/UndoDeleteBar.js.map +0 -1
  87. package/lib/commonjs/components/list/WipeAllRow.js.map +0 -1
  88. package/lib/commonjs/components/preview/ItemDiffPanel.js.map +0 -1
  89. package/lib/commonjs/components/preview/PreviewFlow.js.map +0 -1
  90. package/lib/commonjs/components/preview/RestorePointNameRow.js.map +0 -1
  91. package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +0 -1
  92. package/lib/commonjs/components/preview/verdictMeta.js.map +0 -1
  93. package/lib/commonjs/components/sources.js.map +0 -1
  94. package/lib/commonjs/hooks/useTimeMachine.js.map +0 -1
  95. package/lib/commonjs/index.js.map +0 -1
  96. package/lib/commonjs/preset.js.map +0 -1
  97. package/lib/commonjs/store/routeRestore.js.map +0 -1
  98. package/lib/commonjs/store/snapshotVault.js.map +0 -1
  99. package/lib/commonjs/store/sourceIds.js.map +0 -1
  100. package/lib/commonjs/store/sourceSettings.js.map +0 -1
  101. package/lib/commonjs/store/timeMachineStore.js.map +0 -1
  102. package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +0 -1
  103. package/lib/commonjs/ui/SwipeActionsRow.js.map +0 -1
  104. package/lib/commonjs/ui/primitives.js.map +0 -1
  105. package/lib/commonjs/ui/tmTheme.js.map +0 -1
  106. package/lib/module/components/HeaderActions.js.map +0 -1
  107. package/lib/module/components/HeaderReloadButton.js.map +0 -1
  108. package/lib/module/components/TimeMachineBody.js.map +0 -1
  109. package/lib/module/components/TimeMachineModal.js.map +0 -1
  110. package/lib/module/components/confirm.js.map +0 -1
  111. package/lib/module/components/floating/NamePromptModal.js.map +0 -1
  112. package/lib/module/components/floating/TimeMachineFloatingTool.js.map +0 -1
  113. package/lib/module/components/floating/armedPoint.js.map +0 -1
  114. package/lib/module/components/floating/barSettings.js.map +0 -1
  115. package/lib/module/components/format.js.map +0 -1
  116. package/lib/module/components/list/CaptureBar.js.map +0 -1
  117. package/lib/module/components/list/RestoreOutcomeCard.js.map +0 -1
  118. package/lib/module/components/list/SnapshotRow.js.map +0 -1
  119. package/lib/module/components/list/SourcesStrip.js.map +0 -1
  120. package/lib/module/components/list/UndoDeleteBar.js.map +0 -1
  121. package/lib/module/components/list/WipeAllRow.js.map +0 -1
  122. package/lib/module/components/preview/ItemDiffPanel.js.map +0 -1
  123. package/lib/module/components/preview/PreviewFlow.js.map +0 -1
  124. package/lib/module/components/preview/RestorePointNameRow.js.map +0 -1
  125. package/lib/module/components/preview/RestorePreviewScreen.js.map +0 -1
  126. package/lib/module/components/preview/verdictMeta.js.map +0 -1
  127. package/lib/module/components/sources.js.map +0 -1
  128. package/lib/module/hooks/useTimeMachine.js.map +0 -1
  129. package/lib/module/index.js.map +0 -1
  130. package/lib/module/preset.js.map +0 -1
  131. package/lib/module/store/routeRestore.js.map +0 -1
  132. package/lib/module/store/snapshotVault.js.map +0 -1
  133. package/lib/module/store/sourceIds.js.map +0 -1
  134. package/lib/module/store/sourceSettings.js.map +0 -1
  135. package/lib/module/store/timeMachineStore.js.map +0 -1
  136. package/lib/module/sync/timeMachineSyncAdapter.js.map +0 -1
  137. package/lib/module/ui/SwipeActionsRow.js.map +0 -1
  138. package/lib/module/ui/primitives.js.map +0 -1
  139. package/lib/module/ui/tmTheme.js.map +0 -1
  140. package/lib/typescript/components/HeaderActions.d.ts.map +0 -1
  141. package/lib/typescript/components/HeaderReloadButton.d.ts.map +0 -1
  142. package/lib/typescript/components/TimeMachineBody.d.ts.map +0 -1
  143. package/lib/typescript/components/TimeMachineModal.d.ts.map +0 -1
  144. package/lib/typescript/components/confirm.d.ts.map +0 -1
  145. package/lib/typescript/components/floating/NamePromptModal.d.ts.map +0 -1
  146. package/lib/typescript/components/floating/TimeMachineFloatingTool.d.ts.map +0 -1
  147. package/lib/typescript/components/floating/armedPoint.d.ts.map +0 -1
  148. package/lib/typescript/components/floating/barSettings.d.ts.map +0 -1
  149. package/lib/typescript/components/format.d.ts.map +0 -1
  150. package/lib/typescript/components/list/CaptureBar.d.ts.map +0 -1
  151. package/lib/typescript/components/list/RestoreOutcomeCard.d.ts.map +0 -1
  152. package/lib/typescript/components/list/SnapshotRow.d.ts.map +0 -1
  153. package/lib/typescript/components/list/SourcesStrip.d.ts.map +0 -1
  154. package/lib/typescript/components/list/UndoDeleteBar.d.ts.map +0 -1
  155. package/lib/typescript/components/list/WipeAllRow.d.ts.map +0 -1
  156. package/lib/typescript/components/preview/ItemDiffPanel.d.ts.map +0 -1
  157. package/lib/typescript/components/preview/PreviewFlow.d.ts.map +0 -1
  158. package/lib/typescript/components/preview/RestorePointNameRow.d.ts.map +0 -1
  159. package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +0 -1
  160. package/lib/typescript/components/preview/verdictMeta.d.ts.map +0 -1
  161. package/lib/typescript/components/sources.d.ts.map +0 -1
  162. package/lib/typescript/hooks/useTimeMachine.d.ts.map +0 -1
  163. package/lib/typescript/index.d.ts.map +0 -1
  164. package/lib/typescript/preset.d.ts.map +0 -1
  165. package/lib/typescript/store/routeRestore.d.ts.map +0 -1
  166. package/lib/typescript/store/snapshotVault.d.ts.map +0 -1
  167. package/lib/typescript/store/sourceIds.d.ts.map +0 -1
  168. package/lib/typescript/store/sourceSettings.d.ts.map +0 -1
  169. package/lib/typescript/store/timeMachineStore.d.ts.map +0 -1
  170. package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +0 -1
  171. package/lib/typescript/ui/SwipeActionsRow.d.ts.map +0 -1
  172. package/lib/typescript/ui/primitives.d.ts.map +0 -1
  173. package/lib/typescript/ui/tmTheme.d.ts.map +0 -1
@@ -1,253 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Sync adapter for the Time Machine tool, consumed by @buoy-gg/external-sync's
5
- * `useExternalSync` (structurally matches its ToolSyncAdapter interface so
6
- * this package doesn't need a dependency on it).
7
- *
8
- * Snapshots stay ON-DEVICE — getSnapshot ships METADATA only (list, provider
9
- * statuses, last restore outcome), far under the 2MB per-tool budget. Payload
10
- * inspection goes through the `inspect` action (8MB action-result budget).
11
- *
12
- * The `restore` action uses the store's scheduleReloadApp path for reload
13
- * mode, so the action RESULT is flushed to the broker before the JS realm
14
- * dies — a remote caller always gets its answer.
15
- */
16
- import { getStateSnapshotProviders, subscribeToStateSnapshotProviders, superJsonDeserialize } from "@buoy-gg/shared-ui";
17
- import { jsonLikelyLargerThan } from "@buoy-gg/shared-ui/dataViewer";
18
- import { timeMachineStore } from "../store/timeMachineStore";
19
- import { loadSnapshot } from "../store/snapshotVault";
20
- import { canNavigate, currentRoute } from "../store/routeRestore";
21
- import { isSourceEnabled } from "../store/sourceSettings";
22
- import { ROUTE_SOURCE_ID } from "../store/sourceIds";
23
- function providerStatuses() {
24
- return getStateSnapshotProviders().map(p => {
25
- const s = p.status();
26
- return {
27
- id: p.id,
28
- label: p.label,
29
- canCapture: s.canCapture,
30
- canRestore: s.canRestore,
31
- detail: s.detail,
32
- enabled: isSourceEnabled(p.id)
33
- };
34
- });
35
- }
36
- function metadata() {
37
- const {
38
- snapshots,
39
- busy,
40
- lastOutcome
41
- } = timeMachineStore.getState();
42
- const current = currentRoute();
43
- return {
44
- snapshots,
45
- busy,
46
- lastOutcome,
47
- providers: providerStatuses(),
48
- // Route capture/restore is a device capability, not a snapshot provider —
49
- // a dashboard has no router of its own to probe, so it's mirrored here.
50
- route: {
51
- available: canNavigate(),
52
- enabled: isSourceEnabled(ROUTE_SOURCE_ID),
53
- ...(current ? {
54
- current: current.href
55
- } : {})
56
- }
57
- };
58
- }
59
- export const timeMachineSyncAdapter = {
60
- // v2 adds `route` (device route capability) and `snapshots[].route`.
61
- version: 2,
62
- getSnapshot: () => metadata(),
63
- subscribe: onChange => {
64
- const unsubStore = timeMachineStore.subscribe(onChange);
65
- const unsubProviders = subscribeToStateSnapshotProviders(onChange);
66
- return () => {
67
- unsubStore();
68
- unsubProviders();
69
- };
70
- },
71
- actions: {
72
- list: () => metadata(),
73
- capture: async params => {
74
- const {
75
- name = "",
76
- sourceIds
77
- } = params ?? {};
78
- const meta = await timeMachineStore.capture(name, sourceIds);
79
- return {
80
- captured: true,
81
- snapshot: meta
82
- };
83
- },
84
- captureBaseline: async () => {
85
- const meta = await timeMachineStore.captureBaseline();
86
- return {
87
- captured: true,
88
- snapshot: meta
89
- };
90
- },
91
- /** Wipe every clearable source to fresh-install state, then reload. */
92
- wipeAll: async () => await timeMachineStore.wipeAll(),
93
- /** mode "live" (default) replaces state in place; "reload" restores
94
- * persisted storage then reloads the JS bundle (always the path for
95
- * baseline snapshots). */
96
- restore: async params => {
97
- const {
98
- id,
99
- mode = "live",
100
- excludeKeys,
101
- restoreRoute
102
- } = params ?? {};
103
- if (!id) throw new Error("restore requires a snapshot `id`");
104
- return await timeMachineStore.restore(id, mode, excludeKeys, {
105
- restoreRoute
106
- });
107
- },
108
- delete: async params => {
109
- const {
110
- id
111
- } = params ?? {};
112
- if (!id) throw new Error("delete requires a snapshot `id`");
113
- await timeMachineStore.delete(id);
114
- return {
115
- deleted: true,
116
- id
117
- };
118
- },
119
- rename: async params => {
120
- const {
121
- id,
122
- name
123
- } = params ?? {};
124
- if (!id || !name) throw new Error("rename requires `id` and `name`");
125
- await timeMachineStore.rename(id, name);
126
- return {
127
- renamed: true,
128
- id,
129
- name
130
- };
131
- },
132
- /**
133
- * Save (or clear with null/empty) the items a restore of this snapshot
134
- * must leave alone — the persisted form of the preview's checkboxes.
135
- */
136
- setExclusions: async params => {
137
- const {
138
- id,
139
- excludedKeys
140
- } = params ?? {};
141
- if (!id) throw new Error("setExclusions requires `id`");
142
- await timeMachineStore.setExclusions(id, excludedKeys ?? null);
143
- return {
144
- id,
145
- excluded: excludedKeys?.length ?? 0
146
- };
147
- },
148
- /** Turn a restore point's route restore on or off. */
149
- setRestoreRoute: async params => {
150
- const {
151
- id,
152
- restoreRoute
153
- } = params ?? {};
154
- if (!id) throw new Error("setRestoreRoute requires `id`");
155
- await timeMachineStore.setRestoreRoute(id, restoreRoute !== false);
156
- return {
157
- id,
158
- restoreRoute: restoreRoute !== false
159
- };
160
- },
161
- /** Copy a restore point so a variation can start from a known base. */
162
- duplicate: async params => {
163
- const {
164
- id
165
- } = params ?? {};
166
- if (!id) throw new Error("duplicate requires `id`");
167
- const snapshot = await timeMachineStore.duplicate(id);
168
- if (!snapshot) throw new Error(`No snapshot with id "${id}"`);
169
- return {
170
- snapshot
171
- };
172
- },
173
- /** Save (or clear with null/empty) a snapshot's targeted-restore scope. */
174
- setScope: async params => {
175
- const {
176
- id,
177
- scope
178
- } = params ?? {};
179
- if (!id) throw new Error("setScope requires a snapshot `id`");
180
- await timeMachineStore.setScope(id, scope ?? null);
181
- return {
182
- scoped: true,
183
- id,
184
- count: scope?.length ?? 0
185
- };
186
- },
187
- /**
188
- * Item-level restore preview, computed ON-DEVICE. Values above ~4KB per
189
- * item are omitted (valueOmitted) so the result stays far under the 8MB
190
- * action budget on any app size.
191
- */
192
- preview: async params => {
193
- const {
194
- id,
195
- compareTo
196
- } = params ?? {};
197
- if (!id) throw new Error("preview requires a snapshot `id`");
198
- const right = {
199
- snapshotId: id
200
- };
201
- const left = compareTo ? {
202
- snapshotId: compareTo
203
- } : "current";
204
- await timeMachineStore.buildPreview(right, left);
205
- const preview = timeMachineStore.getState().preview;
206
- if (!preview) throw new Error("preview build produced no result");
207
- const VALUE_BUDGET = 4 * 1024;
208
- return {
209
- left,
210
- right,
211
- builtAt: preview.builtAt,
212
- sources: preview.sources.map(src => ({
213
- ...src,
214
- items: src.items.map(item => {
215
- const oldBig = item.oldValue !== undefined && jsonLikelyLargerThan(item.oldValue, VALUE_BUDGET);
216
- const newBig = item.newValue !== undefined && jsonLikelyLargerThan(item.newValue, VALUE_BUDGET);
217
- return {
218
- ...item,
219
- oldValue: oldBig ? undefined : item.oldValue,
220
- newValue: newBig ? undefined : item.newValue,
221
- ...(oldBig || newBig ? {
222
- valueOmitted: true
223
- } : {})
224
- };
225
- })
226
- }))
227
- };
228
- },
229
- /** One source's captured payload, deserialized — for remote inspection. */
230
- inspect: async params => {
231
- const {
232
- id,
233
- sourceId
234
- } = params ?? {};
235
- if (!id || !sourceId) {
236
- throw new Error("inspect requires `id` and `sourceId`");
237
- }
238
- const stored = await loadSnapshot(id);
239
- if (!stored) throw new Error(`No snapshot with id "${id}"`);
240
- const payload = stored.data[sourceId];
241
- if (!payload) {
242
- throw new Error(`Snapshot "${id}" has no "${sourceId}" source`);
243
- }
244
- return {
245
- id,
246
- sourceId,
247
- warnings: stored.meta.sources[sourceId]?.warnings ?? [],
248
- data: superJsonDeserialize(payload)
249
- };
250
- }
251
- }
252
- };
253
- //# sourceMappingURL=timeMachineSyncAdapter.js.map
1
+ "use strict";import{getStateSnapshotProviders as f,subscribeToStateSnapshotProviders as m,superJsonDeserialize as E}from"@buoy-gg/shared-ui";import{jsonLikelyLargerThan as p}from"@buoy-gg/shared-ui/dataViewer";import{timeMachineStore as s}from"../store/timeMachineStore";import{loadSnapshot as b}from"../store/snapshotVault";import{canNavigate as y,currentRoute as S}from"../store/routeRestore";import{isSourceEnabled as w}from"../store/sourceSettings";import{ROUTE_SOURCE_ID as v}from"../store/sourceIds";function R(){return f().map(t=>{const e=t.status();return{id:t.id,label:t.label,canCapture:e.canCapture,canRestore:e.canRestore,detail:e.detail,enabled:w(t.id)}})}function h(){const{snapshots:t,busy:e,lastOutcome:r}=s.getState();const o=S();return{snapshots:t,busy:e,lastOutcome:r,providers:R(),route:{available:y(),enabled:w(v),...o?{current:o.href}:{}}}}export const timeMachineSyncAdapter={version:2,getSnapshot:()=>h(),subscribe:t=>{const e=s.subscribe(t);const r=m(t);return()=>{e();r()}},actions:{list:()=>h(),capture:async t=>{const{name:e="",sourceIds:r}=t??{};const o=await s.capture(e,r);return{captured:true,snapshot:o}},captureBaseline:async()=>{const t=await s.captureBaseline();return{captured:true,snapshot:t}},wipeAll:async()=>await s.wipeAll(),restore:async t=>{const{id:e,mode:r="live",excludeKeys:o,restoreRoute:n}=t??{};if(!e)throw new Error("restore requires a snapshot `id`");return await s.restore(e,r,o,{restoreRoute:n})},delete:async t=>{const{id:e}=t??{};if(!e)throw new Error("delete requires a snapshot `id`");await s.delete(e);return{deleted:true,id:e}},rename:async t=>{const{id:e,name:r}=t??{};if(!e||!r)throw new Error("rename requires `id` and `name`");await s.rename(e,r);return{renamed:true,id:e,name:r}},setExclusions:async t=>{const{id:e,excludedKeys:r}=t??{};if(!e)throw new Error("setExclusions requires `id`");await s.setExclusions(e,r??null);return{id:e,excluded:r?.length??0}},setRestoreRoute:async t=>{const{id:e,restoreRoute:r}=t??{};if(!e)throw new Error("setRestoreRoute requires `id`");await s.setRestoreRoute(e,r!==false);return{id:e,restoreRoute:r!==false}},duplicate:async t=>{const{id:e}=t??{};if(!e)throw new Error("duplicate requires `id`");const r=await s.duplicate(e);if(!r)throw new Error(`No snapshot with id "${e}"`);return{snapshot:r}},setScope:async t=>{const{id:e,scope:r}=t??{};if(!e)throw new Error("setScope requires a snapshot `id`");await s.setScope(e,r??null);return{scoped:true,id:e,count:r?.length??0}},preview:async t=>{const{id:e,compareTo:r}=t??{};if(!e)throw new Error("preview requires a snapshot `id`");const o={snapshotId:e};const n=r?{snapshotId:r}:"current";await s.buildPreview(o,n);const i=s.getState().preview;if(!i)throw new Error("preview build produced no result");const u=4*1024;return{left:n,right:o,builtAt:i.builtAt,sources:i.sources.map(c=>({...c,items:c.items.map(a=>{const d=a.oldValue!==void 0&&p(a.oldValue,u);const l=a.newValue!==void 0&&p(a.newValue,u);return{...a,oldValue:d?void 0:a.oldValue,newValue:l?void 0:a.newValue,...d||l?{valueOmitted:true}:{}}})}))}},inspect:async t=>{const{id:e,sourceId:r}=t??{};if(!e||!r){throw new Error("inspect requires `id` and `sourceId`")}const o=await b(e);if(!o)throw new Error(`No snapshot with id "${e}"`);const n=o.data[r];if(!n){throw new Error(`Snapshot "${e}" has no "${r}" source`)}return{id:e,sourceId:r,warnings:o.meta.sources[r]?.warnings??[],data:E(n)}}}};
@@ -1,173 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Swipe-left-to-reveal-actions wrapper for a grouped-list row.
5
- *
6
- * Deliberately dependency-free (Animated + PanResponder): the package has no
7
- * gesture-handler peer and a devtool must not add one to the host app.
8
- *
9
- * Gesture contract, in the order the checks matter:
10
- * - The pan only claims the gesture once the finger has moved LEFT past a
11
- * threshold and is travelling more horizontally than vertically, so taps
12
- * still reach the row and vertical drags still scroll the list.
13
- * - Releasing past half the action width latches open; anything less snaps
14
- * shut, so a hesitant swipe never leaves a half-open row.
15
- * - Only one row stays open at a time (module-level latch below) — matching
16
- * iOS, and it means "swipe, then tap an action" can't hit the wrong row.
17
- */
18
- import { useEffect, useRef } from "react";
19
- import { Animated, PanResponder, StyleSheet, Text, TouchableOpacity, View } from "react-native";
20
- import { tm } from "./tmTheme";
21
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
- const ACTION_WIDTH = 84;
23
- /** Horizontal travel before the pan takes the gesture from the scroll view. */
24
- const CLAIM_THRESHOLD = 8;
25
-
26
- /** The one open row, so opening another closes it. */
27
- let closeOpenRow = null;
28
- /**
29
- * Everything gesture-side for one row, built once. Kept out of the component
30
- * so it reads as the state machine it is: `open` is the only state, and the
31
- * pan handlers are the only writers.
32
- */
33
- function createGesture(translateX, openWidth) {
34
- let open = false;
35
- const settle = next => {
36
- open = next;
37
- if (next) {
38
- if (closeOpenRow && closeOpenRow !== close) closeOpenRow();
39
- closeOpenRow = close;
40
- } else if (closeOpenRow === close) {
41
- closeOpenRow = null;
42
- }
43
- Animated.spring(translateX, {
44
- toValue: next ? -openWidth : 0,
45
- useNativeDriver: true,
46
- bounciness: 0,
47
- speed: 18
48
- }).start();
49
- };
50
- const close = () => settle(false);
51
- const pan = PanResponder.create({
52
- onMoveShouldSetPanResponder: (_e, g) => {
53
- const horizontal = Math.abs(g.dx) > Math.abs(g.dy) * 1.5;
54
- if (!horizontal) return false;
55
- // Left to open; right only matters when there is something to close.
56
- return g.dx < -CLAIM_THRESHOLD || open && g.dx > CLAIM_THRESHOLD;
57
- },
58
- onPanResponderMove: (_e, g) => {
59
- const base = open ? -openWidth : 0;
60
- // Clamp: no rubber-banding past the actions, none past closed.
61
- translateX.setValue(Math.min(0, Math.max(-openWidth, base + g.dx)));
62
- },
63
- onPanResponderRelease: (_e, g) => {
64
- const resting = (open ? -openWidth : 0) + g.dx;
65
- // A fast flick decides on velocity; a slow drag on distance.
66
- settle(g.vx < -0.5 ? true : g.vx > 0.5 ? false : resting < -openWidth / 2);
67
- },
68
- onPanResponderTerminate: () => settle(open)
69
- });
70
- return {
71
- pan,
72
- close
73
- };
74
- }
75
- export function SwipeActionsRow({
76
- children,
77
- actions,
78
- testID
79
- }) {
80
- const openWidth = ACTION_WIDTH * actions.length;
81
- const translateX = useRef(new Animated.Value(0)).current;
82
- const gestureRef = useRef(null);
83
- if (gestureRef.current === null) gestureRef.current = createGesture(translateX, openWidth);
84
- const {
85
- pan,
86
- close
87
- } = gestureRef.current;
88
-
89
- // A row that unmounts while open (deleted, filtered out, screen changed)
90
- // must not leave the latch pointing at a dead closer.
91
- useEffect(() => () => {
92
- if (closeOpenRow === close) closeOpenRow = null;
93
- }, [close]);
94
-
95
- // The row is glass now, so the actions can't hide under it: they fade in
96
- // with the first points of the drag instead of sitting there at rest.
97
- const actionOpacity = translateX.interpolate({
98
- inputRange: [-24, 0],
99
- outputRange: [1, 0],
100
- extrapolate: "clamp"
101
- });
102
- return /*#__PURE__*/_jsxs(View, {
103
- style: styles.clip,
104
- children: [/*#__PURE__*/_jsx(Animated.View, {
105
- style: [styles.actionLayer, {
106
- width: openWidth,
107
- opacity: actionOpacity
108
- }],
109
- children: actions.map(action => /*#__PURE__*/_jsx(TouchableOpacity, {
110
- style: [styles.action, action.background ? {
111
- backgroundColor: action.background
112
- } : null],
113
- onPress: () => {
114
- close();
115
- action.onPress();
116
- },
117
- accessibilityLabel: action.label,
118
- testID: action.testID ?? (testID ? `${testID}-${action.label.toLowerCase()}` : undefined),
119
- children: /*#__PURE__*/_jsx(Text, {
120
- style: [styles.actionText, action.color ? {
121
- color: action.color
122
- } : null],
123
- numberOfLines: 1,
124
- children: action.label
125
- })
126
- }, action.label))
127
- }), /*#__PURE__*/_jsx(Animated.View, {
128
- style: [styles.content, {
129
- transform: [{
130
- translateX
131
- }]
132
- }],
133
- ...pan.panHandlers,
134
- children: children
135
- })]
136
- });
137
- }
138
- const styles = StyleSheet.create({
139
- clip: {
140
- overflow: "hidden"
141
- },
142
- // Own geometry, no percentages: an absoluteFill layer with a `height:
143
- // "100%"` child measured against this content-sized parent inflated every
144
- // row to several hundred points on iOS/Fabric.
145
- actionLayer: {
146
- position: "absolute",
147
- top: 0,
148
- bottom: 0,
149
- right: 0,
150
- flexDirection: "row"
151
- },
152
- action: {
153
- width: ACTION_WIDTH,
154
- height: "100%",
155
- backgroundColor: tm.color.fillStrong,
156
- alignItems: "center",
157
- justifyContent: "center",
158
- paddingHorizontal: 6
159
- },
160
- actionText: {
161
- color: tm.color.label,
162
- fontSize: tm.font.footnote,
163
- fontWeight: "600",
164
- letterSpacing: tm.tracking.control
165
- },
166
- // Glass, like the card it sits in. The actions underneath are faded out
167
- // at rest (see actionOpacity), which is what keeps them from bleeding
168
- // through a translucent row.
169
- content: {
170
- backgroundColor: tm.color.group
171
- }
172
- });
173
- //# sourceMappingURL=SwipeActionsRow.js.map
1
+ "use strict";import{useEffect as g,useRef as m}from"react";import{Animated as d,PanResponder as y,StyleSheet as R,Text as w,TouchableOpacity as S,View as T}from"react-native";import{tm as u}from"./tmTheme";import{jsx as b,jsxs as v}from"react/jsx-runtime";const h=84;const x=8;let s=null;function C(p,o){let n=false;const c=l=>{n=l;if(l){if(s&&s!==r)s();s=r}else if(s===r){s=null}d.spring(p,{toValue:l?-o:0,useNativeDriver:true,bounciness:0,speed:18}).start()};const r=()=>c(false);const i=y.create({onMoveShouldSetPanResponder:(l,e)=>{const a=Math.abs(e.dx)>Math.abs(e.dy)*1.5;if(!a)return false;return e.dx<-x||n&&e.dx>x},onPanResponderMove:(l,e)=>{const a=n?-o:0;p.setValue(Math.min(0,Math.max(-o,a+e.dx)))},onPanResponderRelease:(l,e)=>{const a=(n?-o:0)+e.dx;c(e.vx<-.5?true:e.vx>.5?false:a<-o/2)},onPanResponderTerminate:()=>c(n)});return{pan:i,close:r}}export function SwipeActionsRow({children:p,actions:o,testID:n}){const c=h*o.length;const r=m(new d.Value(0)).current;const i=m(null);if(i.current===null)i.current=C(r,c);const{pan:l,close:e}=i.current;g(()=>()=>{if(s===e)s=null},[e]);const a=r.interpolate({inputRange:[-24,0],outputRange:[1,0],extrapolate:"clamp"});return v(T,{style:f.clip,children:[b(d.View,{style:[f.actionLayer,{width:c,opacity:a}],children:o.map(t=>b(S,{style:[f.action,t.background?{backgroundColor:t.background}:null],onPress:()=>{e();t.onPress()},accessibilityLabel:t.label,testID:t.testID??(n?`${n}-${t.label.toLowerCase()}`:void 0),children:b(w,{style:[f.actionText,t.color?{color:t.color}:null],numberOfLines:1,children:t.label})},t.label))}),b(d.View,{style:[f.content,{transform:[{translateX:r}]}],...l.panHandlers,children:p})]})}const f=R.create({clip:{overflow:"hidden"},actionLayer:{position:"absolute",top:0,bottom:0,right:0,flexDirection:"row"},action:{width:h,height:"100%",backgroundColor:u.color.fillStrong,alignItems:"center",justifyContent:"center",paddingHorizontal:6},actionText:{color:u.color.label,fontSize:u.font.footnote,fontWeight:"600",letterSpacing:u.tracking.control},content:{backgroundColor:u.color.group}});
@@ -1,164 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Grouped-inset list primitives — the building blocks of the Time Machine
5
- * surface (see ./tmTheme for the tokens and the promotion plan).
6
- *
7
- * The shape they compose to:
8
- *
9
- * SectionLabel SOURCES ← outside the card, uppercase
10
- * Group ┌──────────────────┐
11
- * <row> │ All sources … 6 ›│ ← rows are plain children;
12
- * <row> ├──────────────────┤ Group draws the hairlines
13
- * └──────────────────┘
14
- * Footnote Route is captured with… ← explains the group above
15
- *
16
- * Rows are whatever a screen needs — Group only owns the card, the clipping
17
- * and the separators, so a row never has to know its position in the list.
18
- */
19
- import { Children } from "react";
20
- import { StyleSheet, Text, View } from "react-native";
21
- import { ChevronRight } from "@buoy-gg/shared-ui";
22
- import { tm } from "./tmTheme";
23
-
24
- /** Uppercase section label that sits above a Group. */
25
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
26
- export function SectionLabel({
27
- children,
28
- testID
29
- }) {
30
- return /*#__PURE__*/_jsx(Text, {
31
- style: styles.sectionLabel,
32
- testID: testID,
33
- children: children
34
- });
35
- }
36
-
37
- /**
38
- * Explanatory line under a Group ("Swipe a restore point to delete it").
39
- * `centered` matches the iOS convention for a footnote under a lone button.
40
- */
41
- export function Footnote({
42
- children,
43
- centered,
44
- tone = "secondary",
45
- testID
46
- }) {
47
- return /*#__PURE__*/_jsx(Text, {
48
- style: [styles.footnote, centered ? styles.footnoteCentered : null, tone === "warning" ? styles.footnoteWarning : null],
49
- testID: testID,
50
- children: children
51
- });
52
- }
53
-
54
- /**
55
- * A rounded grouped card. Draws a hairline between consecutive children and
56
- * clips them, so a row can paint edge-to-edge (swipe actions, press washes)
57
- * without punching through the corners.
58
- */
59
- export function Group({
60
- children,
61
- style
62
- }) {
63
- const rows = Children.toArray(children);
64
- return /*#__PURE__*/_jsx(View, {
65
- style: [styles.group, style],
66
- children: rows.map((row, index) =>
67
- /*#__PURE__*/
68
- // Children.toArray assigns stable synthetic keys ('.$id' for keyed
69
- // children), so a row keeps its identity as the list changes.
70
- _jsxs(View, {
71
- children: [index > 0 ? /*#__PURE__*/_jsx(View, {
72
- style: styles.separator
73
- }) : null, row]
74
- }, row.key ?? index))
75
- });
76
- }
77
-
78
- /**
79
- * Trailing disclosure chevron for a row that opens or expands.
80
- *
81
- * A real glyph, not two rotated hairlines: at this size the hand-built
82
- * version's strokes never met at the vertex, so it read as a broken arrow.
83
- */
84
- export function DisclosureChevron() {
85
- return /*#__PURE__*/_jsx(ChevronRight, {
86
- size: 16,
87
- color: tm.color.labelTertiary
88
- });
89
- }
90
-
91
- /**
92
- * Pill button. Parameterized by color rather than by variant flags so a
93
- * screen can name its own (`CapturePill`, `RestorePill`) in one line.
94
- */
95
- export function PillLabel({
96
- label,
97
- color,
98
- background,
99
- testID
100
- }) {
101
- return /*#__PURE__*/_jsx(View, {
102
- style: [styles.pill, {
103
- backgroundColor: background
104
- }],
105
- children: /*#__PURE__*/_jsx(Text, {
106
- style: [styles.pillText, {
107
- color
108
- }],
109
- testID: testID,
110
- children: label
111
- })
112
- });
113
- }
114
- const styles = StyleSheet.create({
115
- sectionLabel: {
116
- color: tm.color.labelSecondary,
117
- fontSize: tm.font.footnote,
118
- fontWeight: "500",
119
- textTransform: "uppercase",
120
- letterSpacing: 0.4,
121
- paddingHorizontal: tm.gutter + tm.textInset,
122
- paddingTop: 22,
123
- paddingBottom: 7
124
- },
125
- footnote: {
126
- color: tm.color.labelSecondary,
127
- fontSize: tm.font.footnote,
128
- lineHeight: tm.font.footnote * 1.35,
129
- paddingHorizontal: tm.gutter + tm.textInset,
130
- paddingTop: 7
131
- },
132
- footnoteCentered: {
133
- textAlign: "center"
134
- },
135
- footnoteWarning: {
136
- color: tm.color.warning
137
- },
138
- group: {
139
- marginHorizontal: tm.gutter,
140
- backgroundColor: tm.color.group,
141
- borderRadius: tm.radius.group,
142
- borderWidth: 1,
143
- borderColor: tm.color.groupBorder,
144
- overflow: "hidden"
145
- },
146
- separator: {
147
- height: StyleSheet.hairlineWidth,
148
- marginLeft: tm.separatorInset,
149
- backgroundColor: tm.color.separator
150
- },
151
- pill: {
152
- height: 32,
153
- paddingHorizontal: 15,
154
- borderRadius: tm.radius.pill,
155
- alignItems: "center",
156
- justifyContent: "center"
157
- },
158
- pillText: {
159
- fontSize: tm.font.control,
160
- fontWeight: "600",
161
- letterSpacing: tm.tracking.control
162
- }
163
- });
164
- //# sourceMappingURL=primitives.js.map
1
+ "use strict";import{Children as p}from"react";import{StyleSheet as d,Text as c,View as a}from"react-native";import{ChevronRight as g}from"@buoy-gg/shared-ui";import{tm as o}from"./tmTheme";import{jsx as n,jsxs as u}from"react/jsx-runtime";export function SectionLabel({children:e,testID:r}){return n(c,{style:t.sectionLabel,testID:r,children:e})}export function Footnote({children:e,centered:r,tone:i="secondary",testID:l}){return n(c,{style:[t.footnote,r?t.footnoteCentered:null,i==="warning"?t.footnoteWarning:null],testID:l,children:e})}export function Group({children:e,style:r}){const i=p.toArray(e);return n(a,{style:[t.group,r],children:i.map((l,s)=>u(a,{children:[s>0?n(a,{style:t.separator}):null,l]},l.key??s))})}export function DisclosureChevron(){return n(g,{size:16,color:o.color.labelTertiary})}export function PillLabel({label:e,color:r,background:i,testID:l}){return n(a,{style:[t.pill,{backgroundColor:i}],children:n(c,{style:[t.pillText,{color:r}],testID:l,children:e})})}const t=d.create({sectionLabel:{color:o.color.labelSecondary,fontSize:o.font.footnote,fontWeight:"500",textTransform:"uppercase",letterSpacing:.4,paddingHorizontal:o.gutter+o.textInset,paddingTop:22,paddingBottom:7},footnote:{color:o.color.labelSecondary,fontSize:o.font.footnote,lineHeight:o.font.footnote*1.35,paddingHorizontal:o.gutter+o.textInset,paddingTop:7},footnoteCentered:{textAlign:"center"},footnoteWarning:{color:o.color.warning},group:{marginHorizontal:o.gutter,backgroundColor:o.color.group,borderRadius:o.radius.group,borderWidth:1,borderColor:o.color.groupBorder,overflow:"hidden"},separator:{height:d.hairlineWidth,marginLeft:o.separatorInset,backgroundColor:o.color.separator},pill:{height:32,paddingHorizontal:15,borderRadius:o.radius.pill,alignItems:"center",justifyContent:"center"},pillText:{fontSize:o.font.control,fontWeight:"600",letterSpacing:o.tracking.control}});