@jiujue/react-canvas-fiber 2.1.1 → 2.1.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/dist/index.d.cts CHANGED
@@ -86,6 +86,10 @@ type ViewProps = {
86
86
  children?: ReactNode;
87
87
  style?: YogaStyle;
88
88
  background?: string;
89
+ backgroundImage?: string;
90
+ backgroundPosition?: string;
91
+ backgroundSize?: string;
92
+ backgroundRepeat?: string;
89
93
  border?: string;
90
94
  borderRadius?: number;
91
95
  scrollX?: boolean;
package/dist/index.d.ts CHANGED
@@ -86,6 +86,10 @@ type ViewProps = {
86
86
  children?: ReactNode;
87
87
  style?: YogaStyle;
88
88
  background?: string;
89
+ backgroundImage?: string;
90
+ backgroundPosition?: string;
91
+ backgroundSize?: string;
92
+ backgroundRepeat?: string;
89
93
  border?: string;
90
94
  borderRadius?: number;
91
95
  scrollX?: boolean;
package/dist/index.js CHANGED
@@ -42,6 +42,8 @@ function createNode(type, props) {
42
42
  };
43
43
  if (type === "Image") {
44
44
  node.imageInstance = null;
45
+ } else if (type === "View") {
46
+ node.backgroundImageInstance = null;
45
47
  }
46
48
  return node;
47
49
  }
@@ -125,6 +127,105 @@ function drawBorder(ctx, x, y, w, h, radius, border) {
125
127
  ctx.stroke();
126
128
  ctx.restore();
127
129
  }
130
+ function resolveBgRepeat(repeat) {
131
+ if (!repeat) return "repeat";
132
+ if (repeat === "no-repeat" || repeat === "repeat-x" || repeat === "repeat-y" || repeat === "repeat")
133
+ return repeat;
134
+ return "repeat";
135
+ }
136
+ function parseBgSize(size, w, h, imgW, imgH) {
137
+ if (!size || size === "auto") return { width: imgW, height: imgH };
138
+ if (size === "cover") {
139
+ const scale = Math.max(w / imgW, h / imgH);
140
+ return { width: imgW * scale, height: imgH * scale };
141
+ }
142
+ if (size === "contain") {
143
+ const scale = Math.min(w / imgW, h / imgH);
144
+ return { width: imgW * scale, height: imgH * scale };
145
+ }
146
+ const parts = size.trim().split(/\s+/);
147
+ let rw = imgW;
148
+ let rh = imgH;
149
+ if (parts[0]) {
150
+ if (parts[0].endsWith("%")) {
151
+ rw = w * parseFloat(parts[0]) / 100;
152
+ } else if (parts[0] !== "auto") {
153
+ rw = parseFloat(parts[0]);
154
+ }
155
+ }
156
+ if (parts[1]) {
157
+ if (parts[1].endsWith("%")) {
158
+ rh = h * parseFloat(parts[1]) / 100;
159
+ } else if (parts[1] !== "auto") {
160
+ rh = parseFloat(parts[1]);
161
+ }
162
+ } else {
163
+ if (parts[0] !== "auto") {
164
+ rh = imgH * (rw / imgW);
165
+ }
166
+ }
167
+ return { width: rw, height: rh };
168
+ }
169
+ function parseBgPos(pos, w, h, targetW, targetH) {
170
+ const parts = (pos || "").trim().split(/\s+/);
171
+ if (parts.length === 0 || parts.length === 1 && !parts[0]) {
172
+ return { x: 0, y: 0 };
173
+ }
174
+ const xStr = parts[0];
175
+ let yStr = parts[1];
176
+ if (parts.length === 1) {
177
+ yStr = "center";
178
+ }
179
+ function resolve(val, containerDim, imgDim) {
180
+ if (val === "left" || val === "top") return 0;
181
+ if (val === "right" || val === "bottom") return containerDim - imgDim;
182
+ if (val === "center") return (containerDim - imgDim) / 2;
183
+ if (val.endsWith("%")) {
184
+ return (containerDim - imgDim) * parseFloat(val) / 100;
185
+ }
186
+ if (val.endsWith("px")) {
187
+ return parseFloat(val);
188
+ }
189
+ return parseFloat(val) || 0;
190
+ }
191
+ return {
192
+ x: resolve(xStr, w, targetW),
193
+ y: resolve(yStr, h, targetH)
194
+ };
195
+ }
196
+ function drawBackgroundImage(ctx, node, x, y, w, h, radius) {
197
+ const img = node.backgroundImageInstance;
198
+ if (!img || !img.complete || img.naturalWidth === 0 || img.naturalHeight === 0) return;
199
+ const props = node.props;
200
+ const bgSize = props.backgroundSize;
201
+ const bgPos = props.backgroundPosition;
202
+ const bgRepeat = resolveBgRepeat(props.backgroundRepeat);
203
+ const imgW = img.naturalWidth;
204
+ const imgH = img.naturalHeight;
205
+ const { width: targetW, height: targetH } = parseBgSize(bgSize, w, h, imgW, imgH);
206
+ const { x: posX, y: posY } = parseBgPos(bgPos, w, h, targetW, targetH);
207
+ ctx.save();
208
+ drawRoundedRect(ctx, x, y, w, h, radius);
209
+ ctx.clip();
210
+ if (bgRepeat === "no-repeat") {
211
+ ctx.drawImage(img, x + posX, y + posY, targetW, targetH);
212
+ } else {
213
+ const pattern = ctx.createPattern(img, bgRepeat);
214
+ if (pattern) {
215
+ const matrix = new DOMMatrix();
216
+ const scaleX = targetW / imgW;
217
+ const scaleY = targetH / imgH;
218
+ matrix.translateSelf(x + posX, y + posY);
219
+ matrix.scaleSelf(scaleX, scaleY);
220
+ pattern.setTransform(matrix);
221
+ ctx.fillStyle = pattern;
222
+ ctx.beginPath();
223
+ ctx.rect(x, y, w, h);
224
+ ctx.fill();
225
+ }
226
+ }
227
+ ctx.restore();
228
+ }
128
229
  function drawNode(state, node, offsetX, offsetY) {
129
230
  const { ctx } = state;
130
231
  const x = offsetX + node.layout.x;
@@ -159,6 +260,10 @@ function drawNode(state, node, offsetX, offsetY) {
159
260
  ctx.fill();
160
261
  ctx.restore();
161
262
  }
263
+ const viewNode = node;
264
+ if (viewNode.backgroundImageInstance) {
265
+ drawBackgroundImage(ctx, viewNode, x, y, w, h, viewRadius);
266
+ }
162
267
  if (scrollX || scrollY) {
163
268
  viewIsScroll = true;
164
269
  ctx.save();
@@ -639,6 +744,18 @@ var hostConfig = {
639
744
  if (!img.complete) {
640
745
  img.onload = () => rootContainer.invalidate();
641
746
  }
747
+ } else if (type === "View" && props.backgroundImage) {
748
+ const viewNode = node;
749
+ const img = new Image();
750
+ img.crossOrigin = "anonymous";
751
+ img.src = props.backgroundImage;
752
+ if (img.dataset) {
753
+ img.dataset.src = props.backgroundImage;
754
+ }
755
+ viewNode.backgroundImageInstance = img;
756
+ if (!img.complete) {
757
+ img.onload = () => rootContainer.invalidate();
758
+ }
642
759
  }
643
760
  return node;
644
761
  },
@@ -723,6 +840,38 @@ var hostConfig = {
723
840
  }
724
841
  }
725
842
  }
843
+ } else if (instance.type === "View") {
844
+ const viewNode = instance;
845
+ const newBg = instance.props.backgroundImage;
846
+ const currentBg = viewNode.backgroundImageInstance?.dataset?.src;
847
+ if (newBg !== currentBg) {
848
+ if (!newBg) {
849
+ viewNode.backgroundImageInstance = null;
850
+ } else {
851
+ const img = new Image();
852
+ img.crossOrigin = "anonymous";
853
+ img.src = newBg;
854
+ if (img.dataset) {
855
+ img.dataset.src = newBg;
856
+ }
857
+ viewNode.backgroundImageInstance = img;
858
+ const invalidate = () => {
859
+ let p = viewNode;
860
+ while (p) {
861
+ if (p.type === "Root") {
862
+ p.container?.invalidate();
863
+ return;
864
+ }
865
+ p = p.parent;
866
+ }
867
+ };
868
+ if (!img.complete) {
869
+ img.onload = invalidate;
870
+ } else {
871
+ invalidate();
872
+ }
873
+ }
874
+ }
726
875
  }
727
876
  },
728
877
  commitTextUpdate() {