Skip to content

Commit

Permalink
feat(text-input): setup invalid state
Browse files Browse the repository at this point in the history
- Define 'invalid message' prop & slot
- Add 'data-invalid' to input wrapper
- Add *--text-input--invalid class to input
- Add WarningFilled16 icon
  • Loading branch information
felipebritor committed Apr 15, 2023
1 parent 18b8dbf commit 0972a4f
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 2 deletions.
33 changes: 31 additions & 2 deletions src/components/CvTextInput/CvTextInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,60 @@
<label :for="cvId" :class="[`${carbonPrefix}--label`]">
{{ label }}
</label>
<div :class="[`${carbonPrefix}--text-input__field-wrapper`]">
<div
:class="[`${carbonPrefix}--text-input__field-wrapper`]"
:data-invalid="isInvalid"
>
<WarningFilled16
v-if="isInvalid"
:class="`${carbonPrefix}--text-input__invalid-icon`"
/>
<input
:id="cvId"
:class="[`${carbonPrefix}--text-input`]"
:class="[
`${carbonPrefix}--text-input`,
{
[`${carbonPrefix}--text-input--invalid`]: isInvalid,
},
]"
v-bind="$attrs"
type="text"
:value="modelValue"
@input="$event => $emit('update:modelValue', $event.target.value)"
/>
</div>
<div v-if="isInvalid" :class="`${carbonPrefix}--form-requirement`">
<slot name="invalid-message">{{ invalidMessage }}</slot>
</div>
</div>
</template>

<script setup>
import { onBeforeMount, onBeforeUpdate, ref, useSlots } from 'vue';
import { carbonPrefix } from '../../global/settings';
import { useCvId, props as propsCvId } from '../../use/cvId';
import { WarningFilled16 } from '@carbon/icons-vue';
const props = defineProps({
invalidMessage: { type: String, default: undefined },
label: String,
modelValue: String,
...propsCvId,
});
const cvId = useCvId(props);
const emit = defineEmits(['update:modelValue']);
const slots = useSlots();
const isInvalid = ref(false);
function updateMessageFlags() {
isInvalid.value = !!(
props.invalidMessage?.length || slots['invalid-message']
);
}
onBeforeMount(updateMessageFlags);
onBeforeUpdate(updateMessageFlags);
</script>
<script>
Expand Down
37 changes: 37 additions & 0 deletions src/components/CvTextInput/__tests__/CvTextInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,41 @@ describe('CvTextInput', () => {
expect(input.value).toBe('');
});
});

describe('Invalid state', () => {
it("displays 'invalid-message' slot content", () => {
const dummySlottedMessage = 'Slotted invalid message';
const { getByText } = render(CvTextInput, {
slots: { 'invalid-message': dummySlottedMessage },
});

const wrapper = getByText(dummySlottedMessage);
expect(wrapper.textContent).toBe(dummySlottedMessage);
expect(wrapper.classList.contains('bx--form-requirement')).toBeTruthy();
});

it("displays 'invalid-message' prop", () => {
const dummyInvalidMessage = 'Prop invalid message';
const { getByText } = render(CvTextInput, {
props: { invalidMessage: dummyInvalidMessage },
});

const wrapper = getByText(dummyInvalidMessage);
expect(wrapper.textContent).toBe(dummyInvalidMessage);
expect(wrapper.classList.contains('bx--form-requirement')).toBeTruthy();
});

it('favors invalid message slot when both prop and slot are set', () => {
const dummyInvalidMessage = 'Prop invalid message';
const dummySlottedMessage = 'Slotted invalid message';
const { getByText } = render(CvTextInput, {
props: { invalidMessage: dummyInvalidMessage },
slots: { 'invalid-message': dummySlottedMessage },
});

const wrapper = getByText(dummySlottedMessage);
expect(wrapper.textContent).toBe(dummySlottedMessage);
expect(wrapper.classList.contains('bx--form-requirement')).toBeTruthy();
});
});
});

0 comments on commit 0972a4f

Please sign in to comment.