[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/messages/nn.json from the store-components VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/search.placeholder": "Søk",
  "store/search.searchFor": "Søk etter {term}",
  "store/search.search-term-too-short": "Søketermen er for kort",
  "admin/editor.productName.title": "Produktnavn",
  "admin/editor.productName.description": "Produktnavn på komponent",
  "admin/editor.productName.showBrandName.title": "Viser merkenavnet",
  "admin/editor.productName.showSku.title": "Viser sku",
  "admin/editor.productName.showProductReference.title": "Viser produktreferansen",
  "admin/editor.productName.displayMode.title": "Viser lenken som er tilknyttet produktnavnet eller ren tekst",
  "admin/editor.productName.displayMode.plainText": "Ren tekst",
  "admin/editor.productName.displayMode.linkToProductPage": "Lenke til produktside",
  "admin/editor.productPrice.title": "Produktpris",
  "admin/editor.productPrice.description": "Produktpris på komponent",
  "admin/editor.productPrice.showListPrice": "Vis produktlistepris",
  "admin/editor.productPrice.showSellingPriceRange": "Vis produktets salgsprisområde",
  "admin/editor.productPrice.showListPriceRange": "Vis produktets listeprisområde",
  "admin/editor.productPrice.showLabels": "Vis produktets prisetiketter",
  "admin/editor.productPrice.showInstallments": "Vis produktets betalingsavdrag",
  "admin/editor.productPrice.showSavings": "Vis produktliste og salgsprisdifferanse",
  "admin/editor.productPrice.labelSellingPrice": "Salgsprisens etikett",
  "admin/editor.productPrice.labelListPrice": "Listeprisens etikett",
  "admin/editor.share.title": "Del",
  "admin/editor.share.description": "Liste over del-knapper",
  "admin/editor.share.social.title": "Sosiale nettverk",
  "store/product-description.title": "Produktbeskrivelse",
  "store/product-description.property": "Egenskap",
  "store/product-description.specification": "Spesifikasjon",
  "store/product-description.collapse.showMore": "Vis mer",
  "store/product-description.collapse.showLess": "Vis mindre",
  "store/pricing.installment-display": "Eller {installments} {times} av {installmentPrice}",
  "store/pricing.from": "Fra",
  "store/pricing.to": "Til",
  "store/pricing.savings": "Spar {savings}",
  "store/pricing.interest-free": "rentefri",
  "store/loading": "Laster inn…",
  "store/shipping.deliveryName": "Levering",
  "store/shipping.deliveryEstimate": "Anslag",
  "store/shipping.deliveryPrice": "Verdi",
  "store/shipping.label": "Beregn frakt",
  "store/shipping.free": "Gratis",
  "store/shipping.empty-sla": "Det finnes ingen forsendelsesinformasjon tilgjengelig for dette postnummeret",
  "store/buy-button.add-to-cart": "Legg i handlekurv",
  "store/buybutton.buy-success": "Vare lagt i handlevognen",
  "store/buybutton.buy-success-duplicate": "Varen finnes allerede i handlevognen",
  "store/buybutton.add-failure": "Noe gikk galt og varen ble ikke lagt i handlekurven!",
  "store/buybutton.buy-offline-success": "Vare lagt i offline handlekurv",
  "store/buybutton.select-sku-variations": "Velg et alternativ for hver variant",
  "store/buybutton.see-cart": "Vis handlekurv",
  "store/technicalspecifications.title": "Tekniske spesifikasjoner",
  "store/availability-subscriber.title": "Dette produktet er ikke tilgjengelig nå",
  "store/availability-subscriber.subscribe-label": "Jeg få beskjed når dette produktet blir tilgjengelig",
  "store/availability-subscriber.email-placeholder": "E-post",
  "store/availability-subscriber.name-placeholder": "Navn",
  "store/availability-subscriber.send-label": "Send",
  "store/availability-subscriber.invalid-email": "Ugyldig e-postadresse",
  "store/availability-subscriber.added-message": "E-postadressen ble registrert",
  "store/availability-subscriber.error-message": "Mislyktes, prøv igjen",
  "store/newsletter.label": "Abonner på nyhetsbrevet vårt",
  "store/newsletter.placeholder": "Skriv inn e-postadressen din",
  "store/newsletter.submit": "Registrer deg",
  "store/newsletter.invalidEmail": "Skriv inn en gyldig e-postadresse.",
  "store/newsletter.confirmationTitle": "Tusen takk!",
  "store/newsletter.confirmationText": "E-postadressen ble registrert.",
  "store/newsletter.error": "Noe gikk galt. Prøv igjen senere",
  "admin/editor.newsletter.title": "Nyhetsbrev",
  "admin/editor.newsletter.description": "Nyhetsbrevskjema",
  "admin/editor.newsletter.label": "Etikett for skjemaet som brukes av komponenten",
  "admin/editor.newsletter.placeholder": "Plassholder for e-postinndata",
  "admin/editor.newsletter.submit": "Etikett for \"Send inn\"-knapp",
  "admin/editor.newsletter.hideLabel": "Skjul etikett",
  "admin/editor.categoriesHighlighted.title": "Markerte kategorier",
  "admin/editor.categoriesHighlighted.description": "Markerte kategorier for avdelingen",
  "admin/editor.categoriesHighlighted.item.categoryName": "Kategorinavn",
  "admin/editor.categoriesHighlighted.item.categoryImage": "Kategoribilde",
  "admin/editor.categoriesHighlighted.category": "Kategori",
  "admin/editor.categoriesHighlighted.categoriesHighlighted": "Markerte kategorier",
  "admin/editor.categoriesHighlighted.showCategoriesHighlighted": "Vis markerte kategorier",
  "admin/editor.categoriesHighlighted.quantityOfItems": "Antall varer",
  "admin/editor.categoriesHighlighted.cardShape": "Eskens form",
  "admin/editor.categoriesHighlighted.cardShape.squared": "Firkantet",
  "admin/editor.categoriesHighlighted.cardShape.rectangular": "Rektangulær",
  "store/searchBar.button.cancel.label": "Avbryt",
  "store/buyButton-label-unavailable": "Utilgjengelig",
  "store/greeting": "Hei",
  "store/store-components.share.label": "Del",
  "store/share.title": "{product} {sku} hos {store}: ",
  "admin/editor.info-card.title": "Infokort",
  "admin/editor.info-card.description": "En komponent med bilde og tekst som gjør at du kan velge hvordan du viser dem",
  "admin/editor.info-card.isFullModeStyle.title": "Bilde som bakgrunn",
  "admin/editor.info-card.isFullModeStyle.description": "Hvis det stemmer, vil det angitte bildet bli brukt som bakgrunnsbilde og tekst vil vises over det",
  "admin/editor.info-card.textPosition.title": "Tekstplassering",
  "admin/editor.info-card.textPosition.description": "Velg hvilken posisjon av komponentteksten som skal vises, venstre, sentrum eller høyre",
  "admin/editor.info-card.headline.title": "Overskrift",
  "admin/editor.info-card.headline.description": "Tekst som skal vises som overskrift inne i komponenten",
  "admin/editor.info-card.subhead.title": "Undertittel",
  "admin/editor.info-card.subhead.description": "Tekst som skal vises under overskriften inne i komponenten",
  "admin/editor.info-card.body-text.title": "Hovedtekst",
  "admin/editor.info-card.body-text.description": "Tekst under undertittel inne i komponenten",
  "admin/editor.info-card.callToActionMode.title": "Oppfordring til handling-modus",
  "admin/editor.info-card.callToActionMode.description": "Kontrollerer hvordan oppfordring til handling vises",
  "admin/editor.info-card.callToActionText.title": "Oppfordring til handling-tekst",
  "admin/editor.info-card.callToActionText.description": "Tekst som skal vises i oppfordring til handling-komponenten",
  "admin/editor.info-card.callToActionUrl.title": "Oppfordring til handling-URL",
  "admin/editor.info-card.callToActionLinkTarget.title": "Omadresseringstype for oppfordring til handling-lenke",
  "admin/editor.info-card.callToActionLinkTarget.description": "callToActionLinkTarget egenskapsbeskrivelse",
  "admin/editor.info-card.callToActionLinkTarget.blank": "Lenken åpnes i en ny fane",
  "admin/editor.info-card.callToActionLinkTarget.self": "Lenken åpnes i samme fane",
  "admin/editor.info-card.callToActionUrl.description": "URL å omdirigere til når CTA klikkes på",
  "admin/editor.info-card.imageUrl.title": "Bilde",
  "admin/editor.info-card.imageUrl.description": "Bilde som skal brukes på skrivebordet",
  "admin/editor.info-card.mobileImageUrl.title": "Mobilbilde",
  "admin/editor.info-card.mobileImageUrl.description": "Bilde som skal brukes på mobil",
  "admin/editor.info-card.textAlignment.title": "Tekstjustering",
  "admin/editor.info-card.textAlignment.description": "Kontroller tekstjusteringen inne i komponenten",
  "admin/editor.info-card.textPosition.left": "Venstre",
  "admin/editor.info-card.textPosition.center": "Midten",
  "admin/editor.info-card.textPosition.right": "Høyre",
  "admin/editor.info-card.textAlignment.left": "Venstre",
  "admin/editor.info-card.textAlignment.center": "Midten",
  "admin/editor.info-card.textAlignment.right": "Høyre",
  "admin/editor.info-card.textMode.title": "Tekstmodus",
  "admin/editor.info-card.textMode.description": "Hvilken tekstmodus InfoCard forventer å motta. HTML er standard og \"Rik tekst\" lar deg bruke Markdown.",
  "admin/editor.info-card.textMode.html": "HTML",
  "admin/editor.info-card.textMode.rich-text": "Rik tekst",
  "admin/editor.info-card.callAction.none": "Ingen",
  "admin/editor.info-card.callAction.button": "Knapp",
  "admin/editor.info-card.callAction.link": "Lenke",
  "admin/editor.info-card.imageActionUrl.title": "Bildehandlings-URL",
  "admin/editor.info-card.imageActionUrl.description": "Send URL for å gjøre bildet til en lenke og i stand til å omdirigere brukeren",
  "store/user-address.pickup": "Hent hos {name}",
  "store/user-address.order": "Bestill til",
  "store/user-address.change": "Endre",
  "store/user-address.add": "Legg til sted",
  "admin/editor.notification-bar.title": "Varslingslinje",
  "admin/editor.notification-bar.description": "En komponent som viser tekst i linjestil",
  "admin/editor.notification-bar.content.title": "Innhold",
  "admin/editor.notification-bar.content.description": "Tekst på linjen",
  "admin/editor.blockClass.title": "CSS-blokkeringsklasse",
  "admin/editor.blockClass.description": "Legger til et ekstra klassenavn for å lette stilen",
  "admin/editor.image.title": "Bilde",
  "admin/editor.image.description": "Vis hvilket som helst bilde",
  "admin/editor.image.src.title": "Bilde",
  "admin/editor.image.title.title": "Bildetittel",
  "admin/editor.image.title.description": "Tittel som skal vises på pekeren",
  "admin/editor.image.alt.title": "Alternativ tekst",
  "admin/editor.info-card.imageAltText.title": "Alternativ tekst for bilde",
  "admin/editor.info-card.imageAltText.description": "Alternativ tekst til bildet",
  "admin/editor.product-images.title": "Produktbilder",
  "admin/editor.product-images.description": "Produktbildekomponenten lar deg tilpasse produktbildene",
  "admin/editor.product-images.zoomOptions.title": "Zoom-innstillinger",
  "admin/editor.product-images.zoomType.title": "Zoom-type",
  "admin/editor.product-images.bgopacity.title": "Bakgrunnsopasitet",
  "admin/editor.product-images.thumbnailsOrientation.title": "Retning på miniatyrbilder",
  "admin/editor.product-images.gallery": "I galleri",
  "admin/editor.product-images.in-page": "På side",
  "admin/editor.product-images.no-zoom": "Ingen zoom",
  "admin/editor.product-images.vertical": "Vertikal",
  "admin/editor.product-images.horizontal": "Horisontal",
  "admin/editor.product-images.position.title": "Plassering av miniatyrbilde",
  "admin/editor.product-images.position.description": "Brukes kun når plasseringen er vertikal",
  "admin/editor.product-images.left": "Venstre",
  "admin/editor.product-images.right": "Høyre",
  "admin/editor.product-images.displayThumbnailsArrows.title": "Vis piler i miniatyrbilder",
  "admin/editor.product-specifications.title": "Produktspesifikasjoner",
  "admin/editor.product-specifications.hidden-specifications.title": "Skjulte spesifikasjoner",
  "admin/editor.product-specifications.hidden-specifications.description": "Typenavn for spesifikasjoner du vil skjule",
  "admin/editor.product-specifications.visible-specifications.title": "Synlige spesifikasjoner",
  "admin/editor.product-specifications.visible-specifications.description": "Typrenavn på spesifikasjoner du ønsker å vise. Oppgi kun én av de skjulte spesifikasjonene eller de synlige spesifikasjonene",
  "admin/editor.product-specifications.items.title": "Spesifikasjon",
  "admin/editor.logo.title": "Logo",
  "admin/editor.logo.description": "Komponent som skal vise butikklogoen din",
  "admin/editor.logo.href.title": "Lenke til omdirigering",
  "admin/editor.logo.href.description": "Lenke som skal omdirigeres når logoen klikkes på. La den være tom for at den ikke skal være klikkbar.",
  "admin/editor.logo.url.title": "Bilde",
  "admin/editor.logo.url.description": "Bilde som skal brukes",
  "admin/editor.logo.width.title": "Bredde",
  "admin/editor.logo.width.description": "Bredden som skal brukes på logo.",
  "admin/editor.logo.height.title": "Høyde",
  "admin/editor.logo.height.description": "Høyden som skal brukes på logo.",
  "admin/editor.logo.title.title": "Alternativ tekst",
  "admin/editor.logo.title.description": "Alternativ tekst som skal fremskaffes til logobilde",
  "admin/editor.logo.mobileWidth.title": "Mobilbredde",
  "admin/editor.logo.mobileWidth.description": "Bredden som skal brukes på mobilen. Hvis tom, vil den oppgitte breddeverdien brukes.",
  "admin/editor.logo.mobileHeight.title": "Mobilhøyde",
  "admin/editor.logo.mobileHeight.description": "Høyden som skal brukes på mobilen. Hvis tom, vil den angitte høydeverdien brukes.",
  "store/skuSelector.seeMore": "Se {quantity} mer",
  "store/sku-selector.select.placeholder": "Velg et alternativ",
  "store/sku-selector.variation.select-an-option": "Velg et alternativ",
  "admin/editor.skuSelector.title": "SKU-velger",
  "admin/editor.skuSelector.description": "Komponent som viser forskjellige varianter av en vare brukeren kan velge",
  "admin/editor.skuSelector.seeMoreLabel.title": "Se flere etiketter",
  "admin/editor.skuSelector.seeMoreLabel.description": "Etiketten på Se mer-knappen. Strengen må ha en {quantity} plassholder for å vise de riktige gjenstående varene som er tilgjengelig. Eksempel: \"Se {quantity} mer\"",
  "admin/editor.product-description.title": "Produktbeskrivelse",
  "admin/editor.product-description.title-prop.title": "Tittel",
  "admin/editor.search-bar.title": "Søkefelt",
  "admin/editor.search-bar.placeholder.title": "Plassholder",
  "store/back-to-top.label": "Tilbake til toppen",
  "admin/editor.toTop.title": "Tilbake til toppen-knapp",
  "admin/editor.toTop.description": "Når den er klikket på tas siden til toppen",
  "admin/editor.toTop.topPixel.title": "Antall piksler",
  "admin/editor.toTop.topPixel.description": "Når du overskrider den angitte pikselverdien, vil knappen for å gå tilbake til toppen vises"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/messages/es.json from the store-components VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/search.clear-input": "Borrar campo de búsqueda",
  "store/search.submit-search": "Buscar Productos",
  "store/search.placeholder": "Buscar",
  "store/search.searchFor": "Buscar por {term}",
  "store/search.search-term-too-short": "El término de búsqueda es demasiado corto",
  "admin/editor.productName.title": "Nombre del producto",
  "admin/editor.productName.description": "Componente del nombre del producto",
  "admin/editor.productName.showBrandName.title": "Mostrar marca",
  "admin/editor.productName.showSku.title": "Mostrar SKU",
  "admin/editor.productName.showProductReference.title": "Mostrar referencia del producto",
  "admin/editor.productName.displayMode.title": "Mostrar link asociado al nombre del producto o texto simple",
  "admin/editor.productName.displayMode.plainText": "Texto simple",
  "admin/editor.productName.displayMode.linkToProductPage": "Link a la página del producto",
  "admin/editor.productPrice.title": "Precio del producto",
  "admin/editor.productPrice.description": "Componente del precio del producto",
  "admin/editor.productPrice.showListPrice": "Mostrar precio de lista del producto",
  "admin/editor.productPrice.showSellingPriceRange": "Mostrar rango de precios de venta del producto",
  "admin/editor.productPrice.showListPriceRange": "Mostrar rango de precios de lista del producto",
  "admin/editor.productPrice.showLabels": "Mostrar leyendas en los precios",
  "admin/editor.productPrice.showInstallments": "Mostrar opción de pago en cuotas",
  "admin/editor.productPrice.showSavings": "Mostrar diferencia entre precio de lista y precio de venta",
  "admin/editor.productPrice.labelSellingPrice": "Etiqueta de precio de venta",
  "admin/editor.productPrice.labelListPrice": "Etiqueta de precio de lista",
  "admin/editor.share.title": "Compartir",
  "admin/editor.share.description": "Lista de botones de compartir",
  "admin/editor.share.social.title": "Redes sociales",
  "store/product-description.title": "Descripción del producto",
  "store/product-description.property": "Propiedad",
  "store/product-description.specification": "Especificación",
  "store/product-description.collapse.showMore": "Mostrar más",
  "store/product-description.collapse.showLess": "Mostrar menos",
  "store/pricing.installment-display": "O {installments} {times} de {installmentPrice}",
  "store/pricing.from": "De",
  "store/pricing.to": "Por",
  "store/pricing.savings": "Ahorra {savings}",
  "store/pricing.interest-free": "sin intereses",
  "store/loading": "Cargando…",
  "store/shipping.deliveryName": "Entrega",
  "store/shipping.deliveryEstimate": "Plazo",
  "store/shipping.deliveryPrice": "Valor",
  "store/shipping.label": "Calcular envío",
  "store/shipping.free": "Gratis",
  "store/shipping.empty-sla": "No hay ninguna tarifa de envío disponible para el código postal informado",
  "store/buy-button.add-to-cart": "Agregar al carrito",
  "store/buybutton.buy-success": "Se agregó el ítem al carrito",
  "store/buybutton.buy-success-duplicate": "El ítem ya está en el carrito",
  "store/buybutton.add-failure": "Se produjo un error. El ítem no se agregó al carrito.",
  "store/buybutton.buy-offline-success": "Se agregó el ítem al carrito offline",
  "store/buybutton.select-sku-variations": "Por favor, selecciona una opción de cada variación",
  "store/buybutton.see-cart": "Ver carrito",
  "store/technicalspecifications.title": "Especificaciones técnicas",
  "store/availability-subscriber.title": "Este producto no está disponible en este momento",
  "store/availability-subscriber.subscribe-label": "Quiero que me avisen cuando esté disponible",
  "store/availability-subscriber.email-placeholder": "Email",
  "store/availability-subscriber.name-placeholder": "Nombre",
  "store/availability-subscriber.send-label": "Enviar",
  "store/availability-subscriber.invalid-email": "Email inválido",
  "store/availability-subscriber.added-message": "Email registrado con éxito",
  "store/availability-subscriber.error-message": "Se produjo una falla al intentar registrarte. Inténtalo de nuevo",
  "store/newsletter.label": "Suscríbete a nuestro newsletter",
  "store/newsletter.placeholder": "Ingresa tu email",
  "store/newsletter.submit": "Suscribir",
  "store/newsletter.invalidEmail": "Por favor, ingresa un email válido.",
  "store/newsletter.confirmationTitle": "¡Gracias!",
  "store/newsletter.confirmationText": "Tu email se registró correctamente.",
  "store/newsletter.error": "Se produjo un error. Por favor, inténtalo de nuevo más tarde",
  "admin/editor.newsletter.title": "Newsletter",
  "admin/editor.newsletter.description": "Formulario de newsletter",
  "admin/editor.newsletter.label": "Título del formulario",
  "admin/editor.newsletter.placeholder": "Placeholder de la entrada del email",
  "admin/editor.newsletter.submit": "Texto del botón",
  "admin/editor.newsletter.hideLabel": "Ocultar título",
  "admin/editor.categoriesHighlighted.title": "Categorías destacadas",
  "admin/editor.categoriesHighlighted.description": "Categorías destacadas del departamento",
  "admin/editor.categoriesHighlighted.item.categoryName": "Nombre de categoría",
  "admin/editor.categoriesHighlighted.item.categoryImage": "Imagen de categoría",
  "admin/editor.categoriesHighlighted.category": "Categoría",
  "admin/editor.categoriesHighlighted.categoriesHighlighted": "Categorías destacadas",
  "admin/editor.categoriesHighlighted.showCategoriesHighlighted": "Mostrar categorías destacadas",
  "admin/editor.categoriesHighlighted.quantityOfItems": "Cantidad de ítems",
  "admin/editor.categoriesHighlighted.cardShape": "Forma de la caja",
  "admin/editor.categoriesHighlighted.cardShape.squared": "Cuadrada",
  "admin/editor.categoriesHighlighted.cardShape.rectangular": "Rectangular",
  "store/searchBar.button.cancel.label": "Cancelar",
  "store/buyButton-label-unavailable": "Indisponible",
  "store/greeting": "Hola",
  "store/store-components.share.label": "Comparte",
  "store/share.title": "{product} {sku} en {store}: ",
  "admin/editor.info-card.title": "InfoCard",
  "admin/editor.info-card.description": "Un componente con imagen y texto que permite elegir cómo mostrar tu contenido",
  "admin/editor.info-card.isFullModeStyle.title": "Imagen como fondo",
  "admin/editor.info-card.isFullModeStyle.description": "Si es verdadero, la imagen proporcionada se utilizará como imagen de fondo de todo el componente y el texto se mostrará sobre ella",
  "admin/editor.info-card.textPosition.title": "Posición del texto",
  "admin/editor.info-card.textPosition.description": "Elige en qué posición se mostrará el texto (izquierda, centro o derecha)",
  "admin/editor.info-card.headline.title": "Título",
  "admin/editor.info-card.headline.description": "Texto presentado de forma destacada",
  "admin/editor.info-card.subhead.title": "Subtítulo",
  "admin/editor.info-card.subhead.description": "Texto que aparece debajo del título",
  "admin/editor.info-card.body-text.title": "Cuerpo del texto",
  "admin/editor.info-card.body-text.description": "Texto debajo del subtítulo dentro del componente",
  "admin/editor.info-card.callToActionMode.title": "Modo call to action",
  "admin/editor.info-card.callToActionMode.description": "Controla cómo se muestra tu componente de call to action",
  "admin/editor.info-card.callToActionText.title": "Texto de call to action",
  "admin/editor.info-card.callToActionText.description": "Texto a mostrar dentro del componente call to action",
  "admin/editor.info-card.callToActionUrl.title": "URL de call to action",
  "admin/editor.info-card.callToActionLinkTarget.title": "Tipo de redirección del link de call to action",
  "admin/editor.info-card.callToActionLinkTarget.description": "Descripción de la propiedad callToActionLinkTarget",
  "admin/editor.info-card.callToActionLinkTarget.blank": "El link se abre en una nueva pestaña",
  "admin/editor.info-card.callToActionLinkTarget.self": "El link se abre en la misma pestaña",
  "admin/editor.info-card.callToActionUrl.description": "URL de redirección cuando se hace clic en el CTA",
  "admin/editor.info-card.imageUrl.title": "Imagen",
  "admin/editor.info-card.imageUrl.description": "Imagen que se utilizará en dispositivos de escritorio",
  "admin/editor.info-card.mobileImageUrl.title": "Imagen para dispositivos móviles",
  "admin/editor.info-card.mobileImageUrl.description": "Imagen que se utilizará en dispositivos móviles",
  "admin/editor.info-card.textAlignment.title": "Alineación de texto",
  "admin/editor.info-card.textAlignment.description": "Controla la alineación del texto dentro del componente",
  "admin/editor.info-card.textPosition.left": "Izquierda",
  "admin/editor.info-card.textPosition.center": "Centro",
  "admin/editor.info-card.textPosition.right": "Derecha",
  "admin/editor.info-card.textAlignment.left": "Izquierda",
  "admin/editor.info-card.textAlignment.center": "Centro",
  "admin/editor.info-card.textAlignment.right": "Derecha",
  "admin/editor.info-card.textMode.title": "Modo de texto",
  "admin/editor.info-card.textMode.description": "Qué tipo de texto recibirá el InfoCard. HTML es el predeterminado y Rich-Text permite el uso de Markdown.",
  "admin/editor.info-card.textMode.html": "HTML",
  "admin/editor.info-card.textMode.rich-text": "Rich-Text",
  "admin/editor.info-card.callAction.none": "Ninguno",
  "admin/editor.info-card.callAction.button": "Botón",
  "admin/editor.info-card.callAction.link": "Link",
  "admin/editor.info-card.imageActionUrl.title": "URL de acción de la imagen",
  "admin/editor.info-card.imageActionUrl.description": "Pasa la URL para convertir la imagen en un link y poder redirigir al usuario",
  "store/user-address.pickup": "Recoger en {name}",
  "store/user-address.order": "Enviar para",
  "store/user-address.change": "Modificar",
  "store/user-address.add": "Agregar localización",
  "admin/editor.notification-bar.title": "Barra de notificaciones",
  "admin/editor.notification-bar.description": "Un componente que muestra cualquier texto en forma de barra",
  "admin/editor.notification-bar.content.title": "Contenido",
  "admin/editor.notification-bar.content.description": "Texto de la barra",
  "admin/editor.blockClass.title": "Clase de bloque CSS",
  "admin/editor.blockClass.description": "Agrega un nombre de clase extra para facilitar el estilo",
  "admin/editor.image.title": "Imagen",
  "admin/editor.image.description": "Mostrar cualquier imagen",
  "admin/editor.image.src.title": "Imagen",
  "admin/editor.image.title.title": "Título de la imagen",
  "admin/editor.image.title.description": "Título que se mostrará al pasar el mouse sobre la imagen",
  "admin/editor.image.alt.title": "Texto alternativo",
  "admin/editor.info-card.imageAltText.title": "Texto alternativo de la imagen",
  "admin/editor.info-card.imageAltText.description": "Alternative text for the image",
  "admin/editor.product-images.title": "Texto alternativo para la imagen",
  "admin/editor.product-images.description": "Componente que permite personalizar las propiedades de las imágenes de los productos",
  "admin/editor.product-images.zoomOptions.title": "Opciones de zoom",
  "admin/editor.product-images.zoomType.title": "Tipo de zoom",
  "admin/editor.product-images.bgopacity.title": "Opacidad del fondo",
  "admin/editor.product-images.thumbnailsOrientation.title": "Orientación de miniaturas",
  "admin/editor.product-images.gallery": "En galería",
  "admin/editor.product-images.in-page": "En la página",
  "admin/editor.product-images.no-zoom": "Sin zoom",
  "admin/editor.product-images.vertical": "Vertical",
  "admin/editor.product-images.horizontal": "Horizontal",
  "admin/editor.product-images.position.title": "Posición de miniaturas",
  "admin/editor.product-images.position.description": "Se utiliza solo cuando la orientación es vertical",
  "admin/editor.product-images.left": "Izquierda",
  "admin/editor.product-images.right": "Derecha",
  "admin/editor.product-images.displayThumbnailsArrows.title": "Mostrar flechas en miniaturas",
  "admin/editor.product-specifications.title": "Especificaciones del producto",
  "admin/editor.product-specifications.hidden-specifications.title": "Especificaciones ocultas",
  "admin/editor.product-specifications.hidden-specifications.description": "Escribe los nombres de las especificaciones que deseas ocultar",
  "admin/editor.product-specifications.visible-specifications.title": "Especificaciones visibles",
  "admin/editor.product-specifications.visible-specifications.description": "Escribe los nombres de las especificaciones que deseas que aparezcan. Solo proporciona una de las especificaciones ocultas o especificaciones visibles",
  "admin/editor.product-specifications.items.title": "Especificación",
  "admin/editor.logo.title": "Logotipo",
  "admin/editor.logo.description": "Componente para mostrar el logotipo de tu tienda",
  "admin/editor.logo.href.title": "Link de redirección",
  "admin/editor.logo.href.description": "Link de redirección cuando se hace clic en el logotipo. Déjalo en blanco para que no se pueda hacer clic.",
  "admin/editor.logo.url.title": "Imagen",
  "admin/editor.logo.url.description": "Imagen que se utilizará",
  "admin/editor.logo.width.title": "Anchura",
  "admin/editor.logo.width.description": "Anchura que se utilizará para el logotipo.",
  "admin/editor.logo.height.title": "Altura",
  "admin/editor.logo.height.description": "Altura que se utilizará para el logotipo.",
  "admin/editor.logo.title.title": "Texto alternativo",
  "admin/editor.logo.title.description": "Texto alternativo para la imagen del logotipo",
  "admin/editor.logo.mobileWidth.title": "Anchura en dispositivo móvil",
  "admin/editor.logo.mobileWidth.description": "Anchura que se utilizará en dispositivos móviles. Si está en blanco, se utilizará el valor de anchura proporcionado.",
  "admin/editor.logo.mobileHeight.title": "Altura en dispositivo móvil",
  "admin/editor.logo.mobileHeight.description": "Altura que se utilizará en los dispositivos móviles. Si está en blanco, se utilizará el valor de altura proporcionado.",
  "store/skuSelector.seeMore": "Ver más {quantity}",
  "store/sku-selector.select.placeholder": "Elige una opción",
  "store/sku-selector.variation.select-an-option": "Selecciona una opción",
  "admin/editor.skuSelector.title": "Selector de SKU",
  "admin/editor.skuSelector.description": "Componente que muestra diferentes variaciones dadas de un ítem entre las que el usuario puede escoger",
  "admin/editor.skuSelector.seeMoreLabel.title": "Etiqueta \"ver más\"",
  "admin/editor.skuSelector.seeMoreLabel.description": "Etiqueta del botón \"ver más\". El mensaje debe tener un espacio reservado {quantity} para mostrar los ítems restantes disponibles. Ejemplo: \"Ver {quantity} más\"",
  "admin/editor.product-description.title": "Descripción del producto",
  "admin/editor.product-description.title-prop.title": "Título",
  "admin/editor.search-bar.title": "Barra de búsqueda",
  "admin/editor.search-bar.placeholder.title": "Texto de la búsqueda",
  "store/back-to-top.label": "Volver a la parte superior",
  "admin/editor.toTop.title": "Botón volver a la parte superior",
  "admin/editor.toTop.description": "Cuando se hace clic, vuelve a la parte superior de la página",
  "admin/editor.toTop.topPixel.title": "Número de píxeles",
  "admin/editor.toTop.topPixel.description": "Al exceder el valor de píxeles definido, aparecerá el botón para volver a la parte superior"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/messages/ar.json from the store-components VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/search.placeholder": "بحث",
  "store/search.searchFor": "بحث عن {term}",
  "store/search.search-term-too-short": "مصطلح البحث قصير جدًا",
  "admin/editor.productName.title": "اسم المنتج",
  "admin/editor.productName.description": "مكون اسم المنتج",
  "admin/editor.productName.showBrandName.title": "يعرض اسم العلامة التجارية",
  "admin/editor.productName.showSku.title": "تظهر وحدة ادارة بالمخزون",
  "admin/editor.productName.showProductReference.title": "يعرض مرجع المنتج",
  "admin/editor.productName.displayMode.title": "عرض الرابط المرتبط باسم المنتج أو النص العادي",
  "admin/editor.productName.displayMode.plainText": "نص عادي",
  "admin/editor.productName.displayMode.linkToProductPage": "رابط إلى صفحة المنتج",
  "admin/editor.productPrice.title": "سعر المنتج",
  "admin/editor.productPrice.description": "مكون سعر المنتج",
  "admin/editor.productPrice.showListPrice": "إظهار قائمة أسعار المنتجات",
  "admin/editor.productPrice.showSellingPriceRange": "إظهار نطاق أسعار بيع المنتج",
  "admin/editor.productPrice.showListPriceRange": "إظهار نطاق قائمة المنتجات",
  "admin/editor.productPrice.showLabels": "عرض تسميات أسعار المنتج",
  "admin/editor.productPrice.showInstallments": "عرض أقساط الدفع الخاصة بالمنتج",
  "admin/editor.productPrice.showSavings": "عرض قائمة المنتجات وفرق أسعار البيع",
  "admin/editor.productPrice.labelSellingPrice": "تسمية أسعار البيع",
  "admin/editor.productPrice.labelListPrice": "تسمية لائحة الأسعار",
  "admin/editor.share.title": "مشاركة",
  "admin/editor.share.description": "قائمة أزرار المشاركة",
  "admin/editor.share.social.title": "مواقع التواصل الإجتماعي",
  "store/product-description.title": "خصائص المنتج",
  "store/product-description.property": "المؤسسة",
  "store/product-description.specification": "المواصفات",
  "store/product-description.collapse.showMore": "عرض المزيد",
  "store/product-description.collapse.showLess": "عرض أقل",
  "store/pricing.installment-display": "أو {installments} {times} من {installmentPrice}",
  "store/pricing.from": "من",
  "store/pricing.to": "إلى",
  "store/pricing.savings": "توفير {savings}",
  "store/pricing.interest-free": "بدون فوائد",
  "store/loading": "تحميل…",
  "store/shipping.deliveryName": "التسليم",
  "store/shipping.deliveryEstimate": "تقدير",
  "store/shipping.deliveryPrice": "القيمة",
  "store/shipping.label": "حساب الشحن",
  "store/shipping.free": "مجانًا",
  "store/shipping.empty-sla": "لا توجد معلومات شحن متاحة للرمز البريدي المعلن",
  "store/buy-button.add-to-cart": "إضافة إلى عربة التسوق",
  "store/buybutton.buy-success": "تمت إضافة المنتج إلى السلة بنجاح",
  "store/buybutton.buy-success-duplicate": "عنصر موجود مسبقًا في عربتك",
  "store/buybutton.add-failure": "حدث خطأ ولم تتم إضافة العنصر إلى عربة التسوق الخاصة بك!",
  "store/buybutton.buy-offline-success": "تمت اضافة المنتج الى عربتك دون اتصال بالإنترنت",
  "store/buybutton.select-sku-variations": "الرجاء تحديد خيار من كل متغير",
  "store/buybutton.see-cart": "عرض عربة التسوق",
  "store/technicalspecifications.title": "المواصفات الفنية",
  "store/availability-subscriber.title": "هذا المنتج غير متوفر الآن",
  "store/availability-subscriber.subscribe-label": "أريد أن أعرف متى يصبح هذا المنتج متاحًا",
  "store/availability-subscriber.email-placeholder": "البريد الإلكتروني",
  "store/availability-subscriber.name-placeholder": "الإسم",
  "store/availability-subscriber.send-label": "إرسال",
  "store/availability-subscriber.invalid-email": "بريد إلكتروني خاطئ",
  "store/availability-subscriber.added-message": "تم تسجيل البريد الإلكتروني بنجاح",
  "store/availability-subscriber.error-message": "محاولة فاشلة، الرجاء المحاولة مرة أخرى",
  "store/newsletter.label": "اشتراك في القائمة البريدية",
  "store/newsletter.placeholder": "أدخل عنوان بريدك الإلكتروني",
  "store/newsletter.submit": "الاشتراك",
  "store/newsletter.invalidEmail": "يرجى إدخال البريد الإلكتروني الصحيح.",
  "store/newsletter.confirmationTitle": "شكرًا!",
  "store/newsletter.confirmationText": "تم تسجيل بريدك الإلكتروني بنجاح.",
  "store/newsletter.error": "حدث خطأ ما الرجاء المحاولة مرة أخرى في وقت لاحق",
  "admin/editor.newsletter.title": "الرسائل الإخبارية",
  "admin/editor.newsletter.description": "إستمارة الرسالة الإخبارية",
  "admin/editor.newsletter.label": "تسمية الاستمارة المستخدمة من قبل المكون",
  "admin/editor.newsletter.placeholder": "عنصر محجوز لإدخال البريد الإلكتروني",
  "admin/editor.newsletter.submit": "تسمية زر الإرسال",
  "admin/editor.newsletter.hideLabel": "إخفاء التسمية",
  "admin/editor.categoriesHighlighted.title": "الفئات المميزة",
  "admin/editor.categoriesHighlighted.description": "فئات الخدمات التي تم إبرازها",
  "admin/editor.categoriesHighlighted.item.categoryName": "اسم الفئة",
  "admin/editor.categoriesHighlighted.item.categoryImage": "صورة الفئة",
  "admin/editor.categoriesHighlighted.category": "الفئة",
  "admin/editor.categoriesHighlighted.categoriesHighlighted": "الفئات المميزة",
  "admin/editor.categoriesHighlighted.showCategoriesHighlighted": "عرض الفئات المميزة",
  "admin/editor.categoriesHighlighted.quantityOfItems": "عدد العناصر",
  "admin/editor.categoriesHighlighted.cardShape": "شكل الصندوق",
  "admin/editor.categoriesHighlighted.cardShape.squared": "مربعة",
  "admin/editor.categoriesHighlighted.cardShape.rectangular": "مستطيلة",
  "store/searchBar.button.cancel.label": "إلغاء",
  "store/buyButton-label-unavailable": "غير متوفر",
  "store/greeting": "مرحبًا",
  "store/store-components.share.label": "مشاركة",
  "store/share.title": "{product} {sku} في {store}: ",
  "admin/editor.info-card.title": "بطاقة المعلومات",
  "admin/editor.info-card.description": "مكون يحتوي على صورة ونص يمكنك اختيار كيفية عرضهما",
  "admin/editor.info-card.isFullModeStyle.title": "الصورة كخلفية",
  "admin/editor.info-card.isFullModeStyle.description": "إذا كان صحيحًا، فسيتم استخدام الصورة المقدمة كصورة خلفية وسيتم عرض النص فوقها",
  "admin/editor.info-card.textPosition.title": "موقع النص",
  "admin/editor.info-card.textPosition.description": "اختر موضع نص المكون الذي سيتم عرضه، يسار أو وسط أو يمين",
  "admin/editor.info-card.headline.title": "العنوان الرئيسي",
  "admin/editor.info-card.headline.description": "النص الذي سيتم عرضه كعنوان رئيسي داخل المكون",
  "admin/editor.info-card.subhead.title": "عنوان فرعي",
  "admin/editor.info-card.subhead.description": "النص الذي سيتم عرضه كعنوان فرعي داخل المكون",
  "admin/editor.info-card.body-text.title": "النص الأساسي",
  "admin/editor.info-card.body-text.description": "نص تحت عنوان فرعي داخل المكون",
  "admin/editor.info-card.callToActionMode.title": "استدعاء إلى وضع العمل",
  "admin/editor.info-card.callToActionMode.description": "للتحكم في كيفية عرض عبارة اتخاذ إجراء",
  "admin/editor.info-card.callToActionText.title": "نص الدعوة إلى الإجراء",
  "admin/editor.info-card.callToActionText.description": "نص لإظهاره في مكون الدعوة الداخلية إلى الإجراء",
  "admin/editor.info-card.callToActionUrl.title": "رابط الدعوة إلى العمل",
  "admin/editor.info-card.callToActionLinkTarget.title": "نوع إعادة توجيه الاتصال إلى رابط العمل",
  "admin/editor.info-card.callToActionLinkTarget.description": "وصف الخاصية callToActionLinkTarget",
  "admin/editor.info-card.callToActionLinkTarget.blank": "فتح الرابط في علامة تبويب جديدة",
  "admin/editor.info-card.callToActionLinkTarget.self": "فتح الرابط في نفس علامة التبويب",
  "admin/editor.info-card.callToActionUrl.description": "رابط لإعادة التوجيه عند النقر على CTA (دعوة للعمل)",
  "admin/editor.info-card.imageUrl.title": "الصورة",
  "admin/editor.info-card.imageUrl.description": "الصورة التي سيتم استخدامها على سطح المكتب",
  "admin/editor.info-card.mobileImageUrl.title": "صورة الهاتف",
  "admin/editor.info-card.mobileImageUrl.description": "الصورة التي سيتم استخدامها على الهاتف",
  "admin/editor.info-card.textAlignment.title": "توجيه النص",
  "admin/editor.info-card.textAlignment.description": "التحكم في توجيه النص داخل المكون",
  "admin/editor.info-card.textPosition.left": "اليسار",
  "admin/editor.info-card.textPosition.center": "الوسط",
  "admin/editor.info-card.textPosition.right": "اليمين",
  "admin/editor.info-card.textAlignment.left": "اليسار",
  "admin/editor.info-card.textAlignment.center": "الوسط",
  "admin/editor.info-card.textAlignment.right": "اليمين",
  "admin/editor.info-card.textMode.title": "وضع الكتابة",
  "admin/editor.info-card.textMode.description": "ما هو وضع النص الذي يجب أن تتوقع بطاقة المعلومات استلامه. HTML هو الافتراضي والنص المنسق يتيح لك استخدام التحديد.",
  "admin/editor.info-card.textMode.html": "HTML",
  "admin/editor.info-card.textMode.rich-text": "نصّ مُنـسّق",
  "admin/editor.info-card.callAction.none": "لا شيء",
  "admin/editor.info-card.callAction.button": "الزر",
  "admin/editor.info-card.callAction.link": "الرابط",
  "admin/editor.info-card.imageActionUrl.title": "رابط إجراء الصورة",
  "admin/editor.info-card.imageActionUrl.description": "مرر عنوان الرابط لجعل الصورة رابطًا يمكّن من إعادة توجيه المستخدم",
  "store/user-address.pickup": "الاستلام في {name}",
  "store/user-address.order": "طلب من",
  "store/user-address.change": "تغيير",
  "store/user-address.add": "أضف موقع",
  "admin/editor.notification-bar.title": "شريط الإشعارات",
  "admin/editor.notification-bar.description": "مكون يعرض أي نص بنمط شريط",
  "admin/editor.notification-bar.content.title": "المحتوى",
  "admin/editor.notification-bar.content.description": "نص الشريط",
  "admin/editor.blockClass.title": "فئة كتلة CSS",
  "admin/editor.blockClass.description": "يضيف اسم فصل إضافي لتسهيل النمط",
  "admin/editor.image.title": "الصورة",
  "admin/editor.image.description": "عرض أي صورة",
  "admin/editor.image.src.title": "الصورة",
  "admin/editor.image.title.title": "عنوان الصورة",
  "admin/editor.image.title.description": "العنوان الذي سيتم عرضه عند المرور بالفأررة",
  "admin/editor.info-card.imageAltText.title": "صورة النص البديل",
  "admin/editor.info-card.imageAltText.description": "نص بديل للصورة",
  "admin/editor.image.alt.title": "النص البديل",
  "admin/editor.product-images.title": "صور المنتج",
  "admin/editor.product-images.description": "يسمح لك مكون صور المنتج بتخصيص صور المنتج",
  "admin/editor.product-images.zoomOptions.title": "خيارات التكبير",
  "admin/editor.product-images.zoomType.title": "نوع التكبير",
  "admin/editor.product-images.bgopacity.title": "درجة تعتيم الخلفية",
  "admin/editor.product-images.thumbnailsOrientation.title": "توجيه الصور المصغرة",
  "admin/editor.product-images.gallery": "في المعرض",
  "admin/editor.product-images.in-page": "في الصفحة",
  "admin/editor.product-images.no-zoom": "بدون تكبير",
  "admin/editor.product-images.vertical": "رأسي",
  "admin/editor.product-images.horizontal": "أفقي",
  "admin/editor.product-images.position.title": "موضع الصورة المصغرة",
  "admin/editor.product-images.position.description": "يُستخدم فقط عندما يكون الاتجاه رأسيًا",
  "admin/editor.product-images.left": "اليسار",
  "admin/editor.product-images.right": "اليمين",
  "admin/editor.product-images.displayThumbnailsArrows.title": "عرض الأسهم في الصور المصغرة",
  "admin/editor.product-specifications.title": "مواصفات المنتج",
  "admin/editor.product-specifications.hidden-specifications.title": "المواصفات المخفية",
  "admin/editor.product-specifications.hidden-specifications.description": "اكتب أسماء المواصفات التي تريد إخفاءها",
  "admin/editor.product-specifications.visible-specifications.title": "المواصفات المرئية",
  "admin/editor.product-specifications.visible-specifications.description": "اكتب أسماء المواصفات التي تريد إظهارها. قم بتوفير إحدى المواصفات المخفية أو المواصفات المرئية فقط",
  "admin/editor.product-specifications.items.title": "المواصفات",
  "admin/editor.logo.title": "الشعار",
  "admin/editor.logo.description": "مكون لعرضه على شعار متجرك",
  "admin/editor.logo.href.title": "رابط إعادة التوجيه",
  "admin/editor.logo.href.description": "الرابط الذي ستتم إعادة توجيهك إليه عند النقر فوق الشعار. اترك الحقل فارغًا حتى لا يكون قابلاً للنقر.",
  "admin/editor.logo.url.title": "الصورة",
  "admin/editor.logo.url.description": "الصورة التي سيتم استعالها",
  "admin/editor.logo.width.title": "العرض",
  "admin/editor.logo.width.description": "العرض الذي سيتم استخدامه للشعار.",
  "admin/editor.logo.height.title": "الإرتفاع",
  "admin/editor.logo.height.description": "الارتفاع الذي سيتم استخدامه للشعار.",
  "admin/editor.logo.title.title": "النص البديل",
  "admin/editor.logo.title.description": "نص بديل يتم توفيره لصورة الشعار",
  "admin/editor.logo.mobileWidth.title": "عرض الهاتف",
  "admin/editor.logo.mobileWidth.description": "العرض المستخدم على الهاتف المحمول. إذا كان فارغًا، فسيستخدم قيمة العرض المقدمة.",
  "admin/editor.logo.mobileHeight.title": "إرتفاع الهاتف",
  "admin/editor.logo.mobileHeight.description": "الطول المستخدم على الهاتف المحمول. إذا كان فارغًا، فسيستخدم قيمة الطول المقدمة.",
  "store/skuSelector.seeMore": "عرض {quantity} أكثر",
  "store/sku-selector.select.placeholder": "اختر أحد الخيارات",
  "store/sku-selector.variation.select-an-option": "حدد خيارًا",
  "admin/editor.skuSelector.title": "خيار وحدة إدارة التخزين",
  "admin/editor.skuSelector.description": "مكون يعرض متغيرات معينة مختلفة لعنصر من اختيار المستخدم",
  "admin/editor.skuSelector.seeMoreLabel.title": "عرض المزيد من التسميات",
  "admin/editor.skuSelector.seeMoreLabel.description": "تسمية لعرض مزيد من الأزرار. يجب أن تحتوي الخانة على {quantity} عنصر محجوز لإظهار العناصر المتبقية المناسبة المتوفرة. مثال: \"عرض {quantity} أخرى\"",
  "admin/editor.product-description.title": "وصف المنتج",
  "admin/editor.product-description.title-prop.title": "العنوان",
  "admin/editor.search-bar.title": "شريط البحث",
  "admin/editor.search-bar.placeholder.title": "مساحة محجوزة",
  "store/back-to-top.label": "العودة الى الاعلى",
  "admin/editor.toTop.title": "العودة إلى زر الأعلى",
  "admin/editor.toTop.description": "عند النقر عليه يأخذ الصفحة إلى الأعلى",
  "admin/editor.toTop.topPixel.title": "عدد البكسلات",
  "admin/editor.toTop.topPixel.description": "عند تجاوز قيمة البكسل المحددة، سيظهر الزر للعودة إلى الأعلى"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/docs/README.md from the store-components VTEX app.

[Assistant]
Here's the implementation:

```markdown
>📢 **Disclaimer** Don't fork this project. Use it, [contribute](https://github.com/vtex-apps/store-components) to it or open issues through [Store Discussion](https://github.com/vtex-apps/store-discussion) to help us evolve it.

# VTEX Store Components
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

VTEX Store Components is a collection of components that can be used to create/extend others VTEX apps.

- [VTEX Store Components](#vtex-store-components)
  - [Usage](#usage)
  - [Styles API](#styles-api)
  - [Components](#components)
  - [Creating a new component](#creating-a-new-component)
    - [Project structure](#project-structure)
  - [Troubleshooting](#troubleshooting)
  - [Contributing](#contributing)
  - [Tests](#tests)
    - [Travis CI](#travis-ci)
  - [Contributors](#contributors)

## Usage

The Store Components collection uses the `store` builder with the blocks architecture. Please refer to our [Builder](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-builders) documentation to learn more about the `store` builder.

To use this app, you must import it as dependency of your project in the `manifest.json` file.

```json
  "dependencies": {
    "vtex.store-components": "3.x"
  }
```

Then, you can start adding components to your store theme app.

## Styles API

The Store Components collection provides some CSS classes as an API for style customization.

To use this CSS API, you must add the `styles` builder and create an app styling CSS file.

1. Add the `styles` builder to your `manifest.json`:

```json
  "builders": {
    "styles": "2.x"
  }
```

2. Create a file called `vtex.store-components.css` inside the `styles/css` folder. Add your custom styles:

```css
.container {
  margin-top: 10px;
}
```

## Components

For more information, check the documentation of all components of the Store Components collection.

- [Availability Subscriber](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-availabilitysubscriber)
- [Back To Top Button](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-backtotopbutton)
- [Buy Button](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-buybutton)
- [Image](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-image)
- [InfoCard](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-infocard)
- [Logo](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-logo)
- [Newsletter](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-newsletter)
- [Product Brand](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productbrand)
- [Product Description](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productdescription)
- [Product Images](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productimages)
- [Product Name](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productname)
- [Product SKU Attributes](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productskuattributes)
- [Product Price](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productprice)
- [Product Specifications](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-productspecifications)
- [SKU Selector](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-skuselector)
- [Search Bar](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-searchbar)
- [Share](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-share)
- [Shipping Simulator](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-shippingsimulator)
- [Notification](https://developers.vtex.com/vtex-developer-docs/docs/vtex-store-components-notification)

> ⚠ Warning
>
> **The following blocks have been deprecated:** `Animation`, `Categories Highlights`, `Collection Badges`, `Container`, `Discount Badge`, `Gradient Collapse`, `Greeting`, `Slider`. Despite this, support for them is still granted.

## Creating a new component

To start your development, create a new folder on react/components. That's where your source code will be stored. Also create a new js file on /react, this file should be used to expose your component, like:

### Project structure

Inside your `react/components/<component_name>` you should have:

- index.js
- README.md
- [Optional] components/
- [Optional] constants/
- [Optional] utils/
- [Optional] queries/
- [Optional] mutations/
- [Optional] styles.css

Next, inside of `react/` folder you need to export your component, such as:

```js
import ProductPrice from './components/ProductPrice/index'

export default ProductPrice
```

Also, all dependencies needed should be inserted inside the react/package.json.

## Troubleshooting

You can check if others are passing through similar issues [here](https://github.com/vtex-apps/store-components/issues). Also feel free to [open issues](https://github.com/vtex-apps/store-components/issues/new) or contribute with pull requests.

## Contributing

Check it out [how to contribute](https://github.com/vtex-apps/awesome-io#contributing) with this project.

## Tests

To execute our tests go to `react/` folder and run `yarn test`

### Travis CI

[![Build Status](https://api.travis-ci.org/vtex-apps/store-components.svg?branch=master)](https://travis-ci.org/vtex-apps/store-components)

<!-- DOCS-IGNORE:start -->
## Contributors

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/hapoza"><img src="https://avatars3.githubusercontent.com/u/27775611?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dan</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=hapoza" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/JNussens"><img src="https://avatars0.githubusercontent.com/u/7662734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jean Nussenzveig</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=JNussens" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/lucasayb"><img src="https://avatars2.githubusercontent.com/u/17356081?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lucas Antônio Yamamoto Borges</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=lucasayb" title="Code">💻</a></td>
    <td align="center"><a href="https://t.co/LTjWBxRnqE"><img src="https://avatars3.githubusercontent.com/u/28419764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sebastian Sanchez Vega</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=sebaskun98" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/Erislandio"><img src="https://avatars1.githubusercontent.com/u/34255207?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Erislandio</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=Erislandio" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/BeatrizMiranda"><img src="https://avatars2.githubusercontent.com/u/28959326?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Beatriz Miranda</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=BeatrizMiranda" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/Jayendra88"><img src="https://avatars1.githubusercontent.com/u/2637457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jayendra</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=Jayendra88" title="Code">💻</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/pgrimaud"><img src="https://avatars1.githubusercontent.com/u/1866496?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pierre Grimaud</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=pgrimaud" title="Documentation">📖</a></td>
    <td align="center"><a href="https://www.linkedin.com/in/igorpoubel"><img src="https://avatars2.githubusercontent.com/u/6241622?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Igor Poubel</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=igorpoubel" title="Code">💻</a></td>
    <td align="center"><a href="http://www.hugoccosta.com"><img src="https://avatars2.githubusercontent.com/u/20212776?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hugo Costa</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=hugocostadev" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/MatheusR42"><img src="https://avatars0.githubusercontent.com/u/16908590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matheus Araujo</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=MatheusR42" title="Documentation">📖</a></td>
    <td align="center"><a href="https://github.com/LuisaFCorrea"><img src="https://avatars3.githubusercontent.com/u/66276121?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luisa Correa</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=LuisaFCorrea" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/pmarignan"><img src="https://avatars2.githubusercontent.com/u/32361926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pmarignan</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=pmarignan" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/rcmuniz1994"><img src="https://avatars.githubusercontent.com/u/32344098?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodrigo Muniz</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=rcmuniz1994" title="Code">💻</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/ovio224"><img src="https://avatars.githubusercontent.com/u/68231117?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ovi</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=oviolion" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/LucasCastroJussi"><img src="https://avatars.githubusercontent.com/u/80407814?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LucasCastroJussi</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=LucasCastroJussi" title="Code">💻</a></td>
    <td align="center"><a href="https://razvanudrea.com"><img src="https://avatars.githubusercontent.com/u/71461884?v=4?s=100" width="100px;" alt=""/><br /><sub><b>razvanudream</b></sub></a><br /><a href="https://github.com/vtex-apps/store-components/commits?author=razvanudream" title="Code">💻</a></td>
  </tr>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

<!-- DOCS-IGNORE:end -->

**Upcoming documentation:**

 - [Render logo as amp-img if in AMP page](https://github.com/vtex-apps/store-components/pull/580)
 - [Update CSS handles on ProductSpecification](https://github.com/vtex-apps/store-components/pull/599)

 - [Including classes on searchBar to identify when is open and/or filled](https://github.com/vtex-apps/store-components/pull/792)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/NotificationBar.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { memo } from 'react'
import { useIntl } from 'react-intl'
import { formatIOMessage } from 'vtex.native-types'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'

import { SanitizedHTML } from './components/SanitizedHTML'

const CSS_HANDLES = [
  'notificationBarContainer',
  'notificationBarInner',
  'notificationContent',
] as const

interface Props {
  /** Text to be used in the bar */
  content?: string
  /** Used to override default CSS handles */
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function NotificationBar({ content = '', classes }: Props) {
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const intl = useIntl()

  if (!content) {
    return null
  }

  return (
    <div
      className={`${handles.notificationBarContainer} bg-base--inverted c-on-base--inverted w-100`}
    >
      <div
        className={`${handles.notificationBarInner} min-h-large flex items-center justify-center`}
      >
        <div className={handles.notificationContent}>
          <SanitizedHTML
            content={formatIOMessage({ id: content, intl }) as string}
          />
        </div>
      </div>
    </div>
  )
}

const MemoizedNotificationBar: React.MemoExoticComponent<
  typeof NotificationBar
> & { schema?: Record<string, string> } = memo(NotificationBar)

MemoizedNotificationBar.schema = {
  title: 'admin/editor.notification-bar.title',
}

export default MemoizedNotificationBar

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/ProductDescription.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { memo } from 'react'
import type { MemoExoticComponent, PropsWithChildren } from 'react'
import { FormattedMessage, useIntl } from 'react-intl'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { formatIOMessage } from 'vtex.native-types'
import { useProduct } from 'vtex.product-context'

import { SanitizedHTML, DEFAULTS } from './components/SanitizedHTML'
import GradientCollapse from './components/GradientCollapse'

const CSS_HANDLES = [
  'productDescriptionContainer',
  'productDescriptionTitle',
  'productDescriptionText',
] as const

type Props = {
  /** Description fallback */
  description?: string
  /** Section title */
  title?: string
  /** Define whether or not to show the title */
  showTitle?: boolean
  /** Define if content should start collapsed or not */
  collapseContent?: boolean
  /** Used to override default CSS handles */
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

const allowedTags = [
  ...DEFAULTS.allowedTags,
  'link',
  'body',
  'html',
  'style',
  'link',
  'script',
  'head',
  'meta',
  'object',
  'embed',
]

const allowedAttributes = {
  ...DEFAULTS.allowedAttributes,
  meta: ['charset', 'name', 'content'],
  object: ['type', 'height', 'width', 'data'],
  embed: ['height', 'width', 'src'],
}

/**
 * Product Description Component.
 * Render the description of a product
 */
function ProductDescription(props: PropsWithChildren<Props>) {
  const { handles } = useCssHandles(CSS_HANDLES, { classes: props.classes })
  const intl = useIntl()
  const { product } = useProduct()

  const description = props.description ?? product?.description

  if (!description) {
    return null
  }

  const { collapseContent = true, showTitle = true, title } = props

  return (
    <div className={handles.productDescriptionContainer}>
      {showTitle && (
        <FormattedMessage id="store/product-description.title">
          {txt => (
            <h2
              className={`${handles.productDescriptionTitle} t-heading-5 mb5 mt0`}
            >
              {title ? formatIOMessage({ id: title, intl }) : txt}
            </h2>
          )}
        </FormattedMessage>
      )}

      <div className={`${handles.productDescriptionText} c-muted-1`}>
        {collapseContent ? (
          <GradientCollapse collapseHeight={220}>
            <SanitizedHTML
              content={description}
              allowedTags={allowedTags}
              allowedAttributes={allowedAttributes}
            />
          </GradientCollapse>
        ) : (
          <SanitizedHTML
            content={description}
            allowedTags={allowedTags}
            allowedAttributes={allowedAttributes}
          />
        )}
      </div>
    </div>
  )
}

const MemoizedProductDescription: MemoExoticComponent<
  typeof ProductDescription
> & { schema?: Record<string, string> } = memo(ProductDescription)

MemoizedProductDescription.schema = {
  title: 'admin/editor.product-description.title',
}

export default MemoizedProductDescription

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/InfoCard.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import InfoCard from './components/InfoCard/index'

export default InfoCard

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/AvailabilitySubscriber.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import type { FormEvent, ChangeEvent } from 'react'
import { useIntl } from 'react-intl'
import { useMutation } from 'react-apollo'
import { Button, Input } from 'vtex.styleguide'
import { useProduct } from 'vtex.product-context'
import type { Seller } from 'vtex.product-context'

import ADD_TO_AVAILABILITY_SUBSCRIBER_MUTATION from './graphql/addToAvailabilitySubscriberMutation.gql'
import styles from './AvailabilitySubscriber.css'
import { getDefaultSeller } from './utils/sellers'

interface MutationVariables {
  acronym: string
  document: {
    fields: Array<{
      key: string
      value?: string | null
    }>
  }
}
interface Props {
  /* Product's availability */
  available?: boolean
  /* SKU id to subscribe to */
  skuId?: string
}

const isAvailable = (commertialOffer?: Seller['commertialOffer']) => {
  return (
    commertialOffer &&
    (Number.isNaN(+commertialOffer.AvailableQuantity) ||
      commertialOffer.AvailableQuantity > 0)
  )
}

/**
 * Availability Subscriber Component.
 * A form where users can sign up to be alerted
 * when a product becomes available again
 */
function AvailabilitySubscriber(props: Props) {
  const productContext = useProduct()
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [emailError, setEmailError] = useState(false)
  const [didBlurEmail, setDidBlurEmail] = useState(false)

  const [signUp, { loading, error, data }] = useMutation<
    unknown,
    MutationVariables
  >(ADD_TO_AVAILABILITY_SUBSCRIBER_MUTATION)

  const intl = useIntl()

  const seller = getDefaultSeller(productContext.selectedItem?.sellers)

  const available = props.available ?? isAvailable(seller?.commertialOffer)
  const skuId = props.skuId ?? productContext.selectedItem?.itemId

  // Render component only if the product is out of stock
  if (available || !skuId) {
    return null
  }

  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    const variables: MutationVariables = {
      acronym: 'AS',
      document: {
        fields: [
          {
            key: 'skuId',
            value: skuId,
          },
          {
            key: 'name',
            value: name,
          },
          {
            key: 'email',
            value: email,
          },
          {
            key: 'notificationSend',
            value: 'false',
          },
          {
            key: 'createdAt',
            value: new Date().toISOString(),
          },
          {
            key: 'sendAt',
            value: null,
          },
        ],
      },
    }

    const signUpMutationResult = await signUp({
      variables,
    })

    if (!signUpMutationResult.errors) {
      setName('')
      setEmail('')
    }

    const event = new CustomEvent('message:success', {
      detail: {
        success: true,
        message: intl.formatMessage({
          id: 'store/availability-subscriber.added-message',
        }),
      },
    })

    document.dispatchEvent(event)
  }

  const validateEmail = (newEmail: string) => {
    const emailRegex =
      /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

    setEmailError(!emailRegex.test(newEmail.toLowerCase()))
  }

  const handleEmailChange = (e: ChangeEvent<HTMLInputElement>) => {
    setEmail(e.target.value)
    validateEmail(e.target.value)
  }

  const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value)
  }

  let emailErrorMessage = ''

  if (didBlurEmail && emailError) {
    emailErrorMessage = intl.formatMessage({
      id: 'store/availability-subscriber.invalid-email',
    })
  }

  const isFormDisabled = name === '' || email === '' || emailError || loading

  return (
    <div className={styles.subscriberContainer}>
      <div className={`${styles.title} t-body mb3`}>
        {intl.formatMessage({ id: 'store/availability-subscriber.title' })}
      </div>
      <div className={`${styles.subscribeLabel} t-small fw3`}>
        {intl.formatMessage({
          id: 'store/availability-subscriber.subscribe-label',
        })}
      </div>
      <form className={`${styles.form} mb4`} onSubmit={e => handleSubmit(e)}>
        <div className={`${styles.content} flex-ns justify-between mt4 mw6`}>
          <div className={`${styles.input} ${styles.inputName} w-100 mr5 mb4`}>
            <Input
              name="name"
              type="text"
              placeholder={intl.formatMessage({
                id: 'store/availability-subscriber.name-placeholder',
              })}
              value={name}
              onChange={handleNameChange}
            />
          </div>
          <div className={`${styles.input} ${styles.inputEmail} w-100 mr5 mb4`}>
            <Input
              name="email"
              type="text"
              placeholder={intl.formatMessage({
                id: 'store/availability-subscriber.email-placeholder',
              })}
              value={email}
              onChange={handleEmailChange}
              onBlur={() => setDidBlurEmail(true)}
              error={didBlurEmail && emailError}
              errorMessage={emailErrorMessage}
            />
          </div>
          <div className={`${styles.submit} flex items-center mb4`}>
            <Button
              type="submit"
              variation="primary"
              size="small"
              disabled={isFormDisabled}
              isLoading={loading}
            >
              {intl.formatMessage({
                id: 'store/availability-subscriber.send-label',
              })}
            </Button>
          </div>
        </div>
        {!error && data && (
          <div className={`${styles.success} t-body c-success`}>
            {intl.formatMessage({
              id: 'store/availability-subscriber.added-message',
            })}
          </div>
        )}
        {error && (
          <div className={`${styles.error} c-danger`}>
            {intl.formatMessage({
              id: 'store/availability-subscriber.error-message',
            })}
          </div>
        )}
      </form>
    </div>
  )
}

export default AvailabilitySubscriber

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/SanitizedHTML.ts from the store-components VTEX app.

[Assistant]
Here's the implementation:

```typescript
export { SanitizedHTML as default } from './components/SanitizedHTML'

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/BuyButton.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import BuyButton from './components/BuyButton/Wrapper'

export default BuyButton

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/HighQualityProductImage.ts from the store-components VTEX app.

[Assistant]
Here's the implementation:

```typescript
export { default } from './components/ProductImages/components/HighQualityProductImage'

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/NotificationInline.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { memo } from 'react'
import { useIntl } from 'react-intl'
import { formatIOMessage } from 'vtex.native-types'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'

import { SanitizedHTML } from './components/SanitizedHTML'

const CSS_HANDLES = ['notificationContent'] as const

interface Props {
  /** Text to be used in the bar */
  content?: string
  /** Used to override default CSS handles */
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function NotificationInline({ content = '', classes }: Props) {
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const intl = useIntl()

  if (!content) {
    return null
  }

  return (
    <div className={handles.notificationContent}>
      <SanitizedHTML
        content={formatIOMessage({ id: content, intl }) as string}
      />
    </div>
  )
}

const MemoizedNotificationInline: React.MemoExoticComponent<
  typeof NotificationInline
> & { schema?: Record<string, string> } = memo(NotificationInline)

MemoizedNotificationInline.schema = {
  title: 'admin/editor.notification-bar.title',
}

export default MemoizedNotificationInline

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/CategoriesHighlights.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import CategoriesHighlights from './components/CategoriesHighlights'

export default CategoriesHighlights

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/Container.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { PropsWithChildren, ForwardedRef } from 'react'

import styles from './Container.css'

type Props = PropsWithChildren<{
  className?: string
}>

function InnerContainer(
  { className, children, ...props }: Props,
  ref: ForwardedRef<HTMLDivElement>
) {
  return (
    <section
      {...props}
      className={`${styles.container} ph3 ph5-m ph2-xl mw9 center ${
        className ?? ''
      }`}
      ref={ref}
    >
      {children}
    </section>
  )
}

InnerContainer.displayName = 'Container'

/**
 * Renders a container to wrap elements in the middle of the viewport.
 */
const Container = React.forwardRef<HTMLDivElement, Props>(InnerContainer)

export default Container

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/SKUSelector.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import SKUSelector from './components/SKUSelector/Wrapper'

export default SKUSelector

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/ProductImages.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import ProductImages from './components/ProductImages/Wrapper'

export default ProductImages

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/SearchBar.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useCallback, useEffect } from 'react'
import { useIntl } from 'react-intl'
import { ModalContext } from 'vtex.modal-layout'
import { useRuntime } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { usePixel } from 'vtex.pixel-manager'

import SearchBar, {
  CSS_HANDLES as SearchBarCssHandles,
} from './components/SearchBar/SearchBar'
import { CSS_HANDLES as AutocompleteInputCssHandles } from './components/SearchBar/AutocompleteInput'
import { SearchBarCssHandlesProvider } from './components/SearchBar/SearchBarCssHandles'

const { useModalDispatch } = ModalContext

export const SEARCH_BAR_CSS_HANDLES = [
  ...SearchBarCssHandles,
  ...AutocompleteInputCssHandles,
] as const

interface Props {
  /** Define when use the compact version of the component */
  compactMode?: boolean
  /** Define if the search icon is on left or right position */
  hasIconLeft?: boolean
  /** Custom classes for the search icon */
  iconClasses?: string
  /** Define if the search input should autofocus or not */
  autoFocus?: boolean
  /** Max width of the search bar */
  maxWidth?: string | number
  /**
   * Uses the term the user has inputed to try to navigate to the proper
   * page type (e.g. a department, a brand, a category)
   */
  attemptPageTypeSearch?: boolean
  /** A template for a custom url. It can have a substring ${term} used as placeholder to interpolate the searched term. (e.g. `/search?query=${term}`) */
  customSearchPageUrl?: string
  placeholder?: string
  /* Autocomplete Horizontal alignment */
  autocompleteAlignment?: 'right' | 'left' | 'center'
  /** Define if autocomplete should be open on input focus or not */
  openAutocompleteOnFocus?: boolean
  /** Define if input should blur on submit */
  blurOnSubmit?: boolean
  /** Define if icon should submit on click */
  submitOnIconClick?: boolean
  /** Minimum search term length allowed */
  minSearchTermLength?: number
  /** If true, the autocomplete will fill the whole window horizontally */
  autocompleteFullWidth?: boolean
  /** The type of the search input */
  inputType?: 'text' | 'search'
  /** Define the component display mode, such as which buttons should be visible */
  displayMode?: 'clear-button' | 'search-and-clear-buttons' | 'search-button'
  /** Define how the autocomplete component should be displayed. Possible values are: `overlay` (suggestions overlapping other components) and `container` (displays the suggestion within a container). */
  containerMode: 'overlay' | 'container'
  /** Used to override default CSS handles */
  classes?: CssHandlesTypes.CustomClasses<typeof SEARCH_BAR_CSS_HANDLES>
  /** The autocomplete can have touchable/clickable components. Interacting with those components may trigger blur and touch events that will close the autocomplete. When set to true, this prop will disable those handlers */
  disableBlurAndTouchEndHandler?: boolean
}

/**
 * Canonical search bar that uses the autocomplete endpoint to search for a specific product
 * */
function SearchBarContainer(props: Props) {
  const intl = useIntl()
  const {
    compactMode,
    hasIconLeft,
    iconClasses,
    autoFocus,
    maxWidth,
    attemptPageTypeSearch,
    customSearchPageUrl,
    placeholder = intl.formatMessage({
      id: 'store/search.placeholder',
    }),
    autocompleteAlignment = 'right',
    openAutocompleteOnFocus = false,
    containerMode = 'overlay',
    blurOnSubmit = false,
    submitOnIconClick,
    displayMode = 'clear-button',
    minSearchTermLength,
    autocompleteFullWidth = false,
    inputType = 'text',
    classes,
    disableBlurAndTouchEndHandler = false,
  } = props

  const modalDispatch = useModalDispatch()
  const { navigate, query } = useRuntime()
  const { push } = usePixel()

  const [inputValue, setInputValue] = useState(query?._q ?? '')

  useEffect(() => {
    setInputValue(query?._q ?? '')
  }, [query?._q])

  const { handles, withModifiers } = useCssHandles(SEARCH_BAR_CSS_HANDLES, {
    classes,
  })

  const closeModal = useCallback(() => {
    if (modalDispatch) {
      modalDispatch({
        type: 'CLOSE_MODAL',
      })
    }
  }, [modalDispatch])

  const handleClearInput = useCallback(() => {
    setInputValue('')
  }, [])

  const handleInputChange = useCallback(event => {
    setInputValue(event.target.value)
  }, [])

  const handleGoToSearchPage = useCallback(() => {
    const search = encodeURIComponent(inputValue.trim())

    push({
      event: 'search',
      term: search,
    })

    if (attemptPageTypeSearch) {
      window.location.href = `/${search}`
      closeModal()

      return
    }

    if (customSearchPageUrl) {
      navigate({
        to: customSearchPageUrl.replace(/\$\{term\}/g, search),
      })
      closeModal()

      return
    }

    // This param is only useful to track terms searched
    // See: https://support.google.com/analytics/answer/1012264
    const paramForSearchTracking = `&_q=${search}`

    navigate({
      page: 'store.search',
      params: { term: search },
      query: `map=ft${paramForSearchTracking}`,
      fallbackToWindowLocation: false,
    })
    closeModal()
  }, [
    inputValue,
    attemptPageTypeSearch,
    customSearchPageUrl,
    navigate,
    closeModal,
    push,
  ])

  return (
    <SearchBarCssHandlesProvider
      handles={handles}
      withModifiers={withModifiers}
    >
      <SearchBar
        // eslint-disable-next-line jsx-a11y/no-autofocus
        autoFocus={autoFocus}
        placeholder={placeholder}
        inputValue={inputValue}
        onClearInput={handleClearInput}
        onGoToSearchPage={handleGoToSearchPage}
        onInputChange={handleInputChange}
        compactMode={compactMode}
        hasIconLeft={hasIconLeft}
        iconClasses={iconClasses}
        maxWidth={maxWidth}
        attemptPageTypeSearch={attemptPageTypeSearch}
        customSearchPageUrl={customSearchPageUrl}
        autocompleteAlignment={autocompleteAlignment}
        openAutocompleteOnFocus={openAutocompleteOnFocus}
        blurOnSubmit={blurOnSubmit}
        submitOnIconClick={submitOnIconClick}
        displayMode={displayMode}
        minSearchTermLength={minSearchTermLength}
        autocompleteFullWidth={autocompleteFullWidth}
        inputType={inputType}
        containerMode={containerMode}
        disableBlurAndTouchEndHandler={disableBlurAndTouchEndHandler}
      />
    </SearchBarCssHandlesProvider>
  )
}

SearchBarContainer.schema = {
  title: 'admin/editor.search-bar.title',
}

export default SearchBarContainer

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/ProductBrand.tsx from the store-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import { useQuery } from 'react-apollo'
import { useProduct } from 'vtex.product-context'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'

import { ProductBrandCssHandlesProvider } from './components/ProductBrand/ProductBrandCssHandles'
import ProductBrandName, {
  CSS_HANDLES as ProductBrandNameCssHandles,
} from './components/ProductBrand/ProductBrandName'
import { changeImageUrlSize } from './utils/imgUrlHelpers'
import brandLogoQuery from './graphql/productBrand.gql'

type DisplayModeOptions = 'logo' | 'text'
type WithLinkOptions = 'none' | 'logo' | 'text' | 'logoAndText'

interface ProductBrandQueryVariables {
  id: number
}

interface ProductBrandQueryResult {
  brand?: {
    imageUrl: string | null
    slug: string
  }
}

export const PRODUCT_BRAND_CSS_HANDLES = [
  'productBrandContainer',
  'productBrandLogo',
  'productBrandLogoWrapper',
  'productBrandLogoLink',
  'productBrandLogoSpacer',
  'productBrandNameSpacer',
  ...ProductBrandNameCssHandles,
] as const

export interface ProductBrandProps {
  /** The brand name. If no value is declared, the product context should provide the data. */
  brandName?: string
  /** The brand ID.  If no value is declared, the product context should provide the data. */
  brandId?: number
  /** This will define if the product brand will be displayed by text or logo */
  displayMode?: DisplayModeOptions
  /** This will define if the loading placeholder should have the size of the logo or the text */
  loadingPlaceholder?: DisplayModeOptions
  /** This prop should only be used when `displayMode` is set to `logo`.
   * It defines what should be done when the Product Brand was set to display a brand logo
   * but no image was registered in the VTEX admin's Catalog
   * */
  fallbackToText?: boolean
  /** The brand names or brand IDs listed in the array will never be displayed by the Brand component.
   * It is usually useful to hide default or test brand names/logos on the store front
   * */
  excludeBrands?: Array<string | number>
  /** It sets the logo height. It should only be used when `displayMode` is set to `logo` */
  height?: number
  /** @deprecated use withLink instead */
  logoWithLink?: boolean
  /** Defines the scenarios in which the product brand should have a link that leads to its website. */
  withLink?: WithLinkOptions
  /** Used to override default CSS handles */
  classes?: CssHandlesTypes.CustomClasses<typeof PRODUCT_BRAND_CSS_HANDLES>
  blockClass?: string
}

const shouldExcludeBrand = (
  brandName: string,
  brandId: number,
  excludeList: ProductBrandProps['excludeBrands']
) => {
  if (Array.isArray(excludeList)) {
    return excludeList.includes(brandName) || excludeList.includes(brandId)
  }

  return false
}

const useBrandInfoProps = (
  brandName: string | undefined,
  brandId: number | undefined
) => {
  const productContext = useProduct()
  const product = productContext?.product

  if ((brandName && brandId) || !product) {
    return { brandName, brandId }
  }

  return { brandName: product.brand, brandId: Number(product.brandId) }
}

/**
 * The `ProductBrand` is a VTEX block that displays either the **name** or the **logo** of a **product's brand**.
 */
function ProductBrand({
  displayMode = 'logo',
  fallbackToText = true,
  loadingPlaceholder = 'logo',
  /** TODO: decide whether the prop width should be supported
   * It makes sense at surface, but setting both width and height
   * messes with the alignment of the logo, due to how our image
   * server handles resizing. */
  height = 100,
  excludeBrands,
  logoWithLink,
  withLink = 'none',
  brandName: brandNameProp,
  brandId: brandIdProp,
  classes,
}: ProductBrandProps) {
  const { brandName, brandId } = useBrandInfoProps(brandNameProp, brandIdProp)
  const { handles, withModifiers } = useCssHandles(PRODUCT_BRAND_CSS_HANDLES, {
    classes,
  })

  const { data, loading, error } = useQuery<
    ProductBrandQueryResult,
    ProductBrandQueryVariables
  >(brandLogoQuery, {
    variables: { id: Number(brandId) },
    ssr: false,
  })

  const logoHasLink =
    withLink === 'logo' || withLink === 'logoAndText' || Boolean(logoWithLink)

  const nameHasLink = withLink === 'text' || withLink === 'logoAndText'

  if (!brandName || !brandId) {
    return null
  }

  /** Certain brands (e.g. placeholder brands) can be filtered out via theme config */
  if (shouldExcludeBrand(brandName, Number(brandId), excludeBrands)) {
    return null
  }

  const brandNameElement = (
    <ProductBrandCssHandlesProvider
      handles={handles}
      withModifiers={withModifiers}
    >
      <ProductBrandName
        brandName={brandName}
        withLink={nameHasLink}
        slug={data?.brand?.slug}
      />
    </ProductBrandCssHandlesProvider>
  )

  const BrandContainer: FC = ({ children }) => (
    <div className={`${handles.productBrandContainer}`}>{children}</div>
  )

  if (displayMode === 'text') {
    return <BrandContainer>{brandNameElement}</BrandContainer>
  }

  if (!height) {
    console.warn(
      'ProductBrand: It is strongly recommended that the height of the logo should be set, to avoid shifting positions of elements while the logo is loading.'
    )
  }

  if (loading) {
    /** Renders an empty spacer in the size of the preferred
     * type (i.e. if most brands have no logo, it should render
     * a placeholder in the size of the brand name text; if
     * most brands do have a logo, it should render a spacer
     * in the size of the predefined image size)
     */
    if (loadingPlaceholder === 'logo') {
      return (
        <BrandContainer>
          <div
            style={{
              height,
            }}
            className={`${handles.productBrandLogoSpacer}`}
          />
        </BrandContainer>
      )
    }

    if (loadingPlaceholder === 'text' && fallbackToText) {
      return (
        <BrandContainer>
          <span className={`${handles.productBrandNameSpacer} o-0`}>
            {brandNameElement}
          </span>
        </BrandContainer>
      )
    }

    return null
  }

  if (error || !data?.brand) {
    return null
  }

  const { imageUrl, slug } = data.brand

  /** If imageUrl is exactly null, it means no brand
   * logo was uploaded. So it falls back to the brand name,
   * if said fallback is enabled. */
  if (imageUrl === null && fallbackToText) {
    return <BrandContainer>{brandNameElement}</BrandContainer>
  }

  if (imageUrl === null && !fallbackToText) {
    return null
  }

  const dpi = window?.devicePixelRatio ?? 1
  const logoLink = `/${slug}`

  const logoImageSrc = changeImageUrlSize({
    imageUrl: `/arquivos/ids${imageUrl}`,
    height: height ? height * dpi : undefined,
  })

  const logoImage = (
    <img
      className={`${handles.productBrandLogo}`}
      src={logoImageSrc}
      alt={brandName}
      style={{
        height: height || 'auto',
      }}
    />
  )

  return (
    <BrandContainer>
      <div
        style={{
          height,
        }}
        className={`${handles.productBrandLogoWrapper}`}
      >
        {/** TODO: Use a smarter Image component that handles VTEX image resizing etc. */}
        {logoHasLink ? (
          <a
            href={logoLink}
            className={`${handles.productBrandLogoLink}`}
            data-testid="logo-redirect"
          >
            {' '}
            {logoImage}{' '}
          </a>
        ) : (
          logoImage
        )}
      </div>
    </BrandContainer>
  )
}

export default ProductBrand

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/AvailabilitySubscriber.css from the store-components VTEX app.

[Assistant]
Here's the implementation:

```css
/**
* AvailabilitySubscriber CSS Module
*/

.subscriberContainer {}

.title {}

.subscribeLabel {}

.form {}

.content {}

.input {}

.inputName {}

.inputEmail {}

.submit {}

.success {}

.error {}
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/DiscountBadge.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import DiscountBadge from './components/DiscountBadge/index'

export default DiscountBadge

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/BackToTopButton.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import BackToTopButton from './components/BackToTopButton'

export default BackToTopButton

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/ShippingSimulator.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import ShippingSimulator from './components/ShippingSimulator/Wrapper'

export default ShippingSimulator

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/CollectionBadges.ts from the store-components VTEX app.

[Assistant]
Here's the implementation:

```typescript
import CollectionBadges from './components/CollectionBadges'

export default CollectionBadges

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/package.json from the store-components VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "private": true,
  "scripts": {
    "pretest": "yarn",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "@vtex/css-handles": "^1.1.3",
    "@vtex/insane": "^2.8.0",
    "apollo-client": "^2.5.1",
    "classnames": "^2.2.5",
    "debounce": "^1.2.0",
    "downshift": "^3.2.10",
    "graphql": "~0.13.2",
    "graphql-tag": "~2.8.0",
    "hoist-non-react-statics": "^3.3.0",
    "prop-types": "^15.6.2",
    "ramda": "^0.25.0",
    "react": "^16.3.2",
    "react-amphtml": "^4.0.1",
    "react-apollo": "3.1.3",
    "react-content-loader": "^3.1.2",
    "react-dom": "^16.8.3",
    "react-html-parser": "^2.0.2",
    "react-intl": "^3.12.1",
    "react-resize-detector": "^3.0.1",
    "react-share": "^4.2.1",
    "react-slick": "^0.23.1",
    "react-transition-group": "^4.3.0",
    "recompose": "^0.30.0",
    "slick-carousel": "^1.8.1",
    "slugify": "^1.3.4",
    "swiper": "6.2.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "3.1.3",
    "@types/classnames": "^2.2.9",
    "@types/debounce": "^1.2.0",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.7.5",
    "@types/ramda": "^0.26.18",
    "@types/react": "^16.9.2",
    "@types/react-content-loader": "3",
    "@types/react-dom": "^16.9.0",
    "@vtex/test-tools": "^3.4.3",
    "@vtex/tsconfig": "^0.5.5",
    "apollo-cache-inmemory": "^1.4.3",
    "babel-eslint": "^10.1.0",
    "typescript": "3.9.7",
    "vtex.address-form": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.address-form@4.25.5/public/@types/vtex.address-form",
    "vtex.apps-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.apps-graphql@3.17.4/public/@types/vtex.apps-graphql",
    "vtex.checkout-resources": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-resources@0.50.0/public/@types/vtex.checkout-resources",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.1/public/@types/vtex.css-handles",
    "vtex.device-detector": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.device-detector@0.2.6/public/@types/vtex.device-detector",
    "vtex.format-currency": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.format-currency@0.4.1/public/@types/vtex.format-currency",
    "vtex.modal": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.modal@0.2.2/public/@types/vtex.modal",
    "vtex.modal-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.modal-layout@0.14.1/public/@types/vtex.modal-layout",
    "vtex.native-types": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.native-types@0.10.1/public/@types/vtex.native-types",
    "vtex.order-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-manager@0.12.0/public/@types/vtex.order-manager",
    "vtex.order-shipping": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-shipping@0.8.0/public/@types/vtex.order-shipping",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.9.0/public/@types/vtex.pixel-manager",
    "vtex.product-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.10.1/public/@types/vtex.product-context",
    "vtex.react-portal": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.react-portal@0.4.1/public/@types/vtex.react-portal",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.134.11/public/@types/vtex.render-runtime",
    "vtex.responsive-values": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.responsive-values@0.4.2/public/@types/vtex.responsive-values",
    "vtex.rich-text": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.rich-text@0.16.0/public/@types/vtex.rich-text",
    "vtex.search-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-graphql@0.64.0/public/@types/vtex.search-graphql",
    "vtex.shipping-estimate-translator": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.shipping-estimate-translator@2.3.0/public/@types/vtex.shipping-estimate-translator",
    "vtex.slider-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.slider-layout@0.24.6/public/@types/vtex.slider-layout",
    "vtex.store-components": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-components@3.175.1/public/@types/vtex.store-components",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.172.1/public/@types/vtex.store-graphql",
    "vtex.store-icons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons",
    "vtex.store-image": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-image@0.22.3/public/@types/vtex.store-image",
    "vtex.store-resources": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-resources@0.100.0/public/@types/vtex.store-resources",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.146.13/public/@types/vtex.styleguide"
  },
  "resolutions": {
    "json-schema": "^0.4.0",
    "jsdom": "^16.5.0",
    "jest-environment-jsdom": "^26.0.0",
    "node-fetch": "^2.6.7",
    "node-notifier": "^8.0.1"
  },
  "vtexTestTools": {
    "defaultLocale": "en"
  },
  "jest": {
    "setupFilesAfterEnv": [
      "./setupTests.js"
    ]
  },
  "version": "3.178.5"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-components/react/ProductSeparator.js from the store-components VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'

/**
 * @deprecated This block is deprecated. Please, implement your own.
 */
export default function ProductSeparator() {
  return <hr className="o-30" size="1" />
}

```