Skip to content

Commit c1c7ce9

Browse files
Merge pull request #1 from Travelopia/feature/slider
New Component: Slider
2 parents bd995d6 + 3fbe074 commit c1c7ce9

File tree

13 files changed

+690
-1
lines changed

13 files changed

+690
-1
lines changed

src/modal/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ import '@travelopia/web-components/dist/modal/style.css';
2424

2525
// TypeScript usage:
2626
import { TPModalElement, TPModalCloseElement } from '@travelopia/web-components';
27+
28+
...
29+
30+
const modal: TPModalElement = document.querySelector( 'tp-modal' );
31+
modal.open();
2732
```
2833

2934
```html
3035
<tp-modal overlay-click-close="yes">
3136
<tp-modal-close>
32-
<button>Close</button> <-- There must be a button inside inside this component.
37+
<button>Close</button> <-- There must be a button inside this component.
3338
</tp-modal-close>
3439
<tp-modal-content>
3540
<p>Any modal content here.</p>
@@ -42,3 +47,20 @@ import { TPModalElement, TPModalCloseElement } from '@travelopia/web-components'
4247
| Attribute | Required | Values | Notes |
4348
|----------------------|----------|--------|----------------------------------------------|
4449
| overlay-click-close | No | `yes` | Closes the modal when the overlay is clicked |
50+
51+
## Events
52+
53+
| Event | Notes |
54+
|-------|--------------------------|
55+
| open | When the modal is opened |
56+
| close | When the modal is closed |
57+
58+
## Methods
59+
60+
### `open`
61+
62+
Open the modal.
63+
64+
### `close`
65+
66+
Close the modal.

src/slider/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Slider
2+
3+
<table width="100%">
4+
<tr>
5+
<td align="left" width="70%">
6+
<p>Built by the super talented team at <strong><a href="https://www.travelopia.com/work-with-us/">Travelopia</a></strong>.</p>
7+
</td>
8+
<td align="center" width="30%">
9+
<img src="https://www.travelopia.com/wp-content/themes/travelopia/assets/svg/logo-travelopia-circle.svg" width="50" />
10+
</td>
11+
</tr>
12+
</table>
13+
14+
## Sample Usage
15+
16+
This is a highly customizable slider component. Pick and choose subcomponents to use, and style as needed!
17+
18+
Example:
19+
20+
```js
21+
// Import the component as needed:
22+
import '@travelopia/web-components/dist/slider';
23+
import '@travelopia/web-components/dist/slider/style.css';
24+
25+
// TypeScript usage:
26+
import { TPSliderElement } from '@travelopia/web-components';
27+
28+
...
29+
30+
const slider: TPSliderElement = document.querySelector( 'tp-slider' );
31+
slider.setCurrentSlide( 2 );
32+
```
33+
34+
```html
35+
<tp-slider flexible-height="yes" infinite="yes" swipe="yes">
36+
<tp-slider-arrow direction="previous"><button>&laquo; Previous</button></tp-slider-arrow> <-- There must be a button inside this component
37+
<tp-slider-arrow direction="next"><button>Next &raquo;</button></tp-slider-arrow> <-- There must be a button inside this component
38+
<tp-slider-track>
39+
<tp-slider-slides>
40+
<tp-slider-slide><img src="image.jpg" width="600" height="300" alt=""></tp-slider-slide>
41+
<tp-slider-slide>
42+
<p>Any content you want here.</p>
43+
</tp-slider-slide>
44+
</tp-slider-slides>
45+
</tp-slider-track>
46+
<tp-slider-nav>
47+
<tp-slider-nav-item><button>1</button></tp-slider-nav-item> <-- There must be a button inside this component
48+
<tp-slider-nav-item><button>2</button></tp-slider-nav-item> <-- There must be a button inside this component
49+
</tp-slider-nav>
50+
<tp-slider-count current="1" total="2" format="$current / $total">1 / 2</tp-slider-count>
51+
</tp-slider>
52+
```
53+
54+
## Attributes
55+
56+
| Attribute | Required | Values | Notes |
57+
|-----------------|----------|--------|--------------------------------------------------------------------------------------------------------|
58+
| flexible-height | No | `yes` | Whether the height of the slider changes depending on the content inside the slides |
59+
| infinite | No | `yes` | Go back to the first slide at the end of all slides, and open the last slide when navigating backwards |
60+
| swipe | No | `yes` | Whether to add support for swiping gestures on touch devices |
61+
62+
## Events
63+
64+
| Event | Notes |
65+
|----------------|---------------------------------------------------|
66+
| slide-set | When the current slide is set, but before sliding |
67+
| slide-complete | After sliding is complete |
68+
69+
## Methods
70+
71+
### `next`
72+
73+
Navigate to the next slide.
74+
75+
### `previous`
76+
77+
Navigate to the previous slide.
78+
79+
### `getCurrentSlide`
80+
81+
Gets the current slide's index.
82+
83+
### `setCurrentSlide`
84+
85+
Sets the current slide based on its index.

src/slider/index.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7+
<title>Web Component: Slider</title>
8+
9+
<link rel="stylesheet" href="../../dist/slider/style.css" media="all">
10+
<script type="module" src="../../dist/slider/index.js"></script>
11+
12+
<style>
13+
tp-slider-slide {
14+
background-color: #eee
15+
}
16+
17+
tp-slider-slide img {
18+
width: 100%;
19+
height: auto;
20+
}
21+
22+
img {
23+
display: block;
24+
}
25+
26+
main {
27+
max-width: 600px;
28+
margin: 0 auto;
29+
padding: 0 20px;
30+
}
31+
</style>
32+
</head>
33+
<body>
34+
<main>
35+
<tp-slider flexible-height="yes" infinite="yes" swipe="yes">
36+
<tp-slider-arrow direction="previous"><button>&laquo; Previous</button></tp-slider-arrow>
37+
<tp-slider-arrow direction="next"><button>Next &raquo;</button></tp-slider-arrow>
38+
<tp-slider-track>
39+
<tp-slider-slides>
40+
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
41+
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
42+
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
43+
<tp-slider-slide>
44+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
45+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
46+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
47+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
48+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
49+
</tp-slider-slide>
50+
</tp-slider-slides>
51+
</tp-slider-track>
52+
<tp-slider-nav>
53+
<tp-slider-nav-item><button>1</button></tp-slider-nav-item>
54+
<tp-slider-nav-item><button>2</button></tp-slider-nav-item>
55+
<tp-slider-nav-item><button>3</button></tp-slider-nav-item>
56+
<tp-slider-nav-item><button>4</button></tp-slider-nav-item>
57+
</tp-slider-nav>
58+
<tp-slider-count current="1" total="4" format="$current / $total">1 / 4</tp-slider-count>
59+
</tp-slider>
60+
</main>
61+
</body>
62+
</html>

src/slider/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Styles.
3+
*/
4+
import './style.scss';
5+
6+
/**
7+
* Components.
8+
*/
9+
import { TPSliderElement } from './tp-slider';
10+
import { TPSliderSlidesElement } from './tp-slider-slides';
11+
import { TPSliderSlideElement } from './tp-slider-slide';
12+
import { TPSliderArrowElement } from './tp-slider-arrow';
13+
import { TPSliderNavElement } from './tp-slider-nav';
14+
import { TPSliderNavItemElement } from './tp-slider-nav-item';
15+
import { TPSliderCountElement } from './tp-slider-count';
16+
17+
/**
18+
* Register Components.
19+
*/
20+
customElements.define( 'tp-slider', TPSliderElement );
21+
customElements.define( 'tp-slider-slides', TPSliderSlidesElement );
22+
customElements.define( 'tp-slider-slide', TPSliderSlideElement );
23+
customElements.define( 'tp-slider-arrow', TPSliderArrowElement );
24+
customElements.define( 'tp-slider-nav', TPSliderNavElement );
25+
customElements.define( 'tp-slider-nav-item', TPSliderNavItemElement );
26+
customElements.define( 'tp-slider-count', TPSliderCountElement );

src/slider/style.scss

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
tp-slider {
2+
display: block;
3+
}
4+
5+
tp-slider-track {
6+
display: block;
7+
overflow-y: visible;
8+
overflow-x: clip;
9+
position: relative;
10+
}
11+
12+
tp-slider-slides {
13+
position: relative;
14+
display: flex;
15+
align-items: flex-start;
16+
17+
tp-slider:not([resizing="yes"]) & {
18+
transition-duration: 0.6s;
19+
transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
20+
}
21+
}
22+
23+
tp-slider-slide {
24+
flex: 0 0 100%;
25+
scroll-snap-align: start;
26+
27+
tp-slider[flexible-height="yes"]:not([initialized]) &:not(:first-child) {
28+
display: none;
29+
}
30+
}
31+
32+
tp-slider-nav {
33+
display: flex;
34+
gap: 10px;
35+
}

src/slider/tp-slider-arrow.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Internal dependencies.
3+
*/
4+
import { TPSliderElement } from './tp-slider';
5+
6+
/**
7+
* TP Slider Arrow.
8+
*/
9+
export class TPSliderArrowElement extends HTMLElement {
10+
/**
11+
* Connected callback.
12+
*/
13+
connectedCallback(): void {
14+
this.querySelector( 'button' )?.addEventListener( 'click', this.handleClick.bind( this ) );
15+
}
16+
17+
/**
18+
* Handle when the button is clicked.
19+
*/
20+
handleClick(): void {
21+
if ( 'yes' === this.getAttribute( 'disabled' ) ) {
22+
return;
23+
}
24+
25+
const slider: TPSliderElement | null = this.closest( 'tp-slider' );
26+
if ( ! slider ) {
27+
return;
28+
}
29+
30+
if ( 'previous' === this.getAttribute( 'direction' ) ) {
31+
slider.previous();
32+
} else if ( 'next' === this.getAttribute( 'direction' ) ) {
33+
slider.next();
34+
}
35+
}
36+
}

src/slider/tp-slider-count.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* TP Slider Count.
3+
*/
4+
export class TPSliderCountElement extends HTMLElement {
5+
/**
6+
* Get observed attributes.
7+
*
8+
* @return {Array} Observed attributes.
9+
*/
10+
static get observedAttributes(): string[] {
11+
return [ 'current', 'total', 'format' ];
12+
}
13+
14+
/**
15+
* Get format.
16+
*
17+
* @return {string} Format.
18+
*/
19+
get format(): string {
20+
return this.getAttribute( 'format' ) ?? '$current / $total';
21+
}
22+
23+
/**
24+
* Set format.
25+
*
26+
* @param {string} format Format.
27+
*/
28+
set format( format: string ) {
29+
this.setAttribute( 'format', format );
30+
}
31+
32+
/**
33+
* Attribute changed callback.
34+
*/
35+
attributeChangedCallback(): void {
36+
this.update();
37+
}
38+
39+
/**
40+
* Update component.
41+
*/
42+
update(): void {
43+
this.innerHTML =
44+
this.format
45+
.replace( '$current', this.getAttribute( 'current' ) ?? '' )
46+
.replace( '$total', this.getAttribute( 'total' ) ?? '' );
47+
}
48+
}

src/slider/tp-slider-nav-item.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Internal dependencies.
3+
*/
4+
import { TPSliderElement } from './tp-slider';
5+
import { TPSliderNavElement } from './tp-slider-nav';
6+
7+
/**
8+
* TP Slider Nav Item.
9+
*/
10+
export class TPSliderNavItemElement extends HTMLElement {
11+
/**
12+
* Connected callback.
13+
*/
14+
connectedCallback(): void {
15+
this.querySelector( 'button' )?.addEventListener( 'click', this.handleClick.bind( this ) );
16+
}
17+
18+
/**
19+
* Handle when the button is clicked.
20+
*/
21+
handleClick(): void {
22+
const slider: TPSliderElement | null = this.closest( 'tp-slider' );
23+
if ( ! slider ) {
24+
return;
25+
}
26+
27+
slider.setCurrentSlide( this.getIndex() );
28+
}
29+
30+
/**
31+
* Get index of this item inside the navigation.
32+
*
33+
* @return {number} Index.
34+
*/
35+
getIndex(): number {
36+
if ( this.getAttribute( 'index' ) ) {
37+
return parseInt( this.getAttribute( 'index' ) ?? '0' );
38+
}
39+
40+
const slideNav: TPSliderNavElement | null = this.closest( 'tp-slider-nav' );
41+
return Array.from( slideNav?.children ?? [] ).indexOf( this ) + 1;
42+
}
43+
}

src/slider/tp-slider-nav.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* TP Slider Nav.
3+
*/
4+
export class TPSliderNavElement extends HTMLElement {
5+
}

src/slider/tp-slider-slide.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* TP Slider Slide.
3+
*/
4+
export class TPSliderSlideElement extends HTMLElement {
5+
}

0 commit comments

Comments
 (0)