react-native-icon-switcher 0.0.0-stage → 0.1.1

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 (86) hide show
  1. package/IconSwitcher.podspec +20 -0
  2. package/LICENSE +20 -0
  3. package/README.md +252 -2
  4. package/android/build.gradle +51 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/iconswitcher/IconSwitcher.kt +380 -0
  7. package/android/src/main/java/com/iconswitcher/IconSwitcherExceptions.kt +24 -0
  8. package/android/src/main/java/com/iconswitcher/IconSwitcherModule.kt +67 -0
  9. package/android/src/main/java/com/iconswitcher/IconSwitcherPackage.kt +30 -0
  10. package/android/src/test/AndroidManifest.xml +39 -0
  11. package/android/src/test/java/com/iconswitcher/IconSwitcherTest.kt +392 -0
  12. package/app.plugin.js +1 -0
  13. package/ios/ISIconSwitcher.h +49 -0
  14. package/ios/ISIconSwitcher.m +205 -0
  15. package/ios/IconSwitcher.h +5 -0
  16. package/ios/IconSwitcher.mm +100 -0
  17. package/jest/index.d.ts +31 -0
  18. package/jest/index.js +98 -0
  19. package/lib/module/NativeIconSwitcher.js +5 -0
  20. package/lib/module/NativeIconSwitcher.js.map +1 -0
  21. package/lib/module/config.js +6 -0
  22. package/lib/module/config.js.map +1 -0
  23. package/lib/module/errors.js +28 -0
  24. package/lib/module/errors.js.map +1 -0
  25. package/lib/module/index.js +69 -0
  26. package/lib/module/index.js.map +1 -0
  27. package/lib/module/package.json +1 -0
  28. package/lib/module/register.js +2 -0
  29. package/lib/module/register.js.map +1 -0
  30. package/lib/module/remote/index.js +119 -0
  31. package/lib/module/remote/index.js.map +1 -0
  32. package/lib/module/types.js +2 -0
  33. package/lib/module/types.js.map +1 -0
  34. package/lib/typescript/package.json +1 -0
  35. package/lib/typescript/src/NativeIconSwitcher.d.ts +18 -0
  36. package/lib/typescript/src/NativeIconSwitcher.d.ts.map +1 -0
  37. package/lib/typescript/src/config.d.ts +4 -0
  38. package/lib/typescript/src/config.d.ts.map +1 -0
  39. package/lib/typescript/src/errors.d.ts +7 -0
  40. package/lib/typescript/src/errors.d.ts.map +1 -0
  41. package/lib/typescript/src/index.d.ts +20 -0
  42. package/lib/typescript/src/index.d.ts.map +1 -0
  43. package/lib/typescript/src/register.d.ts +7 -0
  44. package/lib/typescript/src/register.d.ts.map +1 -0
  45. package/lib/typescript/src/remote/index.d.ts +17 -0
  46. package/lib/typescript/src/remote/index.d.ts.map +1 -0
  47. package/lib/typescript/src/types.d.ts +59 -0
  48. package/lib/typescript/src/types.d.ts.map +1 -0
  49. package/package.json +253 -4
  50. package/plugin/build/cli.d.ts +3 -0
  51. package/plugin/build/cli.js +89 -0
  52. package/plugin/build/core/assets.d.ts +80 -0
  53. package/plugin/build/core/assets.js +463 -0
  54. package/plugin/build/core/errors.d.ts +4 -0
  55. package/plugin/build/core/errors.js +11 -0
  56. package/plugin/build/core/validate.d.ts +6 -0
  57. package/plugin/build/core/validate.js +229 -0
  58. package/plugin/build/index.d.ts +6 -0
  59. package/plugin/build/index.js +134 -0
  60. package/plugin/build/load-config.d.ts +3 -0
  61. package/plugin/build/load-config.js +50 -0
  62. package/plugin/build/paths.d.ts +15 -0
  63. package/plugin/build/paths.js +153 -0
  64. package/plugin/build/sync.d.ts +12 -0
  65. package/plugin/build/sync.js +162 -0
  66. package/plugin/build/transforms/android.d.ts +5 -0
  67. package/plugin/build/transforms/android.js +212 -0
  68. package/plugin/build/transforms/errors.d.ts +4 -0
  69. package/plugin/build/transforms/errors.js +11 -0
  70. package/plugin/build/transforms/index.d.ts +4 -0
  71. package/plugin/build/transforms/index.js +12 -0
  72. package/plugin/build/transforms/ios.d.ts +4 -0
  73. package/plugin/build/transforms/ios.js +111 -0
  74. package/plugin/build/transforms/sampleConfigs.d.ts +3 -0
  75. package/plugin/build/transforms/sampleConfigs.js +33 -0
  76. package/plugin/build/transforms/types.d.ts +2 -0
  77. package/plugin/build/transforms/types.js +14 -0
  78. package/plugin/build/types.d.ts +61 -0
  79. package/plugin/build/types.js +5 -0
  80. package/src/NativeIconSwitcher.ts +17 -0
  81. package/src/config.ts +15 -0
  82. package/src/errors.ts +38 -0
  83. package/src/index.tsx +78 -0
  84. package/src/register.ts +4 -0
  85. package/src/remote/index.ts +142 -0
  86. package/src/types.ts +59 -0
@@ -0,0 +1,59 @@
1
+ /** A path to a square PNG master, ideally 1024 px. Relative to the project root. */
2
+ export type ImagePath = string;
3
+ /** Hex colour, `#RGB` or `#RRGGBB`. */
4
+ export type HexColor = string;
5
+ export interface IosIconVariants {
6
+ light: ImagePath;
7
+ /** Phase 2. */
8
+ dark?: ImagePath;
9
+ /** Phase 2. */
10
+ tinted?: ImagePath;
11
+ }
12
+ export interface AndroidAdaptiveIcon {
13
+ foreground: ImagePath;
14
+ background: ImagePath | HexColor;
15
+ /** Phase 2. Android 13+ themed icons. */
16
+ monochrome?: ImagePath;
17
+ }
18
+ export interface IconSpec {
19
+ ios?: ImagePath | IosIconVariants;
20
+ android?: ImagePath | AndroidAdaptiveIcon;
21
+ }
22
+ /** A bare path means "same master for both platforms". */
23
+ export type IconSource = ImagePath | IconSpec;
24
+ export interface IconSwitcherConfig {
25
+ /** Primary icon. Omit on Expo to reuse `icon` / `android.adaptiveIcon`. */
26
+ default?: IconSource;
27
+ icons: Record<string, IconSource>;
28
+ ios?: {
29
+ /** Background colour that transparent pixels are flattened onto. Default `#FFFFFF`. */
30
+ flattenOn?: HexColor;
31
+ };
32
+ android?: {
33
+ /** Default `'background'`. */
34
+ applyOn?: 'background' | 'immediate';
35
+ /** Lower-cased `Build.BRAND` values where switching is disabled. Default `[]`. */
36
+ skipBrands?: string[];
37
+ };
38
+ }
39
+ /** Config after validation and defaults; every icon normalised to per-platform specs. */
40
+ export interface ResolvedIcon {
41
+ name: string;
42
+ isDefault: boolean;
43
+ ios: IosIconVariants | null;
44
+ android: AndroidAdaptiveIcon | {
45
+ legacy: ImagePath;
46
+ } | null;
47
+ }
48
+ export interface ResolvedConfig {
49
+ /** `default` first, then alternates in declaration order. */
50
+ icons: ResolvedIcon[];
51
+ ios: {
52
+ flattenOn: HexColor;
53
+ };
54
+ android: {
55
+ applyOn: 'background' | 'immediate';
56
+ skipBrands: string[];
57
+ };
58
+ }
59
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,uCAAuC;AACvC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,eAAe;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,eAAe;IACf,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,SAAS,CAAC;IACtB,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC,yCAAyC;IACzC,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,SAAS,GAAG,eAAe,CAAC;IAClC,OAAO,CAAC,EAAE,SAAS,GAAG,mBAAmB,CAAC;CAC3C;AAED,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE;QACJ,uFAAuF;QACvF,SAAS,CAAC,EAAE,QAAQ,CAAC;KACtB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,8BAA8B;QAC9B,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;QACrC,kFAAkF;QAClF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH;AAED,yFAAyF;AACzF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,mBAAmB,GAAG;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,GAAG,EAAE;QAAE,SAAS,EAAE,QAAQ,CAAA;KAAE,CAAC;IAC7B,OAAO,EAAE;QAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACxE"}
package/package.json CHANGED
@@ -1,6 +1,255 @@
1
1
  {
2
2
  "name": "react-native-icon-switcher",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Switch the app icon at runtime on React Native and Expo from one config file, with the native wiring generated for you",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "react-native-icon-switcher-source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./config": {
14
+ "react-native-icon-switcher-source": "./src/config.ts",
15
+ "types": "./lib/typescript/src/config.d.ts",
16
+ "default": "./lib/module/config.js"
17
+ },
18
+ "./remote": {
19
+ "react-native-icon-switcher-source": "./src/remote/index.ts",
20
+ "types": "./lib/typescript/src/remote/index.d.ts",
21
+ "default": "./lib/module/remote/index.js"
22
+ },
23
+ "./jest": {
24
+ "types": "./jest/index.d.ts",
25
+ "default": "./jest/index.js"
26
+ },
27
+ "./app.plugin.js": "./app.plugin.js",
28
+ "./package.json": "./package.json"
29
+ },
30
+ "bin": "./plugin/build/cli.js",
31
+ "files": [
32
+ "src",
33
+ "lib",
34
+ "android",
35
+ "ios",
36
+ "cpp",
37
+ "jest",
38
+ "app.plugin.js",
39
+ "plugin/build",
40
+ "*.podspec",
41
+ "react-native.config.js",
42
+ "!ios/build",
43
+ "!android/build",
44
+ "!android/gradle",
45
+ "!android/gradlew",
46
+ "!android/gradlew.bat",
47
+ "!android/local.properties",
48
+ "!**/__tests__",
49
+ "!**/__fixtures__",
50
+ "!**/__mocks__",
51
+ "!**/.*",
52
+ "!plugin/build/**/__tests__",
53
+ "!**/typetests"
54
+ ],
55
+ "scripts": {
56
+ "example": "yarn workspace react-native-icon-switcher-example",
57
+ "clean": "del-cli lib plugin/build",
58
+ "prepare": "bob build && yarn build:plugin",
59
+ "build:plugin": "tsc -p plugin",
60
+ "typecheck": "tsc && tsc -p plugin --noEmit",
61
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
62
+ "test": "jest",
63
+ "release": "release-it --only-version",
64
+ "check:exports": "node -e \"for (const s of ['react-native-icon-switcher/app.plugin.js','react-native-icon-switcher/jest','react-native-icon-switcher/package.json','react-native-icon-switcher/config','react-native-icon-switcher/remote']) require.resolve(s); console.log('exports ok')\"",
65
+ "example-bare": "yarn workspace react-native-icon-switcher-example-bare"
66
+ },
67
+ "keywords": [
68
+ "react-native",
69
+ "ios",
70
+ "android",
71
+ "expo",
72
+ "expo-config-plugin",
73
+ "app-icon",
74
+ "alternate-icons",
75
+ "icon"
76
+ ],
77
+ "repository": {
78
+ "type": "git",
79
+ "url": "git+https://github.com/RRigueira/react-native-icon-switcher.git"
80
+ },
81
+ "author": "Rui Rigueira <14238908+RRigueira@users.noreply.github.com> (https://github.com/RRigueira)",
82
+ "license": "MIT",
83
+ "bugs": {
84
+ "url": "https://github.com/RRigueira/react-native-icon-switcher/issues"
85
+ },
86
+ "homepage": "https://github.com/RRigueira/react-native-icon-switcher#readme",
87
+ "publishConfig": {
88
+ "registry": "https://registry.npmjs.org/",
89
+ "access": "public",
90
+ "provenance": true
91
+ },
92
+ "dependencies": {
93
+ "@expo/config-plugins": "^58.0.10",
94
+ "@expo/plist": "^0.10.1",
95
+ "jiti": "^2.7.0",
96
+ "sharp": "^0.35.5",
97
+ "xcode": "^4.0.0"
98
+ },
99
+ "devDependencies": {
100
+ "@commitlint/cli": "^21.2.4",
101
+ "@commitlint/config-conventional": "^21.2.3",
102
+ "@eslint/compat": "^2.1.1",
103
+ "@eslint/eslintrc": "^3.3.7",
104
+ "@eslint/js": "^9.39.5",
105
+ "@react-native/babel-preset": "0.88.0",
106
+ "@react-native/eslint-config": "0.88.0",
107
+ "@react-native/jest-preset": "0.88.0",
108
+ "@release-it/conventional-changelog": "^12.0.2",
109
+ "@testing-library/react-native": "^14.1.0",
110
+ "@types/jest": "^30.0.0",
111
+ "@types/node": "^26.6.3",
112
+ "@types/react": "^19.2.0",
113
+ "@types/react-test-renderer": "^19",
114
+ "del-cli": "^8.0.1",
115
+ "eslint": "^9.39.5",
116
+ "eslint-config-prettier": "^10.1.8",
117
+ "eslint-plugin-ft-flow": "^3.0.11",
118
+ "eslint-plugin-prettier": "^5.5.7",
119
+ "expo": "~58.0.19",
120
+ "jest": "^30.5.2",
121
+ "lefthook": "^2.2.2",
122
+ "prettier": "^3.9.10",
123
+ "react": "19.3.0",
124
+ "react-native": "0.88.0",
125
+ "react-native-builder-bob": "^0.44.1",
126
+ "react-test-renderer": "19.3.0",
127
+ "release-it": "^21.1.1",
128
+ "turbo": "^2.11.10",
129
+ "typescript": "^6.0.3"
130
+ },
131
+ "peerDependencies": {
132
+ "expo": ">=52",
133
+ "react": "*",
134
+ "react-native": "*"
135
+ },
136
+ "peerDependenciesMeta": {
137
+ "expo": {
138
+ "optional": true
139
+ }
140
+ },
141
+ "workspaces": [
142
+ "example",
143
+ "example-bare"
144
+ ],
145
+ "packageManager": "yarn@4.18.1",
146
+ "react-native-builder-bob": {
147
+ "source": "src",
148
+ "output": "lib",
149
+ "targets": [
150
+ [
151
+ "module",
152
+ {
153
+ "esm": true
154
+ }
155
+ ],
156
+ [
157
+ "typescript",
158
+ {
159
+ "project": "tsconfig.build.json"
160
+ }
161
+ ]
162
+ ],
163
+ "exclude": "**/{__tests__,__fixtures__,__mocks__,typetests}/**"
164
+ },
165
+ "codegenConfig": {
166
+ "name": "IconSwitcherSpec",
167
+ "type": "modules",
168
+ "jsSrcsDir": "src",
169
+ "android": {
170
+ "javaPackageName": "com.iconswitcher"
171
+ }
172
+ },
173
+ "prettier": {
174
+ "quoteProps": "consistent",
175
+ "singleQuote": true,
176
+ "tabWidth": 2,
177
+ "trailingComma": "es5",
178
+ "useTabs": false
179
+ },
180
+ "jest": {
181
+ "preset": "@react-native/jest-preset",
182
+ "modulePathIgnorePatterns": [
183
+ "<rootDir>/example/node_modules",
184
+ "<rootDir>/example-bare/node_modules",
185
+ "<rootDir>/lib/",
186
+ "<rootDir>/plugin/build"
187
+ ],
188
+ "testPathIgnorePatterns": [
189
+ "<rootDir>/plugin/build",
190
+ "<rootDir>/jest",
191
+ "<rootDir>/example/",
192
+ "<rootDir>/example-bare/"
193
+ ],
194
+ "collectCoverageFrom": [
195
+ "src/**/*.{ts,tsx}",
196
+ "!src/**/__tests__/**",
197
+ "!src/**/__mocks__/**",
198
+ "!src/typetests/**",
199
+ "!src/NativeIconSwitcher.ts",
200
+ "!src/types.ts",
201
+ "!src/register.ts",
202
+ "plugin/src/**/*.ts",
203
+ "!plugin/src/**/__tests__/**",
204
+ "!plugin/src/__fixtures__/**",
205
+ "!plugin/src/types.ts",
206
+ "!**/*.d.ts"
207
+ ],
208
+ "coverageThreshold": {
209
+ "global": {
210
+ "statements": 95,
211
+ "branches": 90,
212
+ "functions": 85,
213
+ "lines": 95
214
+ }
215
+ }
216
+ },
217
+ "commitlint": {
218
+ "extends": [
219
+ "@commitlint/config-conventional"
220
+ ]
221
+ },
222
+ "release-it": {
223
+ "git": {
224
+ "commitMessage": "chore: release ${version}",
225
+ "tagName": "v${version}",
226
+ "requireBranch": "main",
227
+ "requireCleanWorkingDir": true
228
+ },
229
+ "npm": {
230
+ "publish": false
231
+ },
232
+ "github": {
233
+ "release": true
234
+ },
235
+ "plugins": {
236
+ "@release-it/conventional-changelog": {
237
+ "preset": {
238
+ "name": "angular"
239
+ },
240
+ "infile": "CHANGELOG.md"
241
+ }
242
+ }
243
+ },
244
+ "create-react-native-library": {
245
+ "type": "turbo-module",
246
+ "languages": "kotlin-objc",
247
+ "tools": [
248
+ "eslint"
249
+ ],
250
+ "version": "0.64.0"
251
+ },
252
+ "resolutions": {
253
+ "release-it/undici": "7.29.1"
254
+ }
255
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export { syncProject } from './sync';
3
+ export declare function run(argv: string[]): Promise<number>;
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.syncProject = void 0;
8
+ exports.run = run;
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const errors_1 = require("./core/errors");
11
+ const errors_2 = require("./transforms/errors");
12
+ const paths_1 = require("./paths");
13
+ const sync_1 = require("./sync");
14
+ var sync_2 = require("./sync");
15
+ Object.defineProperty(exports, "syncProject", { enumerable: true, get: function () { return sync_2.syncProject; } });
16
+ function _printError(message) {
17
+ process.stderr.write(`${message}\n`);
18
+ }
19
+ async function run(argv) {
20
+ const command = argv[0];
21
+ if (command !== 'sync') {
22
+ _printError('Usage: react-native-icon-switcher sync [--check] [--project-root <dir>] [--config <path>]');
23
+ return 2;
24
+ }
25
+ let check = false;
26
+ let projectRoot = process.cwd();
27
+ let configPath;
28
+ for (let i = 1; i < argv.length; i += 1) {
29
+ const arg = argv[i];
30
+ if (arg === '--check') {
31
+ check = true;
32
+ continue;
33
+ }
34
+ if (arg === '--project-root') {
35
+ const value = argv[i + 1];
36
+ if (!value) {
37
+ _printError('--project-root requires a directory');
38
+ return 2;
39
+ }
40
+ projectRoot = value;
41
+ i += 1;
42
+ continue;
43
+ }
44
+ if (arg === '--config') {
45
+ const value = argv[i + 1];
46
+ if (!value) {
47
+ _printError('--config requires a path');
48
+ return 2;
49
+ }
50
+ configPath = value;
51
+ i += 1;
52
+ continue;
53
+ }
54
+ _printError(`Unknown argument: ${arg}`);
55
+ return 2;
56
+ }
57
+ try {
58
+ const result = await (0, sync_1.syncProject)({
59
+ projectRoot: node_path_1.default.resolve(projectRoot),
60
+ configPath,
61
+ check,
62
+ });
63
+ if (check) {
64
+ if (result.driftedPaths.length > 0) {
65
+ for (const rel of result.driftedPaths.sort()) {
66
+ _printError(rel);
67
+ }
68
+ return 1;
69
+ }
70
+ return 0;
71
+ }
72
+ process.stdout.write(`updated ${result.updated} files, unchanged ${result.unchanged}\n`);
73
+ return 0;
74
+ }
75
+ catch (err) {
76
+ if (err instanceof errors_1.ConfigError ||
77
+ err instanceof errors_2.TransformError ||
78
+ err instanceof paths_1.ProjectLayoutError) {
79
+ _printError(err.message);
80
+ return 2;
81
+ }
82
+ throw err;
83
+ }
84
+ }
85
+ if (require.main === module) {
86
+ void run(process.argv.slice(2)).then((code) => {
87
+ process.exitCode = code;
88
+ });
89
+ }
@@ -0,0 +1,80 @@
1
+ import type { HexColor, ResolvedConfig } from '../types';
2
+ export type IosVariant = 'light' | 'dark' | 'tinted';
3
+ export type AssetJob = {
4
+ kind: 'ios-png';
5
+ iconName: string;
6
+ isDefault: boolean;
7
+ variant: IosVariant;
8
+ sourcePath: string;
9
+ flattenOn: HexColor;
10
+ width: number;
11
+ height: number;
12
+ } | {
13
+ kind: 'ios-contents';
14
+ iconName: string;
15
+ isDefault: boolean;
16
+ variants: IosVariant[];
17
+ } | {
18
+ kind: 'android-legacy';
19
+ iconName: string;
20
+ isDefault: boolean;
21
+ round: boolean;
22
+ sourcePath: string;
23
+ density: string;
24
+ size: number;
25
+ backgroundColor?: HexColor;
26
+ backgroundImagePath?: string;
27
+ } | {
28
+ kind: 'android-adaptive-foreground';
29
+ iconName: string;
30
+ isDefault: boolean;
31
+ sourcePath: string;
32
+ density: string;
33
+ size: number;
34
+ } | {
35
+ kind: 'android-adaptive-background-image';
36
+ iconName: string;
37
+ isDefault: boolean;
38
+ sourcePath: string;
39
+ density: string;
40
+ size: number;
41
+ } | {
42
+ kind: 'android-adaptive-xml';
43
+ iconName: string;
44
+ isDefault: boolean;
45
+ round: boolean;
46
+ backgroundIsColor: boolean;
47
+ hasMonochrome: boolean;
48
+ } | {
49
+ kind: 'android-colors-xml';
50
+ entries: {
51
+ resourceName: string;
52
+ color: HexColor;
53
+ }[];
54
+ };
55
+ export interface PlannedAsset {
56
+ /** Path relative to `iosAssetCatalog` or `androidResDir`. */
57
+ relativePath: string;
58
+ job: AssetJob;
59
+ }
60
+ export interface AssetPlan {
61
+ projectRoot: string;
62
+ flattenOn: HexColor;
63
+ assets: PlannedAsset[];
64
+ }
65
+ export interface WrittenFile {
66
+ relativePath: string;
67
+ absolutePath: string;
68
+ sha256: string;
69
+ }
70
+ export declare function planAssets(cfg: ResolvedConfig, projectRoot: string): AssetPlan;
71
+ export declare function writeAssets(plan: AssetPlan, opts: {
72
+ iosAssetCatalog: string;
73
+ androidResDir: string;
74
+ }): Promise<WrittenFile[]>;
75
+ /** Test helper: corner pixel RGB after iOS flatten (alpha removed). */
76
+ export declare function _readCornerRgb(pngPath: string): Promise<{
77
+ r: number;
78
+ g: number;
79
+ b: number;
80
+ }>;