@teamnovu/nuxt-image 0.5.5 → 1.0.0-beta.1

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 (91) hide show
  1. package/README.md +229 -24
  2. package/dist/module.d.mts +70 -0
  3. package/dist/module.json +12 -0
  4. package/dist/module.mjs +67 -0
  5. package/dist/runtime/components/NovuBunnyImage.d.vue.ts +11 -0
  6. package/dist/runtime/components/NovuBunnyImage.vue +67 -0
  7. package/dist/runtime/components/NovuBunnyImage.vue.d.ts +11 -0
  8. package/dist/runtime/components/NovuCloudinaryImage.d.vue.ts +19 -0
  9. package/dist/runtime/components/NovuCloudinaryImage.vue +79 -0
  10. package/dist/runtime/components/NovuCloudinaryImage.vue.d.ts +19 -0
  11. package/dist/runtime/components/NovuImage.d.vue.ts +28 -0
  12. package/dist/runtime/components/NovuImage.vue +90 -0
  13. package/dist/runtime/components/NovuImage.vue.d.ts +28 -0
  14. package/dist/runtime/components/NovuImgproxyImage.d.vue.ts +12 -0
  15. package/dist/runtime/components/NovuImgproxyImage.vue +68 -0
  16. package/dist/runtime/components/NovuImgproxyImage.vue.d.ts +12 -0
  17. package/dist/runtime/components/NovuStatamicImage.d.vue.ts +17 -0
  18. package/dist/runtime/components/NovuStatamicImage.vue +87 -0
  19. package/dist/runtime/components/NovuStatamicImage.vue.d.ts +17 -0
  20. package/dist/runtime/composables/useResponsiveImage.d.ts +42 -0
  21. package/dist/runtime/composables/useResponsiveImage.js +115 -0
  22. package/dist/runtime/providers/imgproxy.d.ts +68 -0
  23. package/dist/runtime/providers/imgproxy.js +161 -0
  24. package/dist/runtime/types.d.ts +56 -0
  25. package/dist/runtime/types.js +0 -0
  26. package/dist/runtime/utils/focal.d.ts +11 -0
  27. package/dist/runtime/utils/focal.js +33 -0
  28. package/dist/runtime/utils/i18n.d.ts +1 -0
  29. package/dist/runtime/utils/i18n.js +10 -0
  30. package/dist/runtime/utils/numbers.d.ts +1 -0
  31. package/dist/runtime/utils/numbers.js +6 -0
  32. package/dist/runtime/utils/providerModifiers.d.ts +4 -0
  33. package/dist/runtime/utils/providerModifiers.js +36 -0
  34. package/dist/runtime/utils/screens.d.ts +5 -0
  35. package/dist/runtime/utils/screens.js +19 -0
  36. package/dist/runtime/utils/statamic.d.ts +3 -0
  37. package/dist/runtime/utils/statamic.js +143 -0
  38. package/dist/types.d.mts +3 -0
  39. package/package.json +65 -68
  40. package/CHANGELOG.md +0 -373
  41. package/LICENSE +0 -21
  42. package/dist/module.js +0 -482
  43. package/dist/runtime/components/image.mixin.d.ts +0 -46
  44. package/dist/runtime/components/image.mixin.js +0 -58
  45. package/dist/runtime/components/nuxt-img.vue +0 -49
  46. package/dist/runtime/components/nuxt-img.vue.d.ts +0 -12
  47. package/dist/runtime/components/nuxt-picture.vue +0 -86
  48. package/dist/runtime/components/nuxt-picture.vue.d.ts +0 -15
  49. package/dist/runtime/image.d.ts +0 -2
  50. package/dist/runtime/image.js +0 -194
  51. package/dist/runtime/index.d.ts +0 -2
  52. package/dist/runtime/index.js +0 -2
  53. package/dist/runtime/ipx.d.ts +0 -3
  54. package/dist/runtime/ipx.js +0 -3
  55. package/dist/runtime/plugin.d.ts +0 -1
  56. package/dist/runtime/plugin.js +0 -31
  57. package/dist/runtime/providers/cloudinary.d.ts +0 -2
  58. package/dist/runtime/providers/cloudinary.js +0 -96
  59. package/dist/runtime/providers/fastly.d.ts +0 -2
  60. package/dist/runtime/providers/fastly.js +0 -21
  61. package/dist/runtime/providers/glide.d.ts +0 -2
  62. package/dist/runtime/providers/glide.js +0 -49
  63. package/dist/runtime/providers/imagekit.d.ts +0 -2
  64. package/dist/runtime/providers/imagekit.js +0 -172
  65. package/dist/runtime/providers/imgix.d.ts +0 -3
  66. package/dist/runtime/providers/imgix.js +0 -153
  67. package/dist/runtime/providers/ipx.d.ts +0 -4
  68. package/dist/runtime/providers/ipx.js +0 -28
  69. package/dist/runtime/providers/netlify.d.ts +0 -3
  70. package/dist/runtime/providers/netlify.js +0 -40
  71. package/dist/runtime/providers/prismic.d.ts +0 -2
  72. package/dist/runtime/providers/prismic.js +0 -10
  73. package/dist/runtime/providers/sanity.d.ts +0 -2
  74. package/dist/runtime/providers/sanity.js +0 -87
  75. package/dist/runtime/providers/static.d.ts +0 -3
  76. package/dist/runtime/providers/static.js +0 -6
  77. package/dist/runtime/providers/storyblok.d.ts +0 -2
  78. package/dist/runtime/providers/storyblok.js +0 -27
  79. package/dist/runtime/providers/twicpics.d.ts +0 -2
  80. package/dist/runtime/providers/twicpics.js +0 -58
  81. package/dist/runtime/providers/vercel.d.ts +0 -3
  82. package/dist/runtime/providers/vercel.js +0 -28
  83. package/dist/runtime/utils/index.d.ts +0 -17
  84. package/dist/runtime/utils/index.js +0 -72
  85. package/dist/runtime/utils/meta.d.ts +0 -2
  86. package/dist/runtime/utils/meta.js +0 -67
  87. package/dist/runtime/utils/static-map.d.ts +0 -2
  88. package/dist/runtime/utils/static-map.js +0 -20
  89. package/dist/types.d.ts +0 -172
  90. package/vetur/attributes.json +0 -32
  91. package/vetur/tags.json +0 -32
@@ -0,0 +1,90 @@
1
+ <script setup>
2
+ import { computed, useTemplateRef } from "vue";
3
+ import { useRuntimeConfig } from "#imports";
4
+ import { useResponsiveImage } from "../composables/useResponsiveImage";
5
+ import { toFiniteNumber } from "../utils/numbers";
6
+ const props = defineProps({
7
+ src: { type: String, required: true },
8
+ alt: { type: String, required: false, default: void 0 },
9
+ width: { type: [Number, String], required: false, default: void 0 },
10
+ height: { type: [Number, String], required: false, default: void 0 },
11
+ sourceWidth: { type: [Number, String], required: false, default: void 0 },
12
+ sourceHeight: { type: [Number, String], required: false, default: void 0 },
13
+ aspectRatio: { type: Number, required: false, default: void 0 },
14
+ quality: { type: [Number, String], required: false, default: void 0 },
15
+ format: { type: String, required: false, default: void 0 },
16
+ fit: { type: String, required: false, default: void 0 },
17
+ focal: { type: [String, Array], required: false, default: void 0 },
18
+ modifiers: { type: Object, required: false, default: void 0 },
19
+ provider: { type: String, required: false, default: void 0 },
20
+ sizes: { type: String, required: false, default: void 0 },
21
+ loading: { type: String, required: false, default: "lazy" },
22
+ decoding: { type: String, required: false, default: "async" },
23
+ priority: { type: Boolean, required: false, default: false },
24
+ fallbackWidth: { type: Number, required: false, default: void 0 },
25
+ usePlaceholder: { type: Boolean, required: false, default: void 0 },
26
+ placeholderQuality: { type: Number, required: false, default: void 0 },
27
+ placeholderWidth: { type: Number, required: false, default: void 0 },
28
+ placeholderSrc: { type: String, required: false, default: void 0 }
29
+ });
30
+ const runtimeConfig = useRuntimeConfig().public.novuImage;
31
+ const effectiveProvider = computed(() => props.provider ?? runtimeConfig.provider);
32
+ const effectiveQuality = computed(() => props.quality ?? runtimeConfig.defaultQuality);
33
+ const effectiveFormat = computed(() => props.format ?? runtimeConfig.defaultFormat);
34
+ const effectiveFallbackWidth = computed(() => props.fallbackWidth ?? runtimeConfig.fallbackWidth);
35
+ const effectiveUsePlaceholder = computed(() => props.usePlaceholder ?? runtimeConfig.usePlaceholder);
36
+ const effectivePlaceholderQuality = computed(() => props.placeholderQuality ?? runtimeConfig.placeholderQuality);
37
+ const effectivePlaceholderWidth = computed(() => props.placeholderWidth ?? runtimeConfig.placeholderWidth);
38
+ const imgRef = useTemplateRef("imgRef");
39
+ const { srcset, sizes, fallbackUrl } = useResponsiveImage({
40
+ src: () => props.src,
41
+ width: () => props.width,
42
+ height: () => props.height,
43
+ sourceWidth: () => props.sourceWidth,
44
+ sourceHeight: () => props.sourceHeight,
45
+ aspectRatio: () => props.aspectRatio,
46
+ quality: effectiveQuality,
47
+ format: effectiveFormat,
48
+ fit: () => props.fit,
49
+ modifiers: () => props.modifiers,
50
+ provider: effectiveProvider,
51
+ focal: () => props.focal,
52
+ sizes: () => props.sizes,
53
+ fallbackWidth: effectiveFallbackWidth,
54
+ usePlaceholder: effectiveUsePlaceholder,
55
+ placeholderQuality: effectivePlaceholderQuality,
56
+ placeholderWidth: effectivePlaceholderWidth,
57
+ placeholderSrc: () => props.placeholderSrc,
58
+ screens: () => runtimeConfig.screens,
59
+ imgRef
60
+ });
61
+ const aspectRatioStyle = computed(() => {
62
+ const explicit = props.aspectRatio;
63
+ if (explicit && Number.isFinite(explicit) && explicit > 0) {
64
+ return { aspectRatio: String(explicit) };
65
+ }
66
+ const w = toFiniteNumber(props.width);
67
+ const h = toFiniteNumber(props.height);
68
+ if (w && h) return { aspectRatio: `${w} / ${h}` };
69
+ return void 0;
70
+ });
71
+ const effectiveLoading = computed(() => props.priority ? "eager" : props.loading);
72
+ const fetchPriority = computed(() => props.priority ? "high" : "auto");
73
+ </script>
74
+
75
+ <template>
76
+ <img
77
+ v-if="src"
78
+ ref="imgRef"
79
+ :src="fallbackUrl"
80
+ :srcset="srcset"
81
+ :sizes="sizes"
82
+ :alt="alt ?? ''"
83
+ :width="width"
84
+ :height="height"
85
+ :loading="effectiveLoading"
86
+ :decoding="decoding"
87
+ :fetchpriority="fetchPriority"
88
+ :style="aspectRatioStyle"
89
+ >
90
+ </template>
@@ -0,0 +1,28 @@
1
+ import type { FocalPoint } from '../utils/focal.js';
2
+ export interface NovuImageProps {
3
+ src: string;
4
+ alt?: string;
5
+ width?: number | string;
6
+ height?: number | string;
7
+ sourceWidth?: number | string;
8
+ sourceHeight?: number | string;
9
+ aspectRatio?: number;
10
+ quality?: number | string;
11
+ format?: string;
12
+ fit?: string;
13
+ focal?: FocalPoint;
14
+ modifiers?: Record<string, unknown>;
15
+ provider?: string;
16
+ sizes?: string;
17
+ loading?: 'lazy' | 'eager';
18
+ decoding?: 'async' | 'sync' | 'auto';
19
+ priority?: boolean;
20
+ fallbackWidth?: number;
21
+ usePlaceholder?: boolean;
22
+ placeholderQuality?: number;
23
+ placeholderWidth?: number;
24
+ placeholderSrc?: string;
25
+ }
26
+ declare const __VLS_export: import("vue").DefineComponent<NovuImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NovuImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import type { NovuImageProps } from './NovuImage.vue.js';
2
+ import type { ImgproxyResizingType } from '../providers/imgproxy.js';
3
+ export interface NovuImgproxyImageProps extends Omit<NovuImageProps, 'provider'> {
4
+ preset?: string;
5
+ /** Raw imgproxy gravity string (e.g. `'sm'`, `'ce'`, `'fp:0.5:0.5'`). Overrides `focal`. */
6
+ gravity?: string;
7
+ resizingType?: ImgproxyResizingType;
8
+ extend?: boolean;
9
+ }
10
+ declare const __VLS_export: import("vue").DefineComponent<NovuImgproxyImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NovuImgproxyImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const _default: typeof __VLS_export;
12
+ export default _default;
@@ -0,0 +1,68 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import NovuImage from "./NovuImage.vue";
4
+ const props = defineProps({
5
+ preset: { type: String, required: false, default: void 0 },
6
+ gravity: { type: String, required: false, default: void 0 },
7
+ resizingType: { type: String, required: false, default: void 0 },
8
+ extend: { type: Boolean, required: false, default: void 0 },
9
+ src: { type: String, required: true },
10
+ alt: { type: String, required: false },
11
+ width: { type: [Number, String], required: false },
12
+ height: { type: [Number, String], required: false },
13
+ sourceWidth: { type: [Number, String], required: false },
14
+ sourceHeight: { type: [Number, String], required: false },
15
+ aspectRatio: { type: Number, required: false },
16
+ quality: { type: [Number, String], required: false },
17
+ format: { type: String, required: false },
18
+ fit: { type: String, required: false },
19
+ focal: { type: [String, Array], required: false },
20
+ modifiers: { type: Object, required: false },
21
+ sizes: { type: String, required: false },
22
+ loading: { type: String, required: false },
23
+ decoding: { type: String, required: false },
24
+ priority: { type: Boolean, required: false },
25
+ fallbackWidth: { type: Number, required: false },
26
+ usePlaceholder: { type: Boolean, required: false },
27
+ placeholderQuality: { type: Number, required: false },
28
+ placeholderWidth: { type: Number, required: false },
29
+ placeholderSrc: { type: String, required: false }
30
+ });
31
+ const imgproxyModifiers = computed(() => {
32
+ const out = { ...props.modifiers ?? {} };
33
+ if (props.preset !== void 0) out.preset = props.preset;
34
+ if (props.gravity !== void 0) out.gravity = props.gravity;
35
+ if (props.resizingType !== void 0) out.resizingType = props.resizingType;
36
+ if (props.extend !== void 0) out.extend = props.extend;
37
+ return out;
38
+ });
39
+ const effectiveFocal = computed(() => props.gravity !== void 0 ? void 0 : props.focal);
40
+ </script>
41
+
42
+ <template>
43
+ <NovuImage
44
+ v-bind="$attrs"
45
+ :src="src"
46
+ :alt="alt"
47
+ :width="width"
48
+ :height="height"
49
+ :source-width="sourceWidth"
50
+ :source-height="sourceHeight"
51
+ :aspect-ratio="aspectRatio"
52
+ :quality="quality"
53
+ :format="format"
54
+ :fit="fit"
55
+ :focal="effectiveFocal"
56
+ :modifiers="imgproxyModifiers"
57
+ :sizes="sizes"
58
+ :loading="loading"
59
+ :decoding="decoding"
60
+ :priority="priority"
61
+ :fallback-width="fallbackWidth"
62
+ :use-placeholder="usePlaceholder"
63
+ :placeholder-quality="placeholderQuality"
64
+ :placeholder-width="placeholderWidth"
65
+ :placeholder-src="placeholderSrc"
66
+ provider="imgproxy"
67
+ />
68
+ </template>
@@ -0,0 +1,12 @@
1
+ import type { NovuImageProps } from './NovuImage.vue.js';
2
+ import type { ImgproxyResizingType } from '../providers/imgproxy.js';
3
+ export interface NovuImgproxyImageProps extends Omit<NovuImageProps, 'provider'> {
4
+ preset?: string;
5
+ /** Raw imgproxy gravity string (e.g. `'sm'`, `'ce'`, `'fp:0.5:0.5'`). Overrides `focal`. */
6
+ gravity?: string;
7
+ resizingType?: ImgproxyResizingType;
8
+ extend?: boolean;
9
+ }
10
+ declare const __VLS_export: import("vue").DefineComponent<NovuImgproxyImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NovuImgproxyImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const _default: typeof __VLS_export;
12
+ export default _default;
@@ -0,0 +1,17 @@
1
+ import type { FocalPoint } from '../utils/focal.js';
2
+ import type { StatamicAsset } from '../types.js';
3
+ export interface NovuStatamicImageProps {
4
+ src?: string | StatamicAsset | null;
5
+ provider?: string;
6
+ alt?: string;
7
+ fallbackAlt?: string;
8
+ locale?: string;
9
+ focal?: FocalPoint;
10
+ width?: number | string;
11
+ height?: number | string;
12
+ aspectRatio?: number;
13
+ placeholderField?: string | string[];
14
+ }
15
+ declare const __VLS_export: import("vue").DefineComponent<NovuStatamicImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NovuStatamicImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
@@ -0,0 +1,87 @@
1
+ <script setup>
2
+ import { computed, useAttrs } from "vue";
3
+ import { useNuxtApp, useRuntimeConfig } from "#imports";
4
+ import NovuImage from "./NovuImage.vue";
5
+ import NovuCloudinaryImage from "./NovuCloudinaryImage.vue";
6
+ import NovuBunnyImage from "./NovuBunnyImage.vue";
7
+ import NovuImgproxyImage from "./NovuImgproxyImage.vue";
8
+ import { resolveStatamicAsset } from "../utils/statamic";
9
+ import { getI18nLocale } from "../utils/i18n";
10
+ import { toFiniteNumber } from "../utils/numbers";
11
+ defineOptions({ inheritAttrs: false });
12
+ const props = defineProps({
13
+ src: { type: [String, Object, null], required: false, default: void 0 },
14
+ provider: { type: String, required: false, default: void 0 },
15
+ alt: { type: String, required: false, default: void 0 },
16
+ fallbackAlt: { type: String, required: false, default: void 0 },
17
+ locale: { type: String, required: false, default: void 0 },
18
+ focal: { type: [String, Array], required: false, default: void 0 },
19
+ width: { type: [Number, String], required: false, default: void 0 },
20
+ height: { type: [Number, String], required: false, default: void 0 },
21
+ aspectRatio: { type: Number, required: false, default: void 0 },
22
+ placeholderField: { type: [String, Array], required: false, default: void 0 }
23
+ });
24
+ const runtimeConfig = useRuntimeConfig().public.novuImage;
25
+ const nuxtApp = useNuxtApp();
26
+ const attrs = useAttrs();
27
+ const i18nLocale = computed(() => getI18nLocale(nuxtApp));
28
+ const effectiveLocale = computed(() => props.locale ?? i18nLocale.value);
29
+ const effectiveProvider = computed(() => props.provider ?? runtimeConfig.provider);
30
+ const resolved = computed(
31
+ () => resolveStatamicAsset(
32
+ props.src,
33
+ {
34
+ alt: props.alt,
35
+ fallbackAlt: props.fallbackAlt,
36
+ focal: props.focal,
37
+ width: toFiniteNumber(props.width),
38
+ height: toFiniteNumber(props.height),
39
+ aspectRatio: props.aspectRatio,
40
+ placeholderField: props.placeholderField
41
+ },
42
+ {
43
+ locale: effectiveLocale.value,
44
+ provider: effectiveProvider.value,
45
+ statamicPlaceholderFields: runtimeConfig.statamicPlaceholderFields
46
+ }
47
+ )
48
+ );
49
+ const wrapperByProvider = {
50
+ cloudinary: NovuCloudinaryImage,
51
+ bunny: NovuBunnyImage,
52
+ imgproxy: NovuImgproxyImage
53
+ };
54
+ const resolvedComponent = computed(() => {
55
+ const provider = effectiveProvider.value;
56
+ if (provider && provider in wrapperByProvider) {
57
+ return wrapperByProvider[provider];
58
+ }
59
+ return NovuImage;
60
+ });
61
+ const imageProps = computed(() => {
62
+ const base = {
63
+ src: resolved.value.src ?? "",
64
+ alt: resolved.value.alt,
65
+ focal: resolved.value.focal,
66
+ width: resolved.value.width,
67
+ height: resolved.value.height,
68
+ sourceWidth: resolved.value.sourceWidth,
69
+ sourceHeight: resolved.value.sourceHeight,
70
+ aspectRatio: resolved.value.aspectRatio,
71
+ placeholderSrc: resolved.value.placeholderSrc
72
+ };
73
+ if (resolvedComponent.value === NovuImage) {
74
+ return { ...base, provider: effectiveProvider.value };
75
+ }
76
+ return base;
77
+ });
78
+ const componentBindings = computed(() => ({ ...attrs, ...imageProps.value }));
79
+ </script>
80
+
81
+ <template>
82
+ <component
83
+ :is="resolvedComponent"
84
+ v-if="resolved.src"
85
+ v-bind="componentBindings"
86
+ />
87
+ </template>
@@ -0,0 +1,17 @@
1
+ import type { FocalPoint } from '../utils/focal.js';
2
+ import type { StatamicAsset } from '../types.js';
3
+ export interface NovuStatamicImageProps {
4
+ src?: string | StatamicAsset | null;
5
+ provider?: string;
6
+ alt?: string;
7
+ fallbackAlt?: string;
8
+ locale?: string;
9
+ focal?: FocalPoint;
10
+ width?: number | string;
11
+ height?: number | string;
12
+ aspectRatio?: number;
13
+ placeholderField?: string | string[];
14
+ }
15
+ declare const __VLS_export: import("vue").DefineComponent<NovuStatamicImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NovuStatamicImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
@@ -0,0 +1,42 @@
1
+ import type { MaybeRefOrGetter, Ref } from 'vue';
2
+ import type { FocalPoint } from '../utils/focal.js';
3
+ export interface UseResponsiveImageOptions {
4
+ src: MaybeRefOrGetter<string | undefined | null>;
5
+ width?: MaybeRefOrGetter<number | string | undefined>;
6
+ height?: MaybeRefOrGetter<number | string | undefined>;
7
+ sourceWidth?: MaybeRefOrGetter<number | string | undefined>;
8
+ sourceHeight?: MaybeRefOrGetter<number | string | undefined>;
9
+ aspectRatio?: MaybeRefOrGetter<number | undefined>;
10
+ quality?: MaybeRefOrGetter<number | string | undefined>;
11
+ format?: MaybeRefOrGetter<string | undefined>;
12
+ fit?: MaybeRefOrGetter<string | undefined>;
13
+ modifiers?: MaybeRefOrGetter<Record<string, unknown> | undefined>;
14
+ provider?: MaybeRefOrGetter<string | undefined>;
15
+ focal?: MaybeRefOrGetter<FocalPoint | undefined>;
16
+ sizes?: MaybeRefOrGetter<string | undefined>;
17
+ fallbackWidth: MaybeRefOrGetter<number>;
18
+ usePlaceholder: MaybeRefOrGetter<boolean>;
19
+ placeholderQuality: MaybeRefOrGetter<number>;
20
+ placeholderWidth: MaybeRefOrGetter<number>;
21
+ placeholderSrc?: MaybeRefOrGetter<string | undefined>;
22
+ screens: MaybeRefOrGetter<Record<string, number | string>>;
23
+ imgRef: Readonly<Ref<HTMLImageElement | null>>;
24
+ }
25
+ interface ElementSize {
26
+ width: number;
27
+ height: number;
28
+ }
29
+ export declare function useResponsiveImage(options: UseResponsiveImageOptions): {
30
+ srcset: import("vue").ComputedRef<string | undefined>;
31
+ sizes: import("vue").ComputedRef<string>;
32
+ placeholderSrc: import("vue").ComputedRef<string | undefined>;
33
+ fallbackUrl: import("vue").ComputedRef<string | undefined>;
34
+ elementSize: Ref<{
35
+ width: number;
36
+ height: number;
37
+ } | null, ElementSize | {
38
+ width: number;
39
+ height: number;
40
+ } | null>;
41
+ };
42
+ export {};
@@ -0,0 +1,115 @@
1
+ import { computed, ref, toValue } from "vue";
2
+ import { useResizeObserver } from "@vueuse/core";
3
+ import { useImage } from "#imports";
4
+ import { parseScreens } from "../utils/screens.js";
5
+ import { applyFocal, defaultFocalForProvider } from "../utils/focal.js";
6
+ import { transformProviderModifiers } from "../utils/providerModifiers.js";
7
+ import { toFiniteNumber } from "../utils/numbers.js";
8
+ const PLACEHOLDER_DESCRIPTOR = "32w";
9
+ export function useResponsiveImage(options) {
10
+ const $img = useImage();
11
+ const breakpointWidths = computed(() => parseScreens(toValue(options.screens)));
12
+ const intrinsicAspectRatio = computed(() => {
13
+ return resolveImageAspectRatio(
14
+ toValue(options.aspectRatio),
15
+ toFiniteNumber(toValue(options.width)),
16
+ toFiniteNumber(toValue(options.height))
17
+ );
18
+ });
19
+ const baseModifiers = computed(() => {
20
+ const explicitFocal = toValue(options.focal);
21
+ const provider = toValue(options.provider);
22
+ const focal = explicitFocal ?? defaultFocalForProvider(provider);
23
+ const sourceW = toFiniteNumber(toValue(options.sourceWidth)) ?? toFiniteNumber(toValue(options.width));
24
+ const sourceH = toFiniteNumber(toValue(options.sourceHeight)) ?? toFiniteNumber(toValue(options.height));
25
+ const quality = toValue(options.quality);
26
+ const format = toValue(options.format);
27
+ const fit = toValue(options.fit);
28
+ const extra = toValue(options.modifiers) ?? {};
29
+ const focalModifiers = applyFocal(provider, focal, { width: sourceW, height: sourceH });
30
+ return {
31
+ ...explicitFocal === void 0 ? focalModifiers : {},
32
+ ...extra,
33
+ ...quality !== void 0 ? { quality } : {},
34
+ ...format !== void 0 ? { format } : {},
35
+ ...explicitFocal !== void 0 ? focalModifiers : {},
36
+ ...fit !== void 0 ? { fit } : {}
37
+ };
38
+ });
39
+ const renderUrl = (src, modifiers) => {
40
+ const provider = toValue(options.provider);
41
+ const callOptions = provider ? { provider } : {};
42
+ return $img(src, modifiers, callOptions);
43
+ };
44
+ const candidateModifiers = (width) => {
45
+ const ar = intrinsicAspectRatio.value;
46
+ const base = {
47
+ ...baseModifiers.value,
48
+ width,
49
+ ...ar !== void 0 ? { height: Math.round(width / ar) } : {}
50
+ };
51
+ return transformProviderModifiers(toValue(options.provider), base);
52
+ };
53
+ const placeholderSrc = computed(() => {
54
+ const custom = toValue(options.placeholderSrc);
55
+ if (custom) return custom;
56
+ if (!toValue(options.usePlaceholder)) return void 0;
57
+ const src = toValue(options.src);
58
+ if (!src) return void 0;
59
+ return renderUrl(src, {
60
+ ...candidateModifiers(toValue(options.placeholderWidth)),
61
+ quality: toValue(options.placeholderQuality)
62
+ });
63
+ });
64
+ const srcset = computed(() => {
65
+ const src = toValue(options.src);
66
+ if (!src) return void 0;
67
+ const widths = breakpointWidths.value;
68
+ if (!widths.length) return void 0;
69
+ const entries = widths.map((w) => `${renderUrl(src, candidateModifiers(w))} ${w}w`);
70
+ const placeholder = placeholderSrc.value;
71
+ if (placeholder) entries.push(`${placeholder} ${PLACEHOLDER_DESCRIPTOR}`);
72
+ return entries.join(", ");
73
+ });
74
+ const fallbackUrl = computed(() => {
75
+ const src = toValue(options.src);
76
+ if (!src) return void 0;
77
+ return renderUrl(src, candidateModifiers(toValue(options.fallbackWidth)));
78
+ });
79
+ const elementSize = ref(null);
80
+ useResizeObserver(options.imgRef, ([entry]) => {
81
+ if (!entry) return;
82
+ const { width, height } = entry.contentRect;
83
+ elementSize.value = { width, height };
84
+ });
85
+ const sizes = computed(() => {
86
+ const override = toValue(options.sizes);
87
+ if (override) return override;
88
+ const size = elementSize.value;
89
+ if (!size || size.width <= 0) return "1px";
90
+ const el = options.imgRef.value;
91
+ const objectFit = el ? readObjectFit(el) : "fill";
92
+ const containerAspect = size.height > 0 ? size.width / size.height : 0;
93
+ const imgAspect = intrinsicAspectRatio.value;
94
+ if (objectFit === "cover" && imgAspect !== void 0 && containerAspect > 0 && imgAspect > containerAspect) {
95
+ return `${Math.ceil(size.height * imgAspect)}px`;
96
+ }
97
+ return `${Math.ceil(size.width)}px`;
98
+ });
99
+ return {
100
+ srcset,
101
+ sizes,
102
+ placeholderSrc,
103
+ fallbackUrl,
104
+ elementSize
105
+ };
106
+ }
107
+ function readObjectFit(el) {
108
+ if (typeof window === "undefined") return "fill";
109
+ return window.getComputedStyle(el).objectFit || "fill";
110
+ }
111
+ function resolveImageAspectRatio(explicitRatio, width, height) {
112
+ if (explicitRatio && Number.isFinite(explicitRatio) && explicitRatio > 0) return explicitRatio;
113
+ if (width && height && width > 0 && height > 0) return width / height;
114
+ return void 0;
115
+ }
@@ -0,0 +1,68 @@
1
+ import type { ImageModifiers, ProviderGetImage } from '@nuxt/image';
2
+ export type ImgproxyResizingType = 'fit' | 'fill' | 'fill-down' | 'force' | 'auto';
3
+ export type ImgproxyGravityType = 'ce' | 'no' | 'so' | 'ea' | 'we' | 'noea' | 'nowe' | 'soea' | 'sowe';
4
+ export interface ImgproxyCrop {
5
+ width: number;
6
+ height: number;
7
+ gravity?: ImgproxyGravityType;
8
+ }
9
+ export type ImgproxyFormat = 'webp' | 'png' | 'jpg' | 'jpeg' | 'jxl' | 'avif' | 'gif' | 'ico' | 'svg' | 'heic' | 'bmp' | 'tiff' | 'pdf' | 'psd' | 'mp4';
10
+ export type ImgproxyBooleanPrimitive = string | number | boolean;
11
+ export interface ImgproxyModifiers extends Omit<ImageModifiers, 'fit' | 'format' | 'gravity'> {
12
+ width: number;
13
+ height: number;
14
+ format: ImgproxyFormat;
15
+ fit: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
16
+ resizingType: ImgproxyResizingType;
17
+ resize: string;
18
+ size: string;
19
+ minWidth: number;
20
+ minHeight: number;
21
+ zoom: string | number;
22
+ dpr: number;
23
+ enlarge: boolean;
24
+ extend: boolean;
25
+ extendAspectRatio: string;
26
+ gravity: ImgproxyGravityType | string;
27
+ crop: ImgproxyCrop | string;
28
+ autoRotate: boolean;
29
+ rotate: number;
30
+ background: string;
31
+ blur: number;
32
+ sharpen: number;
33
+ pixelate: number;
34
+ stripMetadata: boolean;
35
+ keepCopyright: boolean;
36
+ stripColorProfile: boolean;
37
+ enforceThumbnail: boolean;
38
+ maxBytes: number;
39
+ raw: boolean;
40
+ cachebuster: string;
41
+ expires: number;
42
+ filename: string;
43
+ returnAttachment: boolean;
44
+ preset: string;
45
+ maxSrcResolution: number;
46
+ maxSrcFileSize: number;
47
+ maxAnimationFrames: number;
48
+ maxAnimationFrameResolution: string;
49
+ maxResultDimension: string;
50
+ }
51
+ interface ImgproxyOptions {
52
+ baseURL: string;
53
+ salt: string;
54
+ key: string;
55
+ modifiers?: Partial<ImgproxyModifiers>;
56
+ }
57
+ interface ImgproxyContext {
58
+ baseURL?: string;
59
+ key?: string;
60
+ salt?: string;
61
+ modifiers?: Partial<ImgproxyModifiers>;
62
+ }
63
+ export declare const getImage: ProviderGetImage<ImgproxyContext>;
64
+ declare const _default: () => {
65
+ getImage: ProviderGetImage<ImgproxyContext>;
66
+ };
67
+ export default _default;
68
+ export type { ImgproxyOptions };