@buoy-gg/images 7.0.41 → 7.0.43

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 (194) hide show
  1. package/README.md +11 -70
  2. package/lib/commonjs/autoCapture.js +1 -4
  3. package/lib/commonjs/autoCapture.web.js +1 -6
  4. package/lib/commonjs/capture/actions.js +1 -243
  5. package/lib/commonjs/capture/install.js +1 -45
  6. package/lib/commonjs/capture/install.web.js +1 -250
  7. package/lib/commonjs/capture/installExpoImage.js +1 -99
  8. package/lib/commonjs/capture/installRnImage.js +1 -132
  9. package/lib/commonjs/capture/nativeImageModules.js +1 -30
  10. package/lib/commonjs/capture/nativeImageModules.web.js +1 -18
  11. package/lib/commonjs/capture/overrides.js +1 -346
  12. package/lib/commonjs/capture/rnDecoratorEarly.js +1 -55
  13. package/lib/commonjs/capture/savings.js +1 -209
  14. package/lib/commonjs/capture/savings.web.js +1 -71
  15. package/lib/commonjs/capture/shared.js +1 -378
  16. package/lib/commonjs/components/ImageDetail.js +1 -455
  17. package/lib/commonjs/components/ImageDetailFooter.js +1 -158
  18. package/lib/commonjs/components/ImageRow.js +1 -156
  19. package/lib/commonjs/components/ImagesHeader.js +1 -63
  20. package/lib/commonjs/components/ImagesIcon.js +1 -19
  21. package/lib/commonjs/components/ImagesListFooter.js +1 -126
  22. package/lib/commonjs/components/ImagesModal.js +1 -240
  23. package/lib/commonjs/components/ImagesRoot.js +1 -24
  24. package/lib/commonjs/components/ImagesRoot.web.js +1 -13
  25. package/lib/commonjs/components/InsightsBar.js +1 -59
  26. package/lib/commonjs/export.js +1 -81
  27. package/lib/commonjs/format.js +1 -117
  28. package/lib/commonjs/hooks/useImageRecords.js +1 -20
  29. package/lib/commonjs/index.js +1 -261
  30. package/lib/commonjs/preset.js +1 -39
  31. package/lib/commonjs/register.js +1 -19
  32. package/lib/commonjs/registerEarly.js +1 -14
  33. package/lib/commonjs/remote.js +1 -42
  34. package/lib/commonjs/state.js +1 -58
  35. package/lib/commonjs/store/imageEventStore.js +1 -238
  36. package/lib/commonjs/store/insights.js +1 -76
  37. package/lib/commonjs/sync/imagesSyncAdapter.js +1 -361
  38. package/lib/commonjs/types.js +0 -1
  39. package/lib/module/autoCapture.js +1 -4
  40. package/lib/module/autoCapture.web.js +1 -5
  41. package/lib/module/capture/actions.js +1 -230
  42. package/lib/module/capture/install.js +1 -40
  43. package/lib/module/capture/install.web.js +1 -243
  44. package/lib/module/capture/installExpoImage.js +1 -94
  45. package/lib/module/capture/installRnImage.js +1 -125
  46. package/lib/module/capture/nativeImageModules.js +1 -24
  47. package/lib/module/capture/nativeImageModules.web.js +1 -12
  48. package/lib/module/capture/overrides.js +1 -329
  49. package/lib/module/capture/rnDecoratorEarly.js +1 -50
  50. package/lib/module/capture/savings.js +1 -205
  51. package/lib/module/capture/savings.web.js +1 -67
  52. package/lib/module/capture/shared.js +1 -369
  53. package/lib/module/components/ImageDetail.js +1 -451
  54. package/lib/module/components/ImageDetailFooter.js +1 -154
  55. package/lib/module/components/ImageRow.js +1 -152
  56. package/lib/module/components/ImagesHeader.js +1 -59
  57. package/lib/module/components/ImagesIcon.js +1 -12
  58. package/lib/module/components/ImagesListFooter.js +1 -122
  59. package/lib/module/components/ImagesModal.js +1 -235
  60. package/lib/module/components/ImagesRoot.js +1 -20
  61. package/lib/module/components/ImagesRoot.web.js +1 -9
  62. package/lib/module/components/InsightsBar.js +1 -55
  63. package/lib/module/export.js +1 -76
  64. package/lib/module/format.js +1 -108
  65. package/lib/module/hooks/useImageRecords.js +1 -16
  66. package/lib/module/index.js +1 -79
  67. package/lib/module/preset.js +1 -35
  68. package/lib/module/register.js +1 -19
  69. package/lib/module/registerEarly.js +1 -14
  70. package/lib/module/remote.js +1 -36
  71. package/lib/module/state.js +1 -54
  72. package/lib/module/store/imageEventStore.js +1 -221
  73. package/lib/module/store/insights.js +1 -71
  74. package/lib/module/sync/imagesSyncAdapter.js +1 -356
  75. package/lib/module/types.js +0 -1
  76. package/lib/web/chunks/chunk-TTS5EH4R.mjs +1 -2
  77. package/lib/web/index.mjs +3 -4
  78. package/lib/web/register.mjs +1 -2
  79. package/package.json +3 -7
  80. package/register.js +1 -15
  81. package/lib/commonjs/autoCapture.js.map +0 -1
  82. package/lib/commonjs/autoCapture.web.js.map +0 -1
  83. package/lib/commonjs/capture/actions.js.map +0 -1
  84. package/lib/commonjs/capture/install.js.map +0 -1
  85. package/lib/commonjs/capture/install.web.js.map +0 -1
  86. package/lib/commonjs/capture/installExpoImage.js.map +0 -1
  87. package/lib/commonjs/capture/installRnImage.js.map +0 -1
  88. package/lib/commonjs/capture/nativeImageModules.js.map +0 -1
  89. package/lib/commonjs/capture/nativeImageModules.web.js.map +0 -1
  90. package/lib/commonjs/capture/overrides.js.map +0 -1
  91. package/lib/commonjs/capture/rnDecoratorEarly.js.map +0 -1
  92. package/lib/commonjs/capture/savings.js.map +0 -1
  93. package/lib/commonjs/capture/savings.web.js.map +0 -1
  94. package/lib/commonjs/capture/shared.js.map +0 -1
  95. package/lib/commonjs/components/ImageDetail.js.map +0 -1
  96. package/lib/commonjs/components/ImageDetailFooter.js.map +0 -1
  97. package/lib/commonjs/components/ImageRow.js.map +0 -1
  98. package/lib/commonjs/components/ImagesHeader.js.map +0 -1
  99. package/lib/commonjs/components/ImagesIcon.js.map +0 -1
  100. package/lib/commonjs/components/ImagesListFooter.js.map +0 -1
  101. package/lib/commonjs/components/ImagesModal.js.map +0 -1
  102. package/lib/commonjs/components/ImagesRoot.js.map +0 -1
  103. package/lib/commonjs/components/ImagesRoot.web.js.map +0 -1
  104. package/lib/commonjs/components/InsightsBar.js.map +0 -1
  105. package/lib/commonjs/export.js.map +0 -1
  106. package/lib/commonjs/format.js.map +0 -1
  107. package/lib/commonjs/hooks/useImageRecords.js.map +0 -1
  108. package/lib/commonjs/index.js.map +0 -1
  109. package/lib/commonjs/preset.js.map +0 -1
  110. package/lib/commonjs/register.js.map +0 -1
  111. package/lib/commonjs/registerEarly.js.map +0 -1
  112. package/lib/commonjs/remote.js.map +0 -1
  113. package/lib/commonjs/state.js.map +0 -1
  114. package/lib/commonjs/store/imageEventStore.js.map +0 -1
  115. package/lib/commonjs/store/insights.js.map +0 -1
  116. package/lib/commonjs/sync/imagesSyncAdapter.js.map +0 -1
  117. package/lib/commonjs/types.js.map +0 -1
  118. package/lib/module/autoCapture.js.map +0 -1
  119. package/lib/module/autoCapture.web.js.map +0 -1
  120. package/lib/module/capture/actions.js.map +0 -1
  121. package/lib/module/capture/install.js.map +0 -1
  122. package/lib/module/capture/install.web.js.map +0 -1
  123. package/lib/module/capture/installExpoImage.js.map +0 -1
  124. package/lib/module/capture/installRnImage.js.map +0 -1
  125. package/lib/module/capture/nativeImageModules.js.map +0 -1
  126. package/lib/module/capture/nativeImageModules.web.js.map +0 -1
  127. package/lib/module/capture/overrides.js.map +0 -1
  128. package/lib/module/capture/rnDecoratorEarly.js.map +0 -1
  129. package/lib/module/capture/savings.js.map +0 -1
  130. package/lib/module/capture/savings.web.js.map +0 -1
  131. package/lib/module/capture/shared.js.map +0 -1
  132. package/lib/module/components/ImageDetail.js.map +0 -1
  133. package/lib/module/components/ImageDetailFooter.js.map +0 -1
  134. package/lib/module/components/ImageRow.js.map +0 -1
  135. package/lib/module/components/ImagesHeader.js.map +0 -1
  136. package/lib/module/components/ImagesIcon.js.map +0 -1
  137. package/lib/module/components/ImagesListFooter.js.map +0 -1
  138. package/lib/module/components/ImagesModal.js.map +0 -1
  139. package/lib/module/components/ImagesRoot.js.map +0 -1
  140. package/lib/module/components/ImagesRoot.web.js.map +0 -1
  141. package/lib/module/components/InsightsBar.js.map +0 -1
  142. package/lib/module/export.js.map +0 -1
  143. package/lib/module/format.js.map +0 -1
  144. package/lib/module/hooks/useImageRecords.js.map +0 -1
  145. package/lib/module/index.js.map +0 -1
  146. package/lib/module/preset.js.map +0 -1
  147. package/lib/module/register.js.map +0 -1
  148. package/lib/module/registerEarly.js.map +0 -1
  149. package/lib/module/remote.js.map +0 -1
  150. package/lib/module/state.js.map +0 -1
  151. package/lib/module/store/imageEventStore.js.map +0 -1
  152. package/lib/module/store/insights.js.map +0 -1
  153. package/lib/module/sync/imagesSyncAdapter.js.map +0 -1
  154. package/lib/module/types.js.map +0 -1
  155. package/lib/typescript/autoCapture.d.ts.map +0 -1
  156. package/lib/typescript/autoCapture.web.d.ts.map +0 -1
  157. package/lib/typescript/capture/actions.d.ts.map +0 -1
  158. package/lib/typescript/capture/install.d.ts.map +0 -1
  159. package/lib/typescript/capture/install.web.d.ts.map +0 -1
  160. package/lib/typescript/capture/installExpoImage.d.ts.map +0 -1
  161. package/lib/typescript/capture/installRnImage.d.ts.map +0 -1
  162. package/lib/typescript/capture/nativeImageModules.d.ts.map +0 -1
  163. package/lib/typescript/capture/nativeImageModules.web.d.ts.map +0 -1
  164. package/lib/typescript/capture/overrides.d.ts.map +0 -1
  165. package/lib/typescript/capture/rnDecoratorEarly.d.ts.map +0 -1
  166. package/lib/typescript/capture/savings.d.ts.map +0 -1
  167. package/lib/typescript/capture/savings.web.d.ts.map +0 -1
  168. package/lib/typescript/capture/shared.d.ts.map +0 -1
  169. package/lib/typescript/components/ImageDetail.d.ts.map +0 -1
  170. package/lib/typescript/components/ImageDetailFooter.d.ts.map +0 -1
  171. package/lib/typescript/components/ImageRow.d.ts.map +0 -1
  172. package/lib/typescript/components/ImagesHeader.d.ts.map +0 -1
  173. package/lib/typescript/components/ImagesIcon.d.ts.map +0 -1
  174. package/lib/typescript/components/ImagesListFooter.d.ts.map +0 -1
  175. package/lib/typescript/components/ImagesModal.d.ts.map +0 -1
  176. package/lib/typescript/components/ImagesRoot.d.ts.map +0 -1
  177. package/lib/typescript/components/ImagesRoot.web.d.ts.map +0 -1
  178. package/lib/typescript/components/InsightsBar.d.ts.map +0 -1
  179. package/lib/typescript/export.d.ts.map +0 -1
  180. package/lib/typescript/format.d.ts.map +0 -1
  181. package/lib/typescript/hooks/useImageRecords.d.ts.map +0 -1
  182. package/lib/typescript/index.d.ts.map +0 -1
  183. package/lib/typescript/preset.d.ts.map +0 -1
  184. package/lib/typescript/register.d.ts.map +0 -1
  185. package/lib/typescript/registerEarly.d.ts.map +0 -1
  186. package/lib/typescript/remote.d.ts.map +0 -1
  187. package/lib/typescript/state.d.ts.map +0 -1
  188. package/lib/typescript/store/imageEventStore.d.ts.map +0 -1
  189. package/lib/typescript/store/insights.d.ts.map +0 -1
  190. package/lib/typescript/sync/imagesSyncAdapter.d.ts.map +0 -1
  191. package/lib/typescript/types.d.ts.map +0 -1
  192. package/lib/web/chunks/chunk-7CWLRQ2L.mjs +0 -2
  193. package/lib/web/chunks/chunk-B5A6CYSS.mjs +0 -2
  194. package/lib/web/chunks/chunk-LKTR6X2V.mjs +0 -2
@@ -1,152 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ImageRow — one captured image in the list: thumbnail, filename, library +
5
- * cache badges, load time, and the size verdict.
6
- *
7
- * Thumbnails carry the buoy-internal testID so the capture layer skips them —
8
- * the tool must never appear in its own registry.
9
- */
10
-
11
- import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
12
- import { macOSColors, night, Pill } from "@buoy-gg/shared-ui";
13
- import { cacheBadge, formatMs, sizeVerdict, statusColor, uriTail } from "../format";
14
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
- export function ImageRow({
16
- record,
17
- onPress
18
- }) {
19
- const verdict = sizeVerdict(record);
20
- const cache = cacheBadge(record);
21
- const showThumb = record.sourceKind === "network" || record.sourceKind === "asset" || record.sourceKind === "file";
22
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
23
- style: styles.row,
24
- testID: `buoy-image-row-${record.id}`,
25
- onPress: () => onPress(record.id),
26
- children: [/*#__PURE__*/_jsxs(View, {
27
- style: styles.thumbBox,
28
- children: [showThumb && record.uri ? /*#__PURE__*/_jsx(Image, {
29
- testID: "buoy-internal-images-thumb",
30
- source: {
31
- uri: record.uri
32
- },
33
- style: styles.thumb,
34
- resizeMode: "cover"
35
- }) : /*#__PURE__*/_jsx(Text, {
36
- style: styles.thumbFallback,
37
- children: "?"
38
- }), /*#__PURE__*/_jsx(View, {
39
- style: [styles.statusDot, {
40
- backgroundColor: statusColor(record)
41
- }]
42
- })]
43
- }), /*#__PURE__*/_jsxs(View, {
44
- style: styles.main,
45
- children: [/*#__PURE__*/_jsx(Text, {
46
- style: styles.name,
47
- numberOfLines: 1,
48
- children: uriTail(record.uri)
49
- }), /*#__PURE__*/_jsxs(View, {
50
- style: styles.metaRow,
51
- children: [/*#__PURE__*/_jsx(Pill, {
52
- variant: "text",
53
- label: record.lib === "web" ? "WEB" : record.lib === "expo" ? "EXPO" : "RN",
54
- color: night.color.textTertiary
55
- }), /*#__PURE__*/_jsx(Pill, {
56
- variant: "text",
57
- label: cache.label,
58
- color: cache.color
59
- }), record.overrideLabel ? /*#__PURE__*/_jsx(Pill, {
60
- variant: "text",
61
- label: "SIM",
62
- color: night.color.warning
63
- }) : null, /*#__PURE__*/_jsx(Text, {
64
- style: styles.meta,
65
- children: formatMs(record.durationMs)
66
- }), record.intrinsic ? /*#__PURE__*/_jsxs(Text, {
67
- style: styles.meta,
68
- children: [record.intrinsic.width, "\xD7", record.intrinsic.height]
69
- }) : null]
70
- })]
71
- }), /*#__PURE__*/_jsx(View, {
72
- style: styles.right,
73
- children: record.status === "error" ? /*#__PURE__*/_jsx(Text, {
74
- style: [styles.verdict, {
75
- color: macOSColors.semantic.error
76
- }],
77
- children: "FAILED"
78
- }) : verdict.label ? /*#__PURE__*/_jsx(Text, {
79
- style: [styles.verdict, {
80
- color: verdict.color
81
- }],
82
- children: verdict.label
83
- }) : null
84
- })]
85
- });
86
- }
87
- const styles = StyleSheet.create({
88
- row: {
89
- flexDirection: "row",
90
- alignItems: "center",
91
- paddingHorizontal: 12,
92
- paddingVertical: 8,
93
- borderBottomWidth: StyleSheet.hairlineWidth,
94
- borderBottomColor: night.color.border,
95
- gap: 10
96
- },
97
- thumbBox: {
98
- width: 40,
99
- height: 40,
100
- borderRadius: 6,
101
- backgroundColor: night.color.bg,
102
- alignItems: "center",
103
- justifyContent: "center",
104
- overflow: "hidden"
105
- },
106
- thumb: {
107
- width: 40,
108
- height: 40
109
- },
110
- thumbFallback: {
111
- color: night.color.textTertiary,
112
- fontSize: 16,
113
- fontWeight: "700"
114
- },
115
- statusDot: {
116
- position: "absolute",
117
- right: 2,
118
- bottom: 2,
119
- width: 8,
120
- height: 8,
121
- borderRadius: 4,
122
- borderWidth: 1,
123
- borderColor: night.color.bg
124
- },
125
- main: {
126
- flex: 1,
127
- gap: 2
128
- },
129
- name: {
130
- color: night.color.text,
131
- fontSize: 12,
132
- fontWeight: "600"
133
- },
134
- metaRow: {
135
- flexDirection: "row",
136
- alignItems: "center",
137
- gap: 8
138
- },
139
- meta: {
140
- color: night.color.textSecondary,
141
- fontSize: 10,
142
- fontVariant: ["tabular-nums"]
143
- },
144
- right: {
145
- alignItems: "flex-end"
146
- },
147
- verdict: {
148
- fontSize: 10,
149
- fontWeight: "700"
150
- }
151
- });
152
- //# sourceMappingURL=ImageRow.js.map
1
+ "use strict";import{Image as b,StyleSheet as h,Text as l,TouchableOpacity as d,View as r}from"react-native";import{macOSColors as g,night as o,Pill as s}from"@buoy-gg/shared-ui";import{cacheBadge as f,formatMs as y,sizeVerdict as x,statusColor as w,uriTail as p}from"../format";import{jsx as i,jsxs as n}from"react/jsx-runtime";export function ImageRow({record:t,onPress:m}){const a=x(t);const c=f(t);const u=t.sourceKind==="network"||t.sourceKind==="asset"||t.sourceKind==="file";return n(d,{style:e.row,testID:`buoy-image-row-${t.id}`,onPress:()=>m(t.id),children:[n(r,{style:e.thumbBox,children:[u&&t.uri?i(b,{testID:"buoy-internal-images-thumb",source:{uri:t.uri},style:e.thumb,resizeMode:"cover"}):i(l,{style:e.thumbFallback,children:"?"}),i(r,{style:[e.statusDot,{backgroundColor:w(t)}]})]}),n(r,{style:e.main,children:[i(l,{style:e.name,numberOfLines:1,children:p(t.uri)}),n(r,{style:e.metaRow,children:[i(s,{variant:"text",label:t.lib==="web"?"WEB":t.lib==="expo"?"EXPO":"RN",color:o.color.textTertiary}),i(s,{variant:"text",label:c.label,color:c.color}),t.overrideLabel?i(s,{variant:"text",label:"SIM",color:o.color.warning}):null,i(l,{style:e.meta,children:y(t.durationMs)}),t.intrinsic?n(l,{style:e.meta,children:[t.intrinsic.width,"\xD7",t.intrinsic.height]}):null]})]}),i(r,{style:e.right,children:t.status==="error"?i(l,{style:[e.verdict,{color:g.semantic.error}],children:"FAILED"}):a.label?i(l,{style:[e.verdict,{color:a.color}],children:a.label}):null})]})}const e=h.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:h.hairlineWidth,borderBottomColor:o.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:o.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:o.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:o.color.bg},main:{flex:1,gap:2},name:{color:o.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:o.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});
@@ -1,59 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ImagesHeader — shared ModalHeader wiring for the Images tool, matching the
5
- * Console/Network header pattern. List mode shows aggregate stats, the shared
6
- * ToolbarCopyButton (full registry report) and the shared ToolbarClearButton;
7
- * detail mode shows back navigation plus the copy button for that record's
8
- * report. Copy behavior (Pro gating, hint banner, success/error feedback)
9
- * comes from shared-ui — identical to every other tool.
10
- */
11
-
12
- import { ModalHeader, ToolbarClearButton, ToolbarCopyButton } from "@buoy-gg/shared-ui";
13
- import { formatBytes } from "../format";
14
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
- export function ImagesHeader({
16
- stats,
17
- detailOpen,
18
- detailIndex = -1,
19
- detailTotal = 0,
20
- onCloseDetail,
21
- onClear,
22
- getReport,
23
- onBack
24
- }) {
25
- if (detailOpen) {
26
- const counter = detailIndex >= 0 && detailTotal > 0 ? `${detailIndex + 1} of ${detailTotal}` : undefined;
27
- return /*#__PURE__*/_jsxs(ModalHeader, {
28
- children: [/*#__PURE__*/_jsx(ModalHeader.Navigation, {
29
- onBack: onCloseDetail
30
- }), /*#__PURE__*/_jsx(ModalHeader.Content, {
31
- title: "Image detail",
32
- subtitle: counter
33
- }), /*#__PURE__*/_jsx(ModalHeader.Actions, {
34
- children: /*#__PURE__*/_jsx(ToolbarCopyButton, {
35
- value: getReport
36
- })
37
- })]
38
- });
39
- }
40
- const subtitleParts = [`${stats.total} images`, `${stats.errors} failed`, `≈${formatBytes(stats.estDecodedBytes)} decoded`];
41
- if (stats.estWastedBytes > 0) {
42
- subtitleParts.push(`${formatBytes(stats.estWastedBytes)} wasted`);
43
- }
44
- return /*#__PURE__*/_jsxs(ModalHeader, {
45
- children: [onBack ? /*#__PURE__*/_jsx(ModalHeader.Navigation, {
46
- onBack: onBack
47
- }) : null, /*#__PURE__*/_jsx(ModalHeader.Content, {
48
- title: "Images",
49
- subtitle: subtitleParts.join(" · ")
50
- }), /*#__PURE__*/_jsxs(ModalHeader.Actions, {
51
- children: [/*#__PURE__*/_jsx(ToolbarCopyButton, {
52
- value: getReport
53
- }), /*#__PURE__*/_jsx(ToolbarClearButton, {
54
- onPress: onClear
55
- })]
56
- })]
57
- });
58
- }
59
- //# sourceMappingURL=ImagesHeader.js.map
1
+ "use strict";import{ModalHeader as e,ToolbarClearButton as $,ToolbarCopyButton as d}from"@buoy-gg/shared-ui";import{formatBytes as u}from"../format";import{jsx as t,jsxs as r}from"react/jsx-runtime";export function ImagesHeader({stats:o,detailOpen:c,detailIndex:s=-1,detailTotal:n=0,onCloseDetail:m,onClear:f,getReport:i,onBack:a}){if(c){const B=s>=0&&n>0?`${s+1} of ${n}`:void 0;return r(e,{children:[t(e.Navigation,{onBack:m}),t(e.Content,{title:"Image detail",subtitle:B}),t(e.Actions,{children:t(d,{value:i})})]})}const l=[`${o.total} images`,`${o.errors} failed`,`\u2248${u(o.estDecodedBytes)} decoded`];if(o.estWastedBytes>0){l.push(`${u(o.estWastedBytes)} wasted`)}return r(e,{children:[a?t(e.Navigation,{onBack:a}):null,t(e.Content,{title:"Images",subtitle:l.join(" \xB7 ")}),r(e.Actions,{children:[t(d,{value:i}),t($,{onPress:f})]})]})}
@@ -1,12 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ImagesIcon — re-exported from the Buoy Icon Format.
5
- *
6
- * The artwork lives in shared/icons/images.json and is generated into
7
- * @buoy-gg/floating-tools-core, so React Native, the desktop dashboard and
8
- * Flutter all render the same drawing. Edit the JSON, then `pnpm icons`.
9
- */
10
-
11
- export { ImagesIcon, IMAGES_ICON_COLOR } from "@buoy-gg/shared-ui";
12
- //# sourceMappingURL=ImagesIcon.js.map
1
+ "use strict";export{ImagesIcon,IMAGES_ICON_COLOR}from"@buoy-gg/shared-ui";
@@ -1,122 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ImagesListFooter — the list screen's action bar: mass simulations applied
5
- * to EVERY mounted image at once (error / loading / blank), mass hard-reload,
6
- * flash everything, restore all — plus the global network simulation modes
7
- * (Normal / Offline / Cold). Styled to match the detail footer.
8
- */
9
-
10
- import { useState, useSyncExternalStore } from "react";
11
- import { StyleSheet, Text } from "react-native";
12
- import { FooterButton, FooterCaption, FooterMessage, FooterRow, ToolFooter, night } from "@buoy-gg/shared-ui";
13
- import { hardReloadAllMounted, subscribeActions } from "../capture/actions";
14
- import { clearAllOverrides, flashAllMounted, getGlobalModes, setNetworkMode, setOverrideForAllMounted } from "../capture/overrides";
15
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
- const NETWORK_MODES = [{
17
- key: "normal",
18
- label: "Normal"
19
- }, {
20
- key: "offline",
21
- label: "Offline"
22
- }, {
23
- key: "cold",
24
- label: "Cold"
25
- }];
26
- export function ImagesListFooter() {
27
- const [message, setMessage] = useState(null);
28
- const network = useSyncExternalStore(subscribeActions, () => getGlobalModes().network);
29
- const massOverride = (source, label) => {
30
- const count = setOverrideForAllMounted(source, label);
31
- setMessage(count > 0 ? `${label} on ${count} image${count === 1 ? "" : "s"} — Restore all to undo` : "No mounted images");
32
- };
33
- return /*#__PURE__*/_jsxs(ToolFooter, {
34
- paddingBottom: 10,
35
- style: {
36
- paddingTop: 8
37
- },
38
- children: [message ? /*#__PURE__*/_jsx(FooterMessage, {
39
- children: message
40
- }) : /*#__PURE__*/_jsx(FooterCaption, {
41
- children: "MASS ACTIONS \u2014 every image on screen"
42
- }), /*#__PURE__*/_jsxs(FooterRow, {
43
- children: [/*#__PURE__*/_jsx(MassButton, {
44
- label: "Error",
45
- onPress: () => massOverride({
46
- type: "error"
47
- }, "Forced error")
48
- }), /*#__PURE__*/_jsx(MassButton, {
49
- label: "Loading",
50
- onPress: () => massOverride({
51
- type: "hang"
52
- }, "Forced loading")
53
- }), /*#__PURE__*/_jsx(MassButton, {
54
- label: "Blank",
55
- onPress: () => massOverride({
56
- type: "blank"
57
- }, "Blanked")
58
- }), /*#__PURE__*/_jsx(MassButton, {
59
- label: "Reload",
60
- onPress: () => {
61
- setMessage("…");
62
- hardReloadAllMounted().then(r => setMessage(r.message));
63
- }
64
- }), /*#__PURE__*/_jsx(MassButton, {
65
- label: "Find",
66
- onPress: () => {
67
- const count = flashAllMounted();
68
- setMessage(`Flashing ${count} image${count === 1 ? "" : "s"} (2.5s)`);
69
- }
70
- }), /*#__PURE__*/_jsx(MassButton, {
71
- label: "Restore",
72
- accent: true,
73
- onPress: () => {
74
- const count = clearAllOverrides();
75
- setMessage(count > 0 ? `Restored ${count} image${count === 1 ? "" : "s"}` : "No overrides active");
76
- }
77
- })]
78
- }), /*#__PURE__*/_jsxs(FooterRow, {
79
- children: [/*#__PURE__*/_jsx(Text, {
80
- style: styles.netLabel,
81
- children: "NET"
82
- }), NETWORK_MODES.map(mode => {
83
- const active = network === mode.key;
84
- return /*#__PURE__*/_jsx(FooterButton, {
85
- label: mode.label,
86
- active: active,
87
- style: {
88
- paddingVertical: 6
89
- },
90
- onPress: () => {
91
- setNetworkMode(mode.key);
92
- // Modes only affect loads that happen AFTER they're set — an
93
- // on-screen image keeps its bitmap until something reloads it.
94
- setMessage(mode.key === "normal" ? "Network simulation off — tap RELOAD to load normally again" : mode.key === "offline" ? "Offline: network images FAIL (bundled assets still load) — tap RELOAD to apply to on-screen images" : "Cold (bypass caches) — tap RELOAD: everything refetches like first launch");
95
- }
96
- }, mode.key);
97
- })]
98
- })]
99
- });
100
- }
101
- function MassButton({
102
- label,
103
- onPress,
104
- accent
105
- }) {
106
- return /*#__PURE__*/_jsx(FooterButton, {
107
- label: label,
108
- onPress: onPress,
109
- accent: accent
110
- });
111
- }
112
- const styles = StyleSheet.create({
113
- netLabel: {
114
- color: night.color.textTertiary,
115
- fontSize: 9,
116
- fontWeight: "700",
117
- letterSpacing: 0.8,
118
- alignSelf: "center",
119
- marginRight: 2
120
- }
121
- });
122
- //# sourceMappingURL=ImagesListFooter.js.map
1
+ "use strict";import{useState as m,useSyncExternalStore as u}from"react";import{StyleSheet as f,Text as p}from"react-native";import{FooterButton as d,FooterCaption as y,FooterMessage as b,FooterRow as g,ToolFooter as h,night as k}from"@buoy-gg/shared-ui";import{hardReloadAllMounted as F,subscribeActions as S}from"../capture/actions";import{clearAllOverrides as A,flashAllMounted as O,getGlobalModes as R,setNetworkMode as M,setOverrideForAllMounted as v}from"../capture/overrides";import{jsx as o,jsxs as c}from"react/jsx-runtime";const x=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];export function ImagesListFooter(){const[s,t]=m(null);const l=u(S,()=>R().network);const a=(e,n)=>{const i=v(e,n);t(i>0?`${n} on ${i} image${i===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return c(h,{paddingBottom:10,style:{paddingTop:8},children:[s?o(b,{children:s}):o(y,{children:"MASS ACTIONS \u2014 every image on screen"}),c(g,{children:[o(r,{label:"Error",onPress:()=>a({type:"error"},"Forced error")}),o(r,{label:"Loading",onPress:()=>a({type:"hang"},"Forced loading")}),o(r,{label:"Blank",onPress:()=>a({type:"blank"},"Blanked")}),o(r,{label:"Reload",onPress:()=>{t("\u2026");F().then(e=>t(e.message))}}),o(r,{label:"Find",onPress:()=>{const e=O();t(`Flashing ${e} image${e===1?"":"s"} (2.5s)`)}}),o(r,{label:"Restore",accent:true,onPress:()=>{const e=A();t(e>0?`Restored ${e} image${e===1?"":"s"}`:"No overrides active")}})]}),c(g,{children:[o(p,{style:E.netLabel,children:"NET"}),x.map(e=>{const n=l===e.key;return o(d,{label:e.label,active:n,style:{paddingVertical:6},onPress:()=>{M(e.key);t(e.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":e.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},e.key)})]})]})}function r({label:s,onPress:t,accent:l}){return o(d,{label:s,onPress:t,accent:l})}const E=f.create({netLabel:{color:k.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});
@@ -1,235 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ImagesModal — bottom-sheet wrapper rendered by FloatingDevTools when the
5
- * Images tool is opened. List of captured images → tap for detail. Also
6
- * surfaces the capture status so a mis-ordered install is self-diagnosing
7
- * instead of silently empty.
8
- */
9
-
10
- import { useEffect, useState } from "react";
11
- import { FlatList, StyleSheet, Text, View } from "react-native";
12
- import { JsModal, macOSColors, night, windowDragProps, ToolEmptyState } from "@buoy-gg/shared-ui";
13
- import { getCaptureStatus, installImageCapture } from "../capture/install";
14
- import { getGlobalModes } from "../capture/overrides";
15
- import { formatRecordMarkdown, formatRegistryMarkdown } from "../export";
16
- import { useImageRecords } from "../hooks/useImageRecords";
17
- import { remoteImagesDispatch } from "../remote";
18
- import { clearRecords, getRecord, updateRecord } from "../store/imageEventStore";
19
- import { ImageDetail } from "./ImageDetail";
20
- import { ImageDetailFooter } from "./ImageDetailFooter";
21
- import { ImageRow } from "./ImageRow";
22
- import { ImagesHeader } from "./ImagesHeader";
23
- import { ImagesListFooter } from "./ImagesListFooter";
24
- import { InsightsBar } from "./InsightsBar";
25
- import { computeInsights } from "../store/insights";
26
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
27
- function CaptureNotice() {
28
- const status = getCaptureStatus();
29
- const notices = [];
30
- if (status.rnDecoratorTooLate) {
31
- notices.push('RN <Image> instrumentation missed the module-load race — add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.');
32
- }
33
- if (!status.browserObserverActive && !status.expoAvailable && !status.rnDecoratorActive && !status.rnDecoratorTooLate) {
34
- notices.push("Waiting for images… render some <Image> components to populate the list.");
35
- }
36
- if (notices.length === 0) return null;
37
- return /*#__PURE__*/_jsx(View, {
38
- style: styles.notice,
39
- children: notices.map(n => /*#__PURE__*/_jsx(Text, {
40
- style: styles.noticeText,
41
- children: n
42
- }, n))
43
- });
44
- }
45
- function EmptyState() {
46
- return /*#__PURE__*/_jsx(ToolEmptyState, {
47
- testID: "buoy-images-empty"
48
- // listening: capture is armed, waiting for the first image load.
49
- ,
50
- otto: "listening",
51
- title: "No images captured yet",
52
- message: "Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."
53
- });
54
- }
55
- export function ImagesModal({
56
- visible,
57
- onClose,
58
- onBack,
59
- onMinimize,
60
- persistenceKey,
61
- inline = false
62
- }) {
63
- // Safety net: ensures capture is live even without the early register
64
- // import (expo-image capture is timing-immune, so this still gets most data).
65
- installImageCapture();
66
- const {
67
- records,
68
- stats
69
- } = useImageRecords();
70
- const [selectedId, setSelectedId] = useState(null);
71
- const selected = selectedId != null ? getRecord(selectedId) : undefined;
72
-
73
- // Mirror mode: the synced wire records omit errorHeaders (detail-only data)
74
- // — pull them from the device the first time a failed record is opened.
75
- const wantHeadersFor = selected?.status === "error" && selected.errorHeaders == null ? selected.id : null;
76
- useEffect(() => {
77
- const remote = remoteImagesDispatch();
78
- if (wantHeadersFor == null || !remote) return;
79
- let cancelled = false;
80
- remote("getDetail", {
81
- id: wantHeadersFor
82
- }).then(detail => {
83
- if (cancelled) return;
84
- const headers = detail?.errorHeaders;
85
- // `{}` (not undefined) so a headerless error doesn't refetch forever.
86
- updateRecord(wantHeadersFor, {
87
- errorHeaders: headers ?? {}
88
- });
89
- }).catch(() => {});
90
- return () => {
91
- cancelled = true;
92
- };
93
- }, [wantHeadersFor]);
94
-
95
- // Stepping is relative to the live list (newest first): previous = newer.
96
- const selectedIndex = selected ? records.findIndex(r => r.id === selected.id) : -1;
97
- const stepTo = index => {
98
- const target = records[index];
99
- if (target) setSelectedId(target.id);
100
- };
101
-
102
- // Mode-appropriate report: single record in detail, full registry (stats +
103
- // insights + table) in the list. The shared ToolbarCopyButton resolves this
104
- // lazily on press and handles clipboard + feedback + gating.
105
- const getReport = () => selected ? formatRecordMarkdown(selected) : formatRegistryMarkdown(records, stats, computeInsights(records), getCaptureStatus(), getGlobalModes());
106
- const headerContent = /*#__PURE__*/_jsx(ImagesHeader, {
107
- stats: stats,
108
- detailOpen: selected != null,
109
- detailIndex: selectedIndex,
110
- detailTotal: records.length,
111
- onCloseDetail: () => setSelectedId(null),
112
- onClear: clearRecords,
113
- getReport: getReport,
114
- onBack: onBack
115
- });
116
- const body = selected ? /*#__PURE__*/_jsxs(View, {
117
- style: styles.detailContainer,
118
- children: [/*#__PURE__*/_jsx(ImageDetail, {
119
- record: selected
120
- }), /*#__PURE__*/_jsx(ImageDetailFooter, {
121
- record: selected,
122
- hasPrevious: selectedIndex > 0,
123
- hasNext: selectedIndex >= 0 && selectedIndex < records.length - 1,
124
- onPrevious: () => stepTo(selectedIndex - 1),
125
- onNext: () => stepTo(selectedIndex + 1)
126
- }, selected.id)]
127
- }) : /*#__PURE__*/_jsxs(View, {
128
- style: styles.listContainer,
129
- children: [/*#__PURE__*/_jsx(InsightsBar, {
130
- insights: computeInsights(records)
131
- }), /*#__PURE__*/_jsx(CaptureNotice, {}), /*#__PURE__*/_jsx(FlatList, {
132
- data: records,
133
- keyExtractor: item => String(item.id),
134
- renderItem: ({
135
- item
136
- }) => /*#__PURE__*/_jsx(ImageRow, {
137
- record: item,
138
- onPress: setSelectedId
139
- }),
140
- ListEmptyComponent: /*#__PURE__*/_jsx(EmptyState, {})
141
- }), /*#__PURE__*/_jsx(ImagesListFooter, {})]
142
- });
143
-
144
- // The ONLY difference between the phone and the desktop dashboard is which
145
- // shell the header and body go in. Everything above this is shared.
146
- if (inline) {
147
- return /*#__PURE__*/_jsxs(View, {
148
- style: styles.inlineRoot,
149
- children: [/*#__PURE__*/_jsx(View, {
150
- style: styles.inlineHeader,
151
- ...windowDragProps,
152
- children: headerContent
153
- }), body]
154
- });
155
- }
156
- return /*#__PURE__*/_jsx(JsModal, {
157
- visible: visible,
158
- onClose: onClose,
159
- onMinimize: onMinimize,
160
- persistenceKey: persistenceKey,
161
- header: {
162
- showToggleButton: true,
163
- customContent: headerContent
164
- },
165
- enablePersistence: true,
166
- initialMode: "bottomSheet",
167
- disableScrollWrapper: true,
168
- children: body
169
- });
170
- }
171
-
172
- /**
173
- * The same Images tool as `ImagesModal`, rendered INLINE for hosts that place
174
- * tools in a panel rather than a modal (the desktop dashboard). Exists so
175
- * there is exactly one implementation of the tool's header, list and detail.
176
- */
177
- export function ImagesToolView(props = {}) {
178
- return /*#__PURE__*/_jsx(ImagesModal, {
179
- ...props,
180
- inline: true,
181
- visible: true,
182
- onClose: () => {}
183
- });
184
- }
185
- const styles = StyleSheet.create({
186
- inlineRoot: {
187
- flex: 1,
188
- minHeight: 0,
189
- // Transparent so the desktop workbench's hoisted sky (one field spanning
190
- // sidebar + panel) shows through — the shell paints its base beneath it.
191
- backgroundColor: "transparent"
192
- },
193
- inlineHeader: {
194
- paddingHorizontal: 12,
195
- paddingVertical: 8,
196
- borderBottomWidth: 1,
197
- borderBottomColor: macOSColors.border.default,
198
- // Clear, like Bench — the host's hoisted sky shows through the header.
199
- backgroundColor: "transparent"
200
- },
201
- listContainer: {
202
- flex: 1
203
- },
204
- detailContainer: {
205
- flex: 1
206
- },
207
- notice: {
208
- margin: 10,
209
- padding: 10,
210
- borderRadius: 8,
211
- backgroundColor: night.color.warningSoft,
212
- gap: 4
213
- },
214
- noticeText: {
215
- color: night.color.warning,
216
- fontSize: 11
217
- },
218
- empty: {
219
- alignItems: "center",
220
- padding: 32,
221
- gap: 8
222
- },
223
- emptyTitle: {
224
- color: night.color.text,
225
- fontSize: 13,
226
- fontWeight: "600"
227
- },
228
- emptyText: {
229
- color: night.color.textSecondary,
230
- fontSize: 11,
231
- textAlign: "center",
232
- lineHeight: 16
233
- }
234
- });
235
- //# sourceMappingURL=ImagesModal.js.map
1
+ "use strict";import{useEffect as H,useState as k}from"react";import{FlatList as M,StyleSheet as z,Text as E,View as d}from"react-native";import{JsModal as N,macOSColors as B,night as g,windowDragProps as F,ToolEmptyState as L}from"@buoy-gg/shared-ui";import{getCaptureStatus as b,installImageCapture as P}from"../capture/install";import{getGlobalModes as j}from"../capture/overrides";import{formatRecordMarkdown as A,formatRegistryMarkdown as W}from"../export";import{useImageRecords as O}from"../hooks/useImageRecords";import{remoteImagesDispatch as V}from"../remote";import{clearRecords as _,getRecord as G,updateRecord as J}from"../store/imageEventStore";import{ImageDetail as K}from"./ImageDetail";import{ImageDetailFooter as q}from"./ImageDetailFooter";import{ImageRow as Q}from"./ImageRow";import{ImagesHeader as U}from"./ImagesHeader";import{ImagesListFooter as X}from"./ImagesListFooter";import{InsightsBar as Y}from"./InsightsBar";import{computeInsights as C}from"../store/insights";import{jsx as e,jsxs as u}from"react/jsx-runtime";function Z(){const r=b();const i=[];if(r.rnDecoratorTooLate){i.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.')}if(!r.browserObserverActive&&!r.expoAvailable&&!r.rnDecoratorActive&&!r.rnDecoratorTooLate){i.push("Waiting for images\u2026 render some <Image> components to populate the list.")}if(i.length===0)return null;return e(d,{style:s.notice,children:i.map(c=>e(E,{style:s.noticeText,children:c},c))})}function $(){return e(L,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}export function ImagesModal({visible:r,onClose:i,onBack:c,onMinimize:S,persistenceKey:R,inline:w=false}){P();const{records:n,stats:f}=O();const[h,p]=k(null);const t=h!=null?G(h):void 0;const m=t?.status==="error"&&t.errorHeaders==null?t.id:null;H(()=>{const o=V();if(m==null||!o)return;let l=false;o("getDetail",{id:m}).then(v=>{if(l)return;const D=v?.errorHeaders;J(m,{errorHeaders:D??{}})}).catch(()=>{});return()=>{l=true}},[m]);const a=t?n.findIndex(o=>o.id===t.id):-1;const y=o=>{const l=n[o];if(l)p(l.id)};const T=()=>t?A(t):W(n,f,C(n),b(),j());const x=e(U,{stats:f,detailOpen:t!=null,detailIndex:a,detailTotal:n.length,onCloseDetail:()=>p(null),onClear:_,getReport:T,onBack:c});const I=t?u(d,{style:s.detailContainer,children:[e(K,{record:t}),e(q,{record:t,hasPrevious:a>0,hasNext:a>=0&&a<n.length-1,onPrevious:()=>y(a-1),onNext:()=>y(a+1)},t.id)]}):u(d,{style:s.listContainer,children:[e(Y,{insights:C(n)}),e(Z,{}),e(M,{data:n,keyExtractor:o=>String(o.id),renderItem:({item:o})=>e(Q,{record:o,onPress:p}),ListEmptyComponent:e($,{})}),e(X,{})]});if(w){return u(d,{style:s.inlineRoot,children:[e(d,{style:s.inlineHeader,...F,children:x}),I]})}return e(N,{visible:r,onClose:i,onMinimize:S,persistenceKey:R,header:{showToggleButton:true,customContent:x},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:I})}export function ImagesToolView(r={}){return e(ImagesModal,{...r,inline:true,visible:true,onClose:()=>{}})}const s=z.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:B.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:g.color.warningSoft,gap:4},noticeText:{color:g.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:g.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:g.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});
@@ -1,20 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Mount once near the app root to start image capture immediately.
5
- *
6
- * NOTE: for full RN-core <Image> coverage prefer the side-effect import
7
- * `import "@buoy-gg/images/register"` as the first import of your entry file —
8
- * the RN decorator must be installed before React Native's Image module first
9
- * evaluates. ImagesRoot alone still captures every expo-image instance
10
- * (timing-immune) and reports whether the RN hook landed.
11
- */
12
-
13
- import { installImageCapture } from "../capture/install";
14
- export function ImagesRoot() {
15
- // Synchronous on first render — earlier than an effect, though still later
16
- // than the register import. Idempotent.
17
- installImageCapture();
18
- return null;
19
- }
20
- //# sourceMappingURL=ImagesRoot.js.map
1
+ "use strict";import{installImageCapture as t}from"../capture/install";export function ImagesRoot(){t();return null}
@@ -1,9 +1 @@
1
- "use strict";
2
-
3
- import { useEffect } from 'react';
4
- import { startBrowserImageCapture } from '../capture/install.web';
5
- export function ImagesRoot() {
6
- useEffect(startBrowserImageCapture, []);
7
- return null;
8
- }
9
- //# sourceMappingURL=ImagesRoot.web.js.map
1
+ "use strict";import{useEffect as r}from"react";import{startBrowserImageCapture as t}from"../capture/install.web";export function ImagesRoot(){r(t,[]);return null}