Skip to content

Commit

Permalink
feat(v-input): improved v-input styles
Browse files Browse the repository at this point in the history
  • Loading branch information
gravitano committed Mar 22, 2022
1 parent 3aea3e2 commit 8633ab6
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 25 deletions.
46 changes: 40 additions & 6 deletions packages/input/src/VInput.stories.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import VInput from './VInput.vue';
// import {themeColors} from '../utils/colors';
import {sizes} from '@gits-id/utils/sizes';
import {Meta, Story} from '@storybook/vue3';
import type {VInputProps} from './types';
import {RiSearchLine} from 'vue-remix-icons';
import {themeColors} from '@gits-id/utils';

export default {
title: 'Components/Form/Input',
Expand All @@ -13,18 +13,25 @@ export default {
control: 'select',
options: sizes,
},
color: {
control: 'select',
options: themeColors,
},
},
args: {
value: '',
modelValue: 'Text',
modelValue: '',
placeholder: 'Type something...',
type: 'text',
color: 'primary',
name: '',
error: false,
errorMessages: [],
readonly: false,
disabled: false,
size: '',
size: 'default',
noShadow: false,
text: false,
},
} as Meta;

Expand All @@ -36,7 +43,9 @@ const Template: Story<VInputProps> = (args) => ({
return {args};
},
// And then the `args` are bound to your component with `v-bind="args"`
template: `<VInput v-bind='args'/>`,
template: `
<VInput v-bind='args'/>
`,
});

export const Default = Template.bind({});
Expand All @@ -58,6 +67,16 @@ Disabled.args = {
disabled: true,
};

export const NoShadow = Template.bind({});
NoShadow.args = {
noShadow: true,
};

export const Text = Template.bind({});
Text.args = {
text: true,
};

export const Error = Template.bind({});
Error.args = {
error: true,
Expand All @@ -73,15 +92,30 @@ export const Slots: Story<VInputProps> = (args) => ({
<div class="space-y-2">
<v-input placeholder="Search...">
<template #prepend>
<RiSearchLine class="fill-current ml-3 w-6 h-6" />
<RiSearchLine class="fill-current ml-2 -mr-2 w-5 h-5" />
</template>
</v-input>
<v-input placeholder="Search...">
<template #append>
<RiSearchLine class="fill-current mr-3 w-6 h-6" />
<RiSearchLine class="fill-current mr-3 w-5 h-5" />
</template>
</v-input>
</div>
`,
});

export const Sizes: Story<VInputProps> = (args) => ({
// Components used in your story `template` are defined in the `components` object
components: {VInput},
// The story's `args` need to be mapped into the template through the `setup()` method
setup() {
return {args, sizes};
},
// And then the `args` are bound to your component with `v-bind="args"`
template: `
<div class="flex gap-2 flex-wrap">
<VInput v-for="size in sizes" :key="size" v-bind='args' :size="size" :placeholder="size"/>
</div>
`,
});
123 changes: 104 additions & 19 deletions packages/input/src/VInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const props = defineProps({
},
size: {
type: String,
default: '',
default: 'default',
},
placeholder: {
type: String,
Expand All @@ -53,10 +53,27 @@ const props = defineProps({
type: String,
default: '',
},
color: {
type: String,
default: 'primary',
},
text: {
type: Boolean,
default: false,
},
noShadow: {
type: Boolean,
default: false,
},
classes: {
type: Object,
default: () => ({
wrapper: '',
input: '',
prepend: '',
append: '',
}),
},
});
const {
Expand All @@ -67,22 +84,54 @@ const {
value: externalValue,
readonly,
disabled,
size,
placeholder,
prependIcon,
appendIcon,
text,
} = toRefs(props);
const emit = defineEmits(['input:modelValue', 'blur']);
const inputValue = ref(props.value || props.modelValue);
const {class: sizeClass} = useTextSize(size.value);
const {class: heightClass} = useHeight(size.value);
const inputClass = computed(() => useInputClasses(error.value));
const sizeClass = computed(() => {
const sizes: Record<string, string> = {
xs: 'text-xs',
sm: 'text-sm',
default: 'text-sm',
md: 'text-sm',
lg: 'text-lg',
xl: 'text-xl',
};
return sizes[props.size];
});
const inputClasses = computed(() => {
return [sizeClass.value];
});
const classes = computed(() => [inputClass.value, sizeClass.value]);
const wrapperColorClasses = computed(() => {
let colorClass = '';
if (error.value) {
colorClass = 'input-has-error';
} else {
const colors: Record<string, string> = {
default: 'input-default',
primary: 'input-primary',
secondary: 'input-secondary',
info: 'input-info',
warning: 'input-warning',
error: 'input-error',
success: 'input-success',
dark: 'input-dark',
};
colorClass = colors[props.color];
}
return colorClass;
});
const wrapperClasses = computed(() => {
return [wrapperColorClasses.value];
});
watch(modelValue, (val) => {
inputValue.value = val;
Expand All @@ -97,23 +146,21 @@ const onBlur = () => emit('blur');

<template>
<div
class="flex w-full items-center transition duration-300 rounded-md text-gray-500"
:class="[
text
? 'focus:border-none focus:ring-0'
: 'border focus-within:text-primary-500 focus-within:border-primary-500 focus-within:ring-primary-500 focus-within:ring-1',
error
? 'border-error-500 focus-within:text-error-500 focus-within:border-error-500 focus-within:ring-error-500 focus-within:ring-1'
: '',
]"
class="flex w-full gap-2 items-center transition duration-300 rounded-md border border-gray-300 text-gray-500"
:class="[wrapperClasses, noShadow ? '' : 'shadow-sm']"
>
<slot name="prepend">
<SearchIcon v-if="prependIcon === 'search'" class="w-5 h-5 ml-3" />
</slot>
<input
v-model="inputValue"
class="w-full block rounded-md border-none ring-0 text-gray-800 focus:border-none focus:ring-0"
:class="[text ? 'p-0' : heightClass, sizeClass]"
class="v-input-field"
:class="[
inputClasses,
error ? 'has-error' : '',
$slots.prepend ? 'input-prepend' : '',
$slots.append ? 'input-append' : '',
]"
:type="type"
:readonly="readonly"
:disabled="disabled"
Expand All @@ -133,4 +180,42 @@ const onBlur = () => emit('blur');
/>
</template>

<style scoped></style>
<style scoped>
.v-input-field {
@apply text-gray-800 w-full block transition duration-300 border-none rounded-md focus:outline-none focus:border-none focus:ring-transparent focus:ring-0 focus:shadow-none;
}
.v-input-field.has-error {
@apply text-error-500;
}
.input-append {
@apply px-0 pl-4;
}
.input-prepend {
@apply px-0 pr-4;
}
.input-has-error {
@apply border-error-500 focus-within:text-error-500 focus-within:border-error-500 focus-within:ring-error-500 focus-within:ring-1;
}
.input-default,
.input-primary {
@apply focus-within:border-primary-500 focus-within:ring-primary-500 focus-within:ring-1;
}
.input-secondary {
@apply focus-within:border-secondary-500 focus-within:ring-secondary-500 focus-within:ring-1;
}
.input-info {
@apply focus-within:border-info-500 focus-within:ring-info-500 focus-within:ring-1;
}
.input-warning {
@apply focus-within:border-warning-500 focus-within:ring-warning-500 focus-within:ring-1;
}
.input-success {
@apply focus-within:border-success-500 focus-within:ring-success-500 focus-within:ring-1;
}
.input-error {
@apply focus-within:border-error-500 focus-within:ring-error-500 focus-within:ring-1;
}
.input-dark {
@apply focus-within:border-gray-500 focus-within:ring-gray-500 focus-within:ring-1;
}
</style>
2 changes: 2 additions & 0 deletions packages/input/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export type VInputProps = {
readonly: boolean;
disabled: boolean;
size: Sizes;
noShadow?: boolean;
text?: boolean;
};
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8633ab6

Please sign in to comment.