-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(esl-image-utils): update implementation to use json attr and…
… new compact representation BREAKING-CHANGE: legacy implementation of `esl-image` no longer distributes aspect-ratio styles
- Loading branch information
Showing
7 changed files
with
118 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
@import './core/esl-image-conyainer.less'; | ||
@import './core/esl-image-utils.container.less'; | ||
@import './core/esl-image-utils.fade.less'; | ||
@import './core/esl-image-utils.ratios.less'; |
93 changes: 61 additions & 32 deletions
93
src/modules/esl-image-utils/core/esl-image-container.mixin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,88 @@ | ||
import {ESLMixinElement} from '../../esl-mixin-element/core'; | ||
import {ESLTraversingQuery} from '../../esl-traversing-query/core'; | ||
import {attr, listen} from '../../esl-utils/decorators'; | ||
import {CSSClassUtils} from '../../esl-utils/dom'; | ||
import {jsonAttr, listen, memoize} from '../../esl-utils/decorators'; | ||
import {ExportNs} from '../../esl-utils/environment/export-ns'; | ||
import {findAll} from '../../esl-utils/dom/traversing'; | ||
|
||
/** | ||
* ESLImgContainerMixin - mixin to provide image container functionality | ||
* ESLImageContainerConfig - interface for ESLImageContainerMixin config | ||
*/ | ||
export interface ESLImageContainerConfig { | ||
/** Class to add to the target element when the image is loaded (successfully) */ | ||
readyCls: string; | ||
/** Class to add to the target element when the image is not loaded (error) */ | ||
errorCls: string; | ||
/** Image element selector */ | ||
selector: string; | ||
} | ||
|
||
/** | ||
* ESLImageContainerMixin - mixin to provide image loading state class functionality | ||
* @author Anna Barmina, Alexey Stsefanovich (ala'n) | ||
* | ||
* Use example: | ||
* ``` | ||
* <picture class="img-container img-container-16-9"> | ||
* <img esl-img-container loading="lazy" alt="img" src="img.png"/> | ||
* <picture class="img-container img-container-16-9" esl-image-container> | ||
* <img loading="lazy" alt="img" src="img.png"/> | ||
* </picture> | ||
* ``` | ||
* | ||
* This mixin is used to enhance an image element by adding specific classes to a target when the image has completely loaded or not | ||
* This mixin is used to enhance native image developer experience by adding specific classes when the image has completely loaded or not | ||
*/ | ||
@ExportNs('ImageContainer') | ||
export class ESLImageContainerMixin extends ESLMixinElement { | ||
public static override is = 'esl-image-container'; | ||
|
||
/** Default configuration object */ | ||
public static DEFAULT_CONFIG: ESLImageContainerConfig = { | ||
readyCls: 'img-container-loaded', | ||
errorCls: '', | ||
selector: 'img', | ||
}; | ||
|
||
@ExportNs('ImgContainer') | ||
export class ESLImgContainerMixin extends ESLMixinElement { | ||
static override is = 'esl-img-container'; | ||
/** Configuration object */ | ||
@jsonAttr({name: ESLImageContainerMixin.is}) public rawConfig: Partial<ESLImageContainerConfig>; | ||
|
||
/** Target element selector ('::parent' by default) */ | ||
@attr({name: ESLImgContainerMixin.is}) public target: string; | ||
/** Class to add to the target element when the image is loaded */ | ||
@attr({name: ESLImgContainerMixin.is + '-cls', defaultValue: 'img-container-loaded'}) public targetCls: string; | ||
/** Class to add to the target element when the image is not loaded */ | ||
@attr({name: ESLImgContainerMixin.is + '-error-cls'}) public targetErrorCls: string; | ||
/** Merged configuration object */ | ||
@memoize() | ||
public get config(): ESLImageContainerConfig { | ||
return {...ESLImageContainerMixin.DEFAULT_CONFIG, ...this.rawConfig}; | ||
} | ||
|
||
public override $host!: HTMLImageElement; | ||
/** Image element */ | ||
@memoize() | ||
protected get $images(): HTMLImageElement[] { | ||
if (this.$host.tagName === 'IMG') return [this.$host as HTMLImageElement]; | ||
return findAll(this.$host, this.config.selector) as HTMLImageElement[]; | ||
} | ||
|
||
get $target(): Element | null { | ||
return ESLTraversingQuery.first(this.target || '::parent', this.$host); | ||
/** Check if all images are loaded */ | ||
public get complete(): boolean { | ||
return this.$images.every(img => img.complete); | ||
} | ||
/** Check if any image has loading error */ | ||
public get hasError(): boolean { | ||
return this.$images.some(img => !img.naturalHeight && !img.naturalWidth); | ||
} | ||
|
||
protected override connectedCallback(): void { | ||
if (this.$host.tagName !== 'IMG') return; | ||
super.connectedCallback(); | ||
if (this.$host.complete) { | ||
const eventType = this.$host.naturalHeight && this.$host.naturalWidth ? 'load' : 'error'; | ||
this._onReady(new Event(eventType)); | ||
} | ||
else this.$$on(this._onReady); | ||
this._onReady(); | ||
} | ||
|
||
protected override attributeChangedCallback(name: string): void { | ||
if (name !== ESLImageContainerMixin.is) return; | ||
memoize.clear(this, ['config', '$images']); | ||
this._onReady(); | ||
} | ||
|
||
@listen({ | ||
event: 'load error', | ||
auto: false, | ||
once: true | ||
target: (that: ESLImageContainerMixin) => that.$images | ||
}) | ||
protected _onReady(event: Event): void { | ||
const {$target} = this; | ||
if (!$target) return; | ||
CSSClassUtils.add($target, this.targetCls); | ||
if (event.type === 'error') CSSClassUtils.add($target, this.targetErrorCls); | ||
protected _onReady(): void { | ||
if (!this.complete) return; | ||
this.$$off(); | ||
this.$$cls(this.config.readyCls, true); | ||
this.$$cls(this.config.errorCls, this.hasError); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
28 changes: 28 additions & 0 deletions
28
src/modules/esl-image-utils/core/esl-image-utils.container.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Image Container Defaults | ||
.img-container { | ||
position: relative; | ||
overflow: hidden; | ||
|
||
> img { | ||
width: 100%; | ||
} | ||
|
||
> img:is(.img-stretch, .img-cover, .img-contain) { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
height: 100%; | ||
} | ||
|
||
> img.img-cover { | ||
object-fit: cover; | ||
} | ||
|
||
> img.img-contain { | ||
object-fit: contain; | ||
} | ||
} | ||
|
||
picture.img-container { | ||
display: block; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.img-fade { | ||
opacity: 0; | ||
|
||
&.img-container-loaded, | ||
.img-container-loaded & { | ||
opacity: 1; | ||
transition: opacity 0.4s; | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/modules/esl-image-utils/core/esl-image-utils.ratios.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
.img-container { | ||
&.img-container-1-1 { | ||
aspect-ratio: 1; | ||
} | ||
|
||
&.img-container-4-3 { | ||
aspect-ratio: ~'4 / 3'; | ||
} | ||
|
||
&.img-container-16-9 { | ||
aspect-ratio: ~'16 / 9'; | ||
} | ||
|
||
&.img-container-26-9 { | ||
aspect-ratio: ~'26 / 9'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters