[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-on-localhost/src/monobloco/components/new/Styleguide/components/FilterBar/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import ButtonWithIcon from '../ButtonWithIcon'
import IconClose from '../icon/Close'
import deprecated from '../../modules/deprecated'
import FilterTag from './FilterTag'

const HEAVY_ICON_OPTICAL_COMPENSATION = { marginTop: '1px' }

const isStatementComplete = st => st.subject && st.verb && st.object
const filterExtraOptions = (options, alwaysVisibleFilters, statements) => {
  return Object.keys(options)
    .filter(
      key =>
        !alwaysVisibleFilters.includes(key) &&
        !statements.some(st => st.subject === key && st.object)
    )
    .reduce(
      (filteredOptions, key) => ({ ...filteredOptions, [key]: options[key] }),
      {}
    )
}

const FILTER_VALUE_LABEL_MAX_LENGTH = 17
const truncateFilterValue = filterValue =>
  `${filterValue.substring(0, FILTER_VALUE_LABEL_MAX_LENGTH)}${
    filterValue.length <= FILTER_VALUE_LABEL_MAX_LENGTH ? '' : '…'
  }`

class FilterBar extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      visibleExtraOptions: [],
    }
  }

  toggleExtraFilterOption = key => {
    const { visibleExtraOptions } = this.state
    const newVisibleExtraOptions = [
      ...(visibleExtraOptions.indexOf(key) === -1 ? [key] : []),
      ...visibleExtraOptions.filter(op => op !== key),
    ]
    this.setState({ visibleExtraOptions: newVisibleExtraOptions })
  }

  handleSubmitFilter = st => {
    const { statements } = this.props
    const hasStatement = statements.some(_st => _st.subject === st.subject)
    if (hasStatement) {
      const newStatements = statements.map(_st => {
        if (_st.subject === st.subject) {
          return {
            ..._st,
            ...st,
          }
        }
        return _st
      })
      this.changeStatementsCallback(newStatements)
    } else {
      const newStatements = statements.slice(0)
      newStatements.push(st)
      this.changeStatementsCallback(newStatements)
    }
  }

  handleMoreOptionsSelected = st => {
    if (isStatementComplete(st)) {
      this.handleSubmitFilter(st)
      this.toggleExtraFilterOption(st.subject)
    }
  }

  handleFilterClear = subject => {
    const { alwaysVisibleFilters, statements } = this.props
    const newStatements = statements.filter(_st => _st.subject !== subject)
    this.changeStatementsCallback(newStatements)
    !alwaysVisibleFilters.includes(subject) &&
      this.toggleExtraFilterOption(subject)
  }

  changeStatementsCallback = statements => {
    this.props.onChangeStatements(statements)
  }

  handleClearAllfilters = () => {
    this.setState({ visibleExtraOptions: [] })
    this.changeStatementsCallback([])
  }

  render() {
    const {
      options,
      moreOptionsLabel,
      alwaysVisibleFilters,
      clearAllFiltersButtonLabel,
      statements,
      subjectPlaceholder,
      submitFilterLabel,
      newFilterLabel,
      testIds,
    } = this.props
    const { visibleExtraOptions } = this.state
    const optionsKeys = Object.keys(options)

    return (
      optionsKeys.length > 0 && (
        <div className={`flex flex-wrap nl1`}>
          {optionsKeys
            .filter(
              key =>
                alwaysVisibleFilters.includes(key) ||
                visibleExtraOptions.includes(key)
            )
            .map(subject => {
              const statement = statements.find(st => st.subject === subject)
              return (
                <div key={`VTEX__filter_option--${subject}`} className="ma2">
                  <FilterTag
                    alwaysVisible={alwaysVisibleFilters.includes(subject)}
                    getFilterLabel={() => {
                      const label =
                        options[subject] &&
                        options[subject].renderFilterLabel(statement)
                      return (
                        (label &&
                          typeof label === 'string' &&
                          truncateFilterValue(label)) ||
                        '…'
                      )
                    }}
                    submitFilterLabel={submitFilterLabel}
                    subject={subject}
                    options={options}
                    statements={statements}
                    onClickClear={() => this.handleFilterClear(subject)}
                    onSubmitFilterStatement={this.handleSubmitFilter}
                  />
                </div>
              )
            })}
          {alwaysVisibleFilters.length + visibleExtraOptions.length !==
            optionsKeys.length && (
            <div className="ma2">
              <FilterTag
                testIds={testIds}
                isMoreOptions
                subjectPlaceholder={subjectPlaceholder}
                getFilterLabel={() => moreOptionsLabel}
                submitFilterLabel={submitFilterLabel}
                newFilterLabel={newFilterLabel}
                options={{
                  ...filterExtraOptions(
                    options,
                    alwaysVisibleFilters,
                    statements
                  ),
                }}
                statements={[]}
                onSubmitFilterStatement={this.handleMoreOptionsSelected}
              />
            </div>
          )}
          {clearAllFiltersButtonLabel &&
            statements.some(st => !!st && !!st.object) && (
              <div className="ml-auto mt1">
                <ButtonWithIcon
                  icon={
                    <span
                      className="flex items-center c-muted-2"
                      style={HEAVY_ICON_OPTICAL_COMPENSATION}>
                      <IconClose size={13} />
                    </span>
                  }
                  size="small"
                  variation="tertiary"
                  onClick={this.handleClearAllfilters}>
                  <span className="c-muted-2">
                    {clearAllFiltersButtonLabel}
                  </span>
                </ButtonWithIcon>
              </div>
            )}
        </div>
      )
    )
  }
}

FilterBar.defaultProps = {
  options: [],
  moreOptionsLabel: 'More',
  alwaysVisibleFilters: [],
  subjectPlaceholder: 'Select a filter…',
  submitFilterLabel: 'Apply',
  newFilterLabel: 'New Filter',
  statements: [],
  testIds: {},
}

export const filterBarPropTypes = {
  /** filter options (mirroring statements from Conditions component) */
  options: PropTypes.object.isRequired,
  /** filter statements (mirroring statements from Conditions component) */
  statements: PropTypes.array,
  /** Filters change callback: returns array of statement definitions */
  onChangeStatements: PropTypes.func.isRequired,
  /** label for MORE options */
  moreOptionsLabel: PropTypes.string,
  /** filter options that are always visible outside MORE options */
  alwaysVisibleFilters: PropTypes.arrayOf(PropTypes.string),
  /** if this label is passed, when some filter is not empty a clear all button will appear */
  clearAllFiltersButtonLabel: PropTypes.string,
  /** Subject select placeholder inside 'More options' */
  subjectPlaceholder: PropTypes.string,
  /** Submit button label for statement inside FilterTag */
  submitFilterLabel: PropTypes.string,
  /** New Filter title label for inside the 'More options' menu */
  newFilterLabel: PropTypes.string,
  testIds: PropTypes.shape({
    moreOptionsButton: PropTypes.string,
    submitFiltersButton: PropTypes.string,
  }),
}

FilterBar.propTypes = filterBarPropTypes

export default deprecated({
  useNewProps: {
    submitFilterLable: 'submitFilterLabel',
    newFilterLable: 'newFilterLabel',
  },
})(FilterBar)

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/FilterBar/FilterTag.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { PureComponent, Fragment } from 'react'
import PropTypes from 'prop-types'
import merge from 'lodash/merge'
import classNames from 'classnames'

import withDevice from '../utils/withDeviceHoc'
import Button from '../Button'
import IconClear from '../icon/Clear'
import IconCaretDown from '../icon/CaretDown'
import Statement from '../Statement'
import Menu from './Menu'

const OPEN_MENU_STYLE = { backgroundColor: '#dbe9fd' }
const emptyVirtualStatement = {
  subject: null,
  verb: null,
  object: null,
  error: null,
}

const filterStatementBySubject = (statements = [], subject, options = {}) => {
  const hasStatement = statements.some(st => st.subject === subject)
  return hasStatement
    ? statements.filter(st => st.subject === subject)
    : [
        {
          ...emptyVirtualStatement,
          subject: subject,
          verb:
            options[subject] && options[subject].verbs.length > 0
              ? options[subject].verbs[0].value
              : null,
        },
      ]
}

class FilterTag extends PureComponent {
  constructor(props) {
    super(props)
    this.filterMenuContainer = React.createRef()

    this.state = {
      isMenuOpen: false,
      virtualStatement: filterStatementBySubject(
        props.statements,
        props.subject,
        props.options
      )[0],
    }
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    if (
      nextProps.statements &&
      nextProps.statements.length > 0 &&
      nextProps.subject &&
      nextProps.statements.some(st => st.subject === nextProps.subject)
    ) {
      const statement = filterStatementBySubject(
        nextProps.statements,
        nextProps.subject,
        nextProps.options
      )[0]
      return {
        virtualStatement: merge({}, statement, prevState.virtualStatement),
      }
    }
    return prevState
  }

  openMenu = () => {
    if (this.state.isMenuOpen) return

    document.addEventListener('mousedown', this.handleClickOutside)
    this.setState({
      isMenuOpen: true,
      virtualStatement: filterStatementBySubject(
        this.props.statements,
        this.props.subject,
        this.props.options
      )[0],
    })
  }

  handleCloseMenu = () => {
    if (!this.state.isMenuOpen) return

    document.removeEventListener('mousedown', this.handleClickOutside)
    this.setState({
      isMenuOpen: false,
      virtualStatement: filterStatementBySubject(
        [],
        this.props.subject,
        this.props.options
      )[0],
    })
  }

  handleClickOutside = e => {
    if (
      this.filterMenuContainer &&
      this.filterMenuContainer.current &&
      !this.filterMenuContainer.current.contains(e.target) &&
      this.state.isMenuOpen
    ) {
      this.handleCloseMenu()
    }
  }

  componentWillUnmount() {
    if (this.state.isMenuOpen) {
      this.handleCloseMenu()
    }
  }

  handleChangeStatement = statement => {
    this.setState(state => {
      return {
        virtualStatement: merge({}, state.virtualStatement, {
          ...statement,
        }),
      }
    })
  }

  resetVirtualStatement = () => {
    const { subject, options } = this.props
    const statement = filterStatementBySubject([], subject, options)
    this.setState({ virtualStatement: statement })
  }

  render() {
    const {
      options,
      subject,
      statements,
      alwaysVisible,
      getFilterLabel,
      subjectPlaceholder,
      onClickClear,
      isMoreOptions,
      onSubmitFilterStatement,
      submitFilterLabel,
      newFilterLabel,
      isMobile,
      testIds,
    } = this.props
    const { isMenuOpen, virtualStatement } = this.state

    const statement = filterStatementBySubject(statements, subject)[0]
    const isEmpty = !!(
      statements &&
      (!statement || (statement && !statement.object))
    )

    const shouldOmitSubject = !isMoreOptions
    const shouldOmitVerb = isMoreOptions
      ? false
      : options[subject].verbs.length === 1

    // this is temporary just to assure backward compatibility
    const compatibleOptions = {}
    Object.keys(options).forEach(opt => {
      compatibleOptions[opt] = merge({}, { ...options[opt] })
      compatibleOptions[opt].verbs = options[opt].verbs.map(verb => {
        if (typeof verb.object === 'function') {
          return verb
        }
        console.warn(
          '[Deprecation alert]',
          'FilterBar prop "options" will change contract due to Conditions and Statement refactor.',
          'please if you are using it let @guigs and @eric know...'
        )
        return {
          ...verb,
          object: ({ error, onChange, value }) => {
            return (
              <>
                {verb.object.renderFn({
                  statements: [merge({}, statement, virtualStatement)],
                  values: value,
                  statementIndex: 0,
                  error,
                  extraParams: verb.object && verb.object.extraParams,
                  onChangeObjectCallback: onChange,
                })}
              </>
            )
          },
        }
      })
    })

    return (
      <div
        ref={this.filterMenuContainer}
        style={{
          ...(isMenuOpen && OPEN_MENU_STYLE),
        }}
        className={`br2 ba b--solid ${
          isEmpty || isMoreOptions ? '' : 'pr4'
        } pv1 dib ${
          alwaysVisible && isEmpty
            ? 'bg-transparent hover-bg-muted-5 b--muted-4'
            : isMoreOptions
            ? 'hover-bg-muted-5 b--muted-4'
            : 'bg-action-secondary hover-bg-action-secondary b--action-secondary'
        } c-on-base`}>
        <div className="flex items-stretch">
          <Menu
            open={isMenuOpen}
            onBackgroundClick={this.handleCloseMenu}
            align="left"
            options={options[subject]}
            button={
              <button
                type="button"
                className="bw1 ba br2 v-mid relative bg-transparent b--transparent c-action-primary pointer w-100 outline-0"
                onClick={isMenuOpen ? this.handleCloseMenu : this.openMenu}>
                <div className="flex items-center justify-center h-100 ph3 ">
                  <span className="flex items-center nl1 nowrap">
                    {isMoreOptions ? (
                      <span
                        className="fw5"
                        data-testid={testIds.moreOptionsButton}>
                        {getFilterLabel()}
                      </span>
                    ) : isMobile ? (
                      <span className="ttu f6 fw5">
                        {options[subject].label}
                      </span>
                    ) : (
                      <Fragment>
                        <span>{`${options[subject].label}:\xa0`}</span>
                        <span className="fw5">{`${getFilterLabel(
                          filterStatementBySubject(statements, subject)
                        )}`}</span>
                      </Fragment>
                    )}
                    {!isMobile && (
                      <div className="ml2 nr2">
                        <IconCaretDown size={11} color="currentColor" />
                      </div>
                    )}
                  </span>
                </div>
              </button>
            }>
            <div className="ma6 ma5-ns h-75 h-auto-ns flex flex-column justify-between">
              <div
                className={classNames({
                  'overflow-scroll': isMobile && 'overflow-scroll',
                })}>
                <div
                  className={`flex flex-wrap ${isMoreOptions ? 'mb6' : 'mb3'}`}>
                  {isMoreOptions && (
                    <span className="f4 mh3">{newFilterLabel}</span>
                  )}
                  <div className="flex flex-column">
                    {shouldOmitVerb && (
                      <span className="mh3">
                        {options[subject].verbs[0].label}
                      </span>
                    )}
                  </div>
                </div>
                <Statement
                  isFullWidth
                  omitSubject={shouldOmitSubject}
                  omitVerbs={shouldOmitVerb}
                  options={compatibleOptions}
                  subjectPlaceholder={subjectPlaceholder}
                  statement={
                    isMoreOptions
                      ? virtualStatement
                      : merge({}, statement, virtualStatement)
                  }
                  onChangeStatement={this.handleChangeStatement}
                  onChangeObjectCallback={st =>
                    this.handleChangeStatement({
                      ...st,
                      error: null,
                    })
                  }
                />
              </div>
              <div className="flex justify-end mt4 mh3">
                <Button
                  testId={testIds.submitFiltersButton}
                  block={isMobile}
                  type="submit"
                  disabled={virtualStatement && !virtualStatement.object}
                  onClick={() => {
                    onSubmitFilterStatement(virtualStatement)
                    this.resetVirtualStatement()
                    this.handleCloseMenu()
                  }}>
                  {submitFilterLabel}
                </Button>
              </div>
            </div>
          </Menu>
          {!isEmpty && !isMoreOptions && (
            <div
              className="flex items-center c-link hover-c-link pointer"
              onClick={() => {
                this.resetVirtualStatement()
                onClickClear()
              }}>
              <IconClear solid size={16} />
            </div>
          )}
        </div>
      </div>
    )
  }
}

FilterTag.defaultProps = {
  alwaysVisible: false,
  isMoreOptions: false,
  subjectPlaceholder: '…',
  newFilterLabel: 'New filter',
  testIds: {},
}

FilterTag.propTypes = {
  options: PropTypes.object.isRequired,
  subject: PropTypes.string,
  statements: PropTypes.array,
  alwaysVisible: PropTypes.bool,
  getFilterLabel: PropTypes.func,
  subjectPlaceholder: PropTypes.string,
  onClickClear: PropTypes.func,
  isMoreOptions: PropTypes.bool,
  onSubmitFilterStatement: PropTypes.func.isRequired,
  submitFilterLabel: PropTypes.string.isRequired,
  newFilterLabel: PropTypes.string,
  device: PropTypes.string,
  isMobile: PropTypes.bool,
  testIds: PropTypes.shape({
    moreOptionsButton: PropTypes.string,
    submitFiltersButton: PropTypes.string,
  }),
}

export default withDevice(FilterTag)

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/FilterBar/README.md from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```markdown
#### The FilterBar is a slim, optimized way of displaying filter atoms. Although tailored to be used with the Table component, it can also be used on its own with any other way you chose to display your data.

<div className="center mw7 pv6">
  ![](./filters_table.png)
</div>

Different from regular filter panels, ours optimizes for both the screen real-estate and discoverability of new filters. You can have dozens of different, complex available filters, and still present to the user a slim and simple-to-use interface.

### 👍 Dos

- Apply user research to choose which filters to show in the highlighted section.
- Use the FilterBar always on top of the content that will be filtered.
- Try offering as many filters and operators as possible. With the diversity of operations VTEX supports, we can never predict all the diverse use cases our merchants need.

### 👎 Don'ts

- Don't present too many filters in the highlighted zone.

### Related components

- For applications with a small viewport or when working with modals prefer using the <a href="#/Components/Display/FilterOptions">FilterOptions</a> component.

Simple product filter example

```js
const Input = require('../Input').default

function SimpleInputObject({ value, onChange }) {
  return <Input value={value || ''} onChange={e => onChange(e.target.value)} />
}

class MySimpleFilter extends React.Component {
  constructor() {
    super()
    this.state = { statements: [] }
    this.getSimpleVerbs = this.getSimpleVerbs.bind(this)
    this.renderSimpleFilterLabel = this.renderSimpleFilterLabel.bind(this)
  }

  getSimpleVerbs() {
    return [
      {
        label: 'is',
        value: '=',
        object: props => <SimpleInputObject {...props} />,
      },
      {
        label: 'is not',
        value: '!=',
        object: props => <SimpleInputObject {...props} />,
      },
      {
        label: 'contains',
        value: 'contains',
        object: props => <SimpleInputObject {...props} />,
      },
    ]
  }

  renderSimpleFilterLabel(statement) {
    if (!statement || !statement.object) {
      // you should treat empty object cases only for alwaysVisibleFilters
      return 'Any'
    }
    return `${
      statement.verb === '='
        ? 'is'
        : statement.verb === '!='
        ? 'is not'
        : 'contains'
    } ${statement.object}`
  }

  render() {
    return (
      <FilterBar
        alwaysVisibleFilters={['id', 'category', 'brand']}
        statements={this.state.statements}
        onChangeStatements={statements => this.setState({ statements })}
        clearAllFiltersButtonLabel="Clear Filters"
        options={{
          id: {
            label: 'ID',
            renderFilterLabel: this.renderSimpleFilterLabel,
            verbs: this.getSimpleVerbs(),
          },
          category: {
            label: 'Category',
            renderFilterLabel: this.renderSimpleFilterLabel,
            verbs: this.getSimpleVerbs(),
          },
          brand: {
            label: 'Brand',
            renderFilterLabel: this.renderSimpleFilterLabel,
            verbs: this.getSimpleVerbs(),
          },
        }}
      />
    )
  }
}
;<MySimpleFilter />
```

Filter users example

```js
const Input = require('../Input').default
const Checkbox = require('../Checkbox').default

const CPF_VALIDATION_REGEX = RegExp('[0-9]{3}.[0-9]{3}.[0-9]{3}-[0-9]{2}')

function SimpleInputObject({ value, onChange }) {
  return <Input value={value || ''} onChange={e => onChange(e.target.value)} />
}

function CpfInputObject({ value, error, onChange }) {
  return (
    <Input
      placeholder="Insert cpf (with punctuation)…"
      errorMessage={value && error}
      value={value || ''}
      onChange={e => onChange(e.target.value)}
    />
  )
}

function CpfInputObjectWithValidation({ onChange, ...props }) {
  return (
    <CpfInputObject
      {...props}
      onChange={value => {
        if (value && value.length < 15 && CPF_VALIDATION_REGEX.test(value)) {
          onChange(value)
        } else {
          onChange(value, 'Invalid CPF')
        }
      }}
    />
  )
}

function AgeInputObject({ value, onChange }) {
  return (
    <Input
      placeholder="Insert age…"
      type="number"
      min="0"
      max="180"
      value={value || ''}
      onChange={e => {
        onChange(e.target.value.replace(/\D/g, ''))
      }}
    />
  )
}

function AgeInputRangeObject({ value, onChange }) {
  const { from = '', to = '' } = value
  return (

      <Input
        placeholder="Age from…"
        errorMessage={
          parseInt(from) >= parseInt(to)
            ? 'Must be smaller than other input'
            : ''
        }
        value={from}
        onChange={e => {
          const newValue = { from, to }
          newValue.from = e.target.value.replace(/\D/g, '')

          onChange(newValue)
        }}
      />

and

      <Input
        placeholder="Age to…"
        value={to}
        onChange={e => {
          const newValue = { from, to }
          newValue.to = e.target.value.replace(/\D/g, '')

          onChange(newValue)
        }}
      />

  )
}

function ClassSelectorObject({ value, error, onChange }) {
  const initialValue = {
    vip: true,
    gold: true,
    silver: true,
    platinum: true,
    ...(value || {}),
  }
  const toggleValueByKey = key => {
    const newValues = {
      ...(value || initialValue),
      [key]: value ? !value[key] : false,
    }
    return newValues
  }
  return (

      {Object.keys(initialValue).map((opt, index) => {
        return (
          <div className="mb3" key={`class-statment-object-${opt}-${index}`}>
            <Checkbox
              checked={value ? value[opt] : initialValue[opt]}
              id={`class-${opt}`}
              label={opt}
              name="class-checkbox-group"
              onChange={() => {
                const newValue = toggleValueByKey(`${opt}`)
                onChange(newValue)
              }}
              value={opt}
            />

        )
      })}

  )
}

class MyUsersFilter extends React.Component {
  constructor() {
    super()
    this.state = { statements: [] }
  }

  render() {
    return (
      <FilterBar
        alwaysVisibleFilters={['name', 'email', 'class']}
        statements={this.state.statements}
        onChangeStatements={statements => this.setState({ statements })}
        clearAllFiltersButtonLabel="Clear Filters"
        options={{
          name: {
            label: 'Name',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'Any'
              }
              return `${
                st.verb === '='
                  ? 'is'
                  : st.verb === '!='
                  ? 'is not'
                  : 'contains'
              } ${st.object}`
            },
            verbs: [
              {
                label: 'is',
                value: '=',
                object: props => <SimpleInputObject {...props} />,
              },
              {
                label: 'is not',
                value: '!=',
                object: props => <SimpleInputObject {...props} />,
              },
              {
                label: 'contains',
                value: 'contains',
                object: props => <SimpleInputObject {...props} />,
              },
            ],
          },
          email: {
            label: 'Email',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'Any'
              }
              return `${
                st.verb === '='
                  ? 'is'
                  : st.verb === '!='
                  ? 'is not'
                  : 'contains '
              } ${st.object}`
            },
            verbs: [
              {
                label: 'contains',
                value: 'contains',
                object: props => <SimpleInputObject {...props} />,
              },
              {
                label: 'is',
                value: '=',
                object: props => <SimpleInputObject {...props} />,
              },
              {
                label: 'is not',
                value: '!=',
                object: props => <SimpleInputObject {...props} />,
              },
            ],
          },
          class: {
            label: 'Class',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'All'
              }
              const keys = st.object ? Object.keys(st.object) : {}
              const isAllTrue = !keys.some(key => !st.object[key])
              const isAllFalse = !keys.some(key => st.object[key])
              const trueKeys = keys.filter(key => st.object[key])
              let trueKeysLabel = ''
              trueKeys.forEach((key, index) => {
                trueKeysLabel += `${key}${
                  index === trueKeys.length - 1 ? '' : ', '
                }`
              })
              return `${
                isAllTrue ? 'All' : isAllFalse ? 'None' : `${trueKeysLabel}`
              }`
            },
            verbs: [
              {
                label: 'includes',
                value: 'includes',
                object: props => <ClassSelectorObject {...props} />,
              },
            ],
          },
          age: {
            label: 'Age',
            renderFilterLabel: st =>
              `${
                st.verb === 'between'
                  ? `between ${st.object.first} and ${st.object.last}`
                  : `is ${st.object}`
              }`,
            verbs: [
              {
                label: 'is',
                value: '=',
                object: props => <AgeInputObject {...props} />,
              },
              {
                label: 'is between',
                value: 'between',
                object: props => <AgeInputRangeObject {...props} />,
              },
            ],
          },
          cpf: {
            label: 'Document',
            renderFilterLabel: st =>
              `${st.verb === '=' ? 'is' : 'contains'} ${st.object}`,
            verbs: [
              {
                label: 'is',
                value: '=',
                object: props => <CpfInputObjectWithValidation {...props} />,
              },
              {
                label: 'contains',
                value: 'contains',
                object: props => <CpfInputObject {...props} />,
              },
            ],
          },
        }}
      />
    )
  }
}
;<MyUsersFilter />
```

Filter orders example

```js
const Input = require('../Input').default
const Checkbox = require('../Checkbox').default
const DatePicker = require('../DatePicker').default

function SimpleInputObject({ value, onChange }) {
  return <Input value={value || ''} onChange={e => onChange(e.target.value)} />
}

function DatePickerObject({ value, onChange }) {
  return (

      <DatePicker
        value={value || new Date()}
        onChange={date => {
          onChange(date)
        }}
        locale="pt-BR"
      />

  )
}

function DatePickerRangeObject({ value, onChange }) {
  return (

      <DatePicker
        label="from"
        value={(value && value.from) || new Date()}
        onChange={date => {
          onChange({ ...(value || {}), from: date })
        }}
        locale="pt-BR"
      />

      <DatePicker
        label="to"
        value={(value && value.to) || new Date()}
        onChange={date => {
          onChange({ ...(value || {}), to: date })
        }}
        locale="pt-BR"
      />

  )
}

function StatusSelectorObject({ value, onChange }) {
  const initialValue = {
    'Window to cancelation': true,
    Canceling: true,
    Canceled: true,
    'Payment pending': true,
    'Payment approved': true,
    'Ready for handling': true,
    'Handling shipping': true,
    'Ready for invoice': true,
    Invoiced: true,
    Complete: true,
    ...(value || {}),
  }
  const toggleValueByKey = key => {
    return {
      ...(value || initialValue),
      [key]: value ? !value[key] : false,
    }
  }
  return (

      {Object.keys(initialValue).map((opt, index) => {
        return (
          <div className="mb3" key={`class-statment-object-${opt}-${index}`}>
            <Checkbox
              checked={value ? value[opt] : initialValue[opt]}
              id={`status-${opt}`}
              label={opt}
              name="status-checkbox-group"
              onChange={() => {
                const newValue = toggleValueByKey(`${opt}`)
                onChange(newValue)
              }}
              value={opt}
            />

        )
      })}

  )
}

class MyOrdersFilter extends React.Component {
  constructor() {
    super()
    this.state = { statements: [] }
    this.simpleInputVerbs = this.simpleInputVerbs.bind(this)
  }

  simpleInputVerbs() {
    return [
      {
        label: 'is',
        value: '=',
        object: props => <SimpleInputObject {...props} />,
      },
      {
        label: 'is not',
        value: '!=',
        object: props => <SimpleInputObject {...props} />,
      },
      {
        label: 'contains',
        value: 'contains',
        object: props => <SimpleInputObject {...props} />,
      },
    ]
  }

  render() {
    return (
      <FilterBar
        alwaysVisibleFilters={['id', 'email', 'status', 'invoicedate']}
        statements={this.state.statements}
        onChangeStatements={statements => this.setState({ statements })}
        clearAllFiltersButtonLabel="Clear Filters"
        options={{
          id: {
            label: 'Order ID',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'Any'
              }
              return `${
                st.verb === '='
                  ? 'is'
                  : st.verb === '!='
                  ? 'is not'
                  : 'contains'
              } ${st.object}`
            },
            verbs: this.simpleInputVerbs(),
          },
          email: {
            label: 'Email',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'Any'
              }
              return `${
                st.verb === '='
                  ? 'is'
                  : st.verb === '!='
                  ? 'is not'
                  : 'contains '
              } ${st.object}`
            },
            verbs: this.simpleInputVerbs(),
          },
          status: {
            label: 'Status',
            renderFilterLabel: st => {
              if (!st || !st.object) {
                // you should treat empty object cases only for alwaysVisibleFilters
                return 'All'
              }
              const keys = st.object ? Object.keys(st.object) : {}
              const isAllTrue = !keys.some(key => !st.object[key])
              const isAllFalse = !keys.some(key => st.object[key])
              const trueKeys = keys.filter(key => st.object[key])
              let trueKeysLabel = ''
              trueKeys.forEach((key, index) => {
                trueKeysLabel += `${key}${
                  index === trueKeys.length - 1 ? '' : ', '
                }`
              })
              return `${
                isAllTrue ? 'All' : isAllFalse ? 'None' : `${trueKeysLabel}`
              }`
            },
            verbs: [
              {
                label: 'includes',
                value: 'includes',
                object: props => <StatusSelectorObject {...props} />,
              },
            ],
          },
          invoicedate: {
            label: 'Invoiced date',
            renderFilterLabel: st => {
              if (!st || !st.object) return 'All'
              return `${
                st.verb === 'between'
                  ? `between ${st.object.from} and ${st.object.to}`
                  : `is ${st.object}`
              }`
            },
            verbs: [
              {
                label: 'is',
                value: '=',
                object: props => <DatePickerObject {...props} />,
              },
              {
                label: 'is between',
                value: 'between',
                object: props => <DatePickerRangeObject {...props} />,
              },
            ],
          },
          utm: {
            label: 'UTM Source',
            renderFilterLabel: st =>
              `${st.verb === '=' ? 'is' : 'contains'} ${st.object}`,
            verbs: this.simpleInputVerbs(),
          },
          seller: {
            label: 'Seller',
            renderFilterLabel: st =>
              `${st.verb === '=' ? 'is' : 'contains'} ${st.object}`,
            verbs: this.simpleInputVerbs(),
          },
        }}
      />
    )
  }
}
;<MyOrdersFilter />
```

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/FilterBar/Menu.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import Close from '../icon/Close'
import withDevice from '../utils/withDeviceHoc'

const DEFAULT_WIDTH = 292
const CONTAINER_MARGIN = 6
const WINDOW_MARGIN = 10

class Menu extends Component {
  constructor(props) {
    super(props)
    this.containerElement = React.createRef()
    this.menuElement = React.createRef()
  }

  state = {
    hasCalculatedSize: false, // hides the menu while calculating its size and position
    isUpwards: false, // opens the menu from bottom to top, if it doesn't fit on the screen otherwise
    isVisible: false, // triggers the opening animation
    menuHeight: 0,
    containerHeight: 0,
  }

  getMenuBounds = () =>
    this.menuElement.current &&
    this.menuElement.current.getBoundingClientRect &&
    this.menuElement.current.getBoundingClientRect()

  getContainerBounds = () =>
    this.containerElement.current &&
    this.containerElement.current.getBoundingClientRect &&
    this.containerElement.current.getBoundingClientRect()

  updateMenu() {
    const menuBounds = this.getMenuBounds()
    const containerBounds = this.getContainerBounds()

    if (!menuBounds || !containerBounds) return

    const containerHeight = containerBounds.height

    const initialMenuHeight = menuBounds.height

    const itemHeight = initialMenuHeight / this.props.options.length

    const isOutOfBounds =
      menuBounds.top + initialMenuHeight + containerHeight > window.innerHeight

    const isUpwards =
      isOutOfBounds && containerBounds.top > window.innerHeight / 2

    const maxMenuHeight = isUpwards
      ? menuBounds.top - CONTAINER_MARGIN - WINDOW_MARGIN
      : window.innerHeight -
        menuBounds.top -
        containerHeight -
        CONTAINER_MARGIN -
        WINDOW_MARGIN

    // Makes the height of the menu, if it doesn't entirely fit on the screen,
    // fall in the middle of an item, to hint that the menu scrolls
    const visibleItemsNum = Math.round(maxMenuHeight / itemHeight)
    const adjustedMenuHeight = visibleItemsNum * itemHeight - itemHeight / 2

    const menuHeight =
      maxMenuHeight < initialMenuHeight ? adjustedMenuHeight : 0

    this.setState(
      {
        containerHeight,
        menuHeight,
        isUpwards,
        hasCalculatedSize: true,
      },
      () => {
        // triggers the menu opening animation
        setTimeout(() => {
          this.setState({ isVisible: true })
        }, 1)
      }
    )
  }

  componentDidUpdate(prevProps) {
    if (!prevProps.open && this.props.open) {
      this.updateMenu()
    }

    if (prevProps.open && !this.props.open) {
      this.setState({
        hasCalculatedSize: false,
        isUpwards: false,
        isVisible: false,
        menuHeight: 0,
        containerHeight: 0,
      })
    }
  }

  render() {
    const {
      width,
      align,
      open,
      children,
      button,
      isMobile,
      options,
    } = this.props
    const {
      hasCalculatedSize,
      isUpwards,
      isVisible,
      menuHeight,
      containerHeight,
    } = this.state

    const isRight = align === 'right'

    const optionsLabel = (options && options.label) || ''

    let styles = {
      boxShadow: '0px 1px 18px rgba(0, 0, 0, 0.14)',
    }

    if (isMobile) {
      styles = {
        ...styles,
        top: 0,
        height: '100%',
      }
    }

    if (!isMobile) {
      styles = {
        ...styles,
        transform:
          !hasCalculatedSize || isVisible ? 'scale(1)' : 'scale(0.9, 0.6)',
        transformOrigin: `${isRight ? '75%' : '25%'} ${
          isUpwards ? '100%' : '0'
        }`,
        transition: isVisible
          ? `transform 50ms ease-out, opacity 25ms`
          : 'none',
        [isUpwards ? 'bottom' : 'top']: containerHeight + CONTAINER_MARGIN,
      }
    }

    const openContainerClasses = classNames(
      'fixed absolute-ns w-100 w-auto-ns z-999 ba bw1 b--muted-4 bg-base',
      {
        'right-0': isRight,
        'left-0': !isRight,
        br0: isMobile,
        br2: !isMobile,
        'o-100': isVisible,
        'o-0': !isVisible,
      }
    )

    return (
      <div className="relative">
        <div ref={this.containerElement}>{button}</div>
        {open && (
          <>
            <div
              ref={this.menuElement}
              style={styles}
              className={openContainerClasses}>
              <div
                className="b2-ns br2-ns bg-base h-100 h-auto-ns"
                style={{ width: isMobile ? '100%' : width || DEFAULT_WIDTH }}>
                <div
                  className={
                    menuHeight
                      ? 'overflow-auto h-100 h-auto-ns'
                      : 'h-100 h-auto-ns'
                  }>
                  {isMobile && (
                    <div className="flex justify-between flex-row items-baseline pa6 mh3">
                      <div className="truncate f3 pr6">{optionsLabel}</div>
                      <div onClick={this.props.onBackgroundClick}>
                        <Close size={20} color="currentColor" />
                      </div>
                    </div>
                  )}
                  {children}
                </div>
              </div>
            </div>
          </>
        )}
      </div>
    )
  }
}

Menu.defaultProps = {
  options: [],
  align: 'right',
  open: false,
}

Menu.propTypes = {
  /** The element which will open the menu--the menu will
   * be positioned around this element */
  children: PropTypes.node,
  /** Menu visibility (default is false) */
  open: PropTypes.bool,
  options: PropTypes.array,
  button: PropTypes.element,
  /** Menu Box width (default is 292px) */
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  /** function to close the menu after clicking an option */
  onClose: PropTypes.func,
  /** Menu Box align (default is right) */
  align: PropTypes.oneOf(['right', 'left']),
  /** Function to handle callback on overlay click */
  onBackgroundClick: PropTypes.func,
  /** Boolean if the device is mobile  */
  isMobile: PropTypes.bool,
}

export default withDevice(Menu)

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Dropdown/ArrowDownIcon.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

class ArrowDownIcon extends PureComponent {
  render() {
    return (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width={this.props.size}
        height={this.props.size}
        viewBox="0 0 24 24">
        <g fill={this.props.color}>
          <path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" />
        </g>
      </svg>
    )
  }
}

ArrowDownIcon.defaultProps = {
  size: 16,
  color: 'currentColor',
}

ArrowDownIcon.propTypes = {
  size: PropTypes.number.isRequired,
  color: PropTypes.string.isRequired,
}

export default ArrowDownIcon

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Dropdown/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import ArrowDownIcon from './ArrowDownIcon'
import { withForwardedRef, refShape } from '../../modules/withForwardedRef'

class Dropdown extends Component {
  constructor(props) {
    super(props)

    // The initial value sent to the dropdown is kept in order to know
    // whether or not to create and keep a first disabled option.
    // If the initial value is invalid/empty, an empty option is kept
    // so the select will have an empty state. Otherwise, the first
    // value would automatically be chosen.
    // However, you can't select a null/undefined option, so nil values
    // are transformed to empty string.
    this.initialValue = props.value == null ? '' : props.value
  }

  handleChange = e => {
    const { disabled, onChange } = this.props
    const {
      target: { value },
    } = e

    !disabled && onChange && onChange(e, value)
  }

  getOptionFromValue = value => {
    const { options } = this.props
    const option = options.filter(option => option.value === value)[0]
    if (!option) return null
    return option
  }

  getDropdownIdentification = () => {
    const { label, id, options } = this.props
    if (label) {
      return `Dropdown with the label "${label}"`
    } else if (id) {
      return `Dropdown #${id}`
    }
    return `Dropdown with the options ${options
      .map(option => option.label)
      .join(', ')}`
  }

  getPlaceholder = () => {
    const { placeholder, label, helpText } = this.props
    const placeholderValue = placeholder || label || helpText || ''

    if (placeholderValue === '' && !this.sentPlaceholderWarning) {
      const identificationText = this.getDropdownIdentification()
      console.warn(
        `The following dropdown has a placeholder option, but no placeholder text. Please use at least one of these props: placeholder, label, or helpText. ${identificationText}`
      )

      this.sentPlaceholderWarning = true
    }

    return placeholderValue
  }

  getSelectedOption = () => {
    return this.getOptionFromValue(this.props.value)
  }

  getValueLabel() {
    const selectedOption = this.getSelectedOption()
    return selectedOption ? selectedOption.label : this.getPlaceholder()
  }

  componentDidMount() {
    if (this.props.size === 'x-large') {
      console.warn(
        'Dropdown: The value "x-large" for the prop "size" is deprecated. In the next major version, it will be equivalent to "large", and removed altogether in future versions'
      )
    }
  }

  render() {
    const {
      label,
      id,
      testId,
      value,
      size,
      disabled,
      options,
      error,
      errorMessage,
      helpText,
      placeholder,
      preventTruncate,
      autoFocus,
      form,
      name,
      required,
      variation,
      selectTestId,
    } = this.props

    const hasValidInitialValue =
      this.getOptionFromValue(this.initialValue) !== null

    const isPlaceholder = this.getSelectedOption() === null
    const isInline = variation.toLowerCase() === 'inline'
    let width
    let iconSize

    let classes = 'bg-transparent bn w-100 h-100 '
    let containerClasses = `${isInline ? '' : 'bw1'} br2 relative `
    let selectClasses = 'o-0 absolute top-0 left-0 h-100 w-100 bottom-00 '

    let labelClasses = 'vtex-dropdown__label db mb3 w-100 c-on-base '

    const valueLabel = this.getValueLabel()
    const showCaption = !valueLabel

    const color = isInline ? 'c-link ' : 'c-on-base '

    classes += disabled ? '' : 'pointer '
    selectClasses += disabled ? '' : 'pointer '
    classes +=
      !disabled && valueLabel
        ? !isPlaceholder
          ? color
          : 'c-muted-2 '
        : 'c-disabled '

    switch (size) {
      case 'small':
        classes += isInline ? 'ph2 ' : 'pl5 pr3 '
        selectClasses += 't-small '
        labelClasses += 't-small '
        containerClasses += `${isInline ? 'h-auto' : 'h-small'} t-small `
        iconSize = 18
        break
      case 'large':
        classes += isInline ? 'ph2 ' : 'ph5 '
        selectClasses += 't-body '
        labelClasses += 't-body '
        containerClasses += `${isInline ? 'h-auto' : 'h-large'} t-body `
        iconSize = 18
        break
      case 'x-large':
        // DEPRECATED
        classes += 't-body pv5 ph5 '
        selectClasses += 't-body '
        labelClasses += 't-body '
        iconSize = 22
        break
      default:
        classes += isInline ? 'ph2 ' : 'pl5 pr4 '
        selectClasses += 't-body '
        labelClasses += 't-small '
        containerClasses += `${isInline ? 'h-auto' : 'h-regular'} t-body `
        iconSize = 18
        break
    }

    const containerStyle = { width }

    if (disabled) {
      containerClasses += 'ba b--disabled bw1 bg-disabled '
    } else if (error || errorMessage) {
      containerClasses += 'ba b--danger hover-b--danger '
    } else if (isInline) {
      containerClasses += 'fw5 '
    } else {
      containerClasses += 'bg-base hover-b--muted-3 ba b--muted-4 '
    }

    return (
      <div
        className={`vtex-dropdown ${
          isInline ? 'vtex-dropdown--inline dib' : ''
        }`}
        data-testid={testId}>
        <label>
          {label && <span className={labelClasses}>{label}</span>}
          <div className={containerClasses} style={containerStyle}>
            <div id={id} className={`vtex-dropdown__button ${classes}`}>
              <div className={`flex ${isInline ? '' : 'h-100'}`}>
                <div
                  className={`vtex-dropdown__caption flex-auto tl truncate ${
                    isInline ? '' : 'h-100'
                  }`}>
                  <div
                    className={`${isInline ? '' : 'h-100'} flex items-center`}>
                    {showCaption ? placeholder : valueLabel}
                  </div>
                </div>
                <div
                  className={`vtex-dropdown__arrow flex-none flex items-center pl2 ${
                    disabled ? 'c-on-disabled' : 'c-action-primary'
                  }`}>
                  <ArrowDownIcon size={iconSize} />
                </div>
              </div>
            </div>

            <select
              data-testid={selectTestId}
              disabled={disabled}
              className={selectClasses}
              onChange={this.handleChange}
              ref={this.props.forwardedRef}
              // Check the comment on the constructor regarding nil values
              value={value == null ? '' : value}
              autoFocus={autoFocus}
              form={form}
              name={name}
              required={required}
              style={{
                // safari select height fix
                WebkitAppearance: 'menulist-button',
              }}>
              {/* iOS hack to optionally prevent truncating options */}
              {preventTruncate && <optgroup label={label || helpText || ''} />}

              {/* Creates a disabled first option in case the first value is invalid or empty */}
              {(!hasValidInitialValue || placeholder) && (
                <option
                  disabled
                  value={!hasValidInitialValue ? this.initialValue : null}>
                  {this.getPlaceholder()}
                </option>
              )}
              {options.map(option => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </div>
        </label>
        {errorMessage && (
          <div className="c-danger t-small mt3 lh-title">{errorMessage}</div>
        )}
        {helpText && (
          <div className="c-muted-1 t-small mt3 lh-title">{helpText}</div>
        )}
      </div>
    )
  }
}

Dropdown.defaultProps = {
  size: 'regular',
  options: [],
  variation: 'default',
}

Dropdown.propTypes = {
  /** Error highlight */
  error: PropTypes.bool,
  /** Error message */
  errorMessage: PropTypes.node,
  /** @ignore Forwarded Ref */
  forwardedRef: refShape,
  /** Help text */
  helpText: PropTypes.node,
  /** Dropdown label */
  label: PropTypes.node,
  /** Dropdown placeholder value */
  placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  /** Dropdown size */
  size: PropTypes.oneOf(['small', 'regular', 'large']),
  /** Dropdown options list */
  options: PropTypes.arrayOf(
    PropTypes.shape({
      value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
        .isRequired,
      label: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
        .isRequired,
    })
  ),
  /** Prevent truncating large options texts on some devices/browsers, such as iOS */
  preventTruncate: PropTypes.bool,
  /** Spec attribute */
  id: PropTypes.string,
  /** Data attribute */
  testId: PropTypes.string,
  /**  Data attribute for select*/
  selectTestId: PropTypes.string,
  /** Spec attribute */
  autoFocus: PropTypes.bool,
  /** Spec attribute */
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  /** Spec attribute */
  disabled: PropTypes.bool,
  /** Dropdown variation */
  variation: PropTypes.oneOf(['default', 'inline']),
  /** Spec attribute */
  form: PropTypes.string,
  /** Spec attribute */
  name: PropTypes.string,
  /** Spec attribute */
  required: PropTypes.bool,
  /** onChange event */
  onChange: PropTypes.func,
  /** onClose event */
  onClose: PropTypes.func,
  /** onOpen event */
  onOpen: PropTypes.func,
}

export default withForwardedRef(Dropdown)

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Dropdown/README.md from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```markdown
#### A Dropdown lets the user pick an option from a list.

### 👍 Dos

- Mind the order of the options, like putting more probable to be picked on that. In doubt, sort them alphanumerically (from A to Z and from 0 to 9).

### 👎 Don'ts

- Don't use a Dropdown if you have more than a few dozens options. Most users don't know about the keyboard search feature and will have to scan through all the options. In this case you'll probably need something a little fancier (work not in progress).

### Related components

- Consider a <a href="#/Components/Forms/RadioGroup">Radio Group</a> if there are fewer than 4 options to choose from, or you need more space to explain each of the options.
- For multiple picks, use the <a href="#/Components/👻%20Experimental/Select">Select</a> (work in progress).

Sizes

```js

    <Dropdown
      label="Small"
      size="small"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    <Dropdown
      label="Regular"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    <Dropdown
      label="Large"
      size="large"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

```

Variations

```js
;

    <Dropdown
      label="Placeholder"
      placeholder="Select an artist"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value=""
      onChange={() => {}}
    />

    <Dropdown
      label="Disabled"
      disabled
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    <Dropdown
      label="Error"
      errorMessage="Required field"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    <Dropdown
      label="Help text"
      helpText={Your help text goes here!}
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
        { value: 'goya', label: 'Goya' },
        { value: 'monet', label: 'Monet' },
        { value: 'picasso', label: 'Picasso' },
        { value: 'tolouseLautrec', label: 'Toulouse-Lautrec' },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    <Dropdown
      label="Prevent truncate"
      preventTruncate
      options={[
        {
          value: 'chagall',
          label: 'Marc Zakharovich Chagall, born Moishe Zakharovich Shagal',
        },
        {
          value: 'dali',
          label:
            'Salvador Domingo Felipe Jacinto Dalí i Domènech, Marquis of Dalí de Púbol, known professionally as Salvador Dalí',
        },
        { value: 'goya', label: 'Francisco José de Goya y Lucientes' },
        { value: 'monet', label: 'Oscar-Claude Monet' },
        { value: 'picasso', label: 'Pablo Picasso' },
        {
          value: 'tolouseLautrec',
          label:
            'Henri Marie Raymond de Toulouse-Lautrec-Monfa, also known as Henri de Toulouse-Lautrec',
        },
      ]}
      value="tolouseLautrec"
      onChange={() => {}}
    />

    Inline example:
    <Dropdown
      variation="inline"
      size="large"
      options={[
        { value: 'chagall', label: 'Chagall' },
        { value: 'dali', label: 'Dali' },
      ]}
      value="dali"
      onChange={() => {}}
    />

```

Example: Working React Component

```js
class Example extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      options: [
        { value: 'painterChagall', label: 'Chagall' },
        { value: 'painterDali', label: 'Dali' },
        { value: 'painterGoya', label: 'Goya' },
        { value: 'painterMonet', label: 'Monet' },
        { value: 'painterPicasso', label: 'Picasso' },
        { value: 'painterTolouseLautrec', label: 'Toulouse-Lautrec' },
      ],
      selectedPainter: '',
    }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(e, value) {
    this.setState({ selectedPainter: value })
  }

  render() {
    const selectedPainter = this.state.options.find(
      painter => painter.value === this.state.selectedPainter
    )

    const { label, value } = selectedPainter || {}

    return (

          <Dropdown
            label="Painter"
            options={this.state.options}
            onChange={this.handleChange}
            value={this.state.selectedPainter}
            placeholder="Select a painter"
            {...this.props}
          />

Selected Painter

Label: {label || undefined}

Value: {value || undefined}

    )
  }
}
;<Example />
```

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/ToastProvider/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import ToastManager from './ToastManager'

const ToastContext = React.createContext({
  showToast: () => {},
  hideToast: () => {},
  toastState: null,
})

class ToastProvider extends Component {
  constructor(props) {
    super(props)

    this.toastManager = React.createRef()
  }

  render() {
    const { children, positioning } = this.props
    return (
      <ToastManager positioning={positioning}>
        {({ showToast, hideToast, state: toastState }) => (
          <ToastContext.Provider
            value={{
              showToast,
              hideToast,
              toastState,
            }}>
            {children}
          </ToastContext.Provider>
        )}
      </ToastManager>
    )
  }
}

ToastProvider.propTypes = {
  children: PropTypes.node,
  /** Sets the position of the toasts based either on the dimensions of the parent element of the ToastProvider, or window dimensions */
  positioning: PropTypes.oneOf(['parent', 'window']),
}

ToastProvider.defaultProps = {
  positioning: 'parent',
}

const ToastConsumer = ({ children }) => (
  <ToastContext.Consumer>{value => children(value)}</ToastContext.Consumer>
)

ToastConsumer.propTypes = {
  children: PropTypes.func.isRequired,
}

// eslint-disable-next-line react/display-name
const withToast = WrappedComponent => props => (
  <ToastConsumer>
    {({ showToast, hideToast, toastState }) => (
      <WrappedComponent
        showToast={showToast}
        hideToast={hideToast}
        toastState={toastState}
        {...props}
      />
    )}
  </ToastConsumer>
)

export { ToastContext, ToastProvider, ToastConsumer, withToast }

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/ToastProvider/README.md from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```markdown
#### Toasts give users instant feedback about the tasks they just did. Its main objective is to ensure tasks confirmation and success.

### 👍 Dos
- Toasts are always self-dismissing, but users should be allowed to dismiss by themselves as well.
- Keep messages in a low to mild priority spectrum. Toasts are intended to be either neutral or positive.

### 👎 Don'ts
- Do not present critical or high priority actions on a Toast. If that's the case, you might consider using [Alerts](#alert) instead.
- Due to its low to mild priority usage and dismissability, warning and error semantic styles do not apply to Toasts.

```js
import { useState } from 'react'
const Button = require('../Button').default
const ToastConsumer = require('./index').ToastConsumer

const App = () => (
  // Wrap the entire application on a toast provider
  <ToastProvider
    positioning="window"
  >
    <Content/>
  </ToastProvider>
)

const Content = () => {
  const [count, setCount] = useState(0)
  return(
  // Wrap the components that are going to display toasts
  // on a ToastConsumer, with a function as a child, as
  // the example below:

      Click on a button to show the corresponding toast

      <ToastConsumer>
        { ({ showToast }) => (

              <Button
                size="small"
                variation="secondary"
                onClick={() => showToast('Your toast is ready')}>
                Short text
              </Button>

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'The bread has been inserted into the toaster',
                    action: {
                      label:'Undo',
                      onClick: () =>
                        alert('Bread removed from toaster'),
                    },
                  })
                }
              >
                With action
              </Button>

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'The toast is done, with a layer of butter on top, along with a nice cup of coffee.',
                    action: {
                      label: 'Thanks',
                      onClick: () => {},
                    }
                  })
                }
              >
                Long text
              </Button>

        )}
      </ToastConsumer>

      Toast duration and control

      <ToastConsumer>
        {({showToast, hideToast}) => (

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'This message lasts 30 seconds',
                    duration: 30000,
                  })
                }
              >
                30 seconds
              </Button>

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'This message stays here until closed',
                    duration: Infinity,
                  })
                }
              >
                Permanent
              </Button>

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'This message stays here until closed programatically',
                    dismissable: false,
                  })
                }
              >
                Undismissable
              </Button>

              <Button
                size="small"
                variation="danger"
                onClick={hideToast}
              >
                Close all toasts
              </Button>

        )}
      </ToastConsumer>

      Toast position

      <ToastConsumer>
        {({showToast, hideToast}) => (

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'Everything you own in the box to the left',
                    duration: 3000,
                    horizontalPosition: 'left'
                  })
                }
              >
                To the left, to the left
              </Button>

              <Button
                size="small"
                variation="secondary"
                onClick={
                  () => showToast({
                    message: 'All right all right all right',
                    duration: 3000,
                    horizontalPosition: 'right'
                  })
                }
              >
                All right
              </Button>

        )}
      </ToastConsumer>

      Link on toast action

    <ToastConsumer>
      {({showToast, hideToast}) => (

            <Button
              size="small"
              variation="secondary"
              onClick={
                () => showToast({
                  message: 'Item added to cart',
                  duration: 8000,
                  action: {
                    label: 'See cart',
                    href: 'http://vtex.com',
                    target: '_blank'
                  }
                })
              }
            >
              Add to cart
            </Button>

      )}
    </ToastConsumer>

      Link on toast action

    <ToastConsumer>
      {({showToast, hideToast}) => (

            <Button
              size="small"
              variation="secondary"
              onClick={
                () => {
                  setCount(count => count + 1)
                  showToast({
                    message: `You clicked ${count} times`,
                    keepAfterUpdate: true,
                    duration: 5000,
                  })
                }
              }
            >
              One more in same Toast
            </Button>

      )}
    </ToastConsumer>

)
}

;<App/>

```

```js
  const withToast = require('./index').withToast
  const Input = require('../Input').default
  const debounce = require('lodash/debounce')

  class App extends React.Component {
    constructor(props){
      super(props)

      this.state = {
        value: '',
      }

      this.handleInputChange = this.handleInputChange.bind(this)
      this.showToast = debounce(this.showToast.bind(this), 300)
    }

    handleInputChange(event) {
      this.setState({ value: event.currentTarget.value })
    }

    componentDidUpdate(_, prevState) {
      const { value } = this.state
      if ( prevState.value !== this.state.value ) {
        if (value === ''){
          this.showToast('The text has been erased')
        } else {
          this.showToast(`You typed: “${this.state.value}”`)
        }
      }
    }

    showToast(message) {
      this.props.showToast({ message })
    }

    render() {
      const {value} = this.state
      return (
        <React.Fragment>

Higher-order component

            For use on component lifecycle methods (componentDidMount, componentDidUpdate, etc)

          <Input
            value={value}
            label="Write something below to display a toast"
            onChange={this.handleInputChange}
            placeholder="Type here"
          />
        </React.Fragment>
      )
    }
  }

  const AppWithToast = withToast(App)

  ;<ToastProvider positioning="window">
    <AppWithToast />
  </ToastProvider>
```

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/ToastProvider/ToastManager.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import isString from 'lodash/isString'

import Toast from './Toast'

export default class ToastManager extends Component {
  constructor(props) {
    super(props)

    this.container = React.createRef()
  }

  state = {
    currentToast: null,
    nextToast: null,
    isToastVisible: false,
  }

  showToast = args => {
    if (isString(args)) {
      args = { message: args }
    }
    const {
      message = '',
      action,
      dismissable,
      duration,
      horizontalPosition = 'left',
      keepAfterUpdate = false,
    } = args

    if (this.state.currentToast && !keepAfterUpdate) {
      // If there is a toast present already, queue up the next toast
      // It will be displayed when the current toast is closed, on handleToastClose
      this.setState({
        nextToast: {
          message,
          action,
          dismissable,
          duration,
          horizontalPosition,
        },
      })
      this.hideToast()
    } else {
      this.setState({
        currentToast: {
          message,
          action,
          dismissable,
          duration,
          horizontalPosition,
          keepAfterUpdate,
        },
        isToastVisible: true,
      })
    }
  }

  hideToast = () => {
    this.setState({
      isToastVisible: false,
    })
  }

  handleToastClose = () => {
    this.setState(state => {
      return {
        // If there is a toast queued up, shows it.
        // Otherwise, nextToast will be null, and state.toast will be cleared up
        currentToast: state.nextToast,
        isToastVisible: !!state.nextToast,
        nextToast: null,
        state: state.horizontalPosition,
      }
    })
  }

  getParentBounds = () => {
    const parentContainer =
      this.container.current && this.container.current.parentNode
    return (
      parentContainer &&
      parentContainer.getBoundingClientRect &&
      parentContainer.getBoundingClientRect()
    )
  }

  updateContainerBounds = () => {
    const windowBounds = {
      left: 0,
      right: window.innerWidth,
      top: 0,
      bottom: window.innerHeight,
    }

    const bounds =
      (this.props.positioning === 'parent' && this.getParentBounds()) ||
      windowBounds

    if (this.container.current) {
      this.container.current.style.left = `${bounds.left}px`
      this.container.current.style.right = `${window.innerWidth -
        bounds.right}px`
      this.container.current.style.top = `${bounds.top}px`
      this.container.current.style.bottom = `${Math.max(
        0,
        window.innerHeight - bounds.bottom
      )}px`
    }
  }

  componentDidUpdate() {
    this.updateContainerBounds()
  }

  render() {
    const { children } = this.props
    const { currentToast } = this.state

    return (
      <Fragment>
        {children({
          showToast: this.showToast,
          hideToast: this.hideToast,
          state: this.state,
        })}
        <div
          className="fixed z-max overflow-hidden"
          ref={this.container}
          style={{
            pointerEvents: 'none',
          }}>
          {currentToast && (
            <Toast
              message={currentToast.message}
              action={currentToast.action}
              duration={currentToast.duration}
              dismissable={currentToast.dismissable}
              horizontalPosition={currentToast.horizontalPosition}
              keepAfterUpdate={currentToast.keepAfterUpdate}
              visible={this.state.isToastVisible}
              onClose={this.handleToastClose}
            />
          )}
        </div>
      </Fragment>
    )
  }
}

ToastManager.propTypes = {
  positioning: PropTypes.oneOf(['parent', 'window']),
  children: PropTypes.func.isRequired,
}

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/ToastProvider/Toast.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import CloseIcon from '../icon/Close'
import Button from '../Button'

const nextFrame = callback => {
  const FRAME_DURATION = 16
  setTimeout(callback, FRAME_DURATION)
}

const DURATION_BASE = 3000
const DURATION_INCREMENT = 30
const DURATION_ACTION_INCREMENT = 2000
const TRANSITION_DURATION = 160

export default class Toast extends Component {
  static defaultProps = {
    dismissable: true,
  }

  constructor(props) {
    super(props)
    this.state = {
      isOpen: false,
      isSingleLine: false,
    }
    this.messageElement = React.createRef()
    this.buttonElement = React.createRef()
  }

  componentDidMount() {
    if (this.props.visible) {
      // sets the open state on the next frame
      // so the opening transition will run
      nextFrame(() => this.open())

      this.startAutoClose()
    }
    this.updateButtonWrap()
  }

  // Duration increases along with the length of the message
  getDefaultDuration = () =>
    DURATION_BASE +
    this.props.message.length * DURATION_INCREMENT +
    (this.props.action ? DURATION_ACTION_INCREMENT : 0)

  startAutoClose = () => {
    this.stopAutoClose()
    const { duration } = this.props

    if (duration <= 0 || duration === Infinity) {
      return
    }

    this.autoCloseTimeout = setTimeout(
      this.close,
      this.props.duration || this.getDefaultDuration()
    )
  }

  stopAutoClose = () => {
    if (this.autoCloseTimeout == null) return

    clearTimeout(this.autoCloseTimeout)
    this.autoCloseTimeout = null
  }

  handleMouseOver = () => {
    this.stopAutoClose()
  }

  handleMouseOut = () => {
    this.startAutoClose()
  }

  handleCloseClick = () => {
    this.close()
  }

  open = () => {
    this.setState({
      isOpen: true,
    })
  }

  close = () => {
    if (!this.state.isOpen) {
      return
    }
    this.stopAutoClose()

    setTimeout(() => {
      this.props.onClose()
    }, TRANSITION_DURATION)

    this.setState({
      isOpen: false,
    })
  }

  handleActionClick = e => {
    const { isOpen } = this.state
    if (!isOpen) return

    const { action } = this.props
    const actionHandler = action && action.onClick

    if (actionHandler) {
      actionHandler(e)
    }

    this.close()
  }

  componentDidUpdate(prevProps) {
    if (!this.props.visible && prevProps.visible) {
      this.close()
    } else if (this.props.visible && !prevProps.visible) {
      this.open()
      this.startAutoClose()
    }
    if (
      this.props.message !== prevProps.message ||
      (this.props.visible && !prevProps.visible)
    ) {
      this.updateButtonWrap()
    }

    if (this.props.keepAfterUpdate) {
      this.startAutoClose()
    }
  }

  // Lets the toast to be single line on mobile
  // if the message is short enough
  updateButtonWrap() {
    this.setState(
      {
        isSingleLine: false,
      },
      () => {
        const messageWidth = this.getElementWidth(this.messageElement)
        const buttonWidth = this.getElementWidth(this.buttonElement)
        const windowWidth = window.innerWidth || 0
        const threshold = 75

        if (messageWidth != null && buttonWidth != null) {
          if (messageWidth + buttonWidth <= windowWidth - threshold) {
            this.setState({
              isSingleLine: true,
            })
          }
        }
      }
    )
  }

  getElementWidth(ref) {
    const element = ref && ref.current
    const bounds =
      element &&
      element.getBoundingClientRect &&
      element.getBoundingClientRect()
    return bounds && bounds.width
  }

  render() {
    const { isOpen, isSingleLine } = this.state
    const { action, dismissable, horizontalPosition, message } = this.props
    const hasAction = !!(
      action &&
      action.label &&
      (action.onClick || action.href)
    )

    return (
      <div
        className={`vtex-toast-container absolute bottom-0 ${horizontalPosition}-0 z-5 ma7-ns mb0-s w-100 w-auto-ns mw6-m mw-40-l`}
        onMouseOver={this.handleMouseOver}
        onMouseOut={this.handleMouseOut}
        style={{
          pointerEvents: 'all',
          transition: `transform ${TRANSITION_DURATION}ms ${
            isOpen ? 'ease-out' : 'ease-in'
          }`,
          transform: `translate3d(0, ${isOpen ? 0 : '170%'}, 0)`,
          minWidth: '18rem',
        }}>
        <div className="vtex-toast flex justify-between items-start items-center-ns t-body bg-base--inverted c-on-base--inverted pa5 br2-ns shadow-5">
          <div className={`${isSingleLine ? 'flex' : 'flex-ns'} flex-grow-1`}>
            <div className="flex items-center flex-grow-1">
              <div className="pr5 mw6-ns lh-copy" ref={this.messageElement}>
                {message}
              </div>
            </div>

            {hasAction && (
              <div className="flex flex-grow-1 justify-end items-center">
                <div className={`${isSingleLine ? 'nt4' : 'nt4-ns'} nb4`}>
                  <Button
                    ref={this.buttonElement}
                    variation="inverted-tertiary"
                    href={action.href}
                    target={action.target}
                    rel={action.rel}
                    download={action.download}
                    onClick={this.handleActionClick}>
                    {action.label}
                  </Button>
                </div>
              </div>
            )}
          </div>
          {dismissable && (
            <div className="pt2 pt0-ns">
              <div
                className="vtex-alert__close-icon pointer flex items-center pa3 white nr3 nv3"
                onClick={this.handleCloseClick}>
                <CloseIcon color="currentColor" size={16} />
              </div>
            </div>
          )}
        </div>
      </div>
    )
  }
}

Toast.propTypes = {
  onClose: PropTypes.func.isRequired,
  message: PropTypes.string.isRequired,
  horizontalPosition: PropTypes.oneOf(['left', 'right']),
  action: PropTypes.shape({
    label: PropTypes.string.isRequired,
    onClick: PropTypes.func,
    href: PropTypes.string,
    target: PropTypes.string,
    rel: PropTypes.string,
    download: PropTypes.string,
  }),
  keepAfterUpdate: PropTypes.string,
  visible: PropTypes.bool,
  duration: PropTypes.number,
  dismissable: PropTypes.bool,
}

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Pagination/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'

import CaretLeft from '../icon/CaretLeft'
import CaretRight from '../icon/CaretRight'
import ButtonWithIcon from '../ButtonWithIcon'
import Dropdown from '../Dropdown'
import PageIndicator from './PageIndicator'

const caretLeft = <CaretLeft />
const caretRight = <CaretRight />

class Pagination extends PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      selectedRowsOptionIndex: 0,
    }
  }

  handleRowsChange = (e, value) => {
    const { rowsOptions } = this.props
    const optionIndex = rowsOptions.indexOf(parseInt(value, 10))
    this.setState({ selectedRowsOptionIndex: optionIndex })
    this.props.onRowsChange && this.props.onRowsChange(e, value)
  }

  handlePrevPage = e => {
    this.props.onPrevClick && this.props.onPrevClick(e)
  }

  handleNextPage = e => {
    this.props.onNextClick && this.props.onNextClick(e)
  }

  createRowOptions = rowsOptions => {
    if (rowsOptions) {
      const opts = []
      rowsOptions.forEach(o => opts.push({ label: o, value: o }))
      return opts
    }
    return null
  }

  render() {
    const {
      rowsOptions,
      totalItems,
      currentItemFrom,
      currentItemTo,
      textOf,
      textShowRows,
      selectedOption,
      hasPageTopIndicator,
      itemLabel,
      testIds,
    } = this.props
    const { selectedRowsOptionIndex } = this.state

    const dropdownOptions = this.createRowOptions(rowsOptions)

    const isPrevDisabled = currentItemFrom <= 1
    const isNextDisabled = currentItemTo >= totalItems

    const itemTo = currentItemTo > totalItems ? totalItems : currentItemTo

    return (
      <div className="flex flex-column">
        {hasPageTopIndicator && (
          <div className="mt2 mb5">
            <PageIndicator
              currentItemFrom={currentItemFrom}
              itemTo={itemTo}
              textOf={textOf}
              totalItems={totalItems}
              itemLabel={itemLabel}
            />
          </div>
        )}
        {this.props.children}
        <div
          className={classNames([
            'flex flex-row items-center',
            {
              'justify-between': rowsOptions,
              'justify-end': !rowsOptions,
            },
          ])}>
          {dropdownOptions && (
            <div className="flex flex-row pt5 items-baseline">
              <span className="mr4 c-muted-2 t-small self-center">
                {textShowRows}
              </span>
              <Dropdown
                size="small"
                options={dropdownOptions}
                selectTestId={testIds.rowsOptions}
                value={
                  selectedOption ||
                  dropdownOptions[selectedRowsOptionIndex].label
                }
                onChange={this.handleRowsChange}
              />
            </div>
          )}

          <div className="flex flex-row pt5 items-center">
            <PageIndicator
              currentItemFrom={currentItemFrom}
              itemTo={itemTo}
              textOf={textOf}
              totalItems={totalItems}
              testId={testIds.pageIndicator}
            />
            <div className="ml4">
              <ButtonWithIcon
                icon={caretLeft}
                variation="secondary"
                size="small"
                disabled={isPrevDisabled}
                onClick={this.handlePrevPage}
                testId={testIds.prevBtn}
              />
            </div>
            <div className="ml2">
              <ButtonWithIcon
                icon={caretRight}
                variation="secondary"
                size="small"
                disabled={isNextDisabled}
                onClick={this.handleNextPage}
                testId={testIds.nextBtn}
              />
            </div>
          </div>
        </div>
      </div>
    )
  }
}

Pagination.defaultProps = {
  rowsOptions: null,
  hasPageTopIndicator: false,
  testIds: {},
}

Pagination.propTypes = {
  children: PropTypes.node,

  rowsOptions: PropTypes.array,
  currentItemFrom: PropTypes.number.isRequired,
  currentItemTo: PropTypes.number.isRequired,
  textOf: PropTypes.node.isRequired,
  textShowRows: PropTypes.node.isRequired,
  totalItems: PropTypes.number.isRequired,
  itemLabel: PropTypes.string,
  /**
   * Use this prop if you want to control the number of rows selected, instead of leaving it to the Pagination component.
   */
  selectedOption: PropTypes.number,

  onRowsChange: PropTypes.func,
  onNextClick: PropTypes.func,
  onPrevClick: PropTypes.func,

  hasPageTopIndicator: PropTypes.bool,

  testIds: PropTypes.shape({
    rowsOptions: PropTypes.string,
    prevBtn: PropTypes.string,
    nextBtn: PropTypes.string,
    pageIndicator: PropTypes.string,
  }),
}

export default Pagination

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Pagination/README.md from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```markdown
```js
  <div>
    <Pagination
      rowsOptions={[5,10,15,20]}
      currentItemFrom={1}
      currentItemTo={10}
      textOf="de"
      textShowRows="show rows"
      totalItems={20}
    />
  </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 store-on-localhost/src/monobloco/components/new/Styleguide/components/Pagination/PageIndicator.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'

function PageIndicator({
  currentItemFrom,
  itemTo,
  textOf,
  totalItems,
  itemLabel,
  testId,
}) {
  return (
    <div className="c-muted-2 t-small" data-testid={testId}>
      {`${currentItemFrom} - ${itemTo} `}
      {textOf} {totalItems} {itemLabel}
    </div>
  )
}

PageIndicator.defaultProps = {
  itemLabel: '',
}

PageIndicator.propTypes = {
  currentItemFrom: PropTypes.number.isRequired,
  itemTo: PropTypes.number.isRequired,
  textOf: PropTypes.string.isRequired,
  totalItems: PropTypes.node.isRequired,
  itemLabel: PropTypes.node,
  testId: PropTypes.string,
}

export default PageIndicator

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/TimePicker/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'

import DatePicker from '../DatePicker'
import IconClock from '../icon/Clock'
import { withForwardedRef, refShape } from '../../modules/withForwardedRef'

function TimePicker(props) {
  return (
    <DatePicker
      {...props}
      ref={props.forwardedRef}
      timeIntervals={props.interval}
      prefix={<IconClock />}
      useTimeOnly
    />
  )
}

TimePicker.propTypes = {
  /** @ignore Forwarded Ref */
  forwardedRef: refShape,
  /** Popper alignment in relation to the input */
  align: PropTypes.oneOf(['left', 'right']),
  /** Spec attribute  */
  autoFocus: PropTypes.bool,
  /** Popper position in relation to the input */
  direction: PropTypes.oneOf(['down', 'up']),
  /** Spec attribute  */
  disabled: PropTypes.bool,
  /** Error highlight  */
  error: PropTypes.bool,
  /** Error message  */
  errorMessage: PropTypes.string,
  /** Times to be excluded  */
  excludeTimes: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
  /** Help text  */
  helpText: PropTypes.node,
  /** Spec attribute  */
  id: PropTypes.string,
  /** Times to be included  */
  includeTimes: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
  /** Interval between times */
  interval: PropTypes.oneOf([5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]),
  /** Label  */
  label: PropTypes.string,
  /** Locale string ('en-US', 'pt-BR', ...)  */
  locale: PropTypes.string.isRequired,
  /** Spec attribute  */
  name: PropTypes.string,
  /** onChange event  */
  onChange: PropTypes.func.isRequired,
  /** onFocus event  */
  onFocus: PropTypes.func,
  /** onBlur event  */
  onBlur: PropTypes.func,
  /** Placeholder text  */
  placeholder: PropTypes.string,
  /** Spec attribute  */
  readOnly: PropTypes.bool,
  /** Spec attribute  */
  required: PropTypes.bool,
  /** TimePicker size  */
  size: PropTypes.oneOf(['small', 'regular', 'large']),
  /** Spec attribute  */
  tabIndex: PropTypes.string,
  /** Interval between times (in min)  */
  intervals: PropTypes.number,
  /** Value of the selected time  */
  value: PropTypes.instanceOf(Date).isRequired,
}

export default withForwardedRef(TimePicker)

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/TimePicker/README.md from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```markdown
#### A TimePicker lets the user select a single time.

### 👎 Don'ts

- Time suggestions should help the user to find an option more easily given its context of use (per hour, every half hour, 15 minutes, etc.) so we do not recommend using intervals shorter than 5 minutes.

### Supported locales

You can check out the list of supported locales [here](https://github.com/date-fns/date-fns/blob/master/src/locale/index.js).

Simple _TimePicker_

```js
initialState = { date1: undefined, date2: undefined, date3: undefined }
;

    <TimePicker
      label="Small"
      size="small"
      placeholder="Select a time or type a custom one..."
      value={state.date1}
      onChange={date => setState({ date1: date })}
      locale="pt-BR"
    />

    <TimePicker
      label="Regular"
      placeholder="Select a time or type a custom one..."
      value={state.date2}
      onChange={date => setState({ date2: date })}
      locale="pt-BR"
    />

    <TimePicker
      label="Large"
      placeholder="Select a time or type a custom one..."
      size="large"
      value={state.date3}
      onChange={date => setState({ date3: date })}
      locale="pt-BR"
    />

```

Locale

```js
const RadioGroup = require('../RadioGroup').default
initialState = { locale: 'pt-BR', date: undefined }
;

    <RadioGroup
      name="locale"
      label="Choose locale for DateTimePicker"
      options={[
        { value: 'pt-BR', label: 'pt-BR' },
        { value: 'en-US', label: 'en-US' },
        { value: 'en-GB', label: 'en-GB' },
        { value: 'es', label: 'es' },
      ]}
      value={state.locale}
      onChange={e => setState({ locale: e.target.value })}
    />

    <TimePicker
      placeholder="Select a time or type a custom one..."
      locale={state.locale}
      value={state.date}
      onChange={date => setState({ date })}
    />

```

Using ref

```js
const Button = require('../Button').default
initialState = { date: undefined }
const ref = React.createRef()
;

    <TimePicker
      ref={ref}
      label="Click in the button below to focus on this TimePicker"
      placeholder="Select a time or type a custom one..."
      value={state.date}
      onChange={date => setState({ date })}
      locale="pt-BR"
    />

    <Button onClick={() => ref.current.setFocus()}>Focus!</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 store-on-localhost/src/monobloco/components/new/Styleguide/components/Tooltip/index.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import PropTypes from 'prop-types'
import React, { FC, cloneElement, Children } from 'react'

import TooltipPopup, { Position, Size } from './TooltipPopup'
import { useTooltip, Trigger } from './hooks'

const propTypes = {
  /** Label to be shown. As element, can be a string, number...*/
  label: PropTypes.node.isRequired,
  /** Tooltip position */
  position: PropTypes.oneOf<Position>(['top', 'right', 'bottom', 'left']),
  /** Tooltip font size */
  size: PropTypes.oneOf<Size>(['mini', 'small']),
  /** Fallback position. Used when the tooltip cannot be shown in the original position */
  fallbackPosition: PropTypes.oneOf<Position>([
    'top',
    'right',
    'bottom',
    'left',
  ]),
  /** Event to trigger the tooltip */
  trigger: PropTypes.oneOf<Trigger>(['click', 'hover', 'focus']),
  /** Element that will trigger the event */
  children: PropTypes.element.isRequired,
  /** Delay to show and hide the tooltip (ms) */
  delay: PropTypes.number,
  /** Tooltip animation duration (ms) */
  duration: PropTypes.number,
  /** Tooltip timming function used to animate the tooltip */
  timmingFn: PropTypes.string,
}

type Props = PropTypes.InferProps<typeof propTypes>

const defaultProps: Props = {
  trigger: 'hover',
  position: 'top',
  size: 'small',
  delay: 0,
  duration: 200,
  timmingFn: 'ease-in-out',
}

const Tooltip: FC<Props> = ({ trigger, children, ...popupProps }) => {
  const [handleTooltip, tooltip] = useTooltip({ trigger })
  const child = Children.only(children)
  return (
    <>
      <TooltipPopup {...tooltip} {...popupProps} />
      {cloneElement(child, handleTooltip(child))}
    </>
  )
}

Tooltip.propTypes = propTypes
Tooltip.defaultProps = defaultProps

export default Tooltip

```


[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-on-localhost/src/monobloco/components/new/Styleguide/components/Tooltip/tooltip.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
.popup {
  max-height: 11rem;
  will-change: transform;
}

```