@symbiote-native/components 0.2.5 → 0.2.6

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/build/index.js CHANGED
@@ -24,7 +24,7 @@ export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChang
24
24
  export { resolveDecelerationRate, selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, SCROLL_VIEW_BASE_HORIZONTAL, SCROLL_VIEW_BASE_VERTICAL, } from './view/render-scroll-view.js';
25
25
  export { buildScrollViewHandle, splitLayoutProps, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands.js';
26
26
  export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky.js';
27
- export { renderImage } from './view/render-image.js';
27
+ export { renderImage } from './view/render-image/index.js';
28
28
  export { imageStatics, setImageSourceResolver } from '@symbiote-native/engine';
29
29
  // ImageBackground: render-only composition (absolute-fill image behind, children on top).
30
30
  export { renderImageBackground } from './view/render-image-background.js';
@@ -10,7 +10,7 @@
10
10
  // the box. `imageStyle` wins last.
11
11
  import { dlog, flattenStyle, } from '@symbiote-native/engine';
12
12
  import { el } from '../descriptor.js';
13
- import { renderImage } from './render-image.js';
13
+ import { renderImage } from './render-image/index.js';
14
14
  // The inner Image's positioning: absolute-fill behind the wrapper's children.
15
15
  const IMAGE_BACKGROUND_ABSOLUTE_FILL = {
16
16
  position: 'absolute',
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@symbiote-native/components",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Framework-agnostic component logic (state machines + render functions) for SymbioteNative — written once, inherited by every adapter (React, Vue, Angular, ...).",
5
+ "license": "MIT",
5
6
  "repository": {
6
7
  "type": "git",
7
8
  "url": "git+https://github.com/OneEyed1366/symbiote-native.git",
@@ -33,12 +34,12 @@
33
34
  "access": "public"
34
35
  },
35
36
  "peerDependencies": {
36
- "@symbiote-native/engine": ">=0.1.6",
37
+ "@symbiote-native/engine": ">=0.1.7",
37
38
  "react-native": ">=0.86"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/node": "^26.0.0",
41
- "@symbiote-native/engine": "0.1.6"
42
+ "@symbiote-native/engine": "0.1.7"
42
43
  },
43
44
  "scripts": {
44
45
  "typecheck": "tsc --build",
@@ -1,56 +0,0 @@
1
- import { type IImageSource, type IImageSourceProp, type IStyleProp, type ISymbioteEvent, type IViewStyle } from '@symbiote-native/engine';
2
- import type { IAccessibilityProps, IAriaProps } from '../accessibility-props';
3
- import { type IDescriptor } from '../descriptor';
4
- export type { IImageSource, IImageSourceProp };
5
- type IImageEventHandler = (event: ISymbioteEvent) => void;
6
- export type IResizeMode = 'cover' | 'contain' | 'stretch' | 'repeat' | 'center';
7
- export type IImageCapInsets = {
8
- top: number;
9
- left: number;
10
- bottom: number;
11
- right: number;
12
- };
13
- export type IResizeMethod = 'auto' | 'resize' | 'scale' | 'none';
14
- export type IImageProps = IAccessibilityProps & IAriaProps & {
15
- source?: IImageSourceProp;
16
- defaultSource?: IImageSourceProp;
17
- loadingIndicatorSource?: IImageSourceProp;
18
- style?: IStyleProp<IViewStyle>;
19
- resizeMode?: IResizeMode;
20
- resizeMethod?: IResizeMethod;
21
- tintColor?: string;
22
- blurRadius?: number;
23
- capInsets?: IImageCapInsets;
24
- fadeDuration?: number;
25
- progressiveRenderingEnabled?: boolean;
26
- src?: string;
27
- srcSet?: string;
28
- alt?: string;
29
- width?: number;
30
- height?: number;
31
- crossOrigin?: 'anonymous' | 'use-credentials';
32
- referrerPolicy?: string;
33
- onLoadStart?: IImageEventHandler;
34
- onLoad?: IImageEventHandler;
35
- onLoadEnd?: IImageEventHandler;
36
- onError?: IImageEventHandler;
37
- onProgress?: IImageEventHandler;
38
- onPartialLoad?: IImageEventHandler;
39
- };
40
- export type IImageViewProps = {
41
- source?: IImageSourceProp;
42
- defaultSource?: IImageSourceProp;
43
- loadingIndicatorSource?: IImageSourceProp;
44
- style?: IStyleProp<IViewStyle>;
45
- resizeMode?: IResizeMode;
46
- tintColor?: string;
47
- src?: string;
48
- srcSet?: string;
49
- alt?: string;
50
- width?: number;
51
- height?: number;
52
- crossOrigin?: 'anonymous' | 'use-credentials';
53
- referrerPolicy?: string;
54
- passthrough: Record<string, unknown>;
55
- };
56
- export declare function renderImage(view: IImageViewProps): IDescriptor;
@@ -1,133 +0,0 @@
1
- import { dlog, flattenStyle, resolveImageSource, } from '@symbiote-native/engine';
2
- import { el } from '../descriptor.js';
3
- // Resolve the source, then normalize to the array shape native expects. A single
4
- // object/number becomes a one-element array; an already-array source passes through.
5
- function normalizeSource(source) {
6
- const resolved = resolveImageSource(source);
7
- const sources = Array.isArray(resolved) ? resolved : [resolved];
8
- dlog(`Image source resolved to ${JSON.stringify(sources)}`);
9
- return sources;
10
- }
11
- // The HTTP headers the W3C aliases (crossOrigin / referrerPolicy) contribute to
12
- // every folded source, mirroring ImageSourceUtils.js getImageSourcesFromImageProps:
13
- // 'use-credentials' adds the credentials header; referrerPolicy adds Referrer-Policy.
14
- function headersFromAliases(view) {
15
- const headers = {};
16
- if (view.crossOrigin === 'use-credentials') {
17
- headers['Access-Control-Allow-Credentials'] = 'true';
18
- }
19
- if (view.referrerPolicy !== undefined) {
20
- headers['Referrer-Policy'] = view.referrerPolicy;
21
- }
22
- return headers;
23
- }
24
- // Expand a `srcSet` descriptor list into scaled sources, falling back to `src` for
25
- // the 1x slot when srcSet omits it. Direct port of getImageSourcesFromImageProps'
26
- // srcSet branch (ImageSourceUtils.js:48). Invalid scale tokens are skipped, matching
27
- // RN's parse-and-warn behavior.
28
- function expandSrcSet(srcSet, view, headers) {
29
- const sources = [];
30
- let useSrcForDefaultScale = true;
31
- for (const entry of srcSet.split(', ')) {
32
- const [uri, xScale = '1x'] = entry.split(' ');
33
- if (!xScale.endsWith('x')) {
34
- dlog(`Image srcSet: unsupported scale token "${xScale}", skipping`);
35
- continue;
36
- }
37
- const scale = parseInt(xScale.slice(0, -1), 10);
38
- if (Number.isNaN(scale))
39
- continue;
40
- if (scale === 1)
41
- useSrcForDefaultScale = false;
42
- sources.push({ uri, scale, width: view.width, height: view.height, ...{ headers } });
43
- }
44
- if (useSrcForDefaultScale && view.src !== undefined) {
45
- sources.push({
46
- uri: view.src,
47
- scale: 1,
48
- width: view.width,
49
- height: view.height,
50
- ...{ headers },
51
- });
52
- }
53
- if (sources.length === 0)
54
- dlog('Image srcSet: produced no valid sources');
55
- return sources;
56
- }
57
- // Resolve the native `source` array from whichever of source / src / srcSet the
58
- // caller provided. Mirrors ImageSourceUtils.js getImageSourcesFromImageProps:
59
- // srcSet wins, then src, then a header-decorated source, then the plain source.
60
- // Always returns the array shape native expects (the same contract normalizeSource
61
- // guarantees), so the component never sends a bare object.
62
- function resolveSourceArray(view) {
63
- const headers = headersFromAliases(view);
64
- if (view.srcSet !== undefined) {
65
- return expandSrcSet(view.srcSet, view, headers);
66
- }
67
- if (view.src !== undefined) {
68
- return [{ uri: view.src, width: view.width, height: view.height, ...{ headers } }];
69
- }
70
- if (view.source === undefined) {
71
- dlog('Image: no source / src / srcSet provided');
72
- return [];
73
- }
74
- const sources = normalizeSource(view.source);
75
- // A header-decorated single object source gets the headers merged in, per RN's
76
- // `source.uri && headers` branch; the array/number shapes pass through untouched.
77
- if (Object.keys(headers).length > 0 && sources.length === 1) {
78
- const [only] = sources;
79
- if (typeof only === 'object' && only !== null && typeof Reflect.get(only, 'uri') === 'string') {
80
- return [{ ...only, headers }];
81
- }
82
- }
83
- return sources;
84
- }
85
- function readStyleString(style, key) {
86
- if (style === undefined)
87
- return undefined;
88
- // style is a StyleProp (possibly a nested array), so flatten before reading a key.
89
- const flat = flattenStyle(style);
90
- const value = Object.hasOwn(flat, key) ? flat[key] : undefined;
91
- return typeof value === 'string' ? value : undefined;
92
- }
93
- // Resolve an asset source and read its single uri. RN forwards the Android
94
- // loading indicator as a bare uri string (`loadingIndicatorSrc`), not the
95
- // array shape the main source uses, so we resolve and pluck the uri.
96
- function readSourceUri(source) {
97
- const [resolved] = normalizeSource(source);
98
- if (typeof resolved === 'object' && resolved !== null) {
99
- const uri = Reflect.get(resolved, 'uri');
100
- if (typeof uri === 'string')
101
- return uri;
102
- }
103
- return undefined;
104
- }
105
- export function renderImage(view) {
106
- // `width` / `height` aliases fold into style (ImageProps.js:195,202); explicit
107
- // style keys win, matching RN's `{width, height}, ...style` ordering.
108
- const foldedStyle = view.width === undefined && view.height === undefined
109
- ? view.style
110
- : [{ width: view.width, height: view.height }, view.style];
111
- const mapped = {
112
- ...view.passthrough,
113
- style: foldedStyle,
114
- source: resolveSourceArray(view),
115
- resizeMode: view.resizeMode ?? readStyleString(view.style, 'resizeMode'),
116
- tintColor: view.tintColor ?? readStyleString(view.style, 'tintColor'),
117
- };
118
- // `alt` is the accessibility text: it sets accessibilityLabel and marks the image
119
- // accessible (Image.ios.js / Image.android.js: alt -> accessibilityLabel + accessible).
120
- // An explicit accessibilityLabel (already folded into passthrough) still wins.
121
- if (view.alt !== undefined) {
122
- if (mapped.accessibilityLabel === undefined)
123
- mapped.accessibilityLabel = view.alt;
124
- mapped.accessible = true;
125
- }
126
- if (view.defaultSource !== undefined)
127
- mapped.defaultSource = normalizeSource(view.defaultSource);
128
- if (view.loadingIndicatorSource !== undefined) {
129
- mapped.loadingIndicatorSrc = readSourceUri(view.loadingIndicatorSource);
130
- }
131
- dlog('Image -> RCTImageView');
132
- return el('symbiote-image', mapped);
133
- }