@buoy-gg/time-machine 7.0.22 → 7.0.23
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/lib/commonjs/components/TimeMachineBody.js +147 -677
- package/lib/commonjs/components/TimeMachineBody.js.map +1 -1
- package/lib/commonjs/components/TimeMachineModal.js +10 -11
- package/lib/commonjs/components/TimeMachineModal.js.map +1 -1
- package/lib/commonjs/components/confirm.js +39 -0
- package/lib/commonjs/components/confirm.js.map +1 -0
- package/lib/commonjs/components/format.js +24 -0
- package/lib/commonjs/components/format.js.map +1 -0
- package/lib/commonjs/components/list/CaptureBar.js +95 -0
- package/lib/commonjs/components/list/CaptureBar.js.map +1 -0
- package/lib/commonjs/components/list/RestoreOutcomeCard.js +162 -0
- package/lib/commonjs/components/list/RestoreOutcomeCard.js.map +1 -0
- package/lib/commonjs/components/list/SnapshotRow.js +141 -0
- package/lib/commonjs/components/list/SnapshotRow.js.map +1 -0
- package/lib/commonjs/components/list/SourcesStrip.js +126 -0
- package/lib/commonjs/components/list/SourcesStrip.js.map +1 -0
- package/lib/commonjs/components/list/UndoDeleteBar.js +81 -0
- package/lib/commonjs/components/list/UndoDeleteBar.js.map +1 -0
- package/lib/commonjs/components/list/WipeAllRow.js +46 -0
- package/lib/commonjs/components/list/WipeAllRow.js.map +1 -0
- package/lib/commonjs/components/preview/ItemDiffPanel.js +77 -0
- package/lib/commonjs/components/preview/ItemDiffPanel.js.map +1 -0
- package/lib/commonjs/components/preview/PreviewFlow.js +51 -0
- package/lib/commonjs/components/preview/PreviewFlow.js.map +1 -0
- package/lib/commonjs/components/preview/RestorePointNameRow.js +83 -0
- package/lib/commonjs/components/preview/RestorePointNameRow.js.map +1 -0
- package/lib/commonjs/components/preview/RestorePreviewScreen.js +549 -635
- package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +1 -1
- package/lib/commonjs/components/preview/verdictMeta.js +8 -8
- package/lib/commonjs/components/preview/verdictMeta.js.map +1 -1
- package/lib/commonjs/components/sources.js +72 -0
- package/lib/commonjs/components/sources.js.map +1 -0
- package/lib/commonjs/store/snapshotVault.js +93 -9
- package/lib/commonjs/store/snapshotVault.js.map +1 -1
- package/lib/commonjs/store/timeMachineStore.js +125 -6
- package/lib/commonjs/store/timeMachineStore.js.map +1 -1
- package/lib/commonjs/sync/timeMachineSyncAdapter.js +41 -0
- package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +1 -1
- package/lib/commonjs/ui/SwipeActionsRow.js +167 -0
- package/lib/commonjs/ui/SwipeActionsRow.js.map +1 -0
- package/lib/commonjs/ui/primitives.js +164 -0
- package/lib/commonjs/ui/primitives.js.map +1 -0
- package/lib/commonjs/ui/tmTheme.js +103 -0
- package/lib/commonjs/ui/tmTheme.js.map +1 -0
- package/lib/module/components/TimeMachineBody.js +150 -680
- package/lib/module/components/TimeMachineBody.js.map +1 -1
- package/lib/module/components/TimeMachineModal.js +11 -12
- package/lib/module/components/TimeMachineModal.js.map +1 -1
- package/lib/module/components/confirm.js +34 -0
- package/lib/module/components/confirm.js.map +1 -0
- package/lib/module/components/format.js +19 -0
- package/lib/module/components/format.js.map +1 -0
- package/lib/module/components/list/CaptureBar.js +90 -0
- package/lib/module/components/list/CaptureBar.js.map +1 -0
- package/lib/module/components/list/RestoreOutcomeCard.js +156 -0
- package/lib/module/components/list/RestoreOutcomeCard.js.map +1 -0
- package/lib/module/components/list/SnapshotRow.js +138 -0
- package/lib/module/components/list/SnapshotRow.js.map +1 -0
- package/lib/module/components/list/SourcesStrip.js +121 -0
- package/lib/module/components/list/SourcesStrip.js.map +1 -0
- package/lib/module/components/list/UndoDeleteBar.js +78 -0
- package/lib/module/components/list/UndoDeleteBar.js.map +1 -0
- package/lib/module/components/list/WipeAllRow.js +41 -0
- package/lib/module/components/list/WipeAllRow.js.map +1 -0
- package/lib/module/components/preview/ItemDiffPanel.js +72 -0
- package/lib/module/components/preview/ItemDiffPanel.js.map +1 -0
- package/lib/module/components/preview/PreviewFlow.js +46 -0
- package/lib/module/components/preview/PreviewFlow.js.map +1 -0
- package/lib/module/components/preview/RestorePointNameRow.js +78 -0
- package/lib/module/components/preview/RestorePointNameRow.js.map +1 -0
- package/lib/module/components/preview/RestorePreviewScreen.js +552 -638
- package/lib/module/components/preview/RestorePreviewScreen.js.map +1 -1
- package/lib/module/components/preview/verdictMeta.js +9 -8
- package/lib/module/components/preview/verdictMeta.js.map +1 -1
- package/lib/module/components/sources.js +66 -0
- package/lib/module/components/sources.js.map +1 -0
- package/lib/module/store/snapshotVault.js +87 -9
- package/lib/module/store/snapshotVault.js.map +1 -1
- package/lib/module/store/timeMachineStore.js +125 -7
- package/lib/module/store/timeMachineStore.js.map +1 -1
- package/lib/module/sync/timeMachineSyncAdapter.js +41 -0
- package/lib/module/sync/timeMachineSyncAdapter.js.map +1 -1
- package/lib/module/ui/SwipeActionsRow.js +162 -0
- package/lib/module/ui/SwipeActionsRow.js.map +1 -0
- package/lib/module/ui/primitives.js +156 -0
- package/lib/module/ui/primitives.js.map +1 -0
- package/lib/module/ui/tmTheme.js +99 -0
- package/lib/module/ui/tmTheme.js.map +1 -0
- package/lib/typescript/components/TimeMachineBody.d.ts.map +1 -1
- package/lib/typescript/components/TimeMachineModal.d.ts.map +1 -1
- package/lib/typescript/components/confirm.d.ts +2 -0
- package/lib/typescript/components/confirm.d.ts.map +1 -0
- package/lib/typescript/components/format.d.ts +4 -0
- package/lib/typescript/components/format.d.ts.map +1 -0
- package/lib/typescript/components/list/CaptureBar.d.ts +6 -0
- package/lib/typescript/components/list/CaptureBar.d.ts.map +1 -0
- package/lib/typescript/components/list/RestoreOutcomeCard.d.ts +11 -0
- package/lib/typescript/components/list/RestoreOutcomeCard.d.ts.map +1 -0
- package/lib/typescript/components/list/SnapshotRow.d.ts +12 -0
- package/lib/typescript/components/list/SnapshotRow.d.ts.map +1 -0
- package/lib/typescript/components/list/SourcesStrip.d.ts +5 -0
- package/lib/typescript/components/list/SourcesStrip.d.ts.map +1 -0
- package/lib/typescript/components/list/UndoDeleteBar.d.ts +8 -0
- package/lib/typescript/components/list/UndoDeleteBar.d.ts.map +1 -0
- package/lib/typescript/components/list/WipeAllRow.d.ts +5 -0
- package/lib/typescript/components/list/WipeAllRow.d.ts.map +1 -0
- package/lib/typescript/components/preview/ItemDiffPanel.d.ts +5 -0
- package/lib/typescript/components/preview/ItemDiffPanel.d.ts.map +1 -0
- package/lib/typescript/components/preview/PreviewFlow.d.ts +9 -0
- package/lib/typescript/components/preview/PreviewFlow.d.ts.map +1 -0
- package/lib/typescript/components/preview/RestorePointNameRow.d.ts +5 -0
- package/lib/typescript/components/preview/RestorePointNameRow.d.ts.map +1 -0
- package/lib/typescript/components/preview/RestorePreviewScreen.d.ts +1 -5
- package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +1 -1
- package/lib/typescript/components/preview/verdictMeta.d.ts +5 -0
- package/lib/typescript/components/preview/verdictMeta.d.ts.map +1 -1
- package/lib/typescript/components/sources.d.ts +36 -0
- package/lib/typescript/components/sources.d.ts.map +1 -0
- package/lib/typescript/store/snapshotVault.d.ts +48 -0
- package/lib/typescript/store/snapshotVault.d.ts.map +1 -1
- package/lib/typescript/store/timeMachineStore.d.ts +35 -1
- package/lib/typescript/store/timeMachineStore.d.ts.map +1 -1
- package/lib/typescript/sync/timeMachineSyncAdapter.d.ts +17 -0
- package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/ui/SwipeActionsRow.d.ts +32 -0
- package/lib/typescript/ui/SwipeActionsRow.d.ts.map +1 -0
- package/lib/typescript/ui/primitives.d.ts +57 -0
- package/lib/typescript/ui/primitives.d.ts.map +1 -0
- package/lib/typescript/ui/tmTheme.d.ts +67 -0
- package/lib/typescript/ui/tmTheme.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/components/TimeMachineBody.tsx +183 -817
- package/src/components/TimeMachineModal.tsx +10 -11
- package/src/components/confirm.ts +35 -0
- package/src/components/format.ts +17 -0
- package/src/components/list/CaptureBar.tsx +100 -0
- package/src/components/list/RestoreOutcomeCard.tsx +159 -0
- package/src/components/list/SnapshotRow.tsx +155 -0
- package/src/components/list/SourcesStrip.tsx +124 -0
- package/src/components/list/UndoDeleteBar.tsx +76 -0
- package/src/components/list/WipeAllRow.tsx +42 -0
- package/src/components/preview/ItemDiffPanel.tsx +77 -0
- package/src/components/preview/PreviewFlow.tsx +70 -0
- package/src/components/preview/RestorePointNameRow.tsx +80 -0
- package/src/components/preview/RestorePreviewScreen.tsx +535 -535
- package/src/components/preview/verdictMeta.ts +8 -8
- package/src/components/sources.ts +92 -0
- package/src/store/snapshotVault.ts +131 -9
- package/src/store/timeMachineStore.ts +136 -5
- package/src/sync/timeMachineSyncAdapter.ts +30 -0
- package/src/ui/SwipeActionsRow.tsx +199 -0
- package/src/ui/primitives.tsx +157 -0
- package/src/ui/tmTheme.ts +107 -0
- package/lib/commonjs/components/preview/ItemDetailScreen.js +0 -189
- package/lib/commonjs/components/preview/ItemDetailScreen.js.map +0 -1
- package/lib/module/components/preview/ItemDetailScreen.js +0 -184
- package/lib/module/components/preview/ItemDetailScreen.js.map +0 -1
- package/lib/typescript/components/preview/ItemDetailScreen.d.ts +0 -11
- package/lib/typescript/components/preview/ItemDetailScreen.d.ts.map +0 -1
- package/src/components/preview/ItemDetailScreen.tsx +0 -172
|
@@ -7,17 +7,21 @@ exports.RestorePreviewScreen = RestorePreviewScreen;
|
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _floatingToolsCore = require("@buoy-gg/floating-tools-core");
|
|
11
10
|
var _core = require("@buoy-gg/core");
|
|
11
|
+
var _primitives = require("../../ui/primitives");
|
|
12
|
+
var _tmTheme = require("../../ui/tmTheme");
|
|
12
13
|
var _timeMachineStore = require("../../store/timeMachineStore");
|
|
14
|
+
var _ItemDiffPanel = require("./ItemDiffPanel");
|
|
15
|
+
var _RestorePointNameRow = require("./RestorePointNameRow");
|
|
13
16
|
var _verdictMeta = require("./verdictMeta");
|
|
14
17
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
18
|
/**
|
|
16
19
|
* Restore Preview — "what will restoring this snapshot actually change?"
|
|
17
20
|
*
|
|
18
|
-
* ONE virtualized FlatList is the scrollable area (
|
|
19
|
-
* source
|
|
20
|
-
* footer — no nested scroll regions, thousands of
|
|
21
|
+
* ONE virtualized FlatList is the scrollable area (the section header, the
|
|
22
|
+
* source rows, their item rows and the inline diffs are all list rows) with
|
|
23
|
+
* a sticky Restore CTA footer — no nested scroll regions, so thousands of
|
|
24
|
+
* storage keys stay cheap.
|
|
21
25
|
*
|
|
22
26
|
* Layout follows the Time Machine mockup: source sections are card
|
|
23
27
|
* dropdowns with tool-icon tiles, a "N keys · M changed" detection subtitle,
|
|
@@ -28,13 +32,6 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
28
32
|
* items are passed to restore as exclusions and left untouched.
|
|
29
33
|
*/
|
|
30
34
|
|
|
31
|
-
const SOURCE_ICONS = {
|
|
32
|
-
storage: _floatingToolsCore.StorageIcon,
|
|
33
|
-
redux: _floatingToolsCore.ReduxIcon,
|
|
34
|
-
zustand: _floatingToolsCore.ZustandIcon,
|
|
35
|
-
jotai: _floatingToolsCore.JotaiIcon,
|
|
36
|
-
query: _floatingToolsCore.QueryIcon
|
|
37
|
-
};
|
|
38
35
|
const SOURCE_NOUNS = {
|
|
39
36
|
storage: "keys",
|
|
40
37
|
redux: "slices",
|
|
@@ -42,6 +39,29 @@ const SOURCE_NOUNS = {
|
|
|
42
39
|
jotai: "atoms",
|
|
43
40
|
query: "queries"
|
|
44
41
|
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Where a row sits in the one card that holds the whole list. The list has
|
|
45
|
+
* to stay flat to stay virtualized, so each row paints its own share of the
|
|
46
|
+
* card: the first row rounds its top, the last rounds its bottom, and every
|
|
47
|
+
* other row draws the hairline above it.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The route leg, as a row in the same card as the sources. It is not a
|
|
52
|
+
* source — nothing diffs it — but "will this also take me back to
|
|
53
|
+
* /checkout?" is a decision about THIS restore, so it belongs beside the
|
|
54
|
+
* other things the restore is about to do rather than on the list screen.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/** Shared empty selection — a stable identity for "nothing is excluded". */
|
|
58
|
+
const EMPTY_SELECTION = new Set();
|
|
59
|
+
function sameSelection(a, b) {
|
|
60
|
+
if (a.size !== b.size) return false;
|
|
61
|
+
for (const key of a) if (!b.has(key)) return false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
/** Compound exclusion key — what timeMachineStore.restore expects. */
|
|
46
66
|
function cKey(sourceId, itemKey) {
|
|
47
67
|
return `${sourceId}::${itemKey}`;
|
|
@@ -56,95 +76,120 @@ function shortPreview(value) {
|
|
|
56
76
|
return "[complex]";
|
|
57
77
|
}
|
|
58
78
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The grouped-card shell one row paints. Rounds the ends, insets the card
|
|
82
|
+
* from the sheet, and draws the hairline that separates it from the row
|
|
83
|
+
* above — the same shape the home list's <Group> makes, rebuilt per row so
|
|
84
|
+
* the list stays virtualized.
|
|
85
|
+
*/
|
|
86
|
+
function CardRow({
|
|
87
|
+
position,
|
|
88
|
+
children
|
|
89
|
+
}) {
|
|
90
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
91
|
+
style: [styles.cardRow, position.first ? styles.cardRowFirst : null, position.last ? styles.cardRowLast : null],
|
|
92
|
+
children: [position.first ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
93
|
+
style: styles.cardSeparator
|
|
94
|
+
}), children]
|
|
95
|
+
});
|
|
62
96
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
function CountPill({
|
|
98
|
+
glyph,
|
|
99
|
+
count,
|
|
100
|
+
color
|
|
101
|
+
}) {
|
|
102
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
103
|
+
style: [styles.countPill, {
|
|
104
|
+
backgroundColor: `${color}26`
|
|
105
|
+
}],
|
|
106
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
107
|
+
style: [styles.countPillText, {
|
|
108
|
+
color
|
|
109
|
+
}],
|
|
110
|
+
children: [glyph, count]
|
|
111
|
+
})
|
|
112
|
+
});
|
|
70
113
|
}
|
|
71
114
|
function Checkbox({
|
|
72
115
|
state
|
|
73
116
|
}) {
|
|
74
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
117
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
75
118
|
style: [styles.checkbox, state !== "none" && styles.checkboxChecked],
|
|
76
|
-
children:
|
|
77
|
-
style: styles.checkboxGlyph,
|
|
78
|
-
children: "\u2713"
|
|
79
|
-
}), state === "some" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
119
|
+
children: state === "none" ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
80
120
|
style: styles.checkboxGlyph,
|
|
81
|
-
children: "
|
|
82
|
-
})
|
|
121
|
+
children: state === "all" ? "✓" : "−"
|
|
122
|
+
})
|
|
83
123
|
});
|
|
84
124
|
}
|
|
85
125
|
const ItemRow = /*#__PURE__*/(0, _react.memo)(function ItemRow({
|
|
86
126
|
row,
|
|
127
|
+
expanded,
|
|
87
128
|
onOpen,
|
|
88
129
|
onToggle
|
|
89
130
|
}) {
|
|
90
131
|
const meta = _verdictMeta.VERDICT_META[row.item.verdict];
|
|
91
132
|
const dimmed = !meta.applies || row.excluded;
|
|
92
133
|
const openable = row.item.verdict === "changed" || row.item.verdict === "added" || row.item.verdict === "removed";
|
|
93
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
94
|
-
|
|
95
|
-
children:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}],
|
|
116
|
-
children: meta.glyph
|
|
117
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
118
|
-
style: styles.itemBody,
|
|
134
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardRow, {
|
|
135
|
+
position: row,
|
|
136
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
137
|
+
style: [styles.itemRow, dimmed && styles.dimmed],
|
|
138
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
139
|
+
onPress: onToggle,
|
|
140
|
+
disabled: !meta.applies,
|
|
141
|
+
hitSlop: {
|
|
142
|
+
top: 10,
|
|
143
|
+
bottom: 10,
|
|
144
|
+
left: 8,
|
|
145
|
+
right: 8
|
|
146
|
+
},
|
|
147
|
+
testID: `tm-preview-toggle-${row.sourceId}-${row.item.key}`,
|
|
148
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Checkbox, {
|
|
149
|
+
state: !meta.applies || row.excluded ? "none" : "all"
|
|
150
|
+
})
|
|
151
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
152
|
+
style: styles.itemBodyTouch,
|
|
153
|
+
onPress: () => openable && onOpen(),
|
|
154
|
+
disabled: !openable,
|
|
155
|
+
testID: `tm-preview-item-${row.sourceId}-${row.item.key}`,
|
|
119
156
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
120
|
-
style: styles.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
children: [
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
style: [styles.itemGlyph, {
|
|
158
|
+
color: meta.color
|
|
159
|
+
}],
|
|
160
|
+
children: meta.glyph
|
|
161
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
162
|
+
style: styles.itemBody,
|
|
163
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
164
|
+
style: styles.itemLabel,
|
|
165
|
+
numberOfLines: 1,
|
|
166
|
+
children: row.item.label
|
|
167
|
+
}), row.item.verdict === "changed" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
168
|
+
style: styles.itemPreview,
|
|
169
|
+
numberOfLines: 1,
|
|
170
|
+
children: [shortPreview(row.item.oldValue), " \u2192", " ", shortPreview(row.item.newValue)]
|
|
171
|
+
}), row.item.verdict === "added" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
172
|
+
style: styles.itemPreview,
|
|
173
|
+
numberOfLines: 1,
|
|
174
|
+
children: shortPreview(row.item.newValue)
|
|
175
|
+
}), row.item.verdict === "removed" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
176
|
+
style: [styles.itemPreview, styles.itemPreviewRemoved],
|
|
177
|
+
numberOfLines: 1,
|
|
178
|
+
children: shortPreview(row.item.oldValue)
|
|
179
|
+
}), row.excluded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
180
|
+
style: styles.itemExcluded,
|
|
181
|
+
children: "excluded \u2014 restore leaves this untouched"
|
|
182
|
+
}) : row.item.reason && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
183
|
+
style: styles.itemReason,
|
|
184
|
+
numberOfLines: 2,
|
|
185
|
+
children: row.item.reason
|
|
186
|
+
})]
|
|
187
|
+
}), openable ? expanded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
|
|
188
|
+
size: 16,
|
|
189
|
+
color: _tmTheme.tm.color.labelTertiary
|
|
190
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.DisclosureChevron, {}) : null]
|
|
146
191
|
})]
|
|
147
|
-
})
|
|
192
|
+
})
|
|
148
193
|
});
|
|
149
194
|
});
|
|
150
195
|
function RestorePreviewScreen({
|
|
@@ -152,43 +197,65 @@ function RestorePreviewScreen({
|
|
|
152
197
|
snapshots,
|
|
153
198
|
busy,
|
|
154
199
|
onBack,
|
|
155
|
-
|
|
156
|
-
onRestore,
|
|
157
|
-
onPickSide,
|
|
158
|
-
onRefresh
|
|
200
|
+
onRestore
|
|
159
201
|
}) {
|
|
160
202
|
const host = (0, _core.useToolHost)();
|
|
161
203
|
const hosted = host.instanceId !== undefined;
|
|
162
|
-
|
|
204
|
+
// `minBottom` is a floor, not a preference: the dimension map can't know
|
|
205
|
+
// about a device that ships next year, and an unmapped one falls through to
|
|
206
|
+
// `bottom: 0`. This keeps the CTA off the home indicator either way.
|
|
207
|
+
const insets = (0, _sharedUi.useSafeAreaInsets)({
|
|
208
|
+
minBottom: 16
|
|
209
|
+
});
|
|
163
210
|
const [collapsed, setCollapsed] = (0, _react.useState)({});
|
|
164
|
-
const [allCollapsed, setAllCollapsed] = (0, _react.useState)(false);
|
|
165
211
|
const [excluded, setExcluded] = (0, _react.useState)(new Set());
|
|
166
|
-
|
|
212
|
+
/** Set by every checkbox interaction — see the auto-save effect below. */
|
|
213
|
+
const userEditedRef = (0, _react.useRef)(false);
|
|
214
|
+
/** Item rows whose diff is expanded inline, by compound key. */
|
|
215
|
+
const [openDiffs, setOpenDiffs] = (0, _react.useState)(EMPTY_SELECTION);
|
|
216
|
+
const toggleDiff = (0, _react.useCallback)(key => {
|
|
217
|
+
setOpenDiffs(prev => {
|
|
218
|
+
const next = new Set(prev);
|
|
219
|
+
if (next.has(key)) next.delete(key);else next.add(key);
|
|
220
|
+
return next;
|
|
221
|
+
});
|
|
222
|
+
}, []);
|
|
223
|
+
// Filtering lives in the shared modal header (the magnifier), same as the
|
|
224
|
+
// restore-point list and every other Buoy tool — one place to look for it.
|
|
225
|
+
const search = host.search;
|
|
167
226
|
const rightMeta = preview.right === "current" ? undefined : snapshots.find(s => s.id === preview.right.snapshotId);
|
|
227
|
+
// Latest-ref: `renderRow` is memoized on its handlers, so this one has to
|
|
228
|
+
// keep a stable identity while still reading the current snapshot.
|
|
229
|
+
const rightMetaRef = (0, _react.useRef)(rightMeta);
|
|
230
|
+
rightMetaRef.current = rightMeta;
|
|
231
|
+
|
|
232
|
+
/** Flip whether this restore also navigates back to the captured route. */
|
|
233
|
+
const toggleRoute = (0, _react.useCallback)(() => {
|
|
234
|
+
if (!rightMetaRef.current) return;
|
|
235
|
+
const meta = rightMetaRef.current;
|
|
236
|
+
void _timeMachineStore.timeMachineStore.setRestoreRoute(meta.id, !(0, _timeMachineStore.willRestoreRoute)(meta));
|
|
237
|
+
}, []);
|
|
168
238
|
const isBaseline = rightMeta?.baseline === true;
|
|
169
239
|
const liveLeft = preview.left === "current";
|
|
170
240
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
setExcluded(next);
|
|
182
|
-
}, [preview.sources]);
|
|
241
|
+
/**
|
|
242
|
+
* The selection this restore point already remembers, as exclusions. Null
|
|
243
|
+
* until there is a snapshot on the right-hand side to have one.
|
|
244
|
+
*/
|
|
245
|
+
const savedExcluded = (0, _react.useMemo)(() => {
|
|
246
|
+
if (!rightMeta) return null;
|
|
247
|
+
return rightMeta.excludedKeys?.length ? new Set(rightMeta.excludedKeys) : EMPTY_SELECTION;
|
|
248
|
+
}, [rightMeta]);
|
|
183
249
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
250
|
+
/**
|
|
251
|
+
* A snapshot still carrying the older `scope` include-list ("only ever
|
|
252
|
+
* touch these", set via MCP). It seeds the checkboxes and is converted to
|
|
253
|
+
* exclusions on read — a restore of it would otherwise still apply include
|
|
254
|
+
* semantics, and the two forms would disagree about what one tap does.
|
|
255
|
+
*/
|
|
256
|
+
const legacyScoped = !!rightMeta?.scope?.length && !rightMeta?.excludedKeys?.length;
|
|
257
|
+
const legacySeed = (0, _react.useMemo)(() => {
|
|
258
|
+
if (!legacyScoped || !rightMeta?.scope) return EMPTY_SELECTION;
|
|
192
259
|
const scopeSet = new Set(rightMeta.scope);
|
|
193
260
|
const next = new Set();
|
|
194
261
|
for (const src of preview.sources) {
|
|
@@ -199,28 +266,48 @@ function RestorePreviewScreen({
|
|
|
199
266
|
}
|
|
200
267
|
}
|
|
201
268
|
}
|
|
202
|
-
|
|
203
|
-
}, [
|
|
269
|
+
return next;
|
|
270
|
+
}, [legacyScoped, rightMeta, preview.sources]);
|
|
204
271
|
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (!rightMeta) return;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
272
|
+
// Open with the saved selection already applied — once per snapshot, and
|
|
273
|
+
// only once there is a diff to apply it to.
|
|
274
|
+
const seededFor = (0, _react.useRef)(null);
|
|
275
|
+
(0, _react.useEffect)(() => {
|
|
276
|
+
if (!rightMeta || preview.building || !savedExcluded) return;
|
|
277
|
+
if (seededFor.current === rightMeta.id) return;
|
|
278
|
+
seededFor.current = rightMeta.id;
|
|
279
|
+
userEditedRef.current = false;
|
|
280
|
+
const seed = savedExcluded.size > 0 ? savedExcluded : legacySeed;
|
|
281
|
+
if (seed.size > 0) setExcluded(new Set(seed));
|
|
282
|
+
// Convert an older include-list scope the moment it's read, so the two
|
|
283
|
+
// forms never disagree about what a restore will do.
|
|
284
|
+
if (legacyScoped && seed.size > 0) {
|
|
285
|
+
void _timeMachineStore.timeMachineStore.setExclusions(rightMeta.id, Array.from(seed));
|
|
218
286
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
287
|
+
}, [rightMeta, preview.building, savedExcluded, legacySeed, legacyScoped]);
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Auto-save. The checkboxes ARE the restore point's setting, so there is
|
|
291
|
+
* nothing to confirm — every edit persists as EXCLUSIONS (the items to
|
|
292
|
+
* leave alone), and every later restore of this point honors them, one-tap
|
|
293
|
+
* RESTORE and MCP included.
|
|
294
|
+
*
|
|
295
|
+
* Never an include list: unchecking one of ten keys must keep restoring the
|
|
296
|
+
* other nine AND anything that only starts differing tomorrow, which a list
|
|
297
|
+
* built from today's diff cannot do.
|
|
298
|
+
*
|
|
299
|
+
* Gated on a ref rather than on comparing to what's stored, because on the
|
|
300
|
+
* frames before the seed lands `excluded` is legitimately empty — writing
|
|
301
|
+
* that would erase the saved selection we are about to load.
|
|
302
|
+
*/
|
|
303
|
+
(0, _react.useEffect)(() => {
|
|
304
|
+
if (!rightMeta || !savedExcluded || !userEditedRef.current) return;
|
|
305
|
+
if (sameSelection(excluded, savedExcluded)) return;
|
|
306
|
+
const keys = Array.from(excluded);
|
|
307
|
+
void _timeMachineStore.timeMachineStore.setExclusions(rightMeta.id, keys.length ? keys : null);
|
|
308
|
+
}, [excluded, rightMeta, savedExcluded]);
|
|
223
309
|
const toggleItem = (0, _react.useCallback)(key => {
|
|
310
|
+
userEditedRef.current = true;
|
|
224
311
|
setExcluded(prev => {
|
|
225
312
|
const next = new Set(prev);
|
|
226
313
|
if (next.has(key)) next.delete(key);else next.add(key);
|
|
@@ -228,6 +315,7 @@ function RestorePreviewScreen({
|
|
|
228
315
|
});
|
|
229
316
|
}, []);
|
|
230
317
|
const toggleSource = (0, _react.useCallback)((source, includeState) => {
|
|
318
|
+
userEditedRef.current = true;
|
|
231
319
|
setExcluded(prev => {
|
|
232
320
|
const next = new Set(prev);
|
|
233
321
|
for (const item of source.items) {
|
|
@@ -248,13 +336,6 @@ function RestorePreviewScreen({
|
|
|
248
336
|
[id]: !currentlyCollapsed
|
|
249
337
|
}));
|
|
250
338
|
}, []);
|
|
251
|
-
const toggleAllCollapsed = (0, _react.useCallback)(() => {
|
|
252
|
-
setAllCollapsed(prev => {
|
|
253
|
-
const next = !prev;
|
|
254
|
-
setCollapsed(Object.fromEntries(preview.sources.map(s => [s.id, next])));
|
|
255
|
-
return next;
|
|
256
|
-
});
|
|
257
|
-
}, [preview.sources]);
|
|
258
339
|
const totals = (0, _react.useMemo)(() => {
|
|
259
340
|
let applies = 0;
|
|
260
341
|
let excludedCount = 0;
|
|
@@ -285,23 +366,31 @@ function RestorePreviewScreen({
|
|
|
285
366
|
// bottom CTA; the preset's labeled RELOAD APP action stays available.
|
|
286
367
|
(0, _core.useToolHeader)(hosted ? {
|
|
287
368
|
title: "Restore Preview",
|
|
288
|
-
subtitle: rightMeta?.name ?? "
|
|
289
|
-
onBack
|
|
290
|
-
searchable: false // the in-body "Filter keys…" field covers it
|
|
369
|
+
subtitle: rightMeta?.name ?? "preview",
|
|
370
|
+
onBack
|
|
291
371
|
} : null,
|
|
292
372
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
293
373
|
[hosted, rightMeta?.name]);
|
|
294
|
-
const
|
|
374
|
+
const {
|
|
375
|
+
rows,
|
|
376
|
+
blockedSources
|
|
377
|
+
} = (0, _react.useMemo)(() => {
|
|
295
378
|
const q = search.trim().toLowerCase();
|
|
296
379
|
const out = [];
|
|
380
|
+
// Sources the restore would not touch at all get no card: "no changes"
|
|
381
|
+
// rows are noise on a screen about what WILL change.
|
|
382
|
+
/** Sources holding a won't-apply item, so the note can name where to look. */
|
|
383
|
+
const blocked = [];
|
|
297
384
|
for (const src of preview.sources) {
|
|
298
385
|
// Every detected source gets a card whose subtitle carries the
|
|
299
386
|
// detection proof ("60 keys · 7 changed" / "2 slices · no changes"),
|
|
300
387
|
// so clean sources need no expansion. Unchanged ITEMS never render.
|
|
301
388
|
const relevant = src.items.some(i => i.verdict !== "unchanged");
|
|
389
|
+
if (!relevant && !src.error) continue;
|
|
302
390
|
const expandable = relevant || src.notes.length > 0 || !!src.error;
|
|
303
391
|
const applicable = src.items.filter(i => _verdictMeta.VERDICT_META[i.verdict].applies);
|
|
304
392
|
const wontApplyCount = src.items.filter(i => i.verdict === "wont-apply").length;
|
|
393
|
+
if (wontApplyCount > 0) blocked.push(src.label);
|
|
305
394
|
const noun = src.items.length === 1 ? (SOURCE_NOUNS[src.id] ?? "items").replace(/ies$/, "y").replace(/s$/, "") : SOURCE_NOUNS[src.id] ?? "items";
|
|
306
395
|
const summary = `${src.items.length} ${noun} · ` + (applicable.length > 0 ? `${applicable.length} changed` : wontApplyCount > 0 ? `${wontApplyCount} won't apply` : "no changes");
|
|
307
396
|
const excludedInSource = applicable.filter(i => excluded.has(cKey(src.id, i.key))).length;
|
|
@@ -322,7 +411,10 @@ function RestorePreviewScreen({
|
|
|
322
411
|
if (q && !item.label.toLowerCase().includes(q)) return false;
|
|
323
412
|
return true;
|
|
324
413
|
});
|
|
325
|
-
|
|
414
|
+
// Everything starts collapsed. The screen's job on open is "which
|
|
415
|
+
// sources would this touch, and how much" — expanding a source with
|
|
416
|
+
// 58 keys before you asked buries that under its own contents.
|
|
417
|
+
const isCollapsed = expandable ? collapsed[src.id] ?? true : true;
|
|
326
418
|
out.push({
|
|
327
419
|
kind: "source",
|
|
328
420
|
source: src,
|
|
@@ -331,35 +423,73 @@ function RestorePreviewScreen({
|
|
|
331
423
|
applicableCount: applicable.length,
|
|
332
424
|
counts,
|
|
333
425
|
expandable,
|
|
334
|
-
summary
|
|
426
|
+
summary,
|
|
427
|
+
first: false,
|
|
428
|
+
last: false
|
|
335
429
|
});
|
|
336
430
|
if (!isCollapsed) {
|
|
337
431
|
for (const note of src.notes) {
|
|
338
432
|
out.push({
|
|
339
433
|
kind: "note",
|
|
340
434
|
id: `${src.id}:${note}`,
|
|
341
|
-
text: note
|
|
435
|
+
text: note,
|
|
436
|
+
first: false,
|
|
437
|
+
last: false
|
|
342
438
|
});
|
|
343
439
|
}
|
|
344
440
|
if (src.error) {
|
|
345
441
|
out.push({
|
|
346
442
|
kind: "note",
|
|
347
443
|
id: `${src.id}:err`,
|
|
348
|
-
text: `⚠ ${src.error}
|
|
444
|
+
text: `⚠ ${src.error}`,
|
|
445
|
+
first: false,
|
|
446
|
+
last: false
|
|
349
447
|
});
|
|
350
448
|
}
|
|
351
449
|
for (const item of visible) {
|
|
450
|
+
const key = cKey(src.id, item.key);
|
|
352
451
|
out.push({
|
|
353
452
|
kind: "item",
|
|
354
453
|
sourceId: src.id,
|
|
355
454
|
item,
|
|
356
|
-
excluded: excluded.has(
|
|
455
|
+
excluded: excluded.has(key),
|
|
456
|
+
first: false,
|
|
457
|
+
last: false
|
|
357
458
|
});
|
|
459
|
+
if (openDiffs.has(key)) {
|
|
460
|
+
out.push({
|
|
461
|
+
kind: "diff",
|
|
462
|
+
sourceId: src.id,
|
|
463
|
+
item,
|
|
464
|
+
first: false,
|
|
465
|
+
last: false
|
|
466
|
+
});
|
|
467
|
+
}
|
|
358
468
|
}
|
|
359
469
|
}
|
|
360
470
|
}
|
|
361
|
-
|
|
362
|
-
|
|
471
|
+
if (rightMeta?.route) {
|
|
472
|
+
out.push({
|
|
473
|
+
kind: "route",
|
|
474
|
+
href: rightMeta.route.href,
|
|
475
|
+
on: (0, _timeMachineStore.willRestoreRoute)(rightMeta),
|
|
476
|
+
first: false,
|
|
477
|
+
last: false
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
// ONE card holds every source — the ends of the LIST round, and every
|
|
481
|
+
// other boundary is just a hairline. Per-source cards would read as
|
|
482
|
+
// separate groups, which they aren't: this is one list of what a restore
|
|
483
|
+
// would touch.
|
|
484
|
+
if (out.length > 0) {
|
|
485
|
+
out[0].first = true;
|
|
486
|
+
out[out.length - 1].last = true;
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
rows: out,
|
|
490
|
+
blockedSources: blocked
|
|
491
|
+
};
|
|
492
|
+
}, [preview.sources, search, collapsed, excluded, openDiffs, rightMeta]);
|
|
363
493
|
const renderRow = (0, _react.useCallback)(({
|
|
364
494
|
item: row
|
|
365
495
|
}) => {
|
|
@@ -368,86 +498,119 @@ function RestorePreviewScreen({
|
|
|
368
498
|
const {
|
|
369
499
|
counts
|
|
370
500
|
} = row;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
388
|
-
style: styles.sourceCardTouch,
|
|
389
|
-
onPress: () => row.expandable && toggleCollapse(src.id, row.collapsed),
|
|
390
|
-
disabled: !row.expandable,
|
|
391
|
-
testID: `tm-preview-source-${src.id}`,
|
|
392
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
393
|
-
style: styles.sourceIconTile,
|
|
394
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(IconComp, {
|
|
395
|
-
size: 18
|
|
501
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardRow, {
|
|
502
|
+
position: row,
|
|
503
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
504
|
+
style: styles.sourceCard,
|
|
505
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
506
|
+
onPress: () => toggleSource(src, row.includeState),
|
|
507
|
+
disabled: row.applicableCount === 0,
|
|
508
|
+
hitSlop: {
|
|
509
|
+
top: 10,
|
|
510
|
+
bottom: 10,
|
|
511
|
+
left: 8,
|
|
512
|
+
right: 8
|
|
513
|
+
},
|
|
514
|
+
testID: `tm-preview-source-toggle-${src.id}`,
|
|
515
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Checkbox, {
|
|
516
|
+
state: row.applicableCount === 0 ? "none" : row.includeState
|
|
396
517
|
})
|
|
518
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
519
|
+
style: styles.sourceCardTouch,
|
|
520
|
+
onPress: () => row.expandable && toggleCollapse(src.id, row.collapsed),
|
|
521
|
+
disabled: !row.expandable,
|
|
522
|
+
testID: `tm-preview-source-${src.id}`,
|
|
523
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
524
|
+
style: styles.sourceNameBlock,
|
|
525
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
526
|
+
style: styles.sourceName,
|
|
527
|
+
numberOfLines: 1,
|
|
528
|
+
children: src.label
|
|
529
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
530
|
+
style: styles.sourceSummary,
|
|
531
|
+
numberOfLines: 1,
|
|
532
|
+
children: row.includeState === "none" && row.applicableCount > 0 ? `${row.summary} · excluded` : row.summary
|
|
533
|
+
})]
|
|
534
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
535
|
+
style: styles.sourceBadges,
|
|
536
|
+
children: [counts.removed > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(CountPill, {
|
|
537
|
+
glyph: "\u2212",
|
|
538
|
+
count: counts.removed,
|
|
539
|
+
color: _tmTheme.tm.color.danger
|
|
540
|
+
}) : null, counts.added > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(CountPill, {
|
|
541
|
+
glyph: "+",
|
|
542
|
+
count: counts.added,
|
|
543
|
+
color: _tmTheme.tm.color.accent
|
|
544
|
+
}) : null, counts.changed > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(CountPill, {
|
|
545
|
+
glyph: "\u2248",
|
|
546
|
+
count: counts.changed,
|
|
547
|
+
color: _tmTheme.tm.color.info
|
|
548
|
+
}) : null]
|
|
549
|
+
}), row.expandable ? row.collapsed ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.DisclosureChevron, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
|
|
550
|
+
size: 16,
|
|
551
|
+
color: _tmTheme.tm.color.labelTertiary
|
|
552
|
+
}) : null]
|
|
553
|
+
})]
|
|
554
|
+
})
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
if (row.kind === "note") {
|
|
558
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardRow, {
|
|
559
|
+
position: row,
|
|
560
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
561
|
+
style: styles.noteRow,
|
|
562
|
+
children: row.text
|
|
563
|
+
})
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (row.kind === "route") {
|
|
567
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardRow, {
|
|
568
|
+
position: row,
|
|
569
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
570
|
+
style: styles.routeRow,
|
|
571
|
+
onPress: toggleRoute,
|
|
572
|
+
accessibilityRole: "switch",
|
|
573
|
+
accessibilityState: {
|
|
574
|
+
checked: row.on
|
|
575
|
+
},
|
|
576
|
+
accessibilityLabel: `Also return to ${row.href}`,
|
|
577
|
+
testID: "tm-preview-route",
|
|
578
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Checkbox, {
|
|
579
|
+
state: row.on ? "all" : "none"
|
|
397
580
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
398
|
-
style: styles.
|
|
581
|
+
style: styles.routeText,
|
|
399
582
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
400
|
-
style: styles.
|
|
401
|
-
|
|
402
|
-
children: src.label
|
|
583
|
+
style: styles.routeTitle,
|
|
584
|
+
children: "Return to this screen"
|
|
403
585
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
404
|
-
style: styles.
|
|
586
|
+
style: styles.routeHref,
|
|
405
587
|
numberOfLines: 1,
|
|
406
|
-
children: row.
|
|
407
|
-
})]
|
|
408
|
-
}), !clean && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
409
|
-
style: styles.sourceBadges,
|
|
410
|
-
children: [counts.removed > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
411
|
-
style: [styles.sourceBadge, {
|
|
412
|
-
color: _sharedUi.buoyColors.error
|
|
413
|
-
}],
|
|
414
|
-
children: ["\u2212", counts.removed]
|
|
415
|
-
}), counts.added > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
416
|
-
style: [styles.sourceBadge, {
|
|
417
|
-
color: _sharedUi.buoyColors.success
|
|
418
|
-
}],
|
|
419
|
-
children: ["+", counts.added]
|
|
420
|
-
}), counts.changed > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
421
|
-
style: [styles.sourceBadge, {
|
|
422
|
-
color: _sharedUi.buoyColors.info
|
|
423
|
-
}],
|
|
424
|
-
children: ["\u2248", counts.changed]
|
|
588
|
+
children: row.href
|
|
425
589
|
})]
|
|
426
|
-
})
|
|
427
|
-
|
|
428
|
-
color: _sharedUi.buoyColors.textMuted
|
|
429
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
|
|
430
|
-
size: 16,
|
|
431
|
-
color: _sharedUi.buoyColors.textMuted
|
|
432
|
-
}) : null]
|
|
433
|
-
})]
|
|
590
|
+
})]
|
|
591
|
+
})
|
|
434
592
|
});
|
|
435
593
|
}
|
|
436
|
-
if (row.kind === "
|
|
437
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
438
|
-
|
|
439
|
-
children:
|
|
594
|
+
if (row.kind === "diff") {
|
|
595
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardRow, {
|
|
596
|
+
position: row,
|
|
597
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ItemDiffPanel.ItemDiffPanel, {
|
|
598
|
+
item: row.item
|
|
599
|
+
})
|
|
440
600
|
});
|
|
441
601
|
}
|
|
442
602
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(ItemRow, {
|
|
443
603
|
row: row,
|
|
444
|
-
|
|
604
|
+
expanded: openDiffs.has(cKey(row.sourceId, row.item.key)),
|
|
605
|
+
onOpen: () => toggleDiff(cKey(row.sourceId, row.item.key)),
|
|
445
606
|
onToggle: () => toggleItem(cKey(row.sourceId, row.item.key))
|
|
446
607
|
});
|
|
447
|
-
}, [
|
|
608
|
+
}, [openDiffs, toggleDiff, toggleCollapse, toggleItem, toggleSource, toggleRoute]);
|
|
448
609
|
const keyExtractor = (0, _react.useCallback)(row => {
|
|
449
610
|
if (row.kind === "source") return `s:${row.source.id}`;
|
|
450
611
|
if (row.kind === "note") return `n:${row.id}`;
|
|
612
|
+
if (row.kind === "route") return "route";
|
|
613
|
+
if (row.kind === "diff") return `d:${row.sourceId}:${row.item.key}`;
|
|
451
614
|
return `i:${row.sourceId}:${row.item.key}`;
|
|
452
615
|
}, []);
|
|
453
616
|
const header = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -466,179 +629,17 @@ function RestorePreviewScreen({
|
|
|
466
629
|
numberOfLines: 1,
|
|
467
630
|
children: "Restore Preview"
|
|
468
631
|
})]
|
|
469
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
style: styles.compareTagRow,
|
|
477
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
478
|
-
style: [styles.stateDot, {
|
|
479
|
-
backgroundColor: _sharedUi.buoyColors.info
|
|
480
|
-
}]
|
|
481
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
482
|
-
style: styles.compareTag,
|
|
483
|
-
children: liveLeft ? "CURRENT STATE" : "SNAPSHOT"
|
|
484
|
-
})]
|
|
485
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
486
|
-
style: styles.compareName,
|
|
487
|
-
numberOfLines: 1,
|
|
488
|
-
children: sideName(preview.left, snapshots)
|
|
489
|
-
}), liveLeft ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
490
|
-
style: styles.compareMetaRow,
|
|
491
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
492
|
-
style: styles.compareMeta,
|
|
493
|
-
children: ["built ", timeAgo(preview.builtAt), " ago"]
|
|
494
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
495
|
-
onPress: onRefresh,
|
|
496
|
-
disabled: preview.building,
|
|
497
|
-
hitSlop: {
|
|
498
|
-
top: 8,
|
|
499
|
-
bottom: 8,
|
|
500
|
-
left: 6,
|
|
501
|
-
right: 8
|
|
502
|
-
},
|
|
503
|
-
accessibilityLabel: "Rebuild preview",
|
|
504
|
-
testID: "tm-preview-refresh",
|
|
505
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RefreshCw, {
|
|
506
|
-
size: 11,
|
|
507
|
-
color: preview.building ? _sharedUi.macOSColors.text.disabled : _sharedUi.buoyColors.textSecondary
|
|
508
|
-
})
|
|
509
|
-
})]
|
|
510
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
511
|
-
style: styles.compareMeta,
|
|
512
|
-
children: "snapshot"
|
|
513
|
-
})]
|
|
514
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
515
|
-
style: styles.swapBadge,
|
|
516
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
517
|
-
style: styles.swapGlyph,
|
|
518
|
-
children: "\u21C4"
|
|
519
|
-
})
|
|
520
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
521
|
-
style: [styles.compareSide, styles.compareSideRight],
|
|
522
|
-
onPress: () => onPickSide("right"),
|
|
523
|
-
testID: "tm-preview-pick-right",
|
|
524
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
525
|
-
style: styles.compareTagRow,
|
|
526
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
527
|
-
style: styles.compareTag,
|
|
528
|
-
children: isBaseline ? "BASELINE" : "SNAPSHOT"
|
|
529
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
530
|
-
style: [styles.stateDot, {
|
|
531
|
-
backgroundColor: _sharedUi.buoyColors.success
|
|
532
|
-
}]
|
|
533
|
-
})]
|
|
534
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
535
|
-
style: [styles.compareName, styles.compareNameRight],
|
|
536
|
-
numberOfLines: 1,
|
|
537
|
-
children: sideName(preview.right, snapshots)
|
|
538
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
539
|
-
style: [styles.compareMeta, styles.compareMetaRight],
|
|
540
|
-
children: rightMeta ? `${timeAgo(rightMeta.createdAt)} ago` : ""
|
|
541
|
-
})]
|
|
542
|
-
})]
|
|
543
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
544
|
-
style: styles.changesRow,
|
|
545
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
546
|
-
style: styles.changesTitleRow,
|
|
547
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
548
|
-
style: styles.changesTitle,
|
|
549
|
-
children: "Changes to restore"
|
|
550
|
-
}), totals.applies + totals.excludedCount > 1 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
551
|
-
style: styles.selectLinks,
|
|
552
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
553
|
-
onPress: selectAll,
|
|
554
|
-
hitSlop: {
|
|
555
|
-
top: 8,
|
|
556
|
-
bottom: 8,
|
|
557
|
-
left: 4,
|
|
558
|
-
right: 4
|
|
559
|
-
},
|
|
560
|
-
testID: "tm-preview-select-all",
|
|
561
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
562
|
-
style: [styles.selectLink, totals.excludedCount === 0 && styles.selectLinkActive],
|
|
563
|
-
children: "all"
|
|
564
|
-
})
|
|
565
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
566
|
-
style: styles.selectLinkSep,
|
|
567
|
-
children: "\xB7"
|
|
568
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
569
|
-
onPress: selectNone,
|
|
570
|
-
hitSlop: {
|
|
571
|
-
top: 8,
|
|
572
|
-
bottom: 8,
|
|
573
|
-
left: 4,
|
|
574
|
-
right: 4
|
|
575
|
-
},
|
|
576
|
-
testID: "tm-preview-select-none",
|
|
577
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
578
|
-
style: [styles.selectLink, totals.applies === 0 && totals.excludedCount > 0 && styles.selectLinkActive],
|
|
579
|
-
children: "none"
|
|
580
|
-
})
|
|
581
|
-
}), liveLeft && rightMeta && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
582
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
583
|
-
style: styles.selectLinkSep,
|
|
584
|
-
children: "\xB7"
|
|
585
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
586
|
-
onPress: saveScope,
|
|
587
|
-
hitSlop: {
|
|
588
|
-
top: 8,
|
|
589
|
-
bottom: 8,
|
|
590
|
-
left: 4,
|
|
591
|
-
right: 4
|
|
592
|
-
},
|
|
593
|
-
testID: "tm-preview-save-scope",
|
|
594
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
595
|
-
style: [styles.selectLink, !!rightMeta.scope?.length && styles.selectLinkActive],
|
|
596
|
-
children: "save scope"
|
|
597
|
-
})
|
|
598
|
-
})]
|
|
599
|
-
})]
|
|
600
|
-
})]
|
|
601
|
-
}), preview.building ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
|
|
602
|
-
size: "small",
|
|
603
|
-
color: _sharedUi.buoyColors.primary
|
|
604
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
605
|
-
style: styles.changesChip,
|
|
606
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
607
|
-
style: styles.changesChipText,
|
|
608
|
-
numberOfLines: 1,
|
|
609
|
-
children: [totals.applies === 0 ? totals.excludedCount > 0 ? "everything excluded" : "no changes" : totals.perSource.join(" · "), totals.excludedCount > 0 && totals.applies > 0 ? ` · ${totals.excludedCount} excluded` : ""]
|
|
610
|
-
})
|
|
611
|
-
})]
|
|
612
|
-
}), totals.wontApply > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
613
|
-
style: styles.wontApplyLine,
|
|
614
|
-
children: ["\u2298 ", totals.wontApply, " item", totals.wontApply === 1 ? "" : "s", " won't apply \u2014 shown inline with the reason"]
|
|
615
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
616
|
-
style: styles.searchRow,
|
|
617
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
618
|
-
style: styles.searchField,
|
|
619
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
|
|
620
|
-
size: 14,
|
|
621
|
-
color: _sharedUi.buoyColors.textMuted
|
|
622
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
|
|
623
|
-
style: styles.searchInput,
|
|
624
|
-
value: localSearch,
|
|
625
|
-
onChangeText: setLocalSearch,
|
|
626
|
-
placeholder: "Filter keys\u2026",
|
|
627
|
-
placeholderTextColor: _sharedUi.buoyColors.textMuted,
|
|
628
|
-
autoCorrect: false,
|
|
629
|
-
autoCapitalize: "none",
|
|
630
|
-
testID: "tm-preview-search"
|
|
631
|
-
})]
|
|
632
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
633
|
-
style: styles.collapseAllButton,
|
|
634
|
-
onPress: toggleAllCollapsed,
|
|
635
|
-
accessibilityLabel: allCollapsed ? "Expand all" : "Collapse all",
|
|
636
|
-
testID: "tm-preview-collapse-all",
|
|
637
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
|
|
638
|
-
size: 15,
|
|
639
|
-
color: _sharedUi.buoyColors.textSecondary
|
|
632
|
+
}), rightMeta ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
633
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.SectionLabel, {
|
|
634
|
+
children: "Restore Point"
|
|
635
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.Group, {
|
|
636
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RestorePointNameRow.RestorePointNameRow, {
|
|
637
|
+
name: rightMeta.name,
|
|
638
|
+
onRename: next => void _timeMachineStore.timeMachineStore.rename(rightMeta.id, next)
|
|
640
639
|
})
|
|
641
640
|
})]
|
|
641
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.SectionLabel, {
|
|
642
|
+
children: "Changes to Restore"
|
|
642
643
|
})]
|
|
643
644
|
});
|
|
644
645
|
const ctaDisabled = busy || preview.building || totals.applies === 0;
|
|
@@ -649,16 +650,34 @@ function RestorePreviewScreen({
|
|
|
649
650
|
renderItem: renderRow,
|
|
650
651
|
keyExtractor: keyExtractor,
|
|
651
652
|
ListHeaderComponent: header,
|
|
652
|
-
ListEmptyComponent: preview.building ?
|
|
653
|
+
ListEmptyComponent: preview.building ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
|
|
654
|
+
style: styles.buildingSpinner,
|
|
655
|
+
size: "small",
|
|
656
|
+
color: _tmTheme.tm.color.accent
|
|
657
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
653
658
|
style: styles.emptyText,
|
|
654
659
|
children: search ? "Nothing matches this filter." : "No changes — restoring would change nothing."
|
|
655
660
|
}),
|
|
661
|
+
ListFooterComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
662
|
+
children: totals.wontApply > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
663
|
+
style: styles.warnNote,
|
|
664
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
|
|
665
|
+
size: 12,
|
|
666
|
+
color: _tmTheme.tm.color.warning
|
|
667
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
668
|
+
style: styles.warnNoteText,
|
|
669
|
+
children: [totals.wontApply, " item", totals.wontApply === 1 ? "" : "s", " ", "won't apply \u2014 expand", " ", blockedSources.length > 0 ? blockedSources.join(" and ") : "the source", " ", "to see the reason."]
|
|
670
|
+
})]
|
|
671
|
+
}) : null
|
|
672
|
+
}),
|
|
656
673
|
removeClippedSubviews: true,
|
|
657
674
|
initialNumToRender: 20,
|
|
658
675
|
windowSize: 7,
|
|
659
676
|
contentContainerStyle: styles.listContent
|
|
660
677
|
}), liveLeft && rightMeta && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
661
|
-
style: styles.footer,
|
|
678
|
+
style: [styles.footer, {
|
|
679
|
+
paddingBottom: insets.bottom
|
|
680
|
+
}],
|
|
662
681
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
663
682
|
style: [styles.cta, isBaseline && styles.ctaDanger, ctaDisabled && styles.ctaDisabled],
|
|
664
683
|
onPress: () => onRestore(isBaseline ? "reload" : "live", Array.from(excluded)),
|
|
@@ -666,9 +685,9 @@ function RestorePreviewScreen({
|
|
|
666
685
|
testID: "tm-preview-restore",
|
|
667
686
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RefreshCw, {
|
|
668
687
|
size: 16,
|
|
669
|
-
color:
|
|
688
|
+
color: isBaseline ? _tmTheme.tm.color.onDanger : _tmTheme.tm.color.onAccent
|
|
670
689
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
671
|
-
style: styles.ctaText,
|
|
690
|
+
style: [styles.ctaText, isBaseline ? styles.ctaTextDanger : null],
|
|
672
691
|
children: isBaseline ? "Wipe & Reload" : "Restore State"
|
|
673
692
|
})]
|
|
674
693
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -686,226 +705,133 @@ const HIT = {
|
|
|
686
705
|
};
|
|
687
706
|
const styles = _reactNative.StyleSheet.create({
|
|
688
707
|
container: {
|
|
689
|
-
flex: 1
|
|
708
|
+
flex: 1,
|
|
709
|
+
backgroundColor: _tmTheme.tm.color.sheet
|
|
690
710
|
},
|
|
691
711
|
fallbackHeader: {
|
|
692
712
|
flexDirection: "row",
|
|
693
713
|
alignItems: "center",
|
|
694
|
-
|
|
714
|
+
paddingHorizontal: _tmTheme.tm.gutter,
|
|
715
|
+
paddingVertical: 10,
|
|
695
716
|
gap: 10
|
|
696
717
|
},
|
|
697
718
|
backText: {
|
|
698
|
-
color:
|
|
699
|
-
fontSize:
|
|
719
|
+
color: _tmTheme.tm.color.accent,
|
|
720
|
+
fontSize: _tmTheme.tm.font.control
|
|
700
721
|
},
|
|
701
722
|
screenTitle: {
|
|
702
|
-
color:
|
|
703
|
-
fontSize:
|
|
723
|
+
color: _tmTheme.tm.color.label,
|
|
724
|
+
fontSize: 20,
|
|
704
725
|
fontWeight: "700",
|
|
726
|
+
letterSpacing: _tmTheme.tm.tracking.row,
|
|
705
727
|
flex: 1
|
|
706
728
|
},
|
|
707
|
-
toolbarButton: {
|
|
708
|
-
padding: 4,
|
|
709
|
-
justifyContent: "center",
|
|
710
|
-
alignItems: "center"
|
|
711
|
-
},
|
|
712
729
|
dimmed: {
|
|
713
|
-
opacity: 0.
|
|
730
|
+
opacity: 0.5
|
|
714
731
|
},
|
|
715
732
|
listContent: {
|
|
716
|
-
|
|
717
|
-
paddingTop: 8,
|
|
733
|
+
paddingTop: 14,
|
|
718
734
|
paddingBottom: 12
|
|
719
735
|
},
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
backgroundColor: _sharedUi.buoyColors.card,
|
|
725
|
-
borderColor: _sharedUi.buoyColors.border,
|
|
726
|
-
borderWidth: 1,
|
|
727
|
-
borderRadius: 14,
|
|
728
|
-
padding: 14,
|
|
729
|
-
gap: 10
|
|
730
|
-
},
|
|
731
|
-
compareSide: {
|
|
732
|
-
flex: 1,
|
|
733
|
-
minWidth: 0,
|
|
734
|
-
gap: 3
|
|
735
|
-
},
|
|
736
|
-
compareSideRight: {
|
|
737
|
-
alignItems: "flex-end"
|
|
738
|
-
},
|
|
739
|
-
compareTagRow: {
|
|
740
|
-
flexDirection: "row",
|
|
741
|
-
alignItems: "center",
|
|
742
|
-
gap: 5
|
|
743
|
-
},
|
|
744
|
-
stateDot: {
|
|
745
|
-
width: 6,
|
|
746
|
-
height: 6,
|
|
747
|
-
borderRadius: 3
|
|
748
|
-
},
|
|
749
|
-
compareTag: {
|
|
750
|
-
color: _sharedUi.buoyColors.textSecondary,
|
|
751
|
-
fontSize: 10,
|
|
752
|
-
fontWeight: "700",
|
|
753
|
-
letterSpacing: 0.6
|
|
754
|
-
},
|
|
755
|
-
compareName: {
|
|
756
|
-
color: _sharedUi.buoyColors.text,
|
|
757
|
-
fontSize: 15,
|
|
758
|
-
fontWeight: "700"
|
|
759
|
-
},
|
|
760
|
-
compareNameRight: {
|
|
761
|
-
textAlign: "right"
|
|
762
|
-
},
|
|
763
|
-
compareMeta: {
|
|
764
|
-
color: _sharedUi.buoyColors.textMuted,
|
|
765
|
-
fontSize: 10
|
|
766
|
-
},
|
|
767
|
-
compareMetaRight: {
|
|
768
|
-
textAlign: "right"
|
|
769
|
-
},
|
|
770
|
-
compareMetaRow: {
|
|
771
|
-
flexDirection: "row",
|
|
772
|
-
alignItems: "center",
|
|
773
|
-
gap: 6
|
|
736
|
+
// ── The grouped card each list row paints its own share of ──────────────
|
|
737
|
+
cardRow: {
|
|
738
|
+
marginHorizontal: _tmTheme.tm.gutter,
|
|
739
|
+
backgroundColor: _tmTheme.tm.color.group
|
|
774
740
|
},
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
borderRadius: 17,
|
|
779
|
-
backgroundColor: _sharedUi.buoyColors.hover,
|
|
780
|
-
borderColor: _sharedUi.buoyColors.border,
|
|
781
|
-
borderWidth: 1,
|
|
782
|
-
alignItems: "center",
|
|
783
|
-
justifyContent: "center"
|
|
741
|
+
cardRowFirst: {
|
|
742
|
+
borderTopLeftRadius: _tmTheme.tm.radius.group,
|
|
743
|
+
borderTopRightRadius: _tmTheme.tm.radius.group
|
|
784
744
|
},
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
745
|
+
cardRowLast: {
|
|
746
|
+
borderBottomLeftRadius: _tmTheme.tm.radius.group,
|
|
747
|
+
borderBottomRightRadius: _tmTheme.tm.radius.group,
|
|
748
|
+
marginBottom: 10
|
|
788
749
|
},
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
justifyContent: "space-between",
|
|
794
|
-
marginTop: 14,
|
|
795
|
-
gap: 10
|
|
796
|
-
},
|
|
797
|
-
changesTitle: {
|
|
798
|
-
color: _sharedUi.buoyColors.text,
|
|
799
|
-
fontSize: 14,
|
|
800
|
-
fontWeight: "700"
|
|
750
|
+
cardSeparator: {
|
|
751
|
+
height: _reactNative.StyleSheet.hairlineWidth,
|
|
752
|
+
marginLeft: 51,
|
|
753
|
+
backgroundColor: _tmTheme.tm.color.separator
|
|
801
754
|
},
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
},
|
|
807
|
-
selectLinks: {
|
|
755
|
+
// ── Selection card ──────────────────────────────────────────────────────
|
|
756
|
+
|
|
757
|
+
// ── The "won't apply" heads-up under the card ───────────────────────────
|
|
758
|
+
warnNote: {
|
|
808
759
|
flexDirection: "row",
|
|
809
|
-
alignItems: "
|
|
810
|
-
gap:
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
color: _sharedUi.buoyColors.textMuted,
|
|
814
|
-
fontSize: 12
|
|
760
|
+
alignItems: "flex-start",
|
|
761
|
+
gap: 6,
|
|
762
|
+
paddingHorizontal: _tmTheme.tm.gutter + _tmTheme.tm.textInset,
|
|
763
|
+
paddingTop: 8
|
|
815
764
|
},
|
|
816
|
-
|
|
817
|
-
|
|
765
|
+
warnNoteText: {
|
|
766
|
+
flex: 1,
|
|
767
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
768
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
769
|
+
lineHeight: _tmTheme.tm.font.footnote * 1.35
|
|
770
|
+
},
|
|
771
|
+
// ── Count pills on a source row ─────────────────────────────────────────
|
|
772
|
+
countPill: {
|
|
773
|
+
borderRadius: _tmTheme.tm.radius.pill,
|
|
774
|
+
paddingHorizontal: 9,
|
|
775
|
+
paddingVertical: 3
|
|
776
|
+
},
|
|
777
|
+
countPillText: {
|
|
778
|
+
fontFamily: _tmTheme.TM_MONO,
|
|
779
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
818
780
|
fontWeight: "600"
|
|
819
781
|
},
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
borderColor:
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
paddingHorizontal: 10,
|
|
830
|
-
paddingVertical: 5,
|
|
831
|
-
maxWidth: "60%"
|
|
832
|
-
},
|
|
833
|
-
changesChipText: {
|
|
834
|
-
color: _sharedUi.buoyColors.textSecondary,
|
|
835
|
-
fontSize: 11
|
|
782
|
+
// ── Include checkbox ────────────────────────────────────────────────────
|
|
783
|
+
checkbox: {
|
|
784
|
+
width: 23,
|
|
785
|
+
height: 23,
|
|
786
|
+
borderRadius: _tmTheme.tm.radius.pill,
|
|
787
|
+
borderWidth: 1.7,
|
|
788
|
+
borderColor: _tmTheme.tm.color.labelTertiary,
|
|
789
|
+
alignItems: "center",
|
|
790
|
+
justifyContent: "center"
|
|
836
791
|
},
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
marginTop: 6
|
|
792
|
+
checkboxChecked: {
|
|
793
|
+
borderColor: _tmTheme.tm.color.accent,
|
|
794
|
+
backgroundColor: _tmTheme.tm.color.accent
|
|
841
795
|
},
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
marginTop: 10,
|
|
848
|
-
marginBottom: 6
|
|
796
|
+
checkboxGlyph: {
|
|
797
|
+
color: _tmTheme.tm.color.onAccent,
|
|
798
|
+
fontSize: 13,
|
|
799
|
+
fontWeight: "700",
|
|
800
|
+
lineHeight: 15
|
|
849
801
|
},
|
|
850
|
-
|
|
851
|
-
|
|
802
|
+
// ── Route row ───────────────────────────────────────────────────────────
|
|
803
|
+
routeRow: {
|
|
852
804
|
flexDirection: "row",
|
|
853
805
|
alignItems: "center",
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
borderRadius: 10,
|
|
859
|
-
paddingHorizontal: 10
|
|
806
|
+
minHeight: 58,
|
|
807
|
+
paddingHorizontal: _tmTheme.tm.textInset,
|
|
808
|
+
paddingVertical: 9,
|
|
809
|
+
gap: 12
|
|
860
810
|
},
|
|
861
|
-
|
|
811
|
+
routeText: {
|
|
862
812
|
flex: 1,
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
paddingVertical: 8
|
|
866
|
-
},
|
|
867
|
-
collapseAllButton: {
|
|
868
|
-
width: 36,
|
|
869
|
-
height: 36,
|
|
870
|
-
borderRadius: 10,
|
|
871
|
-
backgroundColor: _sharedUi.buoyColors.card,
|
|
872
|
-
borderColor: _sharedUi.buoyColors.border,
|
|
873
|
-
borderWidth: 1,
|
|
874
|
-
alignItems: "center",
|
|
875
|
-
justifyContent: "center"
|
|
876
|
-
},
|
|
877
|
-
// Checkbox
|
|
878
|
-
checkbox: {
|
|
879
|
-
width: 18,
|
|
880
|
-
height: 18,
|
|
881
|
-
borderRadius: 4,
|
|
882
|
-
borderWidth: 1.5,
|
|
883
|
-
borderColor: _sharedUi.buoyColors.textMuted,
|
|
884
|
-
alignItems: "center",
|
|
885
|
-
justifyContent: "center"
|
|
813
|
+
minWidth: 0,
|
|
814
|
+
gap: 2
|
|
886
815
|
},
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
816
|
+
routeTitle: {
|
|
817
|
+
color: _tmTheme.tm.color.label,
|
|
818
|
+
fontSize: _tmTheme.tm.font.row,
|
|
819
|
+
fontWeight: "600",
|
|
820
|
+
letterSpacing: _tmTheme.tm.tracking.row
|
|
890
821
|
},
|
|
891
|
-
|
|
892
|
-
color:
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
lineHeight: 13
|
|
822
|
+
routeHref: {
|
|
823
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
824
|
+
fontFamily: _tmTheme.TM_MONO,
|
|
825
|
+
fontSize: _tmTheme.tm.font.mono
|
|
896
826
|
},
|
|
897
|
-
// Source
|
|
827
|
+
// ── Source header row (first row of its card) ───────────────────────────
|
|
898
828
|
sourceCard: {
|
|
899
829
|
flexDirection: "row",
|
|
900
830
|
alignItems: "center",
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
paddingHorizontal: 12,
|
|
906
|
-
paddingVertical: 10,
|
|
907
|
-
marginTop: 8,
|
|
908
|
-
gap: 10
|
|
831
|
+
minHeight: 58,
|
|
832
|
+
paddingHorizontal: _tmTheme.tm.textInset,
|
|
833
|
+
paddingVertical: 9,
|
|
834
|
+
gap: 12
|
|
909
835
|
},
|
|
910
836
|
sourceCardTouch: {
|
|
911
837
|
flex: 1,
|
|
@@ -914,67 +840,51 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
914
840
|
gap: 12,
|
|
915
841
|
minWidth: 0
|
|
916
842
|
},
|
|
917
|
-
sourceIconTile: {
|
|
918
|
-
width: 36,
|
|
919
|
-
height: 36,
|
|
920
|
-
borderRadius: 10,
|
|
921
|
-
backgroundColor: _sharedUi.buoyColors.hover,
|
|
922
|
-
alignItems: "center",
|
|
923
|
-
justifyContent: "center"
|
|
924
|
-
},
|
|
925
843
|
sourceNameBlock: {
|
|
926
844
|
flex: 1,
|
|
927
845
|
minWidth: 0,
|
|
928
846
|
gap: 2
|
|
929
847
|
},
|
|
930
848
|
sourceName: {
|
|
931
|
-
color:
|
|
932
|
-
fontSize:
|
|
933
|
-
fontWeight: "
|
|
849
|
+
color: _tmTheme.tm.color.label,
|
|
850
|
+
fontSize: _tmTheme.tm.font.row,
|
|
851
|
+
fontWeight: "600",
|
|
852
|
+
letterSpacing: _tmTheme.tm.tracking.row
|
|
934
853
|
},
|
|
935
854
|
sourceSummary: {
|
|
936
|
-
color:
|
|
937
|
-
fontSize:
|
|
855
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
856
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
938
857
|
fontVariant: ["tabular-nums"]
|
|
939
858
|
},
|
|
940
859
|
sourceBadges: {
|
|
941
860
|
flexDirection: "row",
|
|
942
|
-
gap:
|
|
943
|
-
},
|
|
944
|
-
sourceBadge: {
|
|
945
|
-
fontSize: 13,
|
|
946
|
-
fontWeight: "700",
|
|
947
|
-
fontVariant: ["tabular-nums"]
|
|
861
|
+
gap: 6
|
|
948
862
|
},
|
|
949
863
|
noteRow: {
|
|
950
|
-
color:
|
|
951
|
-
fontSize:
|
|
952
|
-
|
|
953
|
-
|
|
864
|
+
color: _tmTheme.tm.color.labelTertiary,
|
|
865
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
866
|
+
lineHeight: _tmTheme.tm.font.footnote * 1.35,
|
|
867
|
+
paddingHorizontal: _tmTheme.tm.textInset,
|
|
868
|
+
paddingVertical: 9
|
|
954
869
|
},
|
|
955
|
-
// Item rows (
|
|
870
|
+
// ── Item rows (further rows of the same card) ───────────────────────────
|
|
956
871
|
itemRow: {
|
|
957
872
|
flexDirection: "row",
|
|
958
873
|
alignItems: "center",
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
paddingHorizontal: 10,
|
|
964
|
-
paddingVertical: 9,
|
|
965
|
-
marginTop: 6,
|
|
966
|
-
marginLeft: 14,
|
|
967
|
-
gap: 10
|
|
874
|
+
paddingLeft: _tmTheme.tm.textInset,
|
|
875
|
+
paddingRight: _tmTheme.tm.textInset,
|
|
876
|
+
paddingVertical: 10,
|
|
877
|
+
gap: 12
|
|
968
878
|
},
|
|
969
879
|
itemBodyTouch: {
|
|
970
880
|
flex: 1,
|
|
971
881
|
flexDirection: "row",
|
|
972
882
|
alignItems: "center",
|
|
973
|
-
gap:
|
|
883
|
+
gap: 10,
|
|
974
884
|
minWidth: 0
|
|
975
885
|
},
|
|
976
886
|
itemGlyph: {
|
|
977
|
-
fontSize:
|
|
887
|
+
fontSize: 14,
|
|
978
888
|
fontWeight: "700",
|
|
979
889
|
width: 14,
|
|
980
890
|
textAlign: "center"
|
|
@@ -984,72 +894,76 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
984
894
|
minWidth: 0
|
|
985
895
|
},
|
|
986
896
|
itemLabel: {
|
|
987
|
-
color:
|
|
988
|
-
fontSize:
|
|
897
|
+
color: _tmTheme.tm.color.label,
|
|
898
|
+
fontSize: _tmTheme.tm.font.control,
|
|
899
|
+
letterSpacing: _tmTheme.tm.tracking.control
|
|
989
900
|
},
|
|
990
901
|
itemPreview: {
|
|
991
|
-
color:
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
902
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
903
|
+
fontFamily: _tmTheme.TM_MONO,
|
|
904
|
+
fontSize: _tmTheme.tm.font.mono,
|
|
905
|
+
marginTop: 3
|
|
995
906
|
},
|
|
996
907
|
itemPreviewRemoved: {
|
|
997
908
|
textDecorationLine: "line-through"
|
|
998
909
|
},
|
|
999
910
|
itemReason: {
|
|
1000
|
-
color:
|
|
1001
|
-
fontSize:
|
|
1002
|
-
marginTop:
|
|
911
|
+
color: _tmTheme.tm.color.warning,
|
|
912
|
+
fontSize: _tmTheme.tm.font.mono,
|
|
913
|
+
marginTop: 3
|
|
1003
914
|
},
|
|
1004
915
|
itemExcluded: {
|
|
1005
|
-
color:
|
|
1006
|
-
fontSize:
|
|
1007
|
-
marginTop:
|
|
916
|
+
color: _tmTheme.tm.color.labelTertiary,
|
|
917
|
+
fontSize: _tmTheme.tm.font.mono,
|
|
918
|
+
marginTop: 3,
|
|
1008
919
|
fontStyle: "italic"
|
|
1009
920
|
},
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
fontSize: 16
|
|
921
|
+
buildingSpinner: {
|
|
922
|
+
marginTop: 28
|
|
1013
923
|
},
|
|
1014
924
|
emptyText: {
|
|
1015
|
-
color:
|
|
1016
|
-
fontSize:
|
|
925
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
926
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
1017
927
|
textAlign: "center",
|
|
1018
|
-
marginTop:
|
|
928
|
+
marginTop: 28
|
|
1019
929
|
},
|
|
1020
|
-
//
|
|
930
|
+
// ── Sticky restore CTA ──────────────────────────────────────────────────
|
|
1021
931
|
footer: {
|
|
1022
|
-
paddingHorizontal:
|
|
1023
|
-
paddingTop:
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
backgroundColor: _sharedUi.buoyColors.base
|
|
932
|
+
paddingHorizontal: _tmTheme.tm.gutter,
|
|
933
|
+
paddingTop: 10,
|
|
934
|
+
gap: 8,
|
|
935
|
+
borderTopColor: _tmTheme.tm.color.separator,
|
|
936
|
+
borderTopWidth: _reactNative.StyleSheet.hairlineWidth,
|
|
937
|
+
backgroundColor: _tmTheme.tm.color.sheet
|
|
1029
938
|
},
|
|
1030
939
|
cta: {
|
|
1031
940
|
flexDirection: "row",
|
|
1032
941
|
alignItems: "center",
|
|
1033
942
|
justifyContent: "center",
|
|
1034
943
|
gap: 8,
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
944
|
+
height: 50,
|
|
945
|
+
backgroundColor: _tmTheme.tm.color.accent,
|
|
946
|
+
borderRadius: _tmTheme.tm.radius.group
|
|
1038
947
|
},
|
|
1039
948
|
ctaDanger: {
|
|
1040
|
-
backgroundColor:
|
|
949
|
+
backgroundColor: _tmTheme.tm.color.danger
|
|
950
|
+
},
|
|
951
|
+
ctaTextDanger: {
|
|
952
|
+
color: _tmTheme.tm.color.onDanger
|
|
1041
953
|
},
|
|
1042
954
|
ctaDisabled: {
|
|
1043
955
|
opacity: 0.4
|
|
1044
956
|
},
|
|
1045
957
|
ctaText: {
|
|
1046
|
-
color:
|
|
1047
|
-
fontSize:
|
|
1048
|
-
fontWeight: "
|
|
958
|
+
color: _tmTheme.tm.color.onAccent,
|
|
959
|
+
fontSize: _tmTheme.tm.font.row,
|
|
960
|
+
fontWeight: "600",
|
|
961
|
+
letterSpacing: _tmTheme.tm.tracking.row
|
|
1049
962
|
},
|
|
1050
963
|
ctaCaption: {
|
|
1051
|
-
color:
|
|
1052
|
-
fontSize:
|
|
964
|
+
color: _tmTheme.tm.color.labelSecondary,
|
|
965
|
+
fontSize: _tmTheme.tm.font.footnote,
|
|
966
|
+
lineHeight: _tmTheme.tm.font.footnote * 1.35,
|
|
1053
967
|
textAlign: "center"
|
|
1054
968
|
}
|
|
1055
969
|
});
|