@buoy-gg/shared-ui 7.0.33 → 7.0.34

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 (189) hide show
  1. package/lib/commonjs/JsModal.js +57 -22
  2. package/lib/commonjs/hooks/index.js +26 -0
  3. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  4. package/lib/commonjs/hooks/useChangeLog.js +55 -0
  5. package/lib/commonjs/hooks/useEventStoreEvents.js +65 -0
  6. package/lib/commonjs/hooks/usePersistedState.js +45 -10
  7. package/lib/commonjs/index.js +143 -0
  8. package/lib/commonjs/storage/definePersistedSetting.js +67 -0
  9. package/lib/commonjs/storage/index.js +8 -1
  10. package/lib/commonjs/stores/ChangeLog.js +197 -0
  11. package/lib/commonjs/stores/createToolStore.js +175 -0
  12. package/lib/commonjs/stores/index.js +15 -1
  13. package/lib/commonjs/sync/toolSyncAdapter.js +63 -0
  14. package/lib/commonjs/sync/wireForm.js +172 -0
  15. package/lib/commonjs/tools/defineTool.js +79 -0
  16. package/lib/commonjs/ui/components/ChangeRow.js +110 -0
  17. package/lib/commonjs/ui/components/ChipStrip.js +94 -0
  18. package/lib/commonjs/ui/components/DetailViewToggle.js +130 -0
  19. package/lib/commonjs/ui/components/DevToolsCard.js +3 -1
  20. package/lib/commonjs/ui/components/EntityFilterView.js +354 -0
  21. package/lib/commonjs/ui/components/ExportPreview.js +174 -0
  22. package/lib/commonjs/ui/components/InfoRow.js +90 -0
  23. package/lib/commonjs/ui/components/ModalHeader.js +40 -7
  24. package/lib/commonjs/ui/components/Pill.js +114 -0
  25. package/lib/commonjs/ui/components/ToggleRow.js +116 -0
  26. package/lib/commonjs/ui/components/ToolFooter.js +204 -0
  27. package/lib/commonjs/ui/components/index.js +100 -1
  28. package/lib/commonjs/ui/index.js +24 -2
  29. package/lib/commonjs/ui/listPresets.js +43 -0
  30. package/lib/commonjs/ui/night/primitives.js +3 -1
  31. package/lib/commonjs/utils/snapshotProviderKit.js +167 -0
  32. package/lib/commonjs/utils/stateTools.js +160 -0
  33. package/lib/module/JsModal.js +57 -22
  34. package/lib/module/hooks/index.js +3 -1
  35. package/lib/module/hooks/safe-area-impl.js +1 -1
  36. package/lib/module/hooks/useChangeLog.js +50 -0
  37. package/lib/module/hooks/useEventStoreEvents.js +61 -0
  38. package/lib/module/hooks/usePersistedState.js +44 -10
  39. package/lib/module/index.js +11 -1
  40. package/lib/module/storage/definePersistedSetting.js +63 -0
  41. package/lib/module/storage/index.js +2 -1
  42. package/lib/module/stores/ChangeLog.js +192 -0
  43. package/lib/module/stores/createToolStore.js +171 -0
  44. package/lib/module/stores/index.js +3 -1
  45. package/lib/module/sync/toolSyncAdapter.js +58 -0
  46. package/lib/module/sync/wireForm.js +159 -0
  47. package/lib/module/tools/defineTool.js +74 -0
  48. package/lib/module/ui/components/ChangeRow.js +105 -0
  49. package/lib/module/ui/components/ChipStrip.js +91 -0
  50. package/lib/module/ui/components/DetailViewToggle.js +125 -0
  51. package/lib/module/ui/components/DevToolsCard.js +3 -1
  52. package/lib/module/ui/components/EntityFilterView.js +350 -0
  53. package/lib/module/ui/components/ExportPreview.js +169 -0
  54. package/lib/module/ui/components/InfoRow.js +86 -0
  55. package/lib/module/ui/components/ModalHeader.js +40 -7
  56. package/lib/module/ui/components/Pill.js +110 -0
  57. package/lib/module/ui/components/ToggleRow.js +112 -0
  58. package/lib/module/ui/components/ToolFooter.js +196 -0
  59. package/lib/module/ui/components/index.js +10 -1
  60. package/lib/module/ui/index.js +4 -1
  61. package/lib/module/ui/listPresets.js +39 -0
  62. package/lib/module/ui/night/primitives.js +3 -1
  63. package/lib/module/utils/snapshotProviderKit.js +156 -0
  64. package/lib/module/utils/stateTools.js +154 -0
  65. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/hooks/index.d.ts +3 -1
  67. package/lib/typescript/commonjs/hooks/index.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  69. package/lib/typescript/commonjs/hooks/useChangeLog.d.ts +38 -0
  70. package/lib/typescript/commonjs/hooks/useChangeLog.d.ts.map +1 -0
  71. package/lib/typescript/commonjs/hooks/useEventStoreEvents.d.ts +25 -0
  72. package/lib/typescript/commonjs/hooks/useEventStoreEvents.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/hooks/usePersistedState.d.ts +34 -5
  74. package/lib/typescript/commonjs/hooks/usePersistedState.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/index.d.ts +6 -1
  76. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/storage/definePersistedSetting.d.ts +39 -0
  78. package/lib/typescript/commonjs/storage/definePersistedSetting.d.ts.map +1 -0
  79. package/lib/typescript/commonjs/storage/index.d.ts +1 -0
  80. package/lib/typescript/commonjs/storage/index.d.ts.map +1 -1
  81. package/lib/typescript/commonjs/stores/ChangeLog.d.ts +100 -0
  82. package/lib/typescript/commonjs/stores/ChangeLog.d.ts.map +1 -0
  83. package/lib/typescript/commonjs/stores/createToolStore.d.ts +92 -0
  84. package/lib/typescript/commonjs/stores/createToolStore.d.ts.map +1 -0
  85. package/lib/typescript/commonjs/stores/index.d.ts +2 -0
  86. package/lib/typescript/commonjs/stores/index.d.ts.map +1 -1
  87. package/lib/typescript/commonjs/sync/toolSyncAdapter.d.ts +66 -0
  88. package/lib/typescript/commonjs/sync/toolSyncAdapter.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/sync/wireForm.d.ts +100 -0
  90. package/lib/typescript/commonjs/sync/wireForm.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/tools/defineTool.d.ts +100 -0
  92. package/lib/typescript/commonjs/tools/defineTool.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/ui/components/ChangeRow.d.ts +52 -0
  94. package/lib/typescript/commonjs/ui/components/ChangeRow.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/ui/components/ChipStrip.d.ts +41 -0
  96. package/lib/typescript/commonjs/ui/components/ChipStrip.d.ts.map +1 -0
  97. package/lib/typescript/commonjs/ui/components/DetailViewToggle.d.ts +36 -0
  98. package/lib/typescript/commonjs/ui/components/DetailViewToggle.d.ts.map +1 -0
  99. package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts +8 -1
  100. package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/ui/components/EntityFilterView.d.ts +51 -0
  102. package/lib/typescript/commonjs/ui/components/EntityFilterView.d.ts.map +1 -0
  103. package/lib/typescript/commonjs/ui/components/ExportPreview.d.ts +48 -0
  104. package/lib/typescript/commonjs/ui/components/ExportPreview.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/ui/components/InfoRow.d.ts +33 -0
  106. package/lib/typescript/commonjs/ui/components/InfoRow.d.ts.map +1 -0
  107. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts +31 -1
  108. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts.map +1 -1
  109. package/lib/typescript/commonjs/ui/components/Pill.d.ts +38 -0
  110. package/lib/typescript/commonjs/ui/components/Pill.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/ui/components/ToggleRow.d.ts +33 -0
  112. package/lib/typescript/commonjs/ui/components/ToggleRow.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/ui/components/ToolFooter.d.ts +69 -0
  114. package/lib/typescript/commonjs/ui/components/ToolFooter.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/ui/components/index.d.ts +9 -0
  116. package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  118. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/listPresets.d.ts +28 -0
  120. package/lib/typescript/commonjs/ui/listPresets.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/ui/night/primitives.d.ts +3 -1
  122. package/lib/typescript/commonjs/ui/night/primitives.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/utils/snapshotProviderKit.d.ts +81 -0
  124. package/lib/typescript/commonjs/utils/snapshotProviderKit.d.ts.map +1 -0
  125. package/lib/typescript/commonjs/utils/stateTools.d.ts +44 -0
  126. package/lib/typescript/commonjs/utils/stateTools.d.ts.map +1 -0
  127. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  128. package/lib/typescript/module/hooks/index.d.ts +3 -1
  129. package/lib/typescript/module/hooks/index.d.ts.map +1 -1
  130. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  131. package/lib/typescript/module/hooks/useChangeLog.d.ts +38 -0
  132. package/lib/typescript/module/hooks/useChangeLog.d.ts.map +1 -0
  133. package/lib/typescript/module/hooks/useEventStoreEvents.d.ts +25 -0
  134. package/lib/typescript/module/hooks/useEventStoreEvents.d.ts.map +1 -0
  135. package/lib/typescript/module/hooks/usePersistedState.d.ts +34 -5
  136. package/lib/typescript/module/hooks/usePersistedState.d.ts.map +1 -1
  137. package/lib/typescript/module/index.d.ts +6 -1
  138. package/lib/typescript/module/index.d.ts.map +1 -1
  139. package/lib/typescript/module/storage/definePersistedSetting.d.ts +39 -0
  140. package/lib/typescript/module/storage/definePersistedSetting.d.ts.map +1 -0
  141. package/lib/typescript/module/storage/index.d.ts +1 -0
  142. package/lib/typescript/module/storage/index.d.ts.map +1 -1
  143. package/lib/typescript/module/stores/ChangeLog.d.ts +100 -0
  144. package/lib/typescript/module/stores/ChangeLog.d.ts.map +1 -0
  145. package/lib/typescript/module/stores/createToolStore.d.ts +92 -0
  146. package/lib/typescript/module/stores/createToolStore.d.ts.map +1 -0
  147. package/lib/typescript/module/stores/index.d.ts +2 -0
  148. package/lib/typescript/module/stores/index.d.ts.map +1 -1
  149. package/lib/typescript/module/sync/toolSyncAdapter.d.ts +66 -0
  150. package/lib/typescript/module/sync/toolSyncAdapter.d.ts.map +1 -0
  151. package/lib/typescript/module/sync/wireForm.d.ts +100 -0
  152. package/lib/typescript/module/sync/wireForm.d.ts.map +1 -0
  153. package/lib/typescript/module/tools/defineTool.d.ts +100 -0
  154. package/lib/typescript/module/tools/defineTool.d.ts.map +1 -0
  155. package/lib/typescript/module/ui/components/ChangeRow.d.ts +52 -0
  156. package/lib/typescript/module/ui/components/ChangeRow.d.ts.map +1 -0
  157. package/lib/typescript/module/ui/components/ChipStrip.d.ts +41 -0
  158. package/lib/typescript/module/ui/components/ChipStrip.d.ts.map +1 -0
  159. package/lib/typescript/module/ui/components/DetailViewToggle.d.ts +36 -0
  160. package/lib/typescript/module/ui/components/DetailViewToggle.d.ts.map +1 -0
  161. package/lib/typescript/module/ui/components/DevToolsCard.d.ts +8 -1
  162. package/lib/typescript/module/ui/components/DevToolsCard.d.ts.map +1 -1
  163. package/lib/typescript/module/ui/components/EntityFilterView.d.ts +51 -0
  164. package/lib/typescript/module/ui/components/EntityFilterView.d.ts.map +1 -0
  165. package/lib/typescript/module/ui/components/ExportPreview.d.ts +48 -0
  166. package/lib/typescript/module/ui/components/ExportPreview.d.ts.map +1 -0
  167. package/lib/typescript/module/ui/components/InfoRow.d.ts +33 -0
  168. package/lib/typescript/module/ui/components/InfoRow.d.ts.map +1 -0
  169. package/lib/typescript/module/ui/components/ModalHeader.d.ts +31 -1
  170. package/lib/typescript/module/ui/components/ModalHeader.d.ts.map +1 -1
  171. package/lib/typescript/module/ui/components/Pill.d.ts +38 -0
  172. package/lib/typescript/module/ui/components/Pill.d.ts.map +1 -0
  173. package/lib/typescript/module/ui/components/ToggleRow.d.ts +33 -0
  174. package/lib/typescript/module/ui/components/ToggleRow.d.ts.map +1 -0
  175. package/lib/typescript/module/ui/components/ToolFooter.d.ts +69 -0
  176. package/lib/typescript/module/ui/components/ToolFooter.d.ts.map +1 -0
  177. package/lib/typescript/module/ui/components/index.d.ts +9 -0
  178. package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
  179. package/lib/typescript/module/ui/index.d.ts +1 -0
  180. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  181. package/lib/typescript/module/ui/listPresets.d.ts +28 -0
  182. package/lib/typescript/module/ui/listPresets.d.ts.map +1 -0
  183. package/lib/typescript/module/ui/night/primitives.d.ts +3 -1
  184. package/lib/typescript/module/ui/night/primitives.d.ts.map +1 -1
  185. package/lib/typescript/module/utils/snapshotProviderKit.d.ts +81 -0
  186. package/lib/typescript/module/utils/snapshotProviderKit.d.ts.map +1 -0
  187. package/lib/typescript/module/utils/stateTools.d.ts +44 -0
  188. package/lib/typescript/module/utils/stateTools.d.ts.map +1 -0
  189. package/package.json +4 -4
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Pill — the small caption chip every tool draws next to a row: a verdict
5
+ * ("UNUSED", "OVERSIZE"), a kind ("event", "transaction"), a link ("↔ 2"),
6
+ * a source ("MMKV"). Sixteen packages defined 150+ local pill styles that
7
+ * fall into five looks; those are the `variant`s here. Text is always in
8
+ * the pill's color (or the muted ink for `quiet`), never the series color
9
+ * of anything else.
10
+ *
11
+ * - `tinted` — color fill at 15% + border at 40% (scenarios, react-query chips)
12
+ * - `soft` — color fill at 20%, rounded, no border (events correlation badge)
13
+ * - `outline` — color border only (sentry envelope types)
14
+ * - `quiet` — neutral 6% white fill, muted text, optional color dot (assets)
15
+ * - `text` — bare colored caption, no chrome (images row badges)
16
+ */
17
+
18
+ import { StyleSheet, Text, View } from "react-native";
19
+ import { night } from "../night/nightTheme.js";
20
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
21
+ export function Pill({
22
+ label,
23
+ color = night.color.textSecondary,
24
+ variant = "tinted",
25
+ size = "xs",
26
+ mono = false,
27
+ uppercase,
28
+ dot = false,
29
+ icon,
30
+ testID,
31
+ style
32
+ }) {
33
+ const upper = uppercase ?? (variant === "tinted" || variant === "quiet" || variant === "text");
34
+ const textColor = variant === "quiet" ? night.color.textSecondary : color;
35
+ const chrome = variant === "tinted" ? {
36
+ backgroundColor: `${color}15`,
37
+ borderColor: `${color}40`,
38
+ borderWidth: 1
39
+ } : variant === "soft" ? {
40
+ backgroundColor: `${color}20`
41
+ } : variant === "outline" ? {
42
+ borderColor: color,
43
+ borderWidth: 1
44
+ } : variant === "quiet" ? {
45
+ backgroundColor: "rgba(255,255,255,0.06)"
46
+ } : {};
47
+ if (variant === "text") {
48
+ return /*#__PURE__*/_jsx(Text, {
49
+ style: [styles.text, size === "sm" && styles.textSm, mono && styles.mono, upper && styles.upper, {
50
+ color: textColor
51
+ }],
52
+ testID: testID,
53
+ children: label
54
+ });
55
+ }
56
+ return /*#__PURE__*/_jsxs(View, {
57
+ style: [styles.pill, variant === "soft" && styles.pillSoft, size === "sm" && styles.pillSm, chrome, style],
58
+ children: [icon, dot && variant === "quiet" ? /*#__PURE__*/_jsx(View, {
59
+ style: [styles.dot, {
60
+ backgroundColor: color
61
+ }]
62
+ }) : null, /*#__PURE__*/_jsx(Text, {
63
+ style: [styles.text, size === "sm" && styles.textSm, mono && styles.mono, upper && styles.upper, {
64
+ color: textColor
65
+ }],
66
+ testID: testID,
67
+ children: label
68
+ })]
69
+ });
70
+ }
71
+ const styles = StyleSheet.create({
72
+ pill: {
73
+ flexDirection: "row",
74
+ alignItems: "center",
75
+ alignSelf: "flex-start",
76
+ gap: 4,
77
+ paddingHorizontal: 6,
78
+ paddingVertical: 2,
79
+ borderRadius: 4
80
+ },
81
+ pillSoft: {
82
+ paddingHorizontal: 8,
83
+ borderRadius: 10
84
+ },
85
+ pillSm: {
86
+ paddingHorizontal: 8,
87
+ paddingVertical: 3
88
+ },
89
+ dot: {
90
+ width: 5,
91
+ height: 5,
92
+ borderRadius: 2.5
93
+ },
94
+ text: {
95
+ fontSize: 10,
96
+ fontWeight: "600",
97
+ letterSpacing: 0.3
98
+ },
99
+ textSm: {
100
+ fontSize: 11
101
+ },
102
+ mono: {
103
+ fontFamily: "monospace"
104
+ },
105
+ upper: {
106
+ textTransform: "uppercase",
107
+ letterSpacing: 0.5,
108
+ fontWeight: "700"
109
+ }
110
+ });
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * ToggleRow — a labeled switch row for a tool's settings surface.
5
+ *
6
+ * Every settings screen (impersonate, image-overlay, highlight-updates,
7
+ * perf-monitor, scenarios, storage, ask-buoy) drew its own `toggleRow` +
8
+ * `<Switch>` pair with the same night track colors. The native switch stays
9
+ * (a custom control would be a visible design change); the row chrome,
10
+ * the label/description stack and the accent/warning tone are shared.
11
+ *
12
+ * - `variant="card"` — an elevated bordered pill row (image-overlay)
13
+ * - `variant="plain"` — a bare list row for use inside a card (impersonate)
14
+ */
15
+
16
+ import { StyleSheet, Switch, Text, View } from "react-native";
17
+ import { night } from "../night/nightTheme.js";
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ export function ToggleRow({
20
+ label,
21
+ description,
22
+ value,
23
+ onValueChange,
24
+ disabled = false,
25
+ tone = "accent",
26
+ accessory,
27
+ variant = "card",
28
+ emphasizeLabel = false,
29
+ testID,
30
+ style
31
+ }) {
32
+ const onColor = tone === "warning" ? night.color.warning : night.color.accent;
33
+ const isCard = variant === "card";
34
+ return /*#__PURE__*/_jsxs(View, {
35
+ style: [styles.row, isCard ? styles.rowCard : styles.rowPlain, style],
36
+ children: [/*#__PURE__*/_jsxs(View, {
37
+ style: styles.info,
38
+ children: [/*#__PURE__*/_jsxs(View, {
39
+ style: styles.header,
40
+ children: [/*#__PURE__*/_jsx(Text, {
41
+ style: [isCard ? styles.labelCard : styles.labelPlain, emphasizeLabel && {
42
+ color: onColor
43
+ }],
44
+ numberOfLines: 2,
45
+ children: label
46
+ }), accessory]
47
+ }), description ? /*#__PURE__*/_jsx(Text, {
48
+ style: styles.description,
49
+ children: description
50
+ }) : null]
51
+ }), /*#__PURE__*/_jsx(Switch, {
52
+ value: value,
53
+ onValueChange: onValueChange,
54
+ disabled: disabled,
55
+ testID: testID,
56
+ accessibilityLabel: label,
57
+ trackColor: isCard ? {
58
+ false: night.color.surfaceElevated,
59
+ true: onColor
60
+ } : {
61
+ false: night.color.border,
62
+ true: `${onColor}50`
63
+ },
64
+ thumbColor: isCard ? undefined : value ? onColor : night.color.knob
65
+ })]
66
+ });
67
+ }
68
+ const styles = StyleSheet.create({
69
+ row: {
70
+ flexDirection: "row",
71
+ alignItems: "center",
72
+ justifyContent: "space-between"
73
+ },
74
+ rowCard: {
75
+ backgroundColor: night.color.surfaceElevated,
76
+ borderRadius: 8,
77
+ borderWidth: 1,
78
+ borderColor: night.color.border,
79
+ paddingHorizontal: 12,
80
+ paddingVertical: 8
81
+ },
82
+ rowPlain: {
83
+ paddingVertical: 12,
84
+ paddingHorizontal: 12
85
+ },
86
+ info: {
87
+ flex: 1,
88
+ marginRight: 12
89
+ },
90
+ header: {
91
+ flexDirection: "row",
92
+ alignItems: "center",
93
+ gap: 8,
94
+ flexWrap: "wrap"
95
+ },
96
+ labelCard: {
97
+ fontSize: 13,
98
+ fontWeight: "500",
99
+ color: night.color.textSecondary
100
+ },
101
+ labelPlain: {
102
+ fontSize: 14,
103
+ fontWeight: "500",
104
+ color: night.color.text
105
+ },
106
+ description: {
107
+ fontSize: 12,
108
+ color: night.color.textTertiary,
109
+ lineHeight: 16,
110
+ marginTop: 3
111
+ }
112
+ });
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * ToolFooter — the night glass bar pinned to the bottom of a tool: dark
5
+ * backing over the star field, a hairline on top, safe-area padding when
6
+ * docked as a sheet, rounded corners when floating.
7
+ *
8
+ * `EventStepperFooter` draws this bar for the Previous/Next case; the
9
+ * images and react-query tools each re-drew it for their action bars with
10
+ * a comment saying "matches EventStepperFooter". This is that bar as a
11
+ * container, plus `FooterButton` — the mono uppercase plate button those
12
+ * action bars are made of — and the caption/message lines above the row.
13
+ */
14
+
15
+ import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
16
+ import { night } from "../night/nightTheme.js";
17
+ import { useSafeAreaInsets } from "../../hooks/useSafeAreaInsets.js";
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ export function ToolFooter({
20
+ children,
21
+ safeArea = true,
22
+ paddingBottom = 12,
23
+ floating = false,
24
+ absolute = false,
25
+ gap = 8,
26
+ style,
27
+ testID
28
+ }) {
29
+ const insets = useSafeAreaInsets();
30
+ const bottom = typeof safeArea === "number" ? safeArea + insets.bottom : safeArea ? paddingBottom + insets.bottom : paddingBottom;
31
+ return /*#__PURE__*/_jsx(View, {
32
+ style: [styles.footer, floating && styles.footerFloating, absolute && styles.footerAbsolute, {
33
+ paddingBottom: bottom,
34
+ gap
35
+ }, style],
36
+ testID: testID,
37
+ children: children
38
+ });
39
+ }
40
+
41
+ /** A row of footer buttons. */
42
+ export function FooterRow({
43
+ children,
44
+ style
45
+ }) {
46
+ return /*#__PURE__*/_jsx(View, {
47
+ style: [styles.row, style],
48
+ children: children
49
+ });
50
+ }
51
+
52
+ /** Tracking caption above a row ("MASS ACTIONS — every image on screen"). */
53
+ export function FooterCaption({
54
+ children,
55
+ style
56
+ }) {
57
+ return /*#__PURE__*/_jsx(Text, {
58
+ style: [styles.caption, style],
59
+ numberOfLines: 1,
60
+ children: children
61
+ });
62
+ }
63
+
64
+ /** Mono feedback line ("Restored 3 images"). */
65
+ export function FooterMessage({
66
+ children,
67
+ tone = "info",
68
+ style
69
+ }) {
70
+ return /*#__PURE__*/_jsx(Text, {
71
+ style: [styles.message, tone === "muted" && styles.messageMuted, style],
72
+ numberOfLines: 1,
73
+ children: children
74
+ });
75
+ }
76
+ export function FooterButton({
77
+ label,
78
+ onPress,
79
+ accent = false,
80
+ active = false,
81
+ disabled = false,
82
+ icon,
83
+ flex = true,
84
+ size = "sm",
85
+ testID,
86
+ accessibilityLabel,
87
+ style
88
+ }) {
89
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
90
+ onPress: onPress,
91
+ disabled: disabled,
92
+ activeOpacity: 0.7,
93
+ accessibilityRole: "button",
94
+ accessibilityLabel: accessibilityLabel ?? label,
95
+ accessibilityState: {
96
+ disabled,
97
+ selected: active
98
+ },
99
+ testID: testID,
100
+ style: [styles.button, flex ? styles.buttonFlex : styles.buttonFixed, size === "md" && styles.buttonMd, active && styles.buttonActive, disabled && styles.disabled, style],
101
+ children: [icon, /*#__PURE__*/_jsx(Text, {
102
+ style: [styles.buttonText, size === "md" && styles.buttonTextMd, accent && !disabled && styles.buttonTextAccent, active && styles.buttonTextActive, disabled && styles.buttonTextDisabled],
103
+ children: label
104
+ })]
105
+ });
106
+ }
107
+ const styles = StyleSheet.create({
108
+ footer: {
109
+ paddingHorizontal: 12,
110
+ paddingTop: 10,
111
+ // Dark glass over the star field — the same bar EventStepperFooter draws.
112
+ backgroundColor: "rgba(5, 5, 5, 0.92)",
113
+ borderTopWidth: 1,
114
+ borderTopColor: night.color.border
115
+ },
116
+ footerFloating: {
117
+ borderBottomLeftRadius: 14,
118
+ borderBottomRightRadius: 14
119
+ },
120
+ footerAbsolute: {
121
+ position: "absolute",
122
+ left: 0,
123
+ right: 0,
124
+ bottom: 0
125
+ },
126
+ row: {
127
+ flexDirection: "row",
128
+ alignItems: "center",
129
+ gap: 6
130
+ },
131
+ caption: {
132
+ color: night.color.textTertiary,
133
+ fontSize: 9,
134
+ fontWeight: "700",
135
+ letterSpacing: 0.8
136
+ },
137
+ message: {
138
+ color: night.color.info,
139
+ fontSize: 10,
140
+ fontFamily: "monospace"
141
+ },
142
+ messageMuted: {
143
+ color: night.color.textTertiary,
144
+ fontFamily: undefined
145
+ },
146
+ button: {
147
+ flexDirection: "row",
148
+ alignItems: "center",
149
+ justifyContent: "center",
150
+ gap: 6,
151
+ paddingVertical: 8,
152
+ // No horizontal padding: six of these share one row on a phone, and the
153
+ // mono uppercase label needs every point it can get before it wraps.
154
+ paddingHorizontal: 0,
155
+ borderRadius: 6,
156
+ backgroundColor: night.color.button,
157
+ borderWidth: StyleSheet.hairlineWidth,
158
+ borderColor: night.color.border
159
+ },
160
+ buttonFlex: {
161
+ flex: 1
162
+ },
163
+ buttonFixed: {
164
+ paddingHorizontal: 10
165
+ },
166
+ buttonMd: {
167
+ paddingVertical: 8
168
+ },
169
+ buttonActive: {
170
+ backgroundColor: night.color.accentSoft,
171
+ borderColor: night.color.accentBorderStrong
172
+ },
173
+ buttonText: {
174
+ fontSize: 10,
175
+ fontWeight: "600",
176
+ color: night.color.textSecondary,
177
+ fontFamily: "monospace",
178
+ textTransform: "uppercase"
179
+ },
180
+ buttonTextMd: {
181
+ fontSize: 11,
182
+ color: night.color.text
183
+ },
184
+ buttonTextAccent: {
185
+ color: night.color.warning
186
+ },
187
+ buttonTextActive: {
188
+ color: night.color.accent
189
+ },
190
+ buttonTextDisabled: {
191
+ color: night.color.textTertiary
192
+ },
193
+ disabled: {
194
+ opacity: 0.4
195
+ }
196
+ });
@@ -40,4 +40,13 @@ export { PowerToggleButton } from "./PowerToggleButton.js";
40
40
  export { ExpandedInfoRow, PillBadge } from "./ExpandedInfoRow.js";
41
41
 
42
42
  // EventHistoryViewer components
43
- export { EventHistoryViewer, ViewToggleCards, DiffModeTabs, CompareBar, EventPickerModal } from "./EventHistoryViewer/index.js";
43
+ export { EventHistoryViewer, ViewToggleCards, DiffModeTabs, CompareBar, EventPickerModal } from "./EventHistoryViewer/index.js";
44
+ export { InfoRow } from "./InfoRow.js";
45
+ export { DetailViewToggle } from "./DetailViewToggle.js";
46
+ export { ChangeRow } from "./ChangeRow.js";
47
+ export { Pill } from "./Pill.js";
48
+ export { ToolFooter, FooterRow, FooterCaption, FooterMessage, FooterButton } from "./ToolFooter.js";
49
+ export { EntityFilterView } from "./EntityFilterView.js";
50
+ export { ToggleRow } from "./ToggleRow.js";
51
+ export { ChipStrip, useChipTap } from "./ChipStrip.js";
52
+ export { ExportPreview, sizeWarningLevel } from "./ExportPreview.js";
@@ -18,4 +18,7 @@ export { CyberpunkSectionButton } from "./console/CyberpunkSectionButton.js";
18
18
  export * from "./gameUI/index.js";
19
19
 
20
20
  // Otto — the Buoy mascot (see OTTO_PLACEMENT_PLAN.md for where he belongs)
21
- export * from "./otto/index.js";
21
+ export * from "./otto/index.js";
22
+
23
+ // FlatList presets (tuned window/batch values + the E2E clipping guard)
24
+ export { EVENT_LIST_PRESET, LOG_LIST_PRESET, CLIP_OFFSCREEN_CELLS } from "./listPresets.js";
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * FlatList presets for tool lists — the tuned window/batch values and the
5
+ * E2E clipping guard that eleven list sites carried as copy-pasted props.
6
+ *
7
+ * Spread them onto a FlatList: `<FlatList {...EVENT_LIST_PRESET} … />`.
8
+ * A tool that later moves to FlashList changes this file, not eleven.
9
+ */
10
+
11
+ /**
12
+ * `removeClippedSubviews` is off in E2E bundles: clipped rows leave the
13
+ * hierarchy entirely, so a row past the fold reads to the test as "the tool
14
+ * stopped capturing".
15
+ */
16
+ export const CLIP_OFFSCREEN_CELLS = !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E);
17
+ /**
18
+ * Event / change / request lists: rows are tall-ish and arrive in bursts.
19
+ * Window and batch values are the "tuned" winner of the buoy-optimize
20
+ * batch run on the network tool (2026-07-06, batch-1783396983529-6l7w).
21
+ */
22
+ export const EVENT_LIST_PRESET = {
23
+ initialNumToRender: 12,
24
+ maxToRenderPerBatch: 8,
25
+ windowSize: 5,
26
+ updateCellsBatchingPeriod: 50,
27
+ removeClippedSubviews: CLIP_OFFSCREEN_CELLS
28
+ };
29
+
30
+ /**
31
+ * Log tails (console, sentry): rows are short single lines, the list is
32
+ * read from the bottom, and a scroll-to-end must not land on blank cells.
33
+ */
34
+ export const LOG_LIST_PRESET = {
35
+ initialNumToRender: 30,
36
+ maxToRenderPerBatch: 30,
37
+ windowSize: 21,
38
+ removeClippedSubviews: CLIP_OFFSCREEN_CELLS
39
+ };
@@ -154,12 +154,14 @@ export function NightChip({
154
154
  selected,
155
155
  onPress,
156
156
  disabled,
157
- icon
157
+ icon,
158
+ testID
158
159
  }) {
159
160
  return /*#__PURE__*/_jsxs(TouchableOpacity, {
160
161
  activeOpacity: 0.7,
161
162
  disabled: disabled || !onPress,
162
163
  onPress: onPress,
164
+ testID: testID,
163
165
  style: [styles.chip, selected ? styles.chipSelected : null, disabled ? styles.chipDisabled : null],
164
166
  children: [icon, /*#__PURE__*/_jsx(Text, {
165
167
  style: [styles.chipText, selected ? styles.chipTextSelected : null],
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * snapshotProviderKit — the parts of a Time Machine `StateSnapshotProvider`
5
+ * that are the same for every source.
6
+ *
7
+ * storage, redux, zustand, jotai and react-query each register a provider
8
+ * (see stateSnapshotRegistry.ts). What differs is how they read and write
9
+ * their source. What was copied five times is:
10
+ *
11
+ * - the restore SCOPE gate: `excludeKeys` (touch all but these) and
12
+ * `includeKeys` (touch only these), the "N item(s) excluded by you"
13
+ * warning, and the empty `StateSnapshotRestoreResult`;
14
+ * - the preview VERDICT ladder: removed → added → unchanged → too-large →
15
+ * changed, with the 256 KB per-item render cap;
16
+ * - the "won't apply" override: a difference restore cannot apply must say
17
+ * so instead of rendering as a green change.
18
+ *
19
+ * The parts that stay per-tool are the ones that matter: redux verifies the
20
+ * jump by reference identity, zustand grafts action functions back, jotai
21
+ * leaves derived atoms to recompute, storage gates MMKV buffers and
22
+ * biometric keys, react-query diffs a comparable projection.
23
+ */
24
+
25
+ import { boundedDeepEqual, jsonLikelyLargerThan } from "../dataViewer/objectDiff.js";
26
+ /** Beyond this a preview item is "too-large": restore still applies it, the diff isn't drawn. */
27
+ export const PREVIEW_ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
28
+ /**
29
+ * Both option lists use preview item keys, and both mean "leave everything
30
+ * else untouched in BOTH directions". `includeKeys` wins when present;
31
+ * `excludeKeys` still applies on top.
32
+ */
33
+ export function createRestoreScope(options) {
34
+ const excludedSet = new Set(options?.excludeKeys ?? []);
35
+ const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
36
+ let excludedHits = 0;
37
+ const touch = key => !excludedSet.has(key) && (!includedSet || includedSet.has(key));
38
+ return {
39
+ touch,
40
+ allows(key) {
41
+ if (touch(key)) return true;
42
+ excludedHits += 1;
43
+ return false;
44
+ },
45
+ countExcluded(n) {
46
+ excludedHits += n;
47
+ },
48
+ get excludedHits() {
49
+ return excludedHits;
50
+ },
51
+ excludedWarning(noun) {
52
+ return excludedHits > 0 ? `${excludedHits} ${noun} excluded by you` : null;
53
+ }
54
+ };
55
+ }
56
+
57
+ /** A fresh, successful, empty result to accumulate into. */
58
+ export function emptyRestoreResult() {
59
+ return {
60
+ ok: true,
61
+ applied: 0,
62
+ skipped: [],
63
+ warnings: []
64
+ };
65
+ }
66
+
67
+ /** A failed result with one warning (an empty or unusable snapshot). */
68
+ export function failedRestore(warning) {
69
+ return {
70
+ ok: false,
71
+ applied: 0,
72
+ skipped: [],
73
+ warnings: [warning]
74
+ };
75
+ }
76
+
77
+ /** A failed result with one skipped item and its reason. */
78
+ export function skippedRestore(id, reason) {
79
+ return {
80
+ ok: false,
81
+ applied: 0,
82
+ skipped: [{
83
+ id,
84
+ reason
85
+ }],
86
+ warnings: []
87
+ };
88
+ }
89
+ /**
90
+ * The verdict ladder: removed → added → unchanged → too-large → changed.
91
+ * Callers layer source-specific verdicts (`wont-apply`, `recomputes`) on top
92
+ * with `wontApply()`.
93
+ */
94
+ export function classifyPreviewItem(input, options = {}) {
95
+ const {
96
+ key,
97
+ label,
98
+ oldValue,
99
+ newValue,
100
+ inOld,
101
+ inNew
102
+ } = input;
103
+ if (!inNew) return {
104
+ key,
105
+ label,
106
+ verdict: "removed",
107
+ oldValue
108
+ };
109
+ if (!inOld) return {
110
+ key,
111
+ label,
112
+ verdict: "added",
113
+ newValue
114
+ };
115
+ const equal = options.equal ?? boundedDeepEqual;
116
+ if (equal(oldValue, newValue)) return {
117
+ key,
118
+ label,
119
+ verdict: "unchanged"
120
+ };
121
+ const tooLarge = options.tooLarge ?? (value => jsonLikelyLargerThan(value, PREVIEW_ITEM_RENDER_BYTE_LIMIT));
122
+ if (tooLarge(oldValue) || tooLarge(newValue)) {
123
+ return {
124
+ key,
125
+ label,
126
+ verdict: "too-large",
127
+ reason: options.tooLargeReason ?? "value too large to render a diff — restore still applies it"
128
+ };
129
+ }
130
+ return {
131
+ key,
132
+ label,
133
+ verdict: "changed",
134
+ oldValue,
135
+ newValue
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Mark an item as something restore cannot apply. An unchanged item is left
141
+ * alone — there is nothing to apply, so nothing is being refused.
142
+ */
143
+ export function wontApply(item, reason) {
144
+ if (item.verdict === "unchanged") return item;
145
+ return {
146
+ ...item,
147
+ verdict: "wont-apply",
148
+ reason
149
+ };
150
+ }
151
+
152
+ /** Every key present in either record, once. */
153
+ export function unionKeys(a, b) {
154
+ const keysOf = r => r === undefined ? [] : r instanceof Map ? Array.from(r.keys()) : Object.keys(r);
155
+ return new Set([...keysOf(a), ...keysOf(b)]);
156
+ }