svelte-swipeout
Version:
iOS-style swipeable list component for Svelte 5 with delete animations and mobile-optimized touch handling
209 lines (201 loc) • 6.19 kB
CSS
:root {
--swipeout-delete-button-bg-color: #ff3b30;
--swipeout-button-text-color: #fff;
--swipeout-button-padding-vertical: 0;
--swipeout-button-padding-horizontal: 30px;
--swipeout-button-font-size: inherit;
--swipeout-button-font-weight:inherit;
--safe-area-left: 0px;
--safe-area-right: 0px;
--safe-area-top: 0px;
--safe-area-bottom: 0px;
--safe-area-outer-left: 0px;
--safe-area-outer-right: 0px;
--device-pixel-ratio:1;
}
.swipeout-list{
list-style: none;
margin: 0;
padding: 0;
}
.swipeout {
cursor: grab;
overflow: hidden;
transform-style: preserve-3d;
/* FIX: Allow vertical scrolling by default on mobile, but only vertical */
/* This prevents horizontal scrolling interference with swipe gestures */
touch-action: pan-y;
}
/* FIX: Disable all touch actions when actively swiping horizontally */
/* This prevents the page from scrolling vertically while user is swiping horizontally */
.swipeout.swipeout-swiping {
touch-action: none;
}
/* Default: Simple fade only */
.swipeout-deleting {
transition: opacity 0.3s ease-out;
}
.swipeout-deleting-active {
opacity: 0;
}
/* Option: Fade and collapse (add class 'swipeout-delete-collapse' to use) */
.swipeout-delete-collapse .swipeout-deleting {
overflow: hidden;
transition: height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.3s ease-out,
margin 0.4s cubic-bezier(0.4, 0, 0.2, 1),
padding 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.swipeout-delete-collapse .swipeout-deleting-active {
height: 0 ;
opacity: 0;
margin-top: 0 ;
margin-bottom: 0 ;
padding-top: 0 ;
padding-bottom: 0 ;
}
/* Option 1: Slide left (add class 'swipeout-delete-slide' to use) */
.swipeout-delete-slide .swipeout-deleting {
transition: height 0.3s ease-out,
opacity 0.25s ease-out,
transform 0.3s ease-out,
margin 0.3s ease-out,
padding 0.3s ease-out;
}
.swipeout-delete-slide .swipeout-deleting-active {
height: 0 ;
opacity: 0;
transform: translateX(-100%);
margin-top: 0 ;
margin-bottom: 0 ;
padding-top: 0 ;
padding-bottom: 0 ;
}
/* Option 3: Scale and fade (add class 'swipeout-delete-scale' to use) */
.swipeout-delete-scale .swipeout-deleting {
transform-origin: center;
transition: height 0.3s ease-out 0.1s,
opacity 0.2s ease-out,
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
margin 0.3s ease-out 0.1s,
padding 0.3s ease-out 0.1s;
}
.swipeout-delete-scale .swipeout-deleting-active {
height: 0 ;
opacity: 0;
transform: scale(0);
margin-top: 0 ;
margin-bottom: 0 ;
padding-top: 0 ;
padding-bottom: 0 ;
}
.swipeout-transitioning .swipeout-actions-left button,
.swipeout-transitioning .swipeout-actions-right button,
.swipeout-transitioning .swipeout-content,
.swipeout-transitioning .swipeout-overswipe {
transition-duration: 0.3s;
transition-property: transform,left;
}
.swipeout-content {
position: relative;
z-index: 10;
}
.swipeout-overswipe {
transition-duration: 0.2s;
transition-property: left;
}
.swipeout-actions-left,
.swipeout-actions-right {
position: absolute;
top: 0;
height: 100%;
display: flex;
direction: ltr;
}
.swipeout-actions-left > a,
.swipeout-actions-left > button,
.swipeout-actions-left > div,
.swipeout-actions-left > span,
.swipeout-actions-right > a,
.swipeout-actions-right > button,
.swipeout-actions-right > div,
.swipeout-actions-right > span {
cursor: pointer;
color: var(--swipeout-button-text-color);
padding: var(--swipeout-button-padding-vertical) var(--swipeout-button-padding-horizontal);
display: flex;
align-items: center;
position: relative;
left: 0;
font-size: var(--swipeout-button-font-size);
font-weight: var(--swipeout-button-font-weight);
}
/* Button reset styles */
.swipeout-actions-left > button,
.swipeout-actions-right > button {
border: none;
font-family: inherit;
text-align: center;
appearance: none;
-webkit-appearance: none;
}
.swipeout-actions-left > a:after,
.swipeout-actions-left > button:after,
.swipeout-actions-left > div:after,
.swipeout-actions-left > span:after,
.swipeout-actions-right > a:after,
.swipeout-actions-right > button:after,
.swipeout-actions-right > div:after,
.swipeout-actions-right > span:after {
content: "";
position: absolute;
top: 0;
width: 600%;
height: 100%;
background: inherit;
z-index: -1;
transform: translate3d(0, 0, 0);
pointer-events: none;
}
.swipeout-actions-left .swipeout-delete,
.swipeout-actions-right .swipeout-delete {
background: var(--swipeout-delete-button-bg-color);
}
.swipeout-actions-right {
right: 0%;
transform: translateX(calc(100% + 1px));
}
.swipeout-actions-right > a:after,
.swipeout-actions-right > button:after,
.swipeout-actions-right > div:after,
.swipeout-actions-right > span:after {
left: 100%;
}
.swipeout-actions-right > a:last-child,
.swipeout-actions-right > button:last-child,
.swipeout-actions-right > div:last-child,
.swipeout-actions-right > span:last-child {
padding-right: calc(
var(--swipeout-button-padding-horizontal) + var(--safe-area-right)
);
}
.swipeout-actions-left {
left: 0%;
transform: translateX(calc(-100% - 1px));
}
.swipeout-actions-left > a:after,
.swipeout-actions-left > button:after,
.swipeout-actions-left > div:after,
.swipeout-actions-left > span:after {
right: 100%;
}
.swipeout-actions-left > a:first-child,
.swipeout-actions-left > button:first-child,
.swipeout-actions-left > div:first-child,
.swipeout-actions-left > span:first-child {
/* padding-left:calc(var(--swipeout-button-padding-horizontal) + var(--safe-area-left)) */
}
.swipeout-actions-left [class*="color-"],
.swipeout-actions-right [class*="color-"] {
--swipeout-button-bg-color: var(--theme-color);
}