astro-lqip 1.2.1 → 1.3.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <a href="https://github.com/felixicaza/astro-lqip/">
1
+ <a href="https://astro-lqip.web.app/">
2
2
  <img src="./assets/logo.png" alt="Astro LQIP Logo" width="200" height="200" />
3
3
  </a>
4
4
 
@@ -7,7 +7,7 @@
7
7
  [![GitHub Release](https://img.shields.io/github/v/release/felixicaza/astro-lqip?logo=npm)](https://www.npmjs.com/package/astro-lqip)
8
8
  [![GitHub License](https://img.shields.io/github/license/felixicaza/astro-lqip)](https://github.com/felixicaza/astro-lqip/blob/main/LICENSE)
9
9
 
10
- Native extended Astro component for generating low quality image placeholders (LQIP).
10
+ Native extended Astro components for generating low quality image placeholders (LQIP).
11
11
 
12
12
  ## ⬇️ Installation
13
13
 
@@ -31,27 +31,39 @@ yarn add astro-lqip
31
31
 
32
32
  ## 🚀 Usage
33
33
 
34
- In your current Astro project, just replace the import of the native Astro `<Picture />` component with the one provided by [astro-lqip](https://www.npmjs.com/package/astro-lqip).
34
+ In your current Astro project, just replace the import of the native Astro `<Image>` or `<Picture>` components with the ones provided by [astro-lqip](https://astro-lqip.web.app/).
35
+
36
+ ### Image
37
+
38
+ ```diff
39
+ - import { Image } from 'astro:assets';
40
+ + import { Image } from 'astro-lqip/components';
41
+ ```
42
+
43
+ ### Picture
35
44
 
36
45
  ```diff
37
46
  - import { Picture } from 'astro:assets';
38
- +import { Picture } from 'astro-lqip/components';
47
+ + import { Picture } from 'astro-lqip/components';
39
48
  ```
40
49
 
41
50
  Example:
42
51
 
43
52
  ```astro
44
53
  ---
45
- import { Picture } from 'astro-lqip/components'
54
+ import { Image, Picture } from 'astro-lqip/components'
55
+
46
56
  import image from './path/to/image.png'
57
+ import otherImage from './path/to/other-image.png'
47
58
  ---
48
59
 
49
- <Picture src={image} alt="Cover Image" width={220} height={220} />
60
+ <Image src={image} alt="Cover Image" width={220} height={220} />
61
+ <Picture src={otherImage} alt="Other cover Image" width={220} height={220} />
50
62
  ```
51
63
 
52
64
  ## ⚙️ Props
53
65
 
54
- This `<Picture />` component supports all the props of the [native Astro component](https://docs.astro.build/en/reference/modules/astro-assets/#picture-properties), but adds a couple of props for LQIP management:
66
+ Both `<Image>` and `<Picture>` components support all the props of the [native Astro components](https://docs.astro.build/en/reference/modules/astro-assets/), but adds a couple of props for LQIP management:
55
67
 
56
68
  - `lqip`: The LQIP type to use. It can be one of the following:
57
69
  - `base64`: Generates a Base64-encoded LQIP image. (default option)
@@ -67,24 +79,31 @@ Example:
67
79
 
68
80
  ```astro
69
81
  ---
70
- import { Picture } from 'astro-lqip/components'
82
+ import { Image, Picture } from 'astro-lqip/components'
83
+
71
84
  import image from './path/to/image.png'
85
+ import otherImage from './path/to/other-image.png'
72
86
  ---
73
87
 
74
- <Picture src={image} alt="Cover Image" width={220} height={220} lqip="css" lqipSize={7} />
88
+ <Image src={image} alt="Cover Image" width={220} height={220} lqip="svg" lqipSize={10} />
89
+ <Picture src={otherImage} alt="Other cover Image" width={220} height={220} lqip="css" lqipSize={7} />
75
90
  ```
76
91
 
92
+ > [!TIP]
93
+ > For the `<Image>` component, a `parentAttributes` prop similar to `pictureAttributes` has been added.
94
+
77
95
  ## 📝 ToDo
78
96
 
79
- - [ ] Add support for Image component.
97
+ - [x] Add support for Image component.
80
98
  - [x] Add support for more lqip techniques.
81
99
  - [ ] Test for remote images.
82
100
  - [ ] Optimize current CSS usage.
83
101
  - [x] Improve docs page.
102
+ - [ ] Test support for SSR mode.
84
103
 
85
104
  ## 💡 Knowledge
86
105
 
87
- Since this integration is built on top of Astro's native `<Picture>` component, you can refer to the [Astro documentation](https://docs.astro.build/en/guides/images/#picture-) for more information on how to use it.
106
+ Since this integration is built on top of Astro native `<Image>` and `<Picture>` components, you can refer to the [Astro documentation](https://docs.astro.build/en/guides/images/) for more information on how to use it.
88
107
 
89
108
  ## 🤝 Contributing
90
109
  If you wish to contribute to this project, you can do so by reading the [contribution guide](https://github.com/felixicaza/astro-lqip/blob/main/CONTRIBUTING.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-lqip",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Native extended Astro component for generating low quality image placeholders (LQIP).",
5
5
  "keywords": [
6
6
  "astro",
@@ -36,21 +36,21 @@
36
36
  "plaiceholder": "3.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@eslint/js": "9.30.0",
40
- "@typescript-eslint/parser": "8.35.0",
41
- "astro": "5.10.1",
42
- "bumpp": "10.2.0",
43
- "eslint": "9.30.0",
39
+ "@eslint/js": "9.33.0",
40
+ "@typescript-eslint/parser": "8.39.1",
41
+ "astro": "5.12.9",
42
+ "bumpp": "10.2.3",
43
+ "eslint": "9.33.0",
44
44
  "eslint-plugin-astro": "1.3.1",
45
45
  "eslint-plugin-jsonc": "2.20.1",
46
46
  "eslint-plugin-jsx-a11y": "6.10.2",
47
- "eslint-plugin-package-json": "0.42.0",
47
+ "eslint-plugin-package-json": "0.53.0",
48
48
  "eslint-plugin-yml": "1.18.0",
49
- "globals": "16.2.0",
50
- "jiti": "2.4.2",
49
+ "globals": "16.3.0",
50
+ "jiti": "2.5.1",
51
51
  "nano-staged": "0.8.0",
52
- "neostandard": "0.12.1",
53
- "simple-git-hooks": "2.13.0"
52
+ "neostandard": "0.12.2",
53
+ "simple-git-hooks": "2.13.1"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "astro": ">=3.3.0"
@@ -0,0 +1,95 @@
1
+ ---
2
+ import type { LocalImageProps, RemoteImageProps } from 'astro:assets'
3
+ import type { Props as LqipProps } from '../types'
4
+ import type { HTMLAttributes } from 'astro/types'
5
+
6
+ import { PREFIX } from '../constants'
7
+
8
+ import { resolveImageMetadata } from '../utils/resolveImageMetadata'
9
+ import { renderSVGNode } from '../utils/renderSVGNode'
10
+ import { getLqipStyle } from '../utils/getLqipStyle'
11
+ import { getLqip } from '../utils/getLqip'
12
+
13
+ import { Image as ImageComponent } from 'astro:assets'
14
+
15
+ type Props = (LocalImageProps | RemoteImageProps) & LqipProps & {
16
+ parentAttributes?: HTMLAttributes<'div'>
17
+ }
18
+
19
+ const { class: className, lqip = 'base64', lqipSize = 4, parentAttributes = {}, ...props } = Astro.props as Props
20
+
21
+ const isDevelopment = import.meta.env.MODE === 'development'
22
+
23
+ const imageMetadata = await resolveImageMetadata(props.src)
24
+ const lqipImage = await getLqip(imageMetadata, isDevelopment, lqip, lqipSize)
25
+
26
+ let svgHTML = ''
27
+
28
+ if (lqip === 'svg' && Array.isArray(lqipImage)) {
29
+ svgHTML = renderSVGNode(lqipImage as [string, Record<string, any>, any[]])
30
+ }
31
+
32
+ const lqipStyle = getLqipStyle(lqip, lqipImage, svgHTML)
33
+
34
+ const forbiddenVars = ['--lqip-background', '--z-index', '--opacity']
35
+ const styleProps = parentAttributes.style ?? {}
36
+
37
+ for (const key of Object.keys(styleProps)) {
38
+ if (forbiddenVars.includes(key)) {
39
+ console.warn(
40
+ `${PREFIX} The CSS variable “${key}” should not be passed in \`parentAttributes.style\` because it can override the functionality of LQIP.`
41
+ )
42
+ }
43
+ }
44
+
45
+ const combinedStyle = {
46
+ ...styleProps,
47
+ ...lqipStyle
48
+ }
49
+
50
+ const combinedParentAttributes = {
51
+ ...parentAttributes,
52
+ style: combinedStyle
53
+ }
54
+ ---
55
+
56
+ <style is:inline>
57
+ div[data-astro-lqip] {
58
+ --opacity: 1;
59
+ --z-index: 0;
60
+
61
+ position: relative;
62
+ display: inline-block;
63
+ width: fit-content;
64
+ height: fit-content;
65
+ }
66
+
67
+ div[data-astro-lqip]::after {
68
+ content: "";
69
+ inset: 0;
70
+ width: 100%;
71
+ height: 100%;
72
+ position: absolute;
73
+ pointer-events: none;
74
+ transition: opacity 1s;
75
+ opacity: var(--opacity);
76
+ z-index: var(--z-index);
77
+ background: var(--lqip-background);
78
+ background-size: cover;
79
+ background-position: 50% 50%;
80
+ }
81
+
82
+ div[data-astro-lqip] img {
83
+ z-index: 1;
84
+ position: relative;
85
+ overflow: hidden;
86
+ }
87
+ </style>
88
+
89
+ <div class={className} data-astro-lqip {...combinedParentAttributes}>
90
+ <ImageComponent
91
+ {...props}
92
+ class={className}
93
+ onload="parentElement.style.setProperty('--z-index', 1), parentElement.style.setProperty('--opacity', 0)"
94
+ />
95
+ </div>
@@ -1,5 +1,8 @@
1
1
  ---
2
- import type { Props } from '../types'
2
+ import type { Props as AstroPictureProps } from 'astro/components/Picture.astro'
3
+ import type { Props as LqipProps } from '../types'
4
+
5
+ import { PREFIX } from '../constants'
3
6
 
4
7
  import { resolveImageMetadata } from '../utils/resolveImageMetadata'
5
8
  import { renderSVGNode } from '../utils/renderSVGNode'
@@ -8,7 +11,9 @@ import { getLqip } from '../utils/getLqip'
8
11
 
9
12
  import { Picture as PictureComponent } from 'astro:assets'
10
13
 
11
- const { class: className, lqip = 'base64', lqipSize = 4, ...props } = Astro.props as Props
14
+ type Props = AstroPictureProps & LqipProps
15
+
16
+ const { class: className, lqip = 'base64', lqipSize = 4, pictureAttributes = {}, ...props } = Astro.props as Props
12
17
 
13
18
  const isDevelopment = import.meta.env.MODE === 'development'
14
19
 
@@ -22,10 +27,31 @@ if (lqip === 'svg' && Array.isArray(lqipImage)) {
22
27
  }
23
28
 
24
29
  const lqipStyle = getLqipStyle(lqip, lqipImage, svgHTML)
30
+
31
+ const forbiddenVars = ['--lqip-background', '--z-index', '--opacity']
32
+ const styleProps = pictureAttributes.style ?? {}
33
+
34
+ for (const key of Object.keys(styleProps)) {
35
+ if (forbiddenVars.includes(key)) {
36
+ console.warn(
37
+ `${PREFIX} The CSS variable “${key}” should not be passed in \`pictureAttributes.style\` because it can override the functionality of LQIP.`
38
+ )
39
+ }
40
+ }
41
+
42
+ const combinedStyle = {
43
+ ...styleProps,
44
+ ...lqipStyle
45
+ }
46
+
47
+ const combinedPictureAttributes = {
48
+ ...pictureAttributes,
49
+ style: combinedStyle
50
+ }
25
51
  ---
26
52
 
27
53
  <style is:inline>
28
- picture {
54
+ picture[data-astro-lqip] {
29
55
  --opacity: 1;
30
56
  --z-index: 0;
31
57
 
@@ -33,7 +59,7 @@ const lqipStyle = getLqipStyle(lqip, lqipImage, svgHTML)
33
59
  display: inline-block;
34
60
  }
35
61
 
36
- picture::after {
62
+ picture[data-astro-lqip]::after {
37
63
  content: "";
38
64
  inset: 0;
39
65
  width: 100%;
@@ -48,7 +74,7 @@ const lqipStyle = getLqipStyle(lqip, lqipImage, svgHTML)
48
74
  background-position: 50% 50%;
49
75
  }
50
76
 
51
- picture img {
77
+ picture[data-astro-lqip] img {
52
78
  z-index: 1;
53
79
  position: relative;
54
80
  overflow: hidden;
@@ -58,6 +84,6 @@ const lqipStyle = getLqipStyle(lqip, lqipImage, svgHTML)
58
84
  <PictureComponent
59
85
  {...props}
60
86
  class={className}
61
- pictureAttributes={{ style: lqipStyle }}
87
+ pictureAttributes={{ 'data-astro-lqip': '', ...combinedPictureAttributes }}
62
88
  onload="parentElement.style.setProperty('--z-index', 1), parentElement.style.setProperty('--opacity', 0)"
63
89
  />
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { default as Picture } from './components/Picture.astro'
2
+ export { default as Image } from './components/Image.astro'
@@ -1,8 +1,6 @@
1
- import type { Props as PictureProps } from 'astro/components/Picture.astro'
2
-
3
1
  import type { LqipType } from './lqip.type'
4
2
 
5
- export type Props = PictureProps & {
3
+ export type Props = {
6
4
  /**
7
5
  * LQIP type.
8
6
  * This can be 'color', 'css', 'svg' or 'base64'.