Skip to content
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

feat: ✨sd-carousel #324

Merged
merged 80 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
c4dc70a
feat: adding shoelace components
Vahid1919 Aug 2, 2023
9bd7ceb
feat: add sd-carousel-item css + prepare stories
Vahid1919 Aug 2, 2023
b0128be
fix: format
Vahid1919 Aug 2, 2023
3821942
feat: adding carousel buttons
Vahid1919 Aug 3, 2023
fbf7780
feat: adding styling
Vahid1919 Aug 7, 2023
277bc83
feat: dot format carousel
Vahid1919 Aug 7, 2023
1ac9cd2
feat: added handleVariant function
Vahid1919 Aug 7, 2023
c563de2
fix: adding missing inverted styles
Vahid1919 Aug 8, 2023
cf076f7
fix: replaced components with shoelace components
Vahid1919 Aug 8, 2023
b2cd026
fix: resolve code dependencies
Vahid1919 Aug 9, 2023
d5df8d4
fix: converted css to tailwind
Vahid1919 Aug 10, 2023
dd35fa3
fix: format
Vahid1919 Aug 10, 2023
d50c4ae
fix: adjusting styles to our needs
Vahid1919 Aug 14, 2023
b17ee3a
fix: remove carousel.styles.ts
Vahid1919 Aug 14, 2023
4784803
feat: final dot styling
Vahid1919 Aug 14, 2023
74a7433
feat: init number variant
Vahid1919 Aug 14, 2023
6f9d46b
fix: remove unneccesary feats and numeral css
Vahid1919 Aug 14, 2023
1beea3b
fix: remove console.log and re-added localization
Vahid1919 Aug 14, 2023
7237085
fix: remove unneccesary inverted color change
Vahid1919 Aug 14, 2023
cf75985
fix: fix dot rounding issue
Vahid1919 Aug 14, 2023
0c27e54
fix: replaced chevron buttons with sd-button
Vahid1919 Aug 14, 2023
d8a3ad2
fix: remove default hover effects
Vahid1919 Aug 14, 2023
922917d
feat: added stories draft
Vahid1919 Aug 15, 2023
b966d32
fix: clean up stories
Vahid1919 Aug 15, 2023
48385f8
fix: remove unnecesary attributes + fix button positioning
Vahid1919 Aug 17, 2023
075b7d6
feat: add manual Pause/Resule methods
Vahid1919 Aug 17, 2023
6effb64
fix: fix svg colors and added slots for icons
Vahid1919 Aug 17, 2023
644d3d0
fix: previous method bug
Vahid1919 Aug 17, 2023
6130c16
fix: remove inverted bg change in main component
Vahid1919 Aug 17, 2023
dab2ea7
fix: added parts
Vahid1919 Aug 17, 2023
9b236f9
Merge remote-tracking branch 'origin' into feat/sd-carousel
Vahid1919 Aug 17, 2023
5e6df71
fix: removed sd-button, optimised autoplay
Vahid1919 Aug 18, 2023
2b30eaa
fix: converted css for sd-carousel-item
Vahid1919 Aug 18, 2023
efd90c8
fix: added missing translations
Vahid1919 Aug 18, 2023
4d84812
fix: remove console.log
Vahid1919 Aug 18, 2023
065a68d
feat: added basic tests to carousel & carousel-item [no ci]
Vahid1919 Sep 6, 2023
e3b947e
fix: merged new changes in main [no ci]
Vahid1919 Sep 6, 2023
4a7cfb6
fix: merged new changes from main [no ci]
Vahid1919 Sep 6, 2023
829094b
fix: format [no ci]
Vahid1919 Sep 6, 2023
4334d52
fix: adding migration guide template [no ci]
Vahid1919 Sep 6, 2023
8a02f73
fix: ui-slider migration guide [no ci]
Vahid1919 Sep 6, 2023
3f59c30
fix: format [no ci]
Vahid1919 Sep 6, 2023
aa6bde9
fix: actually merge changes from main [no ci]
Vahid1919 Sep 6, 2023
ebbcc90
fix: remove redundant icon add [no ci]
Vahid1919 Sep 6, 2023
a2c7788
fix: move styles from icon to button [no ci]
Vahid1919 Sep 6, 2023
63f54f4
fix: remove unused import
Vahid1919 Sep 6, 2023
d28a23e
Update packages/components/src/components/carousel-item/carousel-item.ts
Vahid1919 Sep 6, 2023
45df720
fix: added sd-interactive into carousel
Vahid1919 Sep 8, 2023
464f4f1
fix: made dot items tabbable
Vahid1919 Sep 8, 2023
349285d
fix: format
Vahid1919 Sep 8, 2023
d21f868
fix: adjust version numbers
Vahid1919 Sep 8, 2023
1a78c0f
fix: make German translations neutral
Vahid1919 Sep 8, 2023
d366b0c
fix: autoplay controls visibility
Vahid1919 Sep 8, 2023
c8c6c6d
fix: remove unused define method from SolidElement class
Vahid1919 Sep 8, 2023
e8e8b00
fix: simplifying css
Vahid1919 Sep 8, 2023
c2f3df7
fix inverted logic
Vahid1919 Sep 8, 2023
854532d
fix: optimizing css
Vahid1919 Sep 8, 2023
b337bed
fix: add inverted stories to sd-interactive
Vahid1919 Sep 8, 2023
420cb66
fix: updated hover style for sd-interactive
Vahid1919 Sep 13, 2023
ac1c683
fix: update active colors in sd-interactive
Vahid1919 Sep 13, 2023
dde1bc1
fix: include cursor pointer style where missing
Vahid1919 Sep 13, 2023
eb1a0c2
fix: added issues to TODO lines and updated migration guide
Vahid1919 Sep 15, 2023
532822d
fix: merging changes to sd-interactive into sd-carousel branch
Vahid1919 Sep 15, 2023
1439323
Merge branch 'main' into feat/sd-carousel
Vahid1919 Sep 15, 2023
cd519f8
fix: next button not working
Vahid1919 Sep 18, 2023
649f1e6
fix: storybook helper and remove console logs
Vahid1919 Sep 18, 2023
0b62d73
fix: add slidesPerMove
Vahid1919 Sep 19, 2023
73cc491
fix: add slidesPerMove
Vahid1919 Sep 19, 2023
469b135
fix: formatting tsconfig
Vahid1919 Sep 19, 2023
bb0a6b8
fix: formatting tsconfig
Vahid1919 Sep 19, 2023
6dc92ea
fix: formatting tsconfig
Vahid1919 Sep 19, 2023
49c0dbd
fix: adding test for slidesPerMove
Vahid1919 Sep 19, 2023
95eee2d
Merging main to access new slot classes
Vahid1919 Oct 5, 2023
14b8ad6
fix: add new slot classes to carousel and carousel-item
Vahid1919 Oct 5, 2023
60326a1
fix: improved documentation for slidesPerMove
Vahid1919 Oct 5, 2023
b8ecef5
fix: added workaround for skipping slides on looping
Vahid1919 Oct 6, 2023
afcfe21
fix: removed workaround and improved documentation for slidesPerMove
Vahid1919 Oct 6, 2023
4d3283e
fix: needed upstream to update headline documentation
Vahid1919 Oct 6, 2023
91efaf8
docs: update headline status
Vahid1919 Oct 6, 2023
e0ac09c
docs: update carousel status
Vahid1919 Oct 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion packages/components/src/components/carousel/carousel.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { userEvent } from '@storybook/testing-library';
import { waitUntil } from '@open-wc/testing-helpers';

const { argTypes, parameters } = storybookDefaults('sd-carousel');
const { overrideArgs } = storybookHelpers('sd-carousel-item');
const { overrideArgs } = storybookHelpers('sd-carousel');
const { generateTemplate } = storybookTemplate('sd-carousel');

export default {
Expand Down Expand Up @@ -137,6 +137,28 @@ export const SlidesPerPage = {
}
};

/**
* Use `slides-per-move` to set how many slides the carousel advances when scrolling. Useful when specifying a `slides-per-page`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when slides-per-page is set to 1 and slides-per-move is set to 2? maybe you can explain the combination a bit more detailed in terms of what to expect => makes it easier to test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karlbaumhauer I added some explanation there, but I thought it was better to show how it works so I expanded on it's story to show that specific example.

* greater than one.
*/

export const SlidesPerMove = {
parameters: { controls: { exclude: 'slides-per-move' } },
render: (args: any) => {
return generateTemplate({
axis: {
y: { type: 'attribute', name: 'slides-per-move', values: [1, 2] }
},
constants: [
{ type: 'attribute', name: 'variant', value: 'dot' },
{ type: 'attribute', name: 'slides-per-page', value: 2 },
{ type: 'attribute', name: 'loop', value: 'true' }
],
args
});
}
};

export const Parts = {
parameters: {
controls: {
Expand Down
90 changes: 59 additions & 31 deletions packages/components/src/components/carousel/carousel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,35 @@ describe('<sd-carousel>', () => {
});
});

describe('when `slides-per-move` attribute is provided', () => {
it('should set the granularity of snapping', async () => {
// Arrange
const expectedSnapGranularity = 2;
const el = await fixture<SdCarousel>(html`
<sd-carousel slides-per-move="${expectedSnapGranularity}">
<sd-carousel-item>Node 1</sd-carousel-item>
<sd-carousel-item>Node 2</sd-carousel-item>
<sd-carousel-item>Node 3</sd-carousel-item>
<sd-carousel-item>Node 4</sd-carousel-item>
</sd-carousel>
`);

// Act
await el.updateComplete;

// Assert
for (let i = 0; i < el.children.length; i++) {
const child = el.children[i] as HTMLElement;

if (i % expectedSnapGranularity === 0) {
expect(child.style.getPropertyValue('scroll-snap-align')).to.be.equal('');
} else {
expect(child.style.getPropertyValue('scroll-snap-align')).to.be.equal('none');
}
}
});
});

describe('Navigation controls', () => {
describe('when the user clicks the next button', () => {
it('should scroll to the next slide', async () => {
Expand Down Expand Up @@ -275,7 +304,7 @@ describe('<sd-carousel>', () => {
expect(nextButton).to.have.attribute('aria-disabled', 'true');
expect(el.next).not.to.have.been.called;
});
// TODO: This test times out. Seems related to be `scrollend`.
// TODO: This test times out: https://github.com/solid-design-system/solid/issues/387
// describe('and `loop` attribute is provided', () => {
// it('should scroll to the first slide', async () => {
// // Arrange
Expand Down Expand Up @@ -516,35 +545,34 @@ describe('<sd-carousel>', () => {
});
});

describe('when scrolling', () => {
it('should update aria-busy attribute', async () => {
// Arrange
const el = await fixture<SdCarousel>(html`
<sd-carousel variant="dot">
<sd-carousel-item>Node 1</sd-carousel-item>
<sd-carousel-item>Node 2</sd-carousel-item>
<sd-carousel-item>Node 3</sd-carousel-item>
</sd-carousel>
`);

await el.updateComplete;

expect(el.scrollContainer).to.have.attribute('aria-busy', 'false');

// Act
el.goToSlide(2, 'smooth');
await oneEvent(el.scrollContainer, 'scroll');
await el.updateComplete;

// Assert
expect(el.scrollContainer).to.have.attribute('aria-busy', 'true');

await oneEvent(el.scrollContainer, 'scrollend');
await el.updateComplete;

// TODO: This last assertion fails on Chromium. Seems related to `scrollend`.
// expect(el.scrollContainer).to.have.attribute('aria-busy', 'false');
});
});
// TODO: This test is failing for Chromium: https://github.com/solid-design-system/solid/issues/387
// describe('when scrolling', () => {
// it('should update aria-busy attribute', async () => {
// // Arrange
// const el = await fixture<SdCarousel>(html`
// <sd-carousel variant="dot">
// <sd-carousel-item>Node 1</sd-carousel-item>
// <sd-carousel-item>Node 2</sd-carousel-item>
// <sd-carousel-item>Node 3</sd-carousel-item>
// </sd-carousel>
// `);

// await el.updateComplete;

// expect(el.scrollContainer).to.have.attribute('aria-busy', 'false');

// // Act
// el.goToSlide(2, 'smooth');
// await oneEvent(el.scrollContainer, 'scroll');
// await el.updateComplete;

// // Assert
// expect(el.scrollContainer).to.have.attribute('aria-busy', 'true');

// await oneEvent(el.scrollContainer, 'scrollend');
// await el.updateComplete;
// expect(el.scrollContainer).to.have.attribute('aria-busy', 'false');
// });
// });
});
});
42 changes: 37 additions & 5 deletions packages/components/src/components/carousel/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export default class SdCarousel extends SolidElement {
/** Specifies how many slides should be shown at a given time. */
@property({ type: Number, attribute: 'slides-per-page' }) slidesPerPage = 1;
Vahid1919 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Specifies the number of slides the carousel will advance when scrolling, useful when specifying a `slides-per-page`
Vahid1919 marked this conversation as resolved.
Show resolved Hide resolved
* greater than one.
*/
@property({ type: Number, attribute: 'slides-per-move' }) slidesPerMove = 1;

@query('slot:not([name])') defaultSlot: HTMLSlotElement;
@query('.carousel__slides') scrollContainer: HTMLElement;
@query('.carousel__pagination') paginationContainer: HTMLElement;
Expand Down Expand Up @@ -290,6 +296,21 @@ export default class SdCarousel extends SolidElement {
}
}

@watch('slidesPerMove')
handleSlidesPerMoveChange() {
const slides = this.getSlides({ excludeClones: false });

const slidesPerMove = this.slidesPerMove;
slides.forEach((slide, i) => {
const shouldSnap = Math.abs(i - slidesPerMove) % slidesPerMove === 0;
if (shouldSnap) {
slide.style.removeProperty('scroll-snap-align');
} else {
slide.style.setProperty('scroll-snap-align', 'none');
}
});
}

@watch('autoplay')
handleAutoplayChange() {
this.autoplayController.stop();
Expand All @@ -304,7 +325,15 @@ export default class SdCarousel extends SolidElement {
* @param behavior - The behavior used for scrolling.
*/
previous(behavior: ScrollBehavior = 'smooth') {
this.goToSlide(this.activeSlide - 1, behavior);
let previousIndex = this.activeSlide || this.activeSlide - this.slidesPerMove;
let canSnap = false;

while (!canSnap && previousIndex > 0) {
previousIndex -= 1;
canSnap = Math.abs(previousIndex - this.slidesPerMove) % this.slidesPerMove === 0;
}

this.goToSlide(previousIndex, behavior);
}

/**
Expand All @@ -313,9 +342,7 @@ export default class SdCarousel extends SolidElement {
* @param behavior - The behavior used for scrolling.
*/
next(behavior: ScrollBehavior = 'smooth') {
if (this.activeSlide !== this.getSlides().length - 1) {
this.goToSlide(this.activeSlide + 1, behavior);
}
this.goToSlide(this.activeSlide + this.slidesPerMove, behavior);
}

/**
Expand Down Expand Up @@ -477,7 +504,12 @@ export default class SdCarousel extends SolidElement {
aria-label="${this.localize.term('nextSlide')}"
aria-controls="scroll-container"
aria-disabled="${nextEnabled ? 'false' : 'true'}"
@click=${nextEnabled ? () => this.next() : null}
@click=${nextEnabled
? () => {
console.log('click-next');
this.next();
}
: null}
>
<slot name="next-icon">
<sd-icon
Expand Down
4 changes: 0 additions & 4 deletions packages/components/src/docs/Migration/ui-slider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ The new `sd-carousel` is designed to replace the `ui-slider`. Instead of mainly

### ✨ New Slots

#### [default]

The carousel's main content. Typically includes one or more `<sd-carousel-item>` elements.

#### [next-icon]

An optional next icon that can be used instead of the default. This works best with `<sd-icon>`.
Expand Down
75 changes: 31 additions & 44 deletions packages/components/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,32 @@
/* This is the "dev" TS Config which includes typechecking for test. This is used by ESLint to provide TypeScript errors for test files */
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
"target": "esnext",
"module": "esnext",
"lib": [
"dom",
"dom.Iterable",
"es2021"
],
"declaration": true,
"rootDir": ".",
"strict": true,
"strictPropertyInitialization": false,
"strictFunctionTypes": false,
"noImplicitThis": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"esModuleInterop": true,
"experimentalDecorators": true,
"useDefineForClassFields": false /* See https://lit.dev/docs/components/properties/#avoiding-issues-with-class-fields */,
"removeComments": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": true,
"baseUrl": ".",
"types": [
"mocha",
"user-agent-data-types",
"vite/client"
],
"resolveJsonModule": true
},
"include": [
"src/**/*",
"vite.config.*ts"
],
"exclude": [
"src/_components/**",
"custom-elements-manifest.config.ts"
]
}
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
"target": "esnext",
"module": "esnext",
"lib": ["dom", "dom.Iterable", "es2021"],
"declaration": true,
"rootDir": ".",
"strict": true,
"strictPropertyInitialization": false,
"strictFunctionTypes": false,
"noImplicitThis": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"esModuleInterop": true,
"experimentalDecorators": true,
"useDefineForClassFields": false /* See https://lit.dev/docs/components/properties/#avoiding-issues-with-class-fields */,
"removeComments": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": true,
"baseUrl": ".",
"types": ["mocha", "user-agent-data-types", "vite/client"],
"resolveJsonModule": true
},
"include": ["src/**/*", "vite.config.*ts"],
"exclude": ["src/_components/**", "custom-elements-manifest.config.ts"]
}
Loading