Skip to content

Commit

Permalink
feat(immutable-text): add immutable text element
Browse files Browse the repository at this point in the history
  • Loading branch information
stfsy committed Sep 1, 2023
1 parent c22c1d2 commit dd79f48
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 2 deletions.
11 changes: 11 additions & 0 deletions docs/.vuepress/examples/FormImmutableText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<FormImmutableText
label="ZipCode"
description="Please enter a valid zip code"
pattern="[0-9]{5}"
format="85080" />
</template>

<script setup>
import { FormImmutableText } from '@discue/ui-components';
</script>
11 changes: 11 additions & 0 deletions docs/components/form-immutable-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# FormImmutableText <Badge type="tip" text="since v0.40.0" vertical="top" />

A `span` element wrapped inside a labelled form element. Does not allow any user input, hence the name. Use this component to add immutable form elements e.g. to display an API key, or other value that might be interesting to the user.

By default, the component will render a copy-to-clipboard button to allow for easier copy and pasting the component's value.

## Preview
<DynamicComponentDisplay type="FormImmutableText" :attach-v-model="true" label="Your Api Key" text="CaJ_9ajombMlDtlSFI1W_xdfdyyRZofOMgUZlhX" id="FormImmutableInputApiKey" ></DynamicComponentDisplay>

## Example
@[code](@examples/FormImmutableText.vue)
78 changes: 78 additions & 0 deletions src/components/form-immutable-text.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template>
<FormElementContainerWithLabel :description="copyToClipboardErrorMsg" :disabled="true" :focussed="false"
:focus-input-callback="focusInput" :force-show-error-message="true" :id="id" :input-invalid="copyToClipboardFailure"
:label="label" :show-pattern-hint="false" :show-format-hint="false" :value="modelValue">

<div class="relative px-3 my-2 flex flex-row items-center">
<div class="mr-8">
<span :id="id" class="text-gray-900 rounded text-lg outline-none placeholder:text-gray-400 leading-8">{{
text }}</span>
</div>

<button v-if="showClipboardButton"
class="absolute bg-transparent right-0 p-2 text-gray-700 cursor-pointer transform transition-transform hover:-translate-y-1 outline-none"
@click.prevent="copyKeyToClipboard">
<ClipboardIcon class="h-6 w-6 stroke-2" />
</button>
<button click.prevent v-if="copyToClipboardSuccess" class="absolute bg-transparent right-0 p-2 text-green-700 outline-none">
<ClipboardDocumentCheckIcon class="h-6 w-6" />
</button>
<button click.prevent v-if="copyToClipboardFailure" class="absolute bg-transparent right-0 p-2 text-attention outline-none">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-5 10.5l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0" />
</svg>
</button>
</div>
</FormElementContainerWithLabel>
</template>

<script setup>
import { ClipboardDocumentCheckIcon, ClipboardIcon } from '@heroicons/vue/24/outline';
import { computed, ref } from 'vue';
import FormElementContainerWithLabel from './form-element-container-with-label.vue';
const props = defineProps({
enableCopyToClipboard: {
type: Boolean,
default: true
},
id: {
type: String
},
label: {
type: String,
},
text: {
type: String
}
})
const copyToClipboardSuccess = ref(false)
const copyToClipboardFailure = ref(false)
const copyToClipboardErrorMsg = ref()
const showClipboardButton = computed(() => {
return props.text && // do we have a text?
props.enableCopyToClipboard && // does our parent want us to allow copying?
typeof window.ClipboardItem === 'function' && // does the browser allow us to copy?
!copyToClipboardSuccess.value && // have we already finished ...
!copyToClipboardFailure.value // ... or failed copying?
})
async function copyKeyToClipboard() {
// @ts-ignore
try {
await navigator.clipboard.writeText(props.text)
copyToClipboardSuccess.value = true
copyToClipboardFailure.value = false
} catch (e) {
copyToClipboardSuccess.value = false
copyToClipboardFailure.value = true
copyToClipboardErrorMsg.value = 'Sorry, we were not able to copy to the clipboard at this time. Please copy the text manually.'
}
}
</script>
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as DropDownMenuBannerItem } from './components/drop-down-menu-b
export { default as DropDownMenuItem } from './components/drop-down-menu-item.vue';
export { default as DropDownMenu } from './components/drop-down-menu.vue';
export { default as FormElementErrorMessage } from './components/form-element-error-message.vue';
export { default as FormImmutableText } from './components/form-immutable-text.vue';
export { default as FormInputRadio } from './components/form-input-radio.vue';
export { default as FormInputSelect } from './components/form-input-select.vue';
export { default as FormInput } from './components/form-input.vue';
Expand Down
16 changes: 14 additions & 2 deletions styles/preview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
}
}

#FormImmutableTextApiKey {
position: initial !important;
}

#FormImmutableTextApiKeyElementContainer {
button {
position: absolute !important;
}
}

ul {
@apply list-none my-0;
padding-left: inherit;
Expand All @@ -54,15 +64,17 @@

.dsq-form-element-container-with-label {
div {
label, select {

label,
select {
@apply bg-stone-300;
}

input {
margin-top: 0;
}

&> span {
&>span {
position: absolute !important;
}
}
Expand Down

0 comments on commit dd79f48

Please sign in to comment.