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