Skip to content

Commit

Permalink
feat(input): DLT-1945 add clear slot prop to rightIcon (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
ninamarina authored Aug 16, 2024
1 parent 606cfb3 commit 0f90dd4
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 5 deletions.
12 changes: 9 additions & 3 deletions apps/dialtone-documentation/docs/components/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,31 +444,35 @@ showHtmlWarning />

<dt-notice
kind="warning"
hideClose="true"
:hide-close="true"
class="d-wmx100p d-mb24"
>
<template #default>
Note: The usage of <code>type="search"</code> is not recommended for this component as it may cause unintended styling issues in Chrome. Instead, refer to the provided example code if you need to implement a search input.
</template>
</dt-notice>
In this example we show a search input with a clear button on the right side. The clear button is a button with a close icon that clears the input field when clicked. The clear button is only visible when the input field is not empty.

<code-well-header>
<div class="d-w100p">
<dt-input
aria-label="Search items"
placeholder="Search Items"
type="text"
v-model="inputValue"
>
<template #leftIcon="{ iconSize }">
<dt-icon name="search" :size="iconSize" />
</template>
<template #rightIcon>
<template v-if="inputValue.length !== 0" #rightIcon="{ clear }">
<dt-button
kind="muted"
importance="clear"
size="xs"
circle
aria-label="Clear search"
@click="clear"
>
<template #icon="{ iconSize }">
<dt-icon name="close" :size="iconSize" />
Expand Down Expand Up @@ -496,17 +500,19 @@ vueCode='
aria-label="Search items"
placeholder="Search Items"
type="text"
v-model="inputValue"
>
<template #leftIcon="{ iconSize }">
<dt-icon name="search" :size="iconSize" />
</template>
<template #rightIcon>
<template v-if="inputValue.length !== 0" #rightIcon="{ clear }">
<dt-button
kind="muted"
importance="clear"
size="xs"
circle
aria-label="Clear search"
@click="clear"
>
<template #icon="{ iconSize }">
<dt-icon name="close" :size="iconSize" />
Expand Down
5 changes: 5 additions & 0 deletions packages/dialtone-vue2/components/input/input.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DtInput from './input.vue';
import { INPUT_SIZES, INPUT_TYPES } from './input_constants';

import InputDefault from './input_default.story.vue';
import InputSearchVariant from './input_search_variant.story.vue';

const iconsList = getIconNames();

Expand Down Expand Up @@ -373,3 +374,7 @@ export const WithLengthValidation = {
},
},
};

export const SearchVariant = {
render: (argsData) => createRenderConfig(DtInput, InputSearchVariant, argsData),
};
10 changes: 9 additions & 1 deletion packages/dialtone-vue2/components/input/input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<slot
name="rightIcon"
:icon-size="iconSize"
:clear="clearInput"
/>
</span>
</div>
Expand Down Expand Up @@ -562,9 +563,10 @@ export default {
}
},
clear () {
emitClearEvents () {
this.$emit('input', '');
this.$emit('clear');
this.$emit('update:modelValue', '');
},
blur () {
Expand All @@ -586,6 +588,12 @@ export default {
validateLength (length) {
this.isInvalid = (length > this.validationProps.length.max);
},
clearInput () {
this.$refs.input.value = '';
this.$refs.input.focus();
this.emitClearEvents();
},
},
};
</script>
131 changes: 131 additions & 0 deletions packages/dialtone-vue2/components/input/input_search_variant.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<template>
<dt-input
ref="input"
v-model="inputValue"
autocomplete="on"
:type="$attrs.type"
:messages="$attrs.messages"
:size="$attrs.size"
:label="$attrs.label"
:messages-child-props="$attrs.messagesChildProps"
:name="$attrs.name"
:disabled="$attrs.disabled"
:show-messages="$attrs.showMessages"
:messages-class="$attrs.messagesClass"
:placeholder="$attrs.placeholder"
:input-class="$attrs.inputClass"
:retain-warning="$attrs.retainWarning"
:input-wrapper-class="$attrs.inputWrapperClass"
:current-length="$attrs.currentLength"
:validate="validationConfig"
@blur="$attrs.onBlur"
@input="$attrs.onInput"
@clear="$attrs.onClear"
@focus="$attrs.onFocus"
@focusin="$attrs.onFocusIn"
@focusout="$attrs.onFocusOut"
@update:length="updateLength"
@update:invalid="$attrs.onUpdateIsInvalid"
>
<template
v-if="$attrs.labelSlot"
#labelSlot
>
<span v-html="$attrs.labelSlot" />
</template>
<template
v-if="$attrs.description"
#description
>
<span v-html="$attrs.description" />
</template>
<template #leftIcon="{ iconSize }">
<dt-icon
name="search"
:size="iconSize"
/>
</template>
<template
v-if="inputValue.length !== 0"
#rightIcon="{ clear }"
>
<dt-button
kind="muted"
importance="clear"
size="xs"
circle
aria-label="Clear search"
@click="clear"
>
<template #icon="{ iconSize }">
<dt-icon
name="close"
:size="iconSize"
/>
</template>
</dt-button>
</template>
</dt-input>
</template>

<script>
import DtInput from './input.vue';
import { DtButton } from '@/components/button';
import { DtIcon } from '@/components/icon';
export default {
name: 'InputSearchVariant',
components: { DtInput, DtIcon, DtButton },
inheritAttrs: false,
data () {
return {
inputValue: '',
inputLength: 0,
};
},
computed: {
validationMessage () {
const remainingCharacters = this.$attrs.validate?.length?.max - this.inputLength;
if (remainingCharacters < 0) {
return `${Math.abs(remainingCharacters)} characters over limit`;
} else {
return `${remainingCharacters} characters left`;
}
},
validationConfig () {
if (!this?.$attrs?.validate?.length) {
return null;
}
// Deep clone validate object
const validateConfigData = JSON.parse(JSON.stringify(this.$attrs.validate));
// Adds validation message
validateConfigData.length.message = this?.$attrs?.validate?.length?.message
? this.$attrs.validate.length.message
: this.validationMessage;
return validateConfigData;
},
},
watch: {
modelValue (val) {
this.inputValue = val;
},
},
methods: {
updateLength ($event) {
this.inputLength = $event;
this.$attrs.onUpdateLength($event);
},
},
};
</script>
11 changes: 11 additions & 0 deletions packages/dialtone-vue3/components/input/input.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DtInput from './input.vue';
import { INPUT_SIZES, INPUT_TYPES } from './input_constants';

import InputDefault from './input_default.story.vue';
import InputSearchVariant from './input_search_variant.story.vue';

const iconsList = getIconNames();

Expand Down Expand Up @@ -365,3 +366,13 @@ export const WithLengthValidation = {
},
},
};

const SearchVariantTemplate = (args, { argTypes }) => createTemplateFromVueFile(
args,
argTypes,
InputSearchVariant,
);

export const SearchVariant = {
render: SearchVariantTemplate,
};
10 changes: 9 additions & 1 deletion packages/dialtone-vue3/components/input/input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<slot
name="rightIcon"
:icon-size="iconSize"
:clear="clearInput"
/>
</span>
</div>
Expand Down Expand Up @@ -576,9 +577,10 @@ export default {
}
},
clear () {
emitClearEvents () {
this.$emit('input', '');
this.$emit('clear');
this.$emit('update:modelValue', '');
},
blur () {
Expand All @@ -600,6 +602,12 @@ export default {
validateLength (length) {
this.isInvalid = (length > this.validationProps.length.max);
},
clearInput () {
this.$refs.input.value = '';
this.$refs.input.focus();
this.emitClearEvents();
},
},
};
</script>
Loading

0 comments on commit 0f90dd4

Please sign in to comment.