├── .babelrc
├── .browserslistrc
├── .circleci
└── config.yml
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .istanbul.yml
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── README.md
├── config
└── design-tokens
│ ├── alerts.yml
│ ├── box-shadow.yml
│ ├── color.yml
│ ├── font-size.yml
│ ├── font-weight.yml
│ ├── gradients.yml
│ ├── grid.yml
│ ├── input.yml
│ ├── layout.yml
│ ├── table.yml
│ └── tokens.yml
├── gulpfile.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── scripts
├── README.md
├── custom-token-formats
│ ├── css-helper-colors.js
│ ├── css-helper-fills.js
│ ├── css-helper-hover-colors.js
│ ├── custom-properties-as-an-object.js
│ └── theme.js
├── icons.js
└── tokens.js
├── site
├── README.md
├── gatsby-config.js
├── gatsby-node.js
├── package-lock.json
├── package.json
└── src
│ ├── components
│ ├── action-card
│ │ ├── action-card.js
│ │ └── index.js
│ ├── documentation-content
│ │ ├── documentation-content.js
│ │ └── index.js
│ ├── navigation
│ │ ├── index.js
│ │ └── navigation.js
│ ├── prop-table
│ │ ├── index.js
│ │ └── prop-table.js
│ ├── side-nav
│ │ ├── index.js
│ │ └── side-nav.js
│ ├── toc
│ │ ├── index.js
│ │ └── toc.js
│ └── wrapper
│ │ ├── index.js
│ │ └── wrapper.js
│ ├── data
│ └── README.md
│ ├── html.js
│ ├── layouts
│ └── index.js
│ ├── pages
│ ├── 404.js
│ ├── foundations
│ │ ├── color.js
│ │ ├── design-tokens.js
│ │ ├── icons.js
│ │ ├── spacing.js
│ │ └── typography.js
│ └── index.js
│ ├── static
│ └── favicon.png
│ └── templates
│ └── component.js
├── src
├── components
│ ├── alert
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── alert.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── alert.test.js.snap
│ │ │ └── alert.test.js
│ │ ├── alert.module.css
│ │ ├── alert.react.js
│ │ ├── components
│ │ │ └── alert-popover.react.js
│ │ └── index.js
│ ├── avatar-group
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── avatar-group.examples.js
│ │ ├── __tests__
│ │ │ └── avatar-group.test.js
│ │ ├── avatar-group.module.css
│ │ ├── avatar-group.react.js
│ │ └── index.js
│ ├── avatar
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── avatar.examples.js
│ │ ├── __tests__
│ │ │ └── avatar.test.js
│ │ ├── avatar.module.css
│ │ ├── avatar.react.js
│ │ └── index.js
│ ├── button-dropdown
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── button-dropdown.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── button-dropdown.test.js.snap
│ │ │ └── button-dropdown.test.js
│ │ ├── button-dropdown.module.css
│ │ ├── button-dropdown.react.js
│ │ └── index.js
│ ├── button-group
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── button-group.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── button-group.test.js.snap
│ │ │ └── button-group.test.js
│ │ ├── button-group.module.css
│ │ ├── button-group.react.js
│ │ └── index.js
│ ├── button
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── button.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── button.test.js.snap
│ │ │ └── button.test.js
│ │ ├── button.module.css
│ │ ├── button.react.js
│ │ ├── button.react.module.css
│ │ └── index.js
│ ├── callout
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── callout.examples.js
│ │ ├── callout.module.css
│ │ ├── callout.react.js
│ │ └── index.js
│ ├── checkbox
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── checkbox.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── checkbox.test.js.snap
│ │ │ └── checkbox.test.js
│ │ ├── checkbox.module.css
│ │ ├── checkbox.react.js
│ │ └── index.js
│ ├── drop-menu
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── drop-menu.examples.js
│ │ ├── drop-menu-item.react.js
│ │ ├── drop-menu.module.css
│ │ ├── drop-menu.react.js
│ │ └── index.js
│ ├── feature-callout-card
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── feature-callout-card.examples.js
│ │ ├── feature-callout-card.module.css
│ │ ├── feature-callout-card.react.js
│ │ └── index.js
│ ├── field-hint
│ │ ├── __examples__
│ │ │ └── field-hint.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── field-hint.test.js.snap
│ │ │ └── field-hint.test.js
│ │ ├── field-hint.module.css
│ │ ├── field-hint.react.js
│ │ └── index.js
│ ├── field-label
│ │ ├── __examples__
│ │ │ └── field-label.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── field-label.test.js.snap
│ │ │ └── field-label.test.js
│ │ ├── field-label.module.css
│ │ ├── field-label.react.js
│ │ └── index.js
│ ├── field-row
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── field-row.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── field-row.test.js.snap
│ │ │ └── field-row.test.js
│ │ ├── field-row.module.css
│ │ ├── field-row.react.js
│ │ └── index.js
│ ├── field-validation
│ │ ├── field-validation.module.css
│ │ ├── field-validation.react.js
│ │ └── index.js
│ ├── field-validations
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── field-validations.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── field-validations.test.js.snap
│ │ │ └── field-validations.test.js
│ │ ├── field-validations.module.css
│ │ ├── field-validations.react.js
│ │ └── index.js
│ ├── field
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── field.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── field.test.js.snap
│ │ │ └── field.test.js
│ │ ├── field.module.css
│ │ ├── field.react.js
│ │ └── index.js
│ ├── fieldset
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── fieldset.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── fieldset.test.js.snap
│ │ │ └── fieldset.test.js
│ │ ├── fieldset.module.css
│ │ ├── fieldset.react.js
│ │ └── index.js
│ ├── form
│ │ ├── README.md
│ │ ├── __tests__
│ │ │ └── form.test.js
│ │ ├── form.react.js
│ │ └── index.js
│ ├── grid
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── grid.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── grid.test.js.snap
│ │ │ └── grid.test.js
│ │ ├── grid.module.css
│ │ ├── grid.react.js
│ │ └── index.js
│ ├── h1
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── h1.test.js.snap
│ │ │ └── h1.test.js
│ │ ├── h1.react.js
│ │ └── index.js
│ ├── h2
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── h2.test.js.snap
│ │ │ └── h2.test.js
│ │ ├── h2.react.js
│ │ └── index.js
│ ├── h3
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── h3.test.js.snap
│ │ │ └── h3.test.js
│ │ ├── h3.react.js
│ │ └── index.js
│ ├── h4
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── h4.test.js.snap
│ │ │ └── h4.test.js
│ │ ├── h4.react.js
│ │ └── index.js
│ ├── heading
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── heading.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── heading.test.js.snap
│ │ │ └── heading.test.js
│ │ ├── heading.module.css
│ │ ├── heading.react.js
│ │ └── index.js
│ ├── helper-text
│ │ ├── README.md
│ │ ├── helper-text.react.js
│ │ └── index.js
│ ├── icon-symbols
│ │ ├── icon-symbols.react.js
│ │ └── index.js
│ ├── icon
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── icon.examples.js
│ │ ├── __tests__
│ │ │ └── icon.test.js
│ │ ├── constants.js
│ │ ├── icon.module.css
│ │ ├── icon.react.js
│ │ └── index.js
│ ├── image-input
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── image-input.examples.js
│ │ ├── __tests__
│ │ │ └── image-input.test.js
│ │ ├── image-input.js
│ │ ├── image-input.module.css
│ │ ├── image-input.react.js
│ │ └── index.js
│ ├── index.js
│ ├── inline-alert
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── inline-alert.examples.js
│ │ ├── index.js
│ │ ├── inline-alert.module.css
│ │ └── inline-alert.react.js
│ ├── input
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── input.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── input.test.js.snap
│ │ │ └── input.test.js
│ │ ├── index.js
│ │ ├── input.module.css
│ │ ├── input.react.js
│ │ └── input.react.module.css
│ ├── jumbo-button
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── jumbo-button.examples.js
│ │ ├── index.js
│ │ ├── jumbo-button.js
│ │ └── jumbo-button.module.css
│ ├── layout
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── layout.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ ├── layout.test.js.snap
│ │ │ │ └── utils.test.js.snap
│ │ │ ├── layout.test.js
│ │ │ └── utils.test.js
│ │ ├── index.js
│ │ ├── layout.react.js
│ │ ├── layout.react.module.css
│ │ └── utils.js
│ ├── loading-spinner
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── loading-spinner.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── loading-spinner.test.js.snap
│ │ │ └── loading-spinner.test.js
│ │ ├── index.js
│ │ ├── loading-spinner.module.css
│ │ └── loading-spinner.react.js
│ ├── lozenge
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── lozenge.examples.js
│ │ ├── index.js
│ │ ├── lozenge.module.css
│ │ └── lozenge.react.js
│ ├── modal
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── modal.examples.js
│ │ ├── index.js
│ │ ├── modal.module.css
│ │ └── modal.react.js
│ ├── paper-menu
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── paper-menu.examples.js
│ │ ├── components
│ │ │ ├── paper-menu-item.module.css
│ │ │ └── paper-menu-item.react.js
│ │ ├── index.js
│ │ ├── paper-menu.module.css
│ │ └── paper-menu.react.js
│ ├── paper
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── paper.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── paper.test.js.snap
│ │ │ └── paper.test.js
│ │ ├── components
│ │ │ ├── paper-toolbar.module.css
│ │ │ └── paper-toolbar.react.js
│ │ ├── index.js
│ │ ├── paper.module.css
│ │ └── paper.react.js
│ ├── radio
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── radio.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── radio.test.js.snap
│ │ │ └── radio.test.js
│ │ ├── index.js
│ │ ├── radio.module.css
│ │ └── radio.react.js
│ ├── seamless-button
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── seamless-button.examples.js
│ │ ├── index.js
│ │ ├── seamless-button.module.css
│ │ └── seamless-button.react.js
│ ├── select
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── select.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── select.test.js.snap
│ │ │ └── select.test.js
│ │ ├── index.js
│ │ ├── option.react.js
│ │ ├── select.module.css
│ │ ├── select.react.js
│ │ └── select.react.module.css
│ ├── service-tag
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── service-tag.examples.js
│ │ ├── __tests__
│ │ │ └── service-tag.test.js
│ │ ├── index.js
│ │ ├── service-tag.module.css
│ │ └── service-tag.react.js
│ ├── skeleton
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── skeleton.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── skeleton.test.js.snap
│ │ │ └── skeleton.test.js
│ │ ├── components
│ │ │ ├── skeleton-avatar.react.js
│ │ │ ├── skeleton-button.react.js
│ │ │ ├── skeleton-card.react.js
│ │ │ ├── skeleton-content.react.js
│ │ │ ├── skeleton-grid.react.js
│ │ │ ├── skeleton-list-item.react.js
│ │ │ ├── skeleton-list.react.js
│ │ │ ├── skeleton-page-header-heading.react.js
│ │ │ ├── skeleton-page-header-tabs.react.js
│ │ │ ├── skeleton-page-header-toolbar.react.js
│ │ │ ├── skeleton-page-header.react.js
│ │ │ ├── skeleton-page.react.js
│ │ │ ├── skeleton-paper.react.js
│ │ │ ├── skeleton-shape.react.js
│ │ │ ├── skeleton-spacer-box.react.js
│ │ │ └── skeleton-text.react.js
│ │ ├── index.js
│ │ ├── skeleton.module.css
│ │ └── skeleton.react.js
│ ├── star-rating
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── star-rating.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── star-rating.test.js.snap
│ │ │ └── star-rating.test.js
│ │ ├── index.js
│ │ ├── star-rating.module.css
│ │ └── star-rating.react.js
│ ├── sticky
│ │ ├── index.js
│ │ └── sticky.react.js
│ ├── table
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── table.examples.js
│ │ ├── __tests__
│ │ │ ├── table-body.test.js
│ │ │ ├── table-cell.test.js
│ │ │ ├── table-head.test.js
│ │ │ ├── table-row.test.js
│ │ │ └── table.test.js
│ │ ├── index.js
│ │ ├── table-body.react.js
│ │ ├── table-cell.react.js
│ │ ├── table-head.react.js
│ │ ├── table-row.react.js
│ │ ├── table.module.css
│ │ └── table.react.js
│ ├── tabs
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── tabs.examples.js
│ │ ├── __tests__
│ │ │ └── tabs.test.js
│ │ ├── index.js
│ │ ├── tab.react.js
│ │ ├── tabs.module.css
│ │ └── tabs.react.js
│ ├── tag-group
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── tag-group.examples.js
│ │ ├── __tests__
│ │ │ └── tag-group.test.js
│ │ ├── index.js
│ │ ├── tag-group.module.css
│ │ └── tag-group.react.js
│ ├── tag
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── tag.examples.js
│ │ ├── index.js
│ │ ├── tag.module.css
│ │ └── tag.react.js
│ ├── text
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── text.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── text.test.js.snap
│ │ │ └── text.test.js
│ │ ├── constants.js
│ │ ├── index.js
│ │ ├── text.module.css
│ │ └── text.react.js
│ ├── textarea
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── textarea.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── textarea.test.js.snap
│ │ │ └── textarea.test.js
│ │ ├── index.js
│ │ ├── textarea.module.css
│ │ └── textarea.react.js
│ ├── toggle-button
│ │ ├── README.md
│ │ ├── __examples__
│ │ │ └── toggle-button.examples.js
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── toggle-button.test.js.snap
│ │ │ └── toggle-button.test.js
│ │ ├── index.js
│ │ ├── toggle-button.module.css
│ │ └── toggle-button.react.js
│ └── tooltip-box
│ │ ├── README.md
│ │ ├── __examples__
│ │ └── tooltip-box.examples.js
│ │ ├── __tests__
│ │ ├── __snapshots__
│ │ │ └── tooltip-box.test.js.snap
│ │ └── tooltip-box.test.js
│ │ ├── index.js
│ │ ├── tooltip-box.module.css
│ │ └── tooltip-box.react.js
├── design-tokens
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ └── tokens.test.js.snap
│ │ └── tokens.test.js
│ ├── kalo-ui-colors.module.css
│ ├── kalo-ui-fills.module.css
│ ├── kalo-ui-hover-colors.module.css
│ ├── kalo-ui.sketchpalette
│ ├── tokens.css
│ ├── tokens.css.js
│ ├── tokens.js
│ ├── tokens.json
│ ├── tokens.module.js
│ ├── tokens.scss
│ └── tokens.theme.js
├── icons
│ └── svg
│ │ ├── access_time.svg
│ │ ├── account_balance.svg
│ │ ├── account_balance_wallet.svg
│ │ ├── account_box.svg
│ │ ├── account_circle.svg
│ │ ├── add.svg
│ │ ├── add_a_photo.svg
│ │ ├── archive.svg
│ │ ├── arrow_drop_down.svg
│ │ ├── arrow_drop_down_circle.svg
│ │ ├── arrow_drop_up.svg
│ │ ├── art_track.svg
│ │ ├── assignment.svg
│ │ ├── assignment_ind.svg
│ │ ├── attach_file.svg
│ │ ├── attach_money.svg
│ │ ├── autorenew.svg
│ │ ├── book.svg
│ │ ├── border_color.svg
│ │ ├── chat.svg
│ │ ├── check.svg
│ │ ├── check_box.svg
│ │ ├── check_box_outline_blank.svg
│ │ ├── check_circle.svg
│ │ ├── check_circle_outline.svg
│ │ ├── chevron_left.svg
│ │ ├── chevron_right.svg
│ │ ├── clear.svg
│ │ ├── close.svg
│ │ ├── comment.svg
│ │ ├── content_paste.svg
│ │ ├── create.svg
│ │ ├── credit_card.svg
│ │ ├── date_range.svg
│ │ ├── delete.svg
│ │ ├── domain.svg
│ │ ├── done.svg
│ │ ├── done_all.svg
│ │ ├── dribbble.svg
│ │ ├── edit.svg
│ │ ├── email.svg
│ │ ├── error_outline.svg
│ │ ├── exit_to_app.svg
│ │ ├── extension.svg
│ │ ├── file_upload.svg
│ │ ├── file_xls.svg
│ │ ├── folder_shared.svg
│ │ ├── format_color_fill.svg
│ │ ├── globe.svg
│ │ ├── group.svg
│ │ ├── help_outline.svg
│ │ ├── highlight_off.svg
│ │ ├── how_to_reg.svg
│ │ ├── info.svg
│ │ ├── info_outline.svg
│ │ ├── insert_drive_file.svg
│ │ ├── instagram.svg
│ │ ├── kalo_admin.svg
│ │ ├── kalo_categories.svg
│ │ ├── kalo_clients.svg
│ │ ├── kalo_finance.svg
│ │ ├── kalo_index.svg
│ │ ├── kalo_messages.svg
│ │ ├── kalo_premium.svg
│ │ ├── kalo_projects.svg
│ │ ├── kalo_reporting.svg
│ │ ├── kalo_tasks.svg
│ │ ├── kalo_verified.svg
│ │ ├── keyboard_arrow_down.svg
│ │ ├── keyboard_arrow_left.svg
│ │ ├── keyboard_arrow_right.svg
│ │ ├── keyboard_arrow_up.svg
│ │ ├── keyboard_return.svg
│ │ ├── launch.svg
│ │ ├── link.svg
│ │ ├── linkedin.svg
│ │ ├── local_atm.svg
│ │ ├── local_offer.svg
│ │ ├── location_city.svg
│ │ ├── location_on.svg
│ │ ├── lock.svg
│ │ ├── loop.svg
│ │ ├── mail.svg
│ │ ├── megaphone.svg
│ │ ├── message.svg
│ │ ├── mode_edit.svg
│ │ ├── monetization_on.svg
│ │ ├── more_vert.svg
│ │ ├── note_add.svg
│ │ ├── notifications.svg
│ │ ├── open_in_new.svg
│ │ ├── payment.svg
│ │ ├── people.svg
│ │ ├── perm_contact_calendar.svg
│ │ ├── perm_identity.svg
│ │ ├── person.svg
│ │ ├── person_add.svg
│ │ ├── person_outline.svg
│ │ ├── phone.svg
│ │ ├── picture_as_pdf.svg
│ │ ├── playlist_add_check.svg
│ │ ├── present_to_all.svg
│ │ ├── question_help_message.svg
│ │ ├── radio_button_checked.svg
│ │ ├── receipt.svg
│ │ ├── remove.svg
│ │ ├── remove_circle.svg
│ │ ├── remove_red_eye.svg
│ │ ├── search.svg
│ │ ├── security.svg
│ │ ├── send.svg
│ │ ├── settings.svg
│ │ ├── short_text.svg
│ │ ├── star.svg
│ │ ├── swap_vert.svg
│ │ ├── tv.svg
│ │ ├── twitter.svg
│ │ ├── verified_user.svg
│ │ ├── view_headline.svg
│ │ ├── view_module.svg
│ │ ├── view_week.svg
│ │ ├── warning.svg
│ │ ├── website.svg
│ │ └── youtube.svg
├── styles
│ ├── kalo-ui-base.css
│ ├── kalo-ui-transitions.css
│ └── kalo-ui-typography.css
└── utils
│ ├── __tests__
│ ├── array.test.js
│ ├── dom.test.js
│ ├── enum.test.js
│ └── string.test.js
│ ├── array.js
│ ├── dom.js
│ ├── enum.js
│ ├── react.js
│ ├── string.js
│ ├── style.js
│ ├── style
│ ├── prop-whitelist.js
│ └── style-whitelist.js
│ ├── test
│ ├── global-context.js
│ ├── mocks
│ │ └── file-mock.js
│ ├── random-string.js
│ └── react.js
│ └── type.js
└── wallaby.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "lodash",
4 | [
5 | "transform-runtime",
6 | {
7 | "polyfill": false,
8 | "regenerator": true
9 | }
10 | ],
11 | [
12 | "babel-plugin-transform-builtin-extend",
13 | {
14 | "globals": ["Error"]
15 | }
16 | ],
17 | "add-react-displayname"
18 | ],
19 | "presets": ["es2015", "react", "stage-2"],
20 | "env": {
21 | "test": {
22 | "plugins": [
23 | [
24 | "transform-runtime",
25 | {
26 | "polyfill": false,
27 | "regenerator": true
28 | }
29 | ],
30 | [
31 | "babel-plugin-transform-builtin-extend",
32 | {
33 | "globals": ["Error"]
34 | }
35 | ],
36 | "babel-plugin-transform-es2015-modules-commonjs"
37 | ]
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1% in alt-EU
2 | > 1% in alt-NA
3 | Firefox ESR
4 | last 2 iOS major versions
5 | not dead
6 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | src/design-tokens/**
2 | src/components/icon-symbols/
3 | config
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | coverage
4 | npm-debug*
5 | src/design-tokens/*
6 |
7 | ##
8 | # Documentation site
9 | ##
10 |
11 | site/public
12 | site/src/data/examples.js
13 | site/.cache
14 |
--------------------------------------------------------------------------------
/.istanbul.yml:
--------------------------------------------------------------------------------
1 | instrumentation:
2 | extensions: ['.js', '.jsx']
3 | excludes: [
4 | "docs/**",
5 | "build/**",
6 | "vendor/**",
7 | "coverage/**",
8 | "flow/**",
9 | "flow-typed/**",
10 | "webpack/**",
11 | "code-templates/**",
12 | "e2e-test/**",
13 | "src/**/components/**/index.js",
14 | "serve.js",
15 | "src/**/*manifest.js",
16 | ]
17 | include-all-sources: False
18 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v10.14.1
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "bracketSpacing": false,
5 | }
6 |
--------------------------------------------------------------------------------
/config/design-tokens/alerts.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: color
3 | category: alerts
4 | imports:
5 | - ./color.yml
6 | props:
7 | INFO:
8 | value: '#E8FAFC'
9 | CONFIRMATION:
10 | value: '#E5F7F1'
11 | ERROR:
12 | value: '#FFEBEE'
13 | WARNING:
14 | value: '#FFF6D8'
15 |
--------------------------------------------------------------------------------
/config/design-tokens/box-shadow.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: box-shadow
3 | category: layout
4 | props: &BOX_SHADOW
5 | BOX_SHADOW_LEVEL_0:
6 | value: none
7 | BOX_SHADOW_LEVEL_1:
8 | value: 0 3px 6px rgba(140, 140, 140, 0.08)
9 | BOX_SHADOW_LEVEL_2:
10 | value: 0 10px 25px rgba(140, 140, 140, 0.14)
11 | BOX_SHADOW_LEVEL_3:
12 | value: 0 12px 25px rgba(140, 140, 140, 0.21)
13 | BOX_SHADOW_LEVEL_4:
14 | value: 0 14px 25px rgba(140, 140, 140, 0.27)
15 | aliases: *BOX_SHADOW
16 |
--------------------------------------------------------------------------------
/config/design-tokens/font-size.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: font-size
3 | category: typography
4 | props:
5 | FONT_SIZE_HEADING_EXTRA_LARGE:
6 | value: 2.4rem
7 | FONT_SIZE_HEADING_LARGE:
8 | value: 2rem
9 | FONT_SIZE_HEADING_MEDIUM:
10 | value: 1.6rem
11 | FONT_SIZE_HEADING_SMALL:
12 | value: 1.4rem
13 | FONT_SIZE_HEADING_EXTRA_SMALL:
14 | value: 1rem
15 | FONT_SIZE_TEXT_EXTRA_LARGE:
16 | value: 2.4rem
17 | FONT_SIZE_TEXT_LARGE:
18 | value: 1.8rem
19 | FONT_SIZE_TEXT_MEDIUM:
20 | value: 1.6rem
21 | FONT_SIZE_TEXT_SMALL:
22 | value: 1.4rem
23 | FONT_SIZE_TEXT_EXTRA_SMALL:
24 | value: 1.2rem
25 |
--------------------------------------------------------------------------------
/config/design-tokens/font-weight.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: font-weight
3 | category: typography
4 | props:
5 | FONT_WEIGHT_LIGHT:
6 | value: 300
7 | FONT_WEIGHT_NORMAL:
8 | value: 400
9 | FONT_WEIGHT_MEDIUM:
10 | value: 500
11 | FONT_WEIGHT_SEMIBOLD:
12 | value: 600
13 | FONT_WEIGHT_BOLD:
14 | value: 700
15 |
--------------------------------------------------------------------------------
/config/design-tokens/gradients.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: background-image
3 | category: gradients
4 | props: &GRADIENTS
5 | GRADIENT_PINK_STOP_1:
6 | type: color
7 | value: '#E83F94'
8 | GRADIENT_PINK_STOP_2:
9 | type: color
10 | value: '#F54E5E'
11 | GRADIENT_PINK:
12 | value: linear-gradient(to right, {!GRADIENT_PINK_STOP_1} 0%, {!GRADIENT_PINK_STOP_2} 100%)
13 | GRADIENT_BLUE_STOP_1:
14 | type: color
15 | value: '#2DC9EB'
16 | GRADIENT_BLUE_STOP_2:
17 | type: color
18 | value: '#14D2B8'
19 | GRADIENT_BLUE:
20 | value: linear-gradient(to right, {!GRADIENT_BLUE_STOP_1} 0%, {!GRADIENT_BLUE_STOP_2} 100%)
21 | GRADIENT_PURPLE_STOP_1:
22 | type: color
23 | value: '#E62888'
24 | GRADIENT_PURPLE_STOP_2:
25 | type: color
26 | value: '#211660'
27 | GRADIENT_PURPLE:
28 | value: linear-gradient(135deg, {!GRADIENT_PURPLE_STOP_1} 0%, {!GRADIENT_PURPLE_STOP_2} 100%)
29 | GRADIENT_BLUE_TWO_STOP_1:
30 | type: color
31 | value: '#0d7ef2'
32 | GRADIENT_BLUE_TWO_STOP_2:
33 | type: color
34 | value: '#49a1fb'
35 | GRADIENT_BLUE_TWO:
36 | value: linear-gradient(135deg, {!GRADIENT_BLUE_TWO_STOP_1} 0%, {!GRADIENT_BLUE_TWO_STOP_2} 100%)
37 | aliases: *GRADIENTS
38 |
--------------------------------------------------------------------------------
/config/design-tokens/grid.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: unit
3 | category: grid
4 | props:
5 | GRID_MAX_WIDTH:
6 | value: 1200
7 |
--------------------------------------------------------------------------------
/config/design-tokens/input.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: border
3 | category: input
4 | imports:
5 | - ./color.yml
6 | props:
7 | INPUT_DEFAULT_BACKGROUND:
8 | type: color
9 | value: '{!WHITE}'
10 | INPUT_DEFAULT_BORDER:
11 | value: 1px solid {!GREY200}
12 | INPUT_DEFAULT_COLOR:
13 | type: color
14 | value: '{!NAVY900}'
15 | INPUT_HOVER_BORDER:
16 | value: 1px solid {!GREY500}
17 | INPUT_ACTIVE_BORDER:
18 | value: 1px solid {!GREY600}
19 | INPUT_DISABLED_BORDER:
20 | value: 1px solid {!GREY200}
21 | INPUT_DISABLED_BACKGROUND:
22 | type: color
23 | value: '{!GREY100}'
24 | INPUT_DISABLED_COLOR:
25 | type: color
26 | value: '{!GREY400}'
27 | INPUT_READONLY_BORDER:
28 | value: 1px dashed {!GREY200}
29 | INPUT_READONLY_BACKGROUND:
30 | type: color
31 | value: '{!GREY100}'
32 | INPUT_READONLY_COLOR:
33 | type: color
34 | value: '{!GREY400}'
35 | INPUT_PLACEHOLDER_COLOR:
36 | type: 'color'
37 | value: '{!GREY500}'
38 | INPUT_BORDER_RADIUS:
39 | type: 'border-radius'
40 | value: 4px
41 |
--------------------------------------------------------------------------------
/config/design-tokens/layout.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: unit
3 | category: layout
4 | props:
5 | SPACING_NONE:
6 | value: 0px
7 | SPACING_EXTRA_SMALL:
8 | value: 4px
9 | SPACING_SMALL:
10 | value: 8px
11 | SPACING_MEDIUM:
12 | value: 16px
13 | SPACING_LARGE:
14 | value: 24px
15 | SPACING_EXTRA_LARGE:
16 | value: 32px
17 | SPACING_EXTRA_EXTRA_LARGE:
18 | value: 48px
19 |
--------------------------------------------------------------------------------
/config/design-tokens/table.yml:
--------------------------------------------------------------------------------
1 | global:
2 | type: 'border'
3 | category: 'table'
4 | imports:
5 | - ./color.yml
6 | props:
7 | TABLE_DEFAULT_BORDER:
8 | value: 1px solid {!GREY100}
9 |
--------------------------------------------------------------------------------
/config/design-tokens/tokens.yml:
--------------------------------------------------------------------------------
1 | props: {}
2 | imports:
3 | - ./color.yml
4 | - ./gradients.yml
5 | - ./font-weight.yml
6 | - ./font-size.yml
7 | - ./box-shadow.yml
8 | - ./alerts.yml
9 | - ./grid.yml
10 | - ./layout.yml
11 | - ./table.yml
12 | - ./input.yml
13 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | const postcssPresetEnv = require('postcss-preset-env');
2 | const cssVariables = require('./src/design-tokens/tokens.css.js');
3 | const cssnano = require('cssnano');
4 |
5 | module.exports = () => ({
6 | plugins: [
7 | postcssPresetEnv({
8 | autoprefixer: {grid: true},
9 | features: {
10 | 'custom-properties': {variables: cssVariables},
11 | },
12 | }),
13 | cssnano({
14 | normalizeUrl: false,
15 | discardEmpty: false,
16 | core: false,
17 | minifyFontValues: false,
18 | discardUnused: false,
19 | zindex: false,
20 | }),
21 | ],
22 | });
23 |
--------------------------------------------------------------------------------
/scripts/custom-token-formats/css-helper-colors.js:
--------------------------------------------------------------------------------
1 | const camelCase = require('lodash/camelCase');
2 |
3 | /**
4 | * A custom token format that builds CSS helper classes
5 | * for setting the color of an element
6 | *
7 | * example: .color-navy900 { color: var(--navy900)}
8 | */
9 |
10 | module.exports = result =>
11 | `
12 | ${result
13 | .get('props')
14 | .filter(prop => prop.get('category') === 'colors')
15 | .map(
16 | prop =>
17 | `.color-${camelCase(prop.get('name'))} {
18 | ${
19 | prop.get('name') === 'CURRENT_COLOR' ||
20 | prop.get('name') === 'NONE' ||
21 | prop.get('name') === 'INHERIT'
22 | ? `color: ${camelCase(prop.get('name'))};`
23 | : `color: var(--${camelCase(prop.get('name'))});`
24 | }
25 | }
26 | `
27 | )
28 | .toJS()}
29 | `.replace(/,/g, '');
30 |
--------------------------------------------------------------------------------
/scripts/custom-token-formats/css-helper-fills.js:
--------------------------------------------------------------------------------
1 | const camelCase = require('lodash/camelCase');
2 |
3 | /**
4 | * A custom token format that builds CSS helper classes
5 | * for setting the fill of an element
6 | *
7 | * example: .fill-navy900 { color: var(--navy900)}
8 | */
9 |
10 | module.exports = result =>
11 | `
12 | ${result
13 | .get('props')
14 | .filter(prop => prop.get('category') === 'colors')
15 | .map(
16 | prop =>
17 | `.fill-${camelCase(prop.get('name'))} {
18 | ${
19 | prop.get('name') === 'CURRENT_COLOR' ||
20 | prop.get('name') === 'NONE' ||
21 | prop.get('name') === 'INHERIT'
22 | ? `fill: ${camelCase(prop.get('name'))};`
23 | : `fill: var(--${camelCase(prop.get('name'))});`
24 | }
25 | }
26 | `
27 | )
28 | .toJS()}
29 | /* Special gradient fills */
30 | .fill-gradient-pink {
31 | fill: url(#gradient-pink);
32 | }
33 | .fill-gradient-purple {
34 | fill: url(#gradient-purple);
35 | }
36 | .fill-gradient-blue-two {
37 | fill: url(#gradient-blue-two);
38 | }
39 | `.replace(/,/g, '');
40 |
--------------------------------------------------------------------------------
/scripts/custom-token-formats/css-helper-hover-colors.js:
--------------------------------------------------------------------------------
1 | const camelCase = require('lodash/camelCase');
2 |
3 | /**
4 | * A custom token format that builds CSS helper classes
5 | * for setting the color of an element on hover
6 | *
7 | * example: .color-navy900:hover { color: var(--navy900)}
8 | */
9 |
10 | module.exports = result =>
11 | `
12 | ${result
13 | .get('props')
14 | .filter(prop => prop.get('category') === 'colors')
15 | .map(
16 | prop =>
17 | `.hover-color-${camelCase(prop.get('name'))}:hover {
18 | ${
19 | prop.get('name') === 'CURRENT_COLOR' ||
20 | prop.get('name') === 'NONE' ||
21 | prop.get('name') === 'INHERIT'
22 | ? `color: ${camelCase(prop.get('name'))};`
23 | : `color: var(--${camelCase(prop.get('name'))});`
24 | }
25 | }
26 | `
27 | )
28 | .toJS()}
29 | `.replace(/,/g, '');
30 |
--------------------------------------------------------------------------------
/scripts/custom-token-formats/custom-properties-as-an-object.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A custom token format to pass in non-camelCased CSS variables
3 | * in to the post-css build step as a standard JS object.
4 | */
5 | module.exports = `
6 | module.exports = {
7 | {{#each props as |prop|}}
8 | '{{kebabcase prop.name}}': '{{prop.value}}',
9 | {{/each}}
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/scripts/custom-token-formats/theme.js:
--------------------------------------------------------------------------------
1 | const camelCase = require('lodash/camelCase');
2 |
3 | /**
4 | * A custom token format for passing into a ThemeProvider
5 | */
6 |
7 | module.exports = result => {
8 | const grouped = result.get('props').groupBy(token => token.get('category'));
9 | const collect = {};
10 |
11 | grouped.map((category, index) => {
12 | collect[index] = {};
13 | return category.map(token => {
14 | collect[index][camelCase(token.get('name'))] = token.get('value');
15 | return collect;
16 | });
17 | });
18 | return `module.exports = ${JSON.stringify(collect)}`;
19 | };
20 |
--------------------------------------------------------------------------------
/site/README.md:
--------------------------------------------------------------------------------
1 | # @kalo/ui documentation site
2 |
3 | Welcome to the @kalo-ui documentation. The docs are built using [Gatsby](https://www.gatsbyjs.org).
4 |
5 | ## Running locally
6 | - Clone the UI repo locally.
7 | - `cd site` to change in to the site directory
8 | - `npm install`
9 | - `npm run start`
10 | - And you should be up and running at [localhost:8000](http://localhost:8000)
--------------------------------------------------------------------------------
/site/src/components/action-card/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './action-card';
2 |
--------------------------------------------------------------------------------
/site/src/components/documentation-content/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './documentation-content';
2 |
--------------------------------------------------------------------------------
/site/src/components/navigation/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './navigation';
2 |
--------------------------------------------------------------------------------
/site/src/components/prop-table/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './prop-table';
2 |
--------------------------------------------------------------------------------
/site/src/components/side-nav/index.js:
--------------------------------------------------------------------------------
1 | export {default, NAV_IN_FOOTER_BREAKPOINT} from './side-nav.js';
2 |
--------------------------------------------------------------------------------
/site/src/components/toc/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './toc';
2 | export {TocTitle} from './toc';
3 |
--------------------------------------------------------------------------------
/site/src/components/toc/toc.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'react-emotion';
3 |
4 | const StyledToc = styled.div`
5 | position: sticky;
6 | top: 90px;
7 |
8 | ul {
9 | margin: 0;
10 | padding: 0;
11 | list-style: none;
12 | }
13 |
14 | ul:first-of-type li:first-of-type p {
15 | display: none;
16 | }
17 |
18 | a {
19 | text-decoration: none;
20 | color: ${props => props.theme.colors.navy600};
21 |
22 | &:hover {
23 | text-decoration: underline;
24 | }
25 | }
26 | `;
27 |
28 | const StyledTocTitle = styled.span`
29 | font-size: 12px;
30 | font-weight: 600;
31 | color: ${props => props.theme.colors.navy600};
32 | text-transform: uppercase;
33 | margin-bottom: 8px;
34 | display: block;
35 | `;
36 |
37 | export default function Toc(props) {
38 | return (
39 |
40 | Contents
41 |
42 |
50 |
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/site/src/components/wrapper/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './wrapper';
2 |
--------------------------------------------------------------------------------
/site/src/components/wrapper/wrapper.js:
--------------------------------------------------------------------------------
1 | import styled from 'react-emotion';
2 |
3 | const horizontalPadding = '5vw';
4 |
5 | export default styled.div`
6 | width: 100%;
7 | max-width: calc(780px + 2 * ${horizontalPadding});
8 | padding: 0 ${horizontalPadding};
9 | margin: 0 auto;
10 | `;
11 |
--------------------------------------------------------------------------------
/site/src/data/README.md:
--------------------------------------------------------------------------------
1 | ## ⚠️ Don't edit. The contents of this directory is autogenerated
--------------------------------------------------------------------------------
/site/src/html.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import favicon from 'static/favicon.png';
4 |
5 | let stylesStr;
6 |
7 | export default function Html({headComponents, body, postBodyComponents}) {
8 | let css;
9 | if (process.env.NODE_ENV === `production`) {
10 | css = (
11 |
16 | );
17 | }
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 | {headComponents}
31 | {css}
32 |
33 |
34 |
35 | {postBodyComponents}
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/site/src/pages/404.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFoundPage = () => (
4 |
5 |
NOT FOUND
6 |
You just hit a route that doesn't exist... the sadness.
7 |
8 | );
9 |
10 | export default NotFoundPage;
11 |
--------------------------------------------------------------------------------
/site/src/pages/foundations/spacing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import DocumentationContent from '../../components/documentation-content';
4 | import Wrapper from '../../components/wrapper';
5 |
6 | export default () => (
7 |
8 |
9 | Spacing
10 |
11 | Our spacing system is built of multiples of 8px ( 16px, 24px, 32px,
12 | 40px...)
13 |
14 |
15 | -
16 | Use multiples of 8px when defining measurements, spacing, and
17 | positioning elements.
18 |
19 | - When necessary use 4px to make more fine tuned adjustments.
20 | -
21 | Whenever possible, make sure that objects line up, both vertically and
22 | horizontally.
23 |
24 |
25 |
26 |
27 | *Our typography is based on line heights and spacing is measured from
28 | the edge of the text box
29 |
30 |
31 |
32 |
33 | );
34 |
--------------------------------------------------------------------------------
/site/src/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalohq/ui/444eea960223c1ffd87869eefc5545e10d51b320/site/src/static/favicon.png
--------------------------------------------------------------------------------
/src/components/alert/README.md:
--------------------------------------------------------------------------------
1 | # Alert
--------------------------------------------------------------------------------
/src/components/alert/__tests__/alert.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import Alert from 'components/alert';
6 |
7 | describe('Alert', () => {
8 | const defaultProps = {
9 | type: 'info',
10 | };
11 | const create = (props = {}) =>
12 | renderer
13 | .create(
14 |
19 | )
20 | .toJSON();
21 |
22 | test('should render shallow component ok', () => {
23 | const element = create();
24 | expect(element).toMatchSnapshot();
25 | });
26 |
27 | test('should render a warning alert', () => {
28 | const element = create({
29 | type: 'warning',
30 | });
31 | expect(element).toMatchSnapshot();
32 | });
33 |
34 | test('should render a confirmation alert with an icon', () => {
35 | const element = create({
36 | type: 'confirmation',
37 | showIcon: true,
38 | });
39 | expect(element).toMatchSnapshot();
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/src/components/alert/alert.module.css:
--------------------------------------------------------------------------------
1 | .ui-alert {
2 | display: inline-flex;
3 | position: relative;
4 | flex-direction: row;
5 | align-items: flex-start;
6 | justify-content: flex-start;
7 | border-radius: 4px;
8 | padding: 1.6rem 2.4rem;
9 | box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.11);
10 | width: 100%;
11 | flex: 1;
12 | }
13 |
14 | .ui-alert svg {
15 | flex-shrink: 0;
16 | }
17 |
18 | .ui-alert__content {
19 | display: flex;
20 | flex-direction: column;
21 | padding-left: 8px;
22 | }
23 |
24 | .ui-alert__title {
25 | font-weight: 600;
26 | font-size: 1.4rem;
27 | line-height: 1.6rem;
28 | }
29 |
30 | .ui-alert__message {
31 | font-weight: 400;
32 | font-size: 1.2rem;
33 | line-height: 1.6rem;
34 | margin-top: 8px;
35 | }
36 |
37 | .ui-alert--info {
38 | background-color: var(--navy800);
39 | color: var(--white);
40 | }
41 |
42 | .ui-alert--confirmation {
43 | background-color: var(--green600);
44 | color: var(--white);
45 | }
46 |
47 | .ui-alert--error {
48 | background-color: #ea5f6e;
49 | color: var(--white);
50 | }
51 |
52 | .ui-alert--warning {
53 | background-color: var(--orange500);
54 | color: var(--navy900);
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/alert/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './alert.react';
2 | export {default as AlertPopover} from './components/alert-popover.react';
3 |
--------------------------------------------------------------------------------
/src/components/avatar-group/README.md:
--------------------------------------------------------------------------------
1 | # Avatar Group
2 |
--------------------------------------------------------------------------------
/src/components/avatar-group/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './avatar-group.react';
2 |
--------------------------------------------------------------------------------
/src/components/avatar/README.md:
--------------------------------------------------------------------------------
1 | # Avatar
2 |
3 | Avatars are used to represent individual users and teams.
4 |
5 | ## Best practices
6 |
7 | - Avatars should be used with a tooltip, that on hover, displays the entity name (A users full name, or a company name). The tooltip should not contain any other information. See also (Tooltips).
8 |
9 | ## Grouping avatars
10 |
11 | Avatars can be grouped into collections, for example when a project has more than one associated freelancer.
12 |
13 | No more than five avatars should be grouped together. See also the [Avatar Group](/components/avatar-group) component
14 |
--------------------------------------------------------------------------------
/src/components/avatar/__tests__/avatar.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import {mount} from 'enzyme';
4 |
5 | import Avatar, {getFallbackColor} from '../avatar.react';
6 |
7 | describe('Avatar', () => {
8 | test('should render an avatar', () => {
9 | const element = ;
10 |
11 | const result = mount(element);
12 | expect(result.length).toBe(1);
13 | });
14 |
15 | test('should pass fallback initials through to the underlying DOM element', () => {
16 | const element = ;
17 |
18 | const result = mount(element);
19 | expect(
20 | result.find('span.ui-avatar[data-fallback-initials="TP"]').length
21 | ).toBe(1);
22 | });
23 |
24 | describe('getFallbackColor()', () => {
25 | test('should consistently return a color based on a given string', () => {
26 | const result = getFallbackColor('test@example.com'); // blue
27 | const result2 = getFallbackColor('test@example.com'); // blue
28 | const result3 = getFallbackColor('bob@example.com'); // navy
29 | const result4 = getFallbackColor('bob@example.com'); // navy
30 |
31 | expect(result).toBe(result2);
32 | expect(result3).toBe(result4);
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/avatar/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './avatar.react';
2 |
--------------------------------------------------------------------------------
/src/components/button-dropdown/README.md:
--------------------------------------------------------------------------------
1 | # Button Dropdown
--------------------------------------------------------------------------------
/src/components/button-dropdown/__tests__/button-dropdown.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import ButtonDropdown from 'components/button-dropdown';
6 |
7 | describe('ButtonDropdown', () => {
8 | const defaultProps = {
9 | size: 'medium',
10 | variant: 'tertiary',
11 | selectItems: [
12 | {
13 | title: 'Pending',
14 | onClick: () => {},
15 | },
16 | {
17 | title: 'This is a link',
18 | minWidth: 225,
19 | component: 'a',
20 | componentProps: {
21 | href: 'http://google.com',
22 | target: '_blank',
23 | },
24 | },
25 | ],
26 | };
27 | const create = (props = {}) =>
28 | renderer.create().toJSON();
29 |
30 | test('should render shallow component ok', () => {
31 | const element = create();
32 | expect(element).toMatchSnapshot();
33 | });
34 |
35 | test('should render with a checkbox', () => {
36 | const element = create({
37 | checkboxProps: {
38 | onClick: () => {},
39 | },
40 | });
41 |
42 | expect(element).toMatchSnapshot();
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/src/components/button-dropdown/button-dropdown.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | position: absolute;
3 | top: calc(100% + 2px);
4 | min-width: calc(100% + 4px);
5 | left: -2px;
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/button-dropdown/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './button-dropdown.react';
2 |
--------------------------------------------------------------------------------
/src/components/button-group/README.md:
--------------------------------------------------------------------------------
1 | # Button Group
--------------------------------------------------------------------------------
/src/components/button-group/__tests__/button-group.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import ButtonGroup from 'components/button-group';
6 | import Button from 'components/button';
7 |
8 | describe('ButtonGroup', () => {
9 | const defaultProps = {};
10 | const create = (props = {spacing: true}) =>
11 | renderer
12 | .create(
13 |
14 |
15 |
16 |
17 | )
18 | .toJSON();
19 |
20 | test('should render shallow component ok', () => {
21 | const element = create();
22 | expect(element).toMatchSnapshot();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/components/button-group/button-group.module.css:
--------------------------------------------------------------------------------
1 | .ui-btn-group {
2 | display: flex;
3 | align-items: center;
4 | width: auto;
5 | }
6 |
7 | .ui-btn-group--wide {
8 | width: 100%;
9 | }
10 |
11 | .ui-btn-group--align-left {
12 | justify-content: flex-start;
13 | }
14 |
15 | .ui-btn-group--align-center {
16 | justify-content: center;
17 | }
18 |
19 | .ui-btn-group--align-right {
20 | justify-content: flex-end;
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/button-group/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './button-group.react';
2 |
--------------------------------------------------------------------------------
/src/components/button/README.md:
--------------------------------------------------------------------------------
1 | # Button
2 |
3 | Buttons are the primary way that a user interacts with the platform.
4 |
--------------------------------------------------------------------------------
/src/components/button/__tests__/__snapshots__/button.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Button should render shallow component ok 1`] = `
4 |
30 | `;
31 |
--------------------------------------------------------------------------------
/src/components/button/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './button.react';
2 |
--------------------------------------------------------------------------------
/src/components/callout/README.md:
--------------------------------------------------------------------------------
1 | # Callout
2 |
3 | Callouts are used to display persisent notices. They are used to highlight parts of particular feature.
4 |
5 | For flash style alerts, consider the Alert component.
6 |
--------------------------------------------------------------------------------
/src/components/callout/__examples__/callout.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Callout from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Feature Callout Card',
8 | render: () => (
9 |
10 | You're viewing a sample freelancer profile
11 |
12 | ),
13 | html: () => (
14 |
15 | You're viewing a sample freelancer profile
16 |
17 | ),
18 | },
19 | ];
20 |
--------------------------------------------------------------------------------
/src/components/callout/callout.module.css:
--------------------------------------------------------------------------------
1 | .ui-callout {
2 | width: 100%;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | padding: 1.6rem 2.4rem;
7 | line-height: 1.6;
8 | }
9 |
10 | .ui-callout--variant-blue {
11 | background-color: var(--blue000);
12 | border: 1px solid var(--blue300);
13 | color: var(--blue500);
14 | font-weight: var(--font-weight-semibold);
15 | font-size: 1.6rem;
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/callout/callout.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './callout.module.css';
8 |
9 | const Callout = props => {
10 | const {children, variant = 'blue', className, ...otherProps} = props;
11 | const _classNames = cx(
12 | {
13 | [styles['ui-callout']]: true,
14 | [styles[`ui-callout--variant-${variant}`]]: true,
15 | },
16 | className
17 | );
18 |
19 | return (
20 |
21 | {children}
22 |
23 | );
24 | };
25 |
26 | Callout.propTypes = {
27 | children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
28 | className: PropTypes.object,
29 | /** 'blue' */
30 | variant: PropTypes.oneOf(['blue']),
31 | };
32 |
33 | export default Callout;
34 |
--------------------------------------------------------------------------------
/src/components/callout/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './callout.react';
2 |
--------------------------------------------------------------------------------
/src/components/checkbox/README.md:
--------------------------------------------------------------------------------
1 | # Checkbox
2 |
3 | Checkboxes can be used to provide a user with a binary choice, for example, toggling email notifications on and off.
4 |
5 | ## Best practices
6 |
7 | - When changing a setting, checkboxes should always be accompanied with a label.
8 | - Labels should be descriptive enough, that they can stand up on their own. For example: 'Enable email notifications' is better than 'Enable/Disable'.
9 |
--------------------------------------------------------------------------------
/src/components/checkbox/__tests__/checkbox.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import Checkbox from 'components/checkbox';
6 |
7 | describe('Checkbox', () => {
8 | const defaultProps = {
9 | size: 'medium',
10 | checked: true,
11 | };
12 | const create = (props = {}) =>
13 | renderer.create().toJSON();
14 |
15 | test('should render shallow component ok', () => {
16 | const element = create();
17 | expect(element).toMatchSnapshot();
18 | });
19 |
20 | test('should render a checkbox with label', () => {
21 | const element = create({
22 | label: 'A checkbox label',
23 | });
24 |
25 | expect(element).toMatchSnapshot();
26 | });
27 |
28 | test('should render a checkbox partially checked', () => {
29 | const element = create({
30 | label: 'A checkbox label',
31 | checked: false,
32 | indeterminate: true,
33 | });
34 | expect(element).toMatchSnapshot();
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/src/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './checkbox.react';
2 |
--------------------------------------------------------------------------------
/src/components/drop-menu/README.md:
--------------------------------------------------------------------------------
1 | # Drop Menu
2 |
--------------------------------------------------------------------------------
/src/components/drop-menu/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './drop-menu.react';
2 |
3 | export {default as DropMenuItem} from './drop-menu-item.react';
4 |
--------------------------------------------------------------------------------
/src/components/feature-callout-card/README.md:
--------------------------------------------------------------------------------
1 | # Feature Callout Card
2 |
3 | This card component is used to provide prompts about a particular feature to a user
4 |
--------------------------------------------------------------------------------
/src/components/feature-callout-card/feature-callout-card.module.css:
--------------------------------------------------------------------------------
1 | .ui-feature-callout-card {
2 | background-color: var(--grey000);
3 | border-radius: 4px;
4 | border: 1px solid var(--grey100);
5 | display: flex;
6 | flex-direction: column;
7 | padding: 1.6rem 2.4rem;
8 | font-size: 1.4rem;
9 | color: var(--navy900);
10 |
11 | @media screen and (min-width: 768px) {
12 | align-items: flex-start;
13 | flex-direction: row;
14 | }
15 | }
16 |
17 | .ui-feature-callout-card__icon {
18 | margin-right: 1.2rem;
19 |
20 | @media screen and (min-width: 768px) {
21 | margin-top: 0;
22 | }
23 | }
24 |
25 | .ui-feature-callout-card__title {
26 | font-size: 1.4rem;
27 | font-weight: 600;
28 | display: flex;
29 | align-items: center;
30 | flex-shrink: 0;
31 |
32 | @media screen and (min-width: 768px) {
33 | margin-right: 0.6rem;
34 | margin-top: 0;
35 | }
36 | }
37 |
38 | .ui-feature-callout-card__content {
39 | padding-left: 2.8rem;
40 |
41 | @media screen and (min-width: 768px) {
42 | padding-left: 0;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/feature-callout-card/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './feature-callout-card.react';
2 |
--------------------------------------------------------------------------------
/src/components/field-hint/__examples__/field-hint.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import FieldHint from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'FieldHint (default)',
8 | description: 'An example of FieldHint (default)',
9 | render: () => ,
10 | },
11 | ];
12 |
--------------------------------------------------------------------------------
/src/components/field-hint/__tests__/__snapshots__/field-hint.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`FieldHint should render shallow component ok 1`] = `
4 |
8 | `;
9 |
--------------------------------------------------------------------------------
/src/components/field-hint/__tests__/field-hint.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import renderer from 'react-test-renderer';
5 |
6 | import FieldHint from '../';
7 | import Icon from '../../icon';
8 |
9 | describe('FieldHint', () => {
10 | const create = props => ;
11 |
12 | test('should render shallow component ok', () => {
13 | const element = renderer.create().toJSON();
14 | expect(element).toMatchSnapshot();
15 | });
16 |
17 | test('should render with a custom icon', () => {
18 | const element = create({
19 | icon: 'archive',
20 | });
21 |
22 | const result = shallow(element);
23 | expect(result.find(Icon).length).toBe(1);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/field-hint/field-hint.module.css:
--------------------------------------------------------------------------------
1 | .ui-field-hint {
2 | font-size: 1.2rem;
3 | font-weight: 400;
4 | color: var(--grey800);
5 | margin-top: 0.4rem;
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/field-hint/field-hint.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {isString} from 'lodash';
4 |
5 | import {pickStyles} from '../../utils/style';
6 | import Icon from '../icon';
7 | import {UIBase} from '../layout';
8 |
9 | import coreStyles from './field-hint.module.css';
10 |
11 | const FieldHint = props => {
12 | const {hint, icon, ...otherProps} = props;
13 |
14 | return (
15 |
20 | {isString(icon) ? (
21 |
28 | {String(icon)}
29 |
30 | ) : (
31 | icon
32 | )}
33 | {hint}
34 |
35 | );
36 | };
37 |
38 | FieldHint.propTypes = {
39 | hint: PropTypes.string,
40 | icon: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
41 | };
42 |
43 | export default FieldHint;
44 |
--------------------------------------------------------------------------------
/src/components/field-hint/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field-hint.react';
2 |
--------------------------------------------------------------------------------
/src/components/field-label/__examples__/field-label.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import FieldLabel from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'FieldLabel',
8 | description: 'A basic label for a field',
9 | render: () => Name,
10 | },
11 | ];
12 |
--------------------------------------------------------------------------------
/src/components/field-label/__tests__/__snapshots__/field-label.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`FieldLabel should render shallow component ok 1`] = `
4 |
17 | `;
18 |
--------------------------------------------------------------------------------
/src/components/field-label/field-label.module.css:
--------------------------------------------------------------------------------
1 | .ui-field-label {
2 | font-size: 14px;
3 | font-weight: 600;
4 | color: var(--navy800);
5 | display: inline-block;
6 | vertical-align: bottom;
7 | margin-bottom: 4px;
8 | cursor: inherit;
9 | text-align: unset;
10 | text-decoration: inherit;
11 | text-overflow: initial;
12 | overflow: visible;
13 | word-break: break-word;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/field-label/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field-label.react';
2 |
--------------------------------------------------------------------------------
/src/components/field-row/README.md:
--------------------------------------------------------------------------------
1 | # FieldRow
2 |
3 | The FieldRow component is responsible for managing horizontal spacing between child form fields, as well as the vertical spacing between itself and other FieldRow elements.
--------------------------------------------------------------------------------
/src/components/field-row/field-row.module.css:
--------------------------------------------------------------------------------
1 | .ui-field-row {
2 | display: flex;
3 | flex-wrap: wrap;
4 | align-items: top;
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/field-row/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field-row.react';
2 |
--------------------------------------------------------------------------------
/src/components/field-validation/field-validation.module.css:
--------------------------------------------------------------------------------
1 | .ui-field-validation {
2 | font-weight: 500;
3 | font-size: 1.2rem;
4 | color: var(--pink600);
5 | margin-top: 4px;
6 | display: block;
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/field-validation/field-validation.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import coreStyles from './field-validation.module.css';
5 |
6 | const FieldValidation = ({validation}) => (
7 |
8 | {validation.message}
9 |
10 | );
11 |
12 | FieldValidation.propTypes = {
13 | validation: PropTypes.shape({
14 | message: PropTypes.string.isRequired,
15 | }).isRequired,
16 | };
17 |
18 | export default FieldValidation;
19 |
--------------------------------------------------------------------------------
/src/components/field-validation/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field-validation.react';
2 |
--------------------------------------------------------------------------------
/src/components/field-validations/README.md:
--------------------------------------------------------------------------------
1 | # FieldValidations
2 |
3 | The FieldValidations component is rarely used by itself. Instead, validations should be sent via the validations prop on the `Field` component.
--------------------------------------------------------------------------------
/src/components/field-validations/__examples__/field-validations.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import FieldValidations from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'FieldValidations (default)',
8 | description: 'An example of FieldValidations (default)',
9 | render: () => (
10 |
11 | ),
12 | },
13 | ];
14 |
--------------------------------------------------------------------------------
/src/components/field-validations/__tests__/__snapshots__/field-validations.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`FieldValidations should render shallow component ok 1`] = `
4 |
7 | `;
8 |
--------------------------------------------------------------------------------
/src/components/field-validations/__tests__/field-validations.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import {shallow} from 'enzyme';
3 | import React from 'react';
4 | import renderer from 'react-test-renderer';
5 |
6 | import FieldValidations from '../';
7 | import FieldValidation from '../../field-validation';
8 |
9 | describe('FieldValidations', () => {
10 | const defaultProps = {
11 | validations: [
12 | {
13 | message: 'Email can’t be empty',
14 | },
15 | {
16 | message: 'Email must be of email type',
17 | },
18 | ],
19 | };
20 | const create = props => ;
21 |
22 | test('should render shallow component ok', () => {
23 | const element = renderer.create().toJSON();
24 | expect(element).toMatchSnapshot();
25 | });
26 |
27 | it('should render two validation components', () => {
28 | const element = create();
29 | const result = shallow(element);
30 | expect(result.find(FieldValidation).length).toEqual(2);
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/field-validations/field-validations.module.css:
--------------------------------------------------------------------------------
1 | .ui-field-validations {
2 | text-align: left;
3 | }
4 |
5 | .ui-field-validations--align-center {
6 | text-align: center;
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/field-validations/field-validations.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import FieldValidation from '../field-validation';
6 |
7 | import styles from './field-validations.module.css';
8 |
9 | const FieldValidations = props => {
10 | const {validations, centered, className} = props;
11 |
12 | const _classNames = cx(
13 | {
14 | [styles['ui-field-validations']]: true,
15 | [styles['ui-field-validations--align-center']]: centered,
16 | },
17 | className
18 | );
19 |
20 | return (
21 |
22 | {validations &&
23 | validations.map(validation => (
24 | // $FlowFixMe
25 |
26 | ))}
27 |
28 | );
29 | };
30 |
31 | FieldValidations.propTypes = {
32 | /** A list of validations to be displayed to the user */
33 | validations: PropTypes.array,
34 | /** Visually centeres the validations */
35 | centered: PropTypes.bool,
36 | /** Any classes to pass down */
37 | className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
38 | };
39 |
40 | export default FieldValidations;
41 |
--------------------------------------------------------------------------------
/src/components/field-validations/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field-validations.react';
2 |
--------------------------------------------------------------------------------
/src/components/field/README.md:
--------------------------------------------------------------------------------
1 | # Field
2 |
3 | The field component is responsible for implementing many of the lower level form components such as labels, validations, and hints.
4 |
--------------------------------------------------------------------------------
/src/components/field/field.module.css:
--------------------------------------------------------------------------------
1 | .ui-field {
2 | position: relative;
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: inherit;
6 | }
7 |
8 | .ui-field:not(.ui-field--legacy) {
9 | flex: 0 0 auto;
10 | margin-top: 2.4rem;
11 | margin-left: 2.4rem;
12 | min-width: 20rem;
13 | max-width: calc(100% - 2.4rem);
14 | }
15 |
16 | .ui-field-row .ui-field {
17 | flex: 1 1 20rem;
18 | }
19 |
20 | .ui-field--inline {
21 | justify-content: space-between;
22 | flex-direction: row;
23 | align-items: center;
24 | }
25 |
26 | .ui-field .ui-field-label {
27 | flex-shrink: 0;
28 | margin-right: 2.4rem;
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/field/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './field.react';
2 |
--------------------------------------------------------------------------------
/src/components/fieldset/README.md:
--------------------------------------------------------------------------------
1 | # Fieldset
2 |
3 | Fieldset for basic forms
--------------------------------------------------------------------------------
/src/components/fieldset/__examples__/fieldset.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Fieldset from '../';
4 |
5 | import Field from '../../field';
6 | import Input from '../../input';
7 |
8 | export const examples = [
9 | {
10 | title: 'Fieldset',
11 | description: 'A standard Fieldset',
12 | background: 'white',
13 | render: () => (
14 |
19 | ),
20 | },
21 | {
22 | title: 'with inset',
23 | description:
24 | 'You can control the background color of a fieldset to give a visual inset effect',
25 | background: 'white',
26 | render: () => (
27 |
28 |
33 |
38 |
39 | ),
40 | },
41 | ];
42 |
--------------------------------------------------------------------------------
/src/components/fieldset/__tests__/fieldset.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import renderer from 'react-test-renderer';
5 |
6 | import Input from '../../input';
7 | import Fieldset, {FieldsetHeader} from '../fieldset.react';
8 | import Field from '../../field';
9 |
10 | const defaultProps = {
11 | inset: false,
12 | };
13 |
14 | describe('Input', () => {
15 | const create = props =>
16 | shallow(
17 |
22 | );
23 |
24 | test('should render shallow component ok', () => {
25 | const element = renderer
26 | .create(
27 |
32 | )
33 | .toJSON();
34 | expect(element).toMatchSnapshot();
35 | });
36 |
37 | test('should render a FieldsetHeader if a legend is passed', () => {
38 | const element = create({
39 | legend: 'Your name',
40 | });
41 | expect(element.find(FieldsetHeader).length).toBe(1);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/src/components/fieldset/fieldset.module.css:
--------------------------------------------------------------------------------
1 | .ui-fieldset {
2 | border: 0;
3 | border-bottom: 1px solid var(--grey100);
4 | }
5 |
6 | .ui-fieldset--no-border {
7 | border-bottom: 0;
8 | }
9 |
10 | .ui-fieldset--inset {
11 | background-color: var(--grey000);
12 | }
13 |
14 | .ui-fieldset--interactive {
15 | cursor: pointer;
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/fieldset/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './fieldset.react';
2 |
--------------------------------------------------------------------------------
/src/components/form/__tests__/form.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import expect from 'expect';
3 | import {shallow} from 'enzyme';
4 | import {testComponent} from 'utils/test/react';
5 |
6 | import Form from '../';
7 |
8 | describe('Form', () => {
9 | const create = testComponent(Form, () => ({
10 | actions: [],
11 | }));
12 |
13 | test('should render OK', () => {
14 | const {element} = create();
15 | const result = shallow(element);
16 | expect(result.exists()).toEqual(true);
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/src/components/form/form.react.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {HotKeys} from 'react-hotkeys';
4 |
5 | /**
6 | * A generic (and mostly semantic) form component.
7 | */
8 |
9 | export default class Form extends PureComponent {
10 | static propTypes = {
11 | /** Children form components */
12 | children: PropTypes.node,
13 | /** A function to call when the form is submitted */
14 | onSubmit: PropTypes.func,
15 | };
16 |
17 | constructor(props) {
18 | super(props);
19 | this.__handlers__ = {
20 | 'meta+return': this.onSubmitHotkey.bind(this),
21 | };
22 | }
23 |
24 | onSubmitHotkey(event) {
25 | if (this.props.onSubmit) {
26 | this.props.onSubmit(event);
27 | }
28 | }
29 |
30 | render() {
31 | const {children, ...otherProps} = this.props;
32 |
33 | return (
34 |
35 | {children}
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/form/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './form.react';
2 |
--------------------------------------------------------------------------------
/src/components/grid/README.md:
--------------------------------------------------------------------------------
1 | # Grid
2 |
3 | The grid system in UI is based on a 12 column grid.
4 |
5 | There are three main grid components:
6 | - Grid - an outer container that sets a max width, and horizontally centers the rest of the page
7 | - Row - used for a single horizontal row of content. Row also manages spacing between child columns, and gutters to the left and right.
8 | - Column - used for a single vertical column of content.
9 |
10 | ## Spacing
11 | The spacing between columns is managed by the parent Row column. This enforces uniform spacing. One-off adjustments are inevitable, so as all of the grid components compose from either Box or Flex, `margin` and `padding` props are available. However where possible, we reccomend to make use of the `columns`, `gutter`, and `spacing` props.
--------------------------------------------------------------------------------
/src/components/grid/__tests__/__snapshots__/grid.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`components/grid should render shallow component ok 1`] = `
4 |
22 | `;
23 |
--------------------------------------------------------------------------------
/src/components/grid/__tests__/grid.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import {Grid, Row, Column} from 'components/grid';
6 |
7 | describe('components/grid', () => {
8 | const create = (props = {}) =>
9 | renderer
10 | .create(
11 |
12 |
13 |
14 |
15 |
16 |
17 | )
18 | .toJSON();
19 |
20 | test('should render shallow component ok', () => {
21 | const element = create();
22 | expect(element).toMatchSnapshot();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/components/grid/index.js:
--------------------------------------------------------------------------------
1 | export {Grid, Row, Column} from './grid.react';
2 |
--------------------------------------------------------------------------------
/src/components/h1/__tests__/__snapshots__/h1.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`H1 should allow weight to be overridden 1`] = `
4 |
8 | An H1 Tag
9 |
10 | `;
11 |
12 | exports[`H1 should render shallow component ok 1`] = `
13 |
17 | An H1 Tag
18 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/h1/__tests__/h1.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import H1 from 'components/h1';
6 |
7 | describe('H1', () => {
8 | const defaultProps = {};
9 | const create = (props = {}) =>
10 | renderer
11 | .create(
12 |
13 | An H1 Tag
14 |
15 | )
16 | .toJSON();
17 |
18 | test('should render shallow component ok', () => {
19 | const element = create();
20 | expect(element).toMatchSnapshot();
21 | });
22 |
23 | test('should allow weight to be overridden', () => {
24 | const element = create({
25 | weight: 'medium',
26 | });
27 | expect(element).toMatchSnapshot();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/h1/h1.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Heading from '../heading';
5 |
6 | const H1 = props => {
7 | const {children} = props;
8 |
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | };
15 |
16 | H1.propTypes = {
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default H1;
21 |
--------------------------------------------------------------------------------
/src/components/h1/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './h1.react';
2 |
--------------------------------------------------------------------------------
/src/components/h2/__tests__/__snapshots__/h2.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`H2 should allow weight to be overridden 1`] = `
4 |
8 | An H2 Tag
9 |
10 | `;
11 |
12 | exports[`H2 should render shallow component ok 1`] = `
13 |
17 | An H2 Tag
18 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/h2/__tests__/h2.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import H2 from 'components/h2';
6 |
7 | describe('H2', () => {
8 | const defaultProps = {};
9 | const create = (props = {}) =>
10 | renderer
11 | .create(
12 |
13 | An H2 Tag
14 |
15 | )
16 | .toJSON();
17 |
18 | test('should render shallow component ok', () => {
19 | const element = create();
20 | expect(element).toMatchSnapshot();
21 | });
22 |
23 | test('should allow weight to be overridden', () => {
24 | const element = create({
25 | weight: 'light',
26 | });
27 | expect(element).toMatchSnapshot();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/h2/h2.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Heading from '../heading';
5 |
6 | const H2 = props => {
7 | const {children} = props;
8 |
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | };
15 |
16 | H2.propTypes = {
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default H2;
21 |
--------------------------------------------------------------------------------
/src/components/h2/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './h2.react';
2 |
--------------------------------------------------------------------------------
/src/components/h3/__tests__/__snapshots__/h3.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`H3 should allow weight to be overridden 1`] = `
4 |
8 | An H3 Tag
9 |
10 | `;
11 |
12 | exports[`H3 should render shallow component ok 1`] = `
13 |
17 | An H3 Tag
18 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/h3/__tests__/h3.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import H3 from 'components/h3';
6 |
7 | describe('H3', () => {
8 | const defaultProps = {};
9 | const create = (props = {}) =>
10 | renderer
11 | .create(
12 |
13 | An H3 Tag
14 |
15 | )
16 | .toJSON();
17 |
18 | test('should render shallow component ok', () => {
19 | const element = create();
20 | expect(element).toMatchSnapshot();
21 | });
22 |
23 | test('should allow weight to be overridden', () => {
24 | const element = create({
25 | weight: 'light',
26 | });
27 | expect(element).toMatchSnapshot();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/h3/h3.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Heading from '../heading';
4 |
5 | const H3 = props => {
6 | const {children} = props;
7 | return (
8 |
9 | {children}
10 |
11 | );
12 | };
13 |
14 | H3.propTypes = {
15 | children: PropTypes.node.isRequired,
16 | };
17 |
18 | export default H3;
19 |
--------------------------------------------------------------------------------
/src/components/h3/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './h3.react';
2 |
--------------------------------------------------------------------------------
/src/components/h4/__tests__/__snapshots__/h4.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`H4 should allow size to be overridden 1`] = `
4 |
8 | An H4 Tag
9 |
10 | `;
11 |
12 | exports[`H4 should render shallow component ok 1`] = `
13 |
17 | An H4 Tag
18 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/h4/__tests__/h4.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import H4 from 'components/h4';
6 |
7 | describe('H4', () => {
8 | const defaultProps = {};
9 | const create = (props = {}) =>
10 | renderer
11 | .create(
12 |
13 | An H4 Tag
14 |
15 | )
16 | .toJSON();
17 |
18 | test('should render shallow component ok', () => {
19 | const element = create();
20 | expect(element).toMatchSnapshot();
21 | });
22 |
23 | test('should allow size to be overridden', () => {
24 | const element = create({
25 | size: 'large',
26 | });
27 | expect(element).toMatchSnapshot();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/h4/h4.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Heading from '../heading';
5 |
6 | const H4 = props => {
7 | const {children} = props;
8 |
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | };
15 |
16 | H4.propTypes = {
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default H4;
21 |
--------------------------------------------------------------------------------
/src/components/h4/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './h4.react';
2 |
--------------------------------------------------------------------------------
/src/components/heading/README.md:
--------------------------------------------------------------------------------
1 | # Heading
2 |
3 | We have four main heading components (H1, H2, H3, and H4).
4 |
5 | **Note:** All of the heading components (`H1`, `H2`, etc.) inherit their props from `Heading`, however we recommend to avoid using the `Heading` component directly. All of the props displayed below are still applicable.
--------------------------------------------------------------------------------
/src/components/heading/__tests__/__snapshots__/heading.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Heading should match snapshot 1`] = `
4 |
8 | A medium sized header
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/src/components/heading/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './heading.react';
2 |
--------------------------------------------------------------------------------
/src/components/helper-text/README.md:
--------------------------------------------------------------------------------
1 | # HelperText
2 |
--------------------------------------------------------------------------------
/src/components/helper-text/helper-text.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Text from '../text';
5 |
6 | const HelperText = props => {
7 | const {children, ...otherProps} = props;
8 |
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | };
15 |
16 | HelperText.propTypes = {
17 | children: PropTypes.string,
18 | };
19 |
20 | export default HelperText;
21 |
--------------------------------------------------------------------------------
/src/components/helper-text/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './helper-text.react';
2 |
--------------------------------------------------------------------------------
/src/components/icon-symbols/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './icon-symbols.react';
2 |
--------------------------------------------------------------------------------
/src/components/icon/README.md:
--------------------------------------------------------------------------------
1 | # Icon
2 |
3 | Our icons are a mix of Material icons, and custom designed ones. This React allows for a single instance of an Icon to be added, by passing the icon name as a child.
4 |
5 | ## Best practices
6 |
7 | - Use icons sparingly. They should be used to provide extra context to an existing text label.
8 |
9 | ## Usage
10 |
11 | *See below for more detailed examples*
12 |
13 | ```javascript
14 | import {Icon} from '@kalo/ui';
15 |
16 |
20 | person_outline
21 |
22 | ```
23 |
24 | ## IconSymbols
25 | As mentioned above, our icons make use of SVG symbols (def and use). In order to get the icon symbols on to the page, a second component will need to be included somewhere in your application.
26 |
27 | Note, that the IconSymbols component only needs to be included **once** on the page.
28 |
29 | For example:
30 |
31 | ```javascript
32 | import {Icon, IconSymbols} from '@kalo/ui'
33 |
34 | more_vert
35 |
36 | ```
--------------------------------------------------------------------------------
/src/components/icon/icon.module.css:
--------------------------------------------------------------------------------
1 | .ui-icon {
2 | user-select: none;
3 | line-height: 1em;
4 | vertical-align: middle;
5 | cursor: inherit;
6 | display: inline;
7 | }
8 |
9 | .ui-icon--interactive {
10 | cursor: pointer;
11 | }
12 |
13 | .ui-icon--size-12 {
14 | height: 12px;
15 | width: 12px;
16 | }
17 |
18 | .ui-icon--size-14 {
19 | height: 14px;
20 | width: 14px;
21 | }
22 |
23 | .ui-icon--size-16 {
24 | height: 16px;
25 | width: 16px;
26 | }
27 |
28 | .ui-icon--size-18 {
29 | height: 18px;
30 | width: 18px;
31 | }
32 |
33 | .ui-icon--size-20 {
34 | height: 20px;
35 | width: 20px;
36 | }
37 |
38 | .ui-icon--size-23 {
39 | height: 23px;
40 | width: 23px;
41 | }
42 |
43 | .ui-icon--size-24 {
44 | height: 24px;
45 | width: 24px;
46 | }
47 |
48 | .ui-icon--size-26 {
49 | height: 26px;
50 | width: 26px;
51 | }
52 |
53 | .ui-icon--size-36 {
54 | height: 36px;
55 | width: 36px;
56 | }
57 |
58 | .ui-icon--size-48 {
59 | height: 48px;
60 | width: 48px;
61 | }
62 |
--------------------------------------------------------------------------------
/src/components/icon/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './icon.react';
2 |
--------------------------------------------------------------------------------
/src/components/image-input/README.md:
--------------------------------------------------------------------------------
1 | # Image Input
2 |
--------------------------------------------------------------------------------
/src/components/image-input/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './image-input';
2 |
--------------------------------------------------------------------------------
/src/components/inline-alert/README.md:
--------------------------------------------------------------------------------
1 | # Inline Alert
2 |
--------------------------------------------------------------------------------
/src/components/inline-alert/__examples__/inline-alert.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import InlineAlert from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Standard Inline Alert',
8 | render: () => (
9 |
10 | You are currently on a trial version of reporting
11 |
12 | ),
13 | },
14 | {
15 | title: 'Information InlineAlert',
16 | render: () => (
17 |
18 | You are currently on a trial version of reporting
19 |
20 | ),
21 | },
22 | ];
23 |
--------------------------------------------------------------------------------
/src/components/inline-alert/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './inline-alert.react';
2 |
--------------------------------------------------------------------------------
/src/components/inline-alert/inline-alert.module.css:
--------------------------------------------------------------------------------
1 | .ui-inline-alert {
2 | display: flex;
3 | font-size: 1.2rem;
4 | font-weight: 400;
5 | line-height: 1.6rem;
6 | background-color: pink;
7 | padding: 0.8rem 1.6rem;
8 | }
9 |
10 | .ui-inline-alert__content {
11 | padding-left: 8px;
12 | padding-top: 2px;
13 | }
14 |
15 | .ui-inline-alert--info {
16 | background-color: var(--blue000);
17 | color: var(--blue800);
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/inline-alert/inline-alert.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 | import Icon from '../icon';
7 |
8 | import styles from './inline-alert.module.css';
9 |
10 | const TYPE_ICON_MAP = {
11 | info: 'info',
12 | error: 'highlight_off',
13 | warning: 'error_outline',
14 | confirmation: 'check_circle',
15 | };
16 |
17 | const InlineAlert = props => {
18 | const {children, type = 'info'} = props;
19 |
20 | const _classNames = cx({
21 | [styles['ui-inline-alert']]: true,
22 | [styles[`ui-inline-alert--${type}`]]: true,
23 | });
24 |
25 | return (
26 |
27 |
28 | {TYPE_ICON_MAP[type]}
29 |
30 | {children}
31 |
32 | );
33 | };
34 |
35 | InlineAlert.propTypes = {
36 | children: PropTypes.string,
37 | /** 'info' | 'warning' | 'error' | 'confirmation' */
38 | type: PropTypes.oneOf(['info', 'warning', 'error', 'confirmation']),
39 | };
40 |
41 | export default InlineAlert;
42 |
--------------------------------------------------------------------------------
/src/components/input/README.md:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 | ## Best practices
4 | - Use placeholder copy to display the expected shape of data. For example, for a field that asks for a twitter handle, a placeholder of '@kalohq' rather than 'your twitter handle' is better.
--------------------------------------------------------------------------------
/src/components/input/__tests__/__snapshots__/input.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Input should render shallow component ok 1`] = `
4 |
7 |
23 |
24 | `;
25 |
--------------------------------------------------------------------------------
/src/components/input/__tests__/input.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import renderer from 'react-test-renderer';
5 |
6 | import Input, {InputAddon} from '../input.react';
7 |
8 | describe('Input', () => {
9 | const create = props => shallow();
10 |
11 | const defaultProps = {
12 | size: 'medium',
13 | theme: 'default',
14 | };
15 |
16 | test('should render shallow component ok', () => {
17 | const element = renderer.create().toJSON();
18 | expect(element).toMatchSnapshot();
19 | });
20 |
21 | test('should render prefixed addon content', () => {
22 | const element = create({
23 | theme: 'default',
24 | addonPrefix: '£',
25 | });
26 | expect(element.find(InputAddon).length).toBe(1);
27 | });
28 |
29 | test('should render suffixed addon content', () => {
30 | const element = create({
31 | theme: 'default',
32 | addonSuffix: '£',
33 | });
34 | expect(element.find(InputAddon).length).toBe(1);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/src/components/input/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './input.react';
2 |
--------------------------------------------------------------------------------
/src/components/jumbo-button/README.md:
--------------------------------------------------------------------------------
1 | # Jumbo Button
2 |
--------------------------------------------------------------------------------
/src/components/jumbo-button/__examples__/jumbo-button.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import JumboButton from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Jumbo Button',
8 | render: () => Add/invite,
9 | html: () => (
10 |
21 | ),
22 | },
23 | {
24 | title: 'with a forced active state',
25 | render: () => (
26 |
27 | Add/invite
28 |
29 | ),
30 | html: () => (
31 |
42 | ),
43 | },
44 | ];
45 |
--------------------------------------------------------------------------------
/src/components/jumbo-button/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './jumbo-button';
2 |
--------------------------------------------------------------------------------
/src/components/jumbo-button/jumbo-button.module.css:
--------------------------------------------------------------------------------
1 | .ui-jumbo-btn {
2 | padding: 2.4rem 2.8rem;
3 | background-color: var(--white);
4 | border: 1px solid var(--grey200);
5 | color: var(--navy900);
6 | box-shadow: 0 2px 4px 0 rgba(232, 232, 232, 0.5);
7 | border-radius: 4px;
8 | cursor: pointer;
9 | font-size: 1.6rem;
10 | font-weight: 600;
11 | display: flex;
12 | flex-direction: row;
13 | align-items: center;
14 |
15 | &:hover {
16 | border-color: var(--grey300);
17 | background-color: var(--grey000);
18 | }
19 |
20 | &:focus {
21 | box-shadow: 0 0 0 3px var(--grey100);
22 | }
23 |
24 | &:active,
25 | &.ui-jumbo-btn--active {
26 | background-color: var(--grey000);
27 | box-shadow: none;
28 | }
29 | }
30 |
31 | .ui-jumbo-btn__icon {
32 | margin-right: 2rem;
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/layout/README.md:
--------------------------------------------------------------------------------
1 | # Layout
2 |
3 | The layout components are the primitive building blocks of the Kalo User Interface.
4 |
5 | ## Box and Flex
6 |
7 | A wrapper component that implements some default flex values.
8 |
9 | ## Inline
10 |
11 | An `inline-block` element.
12 |
13 | ## Spacing
14 |
15 | Margin and padding can be set via the `margin` and `padding` props. The re are also more granular props for specifying particular directions: `marginLeft`, `paddingTop` etc.
16 |
17 | These props can take a variety of values:
18 |
19 | - Value specific values: `padding="20px"`
20 | - Or scale values: `margin="medium"`
21 |
22 | The scale values relate to a multiple of 8px:
23 |
24 | ```js
25 | marginLeft = 'extra-small'; // margin-left: 2px
26 | marginLeft = 'small'; // margin-left: 4px
27 | marginLeft = 'medium'; // margin-left: 8px
28 | marginLeft = 'large'; // margin-left: 16px
29 | marginLeft = 'extra-large'; // margin-left: 24px
30 | ```
31 |
32 | These can also be mixed with pixel specific values:
33 |
34 | ```js
35 | padding={[20, "large", "medium", 38]}
36 | ```
37 |
--------------------------------------------------------------------------------
/src/components/layout/__examples__/layout.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Box, InlineFlex} from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Box',
8 | description: 'A basic wrapping box component',
9 | render: () => (
10 |
11 | This is the layout box
12 |
13 | ),
14 | },
15 | {
16 | title: 'InlineFlex',
17 | description: 'A span element with inline-flex set as its display property',
18 | render: () => An inline flex component,
19 | },
20 | ];
21 |
--------------------------------------------------------------------------------
/src/components/layout/__tests__/__snapshots__/utils.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`makePrimitive should render correctly 1`] = `
4 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/components/layout/__tests__/utils.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import {makePrimitive} from '../utils';
6 |
7 | describe('makePrimitive', () => {
8 | let wrapper;
9 | const props = {
10 | alignItems: 'center',
11 | display: 'inline-flex',
12 | };
13 |
14 | beforeEach(() => {
15 | const NewElement = makePrimitive('FooComponent', 'p', 'ui-foo-component');
16 | wrapper = renderer.create().toJSON();
17 | });
18 |
19 | test('should render correctly', () => {
20 | expect(wrapper).toMatchSnapshot();
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/src/components/layout/index.js:
--------------------------------------------------------------------------------
1 | export {Box, Flex, Block, Inline, InlineFlex, A, UIBase} from './layout.react';
2 |
--------------------------------------------------------------------------------
/src/components/layout/layout.react.module.css:
--------------------------------------------------------------------------------
1 | .ui-box {
2 | position: relative;
3 | flex-direction: column;
4 | align-items: stretch;
5 | flex-shrink: 0;
6 | align-content: flex-start;
7 | display: flex;
8 | }
9 |
10 | .ui-flex {
11 | display: flex;
12 | }
13 |
14 | .ui-block {
15 | display: block;
16 | }
17 |
18 | .ui-inline {
19 | display: inline-block;
20 | vertical-align: bottom;
21 | }
22 |
23 | .ui-inline-flex {
24 | display: inline-flex;
25 | }
26 |
27 | .ui-a {
28 | display: inline-flex;
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/loading-spinner/README.md:
--------------------------------------------------------------------------------
1 | # Loading Spinner
--------------------------------------------------------------------------------
/src/components/loading-spinner/__examples__/loading-spinner.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import LoadingSpinner from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'LoadingSpinner',
8 | description: 'A standard loading spinner',
9 | render: () => ,
10 | },
11 | {
12 | title: 'Different sizes',
13 | description:
14 | 'There are three different sizes of loading spinner: small, medium, and large',
15 | render: () => (
16 |
17 |
18 |
19 |
20 |
21 | ),
22 | },
23 | ];
24 |
--------------------------------------------------------------------------------
/src/components/loading-spinner/__tests__/loading-spinner.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import LoadingSpinner from 'components/loading-spinner';
6 |
7 | describe('LoadingSpinner', () => {
8 | const defaultProps = {
9 | size: 'medium',
10 | };
11 | const create = (props = {}) =>
12 | renderer.create().toJSON();
13 |
14 | test('should render shallow component ok', () => {
15 | const element = create();
16 | expect(element).toMatchSnapshot();
17 | });
18 |
19 | test('should render a large spinner', () => {
20 | const element = create({
21 | size: 'large',
22 | });
23 | expect(element).toMatchSnapshot();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/loading-spinner/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './loading-spinner.react';
2 |
--------------------------------------------------------------------------------
/src/components/loading-spinner/loading-spinner.module.css:
--------------------------------------------------------------------------------
1 | .ui-loading-spinner {
2 | position: relative;
3 | transform-origin: 48% 50%;
4 | }
5 |
6 | .ui-loading-spinner--small {
7 | height: 20px;
8 | width: 20px;
9 | }
10 |
11 | .ui-loading-spinner--medium {
12 | height: 30px;
13 | width: 30px;
14 | }
15 |
16 | .ui-loading-spinner--large {
17 | height: 50px;
18 | width: 50px;
19 | }
20 |
21 | .ui-loading-spinner svg {
22 | fill: var(--grey400);
23 | position: absolute;
24 | top: 0;
25 | left: 0;
26 | animation: spinner 1600ms linear infinite;
27 | }
28 |
29 | @keyframes spinner {
30 | from {
31 | transform: rotate(0deg);
32 | }
33 |
34 | to {
35 | transform: rotate(360deg);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/lozenge/README.md:
--------------------------------------------------------------------------------
1 | # Lozenge
2 |
--------------------------------------------------------------------------------
/src/components/lozenge/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './lozenge.react';
2 |
--------------------------------------------------------------------------------
/src/components/lozenge/lozenge.module.css:
--------------------------------------------------------------------------------
1 | .ui-lozenge {
2 | display: inline-block;
3 | border-radius: 3px;
4 | font-size: 1.2rem;
5 | padding: 0.4rem 0.8rem;
6 | max-width: 180px;
7 | white-space: nowrap;
8 | overflow: hidden;
9 | text-overflow: ellipsis;
10 | height: 2.4rem;
11 | line-height: 1.6rem;
12 | flex-grow: 0;
13 | }
14 |
15 | .ui-lozenge--variant-red {
16 | background-color: var(--pink000);
17 | color: var(--pink700);
18 | }
19 |
20 | .ui-lozenge--variant-green {
21 | background-color: var(--green000);
22 | color: var(--green700);
23 | }
24 |
25 | .ui-lozenge--variant-purple {
26 | background-color: var(--purple000);
27 | color: var(--purple700);
28 | }
29 |
30 | .ui-lozenge--variant-orange {
31 | background-color: var(--orange000);
32 | color: var(--orange700);
33 | }
34 |
35 | .ui-lozenge--variant-blue {
36 | background-color: var(--blue000);
37 | color: var(--blue700);
38 | }
39 |
40 | .ui-lozenge--variant-grey {
41 | color: var(--grey700);
42 | border: 1px solid var(--grey200);
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/lozenge/lozenge.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './lozenge.module.css';
8 |
9 | const Lozenge = props => {
10 | const {variant = 'blue', children, className, ...otherProps} = props;
11 |
12 | const _classNames = cx(
13 | {
14 | [styles['ui-lozenge']]: true,
15 | [styles[`ui-lozenge--variant-${variant}`]]: true,
16 | },
17 | className
18 | );
19 |
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | };
26 |
27 | Lozenge.propTypes = {
28 | children: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
29 | /** 'blue' | 'green' | 'orange' | 'purple' | 'red' | 'grey' */
30 | variant: PropTypes.oneOf([
31 | 'blue',
32 | 'green',
33 | 'orange',
34 | 'purple',
35 | 'red',
36 | 'grey',
37 | ]),
38 | className: PropTypes.string,
39 | };
40 |
41 | export default Lozenge;
42 |
--------------------------------------------------------------------------------
/src/components/modal/README.md:
--------------------------------------------------------------------------------
1 | # Modal
2 |
3 | Most content creation in our products takes place in modals. The content in modals should be purely single action, for example ‘creating a task’, or ‘submitting an invoice’. Flows that invoke more than one action (such as user onboarding, or payment onboarding) should not take place in modals. Instead, consider using a wizard.
4 |
5 | Modals are also one of the highest stacking order components, second only to alerts and notifications.
6 |
7 | ## Best Practices
8 |
9 | - Modals are invasive in that they block the rest of the application from being used. Keep the action of the modal (whether it is a notice, or a form) as succinct as possible.
10 | - Never stack modals on top of one another. If a modal needs to trigger another modal, then consider using a different flow, such as a wizard.
11 |
--------------------------------------------------------------------------------
/src/components/modal/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './modal.react';
2 |
--------------------------------------------------------------------------------
/src/components/paper-menu/README.md:
--------------------------------------------------------------------------------
1 | # Paper Menu
--------------------------------------------------------------------------------
/src/components/paper-menu/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './paper-menu.react';
2 |
3 | export {default as PaperMenuItem} from './components/paper-menu-item.react';
4 |
--------------------------------------------------------------------------------
/src/components/paper-menu/paper-menu.module.css:
--------------------------------------------------------------------------------
1 | .ui-paper-menu {
2 | transform-origin: top;
3 | transition: box-shadow 0.2s linear;
4 | transition-duration: 0.2s !important;
5 | }
6 |
7 | .ui-paper-menu__header {
8 | display: flex;
9 | padding: 32px 32px 16px 32px;
10 | justify-content: space-between;
11 | }
12 |
13 | .ui-paper-menu__option {
14 | display: flex;
15 | justify-content: flex-end;
16 | margin-top: -6px;
17 | }
18 |
19 | .ui-paper-menu__option__close {
20 | border: 0;
21 | background: transparent;
22 | cursor: pointer;
23 | }
24 |
25 | .ui-paper-menu__option__close:focus {
26 | outline: 0;
27 | }
28 |
29 | .ui-paper-menu__paper {
30 | background-color: var(--white);
31 | border: 1px solid var(--grey200);
32 | box-shadow: var(--box-shadow-level-2);
33 | border-radius: 4px;
34 | overflow: hidden;
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/paper/README.md:
--------------------------------------------------------------------------------
1 | # Paper
2 |
3 | A generic wrapping visual component, used to implement the box-shadow and focus/blur animations.
4 |
5 | ## Usage guidelines
6 | - Paper should always be used to house content, especially when on a non-white background.
7 | - Use a minimum of 16px padding.
8 | - If you're building out a list type UI, consider using the `Card` component.
--------------------------------------------------------------------------------
/src/components/paper/__examples__/paper.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Paper from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Paper',
8 | description:
9 | 'A wrapper component in charge of implementing the box-shadow around cards and the focus/blur animations.',
10 | render: () => this is some demo content,
11 | },
12 | {
13 | title: 'with elevation',
14 | description: 'Paper can be visually elevated with a dropshadow.',
15 | render: () => (
16 |
17 |
18 | elevation 1
19 |
20 |
21 | elevation 2
22 |
23 |
24 | elevation 3
25 |
26 |
27 | elevation 4
28 |
29 |
30 | ),
31 | },
32 | {
33 | title: 'With no border-radius',
34 | render: () => (
35 |
36 | this is some demo content
37 |
38 | ),
39 | },
40 | ];
41 |
--------------------------------------------------------------------------------
/src/components/paper/__tests__/__snapshots__/paper.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`components/paper Paper should render a component with an elevation of 3 1`] = `
4 |
9 | Paper Contents
10 |
11 | `;
12 |
13 | exports[`components/paper Paper should render shallow component ok 1`] = `
14 |
20 | Paper Contents
21 |
22 | `;
23 |
24 | exports[`components/paper PaperToolbar should render shallow component ok 1`] = `
25 |
29 |
34 | Toolbar child contents
35 |
36 |
37 | `;
38 |
--------------------------------------------------------------------------------
/src/components/paper/components/paper-toolbar.module.css:
--------------------------------------------------------------------------------
1 | .ui-paper-toolbar {
2 | display: flex;
3 | border-bottom: 1px solid var(--grey100);
4 | position: relative;
5 | flex-direction: column;
6 | align-items: stretch;
7 | flex-shrink: 0;
8 | align-content: flex-start;
9 | padding: 0 2.4rem;
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/paper/components/paper-toolbar.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import cx from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | import {UIBase} from '../../layout';
6 |
7 | import styles from './paper-toolbar.module.css';
8 |
9 | export const PaperToolbar = props => {
10 | const {children, className} = props;
11 |
12 | const _classNames = cx(
13 | {
14 | [styles['ui-paper-toolbar']]: true,
15 | },
16 | className
17 | );
18 |
19 | return {children};
20 | };
21 |
22 | PaperToolbar.propTypes = {
23 | children: PropTypes.node,
24 | };
25 |
--------------------------------------------------------------------------------
/src/components/paper/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './paper.react';
2 | export {PaperToolbar} from './components/paper-toolbar.react';
3 |
--------------------------------------------------------------------------------
/src/components/radio/README.md:
--------------------------------------------------------------------------------
1 | # Radio
2 |
3 | Radio buttons are most commonly used in groups, to allow a user to pick one of several grouped options. For example, selecting whether a template field is shared or private
4 |
5 | ## Best practices
6 |
7 | - When changing a setting, radio buttons should always be accompanied with a label.
8 | - Labels should be descriptive enough, that they can stand up on their own.
9 |
10 | ## Usage
11 |
12 | ```javascript
13 | import {Radio} from '@kalo/ui';
14 |
15 |
20 | ```
--------------------------------------------------------------------------------
/src/components/radio/__tests__/__snapshots__/radio.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Radio should render shallow component ok 1`] = `
4 |
10 |
17 |
21 |
22 | `;
23 |
--------------------------------------------------------------------------------
/src/components/radio/__tests__/radio.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 | import {shallow} from 'enzyme';
5 |
6 | import Radio from 'components/radio';
7 | import Text from 'components/text';
8 |
9 | describe('Radio', () => {
10 | const defaultProps = {
11 | size: 'medium',
12 | checked: true,
13 | };
14 | const create = (props = {}) =>
15 | renderer.create().toJSON();
16 |
17 | test('should render shallow component ok', () => {
18 | const element = create();
19 | expect(element).toMatchSnapshot();
20 | });
21 |
22 | test('should allow a custom label to be passed in', () => {
23 | const wrapper = shallow(
24 |
27 | A custom label
28 |
29 | }
30 | />
31 | );
32 |
33 | expect(
34 | wrapper
35 | .find('Text')
36 | .childAt(0)
37 | .text()
38 | ).toBe('A custom label');
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/src/components/radio/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './radio.react';
2 |
--------------------------------------------------------------------------------
/src/components/seamless-button/README.md:
--------------------------------------------------------------------------------
1 | # Seamless Button
2 |
--------------------------------------------------------------------------------
/src/components/seamless-button/__examples__/seamless-button.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import SeamlessButton from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Seamless Button',
8 | render: () => ,
9 | html: () => (
10 |
15 | ),
16 | },
17 | {
18 | title: 'Seamless Button with forced active state',
19 | description:
20 | 'This can be useful when used with a contextual menu and the menu is open',
21 | render: () => (
22 |
23 | ),
24 | html: () => (
25 |
30 | ),
31 | },
32 | ];
33 |
--------------------------------------------------------------------------------
/src/components/seamless-button/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './seamless-button.react';
2 |
--------------------------------------------------------------------------------
/src/components/seamless-button/seamless-button.module.css:
--------------------------------------------------------------------------------
1 | .ui-seamless-button {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | background: none;
6 | border: 0;
7 | padding: 0;
8 | border-radius: 4px;
9 | cursor: pointer;
10 | }
11 |
12 | .ui-seamless-button:hover,
13 | .ui-seamless-button--active {
14 | background-color: var(--grey100);
15 | }
16 |
17 | .ui-seamless-button:::-moz-focus-inner {
18 | border: 0;
19 | padding: 0;
20 | }
21 |
22 | .ui-seamless-button svg {
23 | fill: var(--navy700);
24 | }
25 |
26 | .ui-seamless-button--small {
27 | height: 30px;
28 | width: 30px;
29 | }
30 |
31 | .ui-seamless-button--medium {
32 | height: 36px;
33 | width: 36px;
34 | }
35 |
36 | .ui-seamless-button--large {
37 | height: 46px;
38 | width: 46px;
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/select/README.md:
--------------------------------------------------------------------------------
1 | # Select
2 |
3 | The kalo generic select component
--------------------------------------------------------------------------------
/src/components/select/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './select.react';
2 | export {default as Option} from './option.react';
3 |
--------------------------------------------------------------------------------
/src/components/select/option.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const Option = props => {
5 | return {props.children}
;
6 | };
7 |
8 | Option.propTypes = {
9 | /** A value that's passed back via onSelect when a user selects the option */
10 | value: PropTypes.any,
11 | /** Whether or not this option is selected. */
12 | selected: PropTypes.bool,
13 | /** Dropdown children */
14 | children: PropTypes.node.isRequired,
15 | };
16 |
17 | export default Option;
18 |
--------------------------------------------------------------------------------
/src/components/service-tag/README.md:
--------------------------------------------------------------------------------
1 | # Service Tag
2 |
--------------------------------------------------------------------------------
/src/components/service-tag/__tests__/service-tag.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import {mount} from 'enzyme';
4 |
5 | import ServiceTag from '../';
6 |
7 | describe('ServiceTag', () => {
8 | const create = props => {props.children};
9 |
10 | it('should render a service tag', () => {
11 | const element = create({
12 | children: 'Food Photography',
13 | });
14 |
15 | const result = mount(element);
16 | expect(result.exists()).toBe(true);
17 | });
18 |
19 | it('should display a remove button when a onRemove function is passed', () => {
20 | const element = create({
21 | children: 'Food Photography',
22 | onRemove: () => {},
23 | });
24 |
25 | const result = mount(element);
26 | expect(result.render().hasClass('ui-service-tag--removable')).toBe(true);
27 | expect(result.find('.ui-service-tag__remove').length).toBe(1);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/service-tag/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './service-tag.react';
2 |
--------------------------------------------------------------------------------
/src/components/service-tag/service-tag.module.css:
--------------------------------------------------------------------------------
1 | .ui-service-tag {
2 | display: inline-flex;
3 | background-color: var(--white);
4 | border: 1px solid var(--navy500);
5 | color: var(--navy600);
6 | font-size: 1.2rem;
7 | font-weight: 400;
8 | line-height: 1.6rem;
9 | padding: 0.6rem 1.6rem;
10 | border-radius: 30px;
11 | white-space: nowrap;
12 | flex-grow: 0;
13 | }
14 |
15 | .ui-service-tag__inner {
16 | max-width: 220px;
17 | white-space: nowrap;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | }
21 |
22 | .ui-service-tag--removable {
23 | 1padding: 0.6rem 1.2rem 0.6rem 1.8rem;
24 | }
25 |
26 | .ui-service-tag__remove {
27 | appearance: none;
28 | background-color: transparent;
29 | width: 16px;
30 | height: 16px;
31 | text-align: center;
32 | padding: 0;
33 | margin-left: 0.8rem;
34 | cursor: pointer;
35 | border-radius: 50%;
36 | border: 1px solid transparent;
37 | }
38 |
39 | .ui-service-tag__remove:active {
40 | box-shadow: none;
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/service-tag/service-tag.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 | import Icon from '../icon';
7 |
8 | import styles from './service-tag.module.css';
9 |
10 | const ServiceTag = props => {
11 | const {children, className, onRemove, ...otherProps} = props;
12 |
13 | const _classNames = cx(
14 | {
15 | [styles['ui-service-tag']]: true,
16 | [styles['ui-service-tag--removable']]: !!onRemove,
17 | },
18 | className
19 | );
20 | return (
21 |
22 | {children}
23 | {onRemove && (
24 |
27 | )}
28 |
29 | );
30 | };
31 |
32 | ServiceTag.propTypes = {
33 | /** The main tag label */
34 | children: PropTypes.string,
35 | /** A function to call when the tag is removed */
36 | onRemove: PropTypes.func,
37 | className: PropTypes.string,
38 | };
39 |
40 | export default ServiceTag;
41 |
--------------------------------------------------------------------------------
/src/components/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # Skeleton
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-avatar.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 | import SkeletonShape from './skeleton-shape.react';
4 |
5 | import {AVATAR_SIZE_MULTIPLIER} from '../skeleton.react';
6 | /**
7 | * Avatar Skeleton
8 | */
9 | const SkeletonAvatar = props => {
10 | const {size = 4, ...otherProps} = props;
11 | const width = size * AVATAR_SIZE_MULTIPLIER;
12 | return (
13 |
19 | );
20 | };
21 |
22 | SkeletonAvatar.propTypes = {
23 | size: PropTypes.number,
24 | };
25 |
26 | export default SkeletonAvatar;
27 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-button.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SkeletonShape from './skeleton-shape.react';
5 | import {TEXT_SIZE_MULTIPLIER, BUTTON_HEIGHT} from '../skeleton.react';
6 |
7 | /**
8 | * Button Skeleton
9 | */
10 |
11 | const SkeletonButton = props => {
12 | const {size = 7, square, ...otherProps} = props;
13 | const width = square ? BUTTON_HEIGHT : size * TEXT_SIZE_MULTIPLIER;
14 | return ;
15 | };
16 |
17 | SkeletonButton.propTypes = {
18 | size: PropTypes.number,
19 | square: PropTypes.bool,
20 | };
21 |
22 | export default SkeletonButton;
23 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-card.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SkeletonPaper from './skeleton-paper.react';
5 | import SkeletonText from './skeleton-text.react';
6 | import SkeletonAvatar from './skeleton-avatar.react';
7 | import SpacerBox from './skeleton-spacer-box.react';
8 |
9 | /**
10 | * A freelancer card skeleton
11 | */
12 | const SkeletonCard = props => {
13 | const {children, ...otherProps} = props;
14 | return (
15 |
16 |
17 | {children
18 | ? children
19 | : [
20 | ,
21 | ,
22 | ,
23 | ]}
24 |
25 |
26 | );
27 | };
28 |
29 | SkeletonCard.propTypes = {
30 | children: PropTypes.node,
31 | };
32 |
33 | export default SkeletonCard;
34 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-content.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {Box} from '../../layout';
5 |
6 | const SkeletonContent = ({children, ...otherProps}) => (
7 |
8 | {children}
9 |
10 | );
11 |
12 | SkeletonContent.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | };
15 |
16 | export default SkeletonContent;
17 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-grid.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SpacerBox from './skeleton-spacer-box.react';
5 |
6 | const SkeletonGrid = props => {
7 | const {children, center, ...otherProps} = props;
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | SkeletonGrid.propTypes = {
16 | children: PropTypes.node.isRequired,
17 | center: PropTypes.bool,
18 | };
19 |
20 | export default SkeletonGrid;
21 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-list-item.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SkeletonPaper from './skeleton-paper.react';
5 | import SkeletonText from './skeleton-text.react';
6 | import SpacerBox from './skeleton-spacer-box.react';
7 |
8 | const SkeletonListItem = props => {
9 | const {children, ...otherProps} = props;
10 | return (
11 |
12 |
13 | {children
14 | ? children
15 | : [
16 | ,
17 | ,
18 | ]}
19 |
20 |
21 | );
22 | };
23 |
24 | SkeletonListItem.propTypes = {
25 | children: PropTypes.node,
26 | };
27 |
28 | export default SkeletonListItem;
29 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-list.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SpacerBox from './skeleton-spacer-box.react';
5 |
6 | const SkeletonList = props => {
7 | const {children, center, ...otherProps} = props;
8 | return (
9 |
16 | {children}
17 |
18 | );
19 | };
20 |
21 | SkeletonList.propTypes = {
22 | children: PropTypes.node.isRequired,
23 | center: PropTypes.bool,
24 | };
25 | export default SkeletonList;
26 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-page-header-heading.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 |
4 | import {UIBase} from '../../layout';
5 |
6 | import styles from '../skeleton.module.css';
7 |
8 | /**
9 | * Skeleton page header heading
10 | */
11 | export default function SkeletonPageHeaderHeading(props) {
12 | const {width, children, className, ...otherProps} = props;
13 |
14 | const _classNames = cx(
15 | {
16 | [styles['ui-skeleton-page-header-heading']]: true,
17 | },
18 | className
19 | );
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-page-header-tabs.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {Box} from '../../layout';
5 | import SpacerBox from './skeleton-spacer-box.react';
6 |
7 | const SkeletonPageHeaderTabs = props => {
8 | const {width = 1180, children, ...otherProps} = props;
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | };
15 |
16 | SkeletonPageHeaderTabs.propTypes = {
17 | width: PropTypes.number,
18 | children: PropTypes.node.isRequired,
19 | };
20 |
21 | export default SkeletonPageHeaderTabs;
22 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-page-header-toolbar.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {UIBase, Box} from '../../layout';
5 |
6 | import SpacerBox from './skeleton-spacer-box.react';
7 |
8 | import styles from '../skeleton.module.css';
9 |
10 | const SkeletonPageHeaderToolbar = props => {
11 | const {width = 1180, children} = props;
12 | return (
13 |
14 |
15 | {children}
16 |
17 |
18 | );
19 | };
20 |
21 | SkeletonPageHeaderToolbar.propTypes = {
22 | width: PropTypes.number,
23 | children: PropTypes.node.isRequired,
24 | };
25 |
26 | export default SkeletonPageHeaderToolbar;
27 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-page-header.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 |
4 | import {UIBase} from '../../layout';
5 |
6 | import styles from '../skeleton.module.css';
7 |
8 | /**
9 | * Skeleton page header
10 | */
11 |
12 | export default function SkeletonPageHeader(props) {
13 | const {children, className, ...otherProps} = props;
14 | const _classNames = cx(
15 | {
16 | [styles['ui-skeleton-page-header']]: true,
17 | },
18 | className
19 | );
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-page.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {Box} from '../../layout';
5 |
6 | const SkeletonPage = props => {
7 | const {width = 1180, children, ...otherProps} = props;
8 | return (
9 |
10 |
11 | {children}
12 |
13 |
14 | );
15 | };
16 |
17 | SkeletonPage.propTypes = {
18 | width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
19 | children: PropTypes.node,
20 | };
21 |
22 | export default SkeletonPage;
23 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-paper.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Paper from '../../paper';
5 | /**
6 | * Paper Skeleton
7 | */
8 |
9 | const SkeletonPaper = props => {
10 | const {children, ...otherProps} = props;
11 | return (
12 |
13 | {children}
14 |
15 | );
16 | };
17 |
18 | SkeletonPaper.propTypes = {
19 | children: PropTypes.node.isRequired,
20 | };
21 |
22 | export default SkeletonPaper;
23 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-shape.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../../layout';
6 |
7 | import styles from '../skeleton.module.css';
8 |
9 | const SkeletonShape = props => {
10 | const {
11 | children,
12 | className,
13 | shape = 'square',
14 | width,
15 | height,
16 | ...otherProps
17 | } = props;
18 |
19 | const _classNames = cx(
20 | {
21 | [styles['ui-skeleton-shape']]: true,
22 | [styles[`ui-skeleton-shape--${String(shape)}`]]: true,
23 | },
24 | className
25 | );
26 | return (
27 |
28 | {children}
29 |
30 | );
31 | };
32 |
33 | SkeletonShape.propTypes = {
34 | children: PropTypes.node,
35 | className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
36 | /** ['circle' | 'square'] */
37 | shape: PropTypes.oneOf(['circle', 'square']),
38 | width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
39 | height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
40 | };
41 |
42 | export default SkeletonShape;
43 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-spacer-box.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {Box} from '../../layout';
5 |
6 | const SpacerBox = props => {
7 | const {
8 | spacing = 25,
9 | vertical,
10 | center = true,
11 | childFlex,
12 | children,
13 | ...otherProps
14 | } = props;
15 |
16 | return (
17 |
24 | {React.Children.map(children, child =>
25 | React.cloneElement(child, {
26 | marginTop: vertical ? spacing : 0,
27 | marginLeft: !vertical ? spacing : 0,
28 | flex: childFlex,
29 | })
30 | )}
31 |
32 | );
33 | };
34 |
35 | SpacerBox.propTypes = {
36 | spacing: PropTypes.number,
37 | vertical: PropTypes.bool,
38 | center: PropTypes.bool,
39 | childFlex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
40 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
41 | };
42 |
43 | export default SpacerBox;
44 |
--------------------------------------------------------------------------------
/src/components/skeleton/components/skeleton-text.react.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import SkeletonShape from './skeleton-shape.react';
5 | import {TEXT_HEIGHT} from '../skeleton.react';
6 |
7 | /**
8 | * Text Skeleton
9 | * TODO: Allow multiline (with appropriate line spacing)
10 | */
11 |
12 | const SkeletonText = props => {
13 | const {heading, width = '50%', ...otherProps} = props;
14 | const height = heading ? TEXT_HEIGHT * 2 : TEXT_HEIGHT;
15 | return ;
16 | };
17 |
18 | SkeletonText.propTypes = {
19 | width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
20 | heading: PropTypes.bool,
21 | };
22 |
23 | export default SkeletonText;
24 |
--------------------------------------------------------------------------------
/src/components/skeleton/skeleton.react.js:
--------------------------------------------------------------------------------
1 | /** Multiplier for textual content "size" */
2 | export const TEXT_SIZE_MULTIPLIER = 10;
3 |
4 | /** Multiplier for an avatar diameter */
5 | export const AVATAR_SIZE_MULTIPLIER = 20;
6 |
7 | /** Height of text */
8 | export const TEXT_HEIGHT = 12;
9 |
10 | /** Height of a button */
11 | export const BUTTON_HEIGHT = 36;
12 |
--------------------------------------------------------------------------------
/src/components/star-rating/README.md:
--------------------------------------------------------------------------------
1 | # Star Rating
2 |
--------------------------------------------------------------------------------
/src/components/star-rating/__examples__/star-rating.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import StarRating from '../';
4 |
5 | export const examples = [
6 | {
7 | title: 'Star rating',
8 | description: '',
9 | render: () => ,
10 | },
11 | {
12 | title: 'Star rating with half score',
13 | render: () => ,
14 | },
15 | ];
16 |
--------------------------------------------------------------------------------
/src/components/star-rating/__tests__/star-rating.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import StarRating from '../star-rating.react';
6 |
7 | describe('StarRating', () => {
8 | test('should render properly', () => {
9 | const wrapper = renderer.create().toJSON();
10 |
11 | expect(wrapper).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/star-rating/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './star-rating.react';
2 |
--------------------------------------------------------------------------------
/src/components/star-rating/star-rating.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | align-items: center;
4 | }
5 |
6 | .star {
7 | position: relative;
8 | overflow: hidden;
9 | }
10 |
11 | .icon {
12 | transition: all 0.2s linear;
13 | position: absolute;
14 | }
15 |
16 | .background {
17 | display: flex;
18 | color: var(--grey300);
19 | }
20 |
21 | .foreground {
22 | display: flex;
23 | color: var(--grey300);
24 | }
25 |
26 | .half {
27 | width: 50%;
28 | overflow: hidden;
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/sticky/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './sticky.react';
2 |
--------------------------------------------------------------------------------
/src/components/table/README.md:
--------------------------------------------------------------------------------
1 | # Table
2 |
3 | Simple Table, TableHead, TableBody, TableRow and TableCell components. Customisation can be done outside of the core components (sorting, pagination, etc).
4 |
--------------------------------------------------------------------------------
/src/components/table/__tests__/table-body.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import TableBody from '../';
5 |
6 | describe('', () => {
7 | it('should render children', () => {
8 | const result = shallow(
9 |
10 |
11 |
12 | );
13 | const tr = result.find('tr');
14 | expect(tr.length).toBe(1);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/table/__tests__/table-head.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import TableHead from '../';
5 |
6 | describe('', () => {
7 | it('should render children', () => {
8 | const result = shallow(
9 |
10 |
11 |
12 | );
13 | const tr = result.find('tr');
14 | expect(tr.length).toBe(1);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/table/__tests__/table-row.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import TableRow from '../';
5 |
6 | describe('', () => {
7 | it('should render children', () => {
8 | const result = shallow(
9 |
10 | |
11 |
12 | );
13 | const td = result.find('td');
14 | expect(td.length).toBe(1);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/table/__tests__/table.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import {shallow} from 'enzyme';
4 | import Table from '../';
5 |
6 | describe('', () => {
7 | it('should render children', () => {
8 | const result = shallow(
9 |
12 | );
13 | const tbody = result.find('tbody');
14 | expect(tbody.length).toBe(1);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/table/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './table.react';
2 | export {default as TableBody} from './table-body.react';
3 | export {default as TableCell} from './table-cell.react';
4 | export {default as TableHead} from './table-head.react';
5 | export {default as TableRow} from './table-row.react';
6 |
--------------------------------------------------------------------------------
/src/components/table/table-body.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './table.module.css';
8 |
9 | export class TableBody extends React.Component {
10 | static propTypes = {
11 | border: PropTypes.bool,
12 | children: PropTypes.node.isRequired,
13 | };
14 |
15 | static childContextTypes = {
16 | table: PropTypes.object,
17 | };
18 |
19 | getChildContext() {
20 | const {border = true} = this.props;
21 | return {
22 | table: {
23 | body: true,
24 | border,
25 | },
26 | };
27 | }
28 |
29 | render() {
30 | const {className, children, ...otherProps} = this.props;
31 |
32 | const _classNames = cx(
33 | {
34 | [styles['ui-table-body']]: true,
35 | },
36 | className
37 | );
38 | return (
39 |
40 | {children}
41 |
42 | );
43 | }
44 | }
45 |
46 | export default TableBody;
47 |
--------------------------------------------------------------------------------
/src/components/table/table-head.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './table.module.css';
8 |
9 | export class TableHead extends React.Component {
10 | static propTypes = {
11 | children: PropTypes.node.isRequired,
12 | };
13 |
14 | static childContextTypes = {
15 | table: PropTypes.object,
16 | };
17 |
18 | getChildContext() {
19 | return {
20 | table: {
21 | head: true,
22 | },
23 | };
24 | }
25 |
26 | render() {
27 | const {children, className, ...otherProps} = this.props;
28 |
29 | const _classNames = cx(
30 | {
31 | [styles['ui-table-head']]: true,
32 | },
33 | className
34 | );
35 |
36 | return (
37 |
38 | {children}
39 |
40 | );
41 | }
42 | }
43 |
44 | export default TableHead;
45 |
--------------------------------------------------------------------------------
/src/components/table/table-row.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 | import PropTypes from 'prop-types';
4 | import {compose, getContext, withProps, setDisplayName} from 'recompose';
5 |
6 | import {UIBase} from '../layout';
7 | import styles from './table.module.css';
8 |
9 | const TableRow = props => {
10 | const {children, className, ...otherProps} = props;
11 |
12 | const _classNames = cx(
13 | {
14 | [styles['ui-table-row']]: true,
15 | },
16 | className
17 | );
18 |
19 | return (
20 |
21 | {children}
22 |
23 | );
24 | };
25 |
26 | TableRow.propTypes = {
27 | children: PropTypes.node.isRequired,
28 | // Provided by context
29 | table: PropTypes.shape({
30 | head: PropTypes.bool,
31 | body: PropTypes.bool,
32 | footer: PropTypes.bool,
33 | }),
34 | };
35 |
36 | export default compose(
37 | setDisplayName('TableRow'),
38 | getContext({
39 | table: PropTypes.shape({
40 | head: PropTypes.bool,
41 | body: PropTypes.bool,
42 | footer: PropTypes.bool,
43 | }),
44 | }),
45 | withProps(props => ({
46 | header: !!props.table && !!props.table.head,
47 | }))
48 | )(TableRow);
49 |
--------------------------------------------------------------------------------
/src/components/table/table.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './table.module.css';
8 |
9 | export class Table extends React.Component {
10 | static propTypes = {
11 | children: PropTypes.node.isRequired,
12 | };
13 |
14 | static childContextTypes = {
15 | table: PropTypes.object,
16 | };
17 |
18 | getChildContext() {
19 | return {
20 | table: {},
21 | };
22 | }
23 |
24 | render() {
25 | const {className, children, ...otherProps} = this.props;
26 |
27 | const _classNames = cx(
28 | {
29 | [styles['ui-table']]: true,
30 | },
31 | className
32 | );
33 | return (
34 |
40 | {children}
41 |
42 | );
43 | }
44 | }
45 |
46 | export default Table;
47 |
--------------------------------------------------------------------------------
/src/components/tabs/README.md:
--------------------------------------------------------------------------------
1 | # Tabs
2 |
--------------------------------------------------------------------------------
/src/components/tabs/__tests__/tabs.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import {mount} from 'enzyme';
4 |
5 | import {Tabs, Tab} from '../';
6 |
7 | describe('Tabs', () => {
8 | const create = props => (
9 |
10 | Profile
11 | Messages
12 | Notes & Documents
13 |
14 | );
15 |
16 | it('should render a set of three tabs', () => {
17 | const element = create();
18 |
19 | const result = mount(element);
20 | expect(result.exists()).toBe(true);
21 | expect(result.find(Tab).length).toBe(3);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/components/tabs/index.js:
--------------------------------------------------------------------------------
1 | export {default as Tabs} from './tabs.react';
2 | export {default as Tab} from './tab.react';
3 |
--------------------------------------------------------------------------------
/src/components/tabs/tab.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './tabs.module.css';
8 |
9 | const Tab = props => {
10 | const {children, className, active, disabled, ...otherProps} = props;
11 |
12 | return (
13 |
14 |
27 | {children}
28 |
29 |
30 | );
31 | };
32 |
33 | Tab.propTypes = {
34 | /** The contents of the tab */
35 | children: PropTypes.node.isRequired,
36 | /** Any classes to pass down */
37 | className: PropTypes.string,
38 | /** Is the tab in a selected/active state */
39 | active: PropTypes.bool,
40 | /** Prevents the user from interacting, and makes the tab visually disabled */
41 | disabled: PropTypes.bool,
42 | };
43 |
44 | export default Tab;
45 |
--------------------------------------------------------------------------------
/src/components/tabs/tabs.module.css:
--------------------------------------------------------------------------------
1 | .ui-tabs {
2 | overflow-x: auto;
3 | border-bottom: 1px solid var(--grey100);
4 | -webkit-overflow-scrolling: touch;
5 | }
6 |
7 | .ui-tabs::-webkit-scrollbar {
8 | display: none;
9 | }
10 |
11 | .ui-tabs__inner {
12 | display: flex;
13 | flex-direction: row;
14 | align-items: flex-end;
15 | justify-content: flex-start;
16 | margin: 0 auto;
17 | padding: var(--spacing-small) var(--spacing-medium) 0 0;
18 | width: 100%;
19 | height: 4.2rem;
20 | list-style: none;
21 | }
22 |
23 | .ui-tabs__inner li {
24 | flex-shrink: 0;
25 | }
26 |
27 | .ui-tabs__tab {
28 | color: var(--navy800);
29 | padding: 0 var(--spacing-medium) var(--spacing-small);
30 | text-decoration: none;
31 | cursor: pointer;
32 | font-size: 1.4rem;
33 | font-weight: var(--font-weight-semibold);
34 | border-bottom: 2px solid transparent;
35 | display: inline-flex;
36 | }
37 |
38 | .ui-tabs__tab:hover {
39 | color: var(--purple500);
40 | text-decoration: none;
41 | }
42 |
43 | .ui-tabs__tab--active {
44 | color: var(--purple500);
45 | border-bottom-color: var(--purple500);
46 | }
47 |
48 | .ui-tabs__tab--disabled,
49 | .ui-tabs__tab--disabled:hover {
50 | color: var(--grey500);
51 | cursor: default;
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/tabs/tabs.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 |
7 | import styles from './tabs.module.css';
8 |
9 | const Tabs = props => {
10 | const {children, className, ...otherProps} = props;
11 |
12 | return (
13 |
23 |
31 | {children}
32 |
33 |
34 | );
35 | };
36 |
37 | Tabs.propTypes = {
38 | children: PropTypes.node.isRequired,
39 | className: PropTypes.string,
40 | };
41 |
42 | export default Tabs;
43 |
--------------------------------------------------------------------------------
/src/components/tag-group/README.md:
--------------------------------------------------------------------------------
1 | # Tag Group
2 |
3 | Use the TagGroup component to implement consistent vertical spacing between Tags, Lozenges, and ServiceTags
4 |
--------------------------------------------------------------------------------
/src/components/tag-group/__examples__/tag-group.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Tag from '../../tag';
4 | import TagGroup from '../';
5 |
6 | export const examples = [
7 | {
8 | title: 'Tag group',
9 | render: () => (
10 |
11 | Tag one
12 | Another tag
13 | A third tag
14 |
15 | ),
16 | },
17 | ];
18 |
--------------------------------------------------------------------------------
/src/components/tag-group/__tests__/tag-group.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import {mount} from 'enzyme';
4 |
5 | import TagGroup from '../tag-group.react';
6 | import Tag from 'components/tag';
7 |
8 | describe('TagGroup', () => {
9 | const create = props => (
10 |
11 | Tag one
12 | Another tag
13 | A third tag
14 |
15 | );
16 |
17 | it('should render correctly', () => {
18 | const element = create();
19 |
20 | const result = mount(element);
21 | expect(result.exists()).toBe(true);
22 | expect(result.find(Tag).length).toBe(3);
23 | });
24 |
25 | it('should limit the number of children if a limit is set', () => {
26 | const element = (
27 |
28 | Tag one
29 | Another tag
30 | A third tag
31 | A fourth tag
32 | A fifth tag
33 |
34 | );
35 |
36 | const result = mount(element);
37 | expect(result.exists()).toBe(true);
38 | expect(result.find(Tag).length).toBe(4);
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/src/components/tag-group/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './tag-group.react';
2 |
--------------------------------------------------------------------------------
/src/components/tag-group/tag-group.module.css:
--------------------------------------------------------------------------------
1 | .ui-tag-group {
2 | display: flex;
3 | align-items: center;
4 | flex-wrap: wrap;
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/tag/README.md:
--------------------------------------------------------------------------------
1 | # Tag
2 |
--------------------------------------------------------------------------------
/src/components/tag/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './tag.react';
2 |
--------------------------------------------------------------------------------
/src/components/tag/tag.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import cx from 'classnames';
4 |
5 | import {UIBase} from '../layout';
6 | import Icon from '../icon';
7 |
8 | import styles from './tag.module.css';
9 |
10 | const Tag = props => {
11 | const {children, avatar, isLink, onRemove, ...otherProps} = props;
12 |
13 | const _classNames = cx({
14 | [styles['ui-tag']]: true,
15 | [styles['ui-tag--link']]: isLink,
16 | [styles['ui-tag--avatar']]: avatar,
17 | [styles['ui-tag--removable']]: !!onRemove,
18 | });
19 |
20 | return (
21 |
27 | {avatar}
28 | {children}
29 | {onRemove && (
30 |
33 | )}
34 |
35 | );
36 | };
37 |
38 | Tag.propTypes = {
39 | children: PropTypes.string.isRequired,
40 | avatar: PropTypes.node,
41 | isLink: PropTypes.bool,
42 | onRemove: PropTypes.func,
43 | };
44 |
45 | export default Tag;
46 |
--------------------------------------------------------------------------------
/src/components/text/README.md:
--------------------------------------------------------------------------------
1 | # Text
2 |
3 | The core text component
--------------------------------------------------------------------------------
/src/components/text/__tests__/__snapshots__/text.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Text should render green text 1`] = `
4 |
9 | Hello World
10 |
11 | `;
12 |
13 | exports[`Text should render large text 1`] = `
14 |
19 | Hello World
20 |
21 | `;
22 |
23 | exports[`Text should render shallow component ok 1`] = `
24 |
29 | Hello World
30 |
31 | `;
32 |
--------------------------------------------------------------------------------
/src/components/text/__tests__/text.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import * as React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import Text from 'components/text';
6 |
7 | describe('Text', () => {
8 | const defaultProps = {
9 | size: 'medium',
10 | color: 'charcoal',
11 | };
12 | const create = (props = {}) =>
13 | renderer
14 | .create(
15 |
16 | Hello World
17 |
18 | )
19 | .toJSON();
20 |
21 | test('should render shallow component ok', () => {
22 | const element = create();
23 | expect(element).toMatchSnapshot();
24 | });
25 |
26 | test('should render green text', () => {
27 | const element = create({color: 'green'});
28 | expect(element).toMatchSnapshot();
29 | });
30 |
31 | test('should render large text', () => {
32 | const element = create({size: 'large'});
33 | expect(element).toMatchSnapshot();
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/text/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './text.react';
2 |
--------------------------------------------------------------------------------
/src/components/textarea/README.md:
--------------------------------------------------------------------------------
1 | # Textarea
2 |
3 | The textarea component can expand automatically based on user input.
--------------------------------------------------------------------------------
/src/components/textarea/__examples__/textarea.examples.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Textarea from '../';
3 |
4 | export const examples = [
5 | {
6 | title: 'Textarea',
7 | description: 'A standard Textarea',
8 | render: () => ,
9 | html: () => (
10 |
11 | ),
12 | },
13 | {
14 | title: 'Expanding textarea',
15 | description:
16 | "Textarea can also exand automatically in relation to it's contents, by passing an expand prop",
17 | render: () => (
18 |
19 | ),
20 | },
21 | ];
22 |
--------------------------------------------------------------------------------
/src/components/textarea/__tests__/__snapshots__/textarea.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Input should render shallow component ok 1`] = `
4 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/textarea/__tests__/textarea.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import Textarea from '../';
6 |
7 | describe('Input', () => {
8 | const defaultProps = {
9 | size: 'medium',
10 | theme: 'default',
11 | };
12 |
13 | test('should render shallow component ok', () => {
14 | const element = renderer.create().toJSON();
15 | expect(element).toMatchSnapshot();
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/components/textarea/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './textarea.react';
2 |
--------------------------------------------------------------------------------
/src/components/toggle-button/README.md:
--------------------------------------------------------------------------------
1 | # ToggleButton
2 |
3 | A standard toggle button for toggling between two states
--------------------------------------------------------------------------------
/src/components/toggle-button/__tests__/__snapshots__/toggle-button.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`ToggleButton should render shallow component ok 1`] = `
4 |
24 | `;
25 |
--------------------------------------------------------------------------------
/src/components/toggle-button/__tests__/toggle-button.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import ToggleButton from '../toggle-button.react';
6 |
7 | describe('ToggleButton', () => {
8 | test('should render shallow component ok', () => {
9 | const element = renderer
10 | .create( {}} />)
11 | .toJSON();
12 | expect(element).toMatchSnapshot();
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/components/toggle-button/index.js:
--------------------------------------------------------------------------------
1 | export {default, HEIGHT} from './toggle-button.react';
2 |
--------------------------------------------------------------------------------
/src/components/tooltip-box/README.md:
--------------------------------------------------------------------------------
1 | # TooltipBox
2 |
3 | It creates a tooltip-ready element
4 |
--------------------------------------------------------------------------------
/src/components/tooltip-box/index.js:
--------------------------------------------------------------------------------
1 | export {default} from './tooltip-box.react';
2 |
--------------------------------------------------------------------------------
/src/design-tokens/README.md:
--------------------------------------------------------------------------------
1 | # Design Tokens
2 |
3 | > **Note**: The files in this directory are autogenerated. See [config/design-tokens](/config/design-tokens) for the source.
--------------------------------------------------------------------------------
/src/design-tokens/__tests__/tokens.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | import renderer from 'react-test-renderer';
3 |
4 | import JSTokens from '../tokens.js';
5 | import CSSTokens from '../tokens.css.js';
6 | import ThemeTokens from '../tokens.theme.js';
7 |
8 | describe('Tokens', () => {
9 | test('should be present', () => {
10 | expect(JSTokens).toMatchSnapshot();
11 | });
12 |
13 | test('should exist in CSS form', () => {
14 | expect(CSSTokens).toBeDefined();
15 | });
16 |
17 | test('should exist in theme form', () => {
18 | expect(ThemeTokens).toBeDefined();
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/icons/svg/access_time.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/account_balance.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/account_balance_wallet.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/account_box.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/account_circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/add.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/add_a_photo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/archive.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/arrow_drop_down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/arrow_drop_down_circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/arrow_drop_up.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/art_track.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/assignment.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/assignment_ind.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/attach_file.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/attach_money.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/autorenew.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/book.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/border_color.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/chat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/check.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/check_box.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/check_box_outline_blank.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/check_circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/check_circle_outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/chevron_left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/chevron_right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/clear.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/comment.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/content_paste.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/create.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/credit_card.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/date_range.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/domain.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/done.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/done_all.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/error_outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/exit_to_app.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/extension.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/file_upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/file_xls.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/folder_shared.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/format_color_fill.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/icons/svg/group.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/help_outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/highlight_off.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/how_to_reg.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/info_outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/insert_drive_file.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/instagram.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_categories.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_clients.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_index.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_messages.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_premium.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_projects.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_reporting.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_tasks.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/kalo_verified.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/keyboard_arrow_down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/keyboard_arrow_left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/keyboard_arrow_right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/keyboard_arrow_up.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/keyboard_return.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/launch.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/linkedin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/local_atm.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/local_offer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/location_city.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/location_on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/loop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/megaphone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/mode_edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/monetization_on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/more_vert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/note_add.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/notifications.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/open_in_new.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/payment.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/people.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/perm_contact_calendar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/perm_identity.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/person.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/person_add.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/person_outline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/picture_as_pdf.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/playlist_add_check.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/present_to_all.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/question_help_message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/radio_button_checked.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/receipt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/remove.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/remove_circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/remove_red_eye.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/icons/svg/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/security.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/send.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/settings.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/short_text.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/swap_vert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/tv.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/verified_user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/view_headline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/view_module.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/view_week.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/warning.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/youtube.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/styles/kalo-ui-typography.css:
--------------------------------------------------------------------------------
1 | .text--helper {
2 | font-size: 12px;
3 | font-weight: 400;
4 | }
5 |
6 | strong,
7 | b {
8 | font-weight: 600;
9 | }
10 |
11 | em {
12 | font-style: italic;
13 | }
14 |
15 | p,
16 | li,
17 | ol {
18 | font-size: 1.4rem;
19 | }
20 |
21 | p {
22 | margin-top: 1.6rem;
23 | }
24 |
25 | p:first-child {
26 | margin-top: 0;
27 | }
28 |
29 | .u-align-left {
30 | text-align: left;
31 | }
32 |
33 | .u-align-center {
34 | text-align: center;
35 | }
36 |
37 | .u-align-right {
38 | text-align: right;
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils/__tests__/array.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 |
3 | import {returnArray} from '../array';
4 |
5 | describe('utils/array', () => {
6 | describe('returnArray', () => {
7 | it('should return an array if passed value is not an array', () => {
8 | const passedValue = 'ABC';
9 | expect(Array.isArray(returnArray(passedValue))).toBe(true);
10 | });
11 |
12 | it('should return an array if passed value is an array', () => {
13 | const passedValue = ['A', 'B', 'C'];
14 | expect(Array.isArray(returnArray(passedValue))).toBe(true);
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/utils/__tests__/dom.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, jest */
2 | /* eslint func-names: 0 */
3 | import {getFixedOffset} from '../dom';
4 |
5 | describe('utils/dom', () => {
6 | describe('getFixedOffset', () => {
7 | it('should handle null elements gracefully', () => {
8 | expect(getFixedOffset(null)).toEqual({top: 0, left: 0});
9 | });
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/src/utils/array.js:
--------------------------------------------------------------------------------
1 | /** Checks if a value is an array, if not, returns the value wrapped in one */
2 | export const returnArray = value => (Array.isArray(value) ? value : [value]);
3 |
--------------------------------------------------------------------------------
/src/utils/react.js:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom';
2 |
3 | /**
4 | * Focus a ref’d react input when it is mounted
5 | * @param ref
6 | */
7 | export function focusOnMount(ref) {
8 | const el = ReactDOM.findDOMNode(ref);
9 |
10 | if (el) {
11 | // Give focus and put the cursor at the end of
12 | // the value.
13 | el.focus();
14 | el.value = el.value;
15 | }
16 | }
17 |
18 | /**
19 | * Select the text of a ref’d react input when it is mounted
20 | * @param ref
21 | */
22 | export function selectOnMount(ref) {
23 | if (ref && ref.select) {
24 | ref.select();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/utils/string.js:
--------------------------------------------------------------------------------
1 | import {capitalize} from 'lodash';
2 |
3 | /** Get the first name from a potentially multi word string */
4 | export function firstName(name) {
5 | return !!name ? capitalize(name.split(' ')[0]) : '';
6 | }
7 |
8 | /** Turn a string into a url friendly slug */
9 | export function slugify(string) {
10 | return string
11 | .toLowerCase()
12 | .replace(/[^\w\s-]/g, '') // remove non-word [a-z0-9_], non-whitespace, non-hyphen characters
13 | .replace(/[\s_-]+/g, '-') // swap any length of whitespace, underscore, hyphen characters with a single -
14 | .replace(/^-+|-+$/g, ''); // remove leading, trailing -
15 | }
16 |
17 | /** Remove extraneous whitespace and newlines from a string */
18 | export function inline(str, replace = ' ') {
19 | return str.replace(/[\s]+/g, replace).trim();
20 | }
21 |
22 | export function pluralize(size, str, plural = 's', singular = '') {
23 | return Math.abs(size) === 1 ? `${str}${singular}` : `${str}${plural}`;
24 | }
25 |
--------------------------------------------------------------------------------
/src/utils/test/global-context.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | /* eslint-disable no-var, no-console, func-names, global-require */
3 |
4 | // This gets run before each test run
5 |
6 | import {configure} from 'enzyme';
7 | import Adapter from 'enzyme-adapter-react-15';
8 |
9 | configure({adapter: new Adapter()});
10 |
--------------------------------------------------------------------------------
/src/utils/test/mocks/file-mock.js:
--------------------------------------------------------------------------------
1 | export default 'path/to/file';
2 |
--------------------------------------------------------------------------------
/src/utils/test/random-string.js:
--------------------------------------------------------------------------------
1 | import {random} from 'lodash';
2 |
3 | export default () =>
4 | `${random(0.0001, 0.9999).toString(36)}justsomebufferforpeaceofmind`.substr(
5 | 2,
6 | 10
7 | );
8 |
--------------------------------------------------------------------------------
/src/utils/type.js:
--------------------------------------------------------------------------------
1 | import {isNumber} from 'lodash';
2 |
3 | /**
4 | * Return the size of an array-like-iterable object (arrays or immutable iterables)
5 | * @param obj
6 | * @returns Number
7 | */
8 | export function size(obj) {
9 | if (obj && isNumber(obj.size)) {
10 | return obj.size;
11 | }
12 |
13 | if (obj && isNumber(obj.length)) {
14 | return obj.length;
15 | }
16 |
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | process.env.BABEL_ENV = 'test';
3 |
4 | module.exports = function(wallaby) {
5 | return {
6 | files: [
7 | {pattern: 'src/**/__tests__/**/*.test.js', ignore: true},
8 | {pattern: 'src/**/__tests__/**/*.tests.js', ignore: true},
9 | 'src/**/*.js',
10 | 'src/**/*.jsx',
11 | 'src/**/*.css',
12 | 'src/**/*.gif',
13 | 'src/**/*.png',
14 | 'src/**/*.jpg',
15 | 'src/**/*.svg',
16 | 'src/**/*.pdf',
17 | 'src/**/*.html',
18 | ],
19 |
20 | tests: ['src/**/__tests__/**/*.test.js', 'src/**/__tests__/**/*.tests.js'],
21 |
22 | env: {
23 | type: 'node',
24 | runner: 'node',
25 | },
26 |
27 | workers: {
28 | recycle: true,
29 | },
30 |
31 | compilers: {
32 | '**/*.js': wallaby.compilers.babel(),
33 | },
34 |
35 | testFramework: 'jest',
36 |
37 | // bootstrap: function(wallaby) {
38 | // var path = require('path');
39 | // process.env.NODE_ENV = 'test';
40 | // process.env.NODE_PATH = path.join(wallaby.projectCacheDir, 'src');
41 | // require('module').Module._initPaths();
42 | // // require('utils/test/require-hooks');
43 | // },
44 | };
45 | };
46 |
--------------------------------------------------------------------------------