@pooder/kit 6.1.2 → 6.2.1
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/.test-dist/src/extensions/background/BackgroundTool.js +177 -5
- package/.test-dist/src/extensions/constraintUtils.js +44 -0
- package/.test-dist/src/extensions/dieline/DielineTool.js +52 -409
- package/.test-dist/src/extensions/dieline/featureResolution.js +29 -0
- package/.test-dist/src/extensions/dieline/model.js +83 -0
- package/.test-dist/src/extensions/dieline/renderBuilder.js +227 -0
- package/.test-dist/src/extensions/feature/FeatureTool.js +156 -45
- package/.test-dist/src/extensions/featureCoordinates.js +21 -0
- package/.test-dist/src/extensions/featurePlacement.js +46 -0
- package/.test-dist/src/extensions/image/ImageTool.js +281 -25
- package/.test-dist/src/extensions/ruler/RulerTool.js +24 -1
- package/.test-dist/src/shared/constants/layers.js +3 -1
- package/.test-dist/tests/run.js +25 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +47 -13
- package/dist/index.d.ts +47 -13
- package/dist/index.js +1325 -977
- package/dist/index.mjs +1311 -966
- package/package.json +1 -1
- package/src/extensions/background/BackgroundTool.ts +264 -4
- package/src/extensions/dieline/DielineTool.ts +67 -548
- package/src/extensions/dieline/model.ts +165 -1
- package/src/extensions/dieline/renderBuilder.ts +301 -0
- package/src/extensions/feature/FeatureTool.ts +190 -47
- package/src/extensions/featureCoordinates.ts +35 -0
- package/src/extensions/featurePlacement.ts +118 -0
- package/src/extensions/image/ImageTool.ts +139 -157
- package/src/extensions/ruler/RulerTool.ts +24 -2
- package/src/shared/constants/layers.ts +2 -0
- package/tests/run.ts +37 -0
package/package.json
CHANGED
|
@@ -29,6 +29,27 @@ interface Rect {
|
|
|
29
29
|
|
|
30
30
|
export type BackgroundLayerKind = "color" | "image";
|
|
31
31
|
export type BackgroundFitMode = "cover" | "contain" | "stretch";
|
|
32
|
+
export type BackgroundRegionUnit = "normalized" | "px";
|
|
33
|
+
export type BackgroundRegistrationFrame =
|
|
34
|
+
| "trim"
|
|
35
|
+
| "cut"
|
|
36
|
+
| "bleed"
|
|
37
|
+
| "focus"
|
|
38
|
+
| "viewport";
|
|
39
|
+
|
|
40
|
+
export interface BackgroundRegistrationRegion {
|
|
41
|
+
left: number;
|
|
42
|
+
top: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
unit: BackgroundRegionUnit;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface BackgroundRegistration {
|
|
49
|
+
sourceRegion?: BackgroundRegistrationRegion;
|
|
50
|
+
targetFrame?: BackgroundRegistrationFrame;
|
|
51
|
+
fit?: BackgroundFitMode;
|
|
52
|
+
}
|
|
32
53
|
|
|
33
54
|
export interface BackgroundLayer {
|
|
34
55
|
id: string;
|
|
@@ -41,6 +62,7 @@ export interface BackgroundLayer {
|
|
|
41
62
|
exportable: boolean;
|
|
42
63
|
color?: string;
|
|
43
64
|
src?: string;
|
|
65
|
+
registration?: BackgroundRegistration;
|
|
44
66
|
}
|
|
45
67
|
|
|
46
68
|
export interface BackgroundConfig {
|
|
@@ -98,6 +120,32 @@ function normalizeFitMode(
|
|
|
98
120
|
return fallback;
|
|
99
121
|
}
|
|
100
122
|
|
|
123
|
+
function normalizeRegionUnit(
|
|
124
|
+
value: unknown,
|
|
125
|
+
fallback: BackgroundRegionUnit,
|
|
126
|
+
): BackgroundRegionUnit {
|
|
127
|
+
if (value === "px" || value === "normalized") {
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
return fallback;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function normalizeRegistrationFrame(
|
|
134
|
+
value: unknown,
|
|
135
|
+
fallback: BackgroundRegistrationFrame,
|
|
136
|
+
): BackgroundRegistrationFrame {
|
|
137
|
+
if (
|
|
138
|
+
value === "trim" ||
|
|
139
|
+
value === "cut" ||
|
|
140
|
+
value === "bleed" ||
|
|
141
|
+
value === "focus" ||
|
|
142
|
+
value === "viewport"
|
|
143
|
+
) {
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
return fallback;
|
|
147
|
+
}
|
|
148
|
+
|
|
101
149
|
function normalizeAnchor(value: unknown, fallback: string): string {
|
|
102
150
|
if (typeof value !== "string") return fallback;
|
|
103
151
|
const trimmed = value.trim();
|
|
@@ -110,6 +158,86 @@ function normalizeOrder(value: unknown, fallback: number): number {
|
|
|
110
158
|
return numeric;
|
|
111
159
|
}
|
|
112
160
|
|
|
161
|
+
function normalizeRegionValue(value: unknown, fallback: number): number {
|
|
162
|
+
const numeric = Number(value);
|
|
163
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function normalizeRegistrationRegion(
|
|
167
|
+
raw: unknown,
|
|
168
|
+
fallback?: BackgroundRegistrationRegion,
|
|
169
|
+
): BackgroundRegistrationRegion | undefined {
|
|
170
|
+
if (!raw || typeof raw !== "object") {
|
|
171
|
+
return fallback ? { ...fallback } : undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const input = raw as Partial<BackgroundRegistrationRegion>;
|
|
175
|
+
const base = fallback || {
|
|
176
|
+
left: 0,
|
|
177
|
+
top: 0,
|
|
178
|
+
width: 1,
|
|
179
|
+
height: 1,
|
|
180
|
+
unit: "normalized" as BackgroundRegionUnit,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
left: normalizeRegionValue(input.left, base.left),
|
|
185
|
+
top: normalizeRegionValue(input.top, base.top),
|
|
186
|
+
width: normalizeRegionValue(input.width, base.width),
|
|
187
|
+
height: normalizeRegionValue(input.height, base.height),
|
|
188
|
+
unit: normalizeRegionUnit(input.unit, base.unit),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function normalizeRegistration(
|
|
193
|
+
raw: unknown,
|
|
194
|
+
fallback?: BackgroundRegistration,
|
|
195
|
+
): BackgroundRegistration | undefined {
|
|
196
|
+
if (!raw || typeof raw !== "object") {
|
|
197
|
+
return fallback
|
|
198
|
+
? {
|
|
199
|
+
sourceRegion: fallback.sourceRegion
|
|
200
|
+
? { ...fallback.sourceRegion }
|
|
201
|
+
: undefined,
|
|
202
|
+
targetFrame: fallback.targetFrame,
|
|
203
|
+
fit: fallback.fit,
|
|
204
|
+
}
|
|
205
|
+
: undefined;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const input = raw as Partial<BackgroundRegistration>;
|
|
209
|
+
const normalized: BackgroundRegistration = {
|
|
210
|
+
sourceRegion: normalizeRegistrationRegion(
|
|
211
|
+
input.sourceRegion,
|
|
212
|
+
fallback?.sourceRegion,
|
|
213
|
+
),
|
|
214
|
+
targetFrame: normalizeRegistrationFrame(
|
|
215
|
+
input.targetFrame,
|
|
216
|
+
fallback?.targetFrame || "trim",
|
|
217
|
+
),
|
|
218
|
+
fit: normalizeFitMode(input.fit, fallback?.fit || "stretch"),
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
if (!normalized.sourceRegion) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return normalized;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function cloneRegistration(
|
|
229
|
+
registration?: BackgroundRegistration,
|
|
230
|
+
): BackgroundRegistration | undefined {
|
|
231
|
+
if (!registration) return undefined;
|
|
232
|
+
return {
|
|
233
|
+
sourceRegion: registration.sourceRegion
|
|
234
|
+
? { ...registration.sourceRegion }
|
|
235
|
+
: undefined,
|
|
236
|
+
targetFrame: registration.targetFrame,
|
|
237
|
+
fit: registration.fit,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
113
241
|
function normalizeLayer(
|
|
114
242
|
raw: unknown,
|
|
115
243
|
index: number,
|
|
@@ -128,7 +256,10 @@ function normalizeLayer(
|
|
|
128
256
|
};
|
|
129
257
|
|
|
130
258
|
if (!raw || typeof raw !== "object") {
|
|
131
|
-
return {
|
|
259
|
+
return {
|
|
260
|
+
...fallbackLayer,
|
|
261
|
+
registration: cloneRegistration(fallbackLayer.registration),
|
|
262
|
+
};
|
|
132
263
|
}
|
|
133
264
|
|
|
134
265
|
const input = raw as Partial<BackgroundLayer>;
|
|
@@ -167,6 +298,10 @@ function normalizeLayer(
|
|
|
167
298
|
? fallbackLayer.src
|
|
168
299
|
: ""
|
|
169
300
|
: undefined,
|
|
301
|
+
registration:
|
|
302
|
+
kind === "image"
|
|
303
|
+
? normalizeRegistration(input.registration, fallbackLayer.registration)
|
|
304
|
+
: undefined,
|
|
170
305
|
};
|
|
171
306
|
}
|
|
172
307
|
|
|
@@ -207,7 +342,10 @@ function normalizeConfig(raw: unknown): BackgroundConfig {
|
|
|
207
342
|
function cloneConfig(config: BackgroundConfig): BackgroundConfig {
|
|
208
343
|
return {
|
|
209
344
|
version: config.version,
|
|
210
|
-
layers: (config.layers || []).map((layer) => ({
|
|
345
|
+
layers: (config.layers || []).map((layer) => ({
|
|
346
|
+
...layer,
|
|
347
|
+
registration: cloneRegistration(layer.registration),
|
|
348
|
+
})),
|
|
211
349
|
};
|
|
212
350
|
}
|
|
213
351
|
|
|
@@ -501,6 +639,44 @@ export class BackgroundTool implements Extension {
|
|
|
501
639
|
};
|
|
502
640
|
}
|
|
503
641
|
|
|
642
|
+
private resolveTargetFrameRect(frame: BackgroundRegistrationFrame): Rect | null {
|
|
643
|
+
if (frame === "viewport") {
|
|
644
|
+
return this.getViewportRect();
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const layout = this.resolveSceneLayout();
|
|
648
|
+
if (!layout) {
|
|
649
|
+
return frame === "focus" ? this.getViewportRect() : null;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
switch (frame) {
|
|
653
|
+
case "trim":
|
|
654
|
+
case "focus":
|
|
655
|
+
return {
|
|
656
|
+
left: layout.trimRect.left,
|
|
657
|
+
top: layout.trimRect.top,
|
|
658
|
+
width: layout.trimRect.width,
|
|
659
|
+
height: layout.trimRect.height,
|
|
660
|
+
};
|
|
661
|
+
case "cut":
|
|
662
|
+
return {
|
|
663
|
+
left: layout.cutRect.left,
|
|
664
|
+
top: layout.cutRect.top,
|
|
665
|
+
width: layout.cutRect.width,
|
|
666
|
+
height: layout.cutRect.height,
|
|
667
|
+
};
|
|
668
|
+
case "bleed":
|
|
669
|
+
return {
|
|
670
|
+
left: layout.bleedRect.left,
|
|
671
|
+
top: layout.bleedRect.top,
|
|
672
|
+
width: layout.bleedRect.width,
|
|
673
|
+
height: layout.bleedRect.height,
|
|
674
|
+
};
|
|
675
|
+
default:
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
504
680
|
private resolveAnchorRect(anchor: string): Rect {
|
|
505
681
|
if (anchor === "focus") {
|
|
506
682
|
return this.resolveFocusRect() || this.getViewportRect();
|
|
@@ -548,6 +724,85 @@ export class BackgroundTool implements Extension {
|
|
|
548
724
|
};
|
|
549
725
|
}
|
|
550
726
|
|
|
727
|
+
private resolveRegistrationRegion(
|
|
728
|
+
region: BackgroundRegistrationRegion,
|
|
729
|
+
sourceSize: SourceSize,
|
|
730
|
+
): Rect | null {
|
|
731
|
+
const sourceWidth = Math.max(1, Number(sourceSize.width || 0));
|
|
732
|
+
const sourceHeight = Math.max(1, Number(sourceSize.height || 0));
|
|
733
|
+
const width =
|
|
734
|
+
region.unit === "normalized" ? region.width * sourceWidth : region.width;
|
|
735
|
+
const height =
|
|
736
|
+
region.unit === "normalized"
|
|
737
|
+
? region.height * sourceHeight
|
|
738
|
+
: region.height;
|
|
739
|
+
const left =
|
|
740
|
+
region.unit === "normalized" ? region.left * sourceWidth : region.left;
|
|
741
|
+
const top =
|
|
742
|
+
region.unit === "normalized" ? region.top * sourceHeight : region.top;
|
|
743
|
+
|
|
744
|
+
if (
|
|
745
|
+
!Number.isFinite(left) ||
|
|
746
|
+
!Number.isFinite(top) ||
|
|
747
|
+
!Number.isFinite(width) ||
|
|
748
|
+
!Number.isFinite(height) ||
|
|
749
|
+
width <= 0 ||
|
|
750
|
+
height <= 0
|
|
751
|
+
) {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return { left, top, width, height };
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
private resolveRegistrationPlacement(
|
|
759
|
+
layer: BackgroundLayer,
|
|
760
|
+
sourceSize: SourceSize,
|
|
761
|
+
): { left: number; top: number; scaleX: number; scaleY: number } | null {
|
|
762
|
+
const registration = layer.registration;
|
|
763
|
+
if (!registration?.sourceRegion) return null;
|
|
764
|
+
|
|
765
|
+
const targetRect = this.resolveTargetFrameRect(
|
|
766
|
+
registration.targetFrame || "trim",
|
|
767
|
+
);
|
|
768
|
+
if (!targetRect) return null;
|
|
769
|
+
|
|
770
|
+
const sourceRegion = this.resolveRegistrationRegion(
|
|
771
|
+
registration.sourceRegion,
|
|
772
|
+
sourceSize,
|
|
773
|
+
);
|
|
774
|
+
if (!sourceRegion) return null;
|
|
775
|
+
|
|
776
|
+
const fit = registration.fit || "stretch";
|
|
777
|
+
const baseScaleX = targetRect.width / sourceRegion.width;
|
|
778
|
+
const baseScaleY = targetRect.height / sourceRegion.height;
|
|
779
|
+
|
|
780
|
+
if (fit === "stretch") {
|
|
781
|
+
return {
|
|
782
|
+
left: targetRect.left - sourceRegion.left * baseScaleX,
|
|
783
|
+
top: targetRect.top - sourceRegion.top * baseScaleY,
|
|
784
|
+
scaleX: baseScaleX,
|
|
785
|
+
scaleY: baseScaleY,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const uniformScale =
|
|
790
|
+
fit === "contain"
|
|
791
|
+
? Math.min(baseScaleX, baseScaleY)
|
|
792
|
+
: Math.max(baseScaleX, baseScaleY);
|
|
793
|
+
const alignedWidth = sourceRegion.width * uniformScale;
|
|
794
|
+
const alignedHeight = sourceRegion.height * uniformScale;
|
|
795
|
+
const offsetLeft = targetRect.left + (targetRect.width - alignedWidth) / 2;
|
|
796
|
+
const offsetTop = targetRect.top + (targetRect.height - alignedHeight) / 2;
|
|
797
|
+
|
|
798
|
+
return {
|
|
799
|
+
left: offsetLeft - sourceRegion.left * uniformScale,
|
|
800
|
+
top: offsetTop - sourceRegion.top * uniformScale,
|
|
801
|
+
scaleX: uniformScale,
|
|
802
|
+
scaleY: uniformScale,
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
551
806
|
private buildColorLayerSpec(layer: BackgroundLayer): RenderObjectSpec {
|
|
552
807
|
const rect = this.resolveAnchorRect(layer.anchor);
|
|
553
808
|
|
|
@@ -585,8 +840,13 @@ export class BackgroundTool implements Extension {
|
|
|
585
840
|
const sourceSize = this.sourceSizeCache.getSourceSize(src);
|
|
586
841
|
if (!sourceSize) return [];
|
|
587
842
|
|
|
588
|
-
const
|
|
589
|
-
|
|
843
|
+
const placement =
|
|
844
|
+
this.resolveRegistrationPlacement(layer, sourceSize) ||
|
|
845
|
+
this.resolveImagePlacement(
|
|
846
|
+
this.resolveAnchorRect(layer.anchor),
|
|
847
|
+
sourceSize,
|
|
848
|
+
layer.fit,
|
|
849
|
+
);
|
|
590
850
|
|
|
591
851
|
return [
|
|
592
852
|
{
|