Skip to content

Commit

Permalink
Add 'arrownext' and 'arrowprevious' icons (#497)
Browse files Browse the repository at this point in the history
* Add arrowPrevious icon

* Add arrowNext icon

* Update CHANGELOG.md

* add enum iconDirection

* add dir prop

* add dir validation test

* add initial basic story

* add prop description

* add controls to basic icon story

* Add flipped styles

* Add Icon type control

* Add flipping logic to arrowprevious

* Optimize flipped class conditional

* Fix linting issues

Co-authored-by: Itamar Givon <[email protected]>
  • Loading branch information
sai-san and itamargiv authored Nov 10, 2021
1 parent f870f24 commit 6910f8f
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 6 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ development)_

- New TextArea Component
- New Table Component
- New Close icon component
- New Close, ArrowNext and ArrowPrevious icons

### Changed

- Dimension-layout tokens are now based on _rem_ instead of _em_
- Add `dir` prop to Icon component

## [2.0.0] - 19.07.2021

Expand Down
61 changes: 58 additions & 3 deletions vue-components/src/components/Icon.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
/* eslint-disable vue/valid-v-else-if */
<template>
<!-- eslint-disable max-len -->
<span :class="['wikit', 'wikit-Icon', `wikit-Icon--${size}`, `wikit-Icon--${color}`]">
<span
:class="[
'wikit',
'wikit-Icon',
`wikit-Icon--${size}`,
`wikit-Icon--${color}`,
flip ? 'wikit-Icon--flipped' : ''
]"
>

<!-- add icon -->
<svg
Expand All @@ -25,6 +33,28 @@
<path fill="currentColor" d="M9.163 1.68234C9.06078 1.4381 8.89901 1.22746 8.69449 1.07231C8.48997 0.917151 8.25017 0.823144 7.99999 0.800049C7.75116 0.82453 7.51294 0.919178 7.30987 1.07425C7.10679 1.22933 6.94619 1.43922 6.84459 1.68234L0.672272 13.0631C0.0337565 14.2368 0.558251 15.2 1.82768 15.2H14.1723C15.4417 15.2 15.9662 14.2368 15.3277 13.0631L9.163 1.68234ZM8.76013 12.7717H7.23986V11.1528H8.76013V12.7717ZM8.76013 9.53394H7.23986V4.67728H8.76013V9.53394Z" />
</svg>

<!-- arrownext icon -->
<svg
class="wikit-Icon__svg"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
v-else-if="type === IconTypes.ARROWNEXT"
>
<path fill="currentColor" d="M8.59 3.42L14.17 9H2V11H14.17L8.59 16.59L10 18L18 10L10 2L8.59 3.42Z" />
</svg>

<!-- arrowprevious icon -->
<svg
class="wikit-Icon__svg"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
v-else-if="type === IconTypes.ARROWPREVIOUS"
>
<path fill="currentColor" d="M5.83 9L11.41 3.42L10 2L2 10L10 18L11.41 16.59L5.83 11H18V9H5.83Z" />
</svg>

<!-- checkmark icon -->
<svg
class="wikit-Icon__svg"
Expand Down Expand Up @@ -181,8 +211,8 @@
</template>

<script lang="ts">
import Vue from 'vue';
import { IconTypes, iconColors, iconSizes } from './iconProps';
import Vue, { PropType } from 'vue';
import { IconTypes, flippable, IconDirection, iconColors, iconSizes } from './iconProps';
import generateUid from '@/components/util/generateUid';
/**
Expand All @@ -204,13 +234,28 @@ export default Vue.extend( {
},
props: {
/**
* The type of icon to display.
*/
type: {
type: String,
validator( value: string ): boolean {
return Object.values( IconTypes ).includes( value as IconTypes );
},
required: true,
},
/**
* Determines the direction of localizable icons.
*
* Possible values: `rtl` and `ltr`.
*/
dir: {
type: String as PropType<IconDirection>,
validator( value: string ): boolean {
return Object.values( IconDirection ).includes( value as IconDirection );
},
default: IconDirection.LTR,
},
color: {
type: String,
Expand All @@ -228,6 +273,12 @@ export default Vue.extend( {
default: 'large',
},
},
computed: {
flip(): boolean {
return this.dir === IconDirection.RTL && flippable.includes( this.type as IconTypes );
},
},
} );
</script>

Expand Down Expand Up @@ -287,5 +338,9 @@ export default Vue.extend( {
width: $wikit-Icon-size-xsmall;
height: $wikit-Icon-size-xsmall;
}
&--flipped {
transform: scaleX(-1);
}
}
</style>
16 changes: 16 additions & 0 deletions vue-components/src/components/iconProps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export enum IconTypes {
ADD = 'add',
ALERT = 'alert',
ARROWNEXT = 'arrownext',
ARROWPREVIOUS = 'arrowprevious',
CHECKMARK = 'checkmark',
CLEAR = 'clear',
CLOSE = 'close',
Expand All @@ -14,6 +16,20 @@ export enum IconTypes {
TRASH = 'trash'
}

/**
* List icons that should be localized.
*/
export const flippable = [
IconTypes.ARROWNEXT,
IconTypes.ARROWPREVIOUS,
IconTypes.NEWWINDOW,
];

export enum IconDirection {
RTL = 'rtl',
LTR = 'ltr'
}

export const iconColors = [
'base',
'subtle',
Expand Down
47 changes: 46 additions & 1 deletion vue-components/stories/Icon.stories.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
import Icon from '@/components/Icon';
import { iconSizes, iconColors, IconTypes } from '@/components/iconProps';
import { iconSizes, IconDirection, iconColors, IconTypes } from '@/components/iconProps';
import { Component } from 'vue';

export default {
component: Icon,
title: 'Icon',
};

const typeValues = Object.values( IconTypes );
export function basic( args: object ): Component {
return {
components: { Icon },
props: Object.keys( args ),
template: '<Icon :type="type" :dir="dir"/>',
};
}

basic.args = {
type: typeValues[0],
dir: IconDirection.LTR,
};

basic.argTypes = {
type: {
control: {
type: 'select',
options: typeValues,
default: typeValues[0],
},
},
dir: {
control: {
type: 'radio',
options: Object.values( IconDirection ),
default: IconDirection.LTR,
},
table: {
type: {
summary: 'string',
},
defaultValue: {
summary: 'ltr',
},
},
},
color: {
control: false,
},
size: {
control: false,
},
};

export function allTypes(): Component {
return {
data(): object {
Expand Down
37 changes: 36 additions & 1 deletion vue-components/tests/unit/components/Icon.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import Icon from '@/components/Icon.vue';
import { iconSizes, iconColors, IconTypes } from '@/components/iconProps';
import { iconSizes, flippable, IconDirection, iconColors, IconTypes } from '@/components/iconProps';

jest.mock( '@/components/util/generateUid', () => {
return () => 'mockedID';
Expand Down Expand Up @@ -144,4 +144,39 @@ describe( 'Icon', () => {
} ).classes() ).toContain( `wikit-Icon--${size}` );
} );

it.each( flippable )( '%s flips direction when dir is "rtl"', async ( type ) => {
const flippedClass = 'wikit-Icon--flipped';
const wrapper = mount( Icon, {
propsData: { type },
} );

expect( wrapper.props().dir ).toBe( IconDirection.LTR );
expect( wrapper.classes() ).not.toContain( flippedClass );

await wrapper.setProps( { dir: IconDirection.RTL } );
expect( wrapper.props().dir ).toBe( IconDirection.RTL );
expect( wrapper.classes() ).toContain( flippedClass );
} );

it( 'doesn\'t flip direction for unlocalizable icons', async () => {
const flippedClass = 'wikit-Icon--flipped';
const wrapper = mount( Icon, {
propsData: {
type: 'edit',
dir: IconDirection.RTL,
},
} );

expect( wrapper.classes() ).not.toContain( flippedClass );
} );

it( 'validates the dir prop', () => {
expect( () => mount( Icon, {
propsData: {
type: 'error',
dir: 'banana',
},
} ) ).toThrow();
} );

} );

0 comments on commit 6910f8f

Please sign in to comment.