@buoy-gg/assets 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 (204) hide show
  1. package/README.md +12 -73
  2. package/bundlers/vite.mjs +1 -53
  3. package/lib/commonjs/autoCapture.js +1 -5
  4. package/lib/commonjs/autoCapture.web.js +1 -6
  5. package/lib/commonjs/capture/assetLifecycle.js +1 -11
  6. package/lib/commonjs/capture/assetLifecycle.web.js +1 -20
  7. package/lib/commonjs/capture/browserAssets.js +1 -83
  8. package/lib/commonjs/capture/expo.js +1 -46
  9. package/lib/commonjs/capture/expo.web.js +1 -19
  10. package/lib/commonjs/capture/install.js +1 -91
  11. package/lib/commonjs/capture/install.web.js +1 -75
  12. package/lib/commonjs/capture/isBuoyAsset.js +1 -23
  13. package/lib/commonjs/capture/measure.js +1 -187
  14. package/lib/commonjs/capture/metroGraph.js +1 -175
  15. package/lib/commonjs/capture/metroGraph.web.js +1 -27
  16. package/lib/commonjs/capture/registry.js +1 -127
  17. package/lib/commonjs/components/AssetDetail.js +1 -211
  18. package/lib/commonjs/components/AssetImage.js +1 -66
  19. package/lib/commonjs/components/AssetRow.js +1 -232
  20. package/lib/commonjs/components/AssetsFilterBar.js +1 -105
  21. package/lib/commonjs/components/AssetsHeader.js +1 -73
  22. package/lib/commonjs/components/AssetsIcon.js +1 -19
  23. package/lib/commonjs/components/AssetsListControls.js +1 -81
  24. package/lib/commonjs/components/AssetsModal.js +1 -378
  25. package/lib/commonjs/components/ScanNotice.js +1 -86
  26. package/lib/commonjs/components/optionalExpoImage.js +1 -16
  27. package/lib/commonjs/components/optionalExpoImage.web.js +1 -10
  28. package/lib/commonjs/export.js +1 -62
  29. package/lib/commonjs/format.js +1 -59
  30. package/lib/commonjs/hooks/useAssetRecords.js +1 -22
  31. package/lib/commonjs/hooks/useAssetScanStatus.js +1 -28
  32. package/lib/commonjs/index.js +1 -294
  33. package/lib/commonjs/preset.js +1 -39
  34. package/lib/commonjs/remote.js +1 -68
  35. package/lib/commonjs/state.js +1 -51
  36. package/lib/commonjs/store/assetStore.js +1 -256
  37. package/lib/commonjs/store/baseline.js +1 -175
  38. package/lib/commonjs/store/insights.js +1 -120
  39. package/lib/commonjs/sync/assetsSyncAdapter.js +1 -157
  40. package/lib/commonjs/types.js +0 -1
  41. package/lib/commonjs/utils/deviceScale.js +1 -50
  42. package/lib/commonjs/utils/testIDs.js +1 -110
  43. package/lib/module/autoCapture.js +1 -5
  44. package/lib/module/autoCapture.web.js +1 -5
  45. package/lib/module/capture/assetLifecycle.js +1 -7
  46. package/lib/module/capture/assetLifecycle.web.js +1 -16
  47. package/lib/module/capture/browserAssets.js +1 -75
  48. package/lib/module/capture/expo.js +1 -41
  49. package/lib/module/capture/expo.web.js +1 -14
  50. package/lib/module/capture/install.js +1 -85
  51. package/lib/module/capture/install.web.js +1 -68
  52. package/lib/module/capture/isBuoyAsset.js +1 -18
  53. package/lib/module/capture/measure.js +1 -180
  54. package/lib/module/capture/metroGraph.js +1 -168
  55. package/lib/module/capture/metroGraph.web.js +1 -21
  56. package/lib/module/capture/registry.js +1 -120
  57. package/lib/module/components/AssetDetail.js +1 -207
  58. package/lib/module/components/AssetImage.js +1 -62
  59. package/lib/module/components/AssetRow.js +1 -228
  60. package/lib/module/components/AssetsFilterBar.js +1 -101
  61. package/lib/module/components/AssetsHeader.js +1 -69
  62. package/lib/module/components/AssetsIcon.js +1 -12
  63. package/lib/module/components/AssetsListControls.js +1 -77
  64. package/lib/module/components/AssetsModal.js +1 -373
  65. package/lib/module/components/ScanNotice.js +1 -82
  66. package/lib/module/components/optionalExpoImage.js +1 -12
  67. package/lib/module/components/optionalExpoImage.web.js +1 -6
  68. package/lib/module/export.js +1 -57
  69. package/lib/module/format.js +1 -51
  70. package/lib/module/hooks/useAssetRecords.js +1 -18
  71. package/lib/module/hooks/useAssetScanStatus.js +1 -23
  72. package/lib/module/index.js +1 -64
  73. package/lib/module/preset.js +1 -35
  74. package/lib/module/remote.js +1 -61
  75. package/lib/module/state.js +1 -47
  76. package/lib/module/store/assetStore.js +1 -240
  77. package/lib/module/store/baseline.js +1 -167
  78. package/lib/module/store/insights.js +1 -116
  79. package/lib/module/sync/assetsSyncAdapter.js +1 -153
  80. package/lib/module/types.js +0 -1
  81. package/lib/module/utils/deviceScale.js +1 -46
  82. package/lib/module/utils/testIDs.js +1 -99
  83. package/lib/web/index.mjs +3 -4
  84. package/package.json +3 -8
  85. package/lib/commonjs/autoCapture.js.map +0 -1
  86. package/lib/commonjs/autoCapture.web.js.map +0 -1
  87. package/lib/commonjs/capture/assetLifecycle.js.map +0 -1
  88. package/lib/commonjs/capture/assetLifecycle.web.js.map +0 -1
  89. package/lib/commonjs/capture/browserAssets.js.map +0 -1
  90. package/lib/commonjs/capture/expo.js.map +0 -1
  91. package/lib/commonjs/capture/expo.web.js.map +0 -1
  92. package/lib/commonjs/capture/install.js.map +0 -1
  93. package/lib/commonjs/capture/install.web.js.map +0 -1
  94. package/lib/commonjs/capture/isBuoyAsset.js.map +0 -1
  95. package/lib/commonjs/capture/measure.js.map +0 -1
  96. package/lib/commonjs/capture/metroGraph.js.map +0 -1
  97. package/lib/commonjs/capture/metroGraph.web.js.map +0 -1
  98. package/lib/commonjs/capture/registry.js.map +0 -1
  99. package/lib/commonjs/components/AssetDetail.js.map +0 -1
  100. package/lib/commonjs/components/AssetImage.js.map +0 -1
  101. package/lib/commonjs/components/AssetRow.js.map +0 -1
  102. package/lib/commonjs/components/AssetsFilterBar.js.map +0 -1
  103. package/lib/commonjs/components/AssetsHeader.js.map +0 -1
  104. package/lib/commonjs/components/AssetsIcon.js.map +0 -1
  105. package/lib/commonjs/components/AssetsListControls.js.map +0 -1
  106. package/lib/commonjs/components/AssetsModal.js.map +0 -1
  107. package/lib/commonjs/components/ScanNotice.js.map +0 -1
  108. package/lib/commonjs/components/optionalExpoImage.js.map +0 -1
  109. package/lib/commonjs/components/optionalExpoImage.web.js.map +0 -1
  110. package/lib/commonjs/export.js.map +0 -1
  111. package/lib/commonjs/format.js.map +0 -1
  112. package/lib/commonjs/hooks/useAssetRecords.js.map +0 -1
  113. package/lib/commonjs/hooks/useAssetScanStatus.js.map +0 -1
  114. package/lib/commonjs/index.js.map +0 -1
  115. package/lib/commonjs/preset.js.map +0 -1
  116. package/lib/commonjs/remote.js.map +0 -1
  117. package/lib/commonjs/state.js.map +0 -1
  118. package/lib/commonjs/store/assetStore.js.map +0 -1
  119. package/lib/commonjs/store/baseline.js.map +0 -1
  120. package/lib/commonjs/store/insights.js.map +0 -1
  121. package/lib/commonjs/sync/assetsSyncAdapter.js.map +0 -1
  122. package/lib/commonjs/types.js.map +0 -1
  123. package/lib/commonjs/utils/deviceScale.js.map +0 -1
  124. package/lib/commonjs/utils/testIDs.js.map +0 -1
  125. package/lib/module/autoCapture.js.map +0 -1
  126. package/lib/module/autoCapture.web.js.map +0 -1
  127. package/lib/module/capture/assetLifecycle.js.map +0 -1
  128. package/lib/module/capture/assetLifecycle.web.js.map +0 -1
  129. package/lib/module/capture/browserAssets.js.map +0 -1
  130. package/lib/module/capture/expo.js.map +0 -1
  131. package/lib/module/capture/expo.web.js.map +0 -1
  132. package/lib/module/capture/install.js.map +0 -1
  133. package/lib/module/capture/install.web.js.map +0 -1
  134. package/lib/module/capture/isBuoyAsset.js.map +0 -1
  135. package/lib/module/capture/measure.js.map +0 -1
  136. package/lib/module/capture/metroGraph.js.map +0 -1
  137. package/lib/module/capture/metroGraph.web.js.map +0 -1
  138. package/lib/module/capture/registry.js.map +0 -1
  139. package/lib/module/components/AssetDetail.js.map +0 -1
  140. package/lib/module/components/AssetImage.js.map +0 -1
  141. package/lib/module/components/AssetRow.js.map +0 -1
  142. package/lib/module/components/AssetsFilterBar.js.map +0 -1
  143. package/lib/module/components/AssetsHeader.js.map +0 -1
  144. package/lib/module/components/AssetsIcon.js.map +0 -1
  145. package/lib/module/components/AssetsListControls.js.map +0 -1
  146. package/lib/module/components/AssetsModal.js.map +0 -1
  147. package/lib/module/components/ScanNotice.js.map +0 -1
  148. package/lib/module/components/optionalExpoImage.js.map +0 -1
  149. package/lib/module/components/optionalExpoImage.web.js.map +0 -1
  150. package/lib/module/export.js.map +0 -1
  151. package/lib/module/format.js.map +0 -1
  152. package/lib/module/hooks/useAssetRecords.js.map +0 -1
  153. package/lib/module/hooks/useAssetScanStatus.js.map +0 -1
  154. package/lib/module/index.js.map +0 -1
  155. package/lib/module/preset.js.map +0 -1
  156. package/lib/module/remote.js.map +0 -1
  157. package/lib/module/state.js.map +0 -1
  158. package/lib/module/store/assetStore.js.map +0 -1
  159. package/lib/module/store/baseline.js.map +0 -1
  160. package/lib/module/store/insights.js.map +0 -1
  161. package/lib/module/sync/assetsSyncAdapter.js.map +0 -1
  162. package/lib/module/types.js.map +0 -1
  163. package/lib/module/utils/deviceScale.js.map +0 -1
  164. package/lib/module/utils/testIDs.js.map +0 -1
  165. package/lib/typescript/autoCapture.d.ts.map +0 -1
  166. package/lib/typescript/autoCapture.web.d.ts.map +0 -1
  167. package/lib/typescript/capture/assetLifecycle.d.ts.map +0 -1
  168. package/lib/typescript/capture/assetLifecycle.web.d.ts.map +0 -1
  169. package/lib/typescript/capture/browserAssets.d.ts.map +0 -1
  170. package/lib/typescript/capture/expo.d.ts.map +0 -1
  171. package/lib/typescript/capture/expo.web.d.ts.map +0 -1
  172. package/lib/typescript/capture/install.d.ts.map +0 -1
  173. package/lib/typescript/capture/install.web.d.ts.map +0 -1
  174. package/lib/typescript/capture/isBuoyAsset.d.ts.map +0 -1
  175. package/lib/typescript/capture/measure.d.ts.map +0 -1
  176. package/lib/typescript/capture/metroGraph.d.ts.map +0 -1
  177. package/lib/typescript/capture/metroGraph.web.d.ts.map +0 -1
  178. package/lib/typescript/capture/registry.d.ts.map +0 -1
  179. package/lib/typescript/components/AssetDetail.d.ts.map +0 -1
  180. package/lib/typescript/components/AssetImage.d.ts.map +0 -1
  181. package/lib/typescript/components/AssetRow.d.ts.map +0 -1
  182. package/lib/typescript/components/AssetsFilterBar.d.ts.map +0 -1
  183. package/lib/typescript/components/AssetsHeader.d.ts.map +0 -1
  184. package/lib/typescript/components/AssetsIcon.d.ts.map +0 -1
  185. package/lib/typescript/components/AssetsListControls.d.ts.map +0 -1
  186. package/lib/typescript/components/AssetsModal.d.ts.map +0 -1
  187. package/lib/typescript/components/ScanNotice.d.ts.map +0 -1
  188. package/lib/typescript/components/optionalExpoImage.d.ts.map +0 -1
  189. package/lib/typescript/components/optionalExpoImage.web.d.ts.map +0 -1
  190. package/lib/typescript/export.d.ts.map +0 -1
  191. package/lib/typescript/format.d.ts.map +0 -1
  192. package/lib/typescript/hooks/useAssetRecords.d.ts.map +0 -1
  193. package/lib/typescript/hooks/useAssetScanStatus.d.ts.map +0 -1
  194. package/lib/typescript/index.d.ts.map +0 -1
  195. package/lib/typescript/preset.d.ts.map +0 -1
  196. package/lib/typescript/remote.d.ts.map +0 -1
  197. package/lib/typescript/state.d.ts.map +0 -1
  198. package/lib/typescript/store/assetStore.d.ts.map +0 -1
  199. package/lib/typescript/store/baseline.d.ts.map +0 -1
  200. package/lib/typescript/store/insights.d.ts.map +0 -1
  201. package/lib/typescript/sync/assetsSyncAdapter.d.ts.map +0 -1
  202. package/lib/typescript/types.d.ts.map +0 -1
  203. package/lib/typescript/utils/deviceScale.d.ts.map +0 -1
  204. package/lib/typescript/utils/testIDs.d.ts.map +0 -1
@@ -1,211 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.AssetDetail = AssetDetail;
7
- var _reactNative = require("react-native");
8
- var _sharedUi = require("@buoy-gg/shared-ui");
9
- var _AssetImage = require("./AssetImage");
10
- var _format = require("../format");
11
- var _assetStore = require("../store/assetStore");
12
- var _testIDs = require("../utils/testIDs");
13
- var _jsxRuntime = require("react/jsx-runtime");
14
- /**
15
- * AssetDetail — full metadata for one asset: preview, identity, dimensions,
16
- * per-scale sizes, resolution info, and which audit findings apply.
17
- *
18
- * Image previews use registry ids or asset URLs, with optional expo-image for
19
- * native SVGs; fonts render a pangram with fontFamily set to the asset name
20
- * — a best-effort guess (family ≠ filename for many fonts) that falls back
21
- * to the system font silently when it misses.
22
- */
23
-
24
- function Row({
25
- label,
26
- value
27
- }) {
28
- const testID = (0, _testIDs.assetDetailRowTestID)(label);
29
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
30
- style: styles.kvRow,
31
- testID: testID,
32
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
33
- style: styles.kvLabel,
34
- children: label
35
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
36
- style: styles.kvValue,
37
- selectable: true,
38
- testID: `${testID}-value`,
39
- children: value
40
- })]
41
- });
42
- }
43
- function Preview({
44
- record
45
- }) {
46
- if (record.kind === "image") {
47
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
48
- style: styles.previewBox,
49
- testID: _testIDs.ASSETS_TEST_IDS.detailPreview,
50
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_AssetImage.AssetImage, {
51
- testID: "buoy-internal-assets-preview",
52
- record: record,
53
- style: styles.previewImage
54
- })
55
- });
56
- }
57
- if (record.kind === "font") {
58
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
59
- style: styles.previewBox,
60
- testID: _testIDs.ASSETS_TEST_IDS.detailFontPreview,
61
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
62
- style: [styles.fontPreview, {
63
- fontFamily: record.name
64
- }],
65
- children: "The quick brown fox jumps over the lazy dog 0123456789"
66
- })
67
- });
68
- }
69
- return null;
70
- }
71
- function AssetDetail({
72
- record,
73
- insights
74
- }) {
75
- const findings = [];
76
- if (insights.neverLoaded.includes(record.id)) {
77
- findings.push("Not observed in the runtime registry this app run. This does not prove the asset is unused.");
78
- }
79
- if (insights.scaleGaps.includes(record.id)) {
80
- findings.push("Scale gap — no variant covers this device's pixel ratio");
81
- }
82
- if (insights.webpCandidates.includes(record.id)) {
83
- findings.push("WebP candidate — large png/jpeg, converting typically saves 20–40%");
84
- }
85
- const duplicate = insights.duplicates.find(d => d.ids.includes(record.id));
86
- if (duplicate) {
87
- findings.push(`Duplicate content — identical bytes shipped ${duplicate.ids.length} times`);
88
- }
89
- if (insights.overDecode.includes(record.id)) {
90
- findings.push("Decodes larger than 2× this entire screen — resize the source, no view can need this many pixels");
91
- }
92
- if (insights.heavyGifs.includes(record.id)) {
93
- findings.push("Heavy GIF — every frame decodes into memory; a video or Lottie is typically ~90% smaller");
94
- }
95
- if (insights.heavyFonts.includes(record.id)) {
96
- findings.push("Heavy font — likely an unsubset icon font; subsetting to used glyphs usually saves most of it");
97
- }
98
- if (insights.scaleAnomalies.includes(record.id)) {
99
- findings.push("Scale anomaly — a higher-resolution variant is smaller in bytes than a lower one; check the exports");
100
- }
101
- const estimate = (0, _assetStore.estDecodedBytes)(record);
102
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
103
- style: styles.scroll,
104
- contentContainerStyle: styles.content,
105
- testID: _testIDs.ASSETS_TEST_IDS.detailScroll,
106
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Preview, {
107
- record: record
108
- }), findings.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
109
- style: styles.findings,
110
- testID: _testIDs.ASSETS_TEST_IDS.detailFindings,
111
- children: findings.map((finding, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
112
- style: styles.findingText,
113
- testID: (0, _testIDs.assetFindingTestID)(index),
114
- children: finding
115
- }, finding))
116
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
117
- label: "Name",
118
- value: `${record.name}.${record.type}`
119
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
120
- label: "Kind",
121
- value: record.kind
122
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
123
- label: "Status",
124
- value: record.loaded ? "Loaded (registered at runtime)" : "Not observed in the runtime registry"
125
- }), record.kind === "image" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
126
- label: "Dimensions",
127
- value: `${(0, _format.formatDimensions)(record)} (logical)`
128
- }) : null, record.kind === "image" && record.scales.length ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
129
- label: "Scales",
130
- value: (0, _format.formatScales)(record.scales)
131
- }) : null, record.sizesByScale ? Object.entries(record.sizesByScale).map(([scale, bytes]) => /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
132
- label: `Size @${scale}x`,
133
- value: (0, _format.formatBytes)(bytes)
134
- }, scale)) : null, record.sizeBytes != null && record.sizeSource === "measured" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
135
- label: "Total size",
136
- value: (0, _format.formatBytes)(record.sizeBytes)
137
- }) : null, estimate > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
138
- label: "Decoded memory",
139
- value: `~${(0, _format.formatBytes)(estimate)} (RGBA)`
140
- }) : null, record.registryId != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
141
- label: "Registry id",
142
- value: String(record.registryId)
143
- }) : null, record.hash ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
144
- label: "Hash",
145
- value: record.hash
146
- }) : null, record.httpServerLocation ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
147
- label: "Location",
148
- value: record.httpServerLocation
149
- }) : null, record.fileSystemLocation ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
150
- label: "Source dir",
151
- value: record.fileSystemLocation
152
- }) : null, record.resolvedUri ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
153
- label: "Resolved URI",
154
- value: record.resolvedUri
155
- }) : null]
156
- });
157
- }
158
- const styles = _reactNative.StyleSheet.create({
159
- scroll: {
160
- flex: 1
161
- },
162
- content: {
163
- padding: 12,
164
- gap: 8
165
- },
166
- previewBox: {
167
- borderRadius: 8,
168
- backgroundColor: _sharedUi.night.color.bg,
169
- padding: 12,
170
- alignItems: "center",
171
- justifyContent: "center",
172
- minHeight: 96
173
- },
174
- previewImage: {
175
- width: "100%",
176
- height: 140
177
- },
178
- fontPreview: {
179
- color: _sharedUi.night.color.text,
180
- fontSize: 16,
181
- textAlign: "center"
182
- },
183
- findings: {
184
- borderRadius: 8,
185
- borderWidth: 1,
186
- borderColor: _sharedUi.night.color.border,
187
- backgroundColor: _sharedUi.night.color.surface,
188
- padding: 10,
189
- gap: 6
190
- },
191
- findingText: {
192
- color: _sharedUi.night.color.textSecondary,
193
- fontSize: 11,
194
- lineHeight: 15
195
- },
196
- kvRow: {
197
- gap: 2
198
- },
199
- kvLabel: {
200
- color: _sharedUi.night.color.textTertiary,
201
- fontSize: 9,
202
- fontWeight: "700",
203
- letterSpacing: 0.5,
204
- textTransform: "uppercase"
205
- },
206
- kvValue: {
207
- color: _sharedUi.night.color.text,
208
- fontSize: 12
209
- }
210
- });
211
- //# sourceMappingURL=AssetDetail.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AssetDetail=AssetDetail;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _AssetImage=require("./AssetImage");var _format=require("../format");var _assetStore=require("../store/assetStore");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");function Row({label:e,value:s}){const t=(0,_testIDs.assetDetailRowTestID)(e);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.kvRow,testID:t,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.kvLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.kvValue,selectable:true,testID:`${t}-value`,children:s})]})}function Preview({record:e}){if(e.kind==="image"){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.previewBox,testID:_testIDs.ASSETS_TEST_IDS.detailPreview,children:(0,_jsxRuntime.jsx)(_AssetImage.AssetImage,{testID:"buoy-internal-assets-preview",record:e,style:styles.previewImage})})}if(e.kind==="font"){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.previewBox,testID:_testIDs.ASSETS_TEST_IDS.detailFontPreview,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.fontPreview,{fontFamily:e.name}],children:"The quick brown fox jumps over the lazy dog 0123456789"})})}return null}function AssetDetail({record:e,insights:s}){const t=[];if(s.neverLoaded.includes(e.id)){t.push("Not observed in the runtime registry this app run. This does not prove the asset is unused.")}if(s.scaleGaps.includes(e.id)){t.push("Scale gap \u2014 no variant covers this device's pixel ratio")}if(s.webpCandidates.includes(e.id)){t.push("WebP candidate \u2014 large png/jpeg, converting typically saves 20\u201340%")}const a=s.duplicates.find(i=>i.ids.includes(e.id));if(a){t.push(`Duplicate content \u2014 identical bytes shipped ${a.ids.length} times`)}if(s.overDecode.includes(e.id)){t.push("Decodes larger than 2\xD7 this entire screen \u2014 resize the source, no view can need this many pixels")}if(s.heavyGifs.includes(e.id)){t.push("Heavy GIF \u2014 every frame decodes into memory; a video or Lottie is typically ~90% smaller")}if(s.heavyFonts.includes(e.id)){t.push("Heavy font \u2014 likely an unsubset icon font; subsetting to used glyphs usually saves most of it")}if(s.scaleAnomalies.includes(e.id)){t.push("Scale anomaly \u2014 a higher-resolution variant is smaller in bytes than a lower one; check the exports")}const n=(0,_assetStore.estDecodedBytes)(e);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.scroll,contentContainerStyle:styles.content,testID:_testIDs.ASSETS_TEST_IDS.detailScroll,children:[(0,_jsxRuntime.jsx)(Preview,{record:e}),t.length>0?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.findings,testID:_testIDs.ASSETS_TEST_IDS.detailFindings,children:t.map((i,l)=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.findingText,testID:(0,_testIDs.assetFindingTestID)(l),children:i},i))}):null,(0,_jsxRuntime.jsx)(Row,{label:"Name",value:`${e.name}.${e.type}`}),(0,_jsxRuntime.jsx)(Row,{label:"Kind",value:e.kind}),(0,_jsxRuntime.jsx)(Row,{label:"Status",value:e.loaded?"Loaded (registered at runtime)":"Not observed in the runtime registry"}),e.kind==="image"?(0,_jsxRuntime.jsx)(Row,{label:"Dimensions",value:`${(0,_format.formatDimensions)(e)} (logical)`}):null,e.kind==="image"&&e.scales.length?(0,_jsxRuntime.jsx)(Row,{label:"Scales",value:(0,_format.formatScales)(e.scales)}):null,e.sizesByScale?Object.entries(e.sizesByScale).map(([i,l])=>(0,_jsxRuntime.jsx)(Row,{label:`Size @${i}x`,value:(0,_format.formatBytes)(l)},i)):null,e.sizeBytes!=null&&e.sizeSource==="measured"?(0,_jsxRuntime.jsx)(Row,{label:"Total size",value:(0,_format.formatBytes)(e.sizeBytes)}):null,n>0?(0,_jsxRuntime.jsx)(Row,{label:"Decoded memory",value:`~${(0,_format.formatBytes)(n)} (RGBA)`}):null,e.registryId!=null?(0,_jsxRuntime.jsx)(Row,{label:"Registry id",value:String(e.registryId)}):null,e.hash?(0,_jsxRuntime.jsx)(Row,{label:"Hash",value:e.hash}):null,e.httpServerLocation?(0,_jsxRuntime.jsx)(Row,{label:"Location",value:e.httpServerLocation}):null,e.fileSystemLocation?(0,_jsxRuntime.jsx)(Row,{label:"Source dir",value:e.fileSystemLocation}):null,e.resolvedUri?(0,_jsxRuntime.jsx)(Row,{label:"Resolved URI",value:e.resolvedUri}):null]})}const styles=_reactNative.StyleSheet.create({scroll:{flex:1},content:{padding:12,gap:8},previewBox:{borderRadius:8,backgroundColor:_sharedUi.night.color.bg,padding:12,alignItems:"center",justifyContent:"center",minHeight:96},previewImage:{width:"100%",height:140},fontPreview:{color:_sharedUi.night.color.text,fontSize:16,textAlign:"center"},findings:{borderRadius:8,borderWidth:1,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,padding:10,gap:6},findingText:{color:_sharedUi.night.color.textSecondary,fontSize:11,lineHeight:15},kvRow:{gap:2},kvLabel:{color:_sharedUi.night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.5,textTransform:"uppercase"},kvValue:{color:_sharedUi.night.color.text,fontSize:12}});
@@ -1,66 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.AssetImage = AssetImage;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
9
- var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _measure = require("../capture/measure");
11
- var _optionalExpoImage = require("./optionalExpoImage");
12
- var _jsxRuntime = require("react/jsx-runtime");
13
- function AssetImage({
14
- record,
15
- style,
16
- testID,
17
- compact = false
18
- }) {
19
- const source = (0, _measure.displaySource)(record);
20
- const svg = record.type.toLowerCase() === "svg";
21
- const ExpoImage = svg && _reactNative.Platform.OS !== "web" ? (0, _optionalExpoImage.getExpoPreviewImage)() : null;
22
- const sourceKey = `${record.key}:${record.hash ?? ""}:${typeof source === "number" ? source : source?.uri ?? ""}`;
23
- const [failedSource, setFailedSource] = (0, _react.useState)(null);
24
- const unavailable = source == null || failedSource === sourceKey || svg && _reactNative.Platform.OS !== "web" && !ExpoImage;
25
- if (unavailable) {
26
- const label = svg ? "SVG preview unavailable" : "Image preview unavailable";
27
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
28
- style: [style, styles.fallback],
29
- accessibilityLabel: label,
30
- testID: `${testID}-unavailable`,
31
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
32
- style: styles.text,
33
- children: compact ? svg ? "SVG" : "IMG" : label
34
- })
35
- });
36
- }
37
- const onError = () => setFailedSource(sourceKey);
38
- if (ExpoImage) {
39
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(ExpoImage, {
40
- source: source,
41
- style: style,
42
- contentFit: "contain",
43
- onError: onError,
44
- testID: testID
45
- });
46
- }
47
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
48
- source: source,
49
- style: style,
50
- resizeMode: "contain",
51
- onError: onError,
52
- testID: testID
53
- });
54
- }
55
- const styles = _reactNative.StyleSheet.create({
56
- fallback: {
57
- alignItems: "center",
58
- justifyContent: "center"
59
- },
60
- text: {
61
- color: _sharedUi.night.color.textSecondary,
62
- fontSize: 10,
63
- textAlign: "center"
64
- }
65
- });
66
- //# sourceMappingURL=AssetImage.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AssetImage=AssetImage;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _measure=require("../capture/measure");var _optionalExpoImage=require("./optionalExpoImage");var _jsxRuntime=require("react/jsx-runtime");function AssetImage({record:t,style:a,testID:s,compact:u=false}){const e=(0,_measure.displaySource)(t);const r=t.type.toLowerCase()==="svg";const n=r&&_reactNative.Platform.OS!=="web"?(0,_optionalExpoImage.getExpoPreviewImage)():null;const o=`${t.key}:${t.hash??""}:${typeof e==="number"?e:e?.uri??""}`;const[c,v]=(0,_react.useState)(null);const x=e==null||c===o||r&&_reactNative.Platform.OS!=="web"&&!n;if(x){const l=r?"SVG preview unavailable":"Image preview unavailable";return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[a,styles.fallback],accessibilityLabel:l,testID:`${s}-unavailable`,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.text,children:u?r?"SVG":"IMG":l})})}const i=()=>v(o);if(n){return(0,_jsxRuntime.jsx)(n,{source:e,style:a,contentFit:"contain",onError:i,testID:s})}return(0,_jsxRuntime.jsx)(_reactNative.Image,{source:e,style:a,resizeMode:"contain",onError:i,testID:s})}const styles=_reactNative.StyleSheet.create({fallback:{alignItems:"center",justifyContent:"center"},text:{color:_sharedUi.night.color.textSecondary,fontSize:10,textAlign:"center"}});
@@ -1,232 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.AssetRow = AssetRow;
7
- var _reactNative = require("react-native");
8
- var _sharedUi = require("@buoy-gg/shared-ui");
9
- var _AssetImage = require("./AssetImage");
10
- var _format = require("../format");
11
- var _assetStore = require("../store/assetStore");
12
- var _testIDs = require("../utils/testIDs");
13
- var _jsxRuntime = require("react/jsx-runtime");
14
- /**
15
- * AssetRow — one bundled asset as a family-style card (matching the network
16
- * tool's rows): rounded card, colored accent edge per kind, thumbnail, name,
17
- * quiet metadata, bold right-aligned size, and finding badges ONLY when a
18
- * finding exists. A thin proportional bar along the card bottom makes the
19
- * heavy assets feel heavy at a glance.
20
- *
21
- * Thumbnails render through the NUMERIC registry id when available — that
22
- * routes through resolveAssetSource natively, so it works in dev, iOS
23
- * release (file://) and Android release (bare resource id) alike. They carry
24
- * the buoy-internal testID so the images tool never records our own UI.
25
- */
26
-
27
- /** Which audit findings apply to this record (drives the row badges). */
28
-
29
- function Badge({
30
- label,
31
- color,
32
- testID
33
- }) {
34
- // Quiet chip: legibility from light-gray text on a neutral fill. Only the
35
- // serious tiers (red) and WEBP (blue) carry a small dot; the rest are plain.
36
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Pill, {
37
- label: label,
38
- color: color,
39
- variant: "quiet",
40
- dot: Boolean(color),
41
- style: {
42
- paddingVertical: 2.5
43
- },
44
- testID: testID
45
- });
46
- }
47
- function AssetRow({
48
- record,
49
- flags,
50
- sizeFraction,
51
- onPress
52
- }) {
53
- const accent = _format.KIND_COLORS[record.kind];
54
- const badges = [];
55
- if (!record.loaded) badges.push({
56
- label: "NOT OBSERVED"
57
- });
58
- if (flags.oversize) badges.push({
59
- label: "OVERSIZE",
60
- color: _sharedUi.macOSColors.semantic.error
61
- });
62
- if (flags.duplicate) badges.push({
63
- label: "DUP"
64
- });
65
- if (flags.heavy) badges.push({
66
- label: "HEAVY"
67
- });
68
- if (flags.scaleAnomaly) badges.push({
69
- label: "BAD SCALE",
70
- color: _sharedUi.macOSColors.semantic.error
71
- });else if (flags.scaleGap) badges.push({
72
- label: "LOW-RES"
73
- });
74
- if (flags.webp) badges.push({
75
- label: "WEBP",
76
- color: _sharedUi.macOSColors.semantic.info
77
- });
78
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
79
- style: styles.card,
80
- testID: (0, _testIDs.assetRowTestID)(record.name, record.type),
81
- onPress: () => onPress(record.id),
82
- activeOpacity: 0.7,
83
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
84
- style: styles.body,
85
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
86
- style: styles.thumbBox,
87
- children: record.kind === "image" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_AssetImage.AssetImage
88
- // buoy-internal- prefix: the images tool skips its own toolchain's
89
- // views, so previewing an asset never records a render of itself.
90
- , {
91
- testID: "buoy-internal-assets-thumb",
92
- record: record,
93
- style: styles.thumb,
94
- compact: true
95
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
96
- style: [styles.thumbFallback, {
97
- color: accent
98
- }],
99
- children: _format.KIND_LABELS[record.kind]
100
- })
101
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
102
- style: styles.main,
103
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
104
- style: styles.name,
105
- numberOfLines: 1,
106
- testID: `${(0, _testIDs.assetRowTestID)(record.name, record.type)}-name`,
107
- children: [record.name, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
108
- style: styles.ext,
109
- children: [".", record.type]
110
- })]
111
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
112
- style: styles.metaRow,
113
- children: [record.kind === "image" && record.width != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
114
- style: styles.meta,
115
- children: (0, _format.formatDimensions)(record)
116
- }) : null, record.kind === "image" && record.scales.length ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
117
- style: styles.meta,
118
- children: (0, _format.formatScales)(record.scales)
119
- }) : null]
120
- })]
121
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
122
- style: styles.right,
123
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
124
- style: styles.size,
125
- testID: `${(0, _testIDs.assetRowTestID)(record.name, record.type)}-size`,
126
- children: (0, _format.formatSize)(record, (0, _assetStore.estDecodedBytes)(record))
127
- }), badges.length ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
128
- style: styles.badgeRow,
129
- children: badges.slice(0, 3).map(b => /*#__PURE__*/(0, _jsxRuntime.jsx)(Badge, {
130
- label: b.label,
131
- color: b.color,
132
- testID: (0, _testIDs.assetBadgeTestID)(record.name, record.type, b.label)
133
- }, b.label))
134
- }) : null]
135
- })]
136
- }), sizeFraction > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
137
- style: styles.sizeTrack,
138
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
139
- style: [styles.sizeFill, {
140
- backgroundColor: accent,
141
- width: `${Math.max(2, Math.round(sizeFraction * 100))}%`
142
- }]
143
- })
144
- }) : null]
145
- });
146
- }
147
- const styles = _reactNative.StyleSheet.create({
148
- card: {
149
- marginHorizontal: 10,
150
- marginTop: 6,
151
- borderRadius: 10,
152
- backgroundColor: _sharedUi.night.color.surface,
153
- borderWidth: 1,
154
- borderColor: _sharedUi.night.color.border,
155
- overflow: "hidden"
156
- },
157
- body: {
158
- flexDirection: "row",
159
- alignItems: "center",
160
- paddingVertical: 8,
161
- paddingHorizontal: 12,
162
- gap: 10
163
- },
164
- thumbBox: {
165
- width: 40,
166
- height: 40,
167
- borderRadius: 8,
168
- // Light plate so dark glyph assets stay visible on the dark card.
169
- backgroundColor: "rgba(255,255,255,0.10)",
170
- borderWidth: 1,
171
- borderColor: _sharedUi.night.color.border,
172
- alignItems: "center",
173
- justifyContent: "center",
174
- overflow: "hidden"
175
- },
176
- thumb: {
177
- width: 34,
178
- height: 34
179
- },
180
- thumbFallback: {
181
- fontSize: 9,
182
- fontWeight: "700",
183
- letterSpacing: 0.5
184
- },
185
- main: {
186
- flex: 1,
187
- gap: 3
188
- },
189
- name: {
190
- color: _sharedUi.night.color.text,
191
- fontSize: 12,
192
- fontWeight: "600"
193
- },
194
- ext: {
195
- color: _sharedUi.night.color.textTertiary,
196
- fontWeight: "400"
197
- },
198
- metaRow: {
199
- flexDirection: "row",
200
- alignItems: "center",
201
- gap: 8
202
- },
203
- meta: {
204
- color: _sharedUi.night.color.textSecondary,
205
- fontSize: 10,
206
- fontVariant: ["tabular-nums"]
207
- },
208
- right: {
209
- alignItems: "flex-end",
210
- gap: 4
211
- },
212
- size: {
213
- color: _sharedUi.night.color.text,
214
- fontSize: 12,
215
- fontWeight: "700",
216
- fontVariant: ["tabular-nums"]
217
- },
218
- badgeRow: {
219
- flexDirection: "row",
220
- gap: 4
221
- },
222
- sizeTrack: {
223
- height: 2,
224
- backgroundColor: "transparent"
225
- },
226
- sizeFill: {
227
- height: 2,
228
- opacity: 0.45,
229
- borderTopRightRadius: 2
230
- }
231
- });
232
- //# sourceMappingURL=AssetRow.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AssetRow=AssetRow;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _AssetImage=require("./AssetImage");var _format=require("../format");var _assetStore=require("../store/assetStore");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");function Badge({label:e,color:t,testID:s}){return(0,_jsxRuntime.jsx)(_sharedUi.Pill,{label:e,color:t,variant:"quiet",dot:Boolean(t),style:{paddingVertical:2.5},testID:s})}function AssetRow({record:e,flags:t,sizeFraction:s,onPress:o}){const l=_format.KIND_COLORS[e.kind];const i=[];if(!e.loaded)i.push({label:"NOT OBSERVED"});if(t.oversize)i.push({label:"OVERSIZE",color:_sharedUi.macOSColors.semantic.error});if(t.duplicate)i.push({label:"DUP"});if(t.heavy)i.push({label:"HEAVY"});if(t.scaleAnomaly)i.push({label:"BAD SCALE",color:_sharedUi.macOSColors.semantic.error});else if(t.scaleGap)i.push({label:"LOW-RES"});if(t.webp)i.push({label:"WEBP",color:_sharedUi.macOSColors.semantic.info});return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.card,testID:(0,_testIDs.assetRowTestID)(e.name,e.type),onPress:()=>o(e.id),activeOpacity:.7,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.body,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.thumbBox,children:e.kind==="image"?(0,_jsxRuntime.jsx)(_AssetImage.AssetImage,{testID:"buoy-internal-assets-thumb",record:e,style:styles.thumb,compact:true}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.thumbFallback,{color:l}],children:_format.KIND_LABELS[e.kind]})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.main,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.name,numberOfLines:1,testID:`${(0,_testIDs.assetRowTestID)(e.name,e.type)}-name`,children:[e.name,(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.ext,children:[".",e.type]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.metaRow,children:[e.kind==="image"&&e.width!=null?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.meta,children:(0,_format.formatDimensions)(e)}):null,e.kind==="image"&&e.scales.length?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.meta,children:(0,_format.formatScales)(e.scales)}):null]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.right,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.size,testID:`${(0,_testIDs.assetRowTestID)(e.name,e.type)}-size`,children:(0,_format.formatSize)(e,(0,_assetStore.estDecodedBytes)(e))}),i.length?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.badgeRow,children:i.slice(0,3).map(a=>(0,_jsxRuntime.jsx)(Badge,{label:a.label,color:a.color,testID:(0,_testIDs.assetBadgeTestID)(e.name,e.type,a.label)},a.label))}):null]})]}),s>0?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sizeTrack,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.sizeFill,{backgroundColor:l,width:`${Math.max(2,Math.round(s*100))}%`}]})}):null]})}const styles=_reactNative.StyleSheet.create({card:{marginHorizontal:10,marginTop:6,borderRadius:10,backgroundColor:_sharedUi.night.color.surface,borderWidth:1,borderColor:_sharedUi.night.color.border,overflow:"hidden"},body:{flexDirection:"row",alignItems:"center",paddingVertical:8,paddingHorizontal:12,gap:10},thumbBox:{width:40,height:40,borderRadius:8,backgroundColor:"rgba(255,255,255,0.10)",borderWidth:1,borderColor:_sharedUi.night.color.border,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:34,height:34},thumbFallback:{fontSize:9,fontWeight:"700",letterSpacing:.5},main:{flex:1,gap:3},name:{color:_sharedUi.night.color.text,fontSize:12,fontWeight:"600"},ext:{color:_sharedUi.night.color.textTertiary,fontWeight:"400"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:_sharedUi.night.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end",gap:4},size:{color:_sharedUi.night.color.text,fontSize:12,fontWeight:"700",fontVariant:["tabular-nums"]},badgeRow:{flexDirection:"row",gap:4},sizeTrack:{height:2,backgroundColor:"transparent"},sizeFill:{height:2,opacity:.45,borderTopRightRadius:2}});
@@ -1,105 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.AssetsFilterBar = AssetsFilterBar;
7
- var _reactNative = require("react-native");
8
- var _sharedUi = require("@buoy-gg/shared-ui");
9
- var _format = require("../format");
10
- var _testIDs = require("../utils/testIDs");
11
- var _jsxRuntime = require("react/jsx-runtime");
12
- /**
13
- * AssetsFilterBar — kind filter pills with counts, styled like the network
14
- * tool's bordered pills: outlined, kind-accent-colored when active. Wrapping
15
- * row, not a horizontal ScrollView (same height-measurement pitfall the
16
- * images tool documents).
17
- */
18
-
19
- function AssetsFilterBar({
20
- stats,
21
- duplicateCount,
22
- filter,
23
- onChange
24
- }) {
25
- const chips = [{
26
- key: "all",
27
- label: `ALL ${stats.total}`,
28
- accent: _sharedUi.night.color.textSecondary
29
- }, {
30
- key: "duplicates",
31
- label: `DUPLICATES ${duplicateCount}`,
32
- accent: "#FF9F1C"
33
- }];
34
- for (const kind of Object.keys(stats.byKind)) {
35
- const entry = stats.byKind[kind];
36
- if (entry.count > 0) {
37
- chips.push({
38
- key: kind,
39
- label: `${_format.KIND_LABELS[kind]} ${entry.count}`,
40
- accent: _format.KIND_COLORS[kind]
41
- });
42
- }
43
- }
44
- if (stats.neverLoaded > 0) {
45
- // Amber, not semantic.warning — the bright yellow reads as an alarm.
46
- chips.push({
47
- key: "unused",
48
- label: `NOT OBSERVED ${stats.neverLoaded}`,
49
- accent: "#FF9F1C"
50
- });
51
- }
52
- if (chips.length <= 1) return null;
53
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
54
- style: styles.bar,
55
- testID: _testIDs.ASSETS_TEST_IDS.filterBar,
56
- children: chips.map(chip => {
57
- const active = chip.key === filter;
58
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
59
- accessibilityRole: "button",
60
- accessibilityState: {
61
- selected: active
62
- },
63
- testID: (0, _testIDs.assetFilterTestID)(chip.key),
64
- style: [styles.chip, active && {
65
- borderColor: chip.accent,
66
- backgroundColor: `${chip.accent}1A`
67
- }]
68
- // Tapping the active chip again untoggles back to ALL.
69
- ,
70
- onPress: () => onChange(active ? "all" : chip.key),
71
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
72
- testID: `${(0, _testIDs.assetFilterTestID)(chip.key)}-label`,
73
- style: [styles.chipText, {
74
- color: active ? chip.accent : _sharedUi.night.color.textSecondary
75
- }],
76
- children: chip.label
77
- })
78
- }, chip.key);
79
- })
80
- });
81
- }
82
- const styles = _reactNative.StyleSheet.create({
83
- bar: {
84
- flexDirection: "row",
85
- flexWrap: "wrap",
86
- gap: 6,
87
- paddingHorizontal: 10,
88
- paddingVertical: 8
89
- },
90
- chip: {
91
- borderWidth: 1,
92
- borderColor: _sharedUi.night.color.border,
93
- backgroundColor: _sharedUi.night.color.surface,
94
- borderRadius: 999,
95
- paddingHorizontal: 10,
96
- paddingVertical: 5
97
- },
98
- chipText: {
99
- fontSize: 10,
100
- fontWeight: "700",
101
- letterSpacing: 0.4,
102
- lineHeight: 13
103
- }
104
- });
105
- //# sourceMappingURL=AssetsFilterBar.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AssetsFilterBar=AssetsFilterBar;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("../format");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");function AssetsFilterBar({stats:r,duplicateCount:l,filter:o,onChange:i}){const a=[{key:"all",label:`ALL ${r.total}`,accent:_sharedUi.night.color.textSecondary},{key:"duplicates",label:`DUPLICATES ${l}`,accent:"#FF9F1C"}];for(const e of Object.keys(r.byKind)){const t=r.byKind[e];if(t.count>0){a.push({key:e,label:`${_format.KIND_LABELS[e]} ${t.count}`,accent:_format.KIND_COLORS[e]})}}if(r.neverLoaded>0){a.push({key:"unused",label:`NOT OBSERVED ${r.neverLoaded}`,accent:"#FF9F1C"})}if(a.length<=1)return null;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.bar,testID:_testIDs.ASSETS_TEST_IDS.filterBar,children:a.map(e=>{const t=e.key===o;return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{accessibilityRole:"button",accessibilityState:{selected:t},testID:(0,_testIDs.assetFilterTestID)(e.key),style:[styles.chip,t&&{borderColor:e.accent,backgroundColor:`${e.accent}1A`}],onPress:()=>i(t?"all":e.key),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:`${(0,_testIDs.assetFilterTestID)(e.key)}-label`,style:[styles.chipText,{color:t?e.accent:_sharedUi.night.color.textSecondary}],children:e.label})},e.key)})})}const styles=_reactNative.StyleSheet.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8},chip:{borderWidth:1,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{fontSize:10,fontWeight:"700",letterSpacing:.4,lineHeight:13}});