@grida/refig 0.0.2 → 0.0.4
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/README.md +123 -40
- package/dist/browser.d.mts +63 -5
- package/dist/browser.mjs +1 -1
- package/dist/{chunk-YI7PIULZ.mjs → chunk-INJ5F2RK.mjs} +521 -42
- package/dist/cli.mjs +2580 -31
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -1
- package/package.json +2 -1
|
@@ -6784,6 +6784,43 @@ var b4 = function(d, b) {
|
|
|
6784
6784
|
var b8 = function(d, b) {
|
|
6785
6785
|
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
6786
6786
|
};
|
|
6787
|
+
var Inflate = /* @__PURE__ */ (function() {
|
|
6788
|
+
function Inflate2(opts, cb) {
|
|
6789
|
+
if (typeof opts == "function")
|
|
6790
|
+
cb = opts, opts = {};
|
|
6791
|
+
this.ondata = cb;
|
|
6792
|
+
var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);
|
|
6793
|
+
this.s = { i: 0, b: dict ? dict.length : 0 };
|
|
6794
|
+
this.o = new u8(32768);
|
|
6795
|
+
this.p = new u8(0);
|
|
6796
|
+
if (dict)
|
|
6797
|
+
this.o.set(dict);
|
|
6798
|
+
}
|
|
6799
|
+
Inflate2.prototype.e = function(c) {
|
|
6800
|
+
if (!this.ondata)
|
|
6801
|
+
err(5);
|
|
6802
|
+
if (this.d)
|
|
6803
|
+
err(4);
|
|
6804
|
+
if (!this.p.length)
|
|
6805
|
+
this.p = c;
|
|
6806
|
+
else if (c.length) {
|
|
6807
|
+
var n = new u8(this.p.length + c.length);
|
|
6808
|
+
n.set(this.p), n.set(c, this.p.length), this.p = n;
|
|
6809
|
+
}
|
|
6810
|
+
};
|
|
6811
|
+
Inflate2.prototype.c = function(final) {
|
|
6812
|
+
this.s.i = +(this.d = final || false);
|
|
6813
|
+
var bts = this.s.b;
|
|
6814
|
+
var dt = inflt(this.p, this.s, this.o);
|
|
6815
|
+
this.ondata(slc(dt, bts, this.s.b), this.d);
|
|
6816
|
+
this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;
|
|
6817
|
+
this.p = slc(this.p, this.s.p / 8 | 0), this.s.p &= 7;
|
|
6818
|
+
};
|
|
6819
|
+
Inflate2.prototype.push = function(chunk, final) {
|
|
6820
|
+
this.e(chunk), this.c(final);
|
|
6821
|
+
};
|
|
6822
|
+
return Inflate2;
|
|
6823
|
+
})();
|
|
6787
6824
|
function inflateSync(data, opts) {
|
|
6788
6825
|
return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
|
|
6789
6826
|
}
|
|
@@ -6838,6 +6875,165 @@ var z64e = function(d, b) {
|
|
|
6838
6875
|
;
|
|
6839
6876
|
return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];
|
|
6840
6877
|
};
|
|
6878
|
+
var UnzipPassThrough = /* @__PURE__ */ (function() {
|
|
6879
|
+
function UnzipPassThrough2() {
|
|
6880
|
+
}
|
|
6881
|
+
UnzipPassThrough2.prototype.push = function(data, final) {
|
|
6882
|
+
this.ondata(null, data, final);
|
|
6883
|
+
};
|
|
6884
|
+
UnzipPassThrough2.compression = 0;
|
|
6885
|
+
return UnzipPassThrough2;
|
|
6886
|
+
})();
|
|
6887
|
+
var UnzipInflate = /* @__PURE__ */ (function() {
|
|
6888
|
+
function UnzipInflate2() {
|
|
6889
|
+
var _this = this;
|
|
6890
|
+
this.i = new Inflate(function(dat, final) {
|
|
6891
|
+
_this.ondata(null, dat, final);
|
|
6892
|
+
});
|
|
6893
|
+
}
|
|
6894
|
+
UnzipInflate2.prototype.push = function(data, final) {
|
|
6895
|
+
try {
|
|
6896
|
+
this.i.push(data, final);
|
|
6897
|
+
} catch (e) {
|
|
6898
|
+
this.ondata(e, null, final);
|
|
6899
|
+
}
|
|
6900
|
+
};
|
|
6901
|
+
UnzipInflate2.compression = 8;
|
|
6902
|
+
return UnzipInflate2;
|
|
6903
|
+
})();
|
|
6904
|
+
var Unzip = /* @__PURE__ */ (function() {
|
|
6905
|
+
function Unzip2(cb) {
|
|
6906
|
+
this.onfile = cb;
|
|
6907
|
+
this.k = [];
|
|
6908
|
+
this.o = {
|
|
6909
|
+
0: UnzipPassThrough
|
|
6910
|
+
};
|
|
6911
|
+
this.p = et;
|
|
6912
|
+
}
|
|
6913
|
+
Unzip2.prototype.push = function(chunk, final) {
|
|
6914
|
+
var _this = this;
|
|
6915
|
+
if (!this.onfile)
|
|
6916
|
+
err(5);
|
|
6917
|
+
if (!this.p)
|
|
6918
|
+
err(4);
|
|
6919
|
+
if (this.c > 0) {
|
|
6920
|
+
var len = Math.min(this.c, chunk.length);
|
|
6921
|
+
var toAdd = chunk.subarray(0, len);
|
|
6922
|
+
this.c -= len;
|
|
6923
|
+
if (this.d)
|
|
6924
|
+
this.d.push(toAdd, !this.c);
|
|
6925
|
+
else
|
|
6926
|
+
this.k[0].push(toAdd);
|
|
6927
|
+
chunk = chunk.subarray(len);
|
|
6928
|
+
if (chunk.length)
|
|
6929
|
+
return this.push(chunk, final);
|
|
6930
|
+
} else {
|
|
6931
|
+
var f = 0, i = 0, is = void 0, buf = void 0;
|
|
6932
|
+
if (!this.p.length)
|
|
6933
|
+
buf = chunk;
|
|
6934
|
+
else if (!chunk.length)
|
|
6935
|
+
buf = this.p;
|
|
6936
|
+
else {
|
|
6937
|
+
buf = new u8(this.p.length + chunk.length);
|
|
6938
|
+
buf.set(this.p), buf.set(chunk, this.p.length);
|
|
6939
|
+
}
|
|
6940
|
+
var l = buf.length, oc = this.c, add = oc && this.d;
|
|
6941
|
+
var _loop_2 = function() {
|
|
6942
|
+
var _a2;
|
|
6943
|
+
var sig = b4(buf, i);
|
|
6944
|
+
if (sig == 67324752) {
|
|
6945
|
+
f = 1, is = i;
|
|
6946
|
+
this_1.d = null;
|
|
6947
|
+
this_1.c = 0;
|
|
6948
|
+
var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);
|
|
6949
|
+
if (l > i + 30 + fnl + es) {
|
|
6950
|
+
var chks_3 = [];
|
|
6951
|
+
this_1.k.unshift(chks_3);
|
|
6952
|
+
f = 2;
|
|
6953
|
+
var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);
|
|
6954
|
+
var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);
|
|
6955
|
+
if (sc_1 == 4294967295) {
|
|
6956
|
+
_a2 = dd ? [-2] : z64e(buf, i), sc_1 = _a2[0], su_1 = _a2[1];
|
|
6957
|
+
} else if (dd)
|
|
6958
|
+
sc_1 = -1;
|
|
6959
|
+
i += es;
|
|
6960
|
+
this_1.c = sc_1;
|
|
6961
|
+
var d_1;
|
|
6962
|
+
var file_1 = {
|
|
6963
|
+
name: fn_1,
|
|
6964
|
+
compression: cmp_1,
|
|
6965
|
+
start: function() {
|
|
6966
|
+
if (!file_1.ondata)
|
|
6967
|
+
err(5);
|
|
6968
|
+
if (!sc_1)
|
|
6969
|
+
file_1.ondata(null, et, true);
|
|
6970
|
+
else {
|
|
6971
|
+
var ctr = _this.o[cmp_1];
|
|
6972
|
+
if (!ctr)
|
|
6973
|
+
file_1.ondata(err(14, "unknown compression type " + cmp_1, 1), null, false);
|
|
6974
|
+
d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);
|
|
6975
|
+
d_1.ondata = function(err3, dat3, final2) {
|
|
6976
|
+
file_1.ondata(err3, dat3, final2);
|
|
6977
|
+
};
|
|
6978
|
+
for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {
|
|
6979
|
+
var dat2 = chks_4[_i];
|
|
6980
|
+
d_1.push(dat2, false);
|
|
6981
|
+
}
|
|
6982
|
+
if (_this.k[0] == chks_3 && _this.c)
|
|
6983
|
+
_this.d = d_1;
|
|
6984
|
+
else
|
|
6985
|
+
d_1.push(et, true);
|
|
6986
|
+
}
|
|
6987
|
+
},
|
|
6988
|
+
terminate: function() {
|
|
6989
|
+
if (d_1 && d_1.terminate)
|
|
6990
|
+
d_1.terminate();
|
|
6991
|
+
}
|
|
6992
|
+
};
|
|
6993
|
+
if (sc_1 >= 0)
|
|
6994
|
+
file_1.size = sc_1, file_1.originalSize = su_1;
|
|
6995
|
+
this_1.onfile(file_1);
|
|
6996
|
+
}
|
|
6997
|
+
return "break";
|
|
6998
|
+
} else if (oc) {
|
|
6999
|
+
if (sig == 134695760) {
|
|
7000
|
+
is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;
|
|
7001
|
+
return "break";
|
|
7002
|
+
} else if (sig == 33639248) {
|
|
7003
|
+
is = i -= 4, f = 3, this_1.c = 0;
|
|
7004
|
+
return "break";
|
|
7005
|
+
}
|
|
7006
|
+
}
|
|
7007
|
+
};
|
|
7008
|
+
var this_1 = this;
|
|
7009
|
+
for (; i < l - 4; ++i) {
|
|
7010
|
+
var state_1 = _loop_2();
|
|
7011
|
+
if (state_1 === "break")
|
|
7012
|
+
break;
|
|
7013
|
+
}
|
|
7014
|
+
this.p = et;
|
|
7015
|
+
if (oc < 0) {
|
|
7016
|
+
var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 134695760 && 4)) : buf.subarray(0, i);
|
|
7017
|
+
if (add)
|
|
7018
|
+
add.push(dat, !!f);
|
|
7019
|
+
else
|
|
7020
|
+
this.k[+(f == 2)].push(dat);
|
|
7021
|
+
}
|
|
7022
|
+
if (f & 2)
|
|
7023
|
+
return this.push(buf.subarray(i), final);
|
|
7024
|
+
this.p = buf.subarray(i);
|
|
7025
|
+
}
|
|
7026
|
+
if (final) {
|
|
7027
|
+
if (this.c)
|
|
7028
|
+
err(13);
|
|
7029
|
+
this.p = null;
|
|
7030
|
+
}
|
|
7031
|
+
};
|
|
7032
|
+
Unzip2.prototype.register = function(decoder) {
|
|
7033
|
+
this.o[decoder.compression] = decoder;
|
|
7034
|
+
};
|
|
7035
|
+
return Unzip2;
|
|
7036
|
+
})();
|
|
6841
7037
|
function unzipSync(data, opts) {
|
|
6842
7038
|
var files = {};
|
|
6843
7039
|
var e = data.length - 22;
|
|
@@ -13285,6 +13481,93 @@ function readFigFile(data) {
|
|
|
13285
13481
|
}
|
|
13286
13482
|
return { ...parseFigData(archiveData), zip_files: zipFiles };
|
|
13287
13483
|
}
|
|
13484
|
+
async function readFigFileFromStream(stream) {
|
|
13485
|
+
const zipFiles = {};
|
|
13486
|
+
const unzip = new Unzip((file) => {
|
|
13487
|
+
const fileChunks = [];
|
|
13488
|
+
file.ondata = (err3, data, final) => {
|
|
13489
|
+
if (err3) throw err3;
|
|
13490
|
+
if (data && data.length > 0) fileChunks.push(data);
|
|
13491
|
+
if (final) {
|
|
13492
|
+
const size = fileChunks.reduce((s, c) => s + c.length, 0);
|
|
13493
|
+
const result = new Uint8Array(size);
|
|
13494
|
+
let off = 0;
|
|
13495
|
+
for (const c of fileChunks) {
|
|
13496
|
+
result.set(c, off);
|
|
13497
|
+
off += c.length;
|
|
13498
|
+
}
|
|
13499
|
+
zipFiles[file.name] = result;
|
|
13500
|
+
}
|
|
13501
|
+
};
|
|
13502
|
+
file.start();
|
|
13503
|
+
});
|
|
13504
|
+
unzip.register(UnzipPassThrough);
|
|
13505
|
+
unzip.register(UnzipInflate);
|
|
13506
|
+
const buffer = [];
|
|
13507
|
+
let haveCheckedSignature = false;
|
|
13508
|
+
for await (const chunk of stream) {
|
|
13509
|
+
if (haveCheckedSignature) {
|
|
13510
|
+
unzip.push(chunk);
|
|
13511
|
+
continue;
|
|
13512
|
+
}
|
|
13513
|
+
buffer.push(chunk);
|
|
13514
|
+
const total = buffer.reduce((s, c) => s + c.length, 0);
|
|
13515
|
+
if (total < 4) continue;
|
|
13516
|
+
haveCheckedSignature = true;
|
|
13517
|
+
const merged = new Uint8Array(total);
|
|
13518
|
+
let off = 0;
|
|
13519
|
+
for (const c of buffer) {
|
|
13520
|
+
merged.set(c, off);
|
|
13521
|
+
off += c.length;
|
|
13522
|
+
}
|
|
13523
|
+
if (!isSignature(merged, ZIP_SIGNATURE)) {
|
|
13524
|
+
for await (const c of stream) buffer.push(c);
|
|
13525
|
+
const fullSize = buffer.reduce((s, c) => s + c.length, 0);
|
|
13526
|
+
const full = new Uint8Array(fullSize);
|
|
13527
|
+
off = 0;
|
|
13528
|
+
for (const c of buffer) {
|
|
13529
|
+
full.set(c, off);
|
|
13530
|
+
off += c.length;
|
|
13531
|
+
}
|
|
13532
|
+
return { ...parseFigData(full), zip_files: void 0 };
|
|
13533
|
+
}
|
|
13534
|
+
unzip.push(merged);
|
|
13535
|
+
}
|
|
13536
|
+
if (!haveCheckedSignature) {
|
|
13537
|
+
if (buffer.length === 0) {
|
|
13538
|
+
throw new Error("readFigFileFromStream: empty stream");
|
|
13539
|
+
}
|
|
13540
|
+
const total = buffer.reduce((s, c) => s + c.length, 0);
|
|
13541
|
+
if (total < 4) {
|
|
13542
|
+
throw new Error("readFigFileFromStream: stream too short to detect format");
|
|
13543
|
+
}
|
|
13544
|
+
const merged = new Uint8Array(total);
|
|
13545
|
+
let off = 0;
|
|
13546
|
+
for (const c of buffer) {
|
|
13547
|
+
merged.set(c, off);
|
|
13548
|
+
off += c.length;
|
|
13549
|
+
}
|
|
13550
|
+
return { ...parseFigData(merged), zip_files: void 0 };
|
|
13551
|
+
}
|
|
13552
|
+
unzip.push(new Uint8Array(0), true);
|
|
13553
|
+
const keys = Object.keys(zipFiles);
|
|
13554
|
+
const mainFile = keys.find((key) => {
|
|
13555
|
+
const fileData = zipFiles[key];
|
|
13556
|
+
if (!fileData || fileData.length <= 8) return false;
|
|
13557
|
+
const prelude = String.fromCharCode.apply(
|
|
13558
|
+
String,
|
|
13559
|
+
Array.from(fileData.slice(0, 8))
|
|
13560
|
+
);
|
|
13561
|
+
return prelude === FIG_KIWI_PRELUDE || prelude === FIGJAM_KIWI_PRELUDE;
|
|
13562
|
+
}) || keys.find((k) => k.endsWith(".fig"));
|
|
13563
|
+
if (!mainFile) {
|
|
13564
|
+
throw new Error(
|
|
13565
|
+
`ZIP archive found but no valid Figma file inside. Files: ${keys.join(", ")}`
|
|
13566
|
+
);
|
|
13567
|
+
}
|
|
13568
|
+
const archiveData = zipFiles[mainFile];
|
|
13569
|
+
return { ...parseFigData(archiveData), zip_files: zipFiles };
|
|
13570
|
+
}
|
|
13288
13571
|
function parseFigData(data) {
|
|
13289
13572
|
const { header, files } = FigmaArchiveParser.parseArchive(data);
|
|
13290
13573
|
const [schemaFile, dataFile, preview] = files;
|
|
@@ -14098,6 +14381,8 @@ var iofigma;
|
|
|
14098
14381
|
font_size: node.style.fontSize ?? 0,
|
|
14099
14382
|
font_family: node.style.fontFamily,
|
|
14100
14383
|
font_weight: node.style.fontWeight ?? 400,
|
|
14384
|
+
font_postscript_name: node.style.fontPostScriptName || void 0,
|
|
14385
|
+
font_style_italic: node.style.italic ?? false,
|
|
14101
14386
|
font_kerning: true
|
|
14102
14387
|
};
|
|
14103
14388
|
}
|
|
@@ -14568,8 +14853,19 @@ var iofigma;
|
|
|
14568
14853
|
}
|
|
14569
14854
|
};
|
|
14570
14855
|
}
|
|
14856
|
+
function findFontMetaDataEntry(fontMetaData, fontName) {
|
|
14857
|
+
if (!fontMetaData?.length || !fontName) return void 0;
|
|
14858
|
+
const match = fontMetaData.find(
|
|
14859
|
+
(m) => m.key?.family === fontName.family && m.key?.style === fontName.style
|
|
14860
|
+
) ?? fontMetaData[0];
|
|
14861
|
+
return match;
|
|
14862
|
+
}
|
|
14571
14863
|
function kiwi_text_style_trait(nc) {
|
|
14572
14864
|
const characters = nc.textData?.characters ?? "";
|
|
14865
|
+
const fontMetaData = nc.derivedTextData?.fontMetaData ?? nc.textData?.fontMetaData;
|
|
14866
|
+
const fontMeta = findFontMetaDataEntry(fontMetaData, nc.fontName);
|
|
14867
|
+
const fontWeight = fontMeta?.fontWeight ?? 400;
|
|
14868
|
+
const italic = fontMeta?.fontStyle === "ITALIC";
|
|
14573
14869
|
return {
|
|
14574
14870
|
characters,
|
|
14575
14871
|
fills: nc.fillPaints ? paints(nc.fillPaints) : [],
|
|
@@ -14578,8 +14874,9 @@ var iofigma;
|
|
|
14578
14874
|
strokeAlign: nc.strokeAlign ? map.strokeAlign(nc.strokeAlign) : "INSIDE",
|
|
14579
14875
|
style: {
|
|
14580
14876
|
fontFamily: nc.fontName?.family ?? "Inter",
|
|
14581
|
-
fontPostScriptName: nc.fontName?.postscript,
|
|
14582
|
-
fontWeight
|
|
14877
|
+
fontPostScriptName: nc.fontName?.postscript ? nc.fontName.postscript : void 0,
|
|
14878
|
+
fontWeight,
|
|
14879
|
+
italic,
|
|
14583
14880
|
fontSize: nc.fontSize ?? 12,
|
|
14584
14881
|
textAlignHorizontal: nc.textAlignHorizontal ?? "LEFT",
|
|
14585
14882
|
textAlignVertical: nc.textAlignVertical ?? "TOP",
|
|
@@ -14605,7 +14902,8 @@ var iofigma;
|
|
|
14605
14902
|
...kiwi_layout_trait(nc),
|
|
14606
14903
|
...kiwi_geometry_trait(nc),
|
|
14607
14904
|
...kiwi_corner_trait(nc),
|
|
14608
|
-
...kiwi_effects_trait(nc)
|
|
14905
|
+
...kiwi_effects_trait(nc),
|
|
14906
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14609
14907
|
};
|
|
14610
14908
|
}
|
|
14611
14909
|
function ellipse(nc) {
|
|
@@ -14616,7 +14914,8 @@ var iofigma;
|
|
|
14616
14914
|
...kiwi_layout_trait(nc),
|
|
14617
14915
|
...kiwi_geometry_trait(nc),
|
|
14618
14916
|
...kiwi_arc_data_trait(nc),
|
|
14619
|
-
...kiwi_effects_trait(nc)
|
|
14917
|
+
...kiwi_effects_trait(nc),
|
|
14918
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14620
14919
|
};
|
|
14621
14920
|
}
|
|
14622
14921
|
function line(nc) {
|
|
@@ -14632,6 +14931,7 @@ var iofigma;
|
|
|
14632
14931
|
strokeCap: nc.strokeCap ? map.strokeCap(nc.strokeCap) : "NONE",
|
|
14633
14932
|
strokeJoin: nc.strokeJoin ? map.strokeJoin(nc.strokeJoin) : "MITER",
|
|
14634
14933
|
strokeMiterAngle: nc.miterLimit,
|
|
14934
|
+
...kiwi_has_export_settings_trait(nc),
|
|
14635
14935
|
...kiwi_effects_trait(nc)
|
|
14636
14936
|
};
|
|
14637
14937
|
}
|
|
@@ -14642,7 +14942,8 @@ var iofigma;
|
|
|
14642
14942
|
...kiwi_blend_opacity_trait(nc),
|
|
14643
14943
|
...kiwi_layout_trait(nc),
|
|
14644
14944
|
...kiwi_text_style_trait(nc),
|
|
14645
|
-
...kiwi_effects_trait(nc)
|
|
14945
|
+
...kiwi_effects_trait(nc),
|
|
14946
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14646
14947
|
};
|
|
14647
14948
|
}
|
|
14648
14949
|
function isGroupOriginatedFrame(nc) {
|
|
@@ -14667,7 +14968,8 @@ var iofigma;
|
|
|
14667
14968
|
...kiwi_children_trait(),
|
|
14668
14969
|
clipsContent: false,
|
|
14669
14970
|
fills: [],
|
|
14670
|
-
...kiwi_effects_trait(nc)
|
|
14971
|
+
...kiwi_effects_trait(nc),
|
|
14972
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14671
14973
|
};
|
|
14672
14974
|
}
|
|
14673
14975
|
return {
|
|
@@ -14719,7 +15021,8 @@ var iofigma;
|
|
|
14719
15021
|
...kiwi_corner_trait(nc),
|
|
14720
15022
|
...kiwi_frame_clip_trait(nc),
|
|
14721
15023
|
...kiwi_children_trait(),
|
|
14722
|
-
...kiwi_effects_trait(nc)
|
|
15024
|
+
...kiwi_effects_trait(nc),
|
|
15025
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14723
15026
|
};
|
|
14724
15027
|
const symbolOverrides = nc.symbolData?.symbolOverrides;
|
|
14725
15028
|
if (Array.isArray(symbolOverrides) && symbolOverrides.length > 0) {
|
|
@@ -14769,7 +15072,8 @@ var iofigma;
|
|
|
14769
15072
|
...kiwi_children_trait(),
|
|
14770
15073
|
clipsContent: false,
|
|
14771
15074
|
fills: [],
|
|
14772
|
-
...kiwi_effects_trait(nc)
|
|
15075
|
+
...kiwi_effects_trait(nc),
|
|
15076
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14773
15077
|
};
|
|
14774
15078
|
}
|
|
14775
15079
|
function windingRule(kiwi3) {
|
|
@@ -14796,6 +15100,7 @@ var iofigma;
|
|
|
14796
15100
|
...kiwi_layout_trait(nc),
|
|
14797
15101
|
...kiwi_geometry_trait(nc),
|
|
14798
15102
|
...kiwi_effects_trait(nc),
|
|
15103
|
+
...kiwi_has_export_settings_trait(nc),
|
|
14799
15104
|
cornerRadius: nc.cornerRadius ?? 0,
|
|
14800
15105
|
vectorNetwork
|
|
14801
15106
|
};
|
|
@@ -14815,7 +15120,8 @@ var iofigma;
|
|
|
14815
15120
|
path: "",
|
|
14816
15121
|
windingRule: path.windingRule ? windingRule(path.windingRule) : "NONZERO"
|
|
14817
15122
|
})),
|
|
14818
|
-
...kiwi_effects_trait(nc)
|
|
15123
|
+
...kiwi_effects_trait(nc),
|
|
15124
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14819
15125
|
};
|
|
14820
15126
|
}
|
|
14821
15127
|
function star(nc) {
|
|
@@ -14826,6 +15132,7 @@ var iofigma;
|
|
|
14826
15132
|
...kiwi_layout_trait(nc),
|
|
14827
15133
|
...kiwi_geometry_trait(nc),
|
|
14828
15134
|
...kiwi_effects_trait(nc),
|
|
15135
|
+
...kiwi_has_export_settings_trait(nc),
|
|
14829
15136
|
cornerRadius: nc.cornerRadius ?? 0,
|
|
14830
15137
|
pointCount: nc.count ?? 5,
|
|
14831
15138
|
innerRadius: nc.starInnerScale ?? 0.5
|
|
@@ -14867,7 +15174,8 @@ var iofigma;
|
|
|
14867
15174
|
booleanOperation: nc.booleanOperation ?? "UNION",
|
|
14868
15175
|
...kiwi_geometry_trait(nc),
|
|
14869
15176
|
...kiwi_children_trait(),
|
|
14870
|
-
...kiwi_effects_trait(nc)
|
|
15177
|
+
...kiwi_effects_trait(nc),
|
|
15178
|
+
...kiwi_has_export_settings_trait(nc)
|
|
14871
15179
|
};
|
|
14872
15180
|
}
|
|
14873
15181
|
function regularPolygon(nc) {
|
|
@@ -14878,6 +15186,7 @@ var iofigma;
|
|
|
14878
15186
|
...kiwi_layout_trait(nc),
|
|
14879
15187
|
...kiwi_geometry_trait(nc),
|
|
14880
15188
|
...kiwi_effects_trait(nc),
|
|
15189
|
+
...kiwi_has_export_settings_trait(nc),
|
|
14881
15190
|
cornerRadius: nc.cornerRadius ?? 0,
|
|
14882
15191
|
pointCount: nc.count ?? 3
|
|
14883
15192
|
};
|
|
@@ -15118,6 +15427,18 @@ var iofigma;
|
|
|
15118
15427
|
};
|
|
15119
15428
|
}
|
|
15120
15429
|
kiwi2.parseFile = parseFile;
|
|
15430
|
+
async function parseFileFromStream(stream, options = {}) {
|
|
15431
|
+
const figData = await readFigFileFromStream(stream);
|
|
15432
|
+
const pages = extractPages(figData, options);
|
|
15433
|
+
return {
|
|
15434
|
+
pages,
|
|
15435
|
+
metadata: {
|
|
15436
|
+
version: figData.header.version
|
|
15437
|
+
},
|
|
15438
|
+
zip_files: figData.zip_files
|
|
15439
|
+
};
|
|
15440
|
+
}
|
|
15441
|
+
kiwi2.parseFileFromStream = parseFileFromStream;
|
|
15121
15442
|
function extractImages2(zipFiles) {
|
|
15122
15443
|
return extractImages(zipFiles);
|
|
15123
15444
|
}
|
|
@@ -15841,27 +16162,174 @@ async function ensureFigmaDefaultFonts(canvas) {
|
|
|
15841
16162
|
}
|
|
15842
16163
|
|
|
15843
16164
|
// lib.ts
|
|
15844
|
-
|
|
16165
|
+
function isFigFileDocument(value) {
|
|
16166
|
+
return value != null && typeof value === "object" && "pages" in value && "metadata" in value && Array.isArray(value.pages);
|
|
16167
|
+
}
|
|
16168
|
+
var _FigmaDocument = class _FigmaDocument {
|
|
15845
16169
|
/**
|
|
15846
|
-
* @param input Raw `.fig` bytes (Uint8Array)
|
|
15847
|
-
*
|
|
16170
|
+
* @param input Raw `.fig` bytes (Uint8Array), a pre-parsed FigFileDocument
|
|
16171
|
+
* (e.g. from parseFileFromStream for large files), or REST JSON.
|
|
15848
16172
|
*
|
|
15849
16173
|
* For file-path convenience in Node, use `FigmaDocument.fromFile()` from
|
|
15850
16174
|
* the `@grida/refig` entrypoint.
|
|
15851
16175
|
*/
|
|
15852
16176
|
constructor(input) {
|
|
16177
|
+
/**
|
|
16178
|
+
* Cache of ResolvedScene per rootNodeId. REST with images is not cached.
|
|
16179
|
+
* Bounded to avoid unbounded memory growth in --export-all flows.
|
|
16180
|
+
*/
|
|
16181
|
+
this._sceneCache = /* @__PURE__ */ new Map();
|
|
15853
16182
|
if (input instanceof Uint8Array) {
|
|
15854
16183
|
this.sourceType = "fig-file";
|
|
15855
16184
|
this.payload = input;
|
|
15856
16185
|
return;
|
|
15857
16186
|
}
|
|
16187
|
+
if (isFigFileDocument(input)) {
|
|
16188
|
+
this.sourceType = "fig-file";
|
|
16189
|
+
this.payload = input;
|
|
16190
|
+
this._figFile = input;
|
|
16191
|
+
return;
|
|
16192
|
+
}
|
|
15858
16193
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
15859
|
-
throw new Error(
|
|
16194
|
+
throw new Error(
|
|
16195
|
+
"FigmaDocument: input must be a Uint8Array, FigFileDocument, or REST JSON object"
|
|
16196
|
+
);
|
|
15860
16197
|
}
|
|
15861
16198
|
this.sourceType = "rest-api-json";
|
|
15862
16199
|
this.payload = input;
|
|
15863
16200
|
}
|
|
16201
|
+
/**
|
|
16202
|
+
* Resolve document to Grida IR (scene JSON + images to register).
|
|
16203
|
+
* On-demand, cached when deterministic (no images for REST).
|
|
16204
|
+
* Cache is bounded (LRU eviction) to avoid OOM in --export-all flows.
|
|
16205
|
+
* @internal
|
|
16206
|
+
*/
|
|
16207
|
+
_resolve(rootNodeId, images) {
|
|
16208
|
+
const cacheKey = rootNodeId ?? "";
|
|
16209
|
+
if (this.sourceType === "fig-file") {
|
|
16210
|
+
const cached = this._sceneCacheGet(cacheKey);
|
|
16211
|
+
if (cached) return cached;
|
|
16212
|
+
const resolved = this._figToScene(rootNodeId);
|
|
16213
|
+
this._sceneCacheSet(cacheKey, resolved);
|
|
16214
|
+
return resolved;
|
|
16215
|
+
}
|
|
16216
|
+
if (images == null || Object.keys(images).length === 0) {
|
|
16217
|
+
const cached = this._sceneCacheGet(cacheKey);
|
|
16218
|
+
if (cached) return cached;
|
|
16219
|
+
const resolved = this._restToScene(rootNodeId);
|
|
16220
|
+
this._sceneCacheSet(cacheKey, resolved);
|
|
16221
|
+
return resolved;
|
|
16222
|
+
}
|
|
16223
|
+
return this._restToScene(rootNodeId, images);
|
|
16224
|
+
}
|
|
16225
|
+
_sceneCacheGet(key) {
|
|
16226
|
+
const v = this._sceneCache.get(key);
|
|
16227
|
+
if (v === void 0) return void 0;
|
|
16228
|
+
this._sceneCache.delete(key);
|
|
16229
|
+
this._sceneCache.set(key, v);
|
|
16230
|
+
return v;
|
|
16231
|
+
}
|
|
16232
|
+
_sceneCacheSet(key, value) {
|
|
16233
|
+
if (this._sceneCache.size >= _FigmaDocument._MAX_SCENE_CACHE) {
|
|
16234
|
+
const firstKey = this._sceneCache.keys().next().value;
|
|
16235
|
+
if (firstKey !== void 0) this._sceneCache.delete(firstKey);
|
|
16236
|
+
}
|
|
16237
|
+
this._sceneCache.set(key, value);
|
|
16238
|
+
}
|
|
16239
|
+
/** @internal */
|
|
16240
|
+
_restToScene(rootNodeId, images) {
|
|
16241
|
+
const result = restJsonToSceneJson(
|
|
16242
|
+
this.payload,
|
|
16243
|
+
rootNodeId,
|
|
16244
|
+
images
|
|
16245
|
+
);
|
|
16246
|
+
if (images && Object.keys(images).length > 0) {
|
|
16247
|
+
const imagesToRegister = {};
|
|
16248
|
+
for (const ref of result.imageRefsUsed) {
|
|
16249
|
+
if (ref in images) {
|
|
16250
|
+
imagesToRegister[ref] = images[ref];
|
|
16251
|
+
}
|
|
16252
|
+
}
|
|
16253
|
+
return {
|
|
16254
|
+
sceneJson: result.sceneJson,
|
|
16255
|
+
images: imagesToRegister,
|
|
16256
|
+
imageRefsUsed: result.imageRefsUsed
|
|
16257
|
+
};
|
|
16258
|
+
}
|
|
16259
|
+
return {
|
|
16260
|
+
sceneJson: result.sceneJson,
|
|
16261
|
+
images: {},
|
|
16262
|
+
imageRefsUsed: result.imageRefsUsed
|
|
16263
|
+
};
|
|
16264
|
+
}
|
|
16265
|
+
/** @internal */
|
|
16266
|
+
_figToScene(rootNodeId) {
|
|
16267
|
+
if (!this._figFile) {
|
|
16268
|
+
this._figFile = iofigma.kiwi.parseFile(this.payload);
|
|
16269
|
+
}
|
|
16270
|
+
return figFileToSceneJson(this._figFile, rootNodeId);
|
|
16271
|
+
}
|
|
16272
|
+
/**
|
|
16273
|
+
* Returns the list of font family names used in this document.
|
|
16274
|
+
*
|
|
16275
|
+
* The result is family names only — no weights, PostScript names, or other metadata.
|
|
16276
|
+
* That is intentional: in practice, you can load all TTF/OTF files for each family
|
|
16277
|
+
* (variable or static) and pass them to the renderer; it will resolve the correct face
|
|
16278
|
+
* per text style. We prioritize simple usage and accurate font selection over
|
|
16279
|
+
* performance or resource-optimized patterns.
|
|
16280
|
+
*
|
|
16281
|
+
* When rootNodeId is omitted, traverses all pages so fonts from every page are included.
|
|
16282
|
+
*
|
|
16283
|
+
* @param rootNodeId — Optional. When provided, scope to that node's subtree. Omit for the full document (all pages).
|
|
16284
|
+
* @returns Unique font family names (e.g. `["Inter", "Caveat", "Roboto"]`).
|
|
16285
|
+
*/
|
|
16286
|
+
listFontFamilies(rootNodeId) {
|
|
16287
|
+
if (rootNodeId != null && rootNodeId !== "") {
|
|
16288
|
+
const resolved = this._resolve(rootNodeId);
|
|
16289
|
+
return this._collectFontFamiliesFromSceneJson(resolved.sceneJson);
|
|
16290
|
+
}
|
|
16291
|
+
if (this.sourceType === "rest-api-json") {
|
|
16292
|
+
return collectFontFamiliesFromRestDocument(
|
|
16293
|
+
this.payload
|
|
16294
|
+
);
|
|
16295
|
+
}
|
|
16296
|
+
if (!this._figFile) {
|
|
16297
|
+
this._figFile = iofigma.kiwi.parseFile(this.payload);
|
|
16298
|
+
}
|
|
16299
|
+
const figFile = this._figFile;
|
|
16300
|
+
const pages = figFile.pages;
|
|
16301
|
+
if (!pages?.length) return [];
|
|
16302
|
+
const sortedPages = [...pages].sort(
|
|
16303
|
+
(a, b) => a.sortkey.localeCompare(b.sortkey)
|
|
16304
|
+
);
|
|
16305
|
+
const families = /* @__PURE__ */ new Set();
|
|
16306
|
+
for (let i = 0; i < sortedPages.length; i++) {
|
|
16307
|
+
const resolved = figFileToSceneJson(figFile, void 0, i);
|
|
16308
|
+
for (const f of this._collectFontFamiliesFromSceneJson(
|
|
16309
|
+
resolved.sceneJson
|
|
16310
|
+
)) {
|
|
16311
|
+
families.add(f);
|
|
16312
|
+
}
|
|
16313
|
+
}
|
|
16314
|
+
return Array.from(families);
|
|
16315
|
+
}
|
|
16316
|
+
_collectFontFamiliesFromSceneJson(sceneJson) {
|
|
16317
|
+
const parsed = JSON.parse(sceneJson);
|
|
16318
|
+
const nodes = parsed?.document?.nodes;
|
|
16319
|
+
if (!nodes || typeof nodes !== "object") return [];
|
|
16320
|
+
const families = /* @__PURE__ */ new Set();
|
|
16321
|
+
for (const node of Object.values(nodes)) {
|
|
16322
|
+
const family = node.font_family;
|
|
16323
|
+
if (typeof family === "string" && family) {
|
|
16324
|
+
families.add(family);
|
|
16325
|
+
}
|
|
16326
|
+
}
|
|
16327
|
+
return Array.from(families);
|
|
16328
|
+
}
|
|
15864
16329
|
};
|
|
16330
|
+
/** Max cached scenes; evicts LRU when exceeded. */
|
|
16331
|
+
_FigmaDocument._MAX_SCENE_CACHE = 64;
|
|
16332
|
+
var FigmaDocument = _FigmaDocument;
|
|
15865
16333
|
function resolveMimeType(format) {
|
|
15866
16334
|
const map = {
|
|
15867
16335
|
png: "image/png",
|
|
@@ -15968,6 +16436,28 @@ function exportSettingToRenderOptions(node, setting) {
|
|
|
15968
16436
|
}
|
|
15969
16437
|
return { format, width: DEFAULT_EXPORT_SIZE, height: DEFAULT_EXPORT_SIZE };
|
|
15970
16438
|
}
|
|
16439
|
+
function collectFontFamiliesFromRestDocument(json) {
|
|
16440
|
+
const families = /* @__PURE__ */ new Set();
|
|
16441
|
+
const doc = json;
|
|
16442
|
+
const pages = doc?.document?.children;
|
|
16443
|
+
if (!pages?.length) return [];
|
|
16444
|
+
function walk(nodes) {
|
|
16445
|
+
for (const node of nodes) {
|
|
16446
|
+
const style = node.style;
|
|
16447
|
+
const family = style?.fontFamily;
|
|
16448
|
+
if (typeof family === "string" && family) {
|
|
16449
|
+
families.add(family);
|
|
16450
|
+
}
|
|
16451
|
+
const children = node.children;
|
|
16452
|
+
if (children?.length) walk(children);
|
|
16453
|
+
}
|
|
16454
|
+
}
|
|
16455
|
+
for (const page of pages) {
|
|
16456
|
+
const pageChildren = page.children;
|
|
16457
|
+
if (pageChildren?.length) walk(pageChildren);
|
|
16458
|
+
}
|
|
16459
|
+
return Array.from(families);
|
|
16460
|
+
}
|
|
15971
16461
|
function findNodeInRestDocument(json, nodeId) {
|
|
15972
16462
|
const doc = json;
|
|
15973
16463
|
const pages = doc?.document?.children;
|
|
@@ -16134,8 +16624,7 @@ function figFileToRestLikeDocument(figFile) {
|
|
|
16134
16624
|
}
|
|
16135
16625
|
};
|
|
16136
16626
|
}
|
|
16137
|
-
function
|
|
16138
|
-
const figFile = iofigma.kiwi.parseFile(figBytes);
|
|
16627
|
+
function figFileToSceneJson(figFile, rootNodeId, pageIndex) {
|
|
16139
16628
|
const pages = figFile.pages;
|
|
16140
16629
|
if (!pages || pages.length === 0) {
|
|
16141
16630
|
throw new Error("FigmaDocument: .fig file has no pages");
|
|
@@ -16152,6 +16641,8 @@ function figBytesToSceneJson(figBytes, rootNodeId) {
|
|
|
16152
16641
|
);
|
|
16153
16642
|
}
|
|
16154
16643
|
page = pageWithNode;
|
|
16644
|
+
} else if (pageIndex != null && pageIndex >= 0 && pageIndex < sortedPages.length) {
|
|
16645
|
+
page = sortedPages[pageIndex];
|
|
16155
16646
|
} else {
|
|
16156
16647
|
page = sortedPages[0];
|
|
16157
16648
|
}
|
|
@@ -16201,38 +16692,26 @@ var FigmaRenderer = class {
|
|
|
16201
16692
|
this._canvas
|
|
16202
16693
|
);
|
|
16203
16694
|
}
|
|
16695
|
+
if (this.options.fonts) {
|
|
16696
|
+
for (const [family, data] of Object.entries(this.options.fonts)) {
|
|
16697
|
+
const entries = Array.isArray(data) ? data : [data];
|
|
16698
|
+
for (const bytes of entries) {
|
|
16699
|
+
this._canvas.addFont(family, bytes);
|
|
16700
|
+
}
|
|
16701
|
+
}
|
|
16702
|
+
}
|
|
16204
16703
|
return this._canvas;
|
|
16205
16704
|
}
|
|
16206
16705
|
loadScene(canvas, nodeId) {
|
|
16207
16706
|
if (this._sceneLoaded && this._requestedNodeId === nodeId) return;
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
nodeId || void 0
|
|
16214
|
-
);
|
|
16215
|
-
sceneJson = figResult.sceneJson;
|
|
16216
|
-
imagesToRegister = figResult.images;
|
|
16217
|
-
} else {
|
|
16218
|
-
const restResult = restJsonToSceneJson(
|
|
16219
|
-
this.document.payload,
|
|
16220
|
-
nodeId || void 0,
|
|
16221
|
-
this.options.images
|
|
16222
|
-
);
|
|
16223
|
-
sceneJson = restResult.sceneJson;
|
|
16224
|
-
const used = new Set(restResult.imageRefsUsed);
|
|
16225
|
-
const provided = this.options.images ?? {};
|
|
16226
|
-
for (const ref of used) {
|
|
16227
|
-
if (ref in provided) {
|
|
16228
|
-
imagesToRegister[ref] = provided[ref];
|
|
16229
|
-
}
|
|
16230
|
-
}
|
|
16231
|
-
}
|
|
16232
|
-
for (const [ref, bytes] of Object.entries(imagesToRegister)) {
|
|
16707
|
+
const resolved = this.document._resolve(
|
|
16708
|
+
nodeId || void 0,
|
|
16709
|
+
this.options.images
|
|
16710
|
+
);
|
|
16711
|
+
for (const [ref, bytes] of Object.entries(resolved.images)) {
|
|
16233
16712
|
canvas.addImageWithId(bytes, `res://images/${ref}`);
|
|
16234
16713
|
}
|
|
16235
|
-
canvas.loadScene(sceneJson);
|
|
16714
|
+
canvas.loadScene(resolved.sceneJson);
|
|
16236
16715
|
this._requestedNodeId = nodeId;
|
|
16237
16716
|
this._sceneLoaded = true;
|
|
16238
16717
|
}
|