[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 instore-profile/react/inputs/StyleguideInput/index.js from the instore-profile VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { intlShape, injectIntl } from 'react-intl'
import Input from '@vtex/styleguide/lib/Input'
import RuleFieldShape from '../../RuleFieldShape'
import ProfileFieldShape from '../../ProfileFieldShape'
import GenderInput from './GenderInput'

const StyleguideInput = props => {
  const {
    field,
    data,
    options,
    inputRef,
    onChange,
    onBlur,
    intl,
  } = props

  if (field.name === 'gender') {
    return (
      <GenderInput
        {...props}
        shouldShowExtendedGenders={options.shouldShowExtendedGenders}
      />
    )
  }

  return (
    <div
      className={`vtex-profile-form__field-wrapper vtex-profile-form__${field.name} ${
        field.hidden ? 'dn' : ''
      } pb7`}
    >
      <Input
        name={field.name}
        label={intl.formatMessage({
          id: `profile-form.field.${field.label}`,
        })}
        value={data.value || ''}
        errorMessage={
          data.error &&
          intl.formatMessage({
            id: `profile-form.error.${data.error}`,
          })
        }
        placeholder={
          !field.required
            ? intl.formatMessage({ id: 'profile-form.optional' })
            : null
        }
        onChange={onChange}
        onBlur={onBlur}
        ref={inputRef}
        maxLength={field.maxLength}
        disabled={field.disabled}
      />
    </div>
  )
}

StyleguideInput.propTypes = {
  /** Rules for the field this input represents */
  field: RuleFieldShape.isRequired,
  /** Data this input will display */
  data: ProfileFieldShape.isRequired,
  /** Additional options to modify this input */
  options: PropTypes.object,
  /** Ref function to control this input from outside */
  inputRef: PropTypes.func,
  /** Function to be called when input changes */
  onChange: PropTypes.func.isRequired,
  /** Function to be called when input blurs */
  onBlur: PropTypes.func.isRequired,
  /** React-intl utility */
  intl: intlShape.isRequired,
}

export default injectIntl(StyleguideInput)

```


[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 instore-profile/react/inputs/StyleguideInput/AutocompleteMenu.js from the instore-profile VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class AutocompleteMenu extends Component {
  render() {
    const { items, highlightedIndex, getMenuProps, getItemProps } = this.props

    if (!items.length) return null

    const listHeight = items.length > 4 ? 'h5' : ''

    return (
      <div
        {...getMenuProps({
          className: `br2 br--bottom bb br bl b--gray bw1 outline-0 overflow-y-scroll ${
            listHeight
          } absolute w-100 z-1 bg-white vtex-profile-form__autocomplete-menu`,
        })}
      >
        {items.map((item, index) => (
          <div
            {...getItemProps({
              key: item.value,
              index,
              item,
              className: `vtex-profile-form__autocomplete-menu__content f6 ph5 pv5 dark-gray ${
                highlightedIndex === index ? 'bg-light-silver' : 'bg-white'
              }`,
            })}
          >
            {item.label}
          </div>
        ))}
      </div>
    )
  }
}

AutocompleteMenu.propTypes = {
  /** The items this menu contains */
  items: PropTypes.array,
  /** The index of the item currently highlighted */
  highlightedIndex: PropTypes.number,
  /** Function that returns some acessibility props for the menu */
  getMenuProps: PropTypes.func,
  /** Function that returns some acessibility props for the items */
  getItemProps: PropTypes.func,
}

export default AutocompleteMenu

```


[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 instore-profile/react/inputs/StyleguideInput/GenderInput.js from the instore-profile VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { intlShape, injectIntl } from 'react-intl'
import Dropdown from '@vtex/styleguide/lib/Dropdown'
import AutocompleteInput from './AutocompleteInput'
import RuleFieldShape from '../../RuleFieldShape'
import ProfileFieldShape from '../../ProfileFieldShape'
import genders from '../../modules/genders'

class GenderInput extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showExtendedGenders: false,
    }
  }

  componentDidMount() {
    const { data } = this.props

    if (!data.value) return

    this.setState({
      showExtendedGenders: data.value !== 'male' && data.value !== 'female',
    })
  }

  handleChange = e => {
    const { value } = e.target

    this.setState({
      showExtendedGenders: value !== 'male' && value !== 'female',
    })

    this.props.onChange(e)
  }

  getDropdownValue = () => {
    const { data } = this.props
    if (!data.value) return ''

    return data.value === 'male' || data.value === 'female'
      ? data.value
      : 'custom'
  }

  getAutocompleteValue = () => {
    const { data } = this.props
    return data.value === 'custom' ? '' : data.value
  }

  render() {
    const {
      field,
      inputRef,
      onBlur,
      intl,
      shouldShowExtendedGenders,
    } = this.props
    const { showExtendedGenders } = this.state

    const baseGenders = ['male', 'female', 'custom']
      .map(gender => ({
        value: gender,
        label: intl.formatMessage({ id: 'profile-form.gender.' + gender }),
      }))
      .slice(0, shouldShowExtendedGenders ? 3 : 2)

    const extendedGenders = genders.map(gender => ({
      value: gender,
      label: intl.formatMessage({ id: 'profile-form.gender.' + gender }),
    }))

    return (
      <div
        className={`vtex-profile-form__field-wrapper vtex-profile-form__gender ${field.hidden ? 'dn' : ''} pb7`}
      >
        <Dropdown
          name="gender"
          label={intl.formatMessage({
            id: `profile-form.field.gender`,
          })}
          value={this.getDropdownValue()}
          placeholder={
            !field.required
              ? intl.formatMessage({ id: 'profile-form.optional' })
              : null
          }
          onChange={this.handleChange}
          onBlur={onBlur}
          options={baseGenders}
          disabled={field.disabled}
        />
        {showExtendedGenders && (
          <div className="vtex-profile-form__custom-gender bg-light-silver pa5 mt4 br2">
            <AutocompleteInput
              name="custom-gender"
              label={intl.formatMessage({
                id: `profile-form.field.custom-gender`,
              })}
              value={this.getAutocompleteValue()}
              ref={inputRef}
              items={extendedGenders}
              onChange={this.handleChange}
            />
          </div>
        )}
      </div>
    )
  }
}

GenderInput.propTypes = {
  /** Rules for the field this input represents */
  field: RuleFieldShape.isRequired,
  /** Data this input will display */
  data: ProfileFieldShape.isRequired,
  /** Ref function to control this input from outside */
  inputRef: PropTypes.func,
  /** Function to be called when input changes */
  onChange: PropTypes.func.isRequired,
  /** Function to be called when input blurs */
  onBlur: PropTypes.func.isRequired,
  /** Whether to show the full list of genders or just M/F */
  shouldShowExtendedGenders: PropTypes.bool.isRequired,
  /** React-intl utility */
  intl: intlShape.isRequired,
}

export default injectIntl(GenderInput)

```


[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 instore-profile/react/inputs/StyleguideInput/AutocompleteInput.js from the instore-profile VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Downshift from 'downshift'
import matchSorter from 'match-sorter'
import Input from '@vtex/styleguide/lib/Input'
import CaretDown from '@vtex/styleguide/lib/icon/CaretDown'
import AutocompleteMenu from './AutocompleteMenu'

class AutocompleteInput extends Component {
  handleChange = ({ value }) => {
    this.props.onChange({ target: { value } })
  }

  render() {
    const { name, label, items, value, placeholder, forwardedRef } = this.props

    return (
      <Downshift
        onChange={this.handleChange}
        itemToString={item => (item ? item.label : '')}
        defaultInputValue={value}
      >
        {({
          getInputProps,
          getItemProps,
          getMenuProps,
          getToggleButtonProps,
          isOpen,
          inputValue,
          highlightedIndex,
        }) => (
            <div className="vtex-profile-form__autocomplete-input-wrapper relative">
              <Input
                {...getInputProps({
                  name,
                  label,
                  placeholder,
                  ref: forwardedRef,
                  suffixIcon: (
                    <button
                      {...getToggleButtonProps({
                        className: 'blue b--none bg-transparent pointer',
                      })}
                    >
                      <CaretDown color="currentColor" size={10} />
                    </button>
                  ),
                })}
              />
              {isOpen && (
                <AutocompleteMenu
                  items={matchSorter(items, inputValue, {
                    keys: ['label'],
                  })}
                  getMenuProps={getMenuProps}
                  getItemProps={getItemProps}
                  highlightedIndex={highlightedIndex}
                />
              )}
            </div>
          )}
      </Downshift>
    )
  }
}

AutocompleteInput.propTypes = {
  /** Name for this input */
  name: PropTypes.string.isRequired,
  /** List of items to feed the autocompletion */
  items: PropTypes.array.isRequired,
  /** The default selected value */
  value: PropTypes.string.isRequired,
  /** Label for this input */
  label: PropTypes.string,
  /** Placeholder text for the input box */
  placeholder: PropTypes.string,
  /** An icon that can be added to the right corner of the input */
  suffixIcon: PropTypes.any,
  /** Function to be called on data change */
  onChange: PropTypes.func,
  /** A ref function to control this input from outside */
  forwardedRef: PropTypes.func,
}

export default React.forwardRef((props, ref) => (
  <AutocompleteInput {...props} forwardedRef={ref} />
))

```


[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 drawer/docs/README.md from the drawer VTEX app.

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/drawer) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).

# Drawer

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

The **Drawer** component is a sliding panel that displays additional options and menus when expanded. It is typically used in mobile layouts and responsive web designs where screen space is limited.

![drawer](https://github.com/vtex-apps/reviews-and-ratings/assets/60782333/46358b77-e41a-4014-8443-c65cbe947fc2)

When closed, the **Drawer** component is represented by an icon button positioned at the edge of the screen. Upon interaction, the drawer slides into view, revealing its content. Users can interact with the exposed content, perform actions, and navigate menus. To dismiss the drawer, users can either tap outside the drawer or use the close button.

## Configuration

1. Open your store theme in the code editor of your preference.
2. Open the `manifest.json` file and add the `vtex.store-drawer` app to your store theme dependencies as in the following:

```json
"dependencies": {
  "vtex.store-drawer": "0.x"
}
```

2. Add the `drawer` block to your app. The following example is from the [Store Theme](https://github.com/vtex-apps/store-theme).

```json
"drawer": {
  "children": [
    "menu#drawer"
  ]
},

"menu#drawer": {
  "children": [
    "menu-item#category-clothing",
    "menu-item#category-decoration",
    "menu-item#custom-sale"
  ],
  "props": {
    "orientation": "vertical"
  }
},
```

3. Use the `drawer-trigger` block to customize the icon that triggers the opening of the drawer as follows:

```json
"drawer": {
  "children": [
    "menu#drawer"
  ],
  "blocks": ["drawer-trigger"]
},

"drawer-trigger": {
  "children": ["rich-text#open-drawer"]
},

"rich-text#open-drawer": {
  "props": {
    "text": "Open drawer"
  }
}

"menu#drawer": {
  "children": [
    "menu-item#category-clothing",
    "menu-item#category-decoration",
    "menu-item#custom-sale"
  ],
  "props": {
    "orientation": "vertical"
  }
},
```

4. Use the `drawer-header` block to customize the header containing the button that closes the drawer. For example:

```json
// blocks.json
{
  "drawer": {
    "blocks": ["drawer-header#my-drawer"]
  },
  "drawer-header#my-drawer": {
    "children": [
      // you need to include the block `drawer-close-button` somewhere inside here
      "flex-layout.row#something",
      // ...
      "drawer-close-button"
    ]
  }
}
```

### Using the Drawer as a standalone component

If you are using this component as a standalone module, you will need to import it into the specific component where you want to use it. For example:

```tsx
import { Drawer, DrawerHeader, DrawerCloseButton } from "vtex.store-drawer";

const Menu = () => (
  <Drawer
    header={
      <DrawerHeader>
        <DrawerCloseButton />
      </DrawerHeader>
    }
  >

Link 1

Link 2

Link 3

Link 4

Link 5

Link 6

  </Drawer>
);
```

### Props

#### `drawer`

| Prop name              | Type                                                                       | Description                                                                                | Default value  |
| ---------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `maxWidth`             | `number` or `string`                                                       | Defines the maximum width of the open drawer.                                                                                | `450`          |
| `isFullWidth`          | `boolean`                                                                  | Controls whether the open drawer should occupy the full available width.                                                                                | `false`        |
| `slideDirection`       | `'horizontal'`|`'vertical'`|`'rightToLeft'`|`'leftToRight'` | Controls the direction of the opening animation for the drawer.                                                                                | `'horizontal'` |
| `backdropMode`         | `'default'`|`'none'`                                                  | Controls whether the backdrop should be displayed when the drawer is open.                                                                                |                |
| `renderingStrategy`    | `'lazy'`|`'eager'`                                                    | Controls the rendering strategy for the children of the drawer component. It determines whether the children should be rendered only when the drawer is clicked (`lazy`) or immediately when the page loads (`eager`).  Enabling the `eager` strategy may improve SEO performance. However, it may also result in slower page rendering. | `'lazy'`       |
| `customPixelEventId`   | `string`                                                                   | Defines the store event ID responsible for triggering the `drawer` to automatically open on the interface.                                                                                | `undefined`    |
| `customPixelEventName` | `string`                                                                   | Defines the store event name responsible for triggering the `drawer` to automatically open on the interface. Some examples are: `'addToCart'` and `'removeFromCart'` events. Note that if no `customPixelEventId` is set, using this prop will cause the drawer to open in every event with the specified name.                                  | `undefined`    |

#### `drawer-close-button`

| Prop name | Type                     | Description                                                                            | Default value |
| --------- | ------------------------ | -------------------------------------------------------------------------------------- | ------------- |
| `size`    | `number`                 | Defines the size of the icon inside the button.                                         | `30`          |
| `type`    | `'filled'`|`'line'` | Defines the type of the icon.                                                           | `'line'`      |
| `text`    | `string`                 | Defines the text inside the button. The icon will not be rendered if `text` is defined. | `undefined`   |

#### `drawer-trigger`

| Prop name            | Type     | Description                                                                        | Default value |
| -------------------- | -------- | ---------------------------------------------------------------------------------- | ------------- |
| `customPixelEventId` | `string` | Defines the event ID to be sent whenever users interact with the Drawer component. | `undefined`   |

## Customization

In order to apply CSS customizations to this and other blocks, follow the instructions in [Using CSS handles for store customizations](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).

| CSS handles              |
| ------------------------ |
| `drawer`                 |
| `opened`                 |
| `overlay`                |
| `overlay--visible`       |
| `closed`                 |
| `moving`                 |
| `drawerContent`          |
| `drawerHeader`           |
| `drawerTriggerContainer` |
| `openIconContainer`      |
| `closeIconContainer`     |
| `closeIconButton`        |
| `childrenContainer`      |

## 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/Radu1749"><img src="https://avatars2.githubusercontent.com/u/51535501?v=4" width="100px;" alt=""/><br /><sub><b>Radu1749</b></sub></a><br /><a href="https://github.com/vtex-apps/drawer/commits?author=Radu1749" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/rayra-alencar"><img src="https://avatars0.githubusercontent.com/u/28907161?v=4" width="100px;" alt=""/><br /><sub><b>rayra-alencar</b></sub></a><br /><a href="https://github.com/vtex-apps/drawer/commits?author=rayra-alencar" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/renanguerraa1"><img src="https://avatars2.githubusercontent.com/u/69531548?v=4" width="100px;" alt=""/><br /><sub><b>Renan Guerra</b></sub></a><br /><a href="https://github.com/vtex-apps/drawer/commits?author=renanguerraa1" title="Code">💻</a></td>
  </tr>
</table>

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

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

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

```


[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 drawer/react/DrawerCloseButton.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles } from 'vtex.css-handles'
import { IconClose } from 'vtex.store-icons'

import { useDrawer } from './DrawerContext'

const CSS_HANDLES = ['closeIconButton'] as const

interface Props {
  size?: number
  type?: 'filled' | 'line'
  text?: string
}

const DrawerCloseButton: React.FC<Props> = ({
  size = 30,
  type = 'line',
  text,
}) => {
  const { close } = useDrawer()

  const handles = useCssHandles(CSS_HANDLES)

  return (
    <button
      className={`${handles.closeIconButton} pa4 pointer bg-transparent transparent bn pointer`}
      onClick={close}
    >
      {text ?? <IconClose size={size} type={type} />}
    </button>
  )
}

export default DrawerCloseButton

```


[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 drawer/react/DrawerContext.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { createContext, useContext } from 'react'

interface DrawerContext {
  isOpen: boolean
  open: () => void
  close: () => void
}

const ctx = createContext<DrawerContext | undefined>(undefined)

export const useDrawer = () => {
  const contextValue = useContext(ctx)

  if (contextValue === undefined) {
    throw new Error('useDrawer must be used inside <Drawer />')
  }

  return contextValue
}

export const DrawerContextProvider: React.FC<{ value: DrawerContext }> = ({
  value,
  children,
}) => {
  return <ctx.Provider value={value}>{children}</ctx.Provider>
}

export default { DrawerContextProvider, useDrawer }

```


[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 drawer/react/Drawer.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, {
  Suspense,
  useReducer,
  MouseEventHandler,
  useMemo,
  useState,
  useEffect,
} from 'react'
import { defineMessages } from 'react-intl'
import { IconMenu } from 'vtex.store-icons'
import { useCssHandles } from 'vtex.css-handles'
import { useChildBlock, ExtensionPoint } from 'vtex.render-runtime'
import { usePixelEventCallback, PixelEventTypes } from 'vtex.pixel-manager'
import {
  MaybeResponsiveValue,
  useResponsiveValue,
} from 'vtex.responsive-values'

import Portal from './Portal'
import Overlay from './Overlay'
import useLockScroll from './modules/useLockScroll'
import DrawerCloseButton from './DrawerCloseButton'
import { DrawerContextProvider } from './DrawerContext'
import { isElementInsideLink } from './modules/isElementInsideLink'

const Swipable = React.lazy(() => import('./Swipable'))

interface MenuState {
  isOpen: boolean
  hasBeenOpened: boolean
}

interface MenuAction {
  type: 'open' | 'close'
}

const initialMenuState: MenuState = {
  isOpen: false,
  hasBeenOpened: false,
}

type Position = 'left' | 'right' | 'up' | 'down'
type SlideDirection = 'vertical' | 'horizontal' | 'rightToLeft' | 'leftToRight'
type Height = '100%' | 'auto' | 'fullscreen'
type Width = '100%' | 'auto'
type BackdropMode = 'visible' | 'none'
type RenderingStrategy = 'lazy' | 'eager'

interface Props {
  actionIconId?: string
  dismissIconId?: string
  position: Position
  width?: Width
  height?: Height
  slideDirection?: SlideDirection
  isFullWidth?: boolean
  maxWidth?: number | string
  children: React.ReactNode
  customIcon?: React.ReactElement
  header?: React.ReactElement
  backdropMode?: MaybeResponsiveValue<BackdropMode>
  renderingStrategy?: RenderingStrategy
  customPixelEventId?: PixelEventTypes.PixelData['id']
  customPixelEventName?: PixelEventTypes.PixelData['event']
  onVisibilityChanged?: (visible: boolean) => void
  zIndex?: number
}

function menuReducer(state: MenuState, action: MenuAction) {
  switch (action.type) {
    case 'open':
      return {
        ...state,
        isOpen: true,
        hasBeenOpened: true,
      }

    case 'close':
      return {
        ...state,
        isOpen: false,
      }

    default:
      return state
  }
}

const useMenuState = () => {
  const [state, dispatch] = useReducer(menuReducer, initialMenuState)
  const setLockScroll = useLockScroll()

  const setMenuOpen = (value: boolean) => {
    dispatch({ type: value ? 'open' : 'close' })
    setLockScroll(value)
  }

  const openMenu = () => setMenuOpen(true)
  const closeMenu = () => setMenuOpen(false)

  return {
    state,
    openMenu,
    closeMenu,
  }
}

const CSS_HANDLES = [
  'openIconContainer',
  'drawer',
  'opened',
  'closed',
  'moving',
  'drawerContent',
  'childrenContainer',
  'closeIconContainer',
] as const

function Drawer(props: Props) {
  const {
    width,
    header,
    children,
    customIcon,
    isFullWidth,
    maxWidth = 450,
    slideDirection = 'horizontal',
    backdropMode: backdropModeProp = 'visible',
    renderingStrategy = 'lazy',
    customPixelEventId,
    customPixelEventName,
    onVisibilityChanged,
    zIndex = 999,
  } = props

  const handles = useCssHandles(CSS_HANDLES)
  const backdropMode = useResponsiveValue(backdropModeProp)
  const hasTriggerBlock = Boolean(useChildBlock({ id: 'drawer-trigger' }))
  const hasHeaderBlock = Boolean(useChildBlock({ id: 'drawer-header' }))
  const { state: menuState, openMenu, closeMenu } = useMenuState()
  const { isOpen: isMenuOpen, hasBeenOpened: hasMenuBeenOpened } = menuState
  const [shouldRenderChildren, setShouldRenderChildren] = useState(
    renderingStrategy === 'eager'
  )

  const [isMoving, setIsMoving] = useState(false)

  // Always add the listener for 'openDrawer' events, since they're sent by
  // the drawer-trigger block.
  usePixelEventCallback({
    eventId: customPixelEventId,
    handler: openMenu,
    eventName: 'openDrawer',
  })

  usePixelEventCallback({
    eventId: customPixelEventId,
    handler: openMenu,
    eventName: customPixelEventName,
  })

  useEffect(() => {
    if (onVisibilityChanged !== undefined) {
      onVisibilityChanged(isMenuOpen)
    }
  }, [onVisibilityChanged, isMenuOpen])

  const handleContainerClick: MouseEventHandler<HTMLElement> = event => {
    // target is the clicked element
    // currentTarget is the element which was attached the event (e.g. the container)
    const { target, currentTarget } = event

    if (isElementInsideLink(target as HTMLElement, currentTarget)) {
      closeMenu()
    }
  }

  const direction =
    slideDirection === 'horizontal' || slideDirection === 'leftToRight'
      ? 'left'
      : 'right'

  const swipeHandler = direction === 'left' ? 'onSwipeLeft' : 'onSwipeRight'

  const contextValue = useMemo(
    () => ({
      isOpen: isMenuOpen,
      open: openMenu,
      close: closeMenu,
    }),
    [isMenuOpen, openMenu, closeMenu]
  )

  const overlayVisible = backdropMode === 'visible' && isMenuOpen

  useEffect(() => {
    if (isMenuOpen || hasMenuBeenOpened || renderingStrategy === 'eager') {
      setShouldRenderChildren(true)
    }
  }, [
    hasMenuBeenOpened,
    renderingStrategy,
    setShouldRenderChildren,
    isMenuOpen,
  ])

  return (
    <DrawerContextProvider value={contextValue}>
      <div
        role="button"
        aria-hidden={isMenuOpen ? 'false' : 'true'}
        aria-expanded={isMenuOpen}
        aria-label={isMenuOpen ? 'close drawer' : 'open drawer'}
        tabIndex={isMenuOpen ? 0 : -1}
        onClick={openMenu}
        onKeyDown={e => {
          if (
            isMenuOpen &&
            (e.key === 'Enter' || e.key === ' ' || e.key === 'Escape')
          ) {
            e.preventDefault()
            openMenu()
          }
        }}
      >
        {hasTriggerBlock ? (
          <ExtensionPoint id="drawer-trigger" />
        ) : (
          customIcon ?? <IconMenu size={20} />
        )}
      </div>
      <Portal>
        <Overlay visible={overlayVisible} onClick={closeMenu} zIndex={zIndex} />
        <Suspense fallback={<React.Fragment />}>
          <Swipable
            {...{
              [swipeHandler]: closeMenu,
            }}
            enabled={isMenuOpen}
            position={isMenuOpen ? 'center' : direction}
            allowOutsideDrag
            onUpdateOffset={value => {
              setIsMoving(!(value === '0%' || value === '-100%'))
            }}
            className={`${handles.drawer} ${
              isMenuOpen ? handles.opened : handles.closed
            } ${isMoving ? handles.moving : ''} ${
              direction === 'right' ? 'right-0' : 'left-0'
            } fixed top-0 bottom-0 bg-base z-999 flex flex-column`}
            style={{
              width: width ?? (isFullWidth ? '100%' : '85%'),
              maxWidth,
              minWidth: 280,
              pointerEvents: isMenuOpen ? 'auto' : 'none',
              zIndex,
            }}
          >
            <div
              className={`${handles.drawerContent} overflow-y-auto`}
              style={{
                WebkitOverflowScrolling: 'touch',
              }}
            >
              {hasHeaderBlock ? (
                <ExtensionPoint id="drawer-header" />
              ) : (
                header ?? (
                  <div className={`flex ${handles.closeIconContainer}`}>
                    <DrawerCloseButton />
                  </div>
                )
              )}
              {/* The onClick handler below is done to fix a bug regarding drawers that wouldn't close when
               * navigating to the same page (e.g. from a search result page to another). It is not an element
               * intended to be clicked directly, so there's probably no need for it to have a role and to
               * handle keyboard events specifically */}
              {/* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
              <div
                className={`${handles.childrenContainer} flex flex-grow-1`}
                onClick={handleContainerClick}
              >
                {shouldRenderChildren ? children : <></>}
              </div>
              {/* eslint-enable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
            </div>
          </Swipable>
        </Suspense>
      </Portal>
    </DrawerContextProvider>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.drawer.title',
  },
})

Drawer.schema = {
  title: messages.title.id,
}

export default Drawer

```


[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 drawer/react/DrawerHeader.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = ['drawerHeader'] as const

const DrawerHeader: React.FC = ({ children }) => {
  const handles = useCssHandles(CSS_HANDLES)

  return <div className={`flex ${handles.drawerHeader}`}>{children}</div>
}

export default DrawerHeader

```


[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 drawer/react/package.json from the drawer VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "@vtex/css-handles": "^1.1.3",
    "apollo-client": "^2.4.7",
    "classnames": "^2.2.6",
    "graphql": "^14.0.2",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-intl": "^4.5.1"
  },
  "devDependencies": {
    "@types/classnames": "^2.2.7",
    "@types/jest": "^25.1.3",
    "@types/react": "^16.8.14",
    "@types/react-dom": "^16.8.4",
    "@vtex/test-tools": "^3.0.0",
    "typescript": "3.9.7",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.9.0/public/@types/vtex.pixel-manager",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.135.1/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.store-icons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons"
  },
  "version": "0.18.3"
}

```


[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 drawer/react/DrawerTrigger.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { usePixel, PixelEventTypes } from 'vtex.pixel-manager'
import { useCssHandles } from 'vtex.css-handles'

interface Props {
  customPixelEventId?: string
}

const CSS_HANDLES = ['drawerTriggerContainer'] as const

const DrawerTrigger: React.FC<Props> = ({ children, customPixelEventId }) => {
  const { push } = usePixel()
  const handles = useCssHandles(CSS_HANDLES)

  const handleInteraction = () => {
    if (!customPixelEventId) {
      return
    }

    const pixelEvent: PixelEventTypes.PixelData = {
      id: customPixelEventId,
      event: 'openDrawer',
    }

    push(pixelEvent)
  }

  return (
    <div
      role="button"
      tabIndex={0}
      className={handles.drawerTriggerContainer}
      onClick={handleInteraction}
      onKeyDown={handleInteraction}
    >
      {children}
    </div>
  )
}

export default DrawerTrigger

```


[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 drawer/react/Portal.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import ReactDOM from 'react-dom'
import { useSSR } from 'vtex.render-runtime/react/components/NoSSR'

const Portal: React.FunctionComponent = ({ children }) => {
  const body = window?.document?.body
  const isSSR = useSSR()

  if (!body || isSSR) {
    return null
  }

  return ReactDOM.createPortal(children, body)
}

export default Portal

```


[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 drawer/react/Swipable.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

import { animate } from './modules/animation'
import parseMeasure from './modules/parseMeasure'
import getPointerPosition from './modules/getPointerPosition'

const CENTER = 'center'
const LEFT = 'left'
const RIGHT = 'right'

type Position = 'center' | 'left' | 'right'

interface Props {
  children: React.ReactElement
  onSwipeLeft: () => void
  onSwipeRight: () => void
  onTriggerChange: (
    args: {
      type: string
      speed: number
    } | null
  ) => void
  onLockScroll: () => void
  onUnlockScroll: () => void
  onDragStart: () => void
  onDragEnd: () => void
  onSetPosition: (args: {
    element: React.ReactElement | HTMLDivElement
    offset: number | string
  }) => void
  onUpdateOffset: (offset: number | string) => void
  threshold: number
  enabled: boolean
  rubberBanding: boolean
  element: React.ReactElement
  position: Position
  className: string
  style: Record<string, unknown>
  positionRight: number | string
  positionLeft: number | string
  preserveMomentum: boolean
  allowOutsideDrag: boolean
}

export default class Swipable extends React.Component<Props> {
  private dragContainer: React.RefObject<HTMLDivElement>
  private dragStartPos: { x: number; y: number }
  private isDragging: boolean
  private isPointerDown: boolean
  private isScrolling: boolean
  private momentum: number | null
  private momentumTimeout: NodeJS.Timeout | number | null
  private offset: string | number
  private offsetAnimation: { value: number | string }
  private stopAnimation: () => void
  private wasDragging: boolean
  private willTrigger: {
    type: string
    speed: number
  } | null

  private previousDragPositions: Array<{
    x: number
    y: number
    source: string
    timeStamp: number
  }>

  public static defaultProps = {
    onSwipeLeft: null,
    leftTargetPosition: null,
    onSwipeRight: null,
    rightTargetPosition: null,
    onTriggerChange: null,
    position: CENTER,
    onLockScroll: () => {},
    onUnlockScroll: () => {},
    onDragStart: () => {},
    onDragEnd: () => {},
    onSetPosition: ({
      element,
      offset,
    }: {
      element: HTMLDivElement
      offset: number
    }) => {
      const unit = typeof offset === 'number' ? 'px' : ''

      element.style.transform = `translate3d(${offset}${unit},0,0)`
    },
    onUpdateOffset: () => {},
    element: null,
    threshold: 0,
    enabled: true,
    rubberBanding: false,
    style: {},
    positionRight: '100%',
    positionLeft: '-100%',
    preserveMomentum: true,
    allowOutsideDrag: false,
  }

  constructor(props: Props) {
    super(props)

    this.dragContainer = React.createRef()

    this.stopAnimation = () => {}
    this.isPointerDown = false
    this.isDragging = false
    this.isScrolling = false

    /* Used for the click event handler, which is
     * fired after mouseup is fired.
     * See comment on handleClick function */
    this.wasDragging = false

    this.offset = this.getOffsetFromPosition()
    this.offsetAnimation = { value: this.offset }
    this.momentum = null
    this.momentumTimeout = null
    this.dragStartPos = {
      x: 0,
      y: 0,
    }
    this.previousDragPositions = []
    this.willTrigger = null
  }

  public componentDidMount() {
    if (!window || !window.document) {
      return
    }

    window.document.addEventListener('mousedown', this.handleDragStart)
    window.document.addEventListener('touchstart', this.handleDragStart)
    window.document.addEventListener('mousemove', this.handleDragMove)
    window.document.addEventListener('touchmove', this.handleDragMove)
    window.document.addEventListener('mouseup', this.handleDragEnd)
    window.document.addEventListener('touchend', this.handleDragEnd)
    window.document.addEventListener('click', this.handleClick, {
      capture: true,
    })
  }

  public componentWillUnmount() {
    if (!window || !window.document) {
      return
    }

    window.document.removeEventListener('mousedown', this.handleDragStart)
    window.document.removeEventListener('touchstart', this.handleDragStart)
    window.document.removeEventListener('mousemove', this.handleDragMove)
    window.document.removeEventListener('touchmove', this.handleDragMove)
    window.document.removeEventListener('mouseup', this.handleDragEnd)
    window.document.removeEventListener('touchend', this.handleDragEnd)
    window.document.removeEventListener('click', this.handleClick, {
      capture: true,
    })
  }

  /* Prevents click events from firing in the event of
   * firing swipe events. */
  private handleClick = (event: Event) => {
    if (this.wasDragging || this.isPointerDown) {
      event.preventDefault()
      event.stopPropagation()
    }

    this.wasDragging = false
  }

  public componentDidUpdate(prevProps: Props) {
    if (prevProps.enabled && !this.props.enabled && this.isPointerDown) {
      this.isPointerDown = false
    }

    if (prevProps.position !== this.props.position) {
      this.updatePosition()
    }
  }

  private updatePosition = () => {
    if (this.momentumTimeout) {
      clearTimeout(this.momentumTimeout as number)
      this.momentumTimeout = null
    }

    this.offsetAnimation.value = this.offset
    animate({
      object: this.offsetAnimation,
      prop: 'value',
      target: this.getOffsetFromPosition(),
      ...(this.momentum
        ? { speed: this.momentum, acceleration: 1.25 }
        : { duration: 0.25 }),
      onUpdate: (value: string) => {
        this.setOffset(value)
      },
    })

    this.momentum = null
  }

  private getOffsetFromPosition = () => {
    switch (this.props.position) {
      case 'center':
        return 0

      case 'right':
        return this.props.positionRight

      case 'left':
        return this.props.positionLeft

      default:
        return 0
    }
  }

  private handleDragStart = (event: MouseEvent | TouchEvent) => {
    if (this.isPointerDown || !this.props.enabled) {
      return
    }

    if (
      !this.props.allowOutsideDrag &&
      !this.dragContainer.current?.contains(event.target as Node)
    ) {
      return
    }

    const pos = getPointerPosition(event)

    if (pos === null) return

    this.isPointerDown = true
    this.isScrolling = false
    this.isDragging = false
    this.stopAnimation()
    this.dragStartPos = {
      ...pos,
    }
    this.previousDragPositions = [pos]
    this.willTrigger = null
    this.dispatchTriggerChange(this.willTrigger)
  }

  /** Lets the parent know that a swipe event will be triggered if the cursor
   * is released. Useful for displaying UI feedback */
  private dispatchTriggerChange = (
    willTrigger: {
      type: string
      speed: number
    } | null
  ) => {
    const { onTriggerChange } = this.props

    if (onTriggerChange) {
      onTriggerChange(willTrigger)
    }
  }

  private handleDragMove = (event: TouchEvent | MouseEvent) => {
    const {
      onDragStart,
      onLockScroll,
      onSwipeLeft,
      onSwipeRight,
      enabled,
      rubberBanding,
    } = this.props

    if (!this.isPointerDown || this.isScrolling) {
      return
    }

    const pos = getPointerPosition(event)

    if (pos === null) return

    const lastPos =
      this.previousDragPositions[this.previousDragPositions.length - 1]

    if (lastPos && pos.source !== lastPos.source) {
      return
    }

    /* Values to determine if the dragging means either a swipe or a scroll */
    const threshold = {
      x: 15,
      y: 10,
    }

    const distance = {
      x: pos.x - this.dragStartPos.x,
      y: pos.y - this.dragStartPos.y,
    }

    if (!this.isDragging) {
      if (Math.abs(distance.x) >= threshold.x) {
        this.isDragging = true
        onDragStart()
        onLockScroll()
      } else if (Math.abs(distance.y) >= threshold.y) {
        this.isScrolling = true
      }
    } else {
      this.offset = distance.x

      /** Either applies rubberbanding or stops dragging at the limits */
      const limitDragging = (offset: number) => {
        const RUBBER_BANDING_MULTIPLIER = 0.3

        return rubberBanding ? offset * RUBBER_BANDING_MULTIPLIER : 0
      }

      if (!enabled || (!onSwipeLeft && this.offset < 0)) {
        this.offset = limitDragging(this.offset)
      } else if (!enabled || (!onSwipeRight && this.offset > 0)) {
        this.offset = limitDragging(this.offset)
      }

      this.setOffset(this.offset)
      this.previousDragPositions.push(pos)

      const willTrigger = this.checkTrigger()

      // eslint-disable-next-line eqeqeq
      if (this.willTrigger != willTrigger) {
        this.dispatchTriggerChange(willTrigger)
      }

      this.willTrigger = willTrigger
    }
  }

  private setOffset = (offset: number | string) => {
    if (this.dragContainer?.current) {
      this.props.onSetPosition({
        element: this.props.element || this.dragContainer.current,
        offset,
      })
      this.props.onUpdateOffset(offset)
    }

    this.offset = offset
  }

  private setMomentum = (momentum: number, target: number | string) => {
    const [, targetUnit] = parseMeasure(target) ?? []

    if (this.dragContainer.current == null) return

    if (targetUnit === '%') {
      const bounds = this.dragContainer.current.getBoundingClientRect()
      const { width } = bounds

      this.offset = `${(Number(this.offset) / width) * 100}%`
      momentum = (momentum / width) * 100
    }

    this.momentum = momentum

    /* Lets momentum live only for a brief time. If position changes in this meantime,
     * then momentum is applied. Otherwise it's ignored and a regular transition is done */
    if (this.momentumTimeout) {
      clearTimeout(this.momentumTimeout as number)
    }

    this.momentumTimeout = setTimeout(() => {
      this.momentum = null
      this.momentumTimeout = null
    }, 100)
  }

  /** Checks if the mouse/touch movement at the time of release triggers a
   * swipe, and if so, to which direction */
  private checkTrigger = () => {
    if (!this.props.enabled) {
      return null
    }

    /* Checks the last $samples cursor positions to determine the
     * average speed and direction of movement */
    const samples = 6
    const fps = 60
    const releaseSpeed =
      this.previousDragPositions
        .slice(-samples)
        .map((cur, i, arr) => {
          const last = arr[i - 1]

          if (last == null) {
            return null
          }

          return cur.x - last.x
        })
        .filter(cur => cur != null)
        .reduce((sum: number, cur) => sum + (cur ?? 0) / samples, 0) * fps

    const { onSwipeLeft, onSwipeRight } = this.props

    const triggers = {
      left:
        onSwipeLeft != null &&
        releaseSpeed < 0 &&
        typeof this.offset === 'number' &&
        this.offset < -this.props.threshold,
      right:
        onSwipeRight != null &&
        releaseSpeed > 0 &&
        typeof this.offset === 'number' &&
        this.offset > this.props.threshold,
    }

    if (triggers.left) {
      return {
        type: LEFT,
        speed: releaseSpeed,
      }
    }

    if (triggers.right) {
      return {
        type: RIGHT,
        speed: releaseSpeed,
      }
    }

    return null
  }

  private handleDragEnd = (event: Event) => {
    if (this.isPointerDown && this.isDragging) {
      event.preventDefault()
      event.stopPropagation()
      const trigger = this.checkTrigger()

      if (trigger) {
        switch (trigger.type) {
          case LEFT:
            if (this.props.preserveMomentum) {
              this.setMomentum(trigger.speed, this.props.positionLeft)
            }

            this.props.onSwipeLeft()
            break

          case RIGHT:
            if (this.props.preserveMomentum) {
              this.setMomentum(trigger.speed, this.props.positionRight)
            }

            this.props.onSwipeRight()
            break

          default:
            break
        }
      } else {
        this.offsetAnimation.value = this.offset
        animate({
          object: this.offsetAnimation,
          prop: 'value',
          target: 0,
          duration: 0.2,
          onUpdate: (value: string) => {
            this.setOffset(value)
          },
        })
      }

      this.props.onDragEnd()
      this.props.onUnlockScroll()
    }

    this.isScrolling = false
    this.wasDragging = this.isPointerDown && this.isDragging
    this.isPointerDown = false
  }

  public render() {
    return (
      <div
        aria-hidden={this.props.enabled ? 'false' : 'true'}
        ref={this.dragContainer}
        style={{
          ...this.props.style,
          transform: `translate3d(${this.getOffsetFromPosition()}, 0, 0)`,
        }}
        className={this.props.className}
      >
        {this.props.children}
      </div>
    )
  }
}

```


[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 drawer/react/Overlay.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles, applyModifiers } from 'vtex.css-handles'

interface Props {
  visible: boolean
  onClick(event: React.MouseEvent | React.TouchEvent): void
  zIndex?: number
}

const CSS_HANDLES = ['overlay'] as const

const Overlay: React.ForwardRefRenderFunction<HTMLDivElement, Props> = (
  { visible, onClick, zIndex = 999 }: Props,
  ref
) => {
  const handles = useCssHandles(CSS_HANDLES)
  const ariaHidden = visible ? 'false' : 'true'

  return (
    <div
      ref={ref}
      aria-hidden={ariaHidden}
      role="presentation"
      onClick={onClick}
      style={{
        opacity: visible ? 0.5 : 0,
        pointerEvents: visible ? 'auto' : 'none',
        zIndex,
      }}
      className={`${applyModifiers(
        handles.overlay,
        visible ? 'visible' : ''
      )} bg-base--inverted z-999 fixed top-0 bottom-0 left-0 right-0`}
    />
  )
}

export default React.forwardRef(Overlay)

```


[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 drawer/store/blocks.json from the drawer VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "drawer": {
    "blocks": ["drawer-header"]
  },
  "drawer-header": {
    "children": ["drawer-close-button"]
  }
}

```


[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 drawer/store/interfaces.json from the drawer VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "drawer": {
    "component": "Drawer",
    "composition": "children",
    "allowed": ["drawer-trigger", "drawer-header"]
  },
  "drawer-trigger": {
    "component": "DrawerTrigger",
    "composition": "children"
  },
  "drawer-header": {
    "component": "DrawerHeader",
    "composition": "children"
  },
  "drawer-close-button": {
    "component": "DrawerCloseButton"
  }
}

```


[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 drawer/react/typings/vtex.responsive-values.d.ts from the drawer VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.responsive-values' {
  interface ResponsiveValue<T> {
    tablet?: T
    phone?: T
    desktop?: T
    mobile?: T
  }

  type MaybeResponsiveValue<T> = ResponsiveValue<T> | T
  const useResponsiveValue: <T>(value: MaybeResponsiveValue<T>) => T
}

```


[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 drawer/react/modules/getPointerPosition.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
function isMouseEvent(event: TouchEvent | MouseEvent): event is MouseEvent {
  return !!(event as MouseEvent).clientX
}

function isTouchEvent(event: TouchEvent | MouseEvent): event is TouchEvent {
  return 'touches' in event
}

export default function getPointerPosition(event: TouchEvent | MouseEvent) {
  if (isMouseEvent(event)) {
    return {
      x: event.clientX,
      y: event.clientY,
      source: 'mouse',
      timeStamp: event.timeStamp,
    }
  }

  if (!isTouchEvent(event)) {
    return null
  }

  // eslint-disable-next-line prefer-destructuring
  const touch = event.touches[0]

  return {
    x: touch.clientX,
    y: touch.clientY,
    source: 'touch',
    timeStamp: event.timeStamp,
  }
}

```


[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 drawer/react/modules/animation.ts from the drawer VTEX app.

[Assistant]
Here's the implementation:

```typescript
import parseMeasure, { Measure } from './parseMeasure'

interface Animation {
  prop: string
  object: { [prop: string]: Measure }
  isStopped: () => boolean
  stop: () => void
}

const animations: Animation[] = []

const createAnimation = ({
  object,
  prop,
  stop,
  isStopped,
}: Animation): Animation => ({
  object,
  prop,
  stop,
  isStopped,
})

const stopConflictingAnimations = (animation: Animation) =>
  animations.filter(cur => {
    const isConflicting =
      cur.object === animation.object && cur.prop === animation.prop

    if (isConflicting) {
      cur.stop()
    }

    return !cur.isStopped()
  })

interface AnimationOptions {
  object: { [prop: string]: Measure }
  prop: string
  target: Measure
  duration?: number
  speed?: number
  acceleration?: number
  maxSpeed?: number
  onUpdate?: (value: string) => void
  onComplete?: () => void
}

export function animate({
  object,
  prop,
  target,
  duration,
  speed,
  acceleration,
  maxSpeed,
  onUpdate = undefined,
  onComplete = undefined,
}: AnimationOptions) {
  const targetFps = 60
  const frameDuration = 1000 / targetFps

  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const [targetValue, targetUnit, isTargetUnitless] = parseMeasure(target)!
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const [originValue, originUnit] = parseMeasure(object[prop])!
  const unit = isTargetUnitless ? originUnit : targetUnit
  const delta = targetValue - originValue

  const ease = (v: number) => v * (2 - v)
  const maxTimeMultiplier = 2

  let stopped = false

  const stop = () => {
    stopped = true
  }

  const isStopped = () => {
    return stopped
  }

  let current = duration ? 0 : originValue
  let last: number | null | undefined = null

  const update = (now?: number) => {
    if (stopped) return
    let timeMultiplier = 1

    if (last != null) {
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      const deltaTime = now! - last

      timeMultiplier = deltaTime / frameDuration
      if (timeMultiplier > maxTimeMultiplier) timeMultiplier = maxTimeMultiplier
    }

    last = now

    if (duration) {
      const step = frameDuration / (duration * 1000)

      current += step * timeMultiplier
      if (current >= 1) {
        current = 1
        if (onComplete != null) {
          onComplete()
        }

        stop()
      }

      const value = `${originValue + ease(current) * delta}${unit}`

      object[prop] = value

      if (onUpdate != null) {
        onUpdate(value)
      }
    } else if (speed) {
      current += speed / (targetFps * timeMultiplier)

      if (acceleration) {
        speed *= acceleration
      }

      if (maxSpeed && speed > maxSpeed) {
        speed = maxSpeed
      }

      if (
        (speed > 0 && current >= targetValue) ||
        (speed < 0 && current <= targetValue)
      ) {
        current = targetValue
        if (onComplete != null) {
          onComplete()
        }

        stop()
      }

      const formattedValue = `${current}${unit}`

      object[prop] = formattedValue

      if (onUpdate != null) {
        onUpdate(formattedValue)
      }
    }

    requestAnimationFrame(update)
  }

  update()

  const animation = createAnimation({ object, prop, stop, isStopped })

  stopConflictingAnimations(animation)

  animations.push(animation)

  return stop
}

```


[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 drawer/react/modules/isElementInsideLink.ts from the drawer VTEX app.

[Assistant]
Here's the implementation:

```typescript
// This is a totally valid use case for any, eslint.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isHTMLElement(x: any): x is HTMLElement {
  return 'tagName' in x
}

function isLink(element: HTMLElement): element is HTMLAnchorElement {
  return String(element.tagName).toUpperCase() === 'A'
}

export function isElementInsideLink(
  node: HTMLElement | null,
  limit?: HTMLElement
): boolean {
  if (!node || !isHTMLElement(node)) {
    return false
  }

  if (isLink(node)) {
    return true
  }

  const { parentNode } = node

  if (
    !parentNode ||
    !isHTMLElement(parentNode) ||
    parentNode.tagName.toUpperCase() === 'BODY' ||
    (limit && parentNode === limit)
  ) {
    return false
  }

  return isElementInsideLink(parentNode, limit)
}

```


[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 drawer/react/modules/parseMeasure.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
export type Measure = number | string

type Value = number
type Unit = string
type IsUnitless = boolean

type ParsedMeasure = [Value, Unit, IsUnitless]

function parseMeasure(value: Measure): ParsedMeasure | null {
  if (typeof value === 'number') {
    return [value, 'px', true]
  }

  const matchResult = value.match(/([-\d]*)([^0-9\n]+)/)

  if (!matchResult) {
    return null
  }

  const [, parsedValue, parsedUnit] = matchResult

  return [parseInt(parsedValue, 10), parsedUnit, false]
}

export default parseMeasure

```


[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 drawer/react/modules/useLockScroll.tsx from the drawer VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useRef, useState, useEffect } from 'react'

const useLockScroll = () => {
  const [locked, setLocked] = useState(false)
  const prevScroll = useRef('')

  useEffect(() => {
    if (locked) {
      prevScroll.current = document.body.style.overflow
    }

    document.body.style.overflow = locked ? 'hidden' : prevScroll.current

    return () => {
      if (locked) {
        document.body.style.overflow = prevScroll.current
      }
    }
  }, [locked])

  return setLocked
}

export default useLockScroll

```


[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 shopper-location-availability-theme/sitemap/sitemap.json from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "urlset": {
    "url": [
      {
        "loc": "https://storetheme.vtex.com/about-us"
      }
    ]
  }
}
```


[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 shopper-location-availability-theme/docs/README.md from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Store theme
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Our boilerplate theme to create stores in the VTEX IO platform.

## Preview
![store-theme-default](https://user-images.githubusercontent.com/1354492/63937047-e8d81c80-ca37-11e9-86fc-61e88847bbfb.png)

## Tutorial
To understand how things work check our tutorial [Build a store using VTEX IO](https://vtex.io/docs/getting-started/build-stores-with-store-framework/1/)

## Dependencies
All store components that you see on this document are open source too. Production ready, you can found those apps in this GitHub organization.

Store framework is the baseline to create any store using _VTEX IO Web Framework_.
- [Store](https://github.com/vtex-apps/store/blob/master/README.md)

Store GraphQL is a middleware to access all VTEX APIs.
- [Store GraphQL](https://github.com/vtex-apps/store-graphql/blob/master/docs/README.md)

### Store Component Apps
- [Header](https://github.com/vtex-apps/store-header/blob/master/docs/README.md)
- [Footer](https://github.com/vtex-apps/store-footer/blob/master/docs/README.md)
- [Slider Layout](https://github.com/vtex-apps/slider-layout/blob/master/docs/README.md)
- [Shelf](https://github.com/vtex-apps/shelf/blob/master/docs/README.md)
- [Telemarketing](https://github.com/vtex-apps/telemarketing/blob/master/docs/README.md)
- [Menu](https://github.com/vtex-apps/menu/blob/master/docs/README.md)
- [Login](https://github.com/vtex-apps/login/blob/master/docs/README.md)
- [Minicart](https://github.com/vtex-apps/minicart/blob/master/docs/README.md)
- [Category Menu](https://github.com/vtex-apps/category-menu/blob/master/docs/README.md)
- [Product Summary](https://github.com/vtex-apps/product-summary/blob/master/docs/README.md)
- [Breadcrumb](https://github.com/vtex-apps/breadcrumb/blob/master/docs/README.md)
- [Search Result](https://github.com/vtex-apps/search-result/blob/master/docs/README.md)
- [Product Details](https://github.com/vtex-apps/product-details/blob/master/docs/README.md)
- [Store Components](https://github.com/vtex-apps/store-components/blob/master/docs/README.md)
- [Order Placed](https://github.com/vtex-apps/order-placed/blob/master/docs/README.md)

### Store Pixel Apps

 - [Facebook Pixel](https://github.com/vtex-apps/facebook-pixel/blob/master/docs/README.md)
 - [Google Tag Manager](https://github.com/vtex-apps/google-tag-manager/blob/master/docs/README.md)

## Contributing

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

## 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="http://www.hugoccosta.com"><img src="https://avatars2.githubusercontent.com/u/20212776?v=4" width="100px;" alt=""/><br /><sub><b>Hugo Costa</b></sub></a><br /><a href="https://github.com/vtex-apps/store-theme/commits?author=hugocostadev" title="Documentation">📖</a></td>
  </tr>
</table>

<!-- markdownlint-enable -->
<!-- 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!

```


[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 shopper-location-availability-theme/docs/contact-schema.json from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "title": "Contact",
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "title": "Title"
    },
    "name": {
      "type": "string",
      "title": "Name"
    },
    "email": {
      "type": "string",
      "format": "email",
      "title": "Email address"
    },
    "message": {
      "type": "string",
      "title": "Message"
    }
  },
  "required": ["email", "message"],
  "v-security": {
    "publicJsonSchema": true
  }
}

```


[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 shopper-location-availability-theme/store/blocks.jsonc from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```json
/* Blocks can be defined both on the store/blocks.json file, and in any number of json
 * files inside the store/blocks directory, with any arbitrary directory structure.
 *
 * Additionally, all blocks files can support comments, such as this one, if given the
 * .jsonc file extension.
 *
 * The store/blocks.json file is intended for backwards compatibility, for miscellaneous
 * blocks, or if the app is simple enough that it doesn't warrant splitting the file.
 */
{
  "store.orderplaced": {
    "blocks": ["order-placed"]
  },

  "store.account": {
    "blocks": ["my-account"],
    "parent": {
      "challenge": "challenge.profile"
    }
  },

  "store.login": {
    "blocks": ["login-content#default"]
  },

  "login-content#default": {
    "props": {
      "isInitialScreenOptionOnly": false,
      "defaultOption": 1,
      "showPasswordVerificationIntoTooltip": true
    }
  },

  "store.product-review-form": {
    "blocks": ["product-review-form"]
  },

  "store.not-found#product": {
    "blocks": ["rich-text#not-found"]
  },

  "store.not-found#search": {
    "blocks": ["rich-text#not-found"]
  },

  "rich-text#not-found": {
    "props": {
      "textAlignment": "CENTER",
      "textPosition": "CENTER",
      "text": "**PAGE NOT FOUND**",
      "font": "t-heading-1"
    }
  },
  "shopper-location": {
    "children": [
      "modal-trigger#address"
    ],
    "props": {
      "autofill": [
        "city",
        "country",
        "neighborhood",
        "number",
        "postalCode",
        "state",
        "street"
      ]
    }
  },
  "modal-trigger#address": {
    "children": [
      "user-address",
      "modal-layout#address"
    ]
  },
  "user-address": {
    "props": {
      "variation": "bar",
      "showStreet": false,
      "showCityAndState": true,
      "showPostalCode": true,
      "showPrefix": false,
      "showIfEmpty": true
    }
  },
  "modal-layout#address": {
    "children": [
      "modal-header#address",
      "modal-content#address"
    ]
  },
  "modal-header#address": {
    "children": [
      "flex-layout.col#address-header"
    ]
  },
  "flex-layout.col#address-header": {
    "children": [
      "rich-text#address-header"
    ],
    "props": {
      "paddingLeft": 5
    }
  },
  "rich-text#address-header": {
    "props": {
      "text": "### Change Location"
    }
  },
  "modal-content#address": {
    "children": [
      "change-location"
    ]
  },
  "change-location": {
    "props": {
      "postalCode": "first",
      "autocomplete": true,
      "notRequired": [
        "street",
        "number",
        "city",
        "state"
      ],
      "hideFields": [
        "complement",
        "neighborhood",
        "receiverName",
        "reference"
      ]
    }
  }
}

```


[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 shopper-location-availability-theme/store/routes.json from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store.custom#about-us": {
    "path": "/about-us"
  },
  "store.custom#faq": {
    "path": "/faq"
  },
  "store.custom#contact-us": {
    "path": "/contact-us"
  }
}

```


[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 shopper-location-availability-theme/styles/css/vtex.store-video.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.videoContainer {
  width: 100%;
  height: 300px;
  margin-top: 2%;
}

@media only screen and (min-width: 640px) {
  .videoContainer {
    height: 700px;
  }
}

```


[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 shopper-location-availability-theme/styles/css/vtex.product-price.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.listPrice {
  color: #727273;
  margin-bottom: .25rem;
  font-size: 1rem;
}

.sellingPrice {
  color: #3f3f40;
  font-size: 1.25rem;
}

.sellingPriceValue {
  font-size: 2.25rem;
  font-weight: 700;
}

.installments {
  color: #727273;
  margin-bottom: 1rem;
}

.savings {
  font-weight: 500;
  color: #79B03A;
}

.sellingPriceValue--summary {
  font-size: 1.25rem;
  font-weight: 600;
  color: #2E2E2E;
}

.savings--summary {
  background: #8BC34A;
  border-radius: 1000px;
  align-items: center;
  display: flex;

  padding-left: 0.5rem;
  padding-right: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  vertical-align: baseline;
  color: #FFFFFF;
}

.savings-discount--summary {
  font-size: 0.875rem;
  font-weight: 600;
  vertical-align: baseline;
  color: #FFFFFF;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

.listPrice--summary {
  margin-bottom: 0.25rem;
  font-size: .875rem;
}

.installments--summary {
  margin-bottom: 2rem;
  font-size: 0.875rem;
}

.savings--summaryPercentage {
  background: #0f3e99;
  border-radius: 1000px;
  align-items: center;
  display: flex;
}

.savingsPercentage--summaryPercentage {
  font-size: 0.875rem;
  font-weight: 600;
  vertical-align: baseline;
  color: #FFFFFF;
  padding: 0.25rem 0.5rem 0.25rem 0.5rem;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.rich-text.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container--deals {
  color: #ffffff;
  text-align: center;
  justify-content: center;
}

.container--shelfTitle {
  color: #727273;
  justify-content: center;
  text-align: center;
}

.headingLevel2--shelfTitle {
  font-weight: 200;
}

.container--deals .paragraph {
  margin: 0;
}

.container--link {
  justify-content: center;
}

.container--question {
  justify-content: center;
}

.container--question .paragraph {
  text-align: center;
  max-width: 540px;
  margin: 0 16px;
  padding-top: 120px;
  color: #03034E;
}

.container--question .strong {
  font-size: 32px;
  line-height: 2rem;
  font-weight: 700;
}

.container--link .paragraph {
  text-align: center;
  max-width: 540px;
  padding-top: 36px;
  padding-bottom: 84px;
  color: #03034E;
}

.container--link .strong {
  font-size: 16px;
  font-weight: 700;
  text-transform: uppercase;
}

.container--link .link {
  text-decoration: none;
  font-size: 36px;
  font-weight: 300;
  color: #03034E;
}

.container--title {
  color: #03034E;
  font-size: 28px;
  font-weight: 700;
}

@media only screen and (min-width: 640px) {
  .container--question .strong {
    font-size: 40px;
    line-height: 3rem;
  }

  .container--about {
    max-width: 85%;
  }

  .container--title {
    color: #03034E;
    font-size: 40px;
    font-weight: 700;
    max-width: 60%;
  }

  .container--title .paragraph {
    line-height: 1.3em;
  }
}

```


[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 shopper-location-availability-theme/styles/css/vtex.product-summary.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.skuSelectorContainer--quickview .skuSelectorItemImage .frameAround, .skuSelectorContainer--quickview .skuSelectorItemImage .skuSelectorInternalBox {
  border-radius: 50%;
}

.container :global(.vtex-modal-layout-0-x-triggerContainer) {
  opacity: 0;
  transition: opacity 200ms ease-in-out;
}

.container:hover :global(.vtex-modal-layout-0-x-triggerContainer) {
  opacity: 1;
}

@media screen and (max-width: 40em) {
  .container :global(.vtex-modal-layout-0-x-triggerContainer) {
    display: none;
  }
}

.nameContainer {
  justify-content: start;
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.brandName {
  font-weight: 600;
  font-size: 18px;
  color: #2E2E2E;
}

.container {
  text-align: start;
}

.imageContainer {
  text-align: center;
}

.image {
  border-radius: 0.25rem;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.modal-layout.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
@media screen and (min-width: 40em) {
  .paper--quickview {
    height: 260px;
    width: 580px;
  }

  .actionsContainer--quickview {
    padding: 0 2rem 2rem 2rem;
  }
}

@media screen and (min-width: 50em) {
  .paper--quickview {
    height: 450px;
    width: 900px;
  }
}

@media screen and (min-width: 75em) {
  .paper--quickview {
    width: calc(100% - 4rem);
    height: auto;
  }
}

@media screen and (min-width: 82em) {
  .actionsContainer--quickview {
    padding: 0 2.5rem 2.5rem 2.5rem;
  }
}

.paper--quickview {
  min-width: 320px;
  max-width: 96rem;
}

.headerContainer--quickview {
  border: none;
  position: absolute;
  right: 0;
}

.actionsContainer--quickview {
  height: 100%;
  width: 100%;
  transition: box-shadow 150ms ease-in-out, border-top 150ms ease-in-out;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: transparent;
  box-shadow: -4px 0px 27px -12px transparent;
}

.actionsContentWrapper {
  border-top-width: 1px;
  border-top-style: solid;
  border-top-color: #aaa;
  padding-top: 1.5rem;
}

.contentContainer--quickviewContent {
  padding: 2.5rem 0 2.5rem 2rem;
  overflow-x: hidden;
}

.triggerContainer--quickview {
  padding: .75rem;
}

.triggerContainer {
  outline: none;
}

.actionsContainer--quickview:not(.actionsContainerEndOfContent--quickview) {
  border-top-color: rgb(238, 238, 238);
  box-shadow: -4px 0px 27px -12px rgba(0,0,0,0.64);
}

.actionsContainer--quickview:not(.actionsContainerEndOfContent--quickview) .actionsContentWrapper {
  border-top-color: transparent;
}

.closeButton {
  padding-right: 1rem;
}

.paper--product-gifts {
  padding: 1.5rem;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.store-header.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
/* add transitions */
:global(.vtex-sticky-layout-0-x-container)
  :global(.vtex-store-components-3-x-logoLink),
:global(.vtex-sticky-layout-0-x-container)
  :global(.vtex-minicart-2-x-openIconContainer),
:global(.vtex-sticky-layout-0-x-container)
  :global(.vtex-store-components-3-x-searchBarContainer) {
  transition: all 0.3s ease;
  display: block;
}

/* desktop/mobile main header padding and background transitions */
:global(.vtex-flex-layout-0-x-flexRowContent--main-header),
:global(.vtex-flex-layout-0-x-flexRowContent--main-header-mobile) {
  transition: background 0.3s ease;
  will-change: padding, background;
}

/* main header desktop has a bigger padding when not stuck */
:global(.vtex-flex-layout-0-x-flexRowContent--main-header) {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

/* add a box-shadow to desktop/mobile header when stuck */
:global(.vtex-sticky-layout-0-x-wrapper--stuck)
  :global(.vtex-flex-layout-0-x-flexRowContent--main-header),
:global(.vtex-sticky-layout-0-x-wrapper--stuck)
  :global(.vtex-flex-layout-0-x-flexRowContent--main-header-mobile) {
  box-shadow: 0 4px 5px rgba(0, 0, 0, 0.1);
}

/*
 * remove the extra padding when stuck from the desktop header
 * we add a transition only when "stuck" for the "unstick" step seem faster
 */
:global(.vtex-sticky-layout-0-x-wrapper--stuck)
  :global(.vtex-flex-layout-0-x-flexRowContent--main-header) {
  transition: padding 0.3s ease, background 0.3s ease;
  padding-top: 0;
  padding-bottom: 0;
}

/* if supported add some translucency to the desktop/mobile header background */
@supports (backdrop-filter: blur(5px)) {
  :global(.vtex-sticky-layout-0-x-wrapper--stuck)
    :global(.vtex-flex-layout-0-x-flexRowContent--main-header),
  :global(.vtex-sticky-layout-0-x-wrapper--stuck)
    :global(.vtex-flex-layout-0-x-flexRowContent--main-header-mobile) {
    backdrop-filter: blur(8px);
  }

  /* header background when stuck and not hovered */
  :global(.vtex-sticky-layout-0-x-wrapper--stuck):not(:hover)
    :global(.vtex-flex-layout-0-x-flexRowContent--main-header),
  :global(.vtex-sticky-layout-0-x-wrapper--stuck):not(:hover)
    :global(.vtex-flex-layout-0-x-flexRowContent--main-header-mobile) {
    background: rgba(240, 240, 240, 0.8);
  }
}

/* stick wrapper with the same color as the desktop/mobile header */
:global(.vtex-sticky-layout-0-x-wrapper--sticky-header) {
  background-color: #f0f0f0;
}

/* resize the logo for neat effect */
:global(.vtex-sticky-layout-0-x-wrapper--stuck)
  :global(.vtex-store-components-3-x-logoLink) {
  transform: scale(0.85);
}

@media (prefers-reduced-motion: reduce) {
  :global(.vtex-sticky-layout-0-x-container)
    :global(.vtex-store-components-3-x-logoLink),
  :global(.vtex-sticky-layout-0-x-container)
    :global(.vtex-minicart-2-x-openIconContainer),
  :global(.vtex-sticky-layout-0-x-container)
    :global(.vtex-store-components-3-x-searchBarContainer),
  :global(.vtex-sticky-layout-0-x-wrapper--stuck)
    :global(.vtex-flex-layout-0-x-flexRowContent--main-header) {
    transition: none;
  }
}

```


[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 shopper-location-availability-theme/styles/css/vtex.store-components.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.notificationBarContainer {
  background-color: #e6f1e6;
  color: #03034e;
  font-weight: 700;
  font-size: 12px;
  text-decoration: underline;
}

.infoCardContainer--info-card-home {
  max-width: 1520px;
  margin: 0 auto;
  background-color: #e6f1e6;
  padding: 0px;
}

.newsletter {
  background-color: #03054e;
  max-width: 1528px;
  margin: 0 auto;
}

.newsletter .container {
  padding: 60px 10px;
}

.label {
  color: #fff;
  font-size: 26px;
}

.inputGroup {
  padding-bottom: 4px;
  display: flex;
  color: #fff;
}

.inputGroup :global(.vtex-styleguide-9-x-hideDecorators) {
  background-color: transparent;
  color: #fff;
  border: none;
}

.inputGroup :global(.vtex-styleguide-9-x-hideDecorators)::placeholder {
  color: #fff;
  font-size: 16px;
}

.inputGroup :global(.vtex-button) {
  background-color: transparent;
  color: #fff;
  border: none;
  margin-right: -24px;
}

.buttonContainer {
  padding-top: 0px;
}

.imageElement--storePrint {
  max-height: 300px;
  margin-bottom: 20px;
}

.skuSelectorContainer {
  margin: 1rem 0;
}

@media only screen and (min-width: 640px) {
  .newsletter .container {
    padding: 140px;
  }
  .label {
     font-size: 40px;
  }
  .infoCardContainer--info-card-home .infoCardTextContainer {
    width: 30%;
  }
  .infoCardContainer--info-card-home .infoCardImageContainer {
    width: 70%;
  }
  .imageElement--storePrint {
    margin-bottom: 0px;
    max-height: 600px;
  }
}

.productImagesContainer--quickview .carouselContainer {
  justify-content: flex-start;
}

.productImagesContainer--quickview .productImageTag {
  object-fit: cover !important;
}

.productImagesContainer--quickview .carouselGaleryThumbs {
  display: none;
}

.productImagesContainer--quickview .carouselGaleryCursor {
  margin: 0;
  padding: 0;
  width: 100%;
}

.productNameContainer {
  color: #3f3f40;
  font-weight: bold;
  font-size: 30px;
}

.image {
  image-rendering: -webkit-optimize-contrast;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.store-footer.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.row--menu-row {
  padding-right: 24px;
}

.row--menu-row .rowContainer {
  align-items: flex-start;
}

.row--payment-methods {
  padding-top: 16px;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.product-identifier.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.product-identifier--productReference {
  margin-bottom: 1rem;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.reviews-and-ratings.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container {
  max-width: 96rem;
  padding-left: .5rem;
  padding-right: .5rem;
}

.inlineContainer {
  margin-left: 0rem;
}

.star--filled {
  color: #FFB100;
}

.star--empty {
  color: #FFB100;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.product-highlights.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.productHighlightWrapper--collection {
  position: absolute;
  top: 10px;
  left: 5px;
  width: 200px;
}

.productHighlightText {
  background: antiquewhite;
  border-radius: 20px;
  padding: 5px 10px;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.flex-layout.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.flexRowContent--menu-link,
.flexRowContent--main-header {
  padding: 0 0.5rem;
}

@media screen and (min-width: 40em) {
  .flexRowContent--menu-link,
  .flexRowContent--main-header {
    padding: 0 1rem;
  }
}

@media screen and (min-width: 80rem) {
  .flexRowContent--menu-link,
  .flexRowContent--main-header {
    padding: 0 0.25rem;
  }
}

.flexRowContent--menu-link {
  background-color: #03044e;
  color: #fff;
}

.flexRowContent--main-header {
  background-color: #f0f0f0;
}

.flexRowContent--main-header-mobile {
  align-items: center;
  padding: 0.625rem 0.5rem;
  background-color: #f0f0f0;
}

.flexRowContent--menu-link :global(.vtex-menu-2-x-styledLink) {
  color: #ffffff;
  font-size: 14px;
}

.flexRowContent--main-header :global(.vtex-menu-2-x-styledLink) {
  color: #727273;
  font-size: 14px;
}

.flexRow--deals {
  background-color: #0F3E99;
  padding: 14px 0px;
}

.flexRow--deals .stretchChildrenWidth {
  align-items: center;
}

.flexRow--deals .flexCol {
  align-items: center;
  margin-bottom: 5px;
  padding-top: 5px;
}

.flexCol--filterCol {
  max-width: 500px;
  min-width: 230px;
}

.flexCol--productCountCol {
  align-items: flex-start;
}

.flexCol--orderByCol {
  align-items: flex-end;
}

.flexCol--orderByMobileCol {
  width: 42%;
}

.flexCol--filterMobileCol {
  width: 38%;
}

.flexRow--quickviewMainRow {
  display: flex;
  max-height: 100%;
}

.flexColChild--quickviewDetails:first-child {
  overflow-y: auto;
  height: 66% !important;
  overflow-x: hidden;
}

.flexColChild--quickviewDetails:last-child {
  height: 34% !important;
}

.flexRow--addToCartRow {
  padding-bottom: 1rem;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.carousel.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.containerImg {
  background-color: #f0f0f0;
}

.containerImg .img {
  max-width: 100%;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.search-result.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.galleryLayoutOptionButton {
  background-color: #F0F0F0;
  color: #3F3F40;
  padding: 0.375rem 0.75rem 0.375rem 0.75rem;
}

.galleryLayoutOptionButton--selected {
  background-color: #3F3F40;
  color: #FFFFFF;
}

.galleryLayoutSwitcher {
  border-radius: 4px 4px 4px 4px;
  justify-content: center;
  overflow: hidden;
  width: auto !important;
  align-self: center
}

.galleryItem--list {
  border-bottom: 1px #E7E9EE solid;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.slider-layout.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.sliderLayoutContainer {
  justify-content: center;
}

.sliderLayoutContainer--carousel {
  background-color: #F0F0F0;
  min-height: 450px;
}

.sliderTrackContainer {
  max-width: 100%;
}

.paginationDotsContainer {
  margin-top: .5rem;
  margin-bottom: .5rem;
}

.layoutContainer--shelf {
  margin-top: 20px;
  margin-bottom: 20px;
  max-width: 96rem;
  min-height: 550px;
}

.slide--shelf {
  margin-bottom: 25px;
  padding-left: .5rem;
  padding-right: .5rem;
  min-height: 550px;
}

```


[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 shopper-location-availability-theme/styles/css/vtex.stack-layout.css from the shopper-location-availability-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.stackItem--product {
  width: 100%;
  min-height: 257px
}

.stackItem--quickview {
  right: 0;
  top: 0;
  left: auto;
}

```