oasys-lib 2.30.1 → 2.32.0-rc.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.
@@ -928,6 +928,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.21", ngImpo
928
928
  }]
929
929
  }] });
930
930
 
931
+ const UNMEASURED_LAYOUT_WIDTH_PX = 300;
931
932
  /**
932
933
  * ImageComponent is a reusable component. Necessary accessibility attributes are set by default for a decorative image.
933
934
  * alt text and airia described by text can be set to make the image non-decorative.
@@ -951,6 +952,8 @@ class ImageComponent {
951
952
  breakpoints = inject(IMAGE_BREAKPOINTS);
952
953
  fallbackBreakpoint = 768;
953
954
  imageSizes = this.breakpoints.map((size) => `(max-width: ${size}px) ${size}px`).join(', ');
955
+ measuredWidthPx = signal(null, ...(ngDevMode ? [{ debugName: "measuredWidthPx" }] : []));
956
+ resizeObserver = null;
954
957
  intersectionObserver = null;
955
958
  get class() {
956
959
  return this.image_fill ? 'imageFill' : '';
@@ -962,11 +965,22 @@ class ImageComponent {
962
965
  this.createImage();
963
966
  void this.setupLazyLoading();
964
967
  }
968
+ ngAfterViewInit() {
969
+ this.setupResizeObserver();
970
+ }
965
971
  /**
966
972
  * On changes, handle any changes in input properties.
967
973
  */
968
974
  ngOnChanges(changes) {
969
975
  if ('image_src' in changes || 'image_width' in changes || 'preload_aspect_ratio' in changes) {
976
+ if ('image_width' in changes) {
977
+ if (this.image_width) {
978
+ this.cleanupResizeObserver();
979
+ }
980
+ else {
981
+ this.setupResizeObserver();
982
+ }
983
+ }
970
984
  this.createImage();
971
985
  this.cleanupObserver();
972
986
  void this.setupLazyLoading();
@@ -977,6 +991,7 @@ class ImageComponent {
977
991
  */
978
992
  ngOnDestroy() {
979
993
  this.cleanupObserver();
994
+ this.cleanupResizeObserver();
980
995
  }
981
996
  /**
982
997
  * Creates the image object with the provided properties.
@@ -992,12 +1007,41 @@ class ImageComponent {
992
1007
  fill: this.image_fill,
993
1008
  fetchpriority: this.fetchpriority,
994
1009
  preloadAspectRatio: this.preload_aspect_ratio,
995
- width: this.image_width ? `${this.image_width}px` : null,
1010
+ width: this.getSizesAttribute(),
996
1011
  altText: this.image_alt_text,
997
1012
  ariaDescribedby: this.image_aria_describedby ?? null,
998
1013
  };
999
1014
  this.image.set(newImage);
1000
1015
  }
1016
+ getSizesAttribute() {
1017
+ if (this.image_width) {
1018
+ return `${this.image_width}px`;
1019
+ }
1020
+ const measured = this.measuredWidthPx();
1021
+ if (measured && measured > 0) {
1022
+ return `${Math.ceil(measured)}px`;
1023
+ }
1024
+ return `${UNMEASURED_LAYOUT_WIDTH_PX}px`;
1025
+ }
1026
+ setupResizeObserver() {
1027
+ if (this.image_width || typeof ResizeObserver === 'undefined') {
1028
+ return;
1029
+ }
1030
+ this.resizeObserver = new ResizeObserver((entries) => {
1031
+ const width = entries[0]?.contentRect.width ?? 0;
1032
+ const rounded = Math.ceil(width);
1033
+ if (rounded === this.measuredWidthPx()) {
1034
+ return;
1035
+ }
1036
+ this.measuredWidthPx.set(rounded > 0 ? rounded : null);
1037
+ this.createImage();
1038
+ });
1039
+ this.resizeObserver.observe(this.el.nativeElement);
1040
+ }
1041
+ cleanupResizeObserver() {
1042
+ this.resizeObserver?.disconnect();
1043
+ this.resizeObserver = null;
1044
+ }
1001
1045
  /**
1002
1046
  * Sets up lazy loading for the image using IntersectionObserver.
1003
1047
  * This method observes the image element and loads the image when it comes into view.