@adstage/web-sdk 2.2.0 → 2.2.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/index.cjs.js CHANGED
@@ -392,16 +392,23 @@ class BaseAdRenderer {
392
392
  getImageStyles(slot) {
393
393
  const styles = {
394
394
  display: 'block',
395
- 'max-width': '100%',
396
- height: 'auto',
395
+ 'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
397
396
  };
398
- // 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
397
+ // 사용자가 컨테이너 크기를 지정했는지 확인
399
398
  const parsedWidth = this.parseSizeValue(slot?.width);
400
399
  const parsedHeight = this.parseSizeValue(slot?.height);
401
- if (parsedWidth && parsedHeight) {
400
+ const hasUserDefinedSize = parsedWidth || parsedHeight;
401
+ if (hasUserDefinedSize) {
402
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
402
403
  styles.width = '100%';
403
404
  styles.height = '100%';
404
- styles['object-fit'] = 'cover';
405
+ styles['object-fit'] = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
406
+ styles['object-position'] = 'center';
407
+ }
408
+ else {
409
+ // 사용자가 크기를 지정하지 않은 경우: 원본 이미지 크기 유지
410
+ styles['max-width'] = '100%';
411
+ styles.height = 'auto';
405
412
  }
406
413
  return styles;
407
414
  }
@@ -2884,23 +2891,45 @@ class AdsModule {
2884
2891
  */
2885
2892
  async renderOptimizedBannerImage(adElement, ad, slot) {
2886
2893
  try {
2887
- // 이미지 크기 정보 로드
2888
- const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2889
- const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2890
- // 컨테이너 비율 계산
2891
- const containerAspectRatio = slot.aspectRatio || 16 / 9;
2894
+ // 사용자가 크기를 지정했는지 확인
2895
+ const configWidth = slot.config?.width;
2896
+ const configHeight = slot.config?.height;
2897
+ const hasUserDefinedWidth = configWidth &&
2898
+ (typeof configWidth === 'number' || (typeof configWidth === 'string' && configWidth !== '100%'));
2899
+ const hasUserDefinedHeight = configHeight &&
2900
+ (typeof configHeight === 'number' || (typeof configHeight === 'string' && configHeight !== 'auto'));
2901
+ const hasUserDefinedSize = hasUserDefinedWidth || hasUserDefinedHeight;
2892
2902
  // 이미지 요소 생성
2893
2903
  const img = document.createElement('img');
2894
2904
  img.src = ad.imageUrl;
2895
2905
  img.alt = ad.title;
2896
- img.style.width = '100%';
2897
- img.style.height = '100%';
2898
- // 🎨 최적화된 스타일 적용
2899
- this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2906
+ if (hasUserDefinedSize) {
2907
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
2908
+ img.style.width = '100%';
2909
+ img.style.height = '100%';
2910
+ img.style.objectFit = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
2911
+ img.style.objectPosition = 'center';
2912
+ if (this._config?.debug) {
2913
+ console.log(`🎯 User-defined size detected: filling container completely`);
2914
+ }
2915
+ }
2916
+ else {
2917
+ // 사용자가 크기를 지정하지 않은 경우: 동적 최적화 적용
2918
+ const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2919
+ const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2920
+ const containerAspectRatio = slot.aspectRatio || 16 / 9;
2921
+ img.style.width = '100%';
2922
+ img.style.height = '100%';
2923
+ // 🎨 최적화된 스타일 적용
2924
+ this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2925
+ if (this._config?.debug) {
2926
+ console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2927
+ }
2928
+ }
2900
2929
  // 이미지 로드 완료 처리
2901
2930
  img.onload = () => {
2902
2931
  if (this._config?.debug) {
2903
- console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2932
+ console.log(`✅ Banner image loaded successfully`);
2904
2933
  }
2905
2934
  };
2906
2935
  // 에러 처리
@@ -2920,6 +2949,7 @@ class AdsModule {
2920
2949
  img.style.width = '100%';
2921
2950
  img.style.height = '100%';
2922
2951
  img.style.objectFit = 'cover';
2952
+ img.style.objectPosition = 'center'; // 🎯 폴백 이미지도 중앙 정렬
2923
2953
  adElement.appendChild(img);
2924
2954
  }
2925
2955
  }
package/dist/index.esm.js CHANGED
@@ -390,16 +390,23 @@ class BaseAdRenderer {
390
390
  getImageStyles(slot) {
391
391
  const styles = {
392
392
  display: 'block',
393
- 'max-width': '100%',
394
- height: 'auto',
393
+ 'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
395
394
  };
396
- // 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
395
+ // 사용자가 컨테이너 크기를 지정했는지 확인
397
396
  const parsedWidth = this.parseSizeValue(slot?.width);
398
397
  const parsedHeight = this.parseSizeValue(slot?.height);
399
- if (parsedWidth && parsedHeight) {
398
+ const hasUserDefinedSize = parsedWidth || parsedHeight;
399
+ if (hasUserDefinedSize) {
400
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
400
401
  styles.width = '100%';
401
402
  styles.height = '100%';
402
- styles['object-fit'] = 'cover';
403
+ styles['object-fit'] = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
404
+ styles['object-position'] = 'center';
405
+ }
406
+ else {
407
+ // 사용자가 크기를 지정하지 않은 경우: 원본 이미지 크기 유지
408
+ styles['max-width'] = '100%';
409
+ styles.height = 'auto';
403
410
  }
404
411
  return styles;
405
412
  }
@@ -2882,23 +2889,45 @@ class AdsModule {
2882
2889
  */
2883
2890
  async renderOptimizedBannerImage(adElement, ad, slot) {
2884
2891
  try {
2885
- // 이미지 크기 정보 로드
2886
- const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2887
- const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2888
- // 컨테이너 비율 계산
2889
- const containerAspectRatio = slot.aspectRatio || 16 / 9;
2892
+ // 사용자가 크기를 지정했는지 확인
2893
+ const configWidth = slot.config?.width;
2894
+ const configHeight = slot.config?.height;
2895
+ const hasUserDefinedWidth = configWidth &&
2896
+ (typeof configWidth === 'number' || (typeof configWidth === 'string' && configWidth !== '100%'));
2897
+ const hasUserDefinedHeight = configHeight &&
2898
+ (typeof configHeight === 'number' || (typeof configHeight === 'string' && configHeight !== 'auto'));
2899
+ const hasUserDefinedSize = hasUserDefinedWidth || hasUserDefinedHeight;
2890
2900
  // 이미지 요소 생성
2891
2901
  const img = document.createElement('img');
2892
2902
  img.src = ad.imageUrl;
2893
2903
  img.alt = ad.title;
2894
- img.style.width = '100%';
2895
- img.style.height = '100%';
2896
- // 🎨 최적화된 스타일 적용
2897
- this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2904
+ if (hasUserDefinedSize) {
2905
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
2906
+ img.style.width = '100%';
2907
+ img.style.height = '100%';
2908
+ img.style.objectFit = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
2909
+ img.style.objectPosition = 'center';
2910
+ if (this._config?.debug) {
2911
+ console.log(`🎯 User-defined size detected: filling container completely`);
2912
+ }
2913
+ }
2914
+ else {
2915
+ // 사용자가 크기를 지정하지 않은 경우: 동적 최적화 적용
2916
+ const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2917
+ const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2918
+ const containerAspectRatio = slot.aspectRatio || 16 / 9;
2919
+ img.style.width = '100%';
2920
+ img.style.height = '100%';
2921
+ // 🎨 최적화된 스타일 적용
2922
+ this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2923
+ if (this._config?.debug) {
2924
+ console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2925
+ }
2926
+ }
2898
2927
  // 이미지 로드 완료 처리
2899
2928
  img.onload = () => {
2900
2929
  if (this._config?.debug) {
2901
- console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2930
+ console.log(`✅ Banner image loaded successfully`);
2902
2931
  }
2903
2932
  };
2904
2933
  // 에러 처리
@@ -2918,6 +2947,7 @@ class AdsModule {
2918
2947
  img.style.width = '100%';
2919
2948
  img.style.height = '100%';
2920
2949
  img.style.objectFit = 'cover';
2950
+ img.style.objectPosition = 'center'; // 🎯 폴백 이미지도 중앙 정렬
2921
2951
  adElement.appendChild(img);
2922
2952
  }
2923
2953
  }
@@ -390,16 +390,23 @@ class BaseAdRenderer {
390
390
  getImageStyles(slot) {
391
391
  const styles = {
392
392
  display: 'block',
393
- 'max-width': '100%',
394
- height: 'auto',
393
+ 'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
395
394
  };
396
- // 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
395
+ // 사용자가 컨테이너 크기를 지정했는지 확인
397
396
  const parsedWidth = this.parseSizeValue(slot?.width);
398
397
  const parsedHeight = this.parseSizeValue(slot?.height);
399
- if (parsedWidth && parsedHeight) {
398
+ const hasUserDefinedSize = parsedWidth || parsedHeight;
399
+ if (hasUserDefinedSize) {
400
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
400
401
  styles.width = '100%';
401
402
  styles.height = '100%';
402
- styles['object-fit'] = 'cover';
403
+ styles['object-fit'] = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
404
+ styles['object-position'] = 'center';
405
+ }
406
+ else {
407
+ // 사용자가 크기를 지정하지 않은 경우: 원본 이미지 크기 유지
408
+ styles['max-width'] = '100%';
409
+ styles.height = 'auto';
403
410
  }
404
411
  return styles;
405
412
  }
@@ -2882,23 +2889,45 @@ class AdsModule {
2882
2889
  */
2883
2890
  async renderOptimizedBannerImage(adElement, ad, slot) {
2884
2891
  try {
2885
- // 이미지 크기 정보 로드
2886
- const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2887
- const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2888
- // 컨테이너 비율 계산
2889
- const containerAspectRatio = slot.aspectRatio || 16 / 9;
2892
+ // 사용자가 크기를 지정했는지 확인
2893
+ const configWidth = slot.config?.width;
2894
+ const configHeight = slot.config?.height;
2895
+ const hasUserDefinedWidth = configWidth &&
2896
+ (typeof configWidth === 'number' || (typeof configWidth === 'string' && configWidth !== '100%'));
2897
+ const hasUserDefinedHeight = configHeight &&
2898
+ (typeof configHeight === 'number' || (typeof configHeight === 'string' && configHeight !== 'auto'));
2899
+ const hasUserDefinedSize = hasUserDefinedWidth || hasUserDefinedHeight;
2890
2900
  // 이미지 요소 생성
2891
2901
  const img = document.createElement('img');
2892
2902
  img.src = ad.imageUrl;
2893
2903
  img.alt = ad.title;
2894
- img.style.width = '100%';
2895
- img.style.height = '100%';
2896
- // 🎨 최적화된 스타일 적용
2897
- this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2904
+ if (hasUserDefinedSize) {
2905
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
2906
+ img.style.width = '100%';
2907
+ img.style.height = '100%';
2908
+ img.style.objectFit = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
2909
+ img.style.objectPosition = 'center';
2910
+ if (this._config?.debug) {
2911
+ console.log(`🎯 User-defined size detected: filling container completely`);
2912
+ }
2913
+ }
2914
+ else {
2915
+ // 사용자가 크기를 지정하지 않은 경우: 동적 최적화 적용
2916
+ const imageDimensions = await this.loadImageDimensions(ad.imageUrl);
2917
+ const imageAspectRatio = imageDimensions.width / imageDimensions.height;
2918
+ const containerAspectRatio = slot.aspectRatio || 16 / 9;
2919
+ img.style.width = '100%';
2920
+ img.style.height = '100%';
2921
+ // 🎨 최적화된 스타일 적용
2922
+ this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
2923
+ if (this._config?.debug) {
2924
+ console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2925
+ }
2926
+ }
2898
2927
  // 이미지 로드 완료 처리
2899
2928
  img.onload = () => {
2900
2929
  if (this._config?.debug) {
2901
- console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
2930
+ console.log(`✅ Banner image loaded successfully`);
2902
2931
  }
2903
2932
  };
2904
2933
  // 에러 처리
@@ -2918,6 +2947,7 @@ class AdsModule {
2918
2947
  img.style.width = '100%';
2919
2948
  img.style.height = '100%';
2920
2949
  img.style.objectFit = 'cover';
2950
+ img.style.objectPosition = 'center'; // 🎯 폴백 이미지도 중앙 정렬
2921
2951
  adElement.appendChild(img);
2922
2952
  }
2923
2953
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adstage/web-sdk",
3
- "version": "2.2.0",
4
- "description": "AdStage Web SDK - Production-ready marketing platform SDK with auto-initialization and namespace architecture",
3
+ "version": "2.2.2",
4
+ "description": "AdStage Web SDK - Production-ready marketing platform SDK with auto-initialization, dynamic sizing, centered image positioning, and user-defined size support",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.esm.js",
@@ -1076,27 +1076,52 @@ export class AdsModule implements BaseModule {
1076
1076
  */
1077
1077
  private async renderOptimizedBannerImage(adElement: HTMLElement, ad: Advertisement, slot: AdSlot): Promise<void> {
1078
1078
  try {
1079
- // 이미지 크기 정보 로드
1080
- const imageDimensions = await this.loadImageDimensions(ad.imageUrl!);
1081
- const imageAspectRatio = imageDimensions.width / imageDimensions.height;
1079
+ // 사용자가 크기를 지정했는지 확인
1080
+ const configWidth = slot.config?.width;
1081
+ const configHeight = slot.config?.height;
1082
1082
 
1083
- // 컨테이너 비율 계산
1084
- const containerAspectRatio = (slot as any).aspectRatio || 16/9;
1083
+ const hasUserDefinedWidth = configWidth &&
1084
+ (typeof configWidth === 'number' || (typeof configWidth === 'string' && configWidth !== '100%'));
1085
+ const hasUserDefinedHeight = configHeight &&
1086
+ (typeof configHeight === 'number' || (typeof configHeight === 'string' && configHeight !== 'auto'));
1087
+ const hasUserDefinedSize = hasUserDefinedWidth || hasUserDefinedHeight;
1085
1088
 
1086
1089
  // 이미지 요소 생성
1087
1090
  const img = document.createElement('img');
1088
1091
  img.src = ad.imageUrl!;
1089
1092
  img.alt = ad.title;
1090
- img.style.width = '100%';
1091
- img.style.height = '100%';
1092
1093
 
1093
- // 🎨 최적화된 스타일 적용
1094
- this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
1094
+ if (hasUserDefinedSize) {
1095
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
1096
+ img.style.width = '100%';
1097
+ img.style.height = '100%';
1098
+ img.style.objectFit = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
1099
+ img.style.objectPosition = 'center';
1100
+
1101
+ if (this._config?.debug) {
1102
+ console.log(`🎯 User-defined size detected: filling container completely`);
1103
+ }
1104
+ } else {
1105
+ // 사용자가 크기를 지정하지 않은 경우: 동적 최적화 적용
1106
+ const imageDimensions = await this.loadImageDimensions(ad.imageUrl!);
1107
+ const imageAspectRatio = imageDimensions.width / imageDimensions.height;
1108
+ const containerAspectRatio = (slot as any).aspectRatio || 16/9;
1109
+
1110
+ img.style.width = '100%';
1111
+ img.style.height = '100%';
1112
+
1113
+ // 🎨 최적화된 스타일 적용
1114
+ this.applyOptimizedImageStyle(img, imageAspectRatio, containerAspectRatio);
1115
+
1116
+ if (this._config?.debug) {
1117
+ console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
1118
+ }
1119
+ }
1095
1120
 
1096
1121
  // 이미지 로드 완료 처리
1097
1122
  img.onload = () => {
1098
1123
  if (this._config?.debug) {
1099
- console.log(`🖼️ Optimized banner image loaded: ${imageDimensions.width}x${imageDimensions.height} (ratio: ${imageAspectRatio.toFixed(2)})`);
1124
+ console.log(`✅ Banner image loaded successfully`);
1100
1125
  }
1101
1126
  };
1102
1127
 
@@ -1119,6 +1144,7 @@ export class AdsModule implements BaseModule {
1119
1144
  img.style.width = '100%';
1120
1145
  img.style.height = '100%';
1121
1146
  img.style.objectFit = 'cover';
1147
+ img.style.objectPosition = 'center'; // 🎯 폴백 이미지도 중앙 정렬
1122
1148
  adElement.appendChild(img);
1123
1149
  }
1124
1150
  }
@@ -108,18 +108,24 @@ export abstract class BaseAdRenderer implements AdRenderer {
108
108
  protected getImageStyles(slot?: AdSlot): Record<string, string> {
109
109
  const styles: Record<string, string> = {
110
110
  display: 'block',
111
- 'max-width': '100%',
112
- height: 'auto',
111
+ 'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
113
112
  };
114
113
 
115
- // 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
114
+ // 사용자가 컨테이너 크기를 지정했는지 확인
116
115
  const parsedWidth = this.parseSizeValue(slot?.width);
117
116
  const parsedHeight = this.parseSizeValue(slot?.height);
117
+ const hasUserDefinedSize = parsedWidth || parsedHeight;
118
118
 
119
- if (parsedWidth && parsedHeight) {
119
+ if (hasUserDefinedSize) {
120
+ // 🎯 사용자가 크기를 지정한 경우: 컨테이너에 꽉 차도록 설정
120
121
  styles.width = '100%';
121
122
  styles.height = '100%';
122
- styles['object-fit'] = 'cover';
123
+ styles['object-fit'] = 'cover'; // 컨테이너에 꽉 찬 상태로 비율 유지
124
+ styles['object-position'] = 'center';
125
+ } else {
126
+ // 사용자가 크기를 지정하지 않은 경우: 원본 이미지 크기 유지
127
+ styles['max-width'] = '100%';
128
+ styles.height = 'auto';
123
129
  }
124
130
 
125
131
  return styles;