@nice2dev/icons 1.3.15 → 1.3.16

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 (140) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/NiceDesktopIconExporter.js +688 -599
  3. package/dist/cjs/NiceFaviconGenerator.js +603 -417
  4. package/dist/cjs/NiceIconPicker.js +788 -508
  5. package/dist/cjs/NiceIconPreview.js +246 -188
  6. package/dist/cjs/NiceIconSetCreator.js +683 -552
  7. package/dist/cjs/NiceIconStacker.js +547 -171
  8. package/dist/cjs/NiceIconValue.js +27 -35
  9. package/dist/cjs/NtdIconBadge.js +384 -360
  10. package/dist/cjs/NtdIconMorph.js +419 -354
  11. package/dist/cjs/NtdStateMorph.js +150 -147
  12. package/dist/cjs/advancedIconSearch.js +373 -510
  13. package/dist/cjs/animationControls.js +518 -642
  14. package/dist/cjs/client.js +12 -15
  15. package/dist/cjs/createIcon.js +349 -251
  16. package/dist/cjs/design-tokens.js +324 -390
  17. package/dist/cjs/figmaExport.js +162 -257
  18. package/dist/cjs/figmaSync.js +234 -316
  19. package/dist/cjs/headless-ui.js +240 -368
  20. package/dist/cjs/iconAnalytics.js +337 -393
  21. package/dist/cjs/iconHtml.js +64 -86
  22. package/dist/cjs/iconMetadata.js +392 -472
  23. package/dist/cjs/iconParts.js +120 -90
  24. package/dist/cjs/iconStack.js +136 -155
  25. package/dist/cjs/iconStyles.js +1609 -504
  26. package/dist/cjs/iconValue.js +359 -430
  27. package/dist/cjs/icons/accessibility.js +1119 -134
  28. package/dist/cjs/icons/actions.js +1290 -330
  29. package/dist/cjs/icons/ai.js +1424 -144
  30. package/dist/cjs/icons/brand.js +1344 -172
  31. package/dist/cjs/icons/business.js +903 -193
  32. package/dist/cjs/icons/devtech.js +1656 -227
  33. package/dist/cjs/icons/ecommerce.js +802 -111
  34. package/dist/cjs/icons/education.js +1345 -199
  35. package/dist/cjs/icons/files.js +1597 -328
  36. package/dist/cjs/icons/fintech.js +793 -104
  37. package/dist/cjs/icons/food.js +1507 -153
  38. package/dist/cjs/icons/fun.js +786 -109
  39. package/dist/cjs/icons/gaming.js +916 -170
  40. package/dist/cjs/icons/health.js +623 -112
  41. package/dist/cjs/icons/index.js +32 -35
  42. package/dist/cjs/icons/input.js +282 -83
  43. package/dist/cjs/icons/legal.js +1065 -122
  44. package/dist/cjs/icons/media.js +1061 -267
  45. package/dist/cjs/icons/navigation.js +387 -122
  46. package/dist/cjs/icons/omniverk.js +747 -90
  47. package/dist/cjs/icons/realestate.js +1520 -193
  48. package/dist/cjs/icons/saas.js +867 -98
  49. package/dist/cjs/icons/science.js +1451 -202
  50. package/dist/cjs/icons/shapes.js +1316 -308
  51. package/dist/cjs/icons/smarthome.js +786 -90
  52. package/dist/cjs/icons/social.js +591 -59
  53. package/dist/cjs/icons/sports.js +1225 -133
  54. package/dist/cjs/icons/sustainability.js +1211 -139
  55. package/dist/cjs/icons/travel.js +1470 -148
  56. package/dist/cjs/icons/ui.js +1508 -315
  57. package/dist/cjs/icons/weather.js +1160 -173
  58. package/dist/cjs/index.js +566 -568
  59. package/dist/cjs/lottieIntegration.js +261 -266
  60. package/dist/cjs/nicetodev-icons.css +1 -1
  61. package/dist/cjs/particleEffects.js +270 -251
  62. package/dist/cjs/resolver.js +229 -284
  63. package/dist/cjs/rsc.js +175 -193
  64. package/dist/cjs/sharpen.js +73 -130
  65. package/dist/cjs/smilAnimations.js +371 -165
  66. package/dist/cjs/stacking.js +87 -122
  67. package/dist/cjs/tailwind-plugin.js +280 -320
  68. package/dist/cjs/types.js +46 -72
  69. package/dist/cjs/utilities.js +163 -324
  70. package/dist/cjs/variantProps.js +12 -52
  71. package/dist/esm/NiceDesktopIconExporter.js +671 -598
  72. package/dist/esm/NiceFaviconGenerator.js +583 -416
  73. package/dist/esm/NiceIconPicker.js +789 -507
  74. package/dist/esm/NiceIconPreview.js +247 -187
  75. package/dist/esm/NiceIconSetCreator.js +685 -551
  76. package/dist/esm/NiceIconStacker.js +549 -170
  77. package/dist/esm/NiceIconValue.js +29 -34
  78. package/dist/esm/NtdIconBadge.js +388 -359
  79. package/dist/esm/NtdIconMorph.js +423 -353
  80. package/dist/esm/NtdStateMorph.js +152 -146
  81. package/dist/esm/advancedIconSearch.js +391 -509
  82. package/dist/esm/animationControls.js +527 -641
  83. package/dist/esm/client.js +48 -10
  84. package/dist/esm/createIcon.js +350 -250
  85. package/dist/esm/design-tokens.js +334 -387
  86. package/dist/esm/figmaExport.js +170 -256
  87. package/dist/esm/figmaSync.js +237 -315
  88. package/dist/esm/headless-ui.js +254 -365
  89. package/dist/esm/iconAnalytics.js +342 -392
  90. package/dist/esm/iconHtml.js +67 -85
  91. package/dist/esm/iconMetadata.js +404 -471
  92. package/dist/esm/iconParts.js +125 -89
  93. package/dist/esm/iconStack.js +145 -154
  94. package/dist/esm/iconStyles.js +1620 -503
  95. package/dist/esm/iconValue.js +361 -429
  96. package/dist/esm/icons/accessibility.js +1133 -133
  97. package/dist/esm/icons/actions.js +1320 -329
  98. package/dist/esm/icons/ai.js +1441 -143
  99. package/dist/esm/icons/brand.js +1351 -171
  100. package/dist/esm/icons/business.js +931 -201
  101. package/dist/esm/icons/devtech.js +1687 -226
  102. package/dist/esm/icons/ecommerce.js +816 -110
  103. package/dist/esm/icons/education.js +1364 -198
  104. package/dist/esm/icons/files.js +1628 -327
  105. package/dist/esm/icons/fintech.js +807 -103
  106. package/dist/esm/icons/food.js +1524 -152
  107. package/dist/esm/icons/fun.js +801 -108
  108. package/dist/esm/icons/gaming.js +933 -169
  109. package/dist/esm/icons/health.js +636 -111
  110. package/dist/esm/icons/index.js +596 -32
  111. package/dist/esm/icons/input.js +326 -82
  112. package/dist/esm/icons/legal.js +1079 -121
  113. package/dist/esm/icons/media.js +1086 -266
  114. package/dist/esm/icons/navigation.js +401 -121
  115. package/dist/esm/icons/omniverk.js +759 -89
  116. package/dist/esm/icons/realestate.js +1544 -198
  117. package/dist/esm/icons/saas.js +880 -97
  118. package/dist/esm/icons/science.js +1477 -208
  119. package/dist/esm/icons/shapes.js +1343 -307
  120. package/dist/esm/icons/smarthome.js +799 -89
  121. package/dist/esm/icons/social.js +599 -58
  122. package/dist/esm/icons/sports.js +1240 -132
  123. package/dist/esm/icons/sustainability.js +1226 -138
  124. package/dist/esm/icons/travel.js +1486 -147
  125. package/dist/esm/icons/ui.js +1540 -314
  126. package/dist/esm/icons/weather.js +1181 -172
  127. package/dist/esm/index.js +756 -58
  128. package/dist/esm/lottieIntegration.js +264 -265
  129. package/dist/esm/nicetodev-icons.css +1 -1
  130. package/dist/esm/particleEffects.js +271 -250
  131. package/dist/esm/resolver.js +231 -283
  132. package/dist/esm/rsc.js +182 -192
  133. package/dist/esm/sharpen.js +78 -129
  134. package/dist/esm/smilAnimations.js +376 -164
  135. package/dist/esm/stacking.js +99 -121
  136. package/dist/esm/tailwind-plugin.js +282 -319
  137. package/dist/esm/types.js +50 -71
  138. package/dist/esm/utilities.js +177 -321
  139. package/dist/esm/variantProps.js +23 -52
  140. package/package.json +15 -22
@@ -1,338 +1,260 @@
1
- /**
2
- * @file figmaSync.ts
3
- * @description Bidirectional sync between Figma design files and the codebase.
4
- *
5
- * - Sync changes from Figma → codebase (import new/updated icons)
6
- * - Push code changes → Figma (export updated icons to Figma)
7
- * - Version tracking (track which version of icon is in Figma vs code)
8
- * - Conflict detection (detect when both sides changed)
9
- *
10
- * This module provides the data structures and logic for syncing.
11
- * The actual Figma API calls are delegated to callbacks so this
12
- * module can work with any Figma plugin or REST API implementation.
13
- *
14
- * @example
15
- * ```tsx
16
- * const manager = createFigmaSyncManager({
17
- * fetchFromFigma: async () => figmaIcons,
18
- * pushToFigma: async (icons) => { ... },
19
- * getLocalIcons: () => localIcons,
20
- * onConflict: (diff) => 'prefer-local',
21
- * });
22
- *
23
- * // Pull changes from Figma
24
- * const result = await manager.pull();
25
- *
26
- * // Push changes to Figma
27
- * const pushResult = await manager.push();
28
- *
29
- * // Full bidirectional sync
30
- * const syncResult = await manager.sync();
31
- * ```
32
- */
33
- /* ────────────────────────────────────────────────────────────────────────────
34
- HASH UTILITY
35
- ───────────────────────────────────────────────────────────────────────────── */
36
- /**
37
- * Simple content hash for change detection.
38
- * Uses a deterministic djb2-like hash for speed (no crypto needed).
39
- */
40
1
  function hashContent(content) {
41
- let hash = 5381;
42
- for (let i = 0; i < content.length; i++) {
43
- hash = ((hash << 5) + hash + content.charCodeAt(i)) & 0xffffffff;
44
- }
45
- return (hash >>> 0).toString(36);
2
+ let hash = 5381;
3
+ for (let i = 0; i < content.length; i++) {
4
+ hash = (hash << 5) + hash + content.charCodeAt(i) & 4294967295;
5
+ }
6
+ return (hash >>> 0).toString(36);
46
7
  }
47
- /** Generate a hash for an icon's content. */
48
8
  function hashIcon(icon) {
49
- var _a;
50
- return hashContent(icon.svgPaths.join('|') + icon.viewBox + ((_a = icon.variant) !== null && _a !== void 0 ? _a : ''));
9
+ return hashContent(icon.svgPaths.join("|") + icon.viewBox + (icon.variant ?? ""));
51
10
  }
52
- /* ────────────────────────────────────────────────────────────────────────────
53
- DIFF ENGINE
54
- ───────────────────────────────────────────────────────────────────────────── */
55
- /**
56
- * Computes a diff between two sets of tracked icons.
57
- *
58
- * @param localIcons - Icons in the codebase
59
- * @param figmaIcons - Icons in Figma
60
- * @param syncState - Previously synced hashes (for conflict detection)
61
- * @returns Array of diffs
62
- */
63
11
  function diffIconSets(localIcons, figmaIcons, syncState) {
64
- const diffs = [];
65
- const localMap = new Map(localIcons.map((i) => [i.name, i]));
66
- const figmaMap = new Map(figmaIcons.map((i) => [i.name, i]));
67
- const allNames = new Set([...localMap.keys(), ...figmaMap.keys()]);
68
- for (const name of allNames) {
69
- const local = localMap.get(name);
70
- const figma = figmaMap.get(name);
71
- const lastHash = syncState === null || syncState === void 0 ? void 0 : syncState.get(name);
72
- if (local && figma) {
73
- const localHash = hashIcon(local);
74
- const figmaHash = hashIcon(figma);
75
- if (localHash === figmaHash) {
76
- diffs.push({
77
- name,
78
- status: 'unchanged',
79
- direction: 'none',
80
- local,
81
- figma,
82
- lastSyncedHash: lastHash,
83
- });
84
- }
85
- else if (lastHash) {
86
- // Both sides changed since last sync
87
- const localChanged = localHash !== lastHash;
88
- const figmaChanged = figmaHash !== lastHash;
89
- if (localChanged && figmaChanged) {
90
- diffs.push({
91
- name,
92
- status: 'conflict',
93
- direction: 'both',
94
- local,
95
- figma,
96
- lastSyncedHash: lastHash,
97
- });
98
- }
99
- else if (localChanged) {
100
- diffs.push({
101
- name,
102
- status: 'modified',
103
- direction: 'code-to-figma',
104
- local,
105
- figma,
106
- lastSyncedHash: lastHash,
107
- });
108
- }
109
- else {
110
- diffs.push({
111
- name,
112
- status: 'modified',
113
- direction: 'figma-to-code',
114
- local,
115
- figma,
116
- lastSyncedHash: lastHash,
117
- });
118
- }
119
- }
120
- else {
121
- // No previous sync state — treat as conflict if different
122
- diffs.push({ name, status: 'conflict', direction: 'both', local, figma });
123
- }
124
- }
125
- else if (figma && !local) {
126
- diffs.push({ name, status: 'added', direction: 'figma-to-code', figma });
127
- }
128
- else if (local && !figma) {
129
- diffs.push({ name, status: 'added', direction: 'code-to-figma', local });
12
+ const diffs = [];
13
+ const localMap = new Map(localIcons.map((i) => [i.name, i]));
14
+ const figmaMap = new Map(figmaIcons.map((i) => [i.name, i]));
15
+ const allNames = /* @__PURE__ */ new Set([...localMap.keys(), ...figmaMap.keys()]);
16
+ for (const name of allNames) {
17
+ const local = localMap.get(name);
18
+ const figma = figmaMap.get(name);
19
+ const lastHash = syncState?.get(name);
20
+ if (local && figma) {
21
+ const localHash = hashIcon(local);
22
+ const figmaHash = hashIcon(figma);
23
+ if (localHash === figmaHash) {
24
+ diffs.push({
25
+ name,
26
+ status: "unchanged",
27
+ direction: "none",
28
+ local,
29
+ figma,
30
+ lastSyncedHash: lastHash
31
+ });
32
+ } else if (lastHash) {
33
+ const localChanged = localHash !== lastHash;
34
+ const figmaChanged = figmaHash !== lastHash;
35
+ if (localChanged && figmaChanged) {
36
+ diffs.push({
37
+ name,
38
+ status: "conflict",
39
+ direction: "both",
40
+ local,
41
+ figma,
42
+ lastSyncedHash: lastHash
43
+ });
44
+ } else if (localChanged) {
45
+ diffs.push({
46
+ name,
47
+ status: "modified",
48
+ direction: "code-to-figma",
49
+ local,
50
+ figma,
51
+ lastSyncedHash: lastHash
52
+ });
53
+ } else {
54
+ diffs.push({
55
+ name,
56
+ status: "modified",
57
+ direction: "figma-to-code",
58
+ local,
59
+ figma,
60
+ lastSyncedHash: lastHash
61
+ });
130
62
  }
63
+ } else {
64
+ diffs.push({ name, status: "conflict", direction: "both", local, figma });
65
+ }
66
+ } else if (figma && !local) {
67
+ diffs.push({ name, status: "added", direction: "figma-to-code", figma });
68
+ } else if (local && !figma) {
69
+ diffs.push({ name, status: "added", direction: "code-to-figma", local });
131
70
  }
132
- return diffs;
71
+ }
72
+ return diffs;
133
73
  }
134
- /* ────────────────────────────────────────────────────────────────────────────
135
- SYNC MANAGER
136
- ───────────────────────────────────────────────────────────────────────────── */
137
- const STORAGE_KEY = 'ntd-figma-sync-state';
138
- /**
139
- * Creates a FigmaSyncManager for bidirectional icon synchronization.
140
- */
74
+ const STORAGE_KEY = "ntd-figma-sync-state";
141
75
  function createFigmaSyncManager(config) {
142
- return new FigmaSyncManager(config);
76
+ return new FigmaSyncManager(config);
143
77
  }
144
78
  class FigmaSyncManager {
145
- constructor(config) {
146
- this.config = config;
147
- this.syncState = this.loadSyncState();
148
- }
149
- /** Pull changes from Figma → codebase. */
150
- async pull() {
151
- var _a, _b, _c;
152
- const start = performance.now();
153
- const figmaIcons = await this.config.fetchFromFigma();
154
- const localIcons = this.config.getLocalIcons();
155
- const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
156
- const pulled = [];
157
- const conflicts = [];
158
- const skipped = [];
159
- for (const diff of diffs) {
160
- if (diff.status === 'unchanged') {
161
- continue;
162
- }
163
- if (diff.status === 'conflict') {
164
- const resolution = (_c = (_b = (_a = this.config).onConflict) === null || _b === void 0 ? void 0 : _b.call(_a, diff)) !== null && _c !== void 0 ? _c : 'skip';
165
- if (resolution === 'prefer-figma') {
166
- pulled.push(diff);
167
- this.updateSyncHash(diff.name, diff.figma);
168
- }
169
- else if (resolution === 'skip') {
170
- skipped.push(diff);
171
- }
172
- else {
173
- // prefer-local — no pull needed
174
- skipped.push(diff);
175
- }
176
- conflicts.push(diff);
177
- }
178
- else if (diff.direction === 'figma-to-code') {
179
- pulled.push(diff);
180
- if (diff.figma) {
181
- this.updateSyncHash(diff.name, diff.figma);
182
- }
183
- }
79
+ constructor(config) {
80
+ this.config = config;
81
+ this.syncState = this.loadSyncState();
82
+ }
83
+ /** Pull changes from Figma → codebase. */
84
+ async pull() {
85
+ const start = performance.now();
86
+ const figmaIcons = await this.config.fetchFromFigma();
87
+ const localIcons = this.config.getLocalIcons();
88
+ const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
89
+ const pulled = [];
90
+ const conflicts = [];
91
+ const skipped = [];
92
+ for (const diff of diffs) {
93
+ if (diff.status === "unchanged") {
94
+ continue;
95
+ }
96
+ if (diff.status === "conflict") {
97
+ const resolution = this.config.onConflict?.(diff) ?? "skip";
98
+ if (resolution === "prefer-figma") {
99
+ pulled.push(diff);
100
+ this.updateSyncHash(diff.name, diff.figma);
101
+ } else if (resolution === "skip") {
102
+ skipped.push(diff);
103
+ } else {
104
+ skipped.push(diff);
184
105
  }
185
- this.saveSyncState();
186
- return {
187
- pulled,
188
- pushed: [],
189
- conflicts,
190
- skipped,
191
- duration: performance.now() - start,
192
- timestamp: Date.now(),
193
- };
194
- }
195
- /** Push changes from codebase → Figma. */
196
- async push() {
197
- var _a, _b, _c;
198
- const start = performance.now();
199
- const figmaIcons = await this.config.fetchFromFigma();
200
- const localIcons = this.config.getLocalIcons();
201
- const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
202
- const pushed = [];
203
- const conflicts = [];
204
- const skipped = [];
205
- const toPush = [];
206
- for (const diff of diffs) {
207
- if (diff.status === 'unchanged') {
208
- continue;
209
- }
210
- if (diff.status === 'conflict') {
211
- const resolution = (_c = (_b = (_a = this.config).onConflict) === null || _b === void 0 ? void 0 : _b.call(_a, diff)) !== null && _c !== void 0 ? _c : 'skip';
212
- if (resolution === 'prefer-local') {
213
- toPush.push(diff.local);
214
- pushed.push(diff);
215
- this.updateSyncHash(diff.name, diff.local);
216
- }
217
- else if (resolution === 'skip') {
218
- skipped.push(diff);
219
- }
220
- conflicts.push(diff);
221
- }
222
- else if (diff.direction === 'code-to-figma' && diff.local) {
223
- toPush.push(diff.local);
224
- pushed.push(diff);
225
- this.updateSyncHash(diff.name, diff.local);
226
- }
227
- }
228
- if (toPush.length > 0) {
229
- await this.config.pushToFigma(toPush);
106
+ conflicts.push(diff);
107
+ } else if (diff.direction === "figma-to-code") {
108
+ pulled.push(diff);
109
+ if (diff.figma) {
110
+ this.updateSyncHash(diff.name, diff.figma);
230
111
  }
231
- this.saveSyncState();
232
- return {
233
- pulled: [],
234
- pushed,
235
- conflicts,
236
- skipped,
237
- duration: performance.now() - start,
238
- timestamp: Date.now(),
239
- };
112
+ }
240
113
  }
241
- /** Full bidirectional sync. */
242
- async sync() {
243
- var _a, _b, _c;
244
- const start = performance.now();
245
- const figmaIcons = await this.config.fetchFromFigma();
246
- const localIcons = this.config.getLocalIcons();
247
- const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
248
- const pulled = [];
249
- const pushed = [];
250
- const conflicts = [];
251
- const skipped = [];
252
- const toPush = [];
253
- for (const diff of diffs) {
254
- if (diff.status === 'unchanged') {
255
- continue;
256
- }
257
- if (diff.status === 'conflict') {
258
- const resolution = (_c = (_b = (_a = this.config).onConflict) === null || _b === void 0 ? void 0 : _b.call(_a, diff)) !== null && _c !== void 0 ? _c : 'skip';
259
- conflicts.push(diff);
260
- if (resolution === 'prefer-local' && diff.local) {
261
- toPush.push(diff.local);
262
- pushed.push(diff);
263
- this.updateSyncHash(diff.name, diff.local);
264
- }
265
- else if (resolution === 'prefer-figma' && diff.figma) {
266
- pulled.push(diff);
267
- this.updateSyncHash(diff.name, diff.figma);
268
- }
269
- else {
270
- skipped.push(diff);
271
- }
272
- }
273
- else if (diff.direction === 'figma-to-code') {
274
- pulled.push(diff);
275
- if (diff.figma) {
276
- this.updateSyncHash(diff.name, diff.figma);
277
- }
278
- }
279
- else if (diff.direction === 'code-to-figma' && diff.local) {
280
- toPush.push(diff.local);
281
- pushed.push(diff);
282
- this.updateSyncHash(diff.name, diff.local);
283
- }
284
- }
285
- if (toPush.length > 0) {
286
- await this.config.pushToFigma(toPush);
114
+ this.saveSyncState();
115
+ return {
116
+ pulled,
117
+ pushed: [],
118
+ conflicts,
119
+ skipped,
120
+ duration: performance.now() - start,
121
+ timestamp: Date.now()
122
+ };
123
+ }
124
+ /** Push changes from codebase → Figma. */
125
+ async push() {
126
+ const start = performance.now();
127
+ const figmaIcons = await this.config.fetchFromFigma();
128
+ const localIcons = this.config.getLocalIcons();
129
+ const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
130
+ const pushed = [];
131
+ const conflicts = [];
132
+ const skipped = [];
133
+ const toPush = [];
134
+ for (const diff of diffs) {
135
+ if (diff.status === "unchanged") {
136
+ continue;
137
+ }
138
+ if (diff.status === "conflict") {
139
+ const resolution = this.config.onConflict?.(diff) ?? "skip";
140
+ if (resolution === "prefer-local") {
141
+ toPush.push(diff.local);
142
+ pushed.push(diff);
143
+ this.updateSyncHash(diff.name, diff.local);
144
+ } else if (resolution === "skip") {
145
+ skipped.push(diff);
287
146
  }
288
- this.saveSyncState();
289
- return {
290
- pulled,
291
- pushed,
292
- conflicts,
293
- skipped,
294
- duration: performance.now() - start,
295
- timestamp: Date.now(),
296
- };
147
+ conflicts.push(diff);
148
+ } else if (diff.direction === "code-to-figma" && diff.local) {
149
+ toPush.push(diff.local);
150
+ pushed.push(diff);
151
+ this.updateSyncHash(diff.name, diff.local);
152
+ }
297
153
  }
298
- /** Get current diff without making changes. */
299
- async diff() {
300
- const figmaIcons = await this.config.fetchFromFigma();
301
- const localIcons = this.config.getLocalIcons();
302
- return diffIconSets(localIcons, figmaIcons, this.syncState);
154
+ if (toPush.length > 0) {
155
+ await this.config.pushToFigma(toPush);
303
156
  }
304
- /** Get sync history from storage. */
305
- getSyncState() {
306
- return new Map(this.syncState);
157
+ this.saveSyncState();
158
+ return {
159
+ pulled: [],
160
+ pushed,
161
+ conflicts,
162
+ skipped,
163
+ duration: performance.now() - start,
164
+ timestamp: Date.now()
165
+ };
166
+ }
167
+ /** Full bidirectional sync. */
168
+ async sync() {
169
+ const start = performance.now();
170
+ const figmaIcons = await this.config.fetchFromFigma();
171
+ const localIcons = this.config.getLocalIcons();
172
+ const diffs = diffIconSets(localIcons, figmaIcons, this.syncState);
173
+ const pulled = [];
174
+ const pushed = [];
175
+ const conflicts = [];
176
+ const skipped = [];
177
+ const toPush = [];
178
+ for (const diff of diffs) {
179
+ if (diff.status === "unchanged") {
180
+ continue;
181
+ }
182
+ if (diff.status === "conflict") {
183
+ const resolution = this.config.onConflict?.(diff) ?? "skip";
184
+ conflicts.push(diff);
185
+ if (resolution === "prefer-local" && diff.local) {
186
+ toPush.push(diff.local);
187
+ pushed.push(diff);
188
+ this.updateSyncHash(diff.name, diff.local);
189
+ } else if (resolution === "prefer-figma" && diff.figma) {
190
+ pulled.push(diff);
191
+ this.updateSyncHash(diff.name, diff.figma);
192
+ } else {
193
+ skipped.push(diff);
194
+ }
195
+ } else if (diff.direction === "figma-to-code") {
196
+ pulled.push(diff);
197
+ if (diff.figma) {
198
+ this.updateSyncHash(diff.name, diff.figma);
199
+ }
200
+ } else if (diff.direction === "code-to-figma" && diff.local) {
201
+ toPush.push(diff.local);
202
+ pushed.push(diff);
203
+ this.updateSyncHash(diff.name, diff.local);
204
+ }
307
205
  }
308
- /** Reset sync state (forces full re-sync on next operation). */
309
- resetSyncState() {
310
- this.syncState.clear();
311
- this.saveSyncState();
206
+ if (toPush.length > 0) {
207
+ await this.config.pushToFigma(toPush);
312
208
  }
313
- // ── Private helpers ──
314
- updateSyncHash(name, icon) {
315
- this.syncState.set(name, hashIcon(icon));
209
+ this.saveSyncState();
210
+ return {
211
+ pulled,
212
+ pushed,
213
+ conflicts,
214
+ skipped,
215
+ duration: performance.now() - start,
216
+ timestamp: Date.now()
217
+ };
218
+ }
219
+ /** Get current diff without making changes. */
220
+ async diff() {
221
+ const figmaIcons = await this.config.fetchFromFigma();
222
+ const localIcons = this.config.getLocalIcons();
223
+ return diffIconSets(localIcons, figmaIcons, this.syncState);
224
+ }
225
+ /** Get sync history from storage. */
226
+ getSyncState() {
227
+ return new Map(this.syncState);
228
+ }
229
+ /** Reset sync state (forces full re-sync on next operation). */
230
+ resetSyncState() {
231
+ this.syncState.clear();
232
+ this.saveSyncState();
233
+ }
234
+ // ── Private helpers ──
235
+ updateSyncHash(name, icon) {
236
+ this.syncState.set(name, hashIcon(icon));
237
+ }
238
+ loadSyncState() {
239
+ const raw = this.config.storage?.get(STORAGE_KEY);
240
+ if (!raw) {
241
+ return /* @__PURE__ */ new Map();
316
242
  }
317
- loadSyncState() {
318
- var _a;
319
- const raw = (_a = this.config.storage) === null || _a === void 0 ? void 0 : _a.get(STORAGE_KEY);
320
- if (!raw) {
321
- return new Map();
322
- }
323
- try {
324
- return new Map(Object.entries(JSON.parse(raw)));
325
- }
326
- catch (_b) {
327
- return new Map();
328
- }
243
+ try {
244
+ return new Map(Object.entries(JSON.parse(raw)));
245
+ } catch {
246
+ return /* @__PURE__ */ new Map();
329
247
  }
330
- saveSyncState() {
331
- if (!this.config.storage) {
332
- return;
333
- }
334
- this.config.storage.set(STORAGE_KEY, JSON.stringify(Object.fromEntries(this.syncState)));
248
+ }
249
+ saveSyncState() {
250
+ if (!this.config.storage) {
251
+ return;
335
252
  }
253
+ this.config.storage.set(STORAGE_KEY, JSON.stringify(Object.fromEntries(this.syncState)));
254
+ }
336
255
  }
337
-
338
- export { FigmaSyncManager, createFigmaSyncManager, diffIconSets };
256
+ export {
257
+ FigmaSyncManager,
258
+ createFigmaSyncManager,
259
+ diffIconSets
260
+ };