@hanzogui/image 2.0.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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/Image.cjs +62 -0
  3. package/dist/cjs/Image.native.js +33 -0
  4. package/dist/cjs/Image.native.js.map +1 -0
  5. package/dist/cjs/createImage.cjs +128 -0
  6. package/dist/cjs/createImage.native.js +134 -0
  7. package/dist/cjs/createImage.native.js.map +1 -0
  8. package/dist/cjs/index.cjs +19 -0
  9. package/dist/cjs/index.native.js +22 -0
  10. package/dist/cjs/index.native.js.map +1 -0
  11. package/dist/cjs/types.cjs +16 -0
  12. package/dist/cjs/types.native.js +19 -0
  13. package/dist/cjs/types.native.js.map +1 -0
  14. package/dist/cjs/v1/Image.cjs +86 -0
  15. package/dist/cjs/v1/Image.native.js +105 -0
  16. package/dist/cjs/v1/Image.native.js.map +1 -0
  17. package/dist/cjs/v1/index.cjs +18 -0
  18. package/dist/cjs/v1/index.native.js +21 -0
  19. package/dist/cjs/v1/index.native.js.map +1 -0
  20. package/dist/esm/Image.mjs +39 -0
  21. package/dist/esm/Image.mjs.map +1 -0
  22. package/dist/esm/Image.native.js +7 -0
  23. package/dist/esm/Image.native.js.map +1 -0
  24. package/dist/esm/createImage.mjs +105 -0
  25. package/dist/esm/createImage.mjs.map +1 -0
  26. package/dist/esm/createImage.native.js +108 -0
  27. package/dist/esm/createImage.native.js.map +1 -0
  28. package/dist/esm/index.js +3 -0
  29. package/dist/esm/index.js.map +1 -0
  30. package/dist/esm/index.mjs +3 -0
  31. package/dist/esm/index.mjs.map +1 -0
  32. package/dist/esm/index.native.js +3 -0
  33. package/dist/esm/index.native.js.map +1 -0
  34. package/dist/esm/types.mjs +2 -0
  35. package/dist/esm/types.mjs.map +1 -0
  36. package/dist/esm/types.native.js +2 -0
  37. package/dist/esm/types.native.js.map +1 -0
  38. package/dist/esm/v1/Image.mjs +52 -0
  39. package/dist/esm/v1/Image.mjs.map +1 -0
  40. package/dist/esm/v1/Image.native.js +68 -0
  41. package/dist/esm/v1/Image.native.js.map +1 -0
  42. package/dist/esm/v1/index.mjs +2 -0
  43. package/dist/esm/v1/index.mjs.map +1 -0
  44. package/dist/esm/v1/index.native.js +2 -0
  45. package/dist/esm/v1/index.native.js.map +1 -0
  46. package/dist/jsx/Image.mjs +39 -0
  47. package/dist/jsx/Image.mjs.map +1 -0
  48. package/dist/jsx/Image.native.js +33 -0
  49. package/dist/jsx/Image.native.js.map +1 -0
  50. package/dist/jsx/createImage.mjs +105 -0
  51. package/dist/jsx/createImage.mjs.map +1 -0
  52. package/dist/jsx/createImage.native.js +134 -0
  53. package/dist/jsx/createImage.native.js.map +1 -0
  54. package/dist/jsx/index.js +3 -0
  55. package/dist/jsx/index.js.map +1 -0
  56. package/dist/jsx/index.mjs +3 -0
  57. package/dist/jsx/index.mjs.map +1 -0
  58. package/dist/jsx/index.native.js +22 -0
  59. package/dist/jsx/index.native.js.map +1 -0
  60. package/dist/jsx/types.mjs +2 -0
  61. package/dist/jsx/types.mjs.map +1 -0
  62. package/dist/jsx/types.native.js +19 -0
  63. package/dist/jsx/types.native.js.map +1 -0
  64. package/dist/jsx/v1/Image.mjs +52 -0
  65. package/dist/jsx/v1/Image.mjs.map +1 -0
  66. package/dist/jsx/v1/Image.native.js +105 -0
  67. package/dist/jsx/v1/Image.native.js.map +1 -0
  68. package/dist/jsx/v1/index.mjs +2 -0
  69. package/dist/jsx/v1/index.mjs.map +1 -0
  70. package/dist/jsx/v1/index.native.js +21 -0
  71. package/dist/jsx/v1/index.native.js.map +1 -0
  72. package/package.json +53 -0
  73. package/src/Image.native.tsx +6 -0
  74. package/src/Image.tsx +41 -0
  75. package/src/createImage.tsx +236 -0
  76. package/src/index.ts +3 -0
  77. package/src/types.ts +54 -0
  78. package/src/v1/Image.tsx +144 -0
  79. package/src/v1/index.ts +1 -0
  80. package/types/Image.d.ts +3 -0
  81. package/types/Image.native.d.ts +16 -0
  82. package/types/createImage.d.ts +77 -0
  83. package/types/index.d.ts +4 -0
  84. package/types/types.d.ts +42 -0
  85. package/types/v1/Image.d.ts +36 -0
  86. package/types/v1/index.d.ts +2 -0
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@hanzogui/image",
3
+ "version": "2.0.0",
4
+ "source": "src/index.ts",
5
+ "files": [
6
+ "src",
7
+ "types",
8
+ "dist"
9
+ ],
10
+ "type": "module",
11
+ "sideEffects": [
12
+ "*.css"
13
+ ],
14
+ "main": "dist/cjs",
15
+ "module": "dist/esm",
16
+ "types": "./types/index.d.ts",
17
+ "exports": {
18
+ "./package.json": "./package.json",
19
+ ".": {
20
+ "types": "./types/index.d.ts",
21
+ "react-native": "./dist/esm/index.native.js",
22
+ "browser": "./dist/esm/index.mjs",
23
+ "module": "./dist/esm/index.mjs",
24
+ "import": "./dist/esm/index.mjs",
25
+ "require": "./dist/cjs/index.cjs",
26
+ "default": "./dist/esm/index.mjs"
27
+ }
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "scripts": {
33
+ "build": "hanzo-gui-build",
34
+ "watch": "hanzo-gui-build --watch",
35
+ "clean": "hanzo-gui-build clean",
36
+ "clean:build": "hanzo-gui-build clean:build"
37
+ },
38
+ "dependencies": {
39
+ "@hanzogui/constants": "2.0.0-rc.29",
40
+ "@hanzogui/core": "2.0.0-rc.29",
41
+ "@hanzogui/web": "2.0.0-rc.29"
42
+ },
43
+ "devDependencies": {
44
+ "@hanzogui/build": "2.0.0-rc.29",
45
+ "react": ">=19",
46
+ "react-native": "0.83.2"
47
+ },
48
+ "peerDependencies": {
49
+ "react": ">=19",
50
+ "react-native": "*"
51
+ },
52
+ "module:jsx": "dist/jsx"
53
+ }
@@ -0,0 +1,6 @@
1
+ import { Image as RNImage } from 'react-native'
2
+ import { createImage } from './createImage'
3
+
4
+ export const Image = createImage({
5
+ Component: RNImage,
6
+ })
package/src/Image.tsx ADDED
@@ -0,0 +1,41 @@
1
+ import { View, styled } from '@hanzogui/web'
2
+ import type { ImageProps, ImageType } from './types'
3
+
4
+ const StyledImage = styled(View, {
5
+ name: 'Image',
6
+ render: 'img',
7
+ })
8
+
9
+ export const Image = StyledImage.styleable<ImageProps>(
10
+ (inProps, ref) => {
11
+ const {
12
+ // exclude native only props
13
+ blurRadius,
14
+ capInsets,
15
+ defaultSource,
16
+ fadeDuration,
17
+ loadingIndicatorSource,
18
+ onLoadEnd,
19
+ onPartialLoad,
20
+ progressiveRenderingEnabled,
21
+ resizeMethod,
22
+ tintColor,
23
+ ...rest
24
+ } = inProps
25
+ return <StyledImage ref={ref} {...rest} />
26
+ },
27
+ {
28
+ staticConfig: {
29
+ memo: true,
30
+ },
31
+ }
32
+ ) as unknown as ImageType
33
+
34
+ const func = (() => {}) as any
35
+
36
+ Image.getSize = func
37
+ Image.getSizeWithHeaders = func
38
+ Image.prefetch = func
39
+ Image.prefetchWithMetadata = func
40
+ Image.abortPrefetch = func
41
+ Image.queryCache = func
@@ -0,0 +1,236 @@
1
+ import { getTokenValue, styled } from '@hanzogui/web'
2
+ import type { ComponentType } from 'react'
3
+ import type { ImageResizeMode } from 'react-native'
4
+ import type { ImageProps, ImageType } from './types'
5
+
6
+ type GetProps<T> = T extends ComponentType<infer P> ? P : never
7
+
8
+ export type CreateImageOptions<C extends ComponentType<any>> = {
9
+ /**
10
+ * The underlying image component to use.
11
+ * Can be React Native Image, expo-image, react-native-fast-image, or any compatible component.
12
+ */
13
+ Component: C
14
+ /**
15
+ * Map objectFit CSS values to the component's resize mode prop.
16
+ * Default maps to React Native's resizeMode.
17
+ */
18
+ mapObjectFitToResizeMode?: (objectFit: string) => string
19
+ /**
20
+ * The prop name used for resize mode.
21
+ * Default: 'resizeMode' (React Native)
22
+ * expo-image uses: 'contentFit'
23
+ */
24
+ resizeModePropName?: string
25
+ /**
26
+ * The prop name used for object position.
27
+ * Default: undefined (React Native doesn't support it)
28
+ * expo-image uses: 'contentPosition'
29
+ */
30
+ objectPositionPropName?: string
31
+ /**
32
+ * Custom source transformation.
33
+ * Useful for expo-image which has a different source format.
34
+ */
35
+ transformSource?: (props: {
36
+ src?: string | number
37
+ source?: any
38
+ width?: any
39
+ height?: any
40
+ }) => any
41
+ }
42
+
43
+ const defaultObjectFitMap = (objectFit: string): ImageResizeMode => {
44
+ switch (objectFit) {
45
+ case 'fill':
46
+ return 'stretch'
47
+ case 'none':
48
+ return 'center'
49
+ case 'scale-down':
50
+ return 'contain'
51
+ case 'contain':
52
+ return 'contain'
53
+ default:
54
+ return 'cover'
55
+ }
56
+ }
57
+
58
+ const defaultTransformSource = (props: {
59
+ src?: string | number
60
+ source?: any
61
+ width?: any
62
+ height?: any
63
+ }) => {
64
+ const { src, source, width, height } = props
65
+ if (source) return source
66
+ if (src && typeof src !== 'string') return src
67
+ return {
68
+ uri: src,
69
+ width,
70
+ height,
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Create a custom Image component with a pluggable underlying implementation.
76
+ *
77
+ * @example
78
+ * Using with expo-image
79
+ * import { Image as ExpoImage } from 'expo-image'
80
+ * import { createImage } from '@hanzogui/image'
81
+ *
82
+ * export const Image = createImage({
83
+ * Component: ExpoImage,
84
+ * resizeModePropName: 'contentFit',
85
+ * objectPositionPropName: 'contentPosition',
86
+ * })
87
+ *
88
+ * Now you get all expo-image props (transition, placeholder, etc.)
89
+ * plus Gui's unified API (src, objectFit, objectPosition)
90
+ * <Image
91
+ * src="https://example.com/photo.jpg"
92
+ * objectFit="cover"
93
+ * transition={300}
94
+ * placeholder={blurhash}
95
+ * />
96
+ */
97
+ export function createImage<C extends ComponentType<any>>(
98
+ options: CreateImageOptions<C>
99
+ ) {
100
+ const {
101
+ Component,
102
+ mapObjectFitToResizeMode = defaultObjectFitMap,
103
+ resizeModePropName = 'resizeMode',
104
+ objectPositionPropName,
105
+ transformSource = defaultTransformSource,
106
+ } = options
107
+
108
+ // Props that should pass directly to the underlying component without Gui processing
109
+ const inlinePropsSet = new Set([
110
+ 'source',
111
+ 'placeholder',
112
+ 'transition',
113
+ 'contentFit',
114
+ 'contentPosition',
115
+ 'cachePolicy',
116
+ 'recyclingKey',
117
+ 'allowDownscaling',
118
+ 'autoplay',
119
+ 'blurRadius',
120
+ 'priority',
121
+ 'placeholderContentFit',
122
+ 'responsivePolicy',
123
+ 'onLoadStart',
124
+ 'onProgress',
125
+ 'onLoadEnd',
126
+ ])
127
+
128
+ const StyledImage = styled(
129
+ Component as ComponentType<any>,
130
+ {
131
+ name: 'Image',
132
+ },
133
+ {
134
+ inlineProps: inlinePropsSet,
135
+ }
136
+ )
137
+
138
+ // Combined props: ImageProps (Gui) + Component's native props
139
+ type CombinedProps = ImageProps & Omit<GetProps<C>, keyof ImageProps>
140
+
141
+ const ImageComponent = StyledImage.styleable<CombinedProps>((incomingProps, ref) => {
142
+ const props = incomingProps as any
143
+ const {
144
+ src,
145
+ width,
146
+ height,
147
+ objectFit,
148
+ objectPosition,
149
+ // web only props - filter out on native
150
+ decoding,
151
+ elementTiming,
152
+ fetchpriority,
153
+ isMap,
154
+ loading,
155
+ sizes,
156
+ useMap,
157
+ onLoad,
158
+ onError,
159
+ ...rest
160
+ } = props
161
+
162
+ const resolvedWidth =
163
+ typeof width === 'string' && width[0] === '$' ? getTokenValue(width as any) : width
164
+ const resolvedHeight =
165
+ typeof height === 'string' && height[0] === '$'
166
+ ? getTokenValue(height as any)
167
+ : height
168
+
169
+ const finalSource = transformSource({
170
+ src,
171
+ width: resolvedWidth,
172
+ height: resolvedHeight,
173
+ })
174
+
175
+ const incomingStyle = Array.isArray(rest.style)
176
+ ? Object.assign({}, ...rest.style.flat())
177
+ : rest.style
178
+
179
+ const finalProps: any = {
180
+ ...rest,
181
+ source: finalSource,
182
+ style: {
183
+ ...incomingStyle,
184
+ ...(resolvedWidth !== undefined && { width: resolvedWidth }),
185
+ ...(resolvedHeight !== undefined && { height: resolvedHeight }),
186
+ },
187
+ }
188
+
189
+ // Set resize mode / content fit
190
+ if (objectFit) {
191
+ finalProps[resizeModePropName] = mapObjectFitToResizeMode(objectFit)
192
+ }
193
+
194
+ // Add object position if supported
195
+ if (objectPositionPropName && objectPosition) {
196
+ finalProps[objectPositionPropName] = objectPosition
197
+ }
198
+
199
+ // Normalize onLoad event
200
+ if (onLoad) {
201
+ finalProps.onLoad = (e: any) => {
202
+ const source = e?.nativeEvent?.source || e?.source || {}
203
+ onLoad({
204
+ target: {
205
+ naturalHeight: source?.height,
206
+ naturalWidth: source?.width,
207
+ },
208
+ type: 'load',
209
+ } as any)
210
+ }
211
+ }
212
+
213
+ // Normalize onError event
214
+ if (onError) {
215
+ finalProps.onError = () => {
216
+ onError({
217
+ type: 'error',
218
+ } as any)
219
+ }
220
+ }
221
+
222
+ // Render the underlying Component directly to ensure all props pass through
223
+ return <Component ref={ref} {...finalProps} />
224
+ }) as unknown as ImageType & React.FC<CombinedProps>
225
+
226
+ // Add static methods if the component has them
227
+ const comp = Component as any
228
+ ImageComponent.getSize = comp.getSize || (() => {})
229
+ ImageComponent.getSizeWithHeaders = comp.getSizeWithHeaders || (() => {})
230
+ ImageComponent.prefetch = comp.prefetch || (() => {})
231
+ ImageComponent.prefetchWithMetadata = comp.prefetchWithMetadata || (() => {})
232
+ ImageComponent.abortPrefetch = comp.abortPrefetch || (() => {})
233
+ ImageComponent.queryCache = comp.queryCache || (() => {})
234
+
235
+ return ImageComponent
236
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './Image'
2
+ export * from './createImage'
3
+ export type { ImageProps, ImageType } from './types'
package/src/types.ts ADDED
@@ -0,0 +1,54 @@
1
+ import type { ViewProps } from '@hanzogui/web'
2
+ import type {
3
+ ImageResizeMode,
4
+ ImageSourcePropType,
5
+ Image as RNImage,
6
+ ImageProps as RNImageProps,
7
+ } from 'react-native'
8
+
9
+ type RNImageType = typeof RNImage
10
+
11
+ type KeyofViewProps = keyof ViewProps
12
+
13
+ export type ImageProps = ViewProps &
14
+ Omit<RNImageProps, KeyofViewProps | 'source' | 'resizeMode' | 'style'> & {
15
+ /**
16
+ * The image source URL or require() result.
17
+ * Preferred over `source` for better web alignment.
18
+ */
19
+ src?: string | number
20
+ /**
21
+ * @deprecated
22
+ * use src instead
23
+ */
24
+ source?: ImageSourcePropType
25
+ /**
26
+ * @deprecated
27
+ * use objectFit instead
28
+ */
29
+ resizeMode?: ImageResizeMode
30
+ /**
31
+ * How the image should be resized to fit its container.
32
+ * Maps to CSS object-fit on web and resizeMode on native.
33
+ */
34
+ objectFit?: React.CSSProperties['objectFit']
35
+ /**
36
+ * How the image should be positioned within its container.
37
+ * Maps to CSS object-position on web.
38
+ * On native, requires expo-image or similar for full support.
39
+ */
40
+ objectPosition?: React.CSSProperties['objectPosition']
41
+ } & Omit<
42
+ React.ImgHTMLAttributes<HTMLImageElement>,
43
+ 'width' | 'height' | KeyofViewProps | 'src'
44
+ > &
45
+ Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'width' | 'height' | 'style' | 'src'>
46
+
47
+ export type ImageType = React.FC<Partial<ImageProps>> & {
48
+ getSize: RNImageType['getSize']
49
+ getSizeWithHeaders: RNImageType['getSizeWithHeaders']
50
+ prefetch: RNImageType['prefetch']
51
+ prefetchWithMetadata: RNImageType['prefetchWithMetadata']
52
+ abortPrefetch: RNImageType['abortPrefetch']
53
+ queryCache: RNImageType['queryCache']
54
+ }
@@ -0,0 +1,144 @@
1
+ import React from 'react'
2
+ import { isWeb } from '@hanzogui/constants'
3
+ import type {
4
+ GetProps,
5
+ RadiusTokens,
6
+ SizeTokens,
7
+ ViewProps,
8
+ ThemeValueFallback,
9
+ } from '@hanzogui/web'
10
+ import { styled, usePropsAndStyle } from '@hanzogui/web'
11
+ import type { FC } from 'react'
12
+ import { Image as RNImage } from 'react-native'
13
+
14
+ const StyledImage = styled(RNImage, {
15
+ name: 'Image',
16
+ })
17
+
18
+ type StyledImageProps = Omit<GetProps<typeof StyledImage>, 'borderRadius'> & {
19
+ borderRadius?: RadiusTokens
20
+ }
21
+
22
+ type BaseProps = Omit<
23
+ StyledImageProps,
24
+ 'width' | 'height' | 'style' | 'onLayout' | 'resizeMode'
25
+ > & {
26
+ width?: string | number | SizeTokens | ThemeValueFallback
27
+ height?: string | number | SizeTokens | ThemeValueFallback
28
+
29
+ /**
30
+ * @deprecated use `source` instead to disambiguate width/height style from width/height of the actual image
31
+ */
32
+ src?: string | StyledImageProps['source']
33
+ /** @deprecated use objectFit instead */
34
+ resizeMode?: StyledImageProps['resizeMode']
35
+ objectFit?: React.CSSProperties['objectFit']
36
+ }
37
+
38
+ export type ImageProps = BaseProps & Omit<ViewProps, keyof BaseProps>
39
+
40
+ type RNImageType = typeof RNImage
41
+
42
+ type ImageType = FC<ImageProps> & {
43
+ getSize: RNImageType['getSize']
44
+ getSizeWithHeaders: RNImageType['getSizeWithHeaders']
45
+ prefetch: RNImageType['prefetch']
46
+ prefetchWithMetadata: RNImageType['prefetchWithMetadata']
47
+ abortPrefetch: RNImageType['abortPrefetch']
48
+ queryCache: RNImageType['queryCache']
49
+ }
50
+
51
+ let hasWarned = false
52
+
53
+ /**
54
+ * @summary An image is a component that displays an image.
55
+ * @see — Docs https://gui.dev/ui/image
56
+ */
57
+ export const Image = StyledImage.styleable<ImageProps>((inProps, ref) => {
58
+ const [props, style] = usePropsAndStyle(inProps)
59
+ const { src, source, objectFit, ...rest } = props
60
+
61
+ if (process.env.NODE_ENV === 'development') {
62
+ if (typeof src === 'string') {
63
+ if (
64
+ (typeof props.width === 'string' && props.width[0] !== '$') ||
65
+ (typeof props.height === 'string' && props.height[0] !== '$')
66
+ ) {
67
+ if (!hasWarned) {
68
+ hasWarned = true
69
+ console.warn(
70
+ `React Native expects a numerical width/height. If you want to use a percent you must define the "source" prop with width, height, and uri.`
71
+ )
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ let finalSource =
78
+ typeof src === 'string'
79
+ ? {
80
+ uri: src,
81
+ ...(isWeb && {
82
+ width: props.width || style?.width,
83
+ height: props.height || style?.height,
84
+ }),
85
+ }
86
+ : (source ?? src)
87
+
88
+ if (finalSource && typeof finalSource === 'object') {
89
+ if (process.env.HANZO_GUI_TARGET === 'native') {
90
+ // fix: normalize import style images
91
+ if (!Array.isArray(finalSource)) {
92
+ if (typeof finalSource.uri === 'number') {
93
+ finalSource = finalSource.uri
94
+ if (source && typeof source === 'object' && !Array.isArray(source)) {
95
+ // @ts-ignore
96
+ style.width ??= source.width
97
+ // @ts-ignore
98
+ style.height ??= source.height
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ if (process.env.NODE_ENV === 'development' && process.env.HANZO_GUI_IMAGE_CHECK_ERROR) {
105
+ // lets add an onload timeout and warning if it fails to load in console
106
+ React.useEffect(() => {
107
+ async function run() {
108
+ if (typeof src === 'string') {
109
+ try {
110
+ await fetch(src).then((res) => res.text())
111
+ } catch (err) {
112
+ console.error(`Error loading image: ${src}`, { props })
113
+ }
114
+ }
115
+ }
116
+
117
+ run()
118
+ }, [src])
119
+ }
120
+
121
+ // require compat across native/web
122
+ if (finalSource['default']) {
123
+ finalSource = finalSource['default']
124
+ }
125
+ }
126
+
127
+ // must set defaultSource to allow SSR, default it to the same as src
128
+ return (
129
+ <RNImage
130
+ resizeMode={objectFit}
131
+ ref={ref}
132
+ source={finalSource}
133
+ style={style}
134
+ {...(rest as any)}
135
+ />
136
+ )
137
+ }) as any as ImageType
138
+
139
+ Image.getSize = RNImage.getSize
140
+ Image.getSizeWithHeaders = RNImage.getSizeWithHeaders
141
+ Image.prefetch = RNImage.prefetch
142
+ Image.prefetchWithMetadata = RNImage.prefetchWithMetadata
143
+ Image.abortPrefetch = RNImage.abortPrefetch
144
+ Image.queryCache = RNImage.queryCache
@@ -0,0 +1 @@
1
+ export * from './Image'
@@ -0,0 +1,3 @@
1
+ import type { ImageType } from './types';
2
+ export declare const Image: ImageType;
3
+ //# sourceMappingURL=Image.d.ts.map
@@ -0,0 +1,16 @@
1
+ import { Image as RNImage } from 'react-native';
2
+ export declare const Image: import("react").FC<Partial<import("./types").ImageProps>> & {
3
+ getSize: typeof RNImage.getSize;
4
+ getSizeWithHeaders: typeof RNImage.getSizeWithHeaders;
5
+ prefetch: typeof RNImage.prefetch;
6
+ prefetchWithMetadata: typeof RNImage.prefetchWithMetadata;
7
+ abortPrefetch: typeof RNImage.abortPrefetch | undefined;
8
+ queryCache: typeof RNImage.queryCache | undefined;
9
+ } & import("react").FC<import("@gui/web").StackNonStyleProps & import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>> & import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> & import("@gui/web").WithMediaProps<import("@gui/web").WithThemeShorthandsAndPseudos<import("@gui/web").StackStyleBase, {}>> & Omit<import("react-native").ImageProps, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "source" | "resizeMode"> & {
10
+ src?: string | number;
11
+ source?: import("react-native").ImageSourcePropType;
12
+ resizeMode?: import("react-native").ImageResizeMode;
13
+ objectFit?: React.CSSProperties["objectFit"];
14
+ objectPosition?: React.CSSProperties["objectPosition"];
15
+ } & Omit<import("react").ImgHTMLAttributes<HTMLImageElement>, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "src"> & Omit<import("react").ImgHTMLAttributes<HTMLImageElement>, "style" | "height" | "width" | "src"> & Omit<import("react-native").ImageProps, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | "onLayout" | "rel" | "dir" | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "source" | "resizeMode" | "onError" | "onLoad" | "onLoadEnd" | "onLoadStart" | "progressiveRenderingEnabled" | "src" | "srcSet" | "loadingIndicatorSource" | "defaultSource" | "alt" | "crossOrigin" | "tintColor" | "referrerPolicy" | "blurRadius" | "capInsets" | "onProgress" | "onPartialLoad" | "resizeMethod" | "fadeDuration" | "objectPosition" | "decoding" | "fetchPriority" | "loading" | "sizes" | "useMap" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "enterKeyHint" | "hidden" | "lang" | "nonce" | "slot" | "spellCheck" | "title" | "translate" | "radioGroup" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "rev" | "typeof" | "vocab" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "popover" | "popoverTargetAction" | "popoverTarget" | "inert" | "inputMode" | "is" | "exportparts" | "part" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-dropeffect" | "aria-errormessage" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-level" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-setsize" | "aria-sort" | "onCopyCapture" | "onCutCapture" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlurCapture" | "onChangeCapture" | "onBeforeInputCapture" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoadCapture" | "onErrorCapture" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClickCapture" | "onContextMenuCapture" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeaveCapture" | "onDragOverCapture" | "onDragStartCapture" | "onDropCapture" | "onMouseDownCapture" | "onMouseMoveCapture" | "onMouseOutCapture" | "onMouseOverCapture" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancelCapture" | "onTouchMoveCapture" | "onTouchStartCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onToggle" | "onBeforeToggle" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture">>;
16
+ //# sourceMappingURL=Image.native.d.ts.map
@@ -0,0 +1,77 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { ImageResizeMode } from 'react-native';
3
+ import type { ImageProps } from './types';
4
+ type GetProps<T> = T extends ComponentType<infer P> ? P : never;
5
+ export type CreateImageOptions<C extends ComponentType<any>> = {
6
+ /**
7
+ * The underlying image component to use.
8
+ * Can be React Native Image, expo-image, react-native-fast-image, or any compatible component.
9
+ */
10
+ Component: C;
11
+ /**
12
+ * Map objectFit CSS values to the component's resize mode prop.
13
+ * Default maps to React Native's resizeMode.
14
+ */
15
+ mapObjectFitToResizeMode?: (objectFit: string) => string;
16
+ /**
17
+ * The prop name used for resize mode.
18
+ * Default: 'resizeMode' (React Native)
19
+ * expo-image uses: 'contentFit'
20
+ */
21
+ resizeModePropName?: string;
22
+ /**
23
+ * The prop name used for object position.
24
+ * Default: undefined (React Native doesn't support it)
25
+ * expo-image uses: 'contentPosition'
26
+ */
27
+ objectPositionPropName?: string;
28
+ /**
29
+ * Custom source transformation.
30
+ * Useful for expo-image which has a different source format.
31
+ */
32
+ transformSource?: (props: {
33
+ src?: string | number;
34
+ source?: any;
35
+ width?: any;
36
+ height?: any;
37
+ }) => any;
38
+ };
39
+ /**
40
+ * Create a custom Image component with a pluggable underlying implementation.
41
+ *
42
+ * @example
43
+ * Using with expo-image
44
+ * import { Image as ExpoImage } from 'expo-image'
45
+ * import { createImage } from '@gui/image'
46
+ *
47
+ * export const Image = createImage({
48
+ * Component: ExpoImage,
49
+ * resizeModePropName: 'contentFit',
50
+ * objectPositionPropName: 'contentPosition',
51
+ * })
52
+ *
53
+ * Now you get all expo-image props (transition, placeholder, etc.)
54
+ * plus Gui's unified API (src, objectFit, objectPosition)
55
+ * <Image
56
+ * src="https://example.com/photo.jpg"
57
+ * objectFit="cover"
58
+ * transition={300}
59
+ * placeholder={blurhash}
60
+ * />
61
+ */
62
+ export declare function createImage<C extends ComponentType<any>>(options: CreateImageOptions<C>): import("react").FC<Partial<ImageProps>> & {
63
+ getSize: typeof import("react-native").Image.getSize;
64
+ getSizeWithHeaders: typeof import("react-native").Image.getSizeWithHeaders;
65
+ prefetch: typeof import("react-native").Image.prefetch;
66
+ prefetchWithMetadata: typeof import("react-native").Image.prefetchWithMetadata;
67
+ abortPrefetch: typeof import("react-native").Image.abortPrefetch | undefined;
68
+ queryCache: typeof import("react-native").Image.queryCache | undefined;
69
+ } & import("react").FC<import("@gui/web").StackNonStyleProps & import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>> & import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> & import("@gui/web").WithMediaProps<import("@gui/web").WithThemeShorthandsAndPseudos<import("@gui/web").StackStyleBase, {}>> & Omit<import("react-native").ImageProps, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "source" | "resizeMode"> & {
70
+ src?: string | number;
71
+ source?: import("react-native").ImageSourcePropType;
72
+ resizeMode?: ImageResizeMode;
73
+ objectFit?: React.CSSProperties["objectFit"];
74
+ objectPosition?: React.CSSProperties["objectPosition"];
75
+ } & Omit<import("react").ImgHTMLAttributes<HTMLImageElement>, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "src"> & Omit<import("react").ImgHTMLAttributes<HTMLImageElement>, "style" | "height" | "width" | "src"> & Omit<GetProps<C>, `$${string}` | `$${number}` | import("@gui/web").GroupMediaKeys | `$theme-${string}` | `$theme-${number}` | "onLayout" | "rel" | "dir" | keyof import("@gui/web").StackStyleBase | keyof import("@gui/web").StackNonStyleProps | keyof import("@gui/web").WithPseudoProps<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase> & import("@gui/web").WithShorthands<import("@gui/web").WithThemeValues<import("@gui/web").StackStyleBase>>> | "source" | "resizeMode" | "onError" | "onLoad" | "onLoadEnd" | "onLoadStart" | "progressiveRenderingEnabled" | "src" | "srcSet" | "loadingIndicatorSource" | "defaultSource" | "alt" | "crossOrigin" | "tintColor" | "referrerPolicy" | "blurRadius" | "capInsets" | "onProgress" | "onPartialLoad" | "resizeMethod" | "fadeDuration" | "objectPosition" | "decoding" | "fetchPriority" | "loading" | "sizes" | "useMap" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "enterKeyHint" | "hidden" | "lang" | "nonce" | "slot" | "spellCheck" | "title" | "translate" | "radioGroup" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "rev" | "typeof" | "vocab" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "popover" | "popoverTargetAction" | "popoverTarget" | "inert" | "inputMode" | "is" | "exportparts" | "part" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-dropeffect" | "aria-errormessage" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-level" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-setsize" | "aria-sort" | "onCopyCapture" | "onCutCapture" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlurCapture" | "onChangeCapture" | "onBeforeInputCapture" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoadCapture" | "onErrorCapture" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClickCapture" | "onContextMenuCapture" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeaveCapture" | "onDragOverCapture" | "onDragStartCapture" | "onDropCapture" | "onMouseDownCapture" | "onMouseMoveCapture" | "onMouseOutCapture" | "onMouseOverCapture" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancelCapture" | "onTouchMoveCapture" | "onTouchStartCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onToggle" | "onBeforeToggle" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture">>;
76
+ export {};
77
+ //# sourceMappingURL=createImage.d.ts.map