@unmade/text-renderer 0.2.0 → 0.3.0
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 +12 -0
- package/dist/__vite-browser-external-l0sNRNKZ.js +1 -0
- package/dist/ce-adapter/index.cjs +1 -1
- package/dist/ce-adapter/index.js +78 -75
- package/dist/index.d.ts +44 -7
- package/dist/index.js +1663 -9074
- package/dist/node/index.d.ts +44 -7
- package/dist/node/index.js +580 -9065
- package/dist/worker/index.d.ts +44 -7
- package/dist/worker/index.js +6143 -13788
- package/package.json +15 -25
- package/dist/index-BFEQ7yc6.cjs +0 -2
- package/dist/index-F17NutRZ.js +0 -12048
- package/dist/index.cjs +0 -8
- package/dist/node/index.cjs +0 -8
- package/dist/worker/index.cjs +0 -25
package/README.md
CHANGED
|
@@ -34,6 +34,18 @@ import { getRenderedText } from '@unmade/text-renderer/node'; // Node.js
|
|
|
34
34
|
import { getRenderedText } from '@unmade/text-renderer/worker'; // Web Worker
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
### ESM-only
|
|
38
|
+
|
|
39
|
+
This package is ESM-only — `require('@unmade/text-renderer')` will not work. This is a hard constraint: harfbuzzjs (the font shaping engine) uses top-level `await` for WASM initialisation, which Rollup cannot emit as CJS.
|
|
40
|
+
|
|
41
|
+
**Node.js / Lambda**: Node 18+ supports ESM natively, so this is not a blocker. When integrating from a CJS codebase, use dynamic import:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const { getRenderedText } = await import('@unmade/text-renderer/node');
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**CE Lambda integration**: When wiring text-renderer into the Configuration Engine Lambda, use the `/node` ESM entry (`@unmade/text-renderer/node`) from an ESM Lambda handler, or use the `await import()` pattern above from an existing CJS handler. The `ce-adapter` sub-package (`@unmade/text-renderer/ce-adapter`) retains a CJS build and can be `require()`'d normally.
|
|
48
|
+
|
|
37
49
|
## Configuration Engine adapter
|
|
38
50
|
|
|
39
51
|
The `ce-adapter` sub-package bridges CE (Configuration Engine) editor state to renderer options:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function P(t){return t.type==="text"}function w(t){const i=t.getState().garment;return t.settings.garments.find(s=>s.slug===i)}function A(t,l,i){if(!t.embellishment_positions)return;const s=t.embellishment_positions.filter(o=>o.placement!==l?!1:!i||!o.variant?!0:o.variant===i||o.variant.toLowerCase()==="common");if(i&&s.length>1){const o=s.find(a=>a.variant===i);if(o)return o}return s[0]}function U(t,l){const i=t.fonts.find(s=>s.id===l);if(i)return{id:i.id,fontUrl:i.font_url,fontFamily:i.font_family,letterSpacing:i.letter_spacing??0,letterSpacingOutline:i.letter_spacing_outline??0,outlineWidth:i.outline_width??0,fixedColours:i.fixed_colours}}function v(t,l,i,s,o,a){const{library:h}=o,u=[];for(const[r,f]of Object.entries(s)){if(f.type!=="text")continue;const d=f,{meta:e}=d;if(!e?.text)continue;const{libraryItemID:z}=d,g=h[z];if(!g||!P(g))continue;const y=e.font;if(y===void 0)continue;const m=U(g,y);if(!m)continue;const c=A(l,r,a);if(!c)continue;let x=null,b=null;if(e.colours&&g.palette!=null)try{const n=t.palettes.getUsedColours(g.palette,e.colours);x=n[0]??null,b=n[1]??null}catch(n){console.warn(`[extractTextPlacements] Colour resolution failed for ${r}:`,n)}const S=o.byId?.[r],p={vertical:"top",horizontal:"left"};if(S){const n=S;n.vertical_alignment&&(p.vertical=n.vertical_alignment),n.horizontal_alignment&&(p.horizontal=n.horizontal_alignment)}u.push({placementId:r,displayName:r,source:i,text:e.text,font:m,isCurved:e.isCurved??!1,isDistributed:e.isDistributed??!1,verticalAlignment:e.verticalAlignment??p.vertical,horizontalAlignment:e.horizontalAlignment??p.horizontal,rotation:e.rotation??0,spacing:e.spacing??null,fillColour:x,outlineColour:b,position:{width:c.width,height:c.height,physicalWidth:c.physical_width_decimal,physicalHeight:c.physical_height_decimal,physicalUnits:c.physical_size_units,baselinePath:c.baseline_path,rotation:c.rotation},userSetPhysicalSize:e.retainedPhysicalSize??null,fontMetrics:(()=>{const n=e.fontMetrics??{size:0,height:0,baseline:0,width:0},C=n.physicalFontSize||(n.physicalHeight!=null&&n.physicalHeight>0&&n.physicalUnits!=null?[n.physicalHeight,n.physicalUnits]:void 0);return{...n,physicalFontSize:C}})(),manufacturingMethod:e.manufacturing_method??""})}return u}function O(t){const l=t.getState(),i=w(t);if(!i)return console.warn("[extractTextPlacements] No matching garment found"),[];const s=typeof t.getCurrentVariant=="function"?t.getCurrentVariant():void 0,o=[],a=l.vals?.placements,h=t.settings.placements;a&&h&&o.push(...v(t,i,"placements",a,h,s));const u=l.vals?.embellishments,r=t.settings.embellishments;return u&&r&&o.push(...v(t,i,"embellishments",u,r,s)),o.length===0&&console.warn("[extractTextPlacements] No text entries found in either placements or embellishments"),o}function _(t){return t==="center"?"centre":t}function T(t){let l=_(t.horizontalAlignment);t.isDistributed&&(l="distributed");let i;t.position.baselinePath?i={type:"custom",path:t.position.baselinePath}:t.isCurved?i="curved":i="flat";const s=t.userSetPhysicalSize?[t.userSetPhysicalSize[0],t.userSetPhysicalSize[1]]:t.fontMetrics.physicalFontSize!=null?t.fontMetrics.physicalFontSize:[t.position.physicalHeight,t.position.physicalUnits],a={outlineWidth:t.outlineColour!=null?t.font.outlineWidth:0,letterSpacing:t.spacing?.letter_spacing??0,letterSpacingOutline:t.spacing?.letter_spacing_outline??0},h=t.fillColour?{hex:t.fillColour.hex,reference:t.fillColour.reference??void 0}:void 0,u=t.outlineColour?{hex:t.outlineColour.hex,reference:t.outlineColour.reference??void 0}:void 0;let r;if(t.font.fixedColours){const f={};for(const[d,e]of Object.entries(t.font.fixedColours))f[d]={hex:e.hex,reference:e.reference};r=f}return{text:t.text,fontUrl:t.font.fontUrl,physicalSize:s,fontSizeFallback:t.fontMetrics.size,boxDimensions:{width:t.position.width,height:t.position.height,physicalWidth:t.position.physicalWidth,physicalHeight:t.position.physicalHeight,physicalUnits:t.position.physicalUnits},spacing:a,verticalAlignment:_(t.verticalAlignment),horizontalAlignment:l,baseline:i,fillColour:h,strokeColour:u,colourMap:r}}exports.extractTextPlacements=O;exports.mapStateToRendererOptions=T;
|
package/dist/ce-adapter/index.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
function
|
|
1
|
+
function w(t) {
|
|
2
2
|
return t.type === "text";
|
|
3
3
|
}
|
|
4
4
|
function P(t) {
|
|
5
5
|
const i = t.getState().garment;
|
|
6
6
|
return t.settings.garments.find((s) => s.slug === i);
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
if (t.embellishment_positions)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
);
|
|
8
|
+
function A(t, l, i) {
|
|
9
|
+
if (!t.embellishment_positions) return;
|
|
10
|
+
const s = t.embellishment_positions.filter((o) => o.placement !== l ? !1 : !i || !o.variant ? !0 : o.variant === i || o.variant.toLowerCase() === "common");
|
|
11
|
+
if (i && s.length > 1) {
|
|
12
|
+
const o = s.find((a) => a.variant === i);
|
|
13
|
+
if (o) return o;
|
|
14
|
+
}
|
|
15
|
+
return s[0];
|
|
13
16
|
}
|
|
14
|
-
function
|
|
15
|
-
const i = t.fonts.find((s) => s.id ===
|
|
17
|
+
function U(t, l) {
|
|
18
|
+
const i = t.fonts.find((s) => s.id === l);
|
|
16
19
|
if (i)
|
|
17
20
|
return {
|
|
18
21
|
id: i.id,
|
|
@@ -24,109 +27,109 @@ function A(t, o) {
|
|
|
24
27
|
fixedColours: i.fixed_colours
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
|
-
function
|
|
28
|
-
const { library:
|
|
29
|
-
for (const [
|
|
30
|
-
if (
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
33
|
-
const { libraryItemID:
|
|
34
|
-
if (!g || !
|
|
35
|
-
const y =
|
|
30
|
+
function S(t, l, i, s, o, a) {
|
|
31
|
+
const { library: h } = o, u = [];
|
|
32
|
+
for (const [r, f] of Object.entries(s)) {
|
|
33
|
+
if (f.type !== "text") continue;
|
|
34
|
+
const d = f, { meta: e } = d;
|
|
35
|
+
if (!e?.text) continue;
|
|
36
|
+
const { libraryItemID: z } = d, g = h[z];
|
|
37
|
+
if (!g || !w(g)) continue;
|
|
38
|
+
const y = e.font;
|
|
36
39
|
if (y === void 0) continue;
|
|
37
|
-
const m =
|
|
40
|
+
const m = U(g, y);
|
|
38
41
|
if (!m) continue;
|
|
39
|
-
const
|
|
40
|
-
if (!
|
|
42
|
+
const c = A(l, r, a);
|
|
43
|
+
if (!c) continue;
|
|
41
44
|
let x = null, b = null;
|
|
42
|
-
if (
|
|
45
|
+
if (e.colours && g.palette != null)
|
|
43
46
|
try {
|
|
44
|
-
const
|
|
47
|
+
const n = t.palettes.getUsedColours(
|
|
45
48
|
g.palette,
|
|
46
|
-
|
|
49
|
+
e.colours
|
|
47
50
|
);
|
|
48
|
-
x =
|
|
49
|
-
} catch (
|
|
50
|
-
console.warn(`[extractTextPlacements] Colour resolution failed for ${
|
|
51
|
+
x = n[0] ?? null, b = n[1] ?? null;
|
|
52
|
+
} catch (n) {
|
|
53
|
+
console.warn(`[extractTextPlacements] Colour resolution failed for ${r}:`, n);
|
|
51
54
|
}
|
|
52
|
-
const
|
|
55
|
+
const v = o.byId?.[r], p = {
|
|
53
56
|
vertical: "top",
|
|
54
57
|
horizontal: "left"
|
|
55
58
|
};
|
|
56
|
-
if (
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
+
if (v) {
|
|
60
|
+
const n = v;
|
|
61
|
+
n.vertical_alignment && (p.vertical = n.vertical_alignment), n.horizontal_alignment && (p.horizontal = n.horizontal_alignment);
|
|
59
62
|
}
|
|
60
|
-
|
|
61
|
-
placementId:
|
|
62
|
-
displayName:
|
|
63
|
+
u.push({
|
|
64
|
+
placementId: r,
|
|
65
|
+
displayName: r,
|
|
63
66
|
source: i,
|
|
64
|
-
text:
|
|
67
|
+
text: e.text,
|
|
65
68
|
font: m,
|
|
66
|
-
isCurved:
|
|
67
|
-
isDistributed:
|
|
68
|
-
verticalAlignment:
|
|
69
|
-
horizontalAlignment:
|
|
70
|
-
rotation:
|
|
71
|
-
spacing:
|
|
69
|
+
isCurved: e.isCurved ?? !1,
|
|
70
|
+
isDistributed: e.isDistributed ?? !1,
|
|
71
|
+
verticalAlignment: e.verticalAlignment ?? p.vertical,
|
|
72
|
+
horizontalAlignment: e.horizontalAlignment ?? p.horizontal,
|
|
73
|
+
rotation: e.rotation ?? 0,
|
|
74
|
+
spacing: e.spacing ?? null,
|
|
72
75
|
fillColour: x,
|
|
73
76
|
outlineColour: b,
|
|
74
77
|
position: {
|
|
75
|
-
width:
|
|
76
|
-
height:
|
|
77
|
-
physicalWidth:
|
|
78
|
-
physicalHeight:
|
|
79
|
-
physicalUnits:
|
|
80
|
-
baselinePath:
|
|
81
|
-
rotation:
|
|
78
|
+
width: c.width,
|
|
79
|
+
height: c.height,
|
|
80
|
+
physicalWidth: c.physical_width_decimal,
|
|
81
|
+
physicalHeight: c.physical_height_decimal,
|
|
82
|
+
physicalUnits: c.physical_size_units,
|
|
83
|
+
baselinePath: c.baseline_path,
|
|
84
|
+
rotation: c.rotation
|
|
82
85
|
},
|
|
83
|
-
userSetPhysicalSize:
|
|
86
|
+
userSetPhysicalSize: e.retainedPhysicalSize ?? null,
|
|
84
87
|
fontMetrics: (() => {
|
|
85
|
-
const
|
|
86
|
-
return { ...
|
|
88
|
+
const n = e.fontMetrics ?? { size: 0, height: 0, baseline: 0, width: 0 }, C = n.physicalFontSize || (n.physicalHeight != null && n.physicalHeight > 0 && n.physicalUnits != null ? [n.physicalHeight, n.physicalUnits] : void 0);
|
|
89
|
+
return { ...n, physicalFontSize: C };
|
|
87
90
|
})(),
|
|
88
|
-
manufacturingMethod:
|
|
91
|
+
manufacturingMethod: e.manufacturing_method ?? ""
|
|
89
92
|
});
|
|
90
93
|
}
|
|
91
|
-
return
|
|
94
|
+
return u;
|
|
92
95
|
}
|
|
93
|
-
function
|
|
94
|
-
const
|
|
96
|
+
function F(t) {
|
|
97
|
+
const l = t.getState(), i = P(t);
|
|
95
98
|
if (!i)
|
|
96
99
|
return console.warn("[extractTextPlacements] No matching garment found"), [];
|
|
97
|
-
const s = [],
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
return
|
|
100
|
+
const s = typeof t.getCurrentVariant == "function" ? t.getCurrentVariant() : void 0, o = [], a = l.vals?.placements, h = t.settings.placements;
|
|
101
|
+
a && h && o.push(...S(t, i, "placements", a, h, s));
|
|
102
|
+
const u = l.vals?.embellishments, r = t.settings.embellishments;
|
|
103
|
+
return u && r && o.push(...S(t, i, "embellishments", u, r, s)), o.length === 0 && console.warn("[extractTextPlacements] No text entries found in either placements or embellishments"), o;
|
|
101
104
|
}
|
|
102
105
|
function _(t) {
|
|
103
106
|
return t === "center" ? "centre" : t;
|
|
104
107
|
}
|
|
105
|
-
function
|
|
106
|
-
let
|
|
107
|
-
t.isDistributed && (
|
|
108
|
+
function H(t) {
|
|
109
|
+
let l = _(t.horizontalAlignment);
|
|
110
|
+
t.isDistributed && (l = "distributed");
|
|
108
111
|
let i;
|
|
109
112
|
t.position.baselinePath ? i = { type: "custom", path: t.position.baselinePath } : t.isCurved ? i = "curved" : i = "flat";
|
|
110
113
|
const s = t.userSetPhysicalSize ? [
|
|
111
114
|
t.userSetPhysicalSize[0],
|
|
112
115
|
t.userSetPhysicalSize[1]
|
|
113
|
-
] : t.fontMetrics.physicalFontSize != null ? t.fontMetrics.physicalFontSize : [t.position.physicalHeight, t.position.physicalUnits],
|
|
116
|
+
] : t.fontMetrics.physicalFontSize != null ? t.fontMetrics.physicalFontSize : [t.position.physicalHeight, t.position.physicalUnits], a = {
|
|
114
117
|
outlineWidth: t.outlineColour != null ? t.font.outlineWidth : 0,
|
|
115
118
|
letterSpacing: t.spacing?.letter_spacing ?? 0,
|
|
116
119
|
letterSpacingOutline: t.spacing?.letter_spacing_outline ?? 0
|
|
117
|
-
},
|
|
120
|
+
}, h = t.fillColour ? {
|
|
118
121
|
hex: t.fillColour.hex,
|
|
119
122
|
reference: t.fillColour.reference ?? void 0
|
|
120
|
-
} : void 0,
|
|
123
|
+
} : void 0, u = t.outlineColour ? {
|
|
121
124
|
hex: t.outlineColour.hex,
|
|
122
125
|
reference: t.outlineColour.reference ?? void 0
|
|
123
126
|
} : void 0;
|
|
124
|
-
let
|
|
127
|
+
let r;
|
|
125
128
|
if (t.font.fixedColours) {
|
|
126
129
|
const f = {};
|
|
127
|
-
for (const [
|
|
128
|
-
f[
|
|
129
|
-
|
|
130
|
+
for (const [d, e] of Object.entries(t.font.fixedColours))
|
|
131
|
+
f[d] = { hex: e.hex, reference: e.reference };
|
|
132
|
+
r = f;
|
|
130
133
|
}
|
|
131
134
|
return {
|
|
132
135
|
text: t.text,
|
|
@@ -140,18 +143,18 @@ function F(t) {
|
|
|
140
143
|
physicalHeight: t.position.physicalHeight,
|
|
141
144
|
physicalUnits: t.position.physicalUnits
|
|
142
145
|
},
|
|
143
|
-
spacing:
|
|
146
|
+
spacing: a,
|
|
144
147
|
verticalAlignment: _(
|
|
145
148
|
t.verticalAlignment
|
|
146
149
|
),
|
|
147
|
-
horizontalAlignment:
|
|
150
|
+
horizontalAlignment: l,
|
|
148
151
|
baseline: i,
|
|
149
|
-
fillColour:
|
|
150
|
-
strokeColour:
|
|
151
|
-
colourMap:
|
|
152
|
+
fillColour: h,
|
|
153
|
+
strokeColour: u,
|
|
154
|
+
colourMap: r
|
|
152
155
|
};
|
|
153
156
|
}
|
|
154
157
|
export {
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
F as extractTextPlacements,
|
|
159
|
+
H as mapStateToRendererOptions
|
|
157
160
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { default as default_2 } from 'opentype.js';
|
|
2
|
-
import { SVGGlyphData } from '@unmade/svg-glyphs';
|
|
3
|
-
|
|
4
1
|
export declare type BaselineConfig = {
|
|
5
2
|
type: 'flat';
|
|
6
3
|
} | {
|
|
@@ -67,7 +64,7 @@ export declare interface GenerateFlatBaselineOptions {
|
|
|
67
64
|
lineNumber?: number;
|
|
68
65
|
}
|
|
69
66
|
|
|
70
|
-
export declare const getFontCache: () => Map<
|
|
67
|
+
export declare const getFontCache: () => Map<string, LoadedFont>;
|
|
71
68
|
|
|
72
69
|
/**
|
|
73
70
|
* Get the unique colours used by a font's SVG glyphs.
|
|
@@ -147,10 +144,45 @@ export declare type HorizontalTextAlignmentValues = 'left' | 'centre' | 'right'
|
|
|
147
144
|
|
|
148
145
|
export declare const LINE_HEIGHT = 1.1;
|
|
149
146
|
|
|
150
|
-
export declare
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
export declare interface LoadedFont {
|
|
148
|
+
unitsPerEm: number;
|
|
149
|
+
names: {
|
|
150
|
+
fontFamily: string;
|
|
151
|
+
};
|
|
153
152
|
svgGlyphs?: Map<number, SVGGlyphData>;
|
|
153
|
+
charToGlyph(char: string): {
|
|
154
|
+
index: number;
|
|
155
|
+
advanceWidth: number;
|
|
156
|
+
name: string;
|
|
157
|
+
getBoundingBox(): {
|
|
158
|
+
x1: number;
|
|
159
|
+
y1: number;
|
|
160
|
+
x2: number;
|
|
161
|
+
y2: number;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
getPath(text: string, x: number, y: number, fontSize: number, options?: {
|
|
165
|
+
drawSVG?: boolean;
|
|
166
|
+
}): {
|
|
167
|
+
getBoundingBox(): {
|
|
168
|
+
x1: number;
|
|
169
|
+
y1: number;
|
|
170
|
+
x2: number;
|
|
171
|
+
y2: number;
|
|
172
|
+
};
|
|
173
|
+
toPathData(decimals?: number): string;
|
|
174
|
+
};
|
|
175
|
+
getPaths(text: string, x: number, y: number, fontSize: number, options?: {
|
|
176
|
+
drawSVG?: boolean;
|
|
177
|
+
}): Array<{
|
|
178
|
+
getBoundingBox(): {
|
|
179
|
+
x1: number;
|
|
180
|
+
y1: number;
|
|
181
|
+
x2: number;
|
|
182
|
+
y2: number;
|
|
183
|
+
};
|
|
184
|
+
toPathData(decimals?: number): string;
|
|
185
|
+
}>;
|
|
154
186
|
}
|
|
155
187
|
|
|
156
188
|
export declare const loadOpentypeFont: (fontUrl: string, fetchSVGGlyphs?: boolean) => Promise<LoadedFont>;
|
|
@@ -186,6 +218,11 @@ export declare interface RenderTextOptions {
|
|
|
186
218
|
colourMap?: ColourMap;
|
|
187
219
|
}
|
|
188
220
|
|
|
221
|
+
declare interface SVGGlyphData {
|
|
222
|
+
svg: string;
|
|
223
|
+
viewbox: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
189
226
|
export declare interface SvgGlyphEntry {
|
|
190
227
|
content: string;
|
|
191
228
|
viewBox: string;
|