Skip to content

Commit

Permalink
Feat carousel (#106)
Browse files Browse the repository at this point in the history
* Initial Commit

* QuirkBoomerand - added POC

* Quirk-Boomerang code update

* Minor changes

* code imorvment - used method directly instead of creating variable

* fix: move quirk forward gliches

* updated code to deletct scroll end

* QuirkBoomerang - added support to move backward

* QuirkBoomerang - manage visibility of move buttons

* QuirkBoomerang - fix: move button visibility code

* QuirkBoomerang - fix: move issue - 1 display count

* QuirkBoomrang - check elm in parent & viewport

* fix: move button visibility

* added styles to move buttons

* removed shadowDom setting - default set to false

* commnted tests

* scrollTimeout clear interval code update

* added support for keyboard navigation

* support=>btn inaccessible behaviour->hide|disable

* fix: issue with move backward

* style: chnage for element height & btn cursor

* chore: index.html change

* chore: updated library version
  • Loading branch information
akki-jat committed Feb 13, 2021
1 parent c773348 commit c6c6238
Show file tree
Hide file tree
Showing 11 changed files with 12,099 additions and 59 deletions.
4 changes: 2 additions & 2 deletions bindings/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@one-for-all-ui/react",
"version": "0.0.4-beta.9",
"version": "0.0.5-beta.0",
"description": "React Design Library",
"author": {
"name": "Akshay Jat (akki-jat)",
Expand Down Expand Up @@ -29,7 +29,7 @@
"prepublishOnly": "run-s build"
},
"dependencies": {
"@one-for-all-ui/core": "0.0.4-beta.9"
"@one-for-all-ui/core": "0.0.5-beta.0"
},
"peerDependencies": {
"react": "^16.0.0"
Expand Down
1 change: 1 addition & 0 deletions bindings/react/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ import { applyPolyfills, defineCustomElements } from '@one-for-all-ui/core/loade

applyPolyfills().then(() => defineCustomElements());
export const DarkShadow = /*@__PURE__*/createReactComponent<JSX.DarkShadow, HTMLDarkShadowElement>('dark-shadow');
export const QuirkBoomerang = /*@__PURE__*/createReactComponent<JSX.QuirkBoomerang, HTMLQuirkBoomerangElement>('quirk-boomerang');
export const SpecialCard = /*@__PURE__*/createReactComponent<JSX.SpecialCard, HTMLSpecialCardElement>('special-card');
export const ZeroGravityButton = /*@__PURE__*/createReactComponent<JSX.ZeroGravityButton, HTMLZeroGravityButtonElement>('zero-gravity-button');
11,625 changes: 11,607 additions & 18 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@one-for-all-ui/core",
"version": "0.0.4-beta.9",
"version": "0.0.5-beta.0",
"author": {
"name": "Akshay Jat (akki-jat)",
"email": "akshayjat06@gmail.com",
Expand Down
24 changes: 24 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export namespace Components {
"visible": boolean;
"width": string;
}
interface QuirkBoomerang {
"displayCount": | { small: string, medium: string, large: string }
| string | number;
"moveButtonInaccessibleBehaviour": "disable" | "hide";
"moveCount": number;
"moveQuirk": (isMoveForward: boolean | undefined, moveElementIndex?: number | undefined) => Promise<void>;
"totalElements": number;
}
interface SpecialCard {
"borderRadius": string;
"cardSubtitle": string;
Expand Down Expand Up @@ -54,6 +62,12 @@ declare global {
prototype: HTMLDarkShadowElement;
new (): HTMLDarkShadowElement;
};
interface HTMLQuirkBoomerangElement extends Components.QuirkBoomerang, HTMLStencilElement {
}
var HTMLQuirkBoomerangElement: {
prototype: HTMLQuirkBoomerangElement;
new (): HTMLQuirkBoomerangElement;
};
interface HTMLSpecialCardElement extends Components.SpecialCard, HTMLStencilElement {
}
var HTMLSpecialCardElement: {
Expand All @@ -68,6 +82,7 @@ declare global {
};
interface HTMLElementTagNameMap {
"dark-shadow": HTMLDarkShadowElement;
"quirk-boomerang": HTMLQuirkBoomerangElement;
"special-card": HTMLSpecialCardElement;
"zero-gravity-button": HTMLZeroGravityButtonElement;
}
Expand All @@ -86,6 +101,13 @@ declare namespace LocalJSX {
"visible"?: boolean;
"width"?: string;
}
interface QuirkBoomerang {
"displayCount"?: | { small: string, medium: string, large: string }
| string | number;
"moveButtonInaccessibleBehaviour"?: "disable" | "hide";
"moveCount"?: number;
"totalElements"?: number;
}
interface SpecialCard {
"borderRadius"?: string;
"cardSubtitle"?: string;
Expand Down Expand Up @@ -117,6 +139,7 @@ declare namespace LocalJSX {
}
interface IntrinsicElements {
"dark-shadow": DarkShadow;
"quirk-boomerang": QuirkBoomerang;
"special-card": SpecialCard;
"zero-gravity-button": ZeroGravityButton;
}
Expand All @@ -126,6 +149,7 @@ declare module "@stencil/core" {
export namespace JSX {
interface IntrinsicElements {
"dark-shadow": LocalJSX.DarkShadow & JSXBase.HTMLAttributes<HTMLDarkShadowElement>;
"quirk-boomerang": LocalJSX.QuirkBoomerang & JSXBase.HTMLAttributes<HTMLQuirkBoomerangElement>;
"special-card": LocalJSX.SpecialCard & JSXBase.HTMLAttributes<HTMLSpecialCardElement>;
"zero-gravity-button": LocalJSX.ZeroGravityButton & JSXBase.HTMLAttributes<HTMLZeroGravityButtonElement>;
}
Expand Down
84 changes: 84 additions & 0 deletions src/components/quirk-boomerang/quirk-boomerang.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.quirk-boomerang-container {
position: relative;
/* margin-left: 1.4em;
margin-right: 1.4em; */
}

.quirk-boomerang-container .move-btns {
display: flex;
justify-content: space-between;
}

.quirk-boomerang-container .move-btns button {
width: 3rem;
height: 3rem;
cursor: pointer;
border-radius: 2rem;
}

.quirk-boomerang-container .move-btns button:focus {
outline: inherit;
}

.quirk-boomerang-container .move-btns .move-btn-wrapper {
z-index: 1;
position: absolute;
top: calc(50% - calc(3rem - 22px));
}

.quirk-boomerang-container .move-btns .backward-move-btn-wrapper {
left: 0;
}

.quirk-boomerang-container .move-btns .forward-move-btn-wrapper {
right: 0;
}

.quirk-boomerang-container .quirk-container {
overflow-x: hidden;
display: grid;
grid-auto-flow: column;
/* grid-template-columns: 70%;
grid-auto-columns: 70%; */
scroll-snap-type: x mandatory;
}

.quirk-boomerang-container .quirk-container > * {
padding: 1em;
display: flex;
justify-content: center;
align-items: center;
scroll-snap-align: start;
}

.quirk-boomerang-container .quirk-container > * > * {
max-width: calc(100% - 1rem);
max-height: calc(100vh - 3rem);
}

/* Small devices (landscape phones, 576px and up) */
@media (max-width: 767.9px) {
.quirk-boomerang-container .quirk-container {
/* overflow-x: scroll; */
grid-template-columns: repeat(var(--quirk-small-count), calc(100% / var(--quirk-small-count)));
grid-auto-columns: calc(100% / var(--quirk-small-count));
}
}

/* Medium devices (tablets, 768px and up) */
@media (min-width: 768px) {
.quirk-boomerang-container .quirk-container {
/* overflow-x: scroll; */
grid-template-columns: repeat(var(--quirk-medium-count), calc(100% / var(--quirk-medium-count)));
grid-auto-columns: calc(100% / var(--quirk-medium-count));
}
}

/* Large devices (desktops, 992px and up) or Extra large devices (large desktops, 1200px and up) */
@media (min-width: 992px), (min-width: 1200px) {
.quirk-boomerang-container .quirk-container {
overflow-x: hidden;
grid-template-columns: repeat(var(--quirk-large-count), calc(100% / var(--quirk-large-count)));
grid-auto-columns: calc(100% / var(--quirk-large-count));
}
}
206 changes: 206 additions & 0 deletions src/components/quirk-boomerang/quirk-boomerang.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { Component, h, Method, Prop, State, Element } from '@stencil/core';
import { isElementVisibleInViewportAndParent } from '../../utils/utils';

@Component({
tag: 'quirk-boomerang',
styleUrl: 'quirk-boomerang.css',
})
export class QuirkBoomerang {
@Element() quirkEl: HTMLElement;
@Prop() moveCount: number = 1;
@Prop() totalElements: number = 0;
@Prop() displayCount:
| { small: string, medium: string, large: string }
| string | number = { small: "1", medium: "2", large: "4" };
@Prop() moveButtonInaccessibleBehaviour: "disable" | "hide" = "disable";

@State() lastMovedElement: Element;
@State() moveDirection: "forward" | "backward";
@State() visibleMoveButton = { forward: true, backward: false };
scrollTimeoutId: number;

get quirkContainerEl() {
return this.quirkEl.querySelector("quirk-boomerang .quirk-container");
}

get visibleQuirks() {
return this.quirkContainerEl.querySelectorAll(".quirk-visible");
}

get quirkCount() {
let count = 1;

try {
if (typeof this.displayCount === "object") {
return this.displayCount;
}

if (isNaN(this.displayCount as number)) {
return JSON.parse(this.displayCount as string);
} else {
count = +this.displayCount;
}
} catch (error) {
console.warn("Set proper value for displayCount prop. Error: ", error)
}

return { small: count, medium: count, large: count };
}

get elementCount() {
return (this.totalElements || document.querySelectorAll("quirk-boomerang .quirk-container > [quirk-index]").length);
}

get lastMovedElementIndex() {
return this.lastMovedElement ? +this.lastMovedElement.getAttribute("quirk-index") : -1;
}

@Method()
async moveQuirk(isMoveForward: boolean | undefined, moveElementIndex: number | undefined = undefined) {
if (moveElementIndex) {
this.moveDirection = moveElementIndex >= this.lastMovedElementIndex ? "forward" : "backward";
isMoveForward = this.moveDirection === "forward";
} else {
this.moveDirection = isMoveForward ? "forward" : "backward";
}

// if (this.visibleQuirks && this.visibleQuirks.length && (!moveElementIndex || (moveElementIndex && moveElementIndex !== this.lastMovedElementIndex))) {
if (this.visibleQuirks && this.visibleQuirks.length) {
const currentEndIndex = +this.visibleQuirks[this.visibleQuirks.length - 1].getAttribute("quirk-index");
const moveToIndex = moveElementIndex != null ? moveElementIndex
: isMoveForward ? currentEndIndex + this.moveCount : currentEndIndex - this.moveCount;
let moveEl = this.quirkContainerEl.querySelector(`[quirk-index="${moveToIndex}"]`) || this.quirkContainerEl.lastElementChild;

if (this.lastMovedElement === moveEl) {
moveEl = this.quirkContainerEl.querySelector(`[quirk-index="${moveToIndex + this.moveCount}"]`) || this.quirkContainerEl.lastElementChild;
}

if (moveEl) {
this.lastMovedElement = moveEl;
moveEl.scrollIntoView({ behavior: "smooth", block: "center", inline: "end" });
}
}
}

setVisibleQuirks() {
let visibleQuirkClassSetFailCount = 0;
const isFirstRender = this.lastMovedElement == null;
const lastMoveElementIndex = isFirstRender ? 0 : +this.lastMovedElement.getAttribute("quirk-index");
const isVisibleQuirksAvailable = this.visibleQuirks && this.visibleQuirks.length;
const isMoveForward = this.moveDirection == null || this.moveDirection === "forward";
const firstVisibleQuirkIndex = isFirstRender ? 0 : isVisibleQuirksAvailable
? +this.visibleQuirks[0].getAttribute("quirk-index")
: lastMoveElementIndex;
const lastVisibleQuirkIndex = isFirstRender ? this.moveCount : isVisibleQuirksAvailable
? +this.visibleQuirks[this.visibleQuirks.length - 1].getAttribute("quirk-index")
: lastMoveElementIndex;
let index = isMoveForward ? firstVisibleQuirkIndex : lastVisibleQuirkIndex;
this.quirkContainerEl.querySelectorAll("[quirk-index]").forEach(quirk => quirk.classList.remove("quirk-visible"));

while (true) {
const el = this.quirkContainerEl.querySelector(`[quirk-index="${index}"]`);

if (el && isElementVisibleInViewportAndParent(el)) {
el.classList.add("quirk-visible");
} else {
visibleQuirkClassSetFailCount++;
}

if (isMoveForward) {
index++;
} else {
index--;
}

if (visibleQuirkClassSetFailCount > this.elementCount) {
break;
}
}

this.setMoveButtonVisibility(
isMoveForward ? firstVisibleQuirkIndex : firstVisibleQuirkIndex - this.moveCount,
isMoveForward ? lastVisibleQuirkIndex + this.moveCount : lastVisibleQuirkIndex,
isFirstRender
);
}

setMoveButtonVisibility(firstVisibleQuirkIndex: number, lastVisibleQuirkIndex: number, isFirstRender: boolean) {
if (!isFirstRender) {
this.visibleMoveButton = {
...this.visibleMoveButton,
forward: lastVisibleQuirkIndex < this.elementCount - 1,
backward: firstVisibleQuirkIndex > 0
}
}
}

keyPressHandler(event: KeyboardEvent) {
if (event.key === "Tab" && document.activeElement && document.activeElement.getAttribute("quirk-index")) {
let moveElementIndex = +document.activeElement.getAttribute("quirk-index");
// here added 1 to make sure next element to focus is in view
this.moveQuirk(undefined, moveElementIndex + 1);
}
}

scrollEventCallback(_e: Event) {
if (this.scrollTimeoutId != null) {
clearTimeout(this.scrollTimeoutId);
}

this.scrollTimeoutId = window.setTimeout(() => {
this.setVisibleQuirks();
}, 0);
}

componentDidLoad() {
this.setVisibleQuirks();
}

componentDidRender() {
this.quirkContainerEl.addEventListener('scroll', this.scrollEventCallback.bind(this));
}

disconnectedCallback() {
this.quirkContainerEl.removeEventListener("scroll", this.scrollEventCallback.bind(this));
}

render() {
return (
<div class="quirk-boomerang-container">
<div class="move-btns" tabIndex={-1}>
{this.moveButtonInaccessibleBehaviour === "disable" || this.visibleMoveButton.backward ?
<slot name="left-button">
<div class="move-btn-wrapper backward-move-btn-wrapper">
<button
class="move-btn backward-move backward-move-btn"
disabled={!this.visibleMoveButton.backward}
onClick={this.moveQuirk.bind(this, false, undefined)}
>
&lt;
</button>
</div>
</slot>
: null
}
{this.moveButtonInaccessibleBehaviour === "disable" || this.visibleMoveButton.forward ?
<slot name="right-button">
<div class="move-btn-wrapper forward-move-btn-wrapper">
<button
class="move-btn forward-move forward-move-btn"
disabled={!this.visibleMoveButton.forward}
onClick={this.moveQuirk.bind(this, true, undefined)}
>
&gt;
</button>
</div>
</slot>
: null
}
</div>
<div class="quirk-container" onKeyUp={this.keyPressHandler.bind(this)} style={{ "--quirk-small-count": this.quirkCount.small, "--quirk-medium-count": this.quirkCount.medium, "--quirk-large-count": this.quirkCount.large }}>
<slot></slot>
</div>
</div>
);
}
}

0 comments on commit c6c6238

Please sign in to comment.