@pixelfiddler/react 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PixelFiddler
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 all
13
+ 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 THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # @pixelfiddler/react
2
+
3
+ React components for [PixelFiddler](https://pixel-fiddler.com) image transformations with automatic responsive image support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @pixelfiddler/react
9
+ # or
10
+ pnpm add @pixelfiddler/react
11
+ # or
12
+ yarn add @pixelfiddler/react
13
+ ```
14
+
15
+ **Note:** This package requires `react` >= 18.0.0 as a peer dependency.
16
+
17
+ ## Quick Start
18
+
19
+ ```tsx
20
+ import { PixelFiddleImage } from '@pixelfiddler/react';
21
+
22
+ function App() {
23
+ return (
24
+ <PixelFiddleImage
25
+ src="https://example.com/photo.jpg"
26
+ alt="A beautiful photo"
27
+ width={800}
28
+ transformations={{ format: 'WEBP', quality: 80 }}
29
+ />
30
+ );
31
+ }
32
+ ```
33
+
34
+ ## Components
35
+
36
+ ### `PixelFiddleImage`
37
+
38
+ A drop-in replacement for the `<img>` element that automatically generates optimized `srcSet` for responsive images.
39
+
40
+ ```tsx
41
+ import { PixelFiddleImage } from '@pixelfiddler/react';
42
+
43
+ // Fixed-width image with DPR support (x descriptors)
44
+ <PixelFiddleImage
45
+ src="https://example.com/photo.jpg"
46
+ alt="Profile photo"
47
+ width={400}
48
+ />
49
+ // Generates: srcset="...?w=640 1x, ...?w=828 2x"
50
+
51
+ // Fluid/responsive image (w descriptors)
52
+ <PixelFiddleImage
53
+ src="https://example.com/photo.jpg"
54
+ alt="Hero image"
55
+ sizes="(max-width: 768px) 100vw, 50vw"
56
+ />
57
+ // Generates: srcset="...?w=320 320w, ...?w=640 640w, ..."
58
+ ```
59
+
60
+ #### Props
61
+
62
+ | Prop | Type | Default | Description |
63
+ |------|------|---------|-------------|
64
+ | `src` | `string` | **required** | Base URL of the image |
65
+ | `alt` | `string` | - | Alt text (required for accessibility) |
66
+ | `width` | `number \| string` | - | Display width in CSS pixels. Generates DPR descriptors (`1x`, `2x`) |
67
+ | `sizes` | `string` | - | Sizes attribute for responsive images. Generates width descriptors (`w`) |
68
+ | `transformations` | `TransformationOptions` | - | Image transformation options |
69
+ | `responsive` | `boolean` | `true` | Enable automatic srcSet generation |
70
+ | `deviceBreakpoints` | `number[]` | `[320, 375, 640, 768, 1024, 1280, 1536, 1920]` | Breakpoints for viewport-based sizing |
71
+ | `imageBreakpoints` | `number[]` | `[16, 32, 48, 64, 96, 128, 256, 384]` | Breakpoints for smaller images |
72
+ | `config` | `UrlBuilderConfig` | - | Override provider config for this image |
73
+
74
+ All standard `<img>` attributes (`className`, `loading`, `decoding`, etc.) are also supported.
75
+
76
+ ### `PixelFiddlerProvider`
77
+
78
+ A context provider for sharing configuration across all `PixelFiddleImage` components.
79
+
80
+ ```tsx
81
+ import { PixelFiddlerProvider, PixelFiddleImage } from '@pixelfiddler/react';
82
+
83
+ function App() {
84
+ return (
85
+ <PixelFiddlerProvider config={{ baseUrl: 'https://cdn.example.com' }}>
86
+ <PixelFiddleImage src="/photos/hero.jpg" alt="Hero" sizes="100vw" />
87
+ <PixelFiddleImage src="/photos/thumb.jpg" alt="Thumbnail" width={200} />
88
+ </PixelFiddlerProvider>
89
+ );
90
+ }
91
+ ```
92
+
93
+ #### Props
94
+
95
+ | Prop | Type | Description |
96
+ |------|------|-------------|
97
+ | `config` | `PixelFiddlerConfig` | Configuration object with `baseUrl` and optional `signatureKey` |
98
+ | `children` | `ReactNode` | Child components |
99
+
100
+ ## Usage Examples
101
+
102
+ ### Basic Transformations
103
+
104
+ ```tsx
105
+ <PixelFiddleImage
106
+ src="https://example.com/photo.jpg"
107
+ alt="Transformed image"
108
+ responsive={false}
109
+ transformations={{
110
+ width: 800,
111
+ height: 600,
112
+ format: 'WEBP',
113
+ quality: 85,
114
+ }}
115
+ />
116
+ ```
117
+
118
+ ### Responsive Image with Fixed Display Width
119
+
120
+ When you know the exact display size, use `width` to generate DPR variants:
121
+
122
+ ```tsx
123
+ <PixelFiddleImage
124
+ src="https://example.com/avatar.jpg"
125
+ alt="User avatar"
126
+ width={150}
127
+ transformations={{ format: 'WEBP' }}
128
+ />
129
+ // Output:
130
+ // src="...?w=384&f=WEBP"
131
+ // srcset="...?w=384&f=WEBP 1x, ...?w=640&f=WEBP 2x"
132
+ ```
133
+
134
+ ### Responsive Image with Fluid Layout
135
+
136
+ For images that scale with the viewport, use `sizes`:
137
+
138
+ ```tsx
139
+ <PixelFiddleImage
140
+ src="https://example.com/hero.jpg"
141
+ alt="Hero banner"
142
+ sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px"
143
+ transformations={{ format: 'WEBP', quality: 80 }}
144
+ />
145
+ // Generates srcset with width descriptors (320w, 640w, 768w, etc.)
146
+ ```
147
+
148
+ ### Custom Breakpoints
149
+
150
+ ```tsx
151
+ <PixelFiddleImage
152
+ src="https://example.com/photo.jpg"
153
+ alt="Custom breakpoints"
154
+ sizes="100vw"
155
+ deviceBreakpoints={[480, 768, 1024, 1440, 1920]}
156
+ imageBreakpoints={[]}
157
+ />
158
+ ```
159
+
160
+ ### Disable Responsive Behavior
161
+
162
+ ```tsx
163
+ <PixelFiddleImage
164
+ src="https://example.com/photo.jpg"
165
+ alt="Non-responsive"
166
+ responsive={false}
167
+ transformations={{ width: 400, format: 'WEBP' }}
168
+ />
169
+ // Output: just src, no srcset
170
+ ```
171
+
172
+ ### With Standard Image Attributes
173
+
174
+ ```tsx
175
+ <PixelFiddleImage
176
+ src="https://example.com/photo.jpg"
177
+ alt="Lazy loaded image"
178
+ width={600}
179
+ className="rounded-lg shadow-md"
180
+ loading="lazy"
181
+ decoding="async"
182
+ />
183
+ ```
184
+
185
+ ## Responsive Strategy
186
+
187
+ The component automatically chooses the appropriate srcSet strategy:
188
+
189
+ | Input | Strategy | Descriptor | Use Case |
190
+ |-------|----------|------------|----------|
191
+ | `width` only | Fixed-size | `x` (1x, 2x) | Known display size, needs high-DPI support |
192
+ | `sizes` only | Fluid | `w` (640w, 1200w) | Image size varies with viewport |
193
+ | Neither | Fluid | `w` | Full-width responsive image (defaults to `sizes="100vw"`) |
194
+
195
+ ## TypeScript
196
+
197
+ Full TypeScript support with exported types:
198
+
199
+ ```typescript
200
+ import type {
201
+ PixelFiddlerImageProps,
202
+ PixelFiddlerProviderProps,
203
+ } from '@pixelfiddler/react';
204
+
205
+ import type {
206
+ TransformationOptions,
207
+ UrlBuilderConfig,
208
+ PixelFiddlerConfig,
209
+ } from '@pixelfiddler/core';
210
+ ```
211
+
212
+ ## Related
213
+
214
+ - [@pixelfiddler/core](https://www.npmjs.com/package/@pixelfiddler/core) - Core utilities for building transformation URLs
215
+
216
+ ## License
217
+
218
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var core = require('@pixelfiddler/core');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/components/pixel-fiddler-image.tsx
8
+ var PixelFiddlerContext = react.createContext(null);
9
+ function PixelFiddlerProvider({ children, config }) {
10
+ return /* @__PURE__ */ jsxRuntime.jsx(PixelFiddlerContext.Provider, { value: { config }, children });
11
+ }
12
+ function PixelFiddlerImage({
13
+ src,
14
+ sizes,
15
+ width,
16
+ transformations,
17
+ baseUrl,
18
+ deviceBreakpoints,
19
+ imageBreakpoints,
20
+ responsive = true,
21
+ ...imgProps
22
+ }) {
23
+ const context = react.useContext(PixelFiddlerContext);
24
+ const imageAttrs = react.useMemo(() => {
25
+ const finalBaseUrl = baseUrl || context?.config.baseUrl;
26
+ const hasWidthTransformation = transformations?.width;
27
+ if (responsive && !hasWidthTransformation) {
28
+ if (width && sizes) {
29
+ console.warn(
30
+ "[PixelFiddlerImage] Both `width` and `sizes` were provided. `sizes` will be ignored and a fixed-width DPR srcSet will be generated."
31
+ );
32
+ }
33
+ return core.createResponsiveAttributes(src, finalBaseUrl, {
34
+ width: width && +width,
35
+ sizes,
36
+ deviceBreakpoints,
37
+ imageBreakpoints,
38
+ transformations
39
+ });
40
+ }
41
+ return {
42
+ src: core.buildTransformationUrl({ src, baseUrl, transformations })
43
+ };
44
+ }, [src, sizes, transformations, deviceBreakpoints, imageBreakpoints, width, baseUrl, context?.config.baseUrl, responsive]);
45
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
46
+ "img",
47
+ {
48
+ src: imageAttrs.src || src,
49
+ srcSet: imageAttrs.srcSet,
50
+ sizes: imageAttrs.sizes,
51
+ width: imageAttrs.width || width,
52
+ ...imgProps
53
+ }
54
+ ) });
55
+ }
56
+
57
+ exports.PixelFiddlerImage = PixelFiddlerImage;
58
+ exports.PixelFiddlerProvider = PixelFiddlerProvider;
59
+ //# sourceMappingURL=index.cjs.map
60
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/provider/pixel-fiddler-context.tsx","../src/components/pixel-fiddler-image.tsx"],"names":["createContext","jsx","useContext","useMemo","createResponsiveAttributes","buildTransformationUrl","Fragment"],"mappings":";;;;;;;AAOO,IAAM,mBAAA,GAAsBA,oBAA+C,IAAI,CAAA;AAO/E,SAAS,oBAAA,CAAqB,EAAE,QAAA,EAAU,MAAA,EAAO,EAA8B;AACpF,EAAA,uBACEC,cAAA,CAAC,oBAAoB,QAAA,EAApB,EAA6B,OAAO,EAAC,MAAA,IACnC,QAAA,EACH,CAAA;AAEJ;ACyBO,SAAS,iBAAA,CAAkB;AAAA,EACI,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA,GAAa,IAAA;AAAA,EACb,GAAG;AACP,CAAA,EAA2B;AAEzD,EAAA,MAAM,OAAA,GAAUC,iBAAW,mBAAmB,CAAA;AAG9C,EAAA,MAAM,UAAA,GAAaC,cAAQ,MAAM;AAC7B,IAAA,MAAM,YAAA,GAAe,OAAA,IAAW,OAAA,EAAS,MAAA,CAAO,OAAA;AAEhD,IAAA,MAAM,yBAAyB,eAAA,EAAiB,KAAA;AAEhD,IAAA,IAAI,UAAA,IAAc,CAAC,sBAAA,EAAwB;AACvC,MAAA,IAAI,SAAS,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,IAAA;AAAA,UACJ;AAAA,SAEJ;AAAA,MACJ;AAEA,MAAA,OAAOC,+BAAA,CAA2B,KAAK,YAAA,EAAc;AAAA,QACjD,KAAA,EAAO,SAAS,CAAC,KAAA;AAAA,QACjB,KAAA;AAAA,QACA,iBAAA;AAAA,QACA,gBAAA;AAAA,QACA;AAAA,OACH,CAAA;AAAA,IACL;AACA,IAAA,OAAO;AAAA,MACH,KAAKC,2BAAA,CAAuB,EAAC,GAAA,EAAK,OAAA,EAAS,iBAAgB;AAAA,KAC/D;AAAA,EAEJ,CAAA,EAAG,CAAC,GAAA,EAAK,KAAA,EAAO,eAAA,EAAiB,iBAAA,EAAmB,gBAAA,EAAkB,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,MAAA,CAAO,OAAA,EAAS,UAAU,CAAC,CAAA;AAE1H,EAAA,uBACIJ,cAAAA,CAAAK,mBAAA,EAAA,EACI,QAAA,kBAAAL,cAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACG,GAAA,EAAK,WAAW,GAAA,IAAO,GAAA;AAAA,MACvB,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,OAAO,UAAA,CAAW,KAAA;AAAA,MAClB,KAAA,EAAO,WAAW,KAAA,IAAS,KAAA;AAAA,MAC1B,GAAG;AAAA;AAAA,GACR,EACJ,CAAA;AAER","file":"index.cjs","sourcesContent":["import { createContext, type ReactNode } from 'react';\nimport type { PixelFiddlerConfig } from '@pixelfiddler/core';\n\nexport interface PixelFiddlerContextValue {\n config: PixelFiddlerConfig;\n}\n\nexport const PixelFiddlerContext = createContext<PixelFiddlerContextValue | null>(null);\n\nexport interface PixelFiddlerProviderProps {\n children: ReactNode;\n config: PixelFiddlerConfig;\n}\n\nexport function PixelFiddlerProvider({ children, config }: PixelFiddlerProviderProps) {\n return (\n <PixelFiddlerContext.Provider value={{config}}>\n {children}\n </PixelFiddlerContext.Provider>\n );\n}\n","import { ImgHTMLAttributes, useContext, useMemo } from 'react';\r\nimport { buildTransformationUrl, createResponsiveAttributes, TransformationOptions, } from '@pixelfiddler/core';\r\nimport { PixelFiddlerContext } from '../provider/pixel-fiddler-context';\r\n\r\nexport interface PixelFiddlerImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'width' | 'sizes'> {\r\n /** Src to your image - can be both relative or absolute.\r\n * If it's relative, it will be attached to baseUrl from config\r\n * If it's absolute, it will be left as is\r\n * */\r\n src: string\r\n /** This should be your baseURL endpoint for the source from PixelFiddle Dashboard. You can skip this property if\r\n * you either pass it in PixelFiddlerProvider or pass an absolute path to src property.\r\n *\r\n * */\r\n baseUrl?: string\r\n /**\r\n * The sizes attribute for responsive images (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * Required if no fixed width was provided, and you want the image to be responsive\r\n */\r\n sizes?: string;\r\n /**\r\n * Decides whether srcSet should be built automatically for responsive images. In case `width` is passed, this will result in srcSet with `x` (dpr) descriptor.\r\n *\r\n *\r\n * If you want responsiveness based on layout, then you must pass `sizes` property for this to function properly e.g `(max-width: 768px) 100vw, 50vw\")`\r\n * which will generate srcSet based on vw\r\n *\r\n *\r\n * Ignored if `transformation.width` is set.\r\n * @default true\r\n */\r\n responsive?: boolean\r\n /**\r\n * Display width in CSS pixels.\r\n */\r\n width?: number | `${number}`;\r\n /** Transformation options to apply */\r\n transformations?: TransformationOptions;\r\n /** Custom device breakpoints for responsive srcset */\r\n deviceBreakpoints?: number[];\r\n /** Custom image breakpoints for smaller images */\r\n imageBreakpoints?: number[];\r\n}\r\n\r\nexport function PixelFiddlerImage({\r\n src,\r\n sizes,\r\n width,\r\n transformations,\r\n baseUrl,\r\n deviceBreakpoints,\r\n imageBreakpoints,\r\n responsive = true,\r\n ...imgProps\r\n }: PixelFiddlerImageProps) {\r\n\r\n const context = useContext(PixelFiddlerContext);\r\n\r\n\r\n const imageAttrs = useMemo(() => {\r\n const finalBaseUrl = baseUrl || context?.config.baseUrl\r\n\r\n const hasWidthTransformation = transformations?.width\r\n\r\n if (responsive && !hasWidthTransformation) {\r\n if (width && sizes) {\r\n console.warn(\r\n '[PixelFiddlerImage] Both `width` and `sizes` were provided. ' +\r\n '`sizes` will be ignored and a fixed-width DPR srcSet will be generated.'\r\n );\r\n }\r\n\r\n return createResponsiveAttributes(src, finalBaseUrl, {\r\n width: width && +width,\r\n sizes,\r\n deviceBreakpoints,\r\n imageBreakpoints,\r\n transformations\r\n });\r\n }\r\n return {\r\n src: buildTransformationUrl({src, baseUrl, transformations}),\r\n };\r\n\r\n }, [src, sizes, transformations, deviceBreakpoints, imageBreakpoints, width, baseUrl, context?.config.baseUrl, responsive]);\r\n\r\n return (\r\n <>\r\n <img\r\n src={imageAttrs.src || src}\r\n srcSet={imageAttrs.srcSet}\r\n sizes={imageAttrs.sizes}\r\n width={imageAttrs.width || width}\r\n {...imgProps}\r\n />\r\n </>\r\n );\r\n}\r\n"]}
@@ -0,0 +1,56 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ImgHTMLAttributes, ReactNode } from 'react';
3
+ import { TransformationOptions, PixelFiddlerConfig } from '@pixelfiddler/core';
4
+ export { BorderOptions, CropOptions, EffectOptions, FormatOptions, PixelFiddlerConfig, ResizeOptions, TextOptions, TransformationOptions, WatermarkOptions } from '@pixelfiddler/core';
5
+
6
+ interface PixelFiddlerImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'width' | 'sizes'> {
7
+ /** Src to your image - can be both relative or absolute.
8
+ * If it's relative, it will be attached to baseUrl from config
9
+ * If it's absolute, it will be left as is
10
+ * */
11
+ src: string;
12
+ /** This should be your baseURL endpoint for the source from PixelFiddle Dashboard. You can skip this property if
13
+ * you either pass it in PixelFiddlerProvider or pass an absolute path to src property.
14
+ *
15
+ * */
16
+ baseUrl?: string;
17
+ /**
18
+ * The sizes attribute for responsive images (e.g., "100vw", "(max-width: 768px) 100vw, 50vw").
19
+ * Required if no fixed width was provided, and you want the image to be responsive
20
+ */
21
+ sizes?: string;
22
+ /**
23
+ * Decides whether srcSet should be built automatically for responsive images. In case `width` is passed, this will result in srcSet with `x` (dpr) descriptor.
24
+ *
25
+ *
26
+ * If you want responsiveness based on layout, then you must pass `sizes` property for this to function properly e.g `(max-width: 768px) 100vw, 50vw")`
27
+ * which will generate srcSet based on vw
28
+ *
29
+ *
30
+ * Ignored if `transformation.width` is set.
31
+ * @default true
32
+ */
33
+ responsive?: boolean;
34
+ /**
35
+ * Display width in CSS pixels.
36
+ */
37
+ width?: number | `${number}`;
38
+ /** Transformation options to apply */
39
+ transformations?: TransformationOptions;
40
+ /** Custom device breakpoints for responsive srcset */
41
+ deviceBreakpoints?: number[];
42
+ /** Custom image breakpoints for smaller images */
43
+ imageBreakpoints?: number[];
44
+ }
45
+ declare function PixelFiddlerImage({ src, sizes, width, transformations, baseUrl, deviceBreakpoints, imageBreakpoints, responsive, ...imgProps }: PixelFiddlerImageProps): react_jsx_runtime.JSX.Element;
46
+
47
+ interface PixelFiddlerContextValue {
48
+ config: PixelFiddlerConfig;
49
+ }
50
+ interface PixelFiddlerProviderProps {
51
+ children: ReactNode;
52
+ config: PixelFiddlerConfig;
53
+ }
54
+ declare function PixelFiddlerProvider({ children, config }: PixelFiddlerProviderProps): react_jsx_runtime.JSX.Element;
55
+
56
+ export { type PixelFiddlerContextValue, PixelFiddlerImage, type PixelFiddlerImageProps, PixelFiddlerProvider };
@@ -0,0 +1,56 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ImgHTMLAttributes, ReactNode } from 'react';
3
+ import { TransformationOptions, PixelFiddlerConfig } from '@pixelfiddler/core';
4
+ export { BorderOptions, CropOptions, EffectOptions, FormatOptions, PixelFiddlerConfig, ResizeOptions, TextOptions, TransformationOptions, WatermarkOptions } from '@pixelfiddler/core';
5
+
6
+ interface PixelFiddlerImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'width' | 'sizes'> {
7
+ /** Src to your image - can be both relative or absolute.
8
+ * If it's relative, it will be attached to baseUrl from config
9
+ * If it's absolute, it will be left as is
10
+ * */
11
+ src: string;
12
+ /** This should be your baseURL endpoint for the source from PixelFiddle Dashboard. You can skip this property if
13
+ * you either pass it in PixelFiddlerProvider or pass an absolute path to src property.
14
+ *
15
+ * */
16
+ baseUrl?: string;
17
+ /**
18
+ * The sizes attribute for responsive images (e.g., "100vw", "(max-width: 768px) 100vw, 50vw").
19
+ * Required if no fixed width was provided, and you want the image to be responsive
20
+ */
21
+ sizes?: string;
22
+ /**
23
+ * Decides whether srcSet should be built automatically for responsive images. In case `width` is passed, this will result in srcSet with `x` (dpr) descriptor.
24
+ *
25
+ *
26
+ * If you want responsiveness based on layout, then you must pass `sizes` property for this to function properly e.g `(max-width: 768px) 100vw, 50vw")`
27
+ * which will generate srcSet based on vw
28
+ *
29
+ *
30
+ * Ignored if `transformation.width` is set.
31
+ * @default true
32
+ */
33
+ responsive?: boolean;
34
+ /**
35
+ * Display width in CSS pixels.
36
+ */
37
+ width?: number | `${number}`;
38
+ /** Transformation options to apply */
39
+ transformations?: TransformationOptions;
40
+ /** Custom device breakpoints for responsive srcset */
41
+ deviceBreakpoints?: number[];
42
+ /** Custom image breakpoints for smaller images */
43
+ imageBreakpoints?: number[];
44
+ }
45
+ declare function PixelFiddlerImage({ src, sizes, width, transformations, baseUrl, deviceBreakpoints, imageBreakpoints, responsive, ...imgProps }: PixelFiddlerImageProps): react_jsx_runtime.JSX.Element;
46
+
47
+ interface PixelFiddlerContextValue {
48
+ config: PixelFiddlerConfig;
49
+ }
50
+ interface PixelFiddlerProviderProps {
51
+ children: ReactNode;
52
+ config: PixelFiddlerConfig;
53
+ }
54
+ declare function PixelFiddlerProvider({ children, config }: PixelFiddlerProviderProps): react_jsx_runtime.JSX.Element;
55
+
56
+ export { type PixelFiddlerContextValue, PixelFiddlerImage, type PixelFiddlerImageProps, PixelFiddlerProvider };
package/dist/index.js ADDED
@@ -0,0 +1,57 @@
1
+ import { createContext, useContext, useMemo } from 'react';
2
+ import { createResponsiveAttributes, buildTransformationUrl } from '@pixelfiddler/core';
3
+ import { jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/components/pixel-fiddler-image.tsx
6
+ var PixelFiddlerContext = createContext(null);
7
+ function PixelFiddlerProvider({ children, config }) {
8
+ return /* @__PURE__ */ jsx(PixelFiddlerContext.Provider, { value: { config }, children });
9
+ }
10
+ function PixelFiddlerImage({
11
+ src,
12
+ sizes,
13
+ width,
14
+ transformations,
15
+ baseUrl,
16
+ deviceBreakpoints,
17
+ imageBreakpoints,
18
+ responsive = true,
19
+ ...imgProps
20
+ }) {
21
+ const context = useContext(PixelFiddlerContext);
22
+ const imageAttrs = useMemo(() => {
23
+ const finalBaseUrl = baseUrl || context?.config.baseUrl;
24
+ const hasWidthTransformation = transformations?.width;
25
+ if (responsive && !hasWidthTransformation) {
26
+ if (width && sizes) {
27
+ console.warn(
28
+ "[PixelFiddlerImage] Both `width` and `sizes` were provided. `sizes` will be ignored and a fixed-width DPR srcSet will be generated."
29
+ );
30
+ }
31
+ return createResponsiveAttributes(src, finalBaseUrl, {
32
+ width: width && +width,
33
+ sizes,
34
+ deviceBreakpoints,
35
+ imageBreakpoints,
36
+ transformations
37
+ });
38
+ }
39
+ return {
40
+ src: buildTransformationUrl({ src, baseUrl, transformations })
41
+ };
42
+ }, [src, sizes, transformations, deviceBreakpoints, imageBreakpoints, width, baseUrl, context?.config.baseUrl, responsive]);
43
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
44
+ "img",
45
+ {
46
+ src: imageAttrs.src || src,
47
+ srcSet: imageAttrs.srcSet,
48
+ sizes: imageAttrs.sizes,
49
+ width: imageAttrs.width || width,
50
+ ...imgProps
51
+ }
52
+ ) });
53
+ }
54
+
55
+ export { PixelFiddlerImage, PixelFiddlerProvider };
56
+ //# sourceMappingURL=index.js.map
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/provider/pixel-fiddler-context.tsx","../src/components/pixel-fiddler-image.tsx"],"names":["jsx"],"mappings":";;;;;AAOO,IAAM,mBAAA,GAAsB,cAA+C,IAAI,CAAA;AAO/E,SAAS,oBAAA,CAAqB,EAAE,QAAA,EAAU,MAAA,EAAO,EAA8B;AACpF,EAAA,uBACE,GAAA,CAAC,oBAAoB,QAAA,EAApB,EAA6B,OAAO,EAAC,MAAA,IACnC,QAAA,EACH,CAAA;AAEJ;ACyBO,SAAS,iBAAA,CAAkB;AAAA,EACI,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA,GAAa,IAAA;AAAA,EACb,GAAG;AACP,CAAA,EAA2B;AAEzD,EAAA,MAAM,OAAA,GAAU,WAAW,mBAAmB,CAAA;AAG9C,EAAA,MAAM,UAAA,GAAa,QAAQ,MAAM;AAC7B,IAAA,MAAM,YAAA,GAAe,OAAA,IAAW,OAAA,EAAS,MAAA,CAAO,OAAA;AAEhD,IAAA,MAAM,yBAAyB,eAAA,EAAiB,KAAA;AAEhD,IAAA,IAAI,UAAA,IAAc,CAAC,sBAAA,EAAwB;AACvC,MAAA,IAAI,SAAS,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,IAAA;AAAA,UACJ;AAAA,SAEJ;AAAA,MACJ;AAEA,MAAA,OAAO,0BAAA,CAA2B,KAAK,YAAA,EAAc;AAAA,QACjD,KAAA,EAAO,SAAS,CAAC,KAAA;AAAA,QACjB,KAAA;AAAA,QACA,iBAAA;AAAA,QACA,gBAAA;AAAA,QACA;AAAA,OACH,CAAA;AAAA,IACL;AACA,IAAA,OAAO;AAAA,MACH,KAAK,sBAAA,CAAuB,EAAC,GAAA,EAAK,OAAA,EAAS,iBAAgB;AAAA,KAC/D;AAAA,EAEJ,CAAA,EAAG,CAAC,GAAA,EAAK,KAAA,EAAO,eAAA,EAAiB,iBAAA,EAAmB,gBAAA,EAAkB,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,MAAA,CAAO,OAAA,EAAS,UAAU,CAAC,CAAA;AAE1H,EAAA,uBACIA,GAAAA,CAAA,QAAA,EAAA,EACI,QAAA,kBAAAA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACG,GAAA,EAAK,WAAW,GAAA,IAAO,GAAA;AAAA,MACvB,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,OAAO,UAAA,CAAW,KAAA;AAAA,MAClB,KAAA,EAAO,WAAW,KAAA,IAAS,KAAA;AAAA,MAC1B,GAAG;AAAA;AAAA,GACR,EACJ,CAAA;AAER","file":"index.js","sourcesContent":["import { createContext, type ReactNode } from 'react';\nimport type { PixelFiddlerConfig } from '@pixelfiddler/core';\n\nexport interface PixelFiddlerContextValue {\n config: PixelFiddlerConfig;\n}\n\nexport const PixelFiddlerContext = createContext<PixelFiddlerContextValue | null>(null);\n\nexport interface PixelFiddlerProviderProps {\n children: ReactNode;\n config: PixelFiddlerConfig;\n}\n\nexport function PixelFiddlerProvider({ children, config }: PixelFiddlerProviderProps) {\n return (\n <PixelFiddlerContext.Provider value={{config}}>\n {children}\n </PixelFiddlerContext.Provider>\n );\n}\n","import { ImgHTMLAttributes, useContext, useMemo } from 'react';\r\nimport { buildTransformationUrl, createResponsiveAttributes, TransformationOptions, } from '@pixelfiddler/core';\r\nimport { PixelFiddlerContext } from '../provider/pixel-fiddler-context';\r\n\r\nexport interface PixelFiddlerImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'width' | 'sizes'> {\r\n /** Src to your image - can be both relative or absolute.\r\n * If it's relative, it will be attached to baseUrl from config\r\n * If it's absolute, it will be left as is\r\n * */\r\n src: string\r\n /** This should be your baseURL endpoint for the source from PixelFiddle Dashboard. You can skip this property if\r\n * you either pass it in PixelFiddlerProvider or pass an absolute path to src property.\r\n *\r\n * */\r\n baseUrl?: string\r\n /**\r\n * The sizes attribute for responsive images (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * Required if no fixed width was provided, and you want the image to be responsive\r\n */\r\n sizes?: string;\r\n /**\r\n * Decides whether srcSet should be built automatically for responsive images. In case `width` is passed, this will result in srcSet with `x` (dpr) descriptor.\r\n *\r\n *\r\n * If you want responsiveness based on layout, then you must pass `sizes` property for this to function properly e.g `(max-width: 768px) 100vw, 50vw\")`\r\n * which will generate srcSet based on vw\r\n *\r\n *\r\n * Ignored if `transformation.width` is set.\r\n * @default true\r\n */\r\n responsive?: boolean\r\n /**\r\n * Display width in CSS pixels.\r\n */\r\n width?: number | `${number}`;\r\n /** Transformation options to apply */\r\n transformations?: TransformationOptions;\r\n /** Custom device breakpoints for responsive srcset */\r\n deviceBreakpoints?: number[];\r\n /** Custom image breakpoints for smaller images */\r\n imageBreakpoints?: number[];\r\n}\r\n\r\nexport function PixelFiddlerImage({\r\n src,\r\n sizes,\r\n width,\r\n transformations,\r\n baseUrl,\r\n deviceBreakpoints,\r\n imageBreakpoints,\r\n responsive = true,\r\n ...imgProps\r\n }: PixelFiddlerImageProps) {\r\n\r\n const context = useContext(PixelFiddlerContext);\r\n\r\n\r\n const imageAttrs = useMemo(() => {\r\n const finalBaseUrl = baseUrl || context?.config.baseUrl\r\n\r\n const hasWidthTransformation = transformations?.width\r\n\r\n if (responsive && !hasWidthTransformation) {\r\n if (width && sizes) {\r\n console.warn(\r\n '[PixelFiddlerImage] Both `width` and `sizes` were provided. ' +\r\n '`sizes` will be ignored and a fixed-width DPR srcSet will be generated.'\r\n );\r\n }\r\n\r\n return createResponsiveAttributes(src, finalBaseUrl, {\r\n width: width && +width,\r\n sizes,\r\n deviceBreakpoints,\r\n imageBreakpoints,\r\n transformations\r\n });\r\n }\r\n return {\r\n src: buildTransformationUrl({src, baseUrl, transformations}),\r\n };\r\n\r\n }, [src, sizes, transformations, deviceBreakpoints, imageBreakpoints, width, baseUrl, context?.config.baseUrl, responsive]);\r\n\r\n return (\r\n <>\r\n <img\r\n src={imageAttrs.src || src}\r\n srcSet={imageAttrs.srcSet}\r\n sizes={imageAttrs.sizes}\r\n width={imageAttrs.width || width}\r\n {...imgProps}\r\n />\r\n </>\r\n );\r\n}\r\n"]}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@pixelfiddler/react",
3
+ "version": "1.0.0",
4
+ "description": "React components for PixelFiddler image transformation SDK",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "dependencies": {
25
+ "@pixelfiddler/core": "1.0.0"
26
+ },
27
+ "peerDependencies": {
28
+ "react": ">=18.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@testing-library/react": "^16.3.2",
32
+ "@types/react": "^18.2.0",
33
+ "@vitest/coverage-v8": "^4.0.18",
34
+ "jsdom": "^27.4.0",
35
+ "react": "^18.3.1",
36
+ "react-dom": "18",
37
+ "tsup": "^8.0.1",
38
+ "typescript": "^5.3.3",
39
+ "vitest": "^4.0.18"
40
+ },
41
+ "keywords": [
42
+ "pixelfiddler",
43
+ "react",
44
+ "image",
45
+ "transformation",
46
+ "cdn",
47
+ "optimization",
48
+ "component"
49
+ ],
50
+ "license": "MIT",
51
+ "author": "PixelFiddler",
52
+ "homepage": "https://pixel-fiddler.com",
53
+ "bugs": {
54
+ "url": "https://github.com/pixel-fiddler/js-sdk/issues"
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/pixel-fiddler/js-sdk.git",
59
+ "directory": "packages/react"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ },
64
+ "engines": {
65
+ "node": ">=18"
66
+ },
67
+ "sideEffects": false,
68
+ "scripts": {
69
+ "build": "tsup",
70
+ "dev": "tsup --watch",
71
+ "test": "vitest run",
72
+ "test:watch": "vitest",
73
+ "test:coverage": "vitest run --coverage",
74
+ "typecheck": "tsc --noEmit",
75
+ "lint": "eslint src --ext .ts,.tsx",
76
+ "clean": "rm -rf dist coverage"
77
+ }
78
+ }