@grida/refig 0.0.1 → 0.0.2
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 +1 -1
- package/dist/browser.mjs +1 -1
- package/dist/{chunk-PK5L35ID.mjs → chunk-YI7PIULZ.mjs} +88 -10
- package/dist/cli.mjs +2 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@grida/refig`
|
|
2
2
|
|
|
3
|
-
> **re**nder **fig**ma — headless Figma renderer (Node.js + browser) in the spirit of [`resvg
|
|
3
|
+
> **re**nder **fig**ma — headless Figma renderer (Node.js + browser) in the spirit of [`resvg`](https://github.com/linebender/resvg)
|
|
4
4
|
|
|
5
5
|
Render Figma documents to **PNG, JPEG, WebP, PDF, and SVG** in **Node.js (no browser required)** or directly in the **browser**.
|
|
6
6
|
|
package/dist/browser.mjs
CHANGED
|
@@ -13749,11 +13749,19 @@ var iofigma;
|
|
|
13749
13749
|
function hasGeometryTrait(node2) {
|
|
13750
13750
|
return "fillGeometry" in node2 || "strokeGeometry" in node2;
|
|
13751
13751
|
}
|
|
13752
|
+
function getParentBounds(node2) {
|
|
13753
|
+
const box = "absoluteBoundingBox" in node2 ? node2.absoluteBoundingBox : void 0;
|
|
13754
|
+
const sz = "size" in node2 ? node2.size : void 0;
|
|
13755
|
+
return {
|
|
13756
|
+
width: box?.width ?? sz?.x ?? 0,
|
|
13757
|
+
height: box?.height ?? sz?.y ?? 0
|
|
13758
|
+
};
|
|
13759
|
+
}
|
|
13752
13760
|
function createVectorNodeFromPath(pathData, geometry, parentNode, childId, name, options) {
|
|
13753
13761
|
if (!pathData) return null;
|
|
13754
13762
|
try {
|
|
13755
13763
|
const vectorNetwork = index_default2.fromSVGPathData(pathData);
|
|
13756
|
-
const
|
|
13764
|
+
const { width, height } = getParentBounds(parentNode);
|
|
13757
13765
|
const strokeAsFill = options.strokeAsFill === true;
|
|
13758
13766
|
return {
|
|
13759
13767
|
id: childId,
|
|
@@ -13767,10 +13775,10 @@ var iofigma;
|
|
|
13767
13775
|
}),
|
|
13768
13776
|
...positioning_trait({
|
|
13769
13777
|
relativeTransform: [
|
|
13770
|
-
[1, 0,
|
|
13771
|
-
[0, 1,
|
|
13778
|
+
[1, 0, 0],
|
|
13779
|
+
[0, 1, 0]
|
|
13772
13780
|
],
|
|
13773
|
-
size: { x:
|
|
13781
|
+
size: { x: width, y: height }
|
|
13774
13782
|
}),
|
|
13775
13783
|
...strokeAsFill ? {
|
|
13776
13784
|
...fills_trait(
|
|
@@ -13794,8 +13802,8 @@ var iofigma;
|
|
|
13794
13802
|
..."effects" in parentNode && parentNode.effects ? effects_trait(parentNode.effects) : effects_trait(void 0),
|
|
13795
13803
|
type: "vector",
|
|
13796
13804
|
vector_network: vectorNetwork,
|
|
13797
|
-
layout_target_width:
|
|
13798
|
-
layout_target_height:
|
|
13805
|
+
layout_target_width: width,
|
|
13806
|
+
layout_target_height: height,
|
|
13799
13807
|
fill_rule: map.windingRuleMap[geometry.windingRule] ?? "nonzero"
|
|
13800
13808
|
};
|
|
13801
13809
|
} catch (e) {
|
|
@@ -13806,13 +13814,73 @@ var iofigma;
|
|
|
13806
13814
|
return null;
|
|
13807
13815
|
}
|
|
13808
13816
|
}
|
|
13817
|
+
function createPathNodeFromPath(pathData, geometry, parentNode, childId, name, options) {
|
|
13818
|
+
if (!pathData) return null;
|
|
13819
|
+
try {
|
|
13820
|
+
const { width, height } = getParentBounds(parentNode);
|
|
13821
|
+
const strokeAsFill = options.strokeAsFill === true;
|
|
13822
|
+
return {
|
|
13823
|
+
id: childId,
|
|
13824
|
+
...base_node_trait({
|
|
13825
|
+
name,
|
|
13826
|
+
visible: "visible" in parentNode ? parentNode.visible : true,
|
|
13827
|
+
locked: "locked" in parentNode ? parentNode.locked : false,
|
|
13828
|
+
rotation: 0,
|
|
13829
|
+
opacity: "opacity" in parentNode && parentNode.opacity !== void 0 ? parentNode.opacity : 1,
|
|
13830
|
+
blendMode: "blendMode" in parentNode && parentNode.blendMode ? parentNode.blendMode : "NORMAL"
|
|
13831
|
+
}),
|
|
13832
|
+
...positioning_trait({
|
|
13833
|
+
relativeTransform: [
|
|
13834
|
+
[1, 0, 0],
|
|
13835
|
+
[0, 1, 0]
|
|
13836
|
+
],
|
|
13837
|
+
size: { x: width, y: height }
|
|
13838
|
+
}),
|
|
13839
|
+
...strokeAsFill ? {
|
|
13840
|
+
...fills_trait(
|
|
13841
|
+
parentNode.strokes ?? [],
|
|
13842
|
+
context,
|
|
13843
|
+
imageRefsUsed
|
|
13844
|
+
),
|
|
13845
|
+
...stroke_trait(
|
|
13846
|
+
{ strokes: [], strokeWeight: 0 },
|
|
13847
|
+
context,
|
|
13848
|
+
imageRefsUsed
|
|
13849
|
+
)
|
|
13850
|
+
} : {
|
|
13851
|
+
...options.useFill ? fills_trait(parentNode.fills, context, imageRefsUsed) : {},
|
|
13852
|
+
...options.useStroke ? stroke_trait(parentNode, context, imageRefsUsed) : stroke_trait(
|
|
13853
|
+
{ strokes: [], strokeWeight: 0 },
|
|
13854
|
+
context,
|
|
13855
|
+
imageRefsUsed
|
|
13856
|
+
)
|
|
13857
|
+
},
|
|
13858
|
+
..."effects" in parentNode && parentNode.effects ? effects_trait(parentNode.effects) : effects_trait(void 0),
|
|
13859
|
+
type: "path",
|
|
13860
|
+
data: pathData,
|
|
13861
|
+
layout_target_width: width,
|
|
13862
|
+
layout_target_height: height,
|
|
13863
|
+
fill_rule: map.windingRuleMap[geometry.windingRule] ?? "nonzero"
|
|
13864
|
+
};
|
|
13865
|
+
} catch (e) {
|
|
13866
|
+
console.warn(`Failed to create path node (${name}):`, e);
|
|
13867
|
+
return null;
|
|
13868
|
+
}
|
|
13869
|
+
}
|
|
13809
13870
|
function processFillGeometries(node2, parentGridaId, nodeTypeName) {
|
|
13810
13871
|
if (!node2.fillGeometry?.length) return [];
|
|
13811
13872
|
const childIds = [];
|
|
13812
13873
|
node2.fillGeometry.forEach((geometry, idx) => {
|
|
13813
13874
|
const childId = `${parentGridaId}_fill_${idx}`;
|
|
13814
13875
|
const name = `${node2.name || nodeTypeName} Fill ${idx + 1}`;
|
|
13815
|
-
const childNode =
|
|
13876
|
+
const childNode = context.prefer_path_for_geometry ? createPathNodeFromPath(
|
|
13877
|
+
geometry.path ?? "",
|
|
13878
|
+
geometry,
|
|
13879
|
+
node2,
|
|
13880
|
+
childId,
|
|
13881
|
+
name,
|
|
13882
|
+
{ useFill: true, useStroke: false }
|
|
13883
|
+
) : createVectorNodeFromPath(
|
|
13816
13884
|
geometry.path ?? "",
|
|
13817
13885
|
geometry,
|
|
13818
13886
|
node2,
|
|
@@ -13833,7 +13901,14 @@ var iofigma;
|
|
|
13833
13901
|
node2.strokeGeometry.forEach((geometry, idx) => {
|
|
13834
13902
|
const childId = `${parentGridaId}_stroke_${idx}`;
|
|
13835
13903
|
const name = `${node2.name || nodeTypeName} Stroke ${idx + 1}`;
|
|
13836
|
-
const childNode =
|
|
13904
|
+
const childNode = context.prefer_path_for_geometry ? createPathNodeFromPath(
|
|
13905
|
+
geometry.path ?? "",
|
|
13906
|
+
geometry,
|
|
13907
|
+
node2,
|
|
13908
|
+
childId,
|
|
13909
|
+
name,
|
|
13910
|
+
{ useFill: false, useStroke: false, strokeAsFill: true }
|
|
13911
|
+
) : createVectorNodeFromPath(
|
|
13837
13912
|
geometry.path ?? "",
|
|
13838
13913
|
geometry,
|
|
13839
13914
|
node2,
|
|
@@ -14082,7 +14157,7 @@ var iofigma;
|
|
|
14082
14157
|
case "REGULAR_POLYGON":
|
|
14083
14158
|
case "STAR":
|
|
14084
14159
|
case "VECTOR": {
|
|
14085
|
-
const useRestVectorNetwork = context.disable_volatile_apis !== true && "vectorNetwork" in node && node.vectorNetwork != null;
|
|
14160
|
+
const useRestVectorNetwork = context.prefer_path_for_geometry !== true && context.disable_volatile_apis !== true && "vectorNetwork" in node && node.vectorNetwork != null;
|
|
14086
14161
|
if (useRestVectorNetwork) {
|
|
14087
14162
|
try {
|
|
14088
14163
|
const ir = restful2.map.normalizeRestVectorNetworkToIR(
|
|
@@ -15866,7 +15941,8 @@ function exportSettingToRenderOptions(node, setting) {
|
|
|
15866
15941
|
JPG: "jpeg",
|
|
15867
15942
|
PNG: "png",
|
|
15868
15943
|
SVG: "svg",
|
|
15869
|
-
PDF: "pdf"
|
|
15944
|
+
PDF: "pdf",
|
|
15945
|
+
WEBP: "webp"
|
|
15870
15946
|
};
|
|
15871
15947
|
const format = formatMap[setting.format] ?? "png";
|
|
15872
15948
|
const constraint = setting.constraint;
|
|
@@ -15951,6 +16027,7 @@ function restJsonToSceneJson(json, rootNodeId, images) {
|
|
|
15951
16027
|
const resolveImageSrc = images && (Object.keys(images).length > 0 ? (ref) => ref in images ? `res://images/${ref}` : null : void 0);
|
|
15952
16028
|
const buildContext = (overrides) => ({
|
|
15953
16029
|
gradient_id_generator: baseGradientGen,
|
|
16030
|
+
prefer_path_for_geometry: true,
|
|
15954
16031
|
...resolveImageSrc && { resolve_image_src: resolveImageSrc },
|
|
15955
16032
|
...overrides
|
|
15956
16033
|
});
|
|
@@ -16089,6 +16166,7 @@ function figBytesToSceneJson(figBytes, rootNodeId) {
|
|
|
16089
16166
|
node_id_generator: () => `refig-${++counter}`,
|
|
16090
16167
|
gradient_id_generator: () => `grad-${++counter}`,
|
|
16091
16168
|
preserve_figma_ids: true,
|
|
16169
|
+
prefer_path_for_geometry: true,
|
|
16092
16170
|
...resolveImageSrc && { resolve_image_src: resolveImageSrc }
|
|
16093
16171
|
};
|
|
16094
16172
|
const { document: packed } = iofigma.kiwi.convertPageToScene(page, context);
|
package/dist/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
exportSettingToRenderOptions,
|
|
7
7
|
figFileToRestLikeDocument,
|
|
8
8
|
iofigma
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-YI7PIULZ.mjs";
|
|
10
10
|
|
|
11
11
|
// cli.ts
|
|
12
12
|
import {
|
|
@@ -31,6 +31,7 @@ var EXT_BY_FORMAT = {
|
|
|
31
31
|
png: "png",
|
|
32
32
|
jpeg: "jpeg",
|
|
33
33
|
jpg: "jpeg",
|
|
34
|
+
webp: "webp",
|
|
34
35
|
svg: "svg",
|
|
35
36
|
pdf: "pdf"
|
|
36
37
|
};
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grida/refig",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Headless Figma renderer — render .fig and REST API JSON to PNG/JPEG/WebP/PDF/SVG",
|
|
6
6
|
"keywords": [
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"access": "public"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@grida/canvas-wasm": "0.90.0-canary.
|
|
58
|
+
"@grida/canvas-wasm": "0.90.0-canary.8",
|
|
59
59
|
"commander": "^12.1.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|