-
-
Notifications
You must be signed in to change notification settings - Fork 11
feat: implement Material 3 Carousel components #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Carousel | ||
|
|
||
| Carousels display a set of items, such as images or cards, that can be scrolled horizontally. | ||
|
|
||
| ## Example Usage | ||
|
|
||
| ```html | ||
| <script type="module"> | ||
| import 'material/carousel/carousel.js' | ||
| import 'material/carousel/carousel-item.js' | ||
| import 'material/card/card.js' | ||
| </script> | ||
|
|
||
| <md-carousel> | ||
| <md-carousel-item> | ||
| <md-card>Card 1</md-card> | ||
| </md-carousel-item> | ||
| <md-carousel-item> | ||
| <md-card>Card 2</md-card> | ||
| </md-carousel-item> | ||
| <md-carousel-item> | ||
| <md-card>Card 3</md-card> | ||
| </md-carousel-item> | ||
| </md-carousel> | ||
| ``` | ||
|
|
||
| ## CSS Variables | ||
|
|
||
| ### `<md-carousel>` | ||
| * `--md-carousel-gap`: Gap between carousel items (default: `8px`) | ||
| * `--md-carousel-padding`: Padding around the carousel scroll container (default: `0`) | ||
|
|
||
| ### `<md-carousel-item>` | ||
| * `--md-carousel-item-width`: Width of the carousel item (default: `300px`) | ||
| * `--md-carousel-item-shape`: Border radius of the carousel item (default: `28px`) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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` | ||
| <div class="item-container" role="listitem"> | ||
| <slot></slot> | ||
| </div> | ||
| ` | ||
| } | ||
|
|
||
| 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) | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -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' | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| } | ||||||||
|
|
||||||||
| render() { | ||||||||
| return html` | ||||||||
| <div class="scroll-container" role="list" aria-label="${this.ariaLabel}"> | ||||||||
| <slot></slot> | ||||||||
| </div> | ||||||||
| ` | ||||||||
| } | ||||||||
|
|
||||||||
| static styles = css` | ||||||||
| :host { | ||||||||
| display: block; | ||||||||
| /* Carousel styling based on Material Design 3 */ | ||||||||
| /* Note: specific width/height may need to be configurable */ | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| } | ||||||||
|
|
||||||||
| .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 */ | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hiding the scrollbar can negatively impact accessibility and usability, as it removes a visual cue for the amount of content and a means of navigation for some users. Consider allowing the scrollbar to be visible or providing alternative navigation indicators (like dots or arrows) as per Material Design 3 guidelines. |
||||||||
| scrollbar-width: none; /* Firefox */ | ||||||||
| -ms-overflow-style: none; /* IE and Edge */ | ||||||||
|
|
||||||||
| padding: var(--md-carousel-padding, 0); | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using
Suggested change
|
||||||||
| } | ||||||||
|
|
||||||||
| .scroll-container::-webkit-scrollbar { | ||||||||
| display: none; /* Chrome, Safari and Opera */ | ||||||||
| } | ||||||||
| ` | ||||||||
| } | ||||||||
|
|
||||||||
| customElements.define('md-carousel', Carousel) | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
role="listitem"should be applied to the host element rather than an internaldiv. This ensures that the component is correctly identified as a list item by assistive technologies when placed inside arole="list"container (like the one inmd-carousel).