capacitor-extended-dialog 0.0.14 → 0.0.15
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/CapacitorExtendedDialog.podspec +1 -0
- package/Package.swift +4 -2
- package/README.md +23 -23
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/albermonte/extendeddialog/SheetBottomDialogFragment.java +19 -14
- package/android/src/main/java/com/albermonte/extendeddialog/SvgImageLoader.java +90 -0
- package/dist/docs.json +3 -3
- package/dist/esm/definitions.d.ts +15 -3
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/ExtendedDialogPlugin/FullScreenDialogViewController.swift +22 -17
- package/ios/Sources/ExtendedDialogPlugin/SvgImageLoader.swift +70 -0
- package/package.json +1 -1
package/Package.swift
CHANGED
|
@@ -10,14 +10,16 @@ let package = Package(
|
|
|
10
10
|
targets: ["ExtendedDialogPlugin"])
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
13
|
-
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
|
|
14
|
+
.package(url: "https://github.com/SVGKit/SVGKit.git", from: "3.0.0")
|
|
14
15
|
],
|
|
15
16
|
targets: [
|
|
16
17
|
.target(
|
|
17
18
|
name: "ExtendedDialogPlugin",
|
|
18
19
|
dependencies: [
|
|
19
20
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
|
-
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
|
+
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
22
|
+
.product(name: "SVGKit", package: "SVGKit")
|
|
21
23
|
],
|
|
22
24
|
path: "ios/Sources/ExtendedDialogPlugin"),
|
|
23
25
|
.testTarget(
|
package/README.md
CHANGED
|
@@ -249,24 +249,24 @@ Show a message sheet dialog with an optional header logo, title, and message.
|
|
|
249
249
|
|
|
250
250
|
#### SheetOptions
|
|
251
251
|
|
|
252
|
-
| Prop | Type | Description
|
|
253
|
-
| ------------------------ | ------------------------------------------------- |
|
|
254
|
-
| **`headerLogo`** | <code>string</code> | Header logo -
|
|
255
|
-
| **`title`** | <code>string</code> | Sheet title
|
|
256
|
-
| **`subtitle`** | <code>string</code> | Optional subtitle displayed between title and rows
|
|
257
|
-
| **`rows`** | <code>SheetRow[]</code> | Description rows
|
|
258
|
-
| **`confirmButtonTitle`** | <code>string</code> | Confirm button title
|
|
259
|
-
| **`cancelButtonTitle`** | <code>string</code> | Cancel button title
|
|
260
|
-
| **`mode`** | <code><a href="#dialogmode">DialogMode</a></code> | Dialog mode
|
|
252
|
+
| Prop | Type | Description |
|
|
253
|
+
| ------------------------ | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
254
|
+
| **`headerLogo`** | <code>string</code> | Header logo. Supports: - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg` |
|
|
255
|
+
| **`title`** | <code>string</code> | Sheet title |
|
|
256
|
+
| **`subtitle`** | <code>string</code> | Optional subtitle displayed between title and rows |
|
|
257
|
+
| **`rows`** | <code>SheetRow[]</code> | Description rows |
|
|
258
|
+
| **`confirmButtonTitle`** | <code>string</code> | Confirm button title |
|
|
259
|
+
| **`cancelButtonTitle`** | <code>string</code> | Cancel button title |
|
|
260
|
+
| **`mode`** | <code><a href="#dialogmode">DialogMode</a></code> | Dialog mode |
|
|
261
261
|
|
|
262
262
|
|
|
263
263
|
#### SheetRow
|
|
264
264
|
|
|
265
|
-
| Prop | Type | Description
|
|
266
|
-
| ----------- | ------------------- |
|
|
267
|
-
| **`title`** | <code>string</code> | Row title (required)
|
|
268
|
-
| **`logo`** | <code>string</code> | Optional logo/icon -
|
|
269
|
-
| **`value`** | <code>string</code> | Optional value displayed on the right
|
|
265
|
+
| Prop | Type | Description |
|
|
266
|
+
| ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
267
|
+
| **`title`** | <code>string</code> | Row title (required) |
|
|
268
|
+
| **`logo`** | <code>string</code> | Optional logo/icon. Supports: - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg` |
|
|
269
|
+
| **`value`** | <code>string</code> | Optional value displayed on the right |
|
|
270
270
|
|
|
271
271
|
|
|
272
272
|
#### MessageSheetResult
|
|
@@ -278,15 +278,15 @@ Show a message sheet dialog with an optional header logo, title, and message.
|
|
|
278
278
|
|
|
279
279
|
#### MessageSheetOptions
|
|
280
280
|
|
|
281
|
-
| Prop | Type | Description
|
|
282
|
-
| ------------------------ | ------------------------------------------------- |
|
|
283
|
-
| **`headerLogo`** | <code>string</code> | Header logo -
|
|
284
|
-
| **`title`** | <code>string</code> | Sheet title
|
|
285
|
-
| **`subtitle`** | <code>string</code> | Optional subtitle displayed between title and message
|
|
286
|
-
| **`message`** | <code>string</code> | Message body displayed in the sheet
|
|
287
|
-
| **`confirmButtonTitle`** | <code>string</code> | Confirm button title
|
|
288
|
-
| **`cancelButtonTitle`** | <code>string</code> | Cancel button title
|
|
289
|
-
| **`mode`** | <code><a href="#dialogmode">DialogMode</a></code> | Dialog mode
|
|
281
|
+
| Prop | Type | Description |
|
|
282
|
+
| ------------------------ | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
283
|
+
| **`headerLogo`** | <code>string</code> | Header logo. Supports: - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg` |
|
|
284
|
+
| **`title`** | <code>string</code> | Sheet title |
|
|
285
|
+
| **`subtitle`** | <code>string</code> | Optional subtitle displayed between title and message |
|
|
286
|
+
| **`message`** | <code>string</code> | Message body displayed in the sheet |
|
|
287
|
+
| **`confirmButtonTitle`** | <code>string</code> | Confirm button title |
|
|
288
|
+
| **`cancelButtonTitle`** | <code>string</code> | Cancel button title |
|
|
289
|
+
| **`mode`** | <code><a href="#dialogmode">DialogMode</a></code> | Dialog mode |
|
|
290
290
|
|
|
291
291
|
|
|
292
292
|
### Type Aliases
|
package/android/build.gradle
CHANGED
|
@@ -53,6 +53,7 @@ dependencies {
|
|
|
53
53
|
implementation project(':capacitor-android')
|
|
54
54
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
55
55
|
implementation 'com.google.android.material:material:1.12.0'
|
|
56
|
+
implementation 'com.caverock:androidsvg-aar:1.4'
|
|
56
57
|
testImplementation "junit:junit:$junitVersion"
|
|
57
58
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
58
59
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
@@ -7,7 +7,6 @@ import android.content.res.ColorStateList;
|
|
|
7
7
|
import android.graphics.Bitmap;
|
|
8
8
|
import android.graphics.BitmapFactory;
|
|
9
9
|
import android.os.Bundle;
|
|
10
|
-
import android.util.Base64;
|
|
11
10
|
import android.util.TypedValue;
|
|
12
11
|
import android.view.ContextThemeWrapper;
|
|
13
12
|
import android.view.Gravity;
|
|
@@ -52,6 +51,8 @@ public class SheetBottomDialogFragment extends BottomSheetDialogFragment {
|
|
|
52
51
|
private static final String ARG_SUBTITLE = "subtitle";
|
|
53
52
|
private static final String ARG_IS_MESSAGE_SHEET = "isMessageSheet";
|
|
54
53
|
|
|
54
|
+
private static final Executor IMAGE_EXECUTOR = Executors.newCachedThreadPool();
|
|
55
|
+
|
|
55
56
|
private ExtendedDialog.SheetCallback sheetCallback;
|
|
56
57
|
private boolean dismissed = false;
|
|
57
58
|
private Context themedContext;
|
|
@@ -706,28 +707,32 @@ public class SheetBottomDialogFragment extends BottomSheetDialogFragment {
|
|
|
706
707
|
}
|
|
707
708
|
|
|
708
709
|
private void loadImageAsync(ImageView imageView, String imageUrl) {
|
|
709
|
-
|
|
710
|
-
|
|
710
|
+
if (imageUrl == null || imageUrl.isEmpty()) return;
|
|
711
|
+
IMAGE_EXECUTOR.execute(() -> {
|
|
711
712
|
try {
|
|
712
|
-
Bitmap bitmap;
|
|
713
|
-
if (imageUrl.startsWith("data:")) {
|
|
714
|
-
String base64Data = imageUrl.substring(imageUrl.indexOf(",") + 1);
|
|
715
|
-
byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT);
|
|
716
|
-
bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
|
|
717
|
-
} else {
|
|
718
|
-
InputStream inputStream = new URL(imageUrl).openStream();
|
|
719
|
-
bitmap = BitmapFactory.decodeStream(inputStream);
|
|
720
|
-
inputStream.close();
|
|
721
|
-
}
|
|
713
|
+
Bitmap bitmap = decodeImage(imageUrl, imageView);
|
|
722
714
|
if (bitmap != null) {
|
|
723
715
|
imageView.post(() -> imageView.setImageBitmap(bitmap));
|
|
724
716
|
}
|
|
725
717
|
} catch (Exception e) {
|
|
726
|
-
|
|
718
|
+
android.util.Log.w("ExtendedDialog", "Failed to load image: " + e.getMessage());
|
|
727
719
|
}
|
|
728
720
|
});
|
|
729
721
|
}
|
|
730
722
|
|
|
723
|
+
private static Bitmap decodeImage(String imageUrl, ImageView imageView) throws Exception {
|
|
724
|
+
if (SvgImageLoader.isSvgSource(imageUrl)) {
|
|
725
|
+
return SvgImageLoader.render(imageUrl, imageView);
|
|
726
|
+
}
|
|
727
|
+
if (SvgImageLoader.isDataUrl(imageUrl)) {
|
|
728
|
+
byte[] decodedBytes = SvgImageLoader.decodeDataUrl(imageUrl);
|
|
729
|
+
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
|
|
730
|
+
}
|
|
731
|
+
try (InputStream inputStream = new URL(imageUrl).openStream()) {
|
|
732
|
+
return BitmapFactory.decodeStream(inputStream);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
731
736
|
private void handleConfirm() {
|
|
732
737
|
if (dismissed) return;
|
|
733
738
|
dismissed = true;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
package com.albermonte.extendeddialog;
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap;
|
|
4
|
+
import android.graphics.Canvas;
|
|
5
|
+
import android.net.Uri;
|
|
6
|
+
import android.util.Base64;
|
|
7
|
+
import android.view.ViewGroup;
|
|
8
|
+
import android.widget.ImageView;
|
|
9
|
+
import com.caverock.androidsvg.SVG;
|
|
10
|
+
import com.caverock.androidsvg.SVGParseException;
|
|
11
|
+
import java.io.ByteArrayInputStream;
|
|
12
|
+
import java.io.IOException;
|
|
13
|
+
import java.io.InputStream;
|
|
14
|
+
import java.net.URL;
|
|
15
|
+
import java.net.URLDecoder;
|
|
16
|
+
import java.nio.charset.StandardCharsets;
|
|
17
|
+
import java.util.Locale;
|
|
18
|
+
|
|
19
|
+
final class SvgImageLoader {
|
|
20
|
+
|
|
21
|
+
private static final String SVG_DATA_URL_PREFIX = "data:image/svg+xml";
|
|
22
|
+
private static final String DATA_URL_PREFIX = "data:";
|
|
23
|
+
private static final String SVG_SUFFIX = ".svg";
|
|
24
|
+
|
|
25
|
+
private SvgImageLoader() {}
|
|
26
|
+
|
|
27
|
+
static boolean isDataUrl(String source) {
|
|
28
|
+
return source != null && source.regionMatches(true, 0, DATA_URL_PREFIX, 0, DATA_URL_PREFIX.length());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static boolean isSvgSource(String source) {
|
|
32
|
+
if (source == null) return false;
|
|
33
|
+
if (source.regionMatches(true, 0, SVG_DATA_URL_PREFIX, 0, SVG_DATA_URL_PREFIX.length())) return true;
|
|
34
|
+
Uri uri = Uri.parse(source);
|
|
35
|
+
String scheme = uri.getScheme();
|
|
36
|
+
if (scheme == null || (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https"))) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
String path = uri.getPath();
|
|
40
|
+
return path != null && path.toLowerCase(Locale.ROOT).endsWith(SVG_SUFFIX);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Supports `;base64` and percent-encoded payloads. */
|
|
44
|
+
static byte[] decodeDataUrl(String source) throws IOException {
|
|
45
|
+
int comma = source.indexOf(',');
|
|
46
|
+
if (comma < 0) throw new IOException("Malformed data URL");
|
|
47
|
+
String header = source.substring(0, comma);
|
|
48
|
+
String payload = source.substring(comma + 1);
|
|
49
|
+
if (header.toLowerCase(Locale.ROOT).contains(";base64")) {
|
|
50
|
+
return Base64.decode(payload, Base64.DEFAULT);
|
|
51
|
+
}
|
|
52
|
+
return URLDecoder.decode(payload, StandardCharsets.UTF_8.name()).getBytes(StandardCharsets.UTF_8);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Sizes Bitmap to {@code targetView}'s layout params (or 64dp default). */
|
|
56
|
+
static Bitmap render(String source, ImageView targetView) throws SVGParseException, IOException {
|
|
57
|
+
SVG svg = parse(source);
|
|
58
|
+
ViewGroup.LayoutParams params = targetView.getLayoutParams();
|
|
59
|
+
int width = params != null ? params.width : 0;
|
|
60
|
+
int height = params != null ? params.height : 0;
|
|
61
|
+
if (width <= 0 || height <= 0) {
|
|
62
|
+
float density = targetView.getResources().getDisplayMetrics().density;
|
|
63
|
+
int fallback = (int) (64 * density);
|
|
64
|
+
if (width <= 0) width = fallback;
|
|
65
|
+
if (height <= 0) height = fallback;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Rescale via viewBox + preserveAspectRatio so small-viewport SVGs
|
|
69
|
+
// (e.g. width="20") aren't rendered tiny in the top-left corner.
|
|
70
|
+
svg.setDocumentWidth(width);
|
|
71
|
+
svg.setDocumentHeight(height);
|
|
72
|
+
|
|
73
|
+
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
74
|
+
Canvas canvas = new Canvas(bitmap);
|
|
75
|
+
svg.renderToCanvas(canvas);
|
|
76
|
+
return bitmap;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private static SVG parse(String source) throws SVGParseException, IOException {
|
|
80
|
+
if (isDataUrl(source)) {
|
|
81
|
+
byte[] bytes = decodeDataUrl(source);
|
|
82
|
+
try (InputStream in = new ByteArrayInputStream(bytes)) {
|
|
83
|
+
return SVG.getFromInputStream(in);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
try (InputStream in = new URL(source).openStream()) {
|
|
87
|
+
return SVG.getFromInputStream(in);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/docs.json
CHANGED
|
@@ -545,7 +545,7 @@
|
|
|
545
545
|
{
|
|
546
546
|
"name": "headerLogo",
|
|
547
547
|
"tags": [],
|
|
548
|
-
"docs": "Header logo -
|
|
548
|
+
"docs": "Header logo. Supports:\n- PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n- SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`",
|
|
549
549
|
"complexTypes": [],
|
|
550
550
|
"type": "string | undefined"
|
|
551
551
|
},
|
|
@@ -614,7 +614,7 @@
|
|
|
614
614
|
{
|
|
615
615
|
"name": "logo",
|
|
616
616
|
"tags": [],
|
|
617
|
-
"docs": "Optional logo/icon -
|
|
617
|
+
"docs": "Optional logo/icon. Supports:\n- PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n- SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`",
|
|
618
618
|
"complexTypes": [],
|
|
619
619
|
"type": "string | undefined"
|
|
620
620
|
},
|
|
@@ -653,7 +653,7 @@
|
|
|
653
653
|
{
|
|
654
654
|
"name": "headerLogo",
|
|
655
655
|
"tags": [],
|
|
656
|
-
"docs": "Header logo -
|
|
656
|
+
"docs": "Header logo. Supports:\n- PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n- SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`",
|
|
657
657
|
"complexTypes": [],
|
|
658
658
|
"type": "string | undefined"
|
|
659
659
|
},
|
|
@@ -260,13 +260,21 @@ export interface MultiSelectResult {
|
|
|
260
260
|
export interface SheetRow {
|
|
261
261
|
/** Row title (required) */
|
|
262
262
|
title: string;
|
|
263
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Optional logo/icon. Supports:
|
|
265
|
+
* - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL
|
|
266
|
+
* - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`
|
|
267
|
+
*/
|
|
264
268
|
logo?: string;
|
|
265
269
|
/** Optional value displayed on the right */
|
|
266
270
|
value?: string;
|
|
267
271
|
}
|
|
268
272
|
export interface SheetOptions extends DialogStyleOptions {
|
|
269
|
-
/**
|
|
273
|
+
/**
|
|
274
|
+
* Header logo. Supports:
|
|
275
|
+
* - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL
|
|
276
|
+
* - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`
|
|
277
|
+
*/
|
|
270
278
|
headerLogo?: string;
|
|
271
279
|
/** Sheet title */
|
|
272
280
|
title: string;
|
|
@@ -282,7 +290,11 @@ export interface SheetOptions extends DialogStyleOptions {
|
|
|
282
290
|
mode?: DialogMode;
|
|
283
291
|
}
|
|
284
292
|
export interface MessageSheetOptions extends DialogStyleOptions {
|
|
285
|
-
/**
|
|
293
|
+
/**
|
|
294
|
+
* Header logo. Supports:
|
|
295
|
+
* - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL
|
|
296
|
+
* - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`
|
|
297
|
+
*/
|
|
286
298
|
headerLogo?: string;
|
|
287
299
|
/** Sheet title */
|
|
288
300
|
title: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Dialog presentation mode.\n *\n * - `'basic'` — Standard modal dialog (default)\n * - `'fullscreen'` — Full-screen dialog presentation\n */\nexport type DialogMode = 'basic' | 'fullscreen';\n\nexport interface DialogStyleOptions {\n /**\n * Color for the OK/primary button (hex format, e.g., \"#FF5722\")\n */\n buttonColor?: string;\n /**\n * Color for the cancel button (hex format, e.g., \"#757575\")\n */\n cancelButtonColor?: string;\n /**\n * Color for the title text (hex format, e.g., \"#000000\")\n */\n titleColor?: string;\n /**\n * Color for the message text (hex format, e.g., \"#666666\")\n */\n messageColor?: string;\n /**\n * Background color of the dialog (hex format, e.g., \"#FFFFFF\")\n */\n backgroundColor?: string;\n /**\n * Font size for the title text in sp/pt (e.g., 20)\n */\n titleFontSize?: number;\n /**\n * Font size for the message text in sp/pt (e.g., 16)\n */\n messageFontSize?: number;\n /**\n * Font size for the button text in sp/pt (e.g., 14)\n */\n buttonFontSize?: number;\n /**\n * Vertical spacing between dialog content and the confirm/cancel buttons in dp/pt/px (e.g., 16).\n * Only applies to fullscreen and sheet modes.\n *\n * @example\n * // Fullscreen confirm with extra spacing between content and buttons\n * await ExtendedDialog.confirm({\n * title: 'Delete Account',\n * message: 'This action cannot be undone.',\n * mode: 'fullscreen',\n * contentButtonSpacing: 32,\n * });\n *\n * @example\n * // Sheet with tight spacing\n * await ExtendedDialog.sheet({\n * title: 'Order Summary',\n * rows: [{ title: 'Total', value: '$9.99' }],\n * contentButtonSpacing: 8,\n * });\n */\n contentButtonSpacing?: number;\n /**\n * Corner radius for the header logo in sheet dialogs (in dp/pt/px).\n * - Positive number: specific radius (e.g., 12)\n * - 0: square corners (no rounding)\n * - -1: full circle (radius = half of logo size)\n *\n * @default 8\n *\n * @example\n * // Custom rounded corners (12px)\n * await ExtendedDialog.sheet({\n * title: 'Settings',\n * headerLogo: 'https://example.com/logo.png',\n * headerLogoCornerRadius: 12,\n * rows: [],\n * });\n *\n * @example\n * // Full circle logo\n * await ExtendedDialog.sheet({\n * title: 'Profile',\n * headerLogo: 'https://example.com/avatar.png',\n * headerLogoCornerRadius: -1,\n * rows: [],\n * });\n *\n * @example\n * // Square logo (no rounding)\n * await ExtendedDialog.sheet({\n * title: 'Document',\n * headerLogo: 'https://example.com/icon.png',\n * headerLogoCornerRadius: 0,\n * rows: [],\n * });\n */\n headerLogoCornerRadius?: number;\n}\n\nexport interface BaseDialogOptions extends DialogStyleOptions {\n /**\n * Title displayed at the top of the dialog.\n */\n title?: string;\n /**\n * Message body displayed in the dialog.\n */\n message: string;\n /**\n * Presentation mode for the dialog.\n *\n * @default 'basic'\n */\n mode?: DialogMode;\n}\n\nexport interface AlertOptions extends BaseDialogOptions {\n /**\n * Title for the dismiss button.\n *\n * @default \"OK\"\n */\n buttonTitle?: string;\n}\n\nexport interface ConfirmOptions extends BaseDialogOptions {\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface PromptOptions extends BaseDialogOptions {\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n /**\n * Placeholder text shown in the input field when empty.\n */\n inputPlaceholder?: string;\n /**\n * Pre-filled value for the input field.\n */\n inputText?: string;\n /**\n * Whether to automatically focus the input field and open the keyboard when the dialog appears.\n *\n * Note: On iOS, basic (non-fullscreen) dialogs always auto-focus the input field due to\n * UIAlertController's built-in behavior. This option only takes effect on iOS when using\n * fullscreen mode (`mode: 'fullscreen'`). On Android and web, this works for all modes.\n *\n * @default false\n */\n focusInput?: boolean;\n}\n\nexport interface SelectOption {\n /**\n * Display text for the option.\n */\n label: string;\n /**\n * Value returned when the option is selected.\n */\n value: string;\n}\n\nexport interface SingleSelectOptions extends BaseDialogOptions {\n /**\n * List of options to display for selection.\n */\n options: SelectOption[];\n /**\n * Value of the initially selected option.\n */\n selectedValue?: string;\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface MultiSelectOptions extends BaseDialogOptions {\n /**\n * List of options to display for selection.\n */\n options: SelectOption[];\n /**\n * Values of the initially selected options.\n */\n selectedValues?: string[];\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface ConfirmResult {\n /**\n * Whether the user confirmed (`true`) or cancelled (`false`).\n */\n value: boolean;\n}\n\nexport interface PromptResult {\n /**\n * The text entered by the user. Empty string if cancelled.\n */\n value: string;\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface SingleSelectResult {\n /**\n * The value of the selected option, or `null` if cancelled.\n */\n value: string | null;\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface MultiSelectResult {\n /**\n * The values of the selected options. Empty array if cancelled.\n */\n values: string[];\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface SheetRow {\n /** Row title (required) */\n title: string;\n /** Optional logo/icon - supports base64 data URL or HTTP/HTTPS URL */\n logo?: string;\n /** Optional value displayed on the right */\n value?: string;\n}\n\nexport interface SheetOptions extends DialogStyleOptions {\n /** Header logo - supports base64 data URL or HTTP/HTTPS URL */\n headerLogo?: string;\n /** Sheet title */\n title: string;\n /** Optional subtitle displayed between title and rows */\n subtitle?: string;\n /** Description rows */\n rows: SheetRow[];\n /** Confirm button title */\n confirmButtonTitle?: string; // default: \"Confirm\"\n /** Cancel button title */\n cancelButtonTitle?: string; // default: \"Cancel\"\n /** Dialog mode */\n mode?: DialogMode;\n}\n\nexport interface MessageSheetOptions extends DialogStyleOptions {\n /** Header logo - supports base64 data URL or HTTP/HTTPS URL */\n headerLogo?: string;\n /** Sheet title */\n title: string;\n /** Optional subtitle displayed between title and message */\n subtitle?: string;\n /** Message body displayed in the sheet */\n message: string;\n /** Confirm button title */\n confirmButtonTitle?: string; // default: \"Confirm\"\n /** Cancel button title */\n cancelButtonTitle?: string; // default: \"Cancel\"\n /** Dialog mode */\n mode?: DialogMode;\n}\n\nexport interface SheetResult {\n /** True if confirmed, false if cancelled */\n confirmed: boolean;\n}\n\nexport interface MessageSheetResult {\n /** True if confirmed, false if cancelled */\n confirmed: boolean;\n}\n\nexport interface ExtendedDialogPlugin {\n /**\n * Show an alert dialog with a single dismiss button.\n *\n * @param options - Alert configuration options.\n */\n alert(options: AlertOptions): Promise<void>;\n /**\n * Show a confirmation dialog with OK and Cancel buttons.\n *\n * @param options - Confirm configuration options.\n * @returns The user's confirmation choice.\n */\n confirm(options: ConfirmOptions): Promise<ConfirmResult>;\n /**\n * Show a prompt dialog with a text input field.\n *\n * @param options - Prompt configuration options.\n * @returns The entered text and whether the dialog was cancelled.\n */\n prompt(options: PromptOptions): Promise<PromptResult>;\n /**\n * Show a single-select dialog where the user picks one option.\n *\n * @param options - Single select configuration options.\n * @returns The selected value and whether the dialog was cancelled.\n */\n singleSelect(options: SingleSelectOptions): Promise<SingleSelectResult>;\n /**\n * Show a multi-select dialog where the user picks one or more options.\n *\n * @param options - Multi select configuration options.\n * @returns The selected values and whether the dialog was cancelled.\n */\n multiSelect(options: MultiSelectOptions): Promise<MultiSelectResult>;\n /**\n * Show a sheet dialog with a header, title, and structured data rows.\n *\n * @param options - Sheet configuration options.\n * @returns Whether the user confirmed or cancelled the sheet.\n */\n sheet(options: SheetOptions): Promise<SheetResult>;\n\n /**\n * Show a message sheet dialog with an optional header logo, title, and message.\n *\n * @param options - Message sheet configuration options.\n * @returns Whether the user confirmed or cancelled the sheet.\n */\n messageSheet(options: MessageSheetOptions): Promise<MessageSheetResult>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Dialog presentation mode.\n *\n * - `'basic'` — Standard modal dialog (default)\n * - `'fullscreen'` — Full-screen dialog presentation\n */\nexport type DialogMode = 'basic' | 'fullscreen';\n\nexport interface DialogStyleOptions {\n /**\n * Color for the OK/primary button (hex format, e.g., \"#FF5722\")\n */\n buttonColor?: string;\n /**\n * Color for the cancel button (hex format, e.g., \"#757575\")\n */\n cancelButtonColor?: string;\n /**\n * Color for the title text (hex format, e.g., \"#000000\")\n */\n titleColor?: string;\n /**\n * Color for the message text (hex format, e.g., \"#666666\")\n */\n messageColor?: string;\n /**\n * Background color of the dialog (hex format, e.g., \"#FFFFFF\")\n */\n backgroundColor?: string;\n /**\n * Font size for the title text in sp/pt (e.g., 20)\n */\n titleFontSize?: number;\n /**\n * Font size for the message text in sp/pt (e.g., 16)\n */\n messageFontSize?: number;\n /**\n * Font size for the button text in sp/pt (e.g., 14)\n */\n buttonFontSize?: number;\n /**\n * Vertical spacing between dialog content and the confirm/cancel buttons in dp/pt/px (e.g., 16).\n * Only applies to fullscreen and sheet modes.\n *\n * @example\n * // Fullscreen confirm with extra spacing between content and buttons\n * await ExtendedDialog.confirm({\n * title: 'Delete Account',\n * message: 'This action cannot be undone.',\n * mode: 'fullscreen',\n * contentButtonSpacing: 32,\n * });\n *\n * @example\n * // Sheet with tight spacing\n * await ExtendedDialog.sheet({\n * title: 'Order Summary',\n * rows: [{ title: 'Total', value: '$9.99' }],\n * contentButtonSpacing: 8,\n * });\n */\n contentButtonSpacing?: number;\n /**\n * Corner radius for the header logo in sheet dialogs (in dp/pt/px).\n * - Positive number: specific radius (e.g., 12)\n * - 0: square corners (no rounding)\n * - -1: full circle (radius = half of logo size)\n *\n * @default 8\n *\n * @example\n * // Custom rounded corners (12px)\n * await ExtendedDialog.sheet({\n * title: 'Settings',\n * headerLogo: 'https://example.com/logo.png',\n * headerLogoCornerRadius: 12,\n * rows: [],\n * });\n *\n * @example\n * // Full circle logo\n * await ExtendedDialog.sheet({\n * title: 'Profile',\n * headerLogo: 'https://example.com/avatar.png',\n * headerLogoCornerRadius: -1,\n * rows: [],\n * });\n *\n * @example\n * // Square logo (no rounding)\n * await ExtendedDialog.sheet({\n * title: 'Document',\n * headerLogo: 'https://example.com/icon.png',\n * headerLogoCornerRadius: 0,\n * rows: [],\n * });\n */\n headerLogoCornerRadius?: number;\n}\n\nexport interface BaseDialogOptions extends DialogStyleOptions {\n /**\n * Title displayed at the top of the dialog.\n */\n title?: string;\n /**\n * Message body displayed in the dialog.\n */\n message: string;\n /**\n * Presentation mode for the dialog.\n *\n * @default 'basic'\n */\n mode?: DialogMode;\n}\n\nexport interface AlertOptions extends BaseDialogOptions {\n /**\n * Title for the dismiss button.\n *\n * @default \"OK\"\n */\n buttonTitle?: string;\n}\n\nexport interface ConfirmOptions extends BaseDialogOptions {\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface PromptOptions extends BaseDialogOptions {\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n /**\n * Placeholder text shown in the input field when empty.\n */\n inputPlaceholder?: string;\n /**\n * Pre-filled value for the input field.\n */\n inputText?: string;\n /**\n * Whether to automatically focus the input field and open the keyboard when the dialog appears.\n *\n * Note: On iOS, basic (non-fullscreen) dialogs always auto-focus the input field due to\n * UIAlertController's built-in behavior. This option only takes effect on iOS when using\n * fullscreen mode (`mode: 'fullscreen'`). On Android and web, this works for all modes.\n *\n * @default false\n */\n focusInput?: boolean;\n}\n\nexport interface SelectOption {\n /**\n * Display text for the option.\n */\n label: string;\n /**\n * Value returned when the option is selected.\n */\n value: string;\n}\n\nexport interface SingleSelectOptions extends BaseDialogOptions {\n /**\n * List of options to display for selection.\n */\n options: SelectOption[];\n /**\n * Value of the initially selected option.\n */\n selectedValue?: string;\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface MultiSelectOptions extends BaseDialogOptions {\n /**\n * List of options to display for selection.\n */\n options: SelectOption[];\n /**\n * Values of the initially selected options.\n */\n selectedValues?: string[];\n /**\n * Title for the confirmation button.\n *\n * @default \"OK\"\n */\n okButtonTitle?: string;\n /**\n * Title for the cancel button.\n *\n * @default \"Cancel\"\n */\n cancelButtonTitle?: string;\n}\n\nexport interface ConfirmResult {\n /**\n * Whether the user confirmed (`true`) or cancelled (`false`).\n */\n value: boolean;\n}\n\nexport interface PromptResult {\n /**\n * The text entered by the user. Empty string if cancelled.\n */\n value: string;\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface SingleSelectResult {\n /**\n * The value of the selected option, or `null` if cancelled.\n */\n value: string | null;\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface MultiSelectResult {\n /**\n * The values of the selected options. Empty array if cancelled.\n */\n values: string[];\n /**\n * Whether the user cancelled the dialog.\n */\n cancelled: boolean;\n}\n\nexport interface SheetRow {\n /** Row title (required) */\n title: string;\n /**\n * Optional logo/icon. Supports:\n * - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n * - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`\n */\n logo?: string;\n /** Optional value displayed on the right */\n value?: string;\n}\n\nexport interface SheetOptions extends DialogStyleOptions {\n /**\n * Header logo. Supports:\n * - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n * - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`\n */\n headerLogo?: string;\n /** Sheet title */\n title: string;\n /** Optional subtitle displayed between title and rows */\n subtitle?: string;\n /** Description rows */\n rows: SheetRow[];\n /** Confirm button title */\n confirmButtonTitle?: string; // default: \"Confirm\"\n /** Cancel button title */\n cancelButtonTitle?: string; // default: \"Cancel\"\n /** Dialog mode */\n mode?: DialogMode;\n}\n\nexport interface MessageSheetOptions extends DialogStyleOptions {\n /**\n * Header logo. Supports:\n * - PNG/JPEG/WebP/GIF as base64 data URL or HTTP/HTTPS URL\n * - SVG as `data:image/svg+xml;base64,...`, `data:image/svg+xml,<svg ...>...` (URL-encoded or plain), or any HTTP/HTTPS URL ending in `.svg`\n */\n headerLogo?: string;\n /** Sheet title */\n title: string;\n /** Optional subtitle displayed between title and message */\n subtitle?: string;\n /** Message body displayed in the sheet */\n message: string;\n /** Confirm button title */\n confirmButtonTitle?: string; // default: \"Confirm\"\n /** Cancel button title */\n cancelButtonTitle?: string; // default: \"Cancel\"\n /** Dialog mode */\n mode?: DialogMode;\n}\n\nexport interface SheetResult {\n /** True if confirmed, false if cancelled */\n confirmed: boolean;\n}\n\nexport interface MessageSheetResult {\n /** True if confirmed, false if cancelled */\n confirmed: boolean;\n}\n\nexport interface ExtendedDialogPlugin {\n /**\n * Show an alert dialog with a single dismiss button.\n *\n * @param options - Alert configuration options.\n */\n alert(options: AlertOptions): Promise<void>;\n /**\n * Show a confirmation dialog with OK and Cancel buttons.\n *\n * @param options - Confirm configuration options.\n * @returns The user's confirmation choice.\n */\n confirm(options: ConfirmOptions): Promise<ConfirmResult>;\n /**\n * Show a prompt dialog with a text input field.\n *\n * @param options - Prompt configuration options.\n * @returns The entered text and whether the dialog was cancelled.\n */\n prompt(options: PromptOptions): Promise<PromptResult>;\n /**\n * Show a single-select dialog where the user picks one option.\n *\n * @param options - Single select configuration options.\n * @returns The selected value and whether the dialog was cancelled.\n */\n singleSelect(options: SingleSelectOptions): Promise<SingleSelectResult>;\n /**\n * Show a multi-select dialog where the user picks one or more options.\n *\n * @param options - Multi select configuration options.\n * @returns The selected values and whether the dialog was cancelled.\n */\n multiSelect(options: MultiSelectOptions): Promise<MultiSelectResult>;\n /**\n * Show a sheet dialog with a header, title, and structured data rows.\n *\n * @param options - Sheet configuration options.\n * @returns Whether the user confirmed or cancelled the sheet.\n */\n sheet(options: SheetOptions): Promise<SheetResult>;\n\n /**\n * Show a message sheet dialog with an optional header logo, title, and message.\n *\n * @param options - Message sheet configuration options.\n * @returns Whether the user confirmed or cancelled the sheet.\n */\n messageSheet(options: MessageSheetOptions): Promise<MessageSheetResult>;\n}\n"]}
|
|
@@ -946,25 +946,30 @@ public class FullScreenDialogViewController: UIViewController {
|
|
|
946
946
|
}
|
|
947
947
|
|
|
948
948
|
private func loadImage(from urlString: String, into imageView: UIImageView) {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
imageView.image = image
|
|
956
|
-
}
|
|
949
|
+
if SvgImageLoader.isSvgSource(urlString) {
|
|
950
|
+
let targetSize = imageView.bounds.size == .zero
|
|
951
|
+
? CGSize(width: 64, height: 64)
|
|
952
|
+
: imageView.bounds.size
|
|
953
|
+
SvgImageLoader.render(source: urlString, targetSize: targetSize) { [weak imageView] image in
|
|
954
|
+
imageView?.image = image
|
|
957
955
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}.resume()
|
|
956
|
+
return
|
|
957
|
+
}
|
|
958
|
+
if SvgImageLoader.isDataUrl(urlString) {
|
|
959
|
+
if let imageData = SvgImageLoader.decodeDataUrl(urlString),
|
|
960
|
+
let image = UIImage(data: imageData) {
|
|
961
|
+
imageView.image = image
|
|
962
|
+
}
|
|
963
|
+
return
|
|
967
964
|
}
|
|
965
|
+
guard let url = URL(string: urlString) else { return }
|
|
966
|
+
URLSession.shared.dataTask(with: url) { [weak imageView] data, _, _ in
|
|
967
|
+
if let data = data, let image = UIImage(data: data) {
|
|
968
|
+
DispatchQueue.main.async {
|
|
969
|
+
imageView?.image = image
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}.resume()
|
|
968
973
|
}
|
|
969
974
|
|
|
970
975
|
private func applyLiquidGlassStyle() {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import SVGKit
|
|
3
|
+
|
|
4
|
+
enum SvgImageLoader {
|
|
5
|
+
|
|
6
|
+
private static let svgDataUrlPrefix = "data:image/svg+xml"
|
|
7
|
+
private static let dataUrlPrefix = "data:"
|
|
8
|
+
|
|
9
|
+
static func isDataUrl(_ source: String) -> Bool {
|
|
10
|
+
source.range(of: dataUrlPrefix, options: [.anchored, .caseInsensitive]) != nil
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static func isSvgSource(_ source: String) -> Bool {
|
|
14
|
+
if source.range(of: svgDataUrlPrefix, options: [.anchored, .caseInsensitive]) != nil {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
if let url = URL(string: source),
|
|
18
|
+
let scheme = url.scheme?.lowercased(),
|
|
19
|
+
scheme == "http" || scheme == "https" {
|
|
20
|
+
return url.pathExtension.caseInsensitiveCompare("svg") == .orderedSame
|
|
21
|
+
}
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Supports `;base64` and percent-encoded payloads.
|
|
26
|
+
static func decodeDataUrl(_ source: String) -> Data? {
|
|
27
|
+
guard let commaIndex = source.firstIndex(of: ",") else { return nil }
|
|
28
|
+
let header = source[..<commaIndex]
|
|
29
|
+
let payload = String(source[source.index(after: commaIndex)...])
|
|
30
|
+
if header.range(of: ";base64", options: .caseInsensitive) != nil {
|
|
31
|
+
return Data(base64Encoded: payload)
|
|
32
|
+
}
|
|
33
|
+
return (payload.removingPercentEncoding ?? payload).data(using: .utf8)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Uses image's intrinsic size when `targetSize` is `.zero`.
|
|
37
|
+
static func render(source: String, targetSize: CGSize, completion: @escaping (UIImage?) -> Void) {
|
|
38
|
+
if isDataUrl(source) {
|
|
39
|
+
guard let data = decodeDataUrl(source) else {
|
|
40
|
+
completion(nil); return
|
|
41
|
+
}
|
|
42
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
43
|
+
let image = render(data: data, targetSize: targetSize)
|
|
44
|
+
DispatchQueue.main.async { completion(image) }
|
|
45
|
+
}
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
guard let url = URL(string: source) else {
|
|
49
|
+
completion(nil); return
|
|
50
|
+
}
|
|
51
|
+
URLSession.shared.dataTask(with: url) { data, _, _ in
|
|
52
|
+
guard let data = data else {
|
|
53
|
+
DispatchQueue.main.async { completion(nil) }
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
57
|
+
let image = render(data: data, targetSize: targetSize)
|
|
58
|
+
DispatchQueue.main.async { completion(image) }
|
|
59
|
+
}
|
|
60
|
+
}.resume()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private static func render(data: Data, targetSize: CGSize) -> UIImage? {
|
|
64
|
+
guard let svgImage = SVGKImage(data: data) else { return nil }
|
|
65
|
+
if targetSize.width > 0 && targetSize.height > 0 && svgImage.size != targetSize {
|
|
66
|
+
svgImage.size = targetSize
|
|
67
|
+
}
|
|
68
|
+
return svgImage.uiImage
|
|
69
|
+
}
|
|
70
|
+
}
|
package/package.json
CHANGED