@place-framework/place-block-image 1.0.1 → 1.0.2
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/dist/constants/index.d.ts +2 -2
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +4 -5
- package/dist/constants/index.js.map +1 -1
- package/dist/generate-components.d.ts +16 -0
- package/dist/generate-components.d.ts.map +1 -0
- package/dist/generate-components.js +93 -0
- package/dist/generate-components.js.map +1 -0
- package/dist/react/PlaceBlockImage.cjs +1 -0
- package/dist/react/PlaceBlockImage.js +67 -0
- package/dist/templates/shared/index.d.ts.map +1 -1
- package/dist/templates/shared/index.js +8 -16
- package/dist/templates/shared/index.js.map +1 -1
- package/dist/templates/shared/vue.d.ts +6 -0
- package/dist/templates/shared/vue.d.ts.map +1 -0
- package/dist/templates/shared/vue.js +26 -0
- package/dist/templates/shared/vue.js.map +1 -0
- package/dist/templates/vue.d.ts.map +1 -1
- package/dist/templates/vue.js +14 -19
- package/dist/templates/vue.js.map +1 -1
- package/dist/utils/index.d.ts +61 -14
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +108 -40
- package/dist/utils/index.js.map +1 -1
- package/dist/vue/PlaceBlockImage.cjs +1 -0
- package/dist/vue/PlaceBlockImage.js +83 -0
- package/dist/webpack-plugin.d.ts +20 -7
- package/dist/webpack-plugin.d.ts.map +1 -1
- package/dist/webpack-plugin.js +22 -28
- package/dist/webpack-plugin.js.map +1 -1
- package/package.json +36 -10
- package/src/constants/index.ts +5 -6
- package/src/react/PlaceBlockImage.tsx +63 -0
- package/src/react/index.ts +1 -0
- package/src/utils/index.ts +121 -44
- package/src/vue/PlaceBlockImage.vue +98 -0
- package/src/vue/index.ts +1 -0
- package/src/webpack-plugin.ts +45 -40
- package/tsconfig.json +8 -3
- package/vite.config.mts +27 -0
- package/vite.react.config.mts +25 -0
- package/vite.vue.config.mts +26 -0
- package/src/templates/react-jsx.ts +0 -27
- package/src/templates/react-tsx.ts +0 -33
- package/src/templates/shared/index.ts +0 -47
- package/src/templates/shared/react.ts +0 -51
- package/src/templates/vue.ts +0 -98
- package/src/templates.ts +0 -29
package/dist/utils/index.js
CHANGED
|
@@ -1,49 +1,117 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Shared
|
|
2
|
+
// Shared utilities
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.cleanImagePath = void 0;
|
|
5
5
|
exports.generateImageClassName = generateImageClassName;
|
|
6
|
-
exports.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
exports.resolveAssetPath = resolveAssetPath;
|
|
7
|
+
exports.getImageClass = getImageClass;
|
|
8
|
+
exports.getWrapperClass = getWrapperClass;
|
|
9
|
+
exports.getLazyClass = getLazyClass;
|
|
10
|
+
exports.createLazyObserver = createLazyObserver;
|
|
11
|
+
const index_1 = require("../constants/index");
|
|
12
|
+
/**
|
|
13
|
+
* Converts any image URL or path into a CSS-safe kebab-case string.
|
|
14
|
+
* Used at build time by generateImageClassName() and at runtime by
|
|
15
|
+
* the Vue/React components to derive the CSS class from the src prop.
|
|
16
|
+
*/
|
|
17
|
+
const cleanImagePath = (src) => src
|
|
18
|
+
.replace(/^https?:\/\/[^/]+/, '') // Strip protocol + domain
|
|
19
|
+
.replace(/^[/\\]+/, '') // Strip leading slashes
|
|
20
|
+
.replace(/\.[^/.]+$/, '') // Remove file extension
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[^a-z0-9/-]/g, '-') // Special chars → hyphens (keep / and -)
|
|
23
|
+
.replace(/\//g, '-') // Path separators → hyphens
|
|
24
|
+
.replace(/-+/g, '-') // Collapse duplicate hyphens
|
|
25
|
+
.replace(/^-|-$/g, ''); // Trim leading/trailing hyphens
|
|
26
|
+
exports.cleanImagePath = cleanImagePath;
|
|
27
|
+
/**
|
|
28
|
+
* Generate CSS class name from a file path — path-agnostic, works with any URL format.
|
|
29
|
+
* Matches the runtime getImageClassName logic emitted by getSharedLogic().
|
|
30
|
+
*
|
|
31
|
+
* @param filePath - Relative path from imageDir (e.g. "story/accent-orchid.png")
|
|
32
|
+
* @param imagePrefix - The prefix to add to the class name (e.g. "image-")
|
|
33
|
+
* @param outputPrefix - Optional output path prefix prepended before filePath to mirror
|
|
34
|
+
* the served URL (e.g. "images/" when assetModuleFilename outputs
|
|
35
|
+
* to "images/…" so the browser requests "/images/story/…")
|
|
36
|
+
* @returns The generated CSS class name (e.g. "image-images-story-accent-orchid")
|
|
37
|
+
*/
|
|
38
|
+
function generateImageClassName(filePath, imagePrefix, outputPrefix = '') {
|
|
39
|
+
const fullPath = outputPrefix
|
|
40
|
+
? `${outputPrefix.replace(/\/$/, '')}/${filePath}`
|
|
41
|
+
: filePath;
|
|
42
|
+
return `${imagePrefix}${(0, exports.cleanImagePath)(fullPath)}`;
|
|
13
43
|
}
|
|
14
44
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @
|
|
45
|
+
* Strips the Vite/webpack plugin's injected asset-path prefix from a src string
|
|
46
|
+
* so the remaining path matches what the plugin used when generating CSS classes.
|
|
47
|
+
*
|
|
48
|
+
* @param src - The raw src value (may include the asset path prefix)
|
|
49
|
+
* @param assetPath - The value of __PLUGIN_ASSET_PATH__ (empty string if undefined)
|
|
19
50
|
*/
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.toLowerCase()
|
|
25
|
-
.replace(/[^a-z0-9-]/g, '-') // Convert special chars to hyphens
|
|
26
|
-
.replace(/-+/g, '-') // Remove duplicate hyphens
|
|
27
|
-
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
|
|
28
|
-
return `${imagePrefix}${cleanName}`;
|
|
51
|
+
function resolveAssetPath(src, assetPath) {
|
|
52
|
+
if (!assetPath)
|
|
53
|
+
return src;
|
|
54
|
+
return src.replace(new RegExp(`^${assetPath.replace(/\//g, '\\/')}\\/?`), '');
|
|
29
55
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Derives the per-image CSS class from a src URL, stripping the asset-path
|
|
58
|
+
* prefix first so the class matches what the plugin generated at build time.
|
|
59
|
+
*
|
|
60
|
+
* @param src - Raw src prop value
|
|
61
|
+
* @param imagePrefix - e.g. "image-"
|
|
62
|
+
* @param assetPath - Value of __PLUGIN_ASSET_PATH__ (pass '' if not defined)
|
|
63
|
+
*/
|
|
64
|
+
function getImageClass(src, imagePrefix, assetPath) {
|
|
65
|
+
if (!src)
|
|
66
|
+
return '';
|
|
67
|
+
return `${imagePrefix}${(0, exports.cleanImagePath)(resolveAssetPath(src, assetPath))}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Builds the full className string for the <picture> wrapper element.
|
|
71
|
+
*
|
|
72
|
+
* @param src - Raw src prop value
|
|
73
|
+
* @param imagePrefix - e.g. "image-"
|
|
74
|
+
* @param assetPath - Value of __PLUGIN_ASSET_PATH__ (pass '' if not defined)
|
|
75
|
+
* @param extraClass - Any additional class(es) passed by the consumer (e.g. className prop)
|
|
76
|
+
*/
|
|
77
|
+
function getWrapperClass(src, imagePrefix, assetPath, extraClass = '') {
|
|
78
|
+
const parts = [
|
|
79
|
+
`${imagePrefix}${index_1.CLASS_NAMES.WRAPPER_SUFFIX}`,
|
|
80
|
+
getImageClass(src, imagePrefix, assetPath),
|
|
81
|
+
extraClass,
|
|
82
|
+
].filter(Boolean);
|
|
83
|
+
return parts.join(' ');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns the CSS class string for the <img> element based on lazy-load state.
|
|
87
|
+
*
|
|
88
|
+
* @param lazy - Whether lazy loading is enabled
|
|
89
|
+
* @param isLoaded - Whether the image has been loaded (intersected)
|
|
90
|
+
*/
|
|
91
|
+
function getLazyClass(lazy, isLoaded) {
|
|
92
|
+
if (!lazy)
|
|
93
|
+
return '';
|
|
94
|
+
return isLoaded ? `${index_1.CLASS_NAMES.LAZY} ${index_1.CLASS_NAMES.LOADED}` : index_1.CLASS_NAMES.LAZY;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Creates an IntersectionObserver that fires `onIntersect` once when the given
|
|
98
|
+
* element enters the viewport, then automatically stops observing.
|
|
99
|
+
*
|
|
100
|
+
* @param element - The DOM element to observe
|
|
101
|
+
* @param onIntersect - Callback invoked when the element intersects
|
|
102
|
+
* @param threshold - Intersection threshold (default 0.1)
|
|
103
|
+
* @returns The created IntersectionObserver (call .disconnect() to clean up early)
|
|
104
|
+
*/
|
|
105
|
+
function createLazyObserver(element, onIntersect, threshold = 0.1) {
|
|
106
|
+
const observer = new IntersectionObserver((entries) => {
|
|
107
|
+
entries.forEach((entry) => {
|
|
108
|
+
if (entry.isIntersecting) {
|
|
109
|
+
onIntersect();
|
|
110
|
+
observer.unobserve(entry.target);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}, { threshold });
|
|
114
|
+
observer.observe(element);
|
|
115
|
+
return observer;
|
|
48
116
|
}
|
|
49
117
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=require("vue"),d="image-",i={LAZY:"lazy",LOADED:"loaded",WRAPPER_SUFFIX:"wrapper"},A=r=>r.replace(/^https?:\/\/[^/]+/,"").replace(/^[/\\]+/,"").replace(/\.[^/.]+$/,"").toLowerCase().replace(/[^a-z0-9/-]/g,"-").replace(/\//g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");function y(r,a){return a?r.replace(new RegExp(`^${a.replace(/\//g,"\\/")}\\/?`),""):r}function L(r,a,t){return r?`${a}${A(y(r,t))}`:""}function P(r,a,t,s=""){return[`${a}${i.WRAPPER_SUFFIX}`,L(r,a,t),s].filter(Boolean).join(" ")}function E(r,a){return r?a?`${i.LAZY} ${i.LOADED}`:i.LAZY:""}function S(r,a,t=.1){const s=new IntersectionObserver(l=>{l.forEach(n=>{n.isIntersecting&&(a(),s.unobserve(n.target))})},{threshold:t});return s.observe(r),s}const z=["src","alt"],I=e.defineComponent({inheritAttrs:!1,__name:"PlaceBlockImage",props:{src:{type:String,required:!0},alt:{type:String,required:!0},imagePrefix:{type:String,default:()=>d},lazy:{type:Boolean,default:!1}},setup(r){const a=e.useAttrs(),t=r,s=e.computed(()=>{const{class:o,...g}=a;return g}),l=e.ref(null),n=e.ref(t.lazy?"":t.src),c=e.ref(!t.lazy);let u=null;const m=typeof __PLUGIN_ASSET_PATH__<"u"?__PLUGIN_ASSET_PATH__:"",_=e.computed(()=>P(t.src,t.imagePrefix,m)),v=e.computed(()=>E(t.lazy,c.value)),f=()=>{!t.lazy||c.value||!l.value||(u=S(l.value,()=>{n.value=t.src,c.value=!0}))},p=()=>{u&&(u.disconnect(),u=null)};return e.onMounted(()=>{f()}),e.onUnmounted(()=>{p()}),e.watch(()=>t.src,o=>{t.lazy?c.value||(p(),f()):n.value=o}),e.watch(c,o=>{o&&(n.value=t.src,p())}),(o,g)=>(e.openBlock(),e.createElementBlock("picture",{class:e.normalizeClass([_.value,e.unref(a).class])},[e.createElementVNode("img",e.mergeProps({ref_key:"imgRef",ref:l,src:n.value,alt:r.alt,class:v.value},s.value),null,16,z)],2))}});module.exports=I;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { defineComponent as y, useAttrs as L, computed as p, ref as f, onMounted as P, onUnmounted as E, watch as _, openBlock as S, createElementBlock as z, normalizeClass as I, unref as C, createElementVNode as $, mergeProps as h } from "vue";
|
|
2
|
+
const R = "image-", u = {
|
|
3
|
+
// Lazy loading states
|
|
4
|
+
LAZY: "lazy",
|
|
5
|
+
LOADED: "loaded",
|
|
6
|
+
// Suffix appended to imagePrefix to form the wrapper class (e.g. 'image-wrapper')
|
|
7
|
+
WRAPPER_SUFFIX: "wrapper"
|
|
8
|
+
}, b = (t) => t.replace(/^https?:\/\/[^/]+/, "").replace(/^[/\\]+/, "").replace(/\.[^/.]+$/, "").toLowerCase().replace(/[^a-z0-9/-]/g, "-").replace(/\//g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
9
|
+
function w(t, r) {
|
|
10
|
+
return r ? t.replace(new RegExp(`^${r.replace(/\//g, "\\/")}\\/?`), "") : t;
|
|
11
|
+
}
|
|
12
|
+
function N(t, r, e) {
|
|
13
|
+
return t ? `${r}${b(w(t, e))}` : "";
|
|
14
|
+
}
|
|
15
|
+
function B(t, r, e, a = "") {
|
|
16
|
+
return [
|
|
17
|
+
`${r}${u.WRAPPER_SUFFIX}`,
|
|
18
|
+
N(t, r, e),
|
|
19
|
+
a
|
|
20
|
+
].filter(Boolean).join(" ");
|
|
21
|
+
}
|
|
22
|
+
function F(t, r) {
|
|
23
|
+
return t ? r ? `${u.LAZY} ${u.LOADED}` : u.LAZY : "";
|
|
24
|
+
}
|
|
25
|
+
function O(t, r, e = 0.1) {
|
|
26
|
+
const a = new IntersectionObserver(
|
|
27
|
+
(s) => {
|
|
28
|
+
s.forEach((n) => {
|
|
29
|
+
n.isIntersecting && (r(), a.unobserve(n.target));
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
{ threshold: e }
|
|
33
|
+
);
|
|
34
|
+
return a.observe(t), a;
|
|
35
|
+
}
|
|
36
|
+
const U = ["src", "alt"], x = /* @__PURE__ */ y({
|
|
37
|
+
inheritAttrs: !1,
|
|
38
|
+
__name: "PlaceBlockImage",
|
|
39
|
+
props: {
|
|
40
|
+
src: { type: String, required: !0 },
|
|
41
|
+
alt: { type: String, required: !0 },
|
|
42
|
+
imagePrefix: { type: String, default: () => R },
|
|
43
|
+
lazy: { type: Boolean, default: !1 }
|
|
44
|
+
},
|
|
45
|
+
setup(t) {
|
|
46
|
+
const r = L(), e = t, a = p(() => {
|
|
47
|
+
const { class: c, ...m } = r;
|
|
48
|
+
return m;
|
|
49
|
+
}), s = f(null), n = f(e.lazy ? "" : e.src), l = f(!e.lazy);
|
|
50
|
+
let o = null;
|
|
51
|
+
const v = typeof __PLUGIN_ASSET_PATH__ < "u" ? __PLUGIN_ASSET_PATH__ : "", d = p(
|
|
52
|
+
() => B(e.src, e.imagePrefix, v)
|
|
53
|
+
), A = p(() => F(e.lazy, l.value)), g = () => {
|
|
54
|
+
!e.lazy || l.value || !s.value || (o = O(s.value, () => {
|
|
55
|
+
n.value = e.src, l.value = !0;
|
|
56
|
+
}));
|
|
57
|
+
}, i = () => {
|
|
58
|
+
o && (o.disconnect(), o = null);
|
|
59
|
+
};
|
|
60
|
+
return P(() => {
|
|
61
|
+
g();
|
|
62
|
+
}), E(() => {
|
|
63
|
+
i();
|
|
64
|
+
}), _(() => e.src, (c) => {
|
|
65
|
+
e.lazy ? l.value || (i(), g()) : n.value = c;
|
|
66
|
+
}), _(l, (c) => {
|
|
67
|
+
c && (n.value = e.src, i());
|
|
68
|
+
}), (c, m) => (S(), z("picture", {
|
|
69
|
+
class: I([d.value, C(r).class])
|
|
70
|
+
}, [
|
|
71
|
+
$("img", h({
|
|
72
|
+
ref_key: "imgRef",
|
|
73
|
+
ref: s,
|
|
74
|
+
src: n.value,
|
|
75
|
+
alt: t.alt,
|
|
76
|
+
class: A.value
|
|
77
|
+
}, a.value), null, 16, U)
|
|
78
|
+
], 2));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
export {
|
|
82
|
+
x as default
|
|
83
|
+
};
|
package/dist/webpack-plugin.d.ts
CHANGED
|
@@ -3,9 +3,26 @@ export interface PlaceBlockImagePluginOptions {
|
|
|
3
3
|
imagePrefix?: string;
|
|
4
4
|
imageDir: string;
|
|
5
5
|
scssPath: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The URL path at which images are served (e.g. '/images').
|
|
8
|
+
* Used by the webpack plugin to inject a __PLACE_ASSET_PATH__ constant
|
|
9
|
+
* that the React/Vue components use to strip the prefix from src before
|
|
10
|
+
* generating the CSS class name — ensuring it matches what the plugin
|
|
11
|
+
* generates from the file path relative to imageDir.
|
|
12
|
+
*
|
|
13
|
+
* Defaults to the basename of imageDir prefixed with '/' (e.g. '/images').
|
|
14
|
+
*/
|
|
15
|
+
assetPath?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Output path prefix prepended to the relative image path when generating
|
|
18
|
+
* CSS class names — must match the prefix used in assetModuleFilename so
|
|
19
|
+
* the class name the plugin writes into the SCSS matches what the component
|
|
20
|
+
* derives from the served URL at runtime.
|
|
21
|
+
*
|
|
22
|
+
* e.g. if assetModuleFilename outputs "images/story/foo.png" (served as
|
|
23
|
+
* "/images/story/foo.png"), set outputPathPrefix: 'images'
|
|
24
|
+
*/
|
|
25
|
+
outputPathPrefix?: string;
|
|
9
26
|
}
|
|
10
27
|
export interface ImageDimensions {
|
|
11
28
|
width: number;
|
|
@@ -34,10 +51,6 @@ export declare class PlaceBlockImagePlugin {
|
|
|
34
51
|
* Write SCSS file
|
|
35
52
|
*/
|
|
36
53
|
private writeScssFile;
|
|
37
|
-
/**
|
|
38
|
-
* Generate and write component file
|
|
39
|
-
*/
|
|
40
|
-
private writeComponentFile;
|
|
41
54
|
/**
|
|
42
55
|
* Check if images have changed since last generation
|
|
43
56
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webpack-plugin.d.ts","sourceRoot":"","sources":["../src/webpack-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"webpack-plugin.d.ts","sourceRoot":"","sources":["../src/webpack-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAGjD,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAyD;IACxE,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,kBAAkB,CAAa;gBAE3B,OAAO,EAAE,4BAA4B;IASjD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;OAEG;YACW,UAAU;IA8BxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmCpB;;OAEG;YACW,aAAa;IAY3B;;OAEG;YACW,gBAAgB;IAyB9B,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;YA2CjB,mBAAmB;CA6ClC;AAED,eAAe,qBAAqB,CAAC"}
|
package/dist/webpack-plugin.js
CHANGED
|
@@ -41,7 +41,7 @@ const fs = __importStar(require("fs"));
|
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const glob_1 = require("glob");
|
|
43
43
|
const image_size_1 = __importDefault(require("image-size"));
|
|
44
|
-
const
|
|
44
|
+
const webpack_1 = require("webpack");
|
|
45
45
|
const utils_1 = require("./utils");
|
|
46
46
|
class PlaceBlockImagePlugin {
|
|
47
47
|
constructor(options) {
|
|
@@ -49,8 +49,8 @@ class PlaceBlockImagePlugin {
|
|
|
49
49
|
this.lastGenerationTime = 0;
|
|
50
50
|
this.options = {
|
|
51
51
|
imagePrefix: 'image-',
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
outputPathPrefix: '',
|
|
53
|
+
assetPath: `/${path.basename(options.imageDir)}`,
|
|
54
54
|
...options
|
|
55
55
|
};
|
|
56
56
|
}
|
|
@@ -58,7 +58,12 @@ class PlaceBlockImagePlugin {
|
|
|
58
58
|
* Generate CSS class name from filename - uses shared logic
|
|
59
59
|
*/
|
|
60
60
|
generateClassName(filename) {
|
|
61
|
-
|
|
61
|
+
// When outputPathPrefix is set the asset output is flat (just basename),
|
|
62
|
+
// so use only the basename to mirror the served URL: /assets/accent-orchid.png
|
|
63
|
+
const name = this.options.outputPathPrefix
|
|
64
|
+
? path.basename(filename)
|
|
65
|
+
: filename;
|
|
66
|
+
return (0, utils_1.generateImageClassName)(name, this.options.imagePrefix, this.options.outputPathPrefix);
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
69
|
* Scan directory for images and get their dimensions
|
|
@@ -134,29 +139,6 @@ class PlaceBlockImagePlugin {
|
|
|
134
139
|
}
|
|
135
140
|
fs.writeFileSync(this.options.scssPath, scssContent);
|
|
136
141
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Generate and write component file
|
|
139
|
-
*/
|
|
140
|
-
async writeComponentFile() {
|
|
141
|
-
if (!this.options.generateComponent || !this.options.componentPath || !this.options.componentType) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const componentFileName = `PlaceBlockImage.${this.options.componentType}`;
|
|
145
|
-
const componentFilePath = path.resolve(this.options.componentPath, componentFileName);
|
|
146
|
-
// Check if component already exists
|
|
147
|
-
if (fs.existsSync(componentFilePath)) {
|
|
148
|
-
console.log(`📦 Component already exists, skipping: ${componentFilePath}`);
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
const componentContent = (0, templates_1.getTemplate)(this.options.componentType, this.options.imagePrefix);
|
|
152
|
-
const outputDir = path.dirname(componentFilePath);
|
|
153
|
-
// Ensure output directory exists
|
|
154
|
-
if (!fs.existsSync(outputDir)) {
|
|
155
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
156
|
-
}
|
|
157
|
-
fs.writeFileSync(componentFilePath, componentContent);
|
|
158
|
-
console.log(`📦 Generated component: ${componentFilePath}`);
|
|
159
|
-
}
|
|
160
142
|
/**
|
|
161
143
|
* Check if images have changed since last generation
|
|
162
144
|
*/
|
|
@@ -182,6 +164,19 @@ class PlaceBlockImagePlugin {
|
|
|
182
164
|
}
|
|
183
165
|
}
|
|
184
166
|
apply(compiler) {
|
|
167
|
+
// Inject @place-block-image alias so the Vue/React source components can
|
|
168
|
+
// resolve their shared utils/constants imports without requiring the
|
|
169
|
+
// consuming app to configure anything manually.
|
|
170
|
+
const pkgSrc = path.resolve(__dirname, '../src');
|
|
171
|
+
compiler.options.resolve.alias = {
|
|
172
|
+
...(compiler.options.resolve.alias || {}),
|
|
173
|
+
'@place-block-image': pkgSrc,
|
|
174
|
+
};
|
|
175
|
+
// Inject __PLUGIN_ASSET_PATH__ so the React/Vue components can strip the
|
|
176
|
+
// served URL prefix from src before generating the CSS class name.
|
|
177
|
+
new webpack_1.DefinePlugin({
|
|
178
|
+
__PLUGIN_ASSET_PATH__: JSON.stringify(this.options.assetPath),
|
|
179
|
+
}).apply(compiler);
|
|
185
180
|
// Use environment hook to run only once at startup
|
|
186
181
|
compiler.hooks.environment.tap('PlaceBlockImagePlugin', () => {
|
|
187
182
|
this.generateImageStyles();
|
|
@@ -226,7 +221,6 @@ class PlaceBlockImagePlugin {
|
|
|
226
221
|
return;
|
|
227
222
|
}
|
|
228
223
|
await this.writeScssFile(images);
|
|
229
|
-
await this.writeComponentFile();
|
|
230
224
|
console.log(`✅ Generated CSS custom properties for ${images.length} images`);
|
|
231
225
|
console.log(`📝 Output: ${this.options.scssPath}`);
|
|
232
226
|
// Log some examples
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webpack-plugin.js","sourceRoot":"","sources":["../src/webpack-plugin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAC7B,+BAA4B;AAC5B,4DAAgC;
|
|
1
|
+
{"version":3,"file":"webpack-plugin.js","sourceRoot":"","sources":["../src/webpack-plugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@place-framework/place-block-image",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A utility package for generating CSS custom properties from image dimensions to prevent layout shift",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./utils": {
|
|
13
|
+
"require": "./dist/utils/index.js",
|
|
14
|
+
"types": "./dist/utils/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./constants": {
|
|
17
|
+
"require": "./dist/constants/index.js",
|
|
18
|
+
"types": "./dist/constants/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./vue": {
|
|
21
|
+
"import": "./dist/vue/PlaceBlockImage.js",
|
|
22
|
+
"require": "./dist/vue/PlaceBlockImage.cjs",
|
|
23
|
+
"types": "./dist/vue/PlaceBlockImage.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./react": {
|
|
26
|
+
"import": "./dist/react/PlaceBlockImage.js",
|
|
27
|
+
"require": "./dist/react/PlaceBlockImage.cjs",
|
|
28
|
+
"types": "./dist/react/PlaceBlockImage.d.ts"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
7
31
|
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
32
|
+
"build": "tsc && vite build",
|
|
9
33
|
"dev": "tsc --watch",
|
|
10
|
-
"generate": "node dist/generate.js",
|
|
11
34
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
35
|
},
|
|
13
36
|
"keywords": [
|
|
@@ -22,18 +45,21 @@
|
|
|
22
45
|
"author": "Brian Kelley",
|
|
23
46
|
"license": "MIT",
|
|
24
47
|
"devDependencies": {
|
|
25
|
-
"@types/node": "^20.0.0",
|
|
26
48
|
"@types/glob": "^8.1.0",
|
|
27
|
-
"
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"@types/react": "^18.0.0",
|
|
51
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
52
|
+
"typescript": "^5.0.0",
|
|
53
|
+
"vite": "^5.4.21"
|
|
28
54
|
},
|
|
29
55
|
"dependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
56
|
+
"glob": "^10.0.0",
|
|
57
|
+
"image-size": "^1.0.2"
|
|
32
58
|
},
|
|
33
59
|
"peerDependencies": {
|
|
34
|
-
"webpack": ">=5.0.0",
|
|
35
60
|
"react": ">=16.8.0",
|
|
36
|
-
"vue": ">=3.0.0"
|
|
61
|
+
"vue": ">=3.0.0",
|
|
62
|
+
"webpack": ">=5.0.0"
|
|
37
63
|
},
|
|
38
64
|
"peerDependenciesMeta": {
|
|
39
65
|
"react": {
|
|
@@ -46,4 +72,4 @@
|
|
|
46
72
|
"optional": false
|
|
47
73
|
}
|
|
48
74
|
}
|
|
49
|
-
}
|
|
75
|
+
}
|
package/src/constants/index.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
export const IMAGE_PREFIX = 'image-';
|
|
2
|
+
|
|
1
3
|
export const CLASS_NAMES = {
|
|
2
4
|
// Lazy loading states
|
|
3
5
|
LAZY: 'lazy',
|
|
4
6
|
LOADED: 'loaded',
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Base image class
|
|
10
|
-
IMAGE_BLOCK: 'image-block'
|
|
7
|
+
|
|
8
|
+
// Suffix appended to imagePrefix to form the wrapper class (e.g. 'image-wrapper')
|
|
9
|
+
WRAPPER_SUFFIX: 'wrapper',
|
|
11
10
|
} as const;
|
|
12
11
|
|
|
13
12
|
export const getWrapperClassName = (imagePrefix: string) => `${imagePrefix}wrapper`;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
declare const __PLUGIN_ASSET_PATH__: string;
|
|
2
|
+
|
|
3
|
+
import React, { useRef, useEffect, useState } from 'react';
|
|
4
|
+
import { getWrapperClass, getLazyClass, createLazyObserver } from '../utils/index';
|
|
5
|
+
import { IMAGE_PREFIX } from '../constants/index';
|
|
6
|
+
|
|
7
|
+
interface PlaceBlockImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
|
|
8
|
+
src: string;
|
|
9
|
+
alt: string;
|
|
10
|
+
imagePrefix?: string;
|
|
11
|
+
lazy?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* PlaceBlockImage — prevents layout shift using CSS custom properties.
|
|
16
|
+
* Import: import PlaceBlockImage from '@place-framework/place-block-image/react'
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* <PlaceBlockImage src="/assets/logo.png" alt="Logo" />
|
|
20
|
+
* <PlaceBlockImage src="/assets/hero.jpg" alt="Hero" lazy={true} />
|
|
21
|
+
*/
|
|
22
|
+
export const PlaceBlockImage: React.FC<PlaceBlockImageProps> = ({
|
|
23
|
+
src,
|
|
24
|
+
alt,
|
|
25
|
+
imagePrefix = IMAGE_PREFIX,
|
|
26
|
+
lazy = false,
|
|
27
|
+
className = '',
|
|
28
|
+
...props
|
|
29
|
+
}) => {
|
|
30
|
+
const imgRef = useRef<HTMLImageElement>(null);
|
|
31
|
+
const [imageSrc, setImageSrc] = useState(lazy ? '' : src);
|
|
32
|
+
const [isLoaded, setIsLoaded] = useState(!lazy);
|
|
33
|
+
|
|
34
|
+
const assetPath: string = typeof __PLUGIN_ASSET_PATH__ !== 'undefined' ? __PLUGIN_ASSET_PATH__ : '';
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!lazy || isLoaded || !imgRef.current) return;
|
|
38
|
+
|
|
39
|
+
const observer = createLazyObserver(imgRef.current, () => {
|
|
40
|
+
setImageSrc(src);
|
|
41
|
+
setIsLoaded(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return () => observer.disconnect();
|
|
45
|
+
}, [src, lazy, isLoaded]);
|
|
46
|
+
|
|
47
|
+
const wrapperClassName = getWrapperClass(src, imagePrefix, assetPath, className);
|
|
48
|
+
const imgClassName = getLazyClass(lazy, isLoaded);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<picture className={wrapperClassName}>
|
|
52
|
+
<img
|
|
53
|
+
ref={imgRef}
|
|
54
|
+
src={imageSrc}
|
|
55
|
+
alt={alt}
|
|
56
|
+
className={imgClassName}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
</picture>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default PlaceBlockImage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PlaceBlockImage, default } from './PlaceBlockImage';
|