@inappstory/slide-api 0.1.34 → 0.1.36

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 CHANGED
@@ -1009,7 +1009,9 @@ const animationApi = {
1009
1009
  removeClass(elements[i], "active");
1010
1010
  removeClass(elements[i], "animated");
1011
1011
  elements[i].style.setProperty("transform", "");
1012
- elements[i].style.setProperty("filter", "");
1012
+ if (hasClass(elements[i], "narrative-element-animation-blur")) {
1013
+ elements[i].style.setProperty("filter", "");
1014
+ }
1013
1015
  }
1014
1016
  }
1015
1017
  }
@@ -5992,6 +5994,9 @@ class SlideTimer {
5992
5994
  if (currentTime != null) {
5993
5995
  // timeLeft correction
5994
5996
  this.timeLeft = this.duration - currentTime;
5997
+ if (this.timeLeft < 0) {
5998
+ this.timeLeft = 0;
5999
+ }
5995
6000
  }
5996
6001
  this.tick();
5997
6002
  }
@@ -6008,6 +6013,9 @@ class SlideTimer {
6008
6013
  }
6009
6014
  const dtDiff = new Date().getTime() - rafStartTime;
6010
6015
  this.timeLeft -= dtDiff;
6016
+ if (this.timeLeft < 0) {
6017
+ this.timeLeft = 0;
6018
+ }
6011
6019
  let progressPercent = Math.round(((this.duration - this.timeLeft) / this.duration) * 100 * 10000) / 10000;
6012
6020
  if (progressPercent > 100) {
6013
6021
  progressPercent = 100;
@@ -6077,14 +6085,16 @@ class Slider {
6077
6085
  });
6078
6086
  this.slidesFirstRenders[i] = item;
6079
6087
  }
6080
- const slideWrapper = this.createSliderElement({
6088
+ const { sliderWrapper, safeAreaView } = this.createSliderElement({
6081
6089
  slides: config.slides,
6082
6090
  nonce: config.nonce,
6083
6091
  slideRender: config.slideRender,
6084
6092
  navbarAppearance: config.navbarAppearance,
6093
+ singleSlideTimerAppearance: config.singleSlideTimerAppearance,
6085
6094
  });
6086
- config.root.appendChild(slideWrapper);
6087
- this.slideWrapperElement = slideWrapper;
6095
+ config.root.appendChild(sliderWrapper);
6096
+ this.sliderWrapperElement = sliderWrapper;
6097
+ this.safeAreaViewElement = safeAreaView;
6088
6098
  this.timelineController = createTimelineController(TimelineController, this.slides, this.config.getLayoutDirection.bind(this));
6089
6099
  // cardMounted: (card: HTMLElement) => Promise<void>
6090
6100
  requestAnimationFrame(async () => {
@@ -6100,12 +6110,16 @@ class Slider {
6100
6110
  }
6101
6111
  slides = [];
6102
6112
  sliderTrack = null;
6103
- bulletsContainer = null;
6104
6113
  slidesFirstRenders = [];
6105
- slideWrapperElement;
6114
+ sliderWrapperElement;
6115
+ safeAreaViewElement;
6116
+ isBulletsActive = false;
6117
+ isSingleSlideTimerActive = false;
6118
+ pausedAt = null;
6106
6119
  timelineController;
6107
- assembleNavbarCssVariables(navbarAppearance) {
6120
+ assembleAppearanceCssVariables(navbarAppearance, singleSlideTimerAppearance) {
6108
6121
  let css = "";
6122
+ /** Navbar variables **/
6109
6123
  if (navbarAppearance.edge_offset != null) {
6110
6124
  css += `--navbar-edge-offset: ${navbarAppearance.edge_offset};`;
6111
6125
  }
@@ -6148,25 +6162,53 @@ class Slider {
6148
6162
  if (navbarAppearance.horizontal_padding != null) {
6149
6163
  css += `--navbar-horizontal-padding: ${navbarAppearance.horizontal_padding};`;
6150
6164
  }
6151
- return `.cards-slider {${css}`;
6165
+ /** SingleSlideTimer variables **/
6166
+ if (singleSlideTimerAppearance.edge_offset != null) {
6167
+ css += `--timer-edge-offset: ${singleSlideTimerAppearance.edge_offset};`;
6168
+ }
6169
+ if (singleSlideTimerAppearance.timeline_background_color != null) {
6170
+ css += `--timer-timeline-background-color: ${singleSlideTimerAppearance.timeline_background_color};`;
6171
+ }
6172
+ if (singleSlideTimerAppearance.timeline_fill_color != null) {
6173
+ css += `--timer-timeline-fill-color: ${singleSlideTimerAppearance.timeline_fill_color};`;
6174
+ }
6175
+ if (singleSlideTimerAppearance.timeline_height != null) {
6176
+ css += `--timer-timeline-height: ${singleSlideTimerAppearance.timeline_height};`;
6177
+ }
6178
+ if (singleSlideTimerAppearance.timeline_border_radius != null) {
6179
+ css += `--timer-timeline-border-radius: ${singleSlideTimerAppearance.timeline_border_radius};`;
6180
+ }
6181
+ if (singleSlideTimerAppearance.horizontal_margin != null) {
6182
+ css += `--timer-horizontal-margin: ${singleSlideTimerAppearance.horizontal_margin};`;
6183
+ }
6184
+ return `.cards-slider {${css}}`;
6152
6185
  }
6153
- createSliderElement = ({ slides, nonce, slideRender, navbarAppearance, }) => {
6186
+ createSliderElement = ({ slides, nonce, slideRender, navbarAppearance, singleSlideTimerAppearance, }) => {
6154
6187
  const style = document.createElement("style");
6155
6188
  if (nonce != null) {
6156
6189
  style.nonce = nonce;
6157
6190
  }
6158
- style.innerText = this.assembleNavbarCssVariables(navbarAppearance);
6191
+ style.innerText = this.assembleAppearanceCssVariables(navbarAppearance, singleSlideTimerAppearance);
6159
6192
  const slider = document.createElement("div");
6160
6193
  slider.classList.add("cards-slider");
6161
6194
  const track = document.createElement("div");
6162
6195
  track.classList.add("cards-slider__track");
6163
6196
  this.sliderTrack = track;
6164
- const [bullets, updateTimelineProgress] = this.createBulletPoints(slides.length, this.config.getLayoutDirection.bind(this), navbarAppearance.position);
6165
- this.bulletsContainer = bullets;
6197
+ const [isBulletsActive, bullets, bulletsUpdateTimelineProgress] = this.createBulletPoints(slides.length, this.config.getLayoutDirection.bind(this), navbarAppearance.position);
6198
+ this.isBulletsActive = isBulletsActive;
6199
+ const [isSingleSlideTimerActive, singleSlideTimer, singleSlideTimerUpdateTimelineProgress] = this.createSingleSlideTimer(this.config.getLayoutDirection.bind(this), singleSlideTimerAppearance.position, singleSlideTimerAppearance.timeline_direction);
6200
+ this.isSingleSlideTimerActive = isSingleSlideTimerActive;
6166
6201
  this.slides = slides.map((slide, i) => ({
6167
6202
  element: slideRender(slide, i, this.slidesFirstRenders[i].firstRenderCallPromise),
6168
6203
  timer: new SlideTimer(cb => window.requestAnimationFrame(cb), handle => window.cancelAnimationFrame(handle), progressPercent => this.timelineController.onSlideTimerUpdate(i, progressPercent), this.onSlideTimerEnd.bind(this)),
6169
- updateTimelineProgress: (progressPercent, isActive) => updateTimelineProgress(i, progressPercent, isActive),
6204
+ updateTimelineProgress: (progressPercent, isActive) => {
6205
+ if (isBulletsActive) {
6206
+ bulletsUpdateTimelineProgress(i, progressPercent, isActive);
6207
+ }
6208
+ if (isSingleSlideTimerActive) {
6209
+ singleSlideTimerUpdateTimelineProgress(progressPercent);
6210
+ }
6211
+ },
6170
6212
  }));
6171
6213
  for (let i = 0; i < this.slides.length; ++i) {
6172
6214
  const slideElement = document.createElement("div");
@@ -6181,12 +6223,14 @@ class Slider {
6181
6223
  const safeAreaRelativeZoneView = document.createElement("div");
6182
6224
  safeAreaRelativeZoneView.classList.add("safe-area-relative-zone-view");
6183
6225
  safeAreaRelativeZoneView.appendChild(bullets);
6226
+ safeAreaRelativeZoneView.appendChild(singleSlideTimer);
6184
6227
  safeAreaView.appendChild(safeAreaRelativeZoneView);
6185
6228
  slider.appendChild(safeAreaView);
6186
6229
  slider.appendChild(style);
6187
- return slider;
6230
+ return { sliderWrapper: slider, safeAreaView };
6188
6231
  };
6189
6232
  createBulletPoints(count, getLayoutDirection, position) {
6233
+ let isActive = true;
6190
6234
  const bullets = document.createElement("div");
6191
6235
  bullets.classList.add("cards-slider__navbar");
6192
6236
  // force hide bullets container for single slide
@@ -6194,6 +6238,7 @@ class Slider {
6194
6238
  position = 0;
6195
6239
  }
6196
6240
  if (position === 0) {
6241
+ isActive = false;
6197
6242
  bullets.classList.add("cards-slider__navbar--position-none");
6198
6243
  }
6199
6244
  else if (position === 1) {
@@ -6202,10 +6247,6 @@ class Slider {
6202
6247
  else if (position === 2) {
6203
6248
  bullets.classList.add("cards-slider__navbar--position-bottom");
6204
6249
  }
6205
- else {
6206
- // default
6207
- bullets.classList.add("cards-slider__navbar--position-bottom");
6208
- }
6209
6250
  bullets.dir = getLayoutDirection();
6210
6251
  // skip creating view elements for single slide
6211
6252
  if (count > 1) {
@@ -6252,7 +6293,56 @@ class Slider {
6252
6293
  }
6253
6294
  }
6254
6295
  };
6255
- return [bullets, onUpdateTimelineProgress];
6296
+ return [isActive, bullets, onUpdateTimelineProgress];
6297
+ }
6298
+ createSingleSlideTimer(getLayoutDirection, position, timelineDirection) {
6299
+ let isActive = true;
6300
+ const timer = document.createElement("div");
6301
+ timer.classList.add("cards-slider__timer");
6302
+ if (position === 0) {
6303
+ isActive = false;
6304
+ timer.classList.add("cards-slider__timer--position-none");
6305
+ }
6306
+ else if (position === 1) {
6307
+ timer.classList.add("cards-slider__timer--position-top");
6308
+ }
6309
+ else if (position === 2) {
6310
+ timer.classList.add("cards-slider__timer--position-bottom");
6311
+ }
6312
+ timer.dir = getLayoutDirection();
6313
+ if (timelineDirection === 0) {
6314
+ timer.classList.add("cards-slider__timer--straight-direction");
6315
+ }
6316
+ else if (timelineDirection === 1) {
6317
+ timer.classList.add("cards-slider__timer--reverse-direction");
6318
+ }
6319
+ const timeline = document.createElement("div");
6320
+ timeline.classList.add("cards-slider__timer_timeline", "touchable");
6321
+ const timelineFill = document.createElement("div");
6322
+ timelineFill.classList.add("cards-slider__timer_timeline-fill");
6323
+ timeline.append(timelineFill);
6324
+ timer.appendChild(timeline);
6325
+ const onUpdateTimelineProgress = (progress) => {
6326
+ if (timelineFill != null) {
6327
+ // timeline straight direction
6328
+ if (timelineDirection === 0) {
6329
+ if (this.config.getLayoutDirection() === "rtl") {
6330
+ progress = -1 * progress;
6331
+ }
6332
+ // timeline reverse direction
6333
+ }
6334
+ else if (timelineDirection === 1) {
6335
+ if (this.config.getLayoutDirection() === "ltr") {
6336
+ progress = -100 - progress;
6337
+ }
6338
+ if (this.config.getLayoutDirection() === "rtl") {
6339
+ progress = 100 + progress;
6340
+ }
6341
+ }
6342
+ timelineFill.style.setProperty("transform", `translateX(${progress}%)`);
6343
+ }
6344
+ };
6345
+ return [isActive, timer, onUpdateTimelineProgress];
6256
6346
  }
6257
6347
  async showByIndex(newIndex) {
6258
6348
  const prevIndex = this.activeIndex;
@@ -6301,7 +6391,11 @@ class Slider {
6301
6391
  this.slidesFirstRenders[index].called = true;
6302
6392
  showSlidePromise = new Promise(resolve => {
6303
6393
  this.slidesFirstRenders[index].firstRenderCall(resolve);
6304
- }).then(_ => _);
6394
+ })
6395
+ .then(data => data)
6396
+ .catch(reason => {
6397
+ throw new Error(reason);
6398
+ });
6305
6399
  }
6306
6400
  else {
6307
6401
  showSlidePromise = this.config.onBeforeShowSlide(this.slides[index].element, index);
@@ -6331,6 +6425,8 @@ class Slider {
6331
6425
  }
6332
6426
  onUpdateSizeMetrics(metrics) {
6333
6427
  // this.slideTo(this.activeIndex, 0);
6428
+ // todo CSP violation
6429
+ this.safeAreaViewElement.style.fontSize = metrics.fontSize;
6334
6430
  }
6335
6431
  getSlideOffset(index) {
6336
6432
  if (!this.slides.length)
@@ -6381,8 +6477,9 @@ class Slider {
6381
6477
  }
6382
6478
  destroy() {
6383
6479
  this.activeSlide?.timer.stop();
6384
- if (this.slideWrapperElement != null && this.config.root != null) {
6385
- this.config.root.removeChild(this.slideWrapperElement);
6480
+ this.pausedAt = null;
6481
+ if (this.sliderWrapperElement != null && this.config.root != null) {
6482
+ this.config.root.removeChild(this.sliderWrapperElement);
6386
6483
  }
6387
6484
  }
6388
6485
  async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
@@ -6408,10 +6505,14 @@ class Slider {
6408
6505
  resumeTimer = true;
6409
6506
  }
6410
6507
  if (currentTime === duration) {
6411
- // skip timer start for already ended layer timeline
6412
6508
  // skip timer start for already ended layer timeline
6413
6509
  resumeTimer = false;
6414
6510
  }
6511
+ // if single slide timer mode - calc diff for blur time, override currentTime
6512
+ if (this.isSingleSlideTimerActive && this.pausedAt != null) {
6513
+ currentTime += new Date().getTime() - this.pausedAt;
6514
+ // we must resume timer - for trigger done callback and hide Card (SingleSlideTimer business logic)
6515
+ }
6415
6516
  if (resumeTimer) {
6416
6517
  this.activeSlide?.timer.resume(currentTime, duration);
6417
6518
  }
@@ -6422,6 +6523,9 @@ class Slider {
6422
6523
  this.config.onSlideDataWaiting();
6423
6524
  }
6424
6525
  this.activeSlide?.timer.pause();
6526
+ if (this.isSingleSlideTimerActive) {
6527
+ this.pausedAt = new Date().getTime();
6528
+ }
6425
6529
  // console.log("TIMELINE_ACTION.PAUSE", { activeSlide: this.activeSlide, duration });
6426
6530
  break;
6427
6531
  }
@@ -6449,6 +6553,7 @@ class Slider {
6449
6553
  root: HTMLElement;
6450
6554
  nonce?: string;
6451
6555
  navbarAppearance: NavbarAppearance;
6556
+ singleSlideTimerAppearance: SingleSlideTimerAppearance;
6452
6557
  slideRender: SlideRender<T>;
6453
6558
  onSlideMounted: OnSlideMounted;
6454
6559
  onBeforeShowSlide: OnBeforeShowSlide;
@@ -6660,12 +6765,33 @@ class CardApi {
6660
6765
  return this.activeSlide.showSlide(html);
6661
6766
  }
6662
6767
  slider = null;
6663
- async showSlides(slides, cardAppearance, index = 0) {
6768
+ globalCssVariablesImported = false;
6769
+ importGlobalCssVariables(safeAreaInsetTop, safeAreaInsetBottom) {
6770
+ if (!this.globalCssVariablesImported) {
6771
+ const style = document.createElement("style");
6772
+ if (this.config.nonce != null) {
6773
+ style.nonce = this.config.nonce;
6774
+ }
6775
+ let css = "";
6776
+ if (safeAreaInsetBottom != null) {
6777
+ css += `--safe-area-inset-top: ${safeAreaInsetTop}px;`;
6778
+ }
6779
+ if (safeAreaInsetBottom != null) {
6780
+ css += `--safe-area-inset-bottom: ${safeAreaInsetBottom}px;`;
6781
+ }
6782
+ style.innerText = `:root {${css}}`;
6783
+ this.config.root.appendChild(style);
6784
+ this.globalCssVariablesImported = true;
6785
+ }
6786
+ }
6787
+ async showSlides(slides, cardAppearance, index = 0, config = {}) {
6664
6788
  this.slidesMode = 1 /* SLIDES_MODE.MULTIPLE */;
6665
6789
  if (this.cardLoadingStateController === null) {
6666
6790
  this.cardLoadingStateController = new CardLoadingStateController(this.sdkApi.onCardLoadingStateChange.bind(this.sdkApi));
6667
6791
  }
6668
6792
  this.cardLoadingStateController.onSetLoadStartState();
6793
+ // TODO mv to CardApi CTOR
6794
+ this.importGlobalCssVariables(config.safeAreaInsetTop, config.safeAreaInsetBottom);
6669
6795
  slides.forEach((content, index) => {
6670
6796
  if (this.slides[index] == null) {
6671
6797
  const item = { content, resourcesReadyPromise: null };
@@ -6831,6 +6957,7 @@ class CardApi {
6831
6957
  if (this.slider != null) {
6832
6958
  this.slider.destroy();
6833
6959
  }
6960
+ const singleSlideTimerAppearance = cardAppearance.singleSlideTimer ?? {};
6834
6961
  this.slider = new Slider({
6835
6962
  root: this.config.root,
6836
6963
  slides: this.slides.map(({ content, resourcesReadyPromise }) => ({
@@ -6839,6 +6966,7 @@ class CardApi {
6839
6966
  })),
6840
6967
  nonce: this.config.nonce,
6841
6968
  navbarAppearance: cardAppearance.navbar ?? {},
6969
+ singleSlideTimerAppearance: singleSlideTimerAppearance,
6842
6970
  slideRender,
6843
6971
  onSlideMounted,
6844
6972
  onBeforeShowSlide,
@@ -6847,7 +6975,16 @@ class CardApi {
6847
6975
  onShowSlide,
6848
6976
  onSlideLeft,
6849
6977
  getLayoutDirection: () => this.layoutDirection,
6850
- onSlideTimerEnd: () => this.activeSlide.slideTimerEnd(),
6978
+ onSlideTimerEnd: () => {
6979
+ // special for IAM with type Toast - single slide, close toast after slideTimerEnd
6980
+ // singleSlideTimerAppearance.position !== 0 (SingleSlideTimer is visible) - sign that this is Toast IAM
6981
+ if (singleSlideTimerAppearance.position !== 0) {
6982
+ this.activeSlide.slideApiDeps.closeCard("Single slide timer end");
6983
+ }
6984
+ else {
6985
+ this.activeSlide.slideTimerEnd();
6986
+ }
6987
+ },
6851
6988
  onSlideChangeActiveIndex: index => (this.activeSlide = this.slides[index].slide),
6852
6989
  onSlideStart: () => {
6853
6990
  // return Promise.resolve({currentTime: 0});
@@ -6859,6 +6996,8 @@ class CardApi {
6859
6996
  onSlideDataResume: () => this.cardLoadingStateController.onSetLoadEndState(),
6860
6997
  onSlideDataError: () => this.cardLoadingStateController.onSetLoadEndState(),
6861
6998
  });
6999
+ // to set font size at SafeAreaView inside Slider
7000
+ this.slider.onUpdateSizeMetrics(this.sizeMetrics);
6862
7001
  await this.slider.showByIndex(index);
6863
7002
  // return await onShowActiveCard;
6864
7003
  }
@@ -6971,12 +7110,14 @@ class CardApi {
6971
7110
  this._sdkClientVariables = variables;
6972
7111
  }
6973
7112
  setSlideInCacheStatus(index, status) {
6974
- if (this.slides[index] != null && this.slides[index].resourcesReadyPromisesResolver != null) {
6975
- if (status === 1 /* SLIDE_IN_CACHE_STATUS.SUCCESS */) {
6976
- this.slides[index].resourcesReadyPromisesResolver.resolve();
6977
- }
6978
- else {
6979
- this.slides[index].resourcesReadyPromisesResolver.reject();
7113
+ if (this.slides[index] != null) {
7114
+ if (this.slides[index].resourcesReadyPromisesResolver != null) {
7115
+ if (status === 1 /* SLIDE_IN_CACHE_STATUS.SUCCESS */) {
7116
+ this.slides[index].resourcesReadyPromisesResolver.resolve();
7117
+ }
7118
+ else {
7119
+ this.slides[index].resourcesReadyPromisesResolver.reject();
7120
+ }
6980
7121
  }
6981
7122
  }
6982
7123
  else {
@@ -7380,22 +7521,27 @@ class TimerRenderer {
7380
7521
  render(time) {
7381
7522
  const container = document.createElement("div");
7382
7523
  container.classList.add("narrative-element-timer__container");
7383
- const days = this.createGroup("d");
7384
- const hours = this.createGroup("h");
7385
- const minutes = this.createGroup("m");
7386
- const seconds = this.createGroup("s");
7387
7524
  if (time.days > 0) {
7388
- container.appendChild(days);
7389
- container.appendChild(this.createDelimiter());
7390
- }
7391
- container.appendChild(hours);
7392
- container.appendChild(this.createDelimiter());
7393
- container.appendChild(minutes);
7394
- container.appendChild(this.createDelimiter());
7395
- container.appendChild(seconds);
7525
+ this.renderByFormat(container, "d:h:m");
7526
+ }
7527
+ else if (time.hours > 0) {
7528
+ this.renderByFormat(container, "h:m:s");
7529
+ }
7530
+ else {
7531
+ this.renderByFormat(container, "m:s");
7532
+ }
7396
7533
  this.setTime(time);
7397
7534
  return container;
7398
7535
  }
7536
+ renderByFormat(container, format) {
7537
+ const parts = format.split(":");
7538
+ for (let i = 0; i < parts.length; i++) {
7539
+ container.appendChild(this.createGroup(parts[i]));
7540
+ if (i < parts.length - 1) {
7541
+ container.appendChild(this.createDelimiter());
7542
+ }
7543
+ }
7544
+ }
7399
7545
  pad(num) {
7400
7546
  return num.toString().padStart(2, "0");
7401
7547
  }
@@ -7424,20 +7570,28 @@ class TimerRenderer {
7424
7570
  }
7425
7571
  setDays(days) {
7426
7572
  const padded = this.pad(days);
7573
+ if (!this.digits["d1"] || !this.digits["d2"])
7574
+ return;
7427
7575
  this.digits["d1"].textContent = padded[0];
7428
7576
  this.digits["d2"].textContent = padded[1];
7429
7577
  }
7430
7578
  setHours(hours) {
7579
+ if (!this.digits["h1"] || !this.digits["h2"])
7580
+ return;
7431
7581
  const padded = this.pad(hours);
7432
7582
  this.digits["h1"].textContent = padded[0];
7433
7583
  this.digits["h2"].textContent = padded[1];
7434
7584
  }
7435
7585
  setMinutes(minutes) {
7586
+ if (!this.digits["m1"] || !this.digits["m2"])
7587
+ return;
7436
7588
  const padded = this.pad(minutes);
7437
7589
  this.digits["m1"].textContent = padded[0];
7438
7590
  this.digits["m2"].textContent = padded[1];
7439
7591
  }
7440
7592
  setSeconds(seconds) {
7593
+ if (!this.digits["s1"] || !this.digits["s2"])
7594
+ return;
7441
7595
  const padded = this.pad(seconds);
7442
7596
  this.digits["s1"].textContent = padded[0];
7443
7597
  this.digits["s2"].textContent = padded[1];