exodeui-react-native 1.0.9 → 1.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/engine.ts +63 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exodeui-react-native",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "description": "React Native runtime for ExodeUI animations",
5
5
  "main": "index.js",
6
6
  "files": [
package/src/engine.ts CHANGED
@@ -1670,12 +1670,47 @@ export class ExodeUIEngine {
1670
1670
  canvas.drawText(text, x, y, paint, font);
1671
1671
  }
1672
1672
 
1673
+ private getOrDecodeImage(src: string): any {
1674
+ if (!src) return null;
1675
+ if (this.imageCache.has(src)) return this.imageCache.get(src)!;
1676
+
1677
+ if (src.startsWith('data:image')) {
1678
+ try {
1679
+ const base64Str = src.includes(',') ? src.split(',')[1] : src;
1680
+ const data = Skia.Data.fromBase64(base64Str);
1681
+ const img = Skia.Image.MakeImageFromEncoded(data);
1682
+ if (img) {
1683
+ this.imageCache.set(src, img);
1684
+ return img;
1685
+ }
1686
+ } catch (e) {
1687
+ console.error('[ExodeUIEngine] Failed to decode base64 image:', e);
1688
+ }
1689
+ }
1690
+ return null;
1691
+ }
1692
+
1673
1693
  private renderImage(canvas: any, obj: any, w: number, h: number) {
1674
- // Image support requires Skia.Image.MakeFromExternalSource or similar
1675
- // Placeholder for now
1676
- const paint = Skia.Paint();
1677
- paint.setColor(Skia.Color('#374151'));
1678
- canvas.drawRect({ x: -w/2, y: -h/2, width: w, height: h }, paint);
1694
+ const state = this.objectStates.get(obj.id);
1695
+ const geom = state?.geometry || obj.geometry;
1696
+ const src = obj.src || geom.src || '';
1697
+
1698
+ const img = this.getOrDecodeImage(src);
1699
+ if (img) {
1700
+ const paint = Skia.Paint();
1701
+ paint.setAlphaf(state?.opacity ?? 1);
1702
+ canvas.drawImageRect(
1703
+ img,
1704
+ { x: 0, y: 0, width: img.width(), height: img.height() },
1705
+ { x: -w/2, y: -h/2, width: w, height: h },
1706
+ paint
1707
+ );
1708
+ } else {
1709
+ // Fallback placeholder
1710
+ const paint = Skia.Paint();
1711
+ paint.setColor(Skia.Color('#374151'));
1712
+ canvas.drawRect({ x: -w/2, y: -h/2, width: w, height: h }, paint);
1713
+ }
1679
1714
  }
1680
1715
 
1681
1716
  private renderButton(canvas: any, obj: any, w: number, h: number) {
@@ -2217,8 +2252,9 @@ export class ExodeUIEngine {
2217
2252
  const path = Skia.Path.Make();
2218
2253
  if (geometry.type === 'Rectangle') {
2219
2254
  const rect = { x: -w/2, y: -h/2, width: w, height: h };
2220
- if (state.cornerRadius || geometry.corner_radius) {
2221
- const cr = state.cornerRadius || geometry.corner_radius;
2255
+ if (state.cornerRadius !== undefined || geometry.corner_radius !== undefined) {
2256
+ const rawCr = state.cornerRadius ?? geometry.corner_radius;
2257
+ const cr = Array.isArray(rawCr) ? rawCr[0] : Number(rawCr);
2222
2258
  path.addRRect(Skia.RRectXY(rect, cr, cr));
2223
2259
  } else {
2224
2260
  path.addRect(rect);
@@ -2247,8 +2283,26 @@ export class ExodeUIEngine {
2247
2283
 
2248
2284
  if (style.fill) {
2249
2285
  const paint = Skia.Paint();
2250
- paint.setColor(Skia.Color(style.fill.color || '#000000'));
2251
- paint.setAlphaf((state.opacity ?? 1) * (style.fill.opacity ?? 1));
2286
+
2287
+ let hasImageFill = false;
2288
+ if ((style.fill.type === 'Image' || style.fill.type === 'Pattern' || style.fill.url) && style.fill.url) {
2289
+ const img = this.getOrDecodeImage(style.fill.url);
2290
+ if (img) {
2291
+ const matrix = Skia.Matrix();
2292
+ matrix.translate(-w/2, -h/2);
2293
+ matrix.scale(w / img.width(), h / img.height());
2294
+ paint.setShader(img.makeShaderOptions(0, 0, 0, 0, matrix));
2295
+ hasImageFill = true;
2296
+ }
2297
+ }
2298
+
2299
+ if (!hasImageFill) {
2300
+ const fillCol = style.fill.color;
2301
+ const fillColStr = typeof fillCol === 'string' ? fillCol.replace(/\s+/g, '') : '#000000';
2302
+ try { paint.setColor(Skia.Color(fillColStr)); } catch { paint.setColor(Skia.Color('#000000')); }
2303
+ }
2304
+
2305
+ paint.setAlphaf(Math.max(0, Math.min(1, (state.opacity ?? 1) * (style.fill.opacity ?? 1))));
2252
2306
  paint.setStyle(PaintStyle.Fill);
2253
2307
 
2254
2308
  if (style.shadow && style.shadow.opacity > 0) {