@smoove/core 0.1.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/LICENSE +21 -0
- package/README.md +80 -0
- package/dist/animation/color.d.ts +9 -0
- package/dist/animation/color.d.ts.map +1 -0
- package/dist/animation/color.js +224 -0
- package/dist/animation/color.js.map +1 -0
- package/dist/animation/easing.d.ts +22 -0
- package/dist/animation/easing.d.ts.map +1 -0
- package/dist/animation/easing.js +59 -0
- package/dist/animation/easing.js.map +1 -0
- package/dist/animation/interpolate-colors.d.ts +7 -0
- package/dist/animation/interpolate-colors.d.ts.map +1 -0
- package/dist/animation/interpolate-colors.js +19 -0
- package/dist/animation/interpolate-colors.js.map +1 -0
- package/dist/animation/interpolate.d.ts +12 -0
- package/dist/animation/interpolate.d.ts.map +1 -0
- package/dist/animation/interpolate.js +65 -0
- package/dist/animation/interpolate.js.map +1 -0
- package/dist/audio/asset.d.ts +21 -0
- package/dist/audio/asset.d.ts.map +1 -0
- package/dist/audio/asset.js +2 -0
- package/dist/audio/asset.js.map +1 -0
- package/dist/audio/audio-driver.d.ts +34 -0
- package/dist/audio/audio-driver.d.ts.map +1 -0
- package/dist/audio/audio-driver.js +2 -0
- package/dist/audio/audio-driver.js.map +1 -0
- package/dist/audio/audio-for-preview.d.ts +12 -0
- package/dist/audio/audio-for-preview.d.ts.map +1 -0
- package/dist/audio/audio-for-preview.js +70 -0
- package/dist/audio/audio-for-preview.js.map +1 -0
- package/dist/audio/audio-for-rendering.d.ts +16 -0
- package/dist/audio/audio-for-rendering.d.ts.map +1 -0
- package/dist/audio/audio-for-rendering.js +32 -0
- package/dist/audio/audio-for-rendering.js.map +1 -0
- package/dist/audio/audio-source-browser.d.ts +30 -0
- package/dist/audio/audio-source-browser.d.ts.map +1 -0
- package/dist/audio/audio-source-browser.js +139 -0
- package/dist/audio/audio-source-browser.js.map +1 -0
- package/dist/audio/audio-source.d.ts +38 -0
- package/dist/audio/audio-source.d.ts.map +1 -0
- package/dist/audio/audio-source.js +2 -0
- package/dist/audio/audio-source.js.map +1 -0
- package/dist/audio/index.d.ts +45 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +143 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/audio/mixer.d.ts +43 -0
- package/dist/audio/mixer.d.ts.map +1 -0
- package/dist/audio/mixer.js +51 -0
- package/dist/audio/mixer.js.map +1 -0
- package/dist/audio/types.d.ts +31 -0
- package/dist/audio/types.d.ts.map +1 -0
- package/dist/audio/types.js +2 -0
- package/dist/audio/types.js.map +1 -0
- package/dist/block.d.ts +16 -0
- package/dist/block.d.ts.map +1 -0
- package/dist/block.js +173 -0
- package/dist/block.js.map +1 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js.map +1 -0
- package/dist/easing.d.ts +22 -0
- package/dist/easing.d.ts.map +1 -0
- package/dist/easing.js +59 -0
- package/dist/easing.js.map +1 -0
- package/dist/emitter.d.ts +7 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +29 -0
- package/dist/emitter.js.map +1 -0
- package/dist/engine/composition.d.ts +182 -0
- package/dist/engine/composition.d.ts.map +1 -0
- package/dist/engine/composition.js +527 -0
- package/dist/engine/composition.js.map +1 -0
- package/dist/engine/emitter.d.ts +7 -0
- package/dist/engine/emitter.d.ts.map +1 -0
- package/dist/engine/emitter.js +29 -0
- package/dist/engine/emitter.js.map +1 -0
- package/dist/engine/environment.d.ts +30 -0
- package/dist/engine/environment.d.ts.map +1 -0
- package/dist/engine/environment.js +27 -0
- package/dist/engine/environment.js.map +1 -0
- package/dist/engine/offsets.d.ts +39 -0
- package/dist/engine/offsets.d.ts.map +1 -0
- package/dist/engine/offsets.js +54 -0
- package/dist/engine/offsets.js.map +1 -0
- package/dist/engine/runtime-defaults.d.ts +50 -0
- package/dist/engine/runtime-defaults.d.ts.map +1 -0
- package/dist/engine/runtime-defaults.js +77 -0
- package/dist/engine/runtime-defaults.js.map +1 -0
- package/dist/engine/sequence.d.ts +44 -0
- package/dist/engine/sequence.d.ts.map +1 -0
- package/dist/engine/sequence.js +101 -0
- package/dist/engine/sequence.js.map +1 -0
- package/dist/engine/series.d.ts +40 -0
- package/dist/engine/series.d.ts.map +1 -0
- package/dist/engine/series.js +58 -0
- package/dist/engine/series.js.map +1 -0
- package/dist/engine/signal.d.ts +10 -0
- package/dist/engine/signal.d.ts.map +1 -0
- package/dist/engine/signal.js +39 -0
- package/dist/engine/signal.js.map +1 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js.map +1 -0
- package/dist/flex-engine.d.ts +31 -0
- package/dist/flex-engine.d.ts.map +1 -0
- package/dist/flex-engine.js +186 -0
- package/dist/flex-engine.js.map +1 -0
- package/dist/flex-types.d.ts +165 -0
- package/dist/flex-types.d.ts.map +1 -0
- package/dist/flex-types.js +2 -0
- package/dist/flex-types.js.map +1 -0
- package/dist/flex.d.ts +26 -0
- package/dist/flex.d.ts.map +1 -0
- package/dist/flex.js +179 -0
- package/dist/flex.js.map +1 -0
- package/dist/image.d.ts +10 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +156 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolate-colors.d.ts +7 -0
- package/dist/interpolate-colors.d.ts.map +1 -0
- package/dist/interpolate-colors.js +240 -0
- package/dist/interpolate-colors.js.map +1 -0
- package/dist/interpolate.d.ts +12 -0
- package/dist/interpolate.d.ts.map +1 -0
- package/dist/interpolate.js +65 -0
- package/dist/interpolate.js.map +1 -0
- package/dist/layout/block.d.ts +54 -0
- package/dist/layout/block.d.ts.map +1 -0
- package/dist/layout/block.js +186 -0
- package/dist/layout/block.js.map +1 -0
- package/dist/layout/contract.d.ts +41 -0
- package/dist/layout/contract.d.ts.map +1 -0
- package/dist/layout/contract.js +8 -0
- package/dist/layout/contract.js.map +1 -0
- package/dist/layout/flex/engine.d.ts +31 -0
- package/dist/layout/flex/engine.d.ts.map +1 -0
- package/dist/layout/flex/engine.js +186 -0
- package/dist/layout/flex/engine.js.map +1 -0
- package/dist/layout/flex/flex.d.ts +31 -0
- package/dist/layout/flex/flex.d.ts.map +1 -0
- package/dist/layout/flex/flex.js +175 -0
- package/dist/layout/flex/flex.js.map +1 -0
- package/dist/layout/flex/mixin.d.ts +52 -0
- package/dist/layout/flex/mixin.d.ts.map +1 -0
- package/dist/layout/flex/mixin.js +114 -0
- package/dist/layout/flex/mixin.js.map +1 -0
- package/dist/layout/flex/types.d.ts +31 -0
- package/dist/layout/flex/types.d.ts.map +1 -0
- package/dist/layout/flex/types.js +2 -0
- package/dist/layout/flex/types.js.map +1 -0
- package/dist/layout/image.d.ts +46 -0
- package/dist/layout/image.d.ts.map +1 -0
- package/dist/layout/image.js +198 -0
- package/dist/layout/image.js.map +1 -0
- package/dist/layout/shapes.d.ts +72 -0
- package/dist/layout/shapes.d.ts.map +1 -0
- package/dist/layout/shapes.js +29 -0
- package/dist/layout/shapes.js.map +1 -0
- package/dist/layout/text/font.d.ts +92 -0
- package/dist/layout/text/font.d.ts.map +1 -0
- package/dist/layout/text/font.js +166 -0
- package/dist/layout/text/font.js.map +1 -0
- package/dist/layout/text/geometry.d.ts +31 -0
- package/dist/layout/text/geometry.d.ts.map +1 -0
- package/dist/layout/text/geometry.js +81 -0
- package/dist/layout/text/geometry.js.map +1 -0
- package/dist/layout/text/text.d.ts +98 -0
- package/dist/layout/text/text.d.ts.map +1 -0
- package/dist/layout/text/text.js +676 -0
- package/dist/layout/text/text.js.map +1 -0
- package/dist/layout/text/types.d.ts +103 -0
- package/dist/layout/text/types.d.ts.map +1 -0
- package/dist/layout/text/types.js +2 -0
- package/dist/layout/text/types.js.map +1 -0
- package/dist/media/audio/asset.d.ts +21 -0
- package/dist/media/audio/asset.d.ts.map +1 -0
- package/dist/media/audio/asset.js +2 -0
- package/dist/media/audio/asset.js.map +1 -0
- package/dist/media/audio/audio-driver.d.ts +34 -0
- package/dist/media/audio/audio-driver.d.ts.map +1 -0
- package/dist/media/audio/audio-driver.js +2 -0
- package/dist/media/audio/audio-driver.js.map +1 -0
- package/dist/media/audio/audio-for-preview.d.ts +47 -0
- package/dist/media/audio/audio-for-preview.d.ts.map +1 -0
- package/dist/media/audio/audio-for-preview.js +232 -0
- package/dist/media/audio/audio-for-preview.js.map +1 -0
- package/dist/media/audio/audio-for-rendering.d.ts +16 -0
- package/dist/media/audio/audio-for-rendering.d.ts.map +1 -0
- package/dist/media/audio/audio-for-rendering.js +32 -0
- package/dist/media/audio/audio-for-rendering.js.map +1 -0
- package/dist/media/audio/audio-source-browser.d.ts +30 -0
- package/dist/media/audio/audio-source-browser.d.ts.map +1 -0
- package/dist/media/audio/audio-source-browser.js +139 -0
- package/dist/media/audio/audio-source-browser.js.map +1 -0
- package/dist/media/audio/audio-source-mediabunny.d.ts +45 -0
- package/dist/media/audio/audio-source-mediabunny.d.ts.map +1 -0
- package/dist/media/audio/audio-source-mediabunny.js +79 -0
- package/dist/media/audio/audio-source-mediabunny.js.map +1 -0
- package/dist/media/audio/audio-source.d.ts +38 -0
- package/dist/media/audio/audio-source.d.ts.map +1 -0
- package/dist/media/audio/audio-source.js +2 -0
- package/dist/media/audio/audio-source.js.map +1 -0
- package/dist/media/audio/index.d.ts +57 -0
- package/dist/media/audio/index.d.ts.map +1 -0
- package/dist/media/audio/index.js +170 -0
- package/dist/media/audio/index.js.map +1 -0
- package/dist/media/audio/mixer.d.ts +43 -0
- package/dist/media/audio/mixer.d.ts.map +1 -0
- package/dist/media/audio/mixer.js +51 -0
- package/dist/media/audio/mixer.js.map +1 -0
- package/dist/media/audio/shared-audio-context.d.ts +30 -0
- package/dist/media/audio/shared-audio-context.d.ts.map +1 -0
- package/dist/media/audio/shared-audio-context.js +68 -0
- package/dist/media/audio/shared-audio-context.js.map +1 -0
- package/dist/media/audio/types.d.ts +31 -0
- package/dist/media/audio/types.d.ts.map +1 -0
- package/dist/media/audio/types.js +2 -0
- package/dist/media/audio/types.js.map +1 -0
- package/dist/media/media-marker.d.ts +26 -0
- package/dist/media/media-marker.d.ts.map +1 -0
- package/dist/media/media-marker.js +26 -0
- package/dist/media/media-marker.js.map +1 -0
- package/dist/media/media-time.d.ts +17 -0
- package/dist/media/media-time.d.ts.map +1 -0
- package/dist/media/media-time.js +17 -0
- package/dist/media/media-time.js.map +1 -0
- package/dist/media/video/driver.d.ts +31 -0
- package/dist/media/video/driver.d.ts.map +1 -0
- package/dist/media/video/driver.js +3 -0
- package/dist/media/video/driver.js.map +1 -0
- package/dist/media/video/index.d.ts +66 -0
- package/dist/media/video/index.d.ts.map +1 -0
- package/dist/media/video/index.js +372 -0
- package/dist/media/video/index.js.map +1 -0
- package/dist/media/video/types.d.ts +36 -0
- package/dist/media/video/types.d.ts.map +1 -0
- package/dist/media/video/types.js +2 -0
- package/dist/media/video/types.js.map +1 -0
- package/dist/media/video/video-for-preview.d.ts +17 -0
- package/dist/media/video/video-for-preview.d.ts.map +1 -0
- package/dist/media/video/video-for-preview.js +30 -0
- package/dist/media/video/video-for-preview.js.map +1 -0
- package/dist/media/video/video-for-rendering.d.ts +17 -0
- package/dist/media/video/video-for-rendering.d.ts.map +1 -0
- package/dist/media/video/video-for-rendering.js +59 -0
- package/dist/media/video/video-for-rendering.js.map +1 -0
- package/dist/media/video/video-source-browser.d.ts +37 -0
- package/dist/media/video/video-source-browser.d.ts.map +1 -0
- package/dist/media/video/video-source-browser.js +171 -0
- package/dist/media/video/video-source-browser.js.map +1 -0
- package/dist/media/video/video-source-mediabunny.d.ts +69 -0
- package/dist/media/video/video-source-mediabunny.d.ts.map +1 -0
- package/dist/media/video/video-source-mediabunny.js +236 -0
- package/dist/media/video/video-source-mediabunny.js.map +1 -0
- package/dist/media/video/video-source.d.ts +48 -0
- package/dist/media/video/video-source.d.ts.map +1 -0
- package/dist/media/video/video-source.js +2 -0
- package/dist/media/video/video-source.js.map +1 -0
- package/dist/media-marker.d.ts +19 -0
- package/dist/media-marker.d.ts.map +1 -0
- package/dist/media-marker.js +19 -0
- package/dist/media-marker.js.map +1 -0
- package/dist/media-time.d.ts +17 -0
- package/dist/media-time.d.ts.map +1 -0
- package/dist/media-time.js +17 -0
- package/dist/media-time.js.map +1 -0
- package/dist/signal.d.ts +10 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +39 -0
- package/dist/signal.js.map +1 -0
- package/dist/text.d.ts +91 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +704 -0
- package/dist/text.js.map +1 -0
- package/dist/video/driver.d.ts +31 -0
- package/dist/video/driver.d.ts.map +1 -0
- package/dist/video/driver.js +3 -0
- package/dist/video/driver.js.map +1 -0
- package/dist/video/index.d.ts +45 -0
- package/dist/video/index.d.ts.map +1 -0
- package/dist/video/index.js +276 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/types.d.ts +35 -0
- package/dist/video/types.d.ts.map +1 -0
- package/dist/video/types.js +2 -0
- package/dist/video/types.js.map +1 -0
- package/dist/video/video-for-preview.d.ts +12 -0
- package/dist/video/video-for-preview.d.ts.map +1 -0
- package/dist/video/video-for-preview.js +73 -0
- package/dist/video/video-for-preview.js.map +1 -0
- package/dist/video/video-for-rendering.d.ts +16 -0
- package/dist/video/video-for-rendering.d.ts.map +1 -0
- package/dist/video/video-for-rendering.js +45 -0
- package/dist/video/video-for-rendering.js.map +1 -0
- package/dist/video/video-source-browser.d.ts +37 -0
- package/dist/video/video-source-browser.d.ts.map +1 -0
- package/dist/video/video-source-browser.js +171 -0
- package/dist/video/video-source-browser.js.map +1 -0
- package/dist/video/video-source.d.ts +48 -0
- package/dist/video/video-source.d.ts.map +1 -0
- package/dist/video/video-source.js +2 -0
- package/dist/video/video-source.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { DIRECTION_LTR } from "flexily/classic";
|
|
2
|
+
import Konva from "konva";
|
|
3
|
+
import { isKMLayoutNode } from "../contract.js";
|
|
4
|
+
import { applyChildProps, applyContainerProps, applySize, FlexilyNode, parseSize, setImageMeasure, setTextMeasure, } from "./engine.js";
|
|
5
|
+
const FLEX_KEYS = [
|
|
6
|
+
"flexDirection",
|
|
7
|
+
"justifyContent",
|
|
8
|
+
"alignItems",
|
|
9
|
+
"gap",
|
|
10
|
+
"padding",
|
|
11
|
+
"flexGrow",
|
|
12
|
+
"flexShrink",
|
|
13
|
+
"flexBasis",
|
|
14
|
+
"alignSelf",
|
|
15
|
+
"margin",
|
|
16
|
+
];
|
|
17
|
+
function pickKonvaConfig(config) {
|
|
18
|
+
const out = { ...config };
|
|
19
|
+
for (const k of FLEX_KEYS)
|
|
20
|
+
delete out[k];
|
|
21
|
+
const w = parseSize(config.width);
|
|
22
|
+
const h = parseSize(config.height);
|
|
23
|
+
out.width = w?.kind === "px" ? w.value : undefined;
|
|
24
|
+
out.height = h?.kind === "px" ? h.value : undefined;
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
export class Flex extends Konva.Group {
|
|
28
|
+
_kmRole = "container";
|
|
29
|
+
constructor(config) {
|
|
30
|
+
super(pickKonvaConfig(config));
|
|
31
|
+
this.setAttrs({
|
|
32
|
+
flexDirection: config.flexDirection,
|
|
33
|
+
justifyContent: config.justifyContent,
|
|
34
|
+
alignItems: config.alignItems,
|
|
35
|
+
gap: config.gap,
|
|
36
|
+
padding: config.padding,
|
|
37
|
+
flexGrow: config.flexGrow,
|
|
38
|
+
flexShrink: config.flexShrink,
|
|
39
|
+
flexBasis: config.flexBasis,
|
|
40
|
+
alignSelf: config.alignSelf,
|
|
41
|
+
margin: config.margin,
|
|
42
|
+
flexWidth: config.width,
|
|
43
|
+
flexHeight: config.height,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
computeLayout() {
|
|
47
|
+
layoutRoot(this, false);
|
|
48
|
+
}
|
|
49
|
+
/** @internal — {@link KMLayoutNode}: lay self out as a flex root (Sequence calls this). */
|
|
50
|
+
_kmComputeLayout() {
|
|
51
|
+
this.computeLayout();
|
|
52
|
+
}
|
|
53
|
+
/** @internal — {@link KMLayoutNode}: write the computed box back (nested in a parent flex). */
|
|
54
|
+
_kmPlace(box) {
|
|
55
|
+
this.x(box.left);
|
|
56
|
+
this.y(box.top);
|
|
57
|
+
this.width(box.width);
|
|
58
|
+
this.height(box.height);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Lay out a Konva.Group as a Flexily root: build the layout tree from the
|
|
63
|
+
* group's attrs + children, compute, and write positions/sizes back.
|
|
64
|
+
*
|
|
65
|
+
* When `alwaysSetSize` is true the group's own width/height are always pulled
|
|
66
|
+
* from the computed content size — needed for a hug-content root that draws a
|
|
67
|
+
* background (Block) so the background isn't 0×0. Flex passes false, preserving
|
|
68
|
+
* its behavior of only writing self-size when an explicit px size is given.
|
|
69
|
+
*/
|
|
70
|
+
export function layoutRoot(group, alwaysSetSize) {
|
|
71
|
+
const w = readPixelSize(group.attrs.flexWidth);
|
|
72
|
+
const h = readPixelSize(group.attrs.flexHeight);
|
|
73
|
+
const root = FlexilyNode.create();
|
|
74
|
+
applyContainerProps(root, group.attrs);
|
|
75
|
+
if (w > 0)
|
|
76
|
+
root.setWidth(w);
|
|
77
|
+
if (h > 0)
|
|
78
|
+
root.setHeight(h);
|
|
79
|
+
const pairs = [];
|
|
80
|
+
buildChildren(group.getChildren(), root, pairs, group.attrs.flexDirection ?? "row");
|
|
81
|
+
root.calculateLayout(w > 0 ? w : undefined, h > 0 ? h : undefined, DIRECTION_LTR);
|
|
82
|
+
if (alwaysSetSize || w > 0)
|
|
83
|
+
group.width(root.getComputedWidth());
|
|
84
|
+
if (alwaysSetSize || h > 0)
|
|
85
|
+
group.height(root.getComputedHeight());
|
|
86
|
+
writeBack(pairs);
|
|
87
|
+
root.freeRecursive();
|
|
88
|
+
}
|
|
89
|
+
function readPixelSize(sizeAttr) {
|
|
90
|
+
const parsed = parseSize(sizeAttr);
|
|
91
|
+
if (parsed?.kind === "px")
|
|
92
|
+
return parsed.value;
|
|
93
|
+
// No explicit px size → hug content. Return 0 (not the node's current Konva
|
|
94
|
+
// size): falling back to the last-computed size would pin a hug-content root
|
|
95
|
+
// to its first-tick height and stop it re-growing as children change size.
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
export function buildChildren(children, parentFlex, pairs, parentDirection = "row") {
|
|
99
|
+
// Skip the Block background rect and any hidden child (display:none semantics —
|
|
100
|
+
// an invisible node takes no layout space, so staggered/toggled children don't
|
|
101
|
+
// leave gaps).
|
|
102
|
+
const laidOut = children.filter((c) => !c.attrs.__blockBg && c.visible() !== false);
|
|
103
|
+
const parentIsColumn = parentDirection.startsWith("column");
|
|
104
|
+
laidOut.forEach((child, i) => {
|
|
105
|
+
const node = FlexilyNode.create();
|
|
106
|
+
applyChildProps(node, child.attrs);
|
|
107
|
+
if (isKMLayoutNode(child)) {
|
|
108
|
+
// smoove wrapper: it self-describes its layout via the contract.
|
|
109
|
+
if (child._kmRole === "container") {
|
|
110
|
+
const props = child.attrs;
|
|
111
|
+
applyContainerProps(node, props);
|
|
112
|
+
applySize(node, child.attrs.flexWidth, child.attrs.flexHeight);
|
|
113
|
+
buildChildren(child.getChildren(), node, pairs, props.flexDirection ?? "row");
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
child._kmMeasure?.(node, { parentIsColumn });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (child instanceof Konva.Text) {
|
|
120
|
+
// Raw Konva.Text (no wrapper): measure with wrap awareness.
|
|
121
|
+
if (child.attrs.flexWidth === undefined && parentIsColumn)
|
|
122
|
+
node.setWidthPercent(100);
|
|
123
|
+
else
|
|
124
|
+
applySize(node, child.attrs.flexWidth, undefined);
|
|
125
|
+
setTextMeasure(node, child, parentIsColumn);
|
|
126
|
+
}
|
|
127
|
+
else if (child instanceof Konva.Image) {
|
|
128
|
+
// Raw Konva.Image (no wrapper): intrinsic size from the bitmap.
|
|
129
|
+
applySize(node, child.attrs.flexWidth, child.attrs.flexHeight);
|
|
130
|
+
if (child.attrs.flexWidth === undefined && child.attrs.flexHeight === undefined) {
|
|
131
|
+
setImageMeasure(node, child);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Any other raw Konva node: size from numeric width/height attrs.
|
|
136
|
+
const w = child.attrs.width;
|
|
137
|
+
const h = child.attrs.height;
|
|
138
|
+
if (typeof w === "number" && w > 0)
|
|
139
|
+
node.setWidth(w);
|
|
140
|
+
if (typeof h === "number" && h > 0)
|
|
141
|
+
node.setHeight(h);
|
|
142
|
+
}
|
|
143
|
+
pairs.push({ konva: child, flex: node });
|
|
144
|
+
parentFlex.insertChild(node, i);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function writeBack(pairs) {
|
|
148
|
+
for (const { konva, flex } of pairs) {
|
|
149
|
+
const left = flex.getComputedLeft();
|
|
150
|
+
const top = flex.getComputedTop();
|
|
151
|
+
const width = flex.getComputedWidth();
|
|
152
|
+
const height = flex.getComputedHeight();
|
|
153
|
+
if (isKMLayoutNode(konva)) {
|
|
154
|
+
// Wrapper handles its own position/size/restyle (origin-corrected per shape).
|
|
155
|
+
konva._kmPlace({ left, top, width, height });
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
// Raw Konva fallback. Origin-correct via getSelfRect so centered-origin
|
|
159
|
+
// shapes (e.g. a bare Konva.Circle) land their bounding box at the slot;
|
|
160
|
+
// top-left-origin nodes have selfRect.x === 0, so this is a no-op for them.
|
|
161
|
+
const r = konva.getSelfRect();
|
|
162
|
+
konva.x(left - r.x);
|
|
163
|
+
konva.y(top - r.y);
|
|
164
|
+
if (konva instanceof Konva.Text) {
|
|
165
|
+
if (konva.attrs.wrap === undefined)
|
|
166
|
+
konva.wrap("word");
|
|
167
|
+
konva.width(width);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
konva.width(width);
|
|
171
|
+
konva.height(height);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=flex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flex.js","sourceRoot":"","sources":["../../../src/layout/flex/flex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Node as FlexilyNode } from "flexily/classic";
|
|
2
|
+
import type Konva from "konva";
|
|
3
|
+
import type { KMLayoutNode, LayoutBox } from "../contract.js";
|
|
4
|
+
import type { FlexChildProps, SizeValue } from "./types.js";
|
|
5
|
+
/** Common shape-config shape: a Konva config plus flex-child props + size values. */
|
|
6
|
+
export type LeafConfig = FlexChildProps & {
|
|
7
|
+
width?: SizeValue;
|
|
8
|
+
height?: SizeValue;
|
|
9
|
+
} & Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Strip smoove-only keys and translate `width`/`height` (which may be a
|
|
12
|
+
* `%` string) into a plain Konva config. Mirrors the per-wrapper
|
|
13
|
+
* `pickKonvaConfig` helpers in `block.ts`/`image.ts`/`video.ts` so leaf shapes
|
|
14
|
+
* don't each re-implement it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function pickLeafConfig(config: LeafConfig): Record<string, unknown>;
|
|
17
|
+
/** Record flex child props + the original `width`/`height` size values as attrs. */
|
|
18
|
+
export declare function applyLeafFlexAttrs(node: Konva.Node, config: LeafConfig): void;
|
|
19
|
+
/**
|
|
20
|
+
* Configure a leaf shape's flexily sizing: honor an explicit `px`/`%`
|
|
21
|
+
* width/height, and when neither is given fall back to the shape's intrinsic
|
|
22
|
+
* size (its `getSelfRect()` bounds — diameter for a circle, points-bbox for a
|
|
23
|
+
* line, etc.) as a fixed basis. Using a fixed width/height (rather than a
|
|
24
|
+
* flexily measure callback) keeps the size deterministic — a measure callback
|
|
25
|
+
* isn't reliably consulted for these leaf nodes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function leafMeasure(shape: Konva.Shape, node: FlexilyNode): void;
|
|
28
|
+
/**
|
|
29
|
+
* Write the computed box back onto a leaf shape. Position is corrected for the
|
|
30
|
+
* shape's origin via `getSelfRect()`: top-left-origin shapes (Rect) have
|
|
31
|
+
* `selfRect.x === 0`, while centered-origin shapes (Circle, Ellipse, Ring,
|
|
32
|
+
* Arc, Wedge, RegularPolygon, Star) have a negative offset, so this lands the
|
|
33
|
+
* shape's *bounding box* at the flex slot. width/height are written through
|
|
34
|
+
* Konva's setters; for radius/points-based shapes those derive geometry, so
|
|
35
|
+
* `flexGrow`-driven stretch can distort them — give such shapes an explicit
|
|
36
|
+
* size (or keep them un-stretched) for predictable results.
|
|
37
|
+
*/
|
|
38
|
+
export declare function leafPlace(shape: Konva.Shape, box: LayoutBox): void;
|
|
39
|
+
/**
|
|
40
|
+
* Build a smoove leaf wrapper class over a concrete Konva shape. The
|
|
41
|
+
* returned base implements {@link KMLayoutNode} (leaf role + measure + place)
|
|
42
|
+
* and handles config stripping, so a shape wrapper is just:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* export class Rect extends FlexShape<Konva.Rect, RectConfig>(Konva.Rect) {}
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The `C` type parameter types the resulting constructor's config, so the
|
|
49
|
+
* subclass needs no body.
|
|
50
|
+
*/
|
|
51
|
+
export declare function FlexShape<N extends Konva.Shape, C extends LeafConfig = LeafConfig>(Base: new (...args: any[]) => N): new (config: C) => N & KMLayoutNode;
|
|
52
|
+
//# sourceMappingURL=mixin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mixin.d.ts","sourceRoot":"","sources":["../../../src/layout/flex/mixin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5D,qFAAqF;AACrF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAgB5B;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS1E;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAU7E;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAUvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAMlE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,SAAS,UAAU,GAAG,UAAU,EAEhF,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAC9B,KACD,MAAM,EAAE,CAAC,KACN,CAAC,GAAG,YAAY,CAiBpB"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { applySize, parseSize } from "./engine.js";
|
|
2
|
+
// Keys stripped before handing the config to Konva. width/height are included
|
|
3
|
+
// so they're removed when there's no px size: for radius/points shapes Konva
|
|
4
|
+
// maps width/height onto geometry, so a leftover `width: undefined` in the
|
|
5
|
+
// constructor config would wipe the radius.
|
|
6
|
+
const STRIP_KEYS = [
|
|
7
|
+
"flexGrow",
|
|
8
|
+
"flexShrink",
|
|
9
|
+
"flexBasis",
|
|
10
|
+
"alignSelf",
|
|
11
|
+
"margin",
|
|
12
|
+
"width",
|
|
13
|
+
"height",
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Strip smoove-only keys and translate `width`/`height` (which may be a
|
|
17
|
+
* `%` string) into a plain Konva config. Mirrors the per-wrapper
|
|
18
|
+
* `pickKonvaConfig` helpers in `block.ts`/`image.ts`/`video.ts` so leaf shapes
|
|
19
|
+
* don't each re-implement it.
|
|
20
|
+
*/
|
|
21
|
+
export function pickLeafConfig(config) {
|
|
22
|
+
const out = { ...config };
|
|
23
|
+
for (const k of STRIP_KEYS)
|
|
24
|
+
delete out[k];
|
|
25
|
+
// Only pixel sizes go back to Konva; `%`/hug is resolved later by the engine.
|
|
26
|
+
const w = parseSize(config.width);
|
|
27
|
+
const h = parseSize(config.height);
|
|
28
|
+
if (w?.kind === "px")
|
|
29
|
+
out.width = w.value;
|
|
30
|
+
if (h?.kind === "px")
|
|
31
|
+
out.height = h.value;
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Record flex child props + the original `width`/`height` size values as attrs. */
|
|
35
|
+
export function applyLeafFlexAttrs(node, config) {
|
|
36
|
+
node.setAttrs({
|
|
37
|
+
flexGrow: config.flexGrow,
|
|
38
|
+
flexShrink: config.flexShrink,
|
|
39
|
+
flexBasis: config.flexBasis,
|
|
40
|
+
alignSelf: config.alignSelf,
|
|
41
|
+
margin: config.margin,
|
|
42
|
+
flexWidth: config.width,
|
|
43
|
+
flexHeight: config.height,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Configure a leaf shape's flexily sizing: honor an explicit `px`/`%`
|
|
48
|
+
* width/height, and when neither is given fall back to the shape's intrinsic
|
|
49
|
+
* size (its `getSelfRect()` bounds — diameter for a circle, points-bbox for a
|
|
50
|
+
* line, etc.) as a fixed basis. Using a fixed width/height (rather than a
|
|
51
|
+
* flexily measure callback) keeps the size deterministic — a measure callback
|
|
52
|
+
* isn't reliably consulted for these leaf nodes.
|
|
53
|
+
*/
|
|
54
|
+
export function leafMeasure(shape, node) {
|
|
55
|
+
const w = shape.attrs.flexWidth;
|
|
56
|
+
const h = shape.attrs.flexHeight;
|
|
57
|
+
if (w === undefined && h === undefined) {
|
|
58
|
+
const r = shape.getSelfRect();
|
|
59
|
+
if (r.width > 0)
|
|
60
|
+
node.setWidth(r.width);
|
|
61
|
+
if (r.height > 0)
|
|
62
|
+
node.setHeight(r.height);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
applySize(node, w, h);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Write the computed box back onto a leaf shape. Position is corrected for the
|
|
69
|
+
* shape's origin via `getSelfRect()`: top-left-origin shapes (Rect) have
|
|
70
|
+
* `selfRect.x === 0`, while centered-origin shapes (Circle, Ellipse, Ring,
|
|
71
|
+
* Arc, Wedge, RegularPolygon, Star) have a negative offset, so this lands the
|
|
72
|
+
* shape's *bounding box* at the flex slot. width/height are written through
|
|
73
|
+
* Konva's setters; for radius/points-based shapes those derive geometry, so
|
|
74
|
+
* `flexGrow`-driven stretch can distort them — give such shapes an explicit
|
|
75
|
+
* size (or keep them un-stretched) for predictable results.
|
|
76
|
+
*/
|
|
77
|
+
export function leafPlace(shape, box) {
|
|
78
|
+
const r = shape.getSelfRect();
|
|
79
|
+
shape.x(box.left - r.x);
|
|
80
|
+
shape.y(box.top - r.y);
|
|
81
|
+
shape.width(box.width);
|
|
82
|
+
shape.height(box.height);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Build a smoove leaf wrapper class over a concrete Konva shape. The
|
|
86
|
+
* returned base implements {@link KMLayoutNode} (leaf role + measure + place)
|
|
87
|
+
* and handles config stripping, so a shape wrapper is just:
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* export class Rect extends FlexShape<Konva.Rect, RectConfig>(Konva.Rect) {}
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* The `C` type parameter types the resulting constructor's config, so the
|
|
94
|
+
* subclass needs no body.
|
|
95
|
+
*/
|
|
96
|
+
export function FlexShape(
|
|
97
|
+
// biome-ignore lint/suspicious/noExplicitAny: mixin base accepts any Konva shape constructor.
|
|
98
|
+
Base) {
|
|
99
|
+
class Wrapped extends Base {
|
|
100
|
+
_kmRole = "leaf";
|
|
101
|
+
constructor(config = {}) {
|
|
102
|
+
super(pickLeafConfig(config));
|
|
103
|
+
applyLeafFlexAttrs(this, config);
|
|
104
|
+
}
|
|
105
|
+
_kmMeasure(node) {
|
|
106
|
+
leafMeasure(this, node);
|
|
107
|
+
}
|
|
108
|
+
_kmPlace(box) {
|
|
109
|
+
leafPlace(this, box);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return Wrapped;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=mixin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mixin.js","sourceRoot":"","sources":["../../../src/layout/flex/mixin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type Konva from "konva";
|
|
2
|
+
export type FlexDirection = "row" | "column" | "row-reverse" | "column-reverse";
|
|
3
|
+
export type Justify = "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | "space-evenly";
|
|
4
|
+
export type Align = "flex-start" | "center" | "flex-end" | "stretch";
|
|
5
|
+
export type AlignSelf = "auto" | Align;
|
|
6
|
+
export type EdgeValue = number | [number, number] | [number, number, number, number] | {
|
|
7
|
+
top?: number;
|
|
8
|
+
right?: number;
|
|
9
|
+
bottom?: number;
|
|
10
|
+
left?: number;
|
|
11
|
+
};
|
|
12
|
+
export type SizeValue = number | `${number}%`;
|
|
13
|
+
export type FlexProps = {
|
|
14
|
+
flexDirection?: FlexDirection;
|
|
15
|
+
justifyContent?: Justify;
|
|
16
|
+
alignItems?: Align;
|
|
17
|
+
gap?: number;
|
|
18
|
+
padding?: EdgeValue;
|
|
19
|
+
};
|
|
20
|
+
export type FlexChildProps = {
|
|
21
|
+
flexGrow?: number;
|
|
22
|
+
flexShrink?: number;
|
|
23
|
+
flexBasis?: number;
|
|
24
|
+
alignSelf?: AlignSelf;
|
|
25
|
+
margin?: EdgeValue;
|
|
26
|
+
};
|
|
27
|
+
export type FlexConfig = Omit<Konva.GroupConfig, "width" | "height"> & FlexProps & FlexChildProps & {
|
|
28
|
+
width?: SizeValue;
|
|
29
|
+
height?: SizeValue;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/layout/flex/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEhF,MAAM,MAAM,OAAO,GACf,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,eAAe,GACf,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,MAAM,KAAK,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AACrE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAEvC,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,CAAC,MAAM,EAAE,MAAM,CAAC,GAChB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAChC;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC,GAClE,SAAS,GACT,cAAc,GAAG;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/layout/flex/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Konva from "konva";
|
|
2
|
+
import { type ImageLoader } from "../engine/runtime-defaults.js";
|
|
3
|
+
import type { KMLayoutNode, LayoutBox } from "./contract.js";
|
|
4
|
+
import type { FlexilyNode } from "./flex/engine.js";
|
|
5
|
+
import type { FlexChildProps, SizeValue } from "./flex/types.js";
|
|
6
|
+
export type ObjectFit = "cover" | "contain" | "fill" | "none";
|
|
7
|
+
export type ObjectPosition = "center" | "top" | "bottom" | "left" | "right" | "top left" | "top right" | "bottom left" | "bottom right";
|
|
8
|
+
export type ImageConfig = Omit<Konva.GroupConfig, "width" | "height"> & FlexChildProps & {
|
|
9
|
+
width?: SizeValue;
|
|
10
|
+
height?: SizeValue;
|
|
11
|
+
src: HTMLImageElement | string;
|
|
12
|
+
objectFit?: ObjectFit;
|
|
13
|
+
objectPosition?: ObjectPosition;
|
|
14
|
+
cornerRadius?: number | number[];
|
|
15
|
+
/**
|
|
16
|
+
* Inject an alternative image loader (e.g. a server/skia loader). Defaults
|
|
17
|
+
* to the runtime default — the DOM `<img>` loader in the browser, or
|
|
18
|
+
* whatever a server renderer registered via `setDefaultImageLoader`.
|
|
19
|
+
*/
|
|
20
|
+
loader?: ImageLoader;
|
|
21
|
+
};
|
|
22
|
+
export declare class Image extends Konva.Group implements KMLayoutNode {
|
|
23
|
+
readonly _kmRole: "leaf";
|
|
24
|
+
private readonly _img;
|
|
25
|
+
private _source;
|
|
26
|
+
/** Pending load (string src only); null once resolved or for element sources. */
|
|
27
|
+
private _loadPromise;
|
|
28
|
+
/** Guards the one-time render gate registered on first tick. */
|
|
29
|
+
private _renderGated;
|
|
30
|
+
constructor(config: ImageConfig);
|
|
31
|
+
/**
|
|
32
|
+
* @internal — called by `Sequence` each tick while on-stage. Once, during
|
|
33
|
+
* offline rendering, registers a `delayRender` gate so `renderFrame` waits for
|
|
34
|
+
* the image to finish loading before the frame is captured. No-op in preview.
|
|
35
|
+
*/
|
|
36
|
+
_kmTick(_localFrame: number): void;
|
|
37
|
+
/** @internal — called by `Sequence` when it goes out of range. */
|
|
38
|
+
_kmDeactivate(): void;
|
|
39
|
+
/** @internal — {@link KMLayoutNode}: size from explicit width/height (cover/contain handle the rest). */
|
|
40
|
+
_kmMeasure(node: FlexilyNode): void;
|
|
41
|
+
/** @internal — {@link KMLayoutNode}: write the computed box back + re-fit the bitmap. */
|
|
42
|
+
_kmPlace(box: LayoutBox): void;
|
|
43
|
+
/** @internal */
|
|
44
|
+
_layoutImage(): void;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/layout/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC,GACnE,cAAc,GAAG;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAyBJ,qBAAa,KAAM,SAAQ,KAAK,CAAC,KAAM,YAAW,YAAY;IAC5D,QAAQ,CAAC,OAAO,EAAG,MAAM,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,OAAO,CAA4B;IAC3C,iFAAiF;IACjF,OAAO,CAAC,YAAY,CAA8B;IAClD,gEAAgE;IAChE,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,WAAW;IAmD/B;;;;OAIG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAWlC,kEAAkE;IAClE,aAAa,IAAI,IAAI;IAErB,yGAAyG;IACzG,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAQnC,yFAAyF;IACzF,QAAQ,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI;IAQ9B,gBAAgB;IAChB,YAAY,IAAI,IAAI;CA0CrB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import Konva from "konva";
|
|
2
|
+
import { getComposition } from "../engine/composition.js";
|
|
3
|
+
import { getDefaultImageLoader, } from "../engine/runtime-defaults.js";
|
|
4
|
+
import { TICK_MARK } from "../media/media-marker.js";
|
|
5
|
+
import { applySize, parseSize } from "./flex/engine.js";
|
|
6
|
+
const IMG_KEYS = [
|
|
7
|
+
"src",
|
|
8
|
+
"objectFit",
|
|
9
|
+
"objectPosition",
|
|
10
|
+
"flexGrow",
|
|
11
|
+
"flexShrink",
|
|
12
|
+
"flexBasis",
|
|
13
|
+
"alignSelf",
|
|
14
|
+
"margin",
|
|
15
|
+
"loader",
|
|
16
|
+
];
|
|
17
|
+
function pickKonvaConfig(config) {
|
|
18
|
+
const out = { ...config };
|
|
19
|
+
for (const k of IMG_KEYS)
|
|
20
|
+
delete out[k];
|
|
21
|
+
const w = parseSize(config.width);
|
|
22
|
+
const h = parseSize(config.height);
|
|
23
|
+
out.width = w?.kind === "px" ? w.value : undefined;
|
|
24
|
+
out.height = h?.kind === "px" ? h.value : undefined;
|
|
25
|
+
out.cornerRadius = undefined;
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
export class Image extends Konva.Group {
|
|
29
|
+
_kmRole = "leaf";
|
|
30
|
+
_img;
|
|
31
|
+
_source = null;
|
|
32
|
+
/** Pending load (string src only); null once resolved or for element sources. */
|
|
33
|
+
_loadPromise = null;
|
|
34
|
+
/** Guards the one-time render gate registered on first tick. */
|
|
35
|
+
_renderGated = false;
|
|
36
|
+
constructor(config) {
|
|
37
|
+
super(pickKonvaConfig(config));
|
|
38
|
+
// Discovered by `Sequence._apply` so `_kmTick` runs at attach-time (when the
|
|
39
|
+
// composition is reachable) to gate the async load during offline rendering.
|
|
40
|
+
this.setAttr(TICK_MARK, true);
|
|
41
|
+
this._img = new Konva.Image({ image: undefined, listening: false });
|
|
42
|
+
super.add(this._img);
|
|
43
|
+
this.setAttrs({
|
|
44
|
+
flexGrow: config.flexGrow,
|
|
45
|
+
flexShrink: config.flexShrink,
|
|
46
|
+
flexBasis: config.flexBasis,
|
|
47
|
+
alignSelf: config.alignSelf,
|
|
48
|
+
margin: config.margin,
|
|
49
|
+
objectFit: config.objectFit ?? "cover",
|
|
50
|
+
objectPosition: config.objectPosition ?? "center",
|
|
51
|
+
cornerRadius: config.cornerRadius,
|
|
52
|
+
flexWidth: config.width,
|
|
53
|
+
flexHeight: config.height,
|
|
54
|
+
});
|
|
55
|
+
if (config.cornerRadius !== undefined) {
|
|
56
|
+
const cr = normalizeCorners(config.cornerRadius);
|
|
57
|
+
this.clipFunc((ctx) => roundRectPath(ctx, 0, 0, this.width(), this.height(), cr));
|
|
58
|
+
}
|
|
59
|
+
this.on("widthChange heightChange", () => this._layoutImage());
|
|
60
|
+
if (typeof config.src === "string") {
|
|
61
|
+
// Kick the load off eagerly (preserves preview timing). The promise is
|
|
62
|
+
// captured so `_kmTick` can gate offline rendering on it via delayRender.
|
|
63
|
+
const loader = config.loader ?? getDefaultImageLoader();
|
|
64
|
+
this._loadPromise = loader(config.src)
|
|
65
|
+
.then((img) => {
|
|
66
|
+
this._source = img;
|
|
67
|
+
this._img.image(img);
|
|
68
|
+
this._layoutImage();
|
|
69
|
+
this.getLayer()?.batchDraw();
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
72
|
+
console.error("[smoove] Image load failed:", err);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this._source = config.src;
|
|
77
|
+
this._img.image(config.src);
|
|
78
|
+
}
|
|
79
|
+
this._layoutImage();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @internal — called by `Sequence` each tick while on-stage. Once, during
|
|
83
|
+
* offline rendering, registers a `delayRender` gate so `renderFrame` waits for
|
|
84
|
+
* the image to finish loading before the frame is captured. No-op in preview.
|
|
85
|
+
*/
|
|
86
|
+
_kmTick(_localFrame) {
|
|
87
|
+
if (this._renderGated || !this._loadPromise)
|
|
88
|
+
return;
|
|
89
|
+
const stage = this.getStage();
|
|
90
|
+
if (!stage)
|
|
91
|
+
return;
|
|
92
|
+
const comp = getComposition(stage);
|
|
93
|
+
if (!comp?.environment.isRendering)
|
|
94
|
+
return;
|
|
95
|
+
this._renderGated = true;
|
|
96
|
+
const handle = comp.delayRender("load image");
|
|
97
|
+
this._loadPromise.finally(() => comp.continueRender(handle));
|
|
98
|
+
}
|
|
99
|
+
/** @internal — called by `Sequence` when it goes out of range. */
|
|
100
|
+
_kmDeactivate() { }
|
|
101
|
+
/** @internal — {@link KMLayoutNode}: size from explicit width/height (cover/contain handle the rest). */
|
|
102
|
+
_kmMeasure(node) {
|
|
103
|
+
applySize(node, this.attrs.flexWidth, this.attrs.flexHeight);
|
|
104
|
+
}
|
|
105
|
+
/** @internal — {@link KMLayoutNode}: write the computed box back + re-fit the bitmap. */
|
|
106
|
+
_kmPlace(box) {
|
|
107
|
+
this.x(box.left);
|
|
108
|
+
this.y(box.top);
|
|
109
|
+
this.width(box.width);
|
|
110
|
+
this.height(box.height);
|
|
111
|
+
this._layoutImage();
|
|
112
|
+
}
|
|
113
|
+
/** @internal */
|
|
114
|
+
_layoutImage() {
|
|
115
|
+
const w = this.width();
|
|
116
|
+
const h = this.height();
|
|
117
|
+
if (w <= 0 || h <= 0)
|
|
118
|
+
return;
|
|
119
|
+
const src = this._source;
|
|
120
|
+
const fit = (this.attrs.objectFit ?? "cover");
|
|
121
|
+
const pos = (this.attrs.objectPosition ?? "center");
|
|
122
|
+
if (!src || src.naturalWidth === 0 || src.naturalHeight === 0)
|
|
123
|
+
return;
|
|
124
|
+
const nw = src.naturalWidth;
|
|
125
|
+
const nh = src.naturalHeight;
|
|
126
|
+
if (fit === "fill") {
|
|
127
|
+
this._img.position({ x: 0, y: 0 });
|
|
128
|
+
this._img.size({ width: w, height: h });
|
|
129
|
+
this._img.crop({ x: 0, y: 0, width: nw, height: nh });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (fit === "none") {
|
|
133
|
+
const { x, y } = positionOffset(pos, w - nw, h - nh);
|
|
134
|
+
this._img.position({ x, y });
|
|
135
|
+
this._img.size({ width: nw, height: nh });
|
|
136
|
+
this._img.crop({ x: 0, y: 0, width: nw, height: nh });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (fit === "contain") {
|
|
140
|
+
const scale = Math.min(w / nw, h / nh);
|
|
141
|
+
const dw = nw * scale;
|
|
142
|
+
const dh = nh * scale;
|
|
143
|
+
const { x, y } = positionOffset(pos, w - dw, h - dh);
|
|
144
|
+
this._img.position({ x, y });
|
|
145
|
+
this._img.size({ width: dw, height: dh });
|
|
146
|
+
this._img.crop({ x: 0, y: 0, width: nw, height: nh });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const scale = Math.max(w / nw, h / nh);
|
|
150
|
+
const cropW = w / scale;
|
|
151
|
+
const cropH = h / scale;
|
|
152
|
+
const { x: cx, y: cy } = positionOffset(pos, nw - cropW, nh - cropH);
|
|
153
|
+
this._img.position({ x: 0, y: 0 });
|
|
154
|
+
this._img.size({ width: w, height: h });
|
|
155
|
+
this._img.crop({ x: cx, y: cy, width: cropW, height: cropH });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function positionOffset(pos, freeX, freeY) {
|
|
159
|
+
let fx = 0.5;
|
|
160
|
+
let fy = 0.5;
|
|
161
|
+
if (pos.includes("left"))
|
|
162
|
+
fx = 0;
|
|
163
|
+
else if (pos.includes("right"))
|
|
164
|
+
fx = 1;
|
|
165
|
+
if (pos.includes("top"))
|
|
166
|
+
fy = 0;
|
|
167
|
+
else if (pos.includes("bottom"))
|
|
168
|
+
fy = 1;
|
|
169
|
+
if (pos === "center") {
|
|
170
|
+
fx = 0.5;
|
|
171
|
+
fy = 0.5;
|
|
172
|
+
}
|
|
173
|
+
return { x: freeX * fx, y: freeY * fy };
|
|
174
|
+
}
|
|
175
|
+
function normalizeCorners(c) {
|
|
176
|
+
if (typeof c === "number")
|
|
177
|
+
return [c, c, c, c];
|
|
178
|
+
if (c.length === 1)
|
|
179
|
+
return [c[0] ?? 0, c[0] ?? 0, c[0] ?? 0, c[0] ?? 0];
|
|
180
|
+
if (c.length === 2)
|
|
181
|
+
return [c[0] ?? 0, c[1] ?? 0, c[0] ?? 0, c[1] ?? 0];
|
|
182
|
+
return [c[0] ?? 0, c[1] ?? 0, c[2] ?? 0, c[3] ?? 0];
|
|
183
|
+
}
|
|
184
|
+
function roundRectPath(ctx, x, y, w, h, r) {
|
|
185
|
+
const [tl, tr, br, bl] = r;
|
|
186
|
+
ctx.beginPath();
|
|
187
|
+
ctx.moveTo(x + (tl ?? 0), y);
|
|
188
|
+
ctx.lineTo(x + w - (tr ?? 0), y);
|
|
189
|
+
ctx.quadraticCurveTo(x + w, y, x + w, y + (tr ?? 0));
|
|
190
|
+
ctx.lineTo(x + w, y + h - (br ?? 0));
|
|
191
|
+
ctx.quadraticCurveTo(x + w, y + h, x + w - (br ?? 0), y + h);
|
|
192
|
+
ctx.lineTo(x + (bl ?? 0), y + h);
|
|
193
|
+
ctx.quadraticCurveTo(x, y + h, x, y + h - (bl ?? 0));
|
|
194
|
+
ctx.lineTo(x, y + (tl ?? 0));
|
|
195
|
+
ctx.quadraticCurveTo(x, y, x + (tl ?? 0), y);
|
|
196
|
+
ctx.closePath();
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=image.js.map
|