@octane-xplat/gif 0.0.0-nightly.g2e22171

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 ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Alec Larson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # `@octane-xplat/gif`
2
+
3
+ ```sh
4
+ pnpm add @octane-xplat/gif
5
+ ```
6
+
7
+ Animated images (GIF, animated WebP) for Octane xplat apps: a plain
8
+ `<img>` on web and `@nativescript-community/ui-image`
9
+ (Fresco on Android / SDWebImage on iOS) on native, with a macOS entry.
10
+
11
+ ```tsx
12
+ import { AnimatedImage } from '@octane-xplat/gif'
13
+
14
+ ;<AnimatedImage
15
+ src="https://example.com/loader.gif"
16
+ alt="Loading"
17
+ stretch="aspectFit" // 'none' | 'fill' | 'aspectFit' | 'aspectFill'
18
+ width={96}
19
+ height={96}
20
+ />
21
+ ```
22
+
23
+ `stretch` shares the core `Image` grammar — web maps it to `object-fit`
24
+ and the plugin accepts the same values natively. For Lottie JSON
25
+ animations use [`@octane-xplat/lottie`](../lottie/README.md) instead.
26
+
27
+ ## Prefetch
28
+
29
+ `prefetch` warms the image engine's disk cache for URLs you expect to show
30
+ soon — bytes on disk now, decode still at display time:
31
+
32
+ ```tsx
33
+ import { prefetch } from '@octane-xplat/gif'
34
+
35
+ await prefetch(feed.map((post) => post.imageUrl)) // false if any URL fails
36
+
37
+ await prefetch(urls, {
38
+ headers: { Authorization: 'Bearer …' }, // Android only — see below
39
+ concurrency: 5, // max parallel fetches (default)
40
+ })
41
+ ```
42
+
43
+ On Android that is Fresco's `prefetchToDiskCache`; on iOS, SDWebImage's
44
+ prefetcher storing to disk. On web it loads each URL through a throwaway
45
+ `<img>` so the browser HTTP cache is warm. It resolves `false` when any URL
46
+ fails — and always `false` on macOS, where the AppKit host has no image
47
+ pipeline yet. Same contract as `@octane-xplat/image`'s `prefetch`.
48
+
49
+ Options: `headers` is forwarded to the engine — **honored on Android,
50
+ dropped on iOS** (the plugin's prefetch path lacks the request-modifier
51
+ branch its display path has; an upstream patch is needed) — and ignored on
52
+ web. `concurrency` caps parallel fetches JS-side (default 5).
53
+
54
+ ## Platform props
55
+
56
+ `ios`, `android`, and `web` escape bags apply after the shared props, the
57
+ same convention as `@octane-xplat/ui`. Native bags assign onto the ui-image
58
+ `Img` view, so engine props such as `noCache`, `decodeWidth`,
59
+ `decodeHeight`, `placeholderImageUri`, and `progressiveRenderingEnabled`
60
+ are reachable where the engine supports them:
61
+
62
+ ```tsx
63
+ <AnimatedImage
64
+ src={photo.url}
65
+ ios={{ noCache: true }}
66
+ android={{ decodeWidth: 288, decodeHeight: 288 }}
67
+ />
68
+ ```
69
+
70
+ Per-target limits are recorded in
71
+ [known limits](../../docs/verify/known-limits.md). Exercised by
72
+ [`AnimatedImageDemo`](../demos/src/AnimatedImageDemo.tsrx).
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@octane-xplat/gif",
3
+ "version": "0.0.0-nightly.g2e22171",
4
+ "description": "Animated images (GIF/animated webp) for Octane xplat — web <img> + @nativescript-community/ui-image",
5
+ "keywords": [
6
+ "android",
7
+ "animated-image",
8
+ "animated-webp",
9
+ "cross-platform",
10
+ "gif",
11
+ "image",
12
+ "ios",
13
+ "nativescript",
14
+ "octane",
15
+ "web",
16
+ "xplat"
17
+ ],
18
+ "homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/gif",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/octane-xplat/octane-xplat",
23
+ "directory": "packages/gif"
24
+ },
25
+ "files": [
26
+ "types",
27
+ "src",
28
+ "!src/**/*.test.*",
29
+ "!src/**/*.spec.*"
30
+ ],
31
+ "type": "module",
32
+ "exports": {
33
+ ".": {
34
+ "macos": {
35
+ "types": "./types/index.macos.d.ts",
36
+ "default": "./src/index.macos.ts"
37
+ },
38
+ "web": {
39
+ "types": "./types/generated/index.web.d.ts",
40
+ "default": "./src/index.web.ts"
41
+ },
42
+ "native": {
43
+ "types": "./types/generated/index.d.ts",
44
+ "default": "./src/index.ts"
45
+ },
46
+ "types": "./types/generated/index.d.ts",
47
+ "default": "./src/index.ts"
48
+ }
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "dependencies": {
54
+ "@nativescript-community/ui-image": "4.6.20"
55
+ },
56
+ "devDependencies": {
57
+ "@nativescript-community/octane": "0.2.5",
58
+ "@nativescript/core": "9.1.3",
59
+ "@octane-xplat/macos-renderer": "0.0.0-nightly.g2e22171",
60
+ "@octanejs/vite-plugin": "0.1.61",
61
+ "@tsrx/typescript-plugin": "0.4.11",
62
+ "octane": "0.11.0",
63
+ "tsrx-typegen": "0.3.0",
64
+ "typescript": "5.9.3",
65
+ "vite": "8.3.0"
66
+ },
67
+ "peerDependencies": {
68
+ "@nativescript-community/octane": ">=0.2.1 <1",
69
+ "@nativescript/core": ">=9.1.0 <10",
70
+ "octane": ">=0.6.3 <1"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "@nativescript-community/octane": {
74
+ "optional": true
75
+ },
76
+ "@nativescript/core": {
77
+ "optional": true
78
+ }
79
+ },
80
+ "scripts": {
81
+ "test:packed": "node tests/packed-consumer.mjs",
82
+ "typegen": "tsrx-typegen --target octane",
83
+ "pack:check": "tsrx-typegen --pack-check"
84
+ }
85
+ }
@@ -0,0 +1,7 @@
1
+ /** @jsxImportSource @octane-xplat/macos-renderer */
2
+ import type { AnimatedImageProps } from './props'
3
+
4
+ /** Show an explicit placeholder until the AppKit host has an animation view. */
5
+ export function AnimatedImage(_props: AnimatedImageProps) @{
6
+ <label className="vx-unsupported">Animated images are unsupported by the AppKit host</label>
7
+ }
@@ -0,0 +1,30 @@
1
+ /** @jsxImportSource @nativescript-community/octane */
2
+ import { registerElement } from '@nativescript-community/octane';
3
+ import { Img } from '@nativescript-community/ui-image';
4
+ import type { AnimatedImageProps } from './props';
5
+ import { applyEscapeProps } from './escape-props';
6
+
7
+ // @nativescript-community/ui-image — Fresco DraweeView on Android,
8
+ // SDAnimatedImageView on iOS when `animatedImageView` is set (plain UIImageView
9
+ // otherwise, which would still decode but not animate).
10
+ registerElement('animatedimage', Img);
11
+
12
+ /** AnimatedImage — GIF/animated-webp decode + autoplay via ui-image. `src`
13
+ * takes the Img grammar: remote URL, res://name, ~/bundle path, file path.
14
+ * There is intentionally no play/pause prop — <img> can't pause on web, so
15
+ * the shared contract is always-playing. */
16
+ export function AnimatedImage(props: AnimatedImageProps) @{
17
+ <animatedimage
18
+ ref={(v: any) => applyEscapeProps(v, props)}
19
+ id={props.id}
20
+ className={props.className}
21
+ style={props.style}
22
+ src={props.src}
23
+ stretch={props.stretch ?? 'aspectFit'}
24
+ width={props.width}
25
+ height={props.height}
26
+ animatedImageView={true}
27
+ autoPlayAnimations={true}
28
+ accessibilityLabel={props.alt}
29
+ />
30
+ }
@@ -0,0 +1,27 @@
1
+ import type { AnimatedImageProps } from './props';
2
+ import { applyEscapeProps } from './escape-props.web';
3
+
4
+ const OBJECT_FIT = {
5
+ none: 'none',
6
+ fill: 'fill',
7
+ aspectFit: 'contain',
8
+ aspectFill: 'cover',
9
+ } as const;
10
+
11
+ /** AnimatedImage — a plain <img>; browsers animate GIF/webp natively.
12
+ * `stretch` maps to object-fit. */
13
+ export function AnimatedImage(props: AnimatedImageProps) @{
14
+ <img
15
+ ref={(e: any) => applyEscapeProps(e, props)}
16
+ id={props.id}
17
+ className={props.className}
18
+ style={{
19
+ objectFit: OBJECT_FIT[props.stretch ?? 'aspectFit'],
20
+ width: props.width,
21
+ height: props.height,
22
+ ...props.style,
23
+ }}
24
+ src={props.src}
25
+ alt={props.alt}
26
+ />
27
+ }
@@ -0,0 +1,8 @@
1
+ /** @jsxImportSource @nativescript-community/octane */
2
+ import type { AnimatedImageProps } from './props'
3
+
4
+ /** Unsupported placeholder — the Windows host has no animated-image engine
5
+ * (ui-image ships iOS/Android only). */
6
+ export function AnimatedImage(_props: AnimatedImageProps) @{
7
+ <label className="vx-unsupported" text="Animated images are unsupported on the Windows host" />
8
+ }
@@ -0,0 +1,15 @@
1
+ import { isAndroid, isIOS } from '@nativescript/core'
2
+
3
+ /** Apply only the active device's escape bag after the shared props — the
4
+ * same convention @octane-xplat/ui uses, kept local so this leaf does not
5
+ * depend on ui. */
6
+ export function applyEscapeProps(view: any, props: { ios?: any; android?: any }): void {
7
+ if (!view) {
8
+ return
9
+ }
10
+
11
+ const bag = isIOS ? props.ios : isAndroid ? props.android : undefined
12
+ if (bag) {
13
+ Object.assign(view, bag)
14
+ }
15
+ }
@@ -0,0 +1,26 @@
1
+ /** Apply DOM escape props after the primitive's own props. Dash-named keys
2
+ * are attributes; other keys use the DOM property where available. Mirrors
3
+ * @octane-xplat/ui's web escape-props so this leaf does not depend on ui. */
4
+ export function applyEscapeProps(element: any, props: { web?: any }): void {
5
+ if (!element || !props.web) {
6
+ return
7
+ }
8
+
9
+ for (const [key, value] of Object.entries(props.web)) {
10
+ if (key.includes('-')) {
11
+ if (value == null || value === false) {
12
+ element.removeAttribute(key)
13
+ } else {
14
+ element.setAttribute(key, value === true ? '' : String(value))
15
+ }
16
+ } else if (key in element) {
17
+ try {
18
+ element[key] = value
19
+ } catch {
20
+ element.setAttribute(key, String(value))
21
+ }
22
+ } else if (value != null) {
23
+ element.setAttribute(key, String(value))
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,3 @@
1
+ export { AnimatedImage } from './AnimatedImage.macos.tsrx'
2
+ export { prefetch } from './prefetch.macos'
3
+ export type { AnimatedImageProps, PrefetchOptions } from './props'
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ // Platform barrels — explicit .tsrx leaf imports (moduleSuffixes don't
2
+ // reach .tsrx; same convention as @octane-xplat/ui index.*.ts).
3
+ export { AnimatedImage } from './AnimatedImage.tsrx'
4
+ export { prefetch } from './prefetch'
5
+ export type { AnimatedImageProps, PrefetchOptions } from './props'
@@ -0,0 +1,5 @@
1
+ // Platform barrels — explicit .tsrx leaf imports (moduleSuffixes don't
2
+ // reach .tsrx; same convention as @octane-xplat/ui index.*.ts).
3
+ export { AnimatedImage } from './AnimatedImage.web.tsrx'
4
+ export { prefetch } from './prefetch.web'
5
+ export type { AnimatedImageProps, PrefetchOptions } from './props'
@@ -0,0 +1,5 @@
1
+ // Windows barrel — explicit leaf imports keep @nativescript-community/
2
+ // ui-image (iOS/Android only) out of the windows graph at the file boundary.
3
+ export { AnimatedImage } from './AnimatedImage.windows.tsrx'
4
+ export { prefetch } from './prefetch.windows'
5
+ export type { AnimatedImageProps, PrefetchOptions } from './props'
@@ -0,0 +1,8 @@
1
+ import { Img } from '@nativescript-community/ui-image'
2
+ import type { Attributes } from '@nativescript-community/octane/intrinsics'
3
+
4
+ declare module '@nativescript-community/octane/intrinsics' {
5
+ interface NativeScriptElements {
6
+ animatedimage: Attributes<typeof Img>
7
+ }
8
+ }
@@ -0,0 +1,55 @@
1
+ /** VENDORED — identical copy in packages/image/src/prefetch-batch.ts; keep in
2
+ * sync.
3
+ *
4
+ * Shared batch driver for the image-engine leaves' `prefetch` contract:
5
+ * normalizes `string | string[]`, caps in-flight requests JS-side, and
6
+ * resolves `true` only when every URL warms — `false` on the first failure
7
+ * (in-flight requests settle on their own; the result is already decided). */
8
+
9
+ /** Matches the `maxRequests = 5` ceiling NS core's ImageCache used. */
10
+ export const DEFAULT_PREFETCH_CONCURRENCY = 5
11
+
12
+ export function prefetchBatch(
13
+ srcs: string | string[],
14
+ concurrency: number | undefined,
15
+ warm: (url: string) => Promise<boolean>,
16
+ ): Promise<boolean> {
17
+ const urls = Array.isArray(srcs) ? srcs : [srcs]
18
+ if (urls.length === 0) {
19
+ return Promise.resolve(true)
20
+ }
21
+
22
+ const requested = Math.floor(concurrency ?? DEFAULT_PREFETCH_CONCURRENCY)
23
+ const limit =
24
+ Number.isFinite(requested) && requested > 0 ? requested : DEFAULT_PREFETCH_CONCURRENCY
25
+
26
+ return new Promise<boolean>((resolve) => {
27
+ let next = 0
28
+ let active = Math.min(limit, urls.length)
29
+ // Surviving workers stop dequeuing once a failure decides the result —
30
+ // only already-running warm() calls settle on their own.
31
+ let failed = false
32
+ for (let i = 0; i < active; i++) {
33
+ void (async () => {
34
+ while (!failed && next < urls.length) {
35
+ const url = urls[next++]
36
+ try {
37
+ if (!(await warm(url))) {
38
+ failed = true
39
+ resolve(false)
40
+ return
41
+ }
42
+ } catch {
43
+ failed = true
44
+ resolve(false)
45
+ return
46
+ }
47
+ }
48
+
49
+ if (--active === 0) {
50
+ resolve(true)
51
+ }
52
+ })()
53
+ }
54
+ })
55
+ }
@@ -0,0 +1,8 @@
1
+ import type { PrefetchOptions } from './props'
2
+
3
+ /** prefetch — no-op on the AppKit host: it has no image pipeline yet
4
+ * (AnimatedImage renders a placeholder there), so nothing is warmed.
5
+ * Resolves false to report that honestly. */
6
+ export function prefetch(_srcs: string | string[], _options?: PrefetchOptions): Promise<boolean> {
7
+ return Promise.resolve(false)
8
+ }
@@ -0,0 +1,38 @@
1
+ import { isAndroid } from '@nativescript/core'
2
+ import { getImagePipeline, initialize } from '@nativescript-community/ui-image'
3
+ import { prefetchBatch } from './prefetch-batch'
4
+ import type { PrefetchOptions } from './props'
5
+
6
+ /** prefetch — warm the image engine's disk cache for `srcs` without displaying
7
+ * anything. Android (Fresco): `prefetchToDiskCache` stores encoded bytes on
8
+ * disk and defers bitmap decode to display. iOS (SDWebImage): the prefetcher
9
+ * stores the downloaded image to the disk cache only. Either way a later
10
+ * `AnimatedImage` with the same src hits disk instead of the network.
11
+ * Resolves false when any URL fails; resolves false when the pipeline is not
12
+ * available yet (e.g. called before app launch).
13
+ * `options.concurrency` caps parallel fetches (default 5); `options.headers`
14
+ * is honored on Android and silently dropped on iOS (upstream gap — see
15
+ * PrefetchOptions). */
16
+ export function prefetch(srcs: string | string[], options?: PrefetchOptions): Promise<boolean> {
17
+ try {
18
+ // The plugin lazily initializes Fresco inside createNativeView; a prefetch
19
+ // that runs before any Img mounts has to do it first. initialize() is a
20
+ // no-op once the plugin (or the app) has initialized. iOS has no equivalent
21
+ // requirement and its initialize() is not guarded, so it stays Android-only.
22
+ if (isAndroid) {
23
+ initialize()
24
+ }
25
+
26
+ const pipeline = getImagePipeline()
27
+ const { concurrency, ...engineOptions } = options ?? {}
28
+
29
+ return prefetchBatch(srcs, concurrency, (url) =>
30
+ pipeline.prefetchToDiskCache(url, engineOptions).then(
31
+ () => true,
32
+ () => false,
33
+ ),
34
+ )
35
+ } catch {
36
+ return Promise.resolve(false)
37
+ }
38
+ }
@@ -0,0 +1,21 @@
1
+ import { prefetchBatch } from './prefetch-batch'
2
+ import type { PrefetchOptions } from './props'
3
+
4
+ /** prefetch — load each `src` through a throwaway <img> so the response lands
5
+ * in the browser HTTP cache; decode and render stay with the displaying
6
+ * element. `options.headers` is ignored — an <img> request cannot carry
7
+ * custom headers. `options.concurrency` caps parallel loads (default 5).
8
+ * Resolves false when any URL fails. */
9
+ export function prefetch(srcs: string | string[], options?: PrefetchOptions): Promise<boolean> {
10
+ return prefetchBatch(
11
+ srcs,
12
+ options?.concurrency,
13
+ (url) =>
14
+ new Promise<boolean>((resolve) => {
15
+ const image = new Image()
16
+ image.onload = () => resolve(true)
17
+ image.onerror = () => resolve(false)
18
+ image.src = url
19
+ }),
20
+ )
21
+ }
@@ -0,0 +1,8 @@
1
+ import type { PrefetchOptions } from './props'
2
+
3
+ /** prefetch — no-op on Windows: there is no image pipeline to warm
4
+ * (AnimatedImage renders a placeholder there). Resolves false to report
5
+ * that honestly. */
6
+ export function prefetch(_srcs: string | string[], _options?: PrefetchOptions): Promise<boolean> {
7
+ return Promise.resolve(false)
8
+ }
package/src/props.ts ADDED
@@ -0,0 +1,34 @@
1
+ export interface AnimatedImageProps {
2
+ className?: any
3
+ style?: any
4
+ id?: string
5
+ src: string
6
+ alt?: string
7
+ /** Content fit — same grammar as core Image. Web maps to object-fit;
8
+ * ui-image (Fresco/SDWebImage) accepts the same values. */
9
+ stretch?: 'none' | 'fill' | 'aspectFit' | 'aspectFill'
10
+ width?: string | number
11
+ height?: string | number
12
+ /** Platform-specific properties are applied after shared props. Native
13
+ * bags assign onto the ui-image `Img` view — `noCache`, `decodeWidth`,
14
+ * `decodeHeight`, `placeholderImageUri`, `progressiveRenderingEnabled`,
15
+ * `cacheKey`, and the rest of its prop surface are reachable this way;
16
+ * the shared props stay the parity contract. */
17
+ ios?: any
18
+ android?: any
19
+ web?: any
20
+ }
21
+
22
+ /** Options for `prefetch`. The same contract `@octane-xplat/image`'s
23
+ * `prefetch` carries. */
24
+ export interface PrefetchOptions {
25
+ /** Request headers for the prefetch fetch. Honored on Android (Fresco);
26
+ * **dropped on iOS** — the plugin's prefetch path builds its SDWebImage
27
+ * context without the download-request-modifier branch its `Img`
28
+ * display path has; an upstream patch is needed there. Ignored on web —
29
+ * a plain <img> cannot send custom headers. */
30
+ headers?: Record<string, string>
31
+ /** Max URLs fetched in parallel (JS-side cap). Default 5 — the same
32
+ * ceiling NS core's ImageCache used. */
33
+ concurrency?: number
34
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "version": 1,
3
+ "files": [
4
+ "AnimatedImage.d.ts",
5
+ "AnimatedImage.web.d.ts",
6
+ "escape-props.d.ts",
7
+ "escape-props.web.d.ts",
8
+ "index.d.ts",
9
+ "index.web.d.ts",
10
+ "native-elements.d.ts",
11
+ "prefetch-batch.d.ts",
12
+ "prefetch.d.ts",
13
+ "prefetch.web.d.ts",
14
+ "props.d.ts"
15
+ ]
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { AnimatedImageProps } from './props.js';
2
+ /** AnimatedImage — GIF/animated-webp decode + autoplay via ui-image. `src`
3
+ * takes the Img grammar: remote URL, res://name, ~/bundle path, file path.
4
+ * There is intentionally no play/pause prop — <img> can't pause on web, so
5
+ * the shared contract is always-playing. */
6
+ export declare function AnimatedImage(props: AnimatedImageProps): unknown;
@@ -0,0 +1,5 @@
1
+ /** @jsxImportSource octane */
2
+ import type { AnimatedImageProps } from './props.js';
3
+ /** AnimatedImage — a plain <img>; browsers animate GIF/webp natively.
4
+ * `stretch` maps to object-fit. */
5
+ export declare function AnimatedImage(props: AnimatedImageProps): import("octane/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ /** Apply only the active device's escape bag after the shared props — the
2
+ * same convention @octane-xplat/ui uses, kept local so this leaf does not
3
+ * depend on ui. */
4
+ export declare function applyEscapeProps(view: any, props: {
5
+ ios?: any;
6
+ android?: any;
7
+ }): void;
@@ -0,0 +1,6 @@
1
+ /** Apply DOM escape props after the primitive's own props. Dash-named keys
2
+ * are attributes; other keys use the DOM property where available. Mirrors
3
+ * @octane-xplat/ui's web escape-props so this leaf does not depend on ui. */
4
+ export declare function applyEscapeProps(element: any, props: {
5
+ web?: any;
6
+ }): void;
@@ -0,0 +1,3 @@
1
+ export { AnimatedImage } from './AnimatedImage.js';
2
+ export { prefetch } from './prefetch.js';
3
+ export type { AnimatedImageProps, PrefetchOptions } from './props.js';
@@ -0,0 +1,3 @@
1
+ export { AnimatedImage } from './AnimatedImage.web.js';
2
+ export { prefetch } from './prefetch.web.js';
3
+ export type { AnimatedImageProps, PrefetchOptions } from './props.js';
@@ -0,0 +1,8 @@
1
+ import { Img } from '@nativescript-community/ui-image'
2
+ import type { Attributes } from '@nativescript-community/octane/intrinsics'
3
+
4
+ declare module '@nativescript-community/octane/intrinsics' {
5
+ interface NativeScriptElements {
6
+ animatedimage: Attributes<typeof Img>
7
+ }
8
+ }
@@ -0,0 +1,10 @@
1
+ /** VENDORED — identical copy in packages/image/src/prefetch-batch.ts; keep in
2
+ * sync.
3
+ *
4
+ * Shared batch driver for the image-engine leaves' `prefetch` contract:
5
+ * normalizes `string | string[]`, caps in-flight requests JS-side, and
6
+ * resolves `true` only when every URL warms — `false` on the first failure
7
+ * (in-flight requests settle on their own; the result is already decided). */
8
+ /** Matches the `maxRequests = 5` ceiling NS core's ImageCache used. */
9
+ export declare const DEFAULT_PREFETCH_CONCURRENCY = 5;
10
+ export declare function prefetchBatch(srcs: string | string[], concurrency: number | undefined, warm: (url: string) => Promise<boolean>): Promise<boolean>;
@@ -0,0 +1,12 @@
1
+ import type { PrefetchOptions } from './props.js';
2
+ /** prefetch — warm the image engine's disk cache for `srcs` without displaying
3
+ * anything. Android (Fresco): `prefetchToDiskCache` stores encoded bytes on
4
+ * disk and defers bitmap decode to display. iOS (SDWebImage): the prefetcher
5
+ * stores the downloaded image to the disk cache only. Either way a later
6
+ * `AnimatedImage` with the same src hits disk instead of the network.
7
+ * Resolves false when any URL fails; resolves false when the pipeline is not
8
+ * available yet (e.g. called before app launch).
9
+ * `options.concurrency` caps parallel fetches (default 5); `options.headers`
10
+ * is honored on Android and silently dropped on iOS (upstream gap — see
11
+ * PrefetchOptions). */
12
+ export declare function prefetch(srcs: string | string[], options?: PrefetchOptions): Promise<boolean>;
@@ -0,0 +1,7 @@
1
+ import type { PrefetchOptions } from './props.js';
2
+ /** prefetch — load each `src` through a throwaway <img> so the response lands
3
+ * in the browser HTTP cache; decode and render stay with the displaying
4
+ * element. `options.headers` is ignored — an <img> request cannot carry
5
+ * custom headers. `options.concurrency` caps parallel loads (default 5).
6
+ * Resolves false when any URL fails. */
7
+ export declare function prefetch(srcs: string | string[], options?: PrefetchOptions): Promise<boolean>;
@@ -0,0 +1,33 @@
1
+ export interface AnimatedImageProps {
2
+ className?: any;
3
+ style?: any;
4
+ id?: string;
5
+ src: string;
6
+ alt?: string;
7
+ /** Content fit — same grammar as core Image. Web maps to object-fit;
8
+ * ui-image (Fresco/SDWebImage) accepts the same values. */
9
+ stretch?: 'none' | 'fill' | 'aspectFit' | 'aspectFill';
10
+ width?: string | number;
11
+ height?: string | number;
12
+ /** Platform-specific properties are applied after shared props. Native
13
+ * bags assign onto the ui-image `Img` view — `noCache`, `decodeWidth`,
14
+ * `decodeHeight`, `placeholderImageUri`, `progressiveRenderingEnabled`,
15
+ * `cacheKey`, and the rest of its prop surface are reachable this way;
16
+ * the shared props stay the parity contract. */
17
+ ios?: any;
18
+ android?: any;
19
+ web?: any;
20
+ }
21
+ /** Options for `prefetch`. The same contract `@octane-xplat/image`'s
22
+ * `prefetch` carries. */
23
+ export interface PrefetchOptions {
24
+ /** Request headers for the prefetch fetch. Honored on Android (Fresco);
25
+ * **dropped on iOS** — the plugin's prefetch path builds its SDWebImage
26
+ * context without the download-request-modifier branch its `Img`
27
+ * display path has; an upstream patch is needed there. Ignored on web —
28
+ * a plain <img> cannot send custom headers. */
29
+ headers?: Record<string, string>;
30
+ /** Max URLs fetched in parallel (JS-side cap). Default 5 — the same
31
+ * ceiling NS core's ImageCache used. */
32
+ concurrency?: number;
33
+ }
@@ -0,0 +1,8 @@
1
+ import type { AnimatedImageProps, PrefetchOptions } from './generated/props.js'
2
+
3
+ export type { AnimatedImageProps, PrefetchOptions } from './generated/props.js'
4
+ export declare function AnimatedImage(props: AnimatedImageProps): unknown
5
+ export declare function prefetch(
6
+ srcs: string | string[],
7
+ options?: PrefetchOptions,
8
+ ): Promise<boolean>