@bluexlab/bluex-components

Commonly used UI components for the BlueXTrade code ecosystem

Usage no npm install needed!

<script type="module">
  import bluexlabBluexComponents from 'https://cdn.skypack.dev/@bluexlab/bluex-components';
</script>

README

bluex-components

Installation

npm install @bluexlab/bluex-components

Mocking in unit tests

You can expand on this, but the most basic working mock works as follows:

jest.mock('@bluexlab/bluex-components', () => ({
  MaskedInput: { name: 'MaskedInput' },
  Dropdown: { name: 'Dropdown' }
}))

Components

  • Checkbox
  • DatePicker
  • Dropdown
  • InputWithDropdown
  • MaskedInput
  • Modal
  • PaginationBar
  • PlaintextDropdown
  • RadioButton
  • Searchbar
  • Toggle
  • Tooltip

Designs and colors are all based on BlueX design specs

https://zpl.io/2yqw11L

https://zpl.io/VQRdJyA

Even though these are Vue components, if you'd like to understand the choices I made for the functionality of these components, read up on React controlled components and React Native components.

Examples from React Native (so you can see the similarities):
TextInput
Switch
AlertIOS

A note on input masks

If you're not using an input mask, any component that accepts input will default to ascii only input. These components are designed for BluexTrade engineering. Ascii only was a company decision. You can get around this by passing an empty object to the :mask prop.

Checkbox

Custom checkbox component to meet design specs

Props:

Prop type(s) Description
checkboxId string, number (required) Used for input ID and label for value.
label string, number (required) Used for the label string to the right of the text box.
selected boolean (required) Whether the checkbox is checked or not.
onToggle function (required) Is called when checked/unchecked. Parent should update the selected prop.

Example:

<Checkbox
  :checkbox-id="'someCheckbox'"
  :label="$t('some_locale_string')"
  :selected="someCheckboxSelected"
  :on-select="handleClickCheckbox"
/>

DatePicker

Wraps vue2-datepicker plugin in a custom component

Props:

Prop type(s) Description
date string, date, number (optional) Even though this is marked as optional, it needs to be received by the component. A null value is allowed, which does not work with prop type checking. So date defaults to "null".
startDate date (optional) Allows setting a start date. Use moment().toDate()
required boolean (optional) Will show an asterisk and be used when checking if a selection has been made.
onChange function Called when date is changed. Parent should update date prop.
promptRequired boolean (optional) If required is true, and promptRequired is true, dropdown will show a red border and message below it. When a selection is made, the border and message are hidden
title string (optional) Title display above the date picker input.
errorMessage string Message to show when required and promptRequired are true. Defaults to "This is a required field. Please complete this field to continue" as received from en.json.

Example:

<DatePicker
  :date="dateForPicker"
  :on-change="handleDateChange"
/>

Dropdown

Acts like a React controlled component. Uses vue-inputmask. Can be used as a traditional listbox with no input (but will jump to a match if you start typing while it's focused), works with keyboard navgation (arrow up, down, enter, tab), and can also act as a searchbar similar to those seen on search engines.

Props:

Prop type(s) Description
value string, number (required) String or number for the currently selected or active item.
onSelect function (required) Called on select. Parent should then update value prop with data from selection.
onInput function (required) Called on input. Parent should then update value prop with data from selection.
onBlur function (optional) Called on blur.
onFocus function (optional) Called on focus.
data array of objects (required) A data array of objects with keys:
id: Used when returning data
value: String or number for currently selected item
valueForBackend: The value used for your GraphQL mutation.
nested: An optional array to include nested objects with the same structure. This only goes one level deep.
mask object (optional) Used for masked input. Use or add to directives/inputMasks.js. If no mask is provided, it will default to ASCII only for searchable (accepts input) and no mask for non-searchable (for example, this will allow Chinese text to render for the chosen item)
type string input type (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#%3Cinput%3E_types)
title string (optional) Title display above the dropdown.
placeholder string (optional) Placeholder text.
required boolean (optional) Will show an asterisk and be used when checking if a selection has been made.
promptRequired boolean (optional) If required is true, and promptRequired is true, dropdown will show a red border and message below it. When a selection is made, the border and message are hidden.
showArrow boolean Show or hide the arrow indicating it's a dropdown. Defaults to true.
maxToShow number Maximum dropdown items to show when open before scrolling
searchable boolean If not set, you'll get the default behavior of a dropdown. Click to show items, select an item and it closes. If searchable="true", it acts as an input with results displaying in the dropdown list.
errorMessage string Message to show when required and promptRequired are true. Defaults to "This is a required field. Please complete this field to continue" as received from en.json.
disableDropdown boolean disables dropdown by using pointer-events: none and adds opacity
labelInside boolean Uses style seen in Quotes Search pages (the label is inside the input instead of above it)

Example:

<Dropdown
  :data="arrayForDropdown"
  :title="$t('your_locale_string')"
  :on-select="handleDropdownSelection"
  :searchable="false"
  :value="dropdownValue"
/>

InputWithDropdown

Dropdown and MaskedInput combined

Prop type(s) Description
inputValue string, number (required) String or number for the currently typed input.
dropdownValue string, number (required) String or number for the currently selected or active item.
onSelect function (required) Called on select. Parent should then update value prop with data from selection.
onInput function (required) Called on input. Parent should then update value prop with data from selection.
dropdownData array of objects (required) A data array of objects with keys:
id: Used when returning data
value: String or number for currently selected item
valueForBackend: The value used for your GraphQL mutation.
mask object (optional) Used for masked input. Use or add to directives/inputMasks.js.
type string input type (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#%3Cinput%3E_types)
title string (optional) Title display above the dropdown.
placeholder string (optional) Placeholder text.
required boolean (optional) Will show an asterisk and be used when checking if a selection has been made.
promptRequired boolean (optional) If required is true, and promptRequired is true, dropdown will show a red border and message below it. When a selection is made, the border and message are hidden.
maxToShow number (optional) Maximum dropdown items to show when open before scrolling
errorMessage string (optional) Message to show when required and promptRequired are true. Defaults to "This is a required field. Please complete this field to continue" as received from en.json.
v object (optional) object for vuelidate plugin
autocomplete string (optional) allows custom autocomplete setting (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete)
disableInput boolean disables text input by using pointer-events: none and adds opacity
disableDropdown boolean disables dropdown by using pointer-events: none and adds opacity

Example:

<InputWithDropdown
  :title="$t('locale_string')"
  :on-input="handleInput"
  :input-value="inputValue"
  :dropdown-value="dropdownValue"
  :on-select="handleSelect"
  :dropdown-data="arrayForDropdown"
/>

MaskedInput

Acts like a React controlled component. Uses vue-inputmask. On blur, leading and trailing whitespace is trimmed and returned to the parent via onInput.

Props:

Prop type(s) Description
value string, number (required) String or number for the currently selected or active item.
onInput function (required) Called on input and returns inputed string value. Parent should then update value prop with data from selection.
onBlur function (optional) Called on blur. Returns entire element object.
onFocus function (optional) Called on focus. Returns entire element object.
mask object (optional) Used for masked input. Use or add to directives/inputMasks.js. Defaults to ASCII, pass an
empty object to allow all text
type string (optional) HTML input type
title string (optional) Title display above the input.
disabled boolean If true, input will be disabled and style will reflect that it cannot be edited.
placeholder string (optional) Placeholder text.
required boolean (optional) Will show an asterisk and be used when checking if a selection has been made.
promptRequired boolean (optional) If required is true, and promptRequired is true, dropdown will show a red border and message below it. When a selection is made, the border and message are hidden.
errorMessage string Message to show when required and promptRequired are true. Defaults to "This is a required field. Please complete this field to continue" as received from en.json.

Example:

<MaskedInput
  :title="$t('locale_string')"
  :on-input="handleInput"
  :required="true"
  :prompt-required="promptRequiredBool"
  :value="inputValue"
/>

Modal (can also be an error alert)

A modal component is in App.vue. You can render it via Vuex action (structure based on React Native's Alert component) which has been attached globally. You'll have to create this action in your code base and simply render Modal conditionally. Here's an example:

<Modal
  v-if="showModal"
  :settings="modalSettings"
  :close="closeModal"
/>

...

<script>
export {
  ...
  data () {
    ...
    showModal: false,
    modalSettings: {}
  },
  mounted () {
    this.vuexUnsubscribe = this.$store.subscribe(({ payload, type }) => {
      switch (type) {
        case 'setShowModal':
          this.showModal = true
          this.modalSettings = payload
          break
        ...
      }
    })
  }
}
</script>

// Show
  this.$toggleModal({
    modalType: 'confirmDelete', // If not included Modal will default to a generic modal
    title: $t('confirm_logout'),
    message: $t('cannot_be_undone'),
    buttons: [
      {
        title: $t('cancel'), // Required
        className: 'gray' // Styles button. className must match an existing button class as seen in app.scss
      },
      {
        title: $t('delete'),
        onClick: () => this.commitDelete(uuid), // If not included, Modal will close on click
        className: 'warning'
      }
    ],
    cancelable: false, // Optional. If true or not defined, clicking outside of the modal will close it. If false, close(x) button will be hidden.
  })
// Hide
this.$toggleModal({})

Available modalTypes and resulting bahavior:
confirmAction: Shows warning symbol (exclamation point in a triangle).
confirmDelete: Shows trashcan icon and default confirmation button color is red.
confirmSuccess: Shows a checkmark in a circle.
confirmInfo: Shows the letter "i" in a circle.

If modalType is received, Modal will render a plain modal with no image in the center and all buttons will be gray unless className is added to a button object

PaginationBar

As seen in bookings and documents list. Has previous and next bottons, and individual buttons for each page.

Props:

Prop type(s) Description
pageSize number (required) Number of pages per group. Correlates with your GraphQL API pageSize
numberOfResults number (required) Total number of available results
currentPage number (required) Current page in view
onClickNext function (required) Callback function so you can get the next page if it exists
onClickPrev function (required) Callback function so you can go back a page (will not be called if on the first page
jumpToPage function (required) Callback function so you can get the current page from the API or local state
pageRange number (optional) Used to determine how many pages to show in the bar before displaying ellipsis

Example:

<PaginationBar
  :page-size="pageSize"
  :number-of-results="totalResults"
  :current-page="currentPage"
  :on-click-next="handleNext"
  :on-click-prev="handlePrevious"
  :jump-to-page="jumpToPage"
/>

PlaintextDropdown

A dropdown/listbox that does not accept typed input/searching. The seleted item is displayed as plain text, not inside of a container, and the list appears beneath it when clicked.

Prop type(s) Description
selected string, number (required) String or number for the currently selected or active item.
items array (required) Items to display in the dropdown list
onSelect function (required) Called on select. Parent should then update value prop with data from selection.

Example:

<PlaintextDropdown
  :selected="selected"
  :items="arrayForDropdown"
  :on-select="handleSelect"
/>

RadioButton

Custom radio button

Prop type(s) Description
radioId string, number (required) Used to assign the label to the input
checked boolean (required) https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefchecked
onChange function (required) Returns radio ID prop to parent to determine that it's the currently selected radio button (because radio buttons should be selected one at a time)
label string (optional) Label text displayed next to the radio control

Example:

<RadioButton
  :label="'radio-button-1'"
  :radio-id="'radioButton1'"
  :checked="selected === 'radioButton1'"
  :on-change="handleSelect"
/>

Searchbar

Custom styled searchbar

Prop type(s) Description
onInput function (required) Called on input. Parent should then update value prop with entered string
value string, number (required) String or number for the currently inputted text
placeholder string (optional) Shows placeholder in text input
promptRequired boolean (optional) When true, it will add a class which outlines the input in red. Set to false to remove
onClear function (required) Called when input is cleared via clicking the "X" image
onEnter function (required) Called when hitting the enter key

Example:

<Searchbar
  :value="searchbarValue"
  :placeholder="$t('locale_string')"
  :on-input="handleSearchBarInput"
  :on-enter="handleSearchBarSubmit"
  :on-clear="handleSearchBarClear"
/>

Toggle

Like React Natives "Switch" component, toggles on or off on click.

Prop type(s) Description
value boolean (required) Allows toggle to be on (true) or off (false)
onValueChange function (required) Called on click. Returns boolean.

Example:

<Toggle
  :on-value-change="handleToggle"
  :value="toggleValue"
/>

Tooltip

Accepts a slot for

Prop type(s) Description
loading boolean (optional) shows/hides loader gif

Example:

<Tooltip :loading="someTogglingBoolean">
  <div>your stuff</div>
</Tooltip>

For absolute positioning, use a wrapper

<div class="your-item">
  <div class="your-item-tooltip-wrapper">
    <Tooltip :loading="someTogglingBoolean">
      <div>your stuff</div>
    </Tooltip>
  </div>
</div>
.your-item {
  position: relative;
  &-tooltip-wrapper {
    position: absolute;
    top: 0;
    left: 0;
  }
}