Skip to content

Commit

Permalink
Merge pull request #41 from selemondev/feat/input
Browse files Browse the repository at this point in the history
feat(app): #36 Input
  • Loading branch information
selemondev authored Jul 31, 2023
2 parents 94dd065 + 670995c commit fd37cb0
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 17 deletions.
26 changes: 11 additions & 15 deletions packages/windi/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script setup lang='ts'>
function handle() {
// eslint-disable-next-line no-console
return console.log('Hello there')
}
import { ref } from 'vue'
const value = ref('')
</script>

<template>
Expand All @@ -19,17 +18,14 @@ function handle() {
</WAlertDescription>
</WAlert>
</div> -->
<WButton
:variants="{
'my-variant': {
root: 'bg-black hover:bg-gray-800 disabled:hover:bg-black',
buttonLoading: '!bg-red-500',
},
}" :variant="['danger-ghost']" @click="handle()"
>
Button
</WButton>

<!-- <WButton link @click="handle()">
<WIcon name="ph:x" />
</WButton> -->
<div class="w-96">
<WInput
v-model="value" label="Email" type="email" help="You have to enter your email to proceed" placeholder="Search" size="xl" :variant="['my-variant']"
/>
</div>
<!-- <button @click="handle()">
Button
</button> -->
Expand Down
24 changes: 24 additions & 0 deletions packages/windi/src/Types/componentsTypes/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface WButton extends WComponentRoot {
buttonPadding?: string
buttonFlex?: string
buttonLoadingIcon?: string
buttonLink?: string
}

export interface WButtonGroup extends WComponentRoot {
Expand Down Expand Up @@ -84,6 +85,27 @@ export interface WKbd extends WComponentRoot {
KbdSize?: string
}

export interface WInput extends WComponentRoot {
inputWrapper?: string
inputPlaceholder?: string
inputSize?: string
inputGap?: string
inputPadding?: string
inputLeadingPadding?: string
inputTrailingPadding?: string
inputIcon?: string
inputIconSize?: string
inputIconLeading?: string
inputIconLeadingPadding?: string
inputIconTrailing?: string
inputIconTrailingPadding?: string
inputLoadingIcon?: string
inputLabel?: string
inputHelp?: string
inputRequiredDisplay?: string
inputRequired?: string
}

export type WAccordionVariant = WithVariantProps<WAccordion>

export type WAccordionItemVariants = WithVariantProps<WAccordionItem>
Expand All @@ -105,3 +127,5 @@ export type WButtonGroupVariants = WithVariantProps<WButtonGroup>
export type WAccordionVariants = WithVariantProps<WAccordion>

export type WKbdVariants = WithVariantProps<WKbd>

export type WInputVariants = WithVariantProps<WInput>
1 change: 1 addition & 0 deletions packages/windi/src/Types/enums/Components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export enum Components {
WBadge = 'WBadge',
WButton = 'WButton',
WButtonGroup = 'WButtonGroup',
WInput = 'WInput',
WKbd = 'WKbd',
}
1 change: 1 addition & 0 deletions packages/windi/src/Types/enums/Variants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum Variants {
DEFAULT = 'default',
PRIMARY = 'primary',
SUCCESS = 'success',
WARNING = 'warning',
Expand Down
3 changes: 2 additions & 1 deletion packages/windi/src/Types/variant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Components } from './enums/Components'
import type { WAccordionItemVariants, WAccordionVariants, WAlertVariants, WAvatarGroup, WAvatarVariants, WBadgeVariants, WButtonGroupVariants, WButtonVariants, WIconVariants, WKbdVariants } from './componentsTypes/components'
import type { WAccordionItemVariants, WAccordionVariants, WAlertVariants, WAvatarGroup, WAvatarVariants, WBadgeVariants, WButtonGroupVariants, WButtonVariants, WIconVariants, WInputVariants, WKbdVariants } from './componentsTypes/components'

export declare interface CSSClassKeyValuePair {
[key: string]: any
Expand Down Expand Up @@ -40,4 +40,5 @@ export interface WindiUIConfiguration {
[Components.WButton]?: WButtonVariants
[Components.WButtonGroup]?: WButtonGroupVariants
[Components.WKbd]?: WKbdVariants
[Components.WInput]?: WInputVariants
}
6 changes: 6 additions & 0 deletions packages/windi/src/components/Button/WButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const props = defineProps({
default: 'button',
},
link: {
type: Boolean,
default: false,
},
to: {
type: [String, Object] as PropType<string | RouteLocationRaw>,
default: null,
Expand Down Expand Up @@ -120,6 +125,7 @@ const buttonBlock = computed(() => {
const buttonWrapperClass = computed(() => {
return classNames(
props.link && variant.value.buttonLink,
(props.to) && 'hover:underline',
variant.value.root,
variant.value.buttonFlex,
Expand Down
244 changes: 243 additions & 1 deletion packages/windi/src/components/Input/WInput.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,249 @@
<script setup lang='ts'>
import { computed, defineComponent, onMounted, ref, useSlots } from 'vue'
import type { PropType } from 'vue'
import classNames from 'classnames'
import { Icon } from '@iconify/vue'
import { getVariantPropsWithClassesList } from '../../utils/getVariantProps'
import type { VariantJSWithClassesListProps } from '../../utils/getVariantProps'
import type { WInput } from '../../Types/componentsTypes/components'
import windiTheme from '../../theme/windiTheme'
import { Components } from '../../Types/enums/Components'
import { useVariants } from '../../composables/useVariants'
export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
const props = defineProps({
...getVariantPropsWithClassesList<WInput>(),
modelValue: {
type: [String, Number],
default: '',
},
type: {
type: String,
default: 'text',
},
name: {
type: String,
default: null,
},
padded: {
type: Boolean,
default: true,
},
placeholder: {
type: String,
default: null,
},
required: {
type: Boolean,
default: true,
},
help: {
type: String,
default: null,
},
disabled: {
type: Boolean,
default: false,
},
autofocus: {
type: Boolean,
default: false,
},
label: {
type: String,
default: null,
},
icon: {
type: String,
default: null,
},
loadingIcon: {
type: String,
default: () => windiTheme.WInput.base.inputLoadingIcon,
},
leadingIcon: {
type: String,
default: null,
},
trailingIcon: {
type: String,
default: null,
},
trailing: {
type: Boolean,
default: false,
},
leading: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
size: {
type: String as PropType<Size>,
default: 'md',
validator(value: string) {
return Object.keys(windiTheme.WInput.base.inputSize).includes(value)
},
},
})
const emit = defineEmits<{
(event: 'update:modelValue', value: string | number): void
}>()
const slots = useSlots()
const variant = computed(() => {
const customProps = {
...props,
variant: props.variant,
}
return useVariants<WInput>(
Components.WInput,
customProps as VariantJSWithClassesListProps<WInput>,
)
})
function onInput(event: InputEvent) {
emit('update:modelValue', (event.target as HTMLInputElement).value)
}
const input = ref<HTMLInputElement | null>(null)
function autoFocus() {
if (props.autofocus)
input.value?.focus()
}
const isLeading = computed(() => {
return (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing) || props.leadingIcon
})
const isTrailing = computed(() => {
return (props.icon && props.trailing) || (props.loading && props.trailing) || props.trailingIcon
})
const leadingIconName = computed(() => {
if (props.loading)
return props.loadingIcon
return props.leadingIcon || props.icon
})
const trailingIconName = computed(() => {
if (props.loading && !isLeading.value)
return props.loadingIcon
return props.trailingIcon || props.icon
})
onMounted(() => {
setTimeout(() => {
autoFocus()
}, 100)
})
const inputLabelTextSize = computed(() => {
return classNames(
variant.value.inputLabel,
windiTheme.WInput.base.inputSize && windiTheme.WInput.base.inputSize[props.size],
)
})
const inputWrapperClass = computed(() => {
return classNames(
variant.value.inputWrapper,
variant.value.inputPlaceholder,
windiTheme.WInput.base.inputSize && windiTheme.WInput.base.inputSize[props.size],
props.padded ? windiTheme.WInput.base.inputPadding && windiTheme.WInput.base.inputPadding[props.size] : '!p-0',
(isLeading.value || slots.leading) && windiTheme.WInput.base.inputLeadingPadding && windiTheme.WInput.base.inputLeadingPadding[props.size],
(isTrailing.value || slots.trailing) && windiTheme.WInput.base.inputTrailingPadding && windiTheme.WInput.base.inputTrailingPadding[props.size],
)
})
const leadingIconClass = computed(() => {
return classNames(
variant.value.inputIcon,
windiTheme.WInput.base.inputIconSize && windiTheme.WInput.base.inputIconSize[props.size],
props.loading && 'animate-spin',
)
})
const iconLeadingWrapperClass = computed(() => {
return classNames(
variant.value.inputIconLeading,
windiTheme.WInput.base.inputIconLeadingPadding && windiTheme.WInput.base.inputIconLeadingPadding[props.size],
)
})
const iconTrailingWrapperClass = computed(() => {
return classNames(
variant.value.inputIconTrailing,
windiTheme.WInput.base.inputIconTrailingPadding && windiTheme.WInput.base.inputIconTrailingPadding[props.size],
)
})
const trailingIconClass = computed(() => {
return classNames(
variant.value.inputIcon,
windiTheme.WInput.base.inputIconSize && windiTheme.WInput.base.inputIconSize[props.size],
props.loading && !isLeading.value && 'animate-spin',
)
})
</script>

<script lang="ts">
export default defineComponent({
name: Components.WInput,
inheritAttrs: false,
})
</script>

<template>
<div />
<div>
<div :class="variant.inputRequiredDisplay">
<span v-if="props.label" :class="inputLabelTextSize">{{ props.label }}</span>
<span v-if="required" :class="variant.inputRequired">*</span>
</div>
<div :class="variant.root">
<!-- @vue-ignore -->
<input
:id="name"
ref="input"
:name="name"
:value="modelValue"
:type="type"
:required="required"
:placeholder="placeholder"
:disabled="disabled || loading"
class="form-input"
:class="inputWrapperClass"
v-bind="$attrs"
@input="onInput"
>
<slot />

<span v-if="(isLeading && leadingIconName) || $slots.leading" :class="iconLeadingWrapperClass">
<slot name="leading" :disabled="disabled" :loading="loading">
<Icon :icon="leadingIconName" :class="leadingIconClass" />
</slot>
</span>

<span v-if="(isTrailing && trailingIconName) || $slots.trailing" :class="iconTrailingWrapperClass">
<slot name="trailing" :disabled="disabled" :loading="loading">
<Icon :icon="trailingIconName" :class="trailingIconClass" />
</slot>
</span>
</div>
<div>
<span v-if="props.help" :class="variant.inputHelp">{{ props.help }}</span>
</div>
</div>
</template>

<style>
.form-input {
appearance: none;
}
</style>
5 changes: 5 additions & 0 deletions packages/windi/src/components/Input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Input from './WInput.vue'

export default {
Input,
}
Loading

0 comments on commit fd37cb0

Please sign in to comment.