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

feat: add EsFormTextarea v3 #1519

Merged
merged 10 commits into from
Sep 13, 2024
124 changes: 124 additions & 0 deletions es-ds-components/components/es-form-textarea.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<script setup lang="ts">
// Prevents attributes from being applied to first <div>
// v-bind="$attr" is on the input instead
defineOptions({
inheritAttrs: false,
});

const props = defineProps({
nathanielwarner marked this conversation as resolved.
Show resolved Hide resolved
/**
* Required
*/
required: {
type: Boolean,
default: false,
},
/**
* Disabled
*/
disabled: {
type: Boolean,
default: false,
},
/**
* ID
* required
*/
id: {
type: String,
required: true,
},
/**
* state
*/
state: {
type: [Boolean, null],
default: null,
},
});
const model = defineModel<string>();

const slots = useSlots();

const hasSuccess = () => !!slots.successMessage;
const hasMessage = () => !!slots.message;
const hasError = () => !!slots.errorMessage;
</script>

<template>
<div
class="input-wrapper justify-content-end"
:required="props.required">
<!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->
<label
:for="props.id"
class="label justify-content-start">
<slot name="label" />

<span
v-if="props.required"
class="text-danger">
*
</span>
</label>

<div class="input-holder">
<textarea
:id="props.id"
v-model="model"
v-bind="$attrs"
class="es-form-textarea w-100 form-control"
:class="{ 'is-invalid': props.state === false }"
:disabled="props.disabled"
:invalid="props.state === false" />
<small
v-if="hasMessage() && ((!hasSuccess() && props.state) || props.state == null)"
class="text-muted">
<slot name="message" />
</small>
<small
v-if="props.state === false && (hasError() || props.required)"
class="text-danger">
<slot
v-if="hasError()"
name="errorMessage" />
<template v-else-if="props.required"> This field is required. </template>
</small>
<small
v-if="props.state && hasSuccess()"
class="text-success">
<slot name="successMessage" />
</small>
</div>
</div>
</template>

<style lang="scss" scoped>
@use '@energysage/es-ds-styles/scss/variables' as variables;

.es-form-textarea {
min-height: 8.125rem;
}

.es-form-textarea:disabled,
.es-form-textarea[readonly] {
border: 0;
}

.is-invalid {
color: variables.$danger;
}

.form-inline .input-wrapper {
display: flex;
flex: 0 0 100%;

label {
flex: 0 0 30%;
}

.input-holder {
flex: 0 0 70%;
}
}
</style>
3 changes: 3 additions & 0 deletions es-ds-docs/components/ds-molecules-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
<li>
<ds-link to="/molecules/tabs"> Tabs </ds-link>
</li>
<li>
<ds-link to="/molecules/form-textarea"> Textarea </ds-link>
</li>
<li>
<ds-link to="/molecules/text-input"> Text input </ds-link>
</li>
Expand Down
166 changes: 166 additions & 0 deletions es-ds-docs/pages/molecules/form-textarea.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<script setup>
const docTextarea = ref('');
const successValue = ref('My experience was great!');

const { $prism } = useNuxtApp();
const compCode = ref('');
const docCode = ref('');

onMounted(async () => {
if ($prism) {
const compSource = await import('@energysage/es-ds-components/components/es-form-textarea.vue?raw');
// eslint-disable-next-line import/no-self-import
const docSource = await import('./form-textarea.vue?raw');

compCode.value = $prism.normalizeCode(compSource.default);
docCode.value = $prism.normalizeCode(docSource.default);
$prism.highlight();
}
});

const propTableRows = [
['id', 'String', 'n/a', 'Required. The id of the input.'],
['v-model', 'String', 'n/a', 'Required. The v-model directive binds the input to a data property.'],
['disabled', 'Boolean', 'false', 'Specifies that the input should be disabled.'],
['required', 'Boolean', 'false', 'Specifies that the input is required.'],
[
'state',
'Boolean',
'null',
'Specifies the validity of the input. Can be true (success), false (error), or null (default).',
],
];
</script>

<template>
<div>
<h1>Textarea</h1>
<p>
When using a form textarea, please ensure that the label style is
<nuxt-link
href="https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case"
target="_blank">
Sentence case.
</nuxt-link>
</p>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Basic example</h2>
<es-form-textarea
id="basic-example"
v-model="docTextarea">
<template #label> Notes </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Required</h2>
<es-form-textarea
id="required-example"
v-model="docTextarea"
required>
<template #label> Notes </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Error state</h2>
<es-form-textarea
id="error-example"
v-model="docTextarea"
required
:state="false">
<template #label> Notes </template>
<template #errorMessage> This field is required. </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Success state</h2>
<es-form-textarea
id="success-example"
v-model="successValue"
required
:state="true">
<template #label> Notes </template>
<template #errorMessage> This field is required. </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Success state with message</h2>
<es-form-textarea
id="success-message-example"
v-model="successValue"
required
:state="true">
<template #label> Notes </template>
<template #message> Please enter your notes. </template>
<template #errorMessage> This field is required. </template>
<template #successMessage> Your notes have been entered successfully. </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Disabled state</h2>
<es-form-textarea
id="disabled-example"
v-model="docTextarea"
disabled>
<template #label> Notes </template>
</es-form-textarea>
</b-col>
</b-row>

<b-row class="my-500">
<b-col
cols="12"
lg="6">
<h2>Context message</h2>
<es-form-textarea
id="context-message-example"
v-model="docTextarea"
required>
<template #label> Notes </template>
<template #message> Please enter your notes. </template>
<template #errorMessage> This field is required. </template>
<template #successMessage> Your notes have been entered successfully. </template>
</es-form-textarea>
</b-col>
</b-row>

<div class="mb-500">
<h2>EsFormTextarea props</h2>
<ds-prop-table :rows="propTableRows" />
</div>

<ds-doc-source
:comp-code="compCode"
comp-source="es-ds-components/components/es-form-textarea.vue"
:doc-code="docCode"
doc-source="es-ds-docs/pages/molecules/form-textarea.vue" />
</div>
</template>
Loading