Skip to content

Commit

Permalink
Multiselect component (#8)
Browse files Browse the repository at this point in the history
* Fix variable values and minor style issues

* Rename classes of logos

* Fix font size extra small and its use on code and markdown

* Add border for palette colors and update names

* Remove no longer necessary bootstrap dependency

* Add choicesjs-stencil dependency

* Add multiselect less component

* Add multiselect example page

* Update multiselect style

* Rename host env variable

* Fix choicesjs stencil require path

* Update documentation

* Add multiselect documentation

* Update version and babel preset env dependency

* Fix minor issues
  • Loading branch information
moelders authored Oct 3, 2018
1 parent 9b0d72b commit 00e9fb6
Show file tree
Hide file tree
Showing 27 changed files with 2,891 additions and 1,481 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ install:
script:
- npm run lint
- npm run build
- HOST=//adidas.github.io/ BASE=/adidas-yarn-design-system/ npm run doc
- HOSTNAME=//adidas.github.io/ BASE=/adidas-yarn-design-system/ npm run doc

deploy:
- provider: npm
Expand Down
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
# 1.2.0

- Added `multiselect` less component.
- Added `choicesjs-stencil` library as dependency for multiselect components.
- Renamed `HOST` env variable to `HOSTNAME` in order not to overwrite it.
- Updated example.

### [ logos ]

- Renamed logos:
- `yarn-logo adidas` -> `yarn-logo yarn-logo--adidas`.
- `yarn-logo yarn` -> `yarn-logo yarn-logo--yarn`.

### [ multiselect ]

- Added `.multiselect` class to customize `choicesjs-stencil` web component with YARN style.

### [ palette ]

- Added classes to set the `border-color`.
- Renamed classes according to their variable names for `color` and `background-color`:
- `--black` to `--primary-black`.
- `--silver` to `--primary-silver`.
- `--white` to `--primary-white`.

### [ variables ]

- Fixed values.
- Added `@font-size-x-small` and `@font-size-x-large`.

### [ example ]

- Added multiselect component page.

# 1.1.0

- Added mobile view for the main layout.
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
- Footer: it is shown fixed at the bottom of the screen.
- Main container: it fits the available screen between the header/tabbar/toolbar and the footer. It is the only container which should be able to scroll.

**YARN** is based on [Bootstrap v3][bootstrap], which is a front-end framework used to define HTML elements
like grids, typography, inputs and other interface components, as well as optional JS extensions.
**YARN** is based on [Bootstrap v3][bootstrap], which is a front-end framework used to define HTML elements like grids, typography, inputs and other interface components, as well as optional JS extensions.

Currently **YARN** has two different views based on the default font size of `16px`.

- Mobile version: `screen width < 60rem` (`960px`).
- Left sidebar and tabbar components are hidden by default.
- Desktop version `screen width >= 60rem` (`960px`).

Check all its features on the [**documentation page**][yarn-documentation] (work in progress).

## Use cases

The purpose of this library is to provide CSS classes to customize frontend applications with adidas style.
Expand Down Expand Up @@ -187,21 +188,21 @@ The library is compiled in the `dist` folder, whereas the example is created in
The example can be delivered as [Single Page Application][single-page-application] using the script `npm run build:example:spa`, executed after building the library. It accepts two environment variables:
- `HOST`: host where the application will be deployed, the protocol should be omitted.
- `HOSTNAME`: host where the application will be deployed, the protocol should be omitted.
- `BASE`: path where the application will be available.
Example deploying the application in `https://name.domain:port/app`:
```
HOST=//name.domain:port BASE=app npm run build:example:spa
HOSTNAME=//name.domain:port BASE=app npm run build:example:spa
```
### Documentation
The documentation is generated using the script `doc`, which generates the example in [SPA][single-page-application] mode. It also accepts the environment variables.
```
HOST=//name.domain:port BASE=app npm run doc
HOSTNAME=//name.domain:port BASE=app npm run doc
```
## Development
Expand Down Expand Up @@ -311,3 +312,4 @@ For further information open the [adidas terms and conditions][terms-and-conditi
[vuejs]: https://vuejs.org/
[webpack]: https://webpack.js.org/
[webpack-hot-module-replacement]: https://webpack.js.org/concepts/hot-module-replacement/
[yarn-documentation]: https://adidas.github.io/adidas-yarn-design-system/
2 changes: 1 addition & 1 deletion example/components/headerbar/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<nav class="header__container">
<div class="header__left">
<nuxt-link class="header__brand" :to="{ name: 'index' }">
<span class="header__icon yarn-logo adidas"></span>
<span class="header__icon yarn-logo yarn-logo--adidas"></span>
<span class="header__headline">
{{ $t('meta.yarn') }}
</span>
Expand Down
57 changes: 57 additions & 0 deletions example/locales/components/multiselect/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Documentation

### Installation

```
npm install choices.js choicesjs-stencil
```

```html
<script src="node_modules/choices.js/assets/scripts/dist/choices.min.js"></script>
<script src="node_modules/choicesjs-stencil/dist/choicesjsstencil.js"></script>
```

For modern frameworks check the specific integration in the StencilJS documentation: [framework integration][framework-integration].

### Use of the component

To use the component just add it to the HTML code with the class `multiselect` and apply its configuration via element properties. The box height is fixed to one line unless the class `multiline` is added to the element.

```html
<choicesjs-stencil class="multiselect" type="single"/>
<choicesjs-stencil class="multiselect multiline" type="multiple"/>
```

```js
var select = document.querySelector('choicesjs-stencil[type=single]');

select.choices = [
{ value: 'superstar', label: 'Superstar', selected: true, disabled: false },
{ value: 'stansmith', label: 'Stan Smith', selected: false, disabled: false },
{ value: 'campus', label: 'Campus', selected: false, disabled: false }
];
select.placeholder = true;
select.placeholderValue = 'type the value...';
```

The component has three different behaviors via `type` property:

- `text`: faceted text selector (the user can type any value and it will be added to the list of values).
- `single`: single value selector (from a dropdown list).
- `multiple`: multiple value selector (from a dropdown list).

The full component configuration can be found at [ChoicesJS][choicesjs] library, and a live demo at [choicesjs-stencil][choicesjs-stencil].

#### Customization

Most of the elements can be created using the method `.callbackOnCreateTemplates()` which returns a new template for different items:

- [Documentation][choicesjs-templates].
- [Available elements][choicesjs-templates-elements].

[choicesjs]: https://github.com/jshjohnson/Choices
[choicesjs-stencil]: https://adidas.github.io/choicesjs-stencil/
[choicesjs-templates]: https://www.npmjs.com/package/choices.js#callbackoncreatetemplates
[choicesjs-templates-elements]: https://github.com/jshjohnson/Choices/blob/394bde313d0f8a50b4c2b9d64d35b76ded68a515/assets/scripts/src/choices.js#L2463-L2701
[framework-integration]: https://stenciljs.com/docs/overview/
[stenciljs]: https://stenciljs.com/
15 changes: 15 additions & 0 deletions example/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,21 @@
},
"mobile": "Mobile buttons"
}
},
"components-multiselect": {
"name": "Multiselect components",
"text": "Faceted text selector",
"single": "Single value selector",
"multiple": "Multiple value selector",
"config": {
"placeholder": "select...",
"no-results": "No results found",
"no-choices": "Nothing to select",
"item-selection": "Press to choose",
"add-item": "Press enter to add <b>\"{value}\"</b>",
"max-items": "Maximum {maxItemCount} values",
"remove-button": "Remove item: {label}"
}
}
}
}
4 changes: 4 additions & 0 deletions example/pages/components/multiselect.meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"showInSidebar": true,
"displayName": "views.components-multiselect.name"
}
118 changes: 118 additions & 0 deletions example/pages/components/multiselect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<template>
<div class="container">
<div class="jumbotron">
<div class="row">
<div class="col-xs-12 col-sm-10 col-sm-offset-1">
<p>{{ $t('views.components.name') }}</p>
<h2>{{ $t('views.components-multiselect.name') }}</h2>
</div>
</div>
</div>
<section class="section">
<div class="row">
<div class="col-xs-12 col-sm-10 col-sm-offset-1">
<section class="section">
<div class="row">
<h5 class="col-xs-12">
{{ $t('views.components-multiselect.text') }}
</h5>
<choicesjs-stencil class="col-xs-12 multiselect" type="text" v-pre/>
</div>
</section>
<section class="section">
<div class="row">
<h5 class="col-xs-12">
{{ $t('views.components-multiselect.single') }}
</h5>
<choicesjs-stencil class="col-xs-12 multiselect" type="single" v-pre/>
</div>
</section>
<section class="section">
<div class="row">
<h5 class="col-xs-12">
{{ $t('views.components-multiselect.multiple') }}
</h5>
<choicesjs-stencil class="col-xs-12 multiselect multiline" type="multiple" v-pre/>
</div>
</section>
</div>
</div>
</section>
<section class="section">
<div class="row">
<div class="col-xs-12 col-sm-10 col-sm-offset-1">
<markdown-renderer type="url" :src="'components.multiselect'"/>
</div>
</div>
</section>
</div>
</template>

<script>
import markdownRenderer from '~/components/markdown/renderer';
import { createChoiceTemplate, createItemTemplate } from '~/services/multiselect';
const choices = [
{ value: 'superstar', label: 'Superstar', selected: false, disabled: false, icon: 'footwear', color: 'aliceblue' },
{ value: 'adizero', label: 'adizero', selected: false, disabled: false, icon: 'footwear', color: 'lightblue' },
{ value: 'stansmith', label: 'Stan Smith', selected: true, disabled: false, icon: 'footwear', color: 'darkseagreen' },
{ value: 'gazelle', label: 'Gazelle', selected: false, disabled: false, icon: 'footwear', color: 'grey' },
{ value: 'ultraboost', label: 'ultraboost', selected: true, disabled: false, icon: 'footwear', color: 'mediumslateblue' },
{ value: 'nmd', label: 'NMD', selected: false, disabled: false, icon: 'footwear', color: 'brown' },
{ value: 'yeezy', label: 'YEEZY', selected: false, disabled: false, icon: 'footwear', color: 'gainsboro' },
{ value: 'campus', label: 'Campus', selected: false, disabled: false, icon: 'footwear', color: 'burlywood' },
{ value: 'zx500', label: 'ZX 500', selected: false, disabled: true, icon: 'footwear', color: 'greenyellow' },
{ value: 'samba', label: 'Samba', selected: false, disabled: false, icon: 'footwear', color: 'black' },
{ value: 'predator', label: 'Predator', selected: false, disabled: false, icon: 'footwear', color: 'burlywood' },
{ value: 'munchen', label: 'Munchen', selected: false, disabled: false, icon: 'footwear', color: 'darkcyan' },
{ value: 'zxflux', label: 'ZX Flux', selected: false, disabled: false, icon: 'footwear', color: 'coral' },
{ value: 'eqt', label: 'EQT', selected: false, disabled: false, icon: 'footwear', color: 'blueviolet' },
{ value: 'solar', label: 'Solar', selected: false, disabled: false, icon: 'footwear', color: 'orange' },
{ value: 'copa', label: 'Copa', selected: false, disabled: true, icon: 'footwear', color: 'black' },
{ value: 'terrex', label: 'Terrex', selected: false, disabled: false, icon: 'footwear', color: 'darkgreen' },
{ value: 'pureboost', label: 'pureboost', selected: false, disabled: false, icon: 'footwear', color: 'violet' },
{ value: 'dragon', label: 'Dragon', selected: false, disabled: false, icon: 'footwear', color: 'orange' },
{ value: 'yung', label: 'YUNG', selected: false, disabled: false, icon: 'footwear', color: 'green' },
{ value: 'deerupt', label: 'Deerupt', selected: false, disabled: false, icon: 'footwear', color: 'fuchsia' },
{ value: 'kamanda', label: 'kamanda', selected: false, disabled: false, icon: 'footwear', color: 'burlywood' }
];
export default {
mounted() {
const MAX_ITEMS = 8;
const selectText = document.querySelector('choicesjs-stencil[type=text]');
const selectSingle = document.querySelector('choicesjs-stencil[type=single]');
const selectMultiple = document.querySelector('choicesjs-stencil[type=multiple]');
selectSingle.choices = choices;
selectMultiple.choices = choices;
selectMultiple.maxItemCount = MAX_ITEMS;
selectMultiple.callbackOnCreateTemplates = (($t) => function(template) {
return {
choice: createChoiceTemplate(template, this.config, choices),
item: createItemTemplate(template, this.config, choices, $t)
};
})(this.$t);
[ selectText, selectSingle, selectMultiple ].forEach((select) => {
select.editItems = true;
select.removeItems = true;
select.removeItemButton = true;
select.placeholder = true;
select.placeholderValue = this.$t('views.components-multiselect.config.placeholder');
select.noResultsText = this.$t('views.components-multiselect.config.no-results');
select.noChoicesText = this.$t('views.components-multiselect.config.no-choices');
select.itemSelectText = this.$t('views.components-multiselect.config.item-selection');
select.addItemText = (value) => this.$t('views.components-multiselect.config.add-item', {
value
});
select.maxItemText = (maxItemCount) => this.$t('views.components-multiselect.config.max-items', {
maxItemCount
});
});
},
components: {
markdownRenderer
}
};
</script>
3 changes: 0 additions & 3 deletions example/plugins/bootstrap.js

This file was deleted.

4 changes: 4 additions & 0 deletions example/plugins/vendor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
if (process.browser) {
require('expose-loader?Choices!choices.js');
require('choicesjs-stencil/dist/choicesjsstencil');
}
69 changes: 69 additions & 0 deletions example/services/multiselect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
function getChoiceData(data, choices) {
return {
...choices.find((choice) => choice.value === data.value),
...data
};
}

function createIcon(icon, color) {
const iconClassName = icon ? `yarn-icon yarn-icon--${ icon }` : '';

return iconClassName
? `<span class="${ iconClassName }" ${ color ? ` style="color: ${ color };"` : '' }></span>`
: '';
}

function createRemoveButton(label, visible, $t) {
return visible
? `<button type="button"
class="choices__button"
data-button=""
aria-label="${ $t('views.components-multiselect.config.remove-button', { label }) }">
${ $t('views.components-multiselect.config.remove-button', { label }) }
</button>`
: '';
}

export function createChoiceTemplate(template, { classNames, itemSelectText }, choices) {
return (data) => {
const _data = getChoiceData(data, choices);
const icon = createIcon(_data.icon, _data.color);

return template(`
<div class="${ classNames.item } ${ classNames.itemChoice }
${ classNames[_data.disabled ? 'itemDisabled' : 'itemSelectable'] }"
data-select-text="${ itemSelectText }"
data-id="${ _data.id }"
data-value="${ _data.value }"
data-choice
data-${ _data.disabled ? 'choice-disabled' : 'choice-selectable' }
role="${ data.groupId > 0 ? 'treeitem' : 'option' }"
${ _data.disabled ? 'aria-disabled="true"' : '' }>
${ icon }
<span>${ _data.label }</span>
</div>
`);
};
}

export function createItemTemplate(template, { classNames, removeItemButton }, choices, $t) {
return (data) => {
const _data = getChoiceData(data, choices);
const icon = createIcon(_data.icon, _data.color);
const button = createRemoveButton(_data.label, removeItemButton, $t);

return template(`
<div class="${ classNames.item }
${ _data.highlighted ? classNames.highlightedState : classNames.itemSelectable }"
data-item
data-id="${ _data.id }"
data-value="${ _data.value }"
${ _data.active ? 'aria-selected="true"' : '' }
${ _data.disabled ? 'aria-disabled="true"' : '' }>
${ icon }
<span>${ _data.label }</span>
${ button }
</div>
`);
};
}
Loading

0 comments on commit 00e9fb6

Please sign in to comment.