Skip to content

Commit dec0d4d

Browse files
authored
feat(ui5-carousel): Allow different number of items per page based on component width (#1434)
1 parent 0089db4 commit dec0d4d

File tree

3 files changed

+210
-12
lines changed

3 files changed

+210
-12
lines changed

packages/main/src/Carousel.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
></div>
5757
{{/each}}
5858
{{else}}
59-
<ui5-label>{{currenlySelectedIndexToShow}}&nbsp;{{ofText}}&nbsp;{{pages.length}}</ui5-label>
59+
<ui5-label>{{selectedIndexToShow}}&nbsp;{{ofText}}&nbsp;{{pages.length}}</ui5-label>
6060
{{/if}}
6161
</div>
6262

packages/main/src/Carousel.js

+72-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getI18nBundle,
1313
} from "@ui5/webcomponents-base/dist/i18nBundle.js";
1414
import ScrollEnablement from "@ui5/webcomponents-base/dist/delegate/ScrollEnablement.js";
15+
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
1516
import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
1617
import AnimationMode from "@ui5/webcomponents-base/dist/types/AnimationMode.js";
1718
import { getAnimationMode } from "@ui5/webcomponents-base/dist/config/AnimationMode.js";
@@ -40,17 +41,39 @@ const metadata = {
4041
* @defaultvalue false
4142
* @public
4243
*/
43-
cycling: {
44+
cyclic: {
4445
type: Boolean,
4546
},
4647

4748
/**
48-
* Sets the amount of items per page. If this property is set, on mobile devices it will always fallback to 1.
49+
* Sets the number of items per page on small size (up to 640px). One item per page shown by default.
4950
* @type {Integer}
5051
* @defaultvalue 1
5152
* @public
5253
*/
53-
itemsPerPage: {
54+
itemsPerPageS: {
55+
type: Integer,
56+
defaultValue: 1,
57+
},
58+
59+
/**
60+
* Sets the number of items per page on medium size (from 640px to 1024px). One item per page shown by default.
61+
* @type {Integer}
62+
* @defaultvalue 1
63+
* @public
64+
*/
65+
itemsPerPageM: {
66+
type: Integer,
67+
defaultValue: 1,
68+
},
69+
70+
/**
71+
* Sets the number of items per page on large size (more than 1024px). One item per page shown by default.
72+
* @type {Integer}
73+
* @defaultvalue 1
74+
* @public
75+
*/
76+
itemsPerPageL: {
5477
type: Integer,
5578
defaultValue: 1,
5679
},
@@ -96,6 +119,14 @@ const metadata = {
96119
type: CarouselArrowsPlacement,
97120
defaultValue: CarouselArrowsPlacement.Content,
98121
},
122+
123+
/**
124+
* Defines the carousel width in pixels
125+
* @private
126+
*/
127+
_width: {
128+
type: Integer,
129+
},
99130
},
100131
managedSlots: true,
101132
slots: /** @lends sap.ui.webcomponents.main.Carousel.prototype */ {
@@ -177,12 +208,38 @@ class Carousel extends UI5Element {
177208
});
178209

179210
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
211+
this._onResizeBound = this._onResize.bind(this);
180212
}
181213

182214
onAfterRendering() {
183215
this._scrollEnablement.scrollContainer = this.getDomRef();
184216
}
185217

218+
onEnterDOM() {
219+
ResizeHandler.register(this, this._onResizeBound);
220+
}
221+
222+
onExitDOM() {
223+
ResizeHandler.deregister(this, this._onResizeBound);
224+
}
225+
226+
_onResize() {
227+
const oldItemsPerPage = this.effectiveItemsPerPage;
228+
229+
// Change transitively effectiveItemsPerPage by modifying _width
230+
this._width = this.offsetWidth;
231+
232+
// Items per page did not change, therefore page index does not need to be re-adjusted
233+
if (this.effectiveItemsPerPage === oldItemsPerPage) {
234+
return;
235+
}
236+
237+
// Whenever the number of items per page changes, the selected index needs to be re-adjusted so that the items
238+
// that were visible before, can be visible as much as possible afterwards.
239+
const adjustment = oldItemsPerPage / this.effectiveItemsPerPage;
240+
this.selectedIndex = Math.round(this.selectedIndex * adjustment);
241+
}
242+
186243
_updateScrolling(event) {
187244
if (!event) {
188245
return;
@@ -209,7 +266,7 @@ class Carousel extends UI5Element {
209266

210267
navigateLeft() {
211268
if (this.selectedIndex - 1 < 0) {
212-
if (this.cycling) {
269+
if (this.cyclic) {
213270
this.selectedIndex = this.pages.length - 1;
214271
}
215272
} else {
@@ -219,7 +276,7 @@ class Carousel extends UI5Element {
219276

220277
navigateRight() {
221278
if (this.selectedIndex + 1 > this.pages.length - 1) {
222-
if (this.cycling) {
279+
if (this.cyclic) {
223280
this.selectedIndex = 0;
224281
}
225282
} else {
@@ -261,7 +318,15 @@ class Carousel extends UI5Element {
261318
}
262319

263320
get effectiveItemsPerPage() {
264-
return isDesktop() ? this.itemsPerPage : 1;
321+
if (this._width <= 640) {
322+
return this.itemsPerPageS;
323+
}
324+
325+
if (this._width <= 1024) {
326+
return this.itemsPerPageM;
327+
}
328+
329+
return this.itemsPerPageL;
265330
}
266331

267332
get styles() {
@@ -316,7 +381,7 @@ class Carousel extends UI5Element {
316381
return this.i18nBundle.getText(CAROUSEL_OF_TEXT);
317382
}
318383

319-
get currenlySelectedIndexToShow() {
384+
get selectedIndexToShow() {
320385
return this.selectedIndex + 1;
321386
}
322387

packages/main/test/pages/Carousel.html

+137-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
}
2626
</style>
2727

28-
<ui5-carousel items-per-page="3">
28+
<ui5-carousel items-per-page-s="3" items-per-page-m="3" items-per-page-l="3">
2929
<ui5-card
3030
id="card"
3131
status="4 of 10"
@@ -157,7 +157,140 @@
157157
</ui5-carousel>
158158

159159

160-
<ui5-carousel id="carousel1" cycling="true">
160+
<ui5-carousel items-per-page-s="1" items-per-page-m="2" items-per-page-l="3">
161+
<ui5-card
162+
id="card"
163+
status="Item 1"
164+
heading="Quick Links"
165+
subheading="quick links"
166+
header-interactive
167+
class="myCard">
168+
<ui5-list id="myList3" separators="Inner">
169+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
170+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
171+
<ui5-li icon="line-charts" >Marketing plans</ui5-li>
172+
</ui5-list>
173+
174+
<ui5-input id="field" value="0"></ui5-input>
175+
</ui5-card>
176+
177+
<ui5-card
178+
id="card2"
179+
status="Item 2"
180+
heading="Quick Links"
181+
subheading="quick links"
182+
class="myCard">
183+
<ui5-icon name="group" slot="avatar"></ui5-icon>
184+
<ui5-list id="myList3" separators="Inner">
185+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
186+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
187+
</ui5-list>
188+
</ui5-card>
189+
190+
<ui5-card heading="Quick Links" status="Item 3" subheading="quick links" class="myCard">
191+
<ui5-list id="myList3" separators="Inner">
192+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
193+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
194+
</ui5-list>
195+
</ui5-card>
196+
197+
<ui5-card
198+
id="card"
199+
status="Item 4"
200+
heading="Quick Links"
201+
subheading="quick links"
202+
header-interactive
203+
class="myCard">
204+
<ui5-list id="myList3" separators="Inner">
205+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
206+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
207+
<ui5-li icon="line-charts" >Marketing plans</ui5-li>
208+
</ui5-list>
209+
210+
<ui5-input id="field" value="0"></ui5-input>
211+
</ui5-card>
212+
213+
<ui5-card
214+
id="card2"
215+
status="Item 5"
216+
heading="Quick Links"
217+
subheading="quick links"
218+
class="myCard">
219+
<ui5-icon name="group" slot="avatar"></ui5-icon>
220+
<ui5-list id="myList3" separators="Inner">
221+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
222+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
223+
</ui5-list>
224+
</ui5-card>
225+
226+
<ui5-card heading="Quick Links" status="Item 6" subheading="quick links" class="myCard">
227+
<ui5-list id="myList3" separators="Inner">
228+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
229+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
230+
</ui5-list>
231+
</ui5-card>
232+
233+
<ui5-card
234+
id="card"
235+
status="Item 7"
236+
heading="Quick Links"
237+
subheading="quick links"
238+
header-interactive
239+
class="myCard">
240+
<ui5-list id="myList3" separators="Inner">
241+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
242+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
243+
<ui5-li icon="line-charts" >Marketing plans</ui5-li>
244+
</ui5-list>
245+
246+
<ui5-input id="field" value="0"></ui5-input>
247+
</ui5-card>
248+
249+
<ui5-card
250+
id="card2"
251+
status="Item 8"
252+
heading="Quick Links"
253+
subheading="quick links"
254+
class="myCard">
255+
<ui5-icon name="group" slot="avatar"></ui5-icon>
256+
<ui5-list id="myList3" separators="Inner">
257+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
258+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
259+
</ui5-list>
260+
</ui5-card>
261+
262+
<ui5-card heading="Quick Links" status="Item 9" subheading="quick links" class="myCard">
263+
<ui5-list id="myList3" separators="Inner">
264+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
265+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
266+
</ui5-list>
267+
</ui5-card>
268+
269+
<ui5-card
270+
id="card2"
271+
status="Item 10"
272+
heading="Quick Links"
273+
subheading="quick links"
274+
class="myCard">
275+
<ui5-icon name="group" slot="avatar"></ui5-icon>
276+
<ui5-list id="myList3" separators="Inner">
277+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
278+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
279+
</ui5-list>
280+
</ui5-card>
281+
282+
<ui5-card heading="Quick Links" status="Item 11" subheading="quick links" class="myCard">
283+
<ui5-list id="myList3" separators="Inner">
284+
<ui5-li icon="horizontal-bullet-chart" >Template Based Segmentation</ui5-li>
285+
<ui5-li icon="opportunity" >Segmentation Models</ui5-li>
286+
</ui5-list>
287+
</ui5-card>
288+
289+
</ui5-carousel>
290+
291+
292+
293+
<ui5-carousel id="carousel1" cyclic="true">
161294
<ui5-button>Button 1</ui5-button>
162295
<ui5-button>Button 2</ui5-button>
163296
<ui5-button>Button 3</ui5-button>
@@ -215,7 +348,7 @@
215348
</ui5-list>
216349
</ui5-carousel>
217350

218-
<ui5-carousel id="carousel5" items-per-page="4">
351+
<ui5-carousel id="carousel5" items-per-page-m="4" items-per-page-l="4">
219352
<ui5-button>Button 1</ui5-button>
220353
<ui5-button>Button 2</ui5-button>
221354
<ui5-button>Button 3</ui5-button>
@@ -229,7 +362,7 @@
229362
<ui5-title>Carousel with one page</ui5-title>
230363
<ui5-label>The arrows and dots are not displayed</ui5-label>
231364

232-
<ui5-carousel id="carousel6" items-per-page="3">
365+
<ui5-carousel id="carousel6" items-per-page-m="3" items-per-page-l="4">
233366
<ui5-button>Button 1</ui5-button>
234367
<ui5-button>Button 2</ui5-button>
235368
<ui5-button>Button 3</ui5-button>

0 commit comments

Comments
 (0)