@qite/tide-booking-component 1.4.63 → 1.4.65

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.
@@ -44935,7 +44935,7 @@ var ImageWithTextCard = function (_a) {
44935
44935
  cardClassName += ' image-with-text__card--no-card';
44936
44936
  }
44937
44937
  if (fullImage) {
44938
- cardClassName += ' image-with-text__card--full-image';
44938
+ cardClassName += ' image-with-text__card--full-img';
44939
44939
  }
44940
44940
  if (reverse) {
44941
44941
  cardClassName += ' image-with-text__card--reverse';
@@ -45001,6 +45001,190 @@ var ImageWithTextSection = function (_a) {
45001
45001
  );
45002
45002
  };
45003
45003
 
45004
+ var PhotoGallery = function (_a) {
45005
+ var _b, _c, _d;
45006
+ var images = _a.images,
45007
+ title = _a.title,
45008
+ intro = _a.intro;
45009
+ var _e = React.useState(null),
45010
+ activeIndex = _e[0],
45011
+ setActiveIndex = _e[1];
45012
+ var isOpen = activeIndex !== null;
45013
+ var activeImage = activeIndex !== null ? images[activeIndex] : null;
45014
+ var close = function () {
45015
+ return setActiveIndex(null);
45016
+ };
45017
+ var next = function () {
45018
+ if (activeIndex === null) return;
45019
+ setActiveIndex((activeIndex + 1) % images.length);
45020
+ };
45021
+ var prev = function () {
45022
+ if (activeIndex === null) return;
45023
+ setActiveIndex((activeIndex - 1 + images.length) % images.length);
45024
+ };
45025
+ React.useEffect(
45026
+ function () {
45027
+ if (!isOpen) return;
45028
+ var onKeyDown = function (e) {
45029
+ if (e.key === 'Escape') close();
45030
+ if (e.key === 'ArrowRight') next();
45031
+ if (e.key === 'ArrowLeft') prev();
45032
+ };
45033
+ document.addEventListener('keydown', onKeyDown);
45034
+ document.body.style.overflow = 'hidden';
45035
+ return function () {
45036
+ document.removeEventListener('keydown', onKeyDown);
45037
+ document.body.style.overflow = '';
45038
+ };
45039
+ },
45040
+ [isOpen, activeIndex, images.length]
45041
+ );
45042
+ if (!images.length) {
45043
+ return React__default['default'].createElement(
45044
+ 'section',
45045
+ { className: 'gallery' },
45046
+ React__default['default'].createElement('p', { className: 'gallery__empty' }, 'No photos available.')
45047
+ );
45048
+ }
45049
+ var big = images[0];
45050
+ var thumbs = images.slice(1, 6);
45051
+ var extraCount = Math.max(0, images.length - 6);
45052
+ var openAt = function (index) {
45053
+ if (!images[index]) return;
45054
+ setActiveIndex(index);
45055
+ };
45056
+ return React__default['default'].createElement(
45057
+ 'div',
45058
+ { className: 'content' },
45059
+ React__default['default'].createElement(
45060
+ 'div',
45061
+ { className: 'content__container' },
45062
+ React__default['default'].createElement(
45063
+ 'div',
45064
+ { className: 'content__colums content__colums--2-1' },
45065
+ React__default['default'].createElement(
45066
+ 'section',
45067
+ { className: 'gallery' },
45068
+ React__default['default'].createElement(
45069
+ 'div',
45070
+ { className: 'gallery__layout' },
45071
+ React__default['default'].createElement(
45072
+ 'button',
45073
+ {
45074
+ type: 'button',
45075
+ className: 'gallery__big',
45076
+ onClick: function () {
45077
+ return openAt(0);
45078
+ },
45079
+ 'aria-label': 'Open image 1'
45080
+ },
45081
+ React__default['default'].createElement('img', {
45082
+ className: 'gallery__big__img',
45083
+ src: big.src,
45084
+ alt: (_b = big.alt) !== null && _b !== void 0 ? _b : '',
45085
+ loading: 'eager'
45086
+ })
45087
+ ),
45088
+ React__default['default'].createElement(
45089
+ 'div',
45090
+ { className: 'gallery__thumbs', 'aria-label': 'Gallery thumbnails' },
45091
+ thumbs.map(function (img, i) {
45092
+ var _a;
45093
+ var realIndex = i + 1;
45094
+ var isLastThumbSlot = i === 4;
45095
+ var shouldShowMoreOverlay = isLastThumbSlot && extraCount > 0;
45096
+ return React__default['default'].createElement(
45097
+ 'button',
45098
+ {
45099
+ key: ''.concat(img.src, '-').concat(realIndex),
45100
+ type: 'button',
45101
+ className: 'gallery__thumb '.concat(shouldShowMoreOverlay ? 'gallery__thumb--more' : ''),
45102
+ onClick: function () {
45103
+ return openAt(realIndex);
45104
+ },
45105
+ 'aria-label': 'Open image '.concat(realIndex + 1)
45106
+ },
45107
+ React__default['default'].createElement('img', {
45108
+ className: 'gallery__thumb__img',
45109
+ src: img.src,
45110
+ alt: (_a = img.alt) !== null && _a !== void 0 ? _a : '',
45111
+ loading: 'lazy'
45112
+ }),
45113
+ shouldShowMoreOverlay &&
45114
+ React__default['default'].createElement(
45115
+ 'span',
45116
+ { className: 'gallery__thumb__overlay', 'aria-label': ''.concat(extraCount, ' more photos') },
45117
+ '+',
45118
+ extraCount
45119
+ )
45120
+ );
45121
+ })
45122
+ )
45123
+ ),
45124
+ isOpen &&
45125
+ activeImage &&
45126
+ React__default['default'].createElement(
45127
+ 'div',
45128
+ {
45129
+ className: 'gallery__lightbox',
45130
+ role: 'dialog',
45131
+ 'aria-modal': 'true',
45132
+ onMouseDown: function (e) {
45133
+ if (e.target === e.currentTarget) close();
45134
+ }
45135
+ },
45136
+ React__default['default'].createElement(
45137
+ 'div',
45138
+ { className: 'gallery__lightbox__panel' },
45139
+ React__default['default'].createElement(
45140
+ 'button',
45141
+ { type: 'button', className: 'gallery__btn__icon gallery__btn__icon--close', 'aria-label': 'Close', onClick: close },
45142
+ React__default['default'].createElement(Icon$3, { name: 'ui-close', width: 16, height: 16 })
45143
+ ),
45144
+ React__default['default'].createElement(
45145
+ 'div',
45146
+ { className: 'gallery__lightbox__media' },
45147
+ React__default['default'].createElement('img', {
45148
+ className: 'gallery__lightbox__img',
45149
+ src: activeImage.src,
45150
+ alt: (_c = activeImage.alt) !== null && _c !== void 0 ? _c : ''
45151
+ })
45152
+ ),
45153
+ React__default['default'].createElement(
45154
+ 'div',
45155
+ { className: 'gallery__lightbox__footer' },
45156
+ React__default['default'].createElement(
45157
+ 'div',
45158
+ { className: 'gallery__lightbox__info' },
45159
+ React__default['default'].createElement('span', { className: 'gallery__lightbox__index' }, activeIndex + 1, ' / ', images.length),
45160
+ (activeImage.caption || activeImage.alt) &&
45161
+ React__default['default'].createElement(
45162
+ 'span',
45163
+ { className: 'gallery__lightbox__caption' },
45164
+ (_d = activeImage.caption) !== null && _d !== void 0 ? _d : activeImage.alt
45165
+ )
45166
+ ),
45167
+ React__default['default'].createElement(
45168
+ 'div',
45169
+ { className: 'gallery__lightbox__controls' },
45170
+ React__default['default'].createElement('button', { type: 'button', className: 'gallery__btn', onClick: prev }, '\u2190'),
45171
+ React__default['default'].createElement('button', { type: 'button', className: 'gallery__btn', onClick: next }, '\u2192')
45172
+ )
45173
+ )
45174
+ )
45175
+ )
45176
+ ),
45177
+ React__default['default'].createElement(
45178
+ 'div',
45179
+ null,
45180
+ React__default['default'].createElement('h2', null, title),
45181
+ React__default['default'].createElement('p', null, intro)
45182
+ )
45183
+ )
45184
+ )
45185
+ );
45186
+ };
45187
+
45004
45188
  var signalR$1 = {};
45005
45189
 
45006
45190
  var jqueryDeferred$1 = { exports: {} };
@@ -48903,5 +49087,7 @@ exports.ImageCardGrid = ImageCardGrid;
48903
49087
  exports.ImageWithTextSection = ImageWithTextSection;
48904
49088
  exports.Login = Login;
48905
49089
  exports.Navbar = Navbar;
49090
+ exports.PhotoGallery = PhotoGallery;
48906
49091
  exports.QSM = QSM;
48907
49092
  exports.SearchResults = SearchResults;
49093
+ exports.Slider = Slider;
@@ -4,9 +4,10 @@ export interface GalleryImage {
4
4
  alt?: string;
5
5
  caption?: string;
6
6
  }
7
- interface GalleryProps {
8
- images: GalleryImage[];
7
+ export interface GalleryProps {
9
8
  title?: string;
9
+ intro?: string;
10
+ images: GalleryImage[];
10
11
  }
11
- export default function PhotoGallery({ images, title }: GalleryProps): React.JSX.Element;
12
- export {};
12
+ declare const PhotoGallery: React.FC<GalleryProps>;
13
+ export default PhotoGallery;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- interface SliderProps {
2
+ export interface SliderProps {
3
3
  path?: string;
4
4
  images: string[];
5
5
  mode?: 'auto' | 'manual';
@@ -8,6 +8,8 @@ import SearchResults from './search-results';
8
8
  import ImageCardGrid from './content/image-card-grid';
9
9
  import Login from './content/login';
10
10
  import ImageWithTextSection from './content/image-with-text-section';
11
+ import Slider from './content/components/slider';
12
+ import PhotoGallery from './content/components/gallery';
11
13
  export * from './content/navbar/types';
12
14
  export * from './content/header/types';
13
15
  export * from './content/footer/types';
@@ -17,4 +19,4 @@ export * from './content/image-with-text-section/types';
17
19
  export * from './search-results/types';
18
20
  export * from './qsm/types';
19
21
  export * from './shared/types';
20
- export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection };
22
+ export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection, Slider, PhotoGallery };
@@ -44643,7 +44643,7 @@ var ImageWithTextCard = function (_a) {
44643
44643
  cardClassName += ' image-with-text__card--no-card';
44644
44644
  }
44645
44645
  if (fullImage) {
44646
- cardClassName += ' image-with-text__card--full-image';
44646
+ cardClassName += ' image-with-text__card--full-img';
44647
44647
  }
44648
44648
  if (reverse) {
44649
44649
  cardClassName += ' image-with-text__card--reverse';
@@ -44709,6 +44709,185 @@ var ImageWithTextSection = function (_a) {
44709
44709
  );
44710
44710
  };
44711
44711
 
44712
+ var PhotoGallery = function (_a) {
44713
+ var _b, _c, _d;
44714
+ var images = _a.images,
44715
+ title = _a.title,
44716
+ intro = _a.intro;
44717
+ var _e = useState(null),
44718
+ activeIndex = _e[0],
44719
+ setActiveIndex = _e[1];
44720
+ var isOpen = activeIndex !== null;
44721
+ var activeImage = activeIndex !== null ? images[activeIndex] : null;
44722
+ var close = function () {
44723
+ return setActiveIndex(null);
44724
+ };
44725
+ var next = function () {
44726
+ if (activeIndex === null) return;
44727
+ setActiveIndex((activeIndex + 1) % images.length);
44728
+ };
44729
+ var prev = function () {
44730
+ if (activeIndex === null) return;
44731
+ setActiveIndex((activeIndex - 1 + images.length) % images.length);
44732
+ };
44733
+ useEffect(
44734
+ function () {
44735
+ if (!isOpen) return;
44736
+ var onKeyDown = function (e) {
44737
+ if (e.key === 'Escape') close();
44738
+ if (e.key === 'ArrowRight') next();
44739
+ if (e.key === 'ArrowLeft') prev();
44740
+ };
44741
+ document.addEventListener('keydown', onKeyDown);
44742
+ document.body.style.overflow = 'hidden';
44743
+ return function () {
44744
+ document.removeEventListener('keydown', onKeyDown);
44745
+ document.body.style.overflow = '';
44746
+ };
44747
+ },
44748
+ [isOpen, activeIndex, images.length]
44749
+ );
44750
+ if (!images.length) {
44751
+ return React__default.createElement(
44752
+ 'section',
44753
+ { className: 'gallery' },
44754
+ React__default.createElement('p', { className: 'gallery__empty' }, 'No photos available.')
44755
+ );
44756
+ }
44757
+ var big = images[0];
44758
+ var thumbs = images.slice(1, 6);
44759
+ var extraCount = Math.max(0, images.length - 6);
44760
+ var openAt = function (index) {
44761
+ if (!images[index]) return;
44762
+ setActiveIndex(index);
44763
+ };
44764
+ return React__default.createElement(
44765
+ 'div',
44766
+ { className: 'content' },
44767
+ React__default.createElement(
44768
+ 'div',
44769
+ { className: 'content__container' },
44770
+ React__default.createElement(
44771
+ 'div',
44772
+ { className: 'content__colums content__colums--2-1' },
44773
+ React__default.createElement(
44774
+ 'section',
44775
+ { className: 'gallery' },
44776
+ React__default.createElement(
44777
+ 'div',
44778
+ { className: 'gallery__layout' },
44779
+ React__default.createElement(
44780
+ 'button',
44781
+ {
44782
+ type: 'button',
44783
+ className: 'gallery__big',
44784
+ onClick: function () {
44785
+ return openAt(0);
44786
+ },
44787
+ 'aria-label': 'Open image 1'
44788
+ },
44789
+ React__default.createElement('img', {
44790
+ className: 'gallery__big__img',
44791
+ src: big.src,
44792
+ alt: (_b = big.alt) !== null && _b !== void 0 ? _b : '',
44793
+ loading: 'eager'
44794
+ })
44795
+ ),
44796
+ React__default.createElement(
44797
+ 'div',
44798
+ { className: 'gallery__thumbs', 'aria-label': 'Gallery thumbnails' },
44799
+ thumbs.map(function (img, i) {
44800
+ var _a;
44801
+ var realIndex = i + 1;
44802
+ var isLastThumbSlot = i === 4;
44803
+ var shouldShowMoreOverlay = isLastThumbSlot && extraCount > 0;
44804
+ return React__default.createElement(
44805
+ 'button',
44806
+ {
44807
+ key: ''.concat(img.src, '-').concat(realIndex),
44808
+ type: 'button',
44809
+ className: 'gallery__thumb '.concat(shouldShowMoreOverlay ? 'gallery__thumb--more' : ''),
44810
+ onClick: function () {
44811
+ return openAt(realIndex);
44812
+ },
44813
+ 'aria-label': 'Open image '.concat(realIndex + 1)
44814
+ },
44815
+ React__default.createElement('img', {
44816
+ className: 'gallery__thumb__img',
44817
+ src: img.src,
44818
+ alt: (_a = img.alt) !== null && _a !== void 0 ? _a : '',
44819
+ loading: 'lazy'
44820
+ }),
44821
+ shouldShowMoreOverlay &&
44822
+ React__default.createElement(
44823
+ 'span',
44824
+ { className: 'gallery__thumb__overlay', 'aria-label': ''.concat(extraCount, ' more photos') },
44825
+ '+',
44826
+ extraCount
44827
+ )
44828
+ );
44829
+ })
44830
+ )
44831
+ ),
44832
+ isOpen &&
44833
+ activeImage &&
44834
+ React__default.createElement(
44835
+ 'div',
44836
+ {
44837
+ className: 'gallery__lightbox',
44838
+ role: 'dialog',
44839
+ 'aria-modal': 'true',
44840
+ onMouseDown: function (e) {
44841
+ if (e.target === e.currentTarget) close();
44842
+ }
44843
+ },
44844
+ React__default.createElement(
44845
+ 'div',
44846
+ { className: 'gallery__lightbox__panel' },
44847
+ React__default.createElement(
44848
+ 'button',
44849
+ { type: 'button', className: 'gallery__btn__icon gallery__btn__icon--close', 'aria-label': 'Close', onClick: close },
44850
+ React__default.createElement(Icon$3, { name: 'ui-close', width: 16, height: 16 })
44851
+ ),
44852
+ React__default.createElement(
44853
+ 'div',
44854
+ { className: 'gallery__lightbox__media' },
44855
+ React__default.createElement('img', {
44856
+ className: 'gallery__lightbox__img',
44857
+ src: activeImage.src,
44858
+ alt: (_c = activeImage.alt) !== null && _c !== void 0 ? _c : ''
44859
+ })
44860
+ ),
44861
+ React__default.createElement(
44862
+ 'div',
44863
+ { className: 'gallery__lightbox__footer' },
44864
+ React__default.createElement(
44865
+ 'div',
44866
+ { className: 'gallery__lightbox__info' },
44867
+ React__default.createElement('span', { className: 'gallery__lightbox__index' }, activeIndex + 1, ' / ', images.length),
44868
+ (activeImage.caption || activeImage.alt) &&
44869
+ React__default.createElement(
44870
+ 'span',
44871
+ { className: 'gallery__lightbox__caption' },
44872
+ (_d = activeImage.caption) !== null && _d !== void 0 ? _d : activeImage.alt
44873
+ )
44874
+ ),
44875
+ React__default.createElement(
44876
+ 'div',
44877
+ { className: 'gallery__lightbox__controls' },
44878
+ React__default.createElement('button', { type: 'button', className: 'gallery__btn', onClick: prev }, '\u2190'),
44879
+ React__default.createElement('button', { type: 'button', className: 'gallery__btn', onClick: next }, '\u2192')
44880
+ )
44881
+ )
44882
+ )
44883
+ )
44884
+ ),
44885
+ React__default.createElement('div', null, React__default.createElement('h2', null, title), React__default.createElement('p', null, intro))
44886
+ )
44887
+ )
44888
+ );
44889
+ };
44890
+
44712
44891
  var signalR$1 = {};
44713
44892
 
44714
44893
  var jqueryDeferred$1 = { exports: {} };
@@ -48603,4 +48782,18 @@ var signalR = /*#__PURE__*/ _mergeNamespaces(
48603
48782
  [signalR$1]
48604
48783
  );
48605
48784
 
48606
- export { BookingProduct, BookingWizard, DepartureRange, Footer, Header, ImageCardGrid, ImageWithTextSection, Login, Navbar, QSM, SearchResults };
48785
+ export {
48786
+ BookingProduct,
48787
+ BookingWizard,
48788
+ DepartureRange,
48789
+ Footer,
48790
+ Header,
48791
+ ImageCardGrid,
48792
+ ImageWithTextSection,
48793
+ Login,
48794
+ Navbar,
48795
+ PhotoGallery,
48796
+ QSM,
48797
+ SearchResults,
48798
+ Slider
48799
+ };
@@ -4,9 +4,10 @@ export interface GalleryImage {
4
4
  alt?: string;
5
5
  caption?: string;
6
6
  }
7
- interface GalleryProps {
8
- images: GalleryImage[];
7
+ export interface GalleryProps {
9
8
  title?: string;
9
+ intro?: string;
10
+ images: GalleryImage[];
10
11
  }
11
- export default function PhotoGallery({ images, title }: GalleryProps): React.JSX.Element;
12
- export {};
12
+ declare const PhotoGallery: React.FC<GalleryProps>;
13
+ export default PhotoGallery;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- interface SliderProps {
2
+ export interface SliderProps {
3
3
  path?: string;
4
4
  images: string[];
5
5
  mode?: 'auto' | 'manual';
@@ -8,6 +8,8 @@ import SearchResults from './search-results';
8
8
  import ImageCardGrid from './content/image-card-grid';
9
9
  import Login from './content/login';
10
10
  import ImageWithTextSection from './content/image-with-text-section';
11
+ import Slider from './content/components/slider';
12
+ import PhotoGallery from './content/components/gallery';
11
13
  export * from './content/navbar/types';
12
14
  export * from './content/header/types';
13
15
  export * from './content/footer/types';
@@ -17,4 +19,4 @@ export * from './content/image-with-text-section/types';
17
19
  export * from './search-results/types';
18
20
  export * from './qsm/types';
19
21
  export * from './shared/types';
20
- export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection };
22
+ export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection, Slider, PhotoGallery };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qite/tide-booking-component",
3
- "version": "1.4.63",
3
+ "version": "1.4.65",
4
4
  "description": "React Booking wizard & Booking product component for Tide",
5
5
  "main": "build/build-cjs/index.js",
6
6
  "types": "build/build-cjs/src/index.d.ts",
@@ -7,12 +7,13 @@ export interface GalleryImage {
7
7
  caption?: string;
8
8
  }
9
9
 
10
- interface GalleryProps {
11
- images: GalleryImage[];
10
+ export interface GalleryProps {
12
11
  title?: string;
12
+ intro?: string;
13
+ images: GalleryImage[];
13
14
  }
14
15
 
15
- export default function PhotoGallery({ images, title = 'Gallery' }: GalleryProps) {
16
+ const PhotoGallery: React.FC<GalleryProps> = ({ images, title, intro }) => {
16
17
  const [activeIndex, setActiveIndex] = useState<number | null>(null);
17
18
 
18
19
  const isOpen = activeIndex !== null;
@@ -66,80 +67,87 @@ export default function PhotoGallery({ images, title = 'Gallery' }: GalleryProps
66
67
  };
67
68
 
68
69
  return (
69
- <section className="gallery">
70
- {/* <header className="gallery__header">
71
- <h2 className="gallery__title">{title}</h2>
72
- <span className="gallery__count">{images.length} photos</span>
73
- </header> */}
74
-
75
- <div className="gallery__layout">
76
- <button type="button" className="gallery__big" onClick={() => openAt(0)} aria-label="Open image 1">
77
- <img className="gallery__big__img" src={big.src} alt={big.alt ?? ''} loading="eager" />
78
- </button>
79
-
80
- <div className="gallery__thumbs" aria-label="Gallery thumbnails">
81
- {thumbs.map((img, i) => {
82
- const realIndex = i + 1;
83
- const isLastThumbSlot = i === 4;
84
- const shouldShowMoreOverlay = isLastThumbSlot && extraCount > 0;
85
-
86
- return (
87
- <button
88
- key={`${img.src}-${realIndex}`}
89
- type="button"
90
- className={`gallery__thumb ${shouldShowMoreOverlay ? 'gallery__thumb--more' : ''}`}
91
- onClick={() => openAt(realIndex)}
92
- aria-label={`Open image ${realIndex + 1}`}>
93
- <img className="gallery__thumb__img" src={img.src} alt={img.alt ?? ''} loading="lazy" />
94
-
95
- {shouldShowMoreOverlay && (
96
- <span className="gallery__thumb__overlay" aria-label={`${extraCount} more photos`}>
97
- +{extraCount}
98
- </span>
99
- )}
70
+ <div className="content">
71
+ <div className="content__container">
72
+ <div className="content__colums content__colums--2-1">
73
+ <section className="gallery">
74
+ <div className="gallery__layout">
75
+ <button type="button" className="gallery__big" onClick={() => openAt(0)} aria-label="Open image 1">
76
+ <img className="gallery__big__img" src={big.src} alt={big.alt ?? ''} loading="eager" />
100
77
  </button>
101
- );
102
- })}
103
- </div>
104
- </div>
105
-
106
- {isOpen && activeImage && (
107
- <div
108
- className="gallery__lightbox"
109
- role="dialog"
110
- aria-modal="true"
111
- onMouseDown={(e) => {
112
- if (e.target === e.currentTarget) close();
113
- }}>
114
- <div className="gallery__lightbox__panel">
115
- <button type="button" className="gallery__btn__icon gallery__btn__icon--close" aria-label="Close" onClick={close}>
116
- <Icon name="ui-close" width={16} height={16} />
117
- </button>
118
-
119
- <div className="gallery__lightbox__media">
120
- <img className="gallery__lightbox__img" src={activeImage.src} alt={activeImage.alt ?? ''} />
121
- </div>
122
78
 
123
- <div className="gallery__lightbox__footer">
124
- <div className="gallery__lightbox__info">
125
- <span className="gallery__lightbox__index">
126
- {activeIndex + 1} / {images.length}
127
- </span>
128
- {(activeImage.caption || activeImage.alt) && <span className="gallery__lightbox__caption">{activeImage.caption ?? activeImage.alt}</span>}
79
+ <div className="gallery__thumbs" aria-label="Gallery thumbnails">
80
+ {thumbs.map((img, i) => {
81
+ const realIndex = i + 1;
82
+ const isLastThumbSlot = i === 4;
83
+ const shouldShowMoreOverlay = isLastThumbSlot && extraCount > 0;
84
+
85
+ return (
86
+ <button
87
+ key={`${img.src}-${realIndex}`}
88
+ type="button"
89
+ className={`gallery__thumb ${shouldShowMoreOverlay ? 'gallery__thumb--more' : ''}`}
90
+ onClick={() => openAt(realIndex)}
91
+ aria-label={`Open image ${realIndex + 1}`}>
92
+ <img className="gallery__thumb__img" src={img.src} alt={img.alt ?? ''} loading="lazy" />
93
+
94
+ {shouldShowMoreOverlay && (
95
+ <span className="gallery__thumb__overlay" aria-label={`${extraCount} more photos`}>
96
+ +{extraCount}
97
+ </span>
98
+ )}
99
+ </button>
100
+ );
101
+ })}
129
102
  </div>
103
+ </div>
130
104
 
131
- <div className="gallery__lightbox__controls">
132
- <button type="button" className="gallery__btn" onClick={prev}>
133
-
134
- </button>
135
- <button type="button" className="gallery__btn" onClick={next}>
136
-
137
- </button>
105
+ {isOpen && activeImage && (
106
+ <div
107
+ className="gallery__lightbox"
108
+ role="dialog"
109
+ aria-modal="true"
110
+ onMouseDown={(e) => {
111
+ if (e.target === e.currentTarget) close();
112
+ }}>
113
+ <div className="gallery__lightbox__panel">
114
+ <button type="button" className="gallery__btn__icon gallery__btn__icon--close" aria-label="Close" onClick={close}>
115
+ <Icon name="ui-close" width={16} height={16} />
116
+ </button>
117
+
118
+ <div className="gallery__lightbox__media">
119
+ <img className="gallery__lightbox__img" src={activeImage.src} alt={activeImage.alt ?? ''} />
120
+ </div>
121
+
122
+ <div className="gallery__lightbox__footer">
123
+ <div className="gallery__lightbox__info">
124
+ <span className="gallery__lightbox__index">
125
+ {activeIndex + 1} / {images.length}
126
+ </span>
127
+ {(activeImage.caption || activeImage.alt) && <span className="gallery__lightbox__caption">{activeImage.caption ?? activeImage.alt}</span>}
128
+ </div>
129
+
130
+ <div className="gallery__lightbox__controls">
131
+ <button type="button" className="gallery__btn" onClick={prev}>
132
+
133
+ </button>
134
+ <button type="button" className="gallery__btn" onClick={next}>
135
+
136
+ </button>
137
+ </div>
138
+ </div>
139
+ </div>
138
140
  </div>
139
- </div>
141
+ )}
142
+ </section>
143
+ <div>
144
+ <h2>{title}</h2>
145
+ <p>{intro}</p>
140
146
  </div>
141
147
  </div>
142
- )}
143
- </section>
148
+ </div>
149
+ </div>
144
150
  );
145
- }
151
+ };
152
+
153
+ export default PhotoGallery;
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import Icon from './icon';
3
3
 
4
- interface SliderProps {
4
+ export interface SliderProps {
5
5
  path?: string;
6
6
  images: string[];
7
7
  mode?: 'auto' | 'manual';
@@ -20,7 +20,7 @@ const ImageWithTextCard: React.FC<ImageWithTextCardProps> = ({
20
20
  cardClassName += ' image-with-text__card--no-card';
21
21
  }
22
22
  if (fullImage) {
23
- cardClassName += ' image-with-text__card--full-image';
23
+ cardClassName += ' image-with-text__card--full-img';
24
24
  }
25
25
  if (reverse) {
26
26
  cardClassName += ' image-with-text__card--reverse';
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ import SearchResults from './search-results';
8
8
  import ImageCardGrid from './content/image-card-grid';
9
9
  import Login from './content/login';
10
10
  import ImageWithTextSection from './content/image-with-text-section';
11
+ import Slider from './content/components/slider';
12
+ import PhotoGallery from './content/components/gallery';
11
13
 
12
14
  export * from './content/navbar/types';
13
15
  export * from './content/header/types';
@@ -19,4 +21,4 @@ export * from './search-results/types';
19
21
  export * from './qsm/types';
20
22
  export * from './shared/types';
21
23
 
22
- export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection };
24
+ export { BookingProduct, BookingWizard, QSM, SearchResults, Navbar, Header, Footer, ImageCardGrid, Login, ImageWithTextSection, Slider, PhotoGallery };