create clipboard component and update fields

This commit is contained in:
Jordan Blasenhauer 2024-06-14 11:52:50 +02:00
parent 0eb512fea8
commit aec0c8d966
4 changed files with 117 additions and 81 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
<script setup>
import { defineProps } from "vue";
import { contentIndex } from "@utils/tabindex.js";
import { useClipboard } from "@vueuse/core";
import { v4 as uuidv4 } from "uuid";
/**
@name Forms/Feature/Clipboard.vue
@description This component can be add to some fields to allow to copy the value of the field.
Additionnal clipboardClass and copyClass can be added to fit the parent container.
@example
{
id: 'test-input',
isClipboard: true,
valueToCopy: 'yes',
clipboadClass: 'mx-2',
copyClass: 'mt-2',
}
@param {id} [id=uuidv4()] - Unique id
@param {isClipboard} [isClipboard=false] - Display a clipboard button to copy a value
@param {valueToCopy} [valueToCopy=""] - The value to copy
@param {clipboadClass} [clipboadClass=""] - Additional class for the clipboard container. Useful to fit the component in a specific container.
@param {copyClass} [copyClass=""] - The class of the copy message. Useful to fit the component in a specific container.
*/
const { text, copy, copied, isSupported } = useClipboard({ legacy: true });
const props = defineProps({
id: {
type: String,
required: false,
default: uuidv4(),
},
isClipboard: {
type: Boolean,
required: false,
default: false,
},
valueToCopy: {
type: String,
required: false,
default: "",
},
clipboardClass: {
type: String,
required: false,
default: "",
},
copyClass: {
type: String,
required: false,
default: "",
},
});
</script>
<template>
<div
v-if="props.isClipboard"
:class="['input-clipboard-container', props.clipboardClass]"
>
<button
type="button"
:class="['input-clipboard-button', copied ? 'copied' : 'not-copied']"
:tabindex="contentIndex"
@click.prevent="copy(valueToCopy)"
:aria-describedby="`${props.id}-clipboard-text`"
>
<span :id="`${props.id}-clipboard-text`" class="sr-only">
{{ $t("inp_input_clipboard_desc") }}
</span>
<svg
aria-hidden="true"
role="img"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="input-clipboard-svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z"
></path>
</svg>
<div
v-if="copied"
role="alert"
:class="['input-clipboard-copy', props.copyClass]"
>
{{ $t("inp_input_clipboard_copied") }}
</div>
</button>
</div>
</template>

View file

@ -7,12 +7,13 @@ import {
defineProps,
onUnmounted,
} from "vue";
import { useClipboard } from "@vueuse/core";
import { contentIndex } from "@utils/tabindex.js";
import Container from "@components/Widget/Container.vue";
import Header from "@components/Forms/Header/Field.vue";
import ErrorField from "@components/Forms/Error/Field.vue";
import Clipboard from "@components/Forms/Feature/Clipboard.vue";
import { v4 as uuidv4 } from "uuid";
import "@assets/script/editor/ace.js";
import "@assets/script/editor/theme-dracula.js";
import "@assets/script/editor/theme-dawn.js";
@ -44,7 +45,7 @@ import "@assets/script/editor/theme-dawn.js";
@param {string} [pattern=""]
@param {boolean} [disabled=false]
@param {boolean} [required=false]
@param {boolean} [clipboard=false] - allow to copy the input value
@param {boolean} [isClipboard=true] - allow to copy the input value
@param {boolean} [hideLabel=false]
@param {string} [containerClass=""]
@param {string} [editorClass=""]
@ -52,8 +53,6 @@ import "@assets/script/editor/theme-dawn.js";
@param {string|number} [tabId=contentIndex] - The tabindex of the field, by default it is the contentIndex
*/
const { text, copy, copied, isSupported } = useClipboard({ legacy: true });
const props = defineProps({
// id && value && method
id: {
@ -92,7 +91,7 @@ const props = defineProps({
required: false,
defaut: "",
},
clipboard: {
isClipboard: {
type: Boolean,
required: false,
default: true,
@ -135,7 +134,6 @@ const props = defineProps({
const editor = reactive({
value: props.value,
showInp: false,
isClipAllow: false,
isValid: computed(() => {
if (props.required && !editor.value) return false;
if (props.pattern) {
@ -331,38 +329,12 @@ onUnmounted(() => {
:aria-description="$t('inp_editor_desc')"
:id="props.id"
></div>
<div v-if="props.clipboard" class="input-clipboard-container editor">
<button
type="button"
:class="['input-clipboard-button', copied ? 'copied' : 'not-copied']"
:tabindex="contentIndex"
@click.prevent="copy(editor.value)"
:aria-describedby="`${props.id}-clipboard-text`"
>
<span :id="`${props.id}-clipboard-text`" class="sr-only"
>{{ $t("inp_input_clipboard_desc") }}
</span>
<svg
aria-hidden="true"
role="img"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="input-clipboard-svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z"
></path>
</svg>
<div v-if="copied" role="alert" class="editor input-clipboard-copy">
{{ $t("inp_input_clipboard_copied") }}
</div>
</button>
</div>
<Clipboard
:isClipboard="props.isClipboard"
:clipboardClass="'editor'"
:copyClass="'editor'"
:valueToCopy="editor.value"
/>
</div>
<ErrorField :isValid="editor.isValid" :isValue="!!editor.value" />
</Container>

View file

@ -4,8 +4,8 @@ import { contentIndex } from "@utils/tabindex.js";
import Container from "@components/Widget/Container.vue";
import Header from "@components/Forms/Header/Field.vue";
import ErrorField from "@components/Forms/Error/Field.vue";
import Clipboard from "@components/Forms/Feature/Clipboard.vue";
import { v4 as uuidv4 } from "uuid";
import { useClipboard } from "@vueuse/core";
/**
@name Forms/Field/Input.vue
@ -45,7 +45,7 @@ import { useClipboard } from "@vueuse/core";
@param {boolean} [required=false]
@param {string} [placeholder=""]
@param {string} [pattern="(?.*)"]
@param {boolean} [clipboard=false] - allow to copy the input value
@param {boolean} [isClipboard=true] - allow to copy the input value
@param {boolean} [readonly=false] - allow to read only the input value
@param {boolean} [hideLabel=false]
@param {string} [containerClass=""]
@ -54,8 +54,6 @@ import { useClipboard } from "@vueuse/core";
@param {string|number} [tabId=contentIndex] - The tabindex of the field, by default it is the contentIndex
*/
const { text, copy, copied, isSupported } = useClipboard({ legacy: true });
const props = defineProps({
// id && value && method
id: {
@ -101,7 +99,7 @@ const props = defineProps({
type: String,
required: false,
},
clipboard: {
isClipboard: {
type: Boolean,
required: false,
default: true,
@ -150,7 +148,6 @@ const inputEl = ref(null);
const inp = reactive({
value: props.value,
showInp: false,
isClipAllow: false,
isValid: true,
});
@ -212,42 +209,12 @@ onMounted(() => {
: props.type
"
/>
<div
v-if="props.clipboard"
:class="[props.type === 'password' ? 'pw-input' : 'no-pw-input']"
class="input-clipboard-container"
>
<button
type="button"
:class="['input-clipboard-button', copied ? 'copied' : 'not-copied']"
:tabindex="contentIndex"
@click.prevent="copy(inp.value)"
:aria-describedby="`${props.id}-clipboard-text`"
>
<span :id="`${props.id}-clipboard-text`" class="sr-only"
>{{ $t("inp_input_clipboard_desc") }}
</span>
<svg
aria-hidden="true"
role="img"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="input-clipboard-svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z"
></path>
</svg>
<div v-if="copied" role="alert" class="input input-clipboard-copy">
{{ $t("inp_input_clipboard_copied") }}
</div>
</button>
</div>
<Clipboard
:isClipboard="props.isClipboard"
:valueToCopy="inp.value"
:clipboardClass="props.type === 'password' ? 'pw-input' : 'no-pw-input'"
:copyClass="'input'"
/>
<div v-if="props.type === 'password'" class="input-pw-container">
<button