@ecodev/natural 55.2.0 → 55.4.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.
@@ -5792,14 +5792,20 @@ function stripTags(str) {
5792
5792
  * configured for it in the routing.
5793
5793
  */
5794
5794
  class NaturalSeoService {
5795
- constructor(config, router, titleService, metaTagService, document, locale) {
5796
- this.config = config;
5795
+ constructor(configToken, router, titleService, metaTagService, document, locale) {
5797
5796
  this.router = router;
5798
5797
  this.titleService = titleService;
5799
5798
  this.metaTagService = metaTagService;
5800
5799
  this.document = document;
5801
5800
  this.locale = locale;
5802
- this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
5801
+ this.config = {
5802
+ applicationName: '',
5803
+ };
5804
+ combineLatest({
5805
+ config: configToken instanceof Observable ? configToken.pipe(startWith(this.config)) : of(configToken),
5806
+ navigationEnd: this.router.events.pipe(filter(event => event instanceof NavigationEnd)),
5807
+ }).subscribe(({ config }) => {
5808
+ this.config = config;
5803
5809
  const root = this.router.routerState.root.snapshot;
5804
5810
  this.routeData = this.getRouteData(root);
5805
5811
  const seo = this.routeData.seo ?? { title: '' };
@@ -5819,11 +5825,11 @@ class NaturalSeoService {
5819
5825
  /**
5820
5826
  * Update the SEO with given info. The extra part and app name will be appended automatically.
5821
5827
  *
5822
- * In most cases this should not be used, and instead the SEO should be configured in the routing,
5828
+ * In most cases, this should not be used. And instead, the SEO should be configured in the routing,
5823
5829
  * possibly with the callback variant for some dynamism.
5824
5830
  *
5825
- * But in rare cases only the Component is able to build a proper page title, after it gather everything it
5826
- * needed. For those cases the Component can inject this service and update the SEO directly.
5831
+ * But in rare cases, only the Component is able to build a proper page title, after it gathered everything it
5832
+ * needed. For those cases, the Component can inject this service and update the SEO directly.
5827
5833
  */
5828
5834
  update(seo) {
5829
5835
  // Title
@@ -5843,7 +5849,7 @@ class NaturalSeoService {
5843
5849
  // Canonical
5844
5850
  // Add language in url (after domain) if some languages are provided only
5845
5851
  const language = this.config.languages?.length && this.locale ? this.locale.split('-')[0] : '';
5846
- const urlParts = this.getUrlParts(seo.canonicalQueryParamsWhitelist || []);
5852
+ const urlParts = this.getUrlParts(seo.canonicalQueryParamsWhitelist ?? []);
5847
5853
  this.updateLinkTag({ rel: 'canonical', href: this.getUrl(urlParts, language) });
5848
5854
  this.updateAlternates(urlParts);
5849
5855
  }
@@ -5864,10 +5870,10 @@ class NaturalSeoService {
5864
5870
  }
5865
5871
  // Query Params
5866
5872
  let params = '';
5867
- for (const param in urlTree.queryParams) {
5868
- if (whiteListedParams.includes(param)) {
5869
- const key = encodeURIComponent(param);
5870
- const value = encodeURIComponent(urlTree.queryParams[param]);
5873
+ for (const whiteListedParam of whiteListedParams) {
5874
+ if (whiteListedParam in urlTree.queryParams) {
5875
+ const key = encodeURIComponent(whiteListedParam);
5876
+ const value = encodeURIComponent(urlTree.queryParams[whiteListedParam]);
5871
5877
  if (params.length) {
5872
5878
  params += '&';
5873
5879
  }
@@ -5881,9 +5887,6 @@ class NaturalSeoService {
5881
5887
  }
5882
5888
  /**
5883
5889
  * Add language between domain and uri https://example.com/fr/folder/page
5884
- * @param urlParts
5885
- * @param language
5886
- * @private
5887
5890
  */
5888
5891
  getUrl(urlParts, language) {
5889
5892
  let url = urlParts.url;
@@ -5915,7 +5918,7 @@ class NaturalSeoService {
5915
5918
  }
5916
5919
  }
5917
5920
  updateLinkTag(definition) {
5918
- const linkElement = this.document.head.querySelector(this._parseSelector(definition)) ||
5921
+ const linkElement = this.document.head.querySelector(this.parseSelector(definition)) ??
5919
5922
  this.document.head.appendChild(this.document.createElement('link'));
5920
5923
  if (linkElement) {
5921
5924
  Object.keys(definition).forEach((attribute) => {
@@ -5924,13 +5927,11 @@ class NaturalSeoService {
5924
5927
  }
5925
5928
  }
5926
5929
  /**
5927
- * Parse tag to create a selector
5928
- * @param definition
5929
- * @return {string} selector to use in querySelector
5930
+ * Returns selector to use in querySelector to get the given link
5930
5931
  */
5931
- _parseSelector(definition) {
5932
+ parseSelector(definition) {
5932
5933
  let attributes = 'link';
5933
- Object.keys(definition).forEach((attr) => {
5934
+ Object.keys(definition).forEach(attr => {
5934
5935
  if (attr !== 'href') {
5935
5936
  attributes += `[${attr}="${definition[attr]}"]`;
5936
5937
  }
@@ -10781,7 +10782,7 @@ function getInitials(name, size) {
10781
10782
  */
10782
10783
  class Initials extends Source {
10783
10784
  getAvatar(size) {
10784
- return getInitials(this.getValue(), size);
10785
+ return getInitials(this.getValue().replace(/[^a-zA-Z0-9\s]/g, ''), size); // only letters, numbers and space
10785
10786
  }
10786
10787
  isTextual() {
10787
10788
  return true;
@@ -10815,14 +10816,15 @@ class AvatarService {
10815
10816
  ['initials', Initials],
10816
10817
  ]);
10817
10818
  this.avatarColors = [
10818
- '#1abc9c',
10819
- '#3498db',
10820
- '#f1c40f',
10821
- '#8e44ad',
10822
- '#e74c3c',
10823
- '#d35400',
10824
- '#2c3e50',
10825
- '#7f8c8d',
10819
+ '#ff0000',
10820
+ '#ff8800',
10821
+ '#dabb00',
10822
+ '#00c200',
10823
+ '#01cbcb',
10824
+ '#008cff',
10825
+ '#ff00d8',
10826
+ '#c800ff',
10827
+ '#3b3b3b',
10826
10828
  ];
10827
10829
  this.failedSources = new Map();
10828
10830
  }
@@ -10868,10 +10870,11 @@ class NaturalAvatarComponent {
10868
10870
  constructor(avatarService) {
10869
10871
  this.avatarService = avatarService;
10870
10872
  this.size = 50;
10871
- this.textSizeRatio = 3;
10873
+ this.decorated = true;
10874
+ this.textSizeRatio = 2.25;
10872
10875
  this.fgColor = '#FFF';
10873
10876
  this.borderRadius = '';
10874
- this.textMaximumLength = 0;
10877
+ this.textMaximumLength = 2;
10875
10878
  this.avatarSrc = null;
10876
10879
  this.avatarText = null;
10877
10880
  this.avatarStyle = {};
@@ -10966,6 +10969,8 @@ class NaturalAvatarComponent {
10966
10969
  backgroundColor: this.bgColor ? this.bgColor : this.avatarService.getRandomColor(avatarValue),
10967
10970
  font: Math.floor(+this.size / this.textSizeRatio) + 'px Helvetica, Arial, sans-serif',
10968
10971
  lineHeight: this.size + 'px',
10972
+ width: this.size + 'px',
10973
+ height: this.size + 'px',
10969
10974
  };
10970
10975
  }
10971
10976
  /**
@@ -10980,7 +10985,7 @@ class NaturalAvatarComponent {
10980
10985
  };
10981
10986
  }
10982
10987
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.2", ngImport: i0, type: NaturalAvatarComponent, deps: [{ token: AvatarService }], target: i0.ɵɵFactoryTarget.Component }); }
10983
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.2", type: NaturalAvatarComponent, isStandalone: true, selector: "natural-avatar", inputs: { image: "image", initials: "initials", gravatar: "gravatar", size: "size", textSizeRatio: "textSizeRatio", bgColor: "bgColor", fgColor: "fgColor", borderRadius: "borderRadius", textMaximumLength: "textMaximumLength" }, usesOnChanges: true, ngImport: i0, template: `
10988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.2", type: NaturalAvatarComponent, isStandalone: true, selector: "natural-avatar", inputs: { image: "image", initials: "initials", gravatar: "gravatar", size: "size", decorated: "decorated", textSizeRatio: "textSizeRatio", bgColor: "bgColor", fgColor: "fgColor", borderRadius: "borderRadius", textMaximumLength: "textMaximumLength" }, host: { properties: { "style.height.px": "this.size", "style.width.px": "this.size", "class.decorated": "this.decorated" } }, usesOnChanges: true, ngImport: i0, template: `
10984
10989
  <div class="avatar-container" [ngStyle]="hostStyle">
10985
10990
  <img
10986
10991
  *ngIf="avatarSrc"
@@ -10992,11 +10997,16 @@ class NaturalAvatarComponent {
10992
10997
  class="avatar-content"
10993
10998
  loading="lazy"
10994
10999
  />
10995
- <div *ngIf="avatarText" class="avatar-content" [ngStyle]="avatarStyle">
11000
+ <div
11001
+ *ngIf="avatarText"
11002
+ class="avatar-content"
11003
+ [class.natural-elevation]="decorated"
11004
+ [ngStyle]="avatarStyle"
11005
+ >
10996
11006
  {{ avatarText }}
10997
11007
  </div>
10998
11008
  </div>
10999
- `, isInline: true, styles: [":host{border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
11009
+ `, isInline: true, styles: [":host{display:block}:host.decorated{position:relative}:host.decorated .avatar-container:before{content:\"\";position:absolute;inset:0;border-radius:50%;background:linear-gradient(345deg,rgba(255,255,255,0) 25%,rgba(255,255,255,.33) 100%)}:host.decorated .avatar-content{text-shadow:0 1px 0 rgba(0,0,0,.6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
11000
11010
  }
11001
11011
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.2", ngImport: i0, type: NaturalAvatarComponent, decorators: [{
11002
11012
  type: Component,
@@ -11012,11 +11022,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.2", ngImpor
11012
11022
  class="avatar-content"
11013
11023
  loading="lazy"
11014
11024
  />
11015
- <div *ngIf="avatarText" class="avatar-content" [ngStyle]="avatarStyle">
11025
+ <div
11026
+ *ngIf="avatarText"
11027
+ class="avatar-content"
11028
+ [class.natural-elevation]="decorated"
11029
+ [ngStyle]="avatarStyle"
11030
+ >
11016
11031
  {{ avatarText }}
11017
11032
  </div>
11018
11033
  </div>
11019
- `, standalone: true, imports: [CommonModule], styles: [":host{border-radius:50%}\n"] }]
11034
+ `, standalone: true, imports: [CommonModule], styles: [":host{display:block}:host.decorated{position:relative}:host.decorated .avatar-container:before{content:\"\";position:absolute;inset:0;border-radius:50%;background:linear-gradient(345deg,rgba(255,255,255,0) 25%,rgba(255,255,255,.33) 100%)}:host.decorated .avatar-content{text-shadow:0 1px 0 rgba(0,0,0,.6)}\n"] }]
11020
11035
  }], ctorParameters: function () { return [{ type: AvatarService }]; }, propDecorators: { image: [{
11021
11036
  type: Input
11022
11037
  }], initials: [{
@@ -11024,6 +11039,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.2", ngImpor
11024
11039
  }], gravatar: [{
11025
11040
  type: Input
11026
11041
  }], size: [{
11042
+ type: HostBinding,
11043
+ args: ['style.height.px']
11044
+ }, {
11045
+ type: HostBinding,
11046
+ args: ['style.width.px']
11047
+ }, {
11048
+ type: Input
11049
+ }], decorated: [{
11050
+ type: HostBinding,
11051
+ args: ['class.decorated']
11052
+ }, {
11027
11053
  type: Input
11028
11054
  }], textSizeRatio: [{
11029
11055
  type: Input