Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Rename wInput to wTextfield and add prop validator for input types #58

Merged
merged 4 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions components/forms/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import wField from './w-field.vue'
import wInput from './w-input.vue'
import wSelect from './w-select.vue'
import wTextarea from './w-textarea.vue'
import wTextfield from './w-textfield.vue'
import wToggle from './w-toggle.vue'
import wForm from './w-form.vue'
import wSuffix from './w-suffix.vue'
import wAffix from './w-affix.vue'
import { installer } from '#util'

export const Forms = { install: installer([wField, wInput, wSelect, wTextarea, wToggle, wForm, wSuffix, wAffix]) }
export const Forms = { install: installer([wField, wTextfield, wSelect, wTextarea, wToggle, wForm, wSuffix, wAffix]) }
export * from './validation'
export { wInput, wSelect, wTextarea, wToggle, wField, wForm, wSuffix, wAffix }
export { wTextfield, wSelect, wTextarea, wToggle, wField, wForm, wSuffix, wAffix }
68 changes: 0 additions & 68 deletions components/forms/w-input.vue

This file was deleted.

83 changes: 83 additions & 0 deletions components/forms/w-textfield.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<script setup>
import { ref, computed, useSlots } from 'vue';
import { input as ccInput } from '@warp-ds/css/component-classes';
import { createModel } from 'create-v-model';
import { setupMask } from './w-input-mask.js';
import { default as wField, fieldProps } from './w-field.vue';

const p = defineProps({
...fieldProps,
type: {
type: String,
default: 'text',
validator: inputTypeValidator
},
inputWrapperClass: String,
autocomplete: {
type: String,
default: 'off'
},
mask: Object,
});
const emit = defineEmits(['update:modelValue']);
const slots = useSlots();
const model = createModel({ props: p, emit });
const inputEl = ref(null);
if (p.mask) setupMask({ props: p, emit, inputEl });
const inputClasses = computed(() => ({
[ccInput.default]: true,
[ccInput.disabled]: p.disabled,
[ccInput.readOnly]: p.readOnly,
[ccInput.placeholder]: !!p.placeholder,
[ccInput.suffix]: slots.suffix,
[ccInput.prefix]: slots.prefix,
}));
</script>

<template>
<w-field v-bind="{ ...$attrs, ...$props }" #default="{ triggerValidation, aria, hasValidationErrors }">
<div :class="[ccInput.wrapper, inputWrapperClass]">
<slot name="prefix" :inputElement="inputEl" />
<input
v-if="mask"
:id="id"
ref="inputEl"
:type="type"
:class="[
inputClasses,
{
[ccInput.invalid]: hasValidationErrors,
}
]"
:autocomplete="autocomplete"
:disabled="disabled"
:readOnly="readOnly"
v-bind="{ ...aria, ...$attrs, class: '' }"
@blur="triggerValidation">
<input
v-else
:id="id"
ref="inputEl"
v-model="model"
:type="type"
:class="[
inputClasses,
{
[ccInput.invalid]: hasValidationErrors,
}
]"
:autocomplete="autocomplete"
:disabled="disabled"
:readOnly="readOnly"
v-bind="{ ...aria, ...$attrs, class: '' }"
@blur="triggerValidation"
>
<slot name="suffix" :inputElement="inputEl" />
</div>
</w-field>
</template>

<script>
const inputTypeValidator = (value) => ['text', 'search', 'email', 'password', 'url', 'tel', 'number'].includes(value);
export default { name: 'wTextfield', inheritAttrs: false };
</script>
4 changes: 2 additions & 2 deletions dev/pages/Slider.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { ref } from 'vue'
import { wSlider, wInput } from '#components'
import { wSlider, wTextfield } from '#components'

const largeNumber = ref(30_000_000)
</script>
Expand All @@ -15,6 +15,6 @@ const largeNumber = ref(30_000_000)

<!-- used for testing that outside-model-updates also update the slider value -->
<!-- <w-slider v-model="largeNumber" :min="1000" :max="10_000_000" :step="1000" label="a large number slider" /> -->
<!-- <w-input label="Slider value" v-model="largeNumber" /> -->
<!-- <w-textfield label="Slider value" v-model="largeNumber" /> -->
</div>
</template>
30 changes: 15 additions & 15 deletions dev/pages/Input.vue → dev/pages/TextField.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { ref } from 'vue'
import { wInput, wAffix } from '#components'
import { wTextfield, wAffix } from '#components'

const inputModel = ref('');

Expand All @@ -19,50 +19,50 @@ const moneyMask = { numeral: true, numeralPositiveOnly: true, numeralIntegerScal

<template>
<div>
<component-title title="Input" />
<component-title title="Text Field" />

<token :state="inputModel">
<w-input v-model="inputModel" class="mb-16" #suffix="{ inputElement }" label="A required input with a clear button" hint="A hint" required>
<w-textfield v-model="inputModel" class="mb-16" #suffix="{ inputElement }" label="A required input with a clear button" hint="A hint" required>
<w-affix suffix clear @click="handleClear(inputElement)" />
</w-input>
</w-textfield>
</token>

<token :state="inputModel">
<w-input placeholder="I am placeholder" #prefix v-model="inputModel" label="I have a prefix">
<w-textfield placeholder="I am placeholder" type="tel" #prefix v-model="inputModel" label="I have a prefix" inputmode="numeric">
<w-affix prefix label="+47" />
</w-input>
</w-textfield>
</token>

<!-- TODO tabbing through the input and suffix is off for now. We do not have support for adding multiple slots as of now. So both
suffix and prefix are treated as one slot in this example, making button(suffix) render before input in DOM and "destroy" the tabbing order.
So the support for multiple slots need to be added here -->
<token :state="inputModel">
<w-input #prefix #suffix v-model="inputModel" label="I have a prefix">
<w-textfield #prefix #suffix v-model="inputModel" label="I have a prefix" inputmode="numeric">
<w-affix prefix label="+47" />
<w-affix suffix clear />
</w-input>
</w-textfield>
</token>

<token :state="inputModel">
<w-input #suffix v-model="inputModel" label="I have a suffix">
<w-textfield #suffix v-model="inputModel" label="I have a suffix" inputmode="decimal">
<w-affix suffix label="NOK" />
</w-input>
</w-textfield>
</token>

<token :state="inputModel">
<w-input #suffix disabled v-model="inputModel" label="I am disabled">
<w-textfield #suffix disabled v-model="inputModel" label="I am disabled" inputmode="decimal">
<w-affix suffix label="NOK" />
</w-input>
</w-textfield>
</token>

<token :state="inputModel">
<w-input readOnly value="I'm read only" v-model="placeholderModel" label="I am read only">
<w-textfield readOnly value="I'm read only" v-model="placeholderModel" label="I am read only">
<w-affix suffix label="NOK" />
</w-input>
</w-textfield>
</token>

<token :state="numericInputModel">
<w-input placeholder="I am placeholder" v-model.number="numericInputModel" optional number type="text" inputmode="numeric" :mask="moneyMask" label="A masked (money) input" />
<w-textfield placeholder="I am placeholder" v-model.number="numericInputModel" optional number type="text" inputmode="numeric" :mask="moneyMask" label="A masked (money) input" />
</token>
</div>
</template>
8 changes: 4 additions & 4 deletions dev/src/Search.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup>
import Fuse from 'fuse.js'
import { sidebarConfig } from '../src/sidebar-config.js'
import { sidebarConfig } from './sidebar-config.js'
import { ref, computed, watch } from 'vue'
import { wInput, wModal, wBox } from '#components'
import { modalShowing } from '../src/store.js'
import { wTextfield, wModal, wBox } from '#components'
import { modalShowing } from './store.js'

const inputEl = ref(null)
BalbinaK marked this conversation as resolved.
Show resolved Hide resolved
const showSearch = ref(false)
Expand Down Expand Up @@ -32,7 +32,7 @@ watch(showSearch, (showing) => modalShowing.value = showing)
<template>
<div>
<w-modal title="Search" v-model="showSearch" @dismiss="hide" @right="hide" @shown="focusInput">
<w-input label="Search term" v-model="searchTerm" ref="inputEl" />
<w-textfield label="Search term" v-model="searchTerm" ref="inputEl" />
<w-box neutral class="mt-24">
<h5>Results</h5>
<p v-for="m in matches">
Expand Down
4 changes: 2 additions & 2 deletions dev/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Button from '../pages/Button.vue'
import ButtonGroup from '../pages/ButtonGroup.vue'
import Card from '../pages/Card.vue'
import Expandable from '../pages/Expandable.vue'
import Input from '../pages/Input.vue'
import Modal from '../pages/Modal.vue'
import Pill from '../pages/Pill.vue'
import Select from '../pages/Select.vue'
Expand All @@ -18,6 +17,7 @@ import Switch from '../pages/Switch.vue'
import Tabs from '../pages/Tabs.vue'
import Tag from '../pages/Tag.vue'
import Textarea from '../pages/Textarea.vue'
import Textfield from '../pages/Textfield.vue'
import Toggle from '../pages/Toggle.vue'
// import Forms from '../pages/Forms.vue'

Expand All @@ -31,7 +31,6 @@ export const routes = [
{ path: '/button-group', component: ButtonGroup, name: 'button-group' },
{ path: '/card', component: Card, name: 'card' },
{ path: '/expandable', component: Expandable, name: 'expandable' },
{ path: '/input', component: Input, name: 'input' },
{ path: '/modal', component: Modal, name: 'modal' },
{ path: '/pill', component: Pill, name: 'pill' },
{ path: '/select', component: Select, name: 'select' },
Expand All @@ -41,6 +40,7 @@ export const routes = [
{ path: '/tabs', component: Tabs, name: 'tabs' },
{ path: '/tag', component: Tag, name: 'tag' },
{ path: '/textarea', component: Textarea, name: 'textarea' },
{ path: '/textfield', component: Textfield, name: 'textfield' },
{ path: '/toggle', component: Toggle, name: 'toggle' },
// { path: '/forms', component: Forms, name: 'forms' },
]
Expand Down
4 changes: 2 additions & 2 deletions dev/src/sidebar-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export const sidebarConfig = [
},
{
title: 'Forms',
startOpen: false,
startOpen: true,
links: [
{ to: 'input', title: 'Input' },
{ to: 'select', title: 'Select' },
{ to: 'slider', title: 'Slider' },
{ to: 'switch', title: 'Switch' },
{ to: 'textfield', title: 'Text Field' },
BalbinaK marked this conversation as resolved.
Show resolved Hide resolved
{ to: 'textarea', title: 'Textarea' },
{ to: 'toggle', title: 'Toggle' }
]
Expand Down
10 changes: 5 additions & 5 deletions test/wInput.test.js → test/wTextfield.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { describe, test, assert } from 'vitest'
import { mount } from '@vue/test-utils'
import { wInput } from '#components'
import { wTextfield } from '#components'

describe('input', () => {
assert.ok(wInput.name)
describe('textfield', () => {
assert.ok(wTextfield.name)

test('renders', () => {
const inputValue = 'Hello Warp'
BalbinaK marked this conversation as resolved.
Show resolved Hide resolved
const wrapper = mount(wInput, {
const wrapper = mount(wTextfield, {
props: { modelValue: inputValue }
})
const inputEl = wrapper.get('input')
assert.equal(inputEl.element.value, inputValue)
})
test('prefix/suffix', () => {
const wrapper = mount(wInput, {
const wrapper = mount(wTextfield, {
slots: {
prefix: '<h1>Hello</h1>',
suffix: '<h2>Warp</h2>'
Expand Down