Skip to content

Commit

Permalink
Carousel (#119)
Browse files Browse the repository at this point in the history
* initial demo port

* reduced motion updates, config updates

* update open props to latest

* add product images

* fixes page scrolling

* use the prop

* nits and notes

* more notes

* adds ability to spam next/prev

* task note

* finish accessible content

* bit more prevention for heavy spamming of next/prev

* fixes scroll event keypress bubbling by making carousel focusable

* adds snap scroll item wrapper for non-janky transforms

* demo style updates for multiple carousels

* switch from aria-disabled to disabled, use keyframes for keypress animation, adds content visibility

* adds hover effect to pagination dots

* fixes event bubbling in minimap so items arent accidentally selected

* better button hover states

* removes viewport units

* relative layout

* better layouts for when pagination or controls are set to none

* hide arrows if user has js turned off

* no scrollbar option

* fit nits

* todo updates

* fixes tiny buttons on iOS

* best of both worlds: browser event source is correct and container is no longer focusable

* adds posinset and setsize on the tabs

* update to latest open props

* make defaults more obvious they are an api

* clean up some notes

* fixes scroller gap being slightly shy of the fit needed

* fixes firefox next/prev buttons not snapping to next with scrollBy

* converted to a class

* adds unlisteners

* add more demos

* note a todo for el removal observation and unlistening

* fixes content-visibility affecting document body scroll

* updates todos

* adds aria-label with position of item via js to unburden devs

* handles lots of pagination items and keeps active in view

* hide scrollbars on pagination too if config is set

* better place to scroll dots into view

* add more todos

* tabindex -1 doesnt need this fix

* page load no longer scrolls to the carousel

* add another note

* fixes scroll regression after pagination scroll was added

* use a row size so no layout shift

* pagination hides scrollbars by default

* fixes safari not scrolling items into view

* adds scroll-hint to pagination area for gallery

* add pagination and controls with JS

* js setting as much aria as possible

* clean up initialization

* fixes wide screens

* notes

* support scroll snap always config option

* pagination looks for figcaption text or img alt for labels

* move item styles to external stylesheet

* adds testimonial demo

* fixes horizontal overflow bug when reaching end of pagination

* minor pagination style improvements

* fixes firefox not supporting scrollIntoViewIfNeeded()

* removes duplicate shirt

* demo title change

* adds 1 at a time demo

* first demo has free scroll

* move custom layouts to custom stylesheet

* adds full width demo

* add cascade layers

* add scroll hint demo

* wraps basics in where for easy overrides

* removes some todos

* adds paged collection demo

* responsive paged collection demo

* fixes production build by updating to latest vite and postcss-preset-env and passing custom media to plugin

* fixes full width on large monitors

* adds node removed observer to remove listeners and stuff

* adds touch-action to horizontal scroll areas

* more postcss transform cleanup

* tiny update to support RTL

* add todo

* finishes rtl keyboard support

* minor refactor of keypress animation handling

* support setting scroll start

* fixes typo in scroll start logic

* style header elements in examples

* cleanliness refactor

* minor demo style/text nudge

* updates state initialization with scrollstart logic

* made 2 more methods private

* adds goToElement() method so rootscroller is never invoked

* remove touch-action

* improves forced colors mode pagination and controls

* fixes disabled button having subtle shadow

* switch to eager in-view class assignment

* improves interaction pace with in-view class animation

* cruft removal

* some renaming and added more comments

* easing adjustment to pagination marker

* removes concept of scroll-item

* better product examples

* remove contain-intrinsic-size, shouldnt have that many items

* perf fix with will-change (safari desktop benefited the most)

* fixes product details alignment

* removes guard since no longer using scrollIntoView

* updates comment about usage

* update open props

* fixes rtl regression

* more fixes for RTL

* adds hubs example

* slight improvement to hubs demo

* workaround for vite cascade layers import bug vitejs/vite#9368

* adds build workflow and readme entry
  • Loading branch information
argyleink committed Jul 25, 2022
1 parent 5f29330 commit 884e599
Show file tree
Hide file tree
Showing 33 changed files with 4,118 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Expand Up @@ -70,6 +70,9 @@ jobs:

- name: Build FAB
run: cd FAB && npm install && npm run build

- name: Build Carousel
run: cd carousel && npm install && npm run build

- name: Deploy to Firebase
uses: w9jds/firebase-action@master
Expand Down
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -86,3 +86,6 @@ and expand the diversity of our skills.**
19. FABs
[`Demo`](https://gui-challenges.web.app/FAB/dist/)
[`YouTube`](https://www.youtube.com/watch?v=RXopH5t2Kww&list=PLNYkxOF6rcIAaV1wwI9540OC_3XoIzMjQ)
19. Carousels
[`Demo`](https://gui-challenges.web.app/carousel/dist/)
[`YouTube`](#)(coming soon)
261 changes: 261 additions & 0 deletions carousel/carousel.css
@@ -0,0 +1,261 @@
/*
TODO:
- option for cyclical cycling
NICE TO HAVE:
- variable sized items demo
- arrow placement options
- dynamic add/remove slide handling
- attribute change update handling
- web component
- slots
- async initialization
- js api
*/

:where(.gui-carousel) {
--_carousel-item-size: 80%;
--_carousel-gutters: max(4rem, calc((100% - var(--_carousel-item-size)) / 2));
--_carousel-scrollbar-gutter: var(--size-6);
--_carousel-pagination-size: var(--size-8);

display: grid;
grid-template-columns: [carousel-gutter] var(--_carousel-gutters) 1fr [carousel-gutter] var(--_carousel-gutters);
grid-template-rows:
[carousel-scroller] 1fr
[carousel-pagination] var(--_carousel-pagination-size);

&:focus-visible {
outline-offset: -5px;
}

/* configuration handlers */
&[carousel-pagination="gallery"] {
--_carousel-pagination-size: var(--size-10);

& > .gui-carousel--pagination {
-webkit-mask-image: linear-gradient(to right, #0000 0%, #000 5%, 95%, #000, #0000);
}
}

&[carousel-pagination="none"] {
grid-template-rows: [carousel-scroller] 1fr;

& > .gui-carousel--pagination {
display: none;
}
}

&[carousel-controls="none"] {
grid-template-columns: 0 1fr 0;

& > .gui-carousel--controls {
display: none;
}
}

&[carousel-scrollbar="none"] {
--_carousel-pagination-size: var(--size-5);

& > .gui-carousel--scroller {
scrollbar-width: none;

&::-webkit-scrollbar {
display: none;
}
}

& > .gui-carousel--pagination {
place-self: start center;
}
}

&[carousel-snapstop="always"] .gui-carousel--snap {
scroll-snap-stop: always;
}
}

:where(.gui-carousel--scroller) {
grid-row: 1;
grid-column: 1/-1;

display: grid;
grid-auto-columns: 100%;
grid-auto-flow: column;
align-items: center;
gap: var(--_carousel-gutters);

padding-block: var(--size-2) var(--_carousel-scrollbar-gutter);
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
scroll-padding-inline: var(--_carousel-gutters);
padding-inline: var(--_carousel-gutters);

@media (--motionOK) {
scroll-behavior: smooth;
}
}

:where(.gui-carousel--snap) {
scroll-snap-align: center;
}

:where(.gui-carousel--controls) {
display: flex;
justify-content: space-between;
padding-inline: var(--_carousel-gutters);
display: contents;

& > .gui-carousel--control {
margin-block-end: var(--_carousel-scrollbar-gutter);

&:not([disabled="true"]):active {
transform: scale(.95);
}
}
}

:where(.gui-carousel--control) {
--_shadow-size: 0;
--_shadow-highlight-light: hsl(0 0% 50% / 10%);
--_shadow-highlight-dark: hsl(0 0% 100% / 20%);
--_shadow-highlight: var(--_shadow-highlight-light);

grid-row: 1;
place-self: center;
background: var(--surface-1);
color: var(--text-2);
inline-size: var(--size-8);
aspect-ratio: var(--ratio-square);
border-radius: var(--radius-round);
box-shadow: 0 0 0 var(--_shadow-size) var(--_shadow-highlight);
border: var(--border-size-1) solid transparent;
text-indent: 10ch;
padding: 0;
overflow: hidden;
z-index: var(--layer-1);
transition: opacity .5s var(--ease-2) .5s;

@media (--motionOK) {
transition:
opacity .5s var(--ease-2) .5s,
transform .2s var(--ease-4),
box-shadow .2s var(--ease-4),
outline-offset 145ms var(--ease-2)
;
}

@media (--OSdark) {
--_shadow-highlight: var(--_shadow-highlight-dark);
}

&:hover {
--_shadow-size: 6px;
}

&.--previous {
grid-column: 1;
}

&.--next {
grid-column: 3;
}

@nest [dir="rtl"] & > svg {
transform: rotateY(180deg);
}

&[disabled] {
cursor: not-allowed;
transition-delay: 0s;

& > svg {
opacity: .25;
}
}

&:not([disabled]):is(:hover, :focus-visible) {
color: var(--link);
}

&:not([disabled]) svg > path {
@media (--motionOK) {
--_transform: translateX(var(--_x)) scale(.95);
transition: transform .5s var(--ease-squish-3);
transform-origin: center center;
}
}

&[aria-label="Next Item"]:not([disabled]):is(:hover, :focus-visible) svg > path {
--_x: 2px;
transform: var(--_transform);
}

&[aria-label="Previous Item"]:not([disabled]):is(:hover, :focus-visible) svg > path {
--_x: -2px;
transform: var(--_transform);
}
}

:where(.gui-carousel--pagination) {
grid-column: 1/-1;
place-self: center;

display: grid;
grid-auto-flow: column;
gap: var(--size-2);

max-inline-size: 100%;
overflow-x: auto;
overscroll-behavior-x: contain;

padding-block: var(--size-2);
padding-inline: var(--size-4);

scrollbar-width: none;

&::-webkit-scrollbar {
display: none;
}

@media (--motionOK) {
scroll-behavior: smooth;
}

@nest [carousel-pagination="gallery"] & {
margin-block-end: 0;
}

& > [aria-selected="true"] {
background: var(--link);
}

& > [aria-selected="false"] {
transform: scale(.75);
}

& > button {
inline-size: var(--size-3);
background-color: var(--surface-4);
border: var(--border-size-1) solid transparent;

&.--gallery {
inline-size: var(--size-fluid-5);
border-radius: var(--radius-2);
border: none;
background-origin: border-box;
background-size: cover;
}
}
}

@keyframes gui-carousel--control-keypress {
0% { outline-offset: 5px }
50% { outline-offset: 0; }
}

@keyframes carousel-scrollstart {
from { scroll-snap-align: center }
to { scroll-snap-align: unset }
}

0 comments on commit 884e599

Please sign in to comment.