diff --git a/carousel/README.md b/carousel/README.md new file mode 100644 index 0000000..10e2da2 --- /dev/null +++ b/carousel/README.md @@ -0,0 +1,35 @@ +# Carousel + +Carousels display a set of items, such as images or cards, that can be scrolled horizontally. + +## Example Usage + +```html + + + + + Card 1 + + + Card 2 + + + Card 3 + + +``` + +## CSS Variables + +### `` +* `--md-carousel-gap`: Gap between carousel items (default: `8px`) +* `--md-carousel-padding`: Padding around the carousel scroll container (default: `0`) + +### `` +* `--md-carousel-item-width`: Width of the carousel item (default: `300px`) +* `--md-carousel-item-shape`: Border radius of the carousel item (default: `28px`) diff --git a/carousel/carousel-item.js b/carousel/carousel-item.js new file mode 100644 index 0000000..d21708d --- /dev/null +++ b/carousel/carousel-item.js @@ -0,0 +1,38 @@ +import { html, LitElement, css } from 'lit' + +/** + * A Material Design carousel item component. + * + * @element md-carousel-item + */ +export class CarouselItem extends LitElement { + render() { + return html` +
+ +
+ ` + } + + static styles = css` + :host { + display: inline-block; + flex-shrink: 0; + scroll-snap-align: start; + /* default size for demo, can be overridden */ + width: var(--md-carousel-item-width, 300px); + } + + .item-container { + display: flex; + flex-direction: column; + height: 100%; + box-sizing: border-box; + /* Usually border radius of 28px or 24px in MD3 depending on variant */ + border-radius: var(--md-carousel-item-shape, 28px); + overflow: hidden; + } + ` +} + +customElements.define('md-carousel-item', CarouselItem) diff --git a/carousel/carousel.js b/carousel/carousel.js new file mode 100644 index 0000000..7d1568c --- /dev/null +++ b/carousel/carousel.js @@ -0,0 +1,53 @@ +import { html, LitElement, css } from 'lit' + +/** + * A Material Design carousel component. + * + * @element md-carousel + */ +export class Carousel extends LitElement { + static properties = { + ariaLabel: { type: String, attribute: 'aria-label' }, + } + + constructor() { + super() + this.ariaLabel = 'Carousel' + } + + render() { + return html` +
+ +
+ ` + } + + static styles = css` + :host { + display: block; + /* Carousel styling based on Material Design 3 */ + /* Note: specific width/height may need to be configurable */ + } + + .scroll-container { + display: flex; + gap: var(--md-carousel-gap, 8px); + overflow-x: auto; + scroll-snap-type: x mandatory; + overscroll-behavior-x: contain; + + /* Hide scrollbar for cleaner look, but keep functionality */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + + padding: var(--md-carousel-padding, 0); + } + + .scroll-container::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ + } + ` +} + +customElements.define('md-carousel', Carousel) diff --git a/demo/index.html b/demo/index.html index bb1a109..67452d4 100644 --- a/demo/index.html +++ b/demo/index.html @@ -58,6 +58,9 @@ import 'material/snackbar/snackbar.js' import 'material/app/bar.js' import 'material/progress/progress.js' + import 'material/carousel/carousel.js' + import 'material/carousel/carousel-item.js' + import 'material/card/card.js' import './components/expressive-component.js' @@ -178,7 +181,36 @@

Inputs

-

Progress

+ +

Carousel

+ + + +
Item 1
+
+
+ + +
Item 2
+
+
+ + +
Item 3
+
+
+ + +
Item 4
+
+
+ + +
Item 5
+
+
+
+

Progress