diff --git a/src/components/SizeSelector/images/large.js b/src/components/SizeSelector/images/large.js
new file mode 100644
index 00000000..7f3abc6d
--- /dev/null
+++ b/src/components/SizeSelector/images/large.js
@@ -0,0 +1,5 @@
+const large = ``;
+
+export default large;
diff --git a/src/components/SizeSelector/images/medium.js b/src/components/SizeSelector/images/medium.js
new file mode 100644
index 00000000..95ef5f51
--- /dev/null
+++ b/src/components/SizeSelector/images/medium.js
@@ -0,0 +1,5 @@
+const medium = ``;
+
+export default medium;
diff --git a/src/components/SizeSelector/images/small.js b/src/components/SizeSelector/images/small.js
new file mode 100644
index 00000000..a08478b4
--- /dev/null
+++ b/src/components/SizeSelector/images/small.js
@@ -0,0 +1,5 @@
+const small = ``;
+
+export default small;
diff --git a/src/components/SizeSelector/index.js b/src/components/SizeSelector/index.js
new file mode 100644
index 00000000..1621cc76
--- /dev/null
+++ b/src/components/SizeSelector/index.js
@@ -0,0 +1,164 @@
+import { Component } from 'pet-dex-utilities';
+import small from './images/small';
+import medium from './images/medium';
+import large from './images/large';
+
+import './index.scss';
+
+const events = ['event'];
+
+const html = `
+
+
+ -
+
+
+ ${small}
+
+
+
Small
+ under 14kg
+
+
+
+
+ -
+
+
+ ${medium}
+
+
+
Medium
+ 14-25kg
+
+
+
+
+ -
+
+
+ ${large}
+
+
+
Large
+ over 25kg
+
+
+
+
+
+`;
+
+export default function SizeSelector() {
+ Component.call(this, { html, events });
+
+ this.$sizeList = this.selected.get('sizelist');
+ this.$cards = Array.from(
+ this.$sizeList.querySelectorAll('.container-size-selector__card'),
+ );
+
+ const addEventListeners = (card, index) => {
+ card.addEventListener('click', () => {
+ this.selectCard(card, index);
+ this.getCardActiveEvent('click', card, index);
+ });
+
+ card.addEventListener('keydown', (key) => {
+ this.handleKeyDown(key, card);
+ });
+ };
+
+ this.$cards.forEach((card, index) => addEventListeners(card, index));
+}
+
+SizeSelector.prototype = Object.assign(
+ SizeSelector.prototype,
+ Component.prototype,
+ {
+ setText(index, title, subtitle) {
+ const h3 = this.$cards[index].querySelector('h3');
+ const span = this.$cards[index].querySelector('span');
+ h3.textContent = title;
+ span.textContent = subtitle;
+ },
+
+ handleKeyDown(event, card) {
+ let next;
+ let prev;
+ let nextIndex;
+ let prevIndex;
+ if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
+ next = card.nextElementSibling;
+ if (next) {
+ nextIndex = this.$cards.indexOf(next);
+ next.focus();
+ this.selectCard(next, nextIndex);
+ this.getCardActiveEvent('keydown', next, nextIndex);
+ }
+ }
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
+ prev = card.previousElementSibling;
+ if (prev) {
+ prevIndex = this.$cards.indexOf(prev);
+ prev.focus();
+ this.selectCard(prev, prevIndex);
+ this.getCardActiveEvent('keydown', prev, prevIndex);
+ }
+ }
+ },
+
+ selectCard(selected, index) {
+ this.addActive(selected, 'container-size-selector__card--active');
+ this.centerCard(selected, index);
+ },
+
+ centerCard(card, index) {
+ if (index === 0)
+ this.$sizeList.classList.add(
+ 'container-size-selector__size-list--active-padding',
+ );
+
+ const cardRect = card.getBoundingClientRect();
+ const listRect = this.$sizeList.getBoundingClientRect();
+ const cardCenter = cardRect.left + cardRect.width / 2;
+ const listCenter = listRect.left + listRect.width / 2;
+ const offset = cardCenter - listCenter;
+
+ this.$sizeList.scrollBy({
+ left: offset,
+ behavior: 'smooth',
+ });
+ },
+
+ addActive(element, className) {
+ this.$cards.forEach((card) => {
+ card.setAttribute('aria-checked', 'false');
+ card.classList.remove(className);
+ });
+ element.classList.add(className);
+ element.setAttribute('aria-checked', 'true');
+ },
+
+ getCardActiveEvent(eventName, card, index) {
+ if (eventName === 'click') {
+ this.emit('event', card, index);
+ }
+ if (eventName === 'keydown') {
+ this.emit('event', card, index);
+ }
+ },
+
+ getCardActive() {
+ const $activeCard = this.$cards.find((element) =>
+ element.classList.contains('container-size-selector__card--active'),
+ );
+ const indexCard = this.$cards.findIndex((element) =>
+ element.classList.contains('container-size-selector__card--active'),
+ );
+ return {
+ card: $activeCard,
+ index: indexCard,
+ };
+ },
+ },
+);
diff --git a/src/components/SizeSelector/index.scss b/src/components/SizeSelector/index.scss
new file mode 100644
index 00000000..e9cd578c
--- /dev/null
+++ b/src/components/SizeSelector/index.scss
@@ -0,0 +1,190 @@
+@use '~styles/colors.scss' as colors;
+@use '~styles/breakpoints.scss' as breakpoints;
+@use '~styles/fonts.scss' as fonts;
+
+.container-size-selector {
+ width: 100%;
+ max-width: 60rem;
+
+ display: flex;
+
+ &__size-list {
+ width: 100%;
+ overflow-x: hidden;
+
+ display: flex;
+ flex-direction: row;
+ gap: 1rem;
+
+ padding: 5rem 40% 5rem 0;
+
+ transition: padding 0.4s;
+
+ &--active-padding {
+ padding: 5rem 40%;
+ }
+ }
+
+ &__card:focus {
+ outline: none;
+ }
+
+ &__card {
+ display: flex;
+
+ align-items: center;
+ justify-content: center;
+
+ margin: 0 0.7rem;
+
+ padding: 1rem 0;
+
+ box-sizing: border-box;
+
+ background-color: colors.$secondary100;
+ box-shadow: 0 0 0.3rem 0.3rem colors.$gray150;
+ border-radius: 1.8rem;
+
+ transition: transform 0.3s;
+
+ &:focus {
+ outline: 0.3rem solid colors.$primary200;
+ }
+
+ &:hover {
+ outline: 0.3rem solid colors.$primary200;
+
+ .container-size-selector__svg path {
+ fill: colors.$primary200;
+ }
+
+ .container-size-selector__title {
+ color: colors.$primary200;
+ }
+
+ .container-size-selector__text {
+ color: colors.$primary200;
+ }
+
+ .container-size-selector__container-img {
+ background-color: rgb(209, 230, 255);
+ }
+ }
+
+ &--active {
+ transform: scale(1.3);
+ outline: 0.3rem solid colors.$primary200;
+
+ transition: transform 0.3s;
+
+ .container-size-selector__svg path {
+ fill: colors.$primary200;
+ }
+
+ .container-size-selector__title {
+ color: colors.$primary200;
+ font-size: fonts.$xs;
+ }
+
+ .container-size-selector__text {
+ color: colors.$primary200;
+ font-size: fonts.$xxs;
+ }
+
+ .container-size-selector__container-img {
+ width: 4.5rem;
+ height: 4.5rem;
+
+ background-color: rgb(209, 230, 255);
+ }
+ }
+ }
+
+ &__card-size {
+ width: 9.4rem;
+ height: 10.6rem;
+
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+
+ align-items: center;
+ justify-content: center;
+ }
+
+ &__container-img {
+ width: 4rem;
+ height: 4rem;
+
+ display: flex;
+
+ align-items: center;
+
+ justify-content: center;
+
+ background-color: colors.$gray150;
+ border-radius: 100%;
+ }
+
+ &__container-text {
+ display: flex;
+ flex-direction: column;
+ gap: 0.3em;
+
+ align-items: center;
+
+ justify-content: center;
+ }
+
+ &__title {
+ font-family: fonts.$primaryFont;
+ color: colors.$gray800;
+ font-size: fonts.$xs;
+ font-weight: fonts.$semiBold;
+ }
+
+ &__text {
+ font-family: fonts.$primaryFont;
+ color: colors.$gray600;
+ font-size: fonts.$xxs;
+ font-weight: fonts.$regular;
+ }
+}
+
+@include breakpoints.from360 {
+ .container-size-selector {
+ &__size-list {
+ gap: 1.5rem;
+ }
+
+ &__card {
+ padding: 1rem 0;
+ }
+ }
+}
+
+@include breakpoints.from667 {
+ .container-size-selector {
+ &__size-list {
+ gap: 5rem;
+ }
+
+ &__card {
+ padding: 4rem 2rem;
+
+ &--active {
+ .container-size-selector__title {
+ font-size: fonts.$sm;
+ }
+
+ .container-size-selector__text {
+ font-size: fonts.$xs;
+ }
+ }
+ }
+
+ &__text {
+ font-size: fonts.$xs;
+ }
+ }
+}
diff --git a/src/stories/SizeSelector.stories.js b/src/stories/SizeSelector.stories.js
new file mode 100644
index 00000000..474a0df7
--- /dev/null
+++ b/src/stories/SizeSelector.stories.js
@@ -0,0 +1,51 @@
+import SizeSelector from '../components/SizeSelector';
+
+export default {
+ title: 'Components/SizeSelector',
+ render: (args) => {
+ const sizeselector = new SizeSelector();
+ sizeselector.setText(args.card, args.titleCard, args.subtitleCard);
+ sizeselector.selectCard(
+ sizeselector.$cards[args.selectCard],
+ args.selectCard,
+ );
+ const $container = document.createElement('div');
+ $container.style.width = '100%';
+ $container.style.display = 'flex';
+ $container.style.justifyContent = 'center';
+ sizeselector.mount($container);
+
+ return $container;
+ },
+ argTypes: {
+ card: { control: 'number', default: 1 },
+ titleCard: { control: 'text', default: 'Medium' },
+ subtitleCard: { control: 'text', default: 'under 14kg' },
+ selectCard: { control: 'number', default: 1 },
+ },
+};
+
+export const Default = {
+ args: {
+ card: 1,
+ titleCard: 'Medium',
+ subtitleCard: 'under 14kg',
+ selectCard: 1,
+ },
+};
+
+export const CardText = {
+ args: {
+ ...Default.args,
+ card: 1,
+ titleCard: 'Medium',
+ subtitleCard: 'under 14kg',
+ },
+};
+
+export const CardSelect = {
+ args: {
+ ...Default.args,
+ selectCard: 1,
+ },
+};
diff --git a/src/styles/fonts.scss b/src/styles/fonts.scss
index 6c510fff..6d37f2e1 100644
--- a/src/styles/fonts.scss
+++ b/src/styles/fonts.scss
@@ -3,6 +3,7 @@ $secondaryFont: 'Wix Madefor Display', sans-serif;
$tertiaryFont: 'Helvetica', sans-serif;
$fourthFont: 'Noto Sans', sans-serif;
+$xxs: 1.2rem;
$xs: 1.4rem;
$sm: 1.6rem;
$md: 2rem;