Skip to content

Commit

Permalink
feat(pix-ui): add possibility to use icons on select options
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandre-Monney committed Feb 6, 2025
1 parent a9f7ec2 commit 11ee333
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 17 deletions.
21 changes: 19 additions & 2 deletions addon/components/pix-select-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,19 @@
{{on-enter-action (fn @onChange option)}}
{{on-space-action (fn @onChange option)}}
>

{{#if option.icon}}
<PixIcon role="presentation" @name={{option.icon}} @title={{option.iconTitle}} />
{{/if}}

{{option.label}}

{{#if (eq option.value @value)}}
<PixIcon @name="check" role="presentation" />
<PixIcon
@name="check"
role="presentation"
class="pix-select-list-category__option-checked"
/>
{{/if}}
</li>
{{/each}}
Expand All @@ -74,10 +83,18 @@
{{on-enter-action (fn @onChange option)}}
{{on-space-action (fn @onChange option)}}
>
{{#if option.icon}}
<PixIcon role="presentation" @name={{option.icon}} @title={{option.iconTitle}} />
{{/if}}

{{option.label}}

{{#if (eq option.value @value)}}
<PixIcon @name="check" role="presentation" />
<PixIcon
@name="check"
role="presentation"
class="pix-select-list-category__option-checked"
/>
{{/if}}
</li>
{{/each}}
Expand Down
6 changes: 3 additions & 3 deletions addon/components/pix-select-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ export default class PixSelectList extends Component {

if (!this.displayCategory) return options;

options.forEach(({ category, value, label }) => {
options.forEach(({ category, value, label, icon, iconTitle }) => {
const categoryIndex = results.findIndex((result) => result.category === category);
if (categoryIndex !== -1) {
results[categoryIndex].options.push({ value, label });
results[categoryIndex].options.push({ value, label, icon, iconTitle });
} else {
results.push({ category, options: [{ label, value }] });
results.push({ category, options: [{ label, value, icon, iconTitle }] });
}
});
return results;
Expand Down
17 changes: 10 additions & 7 deletions addon/styles/_pix-select-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
@extend %pix-body-s;

position: relative;
display: flex;
gap: var(--pix-spacing-2x);
align-items: center;
padding: var(--pix-spacing-2x) var(--pix-spacing-10x) var(--pix-spacing-2x) var(--pix-spacing-3x);
color: var(--pix-neutral-900);
border-radius: 0.25rem;
Expand All @@ -46,19 +49,19 @@
cursor: pointer;
}

svg {
position: absolute;
top: 50%;
right: var(--pix-spacing-3x);
transform: translateY(-50%);
}

&--selected {
color: var(--pix-primary-900);
font-weight: var(--pix-font-bold);
background-color: var(--pix-primary-10);
}
}

&__option-checked {
position: absolute;
top: 50%;
right: var(--pix-spacing-3x);
transform: translateY(-50%);
}
}

.pix-select-list__empty-search-message {
Expand Down
8 changes: 7 additions & 1 deletion app/stories/pix-select.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as ComponentStories from './pix-select.stories.js';

Affiche un menu déroulant avec la liste des options fournies.

Les options sont représentées par un tableau d'objet contenant les propriétés value et label.
Les options sont représentées par un tableau d'objet contenant les propriétés value, label, icon et iconTitle.

> **⚠️** **Il est nécessaire d'avoir au moins un label ou un placeholder !**
Expand Down Expand Up @@ -51,6 +51,12 @@ Ici nous avons forcé le placement de la dropdown en haut du select mais sachez

<Story of={ComponentStories.WithIcon} />

## WithOptionIcon

Si on utilise une option on rajoute une propriété 'icon' celui-ci s'affichera avant le label, il faut penser à ajouter également un 'iconTitle' pour l'accessibilité

<Story of={ComponentStories.WithOptionIcon} />

## Usage

```html
Expand Down
14 changes: 13 additions & 1 deletion app/stories/pix-select.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default {
options: {
name: 'options',
description:
'Les options sont représentées par un tableau d‘objet contenant les propriétés ``value``, ``label`` et ``category``. Ce dernier étant optionnel.',
'Les options sont représentées par un tableau d‘objet contenant les propriétés ``value``, ``label``, ``category``, ``icon`` et ``iconTitle``. Ces trois derniers étant optionnel.',
type: { name: 'array', required: true },
},
value: {
Expand Down Expand Up @@ -453,3 +453,15 @@ WithIcon.args = {
],
value: 'fr',
};

export const WithOptionIcon = Template.bind({});
WithOptionIcon.args = {
isSearchable: false,
label: 'With option icon',
onChange: action('onChange'),
options: [
{ value: 'withPlayIcon', label: 'Icone play', icon: 'play', iconTitle: 'play title' },
{ value: 'withSpeedIcon', label: 'Icone speed', icon: 'speed', iconTitle: 'speed title' },
],
value: 'fr',
};
18 changes: 15 additions & 3 deletions tests/dummy/app/controllers/select-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,27 @@ export default class SelectPage extends Controller {

get options() {
return [
{ value: '1', label: 'Figues', category: 'rouge' },
{ value: '3', label: 'Fraises', category: 'rouge' },
{
value: '1',
label: 'Figues',
category: 'rouge',
icon: 'accountOff',
iconTitle: 'titre icone account',
},
{
value: '3',
label: 'Fraises',
category: 'rouge',
icon: 'userCircle',
iconTitle: 'titre icone user',
},
{ value: '2', label: 'Bananes', category: 'jaune' },
{ value: '4', label: 'Mangues', category: 'jaune' },
{ value: '5', label: 'Kaki', category: 'vert' },
{
value: '6',
label: 'Asiminier trilobé oblong vert (à ne pas confondre avec la papaye)',
category: 'vert'
category: 'vert',
},
];
}
Expand Down
41 changes: 41 additions & 0 deletions tests/integration/components/pix-select-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -673,5 +673,46 @@ module('Integration | Component | PixSelect', function (hooks) {
assert.true(svg.includes('#globe'));
});
});

module('option icon', function () {
test('should display option icon with title provided', async function (assert) {
// given
this.selectOptions = [
{ value: '1', label: 'Pika', icon: 'play', iconTitle: 'title play icon' },
{ value: '2', label: 'Chu', icon: 'warning', iconTitle: 'title warning icon' },
];

// when
const screen = await render(hbs`<PixSelect
@options={{this.selectOptions}}
@subLabel={{this.subLabel}}
@placeholder={{this.placeholder}}
><:label>{{this.label}}</:label></PixSelect>`);

// then

assert.ok(screen.getByTitle('title play icon'));
assert.ok(screen.getByTitle('title warning icon'));
});

test('should not display title if icon property does not exists', async function (assert) {
// given
this.selectOptions = [
{ value: '1', label: 'Pika', iconTitle: 'title play icon' },
{ value: '2', label: 'Chu', iconTitle: 'title warning icon' },
];

// when
const screen = await render(hbs`<PixSelect
@options={{this.selectOptions}}
@subLabel={{this.subLabel}}
@placeholder={{this.placeholder}}
><:label>{{this.label}}</:label></PixSelect>`);

// then
assert.notOk(screen.queryByTitle('title play icon'));
assert.notOk(screen.queryByTitle('title warning icon'));
});
});
});
});

0 comments on commit 11ee333

Please sign in to comment.