@place-framework/place-block-image 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.
Files changed (53) hide show
  1. package/README.md +117 -0
  2. package/dist/constants/index.d.ts +9 -0
  3. package/dist/constants/index.d.ts.map +1 -0
  4. package/dist/constants/index.js +17 -0
  5. package/dist/constants/index.js.map +1 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +7 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/templates/react-jsx.d.ts +2 -0
  11. package/dist/templates/react-jsx.d.ts.map +1 -0
  12. package/dist/templates/react-jsx.js +29 -0
  13. package/dist/templates/react-jsx.js.map +1 -0
  14. package/dist/templates/react-tsx.d.ts +2 -0
  15. package/dist/templates/react-tsx.d.ts.map +1 -0
  16. package/dist/templates/react-tsx.js +35 -0
  17. package/dist/templates/react-tsx.js.map +1 -0
  18. package/dist/templates/shared/index.d.ts +6 -0
  19. package/dist/templates/shared/index.d.ts.map +1 -0
  20. package/dist/templates/shared/index.js +49 -0
  21. package/dist/templates/shared/index.js.map +1 -0
  22. package/dist/templates/shared/react.d.ts +10 -0
  23. package/dist/templates/shared/react.d.ts.map +1 -0
  24. package/dist/templates/shared/react.js +48 -0
  25. package/dist/templates/shared/react.js.map +1 -0
  26. package/dist/templates/vue.d.ts +2 -0
  27. package/dist/templates/vue.d.ts.map +1 -0
  28. package/dist/templates/vue.js +100 -0
  29. package/dist/templates/vue.js.map +1 -0
  30. package/dist/templates.d.ts +5 -0
  31. package/dist/templates.d.ts.map +1 -0
  32. package/dist/templates.js +32 -0
  33. package/dist/templates.js.map +1 -0
  34. package/dist/utils/index.d.ts +8 -0
  35. package/dist/utils/index.d.ts.map +1 -0
  36. package/dist/utils/index.js +32 -0
  37. package/dist/utils/index.js.map +1 -0
  38. package/dist/webpack-plugin.d.ts +49 -0
  39. package/dist/webpack-plugin.d.ts.map +1 -0
  40. package/dist/webpack-plugin.js +259 -0
  41. package/dist/webpack-plugin.js.map +1 -0
  42. package/package.json +49 -0
  43. package/src/constants/index.ts +14 -0
  44. package/src/index.ts +4 -0
  45. package/src/templates/react-jsx.ts +27 -0
  46. package/src/templates/react-tsx.ts +33 -0
  47. package/src/templates/shared/index.ts +47 -0
  48. package/src/templates/shared/react.ts +51 -0
  49. package/src/templates/vue.ts +98 -0
  50. package/src/templates.ts +29 -0
  51. package/src/utils/index.ts +35 -0
  52. package/src/webpack-plugin.ts +273 -0
  53. package/tsconfig.json +20 -0
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # @place-framework/place-block-image
2
+
3
+ A webpack plugin that generates CSS custom properties from image dimensions to prevent layout shift and automatically creates components for React and Vue.
4
+
5
+ ## Overview
6
+
7
+ This package provides a webpack plugin that:
8
+
9
+ - Scans your project for images
10
+ - Extracts image dimensions automatically
11
+ - Generates CSS custom properties (CSS variables) for width, height, and aspect ratio
12
+ - Creates optimized components for React and Vue frameworks
13
+ - Prevents cumulative layout shift (CLS) by providing image dimensions upfront
14
+
15
+ ## Features
16
+
17
+ - **Automatic Image Processing**: Automatically detects and processes images in your project
18
+ - **CSS Custom Properties**: Generates CSS variables for image dimensions
19
+ - **Framework Components**: Creates ready-to-use components for React (JSX/TSX) and Vue
20
+ - **Layout Shift Prevention**: Helps maintain stable layouts by providing image dimensions
21
+ - **TypeScript Support**: Full TypeScript support with type definitions
22
+ - **Webpack Integration**: Seamless integration with your webpack build process
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @place-framework/place-block-image
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### Webpack Configuration
33
+
34
+ Add the plugin to your webpack configuration:
35
+
36
+ ```javascript
37
+ const PlaceBlockImagePlugin = require('@place-framework/place-block-image');
38
+
39
+ module.exports = {
40
+ // ... your webpack config
41
+ plugins: [
42
+ new PlaceBlockImagePlugin({
43
+ // Plugin options
44
+ })
45
+ ]
46
+ };
47
+ ```
48
+
49
+ ### Generated CSS Variables
50
+
51
+ The plugin generates CSS custom properties like:
52
+
53
+ ```css
54
+ :root {
55
+ --image-example-width: 800px;
56
+ --image-example-height: 600px;
57
+ --image-example-aspect-ratio: 1.333;
58
+ }
59
+ ```
60
+
61
+ ### Generated Components
62
+
63
+ #### React (JSX/TSX)
64
+ ```jsx
65
+ import { ImageExample } from './generated/images';
66
+
67
+ function MyComponent() {
68
+ return <ImageExample alt="Example image" />;
69
+ }
70
+ ```
71
+
72
+ #### Vue
73
+ ```vue
74
+ <template>
75
+ <ImageExample alt="Example image" />
76
+ </template>
77
+
78
+ <script>
79
+ import { ImageExample } from './generated/images';
80
+
81
+ export default {
82
+ components: {
83
+ ImageExample
84
+ }
85
+ };
86
+ </script>
87
+ ```
88
+
89
+ ## Benefits
90
+
91
+ - **Performance**: Prevents layout shift by providing image dimensions upfront
92
+ - **Developer Experience**: Automatically generates components, reducing boilerplate
93
+ - **Maintainability**: Centralized image dimension management
94
+ - **SEO**: Better Core Web Vitals scores through CLS prevention
95
+
96
+ ## Configuration Options
97
+
98
+ The plugin accepts various configuration options to customize its behavior:
99
+
100
+ - Image source directories
101
+ - Output paths for generated files
102
+ - Component template customization
103
+ - CSS variable naming conventions
104
+
105
+ ## Requirements
106
+
107
+ - **Webpack**: >= 5.0.0
108
+ - **React**: >= 16.8.0 (optional, for React components)
109
+ - **Vue**: >= 3.0.0 (optional, for Vue components)
110
+
111
+ ## License
112
+
113
+ MIT
114
+
115
+ ## Author
116
+
117
+ Brian Kelley
@@ -0,0 +1,9 @@
1
+ export declare const CLASS_NAMES: {
2
+ readonly LAZY: "lazy";
3
+ readonly LOADED: "loaded";
4
+ readonly IMAGE_WRAPPER: "image-wrapper";
5
+ readonly IMAGE_BLOCK: "image-block";
6
+ };
7
+ export declare const getWrapperClassName: (imagePrefix: string) => string;
8
+ export declare const getImageClassName: (imagePrefix: string, filename: string) => string;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW;;;;;CAUd,CAAC;AAEX,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,WAA4B,CAAC;AACpF,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,EAAE,UAAU,MAAM,WAAgC,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getImageClassName = exports.getWrapperClassName = exports.CLASS_NAMES = void 0;
4
+ exports.CLASS_NAMES = {
5
+ // Lazy loading states
6
+ LAZY: 'lazy',
7
+ LOADED: 'loaded',
8
+ // Wrapper classes
9
+ IMAGE_WRAPPER: 'image-wrapper',
10
+ // Base image class
11
+ IMAGE_BLOCK: 'image-block'
12
+ };
13
+ const getWrapperClassName = (imagePrefix) => `${imagePrefix}wrapper`;
14
+ exports.getWrapperClassName = getWrapperClassName;
15
+ const getImageClassName = (imagePrefix, filename) => `${imagePrefix}${filename}`;
16
+ exports.getImageClassName = getImageClassName;
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG;IACzB,sBAAsB;IACtB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAEhB,kBAAkB;IAClB,aAAa,EAAE,eAAe;IAE9B,mBAAmB;IACnB,WAAW,EAAE,aAAa;CAClB,CAAC;AAEJ,MAAM,mBAAmB,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,GAAG,WAAW,SAAS,CAAC;AAAvE,QAAA,mBAAmB,uBAAoD;AAC7E,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,QAAgB,EAAE,EAAE,CAAC,GAAG,WAAW,GAAG,QAAQ,EAAE,CAAC;AAA3F,QAAA,iBAAiB,qBAA0E"}
@@ -0,0 +1,3 @@
1
+ export { PlaceBlockImagePlugin } from './webpack-plugin';
2
+ export type { PlaceBlockImagePluginOptions, ImageDimensions } from './webpack-plugin';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EAAE,4BAA4B,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ // Main exports for place-block-image package
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PlaceBlockImagePlugin = void 0;
5
+ var webpack_plugin_1 = require("./webpack-plugin");
6
+ Object.defineProperty(exports, "PlaceBlockImagePlugin", { enumerable: true, get: function () { return webpack_plugin_1.PlaceBlockImagePlugin; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,6CAA6C;;;AAE7C,mDAAyD;AAAhD,uHAAA,qBAAqB,OAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function getReactJsxTemplate(imagePrefix: string): string;
2
+ //# sourceMappingURL=react-jsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-jsx.d.ts","sourceRoot":"","sources":["../../src/templates/react-jsx.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAwB/D"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getReactJsxTemplate = getReactJsxTemplate;
4
+ const react_1 = require("./shared/react");
5
+ function getReactJsxTemplate(imagePrefix) {
6
+ const shared = (0, react_1.getSharedReactTemplate)(imagePrefix);
7
+ return `${shared.imports}
8
+
9
+ ${shared.comment}
10
+ export const PlaceBlockImage = ({
11
+ src,
12
+ alt,
13
+ lazy = false,
14
+ className = '',
15
+ ...props
16
+ }) => {
17
+ ${shared.hooks}
18
+
19
+ ${shared.getImageClassName}
20
+
21
+ ${shared.classNames}
22
+
23
+ ${shared.jsx}
24
+ };
25
+
26
+ ${shared.export}
27
+ `;
28
+ }
29
+ //# sourceMappingURL=react-jsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-jsx.js","sourceRoot":"","sources":["../../src/templates/react-jsx.ts"],"names":[],"mappings":";;AAEA,kDAwBC;AA1BD,0CAAwD;AAExD,SAAgB,mBAAmB,CAAC,WAAmB;IACrD,MAAM,MAAM,GAAG,IAAA,8BAAsB,EAAC,WAAW,CAAC,CAAC;IAEnD,OAAO,GAAG,MAAM,CAAC,OAAO;;EAExB,MAAM,CAAC,OAAO;;;;;;;;EAQd,MAAM,CAAC,KAAK;;EAEZ,MAAM,CAAC,iBAAiB;;EAExB,MAAM,CAAC,UAAU;;EAEjB,MAAM,CAAC,GAAG;;;EAGV,MAAM,CAAC,MAAM;CACd,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getReactTsxTemplate(imagePrefix: string): string;
2
+ //# sourceMappingURL=react-tsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-tsx.d.ts","sourceRoot":"","sources":["../../src/templates/react-tsx.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8B/D"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getReactTsxTemplate = getReactTsxTemplate;
4
+ const react_1 = require("./shared/react");
5
+ function getReactTsxTemplate(imagePrefix) {
6
+ const shared = (0, react_1.getSharedReactTemplate)(imagePrefix);
7
+ return `${shared.imports}
8
+
9
+ interface PlaceBlockImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
10
+ src: string;
11
+ alt: string;
12
+ lazy?: boolean;
13
+ }
14
+
15
+ ${shared.comment}
16
+ export const PlaceBlockImage: React.FC<PlaceBlockImageProps> = ({
17
+ src,
18
+ alt,
19
+ lazy = false,
20
+ className = '',
21
+ ...props
22
+ }) => {
23
+ ${shared.hooks}
24
+
25
+ ${shared.getImageClassName}
26
+
27
+ ${shared.classNames}
28
+
29
+ ${shared.jsx}
30
+ };
31
+
32
+ ${shared.export}
33
+ `;
34
+ }
35
+ //# sourceMappingURL=react-tsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-tsx.js","sourceRoot":"","sources":["../../src/templates/react-tsx.ts"],"names":[],"mappings":";;AAEA,kDA8BC;AAhCD,0CAAwD;AAExD,SAAgB,mBAAmB,CAAC,WAAmB;IACrD,MAAM,MAAM,GAAG,IAAA,8BAAsB,EAAC,WAAW,CAAC,CAAC;IAEnD,OAAO,GAAG,MAAM,CAAC,OAAO;;;;;;;;EAQxB,MAAM,CAAC,OAAO;;;;;;;;EAQd,MAAM,CAAC,KAAK;;EAEZ,MAAM,CAAC,iBAAiB;;EAExB,MAAM,CAAC,UAAU;;EAEjB,MAAM,CAAC,GAAG;;;EAGV,MAAM,CAAC,MAAM;CACd,CAAC;AACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare const getSharedTemplate: (imagePrefix: string) => {
2
+ comment: string;
3
+ getImageClassNameTemplate: string;
4
+ intersectionObserverTemplate: string;
5
+ };
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM;;;;CA4CnD,CAAC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSharedTemplate = void 0;
4
+ const constants_1 = require("../../constants");
5
+ const getSharedTemplate = (imagePrefix) => ({
6
+ // Common comment block
7
+ comment: `/**
8
+ * PlaceBlockImage component that prevents layout shift using CSS custom properties
9
+ * Generated by place-block-image webpack plugin
10
+ *
11
+ * Usage:
12
+ * <PlaceBlockImage src="/images/logo.svg" alt="Logo" />
13
+ * <PlaceBlockImage src="/images/hero.jpg" alt="Hero" lazy={true} />
14
+ *
15
+ * This will automatically apply:
16
+ * - .${imagePrefix}wrapper class on picture (for dimensions)
17
+ * - .${imagePrefix}logo class on picture (specific dimensions via CSS custom properties)
18
+ * - ${constants_1.CLASS_NAMES.LAZY}/${constants_1.CLASS_NAMES.LAZY}.${constants_1.CLASS_NAMES.LOADED} classes for lazy loading states
19
+ */`,
20
+ // Common filename extraction logic (as string for interpolation)
21
+ getImageClassNameTemplate: `// Extract filename from src to generate class name
22
+ const getImageClassName = (imageSrc: string): string => {
23
+ // Remove /images/ prefix and file extension, convert to kebab-case
24
+ const filename = imageSrc
25
+ .replace(/^.*\\/images\\//, '') // Remove path up to /images/
26
+ .replace(/\\.[^/.]+$/, '') // Remove file extension
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9-]/g, '-') // Convert special chars to hyphens
29
+ .replace(/-+/g, '-') // Remove duplicate hyphens
30
+ .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
31
+
32
+ return \`${imagePrefix}\${filename}\`;
33
+ };`,
34
+ // Common intersection observer logic
35
+ intersectionObserverTemplate: `const observer = new IntersectionObserver(
36
+ (entries) => {
37
+ entries.forEach((entry) => {
38
+ if (entry.isIntersecting) {
39
+ setImageSrc(src);
40
+ setIsLoaded(true);
41
+ observer.unobserve(entry.target);
42
+ }
43
+ });
44
+ },
45
+ { threshold: 0.1 }
46
+ );`
47
+ });
48
+ exports.getSharedTemplate = getSharedTemplate;
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAEvC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,CAAC;IACzD,uBAAuB;IACvB,OAAO,EAAE;;;;;;;;;QASH,WAAW;QACX,WAAW;OACZ,uBAAW,CAAC,IAAI,IAAI,uBAAW,CAAC,IAAI,IAAI,uBAAW,CAAC,MAAM;IAC7D;IAEF,iEAAiE;IACjE,yBAAyB,EAAE;;;;;;;;;;;eAWd,WAAW;KACrB;IAEH,qCAAqC;IACrC,4BAA4B,EAAE;;;;;;;;;;;OAWzB;CACN,CAAC,CAAC;AA5CU,QAAA,iBAAiB,qBA4C3B"}
@@ -0,0 +1,10 @@
1
+ export declare const getSharedReactTemplate: (imagePrefix: string) => {
2
+ imports: string;
3
+ comment: string;
4
+ hooks: string;
5
+ getImageClassName: string;
6
+ classNames: string;
7
+ jsx: string;
8
+ export: string;
9
+ };
10
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/templates/shared/react.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM;;;;;;;;CA+CzD,CAAC"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSharedReactTemplate = void 0;
4
+ const index_1 = require("./index");
5
+ const constants_1 = require("../../constants");
6
+ const getSharedReactTemplate = (imagePrefix) => {
7
+ const shared = (0, index_1.getSharedTemplate)(imagePrefix);
8
+ return {
9
+ imports: `import React, { useRef, useEffect, useState } from 'react';`,
10
+ comment: shared.comment,
11
+ hooks: ` const imgRef = useRef(null);
12
+ const [imageSrc, setImageSrc] = useState(lazy ? '' : src);
13
+ const [isLoaded, setIsLoaded] = useState(!lazy);
14
+
15
+ useEffect(() => {
16
+ if (!lazy || isLoaded) return;
17
+
18
+ ${shared.intersectionObserverTemplate}
19
+
20
+ if (imgRef.current) {
21
+ observer.observe(imgRef.current);
22
+ }
23
+
24
+ return () => observer.disconnect();
25
+ }, [src, lazy, isLoaded]);`,
26
+ getImageClassName: shared.getImageClassNameTemplate,
27
+ classNames: ` const imageClassName = getImageClassName(src);
28
+ const wrapperClassName = \`${imagePrefix}wrapper \${imageClassName} \${className || ''}\`.trim();
29
+
30
+ // Build img className with lazy states
31
+ const lazyClass = lazy ? (isLoaded ? '${constants_1.CLASS_NAMES.LAZY} ${constants_1.CLASS_NAMES.LOADED}' : '${constants_1.CLASS_NAMES.LAZY}') : '';
32
+ const imgClassName = \`${constants_1.CLASS_NAMES.IMAGE_BLOCK} \${lazyClass}\`.trim();`,
33
+ jsx: ` return (
34
+ <picture className={wrapperClassName}>
35
+ <img
36
+ ref={imgRef}
37
+ src={imageSrc}
38
+ alt={alt}
39
+ className={imgClassName}
40
+ {...props}
41
+ />
42
+ </picture>
43
+ );`,
44
+ export: `export default PlaceBlockImage;`
45
+ };
46
+ };
47
+ exports.getSharedReactTemplate = getSharedReactTemplate;
48
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../../../src/templates/shared/react.ts"],"names":[],"mappings":";;;AAAA,mCAA4C;AAC5C,+CAA8C;AAEvC,MAAM,sBAAsB,GAAG,CAAC,WAAmB,EAAE,EAAE;IAC5D,MAAM,MAAM,GAAG,IAAA,yBAAiB,EAAC,WAAW,CAAC,CAAC;IAE9C,OAAO;QACL,OAAO,EAAE,6DAA6D;QAEtE,OAAO,EAAE,MAAM,CAAC,OAAO;QAEvB,KAAK,EAAE;;;;;;;MAOL,MAAM,CAAC,4BAA4B;;;;;;;6BAOZ;QAEzB,iBAAiB,EAAE,MAAM,CAAC,yBAAyB;QAEnD,UAAU,EAAE;+BACe,WAAW;;;0CAGA,uBAAW,CAAC,IAAI,IAAI,uBAAW,CAAC,MAAM,QAAQ,uBAAW,CAAC,IAAI;2BAC7E,uBAAW,CAAC,WAAW,0BAA0B;QAExE,GAAG,EAAE;;;;;;;;;;KAUJ;QAED,MAAM,EAAE,iCAAiC;KAC1C,CAAC;AACJ,CAAC,CAAC;AA/CW,QAAA,sBAAsB,0BA+CjC"}
@@ -0,0 +1,2 @@
1
+ export declare function getVueTemplate(imagePrefix: string): string;
2
+ //# sourceMappingURL=vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.d.ts","sourceRoot":"","sources":["../../src/templates/vue.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8F1D"}
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getVueTemplate = getVueTemplate;
4
+ const shared_1 = require("./shared/");
5
+ const constants_1 = require("../constants");
6
+ function getVueTemplate(imagePrefix) {
7
+ const shared = (0, shared_1.getSharedTemplate)(imagePrefix);
8
+ return `<template>
9
+ <picture :class="wrapperClassName">
10
+ <img
11
+ ref="imgRef"
12
+ :src="imageSrc"
13
+ :alt="alt"
14
+ :class="imgClassName"
15
+ v-bind="$attrs"
16
+ />
17
+ </picture>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import { computed, ref, onMounted, onUnmounted, watch } from 'vue';
22
+
23
+ interface Props {
24
+ src: string;
25
+ alt: string;
26
+ lazy?: boolean;
27
+ class?: string;
28
+ }
29
+
30
+ const props = withDefaults(defineProps<Props>(), {
31
+ lazy: false,
32
+ class: ''
33
+ });
34
+
35
+ ${shared.comment}
36
+
37
+ const imgRef = ref<HTMLImageElement | null>(null);
38
+ const imageSrc = ref(props.lazy ? '' : props.src);
39
+ const isLoaded = ref(!props.lazy);
40
+ let observer: IntersectionObserver | null = null;
41
+
42
+ ${shared.getImageClassNameTemplate}
43
+
44
+ const imageClassName = computed(() => getImageClassName(props.src));
45
+ const wrapperClassName = computed(() =>
46
+ \`${imagePrefix}wrapper \${imageClassName.value}\`
47
+ );
48
+
49
+ const lazyClass = computed(() =>
50
+ props.lazy ? (isLoaded.value ? '${constants_1.CLASS_NAMES.LAZY} ${constants_1.CLASS_NAMES.LOADED}' : '${constants_1.CLASS_NAMES.LAZY}') : ''
51
+ );
52
+
53
+ const imgClassName = computed(() =>
54
+ \`\${props.class} \${lazyClass.value}\`.trim()
55
+ );
56
+
57
+ const setupLazyLoading = () => {
58
+ if (!props.lazy || isLoaded.value) return;
59
+
60
+ ${shared.intersectionObserverTemplate}
61
+
62
+ if (imgRef.value) {
63
+ observer.observe(imgRef.value);
64
+ }
65
+ };
66
+
67
+ const cleanupObserver = () => {
68
+ if (observer) {
69
+ observer.disconnect();
70
+ observer = null;
71
+ }
72
+ };
73
+
74
+ onMounted(() => {
75
+ setupLazyLoading();
76
+ });
77
+
78
+ onUnmounted(() => {
79
+ cleanupObserver();
80
+ });
81
+
82
+ watch(() => props.src, (newSrc) => {
83
+ if (!props.lazy) {
84
+ imageSrc.value = newSrc;
85
+ } else if (!isLoaded.value) {
86
+ cleanupObserver();
87
+ setupLazyLoading();
88
+ }
89
+ });
90
+
91
+ watch(isLoaded, (loaded) => {
92
+ if (loaded) {
93
+ imageSrc.value = props.src;
94
+ cleanupObserver();
95
+ }
96
+ });
97
+ </script>
98
+ `;
99
+ }
100
+ //# sourceMappingURL=vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.js","sourceRoot":"","sources":["../../src/templates/vue.ts"],"names":[],"mappings":";;AAGA,wCA8FC;AAjGD,sCAA8C;AAC9C,4CAA2C;AAE3C,SAAgB,cAAc,CAAC,WAAmB;IAChD,MAAM,MAAM,GAAG,IAAA,0BAAiB,EAAC,WAAW,CAAC,CAAC;IAE9C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BP,MAAM,CAAC,OAAO;;;;;;;EAOd,MAAM,CAAC,yBAAyB;;;;MAI5B,WAAW;;;;oCAImB,uBAAW,CAAC,IAAI,IAAI,uBAAW,CAAC,MAAM,QAAQ,uBAAW,CAAC,IAAI;;;;;;;;;;IAU9F,MAAM,CAAC,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCtC,CAAC;AACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function getReactTsxTemplate(imagePrefix: string): string;
2
+ export declare function getReactJsxTemplate(imagePrefix: string): string;
3
+ export declare function getVueTemplate(imagePrefix: string): string;
4
+ export declare function getTemplate(type: 'tsx' | 'jsx' | 'vue', imagePrefix: string): string;
5
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAKA,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAWpF"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getReactTsxTemplate = getReactTsxTemplate;
4
+ exports.getReactJsxTemplate = getReactJsxTemplate;
5
+ exports.getVueTemplate = getVueTemplate;
6
+ exports.getTemplate = getTemplate;
7
+ // Main template exports
8
+ const react_tsx_1 = require("./templates/react-tsx");
9
+ const react_jsx_1 = require("./templates/react-jsx");
10
+ const vue_1 = require("./templates/vue");
11
+ function getReactTsxTemplate(imagePrefix) {
12
+ return (0, react_tsx_1.getReactTsxTemplate)(imagePrefix);
13
+ }
14
+ function getReactJsxTemplate(imagePrefix) {
15
+ return (0, react_jsx_1.getReactJsxTemplate)(imagePrefix);
16
+ }
17
+ function getVueTemplate(imagePrefix) {
18
+ return (0, vue_1.getVueTemplate)(imagePrefix);
19
+ }
20
+ function getTemplate(type, imagePrefix) {
21
+ switch (type) {
22
+ case 'tsx':
23
+ return getReactTsxTemplate(imagePrefix);
24
+ case 'jsx':
25
+ return getReactJsxTemplate(imagePrefix);
26
+ case 'vue':
27
+ return getVueTemplate(imagePrefix);
28
+ default:
29
+ throw new Error(`Unsupported component type: ${type}`);
30
+ }
31
+ }
32
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":";;AAKA,kDAEC;AAED,kDAEC;AAED,wCAEC;AAED,kCAWC;AA5BD,wBAAwB;AACxB,qDAA2E;AAC3E,qDAA2E;AAC3E,yCAA2D;AAE3D,SAAgB,mBAAmB,CAAC,WAAmB;IACrD,OAAO,IAAA,+BAAW,EAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED,SAAgB,mBAAmB,CAAC,WAAmB;IACrD,OAAO,IAAA,+BAAW,EAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED,SAAgB,cAAc,CAAC,WAAmB;IAChD,OAAO,IAAA,oBAAM,EAAC,WAAW,CAAC,CAAC;AAC7B,CAAC;AAED,SAAgB,WAAW,CAAC,IAA2B,EAAE,WAAmB;IAC1E,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC1C,KAAK,KAAK;YACR,OAAO,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC1C,KAAK,KAAK;YACR,OAAO,cAAc,CAAC,WAAW,CAAC,CAAC;QACrC;YACE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface TemplateData {
2
+ imagePrefix: string;
3
+ baseClassName: string;
4
+ wrapperClassName: string;
5
+ }
6
+ export declare function getTemplateData(imagePrefix: string): TemplateData;
7
+ export declare function getSharedLogic(imagePrefix: string): string;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAMjE;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAkB1D"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ // Shared template utilities
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.getTemplateData = getTemplateData;
5
+ exports.getSharedLogic = getSharedLogic;
6
+ function getTemplateData(imagePrefix) {
7
+ return {
8
+ imagePrefix,
9
+ baseClassName: `${imagePrefix}block`,
10
+ wrapperClassName: `${imagePrefix}wrapper`
11
+ };
12
+ }
13
+ function getSharedLogic(imagePrefix) {
14
+ return `
15
+ // Extract filename from src to generate class name
16
+ const getImageClassName = (imageSrc) => {
17
+ // Remove /images/ prefix and file extension, convert to kebab-case
18
+ const filename = imageSrc
19
+ .replace(/^.*\\/images\\//, '') // Remove path up to /images/
20
+ .replace(/\\.[^/.]+$/, '') // Remove file extension
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9-]/g, '-') // Convert special chars to hyphens
23
+ .replace(/-+/g, '-') // Remove duplicate hyphens
24
+ .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
25
+
26
+ return \`${imagePrefix}\${filename}\`;
27
+ };
28
+
29
+ const imageClassName = getImageClassName(src);
30
+ const wrapperClassName = \`${imagePrefix}wrapper \${imageClassName}\`;`;
31
+ }
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";AAAA,4BAA4B;;AAQ5B,0CAMC;AAED,wCAkBC;AA1BD,SAAgB,eAAe,CAAC,WAAmB;IACjD,OAAO;QACL,WAAW;QACX,aAAa,EAAE,GAAG,WAAW,OAAO;QACpC,gBAAgB,EAAE,GAAG,WAAW,SAAS;KAC1C,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,WAAmB;IAChD,OAAO;;;;;;;;;;;;eAYM,WAAW;;;;+BAIK,WAAW,+BAA+B,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { Compiler } from 'webpack';
2
+ export interface PlaceBlockImagePluginOptions {
3
+ imagePrefix?: string;
4
+ imageDir: string;
5
+ scssPath: string;
6
+ componentPath?: string;
7
+ componentType?: 'tsx' | 'jsx' | 'vue';
8
+ generateComponent?: boolean;
9
+ }
10
+ export interface ImageDimensions {
11
+ width: number;
12
+ height: number;
13
+ filename: string;
14
+ className: string;
15
+ }
16
+ export declare class PlaceBlockImagePlugin {
17
+ private options;
18
+ private isGenerating;
19
+ private lastGenerationTime;
20
+ constructor(options: PlaceBlockImagePluginOptions);
21
+ /**
22
+ * Generate CSS class name from filename
23
+ */
24
+ private generateClassName;
25
+ /**
26
+ * Scan directory for images and get their dimensions
27
+ */
28
+ private scanImages;
29
+ /**
30
+ * Generate SCSS with CSS custom properties and base class
31
+ */
32
+ private generateScss;
33
+ /**
34
+ * Write SCSS file
35
+ */
36
+ private writeScssFile;
37
+ /**
38
+ * Generate and write component file
39
+ */
40
+ private writeComponentFile;
41
+ /**
42
+ * Check if images have changed since last generation
43
+ */
44
+ private shouldRegenerate;
45
+ apply(compiler: Compiler): void;
46
+ private generateImageStyles;
47
+ }
48
+ export default PlaceBlockImagePlugin;
49
+ //# sourceMappingURL=webpack-plugin.d.ts.map