Skip to content

Commit

Permalink
add a default limit of 100 chars to short inputs (closes #120)
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilReinking committed Nov 30, 2023
1 parent 3c846cf commit c9b216c
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 46 deletions.
45 changes: 45 additions & 0 deletions resources/js/components/CharCount.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<span
v-if="maxChars"
class="text-xs"
:class="[
hasMaxChars && charCount > maxChars
? 'font-medium text-red-600'
: 'text-grey-600',
]"
>
{{ charCount }}
<span v-if="hasMaxChars">/ {{ maxChars }}</span>
</span>
</template>

<script lang="ts" setup>
import { watch } from "vue";
import { computed, ref } from "vue";
const props = defineProps<{
text?: string;
maxChars?: number;
}>();
const charCount = ref<number>(props.text?.length ?? 0);
const hasMaxChars = computed(() => {
return props.maxChars && props.maxChars > 0;
});
watch(
() => props.text,
() => {
updateCharCount();
},
);
const updateCharCount = () => {
if (props.text) {
charCount.value = props.text.length;
} else {
charCount.value = 0;
}
};
</script>
15 changes: 14 additions & 1 deletion resources/js/forms/classic/interactions/InputAction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,18 @@
ref="inputElement"
autocomplete="off"
@input="onInput"
maxlength="100"
v-once
/>

<CharCount
v-if="block.type === 'input-short'"
v-bind="{
text: inputText,
maxChars: 100,
}"
/>

<div
class="absolute inset-y-px left-px flex w-12 items-center justify-center rounded bg-content/10 text-sm font-medium"
v-if="useSymbol"
Expand All @@ -44,6 +53,7 @@ import { computed, ComputedRef, inject, onMounted, ref } from "vue";
import { D9Icon } from "@deck9/ui";
import { useConversation } from "@/stores/conversation";
import { useFixedNumberFormatting } from "@/utils/useFixedNumberFormatting";
import CharCount from "@/components/CharCount.vue";
const store = useConversation();
Expand All @@ -54,7 +64,7 @@ const props = defineProps<{
const disableFocus: ComputedRef<boolean> | undefined = inject("disableFocus");
let storeValue = ref(
(store.currentPayload as FormBlockInteractionPayload)?.payload
(store.currentPayload as FormBlockInteractionPayload)?.payload,
);
// if we restore a value from the store, we need to format it
Expand All @@ -69,6 +79,7 @@ if (props.block.type === "input-number" && storeValue.value) {
}
const inputElement = ref<HTMLInputElement | null>(null);
const inputText = ref<string | undefined>(inputElement.value?.value);
const stepValue = 1 / Math.pow(10, props.action.options?.decimalPlaces ?? 0);
const useSymbol = ref(props.action.options?.useSymbol ?? false);
Expand Down Expand Up @@ -145,6 +156,8 @@ const onInput = (event) => {
let input: string | number | null = inputElement.value.value;
inputText.value = input;
if (input && props.block.type === "input-number") {
const { output } = useFixedNumberFormatting(event, {
decimalPlaces: props.action.options?.decimalPlaces ?? 0,
Expand Down
52 changes: 12 additions & 40 deletions resources/js/forms/classic/interactions/TextareaAction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,19 @@
v-once
>
</textarea>

<span
v-if="action.options?.max_chars"
class="text-xs"
:class="[
hasMaxChars && charCount > action.options?.max_chars
? 'font-medium text-red-600'
: 'text-grey-600',
]"
>
{{ charCount }}
<span v-if="hasMaxChars">/ {{ action.options?.max_chars }}</span>
</span>
<CharCount
v-bind="{
text: inputText,
maxChars: action.options?.max_chars,
}"
/>
</div>
</template>

<script lang="ts" setup>
import {
computed,
ComputedRef,
inject,
onMounted,
onUnmounted,
ref,
} from "vue";
import { ComputedRef, inject, onMounted, onUnmounted, ref } from "vue";
import { useConversation } from "@/stores/conversation";
import CharCount from "@/components/CharCount.vue";
const store = useConversation();
Expand All @@ -54,12 +41,11 @@ const disableFocus: ComputedRef<boolean> | undefined = inject("disableFocus");
const storeValue = (store.currentPayload as FormBlockInteractionPayload)
?.payload;
const charCount = ref<number>(0);
const inputElement = ref<HTMLInputElement | null>(null);
const inputText = ref<string | undefined>(inputElement.value?.value);
onMounted(() => {
store.enableInputMode();
updateCharCount();
if (!disableFocus?.value) {
inputElement.value?.focus();
Expand All @@ -70,23 +56,9 @@ onUnmounted(() => {
store.disableInputMode();
});
const hasMaxChars = computed(() => {
return props.action.options?.max_chars && props.action.options?.max_chars > 0;
});
const updateCharCount = () => {
const input = inputElement.value?.value ?? null;
if (input) {
charCount.value = input.length;
} else {
charCount.value = 0;
}
};
const onInput = () => {
const input = inputElement.value?.value ?? null;
updateCharCount();
store.setResponse(props.action, input);
const input = inputElement.value?.value;
inputText.value = input;
store.setResponse(props.action, input ?? null);
};
</script>
14 changes: 9 additions & 5 deletions resources/js/forms/classic/interactions/useInputAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ export function useInputAction(block: PublicFormBlockModel) {
].includes(block.type);

const validator = (input: any) => {
const emailValidator = string().required().email();
const linkValidator = string().required().url();
const numberValidator = number().required();
const defaultValidator = string().max(100).required();
const emailValidator = string().max(100).required().email();
const linkValidator = string().max(100).required().url();
const numberValidator = number().max(100).required();
const phoneValidator = string()
.required()
.min(7)
.max(100)
.matches(/^[+]?(?:[0-9]+[\s-]?[0-9]+)+$/);

switch (block.type) {
Expand Down Expand Up @@ -51,8 +53,10 @@ export function useInputAction(block: PublicFormBlockModel) {
};
default:
return {
valid: block.is_required ? input?.payload.length > 0 : true,
message: "This field is required",
valid:
(!block.is_required && !input?.payload) ||
defaultValidator.isValidSync(input?.payload),
message: "Please enter a valid short text.",
};
}
};
Expand Down

0 comments on commit c9b216c

Please sign in to comment.