Skip to content

Commit

Permalink
feat: match textarea component to related plugin (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpsmartdesign committed Aug 7, 2023
1 parent ccf1a67 commit e17e1fe
Showing 1 changed file with 58 additions and 63 deletions.
121 changes: 58 additions & 63 deletions components/form/BaseTextarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface TextareaProps {
/**
* The shape of the textarea.
*/
shape?: 'straight' | 'rounded' | 'curved' | 'full'
shape?: 'straight' | 'rounded' | 'smooth' | 'curved' | 'full'
/**
* The label for the textarea.
Expand Down Expand Up @@ -72,9 +72,14 @@ export interface TextareaProps {
disabled?: boolean
/**
* Whether the input is condensed.
* The size of the textarea.
*/
condensed?: boolean
size?: 'sm' | 'md' | 'lg'
/**
* The kind of the textarea.
*/
kind?: 'default' | 'default-contrast' | 'muted' | 'muted-contrast'
/**
* Whether the textarea is read-only.
Expand Down Expand Up @@ -140,19 +145,35 @@ const props = withDefaults(defineProps<TextareaProps>(), {
name: undefined,
shape: undefined,
placeholder: '',
size: 'md',
kind: 'default',
rows: 4,
error: false,
classes: () => ({}),
})
const emits = defineEmits<TextareaEmits>()
const appConfig = useAppConfig()
const shape = computed(() => props.shape ?? appConfig.nui.defaultShapes?.input)
const shapeStyle = {
straight: '',
rounded: 'rounded',
curved: 'rounded-xl',
full: 'rounded-full',
rounded: 'nui-textarea-rounded',
smooth: 'nui-textarea-smooth',
curved: 'nui-textarea-curved',
full: 'nui-textarea-full',
}
const sizeStyle = {
sm: 'nui-textarea-sm',
md: 'nui-textarea-md',
lg: 'nui-textarea-lg',
}
const kindStyle = {
default: 'nui-textarea-default',
'default-contrast': 'nui-textarea-default-contrast',
muted: 'nui-textarea-muted',
'muted-contrast': 'nui-textarea-muted-contrast',
}
const value = useVModel(props, 'modelValue', (_, val) => {
if (props.modelModifiers.trim) {
emits('update:modelValue', typeof val === 'string' ? val.trim() : val)
Expand Down Expand Up @@ -193,44 +214,39 @@ const id = useNinjaId(() => props.id)
</script>

<template>
<div class="relative" :class="props.classes?.wrapper">
<div
class="nui-textarea"
:class="[
kindStyle[props.kind],
sizeStyle[props.size],
shape && shapeStyle[shape],
props.error && !props.loading && 'nui-textarea-error',
props.loading && 'nui-textarea-loading',
props.labelFloat && 'nui-textarea-label-float',
props.colorFocus && 'nui-textarea-focus',
!props.resize && 'nui-textarea-not-resize',
props.addon && 'nui-has-addon',
...(props.classes?.wrapper && Array.isArray(props.classes.wrapper)
? props.classes.wrapper
: [props.classes?.wrapper]),
]"
>
<label
v-if="props.label && !props.labelFloat"
:for="id"
class="nui-label pb-1 text-[0.825rem]"
:class="[
...(props.classes?.label && Array.isArray(props.classes.label)
? props.classes.label
: [props.classes?.label]),
]"
class="nui-textarea-label"
:class="props.classes.label"
>
{{ props.label }}
</label>
<div class="group/nui-textarea relative flex flex-col">
<div class="nui-textarea-outer">
<textarea
:id="id"
ref="textareaRef"
v-model="value"
v-bind="$attrs"
class="nui-focus border-muted-300 placeholder:text-muted-300 focus:border-muted-300 focus:shadow-muted-300/50 dark:border-muted-700 dark:bg-muted-900/75 dark:text-muted-200 dark:placeholder:text-muted-500 dark:focus:border-muted-700 dark:focus:shadow-muted-800/50 peer w-full border bg-white font-sans transition-all duration-300 focus:shadow-lg disabled:cursor-not-allowed disabled:opacity-75"
:class="[
props.condensed
? 'min-h-[2rem] text-xs'
: 'min-h-[2.5rem] text-sm leading-[1.6]',
shape && shapeStyle[shape],
props.colorFocus &&
'focus:!border-primary-500 transition-colors duration-300',
props.loading &&
'text-transparent placeholder:text-transparent dark:placeholder:text-transparent',
props.labelFloat &&
'placeholder:text-transparent dark:placeholder:text-transparent',
props.error && !props.loading && '!border-danger-500',
!props.resize && 'resize-none',
props.addon ? 'px-2 pb-14 pt-2' : 'p-2',
...(props.classes?.textarea && Array.isArray(props.classes.textarea)
? props.classes.textarea
: [props.classes?.textarea]),
]"
class="nui-textarea"
:class="props.classes.textarea"
:name="props.name"
:placeholder="props.placeholder"
:readonly="props.readonly"
Expand All @@ -239,48 +255,27 @@ const id = useNinjaId(() => props.id)
></textarea>
<label
v-if="props.label && props.labelFloat"
class="nui-label text-primary-500 peer-focus-visible:text-primary-500 dark:peer-focus-visible:text-primary-500 pointer-events-none absolute inline-flex h-5 select-none items-center leading-none transition-all duration-300"
class="nui-label-float"
:for="id"
:class="[
...(props.classes?.label && Array.isArray(props.classes.label)
? props.classes.label
: [props.classes?.label]),
props.loading
? 'peer-placeholder-shown:text-transparent'
: 'peer-placeholder-shown:text-muted-300 dark:peer-placeholder-shown:text-muted-600',
!props.condensed &&
'start-3 -ms-3 -mt-8 text-xs peer-placeholder-shown:ms-0 peer-placeholder-shown:mt-0 peer-placeholder-shown:text-[0.825rem] peer-focus-visible:-ms-3 peer-focus-visible:-mt-8 peer-focus-visible:text-xs',
props.condensed &&
'start-3 -ms-3 -mt-7 text-xs peer-placeholder-shown:ms-0 peer-placeholder-shown:mt-0 peer-focus-visible:-ms-3 peer-focus-visible:-mt-7',
props.condensed ? 'top-1.5' : 'top-2.5',
]"
:class="props.classes.label"
>
<slot name="label">{{ props.label }}</slot>
</label>
<div
v-if="props.loading"
class="absolute start-0 top-4 flex h-full w-full flex-col space-y-2 px-3"
>
<BasePlaceload class="h-3 w-full max-w-[85%] rounded" />
<BasePlaceload class="h-3 w-full max-w-[65%] rounded" />
<BasePlaceload class="h-3 w-full max-w-[35%] rounded" />
<div v-if="props.loading" class="nui-textarea-placeload">
<BasePlaceload class="nui-placeload" />
<BasePlaceload class="nui-placeload" />
<BasePlaceload class="nui-placeload" />
</div>
<div
v-if="props.addon"
class="border-muted-300 bg-muted-50 dark:border-muted-700 dark:bg-muted-900/50 absolute bottom-0 start-0 flex w-full items-center justify-between border p-2 peer-disabled:cursor-not-allowed peer-disabled:opacity-75"
:class="[
shape === 'rounded' && 'rounded-b',
shape === 'curved' && 'rounded-b-xl',
...(props.classes?.addon && Array.isArray(props.classes.addon)
? props.classes.addon
: [props.classes?.addon]),
]"
class="nui-textarea-addon"
:class="props.classes.addon"
>
<slot name="addon"></slot>
</div>
<span
v-if="props.error && typeof props.error === 'string'"
class="text-danger-600 mt-1 block font-sans text-[0.65rem] font-medium leading-none"
class="text-nui-textarea-error-text"
:class="props.classes?.error"
>
{{ props.error }}
Expand Down

0 comments on commit e17e1fe

Please sign in to comment.